路线图

03 上下文工程与 RAG

星辉 2026-07-02 阅读 5 min 900 字 路线图
03 上下文工程与 RAG 封面

学习目标:能构建企业知识库 Agent(检索/Rerank/引用溯源/评测),并能为长任务 Agent 设计上下文预算与压缩策略。 重点度:必会(12 分) 前置要求:Ch2 LLM 应用基础、Python、基础向量运算概念


概述#

Agent 不能只依赖模型参数里的知识——模型训练截止后的事情、企业内部数据、用户私有上下文,都得靠运行时检索。这就是 RAG(Retrieval-Augmented Generation)解决的问题。

但 2026 的现实是:RAG 已经不够用了。长任务 Agent 跑着跑着上下文窗口就爆了——一次自主任务可能烧几十万 token,单纯堆 RAG 解决不了"运行时上下文预算管理"的问题。

所以本章把 Context 工程 提为一等公民,与 RAG 并列。两者边界清晰:

  • RAG 是"知识获取":把外部知识塞进上下文
  • Context 工程是"运行时上下文预算管理":决定什么进上下文、什么不进、什么时候压缩、什么时候丢弃

Part 1:RAG#

RAG 全链路#

一次完整的 RAG 流程:

text
用户问题
[1. Query Rewrite] ← 改写查询,提升召回
[2. Hybrid Search] ← 向量检索 + 关键词检索
[3. Rerank] ← 重排,把最相关的推到前面
[4. Context Filter] ← 截断/过滤,只保留 top-k
[5. Prompt Assembly] ← 拼到 system/user prompt 里
[6. LLM 生成] ← 引用溯源
[7. RAG Eval] ← 评测检索质量与生成忠实度

文档解析与 Chunking#

文档解析#

格式工具注意点
PDFPyMuPDF / unstructured / Marker扫描件需 OCR;表格/公式易丢失
Word/Excelpython-docx / openpyxl保留段落结构,不要按行粗暴切
HTMLBeautifulSoup / Trafilatura去广告/导航/页脚,保留正文
Markdown直接按 heading 切分天然结构化,最友好

实战坑:PDF 解析是 RAG 工程里最耗时的一块。生产场景建议用 Marker / Docling 这类专门做 PDF → Markdown 的工具,比 PyMuPDF 直接抽文本结构保留好得多。

Chunking(切片)#

Chunking 决定了检索粒度。切太大召回噪声多,切太小语义不完整。

常用策略

  1. 固定长度切分:按 token 数(如 500 token/chunk,overlap 50)—— 简单但破坏语义
  2. 按结构切分:按段落/标题切—— 保留语义但 chunk 大小不均
  3. 递归切分(RecursiveCharacterTextSplitter):先按段落切,太大再按句子切—— LangChain 默认
  4. 语义切分(SemanticChunker):用 embedding 相似度判断边界,相似度骤降处切分 —— 效果好但成本高

关键参数

  • chunk_size:500-1500 token 是常见区间
  • overlap:50-200 token,避免边界信息丢失
  • metadata:每个 chunk 必须带 source/page/section 等元数据,用于引用溯源和权限过滤

Embedding 与 Vector DB#

Embedding 模型#

把文本转成向量,相似度通过余弦距离计算。

模型维度特点
OpenAI text-embedding-3-large3072通用强,国内访问受限
BGE-M31024中文优秀,开源,支持稠密+稀疏+多向量
Qwen3-Embedding多种阿里出品,中文友好
Cohere embed-v31024多语言强

实战策略:国内首选 BGE-M3 / Qwen3-Embedding,闭源场景可考虑 OpenAI/Cohere。

Vector DB 选型#

类型代表适用场景
专用向量库Milvus / Qdrant / Weaviate大规模(千万级 chunk)
数据库扩展pgvector / Redis Vector中小规模,已有 PG/Redis
全托管Pinecone / 腾讯 VectorDB不想运维
内存型FAISS单机百万级,无持久化需求

关键能力对比

  • HNSW 索引:主流近似最近邻算法,查询快但内存占用高
  • IVF + PQ:内存占用低但精度损失
  • Filter:metadata 过滤(如"只检索部门=HR 的文档")—— 生产必备,选型时务必验证

Hybrid Search 与 Rerank#

纯向量检索的弱点:

  • 关键词失效:人名、产品型号、专有名词,向量检索可能召回不到
  • 短查询过泛:"Q3 财报"三个字,向量空间相似的东西太多

解决方案:向量检索 + 关键词检索(BM25)并行,结果融合

RRF 融合#

text
Hybrid Search = Vector Search(top 50) ∪ BM25 Search(top 50)
              → RRF 融合排序 → top 20

RRF(Reciprocal Rank Fusion):score = Σ 1/(rank_i + k),简单有效。

Rerank#

Rerank 模型对 hybrid search 召回的 top-N 重新打分,把真正相关的推到前面。

text
Query: "Q3 财报里提到哪些风险因素?"

Hybrid 召回 top-20:
  chunk_1: Q3 财报封面 ← 向量相似但答非所问
  chunk_2: Q3 风险因素章节 ← 真正想要的
  chunk_3: Q2 风险因素章节 ← 历史内容
  ...

Rerank 后:
  chunk_2 → chunk_3 → chunk_1 → ...

Rerank 模型:BGE-Reranker-v2-m3(开源,中文好)、Cohere Rerank(商用强)。


Query Rewrite#

用户的原始查询往往不是最优检索 query:

  • 口语化:"那个东西怎么用" → 改写为"产品 X 使用说明"
  • 指代不清:"他说的那个文件" → 需要结合上下文消解
  • 多跳问题:"对比 A 和 B 公司 Q3 营收" → 拆成两次检索

HyDE(Hypothetical Document Embedding)#

让 LLM 先编一个"假想答案",用假想答案的 embedding 去检索——因为"答案"比"问题"在向量空间更接近真实文档。

text
Query: "Q3 财报风险因素"
HyDE 生成: "Q3 财报中提到的风险因素包括:原材料价格波动、汇率风险..."
用 HyDE 生成内容做 embedding 检索 → 召回更准

Multi-Query#

LLM 把一个问题改写成多个不同角度的子查询,并行检索后融合。


引用溯源与权限感知检索#

引用溯源#

生产 RAG 系统必须给每个回答附带引用,让用户能验证:

text
回答: "Q3 营收同比增长 12%[1], 主要增长来自云业务[2]"

引用:
[1] 2026 Q3 财报.pdf, p.3, "本季度营收同比增长 12%"
[2] 2026 Q3 财报.pdf, p.5, "云业务收入贡献主要增长"

实现:让模型在每个事实陈述后输出 [cite_id], cite_id 关联到具体 chunk 的 metadata。

权限感知检索(Permission-Aware Retrieval)#

企业场景必须做:

  • 检索时按用户权限过滤 metadata(部门/级别/项目组)
  • 不要"先检索后过滤"——会丢失相关结果;要"检索时就过滤",Vector DB 的 filter 能力在这里用上
  • 引用也按权限显示——用户能看到答案但看不到机密源文件名

RAG Eval#

评测维度#

维度含义评测方法
检索召回相关文档是否被召回标注 golden chunks,看 Recall@k
检索精度召回的文档是否相关Precision@k
生成忠实度回答是否基于检索内容(防幻觉)LLM-as-a-Judge / faithfulness 评分
答案正确性回答是否真的回答了问题人工标注 / LLM-as-a-Judge
引用正确性引用是否准确指向源标注 golden citation

工具#

  • Ragas:开源 RAG 评测框架,覆盖 faithfulness / answer_relevancy / context_precision / context_recall
  • TruLens:可观测 + 评测,能记录每次 RAG 调用并评分
  • DeepEval:单元测试风格的 RAG 评测

Agentic RAG 与 GraphRAG#

Agentic RAG#

传统 RAG 是"一次检索 → 生成"。Agentic RAG 让 Agent 自己决定:

  • 要不要检索?(也许模型已经知道答案)
  • 检索几次?(多跳问题需要迭代检索)
  • 检索结果不够好,要不要改写 query 再检一次?
  • 要不要检索别的源(SQL DB / Web)?
text
用户: "对比 OpenClaw 和 WorkBuddy 的安全模型"
Agent 决策:
  Round 1: 检索 "OpenClaw 安全模型" → 召回 5 篇
  Round 2: 检索 "WorkBuddy 安全模型" → 召回 3 篇
  Round 3: 信息不够,检索 "Confused Deputy MCP" → 补充背景
  最终: 整合三轮结果生成对比

GraphRAG#

传统 RAG 是"扁平 chunk 检索",处理跨文档关系弱(如"找出和 X 有合作的所有公司")。GraphRAG 在 chunk 之上构建知识图谱:

  • 抽取实体 + 关系 → 建图
  • 检索时既找相关 chunk,也找图谱上的关联节点
  • 适合多跳推理、全局总结类问题

何时用 GraphRAG:跨文档关系查询、全局总结、多跳推理。简单问答用 GraphRAG 是过度设计。


Part 2:Context 工程(2026 一等公民)#

为什么 Context 工程独立成章#

RAGContext 工程
解决"知识从哪来"解决"运行时上下文怎么管"
离线建索引,在线检索在线动态决策
关注召回/精度关注 token 预算、压缩、丢弃
一次性的 prompt 增强持续滚动的上下文管理

Agent 跑长任务时,上下文会持续膨胀:每一步的思考、每次工具调用、每次检索结果都往上下文塞。10 步后上下文可能已经 50K token,20 步后 200K,模型窗口再大也撑不住——这就是 Context 工程要解决的核心问题。


Context 窗口预算#

核心问题:什么进上下文、什么不进#

text
[Agent 一次决策的上下文构成]

System Prompt     ─── 必留 (规则/角色)
Conversation      ─── 必留 (用户对话)
Tool List         ─── 必留 (工具 schema)
Tool Call History ─── 选择性保留 (近期留,早期压缩)
RAG Results       ─── 选择性保留 (用完即丢)
Scratchpad        ─── 选择性保留 (工作笔记)
File Content      ─── 几乎不留 (太长,用 reference 替代)

预算分配#

text
假设上下文窗口 200K token:

System Prompt:    2K  (固定)
Conversation:    20K  (用户对话历史)
Tool List:        5K  (工具 schema)
Tool Call History: 30K (近期工具调用)
RAG Results:     20K  (当前任务的检索结果)
Scratchpad:      10K  (工作笔记)
─────────────────────
已用: 87K
剩余给模型生成: 113K (output)

实际工程里要把预算做成动态的——简单任务少给点、复杂任务多给点。


Context Compression(上下文压缩)#

摘要压缩#

对长历史记录做摘要,把 N 轮对话压缩成几句话:

text
原始:
  user: 帮我分析这个 repo
  assistant: 好的,我先看 README... (3K token)
  assistant: 然后看了 package.json... (2K token)
  assistant: 接着分析 src 目录... (5K token)
  ...总共 30K token

压缩后:
  assistant: [已完成 repo 分析,识别为 Node.js 项目,
              使用 React+Express,主要模块包括 auth/payment/user]
  (200 token)

何时 summarize、何时丢弃#

  • summarize:内容可能后续还要用,但不需要原细节 → 工具调用历史、RAG 结果
  • 丢弃:内容用完即弃 → 中间计算结果、临时 scratchpad
  • 保留原文:必须精确的 → 用户原话、合同条款、代码 diff

⚠️ 实战坑:不要无脑 summarize。如果任务涉及"对比第 3 步和第 7 步的输出",summarize 掉就找不回了。要按"未来是否需要细节"判断。


Compaction(长任务上下文滚动压缩)#

Compaction 是 Claude Code / Cursor 等长任务 Agent 的核心技术:当上下文逼近窗口上限时,自动触发压缩,让任务能继续跑下去

基本流程#

text
[Agent 跑到第 25 步, 上下文 180K/200K]
触发 Compaction:
  1. 把最早的 N 步压缩成 summary
  2. 保留近 M 步原文
  3. 保留关键状态: 当前任务/已完成步骤/未完成步骤
  4. 上下文降到 80K
[Agent 继续跑, 25 → 50 步]
再次触发 Compaction
[Agent 能跑到 100+ 步而不爆窗口]

关键设计#

  • 触发阈值:上下文用量超过 70-80% 时触发,留余量给后续步骤
  • 保留窗口:最近 N 步原文必须保留,否则模型会"失忆"
  • 关键状态外置:当前任务/进度/已做决策不应放上下文,应外置到 workspace 文件(见 Ch7)
  • summary 要可恢复:summary 本身要包含足够信息,让模型能"知道自己做过什么"

Subagent 隔离 context#

主 Agent 上下文爆炸时,把子任务派给 subagent:

text
主 Agent (上下文 50K, 剩余预算紧张):
  "我需要分析这个 100 文件的 repo"
派 subagent:
  Subagent 接收: "分析 X repo,输出主要模块清单"
  Subagent 自己加载 100 文件 (自己上下文爆了也不影响主)
  Subagent 返回: "main 模块/auth/payment/user..." (500 token)
主 Agent 上下文只增加了 500 token

Claude Code 的 subagent、Codex 的 parallel agent、WorkBuddy 的多 agent 并行,本质都是这个机制。

何时用 subagent

  • 子任务需要大量上下文,但输出可以浓缩
  • 子任务可以并行(多个独立分析)
  • 子任务失败不该污染主上下文

阶段产出#

完成本章后应该能:

  • 构建完整 RAG 流程:解析 → chunking → embedding → hybrid search → rerank → 引用溯源
  • 实现权限感知检索(metadata filter)
  • 用 Ragas/TruLens 做 RAG Eval(召回/精度/忠实度/引用正确性)
  • 理解 Agentic RAG / GraphRAG 的适用场景
  • 为长任务 Agent 设计上下文预算分配策略
  • 实现 Context Compression(摘要压缩 + 选择性丢弃)
  • 实现 Compaction(阈值触发 + 保留窗口 + 关键状态外置)
  • 用 Subagent 隔离 context,避免主上下文爆炸

下一章 Ch4 进入 Tool Calling 与 MCP——Agent 怎么调用工具、怎么操作浏览器/GUI、MCP 与 A2A 的边界。这是 Agent 真正"能动手"的关键。