Harness架构介绍与示例

Harness架构(Harness Engineering)是AI Agent(智能体)领域的一种工程基础设施参考框架。其核心公式为 Agent = Model + Harness,旨在通过一套系统化的工程方案,将基础大模型的原始智能转化为可靠、可控、可用的智能体能力。

第一章,Harness介绍

1. 研发背景与核心定义

在AI Agent开发中,单纯依赖基座模型(裸模型)面临无记忆、不能执行代码、知识过时、无工作环境等局限。Harness架构的诞生标志着AI工程实践从早期的"提示词工程"、"上下文工程"向构建完整智能体运行环境的重要演进。
如果将大模型比作一匹蓄势待发的"烈马",Harness就是人类牵引、驾驭这匹烈马的"缰绳"与"马具"。它不参与任务执行本身,但决定任务的方向、节奏与停止时机,解决的是"AI如何被约束"以及"AI如何稳定、合规、规模化地干活"的问题。

2. 核心组件

一个完整的Harness架构通常包含以下核心模块,为构建智能体系统提供技术骨架:

  • System Prompt(系统提示词):贯穿所有组件的"神经系统",负责定义角色边界、注入领域知识、约束安全规则,并影响所有组件的工作方式。
  • 文件系统与沙箱:提供工作空间、中间结果存储、版本追踪能力,并通过Bash沙箱赋予Agent代码执行、自我验证及安全隔离的能力。
  • 记忆系统:通过文件存储和上下文注入,为模型提供长期记忆和知识扩展,避免每次对话都"从零开始"。
  • 工具接入(Web Search + MCP):突破模型知识截止日期的限制,获取实时信息并连接外部工具与数据源。
  • 上下文工程:管理模型的输入上下文,对抗"上下文腐烂",通过压缩、工具输出卸载、Skills渐进加载等策略优化信息呈现。
  • 编排与验证(Hooks):协调多个Agent协同工作,并通过Hooks在关键节点注入确定性检查,以保障输出质量。

3. 计算机类比与三层区别

在计算机系统中,可以将Harness架构进行如下类比:模型是提供原始处理能力的CPU,上下文窗口是易失的工作内存(RAM),Agent Harness是负责整理上下文、提供标准驱动的执行基础设施(操作系统OS),而Agent则是运行在操作系统之上的具体应用逻辑(Application)。
在实际开发中,Harness与Framework(框架)、Agent存在明确的分层区别:

  • Framework(如LangChain):是基础构建块,提供原语和工具,灵活但"裸露",需要开发者自行解决生产环境问题。
  • Harness:是执行基础设施,提供有主观立场的默认架构(如上下文管理、状态持久化、验证机制),处理可靠执行的"怎么做"。
  • Agent:是应用逻辑层,关注"做什么",即具体的目标、决策模式和领域逻辑。

4. 核心价值与行业趋势

Harness架构的本质是为企业级智能体构建一套"运行制度"和"控制闭环"。它通过定义目标与标准、递送上下文、智能体执行、验证与观察、追踪与学习五个环节,将原本由管理者凭经验完成的动作机械化、系统化,使AI系统能够自我校正与持续改进。
自2026年初由HashiCorp联合创始人Mitchell Hashimoto明确提出并命名以来,Harness Engineering迅速取代提示词工程,成为硅谷最流行的AI工程化范式,并受到OpenAI、Anthropic、LangChain等头部厂商的广泛实践与推动。

第二章 架构应用示例

为了让你更直观地理解Harness架构在实际项目中的落地,我们可以将核心组件的配置划分为**"工程约束层""运行时基础设施层"**两个维度。以下是基于主流企业级实践(如AgentScope Java Harness及Cow-Harness)梳理的配置示例:

一、 工程约束层:以文件系统为"唯一事实来源"

在实际落地中,Harness通常通过一个结构化的workspace(工作区)目录来承载所有约束。这相当于给AI设定了固定的"办公桌"和"操作手册"。
1. 核心目录结构配置

复制代码
workspace/
├── AGENTS.md          # 核心约束:定义Agent的人格、行为边界与协作规范
├── MEMORY.md          # 长期记忆:精炼后的跨会话事实沉淀
├── knowledge/         # 领域知识:项目文档、API规范、架构设计等
├── skills/            # 可复用技能:封装好的工具或标准操作流程(SOP)
├── subagents/         # 子Agent规格:多Agent协作时的角色声明
└── agents/<agentId>/  # 运行时状态:会话历史、每日记忆流水账

**2. 关键文件配置示例(AGENTS.md)**这是Agent进入项目后的"第一份指南",配置内容通常包括:

  • 项目架构约束:例如"必须遵循 Types → Config → Service → UI 的层级依赖模型"。
  • 检索路径约定:遇到报错时,应该优先查阅哪些文档或日志。
  • 安全与权限边界:明确禁止执行的危险操作(如直接rm -rf、访问未授权数据库等)。

二、 运行时基础设施层:抽象文件系统与沙箱

为了让同一套Agent逻辑能在个人开发、企业SaaS、安全隔离等不同场景下无缝切换,Harness通过AbstractFilesystem(抽象文件系统)进行底层配置。
1. 抽象文件系统模式配置上层Agent只需调用统一的 read/write/execute 接口,底层可根据环境切换三种形态:

  • Local + Shell 模式:数据落点为本机目录,支持Shell执行。适用于个人开发和本地原型验证。
  • Remote 共享存储模式:数据落点为远端KV或对象存储(OSS),默认禁用Shell。适用于多副本、多租户的在线SaaS服务。
  • Sandbox 沙箱模式:数据与命令执行均在隔离环境内。适用于处理不受信任代码的Coding Agent或Data Agent。
    2. 安全沙箱分级配置针对工具链与代码执行,Harness通常会配置分级隔离策略:
  • L1 进程级隔离:速度快,适用于受信任的内部工具调用。
  • L2 容器隔离(Docker):行业标准,适用于大多数工具执行。
  • L3 微虚拟机(Firecracker):适用于多租户或执行不受信任的代码。
  • L4 完全虚拟机:最高安全性,适用于对隔离要求极高的敏感任务。

三、 自动化闭环配置:Hooks与软件过程改进

Harness不仅是静态约束,更是动态的"软件过程改进(SPI)"闭环。通过配置Hooks,将软件工程标准自动化:

  • 上下文注入 Hook(WorkspaceContextHook):在每次推理前,自动将AGENTS.md、MEMORY.md等关键文件注入System Prompt,确保人格与知识不丢失。
  • 记忆持久化 Hook(MemoryFlushHook):在对话结束后,自动提炼新事实写入记忆流水账,并周期性合并为精炼的长期记忆。
  • 验证与评审门禁(Verification & Reviews):配置自动化Linter或"Agent-to-Agent Review"机制。例如,一个Agent负责生成代码,另一个Agent负责运行测试并审核结果,只有验证通过的产物才能进入下一阶段。
    通过以上配置,Harness成功将"下一轮怎么办、上下文爆了怎么办、状态丢了怎么办"等工程难题打包解决,让开发者能够专注于Agent的业务逻辑本身。

第三章,代码审查Agent示例

下面是一个基于 AgentScope Java Harness 的最小可运行 Demo,它将你之前了解到的 workspace、AGENTS.md、AbstractFilesystem 等核心概念全部落地。
这个 Demo 的目标是:构建一个能进行多轮对话、自动持久化记忆、且具备明确安全边界的 Agent。

🛠️ 第一步:准备项目与依赖

  1. 创建一个标准的 Maven 项目。
  2. 在 pom.xml 中引入 Harness 核心依赖。这里以 2.0 版本为例,它提供了 HarnessAgent 这个一站式入口。
XML 复制代码
<dependency>
    <groupId>io.agentscope</groupId>
    <artifactId>agentscope-harness</artifactId>
    <version>2.0.0-RC2</version>
</dependency>

📁 第二步:创建结构化 Workspace

在项目根目录下创建一个 workspace 文件夹,并在其中创建 AGENTS.md 文件。这是 Harness 的核心,Agent 的所有人格、知识和约束都源于此。
workspace/AGENTS.md 内容示例:

XML 复制代码
# Agent 角色定义
你是一个专业的代码审查助手。

# 行为约束
1.  只审查用户提供的 Java 代码片段。
2.  指出潜在的性能问题和空指针风险。
3.  禁止执行任何 Shell 命令或访问外部网络。
4.  如果用户要求执行危险操作,请礼貌拒绝并说明原因。

# 审查标准
-   遵循 Clean Code 原则
-   优先保证代码可读性

💻 第三步:编写核心启动代码

创建一个 Application.java 作为入口。这段代码展示了如何构建 HarnessAgent 并配置运行时上下文,实现会话持久化和安全隔离。

java 复制代码
import io.agentscope.harness.HarnessAgent;
import io.agentscope.harness.RuntimeContext;
import io.agentscope.harness.compaction.CompactionConfig;
import io.agentscope.message.Msg;

import java.nio.file.Paths;

public class Application {
    public static void main(String[] args) {
        // 1. 构建 HarnessAgent
        HarnessAgent agent = HarnessAgent.builder()
                .name("code-reviewer")
                // 配置你的 LLM 模型 (此处以 DeepSeek 为例)
                .model(modelConfig -> modelConfig
                        .apiKey(System.getenv("DEEPSEEK_API_KEY"))
                        .modelName("deepseek-chat")
                        .baseUrl("https://api.deepseek.com")
                )
                // 指向我们刚创建的 workspace
                .workspace(Paths.get("workspace"))
                // 配置上下文压缩,防止 token 溢出
                .compaction(CompactionConfig.builder()
                        .triggerMessages(50) // 消息数超过50条时触发压缩
                        .keepMessages(20)    // 压缩后保留最近20条
                        .build()
                )
                .build();

        // 2. 创建运行时上下文,实现多轮对话与用户隔离
        RuntimeContext ctx = RuntimeContext.builder()
                .sessionId("session-001") // 相同 sessionId 自动续接上下文
                .userId("developer-alice") // 多用户场景必传,用于命名空间隔离
                .build();

        // 3. 与 Agent 进行多轮对话
        Msg userMsg1 = Msg.builder().textContent("请审查这段代码: String s = null; s.length();").build();
        Msg reply1 = agent.call(userMsg1, ctx).block();
        System.out.println("Agent 回复: " + reply1.getTextContent());

        // 第二次调用,Agent 能记住上文的审查标准
        Msg userMsg2 = Msg.builder().textContent("如果我想优化它,应该怎么做?").build();
        Msg reply2 = agent.call(userMsg2, ctx).block();
        System.out.println("Agent 回复: " + reply2.getTextContent());
    }
}

🚀 第四步:运行与验证

  1. 设置环境变量 DEEPSEEK_API_KEY 为你的 API 密钥。
  2. 运行 Application.java。
  3. 关键验证点 :运行结束后,检查 workspace 目录。你会看到自动生成了 memory/ 和 agents// 等文件夹。这说明 Agent 已经成功将对话历史和记忆持久化到了文件系统中,实现了"大脑外化"。下次启动时,只要 sessionId 和 userId 不变,Agent 就能无缝接续上次的对话状态。

💡 Demo 核心亮点解析

|---------------------|---------------|------------------------------------------------------------------------|
| 配置项 | 对应 Harness 概念 | 解决的问题 |
| workspace/AGENTS.md | 工程约束层 | 将 Agent 的人格、安全规则、领域知识从代码中解耦,实现"修改文件即升级 Agent"。 |
| AbstractFilesystem | 运行时基础设施 | 代码中虽未显式配置,但 Harness 默认使用本地文件系统。在生产环境中,只需切换配置即可无缝迁移到远端存储或沙箱模式,无需修改业务代码。 |
| RuntimeContext | 会话与记忆管理 | 通过 sessionId 和 userId 实现多轮对话的上下文自动恢复和多租户隔离,解决了"状态丢失"和"用户混淆"的工程难题。 |
| CompactionConfig | 上下文工程 | 主动管理模型输入窗口,避免因对话过长导致的上下文溢出和性能下降。 |

这个 Demo 已经是一个具备生产级雏形的 Agent 应用。你可以在此基础上,通过修改 AGENTS.md 来调整 Agent 能力,或通过更换 filesystem 配置来适配不同的部署环境,真正体验 Harness 架构带来的工程化便利。


第四章 多Agent协作流水线

我们将之前的单点代码审查扩展为一个**"代码审查 + 自动修复"的多 Agent 协作流水线** 。
在 Harness 架构中,多 Agent 协作的核心在于结构化分工上下文无缝传递 。我们将引入两个角色:

  1. Reviewer Agent(审查员) :负责发现问题,输出结构化报告。
  2. Fixer Agent(修复员) :负责根据审查报告,输出修复后的代码。
    以下是扩展后的最小 Demo 落地方案:

🛠️ 第一步:扩展 Workspace 结构

我们需要为两个 Agent 分别定义约束,并创建一个共享的"上下文传递协议"。

java 复制代码
workspace/
├── AGENTS.md          # 全局系统提示词(定义协作流程)
├── reviewer/          # Reviewer 专属目录
│   └── AGENTS.md      # 审查员人格与输出规范
└── fixer/             # Fixer 专属目录
    └── AGENTS.md      # 修复员人格与代码规范

1. 全局系统提示词 workspace/AGENTS.md

java 复制代码
# 协作流程
本系统由两个 Agent 组成:
1. Reviewer:审查代码,输出结构化问题列表。
2. Fixer:根据 Reviewer 的输出,生成修复后的完整代码。

# 上下文传递协议
Reviewer 的输出必须包含以下 JSON 结构,Fixer 将直接解析此结构:
{
  "issues": [{"line": 1, "type": "NPE", "description": "..."}],
  "original_code": "..."
}

2. Reviewer 专属约束 workspace/reviewer/AGENTS.md

java 复制代码
# 角色
你是代码审查专家。

# 输出规范
必须输出 JSON 格式,包含 issues 数组和 original_code。
禁止输出任何解释性文字,只输出 JSON。

3. Fixer 专属约束 workspace/fixer/AGENTS.md

java 复制代码
# 角色
你是代码修复专家。

# 输入
你将收到一个 JSON,包含 issues 和 original_code。

# 输出规范
只输出修复后的完整 Java 代码,不要包含 markdown 代码块标记,不要包含任何解释。

💻 第二步:编写多 Agent 协作核心代码

java 复制代码
import io.agentscope.harness.HarnessAgent;
import io.agentscope.harness.RuntimeContext;
import io.agentscope.harness.compaction.CompactionConfig;
import io.agentscope.message.Msg;

import java.nio.file.Paths;

public class MultiAgentDemo {
    public static void main(String[] args) {
        // 1. 构建 Reviewer Agent
        HarnessAgent reviewer = HarnessAgent.builder()
                .name("reviewer")
                .model(modelConfig -> modelConfig
                        .apiKey(System.getenv("DEEPSEEK_API_KEY"))
                        .modelName("deepseek-chat")
                        .baseUrl("https://api.deepseek.com")
                )
                .workspace(Paths.get("workspace/reviewer")) // 专属 workspace
                .compaction(CompactionConfig.builder().triggerMessages(50).keepMessages(20).build())
                .build();

        // 2. 构建 Fixer Agent
        HarnessAgent fixer = HarnessAgent.builder()
                .name("fixer")
                .model(modelConfig -> modelConfig
                        .apiKey(System.getenv("DEEPSEEK_API_KEY"))
                        .modelName("deepseek-chat")
                        .baseUrl("https://api.deepseek.com")
                )
                .workspace(Paths.get("workspace/fixer")) // 专属 workspace
                .compaction(CompactionConfig.builder().triggerMessages(50).keepMessages(20).build())
                .build();

        // 3. 协作流水线
        String originalCode = "String s = null; s.length();";
        RuntimeContext ctx = RuntimeContext.builder()
                .sessionId("collab-session-001")
                .userId("developer-alice")
                .build();

        // 第一步:Reviewer 审查
        System.out.println("=== Reviewer 开始审查 ===");
        Msg reviewRequest = Msg.builder().textContent("请审查: " + originalCode).build();
        Msg reviewResult = reviewer.call(reviewRequest, ctx).block();
        String reviewJson = reviewResult.getTextContent();
        System.out.println("Reviewer 输出: " + reviewJson);

        // 第二步:Fixer 修复(直接传递 Reviewer 的 JSON 输出)
        System.out.println("\n=== Fixer 开始修复 ===");
        Msg fixRequest = Msg.builder().textContent("请修复以下问题: " + reviewJson).build();
        Msg fixResult = fixer.call(fixRequest, ctx).block();
        String fixedCode = fixResult.getTextContent();
        System.out.println("Fixer 输出: " + fixedCode);

        // 第三步:可选 - 让 Reviewer 再次验证修复结果
        System.out.println("\n=== Reviewer 二次验证 ===");
        Msg verifyRequest = Msg.builder().textContent("请验证修复后的代码是否解决了问题: " + fixedCode).build();
        Msg verifyResult = reviewer.call(verifyRequest, ctx).block();
        System.out.println("验证结果: " + verifyResult.getTextContent());
    }
}

🚀 第三步:运行与验证

  1. 设置环境变量 DEEPSEEK_API_KEY。
  2. 运行 MultiAgentDemo.java。
  3. 关键验证点
  • Reviewer 输出的是纯 JSON ,没有多余的解释文字。
  • Fixer 接收 JSON 后,输出的是纯代码 ,没有 markdown 标记。
  • 两个 Agent 的 workspace 目录下分别生成了独立的记忆文件,实现了状态隔离
  • 整个协作流程是确定性的 ,JSON 作为上下文传递协议,避免了自然语言传递的歧义。

💡 多 Agent 协作核心亮点解析

|-----------------------|---------------|------------------------------------------------|
| 配置项 | 对应 Harness 概念 | 解决的问题 |
| 独立 workspace | 工程约束层 | 每个 Agent 有专属的人格和约束,避免角色混淆。 |
| JSON 传递协议 | 上下文工程 | 用结构化数据替代自然语言传递,确保下游 Agent 能精准解析上游输出。 |
| 独立 RuntimeContext | 会话管理 | 两个 Agent 共享同一个 sessionId ,但各自维护独立的记忆文件,既协作又隔离。 |
| 二次验证闭环 | 验证与评审门禁 | Fixer 修复后,Reviewer 再次验证,形成"审查→修复→验证"的自动化闭环。 |

📌 进阶:如何扩展到更复杂的协作场景?

如果你需要更多 Agent(如测试 Agent、文档 Agent),只需:

  1. 在 workspace/ 下创建新的专属目录(如 tester/AGENTS.md)。
  2. 定义新的 JSON 传递协议。
  3. 在代码中按流水线顺序调用即可。
    Harness 架构的精髓在于:Agent 是"插件",workspace 是"插槽",JSON 是"接口" 。只要协议定义清晰,你可以像搭积木一样无限扩展协作场景。

第五章 Agent协作逻辑工程化

将多 Agent 协作逻辑封装为工具类,是 Harness 架构迈向工程化、模块化的关键一步。
下面我为你封装了一个通用的 AgentPipeline 工具类。它采用了**"配置即代码"**的设计思路,将 Agent 的初始化、上下文传递和流水线执行全部抽象出来。以后你只需要定义好每个节点的 workspace 和传递协议,就可以像搭积木一样随意扩展流水线。

💻 核心工具类:AgentPipeline.java

java 复制代码
import io.agentscope.harness.HarnessAgent;
import io.agentscope.harness.RuntimeContext;
import io.agentscope.harness.compaction.CompactionConfig;
import io.agentscope.message.Msg;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

/**
 * 多 Agent 协作流水线封装工具类
 */
public class AgentPipeline {

    // 定义流水线中的单个节点
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class PipelineNode {
        private String name;          // 节点名称(对应 workspace 目录)
        private String promptTemplate; // 提示词模板(用于动态注入上游输出)
        private HarnessAgent agent;   // 实际执行的 Agent 实例
    }

    private final List<PipelineNode> nodes;
    private final RuntimeContext context;

    public AgentPipeline(RuntimeContext context) {
        this.nodes = new ArrayList<>();
        this.context = context;
    }

    /**
     * 向流水线中添加一个 Agent 节点
     * @param workspacePath 该 Agent 专属的 workspace 路径
     * @param promptTemplate 提示词模板,使用 {input} 占位符接收上游输出
     */
    public AgentPipeline addNode(Path workspacePath, String promptTemplate, String name) {
        HarnessAgent agent = HarnessAgent.builder()
                .name(name)
                .model(modelConfig -> modelConfig
                        .apiKey(System.getenv("DEEPSEEK_API_KEY"))
                        .modelName("deepseek-chat")
                        .baseUrl("https://api.deepseek.com")
                )
                .workspace(workspacePath)
                .compaction(CompactionConfig.builder()
                        .triggerMessages(50)
                        .keepMessages(20)
                        .build())
                .build();
        
        nodes.add(new PipelineNode(name, promptTemplate, agent));
        return this; // 支持链式调用
    }

    /**
     * 执行流水线
     * @param initialInput 流水线的初始输入
     * @return 最后一个节点的输出结果
     */
    public String execute(String initialInput) {
        String currentInput = initialInput;

        for (PipelineNode node : nodes) {
            System.out.println(">>> 正在执行节点: " + node.getName());
            
            // 将上游输出动态注入提示词模板
            String finalPrompt = node.getPromptTemplate().replace("{input}", currentInput);
            Msg request = Msg.builder().textContent(finalPrompt).build();
            
            Msg response = node.getAgent().call(request, context).block();
            currentInput = response.getTextContent(); // 将当前输出作为下一节点的输入
        }

        return currentInput;
    }
}

🚀 使用示例:一键重构多 Agent 协作

有了这个工具类,原来的 MultiAgentDemo 可以被极度简化。我们只需要关注"业务逻辑"(节点定义和协议),而不再需要关心底层的 API 调用。

java 复制代码
import java.nio.file.Paths;

public class PipelineDemo {
    public static void main(String[] args) {
        // 1. 准备共享的运行时上下文
        RuntimeContext ctx = RuntimeContext.builder()
                .sessionId("collab-session-001")
                .userId("developer-alice")
                .build();

        // 2. 定义流水线(链式调用,清晰直观)
        AgentPipeline pipeline = new AgentPipeline(ctx)
                // 添加审查节点
                .addNode(
                    Paths.get("workspace/reviewer"),
                    "请审查以下代码并输出JSON格式的问题列表: {input}",
                    "reviewer"
                )
                // 添加修复节点(直接接收上游的 JSON 输出)
                .addNode(
                    Paths.get("workspace/fixer"),
                    "请根据以下审查报告修复代码,只输出纯代码: {input}",
                    "fixer"
                );

        // 3. 一键执行
        String originalCode = "String s = null; s.length();";
        String finalResult = pipeline.execute(originalCode);
        
        System.out.println("\n=== 流水线最终输出 ===");
        System.out.println(finalResult);
    }
}

💡 封装后的架构优势

  1. 高度解耦:业务开发人员完全不需要知道 HarnessAgent 是如何构建的,也不需要关心 call() 方法的底层实现。他们只需要定义好 workspace 目录和提示词模板。
  2. 协议标准化:通过 {input} 占位符,我们强制定义了上下游之间的数据传递契约。如果下游需要 JSON,上游的 AGENTS.md 就必须约束输出 JSON。
  3. 无限扩展性:如果未来需要增加一个"测试节点"或"文档生成节点",只需要在 addNode 链式调用中再加一行代码即可,完全符合开闭原则(对扩展开放,对修改关闭)。
    这套封装完美体现了 Harness 架构中"把工程难题打包解决"的理念。你觉得这个工具类的设计符合你的预期吗?如果需要,我们可以继续探讨如何在这个流水线中加入"人工审批(Human-in-the-loop)"的断点机制。