Agent Architecture · 图解走查 · 11 figures

Agent 是怎么跑起来的:11 张图

每张图一个机制。看箭头走向,不需要读段落——文字只用来标注图上发生的事。

读者
会写代码
视角
架构 / 失效面
读法
图 → 边注 → 下一图
图例
状态变化 · 数据/结构 · ─ 实体 · ┄ 概念
01

闭环:模型不做事,只有循环在做事

模型是一个纯函数:进去一段文本,出来一段文本。动作、副作用、停止条件,全都发生在循环里。

Fig 01控制循环 / 三段职责
模型 / policyllm(ctx)无状态 · 无副作用 动作执行tool(args)这里才有副作用 环境 / 结果stdout · 数据真实世界返回 上下文messages[]唯一的状态载体 LOOP CONTROL · 由外层代码决定 什么时候停?模型永远不会自己停 steps > 12 ............... 硬上限 tokens > budget ......... 预算 wall clock > deadline ... 超时 no progress x3 .......... 打转保护 risky action ............ 人工闸门 缺任何一条 = 烧钱循环 ■ 当前轮次: — messages[] 增长(灰色为追加)
读图四个框构成闭环;朱红虚线框是框架的职责,不在模型里。
关键左侧 messages[] 每转一圈就变长——这就是第 4 张图要处理的成本来源
判断如果任务能用 if/else 写完,就不要上 agent。你付出的是延迟、成本与不可复现。
02

采样:每一步只是一次「下一个 token」的分布

模型不执行算法,它在做条件采样。看懂这一层,就知道为什么结构化输出必须靠约束解码,而不是靠请求。

Fig 02token → 分布 → 采样 → 追加 → 重算
① 文本 → token(子词单元,不是字符也不是词)
② 每一步重算上下文 → 打分 → 采样一个 token
成本 ≈ O((prompt + n·out)²) · 每步都要重放整段历史
当前上下文
下一 token 的概率分布(top-5)
■ 采样到的不是「最合理」,是分布里抽中的那个
推论 1需要精确计算 → 调工具。别让模型数数、算钱、比日期。
推论 2要 JSON 就上 schema 约束解码;「请只输出 JSON」是祈祷,不是契约。
推论 3temperature=0 只是更确定,不等于可复现:浮点、批处理、模型版本都会变。
03

工具:模型唯一的「手」,每次调用都是一次边界

模型输出 name + args,运行时校验、执行、把结果作为新消息回填。工具报错写得好不好,直接决定 agent 能不能自愈。

Fig 03三条调用链:通过 / 报错回喂 / 策略拒绝
运行时:校验 → 权限 → 执行
回填进上下文的消息
错误信息的两种写法
设计工具描述是写给模型的文档:参数自解释、枚举穷举、错误写成可恢复提示。
数量3~7 个高内聚工具 > 30 个细碎工具。工具越多,选错率越高。
安全每个工具都是权限边界。别给模型无限 shell、无配额写操作、静默删除接口。
04

上下文:agent 真正的状态机

记忆不在模型里,在你每步塞进去的消息数组里。窗口就是 agent 的全部世界,塞满时必须做取舍。

Fig 04预算被占满 → 压缩 → 保留关键状态
预算占用
0 / 200k tokens
等待开始…
四种取舍
滑动窗口 · 丢最旧 —— 便宜,会丢目标
摘要压缩 · 模型总结 —— 有信息损失
外部记忆 · 落盘再检索 —— 需要索引
结构化状态 · todo/JSON —— 最稳,要设计
第一坑工具输出原样回填:一次 install 或抓网页就是几万 token,95% 是噪声。
做法大结果写文件,上下文只留「路径 + 前 40 行 + 怎么按需读取」。
自检如果只留 5 条消息 agent 就干不下去,说明状态存在聊天记录里,而不是结构化状态里。
05

ReAct:让推理被真实观测约束

每轮先想、再做一个动作、拿到真实返回。没有 observation,模型只是在自我暗示。

Fig 05三轮循环 · 右侧为完整轨迹
每转一圈,右侧轨迹多两行 Thought推理 · 计划 Action工具 + 参数 Observation真实返回 round 0 轨迹可回放 = 唯一的可观测性
trace
变体路径确定 → Plan-and-Execute 省 token;失败要记住教训 → Reflexion。
解析动作解析必须容错:解析失败本身要变成一条 observation 回喂,而不是抛异常崩循环。
取舍thought 要不要给用户看,是产品决策,不是技术决策。
06

验证:把「完成」的定义从模型手里拿走

模型很擅长生成「看起来对」的结果。可靠 agent = 外部验证器 + 原始错误回流。

Fig 06生成 → 跑断言 → 失败原文回流 → 修正
round 0
外部验证器(不采信模型自述)
回流进上下文的原始错误
VERIFIED · 允许返回
顺序编译器 → 单测 → 真跑一遍看退出码 → schema 断言 → 第二个模型当 critic(最弱)。
原则能写成断言的,就不要写成 prompt。
critic 用法只问可核查的问题(哪条断言没过、哪一行),别问「你觉得好吗」。
07

编排:拆分的唯一理由是上下文隔离与并行

不是「像人类团队那样分工」。子任务的输入输出必须是结构化契约,不是自由聊天。

Fig 07派发 → 并行 → 产物回传 → 冲突裁决
orchestrator拆解 · 分配契约 · 裁决冲突 worker · 调研只看自己的子问题 worker · 实现自己的工具子集 worker · 验证只跑断言,不改代码 SHARED_STATE · 结构化产物(不是聊天记录) 并行:墙钟 ≈ max 而非 sum
先问单 agent + 更好的工具 + 验证器能不能解决?能,就别拆。
代价N 个 agent ≈ N 倍 token 与延迟,再加通信开销与不一致风险。
拓扑Supervisor 最可控 → Pipeline 最可测 → Blackboard 适合长任务 → 自由对话群最难调试。
08

失效面:agent 很少「答错」,多数是结构性卡死

六种死法,每种都有可埋点的信号。把它们做成指标,比换更强的模型更有效。

Fig 08六类失效 · 典型信号强度
必埋每轮 token/成本 · 工具成功率 · 同参重复调用次数 · 步数 P50/P99 · 终止原因分布。
兜底同参重复即打断;连续 3 轮无进展就升级或找人;每轮保留结构化状态。
前提没有这些指标,你无法判断一次改动是变好还是变坏。
09

边界:模型可以提议任何动作,能不能执行由运行时说了算

风险分级 → 自动 / 人工批准 / 拒绝 → 沙箱执行 → 审计日志。拒绝理由也要回喂,让模型改道而不是重试。

Fig 09动作流经闸门 · 可手动批准/拒绝
提议的动作队列
闸门状态
等待动作…
steps  0 / 12
tokens 0
cost   $0.0000
wall   0.0s
■ 外部内容永远是数据,不是指令
沙箱三层:进程(无网络)· 文件(白名单)· 凭据(最小权限、可撤销)
头号威胁prompt injection:只要会读外部内容,内容里就可能有指令。
闸门写操作、生产环境、破坏性命令必须经人;拒绝信息作为 observation 回喂。
预算按任务设限,不按调用。到限不是崩,而是输出当前最佳结果 + 说明卡在哪。
10

骨架:把前面九张图写成 20 行

逐行高亮,右侧是这一行在运行时真正产生的效果。换任意模型 SDK,这个循环都成立。

Fig 10代码走查 · 右侧同步运行时轨迹
运行中…
生产化还要补结构化输出约束 · 流式与中断 · 工具级超时重试 · 崩溃可恢复的持久化状态 · 全链路 trace。
为什么这么写每一步都在防前面某张图里的失效:去重防打转、截断防污染、验证防自述、上限防烧钱。
上不上 agent路径能用 if/else 写清楚 → 用工作流。Agent 只买「事先不知道下一步」这件事。
11

责任面:六层职责各自防什么

成熟度不看 prompt 写得多好,看状态在哪、边界在哪、失败怎么被看到、成本怎么被限住

Fig 11六层 → 对应失效 → 对应动作
防住的失效 对应的工程动作
自检六层里哪一层你还没有?缺的通常不是模型,而是 verify 与 guard。
动手写一个只有 2 个工具 + 1 个验证器的 agent,任务限定「修一个失败的测试」。
分界线准备 10 个固定任务当回归集,每次改架构都跑一遍——这是玩具与系统的分界。
Agent 架构图解 · 11 figures · 离线单文件 空白键 = 暂停/继续当前图 · 每图可重播