Simon Willison 很长一段时间都避免用智能体这个词,因为每个人说的都不是一回事。他陆续收集了 211 个定义,分组整理,到 2025 年 9 月终于写下自己认可的一句。
An LLM agent runs tools in a loop to achieve a goal.
翻成中文是,大模型智能体在一个循环里调用工具,去完成一个目标。他说这个说法在 AI 工程圈已经基本成了共识,Anthropic 也在用。
这句话有三个部分,工具、循环、目标。顺着这三样往下讲,智能体是怎么从一个只会续写文字的模型长出来的就比较清楚了。
模型只做一件事
大语言模型再强,做的也只是一件事,给它一段文字,它预测接下来的文字。
你问法国的首都是哪里,它输出巴黎,是因为在它学到的语言规律里,这个问题后面最常接的就是这个答案。它没查资料。每次调用都是独立的,它不记得上一次;它不能上网,读不到你的文件,不能执行代码,也不知道今天几号。
这样已经能做很多事,写作、翻译、总结、写代码片段、回答知识问题。可它只能输出文字,对外面的世界产生不了任何作用。它写的代码,要你复制进编辑器;它建议的命令,要你自己去终端跑;它说你可以查一下某个文档,查的还是你。人是模型和世界之间唯一的桥。
工具调用
变化从模型学会调用工具开始。
做法不复杂。给模型的输入里,除了你的问题,还附一份工具清单,写明每个工具的名称、用途和参数格式。
可用工具
- read_file(path) 读取文件内容
- run_command(cmd) 在终端执行命令,返回输出
- search_web(query) 搜索网页模型经过专门训练,需要的时候不直接回答,改为输出一段结构化的调用请求,比如调用 read_file,参数是 src/index.ts。
模型自己并没有去读文件,它只是说它想读。读文件的是运行模型的那个程序,它看到请求,执行操作,把文件内容当作新的输入交回给模型。模型看到内容后再决定下一步,直接回答,或者再调一个工具。
这个机制一般叫 function calling 或 tool use。模型从此能拿到训练数据以外的信息,也能对外面的世界做点什么。
放进循环
只调一次工具,还算不上智能体。把调用放进循环里,情况就不一样了。
用户给出任务
↓
┌─→ 模型判断下一步做什么
│ ↓
│ 要调用工具吗 ──否──→ 给出结果,结束
│ │是
│ ↓
│ 执行工具,拿到结果
│ ↓
└── 把结果交回模型修一个 bug 可能是这样走的。模型先决定跑一遍测试,结果是 auth.test.ts 第 42 行断言失败。它去读这个测试文件,看到测试期望返回 401,又去读被测的 auth.ts,发现缺了过期检查。改完再跑一遍测试,全部通过,最后告诉你原因。
每一步做什么,都是模型看了上一步的结果才决定的,没有人事先写好先跑测试、再读测试文件、再读源码这个顺序。第一步的结果换一个,后面就完全是另一条路。智能体和普通程序的区别就在这里。
2022 年的 ReAct 论文最早系统地写过这种推理和行动交替进行的做法。Claude Code 的文档把它的循环描述成三个阶段,收集上下文,采取行动,验证结果,三者互相交织,模型在整个过程里一直在用工具。
Willison 定义里的目标,作用是让循环有个尽头,不会无限跑下去。他特意没规定目标必须由用户来定,因为子智能体的目标常常是另一个模型给的。记忆的问题,他认为循环里已经有短期记忆,前面几步的对话就是;长期记忆可以再加一组工具来实现。
工作流和智能体
Anthropic 在 2024 年 12 月发表的《Building effective agents》里,区分了两类系统,这个区分到现在还是理解这个领域最好用的框架。
工作流是用事先写好的代码路径,把大模型和工具编排在一起。每一步做什么由开发者决定,模型只负责其中某些步骤的具体内容。智能体则由模型自己决定流程和工具怎么用,开发者提供工具和目标。
文章列了几种常见的工作流模式。
| 模式 | 做法 |
|---|---|
| 提示词链 | 把任务拆成几个顺序步骤,每步之间可以加检查 |
| 路由 | 先给输入分类,再交给对应的专门流程或模型 |
| 并行 | 子任务同时跑,或者同一任务跑几遍再投票 |
| 编排者和执行者 | 一个模型临时拆分任务,分给几个执行者,最后汇总 |
| 评估者和优化者 | 一个模型生成,另一个模型挑毛病,循环改进 |
两类系统各有用处。工作流成本低,结果可预测,出错时容易找到是哪一步。智能体成本高,步骤不确定,错误还可能一步步累积,适合步骤没法事先确定、需要看中间结果再调整的任务。文章给的建议是先找能用的最简单的方案,一次模型调用加上好的检索能解决,就别上智能体。复杂度确实能带来可测量的提升时再加。
还有一条经验跟编程直接相关。Anthropic 做 SWE-bench 智能体时,花在工具上的时间比花在整体提示词上的还多。模型离开根目录后用相对路径老出错,他们就把工具改成必须传绝对路径,之后模型就没再错过。工具定义值得和主提示词一样认真写。
为什么编程跑在最前面
修 bug、加功能、重构,这些任务的步骤几乎没法事先定好。不知道 bug 在哪,就不知道该读哪些文件;不知道改完会影响哪里,就不知道该跑哪些测试。工作流在这里帮不上忙,正好是智能体的用武之地。
编程又刚好有几个让智能体能稳定干活的条件。代码、配置、日志、命令输出都是文本,正是模型最擅长的东西,不用像操作图形界面那样去认屏幕上的按钮。终端、git、编译器、测试框架,几十年下来积累了大量成熟的命令行工具,智能体直接用人用的那一套就行。
最重要的一条是结果能检查。能不能编译,测试过不过,类型检查报不报错,都有自动化的判断,智能体可以自己验证,错了就改。一份市场分析报告写得好不好,就很难这样自动判断。再加上有 git,改坏了能退回去,犯错的代价相对可控。
Claude Code、Codex、Cursor、Gemini CLI 都是为编程专门打造的智能体,一个强模型,一组为软件开发设计的工具,再加上管理上下文、权限和验证的那一层。
| 层次 | 做什么 | 你能影响的部分 |
|---|---|---|
| 模型 | 理解任务,推理,决定下一步 | 选哪个模型,推理力度 |
| 工具 | 读写文件、执行命令、搜索、联网 | 接 MCP Server,允许哪些命令行工具 |
| 上下文管理 | 决定模型每一步看到什么,压缩历史 | 项目说明,开新会话,主动压缩 |
| 知识 | 项目约定、流程、领域知识 | CLAUDE.md、AGENTS.md、Skill |
| 权限与安全 | 什么能做,什么要问,什么禁止 | 权限规则,沙箱 |
| 扩展点 | 在特定时刻插入自定义逻辑 | Hooks,子智能体 |
模型只是其中一层。同一个模型在不同产品里表现差很多,原因多半在其他几层。这几层分别对应上下文工程和 Harness 工程两篇。
多个智能体一起干活
子智能体是最常用的一种。主智能体把子任务交给一个有独立上下文的智能体,只拿回结论。主要是为了隔离上下文,搜索、大量读文件这类会产生一大堆中间信息的活放到别的窗口里去做。
并行是另一种,几个智能体同时处理互不相干的任务,比如在不同的 git worktree 里各修一个 bug,为的是快。
一个做、一个查,也很常见。检查的那个只看要求和结果,不参与过程,判断更客观,Loop 工程里的验证环节就常这样设计。
多智能体听上去很强,用的时候要谨慎。每交接一次都会丢信息,协调本身也很费 token。很多时候,一个配置得当的单智能体比一套复杂的多智能体系统更可靠。
几个常见的误会
智能体的上限由模型决定,但智能体是一种用模型的方式。同一个模型可以拿来一问一答,也可以放进循环里当智能体。
现在好用的编程智能体,人仍然在循环里。给任务,批准危险操作,方向错了拉回来,最后审结果。全自动更像光谱上的一个位置。
模型的权重不会在使用中改变。智能体在你的项目里越来越顺手,是因为它的环境在变好,项目说明补全了,Skill 写了,测试加了。这些改进会一直累积,但得有人去做,或者设计一个循环去做。
一个能执行任意命令、能联网、能读你所有文件的程序,本身就是一个安全问题。它处理的内容来自外面的时候更要小心,网页、issue、邮件里都可能藏着想操控它的指令。权限控制和沙箱是必需品。
智能体最常用的两种扩展,一种给它知识和流程,见Agent Skills 是怎么设计的;另一种让它连上外部系统,见MCP 是怎么设计的。
参考资料