OpenClaw
Openclaw本质是一个开源的多渠道AI网关 ,不做推理,只做调度和执行。Openclaw的两大核心点是:架构 和 运行时机制(Agentic Loop + 工具生态) 。
架构上
-
Gateway(网关层):不仅是消息的入口,也是常驻基础设施 。 它以守护进程方式7x24小时运行,负责处理以下核心事件:
- 多平台接入 ,统一翻译各渠道消息格式为内部MsgContext
- 会话隔离 ,为每个用户/群/Agent维护独立的Session Key
- 排队控制 ,并发消息的去重、限流、队列调度
- 心跳检测 ,Heartbeat周期性唤醒Agent主动做任务
- Cron定时调度 ,支持cron表达式的精确定时任务系统
- 记忆刷盘 ,在上下文压缩之前把关键信息持久化到磁盘
-
Agent Runtime:接收Gateway派发的消息,组装上下文、调用LLM、执行工具、返回结果。运行时机制的核心是Agentic Loop(Agent 循环) ,也就是基于ReAct范式的推理循环:
每当用户发送消息,Agent拿到用户消息会进入一个循环:
- Load,组装上下文:加载会话历史、记忆文件、系统提示词
- Call,调用LLM:把上下文和工具列表发送给LLM,让LLM思考
- Parse,解析响应,LLM要么直接回复文字(结束循环),要么返回一个tool_call指令,比如我要搜索网页内容
- Execute,执行工具:如果是tool_call,那就执行对应工具拿到结果
- Append,结果回填:把工具执行结果追加到上下文当中
- Loop,循环:回到第2步,这个循环会一直转,直到LLM认为任务完成、输出最终文本
除了这个循环,OpenClaw还有一个重要的内置点在于丰富的一套工具生态 ,能直接操作OS、读写文件、执行终端命令、浏览网页、调用外部API等。
循环是引擎,工具才是手脚。
RAG
RAG 就是让大模型先查资料再回答,用外部知识弥补模型知识滞后和私有知识缺失的问题。它的主流程通常是:数据准备、用户提问、检索相关内容、组装 Prompt、调用大模型生成答案。
RAG 全称是 Retrieval-Augmented Generation ,中文叫 检索增强生成。它的核心思想是:不要让大模型完全凭"记忆"回答,而是在回答前先从外部知识库、文档库、数据库或搜索系统中检索相关资料,再把这些资料作为上下文交给大模型生成答案。
可以把 RAG 理解成给大模型配了一本"可随时翻阅的参考书"。传统大模型只依赖训练时学到的知识,容易遇到两个问题:一是知识有时效性,训练截止后的新信息它不知道;二是它不了解企业内部文档、业务规则、产品手册等私有数据。RAG 正是为了解决这些问题而出现的。
RAG 的主要流程
RAG 通常分为两个阶段:离线知识库构建阶段 和 在线问答阶段。
1. 数据准备与知识库构建
首先需要收集外部知识,比如企业文档、产品说明、FAQ、数据库记录、网页内容、技术文档等。
这些原始数据通常不能直接丢给大模型,而要经过清洗和处理。例如去掉无用内容、统一格式、拆分成较小的文本片段,也就是常说的 Chunk。拆分的原因是大模型上下文长度有限,而且检索系统更适合处理较短、语义集中的片段。
接着,会使用 Embedding 模型把每个文本片段转换成向量,也就是把文字变成机器可以计算相似度的数字表示。然后把这些向量和对应的原文片段存入向量数据库中,例如 Milvus、FAISS、Elasticsearch、PGVector 等。
这一阶段的目标是:把外部知识加工成一个可以被快速检索的知识库。
2. 用户提出问题
当用户输入一个问题时,系统不会直接把问题交给大模型回答,而是先分析用户的问题,并将问题也转换成向量表示。
例如用户问:"RAG 的主要流程是什么?"系统会把这个问题向量化,然后拿它去知识库中查找语义最接近的内容片段。
3. 检索相关资料
系统会在向量数据库或搜索引擎中检索与用户问题最相关的文档片段。
常见检索方式包括:
| 检索方式 | 说明 |
|---|---|
| 向量检索 | 根据语义相似度查找相关内容 |
| 关键词检索 | 根据关键词匹配查找内容 |
| 混合检索 | 同时结合语义检索和关键词检索 |
| Rerank 重排序 | 对初步召回的结果再次排序,提高相关性 |
这一阶段的关键是"找得准"。如果检索出来的资料不相关,后面大模型即使表达能力很强,也可能生成错误答案。
4. 组装 Prompt
检索到相关资料后,系统会把这些资料和用户问题一起拼接成一个 Prompt,交给大模型。
一个简化后的 Prompt 可能类似这样:
text
请根据以下参考资料回答用户问题。
参考资料:
1. RAG 是检索增强生成,通过外部知识库辅助大模型回答问题。
2. RAG 的流程包括数据处理、向量化、检索、上下文构建和答案生成。
用户问题:
什么是 RAG?RAG 的主要流程是什么?
这个步骤的重点是让大模型"基于资料回答",而不是自由发挥。好的 RAG 系统通常还会要求模型:如果参考资料中没有答案,就说明不知道,而不是编造。
5. 大模型生成答案
最后,大模型根据用户问题和检索到的上下文生成回答。
与普通问答不同,RAG 生成的答案不是单纯依赖模型参数中的知识,而是结合了外部检索结果。因此它更适合回答企业知识库问答、客服问答、文档助手、法律/金融/医疗资料检索、代码库问答等场景。
一句话概括流程
RAG 的完整链路可以概括为:
text
文档收集 -> 文档清洗 -> 文本切分 -> 向量化 -> 存入知识库 -> 用户提问 -> 检索相关片段 -> 组装上下文 -> 大模型生成答案
也可以更口语化地理解为三个字:找、拼、答。
先从知识库里"找"相关资料,再把资料和问题"拼"成提示词,最后让大模型基于这些资料"答"出结果。
RAG 的价值
RAG 最大的价值在于让大模型具备使用外部知识的能力。它可以降低幻觉,提高答案的可追溯性,也能让大模型接入实时数据和私有数据。
不过,RAG 并不是简单地"把文档塞给大模型"。一个效果好的 RAG 系统,还需要做好文档切分、Embedding 选择、检索策略、Rerank、Prompt 设计、引用来源、权限控制和答案评估等环节。检索质量越高,最终生成答案的可靠性通常也越高。
什么是RAG中的Rerank?
RAG 中的 Rerank 是对初步检索结果进行"二次精排",目的是把真正和用户问题最相关、最有用的文档排到前面,从而提升最终回答质量。
在 RAG 流程里,初步检索通常追求"快"和"召回多",而 Rerank 追求"准"。它会在向量检索、关键词检索或混合检索返回一批候选文档后,再用更精细的相关性模型重新打分排序,筛掉噪声内容,把最适合交给大模型生成答案的文档放到上下文里。
为什么需要 Rerank
RAG 的典型流程是:用户提问 → 检索相关文档 → 把文档拼进 Prompt → 让大模型回答。问题在于,第一阶段检索通常不够精确。
比如向量检索使用的是 Bi-Encoder 架构,它会提前把问题和文档分别编码成向量,然后计算相似度。这种方式速度很快,适合从海量文档中快速召回候选内容,但它对细粒度语义、上下文关系、否定条件、时间条件、复杂约束的判断能力有限。
举个例子,用户问:"RAG 中 Rerank 和向量检索有什么区别?" 初步检索可能召回很多包含 "RAG""向量检索""检索增强" 的文档,但有些文档只是泛泛介绍 RAG,并没有真正回答 Rerank 的作用。此时如果直接把这些文档塞给大模型,模型就可能回答得泛泛而谈,甚至引用不相关内容。
Rerank 就是为了解决这个问题。它会对候选文档逐条判断:"这段内容到底和用户问题有多相关?" 然后重新排序。
Rerank 在 RAG 中的位置
Rerank 通常位于"召回"和"生成"之间:
#mermaid-svg-CjlJRGajJixmelx7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CjlJRGajJixmelx7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CjlJRGajJixmelx7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CjlJRGajJixmelx7 .error-icon{fill:#552222;}#mermaid-svg-CjlJRGajJixmelx7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CjlJRGajJixmelx7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CjlJRGajJixmelx7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CjlJRGajJixmelx7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CjlJRGajJixmelx7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CjlJRGajJixmelx7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CjlJRGajJixmelx7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CjlJRGajJixmelx7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CjlJRGajJixmelx7 .marker.cross{stroke:#333333;}#mermaid-svg-CjlJRGajJixmelx7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CjlJRGajJixmelx7 p{margin:0;}#mermaid-svg-CjlJRGajJixmelx7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CjlJRGajJixmelx7 .cluster-label text{fill:#333;}#mermaid-svg-CjlJRGajJixmelx7 .cluster-label span{color:#333;}#mermaid-svg-CjlJRGajJixmelx7 .cluster-label span p{background-color:transparent;}#mermaid-svg-CjlJRGajJixmelx7 .label text,#mermaid-svg-CjlJRGajJixmelx7 span{fill:#333;color:#333;}#mermaid-svg-CjlJRGajJixmelx7 .node rect,#mermaid-svg-CjlJRGajJixmelx7 .node circle,#mermaid-svg-CjlJRGajJixmelx7 .node ellipse,#mermaid-svg-CjlJRGajJixmelx7 .node polygon,#mermaid-svg-CjlJRGajJixmelx7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CjlJRGajJixmelx7 .rough-node .label text,#mermaid-svg-CjlJRGajJixmelx7 .node .label text,#mermaid-svg-CjlJRGajJixmelx7 .image-shape .label,#mermaid-svg-CjlJRGajJixmelx7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-CjlJRGajJixmelx7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CjlJRGajJixmelx7 .rough-node .label,#mermaid-svg-CjlJRGajJixmelx7 .node .label,#mermaid-svg-CjlJRGajJixmelx7 .image-shape .label,#mermaid-svg-CjlJRGajJixmelx7 .icon-shape .label{text-align:center;}#mermaid-svg-CjlJRGajJixmelx7 .node.clickable{cursor:pointer;}#mermaid-svg-CjlJRGajJixmelx7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CjlJRGajJixmelx7 .arrowheadPath{fill:#333333;}#mermaid-svg-CjlJRGajJixmelx7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CjlJRGajJixmelx7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CjlJRGajJixmelx7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CjlJRGajJixmelx7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CjlJRGajJixmelx7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CjlJRGajJixmelx7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CjlJRGajJixmelx7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CjlJRGajJixmelx7 .cluster text{fill:#333;}#mermaid-svg-CjlJRGajJixmelx7 .cluster span{color:#333;}#mermaid-svg-CjlJRGajJixmelx7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CjlJRGajJixmelx7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CjlJRGajJixmelx7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-CjlJRGajJixmelx7 .icon-shape,#mermaid-svg-CjlJRGajJixmelx7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CjlJRGajJixmelx7 .icon-shape p,#mermaid-svg-CjlJRGajJixmelx7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CjlJRGajJixmelx7 .icon-shape .label rect,#mermaid-svg-CjlJRGajJixmelx7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CjlJRGajJixmelx7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CjlJRGajJixmelx7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CjlJRGajJixmelx7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户问题
查询改写/查询扩展
初步检索
候选文档 Top K
Rerank 二次排序
选择 Top N 文档
构造 Prompt
大模型生成答案
也就是说,Rerank 不负责从全量知识库里找文档,而是负责在已经找出来的一批候选文档中做精细排序。
常见做法是:先通过向量检索、BM25 或混合检索召回 Top 50、Top 100 个候选片段,然后通过 Rerank 模型重新排序,最后只取 Top 3、Top 5 或 Top 10 个最相关的片段交给大模型。
Rerank 常见实现方式
1. 使用 Cross-Encoder 模型
最常见的 Rerank 方式是使用 Cross-Encoder。
Bi-Encoder 是把 query 和 document 分别编码,再计算向量相似度;Cross-Encoder 则是把 query 和 document 拼在一起输入模型,让模型直接判断二者的相关性。
例如:
text
输入:
Query: 什么是 RAG 中的 Rerank?
Document: Rerank 是对初步检索结果进行重新排序的过程,用于提升检索精度。
输出:
相关性分数:0.92
Cross-Encoder 的好处是判断更准确,因为它能同时看到问题和文档,并建模二者之间的细粒度交互。缺点是速度比向量检索慢,所以通常不会直接用于全库检索,而是只用于候选结果的二次排序。
2. 使用专门的 Rerank API 或模型
实际项目中,可以直接使用成熟的 Rerank 模型或服务,例如:
| 类型 | 示例 | 特点 |
|---|---|---|
| 开源模型 | bge-reranker、jina-reranker、m3e-reranker | 可本地部署,成本可控 |
| 商业 API | Cohere Rerank、Jina AI Reranker、部分云厂商 Rerank 服务 | 接入简单,效果稳定 |
| LLM 评分 | 让大模型判断文档相关性 | 灵活但成本较高、延迟较大 |
在企业级 RAG 项目中,比较常见的选择是"向量检索召回 + Rerank 模型精排",这样可以在速度、成本和准确率之间取得平衡。
具体需要怎么做
第一步:初步召回候选文档
先用向量检索、关键词检索或混合检索从知识库中召回一批候选内容。
例如:
text
用户问题:什么是 RAG 中的 Rerank?
初步检索返回 Top 50:
doc1, doc2, doc3, ... doc50
这里的 Top K 不宜太小。如果只召回 Top 3,可能相关文档根本没被召回,Rerank 也没有机会发挥作用。一般可以先召回 Top 20、Top 50 或 Top 100,再交给 Rerank 精排。
第二步:构造 Query-Document 对
把用户问题和每个候选文档组成一对,交给 Rerank 模型打分。
text
(query, doc1) -> score1
(query, doc2) -> score2
(query, doc3) -> score3
...
(query, doc50) -> score50
Rerank 模型输出的通常是一个相关性分数,分数越高表示文档越相关。
第三步:按相关性分数重新排序
根据 Rerank 分数从高到低排序。
text
排序前:
doc1: 0.61
doc2: 0.84
doc3: 0.35
doc4: 0.92
排序后:
doc4: 0.92
doc2: 0.84
doc1: 0.61
doc3: 0.35
排序之后,通常只保留前几个最相关的文档片段。
第四步:过滤低质量或低相关内容
除了排序,还可以设置阈值过滤。例如只保留分数大于 0.6 的文档,避免无关内容进入上下文。
text
保留:
score >= 0.6 的文档
丢弃:
score < 0.6 的文档
这一步对减少大模型幻觉很重要。如果不相关文档被放入 Prompt,大模型可能会基于错误上下文生成误导性答案。
第五步:控制进入 Prompt 的文档数量
Rerank 后不能把所有文档都塞给大模型,因为上下文窗口有限,而且文档越多,噪声也越多。
一般做法是:
| 场景 | 初步召回数量 | Rerank 后保留数量 |
|---|---|---|
| 简单问答 | Top 20 | Top 3 ~ 5 |
| 复杂问题 | Top 50 | Top 5 ~ 10 |
| 多跳推理 | Top 100 | Top 10 ~ 20 |
| 长文档问答 | Top 50 ~ 100 | 按章节或片段聚合后保留 |
最终进入 Prompt 的内容要兼顾相关性、多样性和上下文长度。
工程实现示例
一个简化的 RAG + Rerank 伪代码如下:
python
def rag_answer(query):
# 1. 初步召回
candidates = vector_store.search(query, top_k=50)
# 2. 构造 query-document 对并 rerank
rerank_inputs = [
{"query": query, "document": doc.content}
for doc in candidates
]
scored_docs = reranker.rank(rerank_inputs)
# 3. 按分数排序
scored_docs = sorted(scored_docs, key=lambda x: x.score, reverse=True)
# 4. 过滤低相关内容
filtered_docs = [
item.document
for item in scored_docs
if item.score >= 0.6
]
# 5. 取 Top N 构造上下文
context = "\n\n".join(doc.content for doc in filtered_docs[:5])
# 6. 调用大模型生成答案
prompt = f"""
请基于以下资料回答问题。
资料:
{context}
问题:
{query}
"""
return llm.generate(prompt)
真实项目中还会加上分块策略、去重、引用来源、上下文压缩、缓存和超时控制。
总结
RAG 中的 Rerank 是指在初步检索之后,对召回的候选文档进行二次排序的过程。初步检索通常使用向量检索、BM25 或混合检索,优势是速度快、召回范围广,但排序结果不一定足够准确。Rerank 会使用 Cross-Encoder、专门的 reranker 模型或大模型评分方式,对 query 和每个候选文档进行更细粒度的相关性判断,然后重新排序,选出最相关的 Top N 文档作为大模型生成答案的上下文。
具体实现时,一般先从知识库召回 Top K 候选文档,比如 Top 50;然后把用户问题和每个候选文档组成 query-document pair,交给 rerank 模型打分;接着按照分数从高到低排序,并过滤掉低分文档;最后取前几个高相关文档拼接到 Prompt 中,让大模型基于这些内容回答。这样可以显著提升 RAG 的检索精度,减少无关上下文和幻觉问题。
A2A协议的五大设计原则
A2A 协议的五大设计原则是:拥抱 Agentic 能力、建立在现有标准之上、默认安全、支持长任务、模态无关。
A2A,也就是 Agent2Agent Protocol,核心目标是让不同框架、不同平台、不同厂商实现的 AI Agent 能够用统一方式互相发现、通信和协作。
1. 拥抱 Agentic 能力
A2A 不是把 Agent 当成一个普通 API 或工具函数,而是把它看作具备自主规划、推理、协作能力的智能体。
传统 API 更像是"我调用你,你返回结果";而 A2A 更强调 Agent 之间可以像同事一样协作。一个 Agent 可以向另一个 Agent 发起任务,对方可以根据自己的能力拆解、执行、追问、返回中间状态或最终结果。双方不需要共享内存,也不需要了解彼此的底层实现,只需要遵循统一协议即可。
2. 建立在现有标准之上
A2A 尽量复用成熟的互联网协议和工程标准,而不是重新发明一套通信体系。
它通常建立在 HTTP、JSON-RPC、SSE 等已有标准之上,这样可以降低接入成本,也方便企业系统、云服务、开发框架快速集成。对开发者来说,这意味着不需要学习一套完全陌生的底层通信机制,就能让 Agent 接入 A2A 生态。
3. 默认安全
A2A 的设计强调身份认证、授权、访问控制和安全边界。
因为 Agent 之间协作时可能涉及企业数据、用户隐私、外部工具调用、跨系统任务执行,所以协议必须保证"谁在请求、能访问什么、能执行什么操作"都是可控的。默认安全的原则可以避免 Agent 被滥用,也方便企业在生产环境中落地。
4. 支持长时间运行的任务
Agent 协作不一定都是一次请求、一次响应就能完成的。
很多真实任务可能需要较长时间,比如调研、审批、生成报告、调用多个外部系统、等待人工确认等。因此 A2A 支持长任务机制,允许任务有状态、有进度、有中间结果,也可以通过流式返回或异步方式让调用方持续感知任务进展。
5. 模态无关
A2A 不局限于文本交互,而是支持多种模态的数据协作。
Agent 之间传递的信息可以是文本,也可以是图片、音频、视频、表格、文件或结构化数据。这样 A2A 可以适配更广泛的智能体场景,比如办公 Agent、客服 Agent、设计 Agent、数据分析 Agent、代码 Agent 等。
总结:A2A 的五大设计原则分别是"把 Agent 当智能体而不是普通工具、复用现有 Web 标准、默认保证安全、支持异步长任务、多模态无关"。这五点共同解决的是跨 Agent 协作中的通信、互操作、安全、任务状态和数据表达问题。
在基于大模型的应用开发中,混合检索主要解决的问题
混合检索就是把向量检索和关键词检索结合起来,在 RAG 等大模型应用中同时兼顾"语义理解"和"精确匹配",主要解决单一检索方式召回不全、匹配不准的问题。
在基于大模型的应用开发中,混合检索通常用于知识库问答、企业文档检索、智能客服、代码问答、搜索增强生成等场景。它的核心思路不是只依赖一种检索算法,而是让多种检索方式并行工作,再把结果融合、排序,选出最适合提供给大模型的上下文。
什么是混合检索?
混合检索,通常指 Hybrid Search,是将多种检索方式组合使用的一种检索策略。最常见的组合是:
| 检索方式 | 代表方法 | 擅长点 | 不擅长点 |
|---|---|---|---|
| 向量检索 | Embedding、ANN、语义向量相似度 | 理解语义相近内容 | 精确匹配专有名词较弱 |
| 关键词检索 | BM25、倒排索引、全文检索 | 精确匹配关键词、编号、术语 | 不理解语义表达变化 |
| 结构化过滤 | metadata filter、SQL 条件 | 按时间、权限、分类过滤 | 不能单独理解自然语言问题 |
举个例子,用户问"怎么提升 RAG 检索准确率?",向量检索可以匹配到"优化召回质量""提升知识库命中率""改进 embedding 表达"等语义相关内容。
但如果用户问的是"查询 iPhone 15 Pro Max 的维修政策"或者"查看订单号 A20250611001",关键词检索往往更可靠,因为这些专有名词、型号、编号必须精确命中。
所以混合检索的做法是:同一个 query 同时走向量检索和关键词检索,有时还会加上元数据过滤、知识图谱检索或规则检索,然后把多个召回结果合并、去重、打分、重排,最后交给大模型生成回答。
为什么需要混合检索?
单独使用向量检索时,系统能理解"意思相近"的内容,但可能漏掉精确词。例如用户搜索"Redis AOF rewrite",向量检索可能召回一堆 Redis 持久化相关文档,但不一定把标题里明确包含 "AOF rewrite" 的文档排到最前。
单独使用关键词检索时,系统能精确匹配词面,但理解不了同义表达。例如用户问"怎么让回答更可靠",关键词检索可能匹配不到"降低幻觉""增强事实一致性""引用知识库上下文"等内容。
混合检索就是为了同时利用两者优势:向量检索负责语义召回,关键词检索负责字面精确命中。它能让系统既找得到"意思相关"的文档,也不会漏掉"关键词必须命中"的文档。
在大模型应用中主要解决什么问题?
1. 解决语义匹配和精确匹配无法兼得的问题
RAG 应用里,用户的问题通常很口语化,而知识库文档往往是正式表达。比如用户问"登录不上怎么办",文档中可能写的是"账号认证失败处理流程"。这类问题适合向量检索。
但另一方面,企业知识库里经常有产品名、接口名、错误码、版本号、订单号、代码类名等内容,比如 ERR_AUTH_401、Spring Security、v2.3.1。这类内容必须靠关键词或精确匹配增强。
混合检索可以让两类需求同时被覆盖。
2. 解决召回不全的问题
RAG 的效果很大程度取决于能不能把正确上下文召回。如果第一步检索没找到正确材料,后面的大模型再强也只能"猜"。
混合检索通过多路召回扩大候选集:向量检索召回语义相关内容,关键词检索召回字面相关内容,必要时再用 metadata 过滤限定范围。这样可以明显降低"明明知识库里有答案,但系统没搜到"的概率。
3. 解决排序不准的问题
多路召回后,结果不能简单拼在一起,否则可能出现重复、噪声或排序混乱。混合检索通常还会配合分数融合和重排序,例如:
- 对向量相似度和 BM25 分数做归一化后加权;
- 使用 RRF,也就是 Reciprocal Rank Fusion,按各检索通道中的排名融合;
- 使用 Reranker 模型对候选文档重新排序;
- 根据业务规则提升标题命中、精确词命中、最近更新时间、用户权限范围内的文档。
这样做的目标是让最相关、最可靠、最适合回答问题的片段排在前面。
4. 解决大模型幻觉问题
大模型在缺少可靠上下文时容易编造答案。混合检索通过提高正确知识片段的命中率,让模型更容易基于真实材料回答,而不是凭训练记忆生成。
尤其是在企业问答、法律合同、医疗资料、技术文档、金融制度等场景中,回答必须基于指定知识库。混合检索可以提高上下文质量,从源头减少幻觉。
5. 解决复杂业务查询问题
真实业务里的查询往往不是单纯语义问题。例如:
"查询 2025 年 3 月之后,华东区域客户关于退款流程的投诉记录。"
这个问题同时包含时间、区域、主题、业务类型。比较合理的做法是:
- 用结构化过滤锁定时间和区域;
- 用关键词检索命中"退款""投诉"等词;
- 用向量检索匹配"退费""售后赔付""取消订单"等语义相近内容;
- 最后融合排序并交给大模型回答。
这类复合型查询只靠单一检索方式很难稳定解决。
典型实现流程
一个常见的混合检索流程可以这样描述:
#mermaid-svg-5fX97Ru2Srq3fA7s{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5fX97Ru2Srq3fA7s .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5fX97Ru2Srq3fA7s .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5fX97Ru2Srq3fA7s .error-icon{fill:#552222;}#mermaid-svg-5fX97Ru2Srq3fA7s .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5fX97Ru2Srq3fA7s .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5fX97Ru2Srq3fA7s .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5fX97Ru2Srq3fA7s .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5fX97Ru2Srq3fA7s .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5fX97Ru2Srq3fA7s .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5fX97Ru2Srq3fA7s .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5fX97Ru2Srq3fA7s .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5fX97Ru2Srq3fA7s .marker.cross{stroke:#333333;}#mermaid-svg-5fX97Ru2Srq3fA7s svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5fX97Ru2Srq3fA7s p{margin:0;}#mermaid-svg-5fX97Ru2Srq3fA7s .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5fX97Ru2Srq3fA7s .cluster-label text{fill:#333;}#mermaid-svg-5fX97Ru2Srq3fA7s .cluster-label span{color:#333;}#mermaid-svg-5fX97Ru2Srq3fA7s .cluster-label span p{background-color:transparent;}#mermaid-svg-5fX97Ru2Srq3fA7s .label text,#mermaid-svg-5fX97Ru2Srq3fA7s span{fill:#333;color:#333;}#mermaid-svg-5fX97Ru2Srq3fA7s .node rect,#mermaid-svg-5fX97Ru2Srq3fA7s .node circle,#mermaid-svg-5fX97Ru2Srq3fA7s .node ellipse,#mermaid-svg-5fX97Ru2Srq3fA7s .node polygon,#mermaid-svg-5fX97Ru2Srq3fA7s .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5fX97Ru2Srq3fA7s .rough-node .label text,#mermaid-svg-5fX97Ru2Srq3fA7s .node .label text,#mermaid-svg-5fX97Ru2Srq3fA7s .image-shape .label,#mermaid-svg-5fX97Ru2Srq3fA7s .icon-shape .label{text-anchor:middle;}#mermaid-svg-5fX97Ru2Srq3fA7s .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5fX97Ru2Srq3fA7s .rough-node .label,#mermaid-svg-5fX97Ru2Srq3fA7s .node .label,#mermaid-svg-5fX97Ru2Srq3fA7s .image-shape .label,#mermaid-svg-5fX97Ru2Srq3fA7s .icon-shape .label{text-align:center;}#mermaid-svg-5fX97Ru2Srq3fA7s .node.clickable{cursor:pointer;}#mermaid-svg-5fX97Ru2Srq3fA7s .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5fX97Ru2Srq3fA7s .arrowheadPath{fill:#333333;}#mermaid-svg-5fX97Ru2Srq3fA7s .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5fX97Ru2Srq3fA7s .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5fX97Ru2Srq3fA7s .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5fX97Ru2Srq3fA7s .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5fX97Ru2Srq3fA7s .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5fX97Ru2Srq3fA7s .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5fX97Ru2Srq3fA7s .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5fX97Ru2Srq3fA7s .cluster text{fill:#333;}#mermaid-svg-5fX97Ru2Srq3fA7s .cluster span{color:#333;}#mermaid-svg-5fX97Ru2Srq3fA7s div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5fX97Ru2Srq3fA7s .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5fX97Ru2Srq3fA7s rect.text{fill:none;stroke-width:0;}#mermaid-svg-5fX97Ru2Srq3fA7s .icon-shape,#mermaid-svg-5fX97Ru2Srq3fA7s .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5fX97Ru2Srq3fA7s .icon-shape p,#mermaid-svg-5fX97Ru2Srq3fA7s .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5fX97Ru2Srq3fA7s .icon-shape .label rect,#mermaid-svg-5fX97Ru2Srq3fA7s .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5fX97Ru2Srq3fA7s .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5fX97Ru2Srq3fA7s .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5fX97Ru2Srq3fA7s :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户问题 Query
查询改写/扩展
向量检索
关键词检索 BM25
元数据过滤
结果合并
去重与分数融合
Rerank 重排序
选择 Top K 上下文
交给大模型生成答案
混合检索是在 RAG 系统中组合向量检索和关键词检索的一种策略。向量检索解决语义理解问题,关键词检索解决精确匹配问题。它主要解决单一检索方式召回不全、专有名词匹配弱、同义表达识别差、排序不准以及上下文质量不稳定的问题,从而提升大模型回答的准确性、覆盖率和可信度。
什么是Google ADK?
Google ADK 是一个用于开发 AI Agent 的智能体开发工具包,核心作用是帮助开发者用工程化方式构建、编排、运行和管理智能体应用。
ADK 全称是 Agent Development Kit,可以理解为面向智能体应用开发的一套框架和工具。它的目标不是单纯让大模型"回答问题",而是帮助开发者把大模型、工具调用、工作流、多 Agent 协作、状态管理、部署运行等能力组织起来,构建真正能完成任务的 AI Agent 系统。
Google ADK 解决什么问题?
传统大模型应用通常是"用户提问,大模型回答",能力边界比较简单。但 Agent 应用更复杂,它可能需要自己判断任务步骤、调用外部工具、读取数据、执行操作、和其他 Agent 协作,甚至持续处理一个较长的业务流程。
Google ADK 的价值就在于把这些复杂能力抽象成开发框架,让开发者可以像写普通软件一样开发智能体,而不是把所有逻辑都堆在 Prompt 里。
举个例子,如果要做一个法律咨询系统,可能会拆成几个不同角色:
| Agent | 职责 |
|---|---|
| 法律条款分析 Agent | 理解用户问题,定位相关法规条款 |
| 案例匹配 Agent | 检索相似案例,补充参考依据 |
| 文档生成 Agent | 生成咨询意见、合同草稿或说明文档 |
| 审核 Agent | 检查回答是否符合格式、事实和风险要求 |
ADK 就是用来定义这些 Agent、连接它们的协作关系,并管理它们执行过程的工具包。
Google ADK 的核心能力
1. Agent 定义与封装
ADK 可以帮助开发者定义一个 Agent 的角色、目标、工具、模型和执行逻辑。比如一个"数据分析 Agent"可以被配置为会调用数据库查询工具、图表生成工具和统计分析函数。
这样每个 Agent 都不只是一个 Prompt,而是一个具备明确职责和可调用能力的软件模块。
2. 工具调用能力
Agent 要完成真实任务,通常不能只靠模型生成文本,还需要调用外部工具。例如搜索知识库、查询数据库、调用 API、执行代码、生成文件、发送通知等。
ADK 通常会提供工具注册和调用机制,让 Agent 能够在合适的时候选择工具,并把工具返回结果继续用于推理和生成。
3. 多 Agent 协作
复杂任务往往不是一个 Agent 就能完成的。ADK 支持把多个 Agent 组合起来,让它们按角色分工协作。
比如一个"旅行规划系统"中,可以有预算 Agent、路线 Agent、酒店 Agent、天气 Agent 和总结 Agent。每个 Agent 负责一部分,最终汇总成完整方案。
4. 工作流编排
Agent 系统需要控制任务执行顺序。例如先理解需求,再检索资料,再调用工具,最后生成答案。有些任务还可能需要条件分支,比如"如果用户预算不足,就重新规划路线"。
ADK 的编排能力可以帮助开发者把这些流程结构化,而不是完全依赖模型临时发挥。
5. 状态与上下文管理
Agent 执行任务时,需要记住中间结果、用户偏好、工具调用结果、历史对话和任务进度。ADK 可以帮助管理这些上下文,避免每一步都从零开始。
这对于长任务、多轮对话和多 Agent 协作尤其重要。
6. 评估、调试与部署
智能体开发不仅是"能跑",还要能调试、能评估、能上线。ADK 通常会围绕 Agent 的执行轨迹、工具调用记录、输入输出结果等提供工程化支持,方便开发者定位问题、优化效果,并部署到实际环境中。
Google ADK,也就是 Agent Development Kit,是 Google 推出的智能体开发工具包,主要用于工程化构建 AI Agent 应用。它可以帮助开发者定义 Agent、接入工具、编排工作流、管理上下文,并支持多个 Agent 之间协作。它解决的是传统大模型应用中 Prompt 逻辑混乱、工具调用难管理、多 Agent 协作复杂、任务状态难维护等问题。简单来说,ADK 让开发者可以像开发普通软件系统一样开发、组织和管理智能体应用。
RAG的完整流程
RAG 的完整流程可以概括为"离线建库 + 在线检索生成":先把知识文档清洗、切分、向量化并存入索引;用户提问时再检索相关内容,经过重排和上下文拼接后交给大模型生成答案。
RAG,全称 Retrieval-Augmented Generation,意思是检索增强生成。它的核心思路是"先查资料,再让大模型回答",用外部知识库补充大模型自身知识的不足,从而提升回答的准确性、时效性和可控性。
一、离线索引阶段:把知识准备好
离线阶段的目标是把原始资料处理成"可检索"的知识库。这里处理得越好,后面在线问答的效果通常越稳定。
1. 数据收集
首先要收集原始知识来源,例如 PDF、Word、网页、Markdown、数据库记录、接口文档、产品手册、FAQ、客服工单、代码仓库等。
这一步要明确知识范围:哪些文档可以入库,哪些文档不能入库;哪些内容是公开知识,哪些内容有权限限制;哪些知识需要定期更新。
2. 数据清洗和预处理
原始文档通常不能直接用于检索,需要先清洗。例如去掉页眉页脚、广告、水印、重复内容、乱码、无意义空行,还要处理表格、图片 OCR、标题层级、代码块、链接、特殊符号等。
清洗的目标是让文档变成结构清晰、语义完整、噪声较少的文本。否则向量化之后,检索结果会被大量无关内容干扰。
3. 文档切分 Chunking
大模型和向量检索都不适合直接处理超长文档,所以要把文档切成较小的文本块,也叫 chunk。
常见做法是按段落、标题、语义边界切分,每块大约几百字,并保留一定 overlap,避免上下文被切断。例如一段说明被拆成两块时,重叠部分可以减少"前后文丢失"的问题。
切分时不能只追求固定长度,更重要的是保证每个 chunk 语义相对完整。
4. 元数据标注
每个文本块最好保留 metadata,例如文档标题、来源链接、章节名、作者、更新时间、业务分类、权限范围、版本号等。
这些元数据在后续检索时很重要,可以用于过滤、排序、溯源和权限控制。比如只检索"2025 年后的制度文档",或者只返回当前用户有权限访问的知识。
5. 向量化 Embedding
接着用 Embedding 模型把每个文本块转换成向量。向量可以理解为文本语义的数字表示,语义越相近,向量距离通常越近。
例如"如何重置密码"和"忘记密码怎么办"虽然字面不同,但向量表示应该比较接近,这样系统就能通过语义相似度把相关内容找出来。
6. 建立索引并入库
最后把文本块、向量和元数据一起存入向量数据库或检索系统中,例如 Milvus、FAISS、Elasticsearch、OpenSearch、pgvector 等。
系统会建立索引,方便后续快速检索。到这里,离线知识库准备完成。
二、在线问答阶段:用户提问后检索并生成
在线阶段的目标是根据用户问题,从知识库中找出最相关的内容,再让大模型基于这些内容回答。
1. 接收用户问题
用户输入问题后,系统首先会进行基础处理,比如去除无效字符、识别语言、判断意图、识别是否需要检索、提取关键词或约束条件。
例如用户问:"2024 版报销制度里,差旅住宿标准是多少?"系统需要识别出"报销制度""差旅住宿标准""2024 版"等关键信息。
2. 查询改写或查询扩展
为了提高召回率,系统可能会对用户问题进行改写或扩展。
比如用户问"登录不上怎么办",可以扩展成"无法登录""账号认证失败""密码错误""验证码失败"等表达。这样可以检索到更多相关文档。
在复杂场景中,还可能把一个问题拆成多个子问题分别检索。
3. 查询向量化
系统用同一个或兼容的 Embedding 模型,把用户问题也转换成向量。然后用这个 query 向量去和知识库里的 chunk 向量做相似度匹配。
4. 召回检索
检索阶段会从知识库中召回候选内容。常见方式包括向量检索、关键词检索、混合检索和元数据过滤。
| 检索方式 | 作用 |
|---|---|
| 向量检索 | 找到语义相近的内容 |
| 关键词检索 | 精确匹配术语、编号、产品名、错误码 |
| 混合检索 | 同时兼顾语义理解和精确匹配 |
| 元数据过滤 | 按时间、权限、分类、版本等条件筛选 |
实际项目里,通常不会只用单一路径,而是多路召回后合并结果,尽量避免"知识库里有答案但没搜到"。
5. 结果去重和重排序 Rerank
初步召回的内容不一定都准确,排序也可能不理想,所以通常要做去重和重排序。
Rerank 模型会更精细地判断"用户问题"和"候选文本块"之间的相关性,把真正有用的内容排到前面。比如向量检索召回了 20 个 chunk,Rerank 后只取最相关的 3 到 5 个进入上下文。
6. 上下文组装 Prompt Construction
系统会把筛选后的文档片段拼接成上下文,再和用户问题、回答要求、角色设定、引用规则等一起组成 Prompt。
这一步要注意上下文长度限制。不是塞得越多越好,而是要选择最相关、最完整、最少噪声的内容。必要时还会做上下文压缩或摘要。
7. 大模型生成答案
大模型基于 Prompt 中的检索内容生成答案。理想情况下,模型应优先依据检索到的上下文回答,而不是凭空发挥。
在企业级 RAG 中,常见要求包括:答案必须可溯源、不能回答知识库外的问题、找不到依据时要说明无法确认、重要结论要引用来源。
8. 后处理和返回结果
生成答案后,系统可能还会进行格式化、敏感信息过滤、事实一致性检查、引用补全、答案评分、多轮追问建议等处理。
最终返回给用户的通常不仅是答案,还可能包括引用来源、相关文档链接、置信度或"是否命中知识库"的判断。
三、完整流程图
#mermaid-svg-3roqYSE2i3WbRz7z{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3roqYSE2i3WbRz7z .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3roqYSE2i3WbRz7z .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3roqYSE2i3WbRz7z .error-icon{fill:#552222;}#mermaid-svg-3roqYSE2i3WbRz7z .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3roqYSE2i3WbRz7z .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3roqYSE2i3WbRz7z .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3roqYSE2i3WbRz7z .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3roqYSE2i3WbRz7z .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3roqYSE2i3WbRz7z .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3roqYSE2i3WbRz7z .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3roqYSE2i3WbRz7z .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3roqYSE2i3WbRz7z .marker.cross{stroke:#333333;}#mermaid-svg-3roqYSE2i3WbRz7z svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3roqYSE2i3WbRz7z p{margin:0;}#mermaid-svg-3roqYSE2i3WbRz7z .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3roqYSE2i3WbRz7z .cluster-label text{fill:#333;}#mermaid-svg-3roqYSE2i3WbRz7z .cluster-label span{color:#333;}#mermaid-svg-3roqYSE2i3WbRz7z .cluster-label span p{background-color:transparent;}#mermaid-svg-3roqYSE2i3WbRz7z .label text,#mermaid-svg-3roqYSE2i3WbRz7z span{fill:#333;color:#333;}#mermaid-svg-3roqYSE2i3WbRz7z .node rect,#mermaid-svg-3roqYSE2i3WbRz7z .node circle,#mermaid-svg-3roqYSE2i3WbRz7z .node ellipse,#mermaid-svg-3roqYSE2i3WbRz7z .node polygon,#mermaid-svg-3roqYSE2i3WbRz7z .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3roqYSE2i3WbRz7z .rough-node .label text,#mermaid-svg-3roqYSE2i3WbRz7z .node .label text,#mermaid-svg-3roqYSE2i3WbRz7z .image-shape .label,#mermaid-svg-3roqYSE2i3WbRz7z .icon-shape .label{text-anchor:middle;}#mermaid-svg-3roqYSE2i3WbRz7z .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3roqYSE2i3WbRz7z .rough-node .label,#mermaid-svg-3roqYSE2i3WbRz7z .node .label,#mermaid-svg-3roqYSE2i3WbRz7z .image-shape .label,#mermaid-svg-3roqYSE2i3WbRz7z .icon-shape .label{text-align:center;}#mermaid-svg-3roqYSE2i3WbRz7z .node.clickable{cursor:pointer;}#mermaid-svg-3roqYSE2i3WbRz7z .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3roqYSE2i3WbRz7z .arrowheadPath{fill:#333333;}#mermaid-svg-3roqYSE2i3WbRz7z .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3roqYSE2i3WbRz7z .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3roqYSE2i3WbRz7z .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3roqYSE2i3WbRz7z .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3roqYSE2i3WbRz7z .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3roqYSE2i3WbRz7z .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3roqYSE2i3WbRz7z .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3roqYSE2i3WbRz7z .cluster text{fill:#333;}#mermaid-svg-3roqYSE2i3WbRz7z .cluster span{color:#333;}#mermaid-svg-3roqYSE2i3WbRz7z div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3roqYSE2i3WbRz7z .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3roqYSE2i3WbRz7z rect.text{fill:none;stroke-width:0;}#mermaid-svg-3roqYSE2i3WbRz7z .icon-shape,#mermaid-svg-3roqYSE2i3WbRz7z .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3roqYSE2i3WbRz7z .icon-shape p,#mermaid-svg-3roqYSE2i3WbRz7z .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3roqYSE2i3WbRz7z .icon-shape .label rect,#mermaid-svg-3roqYSE2i3WbRz7z .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3roqYSE2i3WbRz7z .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3roqYSE2i3WbRz7z .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3roqYSE2i3WbRz7z :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 原始文档
数据清洗与预处理
文档切分 Chunking
元数据标注
Embedding 向量化
向量库/搜索引擎建索引
用户问题
问题理解与查询改写
问题向量化
向量检索/关键词检索/混合检索
候选结果合并与去重
Rerank 重排序
选取 Top K 文档片段
构造 Prompt 上下文
大模型生成答案
后处理、引用与返回结果
四、总结
RAG 的完整流程可以分为离线索引和在线问答两大阶段。离线阶段负责知识入库,包括数据收集、清洗预处理、文档切分、元数据标注、Embedding 向量化、向量库建索引。在线阶段负责回答用户问题,包括接收问题、查询改写、问题向量化、从知识库检索相关文档、对结果去重和 Rerank、选取 Top K 内容拼接到 Prompt 中,最后交给大模型生成答案并做后处理。简单来说,RAG 就是先把知识处理成可检索索引,用户提问时先检索相关知识,再让大模型基于检索结果回答,从而减少幻觉并提升答案的准确性和可追溯性。
A2A协议的工作原理
A2A 协议的工作原理,是让不同 Agent 通过统一的协议发现能力、协商任务、交换上下文,并持续跟踪任务状态,最终完成跨 Agent 协作。
A2A 通常指 Agent-to-Agent 协议,它的核心目标不是让一个大模型单独完成所有事情,而是让多个具备不同能力的 Agent 可以像"服务之间调用接口"一样互相协作。客户端 Agent 负责任务发起、需求描述和结果接收;远程 Agent 负责暴露能力、理解任务、执行动作并返回结果。
核心角色
A2A 协议里一般有两个主要角色:
| 角色 | 作用 |
|---|---|
| 客户端 Agent | 发起任务,请求其他 Agent 提供能力或执行操作 |
| 远程 Agent | 对外暴露自身能力,接收任务并返回执行结果 |
客户端 Agent 可以理解为"调度方"或"请求方",它不一定亲自完成所有任务,而是根据任务需要找到合适的远程 Agent。远程 Agent 则类似一个具备特定技能的服务,比如订票 Agent、日程 Agent、搜索 Agent、代码 Agent、客服 Agent 等。
工作流程
A2A 的工作原理可以概括为以下几个步骤。
1. 能力发现
客户端 Agent 首先需要知道远程 Agent 能做什么。远程 Agent 通常会通过某种描述文件或元数据暴露自己的能力,包括名称、功能说明、输入格式、输出格式、认证方式、调用地址等。
这一步类似于"服务注册与发现"。客户端 Agent 只有知道对方具备什么能力,才能判断是否适合把任务交给它。
2. 任务创建
当客户端 Agent 确定某个远程 Agent 可以处理当前需求后,会创建一个任务,并把任务目标、上下文、输入参数、约束条件等信息发送给远程 Agent。
例如用户说:"帮我安排下周三去北京的行程。"客户端 Agent 可能会把任务拆分成查航班、订酒店、规划日程等多个子任务,然后分别交给不同的远程 Agent。
3. 消息交互
远程 Agent 收到任务后,可能不会一次性完成。它可能需要进一步确认信息,比如时间、预算、偏好、权限等。因此 A2A 支持多轮消息交互。
这意味着两个 Agent 之间不是简单的一问一答,而是可以围绕同一个任务持续通信。客户端 Agent 可以补充信息,远程 Agent 可以请求澄清,也可以阶段性返回处理进度。
4. 状态管理
A2A 通常会把任务看成一个有状态的过程,而不是一次普通接口调用。任务可能处于已创建、处理中、等待输入、已完成、失败、取消等状态。
客户端 Agent 可以根据任务状态决定下一步动作。例如:
| 状态 | 含义 |
|---|---|
| submitted | 任务已提交 |
| working | 远程 Agent 正在处理 |
| input-required | 需要客户端补充信息 |
| completed | 任务完成 |
| failed | 任务失败 |
| canceled | 任务取消 |
状态管理的好处是可以支持长任务、异步任务和复杂协作,而不是要求所有结果都必须立即返回。
5. 结果返回
远程 Agent 完成任务后,会把结果返回给客户端 Agent。结果可以是文本、结构化数据、文件、操作结果,甚至是后续可执行的建议。
客户端 Agent 收到结果后,可能会直接回复用户,也可能继续把结果传递给另一个 Agent,形成多 Agent 协同链路。
可以用一个例子理解
假设用户对个人助理 Agent 说:"帮我准备一次去上海出差的安排。"
个人助理 Agent 本身不一定会查询机票、订酒店、生成日程,但它可以通过 A2A 协议和其他 Agent 协作:
日程 Agent 酒店 Agent 航班 Agent 客户端 Agent 用户 日程 Agent 酒店 Agent 航班 Agent 客户端 Agent 用户 #mermaid-svg-4cZ1KDJTw2hjFbpL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4cZ1KDJTw2hjFbpL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4cZ1KDJTw2hjFbpL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4cZ1KDJTw2hjFbpL .error-icon{fill:#552222;}#mermaid-svg-4cZ1KDJTw2hjFbpL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4cZ1KDJTw2hjFbpL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4cZ1KDJTw2hjFbpL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4cZ1KDJTw2hjFbpL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4cZ1KDJTw2hjFbpL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4cZ1KDJTw2hjFbpL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4cZ1KDJTw2hjFbpL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4cZ1KDJTw2hjFbpL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4cZ1KDJTw2hjFbpL .marker.cross{stroke:#333333;}#mermaid-svg-4cZ1KDJTw2hjFbpL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4cZ1KDJTw2hjFbpL p{margin:0;}#mermaid-svg-4cZ1KDJTw2hjFbpL .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4cZ1KDJTw2hjFbpL text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-4cZ1KDJTw2hjFbpL .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4cZ1KDJTw2hjFbpL .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-4cZ1KDJTw2hjFbpL .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-4cZ1KDJTw2hjFbpL .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-4cZ1KDJTw2hjFbpL #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-4cZ1KDJTw2hjFbpL .sequenceNumber{fill:white;}#mermaid-svg-4cZ1KDJTw2hjFbpL #sequencenumber{fill:#333;}#mermaid-svg-4cZ1KDJTw2hjFbpL #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-4cZ1KDJTw2hjFbpL .messageText{fill:#333;stroke:none;}#mermaid-svg-4cZ1KDJTw2hjFbpL .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4cZ1KDJTw2hjFbpL .labelText,#mermaid-svg-4cZ1KDJTw2hjFbpL .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-4cZ1KDJTw2hjFbpL .loopText,#mermaid-svg-4cZ1KDJTw2hjFbpL .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-4cZ1KDJTw2hjFbpL .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4cZ1KDJTw2hjFbpL .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-4cZ1KDJTw2hjFbpL .noteText,#mermaid-svg-4cZ1KDJTw2hjFbpL .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-4cZ1KDJTw2hjFbpL .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4cZ1KDJTw2hjFbpL .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4cZ1KDJTw2hjFbpL .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4cZ1KDJTw2hjFbpL .actorPopupMenu{position:absolute;}#mermaid-svg-4cZ1KDJTw2hjFbpL .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-4cZ1KDJTw2hjFbpL .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4cZ1KDJTw2hjFbpL .actor-man circle,#mermaid-svg-4cZ1KDJTw2hjFbpL line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-4cZ1KDJTw2hjFbpL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 安排上海出差查询合适航班返回航班方案查询酒店返回酒店方案创建日程日程创建完成汇总出差安排
在这个过程中,客户端 Agent 负责理解用户意图和任务编排,远程 Agent 分别负责具体能力执行。A2A 协议提供的就是它们之间统一沟通的方式。
底层本质
从技术上看,A2A 的本质可以理解为一套面向 Agent 的通信协议。它解决的是"Agent 之间如何标准化协作"的问题,主要包括:
| 解决的问题 | 说明 |
|---|---|
| 如何发现 Agent | 通过能力描述让其他 Agent 知道自己能做什么 |
| 如何表达任务 | 用统一结构描述任务目标、上下文和输入 |
| 如何持续通信 | 支持围绕任务进行多轮消息交互 |
| 如何跟踪进度 | 通过任务状态管理异步和长流程任务 |
| 如何返回结果 | 用标准格式返回文本、数据、文件或操作结果 |
和普通 API 调用的区别
A2A 不是简单的 HTTP API 调用。普通 API 更像是"输入参数,立即返回结果";而 A2A 更强调 Agent 之间的协作、上下文理解、任务状态和多轮交互。
| 对比项 | 普通 API | A2A 协议 |
|---|---|---|
| 调用方式 | 一次性请求响应 | 可多轮交互 |
| 任务状态 | 通常无状态 | 支持任务状态 |
| 调用对象 | 后端服务 | 智能 Agent |
| 上下文理解 | 较弱 | 更强调上下文 |
| 适用场景 | 确定性接口调用 | 复杂任务协作 |
总结
A2A 协议的工作原理是:客户端 Agent 先通过能力描述发现远程 Agent 的能力,然后根据用户需求创建任务,并把任务上下文、输入参数和约束条件发送给远程 Agent。远程 Agent 接收任务后执行处理,在过程中可以与客户端 Agent 进行多轮消息交互,并通过任务状态机制反馈当前进度。任务完成后,远程 Agent 将结果返回给客户端 Agent,由客户端 Agent 进行汇总、继续调度或反馈给用户。
它的核心价值在于让不同厂商、不同系统、不同能力的 Agent 能够以统一方式互相通信和协作,从而实现复杂任务的自动拆解、分发、执行和结果整合。
在 RAG 应用中为了优化检索精度,其中的数据清洗和预处理怎么做?
RAG 中的数据清洗和预处理,核心目标是把"脏、乱、重复、不可检索"的原始资料,处理成"结构清晰、语义完整、方便召回"的知识片段,从而提升向量检索和关键词检索的命中率。
在 RAG 应用里,检索效果很大程度上取决于数据质量。模型回答得不准,很多时候不是生成模型能力不够,而是前面的知识库里有大量噪声、重复、缺失、切分不合理或元数据不完整,导致检索阶段没有召回真正相关的内容。
1. 数据接入与格式统一
首先要把不同来源的数据统一接入,例如 PDF、Word、Markdown、HTML、网页、数据库、CSV、Excel、API 文档、业务系统记录等。不同格式的数据不能直接混在一起做向量化,需要先转成统一的文本或结构化文档格式。
处理时通常要做这些事情:
| 处理项 | 说明 |
|---|---|
| 格式解析 | 从 PDF、Word、HTML、表格等文件中提取正文 |
| 编码统一 | 统一为 UTF-8,避免乱码 |
| 文本标准化 | 统一空格、换行、标点、大小写等 |
| 结构保留 | 尽量保留标题、段落、表格、列表、章节层级 |
| 附件处理 | 图片、扫描件可通过 OCR 转文字 |
这里要注意,预处理不是简单把所有内容抽成一整段纯文本。RAG 很依赖上下文结构,如果标题、章节、表格关系全部丢失,后续切分和检索都会变差。
2. 清洗噪声内容
数据接入后,要去除对检索没有帮助,甚至会干扰召回的内容。常见噪声包括页眉页脚、版权声明、导航栏、广告、目录、重复菜单、无意义符号、乱码、空行、脚注编号、网页按钮文本等。
比如从网页中采集知识时,如果没有清洗,可能会把"登录""注册""上一篇""下一篇""相关推荐""联系客服"等内容也写入知识库。这些内容会稀释真正正文的语义,导致向量检索命中一些无关片段。
常见做法包括:
| 噪声类型 | 处理方式 |
|---|---|
| 页眉页脚 | 基于规则或模板删除 |
| 广告导航 | 通过 HTML 标签、CSS class 或正文抽取算法过滤 |
| 乱码字符 | 替换或删除异常编码字符 |
| 多余空白 | 合并连续空格、空行、换行 |
| 无意义短句 | 删除过短、重复、无业务价值的文本 |
| 样板文本 | 删除版权、免责声明、固定说明等模板内容 |
3. 去重与相似内容合并
重复内容会明显影响 RAG 检索质量。因为向量库中如果存在大量重复片段,检索结果会被同一类内容占满,导致真正有价值的其他材料排不上来。
去重一般分为三类:完全重复、近似重复和语义重复。
| 类型 | 示例 | 处理方式 |
|---|---|---|
| 完全重复 | 两段文本完全一样 | 哈希去重 |
| 近似重复 | 只差少量标点或格式 | SimHash、MinHash、编辑距离 |
| 语义重复 | 表述不同但含义接近 | 向量相似度聚类、人工规则合并 |
在企业知识库里,重复内容很常见,比如同一个制度文档存在多个版本、多个网页转载同一段说明、FAQ 中多个问题对应相似答案。对于这些内容,最好保留最新版本、权威来源或质量最高的一份,同时在元数据中记录来源和版本。
4. 文本规范化和语义增强
清洗之后,需要对文本做规范化,让检索系统更容易匹配用户问题。常见处理包括同义词归一、专有名词统一、缩写扩展、单位统一、时间格式统一等。
例如:
| 原始表达 | 规范化处理 |
|---|---|
| LLM、大模型、大语言模型 | 统一映射或补充同义词 |
| RAG、检索增强生成 | 建立术语别名 |
| 1k、1000、一千 | 统一数值表达 |
| 2026/06/11、2026年6月11日 | 统一时间格式 |
| CPU 利用率、处理器使用率 | 建立同义词关系 |
但这里要避免过度清洗。比如代码、命令、配置项、产品型号、错误码等内容不能随意改写,否则会破坏原始含义。对于技术文档,大小写、符号、缩进、路径和代码块往往都很重要。
5. 保留和补充元数据
元数据是 RAG 检索优化中非常关键的一环。很多检索不准,并不是因为文本相似度不够,而是缺少过滤条件。例如用户问"2025 版员工报销制度",如果没有年份、部门、版本、文档类型等元数据,系统可能召回旧制度或无关制度。
常见元数据包括:
| 元数据 | 用途 |
|---|---|
| 文档标题 | 帮助判断主题 |
| 章节标题 | 提供上下文层级 |
| 来源 URL / 文件名 | 便于溯源 |
| 创建时间 / 更新时间 | 支持按时间过滤 |
| 作者 / 部门 | 支持权限和业务范围过滤 |
| 文档类型 | 区分 FAQ、制度、手册、公告等 |
| 权限标签 | 控制用户能否访问 |
| 版本号 | 避免召回过期内容 |
实践中,元数据应该和文本块一起入库。检索时可以先根据元数据做过滤,再做向量召回或关键词召回,这样能显著提升精度。
6. 合理切分 Chunk
Chunk 切分是 RAG 预处理中最重要的环节之一。切得太大,会导致一个片段包含太多无关信息,向量表达不聚焦;切得太小,又会丢失上下文,模型拿到片段后无法理解完整含义。
常见切分方式包括:
| 切分方式 | 适用场景 |
|---|---|
| 固定长度切分 | 简单文本、快速实现 |
| 按段落切分 | 普通文章、说明文档 |
| 按标题层级切分 | 技术文档、知识库、规章制度 |
| 按语义切分 | 长文章、复杂知识内容 |
| 按结构切分 | 表格、FAQ、API 文档、代码文档 |
实际项目中,一般不建议只按固定 token 数硬切,而是优先按标题、段落、列表、表格、代码块等语义边界切分。每个 chunk 最好表达一个相对完整的知识点。
同时通常会设置一定的重叠窗口,比如相邻 chunk 之间重叠 10% ~ 20% 的内容,避免关键上下文刚好被切断。
7. 处理特殊内容:表格、代码、图片和公式
很多 RAG 应用效果差,是因为只处理普通文本,却忽略了表格、代码、图片、公式这些复杂内容。
对于表格,不能简单按行拼接,否则会丢失表头和字段关系。更好的方式是把每行转成带字段名的自然语言描述,或者保留 Markdown 表格结构。
例如原表格是:
| 产品 | 价格 | 库存 |
|---|---|---|
| A | 100 | 20 |
可以转成:"产品 A 的价格是 100,库存是 20。"这样更利于语义检索。
对于代码文档,要保留函数名、类名、参数、返回值、异常说明和示例代码。对于图片或扫描件,可以使用 OCR 或多模态模型提取文字信息。对于公式,要保留公式本身和解释文字,避免只存公式而没有语义说明。
8. 建立质量校验机制
数据预处理不是一次性脚本跑完就结束,还需要质量校验。否则脏数据会长期留在向量库中,影响后续所有问答。
常见校验指标包括:
| 指标 | 检查内容 |
|---|---|
| 空内容比例 | 是否存在大量空 chunk |
| 重复率 | 是否有大量重复片段 |
| 平均长度 | chunk 是否过长或过短 |
| 乱码率 | 是否存在异常字符 |
| 元数据完整率 | 标题、来源、时间等字段是否缺失 |
| 召回命中率 | 测试问题是否能召回正确片段 |
| Top-K 相关性 | 排名前几的结果是否真的相关 |
比较成熟的做法是准备一批标准测试问题和期望答案,定期评估预处理策略对检索效果的影响。如果调整了切分长度、清洗规则、Embedding 模型或元数据过滤方式,都应该重新评估召回质量。
9. 总结
在 RAG 应用中,为了优化检索精度,数据清洗和预处理一般会从数据接入、格式统一、噪声清洗、去重、文本规范化、元数据补充和合理切分几个方面入手。
首先,需要把 PDF、Word、网页、表格、数据库等多源数据统一解析成标准格式,并保留标题、章节、段落、表格等结构信息。然后要清理页眉页脚、广告、导航、乱码、重复内容、无意义短句等噪声,避免这些内容进入向量库干扰召回。接着要做去重和规范化,比如统一术语、同义词、时间格式、单位和专有名词表达。
之后,要为每个文档或文本块补充元数据,例如来源、标题、章节、时间、版本、权限、文档类型等,方便检索时做过滤和排序。最后,需要按照语义边界进行合理 chunk 切分,尽量保证每个文本块语义完整,并设置适当 overlap,避免上下文被截断。
简单来说,RAG 的数据预处理目标就是把原始数据变成高质量、结构化、可检索、可溯源的知识片段。只有底层知识库干净、准确、粒度合适,后续的 Embedding、向量检索、混合检索和 Rerank 才能发挥出效果。
A2A 协议的工作流程
A2A 协议的工作流程通常分为发现、启动、处理、交互和完成 5 个阶段,用来让不同智能体之间能够安全、标准化地协同完成任务。
A2A,也就是 Agent-to-Agent 协议,核心目标是让一个智能体能够发现另一个智能体的能力,并### A2A 协议的工作流程通常分为发现、启动、处理、交互、完成 5 个阶段,用来让一个智能体安全、标准化地调用另一个智能体完成任务。
A2A,也就是 Agent-to-Agent 协议,核心目标是让不同智能体之间能够互相发现能力、发起任务、传递上下文、协同处理,并最终返回结构化结果。它比较适合多智能体协作场景,比如一个主控 Agent 调用搜索 Agent、代码 Agent、数据分析 Agent、客服 Agent 等共同完成复杂任务。
1. 发现:获取远端智能体能力
客户端或调用方智能体首先需要知道远端智能体是谁、能做什么、怎么调用。通常会向远端服务的固定地址发起请求,例如:
http
GET /.well-known/agent.json
这个地址会返回一个 Agent Card,也就是智能体描述文件。里面通常包含:
| 信息 | 作用 |
|---|---|
| 智能体名称和唯一标识 | 确认要调用的是哪个 Agent |
| 能力列表 | 判断它是否能处理当前任务 |
| 输入输出格式 | 确认数据如何传递 |
| 认证方式 | 判断是否需要 token、API key 等 |
| 服务地址 | 知道后续请求发到哪里 |
| 回调或通知地址 | 用于异步任务状态通知 |
这一阶段解决的是"我要找哪个 Agent 来干活"的问题。
2. 启动:创建任务并发起调用
找到合适的 Agent 后,调用方会根据业务目标创建一个任务。这个任务通常会有唯一的 Task ID,方便后续追踪状态。
调用方式一般基于 JSON-RPC 或 HTTP API。请求中会包含任务目标、输入参数、上下文信息、期望输出格式等内容。例如主控 Agent 可能会告诉远端 Agent:
"请根据这些资料生成一份技术方案,并返回 Markdown 格式。"
这一阶段解决的是"正式把任务交给远端 Agent"的问题。
3. 处理:远端智能体执行任务
远端 Agent 收到任务后,会进入处理阶段。它可能会自己完成任务,也可能继续调用工具、模型、数据库、搜索服务,甚至再调用其他 Agent。
在这个过程中,任务通常会有状态变化,例如:
| 状态 | 含义 |
|---|---|
| submitted | 任务已提交 |
| working | 正在处理 |
| input-required | 需要调用方补充信息 |
| completed | 任务完成 |
| failed | 任务失败 |
| canceled | 任务取消 |
如果任务比较复杂,A2A 协议通常不会要求一次性同步返回完整结果,而是允许异步处理和状态查询。
4. 交互:补充信息或多轮协作
很多 Agent 任务不是一次请求就能完成的。远端 Agent 在执行过程中,可能发现信息不够,需要向调用方发起追问,或者请求用户补充条件。
例如:
"你希望生成中文方案还是英文方案?"
"这份报告面向技术团队还是管理层?"
"是否需要包含成本估算?"
这时任务会进入需要输入的状态,调用方补充信息后,远端 Agent 继续执行。这个阶段体现了 A2A 协议对多轮交互和动态任务推进的支持。
5. 完成:返回结果并结束任务
任务执行完成后,远端 Agent 会返回最终结果。结果可能是文本、结构化 JSON、文件地址、图片、代码、报告,或者多个 artifact。
调用方拿到结果后,可以继续做后续处理,例如:
- 展示给用户;
- 传给另一个 Agent;
- 写入系统;
- 触发下一步工作流;
- 对结果进行校验和总结。
这一阶段解决的是"任务结果如何标准化交付"的问题。
整体流程可以这样理解
#mermaid-svg-lKCaSXeja5CChWFK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lKCaSXeja5CChWFK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lKCaSXeja5CChWFK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lKCaSXeja5CChWFK .error-icon{fill:#552222;}#mermaid-svg-lKCaSXeja5CChWFK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lKCaSXeja5CChWFK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lKCaSXeja5CChWFK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lKCaSXeja5CChWFK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lKCaSXeja5CChWFK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lKCaSXeja5CChWFK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lKCaSXeja5CChWFK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lKCaSXeja5CChWFK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lKCaSXeja5CChWFK .marker.cross{stroke:#333333;}#mermaid-svg-lKCaSXeja5CChWFK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lKCaSXeja5CChWFK p{margin:0;}#mermaid-svg-lKCaSXeja5CChWFK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-lKCaSXeja5CChWFK .cluster-label text{fill:#333;}#mermaid-svg-lKCaSXeja5CChWFK .cluster-label span{color:#333;}#mermaid-svg-lKCaSXeja5CChWFK .cluster-label span p{background-color:transparent;}#mermaid-svg-lKCaSXeja5CChWFK .label text,#mermaid-svg-lKCaSXeja5CChWFK span{fill:#333;color:#333;}#mermaid-svg-lKCaSXeja5CChWFK .node rect,#mermaid-svg-lKCaSXeja5CChWFK .node circle,#mermaid-svg-lKCaSXeja5CChWFK .node ellipse,#mermaid-svg-lKCaSXeja5CChWFK .node polygon,#mermaid-svg-lKCaSXeja5CChWFK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lKCaSXeja5CChWFK .rough-node .label text,#mermaid-svg-lKCaSXeja5CChWFK .node .label text,#mermaid-svg-lKCaSXeja5CChWFK .image-shape .label,#mermaid-svg-lKCaSXeja5CChWFK .icon-shape .label{text-anchor:middle;}#mermaid-svg-lKCaSXeja5CChWFK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lKCaSXeja5CChWFK .rough-node .label,#mermaid-svg-lKCaSXeja5CChWFK .node .label,#mermaid-svg-lKCaSXeja5CChWFK .image-shape .label,#mermaid-svg-lKCaSXeja5CChWFK .icon-shape .label{text-align:center;}#mermaid-svg-lKCaSXeja5CChWFK .node.clickable{cursor:pointer;}#mermaid-svg-lKCaSXeja5CChWFK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lKCaSXeja5CChWFK .arrowheadPath{fill:#333333;}#mermaid-svg-lKCaSXeja5CChWFK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lKCaSXeja5CChWFK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lKCaSXeja5CChWFK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lKCaSXeja5CChWFK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lKCaSXeja5CChWFK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lKCaSXeja5CChWFK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lKCaSXeja5CChWFK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lKCaSXeja5CChWFK .cluster text{fill:#333;}#mermaid-svg-lKCaSXeja5CChWFK .cluster span{color:#333;}#mermaid-svg-lKCaSXeja5CChWFK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lKCaSXeja5CChWFK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lKCaSXeja5CChWFK rect.text{fill:none;stroke-width:0;}#mermaid-svg-lKCaSXeja5CChWFK .icon-shape,#mermaid-svg-lKCaSXeja5CChWFK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lKCaSXeja5CChWFK .icon-shape p,#mermaid-svg-lKCaSXeja5CChWFK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lKCaSXeja5CChWFK .icon-shape .label rect,#mermaid-svg-lKCaSXeja5CChWFK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lKCaSXeja5CChWFK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lKCaSXeja5CChWFK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lKCaSXeja5CChWFK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
调用方 Agent
发现远端 Agent
读取 Agent Card
创建 Task ID
发起任务请求
远端 Agent 处理任务
是否需要补充信息
请求更多输入
返回最终结果
任务完成
总结
A2A 协议的工作流程一般分为发现、启动、处理、交互和完成五个阶段。首先,客户端通过固定地址获取远端智能体的 Agent Card,了解它的能力、认证方式和调用地址;然后根据业务需求创建 Task ID,并通过标准接口发起任务;远端智能体接收任务后开始处理,过程中可能会调用工具或其他智能体;如果信息不足,可以进入多轮交互状态,请求调用方补充信息;最后任务完成后,远端智能体返回结构化结果或产物,调用方再进行展示、存储或继续编排后续流程。
它的核心价值在于把智能体之间的协作标准化,让不同厂商、不同框架、不同能力的 Agent 可以像服务一样被发现、调用和组合。
什么查询扩展?为什么在 RAG 应用中需要查询扩展?
查询扩展就是把用户的原始问题改写、补全或扩充成更适合检索的查询,让 RAG 系统更容易召回相关文档,减少"问得太短、太模糊、词不匹配"导致的漏检问题。
在 RAG 应用中,用户输入的问题往往不等于知识库里文档的表达方式。查询扩展的作用,就是在真正检索前,对用户问题做一层增强,把原始 query 扩展成多个更完整、更丰富、更贴近文档语义的检索表达。
比如用户只输入:
text
减肥
这个查询太短,系统不知道用户是想问饮食、运动、药物、副作用,还是减脂计划。经过查询扩展后,可以变成:
text
健康减肥方法 饮食控制 运动减脂 热量缺口 避免反弹
这样检索系统就更容易找到与"健康减肥""运动减脂""饮食控制"等相关的资料。
为什么 RAG 需要查询扩展?
RAG 的核心流程是"先检索,再生成"。如果检索阶段没有找到正确文档,后面的生成模型再强,也很难回答准确。因此,查询扩展主要是为了解决检索召回不足的问题。
很多真实场景中,用户问题和文档内容之间会存在表达差异。例如用户问"怎么降本",文档里写的是"成本优化策略";用户问"系统卡",文档里写的是"性能瓶颈排查";用户问"员工离职怎么办",文档里可能写的是"人员流失风险与交接流程"。如果只按原始问题检索,很可能匹配不到关键文档。
查询扩展可以把用户的口语化、简略化、模糊化表达,转换成更全面的检索表达,从而提高召回率。
查询扩展主要解决哪些问题?
| 问题 | 表现 | 查询扩展的作用 |
|---|---|---|
| 查询太短 | 用户只输入一个词或一句很短的问题 | 补充上下文和相关概念 |
| 表达不一致 | 用户用口语,文档用专业术语 | 加入同义词、近义词、专业词 |
| 意图不明确 | 问题缺少具体方向 | 推断可能意图并生成多个查询 |
| 语义覆盖不足 | 单个 query 只能命中部分文档 | 扩展多个角度,提高召回 |
| 专有名词缺失 | 用户没有使用文档中的关键词 | 补充领域术语和实体名 |
常见的查询扩展方式
1. 同义词和近义词扩展
这是最基础的方式。系统会把用户问题中的关键词扩展成同义词、近义词或相关表达。
例如:
text
原始查询:系统很慢
扩展查询:系统卡顿、响应慢、性能瓶颈、接口延迟、吞吐量下降
这样可以减少因为"用户用词"和"文档用词"不同导致的漏检。
2. 领域术语扩展
在专业知识库中,用户可能使用通俗表达,而文档中使用专业术语。查询扩展可以把口语表达映射到领域术语。
例如:
text
原始查询:大模型回答不准
扩展查询:幻觉问题、事实性错误、上下文缺失、检索召回不足、RAG 评估
这对于企业知识库、医疗、法律、金融、技术文档等场景非常重要。
3. 意图扩展
有些问题本身比较模糊,需要扩展成多个可能的意图方向。
例如用户问:
text
RAG 效果不好怎么办?
可以扩展成:
text
RAG 检索召回率低如何优化
RAG 生成答案不准确如何评估
RAG chunk 分块策略如何调整
RAG embedding 模型如何选择
RAG rerank 如何提升排序效果
这样系统可以从多个角度检索相关文档,再综合生成回答。
4. 多查询生成
多查询生成是 RAG 中非常常见的做法。它不是只生成一个扩展后的 query,而是生成多个不同表达方式的 query,并分别检索。
例如:
text
原始问题:如何提高 RAG 检索质量?
可以生成:
text
RAG 检索召回率优化方法
RAG 向量检索不准确的原因
RAG 混合检索和重排序优化
RAG 文档分块对检索效果的影响
RAG 查询改写和查询扩展策略
然后把多个查询的检索结果合并、去重、排序,再交给大模型生成最终答案。
5. 假设性文档扩展 HyDE
HyDE,也就是 Hypothetical Document Embeddings,是一种更高级的查询扩展方式。它会先让大模型根据用户问题生成一段"假设答案"或"假设文档",再用这段更完整的文本去做向量检索。
例如用户问:
text
什么是提示压缩?
模型先生成一段类似百科解释的假设内容,再用这段内容去检索真实知识库。这样做的好处是,向量检索时不再依赖短问题本身,而是用语义更丰富的文本来匹配文档。
查询扩展在 RAG 流程中的位置
查询扩展通常发生在检索前,属于 query preprocessing 的一部分。
#mermaid-svg-UMxvUulZ4T3c3ibr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UMxvUulZ4T3c3ibr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UMxvUulZ4T3c3ibr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UMxvUulZ4T3c3ibr .error-icon{fill:#552222;}#mermaid-svg-UMxvUulZ4T3c3ibr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UMxvUulZ4T3c3ibr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UMxvUulZ4T3c3ibr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UMxvUulZ4T3c3ibr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UMxvUulZ4T3c3ibr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UMxvUulZ4T3c3ibr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UMxvUulZ4T3c3ibr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UMxvUulZ4T3c3ibr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UMxvUulZ4T3c3ibr .marker.cross{stroke:#333333;}#mermaid-svg-UMxvUulZ4T3c3ibr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UMxvUulZ4T3c3ibr p{margin:0;}#mermaid-svg-UMxvUulZ4T3c3ibr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UMxvUulZ4T3c3ibr .cluster-label text{fill:#333;}#mermaid-svg-UMxvUulZ4T3c3ibr .cluster-label span{color:#333;}#mermaid-svg-UMxvUulZ4T3c3ibr .cluster-label span p{background-color:transparent;}#mermaid-svg-UMxvUulZ4T3c3ibr .label text,#mermaid-svg-UMxvUulZ4T3c3ibr span{fill:#333;color:#333;}#mermaid-svg-UMxvUulZ4T3c3ibr .node rect,#mermaid-svg-UMxvUulZ4T3c3ibr .node circle,#mermaid-svg-UMxvUulZ4T3c3ibr .node ellipse,#mermaid-svg-UMxvUulZ4T3c3ibr .node polygon,#mermaid-svg-UMxvUulZ4T3c3ibr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UMxvUulZ4T3c3ibr .rough-node .label text,#mermaid-svg-UMxvUulZ4T3c3ibr .node .label text,#mermaid-svg-UMxvUulZ4T3c3ibr .image-shape .label,#mermaid-svg-UMxvUulZ4T3c3ibr .icon-shape .label{text-anchor:middle;}#mermaid-svg-UMxvUulZ4T3c3ibr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UMxvUulZ4T3c3ibr .rough-node .label,#mermaid-svg-UMxvUulZ4T3c3ibr .node .label,#mermaid-svg-UMxvUulZ4T3c3ibr .image-shape .label,#mermaid-svg-UMxvUulZ4T3c3ibr .icon-shape .label{text-align:center;}#mermaid-svg-UMxvUulZ4T3c3ibr .node.clickable{cursor:pointer;}#mermaid-svg-UMxvUulZ4T3c3ibr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UMxvUulZ4T3c3ibr .arrowheadPath{fill:#333333;}#mermaid-svg-UMxvUulZ4T3c3ibr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UMxvUulZ4T3c3ibr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UMxvUulZ4T3c3ibr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UMxvUulZ4T3c3ibr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UMxvUulZ4T3c3ibr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UMxvUulZ4T3c3ibr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UMxvUulZ4T3c3ibr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UMxvUulZ4T3c3ibr .cluster text{fill:#333;}#mermaid-svg-UMxvUulZ4T3c3ibr .cluster span{color:#333;}#mermaid-svg-UMxvUulZ4T3c3ibr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UMxvUulZ4T3c3ibr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UMxvUulZ4T3c3ibr rect.text{fill:none;stroke-width:0;}#mermaid-svg-UMxvUulZ4T3c3ibr .icon-shape,#mermaid-svg-UMxvUulZ4T3c3ibr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UMxvUulZ4T3c3ibr .icon-shape p,#mermaid-svg-UMxvUulZ4T3c3ibr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UMxvUulZ4T3c3ibr .icon-shape .label rect,#mermaid-svg-UMxvUulZ4T3c3ibr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UMxvUulZ4T3c3ibr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UMxvUulZ4T3c3ibr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UMxvUulZ4T3c3ibr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户问题
查询理解
查询扩展
向量检索 / 关键词检索 / 混合检索
重排序
上下文拼接
大模型生成答案
它不是替代检索,而是让检索器拿到更好的查询输入。
查询扩展的好处
查询扩展最大的好处是提高召回率,也就是让系统更容易把相关文档找出来。尤其是在企业知识库中,文档往往来自不同部门、不同作者,表达方式不统一,查询扩展可以显著缓解词汇不匹配问题。
其次,它可以增强语义覆盖。用户的一个问题可能涉及多个子问题,扩展后可以从多个方向检索,避免只命中单一角度的资料。
另外,它还能提升最终回答的完整性。因为召回文档更全面,生成模型能获得更充分的上下文,答案通常会更准确、更有依据。
查询扩展的风险
查询扩展并不是越多越好。如果扩展过度,可能会引入无关词,导致检索结果变"散",甚至把不相关文档召回进来。
例如用户问:
text
苹果电脑怎么截图?
如果系统把"苹果"扩展成"水果、营养、种植",检索结果就会明显跑偏。
所以查询扩展要控制范围,最好结合领域词典、用户意图识别、置信度判断和重排序机制,避免扩展导致噪声增加。
总结
查询扩展是指在 RAG 检索前,对用户原始问题进行改写和补充,例如加入同义词、相关术语、领域概念、隐含意图,或者生成多个等价查询,让检索系统能够覆盖更多可能相关的文档。它主要解决的是用户问题和知识库文档之间表达不一致的问题,比如用户说"系统很慢",文档里可能写的是"性能瓶颈"或"接口延迟"。
在 RAG 中需要查询扩展,是因为 RAG 的答案质量高度依赖检索质量。如果原始 query 太短、太口语化或缺少关键词,就容易召回不到正确文档,导致后续大模型生成答案时缺少可靠上下文。通过查询扩展,可以提高召回率、增强语义覆盖、降低漏检概率,从而提升最终答案的准确性和完整性。但查询扩展也要注意控制范围,避免扩展过度引入噪声,所以通常会配合重排序、去重和相关性过滤一起使用。
A2A 协议 与 MCP 协议的关系
A2A 和 MCP 是互补关系:MCP 解决"智能体如何调用工具和外部资源",A2A 解决"智能体如何与其他智能体协作"。**
可以把 MCP 理解成"Agent 接工具"的协议,把 A2A 理解成"Agent 接 Agent"的协议。两者并不是替代关系,而是面向智能体生态中不同层次的标准化问题。
MCP 关注工具与上下文接入
MCP,全称通常是 Model Context Protocol,主要解决模型或智能体如何以标准方式连接外部工具、数据源和上下文资源。
在一个智能体应用中,模型本身并不直接拥有业务系统能力。它需要访问数据库、搜索引擎、文件系统、Git 仓库、CRM、工单系统、知识库等外部资源。MCP 的作用就是把这些外部能力封装成标准化接口,让智能体可以用统一方式发现、调用和读取。
例如,一个客服 Agent 需要查询订单、读取用户信息、创建工单。通过 MCP,可以把"查订单""查用户资料""创建售后单"封装为工具,Agent 按照协议调用这些工具即可,不需要为每个系统单独适配一套调用方式。
所以 MCP 更像是智能体和外部工具之间的"工具连接层"。
A2A 关注智能体之间的协作
A2A,也就是 Agent-to-Agent,主要解决智能体之间如何互相发现、互相调用、协同完成任务。
在复杂业务中,一个 Agent 往往不可能承担所有能力。例如主控 Agent 负责理解用户意图,搜索 Agent 负责查资料,代码 Agent 负责编写程序,数据分析 Agent 负责处理表格,审核 Agent 负责校验结果。A2A 的作用就是让这些不同 Agent 能够通过统一协议协作,而不是每两个 Agent 之间都私下约定一套接口。
A2A 通常会关注智能体能力描述、任务创建、任务状态流转、多轮交互、结果返回等问题。它标准化的是"一个智能体如何把任务交给另一个智能体"。
所以 A2A 更像是智能体和智能体之间的"协作通信层"。
两者的核心区别
| 对比项 | MCP | A2A |
|---|---|---|
| 连接对象 | Agent 与工具、数据源、外部系统 | Agent 与 Agent |
| 核心问题 | 如何标准化调用工具和获取上下文 | 如何标准化发现、委派、协作和返回任务结果 |
| 典型对象 | 数据库、文件、API、搜索、知识库、业务系统 | 搜索 Agent、代码 Agent、客服 Agent、分析 Agent |
| 交互粒度 | 工具调用,通常是结构化输入输出 | 任务协作,可能包含多轮对话和状态流转 |
| 角色定位 | 工具能力层 | 多智能体协作层 |
两者如何一起工作?
在真实的智能体系统中,A2A 和 MCP 经常会同时出现。
比如用户提出一个复杂需求:
text
帮我分析最近一个月的销售数据,并生成一份经营建议。
主控 Agent 可以通过 A2A 把任务分发给数据分析 Agent;数据分析 Agent 再通过 MCP 调用数据库工具读取销售数据,通过 MCP 调用报表工具生成图表;完成后,数据分析 Agent 通过 A2A 把分析结果返回给主控 Agent;主控 Agent 再交给写作 Agent 生成最终报告。
这个流程可以理解为:
#mermaid-svg-Z5tZaKAgZrLgzguA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Z5tZaKAgZrLgzguA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Z5tZaKAgZrLgzguA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Z5tZaKAgZrLgzguA .error-icon{fill:#552222;}#mermaid-svg-Z5tZaKAgZrLgzguA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Z5tZaKAgZrLgzguA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Z5tZaKAgZrLgzguA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Z5tZaKAgZrLgzguA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Z5tZaKAgZrLgzguA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Z5tZaKAgZrLgzguA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Z5tZaKAgZrLgzguA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Z5tZaKAgZrLgzguA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Z5tZaKAgZrLgzguA .marker.cross{stroke:#333333;}#mermaid-svg-Z5tZaKAgZrLgzguA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Z5tZaKAgZrLgzguA p{margin:0;}#mermaid-svg-Z5tZaKAgZrLgzguA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Z5tZaKAgZrLgzguA .cluster-label text{fill:#333;}#mermaid-svg-Z5tZaKAgZrLgzguA .cluster-label span{color:#333;}#mermaid-svg-Z5tZaKAgZrLgzguA .cluster-label span p{background-color:transparent;}#mermaid-svg-Z5tZaKAgZrLgzguA .label text,#mermaid-svg-Z5tZaKAgZrLgzguA span{fill:#333;color:#333;}#mermaid-svg-Z5tZaKAgZrLgzguA .node rect,#mermaid-svg-Z5tZaKAgZrLgzguA .node circle,#mermaid-svg-Z5tZaKAgZrLgzguA .node ellipse,#mermaid-svg-Z5tZaKAgZrLgzguA .node polygon,#mermaid-svg-Z5tZaKAgZrLgzguA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Z5tZaKAgZrLgzguA .rough-node .label text,#mermaid-svg-Z5tZaKAgZrLgzguA .node .label text,#mermaid-svg-Z5tZaKAgZrLgzguA .image-shape .label,#mermaid-svg-Z5tZaKAgZrLgzguA .icon-shape .label{text-anchor:middle;}#mermaid-svg-Z5tZaKAgZrLgzguA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Z5tZaKAgZrLgzguA .rough-node .label,#mermaid-svg-Z5tZaKAgZrLgzguA .node .label,#mermaid-svg-Z5tZaKAgZrLgzguA .image-shape .label,#mermaid-svg-Z5tZaKAgZrLgzguA .icon-shape .label{text-align:center;}#mermaid-svg-Z5tZaKAgZrLgzguA .node.clickable{cursor:pointer;}#mermaid-svg-Z5tZaKAgZrLgzguA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Z5tZaKAgZrLgzguA .arrowheadPath{fill:#333333;}#mermaid-svg-Z5tZaKAgZrLgzguA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Z5tZaKAgZrLgzguA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Z5tZaKAgZrLgzguA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z5tZaKAgZrLgzguA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Z5tZaKAgZrLgzguA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z5tZaKAgZrLgzguA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Z5tZaKAgZrLgzguA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Z5tZaKAgZrLgzguA .cluster text{fill:#333;}#mermaid-svg-Z5tZaKAgZrLgzguA .cluster span{color:#333;}#mermaid-svg-Z5tZaKAgZrLgzguA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Z5tZaKAgZrLgzguA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Z5tZaKAgZrLgzguA rect.text{fill:none;stroke-width:0;}#mermaid-svg-Z5tZaKAgZrLgzguA .icon-shape,#mermaid-svg-Z5tZaKAgZrLgzguA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z5tZaKAgZrLgzguA .icon-shape p,#mermaid-svg-Z5tZaKAgZrLgzguA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Z5tZaKAgZrLgzguA .icon-shape .label rect,#mermaid-svg-Z5tZaKAgZrLgzguA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z5tZaKAgZrLgzguA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Z5tZaKAgZrLgzguA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Z5tZaKAgZrLgzguA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} A2A 分派任务
MCP 调用
MCP 调用
A2A 返回结果
A2A 分派任务
A2A 返回报告
用户
主控 Agent
数据分析 Agent
数据库工具
报表工具
写作 Agent
在这个例子中,A2A 负责 Agent 之间的任务分工,MCP 负责 Agent 对外部工具和数据的调用。
可以用一个类比理解
如果把智能体系统看成一家公司:
MCP 像是员工使用办公系统的标准方式,比如查数据库、发邮件、调 CRM、读文档。它解决的是"员工怎么使用工具"。
A2A 像是员工之间的协作流程,比如项目经理把任务分给设计师、工程师、测试人员,大家按任务状态协同推进。它解决的是"员工之间怎么协作"。
两者服务的对象不同,但目标一致:降低集成成本,提高系统之间的互操作性。
总结
A2A 和 MCP 是互补而不是竞争关系。MCP 主要面向智能体与工具、数据源、外部系统之间的连接,解决模型如何标准化获取上下文和调用工具的问题;A2A 主要面向智能体与智能体之间的通信协作,解决不同 Agent 如何发现彼此能力、创建任务、传递状态、多轮交互并返回结果的问题。
在实际应用中,一个 Agent 可以通过 MCP 调用数据库、文件系统、API、搜索引擎等工具,也可以通过 A2A 调用另一个具备特定能力的 Agent。简单来说,MCP 是"Agent-to-Tool",A2A 是"Agent-to-Agent"。两者共同构成智能体生态的互操作基础:MCP 打通工具能力,A2A 打通智能体协作。
什么自查询?为什么在 RAG 中需要自查询?
自查询是让 RAG 系统自动把用户的自然语言问题拆成"语义检索条件"和"结构化过滤条件",从而同时做到语义相关和条件精准。
在 RAG 中,自查询通常指 Self-Query Retrieval。它不是让用户手动写过滤条件,而是由系统自动理解用户问题里隐藏的时间、作者、类型、标签、部门、价格、地域、版本等限制条件,再把这些条件转换成向量数据库或检索系统能执行的结构化查询。
比如用户问:
text
找一下 2025 年鸭鸭写的用户报告
普通向量检索可能只会拿"用户报告"去做语义相似度匹配,结果召回很多"用户报告"相关内容,但年份可能不是 2025,作者也可能不是鸭鸭。
自查询会把这个问题拆成两部分:
text
语义查询:用户报告
元数据过滤:year = 2025 AND author = 鸭鸭
这样检索时不仅要求内容语义相关,还要求元数据条件匹配。
为什么 RAG 中需要自查询?
RAG 的检索效果不仅取决于语义相似度,还取决于能不能把用户问题中的限定条件准确用起来。现实业务问题通常不是简单问"什么是报销流程",而是会带上很多约束,比如"2024 年之后发布的报销制度""财务部的差旅报销文档""适用于上海分公司的合同模板""价格低于 1000 的供应商方案"。
如果只依赖向量检索,系统会主要关注语义相似度,而不擅长严格处理这些结构化条件。结果就是文档"看起来相关",但时间、作者、部门、版本、地域、权限、标签并不符合要求。自查询的价值,就是把自然语言里的约束条件显式提取出来,并用于检索过滤。
自查询解决的核心问题
| 问题 | 普通向量检索的表现 | 自查询的改进 |
|---|---|---|
| 时间条件不准确 | 召回旧文档或过期版本 | 提取年份、日期范围做过滤 |
| 作者或部门不匹配 | 内容相关但来源不对 | 按 author、department 过滤 |
| 文档类型混乱 | 报告、制度、FAQ 混在一起 | 按 doc_type 过滤 |
| 标签或业务范围不准 | 召回跨业务线内容 | 按 tag、category、region 过滤 |
| 数值条件难处理 | 很难理解"大于、小于、范围" | 转成结构化比较条件 |
自查询的典型工作流程
自查询一般发生在 RAG 的检索前阶段。它先理解用户问题,再生成检索器可以执行的查询结构。
#mermaid-svg-FliO8Tmm27xFAeWz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FliO8Tmm27xFAeWz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FliO8Tmm27xFAeWz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FliO8Tmm27xFAeWz .error-icon{fill:#552222;}#mermaid-svg-FliO8Tmm27xFAeWz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FliO8Tmm27xFAeWz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FliO8Tmm27xFAeWz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FliO8Tmm27xFAeWz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FliO8Tmm27xFAeWz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FliO8Tmm27xFAeWz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FliO8Tmm27xFAeWz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FliO8Tmm27xFAeWz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FliO8Tmm27xFAeWz .marker.cross{stroke:#333333;}#mermaid-svg-FliO8Tmm27xFAeWz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FliO8Tmm27xFAeWz p{margin:0;}#mermaid-svg-FliO8Tmm27xFAeWz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FliO8Tmm27xFAeWz .cluster-label text{fill:#333;}#mermaid-svg-FliO8Tmm27xFAeWz .cluster-label span{color:#333;}#mermaid-svg-FliO8Tmm27xFAeWz .cluster-label span p{background-color:transparent;}#mermaid-svg-FliO8Tmm27xFAeWz .label text,#mermaid-svg-FliO8Tmm27xFAeWz span{fill:#333;color:#333;}#mermaid-svg-FliO8Tmm27xFAeWz .node rect,#mermaid-svg-FliO8Tmm27xFAeWz .node circle,#mermaid-svg-FliO8Tmm27xFAeWz .node ellipse,#mermaid-svg-FliO8Tmm27xFAeWz .node polygon,#mermaid-svg-FliO8Tmm27xFAeWz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FliO8Tmm27xFAeWz .rough-node .label text,#mermaid-svg-FliO8Tmm27xFAeWz .node .label text,#mermaid-svg-FliO8Tmm27xFAeWz .image-shape .label,#mermaid-svg-FliO8Tmm27xFAeWz .icon-shape .label{text-anchor:middle;}#mermaid-svg-FliO8Tmm27xFAeWz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FliO8Tmm27xFAeWz .rough-node .label,#mermaid-svg-FliO8Tmm27xFAeWz .node .label,#mermaid-svg-FliO8Tmm27xFAeWz .image-shape .label,#mermaid-svg-FliO8Tmm27xFAeWz .icon-shape .label{text-align:center;}#mermaid-svg-FliO8Tmm27xFAeWz .node.clickable{cursor:pointer;}#mermaid-svg-FliO8Tmm27xFAeWz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FliO8Tmm27xFAeWz .arrowheadPath{fill:#333333;}#mermaid-svg-FliO8Tmm27xFAeWz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FliO8Tmm27xFAeWz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FliO8Tmm27xFAeWz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FliO8Tmm27xFAeWz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FliO8Tmm27xFAeWz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FliO8Tmm27xFAeWz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FliO8Tmm27xFAeWz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FliO8Tmm27xFAeWz .cluster text{fill:#333;}#mermaid-svg-FliO8Tmm27xFAeWz .cluster span{color:#333;}#mermaid-svg-FliO8Tmm27xFAeWz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FliO8Tmm27xFAeWz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FliO8Tmm27xFAeWz rect.text{fill:none;stroke-width:0;}#mermaid-svg-FliO8Tmm27xFAeWz .icon-shape,#mermaid-svg-FliO8Tmm27xFAeWz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FliO8Tmm27xFAeWz .icon-shape p,#mermaid-svg-FliO8Tmm27xFAeWz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FliO8Tmm27xFAeWz .icon-shape .label rect,#mermaid-svg-FliO8Tmm27xFAeWz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FliO8Tmm27xFAeWz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FliO8Tmm27xFAeWz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FliO8Tmm27xFAeWz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户问题
查询解析
提取语义查询
提取元数据条件
向量检索
结构化过滤
候选文档
重排序
拼接上下文
大模型生成答案
一个更具体的例子:
text
用户问题:找 2024 年后发布的 RAG 分块策略文章
自查询结果可能是:
json
{
"query": "RAG 分块策略",
"filter": {
"publish_year": { "$gte": 2024 },
"doc_type": "article"
}
}
系统随后会用 query 做语义检索,同时用 filter 限制候选文档范围。
自查询和查询扩展的区别
自查询和查询扩展都属于查询理解与查询优化,但重点不同。
| 对比项 | 查询扩展 | 自查询 |
|---|---|---|
| 目标 | 提高召回率 | 提高条件匹配准确性 |
| 做法 | 补充同义词、相关词、多个 query | 提取结构化过滤条件 |
| 关注点 | 语义覆盖更广 | 过滤条件更准 |
| 例子 | "系统慢"扩展为"卡顿、延迟、性能瓶颈" | "2025 年的性能报告"提取 year=2025 |
| 风险 | 扩展过度引入噪声 | 条件解析错误导致漏召回 |
简单说,查询扩展是"把问题说得更丰富",自查询是"把问题里的限制条件拆出来"。
自查询适合哪些场景?
自查询特别适合文档带有丰富元数据的 RAG 系统。例如企业知识库中,每篇文档通常会有发布时间、部门、作者、文档类型、业务线、版本号、权限级别等字段。用户提问时经常会用这些字段做限制,自查询就能把这些条件自动转成过滤语句。
在电商场景中,用户可能问"找价格低于 500 的蓝牙耳机评测";在客服场景中,用户可能问"查询华东区 2025 年的售后政策";在研发知识库中,用户可能问"找 Java 相关、最近半年更新的性能优化文档"。这些问题都不仅需要语义匹配,还需要结构化过滤。
自查询的价值
自查询的最大价值是减少"语义相关但条件错误"的召回结果。它能让 RAG 系统从"相似内容检索"升级为"语义检索 + 条件过滤"的组合检索。
同时,自查询还能提升用户体验。用户不需要手动选择筛选器,也不需要学习复杂查询语法,只要用自然语言表达需求,系统就能自动识别条件并执行。
不过,自查询也依赖元数据质量。如果文档没有维护好作者、时间、类型、标签等字段,或者字段命名不统一,自查询的效果会明显下降。因此,在真实项目中,自查询通常要配合文档元数据规范、字段映射、查询解析校验和兜底策略一起使用。
总结
自查询是 RAG 中一种查询理解机制,它会自动解析用户自然语言问题,把问题拆成两部分:一部分是用于语义匹配的查询内容,另一部分是用于过滤的结构化条件。比如用户问"2025 年鸭鸭写的用户报告",系统会把"用户报告"作为语义查询,把"作者=鸭鸭、时间=2025"作为元数据过滤条件。
RAG 中需要自查询,是因为普通向量检索主要依赖语义相似度,容易召回内容相关但条件不匹配的文档,比如时间不对、作者不对、类型不对、部门不对。自查询通过"语义检索 + 元数据过滤"的方式,让检索结果既相关又准确,特别适合企业知识库、商品检索、制度文档、报告检索等带有丰富元数据的场景。
什么提示压缩?为什么在 RAG 中需要提示压缩?
提示压缩就是在 RAG 把检索结果交给大模型之前,先对文档内容做筛选、裁剪、摘要和重组,只保留与用户问题最相关的信息,避免上下文过长、噪声过多、成本过高。
在 RAG 中,检索系统通常会召回多个文档片段,但这些内容并不一定都适合直接塞进提示词。它们可能太长、重复、相关性不均、包含目录页或无关段落,也可能只有其中几句话真正能回答用户问题。提示压缩的作用,就是把"检索到的原始上下文"压缩成"更短、更准、更干净的模型输入"。
比如用户问:
text
RAG 中如何优化召回率?
系统检索到一篇 10 页的 RAG 技术白皮书,其中包含架构介绍、产品定价、部署说明、实验数据和召回优化章节。提示压缩不会把整篇文档都交给模型,而是只保留和"召回率优化"相关的段落,例如查询扩展、混合检索、Embedding 模型选择、分块策略、重排序等内容。
提示压缩在 RAG 流程中的位置
提示压缩一般发生在"检索/重排序之后、生成之前"。也就是说,它不是替代检索,而是对检索结果做最后一层上下文整理。
#mermaid-svg-09G3iHARH8dP72N5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-09G3iHARH8dP72N5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-09G3iHARH8dP72N5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-09G3iHARH8dP72N5 .error-icon{fill:#552222;}#mermaid-svg-09G3iHARH8dP72N5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-09G3iHARH8dP72N5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-09G3iHARH8dP72N5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-09G3iHARH8dP72N5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-09G3iHARH8dP72N5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-09G3iHARH8dP72N5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-09G3iHARH8dP72N5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-09G3iHARH8dP72N5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-09G3iHARH8dP72N5 .marker.cross{stroke:#333333;}#mermaid-svg-09G3iHARH8dP72N5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-09G3iHARH8dP72N5 p{margin:0;}#mermaid-svg-09G3iHARH8dP72N5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-09G3iHARH8dP72N5 .cluster-label text{fill:#333;}#mermaid-svg-09G3iHARH8dP72N5 .cluster-label span{color:#333;}#mermaid-svg-09G3iHARH8dP72N5 .cluster-label span p{background-color:transparent;}#mermaid-svg-09G3iHARH8dP72N5 .label text,#mermaid-svg-09G3iHARH8dP72N5 span{fill:#333;color:#333;}#mermaid-svg-09G3iHARH8dP72N5 .node rect,#mermaid-svg-09G3iHARH8dP72N5 .node circle,#mermaid-svg-09G3iHARH8dP72N5 .node ellipse,#mermaid-svg-09G3iHARH8dP72N5 .node polygon,#mermaid-svg-09G3iHARH8dP72N5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-09G3iHARH8dP72N5 .rough-node .label text,#mermaid-svg-09G3iHARH8dP72N5 .node .label text,#mermaid-svg-09G3iHARH8dP72N5 .image-shape .label,#mermaid-svg-09G3iHARH8dP72N5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-09G3iHARH8dP72N5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-09G3iHARH8dP72N5 .rough-node .label,#mermaid-svg-09G3iHARH8dP72N5 .node .label,#mermaid-svg-09G3iHARH8dP72N5 .image-shape .label,#mermaid-svg-09G3iHARH8dP72N5 .icon-shape .label{text-align:center;}#mermaid-svg-09G3iHARH8dP72N5 .node.clickable{cursor:pointer;}#mermaid-svg-09G3iHARH8dP72N5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-09G3iHARH8dP72N5 .arrowheadPath{fill:#333333;}#mermaid-svg-09G3iHARH8dP72N5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-09G3iHARH8dP72N5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-09G3iHARH8dP72N5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-09G3iHARH8dP72N5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-09G3iHARH8dP72N5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-09G3iHARH8dP72N5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-09G3iHARH8dP72N5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-09G3iHARH8dP72N5 .cluster text{fill:#333;}#mermaid-svg-09G3iHARH8dP72N5 .cluster span{color:#333;}#mermaid-svg-09G3iHARH8dP72N5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-09G3iHARH8dP72N5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-09G3iHARH8dP72N5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-09G3iHARH8dP72N5 .icon-shape,#mermaid-svg-09G3iHARH8dP72N5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-09G3iHARH8dP72N5 .icon-shape p,#mermaid-svg-09G3iHARH8dP72N5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-09G3iHARH8dP72N5 .icon-shape .label rect,#mermaid-svg-09G3iHARH8dP72N5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-09G3iHARH8dP72N5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-09G3iHARH8dP72N5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-09G3iHARH8dP72N5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户问题
查询理解 / 查询扩展
检索相关文档
重排序
提示压缩
构造 Prompt
大模型生成答案
这个阶段决定了模型最终能看到什么内容。检索解决"找哪些材料",重排序解决"哪些材料更重要",提示压缩解决"哪些内容真正值得放进上下文"。
为什么 RAG 中需要提示压缩?
1. 上下文窗口有限
大模型的上下文窗口再大,也不是无限的。RAG 一次检索可能召回几十个 chunk,真实业务文档还可能包含长篇制度、合同、日志、技术规范、会议纪要等。如果不做压缩,提示词很容易超出模型上下文限制,或者挤占用户问题、系统指令和输出空间。
即使模型支持很长上下文,也不意味着应该把所有内容都塞进去。过长输入会增加延迟和成本,还可能让模型注意力分散。
2. 检索结果里有噪声
检索系统召回的是"相似内容",不一定都是"有用内容"。比如一个 chunk 可能只是因为出现了关键词而被召回,但真正回答问题的信息很少。还有些文档包含页眉页脚、目录、免责声明、重复模板、导航文本、广告内容等,这些都会干扰模型判断。
提示压缩可以过滤掉这些噪声,让模型看到更干净的证据。
3. 降低生成成本和延迟
大模型通常按输入和输出 token 消耗计费,输入越长,成本越高,响应越慢。提示压缩可以减少无效 token,把预算集中在真正有价值的信息上。
在高并发的企业 RAG 系统中,这一点很关键。比如客服问答、知识库助手、代码助手,如果每次都把大量原文塞给模型,成本和延迟都会快速上升。
4. 提升答案准确性
很多人以为上下文越多越好,但在 RAG 中并不总是这样。过多无关或弱相关内容会稀释关键信息,甚至导致模型引用错误段落、混淆版本、产生不一致结论。
提示压缩可以把最相关的事实、数据、步骤、结论保留下来,提高模型基于证据回答的概率。
5. 适配复杂多文档场景
当问题需要综合多个来源时,直接拼接原文容易出现重复、冲突和结构混乱。提示压缩可以对多个文档片段进行去重、归并和重组,让上下文更像一份面向问题的"证据摘要"。
例如用户问"对比 A、B 两个方案的优缺点",压缩阶段可以分别提取 A 方案的成本、性能、风险,以及 B 方案的成本、性能、风险,再组织成更适合模型生成对比答案的上下文。
常见的提示压缩方法
| 方法 | 做法 | 适用场景 |
|---|---|---|
| 相关句子抽取 | 只保留与问题高度相关的句子 | 文档较长但答案集中在少数句子 |
| 摘要压缩 | 用模型把长文档压缩成短摘要 | 长报告、会议纪要、政策文档 |
| 关键词/实体保留 | 保留关键术语、数值、时间、主体 | 技术文档、合同、财务数据 |
| 去重合并 | 删除重复 chunk,合并相似信息 | 多文档召回、知识库重复内容多 |
| 结构化提取 | 按字段提取条件、步骤、结论、风险 | FAQ、制度、表格、方案对比 |
| 基于评分裁剪 | 按相关性分数或 token 预算截断 | 检索结果较多、上下文预算有限 |
提示压缩和重排序的区别
提示压缩经常和重排序一起出现,但两者解决的问题不同。
| 对比项 | 重排序 Rerank | 提示压缩 Prompt Compression |
|---|---|---|
| 处理对象 | 多个候选文档或 chunk | chunk 内部内容和最终上下文 |
| 目标 | 判断哪些文档更相关 | 判断哪些内容值得保留 |
| 输出 | 排好序的文档列表 | 精简后的上下文文本 |
| 关注粒度 | 文档级、片段级 | 句子级、段落级、信息点级 |
| 典型位置 | 检索之后 | 重排序之后、生成之前 |
简单说,重排序是"选哪些文档",提示压缩是"文档里保留哪些内容"。
提示压缩的风险
提示压缩也不是越狠越好。如果压缩过度,可能丢失关键上下文,导致模型无法正确理解原文;如果摘要模型不可靠,还可能在压缩阶段引入幻觉,把原文没有的信息写进去。
因此,真实系统中通常会保留必要的引用信息,比如文档来源、段落 ID、标题、时间、版本号等,方便生成阶段溯源。同时,对于数字、条款、代码、法律文本等高精度内容,尽量使用抽取式压缩,而不是自由摘要式压缩,以减少信息失真。
总结
提示压缩是指在 RAG 系统把检索结果输入大模型之前,对召回的文档内容进行精简处理,比如过滤无关段落、删除重复内容、提取关键句、保留核心事实,或者把长文档压缩成面向问题的摘要。它的目标是在不丢失关键信息的前提下,让最终 prompt 更短、更准、更干净。
RAG 中需要提示压缩,主要是因为检索出来的内容往往太长、太杂、噪声多,而大模型上下文窗口和 token 成本都是有限的。如果直接把所有检索结果塞给模型,不仅容易超出上下文限制,还会增加成本和延迟,甚至让模型被无关信息干扰,生成不准确答案。提示压缩通过减少无效 token、突出关键证据,可以提升生成质量、降低调用成本,并让 RAG 在多文档、长文档场景下更稳定。
如何进行 RAG 调优后的效果评估?请给出真实应用场景中采用的效果评估标准与方法
RAG 调优后的效果评估要同时看检索质量、生成质量、业务效果和系统性能,不能只看答案"像不像"。真实项目中通常会构建标准测试集,用离线指标评估检索和生成效果,再结合人工评审、线上 A/B 测试、用户反馈和成本延迟指标综合判断是否调优成功。
RAG 调优后的效果评估,本质上是判断系统在"能不能找对资料、能不能基于资料答对问题、能不能稳定低成本地服务真实用户"这几个方面有没有提升。真实应用中,比较成熟的评估方式通常分为离线评估和在线评估两层:离线评估用于快速比较不同方案,在线评估用于验证真实用户场景下的效果。
一、先建立评估集
在评估 RAG 调优效果之前,必须先准备一套相对稳定的评估集,否则很难判断优化是否真的有效。
评估集一般包括用户问题、标准答案、相关文档、业务标签和难度等级。例如在企业知识库问答场景中,可以从客服历史问题、产品文档、工单系统、用户搜索日志中抽取真实问题,再由业务专家标注正确答案和应该命中的知识片段。
一个比较完整的 RAG 评估样本通常包含:
| 字段 | 说明 |
|---|---|
| query | 用户问题 |
| golden answer | 参考答案 |
| golden documents | 正确相关文档或知识片段 |
| category | 问题类型,如产品咨询、故障排查、政策解释 |
| difficulty | 简单、复杂、多跳、模糊问题 |
| expected behavior | 是否应该回答、拒答、追问或提示无资料 |
比如在企业内部知识库场景中,不能只评估"年假有几天"这种简单问题,还要覆盖多跳问题,例如"入职不满一年且在上海办公的员工,病假工资怎么算"。这类问题更能暴露 RAG 系统在召回、重排、上下文拼接和生成推理上的问题。
二、检索质量评估
RAG 的第一步是检索。如果检索不到正确资料,后面的生成模型再强也容易胡编。因此调优后的第一类评估指标是检索质量。
1. Precision@K
Precision@K 表示前 K 个检索结果中,有多少是相关文档。
例如系统返回前 5 个文档,其中 3 个和问题相关,那么:
Precision@5=35=60% Precision@5 = \frac{3}{5} = 60\% Precision@5=53=60%
这个指标适合评估检索结果的"准确性"。如果 Precision@K 很低,说明系统虽然召回了很多内容,但噪声太多,容易把无关信息塞进上下文,导致模型回答跑偏。
在真实场景中,客服知识库、法律条文问答、医疗指南问答都非常看重 Precision@K,因为错误文档进入上下文会直接影响答案可靠性。
2. Recall@K
Recall@K 表示前 K 个结果覆盖了多少应该被召回的相关文档。
例如某个问题在知识库中有 10 个相关文档,系统前 5 个结果中找到了 4 个,那么:
Recall@5=410=40% Recall@5 = \frac{4}{10} = 40\% Recall@5=104=40%
这个指标适合评估"有没有漏掉关键资料"。如果 Recall@K 很低,说明系统经常找不到关键证据,最终答案可能不完整。
在真实应用中,技术文档问答、故障排查、合同审查等场景通常很重视 Recall,因为一个问题可能需要多个知识片段共同支持。
3. MRR
MRR,即 Mean Reciprocal Rank,用来衡量第一个相关文档排在多靠前。
如果第一个相关文档排第 1,得分是 1;排第 2,得分是 1/2;排第 5,得分是 1/5。多个问题取平均值。
MRR 对问答系统很重要,因为大模型通常更关注上下文靠前的内容。如果正确文档虽然被召回了,但排在很后面,实际生成时仍然可能被忽略。
4. NDCG@K
NDCG@K 不仅看相关文档有没有出现,还看它们的排序是否合理。高度相关的文档排得越靠前,分数越高。
这个指标适合评估重排模型、混合检索、向量检索调参后的效果。例如引入 reranker 之后,如果 NDCG@10 明显提高,说明相关内容整体排序更合理。
5. Hit Rate@K
Hit Rate@K 表示前 K 个检索结果中是否至少包含一个正确文档。
例如用户问"怎么重置密码",只要前 5 个结果里有一篇正确的"密码重置指南",就算命中。
这个指标在业务问答场景中很直观,尤其适合快速衡量 RAG 是否"至少找到了能回答问题的资料"。
三、生成质量评估
检索正确不代表最终答案正确。RAG 还需要评估生成结果是否准确、完整、忠实、可读。
1. 答案准确性
答案准确性是最核心的生成指标,判断模型回答是否符合标准答案或业务事实。
在真实项目中,通常会采用人工评审和自动评估结合的方式。人工评审由业务专家按照 1 到 5 分打分,例如:
| 分数 | 标准 |
|---|---|
| 5 分 | 完全正确,覆盖关键点,无明显遗漏 |
| 4 分 | 基本正确,有轻微遗漏 |
| 3 分 | 部分正确,但不完整 |
| 2 分 | 有明显错误 |
| 1 分 | 完全错误或答非所问 |
例如在人力资源政策问答中,用户问"试用期员工可以休年假吗",答案不仅要说"可以或不可以",还要结合公司制度说明适用条件、天数计算方式和审批流程。
2. 忠实性 / Groundedness
忠实性指答案是否严格基于检索到的资料生成,是否存在幻觉。
这是 RAG 评估中非常关键的指标。因为 RAG 的目标不是让模型凭空回答,而是让模型基于知识库回答。
例如检索资料中只写了"报销审批周期通常为 3 到 5 个工作日",模型却回答"财务会在 24 小时内打款",这就是不忠实。
真实场景中可以使用以下标准评估:
| 维度 | 判断方式 |
|---|---|
| 是否有依据 | 答案中的关键结论能否在引用文档中找到 |
| 是否过度推断 | 是否加入了文档没有提到的信息 |
| 是否引用正确 | 引用来源是否真正支持答案 |
| 是否冲突 | 答案是否与文档内容矛盾 |
在金融、医疗、法律、企业制度类 RAG 中,忠实性通常比语言流畅度更重要。
3. 完整性
完整性指答案是否覆盖了用户问题需要的所有关键点。
例如用户问"RAG 调优后如何评估效果",只回答 Precision 和 Recall 是不完整的,因为还需要评估生成质量、延迟、成本、线上转化、用户满意度等。
完整性常用于复杂问题、多步骤问题、政策解释类问题。真实项目中,评估人员通常会先定义标准答案要点,然后检查模型答案覆盖了多少要点。
4. 相关性
相关性指回答是否紧扣用户问题,而不是泛泛而谈。
例如用户问"如何评估 RAG 的检索效果",模型却大篇幅解释向量数据库原理,虽然内容正确,但相关性较差。
相关性可以通过人工评分,也可以用 LLM-as-Judge 自动评估。
5. 可读性和结构化程度
真实业务系统中,答案不仅要正确,还要用户容易理解。
例如客服场景下,答案最好清晰、简短、可执行;技术支持场景下,答案要分步骤;法律或制度问答中,答案要有依据、有引用、有风险提示。
可读性可以从语言清晰度、结构、冗余程度、格式规范等方面评估。
四、业务效果评估
RAG 最终是为业务服务的,所以不能只看算法指标,还要看业务指标。
不同场景的业务指标不同。
在智能客服场景中,常见指标包括问题解决率、人工转接率、用户满意度、重复提问率和会话完成率。如果 RAG 调优后答案更准确,理论上人工转接率应该下降,用户满意度应该提升。
在企业知识库场景中,常见指标包括员工自助解决率、搜索成功率、平均查找时间、知识命中率。如果员工原来需要 10 分钟查制度,现在 1 分钟就能得到可信答案,这就是明显收益。
在电商导购场景中,常见指标包括点击率、转化率、加购率、退款咨询减少率。如果 RAG 能准确回答商品规格、售后政策、兼容性问题,通常能提升购买决策效率。
在研发知识库场景中,常见指标包括问题定位时间、工单处理时长、重复工单比例、文档复用率。比如调优后工程师能更快找到某个报错的历史解决方案,说明系统有实际价值。
五、系统性能评估
RAG 系统上线后,还必须评估性能和成本。一个答案再好,如果响应时间太长、成本太高,也很难在真实业务中落地。
常见系统指标包括:
| 指标 | 含义 |
|---|---|
| 平均响应时间 | 用户从提问到收到答案的平均耗时 |
| P95 / P99 延迟 | 大部分用户在高分位情况下的响应速度 |
| Token 消耗 | 每次问答消耗的输入和输出 Token |
| 检索耗时 | 向量检索、关键词检索、重排等环节耗时 |
| 生成耗时 | 大模型生成答案的耗时 |
| 单次问答成本 | 每次请求的模型、存储、检索和服务成本 |
| 系统稳定性 | 错误率、超时率、服务可用性 |
例如调优后 Recall@10 提升了 5%,但每次请求都要多调用一个大型 reranker,导致 P95 延迟从 2 秒变成 8 秒,线上用户体验可能反而变差。因此真实项目中要综合判断效果、速度和成本。
六、真实应用中的评估方法
1. 离线评估
离线评估适合在上线前比较不同方案。
例如要比较三种方案:
| 方案 | 配置 |
|---|---|
| A | 原始向量检索 |
| B | 向量检索 + BM25 混合检索 |
| C | 向量检索 + BM25 + reranker |
可以在同一套评估集上分别跑三套方案,然后比较 Precision@5、Recall@10、MRR、NDCG、答案准确率、忠实性评分、平均延迟和平均成本。
如果方案 C 的准确率提升明显,但延迟和成本也明显增加,就要结合业务场景决定是否采用。比如法律问答更重视准确性,可能接受较高成本;客服机器人更重视响应速度和成本,可能选择折中方案。
2. 人工评审
人工评审是 RAG 评估中非常重要的一环,尤其适合高风险业务场景。
评审人员通常包括业务专家、产品经理、算法工程师和一线客服。每条回答可以从以下维度打分:
| 维度 | 评分重点 |
|---|---|
| 正确性 | 是否回答正确 |
| 完整性 | 是否覆盖关键点 |
| 忠实性 | 是否基于资料,没有幻觉 |
| 可读性 | 是否表达清晰 |
| 可执行性 | 用户是否知道下一步怎么做 |
| 风险性 | 是否存在误导或合规风险 |
例如在保险理赔问答中,模型不仅要答对,还不能承诺文档中没有写明的赔付结果,否则会带来业务风险。
3. LLM-as-Judge 自动评估
当评估数据量很大时,可以使用另一个大模型作为评审器,对答案进行自动打分。
常见方式是给评审模型输入用户问题、标准答案、检索文档和模型回答,让它判断回答是否正确、是否有依据、是否遗漏关键点。
这种方法效率高,适合持续集成和大规模回归测试。但它不能完全替代人工评审,尤其在强合规、高风险场景中,仍然需要人工抽检。
4. A/B 测试
上线后可以进行 A/B 测试,把一部分流量分给旧版本,一部分流量分给新版本,对比真实用户行为。
例如在客服场景中,对比新旧 RAG 系统的:
| 指标 | 期望变化 |
|---|---|
| 首答解决率 | 提升 |
| 人工转接率 | 下降 |
| 用户满意度 | 提升 |
| 平均会话轮次 | 下降或更合理 |
| 负反馈率 | 下降 |
| 平均响应时间 | 不明显变差 |
A/B 测试能发现离线评估发现不了的问题。比如离线测试中答案准确率提升了,但线上用户满意度没有提升,可能是答案太长、语气不自然、引用太复杂,或者用户真实问题和测试集分布不一致。
5. 日志分析和反馈闭环
真实 RAG 系统上线后,需要持续收集日志和用户反馈。
常见分析内容包括:哪些问题没有命中文档,哪些答案被用户点了"无帮助",哪些问题触发人工转接,哪些文档经常被引用,哪些文档长期无人命中,哪些答案出现高风险幻觉。
这些日志可以反过来指导下一轮调优,例如:
| 问题现象 | 可能优化方向 |
|---|---|
| 检索不到正确文档 | 优化分块、Embedding、查询改写、混合检索 |
| 检索到了但排得靠后 | 引入 reranker 或优化排序特征 |
| 文档正确但答案错误 | 优化提示词、上下文组织、引用约束 |
| 答案太长 | 做提示压缩或输出格式约束 |
| 用户问题太模糊 | 增加澄清追问机制 |
| 无资料时胡编 | 增加拒答策略和置信度判断 |
七、真实场景示例
以企业内部制度问答 RAG 为例,调优前系统经常出现两个问题:一是用户问"异地出差住宿标准是多少"时,检索到了旧版制度;二是用户问"上海员工病假工资怎么算"时,只回答了病假流程,没有回答工资计算规则。
调优方案可能包括:清洗过期文档、增加文档版本字段、按城市和制度类型添加元数据、采用混合检索、增加 reranker、优化 prompt 要求模型必须引用来源并说明适用范围。
调优后的评估可以这样做:
| 评估层面 | 评估标准 |
|---|---|
| 检索质量 | Recall@5 从 70% 提升到 88%,MRR 从 0.62 提升到 0.81 |
| 生成质量 | 人工准确性评分从 3.6/5 提升到 4.4/5 |
| 忠实性 | 幻觉率从 12% 降到 4% |
| 业务效果 | 人工咨询转接率下降 18% |
| 用户体验 | 平均响应时间从 2.1 秒增加到 2.6 秒,仍可接受 |
| 成本 | 单次问答成本增加 8%,但客服人力成本下降更多 |
如果这些指标整体改善,就可以认为这次 RAG 调优是有效的。但如果只提升了 Recall,却导致答案变长、延迟变高、用户满意度下降,那就不能简单认为调优成功。
八、总结
面试中可以这样回答:
RAG 调优后的效果评估不能只看单一指标,我一般会从检索质量、生成质量、业务效果和系统性能四个维度综合评估。首先会构建一套包含真实用户问题、标准答案和标准相关文档的评估集,然后用 Precision@K、Recall@K、MRR、NDCG、Hit Rate@K 等指标评估检索效果,判断正确文档是否被召回以及排序是否靠前。
在生成质量上,我会评估答案准确性、完整性、相关性、忠实性和可读性,尤其关注答案是否严格基于检索内容,是否存在幻觉。对于重要业务场景,会结合人工评审和 LLM-as-Judge 自动评估,人工评审通常由业务专家按正确性、完整性、忠实性、风险性等维度打分。
上线后还会通过 A/B 测试和日志反馈评估真实业务效果,例如智能客服场景看首答解决率、人工转接率、用户满意度和负反馈率;企业知识库场景看搜索成功率、自助解决率和平均查找时间。同时还要关注系统性能,比如响应延迟、P95/P99、Token 消耗、单次问答成本和错误率。
真实项目中,我不会只因为某个离线指标提升就判断调优成功,而是会看它是否在可接受的延迟和成本范围内,稳定提升了用户问题解决率,并降低了幻觉率和人工介入成本。这样才能说明 RAG 调优真正带来了业务价值。
什么是 RAG 中的分块?为什么需要分块?
RAG 中的分块就是把长文档拆成适合检索和模型理解的小文本片段;它的核心作用是让检索更精准、上下文更可控、回答质量更稳定。
在 RAG 中,分块,也叫 Chunking,指的是把原始文档、网页、PDF、知识库内容等长文本,按照一定规则切分成多个较小的文本块。每个文本块通常包含一个相对完整的语义单元,比如一个段落、几个段落、一个标题下的小节,或者固定长度的一段文本。
RAG 的流程一般是:先把文档切成块,再为每个块生成 Embedding 向量并存入向量数据库;用户提问时,系统会把问题也转成向量,然后检索出最相关的文本块,最后把这些文本块作为上下文交给大模型生成答案。
之所以需要分块,主要有几个原因。
首先,大模型的上下文窗口是有限的。真实知识库里的文档往往很长,比如一本书、一份技术文档、几十页 PDF,不能每次用户提问都把完整文档塞给模型。分块后,只需要把和问题最相关的几个片段放进上下文中,既节省 token,也降低模型处理压力。
其次,分块可以提升检索精度。如果整篇文档作为一个检索单元,用户问一个很具体的问题时,系统可能只能召回一大篇内容,其中真正相关的信息只占很小一部分。把文档切成更小的块后,向量检索可以更精准地定位到包含答案的片段。
第三,分块可以减少噪声干扰。RAG 的目标不是把越多内容交给模型越好,而是把最相关、最有用的内容交给模型。如果召回内容太长,里面夹杂大量无关信息,模型可能会被干扰,甚至生成不准确的答案。合理分块可以让上下文更加聚焦。
第四,分块有助于控制语义完整性。好的分块不是机械地每几百字切一次,而是尽量保证一个块内部表达的是完整主题。例如按照标题、段落、列表、代码函数、章节结构来切分,可以避免把一个完整概念切断,影响后续检索和回答。
举个例子,如果有一篇关于"Redis 缓存雪崩、缓存击穿、缓存穿透"的文章,直接作为一个整体存入向量库,用户问"缓存击穿怎么解决?"时,系统可能召回整篇文章。而如果提前按小节分块,系统就能更准确地召回"缓存击穿"对应的小节,模型回答时也会更聚焦。
总结:
RAG 中的分块是指把长文档拆成多个较小的文本片段,再对每个片段做向量化并存入向量数据库。它的主要作用是解决大模型上下文长度有限的问题,同时提升检索精度,让系统能够从知识库中召回更相关、更聚焦的内容。合理分块还能减少无关信息对模型的干扰,提升最终回答的准确性和稳定性。分块时通常要在块大小、重叠窗口和语义完整性之间做平衡。
在 RAG 中,常见的分块策略有哪些?分别有什么区别?
RAG 中常见分块策略主要有固定大小分块、滑动窗口分块、自然结构分块、递归分块、语义分块和混合分块;它们的区别在于切分依据不同:有的按长度切,有的按文档结构切,有的按语义完整性切,有的兼顾多种规则。
在 RAG 中,分块策略会直接影响检索效果。分得太大,召回内容容易包含大量无关信息,影响回答精度;分得太小,又可能破坏语义完整性,导致模型拿不到完整上下文。因此,好的分块策略本质上是在"检索精度"和"语义完整性"之间做平衡。
| 分块策略 | 切分依据 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 固定大小分块 | 按字符数、词数或 token 数 | 实现简单,处理速度快 | 容易切断语义 | 大规模普通文本、快速原型 |
| 滑动窗口分块 | 固定大小 + 重叠内容 | 保留上下文连续性 | 存储和检索成本更高 | 段落连续性强的文档 |
| 自然结构分块 | 按标题、段落、章节、列表等 | 语义完整性较好 | 依赖文档结构质量 | Markdown、HTML、技术文档 |
| 递归分块 | 按层级分隔符逐级切分 | 兼顾长度和结构 | 规则设计稍复杂 | 通用文本、长文档 |
| 语义分块 | 按语义相似度或主题变化 | 语义最自然,召回质量高 | 计算成本高,实现复杂 | 高质量知识库、问答系统 |
| 混合分块 | 多种策略组合 | 效果更稳定,适应性强 | 调参成本较高 | 生产级 RAG 系统 |
1. 固定大小分块
固定大小分块是最简单的方式,按照固定字符数、词数或 token 数切分文本。例如每 500 tokens 切成一块,超过就继续切下一块。
它的优点是实现简单、速度快、容易批量处理,适合快速搭建 RAG 原型。但缺点也很明显:它不理解文本结构,可能会把一个完整段落、一个概念,甚至一句话从中间切开,导致检索到的 chunk 语义不完整。
例如一段内容正在解释"缓存击穿的解决方案",但刚好在"互斥锁"前后被切断,模型拿到的上下文就可能不完整。
2. 滑动窗口分块
滑动窗口分块是在固定大小分块的基础上增加 overlap,也就是块与块之间保留一部分重叠内容。
比如设置 chunk size 为 500 tokens,overlap 为 100 tokens,那么第一个块是 0 到 500,第二个块可能从 400 到 900 开始。这样做的目的是避免重要信息刚好落在两个块的边界处,被切断后影响理解。
它的优点是上下文连续性更好,能够缓解语义断裂问题;缺点是会产生重复内容,增加向量存储、索引构建和检索成本。它适合论文、教程、法律文档、说明书这类上下文连续性较强的内容。
3. 自然结构分块
自然结构分块是按照文档本身的结构来切,比如按照标题、章节、段落、列表、表格、代码块、HTML 标签、Markdown 标题等进行切分。
这种方式更符合人类阅读习惯,能较好保持语义完整性。例如 Markdown 文档可以按 #、##、### 标题切分;技术文档可以按章节切分;网页可以按 DOM 结构切分。
它的优点是语义边界比较自然,适合结构清晰的文档;缺点是非常依赖原始文档质量。如果文档格式混乱、标题层级不规范、PDF 解析结果错乱,切分效果就会下降。
4. 递归分块
递归分块可以理解为"优先按大结构切,切不动再按小结构切"。它会按照一组分隔符从高优先级到低优先级逐层尝试,比如先按章节切,再按段落切,再按句子切,最后才按固定长度切。
例如一个文档先按标题拆,如果某个标题下的内容仍然太长,就继续按段落拆;段落还太长,再按句子或 token 拆。这样既能尽量保留语义结构,又能控制每个 chunk 的大小。
它的优点是通用性强,是很多 RAG 框架中的默认选择;缺点是需要合理设计分隔符和 chunk size,否则仍然可能出现块过大或语义割裂的问题。
5. 语义分块
语义分块不是简单依赖长度或标点,而是根据内容的语义变化来切分。常见做法是先把句子或段落向量化,计算相邻片段之间的语义相似度,当相似度明显下降或主题发生变化时,就在这个位置切分。
它的优点是分出来的 chunk 主题更集中,适合提升检索相关性。比如一篇文章前半部分讲"向量数据库",后半部分讲"重排序",语义分块能更自然地在主题切换处切开。
缺点是实现成本和计算成本更高,因为它通常需要额外的 embedding、相似度计算或模型判断。它更适合对问答质量要求高、知识库规模可控、愿意投入调优成本的场景。
6. 混合分块
混合分块是实际生产中最常见的方式,也就是组合多种策略,而不是只用一种规则。
比如先用自然结构分块按标题和段落拆分,再对过长段落使用递归分块,最后加上一定 overlap;对于代码文档,可以按文件、类、函数优先切分,再对注释和说明文字做 token 限制;对于 FAQ,可以直接一问一答作为一个 chunk。
混合分块的优点是更加灵活、效果更稳定;缺点是规则和参数更多,需要结合业务数据不断评估和调整。
总结
RAG 中常见的分块策略包括固定大小分块、滑动窗口分块、自然结构分块、递归分块、语义分块和混合分块。固定大小分块按字符数或 token 数切,简单高效但容易切断语义;滑动窗口分块会在相邻 chunk 之间保留重叠内容,能缓解上下文断裂,但会增加存储和检索成本;自然结构分块按标题、段落、章节等文档结构切,语义完整性更好,但依赖文档格式质量;递归分块会优先按大结构切,超过长度后再逐级按段落、句子等继续切,兼顾通用性和长度控制;语义分块根据主题变化或语义相似度切分,效果更自然但成本更高;生产环境通常会使用混合分块,结合结构、长度、overlap 和业务特点来取得更稳定的效果。
在 RAG 中的 Embedding 嵌入是什么?
Embedding 嵌入就是把文本等非结构化内容转换成向量,让 RAG 系统能用"语义相似度"来检索相关知识。
在 RAG 中,Embedding 指的是将文本、图片、音频等人类可理解的信息,转换成一组高维数字向量的过程。对于文本 RAG 来说,最常见的是把用户问题、文档段落、知识库内容转换成向量,例如:
text
"什么是 RAG?" → [0.12, -0.35, 0.88, ...]
这些数字本身不重要,重要的是它们能表达文本的语义特征。语义相近的内容,在向量空间中的距离通常更近;语义差异大的内容,距离通常更远。
比如:
- "猫"和"狗"都属于动物,向量距离会比较近;
- "开心"和"高兴"语义相似,向量距离会比较近;
- "数据库索引"和"旅游攻略"语义差异较大,向量距离会比较远。
在 RAG 系统中,Embedding 主要用于"检索"阶段。系统会先把知识库中的文档切分成多个 chunk,然后用 Embedding Model 将每个 chunk 转成向量,并存入向量数据库。当用户提问时,系统也会把用户问题转成向量,再到向量数据库中查找语义最相近的文档片段,最后把这些片段交给大模型生成回答。
一个典型流程是:
#mermaid-svg-J6MrWG20ZNnui0wg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-J6MrWG20ZNnui0wg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-J6MrWG20ZNnui0wg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-J6MrWG20ZNnui0wg .error-icon{fill:#552222;}#mermaid-svg-J6MrWG20ZNnui0wg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-J6MrWG20ZNnui0wg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-J6MrWG20ZNnui0wg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-J6MrWG20ZNnui0wg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-J6MrWG20ZNnui0wg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-J6MrWG20ZNnui0wg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-J6MrWG20ZNnui0wg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-J6MrWG20ZNnui0wg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-J6MrWG20ZNnui0wg .marker.cross{stroke:#333333;}#mermaid-svg-J6MrWG20ZNnui0wg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-J6MrWG20ZNnui0wg p{margin:0;}#mermaid-svg-J6MrWG20ZNnui0wg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-J6MrWG20ZNnui0wg .cluster-label text{fill:#333;}#mermaid-svg-J6MrWG20ZNnui0wg .cluster-label span{color:#333;}#mermaid-svg-J6MrWG20ZNnui0wg .cluster-label span p{background-color:transparent;}#mermaid-svg-J6MrWG20ZNnui0wg .label text,#mermaid-svg-J6MrWG20ZNnui0wg span{fill:#333;color:#333;}#mermaid-svg-J6MrWG20ZNnui0wg .node rect,#mermaid-svg-J6MrWG20ZNnui0wg .node circle,#mermaid-svg-J6MrWG20ZNnui0wg .node ellipse,#mermaid-svg-J6MrWG20ZNnui0wg .node polygon,#mermaid-svg-J6MrWG20ZNnui0wg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-J6MrWG20ZNnui0wg .rough-node .label text,#mermaid-svg-J6MrWG20ZNnui0wg .node .label text,#mermaid-svg-J6MrWG20ZNnui0wg .image-shape .label,#mermaid-svg-J6MrWG20ZNnui0wg .icon-shape .label{text-anchor:middle;}#mermaid-svg-J6MrWG20ZNnui0wg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-J6MrWG20ZNnui0wg .rough-node .label,#mermaid-svg-J6MrWG20ZNnui0wg .node .label,#mermaid-svg-J6MrWG20ZNnui0wg .image-shape .label,#mermaid-svg-J6MrWG20ZNnui0wg .icon-shape .label{text-align:center;}#mermaid-svg-J6MrWG20ZNnui0wg .node.clickable{cursor:pointer;}#mermaid-svg-J6MrWG20ZNnui0wg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-J6MrWG20ZNnui0wg .arrowheadPath{fill:#333333;}#mermaid-svg-J6MrWG20ZNnui0wg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-J6MrWG20ZNnui0wg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-J6MrWG20ZNnui0wg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-J6MrWG20ZNnui0wg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-J6MrWG20ZNnui0wg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-J6MrWG20ZNnui0wg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-J6MrWG20ZNnui0wg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-J6MrWG20ZNnui0wg .cluster text{fill:#333;}#mermaid-svg-J6MrWG20ZNnui0wg .cluster span{color:#333;}#mermaid-svg-J6MrWG20ZNnui0wg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-J6MrWG20ZNnui0wg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-J6MrWG20ZNnui0wg rect.text{fill:none;stroke-width:0;}#mermaid-svg-J6MrWG20ZNnui0wg .icon-shape,#mermaid-svg-J6MrWG20ZNnui0wg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-J6MrWG20ZNnui0wg .icon-shape p,#mermaid-svg-J6MrWG20ZNnui0wg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-J6MrWG20ZNnui0wg .icon-shape .label rect,#mermaid-svg-J6MrWG20ZNnui0wg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-J6MrWG20ZNnui0wg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-J6MrWG20ZNnui0wg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-J6MrWG20ZNnui0wg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 原始文档
文档切分 Chunk
Embedding 模型
向量数据库
用户问题
Embedding 模型
向量相似度检索
召回相关文档片段
交给大模型生成答案
Embedding 在 RAG 中的核心价值,是让系统不只依赖关键词匹配,而是能够理解语义相似性。比如用户问"怎么提升检索准确率",知识库里可能没有完全一样的关键词,但有"如何优化召回效果""RAG 检索调优方法"等内容,Embedding 可以帮助系统把这些语义相关的内容召回出来。
总结:
Embedding 是将文本转换成高维向量表示的过程,用来表达文本的语义信息。在 RAG 中,文档片段和用户问题都会被 Embedding 模型转换成向量,然后通过向量相似度计算,从向量数据库中检索出与问题最相关的内容。它的作用是让 RAG 系统具备语义检索能力,而不仅仅是做关键词匹配,从而提升召回效果和回答质量。
在 RAG 中,你知道有哪些 Embedding Model 嵌入模型?
RAG 中常见的 Embedding Model 可以按来源分为商业闭源模型、开源通用模型、中文优化模型、多模态模型和领域专用模型。
Embedding Model 的作用是把用户问题和知识库文档转换成向量,用于后续的语义相似度检索。实际选型时,不只是看模型效果,还要结合语言支持、成本、部署方式、向量维度、推理速度和业务场景来判断。
常见 Embedding Model 类型
1. 商业闭源 Embedding 模型
这类模型通常通过 API 调用,优点是效果稳定、维护成本低、开箱即用,适合快速搭建 RAG 原型或对效果要求较高但不想自建模型服务的团队。
常见代表包括:
text-embedding-ada-002text-embedding-3-smalltext-embedding-3-largeCohere EmbedVoyage Embeddings
它们通常在英文、多语言检索、通用语义理解上表现较好,但缺点是需要联网调用,存在调用成本、数据隐私、延迟和服务依赖问题。
2. 开源通用 Embedding 模型
开源模型可以本地部署,更适合对数据安全、私有化部署、成本控制有要求的场景。常见代表包括:
BGE系列,例如bge-small、bge-base、bge-largeE5系列,例如multilingual-e5-base、multilingual-e5-largeGTE系列Instructor系列Sentence-BERT系列
这类模型的优势是可控性强,可以部署在企业内网,也方便做微调。但需要自己维护推理服务、向量生成流程和模型版本管理。
3. 中文或多语言优化模型
如果 RAG 应用主要面向中文知识库,就需要重点关注中文语义检索效果。很多通用英文模型在中文场景下不一定表现最好,因此中文业务中经常会选择中文或多语言表现更强的模型。
常见代表包括:
bge-large-zhbge-base-zhtext2vecm3emultilingual-e5gte-multilingual
例如企业知识库、客服问答、中文合同检索、中文技术文档问答等场景,通常会优先评估中文 Embedding 模型的召回率和语义匹配能力。
4. 多模态 Embedding 模型
如果 RAG 不只处理文本,还要处理图片、截图、图文混合文档、商品图片、医学影像说明等内容,就会用到多模态 Embedding 模型。
这类模型可以把文本和图片映射到同一个向量空间中,从而支持"用文字搜图片"或"用图片找相似内容"。
常见代表包括:
CLIPSigLIP- 一些视觉语言模型配套的多模态 Embedding 能力
比如在电商场景中,用户输入"红色运动鞋",系统可以检索相似商品图片;在知识库场景中,也可以对图文混排文档中的图片内容进行检索。
5. 领域专用 Embedding 模型
有些场景对专业语义要求很高,通用模型可能无法准确理解领域术语,比如医疗、法律、金融、代码、科研论文等。这时可以选择领域专用模型,或者基于通用 Embedding 模型进行微调。
典型场景包括:
| 场景 | 关注点 | 示例 |
|---|---|---|
| 法律 RAG | 法条、案例、合同条款语义匹配 | 合同审查、法规问答 |
| 医疗 RAG | 疾病、药品、诊疗术语理解 | 医学知识问答 |
| 金融 RAG | 财报、公告、研报语义检索 | 投研助手 |
| 代码 RAG | 函数、类、接口、调用关系检索 | 代码问答、代码补全 |
| 企业知识库 | 内部术语、产品文档、流程制度 | 智能客服、内部助手 |
这类模型的优势是领域准确性更高,但需要更多数据评估,甚至需要基于业务数据微调。
面试回答可以这样说
在 RAG 中,Embedding Model 是用来把文本转换成向量的模型,常见的模型可以分为几类:第一类是商业闭源模型,比如一些 API 型 Embedding 服务,效果稳定、接入方便;第二类是开源通用模型,比如 BGE、E5、GTE、Sentence-BERT 等,适合私有化部署;第三类是中文或多语言优化模型,比如 bge-zh、text2vec、m3e、multilingual-e5,适合中文知识库;第四类是多模态 Embedding 模型,比如 CLIP,用于图文检索;第五类是领域专用 Embedding 模型,比如面向法律、医疗、金融、代码场景的模型。
如果是实际项目选型,我不会只看模型名称,而是会结合业务语言、知识库类型、召回效果、向量维度、推理速度、部署成本、是否支持私有化以及后续是否需要微调来综合选择。对于中文企业知识库,通常会优先评估中文或多语言开源模型;对于快速验证的项目,可以先用 API 型模型;对于数据安全要求高的项目,则更倾向本地部署开源 Embedding 模型。
在 RAG 中,你如何选择 Embedding Model 嵌入模型,需要考虑哪些因素?
**选择 Embedding Model 的核心,是看它能否在你的业务语料、查询### 选择 Embedding Model 的核心,是在"检索效果、业务适配、性能成本、工程可维护性"之间做平衡。不能只看模型榜单分数,而要结合你的数据类型、查询方式、语言场景、延迟要求和线上评估结果来选。
在 RAG 中,Embedding Model 的作用是把用户问题和知识库文档转成向量,后续通过向量相似度检索出相关内容。因此,Embedding 模型选得好不好,会直接影响召回质量,进而影响最终大模型回答的准确性。
我一般会从以下几个方面选择。
1. 语义表示能力
首先要看模型能不能准确理解文本语义。RAG 检索不是简单关键词匹配,而是要识别"语义相近"的内容。
比如用户问:
"怎么提升召回率?"
知识库里可能写的是:
"可以通过优化分块、改进 Embedding、增加重排序来改善检索效果。"
好的 Embedding 模型应该能把这两段文本映射到比较接近的向量空间中。
这里重点关注几个能力:同义表达识别、长句理解、上下文理解、专业术语理解、相似但不同概念的区分能力。
2. 语言和领域适配能力
如果业务主要是中文知识库,就要优先选择中文效果好的模型,或者中英双语能力强的模型。如果知识库是英文技术文档,可以选择英文语义检索表现更强的模型。如果是中英混合场景,则需要选择多语言 Embedding 模型。
领域也很重要。通用模型在普通问答场景下可能够用,但在金融、医疗、法律、代码、工业文档等垂直领域中,术语密度高,语义边界细,最好选择在相关领域表现更好的模型,或者基于业务数据做微调。
比如金融场景中,"PE"可能表示"市盈率";在计算机领域中,可能表示"可移植可执行文件";在体育语境中又可能是"体育课"。如果模型没有领域理解能力,检索结果就容易跑偏。
3. 与数据形态是否匹配
不同知识库内容对 Embedding 模型的要求不同。
如果文档是 FAQ、短问短答、客服知识库,模型需要擅长短文本语义匹配。如果文档是技术方案、合同、论文、产品手册,就要关注长文本表示能力和复杂语义理解能力。如果是代码知识库,则应该考虑专门支持代码语义的 Embedding 模型。
此外,还要看模型支持的最大输入长度。如果分块后的 chunk 比较长,而模型最大 token 长度较短,就可能导致截断,影响向量质量。
4. 检索效果评估
不能只看模型官方 benchmark,最好用自己的业务数据做离线评估。
常用指标包括:
| 指标 | 含义 | 适用场景 |
|---|---|---|
| Recall@K | 前 K 个结果中是否召回正确文档 | 判断召回能力 |
| Precision@K | 前 K 个结果中相关文档占比 | 判断检索准确性 |
| MRR | 正确答案首次出现的位置 | 关注首个命中结果 |
| NDCG | 综合考虑相关性和排序位置 | 多级相关性评估 |
| Hit Rate | 是否命中目标文档 | 简单问答场景 |
真实项目里,我一般会构造一批"问题-标准文档"测试集,用多个 Embedding 模型分别跑检索,然后比较 Recall@5、Recall@10、MRR 等指标。如果 RAG 后面还有 rerank,可以分别评估"纯向量召回效果"和"召回 + 重排后的效果"。
5. 推理性能和资源成本
Embedding 模型不是只在离线阶段使用,在线用户每次提问时也要把 query 转成向量,所以延迟很关键。
需要考虑:
- 单次 embedding 的延迟;
- 批量处理能力;
- QPS 支撑能力;
- CPU/GPU 资源消耗;
- 向量维度大小;
- 存储和索引成本;
- API 调用费用或本地部署成本。
如果是高并发在线问答场景,模型太大可能会导致延迟高、成本高。此时不一定选最强模型,而是要选效果和性能平衡最好的模型。
6. 向量维度和向量库兼容性
Embedding 模型输出的向量维度会影响向量库索引大小、检索速度和存储成本。
例如 384 维、768 维、1024 维、1536 维、3072 维向量,在表达能力、存储成本和检索速度上都有差异。维度越高,不一定效果一定越好,但通常存储和计算成本会更高。
还要确认模型输出是否能很好适配当前向量数据库,例如 Milvus、FAISS、Elasticsearch、PGVector、Qdrant 等。同时要关注相似度计算方式,比如 cosine similarity、dot product、L2 distance,确保建库和查询时使用的距离度量与模型推荐方式一致。
7. 是否支持微调
如果业务场景比较专业,通用 Embedding 模型效果不够好,就要考虑模型是否支持微调。
微调数据可以来自:
- 用户真实 query 和点击文档;
- 人工标注的问题-答案对;
- FAQ 问答对;
- 正负样本对;
- 历史搜索日志;
- 线上反馈数据。
通过对比学习或排序学习微调后,模型可以更好地适应业务语义。例如企业内部知识库中经常有产品名、系统名、缩写词、内部黑话,通用模型未必理解,微调后效果通常会明显提升。
8. 与 RAG 整体链路的配合
Embedding Model 不是孤立选择的,要结合整个 RAG 链路来看。
如果前面分块策略不好,即使 Embedding 模型很强,也可能召回不到完整答案。如果 query 改写做得不好,用户问题表达模糊,也会影响向量检索。如果没有 rerank,TopK 结果排序可能不够精确。如果 prompt 拼接不合理,召回到了正确文档,大模型也可能答错。
所以选型时要整体考虑:
- 分块策略;
- query rewrite;
- hybrid search;
- rerank;
- metadata filter;
- prompt compression;
- 上下文窗口大小;
- 最终答案评估。
在实际项目中,常见做法是:先用一个效果稳定的通用 Embedding 模型作为 baseline,然后通过评估集比较不同模型,再根据业务场景决定是否引入混合检索、rerank 或领域微调。
9. 数据安全和部署方式
如果知识库包含企业内部资料、合同、用户隐私、研发文档等敏感数据,就要重点考虑数据安全。
可以选择本地私有化部署的开源 Embedding 模型,避免把文本发送到外部 API。如果使用云服务,则要确认数据是否会被存储、是否用于训练、是否满足企业合规要求。
这在金融、医疗、政企、法律、工业制造等场景中非常重要。
总结
在 RAG 中选择 Embedding Model,我不会只看模型排行榜,而是会结合业务场景做综合评估。核心会看几个方面:第一是语义表示能力,能不能准确理解用户问题和文档内容;第二是语言和领域适配,比如中文、英文、多语言,或者金融、法律、代码等垂直领域;第三是模型支持的上下文长度和向量维度,是否适合我们的文档分块方式和向量库;第四是性能和成本,包括推理延迟、QPS、存储成本和部署成本;第五是是否支持微调,方便后续用业务数据优化效果;第六是安全和部署方式,是否支持私有化部署。
真实项目里,我会先构建一批业务评估集,比如用户问题和标准命中文档,然后用 Recall@K、MRR、NDCG、Hit Rate 等指标对不同 Embedding 模型做离线评估。同时还会结合线上指标,比如用户满意度、答案命中率、无答案率和人工反馈。最后选择的模型不一定是榜单最高的,而是检索效果、性能、成本和业务适配综合最优的模型。