LangChain 详解 AI 智能体上下文工程:如何通过检索优化解决上下文膨胀
Context Engineering (Agent Memory) for AI Agents Starts with Retrieval
LangChain 详解了 AI 智能体的上下文工程与记忆构建方法,指出高效检索是防止上下文窗口被冗余信息占满的核心前提。文章以竞争分析智能体为例,提出先用文件系统命令(如 glob 与 grep)替代全文加载,并在处理大结果集时采用返回文件路径而非全文的卸载模式。此外,通过让子智能体并行阅读文件并仅向上层汇报结论,可有效隔离过时与无关上下文对主智能体的干扰。
文章给出了通过文件指针卸载结果和委托子智能体过滤的检索模式,可直接迁移至复杂长流程 Agent 的上下文控制中。
设想一下你正在参加一场开卷考试:所有答案你手头其实都有,但正因如此,想找出那个真正正确的答案反而更难了。
- 该从哪里开始找起?
- 又怎么确认手头的资料准不准?
- 怎样合理分配时间,才不至于把精力全耗在无意义的重复检索上?
高效找到所需的信息,从来都不是一件简单的事。
如果把问题交给智能体,它也会面临类似的困境:由于上下文窗口有限,它不可能把所有内容全装进脑子里,而是必须像人类一样靠检索信息来完成特定任务。而在检索过程中,智能体往往会遇到以下痛点:
- 检索效率低下:每一次搜索都在消耗 token 和时间。如果智能体的检索策略很笨拙(比如挨个打开文件只为看眼内容,或者翻来覆去换着说法搜同一个问题),往往还没查到任何有用信息,上下文窗口就已经被无效搜索结果塞满了。
- 一次性塞入过多上下文:只要一次检索直接倒进来一整份导出数据或十几份文档,就能瞬间吃满上下文窗口,导致后续任务根本没有施展空间。
- 混入无关或过期的上下文:在模型眼里,过时或跑偏的信息可能和正确答案一样“可信”。一旦这类内容进入上下文窗口,智能体就会顺着它继续推理,从而导致后面的每一步都一错再错。
好在,智能体也有不少应对招数,可以精准检索到正确的信息。而 智能体运行框架(agent harness) 的职责,正是灵活运用这些技术策略,确保模型能在执行具体任务时在对的时间拿到对的上下文。
.png&mode=full&exp=1794700800&sig=9dd69ebc930c2cc4)
本文将深入探讨智能体检索面临的挑战(即如何做到只精准抓取当前任务必需的信息)、可供使用的应对方案,以及在设计智能体框架时该如何考量这些问题(文中将以 LangChain 的 Deep Agents 框架为例展开)。
如果你想了解信息进入上下文窗口之后该如何管理,可以参阅这篇关于上下文工程的博文。
实战案例:竞品分析智能体
我们来看一个真实应用场景:竞品分析智能体。每周一,该智能体都要对上百家竞品展开调研,并按团队的模版输出一份报告。它需要完成以下任务:
- 找出上周关于 A 公司的笔记
- 在庞大的市场数据导出文件中,查找某个具体的营收数字
- 在新闻存档库中检索最新动态
这三项任务对应着不同的检索模式,面临的痛点也各不相同。我们基于 Deep Agents 框架构建了这个智能体,因此开箱即可调用几种技术方案,最大程度规避这些问题。
1. 检索效率低下
智能体需要为每家竞品查找三类信息。如果每查一项都要试上十几次(比如挨个打开文件看内容,或者因为原始资料用词不同而反复修改搜索词),那么报告还没写出一个字,上下文窗口就已经被这些无功而返的检索记录填满了。
因此,最理想的检索是无需反复重试的检索,而这就意味着必须针对不同任务选对工具。
从内置的文件系统工具开始
利用文件系统检索信息,是智能体最常用的方式之一。然而,如果智能体每份文件都要点开看一眼,检索效率就会极其低下:每读一份文件,其内容就会塞进上下文窗口,仅仅是翻看这一步,就能把上下文撑爆。
更好的做法是先查文件名和关键词(就像开卷考试时先翻书后的索引,而不是一页一页去通读)。文件系统中就有两个现成的工具能做到这一点:
glob用于按名称规则查找文件。比如,用**/company-a*.md就能找出上周记录的关于 A 公司的笔记。grep可以在不把文件整个塞进上下文窗口的前提下搜索文件内容。它按字面文本进行匹配,能返回匹配的文件列表、具体行内容或匹配次数。

每个 deep agent 都内置了这些工具,此外还配有 ls、read_file、write_file 和 edit_file。无论文件存放在哪里(智能体状态、本地磁盘、持久化存储还是沙盒),这些工具都能正常工作,因为它们都经由智能体的后端统一调用。
关键词不够用时,引入检索工具
当你确切知道要搜哪些字词时,Grep 非常好用,但它只能字面完全匹配。在我们前面提到的第三个任务中,这就成了一个问题:要从新闻归档库中找出最新动向,如果智能体用 grep 搜索“Company A funding”(A 公司融资),就会漏掉标题为“Company A closes $50M Series B”(A 公司完成 5000 万美元 B 轮融资)的文章,哪怕这正是它想要的内容。
如果想按语义而不是精准字词来搜(即语义搜索),可以挂载一个基于向量数据库的检索工具。检索工具泛指智能体可以调用来拉取信息的工具:接收一条查询,在特定数据源中检索,然后返回最相关的匹配结果。
.png&mode=full&exp=1794700800&sig=7436aa2728c086ae)
不过在换用语义搜索之前,也可以先试试同义词。Grep 确实只能死板地按字面匹配,但负责挑词的智能体其实知道“funding”(融资)可能还会写作“Series B”(B 轮)或“raised”(融得)。只要在搜不到时提示它换换说法,它就会按不同词逐个去 grep。针对团队特有的黑话(比如内部产品代号),可以整理在 skill(技能)里。只要用词可预测,这种方法就很奏效;如果用词不可控,就必须用语义搜索了。
检索工具如何匹配,完全取决于背后的数据源。基于向量数据库时,它按语义匹配;但检索工具同样可以对接其他数据源:
- SQL 数据库:用于结构化查询(例如销售数据或客户记录)
- 搜索 API:用于获取网络上的最新信息
- MCP 服务器:用于接入现成工具(例如现成的文档搜索服务)
.png&mode=full&exp=1794700800&sig=a3f870b20a385c9e)
想深入了解语义搜索的原理,可以参考 LangChain 的指南。
把搜索时机交给智能体自己判断
许多检索方案的做法是在最开始检索一次,然后直接生成回答。做问答机器人(两步 RAG)这样没问题,但用在我们的智能体上就行不通了。假设智能体在调研 C 公司中途,看到了一篇自己此前毫不知情的产品发布文章,这时它就需要去查该产品的定价——而在最初检索时,它根本不可能预料到这一点。如果只搜一次,最终报告就会漏掉这项关键信息。
调研类智能体需要的是智能体化检索(agentic retrieval),而非固定的两步 RAG:由智能体自主决定何时发起搜索、搜索什么内容,以及是否还需要更多信息。在 Deep Agents 中,这套逻辑已经是默认行为:智能体以循环方式运行,可以根据需要随时、反复调用任何工具。
.png&mode=full&exp=1794700800&sig=3f2e132bd6c55c53)
把搜索技巧打包成技能
为了帮智能体搜得更准,你可以把搜索经验打包成一项 skill:即针对特定任务的一套操作指引(比如该查哪个索引、查询该怎么措辞,以及如何规范引用格式)。
智能体平时只能看到每项技能的名称和简要描述,只有当任务明确需要时才会加载完整指令。这样一来,冷门专业知识只在需要时提供,平时不会白白占用上下文空间(这种技术被称为渐进式披露)。这里有一段视频讲解。
.gif&mode=full&exp=1794700800&sig=721855f308939ab3)
2. 一次性塞入过多上下文
然而,即便优化了搜索流程,哪怕搜得完全准确,返回的内容也可能多到失控。比如,智能体只需要市场数据导出表中的一个数字(B 公司的季度营收),但若为了找出这个数字而加载整整 4 万行数据,就会直接挤爆上下文窗口。检索工具也面临同样的问题:如果直接把每篇新闻报道都塞给模型,5 家公司每家返回 4 篇,上下文消耗就会迅速失控。
分页读取大文件
文件系统工具的设计原则是尽量少返回内容。read_file 每次只读取一页文件(默认 100 行),智能体可以通过设置 offset(起始行)和 limit(读取行数)直接跳转到所需位置。因此,要查找 B 公司的营收,智能体只需用 grep 过滤定位,然后仅读取匹配行周边的几行内容即可。

让执行框架转储超大结果
有时工具返回的内容无论如何都会超出预期。当工具输出过大(超过约 20,000 个 token)时,执行框架会将其保存到 /large_tool_results/ 目录下的文件中,并只向智能体返回文件路径和简短预览(前几行与后几行)。随后,智能体便可利用 read_file 的 offset 和 limit 参数,仅按需读回自己想要的部分。
.png&mode=full&exp=1794700800&sig=a9db97c34b1a48b6)
让检索工具直接返回文件路径
你也可以将这种思路直接应用到自己的检索工具中,而不必被动等待触发大小限制:让工具把每个结果写入文件,只向外返回路径。这就是“检索、转储、委派”(retrieve, offload, delegate)模式的第一步(LangChain 的 RAG 指南对此有完整介绍)。

下面是一个简化版的检索工具。它负责执行搜索,将每条结果作为文件存入智能体的后端,并仅返回文件路径列表:
backend = StateBackend()
@tool
def search_news(query: str) -> str:
"""Search the news archive and save each result to a file."""
docs = vector_store.similarity_search(query, k=4)
files = [(f"/retrieved/result_{i}.md", doc.page_content.encode()) for i, doc in enumerate(docs)]
backend.upload_files(files)
return "Saved results to: " + ", ".join(path for path, _ in files)
这样一来,主智能体看到的只是 4 条简短的文件路径,而不是 4 篇完整的新闻报道。
3. 无关或过期的上下文
如果检索到的内容本身是错的,体积再小也没用。上述 4 个文件中,任何一个都可能讨论的是同名同姓的另一家公司,或者是一篇两年前的旧闻。对于模型而言,偏离主题或陈旧过时的文本看起来和正确答案一样可信,因此我们的目标是彻底避免它们进入主智能体的上下文。
让子智能体过滤结果
然而,主智能体依然需要阅读这些文件才能分辨哪些有用(而它打开的每一篇无关报道都会进到自己的上下文中)。这正是“检索、转储、委派”模式中“委派”发挥作用的地方:由子智能体去读取每个检索出来的文件,并且只返回关键事实。
- 定义子智能体:描述信息告诉主智能体何时调用它(每次调用处理一个文件),系统提示词则告诉子智能体如何处理该文件。
chunk_analyst = {
"name": "chunk-analyst",
"description": "Analyze one retrieved file. Pass the question and a single path under /retrieved/.",
"system_prompt": "Use read_file to read the assigned file. Return the key facts and the source URL.",
}
- 将检索工具和子智能体一并交给主智能体,并传入在
search_news中使用的相同后端,以便子智能体能够读取该工具保存的文件。
agent = create_deep_agent(
model=model,
tools=[search_news],
backend=backend, # same instance, so read_file can see /retrieved/
subagents=[chunk_analyst],
)
现在的流程变为:
- 搜索:主智能体调用
search_news并获取 4 条路径。 - 委派:主智能体将各条路径分发给 chunk-analyst 子智能体,各子智能体可以并行处理。
- 综合汇总:每位分析员返回一份简短摘要并附上来源。主智能体将它们整合在一起,如果发现遗漏,就继续发起检索。
.png&mode=full&exp=1794700800&sig=fe331e8f61802771)
原始结果直接写入文件,包含大量杂音的阅读环节交给拥有独立上下文窗口的子智能体处理,主智能体自始至终只看结论。任何偏离主题的内容都会被留在子智能体的上下文中,主智能体的上下文窗口则始终保持干净!
从最新数据源获取信息
过滤机制确实能挡掉无关内容,却解决不了信息过时的问题。比如我们的竞品分析智能体每周一运行一次,上个月建好的索引自然抓不到这周的新动态。
解决方案是:借助搜索 API 或 MCP 服务器,智能体就能获取实时动态,而不是几个月前建索引时的陈旧数据。如果数据中包含日期,直接在检索工具里按日期筛选,也能将过时结果排除在外。
有时索引里会同时存在一份文档的新旧两个版本,而且老版本往往更容易被检索出来——因为旧文档通常篇幅更长、细节更多,排序反而更高。换作人来看,一眼扫到“上次更新于公元前 12 年”就会直接跳过,但文档在切块存入向量数据库时,这类日期信息往往就丢失了。如果你的检索工具能拿到日期,请务必把它包含在返回的文本中,方便模型识别。然后让子智能体在返回关键事实的同时附带日期,并对疑似过时的内容打上标记。
谨慎对待检索到的文本
另一方面,即使检索到的内容既相关又最新,也同样可能引发问题!检索出的文本属于外部数据而非系统指令,你检索到的任何内容都可能藏有提示词注入攻击(而且没有任何提示词设计或分隔符策略能做到绝对防御)。因此务必做好输出校验:确认答案引用的确实是预期的来源,并核对论断是否与来源一致。
值得留意的检索策略
无论你基于什么框架构建,以下几点都值得关注:
- 优先选用最轻量有效的工具。如果明确知道关键词,grep 远比向量嵌入查找更管用。把语义搜索留到真正需要的时候再用。
- 分页读取,避免全量加载。大文件要分块切片读取,不要一次性全部载入。
- 返回指针,而非全部载荷。将检索内容写入文件,仅向智能体传递文件路径即可。
- 分流阅读任务。让子智能体负责阅读和总结,主智能体只接收最终结论。
- 核验事实依据。将生成的答案与检索到的原始内容进行比对校验,时刻将检索文本视为不可信数据。
动手试试
uv add deepagents
我在之前的研讨会中详细讲过这一主题,点击这里查看!
检索只解决了一半的问题,即信息如何传递给智能体。那么,随着时间推移、信息不断累积,我们又该如何管理智能体的上下文窗口?
了解更多详情,请查看:
- 关于Deep Agents 上下文工程的博文
- LangChain Academy 上的 Deep Agents 课程(免费、在线且支持自主掌握进度)。
来源:LangChain Blog · langchain.com