
摘要
大语言模型(LLM)Agent 生产化的核心障碍并非模型能力,而在缺乏围绕非确定性模型的外部可靠性约束体系。本文将 Agent 工程化划分为编排、隔离、运维三层:编排层以 Harness 循环推进任务,以幂等键与终止条件抑制失败扩散;隔离层以四档沙箱与最小权利界定操作边界,不可逆操作强制交人工审核;运维层以追踪三轴与持久执行保可观测性与长期可靠性。实证表明,同一模型在不同 Harness 配置下表现差异显著,三层协同是实现 Agent 生产化的关键。
关键词:Agent 工程化;Harness;幂等键;沙箱;最小权利;人工审批;可观测性;Durable Execution
1 定义与架构划分
1.1 Agent 工程化的定义
Agent 工程化是围绕 LLM 构建的一整套系统层 基础设施,把模型的"生成能力"转化为可执行、可约束、可追溯的"行动能力"。Anthropic 在 Building Effective Agents 中把 Agent 定义为"在扩展时间内独立运行、使用各种工具完成复杂任务的系统",并强调工程实践的关键是简单可组合的模式,而非复杂框架1。
这一系统层在学界称 Harness (脚手架/执行栈)。Harness-Bench 将其定义为"管理上下文、工具、状态、约束、权限、追踪与恢复的系统层,在模型输出与外部行动之间做中介"2。Anthropic 在 SWE-bench 技术报告中也明确指出,Agent 是"模型 + 软件脚手架"的组合,脚手架负责生成 prompt、解析输出并管理交互循环3。
1.2 三层架构的职责划分
工程实践围绕"如何在不可靠的模型上构建可靠系统",形成三条互补技术栈:
- 编排层,决定循环的形状(推进节奏与终止)
- 隔离层,决定单步的爆炸半径(能碰什么、谁来批准)
- 运维层,决定长期可信度(能否解释、续跑与审计)
#mermaid-svg-aRnOW94Li2YLE1Mc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aRnOW94Li2YLE1Mc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aRnOW94Li2YLE1Mc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aRnOW94Li2YLE1Mc .error-icon{fill:#552222;}#mermaid-svg-aRnOW94Li2YLE1Mc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aRnOW94Li2YLE1Mc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aRnOW94Li2YLE1Mc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aRnOW94Li2YLE1Mc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aRnOW94Li2YLE1Mc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aRnOW94Li2YLE1Mc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aRnOW94Li2YLE1Mc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aRnOW94Li2YLE1Mc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aRnOW94Li2YLE1Mc .marker.cross{stroke:#333333;}#mermaid-svg-aRnOW94Li2YLE1Mc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aRnOW94Li2YLE1Mc p{margin:0;}#mermaid-svg-aRnOW94Li2YLE1Mc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aRnOW94Li2YLE1Mc .cluster-label text{fill:#333;}#mermaid-svg-aRnOW94Li2YLE1Mc .cluster-label span{color:#333;}#mermaid-svg-aRnOW94Li2YLE1Mc .cluster-label span p{background-color:transparent;}#mermaid-svg-aRnOW94Li2YLE1Mc .label text,#mermaid-svg-aRnOW94Li2YLE1Mc span{fill:#333;color:#333;}#mermaid-svg-aRnOW94Li2YLE1Mc .node rect,#mermaid-svg-aRnOW94Li2YLE1Mc .node circle,#mermaid-svg-aRnOW94Li2YLE1Mc .node ellipse,#mermaid-svg-aRnOW94Li2YLE1Mc .node polygon,#mermaid-svg-aRnOW94Li2YLE1Mc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aRnOW94Li2YLE1Mc .rough-node .label text,#mermaid-svg-aRnOW94Li2YLE1Mc .node .label text,#mermaid-svg-aRnOW94Li2YLE1Mc .image-shape .label,#mermaid-svg-aRnOW94Li2YLE1Mc .icon-shape .label{text-anchor:middle;}#mermaid-svg-aRnOW94Li2YLE1Mc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-aRnOW94Li2YLE1Mc .rough-node .label,#mermaid-svg-aRnOW94Li2YLE1Mc .node .label,#mermaid-svg-aRnOW94Li2YLE1Mc .image-shape .label,#mermaid-svg-aRnOW94Li2YLE1Mc .icon-shape .label{text-align:center;}#mermaid-svg-aRnOW94Li2YLE1Mc .node.clickable{cursor:pointer;}#mermaid-svg-aRnOW94Li2YLE1Mc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-aRnOW94Li2YLE1Mc .arrowheadPath{fill:#333333;}#mermaid-svg-aRnOW94Li2YLE1Mc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aRnOW94Li2YLE1Mc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aRnOW94Li2YLE1Mc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aRnOW94Li2YLE1Mc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aRnOW94Li2YLE1Mc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aRnOW94Li2YLE1Mc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-aRnOW94Li2YLE1Mc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aRnOW94Li2YLE1Mc .cluster text{fill:#333;}#mermaid-svg-aRnOW94Li2YLE1Mc .cluster span{color:#333;}#mermaid-svg-aRnOW94Li2YLE1Mc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-aRnOW94Li2YLE1Mc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aRnOW94Li2YLE1Mc rect.text{fill:none;stroke-width:0;}#mermaid-svg-aRnOW94Li2YLE1Mc .icon-shape,#mermaid-svg-aRnOW94Li2YLE1Mc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aRnOW94Li2YLE1Mc .icon-shape p,#mermaid-svg-aRnOW94Li2YLE1Mc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-aRnOW94Li2YLE1Mc .icon-shape .label rect,#mermaid-svg-aRnOW94Li2YLE1Mc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aRnOW94Li2YLE1Mc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-aRnOW94Li2YLE1Mc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-aRnOW94Li2YLE1Mc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Act 带副作用
产生 trace 与状态
反馈健康信号
运维层
追踪三轴与健康信号
Checkpoint 与续跑
隔离层
四档沙箱
最小权利与审批门
用完即收
编排层
Harness 循环五阶段
重试与幂等
终止条件
成本预算
图1 Agent 工程化三层架构协同关系
三层并非串行流水线,而是同一执行栈上的正交切面:编排层每轮循环调用隔离层的沙箱与审批门,运维层持续采集两层产生的 span、状态与审计记录213。
2 生产化的四类痛点
2.1 LLM 本身的不可靠性
LLM 作为 Agent 的决策方,天然具备三种使传统工程手段失效的特性:非确定性 (同一 prompt 重试可能生成不同参数)、幻觉与"幽灵成功" (报告任务完成却实际失败)、对 prompt injection 敏感 (外部输入可改写决策)。这要求重构传统 CRUD 场景的"重试 + Idempotency-Key"模式------重试时模型可能生成不同参数,单纯哈希 payload 会导致重试无法命中61。
2.2 脚手架差异的实证
Harness 对性能的影响有实证支撑。Anthropic 在 SWE-bench Verified 指出"同一底层模型在不同脚手架下表现差异显著",开源社区也通过优化脚手架在同一模型上获得显著提升3。Harness-Bench 对 5194 条轨迹的统计表明,性能在"模型-Harness 配置"层面存在实质差异,能力应在配置层报告而非归因于基础模型2。Anthropic 另一项研究还发现,基础设施配置差异即可使 Terminal-Bench 2.0 相差 6 个百分点(p < 0.01),超过多数榜单顶尖模型的相对差距5。
2.3 越权与不可逆操作风险
OWASP 在 LLM06:2025 Excessive Agency 中系统梳理了越权典型模式:LLM 获得超出必要的权限(如 UPDATE/INSERT/DELETE 一并授权)、以高权限通用身份连接下游、未经确认即执行高影响操作4。缓解原则是"仅授予最低必要的扩展与函数,并对高影响操作做独立验证与人工批准"4。
2.4 成本失控与循环
Agent 生产化另一大痛点是成本与循环失控。一次任务可能跨多个 provider、产生用户不可见的推理 token,也可能 spawn 子 Agent 重复计费,账单通常按 token × 单价实时累加9。若缺显式终止条件与预算熔断,Agent 会陷入 HTTP 200 持续烧钱的循环,而这类失败在传统 APM 视角下"看似成功"815。
3 方法机制与实现
3.1 编排层
编排层回答"Agent 如何推进",核心是 Harness 循环、幂等防御、终止条件与成本预算四模块。
3.1.1 Harness 循环五阶段
Agent 循环可抽象为五阶段:Perceive(感知)→ Reason(推理)→ Plan(规划)→ Act(执行)→ Observe(观察) ,循环往复直至命中终止条件13。Anthropic 在 SWE-bench 技术报告中描述该循环为:"脚手架把模型上一步动作的结果并入下一步 prompt,持续采样直到模型认为任务完成或超出 200k 上下文"3。
#mermaid-svg-RfC1FclN66SpOqZ2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RfC1FclN66SpOqZ2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RfC1FclN66SpOqZ2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RfC1FclN66SpOqZ2 .error-icon{fill:#552222;}#mermaid-svg-RfC1FclN66SpOqZ2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RfC1FclN66SpOqZ2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RfC1FclN66SpOqZ2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RfC1FclN66SpOqZ2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RfC1FclN66SpOqZ2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RfC1FclN66SpOqZ2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RfC1FclN66SpOqZ2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RfC1FclN66SpOqZ2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RfC1FclN66SpOqZ2 .marker.cross{stroke:#333333;}#mermaid-svg-RfC1FclN66SpOqZ2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RfC1FclN66SpOqZ2 p{margin:0;}#mermaid-svg-RfC1FclN66SpOqZ2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RfC1FclN66SpOqZ2 .cluster-label text{fill:#333;}#mermaid-svg-RfC1FclN66SpOqZ2 .cluster-label span{color:#333;}#mermaid-svg-RfC1FclN66SpOqZ2 .cluster-label span p{background-color:transparent;}#mermaid-svg-RfC1FclN66SpOqZ2 .label text,#mermaid-svg-RfC1FclN66SpOqZ2 span{fill:#333;color:#333;}#mermaid-svg-RfC1FclN66SpOqZ2 .node rect,#mermaid-svg-RfC1FclN66SpOqZ2 .node circle,#mermaid-svg-RfC1FclN66SpOqZ2 .node ellipse,#mermaid-svg-RfC1FclN66SpOqZ2 .node polygon,#mermaid-svg-RfC1FclN66SpOqZ2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RfC1FclN66SpOqZ2 .rough-node .label text,#mermaid-svg-RfC1FclN66SpOqZ2 .node .label text,#mermaid-svg-RfC1FclN66SpOqZ2 .image-shape .label,#mermaid-svg-RfC1FclN66SpOqZ2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-RfC1FclN66SpOqZ2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RfC1FclN66SpOqZ2 .rough-node .label,#mermaid-svg-RfC1FclN66SpOqZ2 .node .label,#mermaid-svg-RfC1FclN66SpOqZ2 .image-shape .label,#mermaid-svg-RfC1FclN66SpOqZ2 .icon-shape .label{text-align:center;}#mermaid-svg-RfC1FclN66SpOqZ2 .node.clickable{cursor:pointer;}#mermaid-svg-RfC1FclN66SpOqZ2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RfC1FclN66SpOqZ2 .arrowheadPath{fill:#333333;}#mermaid-svg-RfC1FclN66SpOqZ2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RfC1FclN66SpOqZ2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RfC1FclN66SpOqZ2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RfC1FclN66SpOqZ2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RfC1FclN66SpOqZ2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RfC1FclN66SpOqZ2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RfC1FclN66SpOqZ2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RfC1FclN66SpOqZ2 .cluster text{fill:#333;}#mermaid-svg-RfC1FclN66SpOqZ2 .cluster span{color:#333;}#mermaid-svg-RfC1FclN66SpOqZ2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RfC1FclN66SpOqZ2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RfC1FclN66SpOqZ2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-RfC1FclN66SpOqZ2 .icon-shape,#mermaid-svg-RfC1FclN66SpOqZ2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RfC1FclN66SpOqZ2 .icon-shape p,#mermaid-svg-RfC1FclN66SpOqZ2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RfC1FclN66SpOqZ2 .icon-shape .label rect,#mermaid-svg-RfC1FclN66SpOqZ2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RfC1FclN66SpOqZ2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RfC1FclN66SpOqZ2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RfC1FclN66SpOqZ2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 未命中终止条件
命中终止条件
Perceive 感知
Reason 推理
Plan 规划
Act 执行
Observe 观察
Terminate 优雅退出
图2 Harness 循环五阶段示意
| 阶段 | 职责 | 失败模式 | 工程护栏 |
|---|---|---|---|
| Perceive | 接收用户输入、工具返回、错误信号 | 上下文污染 | 上下文分层与来源标注 |
| Reason | LLM 基于当前上下文决策 | 幻觉、prompt injection | 系统提示词约束 + 外部校验器[1](#阶段 职责 失败模式 工程护栏 Perceive 接收用户输入、工具返回、错误信号 上下文污染 上下文分层与来源标注 Reason LLM 基于当前上下文决策 幻觉、prompt injection 系统提示词约束 + 外部校验器[1] Plan 复杂任务拆解为子任务 无边界规划 确定性逻辑前置[1] Act 调用工具/API/DB/代码执行 越权、重复调用、误操作 四层幂等防御 + 沙箱[4] Observe 检查结果并判断是否完成 误判完成、循环打转 终止条件 + 断路器[7]) |
| Plan | 复杂任务拆解为子任务 | 无边界规划 | 确定性逻辑前置[1](#阶段 职责 失败模式 工程护栏 Perceive 接收用户输入、工具返回、错误信号 上下文污染 上下文分层与来源标注 Reason LLM 基于当前上下文决策 幻觉、prompt injection 系统提示词约束 + 外部校验器[1] Plan 复杂任务拆解为子任务 无边界规划 确定性逻辑前置[1] Act 调用工具/API/DB/代码执行 越权、重复调用、误操作 四层幂等防御 + 沙箱[4] Observe 检查结果并判断是否完成 误判完成、循环打转 终止条件 + 断路器[7]) |
| Act | 调用工具/API/DB/代码执行 | 越权、重复调用、误操作 | 四层幂等防御 + 沙箱[4](#阶段 职责 失败模式 工程护栏 Perceive 接收用户输入、工具返回、错误信号 上下文污染 上下文分层与来源标注 Reason LLM 基于当前上下文决策 幻觉、prompt injection 系统提示词约束 + 外部校验器[1] Plan 复杂任务拆解为子任务 无边界规划 确定性逻辑前置[1] Act 调用工具/API/DB/代码执行 越权、重复调用、误操作 四层幂等防御 + 沙箱[4] Observe 检查结果并判断是否完成 误判完成、循环打转 终止条件 + 断路器[7]) |
| Observe | 检查结果并判断是否完成 | 误判完成、循环打转 | 终止条件 + 断路器[7](#阶段 职责 失败模式 工程护栏 Perceive 接收用户输入、工具返回、错误信号 上下文污染 上下文分层与来源标注 Reason LLM 基于当前上下文决策 幻觉、prompt injection 系统提示词约束 + 外部校验器[1] Plan 复杂任务拆解为子任务 无边界规划 确定性逻辑前置[1] Act 调用工具/API/DB/代码执行 越权、重复调用、误操作 四层幂等防御 + 沙箱[4] Observe 检查结果并判断是否完成 误判完成、循环打转 终止条件 + 断路器[7]) |
表1 Harness 五阶段职责与护栏
3.1.2 重试与幂等
幂等设计的关键差异:Agent 的调用方是 LLM 而非确定性客户端代码。Stripe 官方幂等文档指出,幂等键应显式传入请求头,API 缓存首次响应并在重试时返回相同结果,参数不匹配时应显式报错而非静默二次执行6。这一原则在 Agent 场景需扩展为多层防御69:
| 层级 | 防御点 | 典型实现 |
|---|---|---|
| L1 目标端原生幂等 | 优先使用上游提供的幂等能力 | Stripe Idempotency-Key header[6](#层级 防御点 典型实现 L1 目标端原生幂等 优先使用上游提供的幂等能力 Stripe Idempotency-Key header[6] L2 幂等键落库 数据库唯一约束 + 状态机 (agent_run_id, step_id, tool_name) 作为主键,状态机流转 processing/success/failed L3 写后读回验证 读回比对声明意图 通过确定性 wrapper 读回结果比对,而非信任模型返回的"成功" L4 本地调用记录 短事务内提交 calling 状态再外呼 重试时若本地已 success 直接返回,不再外呼) |
| L2 幂等键落库 | 数据库唯一约束 + 状态机 | (agent_run_id, step_id, tool_name) 作为主键,状态机流转 processing/success/failed |
| L3 写后读回验证 | 读回比对声明意图 | 通过确定性 wrapper 读回结果比对,而非信任模型返回的"成功" |
| L4 本地调用记录 | 短事务内提交 calling 状态再外呼 | 重试时若本地已 success 直接返回,不再外呼 |
表2 幂等防御的典型分层
幂等键三条铁律:
- 其一,键应从稳定结构上下文派生(如
(run_id, step_id, tool_name)),而非从 LLM 输出哈希------同一 prompt 重试可能生成不同参数; - 其二,粒度对齐业务动作而非执行实例,太粗会错误去重、太细会让重试无法命中;
- 其三,参数不匹配时按 Stripe 模式显式报错6。
3.1.3 终止条件与多路熔断
Agent 不应仅靠模型自行判断"任务完成"。LangChain 官方 Middleware 提供 ModelCallLimitMiddleware 与 ToolCallLimitMiddleware,用于"防止 runaway agent 产生过多 API 调用""在生产部署中强制成本控制",到达上限时可优雅终止(end)或抛异常(error)7。综合工程实践,生产级终止条件至少含五路798:
| 终止类型 | 触发条件 | 典型默认值 | 命中后行为 |
|---|---|---|---|
| 目标达成 | 模型显式产出 final answer | --- | 优雅退出 |
| 步数上限 | 达到 max_model_calls 或 max_tool_calls |
由配置项决定[7](#终止类型 触发条件 典型默认值 命中后行为 目标达成 模型显式产出 final answer — 优雅退出 步数上限 达到 max_model_calls 或 max_tool_calls 由配置项决定[7] 返回"达上限"标记 时间上限 wall-clock 超时 Claude Code 默认请求超时 10 分钟[8] 保存 checkpoint 后终止 预算上限 token / 美元 / API 调用次数超限 按任务等级配置[9] 熔断 + 告警 无进展检测 重复同一 tool call 与参数、观察结果无变化 连续若干次即熔断 触发断路器) | 返回"达上限"标记 |
| 时间上限 | wall-clock 超时 | Claude Code 默认请求超时 10 分钟[8](#终止类型 触发条件 典型默认值 命中后行为 目标达成 模型显式产出 final answer — 优雅退出 步数上限 达到 max_model_calls 或 max_tool_calls 由配置项决定[7] 返回"达上限"标记 时间上限 wall-clock 超时 Claude Code 默认请求超时 10 分钟[8] 保存 checkpoint 后终止 预算上限 token / 美元 / API 调用次数超限 按任务等级配置[9] 熔断 + 告警 无进展检测 重复同一 tool call 与参数、观察结果无变化 连续若干次即熔断 触发断路器) | 保存 checkpoint 后终止 |
| 预算上限 | token / 美元 / API 调用次数超限 | 按任务等级配置[9](#终止类型 触发条件 典型默认值 命中后行为 目标达成 模型显式产出 final answer — 优雅退出 步数上限 达到 max_model_calls 或 max_tool_calls 由配置项决定[7] 返回"达上限"标记 时间上限 wall-clock 超时 Claude Code 默认请求超时 10 分钟[8] 保存 checkpoint 后终止 预算上限 token / 美元 / API 调用次数超限 按任务等级配置[9] 熔断 + 告警 无进展检测 重复同一 tool call 与参数、观察结果无变化 连续若干次即熔断 触发断路器) | 熔断 + 告警 |
| 无进展检测 | 重复同一 tool call 与参数、观察结果无变化 | 连续若干次即熔断 | 触发断路器 |
表3 终止条件的多路熔断设计
无进展检测的关键是定义"什么算一样"------同参数、同观察或状态无变化均可作判据。命中安全停止时须返回"最佳答案"或部分结果,而非悬挂或静默截断。
3.1.4 成本预算
Langfuse 将 LLM 成本管理拆为四层递进:"先在 token 层精确追踪,再归因到用户/会话/特性,再设阈值告警,最后优化",并指出最大的成本错误通常是测量错误 而非用量错误------如同一个调用被 gateway 与 SDK 重复记录、缓存 token 被重复计数、模型名匹配不上价格表、阶梯定价按平价计算9。在 Agent 场景,四维预算统一由 middleware 实现、挂在 Act 层之前:
- token 预算 :按 run 级别设 hard cap,通过 middleware 在每轮 LLM 调用前检查剩余额度7
- 步数预算 :与终止条件的
max_calls共用计数器,避免重复实现7 - 时间预算 :wall-clock watchdog 独立于单次 LLM 调用超时,Claude Code 默认请求超时 10 分钟、可通过
API_TIMEOUT_MS调整8 - 金额预算 :按模型单价表实时累加,超阈值走熔断而非仅告警------告警滞后于成本累计,熔断才能止损9
3.2 隔离层(权限与审计)
隔离层回答"Agent 能碰什么",核心是沙箱分档、最小权利与不可逆操作的审批门。
3.2.1 四档沙箱
沙箱的核心矛盾:Agent 会执行"不是你写也无法 review"的代码------可能来自客户 build 步骤、学生提交、或 Agent 刚读网页后决定执行的 shell 命令10。Fly.io 与 Northflank 的共识是主流隔离原语存在信任边界差异 :容器共享宿主内核、仅适合受信代码;gVisor 用用户态内核拦截 syscall,仍共享内核边界;Firecracker 等 microVM 给每个 workload 独立 guest 内核,隔离最强1011。
| 档位 | 隔离技术 | 适用场景 | 权限边界 |
|---|---|---|---|
| T1 Wasm 组件 | 无 ambient authority,按 import 声明授权 | 单 purpose 工具、MCP server | 仅 import 声明的能力 |
| T2 容器 | Docker / Podman,共享内核 | 受信代码、已有代码库内的 Agent | namespace + cgroup,需限制网络[10](#档位 隔离技术 适用场景 权限边界 T1 Wasm 组件 无 ambient authority,按 import 声明授权 单 purpose 工具、MCP server 仅 import 声明的能力 T2 容器 Docker / Podman,共享内核 受信代码、已有代码库内的 Agent namespace + cgroup,需限制网络[10] T3 硬化容器 / gVisor 用户态内核拦截 syscall 运行 LLM 生成的不完全可信代码 syscall 级拦截,仍共享内核[10][11] T4 microVM Firecracker / Kata Containers,独立内核 开放式 coding agent、任意 shell 最强隔离,worst case 是"扔掉容器"[10][11]) |
| T3 硬化容器 / gVisor | 用户态内核拦截 syscall | 运行 LLM 生成的不完全可信代码 | syscall 级拦截,仍共享内核[10](#档位 隔离技术 适用场景 权限边界 T1 Wasm 组件 无 ambient authority,按 import 声明授权 单 purpose 工具、MCP server 仅 import 声明的能力 T2 容器 Docker / Podman,共享内核 受信代码、已有代码库内的 Agent namespace + cgroup,需限制网络[10] T3 硬化容器 / gVisor 用户态内核拦截 syscall 运行 LLM 生成的不完全可信代码 syscall 级拦截,仍共享内核[10][11] T4 microVM Firecracker / Kata Containers,独立内核 开放式 coding agent、任意 shell 最强隔离,worst case 是"扔掉容器"[10][11])[11](#档位 隔离技术 适用场景 权限边界 T1 Wasm 组件 无 ambient authority,按 import 声明授权 单 purpose 工具、MCP server 仅 import 声明的能力 T2 容器 Docker / Podman,共享内核 受信代码、已有代码库内的 Agent namespace + cgroup,需限制网络[10] T3 硬化容器 / gVisor 用户态内核拦截 syscall 运行 LLM 生成的不完全可信代码 syscall 级拦截,仍共享内核[10][11] T4 microVM Firecracker / Kata Containers,独立内核 开放式 coding agent、任意 shell 最强隔离,worst case 是"扔掉容器"[10][11]) |
| T4 microVM | Firecracker / Kata Containers,独立内核 | 开放式 coding agent、任意 shell | 最强隔离,worst case 是"扔掉容器"[10](#档位 隔离技术 适用场景 权限边界 T1 Wasm 组件 无 ambient authority,按 import 声明授权 单 purpose 工具、MCP server 仅 import 声明的能力 T2 容器 Docker / Podman,共享内核 受信代码、已有代码库内的 Agent namespace + cgroup,需限制网络[10] T3 硬化容器 / gVisor 用户态内核拦截 syscall 运行 LLM 生成的不完全可信代码 syscall 级拦截,仍共享内核[10][11] T4 microVM Firecracker / Kata Containers,独立内核 开放式 coding agent、任意 shell 最强隔离,worst case 是"扔掉容器"[10][11])[11](#档位 隔离技术 适用场景 权限边界 T1 Wasm 组件 无 ambient authority,按 import 声明授权 单 purpose 工具、MCP server 仅 import 声明的能力 T2 容器 Docker / Podman,共享内核 受信代码、已有代码库内的 Agent namespace + cgroup,需限制网络[10] T3 硬化容器 / gVisor 用户态内核拦截 syscall 运行 LLM 生成的不完全可信代码 syscall 级拦截,仍共享内核[10][11] T4 microVM Firecracker / Kata Containers,独立内核 开放式 coding agent、任意 shell 最强隔离,worst case 是"扔掉容器"[10][11]) |
表4 四档沙箱对比
Northflank 强调生产级沙箱需纵深防御 :隔离边界、资源限制、网络控制、权限范围与监控缺一不可11。关键原则:绕过审批(如 Claude Code 的 bypass permissions mode)只有在沙箱边界之后才可接受 ,且沙箱内不应有生产凭证、共享状态写权限或通往关键系统的网络路径411。
3.2.2 最小权利与审批门
每个工具先按两轴分类:可逆性 (能否撤销)与爆炸半径 (破坏扩散多远),再落入权限档位。OWASP LLM06 建议"仅授予最低必要的扩展与函数",并对高影响操作要求"独立验证与批准"4。OpenAI Agents SDK 提供了工程参考:工具可声明 needs_approval,运行时把待审批项作为 interruption 暴露给外层 RunState,人工决策后从同一状态续跑;审批覆盖跨 handoff 与嵌套 Agent.as_tool() 场景12。
| Tier | 示例 | 默认行为 |
|---|---|---|
| Auto-run | 读文件、GET、list | 执行 + 记录 |
| Log-only write | 写草稿、append 队列 | 执行 + 记录完整 payload |
| Human approval | 发外部邮件、扣款、部署、DELETE/DROP、改 prod 配置 |
暂停 + 路由到人[4](#Tier 示例 默认行为 Auto-run 读文件、GET、list 执行 + 记录 Log-only write 写草稿、append 队列 执行 + 记录完整 payload Human approval 发外部邮件、扣款、部署、DELETE/DROP、改 prod 配置 暂停 + 路由到人[4][12] Blocked 破坏性 shell、prod 裸 shell、凭证外传路径 直接拒绝[4])[12](#Tier 示例 默认行为 Auto-run 读文件、GET、list 执行 + 记录 Log-only write 写草稿、append 队列 执行 + 记录完整 payload Human approval 发外部邮件、扣款、部署、DELETE/DROP、改 prod 配置 暂停 + 路由到人[4][12] Blocked 破坏性 shell、prod 裸 shell、凭证外传路径 直接拒绝[4]) |
| Blocked | 破坏性 shell、prod 裸 shell、凭证外传路径 | 直接拒绝[4](#Tier 示例 默认行为 Auto-run 读文件、GET、list 执行 + 记录 Log-only write 写草稿、append 队列 执行 + 记录完整 payload Human approval 发外部邮件、扣款、部署、DELETE/DROP、改 prod 配置 暂停 + 路由到人[4][12] Blocked 破坏性 shell、prod 裸 shell、凭证外传路径 直接拒绝[4]) |
表5 按 blast radius 分层的权限档位
审批门 payload 四要素 :做什么(精确 tool call + 参数)、为什么(推理链与原始请求)、爆炸半径(影响记录数/环境/金额)、一键 approve/deny/edit(超时默认 deny )124。
3.2.3 用完即收与不可逆人工审核
用完即收指一次性凭证、临时 token、任务结束即销毁的 session,避免长活凭证成为重放攻击面;工具结束后释放沙箱、清空环境变量,下次任务重新签发。
不可逆操作必须人工审核 是 OWASP 的明确防护要求4,OpenAI Agents SDK 将其工程化为可序列化的暂停-续跑:工具需审批时 SDK 暂停、返回 interruptions,决策后从同一 RunState 恢复12。这把"人工审核"从流程建议升级为执行栈层级的强约束。
3.3 运维层(监控与恢复)
运维层回答"能否看得见、跑得久",核心是追踪三轴、健康信号、checkpoint 与 durable execution。
3.3.1 可观测与审计
AI Agent 可观测的目标是"出错时能回答'为什么 Agent 这样做'"------传统 APM 在 Agent 场景是盲的,因为 Agent 能返回结构良好却语义错误的结果、做三次多余的工具调用、或陷入 HTTP 200 持续烧钱的循环1415。OpenTelemetry GenAI semantic conventions 在官方仓库定义四个 Agent span 类型:create_agent、invoke_agent、invoke_workflow、execute_tool,span 名称为 create_agent {gen_ai.agent.name}、kind 为 CLIENT13。Datadog 说明,遵循该规范的 span 可经 OTLP 直接接入观测后端,无需重复埋点14。
| 轴 | 内容 | 典型工具 |
|---|---|---|
| 执行轴 | 嵌套 span 树:Trace → invoke_workflow → invoke_agent → execute_tool → LLM call | Langfuse、Arize Phoenix、Datadog[13](#轴 内容 典型工具 执行轴 嵌套 span 树:Trace → invoke_workflow → invoke_agent → execute_tool → LLM call Langfuse、Arize Phoenix、Datadog[13][14] 成本轴 每 span 记录 input_tokens / output_tokens / cached_tokens / reasoning_tokens,向上聚合 Langfuse Token & Cost Tracking[15] 审计轴 Append-only、结构化、含时间戳与审批人 自建 hash chain)[14](#轴 内容 典型工具 执行轴 嵌套 span 树:Trace → invoke_workflow → invoke_agent → execute_tool → LLM call Langfuse、Arize Phoenix、Datadog[13][14] 成本轴 每 span 记录 input_tokens / output_tokens / cached_tokens / reasoning_tokens,向上聚合 Langfuse Token & Cost Tracking[15] 审计轴 Append-only、结构化、含时间戳与审批人 自建 hash chain) |
| 成本轴 | 每 span 记录 input_tokens / output_tokens / cached_tokens / reasoning_tokens,向上聚合 |
Langfuse Token & Cost Tracking[15](#轴 内容 典型工具 执行轴 嵌套 span 树:Trace → invoke_workflow → invoke_agent → execute_tool → LLM call Langfuse、Arize Phoenix、Datadog[13][14] 成本轴 每 span 记录 input_tokens / output_tokens / cached_tokens / reasoning_tokens,向上聚合 Langfuse Token & Cost Tracking[15] 审计轴 Append-only、结构化、含时间戳与审批人 自建 hash chain) |
| 审计轴 | Append-only、结构化、含时间戳与审批人 | 自建 hash chain |
表6 Agent 可观测的追踪三轴
健康信号 须超越"是否 200":任务完成率、工具调用成功率、审批门 deny 率(异常升高可能提示 prompt injection)、断路器触发次数、每成功任务成本、子 Agent spawn 深度分布等14152021。
3.3.2 故障恢复与续跑(Checkpoint 与 Durable Execution)
Checkpoint 与 Durable Execution 是两个不同概念 。LangGraph 的 Checkpointer 在每个 super-step 保存状态快照,以 thread_id 组织,支持人机协同、时间旅行调试、容错执行与会话记忆16。其 interrupt() 可在任意节点调用,触发时保存状态并等待,经 Command 再入图,返回值即恢复时传入的 payload17。
但 checkpoint 不等于 完全 durable execution------Temporal 把它定义为"Workflow 在崩溃、网络超时或多日等待人工审批后自动恢复",并把 ReAct 循环每步作为持久化任务由 worker 重启1819。差异的关键在重放边界 :checkpoint 恢复时 interrupt 前的代码可能再跑一次,因此 node 边界必须工程化 replay 边界,副作用靠幂等防御兜底161718。
Durable pause 实战要点:
interrupt()须设计为幂等边界------假设 interrupt 前的副作用可能被重放,配合 L1--L4 幂等防御兜底617- 审批流持久化是独立工程------需追踪"哪个 run 在等谁审批",审批到达后精准 re-enter 到正确的图步骤;OpenAI Agents SDK 通过序列化
RunState(含 approvals、tool input、嵌套 resumption)实现12 - 重放状态须完整序列化:对话历史、中间变量、已消耗的预算计数器、幂等键------漏掉任何一个都会导致 resume 后行为不一致1619
- 故障演练是必做项:定期 kill worker、模拟审批超时、断网重连,验证 checkpoint 恢复
4 效果评估与适用边界
4.1 效果与实证
三层架构的效果在两个维度均有公开数据。能力维度 :Anthropic 报告称,通过优化脚手架(Tool Using Agent 设计 + error-proof 工具接口),升级后的 Claude 3.5 Sonnet 在 SWE-bench Verified 达 49%,超越此前 45% 的 SOTA3;Harness-Bench 的 5194 条轨迹统计进一步证明,完成率、过程质量、效率与失败行为在"模型-Harness 配置"层面差异显著,应报配置级结果而非归因于基础模型2。稳定性维度 :Temporal 的 durable execution 支持 Workflow 在崩溃、网络超时或多日等待人工审批后自动恢复,已用于 OpenAI 生产基础设施1918。
4.2 局限与适用边界
三层架构并非零成本:复杂度开销 ------四档沙箱 + 审批门 + 追踪三轴需跨编排、隔离、运维三团队协同,小团队落地门槛高;延迟开销 ------每次工具调用要过权限判定、审批路由与 span 采集,延迟敏感场景需权衡;测量成本 ------Langfuse 指出成本最大错误来自测量而非用量,instrumentation 本身就是持续工程9。
适用边界 :三层架构的价值密度随任务危险性与长时性递增。低风险、短周期、单轮交互的简单任务可用轻量 Harness;涉及外部副作用、不可逆操作、多日审批或需审计合规的生产级 Agent,三层不可或缺41119。
适用边界 :三层架构的价值密度随任务危险性与长时性递增。低风险、短周期、单轮交互的简单任务可用轻量 Harness;涉及外部副作用、不可逆操作、多日审批或需审计合规的生产级 Agent,三层不可或缺41119。
总结
给不可靠的 LLM 套三层约束------编排层管"怎么循环推进"、隔离层管"能碰什么"、运维层管"看得见且跑得久",三层协同才能让 Agent 从"演示里能跑"变成"生产里可信"。
知识点
Agent 工程化三层架构
├── 1 定义本质与三层划分
│ ├── Harness 系统层定义
│ └── 三层架构图
├── 2 生产化的四类痛点
│ ├── LLM 不可靠性
│ ├── 脚手架差异实证
│ ├── 越权风险
│ └── 成本与循环
├── 3 方法机制与实现
│ ├── 3.1 编排层
│ │ ├── 五阶段循环
│ │ ├── 幂等四层防御
│ │ ├── 终止条件
│ │ └── 四维预算
│ ├── 3.2 隔离层
│ │ ├── 四档沙箱
│ │ ├── 最小权利与审批门
│ │ └── 用完即收与不可逆人审
│ └── 3.3 运维层
│ ├── 追踪三轴
│ ├── checkpoint 与 durable execution 差异
│ └── durable pause 四要点
├── 4 效果评估与适用边界
│ ├── 效果实证
│ └── 局限与边界
参考文献
1 Anthropic. "Building Effective Agents." Anthropic Engineering Blog , 2024.
2 X. Tan et al. "Harness-Bench: Measuring Harness Effects across Models in Realistic Agent Workflows." arXiv:2605.27922 , 2026.
3 Anthropic. "Claude SWE-Bench Performance." Anthropic Research , 2024.
4 OWASP GenAI Security Project. "LLM06:2025 Excessive Agency." OWASP LLM Top 10 2025 , 2025.
5 Anthropic. "Quantifying Infrastructure Noise in Agentic Coding Evals." Anthropic Research , 2026.
6 Stripe. "Idempotent Requests." Stripe API Reference .
7 LangChain. "Prebuilt Middleware - ModelCallLimitMiddleware and ToolCallLimitMiddleware." LangChain Documentation .
8 Anthropic. "Error Reference - Claude Code." Claude Code Documentation .
9 Langfuse. "LLM Cost Management: Track and Control Spend." Langfuse Engineering , 2025.
10 Fly.io. "Firecracker vs gVisor: Sandbox Isolation for Untrusted Code." Fly.io Learn , 2025.
11 Northflank. "How to Sandbox AI Agents in 2026: MicroVMs, gVisor and Hardened Containers." Northflank Blog , 2026.
12 OpenAI. "Human-in-the-Loop - OpenAI Agents SDK." OpenAI Agents SDK Documentation .
13 OpenTelemetry. "Semantic Conventions for GenAI Agent and Framework Spans." OpenTelemetry GitHub , 2025.
14 Datadog. "Datadog Agent Observability Natively Supports OpenTelemetry GenAI Semantic Conventions." Datadog Blog , 2025.
15 Langfuse. "Token & Cost Tracking." Langfuse Documentation .
16 LangChain. "Persistence - LangGraph." LangChain Documentation .
17 LangChain. "Interrupts - LangGraph." LangChain Documentation .
18 Temporal. "The Definitive Guide to Durable Execution." Temporal Blog , 2025.
19 Temporal. "Durable AI." Temporal Documentation .
20 Langfuse. "AI Agent Observability, Tracing & Evaluation with Langfuse." Langfuse Blog , 2024.
21 K. Nguyen. "AI Agent Observability 2026: Tracing & Monitoring Stack Guide." Digital Applied, 2026.