Agentpath
原理1 / 31 节 · 预计 25 分钟

agent 到底是什么:一个 while 循环

去掉包装,agent 就是「让模型自己决定下一步调什么工具,直到它说完事了」。这个定义决定了后面所有设计取舍。

学完这节你能做到

  • 用一句话说清 agent、chatbot、workflow 三者的界线,并判断手头需求属于哪一类
  • 指出 agent 的自主性来自哪里,以及代价是什么(不可预测、成本、越权)
  • 识别「其实不需要 agent」的场景,避免拿循环去做 if-else 的活

"agent" 这个词现在什么都能指:一个会调 API 的聊天框、一条 LangChain 流水线、一个自动回邮件的脚本。 定义混乱的直接后果是选型混乱 —— 明明一个 if/else 能解决的事,非要塞进一个会自己乱跑的循环里。

所以先把定义钉死。

从一次普通调用说起

最朴素的用法是一问一答:

resp = client.messages.create(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "帮我看看这个函数有什么问题"}],
)
print(resp.content[0].text)

这里模型能做的只有一件事:产出文本。它猜不到你的函数长什么样,也改不了你的文件。 输出好不好,全看你在 prompt 里塞了多少上下文。

加上工具:它开始能改变世界

给它一组工具,模型就能要求你替它执行动作 —— 读文件、跑命令、查数据库:

tools = [
    {"name": "read_file", "description": "读取一个文件的内容", "input_schema": {...}},
    {"name": "bash", "description": "在项目目录里执行 shell 命令", "input_schema": {...}},
]
resp = client.messages.create(model=..., messages=msgs, tools=tools)
# resp.stop_reason == "tool_use" —— 它想读文件

注意这里的分工:模型只是提出请求,执行永远发生在你的代码里。 这一点是后面所有安全边界的基础 —— 它想 rm -rf /,跑不跑得起来是你决定的。

加上循环:谁来决定「还要不要继续」

一次工具调用不够用。真实任务是:读文件 → 发现要看另一个文件 → 改代码 → 跑测试 → 测试挂了 → 再改。 把它包进循环,就成了 agent:

while True:
    resp = call_model(msgs, tools)
    if resp.stop_reason != "tool_use":
        break                          # 模型认为完事了
    results = run_tools(resp.tool_calls)
    msgs.append(resp)
    msgs.append(results)               # 结果(包括报错)回灌

这就是 agent 的全部。 剩下的都是工程:上下文放不下怎么办、工具报错怎么说、 人想插一句话怎么插、跑飞了谁来拦。

i控制流在哪,谁就是主人

上面这段代码里,「下一步做什么」是模型用 tool_use 决定的,代码只负责执行和回灌。 这个位置的移交,就是 agent 与工作流的分水岭。

workflow 与 agent 的分界线

控制流可预测性出错形态适合
workflow写在代码里高,路径可枚举某一步失败,位置明确步骤固定的批处理、抽取、分类
agent由模型决定低,每次都可能不同绕圈、走偏、越权步骤取决于中途发现的任务

判断标准很实用:你能不能提前画出流程图? 能画出来的就别用 agent —— 「把这批 PDF 里的金额抽出来入库」是 workflow;「查清楚这个线上故障的根因」是 agent, 因为下一步查什么取决于上一步看到了什么。

×最常见的浪费

拿 agent 去做只有一条路径的事。结果是慢十倍、贵二十倍,还多出一个「它偶尔会自己发挥」的风险。 既有的判断逻辑该写成代码,别指望模型每次都推理正确。

harness 是什么

那段 while 循环谁都写得出来。真正麻烦的是外面那一圈:

  • 上下文窗口满了,压缩哪一段?压缩之后 prompt 缓存全失效,这笔钱谁付?
  • 工具输出十万行,全塞回去还是截断?截断了模型会不会看不到关键那行?
  • 人在它跑到一半时想改主意,怎么让这句话插进循环,还不留下半截状态?
  • 它要执行 git push --force,谁来拦?拦的规则写在哪一层?
  • 跑了两小时没进展,凭什么判定「该停了」?

把这一圈做好并且做得可改的那层软件,就叫 harness。Pi、Claude Code、Codex 都是 harness。 这门课选 Pi,是因为它的核心刻意做得极小 —— sub-agent、plan mode、权限确认、沙箱在它这里 全都是扩展,不是内置黑盒。能拆开的东西才讲得清。

Pi 的取舍值得先读一遍

Pi 官网有一节「What we didn't build」,明确列出不做 MCP、不做 sub-agent、不做权限弹窗, 每条都给了替代做法。看一个项目决定不做什么,比看它做了什么更能学到东西。

什么时候不该用 agent

  • 路径固定 —— 写成脚本,快且便宜。
  • 一次调用就够 —— 翻译、摘要、分类,不需要循环。
  • 错了不可逆且没人复核 —— 转账、发布、删数据,先把确认门建好再说。
  • 延迟敏感 —— agent 动辄几十秒到几分钟,用户在等的场景撑不住。
检查点多选

下面哪些需求更适合做成 agent(而不是固定工作流)?

这一节的结论

  1. agent = 工具 + 循环 + 由模型决定下一步。
  2. 执行永远在你的代码里,所以边界也永远由你定。
  3. 难的不是循环,是循环外面那一圈;那一圈就是 harness。
  4. 能写成流程图的,别用 agent。

下一节把 Pi 装上手,四种运行形态各跑一遍 —— 先有体感,再拆内部。

延伸资料