深入理解 AI Agent · 第 5 章图解

Coding Agent 与通用 Agent

能处理任意开放任务的通用 Agent,核心是一个 Coding Agent 加上文件系统。从 Manus 到 OpenClaw 都是这个结构。代码之所以能当核心,是因为它是一种元能力:Agent 能在运行时用它写出新的工具、新的约束和新的表达形式。

通用 Agent= Coding Agent+ 文件系统

思考更严谨

“年龄大于 18 且已实名认证”用自然语言说可以有几种理解,写成 age > 18 and verified 就只有一种。

表达能自证

能跑通的代码本身就说明逻辑是自洽的,执行结果给出客观的对错标准。

代码这项元能力的六个作用对象,由内向外排列。点击某一圈可跳到对应小节。
模型思考 / 读取理解 代码执行 / 验证通过 文件系统 / 记忆 / 写入 等待 / 人类介入 失败 / 危险
第一部分 · 5.1

构建一个可靠的 Coding Agent

从最小工具箱开始,到架构、流程、Harness、故障恢复、实现细节、搜索、编辑与安全。

5.1.1

Coding 是每个 Agent 的基础能力

以“整理仓库里所有遗留的 TODO 注释,按优先级分类并生成 issue”为例,要用到五类操作:浏览目录(ls/glob)、读代码(read)、改文件(edit/write)、跑命令(bash)、查模式(grep/search)。几乎所有 Coding Agent 的核心动作都在这五类里。在当前 SOTA 模型下,支持这五类操作只需要七个工具。

七个简单工具组合起来就能完成很多不同的任务。遇到新需求时,Agent 可以自己写代码来扩展能力边界。

七个核心工具 · 看它们怎么配合

主要覆盖“感知”和“执行”两类

    为什么是七个

    其实一个 Bash Shell 就够了。OpenAI Codex 只提供 Bash,文件读写和查找都靠它完成。书里列七个,是为了把 Coding Agent 需要的基本能力讲清楚。

    和第四章的分类不同

    第四章按调用方向和作用性质把工具分为感知、执行、协作、事件触发、用户沟通五类。这七个工具主要属于感知和执行,其余三类需要别的工具提供,但它们不是 Coding Agent 的核心。

    写代码是通用解题手段

    数学推理可以交给求解器算精确答案,业务规则写成代码比自然语言精确,缺工具可以临时写一个,数据格式变了可以现场生成解析逻辑。这几种用法在 5.2 展开。

    5.1.2

    从 Manus 到 OpenClaw:通用 Agent 的 Coding 内核

    这类产品把 Deep Research、Computer Use 和 Coding 三种能力放进同一个系统。核心之所以是 Coding,是因为高效的内容生成几乎最后都要靠代码完成:

    PPT / Word

    本质是 OOXML 格式的代码。

    PDF 报告

    可以由 Markdown、HTML 或 LaTeX 生成。

    数据与图表

    用 Python 脚本完成。

    调研与 GUI

    搜索和综合靠代码发 Web 请求并解析。成功的浏览器操作序列可以固化成代码(第九章)。

    Computer Use 更通用,但成本、延迟和稳定性都比不上直接用代码或 API 做同样的事。代码生成效率最高、成本最低、可复用性最强。

    图 5-1 · OpenClaw 架构,以及一次“分析上季度销售数据”的执行过程

    多平台消息网关 · 用户交互层
    WhatsAppTelegramiMessageSlackCLI
    ↓ 自然语言请求
    Coding Agent 运行时 · 推理 + 执行核心
    Code Interpreter代码执行Bash Shell系统命令Read File读取文件Write File写入文件Edit File编辑文件Glob文件搜索Grep内容搜索
    网络搜索模块 · Deep ResearchWeb 请求 · 解析浏览器自动化 · Computer UsePlaywright DOM
    ↕ 读 / 写文件
    文件系统 · 记忆、知识与能力的中枢
    MEMORY.md高层级事实 / 用户偏好daily/YYYY-MM-DD.md按日归档的交互日志SOUL.mdAgent 身份与行为规则知识库文件任务经验 / 自我进化Git 版本控制记忆回滚 / 历史审计产物文件report.pdf · charts/
    大模型 = 新操作系统:屏蔽智能复杂性,提供统一抽象

      在整个过程里,文件系统都是信息流转的枢纽:记忆从文件读出,产物写进文件,经验也保存成文件。

      为什么用 Markdown,不用向量数据库

      • 用户能直接打开、修改 Agent 的记忆,记错了删掉那一行就行
      • 天然保留时间顺序,不会出现语义检索里的时间混淆
      • 可以用 Git 做版本控制和回滚

      能写文件,就能改自己的外部产物

      例如第一次给某家银行打电话时,发现对方要提供开户行地址才能验证身份,Agent 可以先把这个发现记下来。一条记录什么时候能当作可靠的知识、指令或程序,还要靠更多轨迹和结果来验证(第九章“持续进化”)。

      适用边界

      开放任务型(深度调研、内容生成、数据处理):需要的工具无法事先列全,代码是架构中枢。
      垂直领域型(如客服):任务空间相对封闭,架构围绕业务流程、领域工具和对话策略来搭,代码只是工具箱里的一件工具。即使这样,它仍然是精确计算、数据处理和规则校验离不开的基础能力。

      5.1.3

      Coding Agent 的整体流程

      推荐的工程化流程有五个阶段:项目文档化 → 需求理解 → 设计文档 → 编码与测试 → 审查与交付。每个阶段内部还有闭环反馈。实际产品(如 Claude Code、Codex)会按需裁剪:修简单 bug 时跳过设计文档,只有任务复杂、影响面大时才把各阶段完整走一遍。

      完成的标准是“测试通过”,不是“代码写完”。Coding Agent 最常见的偷懒,就是写完代码不跑测试就报告完成。

      图 5-2 · 五阶段工作流模拟器

      计划先于行动 · 验证贯穿始终 · 文档与代码共同演化
      横轴是动作序号。④ 的测试—修复循环平均 2–3 轮收敛;⑤ 的 lint 在编辑后自动触发;审查发现问题时回到 ④。

      项目指令文件:项目级的系统提示词

      CLAUDE.md、AGENTS.md、.cursorrules 已经是事实标准,每次会话开始时自动注入上下文。README 写给人看,指令文件写的是给 Agent 的行为约定:

      # CLAUDE.md
      - 用 pnpm test 而不是 npm test
      - 禁用 any 类型
      - 不要改动 migrations/ 目录

      SOUL.md 约定“Agent 是谁”,项目指令文件约定“在这个项目里该怎么干活”。它的内容不随任务变化,是最省的稳定前缀,对 KV Cache 友好。

      各阶段要点

      • 文档化:关键文档缺失时,先读代码库,写出架构概览、目录结构和测试指南。知识显式写出来,协作才高效。
      • 需求澄清:“优化性能”要先问清目标(响应时间、内存还是吞吐)、能接受什么代价、瓶颈在哪。
      • 设计文档:审查一份简洁的设计比审查几百行代码容易得多,是人类最省力的介入点。
      • 测试与自审:测试失败就分析、定位、修改,直到全部通过;再通过阅读代码、跑 lint 或调用审查子 Agent 自审。
      • 文档同步:过时的文档比没有文档更糟。

      AI-ready 的简单指标

      一个远程新人只靠代码仓库和文档,能不能独立开展工作?决策记在文档里,上下文写在 issue 和 PR 描述里,经验沉淀在开发者指南里,Agent 才读得到。对远程工作友好的团队,往往也对 AI Agent 友好。

      “先读多少再动手”是模型学到的策略

      有的模型改之前会广泛阅读目录、实现、调用方和测试;有的只读几个最相关的文件就提交补丁,把编译和测试反馈当成调查的一部分。换 Harness 后这个阈值可能不变,同一 Harness 换模型时却可能改变。Harness 能放大或抑制它,但它不一定来自 Harness(第七、八章)。

      5.1.4

      Harness 工程在 Coding Agent 中的实践

      Agent = Model + Harness。Harness 包括上下文与工具(让 Agent 能做事),以及约束、验证与纠正(让 Agent 不做错事)。Agent 能不能稳定运行,往往不取决于模型多强,而取决于这套基础设施是否扎实。在编码场景里,它落成四个组件:

      验收基线

      什么算做完:测试套件、CI 管道、代码审查标准。

      执行边界

      能碰什么、不能碰什么:模块边界、依赖规则、权限控制。

      反馈信号

      自动判断对错:Linter 输出、测试结果、类型检查错误。

      回退手段

      出了问题怎么恢复:Git、沙盒隔离、快照回滚。

      表 5-1 · 任务清晰度 × 验证自动化程度

      点击格子查看

      Coding Agent 是目前最成熟的一类 Agent,原因不是代码模型特别强,而是软件工程几十年积累下来的测试、类型检查、Linter、Git,本身就构成了一套强大的 Harness。

      大规模代码迁移

      一家大型科技公司的公开分享。关键在 Harness 做对三件事:知识存放在代码库里(Agent 看不到就等于不存在);约束写进 Linter 和 CI,不写在文档里;验证和纠正全链路自动化。

      LangChain

      只优化 Harness(系统提示词、工具中间件、自验证循环),就显著提升了基准表现。用 Agent 分析失败轨迹来改进 Harness,让这项工作从凭经验变成靠数据。

      Anthropic

      长任务分给两个角色:初始化 Agent 把任务拆成清单,执行 Agent 逐步推进,并把中间成果留给下一轮。这样解决了“一次想做太多”和“过早声称完成”。

      可迁移到所有 Agent 的四条原则

      1. 约束优先于指导:能用代码强制的规则就不写成文档建议。前者是“做不了”,后者只是“建议别做”。
      2. 验证要自动化:人工审查无法扩展。
      3. 反馈越快、越结构化越好:错误信息越详细、离出错时刻越近,纠正效率越高。
      4. 回退要可靠:在安全网里,Agent 才能大胆试错。

      约束动作,不只约束结果

      修数据库故障时把库删了重建,“修复”确实生效了,数据却没了;修编译错误时把代码全删了重写,编译确实过了,实现却没了。这类破坏性捷径总是存在,即使写进评估指标也常被绕过(第八章 reward hacking)。所以生产级 Harness 要对 rm -rf、删生产数据、覆盖未读文件这类动作专门检查并审批。在训练侧,对应的是第八章的 RLVP:奖励结果,惩罚路径。

      故障边界控制 · 同时读三个文件,其中一个找不到

      点击某一行,切换成功 / 失败

      原则:故障只在同一批并行调用里传播,不上升到父级操作。依赖失败结果的调用会被级联中止,彼此独立的调用继续执行。每个工具要声明自己能否并发,默认不能,这样失败时是安全的。

      5.1.5

      故障与错误恢复

      第一章的消融实验里,只少了一条工具结果反馈,Agent 就陷入了无限循环。生产环境的故障种类更多。本节回答三个问题:会遇到哪些故障,怎么检测和恢复,什么时候必须终止。下面的分析基于对 Claude Code 等生产级 Agent 源码的研究,只提炼其中稳定的工程原则。

      API 层

      限流(HTTP 429)、过载、超时、断连、输出触顶被截断。和任务内容无关,是基础设施的噪声。

      工具层

      幻觉调用、参数畸形、执行抛异常。最危险的是工具反复返回同一个错误,模型却原样反复重试。

      上下文层

      窗口溢出、压缩失败、轨迹结构损坏(例如工具调用缺少配对的结果)。

      控制流层

      死循环:反复做同样的事却没有进展。死亡螺旋:恢复逻辑自己调用 LLM 又出错,引起连锁反应。

      先分类,再决定怎么恢复

      错误 → 恢复策略映射表

      第一个问题不是“要不要重试”,而是“值不值得重试”。不可重试的错误重试多少次结果都一样,必须改变输入或策略。还要检测模式:对“工具名 + 参数”算指纹,同一指纹反复出现,说明陷入了无进展循环;每条恢复路径各自维护连续失败计数,作为熔断的依据。

      恢复要分级升级:能在低一级解决,就不升级

      恢复成功之前,错误不暴露给消费者

      为什么退避要叠加随机抖动

      示意模拟 · 单位为时间片

      不加抖动时,所有客户端在同一时刻重试,形成一波波尖峰,造成二次拥塞。另外两个细节:要遵守服务端返回的等待时长提示;要区分前台和后台调用。主循环请求失败要重试,标题生成、输入建议这类后台辅助调用失败就直接放弃,否则会挤占主链路配额,形成“重试放大”。

      静默卡死:通着但不出水

      示意时间线

      SDK 的超时往往只覆盖初始连接,不覆盖传输过程。每个长连接都需要活性信号,不能只靠连接超时。

      熔断阈值来自生产数据

      Claude Code 压缩熔断 · 对数刻度
      熔断阈值连续 3 次
      这类无效重试每天在全球造成的浪费约 25 万次 API 调用

      第 3 次大约是两种情况的分界点:之前绝大多数故障已经恢复,之后再重试基本没有希望。同样,权限分类连续失败就回退到人工询问,输出接续最多尝试固定轮数。

      死亡螺旋 · 一个真实发生过的连锁故障

      宁可丢掉一次辅助功能(比如自动提取记忆),也不在错误路径上调用模型。所有自动化机制之上,还要有全局的终止与升级条件:最大迭代轮数、会话预算上限、连续失败超过阈值就升级到人工。

      工具层错误:不终止,变成模型的输入

      幻觉调用收到“工具不存在”的结构化错误;参数校验失败收到附带输入约束的提示;本该是对象却输出成字符串的畸形参数,在执行前先用程序修复。它们都作为普通工具结果进入上下文,由模型下一轮自行纠正。喂回的错误越具体,模型自我纠正的成功率越高。

      产品模式宽容,训练模式严格

      发现工具调用缺少配对的结果时,系统在注入上下文前自动修复,不把结构异常抛给模型或用户。有的生产级 Agent 同时跑产品模式和训练数据收集模式:产品模式下可以用占位符补上缺失的消息,训练模式下拒绝修复,因为合成的占位符会污染训练数据。

      接管:把没跑完的轨迹交给另一家模型

      实验 5-1 · 下表是正文推理,实测结果须如实记录

      真正的障碍不是接口地址不同,而是轨迹里有一部分只属于原厂商。工具调用和结果各家结构不同、语义一致,重新渲染就行。难办的是思考:可读的文字换一家仍然读得懂,厂商附在上面的凭证换一家就失效。凭证还可能附在工具调用上。

      所以轨迹应当存成一份中立格式:思考拆成可移植的文字和不可移植的凭证,工具调用只记名称和参数,标识符在渲染请求时按目标厂商重新生成。这份中立轨迹也是第七章评估重放、第八章训练样本、第九章经验提取共用的产物。

      5.1.6

      Coding Agent 的实现技巧

      以下五个技巧都是为了在不降低思考质量的前提下,提高响应速度、减少上下文消耗。它们共同指向一个目标:让 Agent 像经验丰富的开发者那样流畅地工作。

      ① 并行工具调用 + 流式执行

      示意单位。模型在一次推理里依次输出“搜索代码、查配置文件、读日志”三个调用。第一个调用的参数一完整生成并通过校验就开始执行,和后两个调用的生成过程重叠进行;彼此独立的调用还可以并行。

      ② 长输出只留首尾

      第四章的截断与持久化

      前几行通常包含错误上下文,后几行通常是错误总结。读文件也一样:支持按行号范围读取(比如只读第 100–150 行),并在每行前加上实际行号,模型就能精确引用“src/main.py 第 42 行”。

      ③ 环境信息放进 Agent 状态栏

      追加在上下文末尾
      <agent_status>
      cwd: /home/dev/proj
      git branch: feature/rate-limit
      recent commits:
        a1b2c3d add retry middleware
        9f8e7d6 split db module
      staged:   src/api.py
      unstaged: tests/test_api.py
      </agent_status>

      示意内容。四项关键信息:当前工作目录、git 分支、最近提交、已暂存和未暂存的变更。它们不能硬编码进静态系统提示词,否则会破坏 KV Cache,要作为动态的、追加式的状态栏,每次推理前实时生成。

      ④ 持久化终端会话

      激活虚拟环境这类操作只在当前 shell 里有效。持久会话应作为默认模式,同时保留启动隔离终端的能力,用来跑并行任务。

      ⑤ 即时语法反馈

      示意。写文件一完成,工具层就自动运行 linter,把结果放进工具返回值。就像在 IDE 里少打一个括号,编辑器马上画出红线。错误在引入的那一刻就被修正,不用等到跑测试才发现。

      5.1.7

      搜索工具:从粗到细,从语义到语法

      图 5-3 · 四类互补的搜索工具

      选一个需求,看该用哪一类

      路线之争:要不要建嵌入索引

      以 Claude Code 为代表的终端型 Agent 刻意不建索引,靠 agentic 的 grep + glob 现场检索,既不用维护随代码变化而过时的索引,也省掉了一整套索引基础设施。Cursor 这类 IDE 早期走相反路线,为跨文件的语义召回付出建索引的成本。现在 Cursor 等 IDE 也改成了 grep + glob 现场检索。

      语义搜索的两个关键

      结构感知分块:按函数、类、方法这样完整的语义单元切分,而不是按固定字符数切。混合检索:向量嵌入找语义相近但用词不同的代码(搜“验证用户身份”能找到 check_credentials),关键词匹配精确命中函数名,两路并行,再用 reranker 合并排序。

      5.1.8

      文件编辑工具:怎么告诉系统“改哪里、怎么改”

      难点不在编辑操作本身,而在人类语言的表达和机器的精确执行之间存在根本张力。图 5-4 比较了五种方案。下面的计算器估算每种方案下模型需要输出多少字符。

      图 5-4 · 五种编辑方案的输出量与风险

      示意估算:每行按 40 字符计
      方案做法优势劣势实际采用
      Old → New给出要替换的原文和新文本,框架做精确查找替换可预测、无歧义:原文唯一就成功,否则失败大段删除要完整输出原文,差一个字符就匹配失败Claude Code、Codex、今天的 Cursor
      Diff + Apply Model输出 diff 或带“此处不变”的骨架,由更小更快的应用模型合并关注点分离描述和实际代码稍有出入,或有多段相似代码,就可能合并错位Cursor 早期,后来因基础模型变强而放弃
      行号定位“删除第 X 到 Y 行,插入新内容”大段删除只要两个数字每次编辑后行号都会变,多处编辑要统一用初始行号IDE 深度集成场景
      首尾匹配只给要删内容的开头几行和结尾几行兼具文本替换的可靠和行号方案的效率首尾组合在文件中必须唯一部分定制方案
      类 Vim 命令42G、cw、dd、yy/p 等移动、重组代码高效学习负担大,弱模型错误率明显上升;一次输出多条命令时很难预算行号实验性方案

      一次思考里输出两处编辑:行号漂移

      编辑 A:在第 3 行后插入 2 行 · 编辑 B:把第 8 行改成 return x + y

      Vim 命令为什么不适合今天的模型

      Vim 这类编辑器是为人类设计的:人要不断看到当前状态,再规划下一步的小操作。今天的模型是先长时间思考,再批量完成较复杂的操作(比如写几百行代码)。

      5.1.9

      Coding Agent 的安全

      Coding Agent 能读写文件、执行命令、访问网络,一旦被注入恶意指令,就可能造成不可逆的损失。本节按四步展开:威胁模型 → 隔离兜底 → 执行期防御 → 信任与忠诚。

      “致命三要素”+ 持久记忆

      Simon Willison · 第四项是本书补充的放大器

      攻击路径:恶意指令藏在不受信任的内容里进入 Agent,驱使它读取私有数据,再从对外通道传出去。持久记忆不是并列的第四个必要条件,而是放大器,能把一次性攻击变成跨会话潜伏的长期威胁。四点对应四类边界:数据边界、输入信任边界、输出影响边界、跨会话边界。OpenClaw 这类全权限本地 Agent 四类全占。

      单靠输入过滤基本挡不住提示注入。重点不是识别所有攻击,而是让 Agent 即使被注入,也没有机会把危险动作真正执行出去。

      沿攻击链逐层加防线

      打开防线,看攻击在哪一步被拦下

        网络出口控制

        最容易被忽视,也最关键。默认断网,按需通过白名单代理放行少数目的地:包管理源、文档站点、任务明确需要的 API。即使恶意代码在沙盒里读到了敏感数据,没有出口也传不出去。

        文件系统隔离

        源码目录只读挂载,补丁经审查后落盘,或者把副本挂进可写工作区。生成物和中间文件放在单独的可写目录。~/.ssh、密钥、token 根本不挂载。

        资源限额与超时

        用 CPU、内存、磁盘配额和超时,防死循环、fork 炸弹和无限写盘。超时后要返回结构化错误,例如“执行超过 120 秒被终止,最后输出如下……”,不能静默杀掉进程。

        语义解析,而不是关键字黑名单

        黑名单:禁用命令名 rm

        Shell 可以靠管道、子 shell、变量展开组合出无数写法,任何静态规则都能被绕过。语义解析要理解每个命令的参数类型和消费规则,比如哪个标志位会吃掉下一个参数,从而发现藏在里面的危险载荷。

        Agent 为谁效忠:多方委托下的忠诚度光谱

        替主人砍价时,对面坐着的是交涉对手

        一套行之有效的忠诚度守则

        • 保护主人的私密信息,连这些信息是否存在都不透露
        • 拒绝时不逐条念出拒绝清单,那本身就是泄露
        • 私下的底线不等于对外的立场
        • 只执行主人明确、具体的指令
        • 顶住重复施压

        仓库里读到的不可信内容、工具输出、第三方 MCP 服务器发来的指令,都是想策反 Agent 的“对手”。它们一律降级为“可参考,但不具备指令效力”的数据。

        第二部分 · 5.2

        代码:通用 Agent 的元能力

        普通能力是做某件具体的事。元能力是创造其他能力的能力:Agent 用它当场写出新工具(脚本、API 调用序列)、新约束(断言、校验规则)和新的表达形式(HTML 表单、PPT、视频帧),不必事先把所有能力都做好。下面六节按作用对象由内向外排列:思维本身 → 业务规则 → 内容呈现 → 系统接口 → 用户界面 → Agent 自身。

        5.2.1 · ① 思维本身

        代码作为思考工具

        模型的思考本质上是概率性的、近似的,数学和逻辑问题却要求确定、精确的答案。所以让 LLM 负责理解问题、写出代码,让解释器负责精确计算,两者各司其职。

        例题 · 只选物理、没选数学的有多少人

        默认值即书中题设

        纯自然语言推理

        代码推理

        用户自然语言问题
        →
        LLM识别数学 / 逻辑结构,转成形式化语言(Mathematica、SymPy)
        →
        符号计算 / 约束求解器得到精确结果,√2 保持精确形式
        →
        答案可验证

        Stephen Wolfram 的洞察:Wolfram Alpha 这类符号计算系统算得准,但自然语言理解脆弱,问法稍变就可能解析失败,也处理不了开放域的多步推理。LLM 恰好补上这个短板。

        脚手架该多厚,取决于模型多强

        实验 5-3 · 5-4

        实验 5-4 用 python-constraint 解骑士与无赖谜题(K&K 数据集),要求代码辅助模式准确率达到 90% 以上。实验刻意选用较弱的模型来放大对照。同一套脚手架配上不同能力的模型,结论可能截然相反,评估 Agent 技术时这个前提常被忽视。

        5.2.2 · ② 业务规则

        代码作为业务规则的约束

        “购买后 7 天内可退款”看似清楚:7 天是自然日还是工作日?“购买”指下单还是发货?代码要么跑通,要么报错,不会模棱两可。自然语言规则和代码化规则是互补的:写在提示词里,模型能向用户解释政策、找变通方案(例如改签而不是取消);编码成校验,结果精确、确定,适合多条件组合、时间计算和跨数据源验证。

        代码化规则的真正价值不在省 token,而在防止取消订单、转出资金、删除数据这类不可逆的错误操作。

        τ-bench 航空取消政策 · 校验与执行合并在一个工具里

        政策事实一律查库,时间取服务端时钟
        数据库里的真值
        模型自报(expected_*,可选)

        第一重 · 提示词里的自然语言规则

        帮模型理解政策、向用户解释。

        第二重 · 参数即 checklist

        为了填好 expected_*,模型得先查订单、逐条核对。查到经济舱没买保险时,它很可能在准备调用时就想起规则 5,于是不发起调用,直接建议“先购买保险再取消,或者改签”。这一层用来引导思考,不承担安全责任。

        第三重 · 服务端真值校验守门

        模型可能幻觉,也可能被注入操纵,同一上下文里的 Agent 难以自证清白。最后一道防线必须建在模型无法伪造的数据上。“独立验证”里的独立,既指独立的模型,也指独立的数据来源。

        实验 5-5:在 τ-bench 航空场景,用 Qwen3-4B 对照“纯自然语言规则”和“三重保障”,看任务成功率、违规次数、无效调用次数,并统计 expected_* 自报值和数据库真值不一致的比例。

        5.2.3 · ③ 内容呈现

        代码驱动的多媒体生成

        演示文稿、报告、交互应用,底层都是代码:HTML 描述结构,CSS 控制样式,JS 实现交互。GUI 的所见即所得要求视觉理解和精确的坐标定位;改用代码,Agent 就绕开了视觉定位难题,每个元素的位置、样式和内容都有明确定义。

        图 5-5 · PPT 生成的提议者—审核者机制

          两类显式终止条件:审核者判定“质量达标”,或者达到最大轮数(例如 5 轮),用预算上限防止循环失控。审核者给出结构化建议,带页码、问题类型、严重程度,而不是一句模糊的“不好看”。

          为什么拆成两个 Agent:上下文里要装多少张截图

          Reviewer 每次只看最新版本的渲染图,不受旧版本干扰;Proposer 只积累结构化的文字反馈,token 少,也更好推理。它和第四章的事前审批同属提议者—审核者模式,区别是这里要多轮循环,而且审核者能看到提议者看不到的新信息(渲染结果)。建议让两者使用不同的模型家族,降低犯同类错误的概率。

          图 5-6 · 论文 → 讲解视频的端到端流水线

            PPT:10–20 页 · 覆盖主要贡献 · ≥ 3 张原文图表渲染:零文字溢出 · 布局合理 · 图文匹配视频:5–15 分钟 · 每页时长 = 语音时长 · 叙述连贯

            实验 5-8 · 视频剪辑:两步定位“把冲浪部分剪出来”

            示意素材:只有“冲浪在 40–110 秒”来自书中例子

            视频分析封装成子 Agent,大量截图就不会占用主 Agent 的上下文。定位之后生成 Blender Python API 脚本;Reviewer 先做快速预览、检查关键帧,达标后再完整渲染。验收要求起止点误差不超过 3 秒。

            3D 与工业零件:代码生成还是生成模型

            实验 5-9 · 法兰盘

            路线 A · CadQuery / OpenSCAD 代码

            路线 B · 3D 生成模型(如混元 3D)

            一看:有没有紧凑的精确描述

            法兰盘有五六个参数就能完整定义,代码是它的无损表达。一盆绿植、一块太湖石、一张人脸的细节数不清,内在复杂度接近无限。

            二看:精度要求和可验证性

            孔径 5 mm、公差 ±0.05 mm,差一丝就是废品。代码生成的零件可以程序化验证,生成模型的产物没法直接和规格核对。

            表示形式与可编辑性

            制造需要 B-rep 参数化实体(STEP 文件里有特征树和尺寸参数,可以直接驱动 CNC),生成模型输出的是三角面片网格。两条路也能混着走:几何体用代码参数化,表面纹理交给生成模型。对照组生成一盆绿植时,优劣正好反过来。

            5.2.4 · ④ 系统接口

            代码作为系统适配器

            外部服务常常没有现成的 SDK,文档缺失、返回格式不标准、字段随版本漂移。Agent 不必等人写好适配层,可以当场读接口文档或观察一两条真实响应,生成 HTTP 客户端、鉴权头、解析和格式转换代码。哪里接不上,就现场写一段胶水补上。对完全没有 API 的系统,可以先用 Computer Use 操作界面,再把成功的操作序列固化成 RPA 代码(第九章)。

            实验 5-10 · 自适应日志解析:遇到新格式不报错,而是自我修复

            收到的轨迹日志(后两行是系统升级后的新格式)
            已注册的解析器

              图 5-7 · 生产日志智能诊断流水线

              把人工诊断从小时级降到分钟级
              
                  

              Agent 读生产轨迹,结合架构文档和 PRD 判断执行流程是否符合预期,定位出问题的环节和模块,生成结构化报告和回归测试(测试引用轨迹 ID 和交互轮次,由测试框架自动重放),最后通过 MCP 对接 GitHub,创建 Issue 并分配给相关开发者。

              5.2.5 · ⑤ 用户界面

              代码作为生成式 UI

              纯文本对话是线性的:收集结构化信息要反复问答,呈现复杂数据关系时表达力有限,让用户在多个选项里选择时,文本列表不如界面直观。Agent 可以动态生成表单、交互图表甚至完整的 Web 应用,这叫生成式 UI。

              A2UI 类声明式协议:只能点菜单上的菜

              客户端用受信任的组件目录渲染

              如果 Agent 直接生成 HTML/JS,被提示注入后可能写出窃取数据的脚本。成因是提示注入,在浏览器里的效果类似 XSS,但不能把整个攻击都叫作 XSS。声明式协议只让 Agent 输出 JSON 清单,客户端用自己的原生组件渲染,因此能跨平台(React、Flutter、原生应用),也能用流式 JSONL 增量生成。注意 AG-UI(CopilotKit)不是界面描述语言,而是把消息、工具调用和状态补丁流式推到前端的事件/传输协议,甚至可以承载 A2UI 载荷。两者是互补关系,不是同类。表单、表格、卡片这类标准交互适合用声明式协议;自定义可视化、游戏界面仍然直接生成代码更灵活。

              图 5-8 · 动态表单澄清意图:“我想订去北京的机票”

              实验 5-12

              级联逻辑:只有选“往返”时才显示返程日期。表单代码由 LLM 动态生成。

              结构化 JSON 返回
              Agent 拿着完整参数继续执行
              文本问答10 轮对话
              动态表单1 次提交
              OpenAI Deep Research 等仍用文本问答

              图 5-9 · SQL 查询:数据绕过 LLM 直达前端

              build_artifact(
                type="sql",
                code="SELECT dept, COUNT(*) as cnt
                      FROM employees GROUP BY dept")
              build_artifact(type="chart", code="bar(data)")

              传统模式让 LLM 读几千行结果再用文字复述,耗 token、耗时间,而且 LLM“抄写”数据很容易出错。Artifact 模式下 LLM 只写代码,不参与数据传递,这就是“代码生成作为接口”的精髓。

              生成的 SQL 也不能直接执行

              Artifact 模式缩短了数据路径,但不能替代权限检查与执行隔离

              执行层还应当:使用只读数据库账号;限制查询时间、返回行数、可访问的表和时间范围;可视化代码在隔离网络和文件系统的沙盒里运行,只能输出规定格式的结果。

              实验 5-13 · 自然语言交互的 ERP Agent:员工表 + 工资表,自动回答 10 个问题

              员工表:员工 ID、姓名、部门、级别、入职日期、离职日期(为空表示在职);工资表:员工 ID、发薪日期、工资(每月一条)。① 平均每个员工在职多久?② 每个部门有多少在职员工?③ 哪个部门员工平均级别最高?④ 每个部门今年和去年各新入职多少人?⑤ 前年 3 月到去年 5 月,A 部门的平均工资?⑥ 去年 A、B 部门谁的平均工资高?⑦ 今年每个级别的平均工资?⑧ 入职一年内、一到两年、两到三年的员工最近一个月平均工资?⑨ 去年到今年涨薪幅度最大的 10 位员工?⑩ 有没有拖欠工资(某月在职但未发薪)?

              用 HTML 交付成果,替代 Markdown 汇报

              相比一页页翻读的 Markdown,HTML 有三个优势:用可操作的演示说明系统怎么运行;用图表和可下钻的组件呈现数据;网站可以随工作推进持续完善,而不是结束时一次性产出的死物。作者为每个研究项目维护一个交互式网站,用来追溯实验数据(prompt、LLM 原始回复、judge 打分)、监控训练的“内科指标”(损失、梯度范数、学习率、困惑度、奖励、KL 散度、策略熵),以及展示系统的运行原理。你正在看的这个页面就是这种交付形式。

              动态生成软件:从“一刀切”到“千人千面”

              Anthropic 的 “Imagine with Claude” 实时生成界面和交互逻辑,用户操作后 Claude 改代码、生成新界面。这种完全动态的模式成本和延迟较高,更适合作为展示能力边界的实验。更务实的是“半定制”:在已有框架上改,比如“把按钮改成蓝色”“在侧边栏加快捷菜单”,通过 HMR 热加载即时生效(实验 5-14:React + FastAPI,开发模式热加载)。

              把信任边界下移到数据层

              实验 5-15 · 招聘系统

              目标不是“保证 AI 每次都把权限检查写对”,而是“即使 AI 写错了代码,权限约束也绕不过去”。具体做法:行级安全策略按租户隔离;约束和校验器拒绝非法状态;受控视图、存储过程或数据访问服务只暴露允许的操作;每次读写都带上由受信任运行时绑定的访问上下文(用户、租户、角色或 Agent 身份)。生成代码不能伪造身份,拿不到高权限凭证,也不能绕过数据层直连数据库。应用层仍可以做预检查,以便早点给用户反馈,但最终裁决权在数据层。

              5.2.6 · ⑥ Agent 自身

              代码创造代码:Agent 自举

              DNA 自复制

              随机变异 + 自然选择。不理解自身,不能定向修改,经历了 37 亿年盲目试错。

              Agent 自举

              理解代码 + 定向设计。理解自身机制,有目的地创造,继承最佳实践。

              OpenClaw doctor:Agent 修复 Agent 的运行环境

              确定性检查打底,LLM 兜底长尾

              不要夸大 Agent 在这里的作用:高频问题本来就有明确的检测规则和固定的修复动作,和传统运维脚本没有本质区别。真正体现 Agent 能力的是第二层,处理确定性规则覆盖不到的疑难问题。安全的修复(配置归一化、锁文件清理)自动执行;有风险的操作(重启服务、强制覆盖配置)需要用户确认。

              图 5-10 · 复制 + 定向修改:航空客服 → 电商客服

              架构框架完全继承,所以质量有保障
              新增 / 修改被替换原样继承

              从零写 Agent 时的常见缺陷

              1. 上下文管理随意:不用标准上下文格式,把轨迹转成纯文本塞进上下文,放弃了结构化消息带来的 KV Cache 优化,工具调用循环有边界 bug
              2. 工具设计不规范:描述简略,缺少使用边界和负面清单,参数没有具体示例
              3. 技术选型滞后:倾向于用训练数据里最常见、但已经过时的模型和 API。解决办法是维护 SOTA 知识库,或者让 Agent 能搜索
              4. 脱离外部生态:使用已废弃的 API、不再维护的库或有缺陷的模式

              基于范例生成

              最有效的办法不是在提示词里穷尽所有规则,而是给出高质量的 Agent 实现作为范例,让 Agent 在它的基础上改。范例本身就带着最佳实践,好的架构选择会自然保留下来。接到“开发新 Agent”的任务时,先复制自己(或另一个验证过的实现)的代码,再调整系统提示词、增删工具、改业务逻辑,保留架构框架。这就像基因的复制加变异。

              图 5-11 · 能创造 Agent 的 Agent

                实验 5-16:用 ch5/coding-agent 项目本身作为范例,对比“从零生成”和“基于范例修改”两种方式在质量和效率上的差异。验收时检查标准消息格式、工具调用协议、当前推荐的模型和 API,以及多轮对话中上下文和状态管理是否正确。

                本章小结

                代码是 Agent 形式化思考和精确表达的语言

                一、成熟度来自 Harness

                Coding Agent 成熟度高,是因为测试套件、类型系统、版本控制天然构成了 Harness。这个结论可以推广到其他 Agent 场景。

                二、可靠性来自故障路径

                Agent 是否可靠,不取决于模型犯不犯错,而取决于每类故障是否都有对应的检测、恢复、接管与终止路径。

                三、代码是元能力

                代码既是完成任务的手段,也是积累知识、创造工具、优化自身的机制。

                方向代码做什么本页的交互
                ① 思考工具用符号计算和约束求解弥补概率思考的不足选课例题
                ② 业务规则约束无歧义地表达规则,在不可逆操作前提供确定性防线取消政策守门员
                ③ 多媒体生成提议者—审核者生成 PPT 和视频;按内在复杂度和精度要求选择代码或生成模型截图计数、视频定位、法兰盘
                ④ 系统适配器跟随格式演化,自动解析日志、诊断问题自修复解析器
                ⑤ 生成式 UI动态表单、可视化,乃至可定制的完整应用表单、SQL、数据层边界
                ⑥ Agent 自举用代码修复和创造同类 Agentdoctor、复制 + 修改

                到这里,上下文、知识、工具和代码能力已经组合成通用 Agent 的基础架构。但前五章仍然默认 Agent 和世界轮流行动。第六章会把观察与动作空间扩展到异步事件、语音、屏幕和物理世界,第七章再转向评估与持续改进。

                常见误区

                容易想错的地方

                ✗ Coding Agent 成熟,是因为代码模型特别强✓ 是因为软件工程的基础设施天然构成了 Harness
                ✗ 出错就重试✓ 先分可重试和不可重试;每条恢复路径都要有熔断上限
                ✗ 把规则写进提示词就够了✓ 不可逆操作前要用基于数据库真值的代码校验守门;expected_* 只是模型的自述
                ✗ 关键字黑名单能挡住危险命令✓ $(echo rm)、find -exec、curl -o 都能绕过,要做语义解析
                ✗ 跨厂商接管时把思考删干净就安全了✓ 有的厂商要求工具调用附带凭证;应存成中立格式,必要时把历史调用改写成文字叙述
                ✗ 所有 Agent 都该以 Coding 为架构中枢✓ 这一判断针对开放任务型;垂直客服里代码是工具之一,但仍是基础能力
                ✗ 代码写完就算完成✓ 测试通过才算完成,由验证来判定什么时候可以停
                ✗ 在提示词里写全规则,就能让 Agent 写好 Agent✓ 给出高质量范例,复制后定向修改
                深度思考

                思考题

                1 ★★ 代码执行带来漏洞、死循环、资源耗尽等风险,沙盒又限制了能力(比如不能访问网络或文件系统)。安全和能力的最优平衡点在哪里?

                可以从 5.1.9 的三项隔离出发:默认断网 + 白名单代理、源码只读 + 可写工作区 + 凭证不挂载、资源限额 + 结构化超时错误。思考哪些能力可以按任务放开,以及放开后由哪一层兜底。

                2 ★★★ 每次自举都可能引入新的偏差或错误,这种错误会在代际间累积吗?怎样防止自举退化?

                对比“从零生成”和“基于范例修改”,再想想:范例本身由谁验证?实验 5-16 的验收项(标准消息格式、工具调用协议、推荐的模型与 API、多轮状态管理)能否成为每一代的回归测试?

                3 ★★ 日志解析能自动跟随格式演化。如果格式变化本身是个 bug,Agent 的适应性反而会掩盖问题。怎么区分“需要适应的变化”和“需要报告的异常”?

                结合 5.2.4 的诊断流水线:适配之外,是否应把“格式发生了变化”本身也作为一条结构化报告,交给架构文档和 PRD 判断是否符合预期?

                4 ★★ 如果 Reviewer 的审美和目标用户不一致,提议者—审核者循环会收敛到错误的局部最优。怎样让用户偏好也参与进来?

                回顾提议者—审核者的设计原则:共享目标约束,反馈作为特殊事件加入 Proposer 的轨迹。用户反馈能否以同样的结构化形式进入循环,并改变 Reviewer 的审查维度?

                5 ★★ 经验被沉淀进知识库文件、架构文档、项目指令文件和固化的代码。如果再提炼成提示词规则,规则集会不断膨胀。怎样对规则做“垃圾回收”?为什么一次成功的代码修改还不能直接算作持续进化?

                参考 5.1.2:一条记录什么时候足以成为可靠的知识、指令或程序,还要结合更多轨迹和结果来验证(第九章)。

                6 ★ 你的团队在知识文档化方面,离“AI-ready”还有多远?最大的障碍是什么?

                用本章的指标自测:一个远程新人只靠代码仓库和文档,能不能独立开展工作?

                7 ★★★ 在同时具备致命三要素和持久记忆的生产环境里,你会如何设计安全策略?

                可以从本页“沿攻击链逐层加防线”的演示出发,把每条防线对应到验证、执行、数据三个层面,再考虑写入 MEMORY.md 的内容要经过与外部内容同等的信任审查。

                8 ★★ 与“Agent 直接给出答案”相比,“Agent 生成代码、系统执行代码”的 Artifact 模式有哪些优劣?SQL 可能有破坏性、HTML 可能有漏洞,怎么保证安全?

                对照 5.2.5:只读账号、只允许批准过的 SELECT、拒绝 DDL/DML 和多语句、服务端参数化绑定、限制时间/行数/表/时间范围,可视化代码在沙盒里运行;界面优先使用声明式组件目录。

                9 ★★ 把业务规则编码进工具内部基于数据库真值的校验,并用参数设计引导模型调用前核对条件,相比自然语言规则有什么优势和局限?

                回到 5.2.2 的三重保障:哪一重负责解释和变通,哪一重负责引导思考,哪一重负责安全。代码化规则精确、确定,那么它在解释政策和寻找变通方案上欠缺什么?