跳转至

第9章 生产Harness:让Agent可靠地长期运行

状态:初学者展开试稿,待人工审阅(基于Release Candidate 1修订)

本章定位:承接第3章的Runtime与第6—8章的执行边界,把状态、恢复、预算、并发、错误、版本和发布组织成生产控制面。

本章回答的三个问题

  1. 一个已经能调用模型和工具的Demo,距离可长期运行的产品还缺什么?
  2. 任务跨越重启、超时、审批与取消时,怎样恢复且不重复产生副作用?
  3. 怎样限制成本与并发、追踪版本,并让新版本能够逐步发布和快速回退?

我们继续使用前几章的教学任务:

“帮我找一本适合初中生的月球科普书,确认本校图书馆现在能借,生成推荐卡。卡片先交给老师审批,批准后再发到班级群;不要替我预约。”

前八章已经解释怎样查书、组织上下文、调用工具、等待事件与响应取消。本章假设这个Demo能跑通一次,再问更现实的问题:进程在等待老师时重启怎么办?发送请求超时怎么办?旧任务恢复后会不会覆盖新结果?换模型后怎样知道问题来自哪个版本?

证据类型说明

本章的学校、书目、状态值、配置和伪代码均为教学示例;带“本书建议”的内容是需要在具体系统验证的工程建议;只有明确指向已审查运行记录的内容才是限定条件下的实测结论。本章没有重新运行实验,不提供虚构的成功率、延迟、费用或通用阈值。

5分钟速读

  • Harness是Agent边界内、模型之外的运行与治理层;生产控制面是其中管理运行身份、状态、权限、预算、恢复、版本和发布的部分。
  • 每次任务需要唯一的run_id、版本化State Schema和明确终态。模型停止生成,不等于任务成功。
  • Checkpoint(检查点)是持久化的任务存档。副作用前后、进入等待前和重规划前都应保存关键状态。
  • 幂等防止同一写动作因重试而重复生效。写请求超时后先查询幂等记录或权威状态,不能直接再执行一次。
  • 过期运行隔离(stale-run fencing)阻止旧Worker、旧事件或旧审批覆盖新状态。常用依据是状态版本、租约或隔离令牌。
  • 错误要分类。参数错误、权限拒绝和业务拒绝通常不应重试;临时故障也只能在预算和幂等保护下有界重试。
  • Token、模型调用、工具调用、墙钟时间、费用、并发、Artifact大小和委派深度都可以成为硬预算,由程序计数和拒绝超额动作。
  • 取消不是杀进程。先停止接受新工作,向子任务传播取消,在安全点保存状态和释放资源,再核对已经发生的副作用。
  • 模型、Prompt、Schema、工具、政策和执行图都要带版本。新模型不能自动继承旧模型的评估结论。
  • 发布路径是离线回放 → 影子流量 → 金丝雀 → 有限放量 → 全量;每阶段都要预先定义停止与回滚条件。
  • 生产失败不应直接触发在线自我训练。先检查知识、Prompt/Skill和Harness等外部、可版本化载体,再决定是否需要参数更新。
  • 多个Worker若确有必要,应使用私有工作区和带Schema、Hash、来源、ACL的Artifact交接,由单一Owner合并;否则优先单Run顺序执行。

一、先认识生产Harness:不只是给模型套一个循环

1.1 Harness、Runtime与控制面是什么关系

第1章把Harness解释为Agent边界内、Model之外的运行与治理程序。它构造Context、提供Tool接口,并实施约束、验证与纠正。Environment中的数据库、网页和消息系统不属于Harness,即使它们部署在同一台机器上。1

第3章介绍的Runtime(运行时)负责推进一条执行图:调用节点、读写State、等待事件并进入终态。本章所说的生产控制面(Production Control Plane)不是另一个模型,而是Harness中保证大量Run长期、受控运行的那部分程序和基础设施,例如:

  • 创建和归属Run;
  • 保存版本化State与Checkpoint;
  • 计量预算、并发和截止时间;
  • 管理租约、队列、取消和恢复;
  • 执行权限、审批和幂等;
  • 记录配置版本、Artifact与完成证据;
  • 控制新版本放量和回滚。

“控制面”可以类比车站调度室:它不替司机判断每位乘客想去哪儿,却决定哪列车能进入哪条线路、何时停、故障后怎样恢复。这个比喻只帮助理解职责,不代表所有系统必须部署一个独立的“控制面服务”。简单产品可以把这些职责实现在应用内。

1.2 Demo成功一次,为什么还不够

找书Demo在开发者电脑上顺利跑通,并没有回答下面的问题:

  • 老师一天后才批准,原进程已经更新或重启,任务还能继续吗?
  • 消息平台收到发送请求,但回执丢失,重试会不会发两遍?
  • 用户已取消,排队中的Worker还会不会继续发送?
  • 同一个Run被两个Worker同时领取,谁有权写最终状态?
  • 新Prompt上线后失败,能否知道当时使用了哪套模型、工具和政策?
  • 成本、队列和并发突然增长时,系统会降级、排队还是无限扩张?

这些不是提示词能够可靠解决的问题。模型负责有不确定性的语义判断;程序负责身份、状态转移、权限、计数、并发和外部事实。 这延续了第3章的Model—Runtime分工与第6章的统一工具网关。2

1.3 本章贯穿案例的完成合同

为避免“生产化”变成堆组件,本章先写清合同:

目标:找到有依据且当前可借的书,生成推荐卡;老师批准后发送。
权限:查询阶段只读;发送使用受限服务身份;禁止预约。
审批:绑定准确卡片版本、班级群和附件;过期或载荷变化后失效。
恢复:等待审批和进程重启后可以继续;已发送消息不能重复发送。
取消:阻止新动作并级联子任务;对结果未知的发送先查权威状态。
完成:消息系统确认指定载荷已发送;否则只能是等待、阻塞或失败。
回滚:草稿可恢复旧版;已发送消息通常只能更正,不能保证真正撤回。
证据:保存Run版本、审批、幂等键、外部消息ID和最终状态。

这是教学合同,不是学校的真实安全政策。正式系统必须由业务、安全、隐私和运维负责人共同确定权限、保留期、审批和服务目标。

二、生产控制循环:把候选行动变成有证据的状态转移

图3(复用):生产Harness控制循环

本章复用第3章的图3(统一执行图),不另造一张内容重复的图。这里从生产控制面的角度重读同一张图:节点可以换模型或工具,但每条重要转移都必须经过状态、权限、预算和验证。

认证输入并创建Run
→ 从Checkpoint读取版本化State
→ 构造当前Context
→ Model提出候选决定
→ Schema与语义校验
→ 身份、政策、预算与审批检查
→ 写入执行意图和幂等键
→ Tool改变或查询Environment
→ Verifier核对权威结果
→ 原子更新State与Checkpoint
→ 继续 / 等待 / 成功 / 部分成功 / 阻塞 / 失败 / 取消 / 预算耗尽

Verifier(验证器)是检查结果是否满足条件的程序、工具或人工步骤。查到外部消息ID、重新读取文件、运行测试都可以是验证;模型说“完成了”不是独立验证。

工程建议

关键顺序是“先持久化意图,再执行副作用;先验证结果,再提交完成”。具体数据库、队列和事务实现要按业务系统选择,没有一个框架能自动保证这条顺序。

三、Run与State:让每次任务有身份、有主人、有终点

3.1 Run ID不是装饰字段

Run(运行)是一次从输入到终态的任务实例,run_id是它的唯一标识。用户再次发起相同请求,通常是另一个Run;同一个Run因进程重启而恢复,仍应保留原run_id

还需记录:

  • tenant_id:属于哪个租户或组织空间;
  • actor_id:由哪个已认证主体发起;
  • ownerlease:当前哪个Worker拥有推进权;
  • parent_run_id:是否由父任务创建;
  • created_atdeadline:何时开始、最晚运行到何时。

身份来自认证系统和服务凭据,不来自模型声称“我是老师”。凭据由执行层代管,不应写进State、Prompt、Artifact URI或普通日志。

3.2 一份初学者可读的State Schema

下面的YAML是教学示例;时间、预算、ID和版本均为占位值,不是推荐阈值:

run_id: run_demo_01
tenant_id: school_demo
actor_id: student_demo
status: waiting_approval
state_version: 12
owner:
  worker_id: worker_7
  lease_token: lease_31
  lease_expires_at: 2026-09-21T10:10:00Z
current_step: await_teacher_approval
verified_facts:
  book_id: BK-204
  availability: available
  observed_at: 2026-09-21T09:55:00Z
artifacts:
  card:
    uri: artifact://run_demo_01/card-v1.md
    content_hash: sha256:example-only
    acl: [student_demo, teacher_demo]
approval:
  status: pending
  payload_digest: sha256:example-only
completed_effects: []
pending_effects:
  - send_card_v1_to_class_demo
budgets:
  model_calls_remaining: 3
  tool_calls_remaining: 4
  deadline: 2026-09-21T12:00:00Z
versions:
  state_schema: 2
  graph: book-flow-v3
  prompt: recommendation-v5
  output_schema: card-v2
  model_route: reasoning-primary-v2
  toolset: school-tools-v4
  policy: class-message-v7

State Schema(状态结构约定)规定有哪些字段、类型和不变量。state_version是这条状态每次成功修改后的版本号;state_schema则是字段结构的版本。二者不要混淆。

3.3 终态必须说清发生了什么

本书建议至少区分:

状态 普通话解释 找书案例
succeeded 全部成功条件已有证据 指定卡片已被消息系统确认发送
partial_success 有可交付成果,但并非全部目标 卡片生成并核实,但发送失败
waiting 知道在等什么事件,可恢复继续 等待老师审批v1
blocked 缺权限、凭据或决定,当前无自动路径 没有可发送班级群的服务权限
failed 已知无法在本Run内恢复 卡片生成持续违反强制Schema
cancelled 取消已生效并完成必要清理 停止新工作,发送未发生
budget_exhausted 达到硬边界 调用预算用完,仍未找到可借书

waiting可以建模为非终态;团队也可以把长期阻塞结束为blocked,以后新建Run接续。关键是定义清楚,不要全部写成stoppeddone。类型化状态与显式终态来自P04模式。3

四、Checkpoint:把任务从进程内存中救出来

4.1 Checkpoint是什么

Checkpoint(检查点)是持久保存、可恢复的状态快照,类似游戏存档。它不只是聊天记录,而应包含恢复所需的业务状态、版本、Artifact引用、已发生副作用和等待条件。4

适合保存检查点的位置包括:

  • 创建Run并确认任务边界后;
  • 每个外部副作用之前;
  • 副作用得到权威验证之后;
  • 等待用户、审批、定时器或Webhook之前;
  • 重规划、模型路由或Schema迁移之前;
  • 接近预算或服务截止时间时。

短、无副作用、失败后可安全从头执行的原子调用可以简化;不要为了形式每个Token保存一次。

4.2 等待审批时应该发生什么

推荐卡v1准备好后,Runtime应:

  1. 保存卡片Artifact、Hash、目标班级和当前政策版本;
  2. 生成绑定精确载荷的审批请求;
  3. 把State改为waiting_approval
  4. 保存Checkpoint并释放Worker;
  5. 审批事件到达后,验证来源、Run、载荷版本、时效和防重放标识;
  6. 重新取得推进权,再继续发送。

不要让模型每隔一分钟询问“老师批准了吗”。等待是持久状态问题,不是推理问题。

4.3 恢复不是从头重放

进程重启后,Runtime读取最新可信Checkpoint,检查等待事件与外部状态,从未确认完成的节点继续。若机械重放整条轨迹,send_class_message可能再次执行。

恢复前至少核对:

  • Checkpoint是否属于当前租户与Run;
  • State Schema是否能被当前代码读取或迁移;
  • 已完成副作用是否有权威外部ID;
  • 审批、凭据和政策是否仍有效;
  • 原Worker租约是否失效;
  • 目标是否被用户取消或修改;
  • 剩余预算和截止时间是否仍允许继续。

五、幂等:让同一动作的重试不变成第二次动作

5.1 为什么超时最危险

发送工具超时,只说明调用方没有及时收到明确结果。消息可能未到达、已经发送,或仍在处理中。直接重试与直接认定成功都不可靠。

幂等(Idempotency)在本章指同一业务动作重复提交时,不再产生一份额外副作用。稳定的幂等键应由业务语义产生,并绑定主体、对象和已批准载荷摘要。5

class-message:{tenant}:{class_id}:{approved_payload_digest}

不要每次重试生成随机键;不要只使用run_id,因为一个Run可能合法执行多个不同动作;同一个键也不能接受变化后的正文或收件人。

5.2 安全执行顺序

下面是不能直接运行的教学伪代码:

校验当前身份、权限、政策、预算和准确审批
生成稳定业务幂等键,并绑定载荷摘要
保存 Checkpoint(intent, key, state_version)

调用写工具(key, payload)
如果超时或连接中断:
    查询幂等记录或权威业务状态
    已完成 → 复用外部结果
    确认未执行且仍被授权 → 使用同一key有界重试
    状态不确定 → 阻塞并交人工处置

验证外部对象、载荷版本和最终状态
原子保存 completed_effect + external_id + 新state_version

安全边界如下:身份和权限由策略网关判断;凭据只在执行器中短时使用;T3/T4等高影响动作按组织政策审批;超时不改变审批范围;回滚能力在执行前说明;完成证据来自权威系统而不是工具调用返回一行“OK”。

5.3 幂等不是回滚

幂等防止重复发送,却不能让已经看过消息的人忘记。回滚(Rollback)是恢复到先前状态;补偿(Compensation)是无法真正撤销时追加修正,例如发更正消息。设计生产流程时,三者必须分别回答。

六、过期运行隔离:别让昨天的Worker覆盖今天的结果

6.1 什么是stale run

Stale run(过期运行)是仍在执行、但已经失去当前所有权或依据过时状态工作的Run或Worker。常见情况是:Worker A超时,队列把任务交给Worker B;B完成发送并更新状态;A稍后恢复,又试图写入自己的旧结果。

若数据库只执行“最后写入者获胜”,A可能把成功状态覆盖成旧的running,甚至再次产生副作用。

6.2 Fencing怎样阻止旧拥有者

Fencing(隔离)是让每次写入携带当前所有权证明,并由存储或工具端拒绝过期证明。可以使用:

  • 乐观并发版本:仅当state_version = 12时更新为13;
  • 租约:Worker在期限内拥有推进权,续租失败就停止新动作;
  • 单调递增的fencing token:新Owner取得更大令牌,外部写入拒绝旧令牌;
  • 审批和政策版本:旧批准或旧政策不能用于新载荷。

教学SQL式伪代码如下:

UPDATE runs
SET state = new_state, state_version = 13
WHERE run_id = 'run_demo_01'
  AND state_version = 12
  AND lease_token = 'lease_31';

如果更新行数为0:
    不得覆盖;重新读取当前状态并停止、重规划或交人工

这不是可直接复制的完整数据库事务。正式实现还要处理租约时钟、事务隔离、队列语义和工具端幂等。只有应用数据库做版本检查,而外部写工具不做幂等,仍然可能重复发送。

七、错误分类、重试、Fallback与熔断

7.1 不要对所有错误“重试三次”

Fallback(回退路径)是在主路径不可用时采用的替代模型、工具或人工流程。Circuit Breaker(熔断器)是在某服务持续失败时暂时停止调用,避免更多请求放大故障;它类似电路保险装置,但具体开启和恢复条件必须测量。

错误类别 找书案例 默认处理方向
Schema/Validation 缺少book_id 修正候选或拒绝,不原样重试
Authorization/Policy 学生身份请求发送或预约 拒绝、等待授权;不靠重试突破
合法空结果 没有符合条件的书 换查询或诚实结束,不当网络错误
永久业务错误 班级群不存在 澄清、改道或失败
Rate Limit 模型或工具限流 遵循服务提示,有界退避并计入预算
临时网络/服务故障 馆藏服务暂时不可用 对只读调用有界重试;写调用先查状态
不确定副作用 发送超时 查幂等记录/权威状态,不直接重试
Model Refusal/空输出 模型拒绝或返回空内容 分类原因,允许时走经评估Fallback
Context Overflow 输入超过窗口 按第4章压缩、分段或终止
Budget Exhausted 时间或费用耗尽 明确终态,不伪装成功
Policy/Approval Changed 批准后政策或载荷变化 重新预览、重新授权和审批

7.2 重试要满足四个条件

本书建议只有同时满足以下条件才自动重试:

  1. 错误合同明确标为可重试;
  2. 重试不会扩大权限或副作用,写入已有幂等保护;
  3. 仍有时间、调用和费用预算;
  4. 新尝试有变化,例如等待退避、服务恢复或参数已修正。

同一参数、同一错误、同一环境不断重复,不是恢复。可以对错误指纹和状态摘要做无进展检测,达到系统设定上限后熔断或退出;具体次数不能从本章照抄。

7.3 Fallback不能偷偷降低安全标准

主模型失败后可以路由到备用模型,但备用路径仍必须遵守相同的工具权限、审批、预算和完成验证。不能因为主模型拒绝,就改用一个不执行安全策略的模型;不能因为主消息API不可用,就改用一个没有幂等和审计的临时脚本。

八、预算、并发与取消:限制最坏情况

8.1 预算不只有Token

Budget(预算)是一次Run可使用资源的硬上限。可包含:

max_model_calls: <按任务测定>
max_tool_calls: <按任务测定>
max_input_tokens: <按模型与成本测定>
max_output_tokens: <按任务测定>
max_wall_time: <按服务目标测定>
max_cost: <按组织计价与币种测定>
max_concurrency: <按容量与限流测定>
max_delegation_depth: <按拓扑测定>
max_artifact_bytes: <按存储政策测定>

尖括号不是待复制的生产值,而是提醒实施者必须填写自己的上限。费用要使用当前供应商的计费记录计算;不要从Token数量虚构成本。预算由程序预留、扣减和拒绝,展示给模型只用于帮助它规划。P03将这类设计称为有界执行循环。6

8.2 并发不是越多越快

并发会受到模型限流、数据库连接、外部API、队列和合并步骤限制。达到上限时应排队、降级或拒绝,不应无限创建Worker。多个Worker处理同一Run时,租约与fencing必须防止并发写。

只有任务独立且收益经过比较时才并行。多个Agent还要计算Manager、上下文复制、Artifact和合并成本;第14章进一步讨论多Agent准入。10

8.3 取消的正确顺序

安全点(Safe Point)是可以停止而不留下无法解释中间状态的位置。取消流程建议为:

记录取消请求
→ 阻止新的模型、工具和子任务
→ 向子任务树传播取消
→ 在工具调用结束、事务完成或Checkpoint落盘后的安全点退出
→ 释放租约、浏览器、文件锁和临时凭据
→ 查询结果未知的副作用
→ 保存cancelled或需要人工处理的终态与证据

无响应工具在超时后可以强制终止,但不能因此假定外部动作未发生。只停止UI转圈或TTS播报,不是任务取消。P15给出了Safe Point与级联取消模式。7

8.4 多Worker需要隔离工作区

并行查询不一定需要多个Agent;普通受限工具并发可能更简单。确实需要多个Worker读写文件或生成产物时,不应让它们直接修改同一个共享目录。P19的工程建议是:每个Worker使用私有Scratch或Worktree,只发布带Schema、Hash、来源和ACL的Artifact,再由一个明确Owner合并。13

这条边界同时服务可靠性与安全:私有工作区限制相互覆盖;ACL限制不必要的数据扩散;Hash帮助检测交接后内容是否变化;单一Owner避免两个“最终答案”同时结算。父Run取消时,Worker、临时凭据和工作区租约要一起回收;仍需保留的Artifact按生命周期策略转存,而不是把整个Scratch永久保存。

如果任务是单Agent顺序执行,就不要为了采用模式而创建多工作区。隔离的存储、合并和垃圾回收本身都有成本。

九、Artifact、凭据与证据:状态里不要塞进整个世界

9.1 Artifact Store解决什么问题

完整网页、PDF、日志、截图、代码和推荐卡不宜全部放入State或每轮Context。Artifact Store(产物存储)保存这些大对象,State只保留:

  • URI与对象ID;
  • 内容Hash;
  • 来源与创建时间;
  • 创建者或生成节点;
  • Schema、媒体类型和版本;
  • 租户、ACL与数据分类;
  • 生命周期、保留与删除状态;
  • 与当前决策相关的片段引用。

Hash帮助发现内容变化,不能证明内容真实。摘要是派生内容,不能替代原始证据。这个边界承接第4章P10模式。8

9.2 凭据不能成为Artifact

API密钥、SSH私钥、访问令牌和数据库密码应由Secret Manager或执行层按需提供短时、最小作用域凭据。不要把秘密放进Prompt、State、Artifact、幂等键、命令行参数或普通Telemetry。

恢复Run时,不应假设旧凭据仍有效。Runtime重新认证和授权;凭据缺失时进入blocked,不能扫描用户主目录或降级为管理员密钥。

9.3 什么才是完成证据

贯穿案例的完成证据可以是:

run_id
+ 已批准卡片的content_hash
+ 批准者身份、范围、政策版本和有效期
+ 稳定幂等键
+ 消息系统返回的external_message_id
+ 查询到的最终状态sent
+ 最终State与配置版本

“模型说已发”“工具返回HTTP 200”或“队列接受任务”都可能只是中间信号。第10章会系统讲Trace与Evaluation;本章只要求恢复和终态判断所需的证据不能丢。

十、模型路由与全链路版本:问题发生时要知道跑的是哪一套

10.1 一次Run至少记录哪些版本

  • 模型供应商、模型ID和路由决策;
  • Prompt ID、版本和内容Hash;
  • 输入与输出Schema版本;
  • Toolset及每个工具/协议适配器版本;
  • 执行图与State Schema版本;
  • 权限政策、审批政策和验证器版本;
  • 检索索引或知识版本(若使用);
  • Runtime与发布版本。

供应商可能在同一名称下更新服务行为,因此正式记录还应按其接口提供可用的版本或快照标识。不能获得更细标识时,应明确这一可重复性限制。

10.2 路由是什么

模型路由(Model Routing)是根据任务类型、风险、延迟、成本或故障,把调用送到不同模型的程序。简单抽取可走一种路线,复杂规划可走另一种;主服务故障时也可以有Fallback。

路由本身也会错,必须记录“为何选中、使用了谁、回退了几次”。新模型可能改变工具格式、拒答、上下文长度、输出风格和成本。替换模型后,应重新运行私有评估与兼容性检查,不能默认原Prompt和阈值继续成立。 原始书稿的评估章节也强调固定Harness的模型替换实验用于区分模型与Harness瓶颈。11

10.3 Schema演进不能靠运气

旧Run可能在v1 State上等待审批,新代码只认识v2。部署前应决定:

  • 原地迁移旧State;
  • 保留旧Worker完成旧Run;
  • 将旧Run转人工或安全终止;
  • 新旧工具与政策是否兼容;
  • 回滚代码后,新Schema写入的数据能否被旧代码读取。

迁移脚本应可测试、可重复执行并保留备份。涉及副作用的Run不能通过“删状态重跑”迁移。

十一、部署形态:位置可以变,控制合同不能丢

形态 适合的起点 主要工程负担
应用内Runtime 短任务、低规模、简单恢复 持久化、扩缩容和隔离需自建
Worker + Queue 异步、长任务、可重投工作 消息语义、租约、去重和状态一致性
托管Agent Service 快速接入托管模型与观测 平台约束、可移植性、数据边界
本地/端侧Agent 离线、隐私或设备工具 模型能力、更新、资源和设备运维
混合部署 本地敏感处理 + 云端复杂推理 路由、凭据、网络、来源与跨边界恢复

选型首先看问题合同,不要默认最复杂架构。无论部署在哪里,以下合同应保持:Run身份、类型化State、授权主体、预算、幂等、Checkpoint、完成证据和版本可追溯。

队列也不自动保证“恰好一次”业务效果。消息可能重复投递,Worker可能在确认前崩溃;因此仍需业务幂等和权威状态验证。

十二、发布与回滚:不要把新版本一次推给所有任务

12.1 五个发布阶段

Offline Replay
→ Shadow Traffic
→ Canary
→ Bounded Rollout
→ Full Rollout

首次术语解释:

  • 离线回放(Offline Replay):在可重置环境中重跑代表任务与历史失败,不影响真实用户。
  • 影子流量(Shadow Traffic):新版本观察真实输入或脱敏副本,但不让它的写动作影响用户;敏感数据仍须按政策处理。
  • 金丝雀(Canary):仅让小范围、可控真实流量使用新版本。
  • 有限放量(Bounded Rollout):在限定用户、任务、权限和预算内逐步扩大。
  • 全量(Full Rollout):达到门槛后成为默认版本,旧版本仍保留可回退期。

影子版本不得持有生产写凭据,或其写工具必须由网关硬阻断;“在Prompt里说不要写”不够。

12.2 回滚条件必须在发布前定义

第10章会讲指标和统计。本章先要求每阶段预先定义:

  • 哪些政策违规、越权或重复副作用触发立即停止;
  • 哪些任务完成、Fallback、人工接管、错误和恢复指标需要观察;
  • 延迟与每成功任务成本的边界;
  • 最小观察量与负责人;
  • 谁能回滚、回滚哪个组件、多久内完成;
  • 新Schema、数据和在途Run怎样兼容旧版本。

具体数值必须来自业务目标、容量测试和评估,不能由本章虚构。

12.3 回滚不只是切回旧模型

一次发布可能同时改变Prompt、工具、政策、State Schema和索引。若只把模型名切回去,旧模型可能读不懂新工具结果,旧代码也可能读不懂新State。

本书建议让每个变更可独立开关,保留兼容版本和迁移路径。高风险写能力还要准备紧急熔断:关闭动作,不一定关闭只读查询和人工接管。第10章P16将质量门展开为Schema/Unit、Smoke、Offline和Online四层。12

12.4 生产失败怎样进入下一轮改进

上线后出现失败,不应让当前Run直接改Prompt、代码或模型参数。更稳妥的路径是:保存并脱敏证据,定位首个失效边界,形成最小更新提案,再走上述质量门和渐进发布。

P18将选择顺序概括为外部能力优先更新:先看知识是否缺失,再看Prompt/Skill是否缺少可语言化规则,再看Harness是否缺少可确定执行的控制;只有在信息与接口充分、外部方案仍稳定失败,并且已有合格数据和验证器时,才评估参数训练。14

脱敏失败证据
→ 首错归因
→ 知识 / Prompt或Skill / Harness / 参数的载体选择
→ 最小、可回滚提案
→ 触发失败集 + 原有保留集
→ 离线验证
→ 金丝雀与监控
→ 保留、回滚或继续修订

这是工程建议,不是“外部修改永远优于训练”的定律。它优先解决可解释、可审计和可快速回滚的问题,也避免用训练修复实时知识或权限边界。原始第9章将在线执行与离线进化分开:在线Run只记录证据,离线流程生成和验证更新;本章采用这一安全边界,不复述其中尚未完成证据审查的效果数字。15

十三、贯穿案例:一次跨重启、审批和超时的运行

13.1 创建Run并只读查询

API认证学生身份,创建run_demo_01,写入“不预约”约束、只读工具集、预算和版本。模型选择候选书,Runtime经策略网关调用馆藏工具。结果带书目ID、来源和查询时间写入State。

此阶段不向模型提供预约工具。图书网页中的任何指令都不能改变权限。

13.2 生成卡片并等待审批

程序生成卡片v1 Artifact并检查必填字段。审批系统展示完整正文、班级群、附件、政策版本和可撤销边界。State保存payload_digest并进入waiting_approval,Checkpoint落盘,Worker释放。

老师批准的是v1。若模型后来生成v2,或目标班级变化,旧批准失效,需要重新审批。9

13.3 部署重启后恢复

新Worker读取Checkpoint,验证State Schema、Run租约、批准时效、政策兼容性和剩余预算。它取得新的fencing token;旧Worker即使恢复,也不能再写状态。

执行层为发送工具取得短时、仅限目标群组的凭据。凭据不进入模型Context。

13.4 发送超时

Runtime先保存执行意图与稳定幂等键,再调用消息系统。请求超时后,它查询幂等记录或消息状态:

  • 若找到同一载荷的external_message_id且状态为sent,复用结果;
  • 若权威系统确认未执行,且审批、权限和预算仍有效,使用同一键有界重试;
  • 若状态无法确定,进入blocked并通知人工,不能再发一次碰运气。

13.5 完成或取消

只有目标群组、内容Hash和最终消息状态都一致,Verifier才将Run更新为succeeded。若用户在发送前取消,系统阻止发送并进入cancelled;若取消到达时发送结果未知,先查权威状态,再报告“已取消”或“消息可能已经发送,需人工处理”。

这条路径说明生产Harness的核心不是“永不失败”,而是:失败后仍知道当前事实、谁有权继续、怎样避免重复,以及凭什么结束。

十四、失败模式与反例

14.1 反例一:只把聊天记录写进数据库

重启后系统能读到模型说过什么,却不知道审批绑定哪一版卡片、消息是否已发送、预算还剩多少。应保存类型化State、已完成副作用和Artifact引用,而不只是聊天。

14.2 反例二:模型没有工具调用就标记成功

模型可能因截断、拒答或忘记目标而停下。必须进入完成验证节点,对照任务合同和环境证据。

14.3 反例三:所有异常统一重试

权限拒绝、参数错误、空结果和发送超时都重试,会浪费资源,甚至重复副作用。应先分类,再决定修正、等待、查询状态或失败。

14.4 反例四:重试生成新幂等键

新键让消息系统把重试当作新动作。必须由稳定业务语义导出同一个键,并拒绝同键不同载荷。

14.5 反例五:旧Worker最后写入获胜

A超时后B完成任务,A又用旧State覆盖B。应使用状态版本、租约或fencing token,让存储和工具拒绝旧Owner。

14.6 反例六:取消只停止前端动画

后台Worker、子Agent和发送工具继续运行。取消必须持久记录、级联传播、在安全点清理,并核对已发生副作用。

14.7 反例七:把预算写进Prompt

模型看到“最多调用十次”却仍可能继续请求。程序必须计数、预留并拒绝超限;Prompt只是提示,不是计费器。

14.8 反例八:备用模型绕过原政策

主模型拒答后,系统把任务交给“更宽松”模型并开放全部工具。Fallback必须共享同一身份、网关、审批和验证边界。

14.9 反例九:影子流量仍持有写权限

即使结果不展示给用户,影子版本也可能真的发消息或修改数据。影子环境应禁写或隔离到可重置环境。

14.10 反例十:回滚只切回代码

新版本已经写入新Schema或启动在途Run,旧代码无法读取。发布前必须验证向前/向后兼容、数据迁移和在途任务处置。

14.11 反例十一:日志记录所有Prompt和秘密

为了排障保存完整令牌、用户数据和凭据,反而造成泄漏。只记录必要、脱敏的标识、摘要和证据引用;详细Telemetry与审计边界由第10、11章展开。

14.12 反例十二:多个Worker共享同一可写目录

一个Worker生成卡片,另一个同时修订,第三个读取到半写入文件并发起审批。最终Hash、批准载荷和实际发送内容可能不一致。应使用私有工作区、原子发布Artifact和单一合并Owner;简单顺序任务则不要拆成多Worker。

14.13 反例十三:一次失败就让Agent在线改自己

模型根据一条用户抱怨直接重写Prompt或重试代码,并立即影响后续生产Run。反馈可能误导、含提示注入或只适用于旧工具版本。应把在线证据送入离线改进流程,先选择最可控载体,再用失败集和保留集验证、灰度与回滚。

十五、实施检查清单

任务、身份与状态

  • [ ] 每个Run有唯一ID、租户、认证主体、父子关系和截止时间。
  • [ ] State Schema版本化,计划、候选、已核实事实和执行意图可区分。
  • [ ] waitingblocked、成功、部分成功、失败、取消和预算耗尽语义明确。
  • [ ] 模型不能直接修改批准、权限、预算或权威业务状态。

持久、恢复与并发

  • [ ] 副作用前后、等待前和重规划前保存Checkpoint。
  • [ ] 恢复从最新可信状态继续,不从头重放写操作。
  • [ ] 状态版本、租约或fencing token阻止旧Worker写入。
  • [ ] 队列重复投递与多Worker争抢已有测试。
  • [ ] 并行Worker使用私有Scratch/Worktree,Artifact交接带Schema、Hash、来源和ACL。
  • [ ] 最终合并与结算有单一Owner;取消会回收Worker、租约、临时凭据和工作区。
  • [ ] 父任务取消会传播到子任务,不留下孤儿Run。

工具、权限、凭据与审批

  • [ ] 所有工具路径经过统一Schema、身份、政策和预算检查。
  • [ ] 权限来自认证主体;服务凭据最小、短时,并由执行层代管。
  • [ ] 读、预览、写和状态查询分离,高影响动作使用窄工具。
  • [ ] 审批绑定准确对象、参数、载荷Hash、政策版本、期限与批准者。
  • [ ] 载荷、身份、政策或期限变化时会重新授权和审批。

副作用、错误与取消

  • [ ] 每个写动作有稳定业务幂等键并绑定载荷摘要。
  • [ ] 超时后先查幂等记录或权威状态,不盲目重试。
  • [ ] 幂等、回滚和补偿分别定义并实际演练。
  • [ ] 参数、权限、空结果、临时故障和不确定副作用能区分。
  • [ ] 重试有退避、上限、预算和无进展出口。
  • [ ] 取消先阻止新动作,在安全点保存、清理并核对副作用。

预算、Artifact与完成证据

  • [ ] 模型、工具、Token、时间、费用、并发、委派和存储有硬上限。
  • [ ] 费用使用真实计费与币种记录,不从Token数猜测。
  • [ ] Artifact有URI、Hash、来源、ACL、版本和生命周期。
  • [ ] Prompt、State、日志和Artifact中不含不必要凭据或敏感数据。
  • [ ] 完成由权威环境状态或独立验证器证明,并关联当前版本。

版本、发布与回滚

  • [ ] 模型、Prompt、Schema、工具、政策、验证器和执行图可追踪。
  • [ ] State与数据迁移可重复测试;旧Run和在途事件有处置方案。
  • [ ] 新模型和路由重新执行兼容、私有评估与安全检查。
  • [ ] 发布按离线、影子、金丝雀、有限放量逐级进行。
  • [ ] 每阶段已有停止、Owner和回滚条件,不在故障后临时讨论。
  • [ ] 生产失败先脱敏和首错归因,不由在线Run直接修改正式Agent。
  • [ ] 已按知识 → Prompt/Skill → Harness → 参数检查最可控更新载体。
  • [ ] 更新提案同时通过触发失败集与原有保留集,且可灰度、可回滚。
  • [ ] 回滚覆盖代码、配置、Schema、索引和在途Run,而不只模型名。

知识检查

先用自己的话回答,再看参考解释。

  1. Harness、Runtime和Environment分别是什么?
  2. 为什么模型停止请求工具不能直接把Run标记为成功?
  3. Checkpoint为什么不能只保存聊天记录?
  4. 发送请求超时后,正确的第一步是什么?
  5. 幂等、回滚和补偿各解决什么问题?
  6. state_version与State Schema版本有什么区别?
  7. Stale-run fencing解决什么问题?
  8. 哪些错误通常不应自动重试?
  9. 为什么预算必须由程序而不是Prompt执行?
  10. 用户点击取消后,为什么不能立即杀掉所有进程并报告取消成功?
  11. 切换到更强模型后,为什么仍要重新评估?
  12. 影子流量为什么不应拥有真实写权限?
  13. 一条“消息已发送”的可信完成证据至少应关联哪些信息?
  14. 本章与第10、11章的分工是什么?

  15. 为什么生产中的一次失败不应直接触发Agent在线修改自己?

  16. 多个Worker为什么不应直接共享一个可写工作目录?

参考解释

第1题:Harness是Agent边界内、模型之外的运行与治理层;Runtime推进一次执行图;Environment保存和改变外部世界状态。 Runtime通常是Harness的一部分,Environment不是。

第2题:模型可能因拒答、截断、遗忘或错误而停止。 Runtime必须对照成功条件并查询环境证据;不满足时进入等待、阻塞、失败或预算耗尽等状态。

第3题:聊天只记录说过什么,不能稳定表达权威事实、预算、Owner、批准载荷和已完成副作用。 恢复需要类型化State和外部标识。

第4题:使用原幂等键查询幂等记录或权威业务状态。 超时不代表未执行,直接重试可能重复发送。

第5题:幂等防止同一动作重复生效;回滚恢复可撤销状态;补偿是在无法真正撤销时追加修正。 三者不能互相代替。

第6题:state_version表示某条Run State被修改了多少个版本,用于并发检查;State Schema版本表示字段结构的版本,用于兼容与迁移。

第7题:阻止失去所有权的旧Worker、旧事件或旧审批覆盖新状态或再次执行动作。 常用状态版本、租约或隔离令牌。

第8题:确定性参数错误、权限/政策拒绝、合法空结果和永久业务错误通常不应原样重试。 写操作结果未知时也应先查状态。

第9题:模型可以遗漏或请求延长限制。 只有程序计数、预留和拒绝,才能形成硬边界。

第10题:工具可能正处于事务或外部副作用中。 应先阻止新工作,传播取消,在安全点保存和清理,并核对已发生或结果未知的动作。

第11题:模型变化会改变工具调用、拒答、格式、上下文使用和成本。 旧Prompt、路由和阈值不一定仍适用,必须在自己的任务上复测。

第12题:影子运行的目的只是观察新版本行为。 若持有真实写权限,它即使不展示结果,也可能修改生产环境;应硬禁写或使用可重置隔离环境。

第13题:至少关联Run、批准的精确载荷、稳定幂等键、外部消息ID、权威最终状态和执行配置版本。 HTTP 200或模型自述都不够。

第14题:本章负责运行可靠性和发布控制;第10章定义可观测性与评估证据;第11章系统展开威胁、授权、审计与治理。 实际系统需要三者共同工作。

第15题:单次反馈可能错误、带注入或只适用于旧环境。 应先保存和脱敏证据、做首错归因,选择知识、Prompt/Skill、Harness或参数中最可控的载体,再通过失败集、保留集、灰度和回滚验证。

第16题:共享可写目录会产生覆盖、半写入读取和责任不清。 需要并行时,每个Worker使用私有工作区,以带Schema、Hash、来源和ACL的Artifact交接,由单一Owner合并;简单任务保持顺序执行更合适。

小结

回到找书任务,生产Harness先给Run一个身份和版本化State;只读查询得到的事实带来源写入状态;卡片以Artifact保存;老师只批准准确版本;等待期间Checkpoint让进程可以退出。恢复后,新Worker通过租约和fencing取得所有权,发送使用短时最小凭据与稳定幂等键。超时先查消息系统,完成由外部消息ID和最终状态证明。用户取消、预算耗尽、权限缺失和状态未知都有各自终点,不会被包装成成功。

本章核心可以缩写为:

有身份的Run
+ 类型化State
+ 持久Checkpoint
+ 幂等副作用
+ 版本与所有权隔离
+ 分类错误与硬预算
+ 安全取消
+ 渐进发布与可回滚
= 可运营的生产Harness

它不保证模型永远正确,而是让系统在模型、工具、网络和人都可能出错时,仍能回答:现在处于什么状态,谁有权继续,什么已经发生,怎样证明完成,失败后如何安全退出或恢复。

下一章将沿着这些证据继续讨论评估与可观测性;第11章再把权限、提示注入、数据保护、审计和组织治理展开为完整安全体系。

来源与证据

本章保留修订前第9章的生产控制面主线:Harness职责、Run与终态、Checkpoint、幂等、stale-run fencing、错误分类、多维预算、取消、Artifact、全链路版本、部署形态和渐进发布。初学者案例、YAML、SQL式伪代码和字段值均为教学示例;工程建议需要在具体系统测试。本章没有新增或复现实验,也没有引用第9章那些仍处于pending证据审查状态的实验卡,因此没有把其标题中的数字写成实测结论。16


  1. 原始中文书稿第1章的“Harness工程:模型之外的竞争力”一节定义Agent = Model + Harness,并将Harness限定为Agent边界内、模型之外的上下文、工具、约束、验证与纠正层。本章采用该边界,不转述其中时效性产品排行和未经本章复核的效果数字。 

  2. 蓝皮书P02模型与程序职责分离P08统一工具策略网关。前者要求模型提出类型化候选、程序执行政策与环境动作;后者要求本地函数、框架和协议路径统一经过身份、政策、预算、审批与结果验证。 

  3. 蓝皮书P04类型化状态与显式终态。模式要求使用版本化State Schema,并区分成功、部分成功、阻塞、失败、取消和预算耗尽;本章额外保留waiting作为可恢复非终态。 

  4. 蓝皮书P05 Checkpoint与持久恢复,以及原始中文书稿第6章的“异步与事件驱动:当世界主动找上门”一节。二者支持等待期间持久化、进程释放和事件恢复的机制;具体存储与恢复性能未在本章测量。 

  5. 蓝皮书P06幂等副作用要求稳定业务键绑定动作Digest,超时后先查幂等记录或权威状态,并区分幂等、回滚与补偿。外部消息、支付或部署系统的实际幂等合同必须逐项核对。 

  6. 蓝皮书P03有界执行循环要求Runtime强制步骤、时间、费用和无进展上限;本章把它扩展到并发、委派和Artifact预算。具体阈值取决于任务与服务目标。 

  7. 蓝皮书P15 Safe Point与级联取消,以及原始中文书稿第6章的“事件处理机制”一节。取消先阻止新工作、保存状态、清理资源并沿任务树传播;不可中断动作只能在前后设置安全点。 

  8. 蓝皮书P10上下文压缩与Artifact外置。该模式要求大对象外置并保留URI、Hash、来源和权限;Hash与摘要都不构成内容正确性证明。 

  9. 蓝皮书P07准确载荷审批要求审批绑定主体、资源、准确参数、政策版本、期限、Nonce和动作Digest;执行前重新计算。具体哪些动作需要何种审批由组织政策决定。 

  10. 蓝皮书P20多Agent准入与等预算基线要求新增Agent具备独立信息、并行、隔离、身份或Handoff理由,并与同预算单Agent基线比较。第14章将展开协作生命周期。 

  11. 原始中文书稿第7章“Agent的评估”讨论固定Harness的模型替换实验、成本预算、生产轨迹回流和特性开关;蓝皮书第10章承接正式评估与可观测性。本章只采用“模型变化需要重新评估”和“完成证据可关联”的工程结论。 

  12. 蓝皮书P16四级质量门定义Schema/Unit → Smoke → Offline Eval → Online Eval。Smoke只证明最小路径可达,不证明复杂任务质量;发布指标与统计方法见第10章。 

  13. 蓝皮书P19独立Agent工作区与Artifact交换要求每个Worker使用私有Scratch/Worktree,以带Schema、Hash、来源和ACL的Artifact发布,并由单一Owner合并。该模式只在并行和隔离需求真实存在时采用。 

  14. 蓝皮书P18外部能力优先更新建议按知识、Prompt/Skill、程序/Harness、模型参数选择最可控载体。它是可解释和可回滚优先的工程顺序,不排除有合格数据与验证器时进行后训练。 

  15. 原始中文书稿第9章的“构建可长期运行的持续进化闭环”将在线任务执行与离线更新提案分开,并要求回归、安全检查和渐进发布。本章只采用这一生产边界;当前实验卡仍为pending,故不转述其中量化效果。 

  16. 蓝皮书chapter9实验卡目录中的卡片在本次核对时均标记为“待证据审查/pending”,初步等级从E0到E2不等。本章因此仅说明实验资产存在,不使用卡片标题中的运行次数、提升幅度或通过率作为已核验结论。