【Harness Agent】 源码剖析(二):Core Engine 与 Steering——Agent Loop 的源码级实现
写在前面:第一篇我们俯瞰了 Harness Agent 的五层架构和五阶段 Agent Loop。今天,我们深入最核心的子系统——Core Engine 与 Steering。Core Engine 是 Harness 的"心脏",负责驱动 Agent Loop 的每一次心跳;Steering 是 Harness 的"方向盘",确保长会话中 Agent 不偏离轨道。这两个系统解决的是 Coding Agent 最棘手的两个工程问题:如何让 Agent 在长时间运行中保持高效?如何让 Agent 在上下文爆炸时保持清醒?理解了它们,你就理解了 Harness 为什么能在 Harness-Bench 上得分 100%。
📑 文章目录
- 📌 一、Core Engine:四层配置层级
- 🔄 二、三种 Workflow:Execution / Thinking / Compaction
- 🎯 三、Steering:事件驱动的行为引导
- 📦 四、Context 组装:条件提示词组合管道
- 🗜️ 五、Compaction:渐进式上下文压缩
- 🔮 六、系列预告
📌 一、Core Engine:四层配置层级
1.1 为什么需要四层?
Harness 的核心架构是一个Session → Agent → Workflow → LLM的四层配置层级。这不是过度设计——它是解决一个真实工程问题的必要抽象:不同的认知任务需要不同的模型能力、延迟和成本。
考虑一个 Coding Agent 的典型场景:规划任务(“这个 bug 怎么修?”)需要强推理能力,适合用 Claude Sonnet;执行工具(“读取文件内容”)需要快速响应,适合用 GPT-4o;压缩上下文(“总结旧对话”)只需要便宜模型,用 GPT-4o-mini 就够了。如果只用一个模型,你要么在规划时用便宜模型(质量差),要么在压缩时用贵模型(浪费钱)。四层配置层级让每种 Workflow 独立选择模型,各取所长。
1.2 四层详解
| 层级 | 职责 | 核心文件 | 配置示例 |
|---|---|---|---|
| Session | 一次完整的用户交互会话 | core/session.py | session_id,project_root |
| Agent | 会话中的子 Agent(Initializer/Coder) | agents/manager.py | agent_type,allowed_tools |
| Workflow | Agent 中的工作流(Execution/Thinking/Compaction) | core/engine.py | workflow_type,model_binding |
| LLM | 具体的模型调用 | providers/ | model_name,api_key |
1.3 源码映射
# core/session.py — 会话层classSession:session_id:stragents:list[Agent]# 包含多个子 Agentcontext:Context# 共享上下文memory:Memory# 跨会话记忆# agents/manager.py — Agent 层classAgentManager:defcreate_agent(self,agent_type:str)->Agent:# 根据 agent_type 创建 Initializer 或 Coder# 每个 Agent 有自己的工具集和提示词# core/engine.py — Workflow 层classEngine:defrun_workflow(self,workflow_type:str,agent:Agent):# 根据 workflow_type 选择 Execution/Thinking/Compaction# 每种 Workflow 独立绑定 LLMmodel=self.config.get_model(workflow_type)returnself.execute(model,agent.context)1.4 Compound AI System 的核心价值
四层配置层级的核心价值体现在四个方面:成本优化——Thinking 用 Claude Sonnet(贵但强),Compaction 用 GPT-4o-mini(便宜但够用);延迟优化——Execution 用快速模型,Thinking 用慢速但更准确的模型;能力优化——规划任务用强模型,执行任务用快模型,各取所长;模型无关——切换模型只需改配置,不需要改任何代码。
🔄 二、三种 Workflow:Execution / Thinking / Compaction
2.1 Execution Workflow——干活模式
Execution 是默认的工作流,对应标准的 ReAct 循环:LLM 接收上下文 → 决定是否调用工具 → 执行工具 → 返回结果。这是 Agent 大部分时间所处的工作模式。
关键特征:拥有完整的工具访问权限(读写文件、执行命令、搜索代码);直接与外部环境交互;每次工具调用都经过沙箱安全检查;结果追加到上下文,继续循环。
适用场景:读取文件、编辑代码、运行测试、执行 Shell 命令——所有"动手"的操作都在 Execution 中完成。
2.2 Thinking Workflow——思考模式
当 Agent 遇到复杂任务时,会切换到 Thinking Workflow。这个模式的核心思想是:先想清楚再动手。在 Thinking 模式下,Agent 只有只读工具权限,不能修改任何文件或执行任何命令。
关键特征:只有只读工具权限(read_file, search_code, list_dir);强制 LLM 先推理再行动;可选的自我批评(Self-Critique)阶段——LLM 审视自己的计划,找出漏洞;输出一个结构化的执行计划,交给 Execution Workflow 执行。
适用场景:理解复杂代码库、规划多步骤重构、分析 bug 根因——所有"动脑"的操作都在 Thinking 中完成。
2.3 Compaction Workflow——压缩模式
当上下文接近 Token 上限时,Agent 自动切换到 Compaction Workflow。这个模式用便宜模型总结旧对话历史,释放 Token 空间给新的交互。
关键特征:使用便宜模型(如 GPT-4o-mini)降低成本;渐进式压缩——只压缩旧历史,保留最近 N 轮完整对话;压缩后注入 Task Context Reminder,防止 LLM 丢失当前任务目标;压缩结果替换旧历史,上下文长度大幅缩减。
适用场景:长时间运行的会话、上下文超过模型 Token 限制——所有"清理"的操作都在 Compaction 中完成。
2.4 Workflow 切换逻辑
三种 Workflow 之间的切换不是随意的,而是由 Engine 根据明确的条件触发:Execution 遇到复杂任务时切换到 Thinking;Thinking 完成规划后切换回 Execution;上下文超过阈值时切换到 Compaction;Compaction 完成后切换回 Execution。这个切换逻辑定义在core/engine.py中,是整个 Agent Loop 的"调度中心"。
🎯 三、Steering:事件驱动的行为引导
3.1 Instruction Fade-Out 问题
长时间运行的 Agent 会遇到一个致命问题:Instruction Fade-Out(指令遗忘)。初始系统提示词在上下文中的位置越来越远,LLM 的注意力逐渐衰减,开始偏离原始指令。比如,你告诉 Agent"修复 issue #42",但经过 20 轮工具调用后,Agent 可能已经忘了自己在修什么 bug,开始做无关的事情。
3.2 Harness 的解法:事件驱动 System Reminder
Harness 的 Steering 机制不是简单地"把系统提示词写得更长"——而是在关键决策点注入针对性提醒。这些提醒是事件驱动的,只在特定条件触发时才注入:
| 触发事件 | 注入的 Reminder | 目的 |
|---|---|---|
| 工具调用前 | 安全策略提醒 | “不要删除 .git 目录” |
| 上下文压缩后 | 任务上下文提醒 | “你正在修复 issue #42” |
| 迭代超过 N 次 | 停止条件提醒 | “已尝试 10 次,考虑换策略” |
| 文件修改后 | 测试提醒 | “修改后请运行测试” |
| 进入 Thinking 模式 | 规划提醒 | “先理解代码再动手” |
3.3 为什么事件驱动优于静态提示词?
静态提示词的问题是:它总是存在于上下文中,无论是否需要。这浪费了宝贵的 Token 预算,而且长提示词本身也会导致注意力稀释。事件驱动 Reminder 的优势在于:在需要的时候注入,在不需要的时候不占空间。这就像一个好的教练——不是在比赛前把所有战术都喊一遍,而是在关键时刻喊出最关键的提醒。
📦 四、Context 组装:条件提示词组合管道
4.1 提示词不是"一坨"
很多人以为系统提示词就是一大段文本,塞给 LLM 就完事了。但 Harness 的提示词是一个条件组合管道——由多个独立的 Section 按优先级组装而成,每个 Section 只在满足条件时才加载。
4.2 组合管道的四个阶段
阶段一:Base Prompt——始终加载的基础指令,包含 Agent 身份、核心行为准则、工具使用规范。这是"宪法",不可省略。
阶段二:Conditional Sections——按需加载的条件指令,包含项目特定规则、语言偏好、代码风格要求。这些 Section 有优先级排序,高优先级的先加载,Token 不够时低优先级的被裁剪。
阶段三:Event Reminders——事件驱动的动态提醒,由 Steering 系统在运行时注入。这些提醒是临时的,只在当前决策步骤有效。
阶段四:Tool Schemas——工具的 JSON Schema 描述,告诉 LLM 有哪些工具可用。Harness 使用懒加载工具发现——只加载当前 Agent 需要的工具 Schema,不加载全部工具。
4.3 懒加载工具发现
Harness 定义了大量工具(文件读写、Shell 执行、代码搜索、LSP 集成等),但不是所有工具都需要同时暴露给 LLM。懒加载工具发现的核心逻辑是:Initializer Agent 只加载只读工具 Schema;Coder Agent 加载全部工具 Schema;Thinking Workflow 只加载只读工具 Schema;Compaction Workflow 不加载任何工具 Schema。这大大减少了提示词中的 Token 占用,让 LLM 的注意力更集中。
🗜️ 五、Compaction:渐进式上下文压缩
5.1 上下文爆炸是不可避免的
Coding Agent 的上下文增长速度远超普通聊天:一次文件读取可能消耗数千 Token,一次工具调用的结果可能更长。一个典型的编程会话,10 轮交互后上下文就可能超过 50K Token。如果不压缩,模型要么截断旧上下文(丢失重要信息),要么直接报错(超过 Token 限制)。
5.2 Harness 的渐进式压缩
Harness 的 Compaction 不是"一刀切"的截断,而是渐进式压缩——保留最近 N 轮完整对话,用便宜模型总结更早的历史。具体步骤如下:
Step 1:检测阈值。Engine 在每次循环后检查上下文长度。如果超过阈值(如 100K Token),触发 Compaction Workflow。
Step 2:分割上下文。将上下文分为两部分:最近 N 轮(保留原样)和更早的历史(待压缩)。
Step 3:LLM 压缩。用便宜模型(如 GPT-4o-mini)总结旧历史,生成一个压缩摘要。摘要保留关键决策、文件修改记录、错误信息,丢弃冗余的工具输出和中间结果。
Step 4:注入 Reminder。压缩后注入 Task Context Reminder,防止 LLM 丢失当前任务目标。回到 Execution Workflow 继续执行。
5.3 与 OpenClaw Memory Flush 的对比
Harness 的 Compaction 和 OpenClaw 的 Memory Flush 解决的是同一个问题,但策略不同:OpenClaw 在压缩前让 LLM 将重要信息写入 Markdown 文件(文件优先),Harness 在压缩时让便宜模型总结旧历史(摘要优先)。OpenClaw 的优势是记忆可读、可编辑、可 Git 追踪;Harness 的优势是压缩更彻底、Token 节省更多、不需要额外的文件系统依赖。
🔮 六、系列预告
第三篇(也是最后一篇),我们将拆解 Harness Agent 的沙箱安全与工具生态:
| 核心问题 |
|---|
| 沙箱的六阶段 Shell 执行管道是怎么工作的? |
| 命令白名单和文件系统限制如何防止破坏性操作? |
| MCP 协议集成如何扩展 Agent 的工具能力? |
| Skills 技能系统如何实现懒加载和自动发现? |
| 审计日志如何实现全链路追溯? |
关注我,不要错过最终篇!
🎁 总结速查卡
Core Engine 核心概念
| 概念 | 一句话解释 |
|---|---|
| 四层配置 | Session → Agent → Workflow → LLM,每层独立配置 |
| Execution | 干活模式,完整工具权限,标准 ReAct 循环 |
| Thinking | 思考模式,只读权限,强制推理+可选自我批评 |
| Compaction | 压缩模式,便宜模型总结旧历史,释放 Token 空间 |
| Steering | 事件驱动 System Reminder,对抗 Instruction Fade-Out |
| 条件提示词 | 多 Section 按优先级组装,按需加载,不浪费 Token |
| 懒加载工具 | 只加载当前 Agent/Workflow 需要的工具 Schema |
三种 Workflow 速查
| Workflow | 工具权限 | 模型选择 | 触发条件 |
|---|---|---|---|
| Execution | 全部(读写+执行) | 快速模型 | 默认模式 |
| Thinking | 只读 | 强推理模型 | 复杂任务 |
| Compaction | 无 | 便宜模型 | 上下文超阈值 |
一句话总结
Harness 的 Core Engine 用四层配置层级实现了 Compound AI System——不同 Workflow 绑定不同模型,成本、延迟、能力各取所长。Steering 用事件驱动 System Reminder 对抗遗忘——在关键决策点注入针对性提醒,而非依赖初始提示词。Compaction 用渐进式压缩对抗上下文爆炸——便宜模型总结旧历史,保留最近 N 轮完整对话。条件提示词组合管道确保提示词按需加载,不浪费 Token 预算。这三个系统共同解决了 Coding Agent 最棘手的工程问题:如何在长时间运行中既高效又清醒。
参考链接:
- Harness Agent GitHub 仓库
- Building AI Coding Agents for the Terminal (arXiv:2603.05344)
- The Anatomy of an Agent Harness (LangChain Blog)
- Context Management in Agent Harnesses (Arize)