核心摘要
Agent Harness 架构协调身份、状态、模型调用、受策略约束的工具、预算、审批、可观测事件和恢复流程。它可以限制特定副作用,却不能让模型输出天然可信,也不能替代下游服务内部的授权。
📋 目录
✨ 核心要点
- 关注点分离:LLM 是"大脑",而 Harness 是与物理世界交互的"躯干"。
- 状态管理至关重要:Harness 不仅管理短期的对话上下文,还要维护长期的任务执行状态。
- Tool 中介:Harness 在分发前校验模型提出的代码、API 调用和外部动作,并执行策略。
- 纵深防御:生产设计组合预算、审批、隔离、下游授权、可观测性和事件响应。
架构范围
本文以 Agent Harness 术语定义为基础,只讨论组件职责与数据流。Harness 并不是“模型之外的全部代码”:Model Gateway、业务服务、身份系统、数据库、队列和 UI 仍是具有明确契约的独立系统。
可以把 LLM 想象成一位只能通过电话提供建议的顾问:它能回答问题,却不能直接执行外部操作。Agent Harness 架构为模型接入经过控制的工具和数据,并规定每项操作必须遵守的权限与流程。
不存在单一的标准化 Harness 产品。团队可以组合应用代码、队列、状态机、策略引擎、工作流库和隔离执行进程来实现这种架构。
📝 术语链接: AI Agent (人工智能代理) — 了解更多关于由 LLM 驱动的自主系统。
Agent Harness 的工作原理
在最底层,Harness 充当着一个持续运行的 while 循环,精心编排着用户、LLM 和外部工具之间的交互。
原始 API 调用 vs Agent Harness
| 特性 | 原始大模型 API 调用 | Agent Harness |
|---|---|---|
| 记忆与上下文 | 无状态(每次必须传入完整上下文) | 自动管理对话历史和执行变量 |
| 外部动作 | 返回文本或结构化提案 | 校验、授权、分发并记录已批准的副作用 |
| 错误恢复 | 调用方负责处理 | 对故障分类,执行有限重试、补偿、升级处理或停止策略 |
| 执行模式 | 单轮对话(一问一答) | 带有安全限制的多轮自主循环 |
Harness 工具的核心组件
要理解 the anatomy of an agent harness,可以把它拆成以下几个主要子系统:
- 身份与策略上下文:解析调用主体、租户、用途、资源范围和审批要求。
- 状态管理器:把带版本的工作流状态与临时模型上下文、可选的长期记忆分开。
- 工具注册表与适配器:发布用途明确的 Schema、校验参数含义,并根据执行策略把模型提议映射为服务调用。
- 执行边界:使用权限受限的凭据、网络与文件策略、配额、取消机制和结果限制来执行已批准的任务。
- 预算与审批控制器:在模型外执行限制,并为高影响副作用等待持久审批。
- 事件与恢复层:记录脱敏后的可观测事件、检查已提交的副作用,并处理重试、结果未知或补偿。
Agent Harness 实战指南
场景 1: 在 Node.js 中构建一个极简的 Harness
下面是一个使用 OpenAI SDK 的示意循环,展示 allowlist 和基础参数校验;它省略了认证、持久状态、超时/取消、幂等、结果限制、脱敏和审批,不能直接作为生产执行器。
import OpenAI from "openai";
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// 1. 工具注册表
const tools = {
getWeather: async ({ location }) => {
// 模拟 API 调用
return `${location} 的天气是 22°C,晴朗。`;
}
};
const toolDefinitions = [{
type: "function",
function: {
name: "getWeather",
description: "获取指定位置的当前天气",
parameters: {
type: "object",
properties: { location: { type: "string" } },
required: ["location"],
},
},
}];
// 2. Harness 核心循环
async function runAgentHarness(userPrompt) {
let messages = [{ role: "user", content: userPrompt }];
let isDone = false;
let maxSteps = 5; // 核心安全约束
while (!isDone && maxSteps > 0) {
maxSteps--;
// 调用 LLM("大脑")
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: messages,
tools: toolDefinitions,
});
const responseMessage = response.choices[0].message;
messages.push(responseMessage);
// 3. 执行引擎
if (responseMessage.tool_calls) {
for (const toolCall of responseMessage.tool_calls) {
const tool = tools[toolCall.function.name];
if (!tool) throw new Error("unsupported_tool");
const args = JSON.parse(toolCall.function.arguments);
if (
typeof args?.location !== "string" ||
args.location.length < 1 ||
args.location.length > 100
) {
throw new Error("invalid_tool_arguments");
}
const result = await tool(args);
// 将状态和结果反馈给 LLM
messages.push({
role: "tool",
tool_call_id: toolCall.id,
name: toolCall.function.name,
content: result,
});
}
} else {
isDone = true;
return responseMessage.content;
}
}
if (maxSteps === 0) throw new Error("Agent 达到最大执行步数限制(无限循环保护触发)");
return messages[messages.length - 1].content;
}
// 启动 Harness
const finalOutput = await runAgentHarness("旧金山的天气怎么样?");
console.log(finalOutput);
// 预期输出: "旧金山目前的当前天气是 22°C,晴朗。"
场景 2: 使用 LangGraph 构建 Python Harness
对于复杂系统,LangGraph 等工作流库可以表达状态转换。它只是组件选择之一,并不自动提供授权、隔离或安全保证。
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
# 1. 定义状态
class AgentState(TypedDict):
messages: list
scratchpad: str
# 2. 定义 Harness 节点
def call_model(state: AgentState):
llm = ChatOpenAI(model="gpt-4o")
response = llm.invoke(state["messages"])
return {"messages": state["messages"] + [response]}
def should_continue(state: AgentState):
last_message = state["messages"][-1]
if "tool_calls" in last_message.additional_kwargs:
return "execute_tools"
return END
# 3. 构建 Harness 图
workflow = StateGraph(AgentState)
workflow.add_node("agent", call_model)
# ... 此处添加工具执行节点 ...
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue)
# 编译 Harness 运行环境
app = workflow.compile()
高级 Harness 架构技术
1. 人在回路(Human-in-the-Loop, HITL)
生产级的 Harness 极少允许 Agent 自主执行具有破坏性的操作(如删除生产数据库)。高级的 Harness 工具会实现 HITL 暂停机制,冻结状态机,直到人类管理员点击"批准"。
2. 上下文窗口管理(Context Window Management)
随着 while 循环的推进,消息历史会迅速膨胀。Harness 必须实现自动摘要策略或滑动窗口机制,以防止请求超出 LLM 的最大 Token 限制。
3. 沙盒执行环境(Sandboxed Execution)
如果 Agent 需要编写并执行代码(例如运行 Python 数据分析脚本),Harness 必须将该代码放入安全的、隔离的 Docker 容器或 WebAssembly 沙盒中执行,以防止对宿主机系统造成恶意破坏。
最佳实践
- 始终实现步数限制 — LLM 很容易陷入"尝试调用工具 -> 失败 -> 再次尝试相同工具"的无限循环中。在 Harness 中硬编码最大迭代次数是第一准则。
- 分类错误恢复 — 只有确认重试安全时,才向模型返回内容受限且已脱敏的错误。不要在堆栈中暴露密钥,也不要在未确认执行结果时重试非幂等操作。
- 严格的 JSON 校验 — 不要假设 LLM 总能输出合法 JSON。在执行工具前,必须通过校验层(如 Zod 或 Pydantic)验证数据。
- 按需记录可观测事件 — 按照脱敏和保留策略记录提案、策略决定、调用、结果、状态、审批、时间信息与已提交的副作用;不要把隐藏思维链当作审计日志。
⚠️ 常见错误:
- 将未经校验的 LLM 原始输出直接传入
eval()或 SQL 查询中 → 必须使用参数化输入和沙盒环境。 - 无限期地存储整个对话历史 → 实现滑动上下文窗口或对旧消息进行摘要。
常见问题 (FAQ)
Q1: LangChain 和 Agent Harness 有什么区别?
LangChain 是一个宽泛的框架,包含了许多处理 LLM 的实用工具。而 Agent Harness 是一种特定的架构模式(可以使用 LangGraph 或 LangChain 来构建),它完全专注于自主 Agent 的执行循环、状态管理和工具路由。
Q2: 如何防止我的 Agent 在调用工具时产生幻觉?
你的 Harness 工具应当强制执行严格的 JSON Schema。如果 LLM 请求了一个不存在的工具,或者提供了无效的参数,Harness 应该捕获该错误并注入一条系统消息,提示 LLM 纠正其输出,而不是直接让整个程序崩溃。
Q3: 构建 Harness 最好的编程语言是什么?
不存在通用最佳语言。应按身份库、并发模型、策略集成、持久状态、遥测、隔离接口和运维归属选择;Python、TypeScript、Go、Java 等生态都能实现该模式。
Q4: 如何测试 Agent Harness 的架构?
使用确定性的、能返回可预测数据的 Mock 工具。通过确保 Harness 能够正确地将 Mock 数据路由回 LLM,并在目标达成时成功终止循环,来评估 Harness 的可靠性。
总结
Agent Harness 架构把模型提案转换为明确受控的状态转换与副作用。可靠性来自身份、策略、Tool、状态、预算、证据和恢复之间可强制执行的契约,不来自框架名称或模型自我批评能力。
相关资源
- JSON Schema 验证完全指南 — 学习如何验证 Agent 的工具参数
- 代码格式化工具完全指南 — 格式化 Agent 输出的代码
- AI Agent (人工智能代理) 术语 — 什么是 AI Agent?
- LLM (大语言模型) 术语 — 深入理解大语言模型