学习笔记 | 10 月 31 日 · 把 Agent 拆开看
- 2026-11-06 20:48:51
知识小站 · Agent 学习笔记 01
今天只讲一件事:Agent 凭什么能自己把事干完。约 3200 字,读完 8 分钟;赶时间可以先看文末的「今日三句话」。
01 / 认知
能自己决定下一步的,才叫 Agent
先给一个能落地的定义:
Agent 是一个能观察环境、自己决定下一步、调用工具改变环境,并循环到目标完成的系统。
拆开就是四个零件:
模型负责「接下来该做什么」的判断。它不是知识库,是决策者。 工具把判断变成动作——检索、算数、调接口、写文件。 记忆短期是上下文,长期是外部存储。 循环决定「再来一次」还是「到此为止」。
判断一个东西是不是 Agent,不用看它有多少工具,只看一件事:下一步由谁决定。
普通对话是「你问一句,它答一句」,每一步都在你手里;Agent 是「你给一个目标,它自己排步骤」,中间的决定权交出去了。
所以那种「聊天框加三个插件、但每次都要你点名调用」的产品,本质还是带工具的聊天,不是 Agent。
Agent 的门槛不是会不会用工具,而是会不会自己判断:下一步该用哪个工具。
02 / 机制
一次 ReAct 循环,转的到底是什么
ReAct(Reasoning + Acting)是 2022 年提出的一种思路:让模型把「想一想」和「做一下」交替进行,用工具返回的真实结果,去纠正自己脑子里的推理。
骨架不到二十行:
目标 = 用户的话上下文 = [系统提示, 工具清单, 历史]loop: 思考 = 模型(上下文) # 还缺什么? if 思考.类型 == "回答": return 思考.内容 结果 = 执行(工具, 参数) # 真动作 上下文 += [思考, 结果] # 回填拿一个小任务走一遍——「查一下明天北京天气,下雨就提醒我带伞」:
观察:目标里其实有两个动作,查天气、按条件提醒。 思考:先调天气工具,日期是「明天」。 行动: weather(city="北京", date="tomorrow")观察: {"condition":"小雨","temp":"12-18℃"}思考:命中「下雨」条件,创建提醒。 行动: reminder.create(time="07:30", text="带伞")回答:明天北京小雨,12-18℃,已设好 7:30 的提醒。
看起来顺理成章,但真做起来,翻车基本都在这三个地方:
观察要结构化。工具返回 {"ok":true,...},比返回「查询成功!结果如下:……」好处理一百倍。自然语言的结果,模型每次解析都可能不一样。停止条件要显示。最大步数、token 预算、连续两轮没有新信息就停。没有刹车片的循环,一定会跑到预算烧完为止。 失败要能回退。工具报错时,把错误原文喂回模型让它改参数,而不是直接抛异常把整个任务中断。
第二点尤其容易被忽略:Agent 最难的不是想得聪明,是停得下来。
03 / 上下文
Agent 九成的问题,最后都落在上下文上
很多人以为 Agent 效果差是模型不行,实际排查下来,多半是上下文塞坏了。
有个被反复验证的现象:关键信息放在长上下文的中段时,最容易被忽略(业界叫「lost in the middle」)。也就是说,窗口大不等于好用,塞得越满,注意力越稀释。
我给自己的项目定过一份粗略预算,供参考:
系统提示与规则:10%-15% 工具定义:10% 左右 记忆与资料:30% 工具返回结果:30% 留白:至少 15%
超了就先砍工具结果,再砍历史,绝不动系统提示。
三种典型的坏味道:
腐烂:十几轮之后,第一轮定下的关键约束被后来的日志埋了,模型开始「忘记」要求。 淹没:一次检索返回八千字,模型只用了第一段,剩下全是浪费。 漂移:中途冒出一个子任务,主干目标被悄悄带跑,最后交回来一个跑偏的答案。
对应的三个对策,按性价比排序:
摘要压缩:每 N 轮把历史压成「已确认的事实 + 待办 + 约束」三块,原始消息丢掉。 外部化:中间产物写进文件或变量,上下文里只留一句「完整结果在 result.md」。 隔离:子任务丢给子 Agent,只把结论带回来,过程不要污染主上下文。
上下文是工作台,不是仓库。工作台乱了,手就慢了。
04 / 工具
工具是写给模型看的 API
人写 API 追求复用,模型用 API 靠的是「读懂」。所以工具设计的第一原则不是抽象得多漂亮,而是能不能被准确理解。
四条标准,按重要性排:
单一职责。一个工具只做一件事。 get_user和update_user分开,别做成user(action)这种万能入口——模型会在参数上反复试错。名字自解释。 search_orders_by_phone永远好过query2。名字本身就是提示词。返回可读。字段名带语义,给模型的版本可以砍掉给前端用的冗余字段。 失败可恢复。错误信息要告诉模型:哪里错了、可以怎么改。
同一个需求,两种写法:
# 坏:参数是一个自由字符串,模型只能猜run_sql(sql: string)# 好:类型、枚举、上限都写明search_orders( phone: string, # 11 位手机号 status?: "paid" | "shipped", limit?: number = 20 # 上限 100)错误信息的差别更明显:
# 坏Error: 400# 好Error: phone 必须是 11 位数字,收到 8 位。请向用户确认完整手机号后重试。后一种,模型自己就能改对;前一种,它只能瞎猜或者放弃。
工具描述就是模型的说明书。你写得含糊,它就用得含糊——这条在工具变多的时候会指数级放大,这也是为什么工具接口正在标准化(比如 MCP)。
05 / 记忆
该记什么,该忘什么
Agent 的记忆分三层,用途完全不同:
工作记忆:就是上下文,一次任务用完即弃。 情节记忆:过去发生过什么——这次任务的结论、用户的偏好。 程序记忆:一件事怎么做成的——可复用的步骤、踩过的坑。
大多数产品只做了第一层,所以每次都要重新交代一遍背景。
判断一条信息该不该写进长期记忆,我只有一个标准:下次还会用到,而且不写就会重复犯错。
该写的:
用户稳定的偏好(「回答不要用表情符号」) 已经确认过的结论(「这个客户的结算周期是 60 天」) 失败过的路径(「用 A 接口查不到历史订单,要换 B」)
不该写的:
原始工具返回(体积大、时效短) 中间推理过程(下次的推理未必一样) 一次性临时变量
还有一点常被忽略:记忆要有过期机制。每条带时间戳,读取时优先近期,冲突时以新的为准。没有过期的记忆,会慢慢变成一堆互相矛盾的旧事实。
06 / 评估
怎么知道它真的变强了
「感觉这次回答好多了」不是评估,是错觉。至少分三层看:
单步:给固定的上下文,它选的工具和参数对不对。这一层最便宜,也最能定位问题。 任务:20 条真实任务,看端到端成功率、平均步数、平均成本。 回归:每次改提示词、换模型,跑同一套任务集,看有没有掉点。
任务集不用大,20 条就够,但要覆盖四类:
一步就能做完的(考基本功) 需要多步、有依赖的(考规划) 信息不全、需要追问的(考分寸) 注定失败的(考它会不会及时放弃,而不是硬编一个答案)
最后一条最能暴露问题。很多 Agent 在无解任务上不会说「做不到」,而是编一个看起来合理的结论。
评估时看 trace,不要只看答案。答案对了但路径乱七八糟,下次换个任务就会错;答案错了但路径合理,往往只需补一个工具或一条规则。
四个必看指标:成功率、步数、token 消耗、人工介入次数。前两个看能力,后两个看成本。
07 / 动手
30 分钟,做一个只会做一件事的周报 Agent
选周报,是因为它输入稳定、步骤固定、做错了也无害——非常适合第一次动手。
材料:一周的 git log、待办清单、会议纪要,全放进一个文件夹。
三步走,顺序别反:
先写死流程,不写Agent。列清单 → 读文件 → 分类 → 写三段。手工跑通一遍,确认输出是你想要的。 再把「分类」这一步交给模型,给它固定的输出格式。 最后才加工具循环,允许它自己决定读哪个文件。
大多数人第一步就跳过了,直接上 Agent,然后花三天调一个本来不需要 Agent 的东西。
提示词骨架:
你是周报助手,只做一件事:把本周素材整理成周报。规则:1. 只使用素材里出现的事实,不补充、不推测。2. 输出三段:本周完成 / 进行中 / 风险与求助。3. 每条不超过 40 字,动词开头。4. 素材不足就写「素材不足:缺什么」,别编。素材:{{files}}交付前过一遍检查清单:
有没有编造素材里没有的事 有没有超过字数 有没有把「进行中」写成「已完成」
第三条是重灾区。模型天然倾向于把话说圆满,你不明确禁止,它就会替你宣布完工。
今日三句话
Agent = 模型 + 工具 + 记忆 + 循环。决定权在谁手里,是它和聊天机器人的分界线。 循环里最重要的不是「想得聪明」,而是「停得下来、错得回来」。 上下文、工具、记忆、评估,做好任何一件效果都立竿见影;只调提示词,收益最小。
明日预告:工具调用的三种典型失败——选错工具、参数幻觉、连环调用,以及怎么用 schema 把它们堵住。