LLM - 从 RAG 到 Context Engine:2025 实战总结与 2026 落地指南
引言
过去两年,围绕 RAG 的声音两极分化:一边是“RAG 只是临时方案,很快会被长上下文、KV Cache 干掉”;另一边是越来越多严肃做 AI 中台的团队,把 RAG 当作企业非结构化数据的底座来建设。
从 2025 年的实践看,后者正在成为共识:
- 长上下文、KV Cache、简单 Grep 各有适用场景,但都无法在成本、灵活性、可治理性上全面替代 RAG。
- 真正发生的变化是:RAG 从“检索增强生成”组件,升级为面向 Agent 的“上下文引擎(Context Engine)”,成为知识、记忆、工具三类上下文的统一入口。
接下来我们以“实战向”视角,聚焦三个问题:
- 如何搭一个现代 RAG 系统,而不是“向量库 + Embedding”拼凑品。
- 如何把 RAG 升级为支撑 Agent 的 Context Engine,接管知识库、Memory 和 Tool Retrieval。
- 2026 年要不要上多模态 RAG,上了怎么活下来(成本与工程挑战)。
一、RAG vs 长上下文:先别吵,先算账
1.1 四种主流“喂知识”方式
给 LLM 塞外部知识,现在大致有四种套路:
-
方案 A:长上下文
- 直接把一堆文档丢进上下文窗口,模型自己“看着办”。
- 优点:实现简单;易于 PoC。
- 缺点:Lost in the Middle、注意力分散、上下文成本随长度非线性上涨。
-
方案 B:KV Cache / AlayaDB 类方案
- 把文档预先过一遍 LLM 前向,存成张量;推理时做“边生成边检索张量”。
- 优点:推理时可以复用中间表示,理论上能高效重用上下文。
- 缺点:
- 预处理成本高,存储张量很烧钱。
- 超过显存就要走二级存储 + 检索链路,I/O 与架构变复杂。
-
方案 C:无索引 RAG / Grep
- 不建向量索引,直接靠关键词 / 正则搜索文件内容。
- 优点:简单、无索引维护成本;对日志、单一代码库这类“格式规整+术语固定”数据挺好用。
- 缺点:对自然语言、多模态、复杂结构文档基本无能为力。
-
方案 D:RAG(检索增强生成)
- 建立向量索引 + 语义增强,检索后把结果喂给 LLM。
- 优点:
- 成本相对可控,比“全量长上下文”便宜 1–2 个数量级。
- 能结合结构化过滤、多索引、多级召回。
- 缺点:需要打磨数据注入、切片策略、召回与重排,否则效果不稳定。
如果把“单次推理成本”与“可以容纳的知识规模”画成一个简单示意表:
| 方案 | 单次成本量级 | 易用性 | 长期可扩展性 | 适用典型场景 |
|---|---|---|---|---|
| 长上下文 | 最高 | 高 | 低 | 静态少量文档深阅读 |
| KV Cache | 高 | 中 | 中 | 小规模高频问答 |
| Grep / 无索引 | 低 | 中 | 低 | 日志、代码局部搜索 |
| 现代 RAG | 中 | 中 | 高 | 企业知识、Agent 中台 |
结论很直接:
- 长上下文与 KV Cache 更像“局部场景优化器”;
- RAG 更像“通用检索中台”,尤其适合企业要把一大堆私有知识资产稳定接入 LLM 的场景。
1.2 实战建议:如何混用
工程上推荐的组合模式是:“检索前置 + 长上下文容纳”:
用户 Query
↓
(1) 语义检索:先用 RAG 找到可能相关的 10~50 个片段
↓
(2) 上下文组装:按 TreeRAG / PageIndex 之类策略,拼成若干大段
↓
(3) 长上下文模型:把组装好的上下文 + Query 一起喂入模型推理
这样做有几个好处:
- 长上下文窗口被“高浓度信息”占满,而不是一堆噪声。
- 检索逻辑与模型版本解耦,后续换模型不用重做数据处理与索引。
二、现代 RAG:别再只想“切块 + 向量库”
2.1 经典 RAG 的结构性矛盾
传统“分块–嵌入–检索”流水线里有个天然矛盾:
- 为了检索准:块要小,语义纯净(100–256 Token)。
- 为了上下文好用:块要大,语义完整(≥1024 Token)。
结果就是:
- 小块:召回准,但上下文碎,模型缺乏整体语境。
- 大块:上下文连贯,但召回易偏;向量表达过于“平均化”。
要想兼得,最直接的路线是:Search / Retrieve 解耦 + 多粒度表示。
2.2 TreeRAG:Search / Retrieve 解耦的典型实现
TreeRAG 可以看作“树结构版现代 RAG”的代表方案。
架构示意(注入阶段)
原始文档
↓ Parsing(DeepDoc / PDF Parser)
规整文本 + 结构(标题/段落/表格) [page:1]
↓ 切片(Chunking,简单重叠切分)
基础切片序列
↓ LLM 语义增强(离线)
为每个切片/章节生成:
- 多级摘要(章/节/段)
- 关键词 / 实体 / 问题
- 目录树节点关系[page:1]
↓
写入索引:
- 向量索引(小粒度)
- 树结构索引(大粒度)[page:1]
伪代码示意(注入):
def ingest_document(doc_id: str, raw_bytes: bytes):
# 1. 解析
parsed = parse_pdf_or_docx(raw_bytes) # 返回带标题/段落结构文本[page:1]
# 2. 切片
chunks = simple_overlap_chunk(parsed.text, size=256, overlap=64)
# 3. 调用 LLM 做语义增强与树结构构建
outline = llm_generate_outline(parsed.text) # 章/节/小节结构[page:1]
node_summaries = llm_summarize_by_outline(parsed.text, outline)
# 4. 建小粒度向量
for chunk in chunks:
emb = embed(chunk.text)
vec_index.add(doc_id=doc_id, chunk_id=chunk.id, vector=emb,
metadata={"page": chunk.page, "section": chunk.section})
# 5. 建树索引
tree_index.add_document(doc_id, outline, node_summaries)
检索阶段:先找点,再“展开阅读”
def tree_rag_retrieve(query: str, top_k_chunks: int = 20):
# 1. 小粒度 Search:在向量索引里找若干高相关 chunk[page:1]
q_vec = embed(query)
candidates = vec_index.search(q_vec, top_k=top_k_chunks)
# 2. 利用树结构向上 & 横向扩展
expanded_passages = []
for c in candidates:
# 找到所在节点(如“第 3 章 第 2 节”)
node = tree_index.locate_node(c.doc_id, c.metadata)
# 把父节点 / 邻居节点的摘要 + 原文拉进来[page:1]
ctx = tree_index.expand_context(node, window=1)
expanded_passages.append(ctx)
# 3. 去重 & 截断,形成最终上下文
final_context = merge_and_truncate(expanded_passages, max_tokens=4096)
return final_context
这种做法本质上是在做两件事:
- 用“小块”保证召回精度。
- 用“树结构 + 摘要”保证上下文连贯性与覆盖度。
2.3 GraphRAG:补 TreeRAG 不擅长的“跨文档推理”
TreeRAG 主要沿着文档内物理结构(章 / 节 / 段 / 页)扩展上下文,对解决“切块导致的上下文断裂”很有效,但对以下场景不够:
- 答案分散在多个不相邻章节。
- 涉及多个文档间的实体、事件关系推理。
GraphRAG 的思路是:
- 离线抽取实体 & 关系,构成知识图谱;
- 检索时先根据 Query 定位若干“种子实体 / 主题”,在图上做邻域遍历,再聚合对应文本片段。
伪代码示意(极简版):
def build_kg_from_doc(doc_id: str, text: str):
triples = llm_extract_triples(text) # [(head, rel, tail, span_id), ...][page:1]
for h, r, t, span_id in triples:
kg.add_edge(h, t, relation=r, metadata={"doc_id": doc_id, "span_id": span_id})
def graph_rag_retrieve(query: str, top_k_entities: int = 10):
# 1. 先做一个语义检索,得到若干候选片段与实体[page:1]
seeds = entity_index.search(query, top_k=top_k_entities)
# 2. 在图上做个 Personalized PageRank / k-hop BFS
subgraph = kg.expand_from(seeds, hops=2)
# 3. 收集相关实体所属的文本 span
spans = collect_text_spans(subgraph)
# 4. 做摘要 / 去重,组装上下文
ctx = summarize_and_merge(spans, max_tokens=4096)
return ctx
在实战中,更推荐:TreeRAG + GraphRAG 混合:
- TreeRAG 解决“局部语义连贯”;
- GraphRAG 解决“跨章节 / 跨文档关联”。
三、从“知识库 RAG”到“Context Engine”:三类数据统一建模
3.1 PTI:把非结构化数据当成“ETL 同级公民”
企业已经习惯了 ETL/ELT 做结构化数仓,现在要做的是给非结构化数据搭一个 PTI(Parse–Transform–Index)流水线。
对比一下两者的主流程:
| 环节 | ETL/ELT(结构化) | PTI(RAG / Context) |
|---|---|---|
| 解析 | 读 DB / CSV / 日志 | PDF/Word 解析、OCR、VLM 解析、layout 结构化 |
| 转换 | SQL 清洗、聚合、业务逻辑 | LLM 切片、摘要、目录树、实体 / 关系、问题生成等语义增强 |
| 加载 / 索引 | 写数据仓库或湖 | 建立向量索引、倒排索引、树索引、图索引、多模态张量索引 |
PTI 伪代码骨架:
def pti_pipeline(doc_id: str, raw_input: bytes, mime_type: str):
# P: Parse
parsed = parse_by_mime(raw_input, mime_type) # 带 layout 的结构化文本[page:1]
# T: Transform(关键价值点)
chunks = simple_overlap_chunk(parsed.text)
semantic_meta = llm_batch_enhance(chunks) # 摘要、实体、关键词、QA、目录节点等[page:1]
# I: Index
for chunk, meta in zip(chunks, semantic_meta):
vec_index.add(vector=embed(chunk.text),
metadata={**meta, "doc_id": doc_id})
tree_index.update(doc_id, meta["outline"])
# 若开启 GraphRAG
kg_index.ingest_triples(meta["triples"])
工程实战里,PTI 是否设计好,决定了你做的是:
- “能跑的 Demo 知识库”,还是
- “能撑住全公司 Agent 的非结构化数据中台”。
3.2 三类数据:知识库、记忆、工具
Context Engine 要接管三类核心数据源:
-
知识库(RAG):
- 文档、手册、报告、FAQ 等“静态领域知识”。
- 目标:提供事实、背景、规范。
-
记忆(Memory):
- 用户 / Agent 的历史对话、系统状态、LLM 生成的总结与反思。
- 目标:保持长程上下文、个性化、从经验中“学习”。
-
工具(Tool + Playbook):
- 工具描述(名称、参数、功能)、使用示例、Playbook、Guideline。
- 目标:帮助 Agent 选择合适工具、以正确顺序 / 参数调用。
三者在底层都满足一个统一抽象:
@dataclass
class ContextItem:
id: str
type: Literal["knowledge", "memory", "tool"]
content: str # 自然语言描述
embedding: np.ndarray
metadata: dict # 时间、用户、会话、标签、权限等[page:1]
Context Engine 的统一检索接口大致可以长这样:
class ContextEngine:
def __init__(self, knowledge_store, memory_store, tool_store):
self.k_store = knowledge_store
self.m_store = memory_store
self.t_store = tool_store
def query(self, query: str, need_knowledge=True,
need_memory=True, need_tools=True, k=5):
q_vec = embed(query)
results = []
if need_knowledge:
results += self.k_store.search(q_vec, top_k=k)
if need_memory:
results += self.m_store.search(q_vec, top_k=k)
if need_tools:
results += self.t_store.search(q_vec, top_k=k)
return self._rank_and_group(results)
Agent 框架只需要调用 ContextEngine.query(),拿到一包“已组装好的上下文切片”:
- 部分来自知识库。
- 部分来自记忆。
- 部分是“本轮任务最可能用到的工具介绍 + 使用步骤 / Playbook”。
3.3 实战:如何做 Tool Retrieval
简单把所有 MCP 工具的描述塞进 system prompt,在几十个工具时还能撑一下,上百个之后立刻崩溃:
- 上下文成本爆炸。
- 模型选择工具容易“晕”,常出现幻觉调用。
Tool Retrieval 的做法是:
- 针对每个工具建一条
ContextItem(type="tool"),内容包含:- 工具用途说明、典型参数、失败案例说明。
- 工具 Playbook / Guideline 也建成独立条目。
- 在对话中:
- 先对 Query 做一次“工具域”的语义检索,只召回 Top-k 工具 + Playbook。
- 把这些内容拼接进上下文,让模型在“小工具集合”里选择。
伪代码示意:
def select_tools_for_turn(query: str, max_tools: int = 3):
q_vec = embed(query)
# 在工具库中检索(可混合向量 + BM25)
candidates = tool_store.search(q_vec, top_k=20)
# 规则:优先带有高评分 Playbook 的工具
scored = rerank_by_playbook(candidates)
return scored[:max_tools]
Agent 执行循环时,引入一层“工具选择”中间件:
def agent_step(user_query: str, history: list):
# 1. 决定是否需要工具(fast heuristic or LLM call)[page:1]
if should_use_tool(user_query):
tools = select_tools_for_turn(user_query)
else:
tools = []
# 2. 向 Context Engine 请求知识 + 记忆
ctx = context_engine.query(user_query,
need_knowledge=True,
need_memory=True,
need_tools=False)
# 3. 把工具说明一起塞入上下文
full_ctx = assemble_llm_context(history, ctx, tools)
return call_llm(full_ctx)
四、多模态 RAG:什么时候值得上,怎么不上“死”
4.1 什么时候值得用多模态 RAG
从当前公开基准(如医学场景 M3Retrieve)与业界实践看:
- 图文都重要的场景:
- 医学影像 + 报告、图表密集的财报 / 设计图纸、工艺流程图。
- 多模态 RAG 明显强于“纯文本 + OCR”。
- 文本主导的场景:
- 普通 FAQ、产品手册、普通合同。
- 目前成熟的文本 RAG 足够用,多模态未必带来显著增益。
因此可以简单归纳为:
- 你的关键问题是否“看图说话”?是 → 值得考虑多模态 RAG;否则先把文本 RAG 打磨好。
4.2 张量索引的工程地狱:存储与计算
以一页 PDF 转图片、用多模态模型生成 1024 个 Token、每个 128 维 float32 为例:
- 单页张量大小约 512 KB。
- 百万页文档 → 原始索引体积 TB 级。
- 再叠加图像 + 文本双通道,成本更高。
常见工程解法有三条路径:
-
多比特 / 二值量化
- 把向量量化为低比特表示(甚至 1 bit);
- 存储降到原来的 1/32,代价是精度损失,需要模型侧配合做鲁棒训练。
-
减少 Token 数量
- Token 聚类:对 1024 个 Token 做聚类,用几十个中心代替。
- 随机投影 / MUVERA:把多 Token 压到一个大维度向量。
- 模型端 Token 剪枝:训练模型只吐出“关键 Token”。
-
召回+重排两级结构
- 召回阶段用轻量索引(全文 / 单向量);
- 只对 Top-k 结果用张量重排器做精排。
实战建议:
- 没有明确的图像强需求时,不要提前 All-in 多模态。
- 真要上,优先“文本 + 页级张量重排”的折中方案,而不是一上来就做“全量张量检索”。
五、2026 年落地策略:从“拼模型”到“拼上下文”
从 2025 的演进可以看出,一条很清晰的路线:
- 模型层在不断内卷,而真正决定体验与 ROI 的,是上下文层的质量。
- RAG 不再是“问答小模块”,而是承载知识、记忆、工具三类数据的 Context Engine。
如果要在 2026 年系统性推进这条线,建议按下面的优先级落地:
-
先把 PTI 流水线搭起来
- 目标:稳定 ingest 企业的 PDF/Word/网页/代码等,抽出结构化文本 + 基础语义增强。
- 指标:日常增量文档自动入库、失败可观测、切片与索引可灰度调整。
-
再升级“问答知识库”为“统一检索中台”
- 同一套检索服务,支持 FAQ、文档问答、内部搜索等多应用接入。
- 指标:索引、Rerank、日志分析等都集中在一套 Infra 上运维。
-
引入 Memory 与 Tool Retrieval,把 Agent 的“外脑”收回到中台
- Memory:把 Agent 历史对话与状态接到同一检索内核;
- 工具:给 MCP / 内部 API 建工具索引与 Playbook 检索。
- 指标:新 Agent 项目不再自己维护工具清单与记忆逻辑,而是声明式配置使用统一 Context Engine。
-
视业务需求再考虑多模态 RAG 与张量检索
- 优先在强需求垂直场景试点,如医疗、设计、工业文档。
- 逐步演进索引与模型,而不是一次性改造全站。
