Skip to content
Neo's Blog
Go back

生产级 AI Agent 的驭手工程:控制面与上下文战场

模型是引擎,但谁来开车?

大语言模型的能力在过去两年以令人窒息的速度增长。GPT-4o 的上下文窗口开到 128K,Claude 3.5 把 Agent 循环做到了原生支持,各家模型在 benchmark 上轮番刷榜—很容易让人觉得”模型这么强了,直接给它一个 prompt 不就够了?”

但任何一个把 Agent 从 Demo 推到生产的人都会告诉你同一个教训:模型的智商不是瓶颈,控制才是。

这就是 Harness Engineering(驭手工程)要解决的问题。它的定位很清楚:不训模型,只造底盘。模型是引擎,Harness 是底盘、转向和刹车—马力再大没有后者的车,没人敢开。


驭手工程:LLM 周围的七个模块

Harness Engineering 的本质是为 LLM 构建一套控制面(control plane)和运行时基础设施(runtime infrastructure)。把它想象成操作系统的内核—管理资源、调度任务、处理异常、记录日志—只不过这次,被管理的资源是大模型的推理能力

整个控制面可以拆成七个模块:

graph TD
    APP[Application 业务逻辑]
    RT[Agent Runtime 执行循环]
    TOOL[Tool Integration 工具沙箱]
    CTX[Context Window 窗口管理]
    SAFE[Safety Guardrails 安全护栏]
    ERR[Error Handling 错误恢复]
    OBS[Observability 可观测性]
    PROVIDER[Provider Abstraction 模型抽象]

    APP --> RT
    RT --> CTX
    RT --> TOOL
    RT --> SAFE
    RT --> ERR
    RT --> PROVIDER
    OBS -.-> RT
    OBS -.-> CTX
    OBS -.-> TOOL
模块职责
Agent Runtime / Orchestration执行循环(ReAct loop)、多 Agent 编排、Human-in-the-loop
Tool Integration & Sandboxing工具注册、安全执行沙箱、结果格式化
Context Window Management窗口内容组装、对话压缩策略、记忆检索注入
Safety Guardrails输入/输出审查、工具调用拦截、内容安全检测
Error Handling & Recovery重试与退避、降级策略、自愈循环、checkpoint 恢复
Observability全链路 Tracing、Metrics 采集、Cost Tracking
Provider Abstraction统一模型接口、动态路由、fallback chain

这七个模块中,大多数已经相对成熟:编排和工具集成有 LangGraph、AutoGen 这些框架兜底;观测和 Provider 抽象也有 OpenAI SDK 和 LangSmith。但上下文窗口管理,是七模块中最硬核、最不成熟、也最直接影响产品体验的一个。

为什么它这么难?因为你要对抗的不是代码 bug,而是物理定律—自注意力的 O(n²) 复杂度。


上下文战场:三个不可逾越的硬约束

在开始讨论”怎么管上下文”之前,先搞清楚我们在对抗什么。上下文窗口有三个硬约束,是数学和物理决定的,不是工程能绕开的:

约束一:窗口大小是固定的。 即使今天有 1M token 的窗口,它也是有限的。而且更大的窗口意味着更贵的推理—模型不是”免费上下文”,你要为每一寸窗口付费。

约束二:注意力随位置衰减。 这不是模型设计的问题,而是自注意力机制的内在特性—中间地带的 token 天然比开头(首因效应)和结尾(近因效应)获得更少的注意力。这就是著名的 Lost-in-the-Middle 现象:你把关键信息放在对话中途,模型可能根本”看不见”它。

约束三:成本是 O(n²)。 自注意力计算的复杂度与 token 数的平方成正比。这意味着,一个 8K token 的窗口和 128K token 的窗口,不算模型能力的差异,光是物理成本就是天壤之别:

窗口大小      单次推理成本 (est.)      100 轮对话累积
8K            ~$0.10                   ~$10
32K           ~$0.40                   ~$40
128K          ~$1.60                   ~$160
1M            ~$12.00                  ~$1200

所以上下文管理不只是讨好模型—它的核心驱动力是成本控制。 省下来的每一寸窗口都是真金白银。


窗口组装:把窗口当成战略地图

理解了约束之后,核心问题就变成了:有限的窗口里,应该放什么?

答案是分层组装,让最重要信息出现在注意力最强的地方。一个典型的上下文组装结构:

┌──────────────────────────────┐
│  System Prompt        (5-15%)│  ← 固定不变:角色定义、安全规则、工具描述
│  Long-term Memory    (10-30%)│  ← 动态:按需从 Memory Store 检索相关记忆
│  Working Context     (10-20%)│  ← 当前任务描述和约束
│  Conversation History(30-60%)│  ← 最需要管理的部分,消耗最多窗口
│  Retrieved Knowledge  (变动大)│  ← RAG 素材,按需注入
│  Tool Results         (变动大)│  ← 当前轮的工具返回
└──────────────────────────────┘

核心原则:把窗口当成战略地图来布局,让最重要信息出现在注意力最强的地方(开头和结尾),而非机械按时间排列。


三大压缩策略与它们的代价

对话历史压缩有三种经典策略,每一种都是 trade-off:

策略做法优点代价
Sliding Window只保留最近 K 轮,老的全丢弃极简、可预测丢失所有关键上下文
Summarization用 LLM 把老对话生成摘要保留语义有信息损失 + 额外推理成本
Structured Memory提取为结构化条目存外部存储,按需检索信息保真度最高实现复杂、检索有噪声

实际生产中没有人用单一策略。最佳实践是混合方案: 近 5 轮保持原文 + 5-20 轮保持摘要 + 20 轮以上进入 memory store。


结构化提取:Agent 不需要摘要,它需要决策记录

一个在 Agent 场景下被严重低估的工程实践:结构化提取优于自然语言摘要。

Agent 在多轮对话中真正需要的不是”讨论了什么”,而是”决定了什么”和”知道了什么”:

{
    "decisions_made": ["使用 PostgreSQL 作为主数据库", "API 端口定为 8080"],
    "facts_learned": ["用户名是 neo", "项目路径 /workspace/app"],
    "pending_tasks": ["需要完成登录模块", "还没测边缘 case"]
}

每轮对话结束时更新这份结构化记录,下一轮对话的 system prompt 直接注入 key facts—Agent 不需要”理解”对话历史,它只需要拿到确定的事实。


回看全图:为什么上下文工程是护城河?

回到驭手工程的七模块。工具集成有 MCP 做标准化,编排有 LangGraph/ReAct 做兜底,观测有 OpenTelemetry 做支持—这些模块都有社区力量在推动。

但上下文管理几乎没有通用方案。 因为每个 Agent 的对话模式、信息密度、成本容忍度都不同。这就是为什么上下文工程是 Harness 七模块中最有护城河价值的一个。

好的上下文管理,让 Agent 从 Demo 级(跑 3 轮就崩)进化到 Production 级(稳定跑 300 轮)。而差的上下文管理,让你在 128K 的窗口里浪费 90% 的空间。

所以下一次你在设计 Agent 时,不要先想”用什么框架”—先想:我的窗口里放什么、放弃什么、以及谁来为此付费。