Harness Engineering-第17章 Human-in-the-Loop:人机协作设计

《Harness Engineering --- AI Agent 工程方法论》完整目录

第17章 Human-in-the-Loop:人机协作设计

"The best AI systems are not fully autonomous --- they are force multipliers for human intelligence."

:::tip 本章要点

  • 人机协作是一个频谱:从全手动到全自动,Agent 应在中间找到合适的位置
  • 介入时机:高风险操作、模糊需求、主观判断、专业领域
  • 渐进式信任:从高干预开始,随信任积累逐步放权
  • 中断成本:每次人类介入都有延迟代价,最小化不必要的中断 :::

17.1 自动化频谱

graph LR M1["🖐️ 全手动\n人做一切"] --> M2["🤝 AI 辅助\n人做决策\nAI 执行"] M2 --> M3["🤖 AI 主导\n+ 人审批"] M3 --> M4["⚡ 全自动\nAI 做一切"] M2 ---|"代码补全\n搜索建议"| Note1[" "] M3 ---|"Claude Code\nCursor Agent"| Note2[" "] M4 ---|"CI/CD 脚本\n定时任务"| Note3[" "] style M1 fill:#fee2e2,stroke:#ef4444 style M2 fill:#fef3c7,stroke:#f59e0b style M3 fill:#dcfce7,stroke:#22c55e style M4 fill:#dbeafe,stroke:#3b82f6
css 复制代码
全手动              AI 辅助            AI 主导+人审批        全自动
人做一切 ←──────── 人做决策,AI执行 ────── AI做决策,人确认 ────→ AI做一切
                    代码补全              Claude Code          无人值守脚本
                    搜索建议              Cursor Agent          定时任务

大多数 Agent 系统应该处于中间位置------AI 主导执行,人类在关键节点审批 。完全自动化看起来很酷,但在生产环境中几乎不可行------一个错误的 git push --force 就足以让团队加班到凌晨。

17.2 何时需要人类介入

高风险操作

操作的不可逆性越高,越需要人类确认:

markdown 复制代码
低风险(自动执行):
  - 读文件
  - 搜索代码
  - 运行测试
  - 创建新文件

中风险(默认询问):
  - 修改已有文件
  - 安装依赖
  - 执行 Shell 命令

高风险(必须确认):
  - git push
  - 删除文件/分支
  - 修改 CI/CD 配置
  - 发送消息到外部系统(Slack、邮件)
  - 操作生产环境

Claude Code 的做法:评估每个操作的可逆性和影响范围,不可逆或影响共享状态的操作需要确认。

模糊需求

当用户需求不明确时,Agent 应该先澄清再行动

markdown 复制代码
❌ 用户: "优化一下性能"
   Agent: [修改了 20 个文件] 完成!
   用户: 我说的是数据库查询的性能,不是前端...

✅ 用户: "优化一下性能"
   Agent: 请问是指哪方面的性能?
   - 前端渲染速度?
   - API 响应延迟?
   - 数据库查询效率?
   - 构建/打包速度?

主观判断

代码风格、架构选择、命名规范------这些没有唯一正确答案,应该让用户决定。

17.3 审批工作流设计

内联审批

最常见的模式------Agent 在执行前暂停,展示计划,等待用户确认:

bash 复制代码
Agent: 我准备执行以下操作:
  1. 修改 src/auth.ts(添加 JWT 验证)
  2. 修改 src/middleware.ts(注入认证中间件)
  3. 运行 npm test 验证

是否继续?[Y/n]

Claude Code 就是这个模式------用户可以逐个批准或拒绝工具调用。

批量审批

当操作数量多时,逐个确认效率太低:

bash 复制代码
Agent: 需要修改以下 8 个文件来完成重命名:
  src/auth.ts
  src/auth.test.ts
  src/middleware.ts
  ...

全部批准 / 逐个审核 / 取消?

异步审批

对于长时间运行的任务,允许 Agent 先做完不需要审批的部分,把需要审批的积攒起来:

python 复制代码
# LangGraph 的 interrupt 机制
def deployment_node(state):
    # 准备工作(无需审批)
    build_result = build_project()
    run_tests()

    # 部署需要人类审批
    interrupt({
        "action": "deploy_to_production",
        "build": build_result,
        "tests": "all passed",
        "message": "准备部署到生产环境,是否继续?"
    })

    # 人类审批后继续
    deploy(build_result)

三种审批模式的交互对比

sequenceDiagram participant U as 用户 participant A as Agent rect rgb(219, 234, 254) Note over U,A: 内联审批(同步阻塞) A->>U: "准备修改 auth.ts,是否继续?" U->>A: "是" A->>A: 执行修改 end rect rgb(254, 243, 199) Note over U,A: 批量审批(减少中断) A->>A: 分析所有需要修改的文件 A->>U: "需修改 5 个文件:\nauth.ts, user.ts, ...\n全部批准 / 逐个审核?" U->>A: "全部批准" A->>A: 一次性执行所有修改 end rect rgb(220, 252, 231) Note over U,A: 异步审批(非阻塞) A->>A: 执行不需要审批的步骤(构建、测试) A->>U: "构建和测试完成,准备部署\n等待您的批准..." Note over A: Agent 可以处理其他任务 U->>A: "批准部署" A->>A: 执行部署 end

LangGraph 的 interrupt 机制

LangGraph 提供了原生的中断/恢复支持。当图执行到 interrupt() 节点时:

  1. 状态被自动 checkpoint --- 保存到 checkpointer(SQLite/PostgreSQL)
  2. 执行暂停 --- 返回控制权给调用方
  3. 用户审批后 --- 调用 graph.invoke(Command(resume=value)) 从断点恢复
  4. 状态完整恢复 --- 所有之前的计算结果都在

这使得"等待人类审批"不需要占用任何服务器资源------审批可以发生在几小时甚至几天之后。

17.4 渐进式信任

用户对 Agent 的信任需要时间积累。好的系统支持渐进放权:

markdown 复制代码
初次使用:
  - 每个文件修改都需要确认
  - 每个 Shell 命令都需要确认

使用一周后:
  - 文件修改自动批准
  - 安全命令(npm test, git status)自动批准
  - 危险命令仍需确认

使用一个月后:
  - 大部分操作自动批准
  - 只有影响共享状态的操作需要确认

信任积累的决策矩阵

graph TD Op["Agent 请求执行操作"] --> R{"操作类型"} R -->|"只读\n(Read/Grep/Glob)"| Auto["✅ 自动执行\n(所有信任级别)"] R -->|"文件修改\n(Edit/Write)"| Trust{"信任级别?"} Trust -->|"新用户"| Confirm1["需要确认"] Trust -->|"常规用户"| Auto2["自动执行\n(有 Git 兜底)"] R -->|"Shell 命令\n(Bash)"| Cmd{"命令安全?"} Cmd -->|"npm test / git status"| Auto3["自动执行"] Cmd -->|"rm / curl | bash"| Confirm2["必须确认\n(任何信任级别)"] R -->|"外部操作\n(push/发消息)"| Confirm3["必须确认\n(任何信任级别)"] style Auto fill:#dcfce7,stroke:#22c55e style Auto2 fill:#dcfce7,stroke:#22c55e style Auto3 fill:#dcfce7,stroke:#22c55e style Confirm1 fill:#fef3c7,stroke:#f59e0b style Confirm2 fill:#fee2e2,stroke:#ef4444 style Confirm3 fill:#fee2e2,stroke:#ef4444

关键原则:不可逆操作永远需要确认,与信任级别无关。 渐进放权只适用于可逆操作。

Claude Code 通过权限模式实现:

scss 复制代码
Plan Mode → Default Mode → Auto-Edit Mode → Full Auto Mode
(限最大)                                    (限最小)

用户根据自己的信任程度选择模式。关键是选择权在用户手中

17.5 反馈循环

人类的修正是 Agent 最宝贵的学习信号。

即时反馈

makefile 复制代码
Agent: [修改了文件]
用户: "不要这样写,我们团队的规范是..."
Agent: [记录为 feedback 记忆,下次避免]

Claude Code 会将用户的纠正存入长期记忆(feedback 类型),未来对话中自动加载。

隐式反馈

用户的行为本身就是反馈:

arduino 复制代码
Agent 提出方案 A,用户说"好的" → 正向信号
Agent 提出方案 A,用户说"换一种方式" → 需要调整
Agent 修改了文件,用户立即 git checkout 恢复 → 强烈负向信号

反馈闭环

复制代码
观察用户行为 → 提取信号 → 存入记忆 → 下次调整行为 → 观察效果

17.6 降低中断成本

每次人类介入都有成本:打断心流、等待输入、上下文切换。好的人机协作应该最小化不必要的中断

批处理确认

不要一个个文件问,把相关操作打包:

scss 复制代码
❌ 修改 auth.ts? [Y/n]
   修改 auth.test.ts? [Y/n]
   修改 middleware.ts? [Y/n]

✅ 修改以下 3 个文件完成 JWT 集成? [Y/n]
   - auth.ts (添加 JWT 验证函数)
   - auth.test.ts (新增测试用例)
   - middleware.ts (注入认证中间件)

提供足够信息

用户需要足够信息才能做出决策------但不需要看到所有细节:

scss 复制代码
❌ "是否执行这个命令?"  ← 什么命令?为什么?

✅ "准备运行 npm test 验证修改 (预计 30 秒)
    这是为了确保 JWT 集成没有破坏现有测试。
    [执行] [跳过] [查看详情]"

记住用户偏好

typescript 复制代码
// 用户批准了 "npm test",记住这个偏好
if (userApproved && action.type === 'bash') {
  permissionCache.allow(action.command, { scope: 'session' })
  // 本次会话内不再询问相同命令
}

17.7 信任构建要素

用户信任 Agent 需要三个条件:

透明性

Agent 应该解释自己在做什么、为什么这样做:

markdown 复制代码
我准备修改 auth.ts,因为:
1. 当前的 token 验证逻辑在 JWT 过期时不会刷新
2. 这导致了你报告的"用户突然被登出"的 bug
3. 修改方案: 在验证失败时检查是否可刷新,而非直接拒绝

可预测性

相同的输入应该产生相似的行为。如果 Agent 今天谨慎、明天激进,用户无法建立信任。

可逆性

让用户有信心------即使 Agent 做错了,也可以撤销:

markdown 复制代码
Agent: 修改已完成。如果效果不好:
  - git checkout src/auth.ts  (恢复单个文件)
  - git stash                  (暂存所有修改)
  - 我可以帮你 revert

17.8 本章小结

人机协作的核心设计原则:

  1. 频谱定位------大多数 Agent 应处于"AI 主导 + 人审批"的位置
  2. 风险驱动------操作越不可逆,越需要人类确认
  3. 渐进信任------从严格到宽松,让用户选择
  4. 最小中断------批处理、记忆偏好、提供决策信息
  5. 反馈闭环------将人类修正转化为长期记忆
  6. 建立信任------透明、可预测、可逆

下一章我们进入生产化部分------如何评估和测试 Agent 的行为。

相关推荐
杨艺韬4 小时前
Harness Engineering-第6章 工具编排与并发执行
agent
杨艺韬4 小时前
Harness Engineering-第21章 设计模式与架构决策
agent
杨艺韬4 小时前
Harness Engineering-第5章 Tool Design:给 Agent 造趁手的兵器
agent
杨艺韬4 小时前
vLLM内核探秘-第4章 PagedAttention:虚拟内存的启示
agent
杨艺韬4 小时前
vLLM内核探秘-第15章 多模态推理
agent
杨艺韬4 小时前
vLLM内核探秘-第1章 架构总览
agent
杨艺韬4 小时前
vLLM内核探秘-第6章 Worker 与 Executor:GPU 军团
agent
杨艺韬4 小时前
vLLM内核探秘-第11章 分块预填充与混合批处理
agent
杨艺韬4 小时前
vLLM内核探秘-第2章 EngineCore:引擎的心脏
agent