技术记录
什么是 Agent Harness
很多人第一次动手做 Agent,心里想的是"接个 API、prompt 写长一点"就完事了。等真做起来才发现,最磨人的从来不是调模型——而是周边那一堆事:怎么让它循环起来、怎么调外部工具、怎么记住上下文、怎么在它乱来的时候拦得住。
把这些零碎又关键的东西收拢到一起,就是 Agent Harness。这篇文章想把这件事讲透:它到底是什么、为什么你需要它、里面有哪些部件,以及最容易栽进去的坑。
调一次 API 不难,难的是把模型变成能循环、能调工具、还拦得住的系统。
它到底是什么
Agent Harness 是裹在 LLM 外面、负责让模型真正"跑任务"的那层代码。模型负责出思考,harness 负责把思考落地、管住、盯牢。
区别很实际:裸调一次 LLM,你拿到的是一段文本。套上 harness 之后,你拿到的是一连串"思考 → 动手 → 看结果 → 再思考"跑完之后的产物。它能查网页、跑代码、读文件,记得上一轮说了什么,也知道什么时候该停。
打个不一定恰当但好记的比方:LLM 像发动机,harness 像底盘、变速箱和刹车。光有发动机跑不起来,也刹不住。
为什么不能只调 API
模型本身干的事很简单——给一段 prompt,吐一串 token。要变成能办事的 Agent,下面这些它自己不管,你得补:
- 循环:多数任务不是一步到位,得反复"生成—执行—看结果—再生成"。
- 工具:让它真正去动外面的世界,查库、发请求、跑脚本。
- 记忆:跨步骤、跨会话地记住上下文和事实。
- 控制流:什么时候分支、重试、并行、把活派给子 Agent。
- 护栏:限权限、拦危险操作、给预算设上限。
- 兜底:出错能重试,过程能复盘,结果能量化评估。
这些东西单看都不难,凑一起很碎,而且哪一处没接好整套就崩。harness 就是把它们收拢的地方。
拆开来看,它由什么组成
┌─────────────────────────────────────────────────────────────┐
│ AGENT HARNESS │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Planner │──▶│ Orchestration│──▶│ LLM Core │ │
│ │ /Controller│ │ Loop │◀──│ │
│ └──────────┘ └──────┬───────┘ └──────────────────┘ │
│ │ │
│ ┌────────────┼────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Tools │ │ Memory │ │ Context │ │
│ │ Execution│ │(short/ │ │ Builder │ │
│ │ (Sandbox)│ │ long/ │ │ (assemble │ │
│ └──────────┘ │ work) │ │ prompt) │ │
│ └──────────┘ └──────────────┘ │
│ ▲ ▲ ▲ │
│ ┌────────┴────────────┴────────────┴───────────┐ │
│ │ Safety / Guardrails · Observability · State │ │
│ └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
名词比较多,都是用于 Agent Harness 的:
- 模型接口(LLM Core):统一接不同模型,管流式输出和工具调用格式。
- 上下文装配(Context Builder):把系统提示、记忆、工具说明、眼前观察到的事拼成喂给模型的 prompt。窗口不够时还得摘要、裁剪、按需检索。
- 记忆(Memory):本轮的对话上下文、当前任务状态、跨会话长期知识(常配合向量检索)。
- 工具执行(Tools):一份工具注册表加一个执行器,负责沙箱、权限、超时、把结果写回去。
- 编排循环(Loop):把"模型出主意 → 解析动作 → 执行 → 观察 → 再喂回去"串成环。
- 决策(Planner):下一步是直接干、先列计划、还是甩给子 Agent,甚至干脆停。
- 护栏(Guardrails):权限、人工确认、内容校验、预算熔断。
- 可观测(Observability):每步留痕、结构化日志、能回放。
- 状态持久化(State):把运行态存下来,断了能续。
一次任务实际长什么样
收到目标 → 装配初始上下文 → 进循环:
a. 调模型,得到"我打算这么干"。
b. 要调工具的话,先过护栏;通过就在沙箱里跑,抓结果和异常。
c. 把看到的结果写回记忆。
d. 检查该不该停(目标达成 / 步数或预算超了 / 错太多次)。
e. 没停就回到 a。
难点不在"能跑一遍",而在它能可靠地停下、被看见、能恢复。
需要决断的点
- 决策方式:ReAct(边想边干)灵活但容易跑偏;Plan-and-Execute(先规划再执行)更稳,适合长任务。
- 结构:单 Agent 简单;多 Agent 能把复杂任务拆开,但调试是噩梦。
- 工具调用:让模型随心调最通用,用状态机约束最可控、最好验证。
- 上下文:全量拼进去省事但会爆窗口;检索/摘要后注入更省,代价是可能漏关键信息。
- 停止信号:让模型自己说"我好了"最自然,但容易停不下来;写死终止条件更可靠。
这些问题都没有标准答案,最终落地主要看任务长短和风险高低。
安全问题
安全问题就是 harness 的核心部分,决定了 Agent 的能力边界,大模型还在进化中,思考能力越来越强。就拿现阶段的 GPT 5.6 sol 来说,思考起来非常的厉害,这时候就需要 harness 来控制边界,防止出现不可挽回的损失。
重点关注一下几点:
- 最小权限:工具默认啥也不能干,要一个批一个。文件、网络、命令分级。
- 沙箱:代码和命令在隔离环境跑,文件系统、网络出口都收着。
- 人工确认:删库、发消息、动钱这类高危动作,先停一下等人点确认。
- 预算熔断:最大步数、最大 token、最大花费,超了立刻停。
- 输出校验:模型吐出来的东西过一遍 schema 和结构检查,再过滤有害内容。
- 可撤销:关键操作留回滚,别搞成不可逆的破坏。
一个能调删库命令却没有护栏的 Agent,跟你把服务器 root 密码贴在工位上差不多。
观测能力
没可观测性的 harness,出事只能靠"在我机器上是好的"玄学排错。所以好的 harness 一定是能记录和看懂过程和结果的。重点关注一下几点:
- Trace:每次"prompt → 输出 → 调了啥工具 → 结果"存成结构化记录,整条链能回放。
- Replay:固定随机种子、用 mock 工具替掉真实调用,复现失败现场。
- Eval:拿数据集加评分器,看任务成功率、步数效率、护栏命中率。
- Dashboard:实时看 token 消耗、步数、工具调用分布。
想自己写一个?先看看最小骨架
如果上面这些听着不抽象,下面这段 Python 伪代码应该一眼能懂。它把核心循环讲清楚了:
```csharp
public class AgentHarness
{
private readonly ILlm _llm;
private readonly IToolRegistry _tools;
private readonly IMemory _memory;
private readonly IGuardrails _guardrails;
private readonly int _maxSteps;
public AgentHarness(ILlm llm, IToolRegistry tools, IMemory memory,
IGuardrails guardrails, int maxSteps = 20)
{
_llm = llm;
_tools = tools;
_memory = memory;
_guardrails = guardrails;
_maxSteps = maxSteps;
}
public string Run(string goal)
{
var ctx = _memory.BuildContext(goal, _tools.Describe());
for (var step = 0; step < _maxSteps; step++)
{
var output = _llm.Generate(ctx); // 模型出主意
var action = ParseAction(output); // 解析动作
if (action.IsFinal)
return action.Result;
var observation = _guardrails.Allow(action)
? _tools.Execute(action) // 沙箱执行
: "操作被拒绝";
_memory.Observe(observation); // 写回记忆
ctx = _memory.RefreshContext(); // 重装上下文
}
return _memory.Fallback();
}
}
真上生产,这套还得加流式、重试、并行工具、子 Agent 委派、eval 钩子和持久化。换句话说,上面这段只是骨架,离能扛流量的系统还差得远——但它足够让你明白 harness 到底在转什么。
推荐 .NET 和 Python 框架
.NET 生态
- Semantic Kernel:微软官方 SDK,把 LLM、插件(也就是工具)、记忆、规划器编进 .NET / Python 应用。抽象稳、文档全,是 C# 团队落 Agent 的首选起点。
- AutoGen.NET:AutoGen 的 .NET 实现,主打多 Agent 协作和事件驱动编排,和 Python 版思路一致。
- Microsoft.Extensions.AI:.NET 9 起的一层统一抽象,把模型、嵌入、工具调用接口标准化,方便在不同提供商之间切换。
- Kernel Memory:专注 RAG 和长期记忆的 .NET 库,做知识库型 Agent 时和 Semantic Kernel 搭配很顺手。
Python 生态
- LangChain:啥都能接,生态大,适合快速出原型。抽象层多,出问题有点难追。
- LangGraph:把流程画成有状态的图,控制流想怎么定就怎么定,复杂 Agent 首选。
- LlamaIndex:以检索(RAG)为核心,做知识库、文档问答型 Agent 顺手。
- AutoGen / CrewAI:主打多 Agent 互相搭话、分工协作。
大部分团队,一开始别直接自研。Python 侧用 LangGraph 或 AutoGen,.NET 侧直接上 Semantic Kernel,都能省一大堆脚手架。真要自研,通常是因为合规、审计或延迟的要求框架满足不了。
无论走哪条路,有两件事别指望框架默认就帮你做好:安全和可观测。框架给你的是能力,接不接、接多严,是你自己的事。我的习惯是从第一天就把这两块接上,而不是等第一次事故之后再补——那时候代价往往已经付过了。
写在最后
Agent Harness 要解决的,说到底就一件事:别指望模型自己"负责任地跑完"。你需要一层框架,把那股智能之力套进能约束、能看见、能恢复的轨道上。
它不会让模型变得更聪明,但能让聪明的模型变得能上线、能信任。组件记九块:模型、上下文、记忆、工具、循环、决策、护栏、可观测、状态。其中护栏和可观测,请当重点对待——这不是锦上添花,是能不能放心让它跑的前提。
如果你也正打算搭一套,可以发邮件和我交流:scung@qq.com