这是「从零搭建 Agent」系列的第一篇。本系列的目标是像拼积木一样,以 Agent Loop 为核心,逐步添加模块,最终拼装出一套完善的 Agent 系统。第一篇专注理论:搞清楚 Agent 是什么、由哪些模块构成、以及 Harness 在其中扮演什么角色。
# 什么是 Agent?
一个 Agent,本质上是一个在环境中持续行动、以完成目标为导向的自主系统。与单次问答的 LLM 调用不同,Agent 的核心特征是目标导向 **(Goal-Oriented)**:它会反复感知环境、做出决策、执行动作,直到目标达成或任务终止。
这个循环就是 Agent Loop(你也可以叫他 REPL、reAct,实际都是一个东西),也是整个系统的心脏。所有其他模块,都是围绕这个循环展开的。
# Harness 到底在干什么?
一个最小化的 Agent Loop 只有三步:
感知(Observe)→ 思考(Think)→ 行动(Act)
每一轮循环,Agent 接收来自环境的观测(工具返回值、用户消息、错误信息),交给模型进行推理,然后输出下一步动作(调用工具、回复用户、或终止任务)。动作的结果再次成为下一轮的观测,循环往复。
这个结构极其简单,但它是一切复杂能力的基础。后续所有模块的添加,都是在这个循环的某个节点上插入新的处理逻辑,而不是替换它。
# Agent 需要哪些模块?
从最小可运行的 Agent 出发,按照复杂度递增的顺序,一个完善的 Agent 系统需要以下模块:
| 模块 | 核心职责 | 没有它会怎样 | 所属层次 |
|---|---|---|---|
| Agent Loop | 驱动感知→思考→行动的循环 | 系统无法运转 | 核心 |
| 模型调用层(LLM Client) | 封装对 LLM API 的调用,处理流式输出、重试、超时 | 无法与模型通信 | 核心 |
| 工具系统(Tool System) | 定义、注册、调用工具;解析模型的工具调用请求;返回结构化结果 | Agent 只能输出文字,无法操作外部世界 | 核心 |
| 上下文管理器(Context Manager) | 组织和维护每一轮送入模型的 Prompt;管理 Token 预算 | 模型看到的信息混乱,推理质量不稳定 | Harness |
| 记忆系统(Memory System) | 分层存储短期 / 中期 / 长期记忆;按需调入上下文 | Agent 无法跨轮次保持连贯,长任务必然失败 | Harness |
| 规划模块(Planner) | 将复杂目标分解为可执行的子任务;维护任务树和进度状态 | Agent 只能处理单步任务,无法完成需要多步推理的复杂目标 | Harness |
| 反思模块(Reflector) | 监控执行结果;检测失败模式;在死循环或连续错误时介入 | Agent 会在错误中反复打转,无法自我纠正 | Harness |
| 缓存管理器(Cache Manager) | 维护 Prompt 前缀的稳定性;最大化 KV Cache 命中率 | 每次调用都是全量 Token 计费,长任务成本极高 | 成本层 |
| 安全与权限层(Safety Layer) | 拦截危险操作;限制工具调用范围;实现人机确认(Human-in-the-loop) | Agent 可能执行不可逆的破坏性操作 | 治理层 |
| 可观测性模块(Observability) | 记录每一轮的输入输出、工具调用、Token 消耗;支持调试和回放 | 出现问题时无从排查,系统是黑盒 | 治理层 |
这些模块的添加顺序,也是本系列文章的写作顺序:先有能跑起来的最小系统,再一块一块地把积木拼上去。
# Harness 是什么?
在上面的模块表中,上下文管理器、记忆系统、规划模块、反思模块、缓存管理器,这五个模块统称为 Harness。
Harness 这个词来自马具中的 "挽具"—— 它不是马(模型),也不是车(工具),而是把马和车连接起来、让整个系统协调运转的那套装置。
从功能上看,Harness 的本质是上下文工程(Context Engineering)与注意力管理(Attention Management)系统。它解决的是一个核心矛盾:
Agent 运行过程中产生的无限信息空间,与 LLM 有限且易受干扰的上下文窗口之间的矛盾。
Harness 通过控制输入模型的信息内容、格式、位置和密度,引导模型将有限的 "注意力" 集中在当前最关键的决策上,从而避免目标漂移(Goal Drifting)、幻觉(Hallucination)和中间迷失(Lost in the middle)。
# Harness 的核心机制
Harness 的日常工作可以归结为对信息的四种处理机制:
信息过滤与截断(Information Filtering):模型不需要也不应该看到所有的执行细节。Harness 决定哪些信息进入 Prompt,哪些被丢弃。例如,一个耗时极长的报错日志可能被截断或总结后才喂给模型,以防止错误信息挤占正常推理的注意力空间。
格式化与认知减负(Cognitive Offloading):LLM 解析复杂非结构化数据的能力是有限的。Harness 将工具返回的杂乱数据转化为清晰的 Markdown、JSON 或 XML 格式。这种 "预处理" 降低了模型的认知负荷,使其能将注意力用于推理(Reasoning)而非解析(Parsing)。
状态锚定与目标重申(State Anchoring):在长链路任务中,模型极易忘记最初的目标。Harness 通过在每一轮交互中强制注入系统提示词、当前任务状态或进度总结,强行将模型的注意力拉回主线任务。
记忆的分层调度(Memory Scheduling):Harness 将信息分为短期记忆(当前轮次对话)、中期记忆(任务计划与草稿)和长期记忆(知识库或长期偏好)。根据当前上下文的需要,动态地将不同层级的记忆调入或移出模型的上下文窗口。
# Harness 的设计维度
构建一个强大的 Harness,需要在以下五个核心维度上进行精细化设计:
| 设计维度 | 核心目标 | 具体工作内容 | 常见技术手段 |
|---|---|---|---|
| 上下文维度 (Context) | 优化注意力分配,对抗长文本遗忘 | 决定信息的排列顺序;将最关键指令放在首尾;控制总 Token 数量 | 滑动窗口截断、动态摘要压缩、XML 标签结构化隔离 |
| 工具与动作维度 (Action) | 规范输出边界,降低试错成本 | 定义工具的 Schema;提供明确的错误反馈机制;拦截危险操作 | 强类型约束(如 JSON Schema)、自动重试机制、错误堆栈精简 |
| 状态与规划维度 (State) | 维持长期连贯性,防止目标漂移 | 维护 Agent 的内部状态机;跟踪任务完成度 | 显式的 Plan-and-Solve 机制、任务树(Task Tree)管理 |
| 反思与纠错维度 (Reflection) | 引入自我监督,打破死循环 | 监控执行结果;在连续失败时强制介入;引导模型反思 | 失败阈值拦截(如连续失败 3 次后求助)、Critic 机制 |
| 成本与缓存维度 (Cache) | 最大化缓存命中率,降低 API 调用成本 | 将稳定内容固定在上下文前部;禁止动态修改 System Prompt;历史记录只追加不重写 | Prompt Cache(KV Cache)、前缀稳定性设计、变化边界管理 |
# 缓存友好设计:成本维度的核心约束
这是当前 LLM API 经济学下最重要的工程约束之一。主流 LLM API(OpenAI、Anthropic、Google)均已推出 Prompt Cache 机制:对于上下文中前缀完全一致的部分,命中缓存后 token 费用大幅降低(通常为原价的 10%~25%)。
缓存命中的核心条件是前缀的 byte-level 精确匹配,因此设计原则是:越稳定的内容越靠前,越易变的内容越靠后,形成一个变化频率单调递增的分层结构。
| 内容类型 | 变化频率 | 推荐位置 | 注意事项 |
|---|---|---|---|
| System Prompt(角色定义、工具列表、全局规则) | 极低(几乎不变) | 最前,固定锚点 | 任务生命周期内禁止修改;动态内容(如当前时间)必须移出 |
| 长期记忆 / 知识库片段 | 低(内容稳定) | System Prompt 之后 | 一旦加载,内容不得重排或修改 |
| 任务计划 / 当前 Plan | 中(每次推进后更新) | 中间区域 | 更新时只追加新状态,不重写历史状态 |
| 历史对话 / 工具调用记录 | 高(每轮追加) | 靠后 | 严格只追加,禁止对已有记录做任何格式修改 |
| 当前轮次的 User Message | 每轮必变 | 最末尾 | 缓存边界之后,无需考虑缓存 |
此外还有两条关键推论:工具列表应全量固定,不要根据当前步骤动态增删工具定义 —— 工具定义通常体积庞大,任何变动都会导致其后所有内容的缓存全部失效;历史记录只追加不重写,哪怕是微小的格式调整,也会使整个后续前缀失效。
# Harness 设计原则汇总
最小信息原则(Principle of Least Information):只提供当前步骤绝对需要的信息和工具。信息越多,注意力越分散。
显式的结构化隔离(Explicit Structural Isolation):使用清晰的标记(如 <thought> 、 <observation> 、 <plan> )将不同类型的信息隔离开来,帮助模型区分系统指令与外部反馈。
动态的注意力预算管理(Dynamic Attention Budgeting):将上下文窗口视为一种 "预算",实现一套动态打分机制,决定每条信息在 Prompt 中的去留。
失败是第一等公民(Failures as First-Class Citizens):工具调用失败时,将错误信息包装成 "引导性反馈",主动引导模型的注意力去解决特定问题,而非仅仅返回一个报错。
缓存友好的分层结构(Cache-Friendly Layering):上下文的变化频率必须从前到后单调递增,System Prompt 冻结,历史记录只追加不重写。
# 两个视角的统一
注意力管理与缓存友好设计,看似来自不同出发点,实则指向同一个结论:Harness 的上下文必须具备严格的分层结构,且层与层之间的变化频率单调递增。
这一结构既保证了模型在每一轮都能以最低的认知负荷找到最关键的指令,又保证了稳定的前缀能够持续命中缓存,将 API 成本压缩到最低。
# 本系列的路线图
本系列将按照以下顺序,逐步搭建一套完整的 Agent 系统:
- 理论基础(本篇):Agent Loop、模块全景、Harness 的本质与设计原则
- 最小可运行 Agent:实现 Agent Loop + LLM Client + 基础工具调用
- 上下文管理器:Token 预算、信息排序、结构化隔离
- 记忆系统:短期 / 中期 / 长期记忆的分层存储与调度
- 规划模块:任务分解、任务树管理、Plan-and-Solve
- 反思与纠错:失败检测、Critic 机制、Human-in-the-loop
- 缓存管理器:前缀稳定性设计、KV Cache 优化
- 安全与可观测性:权限控制、日志、调试与回放
每一篇都会在前一篇的基础上添加新的模块,最终拼装出一套生产可用的 Agent 系统。