大数跨境

AI Agent 总是失控?真正缺的不是 Prompt,而是这 6 层 Harness !

AI Agent 总是失控?真正缺的不是 Prompt,而是这 6 层 Harness ! AI Agent 领域
2026-09-05
2
导读:AI Agent 为什么总忘规则、乱用工具?一篇讲透 Harness Engineering!

 

一个更好的 Prompt,可能让某一次回答变得更好。

一个更好的 Harness,却能改善 Agent 的每一次运行。

如果你的 Agent 明明具备不错的推理能力,却依然会忘记约束条件、选错 Tool、跳过验证步骤,或者不断循环直到预算耗尽,那么问题就不一定完全出在模型本身。

更大的问题往往是:模型周围的运行环境定义得不够清楚。

接下来将介绍一套实用的六层 Harness。无论你构建的是 Coding Agent、Research Agent、Support Agent,还是 Operations Agent,都可以把这套结构放在模型外围,用来约束和管理 Agent 的执行过程。

读完之后,你将拥有:

  • • 一份 task contract
  • • 一个 context compiler
  • • 一个带权限控制的 tool gateway
  • • 一套 durable state
  • • 一组 evidence gates
  • • 一套 trace 与 recovery loop

这不是再写一个巨大的 Prompt。

而是在给 Agent 构建一套属于它自己的操作系统。

为什么 Harness Engineering 变得重要

2026 年 2 月,OpenAI 介绍过一个内部产品。这个产品最初几乎没有人工手写代码。

开发进行五个月之后,这个代码仓库已经拥有大约 100 万行代码,以及约 1,500 个已经合并的 Pull Request。OpenAI 估计,这个产品的开发速度,大约是传统人工开发方式的 10 倍。

真正有意思的地方,并不仅仅是 Codex 能够写代码。

更值得关注的是:在人类工程师真正让 Codex 产生稳定价值之前,他们必须先围绕 Codex 构建什么。

早期阶段,他们的开发进展其实并不快,因为整个运行环境定义得不够充分。Agent 缺少必要的 Tool、内部结构、可观测的反馈,以及真正能够被执行和约束的规则。

当 Agent 失败时,真正有价值的问题并不是:

“怎样把 Prompt 写得更强硬一点?”

而应该是:

Agent 缺失的能力到底是什么?我们怎样才能让这种能力对 Agent 来说既清晰可见,又能够被系统真正执行?

这就是 Harness Engineering。

模型负责提供带有概率性的推理能力。

Harness 则负责把这种推理能力转化成可控的执行过程。


   
   
   
   
    
   
   
   
   MODEL
提出下一步行动

HARNESS
选择 Context
授权 Tool
保存 State
收集 Evidence
执行限制
从失败中恢复

Prompt 只是整个系统中的一个输入。

Prompt 本身并不是整个系统。

最小可用 Harness

一个实用的 Harness,并不需要二十个服务,也不需要一开始就搭建 Multi-Agent Swarm。

真正重要的是,要明确处理好六件事。


1. 把用户请求转换成 Contract

自然语言请求天然具有灵活性。

但生产环境中的任务不能依靠这种模糊性运行。

在模型真正开始行动之前,Harness 应该先把用户请求转换成一个边界明确的 task object:


   
   
   
   
    
   
   
   
   task_id: feature_042
goal:
 Add CSV export to the analytics dashboard

inputs:

  -
 issue.md
  -
 repository
  -
 design/export-flow.png

constraints:

  -
 preserve the public API
  -
 do not change the database schema
  -
 do not add a new dependency

deliverable:

  type:
 pull_request

done_when:

  -
 tests pass
  -
 typecheck passes
  -
 exported CSV matches the fixture
  -
 UI screenshot passes review

escalate_when:

  -
 schema change appears necessary
  -
 tests fail three times for the same reason
  -
 requested behavior conflicts with an existing product rule

这样做可以防止 Agent 在执行过程中悄悄替换任务目标。

如果没有 Contract,Agent 很可能会选择一个更容易解决的版本,然后非常自信地宣布任务已经完成。

Contract 还为 Harness 提供了一组客观的判断标准。

“看起来不错”不能作为停止条件。

“这四项检查全部通过”才可以。


2. 编译 Context,不把所有内容一股脑塞进去

Context 本质上是一种有限的注意力预算。

最常见的错误,是把所有内容全部注入模型:

完整的历史对话、所有 Tool 返回结果、全部项目文档,以及一份 1,000 行的 instruction file。

但更多的 Context,并不会自动带来更好的理解能力。

OpenAI 在实践中总结出的原则很简单:

给 Agent 一张地图,而不是一本说明书。

Anthropic 给出的整体方向也类似:让 Context 保持高信号密度,并且只在真正需要时,通过 Just-in-Time 的方式加载更多信息。

可以构建一个 context compiler,只组装当前步骤真正需要的内容:


   
   
   
   
    
   
   
   
   function buildContext(task, state) {
  return
 [
    load
("AGENTS.md"),                 // 精简的项目地图
    load
(task.relevantProductSpec),    // 与任务相关的规则
    load
(task.relevantArchitecture),   // 当前任务涉及的架构边界
    summarize
(state.completedSteps),   // 压缩后的执行历史
    state.openRisks,
    state.currentArtifacts
  ];
}

使用 progressive disclosure:


   
   
   
   
    
   
   
   
   AGENTS.md
-> architecture index
-> product rules
-> task-specific guide
-> exact files and evidence

根目录中的 guide,只需要告诉 Agent:知识放在哪里。

当 Agent 真正需要某部分信息时,再通过 Tool 获取更深层的内容。

对话记录不应该充当数据库。

System Prompt 也不应该充当文件柜。


3. 在模型和所有 Tool 之间增加 Gateway

模型可以提出它想执行什么操作。

但真正决定这个操作是否有效、是否允许、是否安全执行的,应该是 Harness。


   
   
   
   
    
   
   
   
   async function handleToolRequest(request, run) {
  validateSchema
(request);

  const
 decision = policy.authorize({
    tool
: request.name,
    args
: request.args,
    task
: run.contract,
    risk
: classifyRisk(request)
  });

  if
 (decision === "deny") {
    return
 observation("permission_denied");
  }

  if
 (decision === "approval_required") {
    return
 pauseForHumanApproval(request);
  }

  const
 result = await sandbox.execute(request);
  return
 normalizeObservation(result);
}

每一个 Tool 都应该具备:

  • • 一个清晰明确的用途
  • • 一个没有歧义的 Schema
  • • 一个明确的权限边界
  • • 一个可预测的成功响应
  • • 一个结构化的失败响应
  • • 一个 Timeout

Tool 返回给模型的,应该是一个 Agent 可以继续推理的 Observation,而不是一大堵没有边界的终端输出。

例如:


   
   
   
   
    
   
   
   
   {
  "status"
: "failed",
  "tool"
: "run_tests",
  "reason"
: "2 snapshot mismatches",
  "evidence"
: [
    "artifacts/home-mobile-before.png"
,
    "artifacts/home-mobile-after.png"

  ],
  "retryable"
: true
}

好的 Tool Design,会减少模型必须依靠猜测做出的决定。

差的 Tool Design,则会让 Agent 的每一次操作,都变成一个新的推理难题。


4. 把 Memory 外部化成 Durable State

长时间运行的 Agent,迟早都会遇到 Context Limit、进程崩溃、重新启动,或者需要把任务交给另一个 Agent 的情况。

如果关键状态只存在于 Transcript 中,那么整个运行过程就非常脆弱。

应该把工作状态持久化到模型之外:


   
   
   
   
    
   
   
   
   {
  "task_id"
: "feature_042",
  "status"
: "verifying",
  "current_step"
: "mobile_visual_check",
  "completed"
: [
    "implementation"
,
    "unit_tests"
,
    "desktop_visual_check"

  ],
  "decisions"
: [
    "reuse existing export endpoint"
,
    "preserve current date format"

  ],
  "artifacts"
: [
    "export.csv"
,
    "desktop-after.png"

  ],
  "open_risks"
: [
    "mobile toolbar may overflow at 390px"

  ],
  "next_action"
: "render mobile viewport"
}

Memory 最好被拆分成四类:


   
   
   
   
    
   
   
   
   FACTS       稳定的项目知识
DECISIONS   当前任务中已经做出的决定
STATE       当前 Run 运行到了哪里
LESSONS     应该影响未来 Run 的失败经验

这种区分非常重要。

一个临时 Tool Output,在被总结之后就可以丢弃。

一个架构层面的 Decision,则应该能够跨越所有 Context Reset 被保留下来。

而一个反复出现的失败经验,则应该最终变成一条 Rule 或一个 Test。

Memory 并不意味着:

“把整段聊天记录永久保存下来。”

Memory 真正应该保存的是:

保证任务能够正确继续所需要的最小信息集合。


5. 用 Evidence 决定任务是否真正完成

模型负责产出 Artifact。

运行环境负责产生关于这个 Artifact 的 Evidence。

最终,Harness 决定这些 Evidence 是否足以证明任务已经完成。


   
   
   
   
    
   
   
   
   async function verify(artifact, contract) {
  const
 evidence = await Promise.all([
    runTests
(),
    runTypecheck
(),
    validateOutputSchema
(artifact),
    renderAndCaptureScreenshots
(),
    checkScope
(contract.constraints)
  ]);

  const
 failed = evidence.filter(check => !check.passed);

  if
 (failed.length === 0) return { status: "accept", evidence };
  if
 (canRepairLocally(failed)) return { status: "retry", failed };
  return
 { status: "escalate", failed };
}

优先使用确定性的检查方式:


   
   
   
   
    
   
   
   
   CODE       tests + types + lint + dependency rules

UI         render + screenshot + interaction replay

RESEARCH   source coverage + citation match + contradiction check

DATA       schema + range + freshness + reconciliation

SUPPORT    policy check + PII check + approval boundary

然后,再针对那些必须依赖判断能力的任务,引入基于模型的 Reviewer。

负责产出的 Maker 和负责检查的 Checker,最好不要拥有完全相同的激励和工作方式。

写出答案的模型当然也可以检查自己的答案,但如果使用一个拥有不同 Instructions、并且基于 Fresh Context 独立工作的 Verifier,就更难出现“自己骗过自己”的情况。

只有 Evidence Quality 提升,Autonomy 才应该随之扩大。


6. 记录整个 Run,并针对具体失败进行 Recovery

如果没有 Trace,一次失败最后只会变成一个故事。

有了 Trace,它才能成为一个可以复现的 Test Case。

记录内容可以类似这样:


   
   
   
   
    
   
   
   
   {
  "run_id"
: "run_2026_08_29_0142",
  "contract_version"
: "3",
  "model_route"
: "reasoning-large",
  "context_sources"
: ["AGENTS.md", "docs/export.md"],
  "tool_calls"
: 17,
  "state_changes"
: 6,
  "verification"
: {
    "passed"
: 4,
    "failed"
: 1
  },
  "retries"
: 1,
  "cost_usd"
: 2.84,
  "stop_reason"
: "human_approval_required",
  "rollback_point"
: "git:9cf31d2"
}

然后,在 Retry 之前先对 Failure 进行分类:


   
   
   
   
    
   
   
   
   switch (failure.type) {
  case
 "missing_context":
    updateProjectMap
(failure.source);
    break
;

  case
 "bad_tool_contract":
    improveToolSchema
(failure.tool);
    break
;

  case
 "missing_guardrail":
    addPolicyCheck
(failure.action);
    break
;

  case
 "weak_verification":
    addRegressionTest
(failure.example);
    break
;

  default
:
    escalateWithEvidence
(failure);
}

不要只是换一个语气更激烈的 Prompt,然后让相同的环境重新跑一遍。

应该修复真正缺失的能力,再重新运行那个精确的失败案例,并把这次修复永久保留下来。

最好的 Harness 会不断产生复利。

一次失败,应该让之后的每一次 Run 都变得更可靠。


一套实用的 Permission Ladder

模型不应该自己批准自己的高风险操作。

应该把“提出操作”“授权操作”和“执行操作”分开:


   
   
   
   
    
   
   
   
   MODEL PROPOSES

POLICY AUTHORIZES

TOOL EXECUTES

HARNESS RECORDS THE RESULT

一个简单的初始 Policy 可以这样设计:


   
   
   
   
    
   
   
   
   permissions:
  read_files:

    mode:
 automatic

  write_workspace:

    mode:
 automatic
    requires:

      -
 isolated_workspace
      -
 diff_recorded

  send_message:

    mode:
 approval_required
    requires:

      -
 final_content_preview

  deploy_production:

    mode:
 approval_required
    requires:

      -
 tests_pass
      -
 rollback_ready

  delete_data:

    mode:
 approval_required
    requires:

      -
 exact_targets
      -
 recovery_plan

不要给所有任务都施加最高级别的摩擦。

阅读一份公开文档,和删除客户数据,不应该经过完全相同的审批流程。

应该根据操作可能造成的后果,匹配对应级别的控制措施。


最小可用的项目结构

你甚至不需要借助任何 Framework,就能搭出第一版 Harness:


   
   
   
   
    
   
   
   
   agent-harness/
├── AGENTS.md              # 小型项目地图,而不是百科全书
├── contracts/
│   └── task.schema.json
├── context/
│   ├── architecture.md
│   ├── product-rules.md
│   └── security.md
├── tools/
│   ├── registry.json
│   └── permissions.yaml
├── state/
│   ├── current.json
│   └── decisions.md
├── checks/
│   ├── verify.ts
│   └── regression-cases/
├── runs/
│   └── traces.jsonl
└── lessons/
    └── harness-updates.md

这些文件夹叫什么并不重要。

真正重要的是:

这些职责必须彼此分离。


按照这个顺序搭建 Harness

不要一上来就做 Multi-Agent Swarm。

先构建一个最小执行循环,让它能够证明自己的工作结果。

Step 1 —— 定义什么叫“完成”

先写 Contract,再定义两到三个能够判断任务是否成功的 Check。

Step 2 —— 封装一个 Tool

给这个 Tool 定义 Schema、Timeout、Permission Rule,以及 Structured Result。

Step 3 —— 持久化一个 State File

记录已经完成的步骤、做出的 Decisions、产生的 Artifacts、尚未解决的 Risks,以及 Next Action。

Step 4 —— 增加一条 Recovery Path

当某项检查失败时,把准确的 Evidence 返回给 Agent,并允许它进行一次有明确边界的修复尝试。

Step 5 —— 保存 Trace

记录:

当前 Run 加载了哪些 Context、执行了哪些 Tool、修改了什么、哪些 Check 通过、哪些 Check 失败,以及 Run 为什么停止。

Step 6 —— 把重复出现的 Failure 变成 Infrastructure

任何反复出现的错误,最终都应该被转化成以下四种东西之一:


   
   
   
   
    
   
   
   
   一个更清晰的 Map

一个更好的 Tool

一个更严格的 Permission

一个新的 Test

只有完成这些事情之后,才值得继续增加更多 Autonomy、更多 Tool,或者更多 Agent。


Harness Engineering 不是什么

它不是一份 5,000 行的 System Prompt。

它不是把所有你能接入的 Tool 全部交给 Agent。

它不是永久保存 Raw Transcript,然后把这种做法称为 Memory。

它不是在一个根本没有 Objective Acceptance Criteria 的任务上,再随便加一个 Reviewer Agent。

它不是不断 Retry,直到某一次随机运行“看起来不错”。

它也不是试图把人类从所有 Decision 中移除。

Harness 真正存在的意义,是:

把人类的注意力留给真正需要判断力的地方,把剩下的事情交给系统自动完成。


真正应该关注的 Metric

不要优化:

生成了多少 Token、调用了多少次 Tool,或者启动了多少个 Task。

更值得优化的是:


   
   
   
   
    
   
   
   
   accepted outputs
----------------
human review minutes

也就是:

被接受的输出数量 ÷ 人工 Review 所花费的时间。

这个比例真正体现了 Harness 应该完成的事情:

把模型本身的能力转化成有实际价值、能够被 Review 的工作成果,同时避免在输出的另一端消耗同等规模的人力。


真正发生的变化

Prompt Engineering 关心的问题是:

What should I tell the model?

我应该告诉模型什么?

Context Engineering 关心的问题是:

What should the model know right now?

模型现在应该知道什么?

Harness Engineering 关心的问题则是:

What system lets the model act, prove its work, recover, and improve safely?

什么样的系统,能够让模型真正执行任务、证明自己的工作成果、从失败中恢复,并且安全地持续改进?

模型会不断变化。

而真正能够不断积累你的工程经验和运行知识的地方,是 Harness。

建立 Contract。

编译 Context。

给 Tool 加上 Gateway。

持久化 State。

要求 Evidence。

把 Failure 转化成 Infrastructure。

这才是把一个能力很强的模型,真正变成一个可靠 Agent 的方法。

 

【声明】内容源于网络
0
0
AI Agent 领域
专注AI智能体(Agentic AI)技术实践与前沿探索,涵盖LLM Agents、工具调用、RAG系统、Agent框架实战等内容,助力开发者构建下一代智能系统。
内容 358
粉丝 0
AI Agent 领域 专注AI智能体(Agentic AI)技术实践与前沿探索,涵盖LLM Agents、工具调用、RAG系统、Agent框架实战等内容,助力开发者构建下一代智能系统。
总阅读10.2k
粉丝0
内容358