← 洞察
观点 · 2026年5月20日 · 10 分钟阅读

用 Agent 开发 Agent:真正有效的是一条循环

评论工程框架

第一次让 Claude “帮我写一个 agent”,它会写 prompt、选模型、交付一个两百行文件,demo 跑得很漂亮。到了第五次,你会发现它只在你给过的那个例子上可靠。用 Agent 开发 Agent 是真的:Claude 规划、写代码、重构 agent 的速度都很快。但失败模式也很真实:一个巨大的 prompt,没有 trace、没有 eval、没有拆解,每次模型或需求变化都会回归。能出货的团队,已经不把这件事当成“一次生成”,而是当成一条可重复的工程循环。

1. 先写 eval,再写 prompt

先写 prompt 很符合直觉,但顺序是错的。Prompt 只是一个假设;没有证伪方式,你会无限迭代,然后说服自己“差不多了”。

更稳的做法很机械:在任何 system prompt 出现之前,先写三行 eval。每一行都是 (input, expected_observable),而不是 (input, full_expected_output)。因为输出往往是一段文字,你很难逐字匹配;你真正要检查的是可观察结果,比如 regex、JSON schema、LLM-as-judge rubric,或某个工具副作用。

三行就够开始:一条 happy path,一条 edge case,一条 agent 必须拒绝的失败用例。如果这三行都写不出来,说明你还没有 spec,只是有一个愿望。继续往 prompt 里堆段落,只是在装饰这个愿望。

2. 把每个 agent 定义成一个 function

下一个常见坑,是把 agent 当成“人设”来设计。人设没有清晰边界,function 有。一个有用的 agent 应该有签名:一两个命名输入、一个命名输出形状、一个成功条件。其他东西,比如背景故事、语气、emoji 策略,都只是装饰。

当边界变成 function,父 agent(这里就是 Claude)才能真正推理它:“给定这些输入和成功条件,需要哪些工具?最短的 system prompt 是什么?” 这种对话短而具体。而“让它 helpful、friendly,还擅长写代码”这种要求,会把讨论拖进无穷无尽的形容词里。

3. 让父 Agent 起草子 Agent

有了 eval 和 function signature,就把它们交给 Claude,让它起草 system prompt、工具列表、权限策略和第一版 fixture。看待它的输出,可以像看一个很强的外包工程师提交的代码:保持怀疑,但默认结构值得认真审。

不要手写第一版 system prompt。父 agent 九十秒生成的初稿,通常比你从空白页写一下午更好,因为它见过的 agent 比你多。你应该从 baseline 开始编辑,而不是从空白页开始发明。Agent 基础 会把这条循环的结构讲清楚。

4. 工具才是真正的 prompt

读任何一个生产级 agent 的 system prompt,你会发现大部分内容其实是工具描述。顶部几段文字决定语气,工具决定能力。每个工具名、参数名和一句话描述,都会进入模型的计划过程。

这带来两个后果。第一,工具命名要非常具体。query_db 太含糊,search_orders_by_email 就清楚得多。工具表面越清晰,模型计划越干净;改名通常也比重写 prompt 便宜。第二,一个好工具可以替代三条 prompt 指令。比如“发送邮件前一定要校验邮箱”应该变成 send_email 工具内部校验,非法时返回 typed error。这样 prompt 变短,行为由代码保证。

工具的合理粒度,是 reviewer 看一行 log 就能判断它做了什么。如果一行 log 说不清这个工具的副作用,它就太大了。MCP servers 把这件事形式化:工具表面就是 agent 和系统其他部分之间的契约。

5. 用子 Agent 拆解,不要堆超长 prompt

最容易走偏的方式,是不断给同一个 system prompt 加段落,直到它看起来“什么都能做”。这和把整个 React 应用塞进一个文件很像:小规模能跑,规模一大就腐烂。

更好的做法是拆成子 agent。主 agent 保持小而清楚,只负责调度;具体工作交给 planner、retriever、reviewer、writer 这类专门的子 agent。每个子 agent 都有自己的 function 边界和 eval set。这样主 agent 的上下文窗口更轻、更可预测,子 agent 则在自己的问题切片上消耗上下文,再把压缩后的结果交回来。

两个好处很实际:独立子 agent 可以并发,延迟会下降;主 agent 也不用读 retriever 翻过的 80kb 文档,上下文更干净。代价是多一层设计,但过了第二个工具之后通常就值得。Multi-agent 设计 会把这个模式落到具体实现。

6. Hook 是系统的免疫层

子 agent 和工具给了 agent 能力,hook 决定这些能力能不能被使用、怎样被使用。Hook 可以在工具调用前后运行:改写参数、拒绝调用、记录 trace,或者在 agent 写完文件后自动跑 linter。

这层看起来无聊,却能挡住大多数生产事故。pre-tool hook 可以拒绝 /tmp 之外路径的 rm -rf;post-tool hook 可以在每次写文件后跑 tsc --noEmit,再把失败结果喂回 agent;refusal hook 可以在 API key 进入日志前先打码。

Hook 是确定性的,每次都会跑,也是你最容易写单元测试的那一层。凌晨两点概率性检查漏掉的东西,它往往能拦住。Claude Agent SDK 暴露 22 个 hook event,就是因为这层值得认真设计。Agent security 会带你走一遍威胁模型。

7. 调试靠回放 trace,不靠重写 prompt

能出货的团队和一直在“调 agent”的团队,最大的区别在于出错之后怎么做。

调 prompt 的团队,会把失败输入再跑一遍,看它换一种方式失败,然后改 prompt,再跑。几个小时过去,修法也不一定能泛化。

能出货的团队,会把每次运行都当成结构化日志:每条消息、每次工具调用、每个 observation 都在 trace 里。出错时,他们打开 trace,找到具体偏离的那一步,再问父 agent:要让这一步正确,prompt、工具或 hook 应该改哪里?修法是针对一个具体决策的 diff,而不是凭感觉重写。失败输入也会变成 eval set 里新的回归用例,让 agent 单调变好。

Trace 本质上就是一组 typed event。Harness 写一次,就能在不同 agent 上复用。每次修复的形状都一样:打开 trace,改 prompt、工具或 hook,重跑 eval set,绿了再提交。

合起来

这条循环很短,每次都一样:

  1. Eval:至少三行,先于其他一切。
  2. Scope:agent 是一个有 signature 的 function。
  3. Scaffold:父 agent 起草 system prompt 和工具,你来 review。
  4. Tool:工具才是真正的 prompt,要命名清楚、粒度收小。
  5. Decompose:过了第二个工具,就优先用子 agent 拆解。
  6. Hook:围绕每个工具放上确定性的关卡。
  7. Replay:调 trace,不调症状;每次修复都让 eval set 增长。

这些步骤不依赖 2026 年以后才会出现的模型能力,只需要把 agent 开发当工程,而不是当聊天。多数团队跳过第一步 eval 和最后一步 replay,然后才会觉得模型一升级就回归。

你真正搭的资产不是某个 agent。模型会被替换,prompt 会被重写,工具会被改名。真正会复利的是这条循环:eval set、trace harness、hook 体系和子 agent 拆解方式。一年后还在工作的,通常也是这些。先把循环选对,agent 反而会自然长出来。

相关路径