Harness Engineering
第1章 Agent 不等于大模型:Harness 的价值
第1章 Agent 不等于大模型:Harness 的价值
1.1 Demo 五分钟,生产五个月
如果你参加过 AI Hackathon,很可能见过这样的场景:一个三人小队用一个周末搭出一个令人惊叹的 AI Agent Demo——它能读代码、调 API、写测试、甚至自动修 bug。评委赞不绝口,观众掌声雷动。
然后这个 Demo 就死了。
不是因为它不够酷,而是因为它无法在真实环境中存活。用户输入一段中文夹英文的需求,它的 prompt 解析崩了;调用一个返回 500 的 API,它陷入了无限重试;用户连续追问几轮,它的上下文窗口爆了;更要命的是,它可能把"清理测试数据"理解成危险写操作——因为没有权限控制、确认流程和回滚边界。
这就是 Agent 工程的核心悖论:大模型的能力已经足够强大,但把这个能力安全、可靠、高效地交付给用户,是一个完全不同的工程问题。
让我用一个简单的对比来说明:
# 这是一个 "Demo 级" Agent —— 30 行代码
import anthropic
client = anthropic.Anthropic()
def simple_agent(user_input: str) -> str:
response = client.messages.create(
model=SELECTED_MODEL,
max_tokens=4096,
messages=[{"role": "user", "content": user_input}]
)
return response.content[0].text
# 它能工作吗?能。它能上生产吗?不能。
这 30 行代码缺少什么?缺少的东西可以列一个长长的清单:
- 工具系统:模型需要调用外部工具(读文件、执行命令、查数据库),但谁来定义工具、校验参数、处理超时?
- 权限控制:模型说"我要删除这个文件",谁来决定它是否有权这样做?
- 上下文管理:对话进行到第 20 轮,token 数量逼近窗口上限,谁来决定裁剪哪些消息?
- 错误恢复:工具调用失败了,是重试、跳过、还是降级处理?
- 流式输出:用户不想等到完整推理结束才看到反馈,怎么实现逐字输出和中间状态提示?
- 可观测性:生产环境中出了问题,怎么知道模型在第几步、因为什么原因做出了错误决策?
- 成本控制:模型陷入循环反复调用工具,谁来设置步数、token 和预算上限?
- 多模态输入:用户传了一张截图,怎么处理?
- 会话持久化:用户关掉浏览器再回来,之前的对话还在吗?
这些"缺少的东西",就是 Harness。
1.2 什么是 Harness Engineering
1.2.1 一个类比:马与马具
"Harness"这个词在英文中的本意是马具——缰绳、鞍座、马镫、笼头的总称。一匹马的奔跑能力再强,没有马具,骑手就无法驾驭它。马具不是马的一部分,但没有马具,马对骑手的价值就无法兑现。
这个类比精确地映射到 AI Agent 的世界:
| 马的世界 | Agent 的世界 |
|---|---|
| 马(原始动力) | 大模型(LLM) |
| 缰绳(方向控制) | Prompt Engineering + 编排逻辑 |
| 鞍座(稳定接口) | 工具系统 + API 抽象 |
| 马镫(安全保障) | 权限模型 + 安全边界 |
| 笼头(约束范围) | 上下文管理 + 输出校验 |
| 马车(承载用途) | 用户界面 + 交互协议 |
| 骑手(使用者) | 终端用户 |
Harness Engineering,就是设计和构建这套"马具"的工程学科。
下面这张图展示了 Harness 在整个 Agent 系统中的位置:
graph TD
User["👤 用户"] -->|输入| Harness
subgraph Harness["Harness 工程层"]
direction TB
PM["提示词管理"] --- TS["工具系统"]
TS --- OE["编排引擎"]
OE --- SP["安全与权限"]
SP --- MC["记忆与上下文"]
MC --- OB["可观测性"]
end
Harness -->|API 调用| LLM["🧠 大模型 (LLM)"]
LLM -->|推理结果| Harness
Harness -->|工具调用| Tools["🔧 外部工具\n文件系统 / Shell / API / DB"]
Tools -->|执行结果| Harness
Harness -->|输出| User
style Harness fill:#f0f4ff,stroke:#3b82f6,stroke-width:2px
style LLM fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
更正式地定义:
Harness Engineering 是指在大模型(LLM)和终端用户之间,设计、实现、优化工程层的方法论。这个工程层负责工具编排、提示词管理、安全控制、上下文管理、状态持久化、可观测性等一系列关键功能,使得大模型的能力能够安全、可靠、高效地交付给用户。
1.2.2 Harness 不是 API Wrapper
很多团队第一次做 Agent,会把 Harness 误解成"给模型 API 包一层函数"。Wrapper 的职责是隐藏调用细节;Harness 的职责是管理一个不确定系统的执行过程。二者差异非常大:
| 维度 | API Wrapper | Harness |
|---|---|---|
| 核心目标 | 简化模型调用 | 管理完整任务执行 |
| 输入输出 | 一次请求、一次响应 | 多轮消息、工具结果、状态变化 |
| 错误处理 | 抛异常或返回错误 | 重试、降级、让模型修正、请求用户介入 |
| 安全边界 | 通常依赖调用方 | 内建权限、沙箱、确认、审计 |
| 状态管理 | 可无状态 | 需要维护会话、计划、环境、记忆 |
| 观测对象 | HTTP 请求 | 决策链路、工具调用、成本、失败原因 |
一个 Wrapper 可以这样写:
async function ask(prompt: string) {
return llm.messages.create({ model: SELECTED_MODEL, messages: [{ role: 'user', content: prompt }] })
}
一个 Harness 至少要回答更多问题:
async function runTask(task: UserTask, session: SessionState) {
const context = await buildContext(task, session)
const plan = await chooseExecutionMode(task, context)
for await (const event of executePlan(plan, context)) {
await auditLog.write(event)
if (event.type === 'tool_call') await enforcePermission(event)
if (event.type === 'failure') await recoverOrEscalate(event)
if (shouldStop(event, context.budget)) break
}
return summarizeOutcome(session)
}
这段伪代码不关心具体模型是哪一个。它关心的是:上下文怎么构造、计划如何执行、工具调用如何授权、失败如何恢复、预算何时耗尽、最终结果如何向用户解释。换句话说,Harness 把"模型回答"提升成"系统完成任务"。
1.2.3 Harness 的六大支柱
一个成熟的 Harness 系统通常包含以下六个核心子系统:
┌──────────────────────────────────────────────┐
│ 用户界面层 │
│ (CLI / Web / IDE / API) │
├──────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 提示词 │ │ 工具系统 │ │ 编排引擎 │ │
│ │ 管理 │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 安全与 │ │ 记忆与 │ │ 可观测 │ │
│ │ 权限 │ │ 上下文 │ │ 性 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Harness Engineering │
├──────────────────────────────────────────────┤
│ 大模型 (LLM) API │
└──────────────────────────────────────────────┘
第一支柱:提示词管理(Prompt Management)
提示词不只是一句"你是一个有帮助的助手"。在生产级 Agent 中,System Prompt 可能长达数万字,包含角色定义、行为规范、工具使用说明、输出格式约束、安全规则等多个维度。提示词管理需要解决版本控制、A/B 测试、动态注入、上下文长度优化等问题。
// Claude Code 的 System Prompt 构建(简化示意)
function buildSystemPrompt(context: AgentContext): string {
return [
getBasePersona(), // 基础人格
getToolDescriptions(context.tools), // 工具描述(根据可用工具动态生成)
getEnvironmentInfo(context.env), // 环境信息(OS、Shell、CWD)
getMemoryContext(context.memory), // 记忆上下文(.claude/CLAUDE.md)
getSafetyRules(context.permissions), // 安全规则
getUserPreferences(context.config), // 用户偏好
].join("\n\n");
}
第二支柱:工具系统(Tool System)
工具系统是 Agent 与外部世界交互的桥梁。一个健壮的工具系统需要处理:工具注册与发现、参数校验(schema validation)、执行超时、错误处理、结果格式化、并发控制。
// 一个生产级工具定义的骨架
interface Tool {
name: string;
description: string;
inputSchema: ZodSchema; // 运行时类型校验
permissions: PermissionRule[];// 权限声明
timeout: number; // 超时限制
execute(input: unknown, context: ToolContext): Promise<ToolResult>;
}
// 工具执行不是简单的函数调用
async function executeTool(tool: Tool, input: unknown, context: ToolContext) {
// 1. 参数校验
const parsed = tool.inputSchema.safeParse(input);
if (!parsed.success) return { error: `Invalid input: ${parsed.error}` };
// 2. 权限检查
const allowed = await checkPermission(tool, parsed.data, context);
if (!allowed) return { error: "Permission denied" };
// 3. 带超时的执行
const result = await Promise.race([
tool.execute(parsed.data, context),
timeout(tool.timeout).then(() => ({ error: "Timeout" }))
]);
// 4. 结果记录(用于可观测性)
context.telemetry.recordToolCall(tool.name, parsed.data, result);
return result;
}
第三支柱:编排引擎(Orchestration Engine)
编排引擎负责 Agent 的核心循环——接收用户输入、调用模型、解析工具调用、执行工具、将结果反馈给模型、判断是否终止。这听起来简单,但实际上涉及大量的工程决策:循环终止条件、并行工具调用、子 Agent 协调、流式输出管理。
# Agent 循环的伪代码
async def agent_loop(user_input: str, context: AgentContext):
messages = context.history + [{"role": "user", "content": user_input}]
for step in range(MAX_STEPS):
# 调用模型
response = await call_model(messages, tools=context.available_tools)
# 检查是否有工具调用
tool_calls = extract_tool_calls(response)
if not tool_calls:
# 模型直接给出了最终回答
yield FinalAnswer(response.text)
return
# 执行所有工具调用(可能并行)
results = await execute_tools_parallel(tool_calls, context)
# 将工具结果追加到消息历史
messages.append(response.to_message())
messages.extend(tool_result_messages(results))
# 上下文窗口管理:如果消息太长,进行裁剪
messages = truncate_if_needed(messages, context.max_tokens)
# 达到最大步数,强制终止
yield Error("Max steps exceeded")
这个循环的核心流程可以用下图表示:
flowchart TD
A["接收用户输入"] --> B["构建消息上下文"]
B --> C["调用 LLM"]
C --> D{"返回工具调用?"}
D -->|是| E["执行工具\n(可能并行)"]
E --> F["将结果追加到消息"]
F --> G{"达到步数上限?"}
G -->|否| C
G -->|是| H["强制终止"]
D -->|否| I["输出最终回答"]
style C fill:#fef3c7,stroke:#f59e0b
style E fill:#dbeafe,stroke:#3b82f6
第四支柱:安全与权限(Safety & Permissions)
这是 Harness 中最容易被低估、也最容易出灾难性事故的部分。安全系统需要回答:哪些工具在什么条件下可以被使用?文件系统的哪些路径可以被读写?哪些操作需要用户确认?如何防止 Prompt Injection?
第五支柱:记忆与上下文(Memory & Context)
短期记忆(当前对话历史)和长期记忆(跨会话持久化的知识)的管理。上下文窗口的裁剪策略、向量数据库的检索、项目级知识的注入(如 Claude Code 的 CLAUDE.md 机制),都属于这个支柱。
第六支柱:可观测性(Observability)
在生产环境中,你需要知道:Agent 执行了多少步?每步花了多长时间?调用了哪些工具?消耗了多少 token?为什么在第 7 步做出了错误决策?这些信息对于调试、优化和合规审计都至关重要。
1.2.4 判断一个系统是否具备 Harness 能力
判断一个 Agent 是否只是 Demo,不要看它能不能在一次演示里完成任务,而要看它在坏情况下怎么表现:
| 问题 | Demo 级表现 | Harness 级表现 |
|---|---|---|
| 工具参数错了 | 报错或继续瞎试 | 返回结构化错误,让模型修正或降级 |
| 用户要求危险操作 | 直接执行或完全拒绝 | 根据权限策略确认、沙箱或阻止 |
| 上下文太长 | 直接超窗 | 摘要、裁剪、检索、分层记忆 |
| 工具超时 | 卡死或无限等待 | 超时、取消、重试上限、替代路径 |
| 结果不确定 | 给出自信答案 | 暴露假设、标记不确定性、请求验证 |
| 成本异常 | 不可见 | 记录 token、步数和工具调用预算 |
| 任务失败 | 只说失败 | 解释失败点、保留可恢复状态 |
这个表也是本书后续章节的路线图。每一类坏情况背后都有一组 Harness 子系统:工具设计、编排循环、上下文工程、权限模型、可观测性、评估测试。生产级 Agent 的差距往往不是"会不会调用模型",而是"坏情况是否被设计过"。
1.3 可观察的 Harness:三个案例
理论总是苍白的,让我们看看几个可观察的 Harness Engineering 形态。
1.3.1 Claude Code:38 万行 TypeScript 的 Harness(本地快照统计)
Claude Code 是 Anthropic 的 AI 编程助手 CLI。它的底层模型通过 API 调用,但用户体验并不只来自模型。本地 ../claude-code-main 快照中,src/ 下所有 .ts 文件合计 379997 行,统计命令是:
find ../claude-code-main/src -name '*.ts' -type f -print0 | xargs -0 wc -l | tail -n 1
这些代码大部分都在做 Harness:命令行 UI、工具定义、权限、API 请求构造、上下文拼装、MCP、子 Agent、沙箱、遥测、错误恢复。
模型本身的代码量?零。因为模型是通过 API 调用的云服务。
这 38 万行代码在做什么?按 src/ 顶层目录重新统计,最大的几个部分如下:
| 子系统 | 实测行数 | 职责 |
|---|---|---|
src/utils/ |
175951 | 占全仓 46%——大量散文件式工具:activityManager / advisor / agentContext / Shell / Cursor / abortController 等数百个 |
src/services/ |
53495 | 后台服务:MCP / analytics / api / SessionMemory / MagicDocs / autoDream / claudeAiLimits 等 |
src/tools/ |
42309 | 25+ 内置工具:BashTool 10894 + PowerShellTool 7829 + AgentTool 4514 + LSPTool 1778 + FileEditTool 1524 + FileReadTool 1418 + 等 |
src/ink/ |
15703 | 终端交互渲染 |
src/hooks/ |
13725 | React hooks(useManageMCPConnections 等) |
src/bridge/ |
12613 | IDE / 外部环境桥接 |
src/cli/ |
11883 | CLI 入口和命令行行为 |
src/commands/ |
9798 | CLI 命令实现 |
src/components/ |
4731 | UI 组件(Ink/React 渲染) |
| 其他目录和顶层文件 | 49984 | 入口、类型、状态、插件、查询引擎等 |
| 合计 | 379997 | — |
这里不需要把每一行都解释成"智能"。恰恰相反,价值在于这些普通工程代码:路径处理、命令解析、权限判断、UI 状态、工具 schema、请求参数、缓存边界、错误信息。Agent 产品越接近生产,越依赖这些不显眼的工程层。
关键洞察是:同一个底层模型,通过不同 Harness 暴露给用户,会形成完全不同的产品能力。模型决定可达到的上限,Harness 决定这个上限能不能被稳定兑现。
1.3.2 LangChain / LangGraph:通用 Harness 框架
如果说 Claude Code 是一个"垂直集成"的 Harness(为特定产品定制),那么 LangChain 和 LangGraph 就是"通用"的 Harness 框架——它们提供构建 Harness 的积木。
LangChain 的核心贡献是建立了一套标准化的抽象:
# LangChain 的 Harness 抽象层
from langchain_core.language_models import BaseChatModel # 模型抽象
from langchain_core.tools import BaseTool # 工具抽象
from langchain_core.prompts import ChatPromptTemplate # 提示词抽象
from langchain_core.output_parsers import BaseOutputParser # 输出解析抽象
from langchain_core.runnables import RunnableSequence # 编排抽象
LangGraph 在此基础上加入了有状态的图执行引擎:
from langgraph.graph import StateGraph, START, END
# 定义状态
class AgentState(TypedDict):
messages: list[BaseMessage]
tool_results: list[dict]
step_count: int
# 构建图
graph = StateGraph(AgentState)
graph.add_node("think", call_model)
graph.add_node("act", execute_tools)
graph.add_edge(START, "think")
graph.add_conditional_edges("think", should_continue, {
"continue": "act",
"end": END,
})
graph.add_edge("act", "think")
# 编译并运行
agent = graph.compile(checkpointer=MemorySaver())
这段代码的每一行都是 Harness,没有一行是模型。模型只是 call_model 节点内部的一个 API 调用。图的定义、状态管理、条件路由、检查点持久化——这些全部是 Harness Engineering 的范畴。
1.3.3 OpenAI Agents SDK:最小化 Harness
OpenAI Agents SDK 代表了另一种 Harness 设计哲学——极简主义:
from agents import Agent, Runner
agent = Agent(
name="assistant",
instructions="你是一个有帮助的助手。",
tools=[web_search, file_reader],
)
result = Runner.run_sync(agent, "帮我搜索最新的 AI 论文")
看起来只有几行代码,但 Runner.run_sync 内部隐藏了一个完整的 Harness:Agent 循环、工具调度、Handoff(Agent 间切换)、Guardrail(安全护栏)、Tracing(追踪)。它的设计选择是"约定优于配置"——大量默认行为被封装在框架内部,开发者只需要声明式地定义 Agent 的行为。
三个案例的对比揭示了一个重要事实:不管外在形态如何不同,Harness 的核心组件是相同的——工具、编排、安全、记忆、可观测性。 差异只在于哪些部分暴露给开发者,哪些部分被封装起来。
graph LR
subgraph CC["Claude Code (垂直集成)"]
CC1["38万行 TS"] --> CC2["深度定制\n每个组件"]
end
subgraph LC["LangChain/LangGraph (通用框架)"]
LC1["标准化抽象"] --> LC2["开发者组装\n自选组件"]
end
subgraph OA["OpenAI Agents SDK (极简)"]
OA1["声明式配置"] --> OA2["约定优于配置\n框架封装"]
end
CC ---|"定制度 高\n灵活度 低"| LC
LC ---|"定制度 中\n灵活度 高"| OA
1.4 为什么是现在
Harness Engineering 并不是一个全新的概念。从某种意义上说,任何在 LLM 和用户之间写代码的人,都在做 Harness Engineering。但为什么近几年它突然成为了一个值得系统化研究的学科?
1.4.1 模型能力已经跨过了"够用"线
在早期通用大模型阶段,模型的能力是主要瓶颈。你可以写出很精巧的 Harness,模型依然会在基本的推理任务上犯错。那个时候,提升模型能力的 ROI 远远高于优化 Harness。
现在,主流模型在代码生成、逻辑推理、工具调用等 Agent 核心能力上已经进入"够用但不完美"的阶段。这里的"够用"不是说模型不会犯错,而是说很多失败已经不再是模型完全无能,而是上下文给错、工具设计差、权限边界不清、错误恢复缺失。
换句话说:瓶颈从模型侧转移到了 Harness 侧。
一个形象的比喻:早期模型还不稳定时,系统上限主要由模型能力决定;当模型具备基本工具调用和推理能力后,系统上限开始被工程层决定。输入是否完整、工具是否可用、失败能否恢复、安全边界是否明确,都会直接影响用户感知。
1.4.2 工具调用成为一等公民
早期的 LLM API 需要开发者自己解析模型输出来提取"函数调用"意图。这种方式不可靠、不规范,导致 Harness 的工具系统需要做大量的容错处理。
随着 Tool Use / Function Calling 变成常见 API 能力,模型可以输出结构化的工具调用请求,Harness 不再需要完全依赖自然语言解析工具意图。这降低了一部分工程复杂度,但同时也提高了标准——用户的期望从"能调工具就行"变成了"调工具要快、要准、要安全"。
1.4.3 Agent 从实验室走向生产
AI Agent 概念从 Demo 走向日常工具和企业流程之后,问题的性质也变了:
- AI 编程 Agent 被开发者日常用于读代码、改代码、跑测试
- Customer Service Agent 开始参与客户工单处理
- Data Analysis Agent 在企业内部分析报表、生成洞察
- Workflow Automation Agent 承担一部分跨系统操作流程
生产环境对可靠性、安全性、可维护性的要求,比 Demo 高出几个数量级。这些要求全部落在 Harness 的肩上。
1.4.4 行业开始标准化
MCP(Model Context Protocol)的出现是一个标志性事件。它试图标准化 Agent 与外部工具/数据源的交互协议——这本质上就是对 Harness 工具系统的标准化尝试。
类似的标准化趋势还包括:
- OpenAI 的 Function Calling 规范 → 工具定义的标准化
- LangChain 的 Runnable 接口 → 编排单元的标准化
- OpenTelemetry for LLM → 可观测性的标准化
当一个领域开始出现标准化努力时,说明它已经从"手工作坊"阶段进入了"工程学科"阶段。Harness Engineering 正处在这个转折点上。
1.5 Harness Engineering 的核心挑战
既然 Harness 如此重要,它的核心工程挑战是什么?我们来逐一分析。
1.5.1 不确定性管理
传统软件的输入输出是确定的:给定相同的输入,函数总是返回相同的输出。但 Agent 的核心组件——LLM——是概率性的。同一个输入,模型可能返回不同的工具调用序列,甚至可能返回完全不同的推理路径。
这意味着 Harness 不能假设模型会"按照预期"行动。它必须:
# 不确定性管理的典型模式
async def robust_tool_call(model_response):
# 1. 校验模型输出的格式
if not is_valid_tool_call(model_response):
# 不是简单报错,而是尝试修复
model_response = await retry_with_clarification(model_response)
# 2. 校验参数的语义合理性
tool_name = model_response.tool_name
if tool_name not in ALLOWED_TOOLS:
return fallback_response("Unknown tool requested")
# 3. 执行时的防御性编程
try:
result = await execute_with_timeout(tool_name, model_response.args)
except ToolExecutionError as e:
# 将错误信息反馈给模型,让它自行修正
return ToolResult(error=str(e), suggestion="Please try a different approach")
# 4. 校验结果的合理性
if is_suspicious_result(result):
return await human_in_the_loop_review(result)
return result
1.5.2 安全边界的划定
Agent 能力越强,安全风险越大。一个能够执行 Shell 命令的 Agent,本质上拥有了操作系统级别的能力。Harness 需要在"有用"和"安全"之间找到平衡:
- 太严格 → Agent 什么都做不了,用户放弃使用
- 太宽松 → Agent 一个错误决策,可能造成不可逆的损失
Claude Code 的权限模型提供了一个可借鉴方向:将操作分成允许、需确认、禁止等不同等级,并支持用户通过配置文件自定义规则。这种"分级授权 + 用户可配置"的模式,比简单的全允许或全拒绝更适合生产 Agent。
1.5.3 上下文窗口的经济学
大模型的上下文窗口虽然在持续扩大,但窗口越大,通常成本越高、延迟越大。Harness 需要做"上下文经济学"的决策:
- 哪些信息值得放进上下文?(相关的代码文件 vs 无关的日志)
- 什么时候该裁剪历史消息?(保留最近对话 vs 摘要式压缩)
- 如何在工具结果太长时进行截断?(保留关键错误 vs 摘要冗长输出)
这些决策直接影响 Agent 的质量、速度和成本,是 Harness 工程中最需要精心调优的部分之一。
1.5.4 状态管理的复杂性
一个生产级 Agent 需要管理多层状态:
对话状态 ← 当前会话的消息历史
工具状态 ← 工具执行的中间结果、文件句柄、数据库连接
Agent 状态 ← 当前在执行计划的第几步、已完成的子任务
用户状态 ← 用户的偏好设置、历史行为、权限级别
环境状态 ← 当前工作目录、Git 分支、运行时环境
这些状态之间有复杂的依赖关系。例如,工具执行的结果会改变环境状态(写了一个文件),环境状态的变化会影响后续工具调用的行为(文件已存在,不需要再创建)。LangGraph 把这个问题抽象为"有状态图",是目前处理 Agent 状态管理最系统化的方法之一。
1.5.5 可迁移性的设计
Harness 的另一个难点是可迁移性。很多 Agent Demo 能在作者自己的电脑上运行,是因为它隐含依赖了一整套环境假设:固定 shell、固定目录结构、固定包管理器、固定权限、固定 API key。真正的 Harness 不能把这些假设藏在代码里,而要把它们变成可检测、可配置、可失败恢复的系统能力。
可迁移性可以拆成四层:
| 层级 | 需要回答的问题 | 典型设计 |
|---|---|---|
| 环境迁移 | 机器、系统、shell 变了还能跑吗 | 启动时探测能力,按平台选择命令 |
| 项目迁移 | 从 Node 项目换到 Rust 项目怎么办 | 根据项目标识文件加载不同规则 |
| 组织迁移 | 不同团队权限和流程不同怎么办 | 配置化权限、项目级记忆、团队 skill |
| 模型迁移 | 换模型供应商是否要重写 Agent | 隔离模型适配层,保留工具和状态协议 |
这也是为什么 Harness Engineering 不应该和某个模型 API 绑定太死。模型会变,供应商接口会变,工具和权限边界也会变;真正值得沉淀的是任务循环、上下文协议、工具契约、错误恢复和可观测性这些可迁移结构。
1.6 本书会教什么,不会教什么
1.6.1 本书的定位
这本书是关于 Harness Engineering 方法论 的书。它关注的是"如何构建从模型到用户之间的工程层"这个普适性问题,而不是某个特定框架的使用教程。
本书会教:
- Harness 各子系统(工具、编排、安全、记忆、可观测性)的设计原则和权衡取舍
- 来自真实项目(Claude Code、LangGraph、OpenClaw 等)的架构模式和实现细节
- 可以直接迁移到你自己项目中的工程模式——不管你用什么语言、什么框架
- 如何评估和选择 Harness 架构方案
- 生产环境中的常见陷阱和最佳实践
本书不会教:
- 大模型的训练和微调(那是模型工程的范畴)
- 某个特定框架的入门教程(官方文档做这件事比我好)
- Prompt Engineering 的技巧大全(这个领域变化太快,任何书籍都会迅速过时)
- 特定业务场景的完整解决方案(但会提供可组合的构建模块)
1.6.2 本书的读者
这本书适合以下读者:
- 正在构建 AI Agent 产品的工程师:你已经会调模型 API,现在需要把 Demo 变成生产级系统
- 技术负责人和架构师:你需要评估和选择 Agent 架构方案,或者需要设计内部的 Agent 平台
- 对 AI Agent 内部机制好奇的开发者:你用过 Claude Code、LangGraph、Dify 等工具,想理解它们内部是怎么工作的
1.6.3 本书的结构
本书共 21 章,按八篇递进组织,每一篇对应 Harness 的一组关联子系统:
- 开篇(ch01):本章——Harness 价值与基本论证
- 架构基础(ch02-04):核心架构模式、Agent 循环、上下文工程
- 工具工程(ch05-07):工具设计哲学、编排、错误恢复
- 提示词架构(ch08-10):System Prompt 分层、指令优先级、Prompting 策略
- 状态与记忆(ch11-13):短期记忆、长期记忆、会话状态机
- 安全与权限(ch14-15):权限模型、沙箱与隔离
- 协调(ch16-17):多 Agent 协调、Human-in-the-Loop
- 生产化(ch18-21):评估测试、可观测性、成本性能、设计模式总结
每一章的组织遵循 "为什么 → 是什么 → 怎么做 → 可迁移模式" 的递进结构。
1.7 小结
回到本章开头的问题:为什么拥有一个强大的大模型远远不够?
因为大模型只是一个概率推理引擎。它不知道你的文件系统长什么样,不知道你的 API 需要什么认证,不知道哪些操作是危险的,不知道你的对话历史有多长,不知道用户等了多久。把这个"不知道"变成"知道",把"不安全"变成"安全",把"不可靠"变成"可靠"——这就是 Harness Engineering 的使命。
在接下来的章节中,我们将逐一深入 Harness 的每个子系统,从原理到实现,从理论到生产实践。
让我们从 Agent 的心脏开始——编排循环。