第九章 Human in the loop:人应该在什么时候接管方向盘

第八章把审批放在安全体系里观察:当 agent 想越过既有边界时,人可以决定是否授权。 但 Human in the loop 远不止“危险命令弹个确认框”。用户还会补充缺失信息、在执行中改变方向、拒绝某条路线、紧急叫停,以及在中断后决定如何继续。 本章把这些看似分散的交互放回同一张图里:模型提出下一步,harness 管理控制权,人只在机器无法独立作出正确决定的边界上介入。


9.1 Human in the loop 不是“人盯着每一步”

如果把 agent 想成一辆自动驾驶汽车,最保守的设计是:每到一个路口都问驾驶员“左转可以吗?直行可以吗?”。它确实很安全,却也失去了自动驾驶的意义。

另一个极端是:驾驶员只说一次目的地,之后方向盘、油门和刹车全部失效。它很自主,但一旦目标理解错了,错误会沿着 LOOP 连续放大。

Human in the loop 要解决的,不是“要不要人”,而是三个更精确的问题:

  1. 何时交出控制权? 是信息不足时、动作越权时、方向偏离时,还是每个步骤都问?
  2. 交出什么控制权? 是请人补充事实、选择方案、授权副作用,还是终止整个轮次?
  3. 拿回控制权后如何继续? 人的回答怎样进入历史,等待中的工具怎样被唤醒,被拒绝的路线怎样让模型真正放弃?

Codex 的答案可以概括为:

默认让 agent 连续工作,只在语义边界、权限边界和生命周期边界上请人介入。

这意味着人并不住在 LOOP 的每一圈里。大多数时候,模型与工具自行完成“采样 → 行动 → 回灌”;只有遇到不能靠推理消除的不确定性,或者准备跨越既有授权时,控制权才短暂交还给人。

flowchart LR
    U["用户<br/>目标 / 偏好 / 授权"] -->|"开始任务"| L["agent LOOP"]
    L -->|"信息不足"| Q["提问<br/>补全决策"]
    L -->|"越过权限边界"| A["审批 / 权限申请<br/>授权动作"]
    U -->|"方向需要调整"| S["steer<br/>追加新输入"]
    U -->|"必须立刻停止"| I["interrupt<br/>取消当前轮次"]
    Q -->|"答案回灌"| L
    A -->|"批准 / 拒绝"| L
    S -->|"下个步骤边界"| L
    I -->|"保留历史,可 recover"| U

这四个入口看起来不同,背后却共享同一个思想:人不是模型的逐步执行器,而是目标、事实与授权的最终来源。


9.2 三方分工:模型提议,harness 仲裁,人负责意图

Human in the loop 经常被画成“模型 → 人 → 模型”两方关系,但生产级 harness 里至少有三方:

参与者 最擅长的事 不应该独自决定的事
模型 理解任务、探索方案、提出下一步行动 自己扩大权限、把外部内容当成用户授权
harness 维护状态、执行策略、冻结快照、挂起与恢复、记录事件 替用户猜业务偏好,凭空创造授权
定义目标、提供缺失事实、权衡业务取舍、承担授权责任 逐条理解所有底层命令和运行时细节

这是一种刻意的不对称:

  • 模型有提议权:它最接近任务语义,知道自己缺什么信息、想采取什么行动;
  • harness 有程序化的裁决权:规则、沙箱和审批策略决定哪些提议可以自动执行,哪些必须上交;
  • 人有意图与授权权:只有人能回答“我真正想要什么”以及“我愿意承担哪种副作用”。

第八章已经说明,用户点了批准也不意味着所有硬边界自动消失。反过来也一样:模型说“用户应该会同意”不构成授权。三方各守一段边界,任何一方都不能代替另外两方。

关键区别:模型可以判断“这个方案技术上更好”,harness 可以判断“这个动作命中了审批规则”,但只有用户能判断“这是不是我愿意接受的取舍”。


9.3 四种介入,不要混成一个“确认框”

Human in the loop 至少包含四种语义不同的介入。它们都需要用户输入,但不能共用一个含糊的“确定/取消”。

介入形式 谁发起 回答的问题 对当前轮次的影响
steer 用户主动 “目标或约束变了吗?” 不打断在途采样,在下个步骤边界注入
提问 模型主动 “缺失的事实或偏好是什么?” 当前工具调用等待,答案作为结果回灌
审批 / 权限申请 harness 或模型 “这个动作或权限是否被授权?” 批准后执行,拒绝后换路或停止
interrupt 用户主动 “当前工作是否必须立刻停下?” 协作式取消当前轮次,保留已发生的历史

它们分别对应四种不同的控制问题:

  • steer 改的是方向
  • 提问补的是信息
  • 审批授的是权力
  • interrupt 控的是生命周期

如果把四者混在一起,语义会迅速变坏。例如把“我不喜欢这个实现方案”表达成“拒绝命令”,模型可能只换一条命令继续走原路线;把“这次不要执行”表达成 interrupt,又会让整个轮次停掉,连本来可以继续的分析也一起丢失。

好的 harness 不只收集一个布尔值,而是让用户表达拒绝什么、是否继续、接下来该往哪里走


9.4 Steer:不中断工作,也能改变方向

Steer 是最轻量的人工介入。用户看到 agent 正在工作,补充一句:

“不要改公共 API,兼容旧配置。”

这条消息不会立刻切断正在进行的模型请求。它先进入待处理输入队列,等本轮采样和已经形成的工具调用走到安全边界,再作为一条新的用户输入写入历史。下一次采样时,模型看到新约束并调整路线。

sequenceDiagram
    participant U as 用户
    participant H as harness
    participant M as 模型
    participant T as 工具

    H->>M: 采样 #1(旧上下文)
    U->>H: steer:"保留旧 API"
    Note over H: 输入排队,不修改在途请求
    M-->>H: 工具调用
    H->>T: 执行并回灌结果
    Note over H: 到达步骤边界
    H->>H: 把 steer 追加进历史
    H->>M: 采样 #2(已包含新约束)

为什么不立即把消息塞进正在流式生成的上下文?因为那次采样已经基于旧快照开始了。中途修改输入,会让“请求到底基于什么上下文”失去答案,也会破坏第五章反复强调的可重试、可缓存和可重放。

因此 steer 的语义不是“抢过模型的话筒”,而是:

让当前原子步骤完成,然后在下一个可观察边界改变后续决策。

这也解释了 steer 与 interrupt 的分界:

  • 只是补充约束、改变优先级、提醒漏项,用 steer;
  • 当前动作继续一秒都可能造成错误,用 interrupt。

9.5 提问:把不可推断的决定交还给人

模型遇到不确定性时,有三种选择:

  1. 从代码、文档或环境中继续调查;
  2. 做一个可逆、低风险的合理假设;
  3. 停下来问用户。

并不是所有不确定性都值得提问。一个 agent 若每发现两个可能的文件名就请示一次,用户很快会变成它的搜索引擎;但如果“迁移后保留兼容层还是直接删除旧接口”会决定整个实现方向,擅自假设的返工成本可能远高于一次提问。

可以用一个简单标准判断:

当继续调查也无法得到答案,并且不同答案会显著改变成本、风险或最终产品行为时,才问人。

Codex 把这类提问做成结构化工具,而不是让模型在普通 assistant 文本里随口问一句。一次提问包含:

  • 稳定的问题 ID,保证回答能对应回原问题;
  • 简短标题和单句问题;
  • 两到三个互斥选项;
  • 每个选项的影响或取舍;
  • 一个明确的推荐项;
  • 前端自动提供的自由填写入口。

结构化的价值不只是 UI 更好看。它迫使模型在开口前完成一半决策工作:把问题缩小、列出可行选项、说明差异、给出建议。用户负责选择,不负责替 agent 从零分析。

差的提问:
"这里怎么做?"

好的提问:
"旧配置字段需要保留多久?"
- 保留一个版本(推荐):兼容现有用户,下个大版本删除
- 立即删除:实现更简单,但现有配置会失效
- 长期保留:无迁移风险,但维护两套语义

提问工具还有一条重要的权限边界:只有根 agent 直接向用户提问。 子 agent 有疑问时先写信给父 agent,由父 agent 汇总、去重,判断是否真的需要打扰用户。这避免一支 agent 队伍同时弹出多个互相重叠的问题。


9.6 审批与权限申请:批准动作,不是批准理由

第八章已经从安全角度拆过审批。本章换一个控制权视角,区分两类容易混淆的请求。

9.6.1 动作审批:这一次可以做吗

动作审批绑定的是一个已经具体化的行动,例如:

  • 执行某条命令;
  • 修改某组文件;
  • 访问某个网络目标;
  • 调用一个需要确认的 MCP 工具。

用户看到的应该是即将发生什么,而不只是模型为什么想做。理由可以帮助理解,但不能代替动作本身。恶意网页也能诱导模型生成一段听起来合理的理由,真正需要审查的是命令、目标、文件范围和副作用。

9.6.2 权限申请:接下来一段时间允许做什么

request_permissions 表达的不是某条具体命令,而是一份最小权限增量,例如:

  • 本轮允许访问网络;
  • 本轮允许写某个额外目录;
  • 本会话允许一组文件系统能力。

权限申请的回答必须同时包含授权内容作用域。用户同意联网,不代表同意任意写盘;同意本轮,不代表后续轮次仍然有效。harness 还应把最终授权与原请求求交集,不能让前端误传一个更宽的响应就扩大权限。

动作审批和权限申请的差别,可以类比为:

  • 动作审批是“这张报销单可以签”;
  • 权限申请是“这个项目在本月有多少预算额度”。

两者都需要人点头,但授权对象完全不同。


9.7 等待不是停机:统一的挂起与唤醒协议

提问、命令审批、补丁审批、权限申请、MCP 表单看起来是五套功能,在运行时里却可以收敛成一个模式:

发出请求事件
→ 为请求登记一个 pending waiter
→ 当前工具 future 挂起
→ 前端展示交互
→ 用户回答形成应答 Op
→ 按请求 ID 找到 waiter
→ 唤醒工具,继续 LOOP
sequenceDiagram
    participant Tool as 工具 future
    participant TurnState as turn 状态
    participant Host as 前端
    participant User as 用户

    Tool->>TurnState: 登记 pending request(请求 ID)
    Tool->>Host: Event:需要人工输入
    Note over Tool: future 挂起,不占 CPU
    Note over TurnState: 提交循环仍可处理<br/>steer / interrupt / 其他应答
    Host->>User: 展示动作、理由、作用域和选项
    User-->>Host: 作出决定
    Host->>TurnState: Op:请求 ID + 应答
    TurnState-->>Tool: oneshot 唤醒
    Tool->>Tool: 执行 / 拒绝 / 取消

这里有五个工程约束。

1. 请求必须可关联。 每个请求都带 turn、item/call 和请求 ID。回答只能唤醒原来的等待者,不能靠“当前屏幕上正好有个弹窗”猜归属。

2. 等待必须可取消。 用户按下 interrupt、turn 结束或连接失效时,pending waiter 要被清理。等待通道关闭应解释为“请求已取消”,不能合成一次普通拒绝后让旧轮次继续执行。

3. 控制通道不能被等待堵住。 工具 future 可以等人,但提交循环仍要处理 interrupt 和应答 Op。否则系统会陷入“要处理批准才能继续,但负责处理批准的循环也被卡住”的死锁。

4. 交互请求不能静默丢失。 普通进度通知漏一条,最终 item 还能重建;审批请求漏掉,turn 会永远等待。网络前端宁可明确报错或中止请求,也不能假装发送成功。

5. 等人的时间与算力时间要分开。 用户可能去开一个小时的会。等待期间没有模型推理,也没有工具执行,不应被误算成“工具超时”或“agent 运行过慢”。可观测性需要分别记录等待时长和实际处理时长。

统一协议的意义在于,新增一种 Human in the loop 交互时,不必再给 LOOP 增加新分支。只要它能表达成“发请求、挂起、应答、唤醒”,就可以复用取消、路由、审计和前端传输。


9.8 一个决定不只有“是”和“否”

成熟的 Human in the loop 协议,至少要表达三个维度:

维度 典型选项 回答的含义
决定 批准 / 拒绝 这件事做不做
作用域 一次 / 本 turn / 本 session / 持久规则 这个决定能复用多久
控制流 继续换路 / 中止当前 turn 拒绝后 agent 还要不要工作

因此“拒绝”至少有两种:

  • Decline:不要做这个动作,但 turn 继续。模型收到明确的拒绝观察,应当换一条路线;
  • Cancel / Abort:不要做,而且暂停当前 turn,等待用户下一步指令。

“批准”也有不同强度:

  • 仅这一次:最窄,适合高风险或上下文敏感动作;
  • 本 turn / 本 session:减少重复打扰,但不跨越明确的生命周期边界;
  • 沉淀为规则:跨会话信任,必须比临时批准有更严格的可解释性和覆盖范围校验。

这里有一个重要原则:

扩大授权范围必须是用户显式选择,不能由“用户连续点了三次同意”自动推断。

行为重复不等于永久信任。尤其是 shell 前缀、解释器和网络外发,同一句命令在不同工作目录、不同输入数据下可能有完全不同的风险。


9.9 人的回答如何进入上下文

Human in the loop 不只是运行时唤醒问题,还是上下文问题。用户回答之后,模型必须知道发生了什么,否则它可能再次提出同一动作。

不同回答进入历史的方式也不同:

  • steer 是新的用户输入,直接改变任务约束;
  • 提问答案是工具结果,和原问题按 call ID 成对出现;
  • 审批拒绝是一次结构化失败观察,告诉模型“不是执行故障,而是用户不允许”;
  • interrupt 留下一条中断标记,提醒下次采样检查部分执行的副作用;
  • 权限变化属于世界状态,下一步通过权限差分片段告诉模型“现在能做什么”。

这几种内容的信任等级也不同。用户亲自给出的业务答案可以确立偏好和授权;网页、工具输出、子 agent 来信只能提供证据,不能假装成用户同意。即使它们最终都出现在模型上下文里,harness 和 guardian 仍要保留来源。

这说明“把回答拼成一段文本塞回去”远远不够。Human in the loop 的结果至少需要保存:

  • 谁作出的决定;
  • 针对哪个请求;
  • 决定内容和作用域;
  • 当时展示给人的动作与理由;
  • 后续是继续、拒绝还是中断;
  • 是否改变了权限或持久规则。

第十章会看到,这些事实也是恢复与审计的重要输入。不过要区分两类状态:已经作出的决定应当持久化,进程内等待应答的临时通道不能被当成可持久化状态。 恢复时要依据事件重新判断是取消、重新询问还是继续,不能盲目复活一个已经过期的弹窗。


9.10 多 agent:业务问题归口,安全审批不绕过

一支 agent 队伍会把人工注意力放大成新的并发瓶颈。三个分身可以同时工作,也就可能同时遇到三个问题、四个审批和两个权限申请。

Codex 用两条不同的规则处理。

业务提问归口到根 agent。 子 agent 不直接向用户问“产品希望怎么做”。它把问题写信给父 agent,父 agent 可以结合其他分身的结果去重、合并,最后只向用户提出真正阻塞全局的决策。

安全审批沿原链路上交。 子 agent 不能因为“只是分身”就绕开审批。它执行危险命令、修改越界文件时仍走同样的策略、沙箱与审批关卡,最终授权来源仍是用户或受管审查者。

flowchart TD
    C1["子 agent A:业务歧义"] --> P["父 / 根 agent 汇总"]
    C2["子 agent B:相同歧义"] --> P
    P -->|"一个结构化问题"| U["用户"]

    C3["子 agent C:危险动作"] --> G["统一审批关卡"]
    G -->|"需要真人授权"| U
    G -->|"规则 / guardian 可决"| R["自动放行或拒绝"]

这形成了一条清晰的治理原则:

问题可以汇总,授权不能转借。

父 agent 可以替子 agent 整理问题,但不能因为自己曾获批某个无关动作,就把权限泛化给整棵树。会话级缓存可以减少同类重复审批,但命中条件和作用域必须由 harness 控制。


9.11 无人值守:没有人回答时,边界必须更硬

CI、批处理和后台 agent 没有一个随时在线的用户。此时最危险的设计是:

“既然没人能点批准,那就默认批准。”

正确语义正好相反:无法获得人工授权,就不能跨越需要授权的边界。

这就是审批策略 never 的含义:

  • 沙箱内已允许的低风险动作照常执行;
  • 本来需要询问的动作直接变成禁止;
  • agent 收到明确拒绝,可以选择受限方案或报告阻塞;
  • 不留下永远等待的交互请求。

同样,前端如果不支持结构化提问,也必须把“不支持”作为工具失败明确回灌,不能吞掉请求继续假设答案。

因此 Human in the loop 不是自主运行的前提,而是一种可选的升级通道。无人值守模式关闭了升级通道,保留的自动能力反而必须被更窄的硬边界包住。


9.12 交互设计:人的注意力也是一种预算

模型 token、工具并发和运行时长都有预算,人的注意力也应该有。

一次弹窗的成本不只是点击两秒。用户需要切换注意力、理解上下文、判断影响;弹窗过多后会出现审批疲劳:用户不再阅读内容,只机械地选择第一个按钮。此时看似更严格的审批系统,实际安全性反而下降。

减少打扰不能靠简单地“少问”,而要从四个位置做设计。

9.12.1 先自动调查,再问不可推断的部分

能从代码、配置和文档查到的事实不问用户;只有业务偏好、风险承受和外部承诺这类机器无法知道的内容才上交。

9.12.2 一次只问一个决策主题

结构化提问可以容纳多个问题,但默认应优先一个。把五个互相依赖的决定塞进同一表单,看似减少弹窗,实际上把决策树甩给了用户。

9.12.3 展示差异,而不只展示对象

审批框不能只有一条原始命令。用户至少需要知道:

  • agent 想做什么;
  • 会影响哪些资源;
  • 为什么现有权限不够;
  • 批准一次、批准本会话、拒绝分别意味着什么;
  • 是否存在更窄的替代方案。

对补丁应展示文件范围和 diff,对网络应展示目标域名,对权限申请应展示新增能力,而不是让用户从底层参数里自行推理。

9.12.4 自动机制过滤低价值请求

安全规则、会话缓存、沙箱内试跑和 guardian 的共同目标,不是替人拥有最终意图,而是过滤掉机器能够可靠处理的低风险决定,把人的注意力留给真正高价值的边界。

可以把介入强度画成一条阶梯:

flowchart LR
    O["Human out of the loop<br/>规则内自动执行"] --> G["Human on the loop<br/>可观察、可 steer / interrupt"]
    G --> H["Human in the loop<br/>关键点必须回答"]
    H --> X["硬禁止<br/>即使确认也不放行"]

不是所有动作都应该进入同一档。优秀的 harness 会根据风险、可逆性和授权状态把它们分层,而不是拿一个全局开关决定“全自动”或“全手动”。


9.13 一个完整例子:控制权如何来回交接

假设用户说:

“把项目的鉴权配置迁移到新格式,并运行验证。”

一次合理的 Human in the loop 流程可能是:

sequenceDiagram
    participant U as 用户
    participant A as agent
    participant H as harness
    participant E as 执行环境

    U->>A: 提交迁移任务
    A->>E: 读取配置、搜索调用点
    E-->>A: 同时存在"兼容一版"和"立即切换"两种产品语义
    A->>U: 提问:旧格式保留多久?<br/>给出选项、影响与推荐
    U-->>A: 保留一个版本
    A->>E: 修改工作区内文件并运行本地测试
    U->>A: steer:还要补迁移告警
    Note over A: 下一步骤边界吸收新约束
    A->>H: 申请访问外部测试环境
    H->>U: 权限申请:仅本 turn 开放指定网络
    U-->>H: 批准本 turn
    H->>E: 执行远端验证
    E-->>A: 验证通过
    A-->>U: 汇总改动、验证结果与剩余风险

这段流程里,人只出现了三次:

  1. 决定机器无法推断的兼容策略;
  2. 主动补充一个新要求;
  3. 授权一次超出现有边界的访问。

文件搜索、方案分析、代码修改和测试都没有逐步请示。介入点少,但每一次都改变了决策空间。 这比“每条命令都点允许”更符合 Human in the loop 的本意。


9.14 常见失败模式

失败模式 表面现象 根因 更好的做法
问得太早 agent 还没调查就问用户文件在哪 把搜索成本转嫁给人 先穷尽低成本、只读调查
问得太晚 已经大改一轮才确认产品方向 把不可逆决策留到执行后 在高分叉成本之前设语义检查点
只给原始命令 用户看不懂,只能盲批 展示了实现,没有展示影响 同时展示目的、对象、范围和替代方案
拒绝语义含糊 模型被拒后换个写法反复重试 没区分执行失败与用户禁止 回灌结构化拒绝原因,必要时中止 turn
授权范围偷偷扩大 一次批准变成长期白名单 把重复行为误当成永久信任 作用域必须由用户显式选择
多个分身同时提问 弹窗风暴、问题重复 没有根 agent 归口 业务问题向上汇总,审批统一排队
旧弹窗仍可提交 turn 已结束,批准却落到新任务 请求没有生命周期和坐标 应答按 ID 关联,turn 结束即作废
把人当唯一安全边界 用户点错一次就能造成灾难 没有纵深防御 审批之外仍保留规则、沙箱和硬禁止
中断被当成回滚 用户以为停下就什么都没发生 忽略工具可能已产生部分副作用 明确中断只停止后续工作,并保留审计记录

最值得警惕的是第一行和最后一行之间的张力:问得太多,用户会机械批准;问得太少,agent 会在错误方向上走太远。Human in the loop 的质量,最终取决于介入点是否选在真正改变结果的边界上


9.15 更深一层:Human in the loop 是控制权协议

把本章所有机制放在一起,会得到三个更深的结论。

9.15.1 它不是 UI 功能,而是分布式状态机

一个审批框跨越模型流、harness 内核、前端进程和真人,任何一层都可能断开。请求要有 ID、状态、取消语义和超时语义;应答要幂等地落到正确 turn;旧请求不能污染新轮次。

所以“弹窗长什么样”只是最后一公里,真正困难的是等待期间谁拥有状态、断线后谁负责收尾、重复应答如何处理

9.15.2 它像两阶段提交,但没有真正回滚

高风险动作先进入“准备”阶段:展示将要发生的事并等待授权;批准后才进入“提交”阶段执行。等待期间环境可能变化,因此执行前仍应重新确认请求绑定的对象和权限没有漂移。

但 agent 操作通常没有数据库事务那样的 rollback。命令跑到一半被 interrupt,文件和外部系统可能已经部分改变。Human in the loop 能控制下一步是否发生,不能保证过去从未发生

9.15.3 人工注意力应投向不可替代的判断

规则擅长处理已知模式,guardian 擅长筛查风险,模型擅长分析方案,harness 擅长执行硬约束。只有业务意图、价值取舍和最终授权必须由人提供。

因此衡量 Human in the loop 设计好坏,不应该看“一天弹了多少审批”,而应该看:

  • 错误方向能否被及时纠正;
  • 高风险动作能否获得与风险匹配的授权;
  • 用户是否理解自己批准了什么;
  • 被拒绝后 agent 能否理性换路;
  • 没有人在线时系统是否安全地退化;
  • 一次人工决定是否在恰当范围内复用。

9.16 小结:Human in the loop 的六条设计原则

  1. 人只在边界上介入。 默认让 LOOP 连续运行;信息不可推断、方案出现重大分叉、动作需要越权或用户主动纠偏时,才交还控制权。Human in the loop 不是逐步遥控。

  2. 四种介入,四种语义。 steer 改方向,提问补信息,审批授权限,interrupt 管生命周期。协议和 UI 必须区分它们,不能把所有决定压成一个“确定/取消”。

  3. 请求统一挂起,应答精确唤醒。 交互请求都是 Event → pending waiter → 应答 Op → oneshot 唤醒;请求带完整坐标、不可静默丢失、可被中断,等待不堵塞提交循环。

  4. 决定必须带作用域和后续控制流。 批准一次、本 turn、本 session、持久规则不是同一件事;拒绝并继续与拒绝并中止也不是同一件事。扩大作用域必须由用户显式选择。

  5. 业务问题归口,安全边界不转借。 子 agent 的业务疑问由根 agent 汇总后再问人,避免弹窗风暴;危险动作仍逐一经过统一策略和审批,父 agent 不能替整棵树创造授权。

  6. 注意力有预算,无人值守则边界更硬。 自动调查、规则、缓存和 guardian 过滤低价值请求,把人留给不可替代的判断;没人能回答时,需要审批的动作应被禁止,而不是默认放行。

留给读者思考的几个问题

  • steer 在步骤边界才生效。如果当前工具是一个持续十分钟、具有外部副作用的部署命令,“等待边界”是否仍然合理?是否需要工具级暂停或更细的安全点?
  • 用户批准的是屏幕上展示的动作,但从批准到执行之间环境可能变化。哪些字段应该成为不可变的审批指纹,才能避免“批准 A,执行成了 B”?
  • request_user_input 的回答被视为可信用户输入。如果问题本身是被网页提示注入诱导出来的,结构化提问是否可能成为“洗白外部指令”的通道?前端应该展示多少提问来源?
  • 会话级审批缓存减少了打扰,却可能跨越工作目录、环境或子 agent 身份复用。缓存键里应该纳入多少上下文,才能在命中率和安全性之间取得平衡?
  • 人工等待期间,模型没有消耗 token,但系统资源、外部锁和任务时限仍可能流逝。哪些资源应该释放,哪些状态必须保留?
  • 如果一次任务需要十次人工介入,这是任务本身高风险,还是 agent 缺少工具、上下文或策略?可观测性应该怎样区分二者?(→ 第 12 章)

下一章我们进入持久化与可恢复性:人的决定、被中断的 turn、权限变化和完整事件流怎样落盘;进程重启后,哪些状态可以安全恢复,哪些等待中的交互必须重新确认。

分类:Agent Harness标签:#agent #harness #codex