跳到主要内容

RAG 与 Agent

RAG 全流程​

Retrieval-Augmented Generation 把「知识」从模型参数里搬到外部检索系统。两条链路:

离线索引:文档 → 解析 → 切片 → 向量化 → 存入向量库 在线查询:问题 → 向量化 → 检索 → 重排 → 拼进 prompt → 生成

1. 切片(chunking)​

最影响效果且最被低估的一步。切太小丢上下文,切太大引入噪声且挤占 context。

策略说明
固定长度 + 重叠最简单。典型 512 token + 10~20% overlap,重叠是为了避免答案正好被切断
按语义边界优先在段落、标题、句子处切,别切断句子
结构感知Markdown 按标题层级切,代码按函数切,表格整体保留
父子切片检索用小块(精准匹配),送给模型用所属大块(上下文完整)。效果通常最好

实务要点:给每个 chunk 附加元数据(来源文档、标题路径、更新时间),既用于过滤也用于生成引用。

2. 向量化(embedding)​

把文本映射成稠密向量,语义相近的距离近。注意:

  • 查询和文档必须用同一个模型编码
  • 很多模型区分 query 和 passage 的前缀指令,用错会掉点
  • 多语言场景要选多语言模型(bge-m3、multilingual-e5)
  • 向量维度与检索精度和存储成本正相关

3. 向量检索​

精确的 KNN 在百万级以上太慢,所以用 ANN(近似最近邻):

索引原理特点
HNSW多层邻近图,上层稀疏做粗导航,下层稠密做精定位召回高、查询快,内存占用大,主流选择
IVF先聚类成若干桶,查询只搜最近的 n 个桶内存友好,需要训练,召回略低
PQ / IVF-PQ向量压缩成乘积量化码极省内存,精度有损,适合超大规模

距离度量:余弦相似度(最常用,只看方向)、内积、欧氏距离。embedding 归一化后三者等价。

4. 混合检索与重排​

纯向量检索的短板:对专有名词、产品型号、错误码这类需要精确匹配的查询效果差 —— 语义相近但字面不同的内容会被排前面。

所以生产方案是混合检索:向量检索(语义)+ BM25 关键词检索(字面),用 RRF(Reciprocal Rank Fusion)融合两路结果。

重排(rerank) —— 用 cross-encoder 对召回的 top-50 重新打分取 top-5。区别在于:

  • 双塔 embedding:query 和 doc 分别编码再算距离。能预计算、可索引,但两者没有交互
  • cross-encoder:query 和 doc 拼在一起送进模型算相关性。精度高得多,但无法预计算,只能对少量候选做

所以标准架构是「召回要广(向量+BM25 取 50~100 条),重排要准(cross-encoder 筛到 3~5 条)」。

5. 生成​

prompt 里要明确三件事:只能基于给定材料回答、材料里没有就说不知道、回答要标注引用的材料编号。

RAG 的常见失效模式​

症状原因解法
检索不到明显存在的内容问题与文档表述差异大查询改写 / HyDE(先让 LLM 生成一个假设答案再用它检索)/ 多查询扩展
检索到了但模型没用相关内容埋在中间(Lost in the Middle)重排后把最相关的放首位,减少送入的块数
答案需要跨多个文档综合单轮检索拿不全多跳检索、GraphRAG
答案需要统计汇总(「一共有几个」)向量检索本质是语义相似,不会做聚合这类问题应走 Text2SQL 而非 RAG
引用了错误来源生成阶段编造引用后处理校验引用编号是否真实存在

:::tip 长上下文能替代 RAG 吗 不能完全替代。四个理由:成本(每次都塞 100 万 token 极贵,RAG 只送几千)、延迟(prefill 时间随长度增长)、Lost in the Middle(长上下文中间信息召回率下降)、可审计性(RAG 能明确给出引用来源)。

但长上下文改变了 RAG 的参数 —— 可以送更多、更大的 chunk,对切片精度的要求下降了。两者是互补关系。 :::

Agent​

Agent 的本质是让 LLM 具备调用外部工具和多步执行的能力,突破「只能输出文本」的限制。

ReAct 范式​

交替进行 Thought(推理)→ Action(调用工具)→ Observation(观察结果),循环直到得出答案。

Thought: 需要先查用户的订单状态
Action: query_order(user_id="123")
Observation: {"status": "shipped", "tracking": "..."}
Thought: 已拿到物流单号,再查物流详情
Action: query_logistics(tracking="...")
...
Thought: 信息齐了,可以回答
Answer: 您的订单已发货,当前在...

关键价值是把推理过程显式化 —— 模型能根据工具返回的真实结果修正方向,而不是一次性凭想象给答案。

Function Calling​

模型被训练成能输出结构化的工具调用请求。流程:

  1. 把工具的 JSON Schema(名称、描述、参数类型)随请求发给模型
  2. 模型判断需要调用时,返回 tool_call(函数名 + JSON 参数)而不是普通文本
  3. 应用代码实际执行该函数 —— 注意模型本身不执行任何东西
  4. 把结果作为 tool 角色的消息回传,模型据此继续

工程要点:工具的 description 写得好不好直接决定模型选不选对 —— 这是 prompt 工程的一部分;参数要有严格 schema 并在执行前校验;工具数量多了(>20)准确率下降,应分层或先做工具检索。

MCP(Model Context Protocol) —— Anthropic 提出的开放协议,把「模型如何连接外部工具和数据源」标准化。价值在于工具提供方实现一次 MCP server,所有支持 MCP 的客户端都能用,不必为每个应用重复适配。

Agent 的工程难点​

  • 错误累积 —— 多步执行中任一步出错会传导到后续。需要每步校验和失败重试
  • 循环与不终止 —— 必须设最大步数和超时
  • 成本不可控 —— 每一步都是一次完整推理,10 步就是 10 倍成本和延迟
  • 权限与安全 —— 工具能改数据就意味着模型能改数据。写操作必须要人确认或有严格的权限边界,且要防 prompt injection(检索到的内容里藏指令)
  • 可观测性 —— 必须记录完整的 trace(每步的思考、调用、返回)才能调试

记忆​

  • 短期 —— 对话历史。超出 context 时做滚动摘要
  • 长期 —— 把用户偏好、历史结论写入向量库或结构化存储,需要时检索回来。本质还是 RAG

提示工程要点​

零样本 / 少样本 —— few-shot 给 2~5 个例子,对格式约束效果显著。例子的多样性比数量重要。

思维链(CoT) —— 「让我们一步步思考」。对数学和逻辑任务提升明显,原理是给模型更多「计算步数」来展开推理。注意对现代推理模型(o 系列、R1)不要加 CoT 提示 —— 它们已经内化了推理过程,额外的 CoT 指令反而干扰。

自我一致性 —— 采样多条推理路径取多数答案,用算力换准确率。

结构化输出 —— 要求 JSON 时用 schema 约束 + 服务端的 structured output 功能,比在 prompt 里写「请返回 JSON」可靠得多。