本文面向:有基础开发能力、但还没深入接触过 AI 应用开发的同学。无论你是后端 Java 开发者、还是 Python 爱好者,跟着这篇文章走,你能从"零"建立起对 AI 应用开发核心技术的系统理解。

阅读建议:建议按章节顺序阅读,每章开头会有概述说明本章内容,方便你快速判断是否需要细读。文中的代码示例均附有详细注释。


第1章 AI 应用开发:从调用 API 到构建系统

本章讲什么:从"大模型能干什么"出发,解释为什么光靠调用大模型 API 不够,为什么需要向量数据库、编排框架、RAG 等一整套技术栈,帮你建立对 AI 应用开发全貌的认知。

1.1 大模型很强,但不是万能的

如果你做过 AI 相关的尝试,大概率是这样的体验——调一个 API,把用户的问题丢给大模型,拿到回答,完事。

# 最简单的 LLM 调用
response = client.chat.completions.create(
    model="qwen3-plus",
    messages=[{"role": "user", "content": "公司年假怎么休?"}]
)
print(response.choices[0].message.content)

这段代码确实能跑,大模型也会给你一个关于年假的回答。但问题是——它回答的是"通用知识"的年假制度,不是你们公司的年假制度。

这就是大模型最核心的三个短板:

短板 说明 举例
知识截止 训练数据有时效性,不知道最新信息 不知道公司昨天刚改的报销政策
缺乏私有知识 没学过你公司的内部资料 无法回答"张三的直属领导是谁"
无法执行操作 只能生成文本,不能帮你查数据库、发邮件 你让它"帮我订个会议室",它只能告诉你怎么订

💡 一句话总结:大模型是一个"读了万卷书但没出过门的书生"——知识面广,但对你的具体情况一无所知,也没有手脚去干活。

1.2 AI 应用开发 = 让书生"接地气"

要让大模型真正有用,我们需要给它三样东西

大模型 LLM

知识
让它知道你的事

工具
让它能动手干活

编排
让它按流程做事

向量数据库 + RAG

Tool / MCP / Function Calling

LangChain / LangGraph / Spring AI

  • 知识:通过 向量数据库RAG 技术,把你的私有文档喂给大模型,让它能回答"你们公司的事"。
  • 工具:通过 Function CallingMCP 等机制,让大模型能调用外部 API、查询数据库、操作文件系统。
  • 编排:通过 LangChainLangGraphSpring AI 等框架,把"调用模型→检索知识→调用工具→生成回答"这套流程编排起来,让大模型按规矩办事。

1.3 技术栈全景图

下面这张图,基本涵盖了当前 AI 应用开发的核心技术栈:

模型层

存储层

增强层

编排框架层

应用层

智能客服

知识库问答

代码助手

数据分析 Agent

LangChain
Python

LangGraph
Python/Java

Spring AI
Java

Spring AI Alibaba
Java

RAG / Agentic RAG

Function Calling

MCP 协议

Memory 记忆管理

向量数据库
Milvus / Chroma / Weaviate

关系型数据库
MySQL / PostgreSQL

对象存储
MinIO / OSS

DeepSeek / Qwen / Claude

Embedding 模型
BGE-M3 / text-embedding-v3

📌 接下来,我们会从底向上,逐层拆解这些技术。先从向量数据库开始——它是整个 AI 应用的"记忆器官"。


第2章 向量数据库:让机器"读懂"语义

本章讲什么:从"为什么传统数据库搞不定语义搜索"出发,讲清向量、Embedding、向量数据库的原理,对比主流向量数据库的选型,并用实际例子演示如何把文档存入向量数据库并进行检索。

2.1 为什么传统数据库搜不准?

假设你有一个公司内部知识库,里面有一段话:

“员工入职满一年后,可享受5天带薪年假。工龄每增加一年,年假天数增加1天,上限为15天。”

现在用户问:“新来的同事能休多少天假?”

用传统数据库的 LIKE '%年假%' 搜索,确实能搜到这段话。但如果用户问的是:“刚入职有假期吗?”——关键词里根本没有"年假"两个字,你就搜不到了。

这就是传统搜索的核心问题:它只看"字面匹配",不理解"语义"。

而人脑是天然理解语义的——你看到"刚入职有假期吗",脑子里自动就把它和"年假制度"关联起来了。向量数据库要做的事,就是让计算机也具备这种"语义理解"能力。

2.2 从文本到向量:Embedding 的魔法

要让计算机理解语义,首先要把文本变成数字——具体来说,变成一组浮点数,也就是向量(Vector)

这个过程叫做 Embedding(嵌入),由专门的 Embedding 模型来完成。

"年假制度"  →  Embedding模型  →  [0.023, -0.156, 0.891, ..., 0.034]  (1536维向量)
"假期规定"  →  Embedding模型  →  [0.025, -0.148, 0.887, ..., 0.031]  (1536维向量)
"红烧肉做法" →  Embedding模型  →  [-0.412, 0.567, -0.234, ..., 0.789] (1536维向量)

🔑 核心原理:语义越相似的文本,转换出来的向量在空间中的距离越近;语义差异大的文本,向量距离越远。

语义空间

● 年假制度

● 假期规定

● 入职休假

● 红烧肉做法

● 糖醋排骨

这样,当用户问"刚入职有假期吗"时,系统会:

  1. 把问题通过 Embedding 模型转成向量
  2. 在向量数据库中找到距离最近的那些文档片段
  3. 返回语义最相关的结果

这比关键词搜索强大太多了——你不需要包含一模一样的词,只要语义相关就能匹配上。

2.3 主流 Embedding 模型对比

Embedding 模型的选择直接影响检索质量。下面是当前主流模型的对比:

模型 提供方 向量维度 特点 适用场景
BGE-M3 智源研究院 1024 支持多语言、多粒度检索,中文效果顶级 企业级 RAG、跨语言检索
GTE-Qwen2 阿里达摩院 1536 基于 Qwen2 架构,代码检索能力强 中文场景、代码检索
text-embedding-v3 阿里百炼 1024 API 调用,与 Spring AI 集成方便 Java 生态、快速接入
text-embedding-3-large OpenAI 3072 效果好但维度高,存储成本大 预算充足的项目
m3e-base 开源社区 768 轻量级,中文效果不错 小规模项目、本地部署

💡 选型建议:如果是 Java 项目,直接用阿里百炼的 text-embedding-v3,和 Spring AI 无缝集成;如果追求最佳中文效果且能本地部署,选 BGE-M3。

2.4 向量数据库:专门存"向量"的数据库

有了 Embedding 模型把文本转成向量,还需要一个专门存储和检索向量的数据库——这就是向量数据库

向量数据库和传统数据库的核心区别

对比维度 传统数据库(MySQL等) 向量数据库(Milvus等)
查询方式 精确匹配(WHERE name = ‘xxx’) 相似度检索(找最近的向量)
索引类型 B+ Tree、Hash HNSW、IVF-PQ、DiskANN
适用场景 结构化数据的增删改查 语义搜索、推荐系统、RAG
返回结果 完全匹配的记录 按相似度排序的 Top-K 结果

2.5 主流向量数据库对比选型

数据库 类型 核心优势 适用场景 部署方式
Milvus 开源 分布式架构,千亿级向量,QPS超百万 大规模企业级 RAG Docker/K8s
Chroma 开源 轻量级,5分钟上手,pip install 即用 原型开发、小规模项目 本地内嵌
Weaviate 开源 内置混合检索(向量+关键词),多模态支持 需要混合搜索的场景 Docker/云服务
Qdrant 开源 Rust 编写,高性能,支持稀疏向量 高并发场景 Docker
Pinecone 云服务 全托管,零运维,Serverless 按量付费 中小团队快速上线 云端
Redis Stack 开源 复用现有 Redis 基础设施 已有 Redis 的团队 Docker

🎯 选型口诀

  • 💰 快速验证 → Chroma(本地跑起来就行)
  • 🏢 企业级生产 → Milvus(稳、快、大规模)
  • 🔀 混合检索 → Weaviate(向量+关键词一把梭)
  • ☁️ 不想运维 → Pinecone(全托管省心)
  • Java/Spring 生态 → Milvus 或 Redis Stack(Spring AI 都有 Starter)

2.6 实战:用 Chroma 快速体验向量检索

以下用 Python + Chroma 演示最简流程。Chroma 是最轻量的选择,pip install 就能跑。

# 安装依赖:pip install chromadb sentence-transformers

import chromadb
from chromadb.utils import embedding_functions

# 1. 初始化客户端(本地持久化存储)
client = chromadb.PersistentClient(path="./my_vector_db")

# 2. 初始化 Embedding 模型(使用开源的 all-MiniLM-L6-v2)
ef = embedding_functions.SentenceTransformerEmbeddingFunction(
    model_name="all-MiniLM-L6-v2"
)

# 3. 创建集合(类似数据库的"表")
collection = client.get_or_create_collection(
    name="company_docs",
    embedding_function=ef
)

# 4. 添加文档
docs = [
    "员工入职满一年后,可享受5天带薪年假。工龄每增加一年,年假天数增加1天,上限为15天。",
    "公司提供弹性工作制,核心工作时间为10:00-16:00,其余时间可灵活安排。",
    "每月最后一个周五为团建日,各部门可申请500元/人的团建经费。",
    "服务器运维规范:所有线上变更必须经过Code Review和测试环境验证,禁止直接操作生产环境。"
]
collection.add(
    documents=docs,
    ids=["doc1", "doc2", "doc3", "doc4"]
)

# 5. 语义检索 —— 注意:查询词和文档中的关键词不完全匹配
results = collection.query(
    query_texts=["刚来的新人能休假吗?"],  # 没有"年假"这个词
    n_results=2
)
print(results["documents"][0])
# 输出:["员工入职满一年后,可享受5天带薪年假..."]  ← 命中了!

🎉 看到了吗? 查询词"刚来的新人能休假吗"里根本没有"年假"二字,但向量数据库通过语义相似度,准确找到了年假制度那条文档。这就是向量检索的威力。

2.7 实战:Java 生态中用 Spring AI + Milvus

如果你是 Java 开发者,Spring AI 提供了对 Milvus 的原生支持:

<!-- pom.xml 添加依赖 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-milvus-store</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
# application.yml 配置
spring:
  ai:
    openai:
      api-key: ${DASHSCOPE_API_KEY}     # 阿里百炼的 Key
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      embedding:
        options:
          model: text-embedding-v3       # 阿里百炼 Embedding 模型
    vectorstore:
      milvus:
        client:
          host: localhost
          port: 19530
        database-name: default
        collection-name: company_docs
        dimension: 1024
// 注入 VectorStore,一行代码完成存储和检索
@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
    return MilvusVectorStore.builder(embeddingModel)
        .milvusClient(milvusClient)
        .build();
}

// 存入文档
vectorStore.add(List.of(
    new Document("员工入职满一年后,可享受5天带薪年假...")
));

// 语义检索
List<Document> results = vectorStore.similaritySearch(
    SearchRequest.builder()
        .query("刚来的新人能休假吗?")
        .topK(3)
        .build()
);

💡 对比感受:Python 生态用 Chroma 几行代码就能跑原型;Java 生态需要多些配置,但 Spring AI + Milvus 的组合在生产环境更稳定、更适合企业级部署。


第3章 LangChain:AI 应用开发的"瑞士军刀"

本章讲什么:从 LangChain 的整体架构出发,逐个拆解它的六大核心模块(Models、Prompts、Indexes、Memory、Chains、Agents),让你理解每个模块解决什么问题、怎么用,以及它在实际项目中的最佳实践。

3.1 为什么需要 LangChain?

设想你要开发一个"智能客服"应用,它的流程大概是:

  1. 用户提问 → 2. 去知识库检索相关文档 → 3. 把检索结果塞进提示词 → 4. 调用大模型生成回答 → 5. 记住对话上下文 → 6. 如果用户追问,继续交互

每一个步骤都需要写一堆胶水代码:调 API、拼提示词、管记忆、处理异常……而且如果明天要换一个模型(比如从 DeepSeek 换到 Qwen),你得改一堆地方。

LangChain 的价值就在于——把这些"脏活累活"标准化了。 它提供了一套统一的抽象和模块,让你像搭积木一样组装 AI 应用。

3.2 LangChain 整体架构

LangChain 的架构分三层:

基础层

能力层

应用层

LangServe
部署服务

LangSmith
调试监控

LangGraph
复杂编排

Chains
链式调用

Agents
自主决策

Memory
对话记忆

Retriever
检索器

ChatModel
模型接口

Prompt
提示词

OutputParser
输出解析

Tools
工具定义

  • 基础层:定义了模型接口、提示词模板、输出解析器等核心抽象,所有上层功能都围绕这些接口展开。换模型只要换实现类就行。
  • 能力层:Chain 负责串步骤,Agent 负责自主决策,Memory 负责记忆,Retriever 负责检索。
  • 应用层:LangServe 做 API 部署,LangSmith 做调试追踪,LangGraph 做复杂工作流编排。

3.3 核心模块一:Models(模型接口)

LangChain 对各家大模型做了统一封装。不管你用 DeepSeek、Qwen 还是 Claude,上层调用的接口都一样:

from langchain_community.chat_models import ChatTongyi  # 通义千问
from langchain_openai import ChatOpenAI                  # OpenAI 兼容接口

# 方式一:直接用通义千问
llm = ChatTongyi(model="qwen3-plus")

# 方式二:通过 OpenAI 兼容接口调 DeepSeek
llm = ChatOpenAI(
    model="deepseek-chat",
    base_url="https://api.deepseek.com",
    api_key="your-key"
)

# 调用方式完全一样,换模型只需改初始化
response = llm.invoke("请解释什么是RAG")
print(response.content)

💡 最佳实践:推荐使用 OpenAI 兼容接口。现在绝大多数模型厂商(阿里百炼、DeepSeek、智谱等)都兼容 OpenAI 的 API 格式,这样你换模型时只需要改 base_urlapi_key,零代码改动。

3.4 核心模块二:Prompts(提示词管理)

提示词的质量直接决定大模型的输出质量。LangChain 提供了 PromptTemplate 来管理提示词模板:

from langchain_core.prompts import ChatPromptTemplate

# 定义带变量的提示词模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个{company_name}的智能客服,请用专业、友好的语气回答问题。"),
    ("human", "{question}")
])

# 填充变量
formatted = prompt.invoke({
    "company_name": "星辰科技",
    "question": "你们支持远程办公吗?"
})

Prompt Engineering 的几个关键技巧

技巧 说明 示例
角色设定 在 System Prompt 中设定 AI 的角色和行为准则 “你是专业的法律顾问,只基于提供的法律条文回答”
Few-Shot 示例 给出几个输入-输出的示例,让模型学习格式 给2-3个问答对作为参考
结构化输出 要求模型按特定格式(JSON等)输出 “请以JSON格式输出,包含title和content字段”
思维链 让模型先思考再回答 “请先分析问题,然后逐步推理,最后给出答案”

3.5 核心模块三:Indexes(文档索引与检索)

这是 RAG 的核心模块,包含四个关键组件:

DocumentLoader
文档加载

TextSplitter
文本分割

Embeddings
向量化

VectorStore
向量存储

Retriever
检索器

DocumentLoader:把各种格式的文档(PDF、Word、HTML、Markdown等)加载为统一的 Document 对象。

TextSplitter:把长文档切成小段。这一步非常关键,切得太大会让检索不精确,切得太小会丢失上下文。

from langchain_text_splitters import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,       # 每段最多500字符
    chunk_overlap=50,     # 相邻段落重叠50字符,防止语义断裂
    separators=["\n\n", "\n", "。", "!", "?", ",", " "]  # 按优先级切分
)

chunks = splitter.split_text(long_document)

💡 分块策略的最佳实践

  • 固定大小分块:简单粗暴,适合快速验证
  • 递归字符分块:LangChain 默认策略,按段落→句子→词逐级切分
  • 语义分块:按语义边界切分,效果最好但计算成本高
  • 建议:先用 RecursiveCharacterTextSplitter 跑通流程,效果不够再换语义分块

VectorStore:把分块后的文档存入向量数据库(上一章讲的)。

Retriever:从向量数据库中检索相关文档。LangChain 提供了多种检索策略:

# 基础语义检索
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# 混合检索(向量 + 关键词),效果通常更好
from langchain.retrievers import EnsembleRetriever
ensemble_retriever = EnsembleRetriever(
    retrievers=[vector_retriever, keyword_retriever],
    weights=[0.7, 0.3]  # 向量检索权重70%,关键词检索权重30%
)

3.6 核心模块四:Memory(对话记忆)

大模型本身是"无记忆"的——每次调用都是独立的对话。Memory 模块帮你维护上下文:

from langgraph.graph import StateGraph
from langgraph.checkpoint.memory import MemorySaver

# 使用 Checkpointer 实现对话记忆
checkpointer = MemorySaver()

# 编译图时传入 checkpointer
graph = workflow.compile(checkpointer=checkpointer)

# 每次对话传入 thread_id,同一 thread 的对话历史会自动维护
result = graph.invoke(
    {"messages": [HumanMessage(content="我叫小明")]},
    config={"configurable": {"thread_id": "user-001"}}
)

# 后续对话,模型会记住"用户叫小明"
result2 = graph.invoke(
    {"messages": [HumanMessage(content="我叫什么名字?")]},
    config={"configurable": {"thread_id": "user-001"}}
)
# 输出:你叫小明
记忆类型 说明 适用场景
短期记忆 存最近几轮对话,直接放进 Prompt 普通对话
长期记忆 存入向量数据库,按语义检索历史 需要回忆很久之前的内容
摘要记忆 对历史对话做摘要,节省 Token 超长对话场景

💡 最佳实践:短期记忆用 LangGraph 的 Checkpointer,长期记忆用 VectorStore。两者结合效果最佳。

3.7 核心模块五:Chains(链式调用)

Chain 把多个步骤串联起来。最经典的是 LLMChain

用户输入 → PromptTemplate(拼提示词) → LLM(调用模型) → OutputParser(解析输出)

但 Chain 是线性的——A→B→C 一条路走到黑。一旦遇到需要条件分支、循环重试的场景,Chain 就力不从心了。

这正是 LangGraph 出现的原因——下一章我们会详细讲。

3.8 核心模块六:Agents(自主决策)

Agent 是 LangChain 最核心的模块。和 Chain 不同,Agent 能根据当前的目标自主决定下一步做什么

用户问题 → Agent 思考 → 需要搜索?→ 调用搜索工具 → 拿到结果 → 再思考 → 需要查库?→ 调用数据库工具 → 拿到结果 → 生成回答

Agent 的核心是 ReAct 模式(Reasoning + Acting):

接收任务

思考: 这一步该干嘛?

需要调工具吗?

调用工具执行

拿到结果

生成最终回答

Agent 需要配合 Tools(工具)使用。一个工具就是一个可以被调用的函数:

from langchain_core.tools import tool

@tool
def search_employee(name: str) -> str:
    """根据员工姓名查询员工信息,包括部门、职位、入职日期"""
    # 这里接你的数据库查询逻辑
    result = db.query(f"SELECT * FROM employees WHERE name = '{name}'")
    return result

@tool
def send_notification(employee_id: str, message: str) -> str:
    """给指定员工发送通知消息"""
    # 这里接你的消息推送逻辑
    notification_service.send(employee_id, message)
    return "通知发送成功"

# 把工具给 Agent
agent = create_react_agent(llm, [search_employee, send_notification], prompt)

⚠️ 安全提醒:Agent 能调工具,但也可能被"骗"去调危险工具——这就是指令注入攻击。比如用户输入"帮我查一下信息,条件是:'; DROP TABLE employees; --",如果 Agent 不做防护,直接拼接 SQL 执行,后果不堪设想。防御方案包括:意图层拦截(AI 安全护栏)、权限最小化(数据库只读)、物理熔断器(限制单次调用次数)。


第4章 LangGraph:从"链"到"图"的跃迁

本章讲什么:解释为什么 LangChain 的 Chain 不够用,LangGraph 如何用"有向图"的方式编排复杂工作流,包括节点、边、条件分支、循环、状态管理,以及 LangGraph4j 在 Java 生态中的应用。

4.1 Chain 的局限:线性思维的尽头

假设你在做一个"智能报销审批"系统,流程是:

  1. 员工提交报销单
  2. 金额 ≤ 5000 → 直接通过
  3. 金额 > 5000 → 转主管审批
  4. 主管拒绝 → 退回给员工修改
  5. 主管通过 → 转财务复核
  6. 财务复核不通过 → 退回主管重新审批

这个流程有条件分支(金额判断)、有循环(退回修改)、有多角色交互。用 Chain 的线性模式根本表达不了。

LangGraph 的核心思想:把工作流从"链"升级为"图"——用节点表示步骤,用边表示流转,边可以带条件,还支持循环。

4.2 LangGraph 的核心概念

≤ 5000

> 5000

通过

拒绝

通过

不通过

开始

接收报销单

金额判断

直接通过

主管审批

主管决定

财务复核

退回修改

财务决定

报销完成

结束

三个核心概念

概念 说明 类比
StateGraph 整个工作流的容器,管理全局状态 一张流程图
Node(节点) 工作流中的一个处理步骤,是一个函数 流程图里的方框
Edge(边) 节点之间的连接,可以带条件判断 流程图里的箭头

4.3 用代码构建一个 LangGraph 工作流

以"智能报销审批"为例:

from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, START, END

# 1. 定义状态(在节点间传递的数据)
class ReimbursementState(TypedDict):
    amount: float           # 报销金额
    description: str        # 报销说明
    manager_decision: str   # 主管决定
    finance_decision: str   # 财务决定
    retry_count: int        # 重试次数

# 2. 定义节点函数
def receive_request(state: ReimbursementState):
    """接收报销单"""
    return {"retry_count": 0}

def auto_approve(state: ReimbursementState):
    """小额自动通过"""
    return {"manager_decision": "approved", "finance_decision": "approved"}

def manager_review(state: ReimbursementState):
    """主管审批(调用LLM模拟审批逻辑)"""
    decision = llm.invoke(f"审批报销:{state['description']},金额{state['amount']}元")
    return {"manager_decision": decision}

def finance_review(state: ReimbursementState):
    """财务复核"""
    decision = llm.invoke(f"财务复核:{state['description']}")
    return {"finance_decision": decision}

def send_back(state: ReimbursementState):
    """退回修改"""
    return {"retry_count": state["retry_count"] + 1}

# 3. 定义条件边
def check_amount(state: ReimbursementState):
    if state["amount"] <= 5000:
        return "auto_approve"
    return "manager_review"

def check_manager(state: ReimbursementState):
    if state["manager_decision"] == "approved":
        return "finance_review"
    return "send_back"

def check_finance(state: ReimbursementState):
    if state["finance_decision"] == "approved":
        return "end"
    if state["retry_count"] >= 3:  # 防止无限循环
        return "end"
    return "manager_review"

# 4. 组装图
workflow = StateGraph(ReimbursementState)
workflow.add_node("receive", receive_request)
workflow.add_node("auto_approve", auto_approve)
workflow.add_node("manager_review", manager_review)
workflow.add_node("finance_review", finance_review)
workflow.add_node("send_back", send_back)

workflow.add_edge(START, "receive")
workflow.add_conditional_edges("receive", check_amount)
workflow.add_conditional_edges("manager_review", check_manager)
workflow.add_conditional_edges("finance_review", check_finance)
workflow.add_edge("send_back", "receive")
workflow.add_edge("auto_approve", END)

# 5. 编译并运行
graph = workflow.compile()
result = graph.invoke({
    "amount": 8000,
    "description": "出差北京的高铁票和住宿费"
})

4.4 LangGraph 的五种经典编排模式

模式 说明 典型场景
提示词链式 A→B→C 线性串联,上一步的输出是下一步的输入 文档摘要→翻译→润色
路由 根据输入意图分发到不同路径 客服系统:售前/售后/投诉各走各路
编排者-工作者 一个"调度员"拆任务,多个"工人"并行执行,最后汇总 多章节报告生成、批量文档处理
评估者-优化者 一个节点生成结果,另一个节点评估,不通过就循环优化 代码生成→代码审查→修改→再审查
并行扇出-扇入 多个节点同时执行,等全部完成后汇聚 同时查多个数据源,汇总后生成回答

评估者-优化者模式

不通过

通过

生成代码

审查代码

修改代码

输出结果

编排者-工作者模式

编排者拆解任务

工作者A

工作者B

工作者C

编排者汇总

路由模式

售前

售后

投诉

输入

意图识别

售前客服

售后客服

投诉处理

💡 最佳实践:不要一上来就用最复杂的编排者-工作者模式。先用简单的链式调用跑通,发现瓶颈后再逐步升级到路由、评估者-优化者等模式。过度设计是 AI 应用开发最常见的坑。

4.5 Java 生态的选择:LangGraph4j

如果你是 Java 开发者,LangGraph4j 是目前 Java 生态中最成熟的图式编排框架,它借鉴了 Python 版 LangGraph 的设计理念,与 LangChain4j、Spring AI 都能无缝集成。

// LangGraph4j 核心概念与 Python 版一致
public class ReimbursementWorkflow {

    // 1. 定义状态
    public record State(
        double amount,
        String description,
        String managerDecision,
        String financeDecision,
        int retryCount
    ) {}

    // 2. 定义节点
    public Map<String, Object> managerReview(State state) {
        String decision = chatModel.call(
            "审批报销:" + state.description() + ",金额" + state.amount() + "元"
        );
        return Map.of("managerDecision", decision);
    }

    // 3. 构建图
    public CompiledGraph<State> buildWorkflow() {
        StateGraph<State> workflow = new StateGraph<>(State.class);

        workflow.addNode("manager_review", this::managerReview);
        workflow.addNode("finance_review", this::financeReview);
        // ... 添加更多节点

        workflow.addEdge(START, "manager_review");
        workflow.addConditionalEdges("manager_review", this::checkManagerDecision);
        // ... 添加更多边

        return workflow.compile();
    }
}

🎯 选型建议

  • Python 项目 → 直接用 LangGraph
  • Java 项目且已有 Spring AI → 用 LangGraph4j 或 Spring AI Alibaba Graph
  • Java 项目且已有 LangChain4j → 用 LangGraph4j

4.6 LangGraph vs LangChain:什么时候该用哪个?

对比维度 LangChain Chain LangGraph
执行模式 线性 A→B→C 图式,支持分支、循环、并行
状态管理 无内置状态 StateGraph 统一管理
复杂度 简单场景快速上手 有学习曲线,但更灵活
适用场景 简单问答、单步工具调用 多步推理、条件分支、需循环重试
调试 LangSmith 追踪 LangSmith + Studio 可视化

💡 经验法则:如果你的工作流超过3个步骤,或者有"如果A则B否则C"的逻辑,就该用 LangGraph 而不是 Chain 了。


第5章 Spring AI 与 Spring AI Alibaba:Java 开发者的 AI 捷径

本章讲什么:如果你是 Java 开发者,不想学 Python 也能做 AI 应用开发——Spring AI 和 Spring AI Alibaba 就是为你准备的。本章会讲清它们的定位、核心能力、与 LangChain 的区别,以及如何在 Spring Boot 项目中快速上手。

5.1 Java 开发者做 AI 的困境

在 AI 应用开发领域,Python 几乎是"默认语言"。LangChain、LangGraph、各种示例全是 Python 的。Java 开发者面临几个尴尬:

  • 🔴 LangChain 没有官方 Java 版本(LangChain4j 是社区版)
  • 🔴 大部分教程和示例都是 Python
  • 🔴 团队技术栈是 Java/Spring Boot,不可能为了 AI 全换 Python

Spring AI 的出现,就是为了让 Java 开发者用熟悉的方式做 AI 开发。

5.2 Spring AI 是什么?

Spring AI 是 Spring 官方推出的 AI 应用开发框架,它的设计理念是——把 AI 能力像 Spring 的其他模块一样,通过 Starter 自动配置、Bean 注入来使用

如果你用过 Spring Data JPA,那你已经理解 Spring AI 的思路了:

Spring 生态 统一抽象 具体实现
Spring Data Repository 接口 JPA / MongoDB / Redis
Spring AI ChatModel 接口 OpenAI / DeepSeek / Qwen

换模型就像换数据库——改配置,不改代码。

5.3 Spring AI 核心能力

Spring AI 核心能力

ChatModel
统一模型接口

EmbeddingModel
向量化

VectorStore
向量存储

Function Calling
工具调用

Structured Output
结构化输出

RAG
检索增强生成

Chat Memory
对话记忆

逐一说明

ChatModel:统一的模型调用接口。支持同步、流式两种调用方式。

@Autowired
private ChatModel chatModel;

// 同步调用
String response = chatModel.call("什么是RAG?");

// 流式调用(逐字输出,用户体验更好)
Flux<ChatResponse> stream = chatModel.stream("请写一首关于春天的诗");

EmbeddingModel:文本向量化接口,和 ChatModel 一样的"换实现不改代码"思路。

VectorStore:统一的向量存储接口,支持 Milvus、Chroma、Redis、PGVector 等。

Function Calling:让大模型能调用 Java 方法,这是构建 Agent 的基础。

@Bean
@Description("根据城市名称查询当前天气")
public Function<WeatherRequest, WeatherResponse> weatherFunction() {
    return request -> weatherService.query(request.city());
}

Structured Output:让大模型的输出直接映射为 Java 对象(POJO),不再需要手动解析 JSON 字符串。

// 定义输出结构
public record BookRecommendation(
    String title,
    String author,
    String reason
) {}

// 自动映射
BookRecommendation rec = chatModel.prompt("推荐一本编程书")
    .call()
    .entity(BookRecommendation.class);

RAG:内置 RAG 全流程支持(下一章详讲)。

Chat Memory:对话记忆管理,支持窗口记忆、摘要记忆等策略。

5.4 Spring AI Alibaba:阿里增强版

Spring AI Alibaba 是基于 Spring AI 的扩展实现,由阿里云团队维护。它在 Spring AI 的基础上增加了:

能力 说明
DashScope ChatModel 直接对接阿里百炼平台的通义系列模型
Agent Framework 构建 Agent 和多 Agent 应用的框架,内置上下文工程支持
Graph 编排 类似 LangGraph的有向图编排,支持复杂工作流
Studio 可视化聊天窗口,查看 Agent 推理和工具执行细节
Admin 本地可视化工具包,支持项目管理、运行时追踪、Agent 评估
MCP 注册中心 支持 MCP 协议的工具注册与发现
Skill 技能体系 智能体技能发现→按需加载→工具执行的全流程自动化

💡 一句话理解:Spring AI 是"标准",Spring AI Alibaba 是"阿里增强版"。如果你用阿里云百炼的模型,Spring AI Alibaba 是最佳选择。

5.5 快速上手:5分钟跑通一个 AI 对话

Step 1:创建 Spring Boot 项目(JDK 17+,Spring Boot 3.x)

<!-- pom.xml -->
<dependencies>
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter</artifactId>
    </dependency>
</dependencies>

<repositories>
    <repository>
        <id>spring-milestones</id>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>
# application.yml
spring:
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}   # 从阿里云百炼获取
      chat:
        options:
          model: qwen3-plus            # 通义千问模型

Step 2:写一个 Controller

@RestController
@RequestMapping("/api/chat")
public class ChatController {

    @Autowired
    private ChatModel chatModel;

    @GetMapping
    public String chat(@RequestParam String message) {
        return chatModel.call(message);
    }

    // 流式输出
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chatStream(@RequestParam String message) {
        return chatModel.stream(message)
            .map(response -> response.getResult().getOutput().getText());
    }
}

Step 3:启动项目,访问接口

curl "http://localhost:8080/api/chat?message=你好,请介绍一下你自己"

🎉 5分钟,零 Python,一个 AI 对话接口就跑起来了。 对于 Java 开发者来说,这就是 Spring AI 最大的价值。

5.6 Spring AI vs LangChain4j:Java 生态怎么选?

对比维度 Spring AI LangChain4j
背景 Spring 官方出品 社区开源
集成风格 Spring Boot Starter 自动配置 手动编码或 Starter
模型支持 OpenAI 兼容接口为主 15+ 模型原生适配
向量数据库 主流都支持 15+ 向量数据库
Agent 编排 Spring AI Alibaba Graph LangGraph4j
生态整合 与 Spring 生态无缝 更独立
适用场景 Spring Boot 项目首选 需要更多模型选择时

🎯 选型建议:如果你已经在用 Spring Boot,直接选 Spring AI + Spring AI Alibaba,学习成本最低、集成最自然。如果你需要更灵活的模型切换或者已经在用 LangChain4j,继续用就好——两者核心能力差距不大。


第6章 RAG:让大模型"读懂"你的私有数据

本章讲什么:RAG(检索增强生成)是目前 AI 应用最主流的架构模式。本章从原理到实战,完整讲清 RAG 的全流程,包括文档处理、分块策略、Embedding、检索、Reranking、生成,以及从传统 RAG 到 Agentic RAG 的进化。

6.1 RAG 解决了什么问题?

回到最初的例子——用户问"我们公司的年假怎么休",大模型不知道你们公司的制度。

RAG 的思路非常直觉:考试时让你开卷答题——先把相关的资料找出来,摆在你面前,再让你根据资料回答。

用户提问

检索相关文档

把文档塞进提示词

大模型基于文档生成回答

对比一下三种方案

方案 优点 缺点
直接问大模型 简单 不知道你的私有数据,会瞎编
微调大模型 模型"记住"了你的数据 成本极高、更新慢、每次改数据都要重新训练
RAG 实时检索、成本低、数据随时更新 检索质量依赖 Embedding 和分块策略

💡 业界共识:对于绝大多数企业场景(客服、知识库、内部问答),RAG 是性价比最高的方案。微调通常只在特定领域(医疗、法律)且数据量极大时才考虑。

6.2 RAG 完整流程详解

一个完整的 RAG 系统分离线在线两个阶段:

渲染错误: Mermaid 渲染失败: Lexical error on line 2. Unrecognized text. ...TB subgraph 离线阶段:知识库构建 A1[原始 ----------------------^
离线阶段:构建知识库

Step 1:文档解析

不同格式的文档需要不同的解析策略。PDF 是最难搞的——PDF 的设计理念关注渲染结果,忽略了文档的逻辑结构信息:

格式 解析难度 说明
HTML / Markdown 结构清晰,标题、段落、列表可直接提取
Word / DOCX ⭐⭐ 有样式信息,但表格和嵌套结构需要特殊处理
PDF ⭐⭐⭐⭐ 表格、图片、多栏排版极难解析,是业界公认的难题

💡 最佳实践:对于 PDF,推荐先用开源工具(如 Apache PDFBox、Unstructured)提取文本,如果效果不好,再考虑用多模态大模型(如 Qwen-VL)做 OCR + 结构化提取。

Step 2:文本分割(Chunking)

这是 RAG 系统中最影响检索质量的环节之一:

分割策略 优点 缺点 适用场景
固定大小 简单快速 可能切断语义 快速验证
递归字符分割 按段落→句子逐级切分 仍可能丢失长距离依赖 推荐默认方案
语义分割 按语义边界切分,效果最好 计算成本高 追求极致效果
按文档结构分割 按章节、段落天然结构切分 需要文档有清晰结构 结构化文档
# 推荐的分割配置
from langchain_text_splitters import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,       # 每段 500 字符
    chunk_overlap=50,     # 重叠 50 字符
    separators=["\n\n", "\n", "。", "!", "?", ";", ",", " "]
)

🎯 经验值:chunk_size 设 300~800、chunk_overlap 设 chunk_size 的 10% 左右,对中文效果通常不错。具体数值需要在你的数据上实验调优。

Step 3 & 4:向量化 + 存储

关键技巧——元数据增强

# 给每个文档块添加元数据,提升检索精度
from langchain_core.documents import Document

chunks = [
    Document(
        page_content="员工入职满一年后,可享受5天带薪年假...",
        metadata={
            "source": "员工手册v3.2",
            "chapter": "假期制度",
            "keywords": "年假, 入职, 工龄",
            "hypothesis_question": "入职多久可以休年假?年假天数怎么算?"  # 假设问题,大幅提升检索率
        }
    )
]

💡 假设问题(HyDE)技巧:为每个文档块生成一个"假设用户可能会问的问题",存入元数据。检索时用用户问题和假设问题做匹配,检索率能提升 15~30%。

在线阶段:检索与生成

Step 5:混合检索

纯向量检索有个问题——它擅长语义匹配,但可能遗漏精确的关键词。混合检索 = 向量检索 + 关键词检索,兼顾语义和精确匹配:

用户问题

向量检索
语义匹配

关键词检索
BM25/ES

结果融合
RRF算法

重排序
Reranker

💡 业界最佳实践:混合检索是目前 RAG 系统的标准配置。推荐向量检索权重 60~70%、关键词检索权重 30~40%。

Step 6:Reranking(重排序)

检索回来的文档可能相关性参差不齐。Reranker 模型会对检索结果做二次排序,把最相关的排到前面:

Reranker 模型 特点
bge-reranker-v2-m3 智源开源,中文效果顶级
monoT5 性能与效率平衡的综合选择
Cohere Rerank API 调用,效果稳定

Step 7:生成回答

把检索到的文档和用户问题拼进提示词,交给大模型生成回答:

system_prompt = """你是公司的智能客服助手。请根据以下参考资料回答用户的问题。

要求:
1. 只基于参考资料回答,不要编造信息
2. 如果参考资料中没有相关内容,请明确告知用户
3. 引用来源时标注文档名称

参考资料:
{context}
"""

# {context} 就是检索回来的文档内容

6.3 Spring AI 中的 RAG 实现

在 Spring AI 中,RAG 的实现非常简洁:

@Service
public class RagService {

    @Autowired
    private ChatModel chatModel;

    @Autowired
    private VectorStore vectorStore;

    public String ask(String question) {
        // 1. 从向量数据库检索相关文档
        List<Document> docs = vectorStore.similaritySearch(
            SearchRequest.builder()
                .query(question)
                .topK(5)
                .similarityThreshold(0.7)
                .build()
        );

        // 2. 拼接上下文
        String context = docs.stream()
            .map(Document::getContent)
            .collect(Collectors.joining("\n\n"));

        // 3. 构造提示词并调用模型
        String prompt = String.format("""
            请根据以下参考资料回答问题。
            参考资料:%s
            问题:%s
            """, context, question);

        return chatModel.call(prompt);
    }
}

💡 更优雅的方式:Spring AI 提供了 QuestionAnswerAdvisor,一行代码实现 RAG:

ChatResponse response = ChatClient.builder(chatModel)
 .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))
 .build()
 .prompt(question)
 .call()
 .chatResponse();

6.4 从传统 RAG 到 Agentic RAG

传统 RAG 的流程是固定的:检索一次→拼接→生成。但真实场景中,用户的问题往往很复杂,一次检索可能不够。

Agentic RAG 的核心思想是:让 Agent 自己决定什么时候检索、检索什么、检索够不够、需不需要再检索

对比维度 传统 RAG Agentic RAG
检索方式 单步固定检索 多步动态检索
推理能力 无推理,仅拼接上下文 支持链式推理和逻辑演绎
自我修正 可验证回答准确性并修正
工具调用 可调用搜索引擎、数据库等外部工具
复杂问题处理 优秀

Agentic RAG 的典型架构

不准确

准确

用户问题

规划器
分解为子任务

检索器
执行检索

推理器
整合信息生成回答

验证器
回答是否准确?

输出最终回答

💡 举个例子:用户问"我们公司2025年和2026年的营收增长率变化趋势是什么?"

  • 传统 RAG:检索一次,可能只拿到其中一年的数据,甚至答不上来
  • Agentic RAG
    1. 规划器把问题拆为"2025年营收"和"2026年营收"两个子任务
    2. 分别检索两年的数据
    3. 推理器计算增长率
    4. 验证器检查数据是否完整
    5. 发现2026年数据不够,自动补充检索
    6. 最终给出准确的趋势分析

6.5 RAG 的常见坑与优化建议

表现 优化方案
分块太粗糙 检索到不相关内容 调整 chunk_size,加 overlap,用语义分割
Embedding 模型不对 中文检索效果差 换 BGE-M3 或 GTE-Qwen2
只做向量检索 漏掉精确匹配 改为混合检索(向量 + BM25)
不做 Reranking 相关文档排在后面 加 Reranker 二次排序
提示词没约束 大模型编造信息 加"只基于参考资料回答"的约束
不处理 PDF 表格 表格信息丢失 用多模态模型做 OCR 提取

第7章 实战串联:用 Spring AI Alibaba 构建一个知识库问答系统

本章讲什么:把前面学的所有知识串起来,从零搭建一个完整的知识库问答系统——包含文档上传、向量存储、混合检索、RAG 问答,以及 Agent 工具调用。这是一个真正能跑的生产级 Demo。

7.1 项目架构

基础设施

Spring Boot 后端

前端

聊天界面
支持上传文档

REST API

RAG 问答服务

VectorStore
Milvus

ChatModel
Qwen3-Plus

文档上传服务

文档解析

文本分割

EmbeddingModel
text-embedding-v3

Agent 服务
工具调用

Function Calling
查库/发通知

Milvus
向量数据库

阿里百炼
模型服务

7.2 核心代码实现

配置文件

# application.yml
spring:
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}
      chat:
        options:
          model: qwen3-plus
      embedding:
        options:
          model: text-embedding-v3
    vectorstore:
      milvus:
        client:
          host: localhost
          port: 19530
        collection-name: knowledge_base
        dimension: 1024

文档上传与向量化

@Service
public class DocumentService {

    @Autowired
    private VectorStore vectorStore;

    @Autowired
    private DocumentReader documentReader;

    @Autowired
    private TokenTextSplitter textSplitter;

    /**
     * 上传文档并构建向量索引
     */
    public void uploadAndIndex(MultipartFile file) {
        // 1. 解析文档
        List<Document> documents = documentReader.read(file);

        // 2. 文本分割
        List<Document> chunks = textSplitter.split(documents);

        // 3. 向量化并存入 Milvus(Spring AI 自动完成 Embedding)
        vectorStore.add(chunks);
    }
}

RAG 问答服务

@Service
public class KnowledgeQAService {

    private final ChatClient chatClient;

    public KnowledgeQAService(ChatModel chatModel, VectorStore vectorStore) {
        this.chatClient = ChatClient.builder(chatModel)
            .defaultSystem("""
                你是星辰科技的智能客服。请基于提供的参考资料回答用户问题。
                如果参考资料中没有相关信息,请明确说"根据现有资料无法回答",
                不要编造任何内容。
                """)
            .defaultAdvisors(
                new QuestionAnswerAdvisor(vectorStore, SearchRequest.builder()
                    .topK(5)
                    .similarityThreshold(0.7)
                    .build())
            )
            .build();
    }

    public String ask(String question) {
        return chatClient.prompt()
            .user(question)
            .call()
            .content();
    }

    // 流式输出
    public Flux<String> askStream(String question) {
        return chatClient.prompt()
            .user(question)
            .stream()
            .content();
    }
}

Agent 工具调用

@Configuration
public class ToolConfig {

    @Bean
    @Description("根据员工姓名查询其部门、职位和联系方式")
    public Function<EmployeeQuery, EmployeeInfo> queryEmployee() {
        return query -> employeeMapper.findByName(query.name());
    }

    @Bean
    @Description("查询指定部门的设备资产清单")
    public Function<DeviceQuery, List<DeviceInfo>> queryDevices() {
        return query -> deviceMapper.findByDepartment(query.department());
    }

    public record EmployeeQuery(String name) {}
    public record EmployeeInfo(String name, String department, String position, String phone) {}
    public record DeviceQuery(String department) {}
    public record DeviceInfo(String name, String type, String status) {}
}

7.3 效果演示

假设用户上传了公司的员工手册和IT运维规范,然后进行以下对话:

用户提问 系统行为 回答
“入职满2年能休多少天假?” 向量检索→找到年假制度文档→生成回答 “根据员工手册,入职满2年可享受6天带薪年假(基础5天+1年工龄1天)”
“帮我查一下张三的部门” Agent 调用 queryEmployee 工具→查数据库 “张三属于技术架构部,职位是高级工程师”
“生产服务器能直接操作吗?” 向量检索→找到运维规范文档→生成回答 “根据IT运维规范,禁止直接操作生产环境,所有变更必须经过Code Review和测试环境验证”

7.4 生产环境的补充考虑

从 Demo 到生产,你还需要考虑:

维度 说明
安全 指令注入防护:意图层拦截 + 数据库只读权限 + 调用次数熔断
监控 接入 LangSmith 或 Spring AI Alibaba Admin,追踪每次检索和生成的质量
性能 Milvus 集群部署、Embedding 结果缓存、高频查询预热
数据更新 文档变更时自动重新索引,避免过期数据干扰回答
多租户 向量数据库按租户分 Collection,避免数据混查
权限控制 不同角色的用户只能检索有权限的文档

第8章 展望与学习路径

本章讲什么:总结全文技术体系,给出从入门到进阶的学习路径建议,并展望 AI 应用开发的未来方向。

8.1 技术体系全景回顾

AI 应用开发

存储

向量数据库

Milvus

Chroma

Weaviate

Embedding 模型

BGE-M3

text-embedding-v3

编排

LangChain

Models / Prompts / Memory

Chains / Agents / Retriever

LangGraph

StateGraph

条件分支 / 循环

LangGraph4j

框架

Spring AI

ChatModel / VectorStore

Function Calling

Spring AI Alibaba

Agent Framework

Graph 编排

Studio / Admin

增强

RAG

文档解析 / 分块

混合检索 / Reranking

Agentic RAG

多步动态检索

自我验证与修正

安全

意图层拦截

权限最小化

物理熔断器

8.2 推荐学习路径

阶段 目标 建议内容
第1周:入门 跑通第一个 AI 对话 Spring AI + 百炼,5分钟搭建 Chat 接口
第2周:向量检索 理解 Embedding 和向量数据库 用 Chroma 做语义搜索实验,感受向量检索的效果
第3~4周:RAG 实战 构建一个知识库问答系统 文档解析→分块→Embedding→检索→生成,完整走一遍
第5~6周:Agent 与编排 让 AI “能动手干活” Function Calling → LangGraph 条件分支工作流
第7~8周:生产化 从 Demo 到生产 安全防护、监控追踪、性能优化、多租户

8.3 未来方向

AI 应用开发正在快速演进,几个值得关注的趋势:

  • MCP(Model Context Protocol):Google 推出的 Agent 对工具的标准化协议,让工具注册、发现、调用变得更规范。未来 Agent 接工具就像微服务注册到注册中心一样自然
  • A2A(Agent-to-Agent):Google 提出的 Agent 间通信协议,让不同框架、不同团队的 Agent 能互操作。MCP 是 Agent 对工具,A2A 是 Agent 对 Agent
  • Agentic RAG:从"查了再答"到"自主规划、多步推理、自我修正",正在成为 RAG 系统的新标准
  • GraphRAG:微软开源的图检索增强技术,用知识图谱做关联推理,在需要跨文档推理的场景比传统 RAG 更强
  • 多模态 RAG:不仅检索文本,还能检索图片、表格、音视频,让知识库的覆盖面大幅扩展

📌 最后的话:AI 应用开发并不神秘——本质上就是"让大模型能用你的数据、能调你的工具、能按你的流程做事"。向量数据库给它记忆,LangChain/Spring AI 给它骨架,RAG 给它知识,LangGraph 给它逻辑。把这些拼起来,就是一个能真正干活的 AI 应用。

技术在飞速迭代,但核心理念不变。掌握了这套体系,不管框架怎么换,你都能快速上手。

祝你在 AI 应用开发的路上一路顺风 🚀

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐