Agent Harness & Harness Engineering(运行外壳与外壳工程)

Agent Harness 是包裹在模型外面、真正把 Agent”跑起来”的那层代码/运行时。模型本身只会”输入文本→输出文本”,它不会自己调工具、不会自己循环、不会自己管历史。这些脏活累活全靠 Harness 来干。

一句话类比:模型是”发动机”,Harness 是”整辆车的底盘 + 变速箱 + 仪表盘”——发动机只负责产生动力(生成 token),而油门怎么传到轮子、怎么循环换挡、仪表盘怎么显示状态,全是底盘(Harness)的事。换个更贴切的:harness 本意是”马具/挽具”,就是套在马(模型)身上、让它的力气能拉动车、还能被驾驭的那套装备。

定位分工:

  • Loop Engineering(见 loop_engineering.md)= 设计”循环的规则”(何时停、喂什么)。
  • Agent Harness = 真正跑这个循环的”机器”(把模型、工具、状态、错误处理全接起来)。
  • Harness Engineering = 如何把这台机器设计得健壮、可观测、可控——就是本篇下半部分。

1. 为什么需要 Harness:模型什么都不会

裸模型能做的仅仅是”给一段文本,续写一段文本”。要变成一个能干活的 Agent,中间缺的全部由 Harness 补上:

能力模型自己能做吗由谁补上
理解目标、决定下一步✅ 能(这是模型的强项)模型
真正去调用工具/API❌ 只能”说”要调,不能真调Harness
循环(多轮想-做-看)❌ 一次生成就结束了Harness
记住历史、管理状态❌ 无状态,每次都要喂回去Harness
处理工具报错、超时、重试Harness
记录日志、可观测Harness

关键认知:你在 agent.md 里见过的 AgentExecutor,就是一个 Harness。 LangGraph 的 graph-based runtime 也是 Harness,只是更强。Claude Code、Kiro 这类 coding agent 背后也各有一套 Harness。它们都在做同一件事:把裸模型武装成能干活的 Agent。

2. 一个 Harness 通常负责哪些模块

                 ┌─────────────────── Agent Harness ───────────────────┐
   用户输入 ───▶  │  ① 上下文组装  →  ② 调模型  →  ③ 解析输出           │
                 │        ▲                            │                │
                 │        │                            ▼                │
                 │  ⑥ 状态/记忆管理  ◀── ⑤ 结果回填 ◀── ④ 工具执行器     │
                 │                                     │  (+错误处理/重试)│
                 │                          ⑦ 日志 / 可观测 / 预算控制    │
                 └──────────────────────────────────────────────────────┘
                                          │ 判停?否→回到① / 是→输出
  1. 上下文组装:把 system prompt、历史、工具定义、检索到的资料拼成这一轮喂给模型的输入(Context Engineering 的落地点)。
  2. 调模型:发请求、处理流式输出。
  3. 解析输出:判断模型是想调工具(解析出 tool name + 参数 JSON,见 tool_calling.md),还是给最终答案。
  4. 工具执行器:真正去跑工具,含超时、重试、错误捕获、权限校验。
  5. 结果回填:把工具返回值写回状态,作为下一轮的 observation。
  6. 状态/记忆管理:维护对话历史、中间产物、短期/长期记忆。⚠️ 注意分工——Harness 负责执行存储与更新(真的把 state 存下来、每轮追加、读写记忆);而”保留多少、怎么压缩、何时外置”这些策略loop_engineering.md 定的。一句话:Loop 定策略,Harness 管执行。
  7. 横切能力:日志、追踪(tracing)、token/时间预算控制、限流、审计。

3. Harness Engineering:把这台机器设计好

Harness 好不好,直接决定 Agent 靠不靠谱。工程上重点关注四件事:

3.1 健壮性(Robustness)

  • 工具报错要捕获并喂回模型,而不是让整个 Agent 崩溃(呼应 loop_engineering.md 的错误处理)。
  • 一切外部调用都要有超时 + 有限重试
  • 解析模型输出要能容错:模型偶尔吐出不合法 JSON,要能重试或纠偏。

3.2 可观测性(Observability)

  • 记录每一轮的 thought / action / observation,出问题能回放。
  • LangChain 的 verbose=True、LangSmith、OpenTelemetry tracing 都属于这一层。
  • 没有可观测性的 Agent = 黑盒,线上出问题只能干瞪眼。

3.3 可控性与安全(Control & Safety)

  • 预算护栏:max iterations、token 上限、超时——防跑飞、防烧钱。
  • 权限控制:危险工具(删文件、发钱、改生产)要不要加人工确认(human-in-the-loop)。
  • 可预测性:结构化输出、固定关键步骤——Day 2 的 AI 可预测性会细讲(计划见 ai_predictability.md)。

3.4 上下文效率(Context Efficiency)

  • Harness 决定每轮塞多少历史进去,直接影响成本和效果。
  • 压缩、裁剪、外置记忆都在这层实现——与 Context Engineering 深度耦合。

3.5 控制流 vs 内容决策:谁说了算

一个 Agent 里,“谁做决定”是分工的——工程师用确定性代码管控制流,模型用推理做内容决策。想清这条线,就不会纠结”某个策略到底该我写死还是交给模型”。

决策类型例子归谁为什么
控制流(怎么跑)max 轮数、何时压缩历史、重试几次、超时多久工程师的确定性代码(即”基座/脚手架”,就是 Harness 本身)要稳定、可预测、可控,不能靠模型”看心情”(呼应 AI 可预测性)
内容决策(做什么)调哪个工具、参数填什么、最终答什么模型推理这是模型的强项,也是 Agent 存在的意义
借用模型的执行压缩历史时生成摘要代码触发 + 模型执行”何时压缩”是代码决定,“摘要内容”借模型能力
if count_tokens(state.history) > 8000:      # 控制流:工程师写死(确定性)
    state.history = summarize(state.history)  # 执行:借模型做摘要
action = model.decide(state)                 # 内容决策:交给模型推理

一句话:控制流靠代码,内容决策靠模型。 越要”可预测”,越往代码这边挪。

⚠️ 还有一种更激进的做法叫 agentic memory:给模型一个 write_memory / compress_context 工具,让它自己决定记什么、忘什么——这就把部分控制流也交给了模型推理,更灵活但更不可预测。属于光谱的另一端。

术语澄清:这里说的”工程师的基座/脚手架”指的是系统层面的地基(就是 Harness)。它和”基座模型(foundation model,如 Llama/Qwen base)“是两个不同的”基座”,千万别混——详见 foundation_model.md

4. 自己写 Harness vs 用现成的

方式代表优点代价
手写裸循环纯 Python while完全可控、看得最清楚、学习最佳健壮性/可观测性全得自己造
轻量封装LangChain AgentExecutor快速起步,封装了循环定制受限,黑盒感
图运行时LangGraph复杂流程、分支、多 Agent、可控性强概念多,学习曲线陡
平台内置Coze / Dify零代码,开箱即用灵活性最低(见 agent_dev.md

选型直觉:学习/搞懂原理 → 手写;快速做产品原型 → LangChain/平台;复杂可控的生产系统 → LangGraph 这类图运行时。先手写一遍再用框架,你会秒懂框架在帮你干什么。

5. 常见坑(复习重点)

  • 把 Harness 的责任推给模型 → 指望模型”自己记住""自己别超时”,它做不到,这些是 Harness 的活。
  • 没有可观测性 → Agent 变黑盒,线上问题无法定位。日志/tracing 要从第一天就加。
  • 危险操作没有人工确认 → Agent 自主删库跑路。高风险工具必须加护栏。
  • 过早上重型框架 → 简单任务硬套 LangGraph,被一堆概念淹没。按需选型。
  • 混淆 Loop 和 Harness → Loop 是”规则”,Harness 是”跑规则的机器”;设计时分开想更清楚。

6. 明天实操钩子 🔧

承接 loop_engineering.md 的手写循环,把它”升级成一个 mini Harness”:

  1. 给循环加上结构化日志:每轮打印 [轮次] thought / action / observation
  2. 给工具执行加超时 + try/except 重试,故意让工具抛错,观察 Agent 能否自愈。
  3. 预算护栏:max_iterations 和一个假的 token 计数器,超了就优雅退出。
  4. 做完后,把它换成 LangChain 的 AgentExecutor(verbose=True) 跑同样的任务,对比:你手写的这些,框架是不是都帮你做了?——这就理解了”Harness”这层的价值。

关联概念