Skip to content

Harness 工程

🎯 学习目标

  • 定义 Harness 作为 Agent 运行时壳层的职责
  • 实现 beforeToolCall / afterLLM / onError 等 Hook
  • 集成 AbortSignal、超时、死循环检测与审计
  • 建立 trace、metrics 与人工 escalation 路径

引言

Loop + Tools 是引擎;Harness 是车架、安全带与仪表盘。没有 Harness 的 Agent 只能 Demo。本节把分散的安全、观测、中断话题收拢为一套运行时工程。

章节正文

第 1 步:Harness 职责边界

Harness 替 LLM 思考;它:

  • 强制执行权限与确认策略
  • 在工具/LLM 前后插入 Hook
  • 统一 timeout、retry、cancel(AbortSignal)
  • emit trace/metrics/audit
  • 检测死循环与 budget 超限
  • 提供 pause/resume/escalate API

业务逻辑在 Tools 与 Planner;策略在 Harness。

第 2 步:Hook 设计

typescript
class AgentHarness {
  async beforeToolCall(call: ToolCall, ctx: SessionCtx) {
    this.audit.log({ phase: 'before', call })
    if (this.isHighRisk(call)) await this.confirmWithUser(call, ctx)
    if (ctx.signal.aborted) throw new AbortError()
  }

  async afterLLM(response: LLMResponse, ctx: SessionCtx) {
    this.metrics.tokens.inc(response.usage.totalTokens)
    this.contentFilter.scan(response.message.content)
  }

  async onError(err: unknown, ctx: SessionCtx) {
    this.trace.fail(ctx.sessionId, err)
    if (isRetryable(err)) return this.retryPolicy.next()
    throw err
  }
}

Hook 保持纯副作用,不改变业务语义,便于单测。

第 3 步:AbortSignal 与优雅中断

typescript
const ac = new AbortController()
ui.onPause(() => ac.abort())

await runAgentLoop(state, { signal: ac.signal, harness })

// ToolExecutor / fetch 均需传入 signal

用户点「停止」后,应在当前 tool 完成后停止,而非 kill 进程留 half-written 文件。

第 4 步:观测:Trace 与 Metrics

OpenTelemetry 风格 span:

text
session.run
  ├─ llm.planner (iteration=1)
  ├─ tool.search_docs
  ├─ llm.planner (iteration=2)
  └─ llm.final

Metrics:agent_run_durationtool_errors_totaliterations_per_runhuman_confirm_denied

日志关联 sessionIduserIdtraceId

第 5 步:Escalation 与降级

abortReason === 'MAX_ITERATIONS' 或 critical tool 失败:

  1. 返回 partial result + 清晰说明
  2. 可选 ticket 转人工,附带 trace link
  3. 降级:关闭 write 工具,只读继续

Harness 配置应用层 policy YAML,而非硬编码 if。

动手练习

  1. 为 AgentHarness 写 3 个 Hook 的单测(mock user deny confirm)。
  2. 设计 policy.yaml:tools.write.requireConfirm、maxIterations、tokenBudget。
  3. 画 OTel span 树示例,含一次失败 retry。
  4. 实现 onPause → AbortController 与 Loop 协作的伪代码。
  5. 写 escalation 工单应包含哪些字段(trace、partial state、user goal)。

常见问题

Q:Harness 和 Middleware 一样吗?

类似 HTTP middleware 链,但面向 Agent 语义(tool、iteration、budget)。可复用 middleware 思想实现 Hook pipeline。

Q:Hook 里能改 tool arguments 吗?

谨慎。sanitize 可以;实质性改参应记 audit 并最好让人确认,否则 accountability 模糊。

Q:Cursor / Claude Code 的 Harness 我们能复用吗?

IDE 产品有内置 Harness(权限、沙箱)。自研 Agent 仍需自己的 policy 与 observability,不能假设 IDE 层覆盖服务端场景。

本节小结

Harness = Agent 的生产运行时:Hook、权限、中断、retry、trace、escalation。策略配置化、观测标准化,Loop 才能从 Demo 进生产。