Harness Engineering
公式很简单:Agent = Model + Harness。模型负责推理,Harness 负责其余一切:工具执行、权限控制、上下文管理、状态持久化、错误恢复、人在回路。Claude Code 官方文档的说法是,Claude Code 提供“工具、上下文管理和执行环境,将语言模型转变为有能力的编程智能体”。模型决定它想做什么,另一个系统决定它是否被允许。
很多团队花几个月优化 Prompt 和模型选择,交付的 Agent 依然脆弱,问题往往出在 Harness。工具不应该被建模为“模型能力的延长线”,而应该被建模为“需要运行时代为管理风险的外部能力”。
权限管线:模型提建议不等于拥有授权
Claude Code 权限系统的核心是一个四阶段管线,每一级都可以短路返回:
权限管线的四个阶段
三个要点:
- allow、deny、ask 三态。 成熟权限系统除了“能”和“不能”,还承认第三种状态:系统也不该替用户做决定。模型理解了意图,不等于有权代替用户执行,更不等于持续授权
- deny 永远优先。 规则按 deny、ask、allow 顺序评估,高风险 Bash 命令命中 deny 规则直接拒绝,不进 ask 路径
- fail-closed 默认值。 新工具在显式声明安全性之前,系统假设最危险的情况。
isConcurrencySafe默认 false,isReadOnly默认 false。这就是“assume not safe, assume writes”
工具执行层
工具执行不是裸调用。Claude Code 的 runTools() 先按并发安全性分批:读工具的 inputSchema,判断 isConcurrencySafe(),适合的归入并发批次,不适合的拆成串行单元。执行周围包着 hooks、permission、telemetry 和 synthetic error。
中断被当成一等语义。工具的 interruptBehavior 决定用户插话时是 cancel(取消执行,生成“用户中断”的合成结果)还是 block(继续跑到自然终点,阻塞新消息)。设计上既要设计开始,也要设计停下。没有停下语义的执行系统,最终只能靠用户外部打断来补完设计。
大工具输出要有界。Claude Code 给 MCP 工具输出设了默认 25,000 token 上限,10,000 token 时告警。超大的结果持久化到磁盘,上下文里只留引用。这种事你不会想到,直到 Agent 因为工具结果被截断而悄悄丢信息。
Bash 是特例治理。高风险工具接受更密的约束:命令前缀检查、重定向处理、安全环境变量、复合命令的子命令数量上限,防止检查失控。
沙箱与纵深防御
当 Agent 能执行 shell、写文件、调外部 API 时,单层防护不够。生产环境的纵深防御:
- Prompt 层:禁止操作的指令和数据安全策略
- Schema 层:按子 Agent 过滤工具;规划模式只生成提议不执行
- 运行时审批:高风险操作前 HITL 检查点
- 工具层校验:执行前的危险模式检测、陈旧读取检测
- 生命周期钩子:操作前后运行用户定义脚本拦截
核心原则:被攻破的模型无法覆盖安全检查,因为那是完全不同的代码路径。推理和权限执行分离,是 Harness 设计的基本盘。
状态与恢复
执行状态必须可序列化、可恢复。50 步任务的第 47 步中断,应该从第 47 步恢复,而不是从第 1 步重来。LangGraph 在每个超级步边界检查执行状态,Claude Code 在代码变更前对受影响文件做快照。机制不重要,重要的是完整的执行状态能持久化,中断后能接续。
会话本身也是资产。Claude Code 的会话保存在本地,每条消息、工具使用和结果都存储,支持回退、恢复和分叉。
可观测性
生产 Harness 必须在关键路径埋点:消息数量、工具结果数量、查询链 ID、查询深度。指标至少覆盖:每轮循环的模型耗时和工具耗时、输入输出 token 趋势、按类型分类的错误率(模型错误、工具错误、权限拒绝)、平均每轮工具调用数、用户中断率。审计日志记录每次权限决策:工具名、输入摘要、决策结果和原因。
与框架的关系
生产级框架(Claude Agent SDK、OpenAI Agents SDK、LangGraph、smolagents)都在收敛到同一个核心循环:模型响应、工具分发、权限检查、结果格式化。框架是带偏好的运行时,Harness 是这些运行时依赖的能力集合。任务范围窄、定义明确的机器人可以自己写最小 harness;长会话、不可信工具输出、几十个工具的系统,用现成框架更稳。
面试追问
- Harness 是什么? Agent 的运行时:工具执行、权限、上下文管理、状态、观测。模型负责推理,Harness 负责行动。公式 Agent = Model + Harness
- 权限系统为什么要有 ask 状态? 系统不该替用户做决定。模型理解意图不等于拥有授权。allow、deny、ask 三态让“会做”和“可以做”分开
- fail-closed 是什么意思? 新工具默认不安全、默认有副作用、默认不可并发,显式声明才能放开。审查通过之前不产生危险行为
- 工具结果为什么要设上限? 大输出会撑爆上下文、淹没关键信息。25K token 默认上限,超大结果持久化到磁盘只留引用
- Harness 怎么防 Prompt Injection? 推理和权限分离,被攻破的模型无法覆盖安全检查。纵深防御:prompt 层、schema 层、运行时审批、工具层校验、生命周期钩子