扩展 LLM 的能力边界:联网搜索、文件读写与记忆功能全景指南
引言
上一篇我们聊了 Function Calling 诞生的背景——LLM 为什么必须学会调用函数。这篇更进一步,把问题摊开:
一个只会输出文本的模型,如何长出"眼睛"、"手"和"记忆"?
- 联网搜索给它眼睛,让它看到训练数据截止之后的世界;
- 文件读写给它手,让它能在真实工作环境中留下成果;
- 记忆功能让它跨越会话,记住你是谁、上次做到哪一步。
这三项能力,加上代码执行和 MCP 协议的标准化,构成了今天所有 AI Agent 的地基。本文逐项拆解它们的原理、实现路径和工程上的坑。
TL;DR
LLM 的能力扩展,本质是同一个模式:把外部能力封装成工具,让模型决定何时调用,执行结果再回到上下文。
| 能力 | 解决什么问题 | 核心实现 |
|---|---|---|
| 联网搜索 | 知识有截止日期、幻觉 | Web Search API + RAG |
| 文件读写 | 无法操作真实工作环境 | 文件系统工具 + 沙箱隔离 |
| 代码执行 | 算不准、不能验证 | Code Interpreter / Bash 沙箱 |
| 记忆功能 | 关掉窗口就失忆 | 短期记忆 + 长期记忆(向量库 / 结构化文件) |
| MCP | 工具接入碎片化 | 标准化协议,一次开发到处可用 |
一切扩展的基础:工具调用循环
无论扩展哪种能力,底层都是同一个循环(ReAct 模式的简化版):
用户提问
↓
模型判断:需要外部能力吗?
↓ 是
生成工具调用请求(函数名 + 参数 JSON)
↓
宿主程序(Harness)真正执行工具
↓
执行结果注入上下文
↓
模型基于结果继续推理 / 再次调用工具 / 给出最终回答
关键认知:模型本身从不执行任何操作。 它只生成"我想调用 search_web(query='...')"这样的结构化文本,真正干活的是模型外面的宿主程序。模型是大脑,工具是感官和四肢,宿主是连接它们的神经系统。
理解这一点,后面每一项能力扩展都只是"往工具箱里放一件新工具"。
一、联网搜索:打破知识的截止日期
为什么需要
LLM 的训练数据有截止日期。问它"今天的股价"、"最新的 API 文档"、"这个 CVE 漏洞的细节",它要么编造,要么承认不知道。而搜索引擎背后是实时索引的整个互联网。
两种实现路径
路径一:模型内置搜索(Search as a Tool)
模型厂商把搜索做成官方工具:模型自主决定搜索关键词,平台执行后把结果喂回去。优点是零接入成本;缺点是搜索源和质量不可控,且通常按次计费。
路径二:自建 RAG 检索管道
def search_web(query: str, top_k: int = 5) -> list[dict]:
"""自定义搜索工具:搜索 → 抓取正文 → 截断摘要"""
results = search_engine.query(query, limit=top_k) # Bing/Google/Tavily/SearXNG
return [
{
"title": r.title,
"url": r.url,
"snippet": fetch_and_extract(r.url)[:2000] # 控制 token 消耗
}
for r in results
]
自建的价值在于可控性:你可以限定搜索源(比如只查内部文档站)、决定摘要长度、做去重和时效过滤。
工程上的三个坑
- 上下文爆炸:一个网页正文可能上万 token,直接塞进上下文既烧钱又稀释注意力。必须做正文提取和截断。
- 时效标注:搜索结果要带上抓取时间,模型才能判断"这条信息是否新鲜",否则它可能拿三年前的价格回答今天的问题。
- 来源引用:要求模型给出信息来源 URL,既是可验证性的要求,也能显著降低幻觉率。
二、文件读写:给模型一个真实的工作环境
为什么需要
没有文件系统,LLM 产出的一切都只是对话窗口里的文字——关掉就没了。有了文件读写,它才能:
- 把中间结果落盘,突破上下文窗口限制(写出去,需要时再读回来);
- 直接操作项目代码、文档、数据文件,产出可用的交付物;
- 多个 Agent 之间通过文件协作(文件即共享白板)。
最小实现
def read_file(path: str) -> str:
"""读取文件内容"""
return Path(sandbox_root, path).read_text(encoding="utf-8")
def write_file(path: str, content: str) -> str:
"""写入文件,返回确认信息"""
target = Path(sandbox_root, path)
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(content, encoding="utf-8")
return f"已写入 {path}({len(content)} 字符)"
加上 list_files、edit_file(精确替换,比全量重写省 token)、search_files(grep),就是一个够用的文件工具集。
三个必须做的防护
- 路径沙箱:所有路径必须限制在工作区根目录内,拒绝
../越界。模型生成的路径不可信。 - 读写分离:读取相对安全,写入要有分寸——大文件截断读、二进制文件拒绝、敏感文件(
.env、私钥)黑名单。 - 变更可回滚:配合 Git,让模型大胆改,人类一键回滚。文件系统 + Git = 模型的试错空间。
三、代码执行:从"会说"到"会做"
严格说这不是用户点名的能力,但它是文件读写的天然搭档,值得一并讲。
模型心算三位数乘法都经常出错,但它写的代码可以算得很准。代码执行把模型从"估算器"变成了"真正的计算器 + 实验员":
- 数据分析:写 pandas 脚本处理 CSV,而不是逐行"心算";
- 自我验证:写完代码跑一遍,报错了自己修——这是 Agent 能迭代进步的关键;
- 产出真实交付物:生成的图表、报表直接保存为文件。
实现上通常是 Code Interpreter(受控 Python 环境)或 Bash 工具 + 容器沙箱。安全是头等大事:沙箱内不挂载敏感目录、限制网络访问、限制 CPU/内存/时长,必要时用 rootless 容器或微 VM。
四、记忆功能:跨越会话的连续性
为什么需要
LLM 的上下文窗口就是它的全部"工作记忆"。窗口之外,一片空白。没有记忆系统,每次对话都从"你好,我叫……"重新开始,复杂的长期项目根本无从谈起。
记忆不是单一技术,而是一套分层体系:
第一层:短期记忆(上下文内)
当前会话的对话历史,模型的"工作台"。管理重点是上下文工程:该保留什么、压缩什么、丢弃什么。长会话中常见的做法是滑动窗口 + 摘要压缩——把前面的对话总结成几段摘要,只保留最近几轮原文。
第二层:长期记忆(跨会话持久化)
两种主流形态,各有利弊:
① 向量记忆(语义检索派)
def memory_search(query: str, top_k: int = 5):
"""语义检索:把过往对话/笔记向量化,按相关度召回"""
embedding = embed(query)
return vector_db.similarity_search(embedding, k=top_k)
- 优点:召回语义相关的内容,即使用词完全不同
- 缺点:是"黑盒",难以审计模型到底记住了什么;过期信息难清理
② 结构化文件记忆(笔记派)
让模型像人一样记 markdown 笔记:
memory/
├── user-profile.md # 用户偏好、习惯、项目背景
├── decisions.md # 做过的关键决策及原因
└── projects/
└── blog-rewrite.md # 每个项目一份进展笔记
- 优点:完全透明、可编辑、可 Git 版本化;人能直接看到 AI"记得"什么
- 缺点:依赖模型自觉维护,检索靠文件索引而非语义匹配
工程实践中两者常混用:重要事实写结构化笔记,海量历史对话进向量库,启动会话时加载笔记 + 按需检索向量库。
记忆工程的两个关键设计
- 记忆写入策略比读取更难。什么值得记?常见规则:用户明确说"记住这个"、纠正过模型的错误、跨会话仍有效的偏好。什么都记 = 记忆库变成垃圾场,召回质量直线下降。
- 遗忘和更新必不可少。偏好会变("我现在改用 pnpm 了"),记忆必须支持更新和过期,否则旧记忆会和新指令打架。
五、MCP:让工具生态标准化
前面讲的每一项能力,传统做法都是在自家代码里手写工具定义、手写 JSON Schema、手写执行逻辑。换个 Agent 框架就得重写一遍。
Model Context Protocol(MCP) 是 Anthropic 在 2024 年底开源的协议,思路类似编程语言里的 LSP(Language Server Protocol):
传统模式: Agent A ──┐
Agent B ──┼── 各自实现一套 GitHub / 数据库 / 文件系统接入
Agent C ──┘
MCP 模式: 任意 Agent ──统一协议── MCP Client ── MCP Server(GitHub)
├─ MCP Server(Postgres)
└─ MCP Server(文件系统)
- 工具提供方只写一次 MCP Server,所有兼容 MCP 的 Agent 都能用;
- Agent 开发方只需实现 MCP Client,瞬间接入整个工具生态;
- 工具列表在运行时动态发现,不用硬编码。
2025 年以来,OpenAI、Google 相继宣布支持 MCP,它已经成为事实上的工具接入标准。对开发者意味着:写工具的价值被放大了——你写的 MCP Server 不再绑定某一家 Agent。
组合起来:从工具到 Agent
单项能力是零件,组合起来才是机器。一个能干活的研究型 Agent 的典型工作流:
- 收到任务"调研 XX 技术并写一份报告";
- 记忆:加载用户偏好(报告要中文、要有 TL;DR);
- 联网搜索:多轮搜索、交叉验证、记录来源;
- 文件读写:调研笔记先落盘,分段写报告;
- 代码执行:做一张对比图表;
- 产出报告文件,更新记忆("用户对上一版报告的反馈是……")。
这就是 Agent 的本质:LLM + 工具 + 记忆 + 循环,缺一不可。
工程实践清单
如果你要给自己的应用加上这些能力,按这个顺序来:
- 先上工具调用循环——这是所有能力的地基,别跳过
- 联网搜索——解决幻觉和时效,收益最快见效
- 文件读写 + 沙箱——打开生产力场景,但先把路径隔离和黑名单做好
- 代码执行——配合文件能力,让模型能自我验证
- 记忆分层——短期靠上下文工程,长期先上结构化笔记,量大了再补向量库
- 工具协议向 MCP 靠拢——新工具直接写成 MCP Server,避免锁定
- 全程可观测——记录每一次工具调用的输入输出,这是调试和信任的基础
结语
回头看,LLM 能力扩展的历史就是一部"给大脑接器官"的历史:
- 搜索让它看到现在,
- 文件让它触摸世界,
- 代码让它验证自己,
- 记忆让它拥有过去,
- MCP 让这一切标准化、可复用。
模型负责推理,工具负责感知和行动,记忆负责连续性。三者齐备,"聊天机器人"才真正变成了"数字员工"。
相关阅读