Function Calling

什么是 Function Calling

传统聊天大模型只会说话,没有工具调用能力,这使得大模型:

  1. 无法感知环境:无法与外部数据源交互,如通过 API 查询网页、查看用户本地文件、访问远程数据库等等
  2. 无法改变环境:无法帮用户实际执行任务,如跑代码、发邮件、上传作业等

因此,Function Calling 是给大模型提供调用工具的能力

Function Calling 是怎么做的

基于提示词的 Function Calling

image-20260414221119358

  1. 输出格式不稳定:如调用指令中存在多余自然语言。
  2. 容易出现幻觉:模型可能编造并不存在的函数名或参数。
  3. 对开发者依赖度高:函数描述、调用指令格式、提示词逻辑完全由开发者设计。
  4. 上下文冗长,Token 消耗大:为确保调用逻辑正确,往往需要在 system prompt 中加入大量说明与规则。

基于 API 的Function Calling

image-20260414221754896

流程:

  1. 用户发起提问
  2. 后端第一次向大模型 API 发起请求,获取函数调用指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
"messages": [
{
"role": "system",
"content": "你是一个助手,可以根据用户的请求调用工具来获取信息。"
},
{
"role": "user",
"content": "广州今天天气如何?适合出门吗?"
}
],
"functions": [
{
"name": "getWeather",
"description": "获取指定城市的天气",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,比如北京"
},
"date": {
"type": "string",
"description": "日期,比如 2025-08-07"
}
},
"required": ["location", "date"]
}
}
]
}

  1. 模型生成调用指令
1
2
3
4
5
6
7
8
9
{
"function_call": {
"name": "getWeather",
"arguments": {
"location": "Guangzhou",
"date": "2025-07-17"
}
}
}
  1. 后端解析调用指令,并执行实际的函数调用

  2. 后端第二次向大模型 API 发起请求,将刚才的调用结果和其他上下文信息一起传给模型,生成最终的回复

存在的问题:

  1. 后端应用适配不同大模型时存在大量冗余开发
  2. 可选模型有限

MCP

为什么会有MCP

  1. 工具接入的冗余开发问题
    1. AI 应用接入他人开发的新工具需完整 copy 代码和函数描述,接入几个就要 copy 几次。
  2. 工具复用困难
    1. 环境问题导致 copy 的代码不一定能跑;很多企业不提供可供 copy 的源码;跨语言的代码 copy 了没用。

什么是MCP

MCP 是一个开放协议,用于标准化应用程序向大语言模型(LLM)提供上下文的方式。

image-20260415204103242

  • MCP Host:协调和管理一个或多个 MCP Server 的人工智能应用程序
  • MCP Client:一个组件,用于维护与 MCP 服务器的连接,并从 MCP 服务器获取上下文,供 MCP 主机使用
  • MCP Server:一个为 MCP Client 提供上下文的程序

MCP 数据层标准化

采用 JSON-RPC 协议进行数据通讯

初始化阶段:建立连接与能力协商

当 MCP Host(智能体应用)启动时,MCP Client 会向 MCP Server 发起 JSON-RPC 请求,进行初始化。

  • 能力协商:客户端和服务端会确认协议版本、功能支持等信息。
  • 准备就绪通知:初始化完成后,客户端会发送 notifications/initialized 告知服务器自己已准备好。
  • 意义:这一阶段保证双方在同一协议下通信,建立通信基础,为后续工具发现和调用做好准备。

请求示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {
"listChanged": true
},
"sampling": {},
"elicitation": {}
},
"clientInfo": {
"name": "ExampleClient",
"title": "Example Client Display Name",
"version": "1.0.0"
}
}
}

初始化成功后,客户端必须发送initialized通知,表明其已准备好开始正常运行

如果没有这步,服务端会认为客户端并未准备好,所以将禁止后续的其他操作。

1
2
3
4
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}

工具发现阶段:获取工具说明书

初始化完成后,客户端需要知道服务器上“有哪些工具”可以使用。

  • 标准化描述:每个工具都以 JSON 格式描述方法名、参数类型、返回格式和使用说明。
  • 无需理解内部逻辑:智能体只需知道工具能做什么、需要哪些参数、返回什么结果,无需关心内部实现。
  • 动态发现:工具可能随时变化,每次获取的都是最新工具列表。

MCP Server 对外暴露三类核心能力:

  • Resources(资源):可供客户端直接读取的外部数据,如文件内容、API 返回结果等。
  • Tools(工具):具体执行的工具服务。(核心能力)
  • Prompts(提示):预定义的提示词模板。

示例请求:

1
2
3
4
5
6
{
"jsonrpc": "2.0",
"method": "tools/list",
"params": {},
"id": 100
}

响应返回所有工具的说明信息。智能体在拿到这些说明后,就可以利用大模型构建调用策略和决策逻辑。

调用阶段:执行具体工具

当智能体通过大模型决策需要调用某个工具(如 get_weather)时,通过 MCP Client 构建标准 JSON-RPC 请求发送给 MCP Server:

1
2
3
4
5
6
7
8
9
10
11
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"city": "Beijing"
}
},
"id": 101
}

服务器收到请求后:

  • 解析工具名和参数:根据 name 找到对应工具执行。
  • 执行工具:独立运行工具逻辑,无需 Host 参与内部过程。
  • 返回结果:按照 JSON-RPC 的 result 或 error 返回数据。

智能体接收到返回值后,可以直接处理输出、组合多个工具结果,或者继续做下一步决策。整个流程完全无需针对每个工具写不同的适配逻辑。

工具变更阶段:处理工具列表更新

在运行过程中,服务器上的工具可能会发生变更(新增、下线或修改)。MCP 支持客户端实时获知变更:

  • 变更通知:服务端通过 notifications/tools/list_changed 通知客户端工具列表已更新。
  • 重新获取列表:客户端收到通知后会重新请求 tools/list,更新内部工具注册表。
  • 保证一致性:智能体始终知道最新的可用工具,实现动态适应和高可扩展性。
1
2
3
4
5
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed",
"params": {}
}

MCP 传输层标准化

方案对比

Stdio 本地直连

父子进程 Stdio 传输不涉及任何网络协议(TCP/HTTP)。它的本质是进程间通信。当 MCP Host(如 Cursor)启动一个 MCP Server 时,它实际上是在操作系统中 fork 了一个子进程

  • **下行通道 (Host -> Server)**:Host 将 JSON-RPC 请求序列化为字符串,写入子进程的 stdin(标准输入流)
  • **上行通道 (Server -> Host)**:Server 处理完后,将结果写入自己的 stdout(标准输出流),Host 监听这个流来获取响应
  • 错误通道:日志信息通常写入 stderr,这样不会干扰正常的 JSON 数据流。

SSE 远程连接

当工具部署在远程服务器时,我们必须使用 HTTP。但在 HTTP/1.1 时代,服务器无法主动发消息给客户端。SSE 是为了解决服务端主动推送消息给客户端而引入的方案。

双工分离 SSE 只能推,不能收。因此 MCP 必须建立两条独立的通道来模拟双向通信:

  1. 接受通道 (Events Channel)

    • Client 发起一个 GET /sse 请求
    • Server 保持连接不关闭 (Keep-Alive),并设置 Content-Type: text/event-stream
    • 一旦有消息(如工具执行结果、日志),Server 就通过这个长连接推送给 Client
  2. 发送通道 (Post Channel)

    • 当 Client 需要调用工具时,它无法通过 SSE 连接发送
    • Client 必须向 Server 的另一个端点(如 /messages)发起一个新的的 HTTP POST 请求

架构痛点:

  1. 状态维护:Client 必须同时维护一个长连接(听)和一个短连接客户端(说)
  2. 重连机制:无法自动断点重连,需要双方自己实现定时心跳检测来维护长连接

Streamable HTTP 远程连接

Streamable HTTP 的出现,就是为了解决 SSE 模式中读写分离带来的架构复杂度和传统 HTTP的一次性交互无法满足 MCP 双向异步通知、以及无法断点重连 等问题

Streamable HTTP 的核心是统一流式化。它将所有交互都汇集到一个标准的 HTTP POST 请求中,并利用 HTTP 的流式能力来承载 MCP 的 JSON-RPC 协议

  • 单一连接:Client 只需要连接一个统一的端点(/mcp),无需维护两个分离的通道
  • 请求发送:Client 将 JSON-RPC 报文(如 tools/call)放在 POST 请求的 Body 中发送给 Server
  • 流式响应:Server 接收请求后,并不会立即关闭连接。它会利用 HTTP 协议的 分块传输编码 (Chunked Encoding) ,将响应(包括结果、日志、通知)分批次、实时地写入 POST 响应的 Body

核心优势:

  • 简化架构:只需要一个 HTTP 端点,不再读写分离即可实现双向异步通信。

  • 灵活性强:可以根据场景选择是否使用流式 SSE 响应,不必每次都保持长连接,支持无状态模式。

  • 资源效率更高:不用一直维持 SSE 长连接时,节省资源;需要流时也能按需开启。

  • 更可靠的恢复机制:支持断点重连,可恢复会话(通过 Session ID + Last‑Event-ID),通信更稳定。

  • 基础设施更友好:与标准 HTTP 基础设施(API 网关、负载均衡、云服务)兼容性更好。

  • 向后兼容:既可以支持新的 Streamable HTTP,也可以保留旧 SSE 通道,方便平滑升级。

Function Calling 和 MCP 的区别是什么?

Function Calling 指的是给大模型提供调用工具的能力

MCP 则是 MCP Client 和 MCP Sever 之间通信的一种协议

二者之间是互补的

RAG

什么是 RAG

RAG(Retrieval-Augmented Generation,检索增强生成)是一种让大模型在生成回答前,先从外部知识库中检索相关信息,然后结合这些检索到的内容来生成答案的技术。主要就是为了解决大模型的幻觉问题,提升大模型在某些专业领域回答的准确性。

RAG流程

RAG之索引构建

原始文档 → 文档预处理 → 文档分片 → 向量化 → 构建向量索引

文档预处理

流程:

  1. 加载不同类型的文档吗,转换为统一格式的 document
  2. 去除文档内的无效内容,比如多余的空格、换行符、无意义的特殊符号、重复的内容
  3. 规范化文本格式,例如统一编码格式、统一大小写等

目的:让后续的“分片”和“向量化”能够在干净的数据上进行,从源头上保证知识库索引的质量

文档分片

为什么分片?

  • LLM 有 token 长度限制,不能直接读长文档
  • 检索只需要相关片段,不需要整篇文章

常见分片方式

  • 固定大小分片
    • 原理:按固定字符数切分,无视结构与语义
    • 优点:最简单、速度最快
    • 缺点:无视段落、极易切断语义
    • 适用:快速测试、结构极简单的文本
  • 递归分片(按标点 / 段落分层切分)
    • 原理:按分隔符优先级递归切分(段落→换行→句子→标点→空格)
    • 逻辑:先按大结构切,超长度再用小符号继续切
    • 优点:尊重文档结构、效果均衡、平台默认方案
    • 适用:绝大多数常规文档(MD、TXT、DOCX)
  • 基于文档结构分块
    • 原理:按文档原生层级切分(标题、段落、表格、代码块)
    • 优点:对 Markdown、代码、PDF、带格式文档极友好
    • 适用:结构化强、带格式的复杂文档
  • 语义分片(按语义边界切分)
    • 原理:用 NLP 模型识别语义边界(主题切换、逻辑段落)
    • 优点:块内语义最完整、检索相关性高
    • 缺点:计算稍慢
    • 适用:对精度要求高的场景、长文本、散文 / 报告类
  • 智能分片
    • 原理:直接让大模型理解内容后按主题切分
    • 优点:最智能、块质量最高
    • 缺点:耗时、成本高
    • 适用:超高精度需求、重要知识库

分片过长 / 过短的问题:

太长:信息混杂、相关性被稀释、浪费上下文

太短:语义断裂、信息不完整、容易产生幻觉

向量化

目的: 把文本片段变成高维数值向量,让机器能理解语义

核心逻辑

  • 语义相似 → 向量距离近 / 方向接近
  • 语义无关 → 向量距离远 / 方向差异大

Embedding:用一个向量模型把文本“投影”到高维向量空间,每个维度代表了文本在某个“语义方向”上的权重

相似度计算(检索对比):

  1. 余弦相似度(RAG 最常用)

    • 只看方向,不看长度

    • 越接近 1 越相似

    • 适合文本语义匹配

  2. 欧几里得距离

    • 看两点直线距离

    • 距离越小越相似

    • 多用于图像等几何场景

  3. 点积

    • 计算向量重叠程度

    • 简单高效

    • Transformer 注意力机制使

生成索引

通过向量数据库,构建索引结构,将文本内容和高维语义持久化存储,并为后续的检索生成提供相似度查询

Pgvector存储

高维向量embedding(用于检索匹配):也就是表达语义信息,用于索引的相似度匹配查询。

原始文本块text(用于LLM 生成答案):我们检索出来,让大模型引用参考的其实就是一些列的原始文本块,高维向量的只是一个用于相似度查询的索引,模型只有基于原始文本块才可以去进行回答效果的增强。

元数据metadata(用于过滤):则让我们在检索时能做精确的过滤、分组或追溯来源。文件名过滤、时间戳过滤,可以使得在某些场景下,我们的检索更加精准

RAG之检索生成

用户提问 → 内容召回 → 上下文融合 → 内容生成

内容召回

目的:如何从知识库中找到与用户问题最相关的文本块

  1. 向量相似度检索

    • 把用户的问题向量化,得到向量语义表示

    • 在向量库用余弦相似度 / 点积找最相似的 Top-K 块

    • 优点:语义匹配、查得广

    • 缺点:对专业词、缩写不够精准

  2. 混合检索

    • 关键词检索 + 向量检索 结合
    • BM25/ES:做精确关键词匹配,保证查得准
    • 向量检索:做语义匹配,保证查得全
    • “查得广”与“查得准”之间取得平衡,让系统既能理解语义,又能保证检索的准确性与可靠性
  3. 重排序

    • 对召回结果做二次精排
    • 先用粗检索快速召回 → 再用重排序模型(Cross-Encoder、专用 Reranker)精细打分
    • 作用:去噪声、提精度、减少上下文浪费
    • 定位:粗召回 → 精筛选

上下文融合

目的:通过检索结果 + 用户问题按模板拼成最终提示词

通过Prompt(提示词)工程实现,例子如下:

1
2
3
4
5
6
根据以下信息回答问题:

[检索结果1] …
[检索结果2] …

问题:2024年诺贝尔物理学奖得主是谁?

向量数据库

  1. PGvector

    • 身份:PostgreSQL 插件

    • 优点:不用新数据库、SQL + 向量混合查询、运维简单

    • 适合:中小企业知识库、百万级数据

    • 不适合:超亿级大规模数据

  2. Chroma

    • 身份:轻量级嵌入式向量库

    • 优点:开箱即用、几行代码跑起来、内存运行

    • 适合:学习、原型、小项目、个人测试

    • 不适合:高并发、大规模生产

  3. Milvus

    • 身份:云原生分布式专业向量库

    • 优点:亿级数据、高性能、多索引、混合检索强

    • 适合:大型生产系统、高并发、海量向量

    • 缺点:部署复杂、运维要求高

  4. Qdrant

    • 身份:高性能 Rust 实现向量库

    • 优点:速度快、元数据过滤强、部署简单

    • 适合:中小到中等规模、追求性能易用平衡

    • 缺点:分布式能力略弱于 Milvus

  5. Elasticsearch(ES)

    • 身份:全文检索引擎 + 向量能力

    • 优点:关键词 + 语义混合检索强、企业普遍已有

    • 适合:已有 ES 集群、快速做混合检索

    • 缺点:非原生向量库,纯检索性能一般

RAG优化之父子分片

子块负责精准检索,父块负责完整生成;父子搭配,RAG 效果翻倍

什么是父子分片

把文档分成父块 + 子块,分工协作:

  • 父块(大):保留完整上下文,存普通数据库(不做向量检索)
  • 子块(小):切细做向量嵌入,专门用于精准检索

为什么需要父子分片

小块问题:检索准,但上下文太短、生成容易信息不全

大块问题:生成完整,但检索会 “信号稀释”、精度下降

Embedding 长度限制:太长的块无法向量化

表格 / 图片不可切割:普通分片会破坏结构

父子分片通过将大块文本作为父块保留上下文,将其切分为多个子块用于检索,从而兼顾两者优势

核心流程

分片阶段

  1. 先切出完整父块(按标题 / 段落)
  2. 再把父块拆成多个小子块
  3. 子块向量化 → 存入向量库
  4. 父块存原文 → 存入普通数据库
  5. 子块记录:parentChunkId(关联父块)

检索阶段

  1. 用户提问 → 匹配子块(检索准)
  2. 通过子块找到对应的父块 ID
  3. 取出完整父块内容
  4. 把父块送给 LLM 生成答案

RAG优化之元数据过滤

先按元数据精确筛选 → 再对剩余结果做向量相似度检索

什么是元数据

附加在文本块(Chunk)上的描述性结构化信息,相当于每个文本片段的身份证

  • 常见内容:文件名、版本、页码、部门 ID、用户权限、时间、文档类型等
  • 存储位置:和文本内容、向量一起存入向量数据库

使用场景

  1. 精确过滤(最核心)

    • 向量检索是模糊语义匹配,无法做精准限定

    • 元数据可以先按条件精筛,再做相似度检索

    • 典型场景:按版本、按年份、按类型、按文档名筛选

  2. 提供参考源(可信度)

    • 给回答附上来源出处(文档名、页码、章节)

    • 让用户知道答案来自真实文档,降低幻觉、提升可信度

    • 支持追溯、校验、定位原文

  3. 权限控制(企业级必备)

    • 给每个 Chunk 标记:部门 ID、角色、用户 ID、密级

    • 查询时先按权限过滤,只返回用户可访问内容

    • 避免数据泄露,满足企业安全要求

核心优势

  1. 解决向量检索无法精准限定范围的问题

  2. 让 RAG 从 “大概相似” 升级为精准可控

  3. 是企业级 RAG 权限、安全、合规的基础

  4. 大幅提升回答准确性与可靠性

RAG优化之问题改写

为什么需要问题改写

  • 用户问题模糊、缺主语、有歧义
  • 复杂问题直接检索不到
  • 用户表述和文档表述风格不一致
  • 多轮对话中指代不清(他、它、这个)

目标:让问题更清晰、更完整、更易匹配

问题改写方法

都是通过Prompt(提示词)工程新增一次大模型调用实现

  1. 分解(Decomposition)

    • 将用户的复杂、多步骤或包含多个子问题的查询,拆解成若干个相互独立、更简单、更具体的子问题

    • 每个子问题可以独立进行检索,最终将多个检索结果合并,用于回答原问题

    • 例子:iPhone15 发布时 CEO 是谁?→ 拆成:发布时间?当时 CEO 是谁?

    • 适用:多条件、多步骤、对比类问题

  2. 富化(Enrichment)

    • 在原始查询中添加上下文信息、背景知识或必要的限制条件,以消除歧义、补充缺失的信息

    • 例子:“他有什么特点”→“刘备有什么特点”

    • 适用:多轮对话、简称、指代模糊

  3. 多样化(Diversification)

    • 对同一个用户查询生成多个多个语义相近或相关的变体,以提升对知识库内容描述多样性的覆盖,从而增强召回率

    • 扩大匹配覆盖面,解决表述不一致

    • 适用:用户说法和文档说法不一样

  4. 回溯提示(Step-Back)

    • 先引导模型“后退一步”,从具体问题中抽象出更一般的原理、概念或背景知识;再基于这些抽象信息进行推理或检索,最终回答原始问题

    • 例子:企业内部知识库咨询,“我老舅结婚能请几天假”→“探亲假政策是什么”

    • 适用:具体场景问规则、制度、原理

注意事项

重写策略不是越多越好,避免过度重写

追求检索效果 + 响应速度平衡

根据业务场景灵活选择,不要全量堆叠

RAG优化之查询构造

用户问题 → Text2SQL 生成 SQL → 执行数据库查询 → 取回真实数据 → 融入 RAG 上下文 → 生成答案

什么是查询构造

多数据源 RAG 中,用户问题不能只靠向量检索,还需要对接关系型数据库、图数据库等。

查询构造就是:把自然语言 → 转换成数据库可执行的查询语句,最典型就是 Text2SQL。

Text2SQL

Text2SQL(也称为 自然语言到SQL)是一种人工智能技术,其目标是将用户用自然语言(如中文、英文等)表达的查询意图,自动转换为结构化的 SQL 查询语句。这项技术融合了自然语言处理(NLP)和数据库查询技术,旨在降低非技术人员使用数据库的门槛,提升数据访问效率

实现逻辑:

  1. 给大模型提供表结构 + 字段注释
  2. 输入用户自然语言问题
  3. 模型输出合法、可直接执行的 SQL
  4. 执行 SQL 获取真实业务数据
  5. 把数据送给 LLM 生成最终答案

也是通过提示词工程来实现以上步骤

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 角色
你是一个SQL专家。请根据以下表结构信息将用户问题转换为SQL查询语句。特别注意,你只能查询,不能做修改、删除等操作。

# 表结构信息

{tables}

# 用户问题

{user_query}

# 要求
1. 只返回SQL语句,不需要包含任何解释和说明
2. 确保SQL语法正确
3. 使用上下文中提供的表名和字段名
4. 如果根据所提供的表无法做查询,请直接返回空字符串""

# 其他说明
今天是:{today}

RAG优化之问题澄清

用户模糊提问 → 系统识别信息不足 → 主动澄清反问 → 用户补充 → 信息完整 → 执行 RAG 检索生成

什么是问题澄清

当用户问题模糊、缺失信息、有歧义时,系统不直接检索回答,而是主动向用户反问、补充关键信息,确认真实意图后再执行 RAG 流程。

核心特点

  1. 主动交互:不是被动回答,而是主动收集信息

  2. 分阶段执行

    • 先:信息收集 → 澄清补齐

    • 后:检索生成 → 给出答案

  3. 依赖对话记忆:必须记住多轮对话内容

  4. 自然引导:每次只问 1~2 个问题,不生硬审问

RAG优化之HyDE

HyDE = 用 “模型脑补的假答案” 搭桥,让检索更容易匹配到真文档,显著解决词汇不匹配与模糊查询问题。

什么是HyDE

HyDE(Hypothetical Document Embeddings,假设性文档嵌入)是一种高级 RAG 优化技术,核心是:先让模型 “编一个假答案”,再用假答案去检索真文档

为什么需要一个假答案?

  1. 词汇不匹配:用户口语化提问 vs 知识库专业表述,语义相关但字面不匹配。
  2. 问题太短 / 模糊:信息量不足,向量检索难以匹配。
  3. 表述风格不一致:问句句式 vs 陈述文档句式差异大。

核心流程

  1. 生成假设答案:LLM 根据用户问题,直接生成一段完整、详细、像文档一样的回答(不管对错,只要语义和格式接近知识库)。
  2. 假设答案向量化检索:用假设答案的向量去匹配知识库,而不是用原始问题。
  3. 用真实文档生成最终答案:检索到真实文档后,再交给 LLM 生成准确回答。

为什么会有效?

  • 假设答案更长、术语更全、句式更像知识库
  • 与文档的向量相似度更高,检索更准
  • 不依赖用户提问方式,大幅提升召回率

RAG优化之混合检索

混合检索 = 向量(懂语义)+ 关键词(够精确)= 高级 RAG 标配检索方案

什么是混合检索

混合检索(Hybrid Search)= 向量检索 + 关键词检索

把两种检索方式的优势结合,弥补单一检索的缺陷。

为什么需要混合检索

  1. 单一向量检索

    • 优点:懂语义、能理解意图
    • 缺点:关键字敏感度低,对专业词、型号、缩写、编号精确匹配弱
  2. 单一关键词检索(BM25/ES)

    • 优点:精确匹配、对术语 / 代号敏感
    • 缺点:不懂语义,同义词、不同表述查不到

混合检索 = 既懂语义,又能精准命中关键词

混合检索将两者结合,使系统既能深刻理解用户意图(语义优势),又能确保检索结果不偏离核心关键词(关键字优势),从而显著提升 RAG 的召回质量,能解决以下问题

  1. 语义对但关键词错(向量偏了 → 关键词拉回)
  2. 关键词对但语义无关(关键词偏了 → 向量修正)
  3. 专业术语 / 缩写召回难(关键词擅长)
  4. 降低幻觉(更准的上下文 → 更可靠回答)

实现流程

  1. 双路并行召回

    • 一路:向量检索(语义匹配)

    • 二路:关键词检索(BM25/ES,精确匹配)

  2. 结果融合排序

  3. (可选)重排序精排

  4. 送入 LLM 生成

RAG优化之重排序

混合检索召回 → RRF 粗排 / ReRank 精排 → 取 Top-K → 送入 LLM 生成

什么是重排序

向量 / 混合检索初步召回后,用更强的模型或专用算法对候选文本块重新计算相关性、重新排序,把最相关内容放到最前。

定位:粗召回 → 精筛选,是 Advanced RAG 核心环节。

核心作用:

  1. 过滤噪声:剔除不相关、低价值内容
  2. 提升精度:比粗检索更细地判断语义相关性
  3. 优化上下文:只保留最相关的 3–5 条,高效利用 token

重排序方案

  1. RRF 算法(倒数排名融合)

    • 定位:轻量、无模型、多检索结果融合

    • 核心思想:只看排名,不看原始分数

      • 规则
        • 文档在多个结果里越靠前、出现越多,得分越高
        • 得分公式:1/(K+排名) 累加,K 一般取 60
    • 优点

      • 无需原始分数:仅依赖排名,适用于异构系统(如传统 BM25 + 向量检索)
      • 对高排名更敏感:靠前的排名对得分贡献更大(因为是倒数关系)
      • 简单高效:计算开销小,易于实现
      • 实证效果好:在 TREC 等标准评测中表现优异,尤其适合多阶段检索架构
    • 适用:混合检索结果融合

  2. ReRank 模型(专用精排模型)

    • 定位:高精度语义重排序(如 Cross-Encoder、qwen3-rerank)

    • 核心思想:把问题 + 文档一起输入,深度语义匹配打分

      • 特点
        • 比 RRF 更准,但开销更大
        • 更侧重语义,可能弱化纯关键词结果
    • 适用:对答案精度要求高的场景

RAG优化之Graph RAG

Graph RAG = 给 RAG 装上 “逻辑大脑”,从 “语义匹配” 升级为 “知识推理”。

什么是Graph RAG

Graph RAG = 传统 RAG + 知识图谱 + 图数据库

在文本分片、向量检索的基础上,用图结构建模实体与关系,让 RAG 具备推理能力,解决复杂问题。

为什么需要Graph RAG

传统RAG有以下痛点:

  1. 上下文碎片化:段落之间孤立,没有关联
  2. 多跳推理弱:不会链式思考(如 “A 在哪工作?该城市属于哪国?”)
  3. 信息冗余冲突:不同文档可能包含相同事实,导致信息冗余或冲突
  4. 缺乏全局结构:无法利用实体之间的关系进行推理

Graph RAG 的核心思想是:将非结构化文本转化为结构化的图,并在图上进行智能检索与推理

相关概念

  1. 知识图谱(Knowledge Graph)

图结构表示知识:

  • 节点(Node)= 实体(人、地点、电影、机构)
  • 边(Edge)= 关系(导演、出演、位于、属于)
  • 格式:(实体,关系,实体):例如 (吴京, 参演过, 战狼)
  1. 图数据库

专门存储图结构的数据库,代表:Neo4j

支持关系查询、多跳推理、路径查找。

核心流程

  1. 抽取文档中的实体与关系
  2. 存入图数据库,构建知识图谱
  3. 用户提问 → 解析为图查询(多跳推理)
  4. 在图中检索路径与关联信息
  5. 把推理结果送给 LLM 生成答案

Agent

Agent = LLM + Memory + Tools + Planning + Action

什么是Agent

AI Agent(智能体)= 以 LLM 为大脑,能自主理解、规划、执行任务的智能助手。

它不只是 “回答问题”,而是能动手做事

核心组件

LLM(大脑):理解意图、做决策、调用工具。

Memory(记忆):短期记忆 + 长期记忆,记住历史对话与任务进度。

Tools(工具):搜索、代码解释器、日历、数据库、API、浏览器等,扩展能力。

Planning(规划):拆解任务、制定步骤、链式思考(CoT)、子目标分解。

Action(执行):真正动手完成任务,是 Agent 有价值的关键。

两大类型

  1. Workflow Agent(编排型智能体)

    • 预先定义好的流程执行

    • 稳定、可控、可预测

    • 适合生产环境

    • 代表:LangGraph、Dify、N8N、Spring AI

  2. Autonomous Agent(自主型智能体)

    • LLM 自主动态决策,没有固定流程

    • 灵活、能应对未知任务

    • 可能跑偏、可靠性一般

    • 代表:AutoGen

ReAct Agent

ReAct = 让 AI 像人一样:边想、边做、边看、边改,直到把问题解决。

什么是ReAct

ReAct = Reasoning(推理思考) + Acting(执行动作)

让大模型像人一样:

先思考 → 再行动 → 看结果 → 再思考 → 再行动……

循环直到把问题解决。

核心步骤

ReAct 固定执行三段式循环:

  1. Thought(思考):分析问题、理解现状、规划下一步做什么。
  2. Action(行动):调用工具:搜索、查数据、算数值、调接口等。
  3. Observation(观察):看工具返回结果,判断对错、是否需要继续。

不断循环 → 最终给出答案。

img

ReAct的优势

  1. 比普通 Agent 更靠谱

    普通 Agent 只会瞎调用工具,不会反思对错。

    ReAct 会观察结果、修正错误、重新尝试

  2. 比纯推理更能解决真实问题

    能调用外部工具,不只是空想。

  3. 比纯动作更有逻辑

    不会盲目调用,每一步都有思考。

实验证明:

ReAct 在多步推理、工具使用、复杂问答上正确率远高于普通模型。

Plan and Execute Agent

Plan and Execute = 先全局规划、再分步执行,比 ReAct 更快、更稳、更可控

什么是Plan and Execute Agent

Plan and Execute(规划 - 执行)Agent 是一种把任务规划步骤执行彻底分开的智能体架构,用来解决 ReAct 效率低、目光短浅的问题

ReAct有如下缺陷:

  1. 效率低:ReAct 一步一想、串行跑,速度慢
  2. 规划短视:只看下一步,没有全局视角,容易走弯路
  3. 难调试:决策散在对话里,没有清晰任务列表

核心步骤

  1. Planner(规划器):用 LLM 一次性生成完整任务步骤清单
  2. Executor(执行器):按清单一步步执行,调用React Agent完成子任务。
  3. (可选)Replan 重规划:执行失败 / 偏差时,重新生成计划。

和ReAct的对比

维度 Plan-and-Execute Agent ReAct Agent
效率 高:规划一次,批量执行;支持并行 低:每步需 LLM 调用,串行执行
成本 低:主 LLM 仅用于规划 / 总结,子任务可用小模型 高:全程依赖大模型
准确性 高:强制全局思考,减少路径错误 中:易受局部最优影响
可解释性 强:任务计划显式输出,便于审计 弱:决策隐含在对话流中
灵活性 中:初始计划可能僵化,需动态重规划 高:每步可灵活调整
实现复杂度 较高:需设计规划器、执行器、记忆、重规划等模块 简单:基础循环即可实现
适合任务 复杂、多步、需可靠输出的结构化任务 目标明确、步骤少、动态性强的任务

Reflection Agent

Reflection Agent = 会自我批判、自我优化的智能体,通过 “生成→反思→修订” 循环,把内容质量提升到更高水平

什么是Reflection Agent

Reflection Agent = 带自我批判、自我修正能力的智能体架构

让 LLM 在生成内容后,先自己 “反思 / 审稿”,发现问题并迭代优化,直到达到最佳效果。

核心流程

生成初稿 → 反思反馈 → 修订优化 → 循环迭代 → 最终输出

架构优势

  1. 大幅降低幻觉,内容更真实
  2. 逻辑性更强,结构更清晰
  3. 准确性更高,可用于专业场景
  4. 质量更稳定,多轮迭代逼近最优
  5. 可解释性强,知道每一步修改原因

Human in the loop

Human in the Loop = 给 AI 加上 “人工审批锁”,兼顾自动化效率与安全性,是企业级 Agent 必备架构

什么是HITL

Human in the Loop = 人工介入 + AI 自动执行的混合架构。

AI 自动处理常规任务,但高风险、高敏感、高影响操作必须经过人类审查、确认、修正后才能继续执行。

为什么需要HITL?

  • 高风险操作防护:写文件、删数据、执行 SQL、转账、下单、封禁用户等,不能全自动。
  • 合规与审计:金融、医疗、法律、企业运维必须人工确认、可追溯
  • 降低 AI 错误成本:模型不确定时,人工介入显著提升准确率。

核心流程

  1. 配置中断:提前设定哪些工具需要人工审批
  2. 运行中断:Agent 推理 → 触发敏感工具 → 自动暂停
  3. 人工决策:人批准 / 修改 / 拒绝
  4. 恢复执行:Agent 继续完成后续流程

Multi Agent

Multi Agent = 让 AI 像团队一样分工协作,专业的人做专业的事,解决单 Agent 搞不定的复杂任务

什么是Multi Agent

多智能体 = 多个专业单一智能体 + 分工协作 + 统一调度

把复杂任务拆分成多个子任务,交给不同专长的 Agent 分别完成,最后汇总结果。

为什么需要Multi Agent?

  1. 注意力发散:任务越复杂,单 Agent 越容易跑偏
  2. 上下文不足:长流程、多步骤会撑爆上下文
  3. 不够专业:全能 Agent 不如专精 Agent 效果好
  4. 效率低下:串行处理复杂任务太慢
  5. 工具滥用:工具太多容易选错、用错

核心模式

  1. SubAgents 子智能体模式(最常用)

    • 结构:1 个主 Agent + 多个子 Agent

    • 逻辑:主 Agent 做调度,子 Agent 当 “工具” 用

    • 特点:上下文隔离、干净无干扰、易维护

  2. HandOff 交接 / 接管模式

    • 逻辑:Agent 处理到一半,发现不擅长,主动交给更专业的 Agent

    • 控制权转移:A → B → C,接力完成任务

  3. Chat Group 群聊模式

    • 结构:多个专家 Agent + 1 个群主(管理器)

    • 逻辑:共同订阅一个话题,轮流发言、互相协作、群主决定谁下一步

    • 适合:超复杂任务(策划、写作、研发、分析)

  4. 自定义工作流(Workflow)

    • 按业务需求自由编排:串行、并行、条件路由、循环等

多智能体协议A2A

什么是A2A

A2A = Agent to Agent Protocol(智能体对智能体协议)

是 Google 提出的跨应用、跨服务、跨团队的多智能体标准化通信协议,

让不同框架、不同机器、不同公司开发的 Agent 可以互相调用、协作。

为什么需要A2A

  • 同一应用内的多智能体可用内部机制通信
  • 跨应用 / 跨服务 / 跨企业的智能体无法直接互通
  • 需要统一标准:能力发现、任务传递、结果返回、状态同步

A2A = 智能体世界的 “通用语言”

核心作用:

  1. 跨框架互通:LangChain、AutoGen、Spring AI 等互相调用
  2. 跨服务协作:不同应用、不同服务器、不同团队的 Agent 联动
  3. 能力发现:知道远程 Agent 能做什么
  4. 任务传递:标准化发送任务、接收结果
  5. 复杂协作:支持多跳、多智能体流水线

关键组件

  • Agent Card(智能体卡片)描述智能体能做什么、入参出参、权限、版本(像 OpenAPI)
  • Client Agent(客户端智能体)发起请求、发送任务、处理结果
  • Remote Agent(服务端智能体)接收任务、执行、返回结果
  • Task(任务)具体工作单元:ID、类型、输入、上下文
  • Message(消息)封装任务,用于网络传输
  • Artifact(工件)任务产出:文件、代码、图片、报告等

核心流程

  1. 获取能力:Client 读取 Remote 的 Agent Card
  2. 构造任务:按规范生成合法 Task
  3. 发送消息:封装 Message 发送
  4. 执行任务:Remote 验证并执行
  5. 返回结果:生成 Artifact,封装 Message 返回
  6. 处理结果:Client 接收并继续流程

A2A流程

上下文工程

Context / Memory / Prompt / Token

Token

模型处理语言的最小单元(字、词、标点)

一切文本最终都会转为 Token

模型有最大 Token 限制(上下文窗口)

估算:1 Token ≈ 1.7 个中文字符

Prompt

直接发给模型的指令 / 问题

包含:系统提示 + 用户当前问题

作用:引导模型本次该做什么

Context

模型当前能看到的所有信息总和

包括:Prompt(系统 + 用户)、历史对话、RAG 检索内容、工具调用结果、Agent 的 Thought/Action/Observation

受最大上下文长度限制

Memory

人为实现的存储能力,模型本身没有记忆

短期记忆 = 对话上下文(Context)

长期记忆 = 存在数据库 / 向量库里的历史信息(用户偏好、对话记录等)

上下文过长的影响

上下文不是越长越好,太长会导致:中间信息丢失、中毒、分散、混乱、冲突,让模型效果急剧下降

Lost in the Middle(中间迷失)

模型只重视上下文的开头和结尾严重忽略中间内容,信息越长,中间内容越等于 “白给”。

即使模型支持 32K/128K 上下文,有效信息利用率并不会线性提升

典型故障

  1. 上下文中毒(Context Poisoning)
  • 现象:错误信息进入上下文,模型信以为真,错误被不断放大
  • 典型例子:上下文写 “爱因斯坦发明了电话”,模型回答 “爱因斯坦发明电话”
  • 解决方案:使用高质量知识库;检索前做事实校验;搭配 Reflection 反思机制
  1. 上下文分散(Context Distraction)
  • 现象:信息过多过杂,模型注意力涣散,答非所问
  • 典型例子:让模型总结文章,却塞入大量无关闲聊,模型跑偏聊八卦
  • 解决方案:精简上下文;用重排序只保留高相关内容;核心指令放在开头和结尾
  1. 上下文混乱(Context Confusion)
  • 现象:工具 / 选项过多,模型选择困难,频繁选错工具
  • 典型例子:任务只需打开文件,却提供几十种工具,模型无法正确决策
  • 解决方案:动态筛选工具;仅提供当前必需工具;采用子 Agent 专业化分工
  1. 上下文冲突(Context Clash)
  • 现象:上下文出现矛盾信息,模型逻辑崩溃,输出前后不一
  • 典型例子:先后说 “我在东京”“我在北京”,模型无法判断、混乱作答
  • 解决方案:清理冲突记忆;新信息覆盖旧信息;长对话做摘要压缩;分离长短时记

上下文工程

上下文工程 = 控制模型 “看什么、看多少、怎么看”,

通过写入、选择、压缩、隔离,实现最优输入,大幅提升效果与稳定性。

什么是上下文工程

上下文工程是对模型输入信息进行全生命周期优化的技术,目的是让模型只看到最精准、最必要的内容,解决上下文过长、混乱、冲突、中毒等问题。

  • 提示词工程:研究怎么跟模型说话
  • 上下文工程:研究让模型看什么内容

核心步骤

  • Write(写入):将对话历史、中间结果、任务计划等重要信息存入上下文窗口之外的外部存储,分为Scratchpad 草稿板(临时工作记忆,用于记录 Agent 执行过程信息)与Long-Term Memory 长期记忆(持久化保存用户偏好、历史任务、专业知识等内容)。
  • Select(选择):从长期记忆、向量库或工具库中精准提取与当前任务最相关的信息,动态加载匹配的工具,获取必要规则与约束,只把最有用的内容注入当前上下文。
  • Compress(压缩):通过摘要总结合并冗余信息、裁剪清理过期对话、智能剪枝删除无关内容,在不丢失关键信息的前提下减少 Token 占用,缓解上下文过长问题。
  • Isolate(隔离):对上下文进行拆分与隔离,通过多智能体分工实现独立上下文环境,使用沙盒执行高风险或大体积内容,通过结构化状态管理控制模型可见信息,避免信息混乱、冲突与干扰。