01
Agent 是什么:一个公式讲清楚
AI Agent(智能体)是让大模型在循环里自主使用工具、朝目标推进的系统。一个值得背下来的公式:Agent = LLM(大脑)+ 工具(手脚)+ 循环(心跳)+ 目标(方向)。LLM 负责判断下一步做什么,工具给它真正改变世界的能力,循环让「做一步、看结果、再决定」成为可能,目标则定义了「做完」长什么样。
它和上一篇的对话助手有什么不同?聊天机器人的世界是一问一答:你发消息,它回文本,交互结束。Agent 的世界是接活—干活—交差:你说目标,它自己拆步骤、调工具、看结果、修正方向,直到完成或需要你拍板。读文件、跑命令、查网页、写代码,都是它的「手」。用一张表看三种形态的边界:
| 形态 | 特征 |
|---|---|
| 聊天机器人 | 一问一答,只产出文本,不改任何东西 |
| 固定工作流(LLM 链) | 人预先写死步骤,模型只负责其中几步 |
| Agent | 只给定目标与工具,步骤由模型现场决定 |
最后一行就是分水岭:步骤谁说了算。步骤是人写的叫工作流,步骤是模型看着办的就是 Agent。自由度更高,不可预测性也更高——第 07 节的所有刹车,都是为这一行字准备的。
为什么这件事最近两年才真正成立?2022 年 ReAct 论文给出「推理与行动交替」的经典循环;2023 年 6 月 OpenAI 给 API 加上 function calling,工具调用第一次有了标准接口;2024 年 11 月 Anthropic 开源 MCP 协议,工具生态开始互通;再加上 Claude Code、Codex 这类编程智能体把「循环+工具」打磨成了日用产品——四块地基同时就位,Agent 才从论文走进日常。
再泼一盆冷水:不是所有任务都该上 Agent。步骤固定、追求稳定的活(每天抓一次数据、固定格式翻译)用工作流更便宜、更可控;步骤没法预先写死的活(修一个还没定位的 bug、调研一个开放问题)才是 Agent 的主场。判断标准就一条:你能预先写出步骤清单吗?能,写工作流;不能,交给 Agent。
- 组成公式
- LLM + 工具 + 循环 + 目标
- 标志性论文
- ReAct(Yao et al., 2022 · ICLR 2023)
- 工具调用标准
- function calling:OpenAI 2023-06 引入;Anthropic 称 tool use
- 工具互通协议
- MCP:Anthropic 2024-11 开源
- 代表编程智能体
- Claude Code · Codex · Kimi Code · OpenCode
- 与聊天机器人的区别
- 一次回答 vs 多步执行
- 自主档位
- 从「每步审批」到「全自动」连续可调
- 自我意识与自定目标
- 没有。它只优化你给定的目标
02
准备环境:三样东西,三条搭法
要亲手拆 Agent,只需要 Python、一个官方 SDK、一把 API Key。三种搭法按投入程度选:想读懂本页所有代码选 A 或 B,只想先体验选 C。
# 先建独立虚拟环境,别污染系统 Python python3 -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install anthropic export ANTHROPIC_API_KEY="sk-ant-..." # 控制台创建;Windows 用 setx # 验证 python3 -c "import anthropic; print(anthropic.__version__)"
python3 -m venv .venv source .venv/bin/activate pip install openai export OPENAI_API_KEY="sk-..." # Windows: setx OPENAI_API_KEY "sk-..." # 验证 python3 -c "import openai; print(openai.__version__)"
# 编程智能体是最成熟的 Agent 产品,装一个直接体验: # Claude Code / Codex / Kimi Code / OpenCode … # 安装与上手见本站对应专页: # claude-code.html · codex.html · kimi-code.html · opencode.html # 观察它们的共同内核:思考 → 调工具 → 观察 → 继续
三条路的共同前提只有一样:一把能用的 API Key(或一个已登录的终端 Agent)。环境就绪的标志是三件小事:Python 里 import 不报错、Key 在环境变量里、能用一句话换回模型的回答。
03
第一次工具调用:模型点菜,你来炒菜
Agent 与普通调用的全部区别,就在这一来一回:模型永远不执行工具,它只输出「我想调哪个工具、带什么参数」;真正动手的,是你的代码。先看 Anthropic 写法:
import anthropic client = anthropic.Anthropic() # 1) 把"菜单"声明给模型:名字 + 描述 + 参数 JSON Schema tools = [{ "name": "get_weather", "description": "查询指定城市的当前天气", # 这句是写给模型看的 "input_schema": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], }, }] messages = [{"role": "user", "content": "北京现在多少度?"}] resp = client.messages.create( model="claude-sonnet-4-5", # 以官方模型列表为准 max_tokens=1024, tools=tools, messages=messages, ) # 2) 模型只会"点菜",不会"炒菜" print(resp.stop_reason) # tool_use —— 它想调工具了 print(resp.content[0].name) # get_weather print(resp.content[0].input) # {'city': '北京'}
-
01
声明菜单
把每个工具的名字、用途、参数 Schema 随请求发给模型。
description写得越清楚,模型点菜越准——它是写给模型看的接口文档。 -
02
模型点菜
返回里出现
tool_use块:工具名 + 参数 JSON。注意此刻什么都没发生,模型只是「说」要调。 -
03
你来执行
你的代码真的去调天气接口,把结果包成
tool_result(带上tool_use_id)追加进对话。工具报错也如实回传——模型能根据报错改道。 -
04
循环到收工
把更新后的 messages 再发给模型。它看完结果要么继续点菜,要么给出最终回答——
stop_reason变为end_turn,循环结束。
OpenAI 兼容写法做同一件事,字段名不同、流程同构:
r = client.chat.completions.create(model=MODEL, messages=messages, tools=tools) msg = r.choices[0].message if msg.tool_calls: # 模型点了菜 messages.append(msg) for call in msg.tool_calls: args = json.loads(call.function.arguments) result = get_weather(**args) # 你来执行 messages.append({"role": "tool", # 回传结果 "tool_call_id": call.id, "content": result})
两家的「菜名」对照着记,看任何框架源码都不慌:
| 角色 | 字段名(Anthropic / OpenAI 兼容) |
|---|---|
| 声明工具 | tools=... / tools=...(这一项两家几乎同名) |
| 调用意图 | tool_use 块 / message.tool_calls |
| 参数包裹 | block.input / call.function.arguments(都是 JSON) |
| 结果回传 | tool_result 块(带 tool_use_id)/ role:"tool"(带 tool_call_id) |
| 收工信号 | stop_reason="end_turn" / finish_reason="stop" |
04
四大核心件:ReAct、工具调用、记忆、规划
4.1 ReAct:把「想」和「做」交替起来
ReAct = Reasoning + Acting。这篇 2022 年论文的核心发现是:让模型把推理写成文字(Thought)、再决定行动(Action)、然后观察结果(Observation),比一口气直接猜答案准确得多。原因不难理解:把「想」写出来,等于强迫模型分步检查自己的判断;而「观察」把真实世界的反馈接回上下文,模型不必靠想象答题。今天几乎所有 Agent 的主循环都是它的后代——包括 Claude Code 每次说「我来看一下这个文件」的那一刻。
Thought: 用户要找"处理登录的函数",应该先搜索代码 Action: grep(pattern="def login") Observation: auth/login.py:31 auth/oauth.py:88 Thought: 先读 auth/login.py Action: read_file(path="auth/login.py") Observation: def login(user, pwd): ... Thought: 找到了,可以回答 Answer: 登录逻辑在 auth/login.py 第 31 行,走的是表单校验……
对照第 03 节的 API 调用:Thought 和 Answer 是模型的文本输出,Action 对应 tool_use,Observation 就是你回传的 tool_result。论文里的三步,落在 API 上就是一次往返。
4.2 工具调用(function calling)怎么工作
模型在训练时见过海量「对话中插入工具调用」的样本,所以它天生会点菜。工程上要抓牢三件事:第一,工具由你执行,模型只输出调用意图;第二,参数是 JSON,用 Schema 约束格式;第三,工具描述是写给模型的接口文档——文档烂,点菜就烂。工具宜少而精,几十个语义重叠的工具会互相干扰。
# 坏:模型猜不出什么时候用、参数什么格式 "description": "读文件" # 好:说清用途、适用时机、限制、参数格式 "description": "读取本地文本文件内容。需要查看代码、配置或 数据文件时使用;不支持列出目录;path 用相对路径"
MCP(Model Context Protocol)把「怎么声明、发现、调用工具」标准化:工具方实现一次 MCP server,任何支持 MCP 的 Agent 都能用。你在本站各工具专页里看到的 MCP 配置,背后就是这个协议。
顺带认识两个进阶词:并行工具调用——模型一次点几道互不依赖的菜,代码并发执行能省一半时间;结构化输出——让模型按固定 JSON 格式作答,是「调工具」之外另一种受控输出。两者在各家 API 文档里都有专门章节。
4.3 记忆:短期靠上下文,长期靠外存
短期记忆就是上下文窗口:本轮对话、每一步工具结果全在里面——这也是为什么 Agent 越跑越慢、越跑越贵(每一步都带着全部历史重新发送)。窗口逼近上限就要压缩(很多 CLI 提供 /compact 类命令,摘要折叠旧内容)。
长期记忆靠外部存储:把结论写进文件、数据库或向量库,下次需要时用 RAG 检索回来。规律一句话:上下文是易失的工作内存,文件与数据库才是持久的。
1. 上下文窗口 : 本会话有效;满了就压缩或截断 2. 项目文件 : AGENTS.md / TODO.md —— 重启之后还在 3. 向量库 + RAG : 海量历史里按语义检索相关片段 # 压缩示例(各 CLI 命令名略有差异): > /compact 保留架构决策与未完成的 TODO
工程上的对应物你已经见过:终端 Agent 的 /compact 是落点 1 的维护命令,AGENTS.md 是落点 2 的标准文件名,而落点 3 就是本站反复出现的 RAG——三个落点各管一段时效,混着用最稳。
4.4 规划:把大目标拆成小步骤
复杂任务直接开干容易翻车。主流做法是先规划再执行:让模型先产出步骤清单(写进 todo、或进入只读的 Plan 模式),人确认后再逐步执行,每完成一步更新状态。规划的本质,是把「一锤子买卖」变成「可检查的进度条」——错了能早发现,上下文也能省。
> 把认证模块从 session 换成 JWT
计划: 1. 通读 auth/ 现有实现(只读)
2. 列出所有引用 session 的调用方
3. 设计 JWT 签发与校验中间件
4. 逐文件替换 + 补测试 ← 每步都要你点头才继续
05
速查表:概念、循环、框架与设计原则
下面这块表格能搜。忘词就搜 ReAct、压缩、审批,选框架就搜 多智能体。
| 概念 | 一句话解释 |
|---|---|
| Agent(智能体) | LLM + 循环 + 工具 + 目标:能多步自主干活的系统 |
| ReAct | 思考—行动—观察交替的经典循环范式(2022 论文) |
| Function Calling / Tool Use | 模型输出结构化调用意图,由你的代码执行工具 |
| JSON Schema | 描述工具参数的结构,约束模型输出的格式 |
| 系统提示词 | 对话最前面定角色、立规矩的指令,用户不可见 |
| 上下文窗口 | 一次能塞给模型的最大 token 数,Agent 的工作内存 |
| 上下文压缩 | 会话变长时摘要折叠旧内容,常见命令如 /compact |
| 长期记忆 | 文件、数据库或向量库;需要时用 RAG 取回 |
| RAG 检索增强生成 | 先检索资料再生成,给 Agent 接上私有知识 |
| Plan 模式 | 只读探索 + 出计划,批准后才动手的执行档位 |
| Human-in-the-loop | 关键步骤回交人类审批的设计 |
| Guardrails 护栏 | 限制动作范围、步数与权限的防护机制 |
| MCP | Anthropic 2024-11 开源的模型上下文协议,工具生态的「USB 接口」 |
| 子代理(Subagent) | 主 Agent 派出去的独立 Agent:各自带干净上下文干子任务 |
| 上下文工程 | 决定「每一步让模型看见什么」的工程——比提示词工程更进一步 |
| 组件 | 在循环里的角色 |
|---|---|
| 目标(Goal) | 循环的输入:一句可验证的任务描述 |
| 主循环 while | 反复:调模型 → 看要不要工具 → 执行 → 回传 |
| stop_reason / finish_reason | 判断这一轮是「点菜」还是「收工」的信号 |
| tool_use / tool_calls | 模型发出的调用意图(两家字段名不同) |
| tool_result / role:"tool" | 你回传给模型的执行结果 |
| 工具注册表 | 名字 + 描述 + Schema 的清单,随请求发给模型 |
| 终止条件 | end_turn、最大步数、预算熔断或人工打断 |
| max_steps 上限 | 防循环失控的保险丝,写 Agent 必加 |
| 错误回传 | 工具失败把报错文本喂回去,让模型自己改道 |
| 观测 / 日志 | 记录每一步提示词与工具结果,出事能回放 |
| 并行工具调用 | 模型一次点多道菜,无依赖的工具并发执行省时间 |
| 流式输出 | 边生成边推送;Agent 里用它实时展示思考与工具进度 |
| 重试与退避 | 限流/超时先退避再重试;工具级失败则把报错喂回模型 |
| 工具白名单 | 按任务裁剪可用工具与目录,权限门的第一道闸 |
| 框架 / 产品 | 一句话定位(细节各有专页) |
|---|---|
| Claude Code(Anthropic) | 终端编程智能体,Plan 模式与 Skills 生态,本站有专页 |
| Codex(OpenAI) | OpenAI 的编程智能体(CLI 与云端),本站有专页 |
| Kimi Code(月之暗面) | 终端 Agent,可接多家模型,本站有专页 |
| OpenCode(开源) | 开源终端编程 Agent,多模型可插拔,本站有专页 |
| LangChain / LangGraph | 最流行的 LLM 应用编排框架,本站有专页 |
| OpenAI Agents SDK | OpenAI 官方的轻量 Agent 框架 |
| AutoGen(Microsoft) | 多智能体对话式协作框架的代表 |
| CrewAI | 角色分工式的多智能体框架 |
| Google ADK | Google 的 Agent 开发套件 |
| smolagents(Hugging Face) | 极简的代码型 Agent 库 |
| MCP | 工具协议:一套工具服务所有支持 MCP 的 Agent |
| 怎么选 | 学概念用裸 SDK;干活用编程智能体;组应用再看 LangChain / AutoGen |
| 本站开源智能体专页 | hermes-agent / pi-agent / deepseek-harness:开源 Agent 实现逐一拆解 |
| 原则 | 为什么 |
|---|---|
| 从最简单的开始 | 一个模型 + 一个循环够用就别加架构;复杂度是成本 |
| 工具即接口 | description 与参数名是给模型的文档,文档质量=点菜质量 |
| 工具少而清晰 | 语义重叠的工具让模型选错;先合并再精简 |
| 错误信息说人话 | 报错写给模型看,它才能自我纠正而不是反复重试 |
| 每一步可观测 | 记录提示词、调用与结果;排障与审计全靠它 |
| 权限最小化 | 默认只读;写操作与 shell 要审批或沙箱 |
| 步数与预算双上限 | max_steps + token 预算,两道保险丝 |
| 关键点要人点头 | 删除、发布、付款类动作永远 human-in-the-loop |
| 大任务先规划 | 先进 Plan / TODO 流程,可检查、可回退 |
| 进度对人类可读 | 每一步打印「正在做什么」,否则没人敢放它跑长任务 |
| 先跑通,再优化 | 最简版本先端到端跑通,再谈架构、并发与缓存 |
没有匹配的条目。换个词试试,比如「循环」「压缩」「权限」。
06
实战:30 行写一个最小 Agent
下面这个文件是所有 Agent 的共同骨架——看懂它,Claude Code 和 LangChain 对你都不再是黑盒。写法是 OpenAI 兼容风格;Anthropic 原生 SDK 把工具结果包成 tool_result 块(见第 03 节),流程完全同构。
完整源码:mini_agent.py
# 跑通思路用:OpenAI 兼容写法,MODEL 换成你有权限的模型 import json from openai import OpenAI client = OpenAI() # 自动读环境变量 OPENAI_API_KEY MODEL = "gpt-4o-mini" # 1) 工具:先给模型一份"菜单" def read_file(path: str) -> str: "读取本地文本文件的前 2000 字符" return open(path, encoding="utf-8").read()[:2000] TOOLS = [{ "type": "function", "function": { "name": "read_file", "description": "读取本地文本文件内容;查看代码/配置时用,不支持列目录", "parameters": { "type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"], }, }, }] EXEC = {"read_file": read_file} # 菜名 → 真正的函数 # 2) 主循环:模型 → 工具 → 观察 → 再问模型,直到它不要工具 def run(goal: str, max_steps: int = 8) -> str: messages = [{"role": "user", "content": goal}] for _ in range(max_steps): # 保险丝:防失控 r = client.chat.completions.create( model=MODEL, messages=messages, tools=TOOLS) msg = r.choices[0].message if not msg.tool_calls: # 不要工具了 = 最终回答 return msg.content messages.append(msg) for call in msg.tool_calls: # 执行每个工具并回传 fn = EXEC.get(call.function.name) result = fn(**json.loads(call.function.arguments)) messages.append({"role": "tool", "tool_call_id": call.id, "content": result}) return "已达最大步数,强制停止。" # 3) 下达目标 print(run("读一下 README.md,用三句话总结这个项目是做什么的"))
数一数:去掉注释与空行,核心逻辑三十行上下——声明工具、主循环、保险丝、目标,一个不少。所有 Agent 框架做的,都是给这个骨架加壳。
练手:五分钟给 Agent 装上第二只手
只改三处,就能让模型学会「先看目录、再挑文件」的组合拳——亲眼看一次工具组合,胜过十篇原理文章:
import os
def list_dir(path: str) -> str:
"列出目录下的文件名,不递归"
return "\n".join(os.listdir(path))
# 1) TOOLS 里照抄一份 schema:name 换成 "list_dir",
# description 写 "不知道文件名时先用我列目录"
# 2) EXEC 注册真函数:
EXEC = {"read_file": read_file, "list_dir": list_dir}
# 3) 换个更开放的目标:
print(run("这个项目是干什么的?自己找入口文件研究"))
# 你会在日志里看到:先 list_dir,再 read_file(它挑中的那个)
if 去安排这个顺序——这就是「步骤由模型现场决定」的体感。拆解:循环里的三个关键点
-
01
声明工具
TOOLS里那段 JSON Schema 是给模型的接口文档:name见名知义,description写「何时该用我、有什么限制」。EXEC把菜单名映射到真函数——菜单和后厨分开。 -
02
主循环
create → 有 tool_calls 就执行并回传 → 再 create。模型不再要工具时返回
content,循环结束。整页第 04 节的 ReAct,落到代码里就是这个for循环。 -
03
加保险丝
max_steps=8防死循环。生产代码还要补:异常捕获、token 统计、每步日志——第 07 节逐条展开。
$ python3 mini_agent.py # 第 1 轮:模型点菜 read_file(README.md) → 你执行回传 # 第 2 轮:模型读完内容,不再点菜,输出三句话总结 这是一个面向初学者的 AI 教程站,共 21 门课程,按五大分类组织。 它提供终端实操风格的中文教程,附带可复制的命令与速查表。 内容依据官方文档整理,强调动手验证。
输出是示意口径——真实回答随模型与 README 内容而变;关键是过程:两轮循环、一次工具调用、零行 if-else 由你编写。
07
局限与风险:四个必须预装的「刹车」
Agent 的自由度比聊天机器人高一个数量级,出事的方式也多一个数量级。四个坑,每个都要在写第一行代码之前就想好刹车在哪。
坑一:循环失控
模型可能对同一个失败工具反复重试,或在两个工具之间来回打转;每转一圈,全部历史都重新发送一遍——错得越久,烧得越多。
for step in range(max_steps): # 1. 步数上限 ... if usage.total_tokens > budget: # 2. 预算熔断 raise BudgetExceeded(...) ... # 3. 工具报错返回"可读"信息,引导模型换路而不是原路重试 return {"error": "文件不存在;检查路径,或改用 list_dir 查看目录"}
坑二:权限过大
Agent 拿到 shell 就等于拿到你的机器:删文件、改配置、外发数据都可能发生。默认最小权限——只读放行,写入与命令要审批;不可信任务跑在容器或沙箱里。各家 CLI 的 --yolo / --auto 档位都是「把判断权交出去」,用之前先 git status 看一眼,确保有退路。权限门的最小实现思路,其实只有一个白名单加一道人工闸:
ALLOW_READ = {"./src", "./docs"} # 只读白名单目录
def guard(tool: str, args: dict) -> bool:
if tool == "read_file":
return args["path"].startswith(tuple(ALLOW_READ))
# 写入与 shell:一律回交人类审批
return ask_human(f"允许 {tool}({args}) 吗? [y/N]")
把 guard() 插在第 06 节主循环「执行工具」之前,两行代码完成接入——所有成熟的 Agent 产品里,都有这个函数的复杂版本。
坑三:成本失控
Agent 每一步都把「全部历史 + 工具结果」重新发给模型:上下文随步数增长,成本近似平方级爬升。长任务要压缩上下文、粗活用小模型、每步打印 usage。
usage,心里有数;长会话勤压缩——省下来的都是真金白银。第 1 步 请求约 2k tokens
第 5 步 请求约 15k tokens
第 10 步 请求约 30k tokens
# 整轮成本 ≈ Σ(每步全量上下文) —— 由"步数 × 上下文"决定
坑四:盲目信任执行结果
幻觉在 Agent 里没有消失,只是换了一身衣服:工具没搜到不代表不存在,网页内容错了模型会「自信地」接着编。对策三层:终稿必审 diff;关键事实让它给出处;重要任务导出会话留档。
git diff # 1. 人工过一遍它到底改了什么 git add -p # 2. 认可一块收一块,不整包吞下 # 3. 会话导出留档(如 Kimi Code 的 /export-md,见本站专页)
08
进阶:多智能体协作,与精选资源
多智能体:把一个大脑变成一个团队
当单 Agent 的工具太多、上下文太挤时,可以把任务分给多个角色化 Agent:一个规划者拆解任务,几个执行者各管一段,一个审查者复核产出,最后由协调者汇总交差。AutoGen、CrewAI 把这套模式产品化;LangGraph 用「图」来编排这类流程。
用户目标 → 规划者拆成 3 个子任务 ├─ 执行者 A: 写代码 → 产出 patch ├─ 执行者 B: 写文档 → 产出 docs └─ 审查者 C: 复核 A/B → 通过 / 打回 协调者汇总 → 交用户审批
- 规划者
- 拆任务、定每步的验收标准
- 执行者
- 干活;一人一域,工具集按角色裁剪
- 审查者
- 复核产出,敢于打回而不是放行
- 协调者
- 维护共享上下文,对外交差
但要泼一盆冷水:多智能体不是免费午餐——通信本身消耗 token,一个角色的错误会顺着消息流向下游放大。Anthropic 在《Building Effective Agents》里的建议是:能用单 Agent + 好工具解决的,就别上多 Agent;确要上,先让每个单 Agent 都可靠。什么信号说明值得上?任务能按专业域干净切分、单 Agent 上下文装不下、且各段之间只需要少量交接信息。
顺手指一条路:怎么读框架源码
任何框架、任何产品,先找主循环:在仓库里搜 stop_reason、finish_reason、tool_calls 这三个词,找到「调模型—判停—执行—回传」四步,剩下都是外围。第 03 节的同构对照表,就是你的寻宝图。
grep -rn "stop_reason\|finish_reason\|tool_calls" src/ | head -20 # 命中的那几行,就是整个框架黑盒的开关
精选资源(真实链接)
- Anthropic《Building Effective Agents》(必读的方法论)——anthropic.com/research/building-effective-agents
- Anthropic 工具使用官方文档——platform.claude.com/docs · tool use
- OpenAI Function Calling 指南——platform.openai.com/docs/guides/function-calling
- Model Context Protocol 官网——modelcontextprotocol.io
- LangChain 文档——python.langchain.com/docs
- Microsoft AutoGen——microsoft.github.io/autogen
09
收尾:照着勾一遍
0 / 5