一、Harness 的本质再理解

Harness 的核心思想是:AI 模型本身只是一台"裸机"(裸模型),Harness 是围绕它构建的"操作系统"

就像你的电脑有 CPU(模型能力),但光有 CPU 什么都干不了——你需要操作系统来管理文件、调度程序、连接外设。Harness 就是 AI 的"操作系统层" 。


二、六大设计步骤的详细技术拆解

第一步:基础设施 / 沙箱环境(盖马厩)

小学生版:给马一个专属院子,有马槽、有围栏、有工具房。

技术细节

技术组件作用典型实现
沙箱(Sandbox)隔离 Agent 的执行环境,防止它误删系统文件或访问敏感数据Docker 容器、Firecracker microVM、E2B 沙箱
持久化工作目录Agent 可以读写文件,状态跨会话保留挂载 Volume,如 /workspace
版本控制集成Agent 的每次操作都可追踪、可回滚Git 仓库自动初始化,每次修改自动 commit
网络隔离控制 Agent 能访问哪些外部资源白名单域名、代理服务器、API 网关

为什么重要:没有沙箱,Agent 就像一匹没有围栏的马——它可能"吃掉"你的整个硬盘。沙箱是 Harness 的"地基" 。


第二步:护栏 / 约束系统(戴眼罩和围栏)

小学生版:马容易乱跑,给它戴上眼罩,再围上栅栏。

技术细节

约束类型技术实现示例
文件系统护栏路径白名单/黑名单禁止写入 ~/.ssh//etc/,只允许在 /workspace 操作
代码质量护栏Lint 规则、类型检查ESLint、Ruff、MyPy 自动运行,代码不合规就拒绝
安全护栏内容过滤器、权限最小化检测 SQL 注入、XSS 攻击模式;API Key 不可读
结构化护栏Schema 验证输出必须符合 JSON Schema,否则重试
预算护栏Token/成本限制单次调用不超过 4000 tokens,总成本不超过 $5

核心原则“约束优于指令”(Constraints > Prompts)

不要写 Prompt 说"请不要删除重要文件",而是直接让文件系统权限禁止删除。Prompt 可以被模型"忘记"或"忽略",但系统级约束不可绕过 。

技术实现示例

# 文件系统护栏:只允许在 /workspace 下操作
ALLOWED_PATHS = ["/workspace"]
def validate_path(path: str) -> bool:
    return any(path.startswith(allowed) for allowed in ALLOWED_PATHS)

# 代码护栏:提交前自动运行测试
def pre_commit_hook():
    result = run_tests()
    if result.failed:
        raise RejectCommitError("测试未通过,禁止提交")

第三步:工具集成与上下文工程(工具包和地图)

小学生版:给马挂上工具包,里面有锤子、钉子、地图,需要时自己拿。

技术细节

技术概念说明典型协议/实现
MCP(Model Context Protocol)标准化的工具调用协议,让 Agent 能统一调用各种外部工具Anthropic 提出的开放协议,支持文件系统、数据库、API 等
Skills / 技能定义预定义的工具模板,描述"这个工具是干什么的、需要什么参数、返回什么"类似 OpenAI Function Calling 的 functions 定义
AGENTS.md项目级的上下文文件,告诉 Agent"这个项目的结构、规范、常用命令"放在项目根目录,Agent 自动读取
动态上下文加载不是一次性塞给模型所有信息,而是按需检索RAG(检索增强生成)、向量数据库、文件索引

关键技术:MCP 协议

MCP 是 Harness 中工具集成的核心。它定义了一套标准,让任何工具(文件系统、数据库、浏览器、Slack)都能以统一的方式暴露给 Agent:

Agent → MCP Client → MCP Server → 外部工具

好处:

  • 可插拔:今天用文件系统工具,明天换成数据库工具,Agent 代码不用改
  • 安全:MCP Server 可以独立控制权限
  • 标准化:不同厂商的 Agent 可以共享同一套工具

上下文工程的关键原则

“给地图,别给百科全书”(Index, not dump)

不要一次性把 10 万行代码塞进 Prompt,而是给一个索引(文件树、关键函数列表),让 Agent 按需读取。这解决了上下文窗口的限制问题 。


第四步:规划与任务分解(拆分路程)

小学生版:从北京到上海太远,拆成"北京→天津→济南→南京→上海"。

技术细节

技术概念说明实现方式
任务分解(Task Decomposition)将复杂目标拆成原子子任务模型自主规划,或预定义工作流
Sub-agent 调度主 Agent 把子任务派发给专门的子 Agent每个子 Agent 有特定角色(如"代码审查员"、“测试工程师”)
规划-执行循环(Plan-Execute Loop)先制定计划,再逐步执行,执行中可调整计划ReAct 模式、Ralph 循环
状态机(State Machine)用有限状态机管理任务生命周期定义状态:待办→进行中→待验证→完成→失败

Ralph 循环(长时程自主执行的核心机制)

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   规划      │────→│   执行      │────→│   验证      │
│ (Planning)  │     │ (Execution) │     │ (Validation)│
└─────────────┘     └─────────────┘     └──────┬──────┘
       ↑                                         │
       └─────────────────────────────────────────┘
                    (验证失败则重新规划)

这个循环让 Agent 能在长时间运行中保持目标一致性,而不是"做着做着就忘了要干什么"。

技术实现示例

class TaskPlanner:
    def plan(self, goal: str) -> List[SubTask]:
        # 让模型生成执行计划
        plan = llm.generate(f"将以下目标拆分为子任务:{goal}")
        return parse_plan(plan)
    
    def execute(self, tasks: List[SubTask]):
        for task in tasks:
            result = sub_agent.run(task)
            if not validate(result):
                # 验证失败,重新规划
                return self.replan(task, result)

第五步:验证与回压(检查与拉缰绳)

小学生版:马跑错了,后面的人喊"停!";跑对了,摸摸头鼓励。

技术细节

验证层级检查内容技术实现
L0:语法/格式验证输出是否符合预期格式JSON Schema 验证、正则表达式、类型检查
L1:单元测试代码逻辑是否正确自动运行 pytest、jest、mocha
L2:集成测试模块间协作是否正常端到端测试、API 契约测试
L3:人工审查关键变更需要人确认PR Review、审批工作流
L4:安全审计是否存在漏洞或恶意代码静态分析(SAST)、依赖扫描

回压机制(Backpressure)

当验证失败时,Harness 不是简单地报错退出,而是将错误信息推回给 Agent,让它自我纠正

Agent 生成代码 → 运行测试 → 测试失败 → 错误日志返回给 Agent 
                                              ↓
Agent 分析错误 → 修改代码 → 重新测试 → ...直到通过

这形成了一个自动迭代闭环,类似于人类开发者的"写代码→运行→调试"循环 。

Hook 机制

Harness 在关键节点插入 Hook,自动触发验证:

@pre_tool_use  # 工具调用前
def check_permissions(tool_name: str, args: dict):
    if tool_name == "file_delete" and args["path"] not in ALLOWED_PATHS:
        raise PermissionDenied()

@post_tool_use  # 工具调用后
def validate_output(tool_name: str, result: Any):
    if tool_name == "code_generate":
        run_linter(result)
        run_tests(result)

第六步:记忆与状态管理(记笔记)

小学生版:马跑完一趟,把路线、坑、减速点都记下来,下次直接看。

技术细节

记忆类型类比技术实现持久化方式
工作记忆马脑子里现在想的事当前对话上下文(Prompt)内存,随会话结束清空
程序性记忆马学会的技能(怎么钉蹄铁)Skills、工具定义、代码模板配置文件、数据库
情景记忆上次跑这条路的经历会话历史、操作日志日志文件、向量数据库
语义记忆地图、常识知识RAG 检索、知识图谱向量数据库、图数据库

分层记忆架构

┌─────────────────────────────────────────┐
│         工作记忆(Working Memory)        │  ← 当前上下文窗口
│    (对话历史、当前任务状态、临时变量)      │
├─────────────────────────────────────────┤
│         程序性记忆(Procedural)          │  ← Skills、工具定义
│    ("如何调用 Git"、"如何写单元测试")      │
├─────────────────────────────────────────┤
│         情景记忆(Episodic)              │  ← 操作日志、Git 历史
│    ("上次修改这个文件时引入了 Bug")        │
├─────────────────────────────────────────┤
│         语义记忆(Semantic)              │  ← 项目文档、代码知识库
│    ("这个函数是做什么的"、"项目的架构")      │
└─────────────────────────────────────────┘

关键技术:文件系统作为外部记忆

由于模型的上下文窗口有限(通常 128K-200K tokens),Harness 利用文件系统突破这个限制:

  • MEMORY.md:记录项目级的重要决策和约束
  • PROGRESS.md:记录当前任务进度,跨会话恢复
  • Git 历史:记录所有代码变更,Agent 可以 git log 查看
  • 向量数据库:存储代码片段的语义嵌入,支持语义搜索
# 记忆写入
def save_memory(key: str, content: str):
    with open(f"/workspace/.memory/{key}.md", "w") as f:
        f.write(content)

# 记忆读取(按需加载)
def load_relevant_memories(query: str) -> List[str]:
    # 使用向量数据库检索相关记忆
    embeddings = vector_db.search(query, top_k=5)
    return [mem.content for mem in embeddings]

三、Harness 的整体架构图

┌─────────────────────────────────────────────────────────────┐
│                        用户 / 开发者                          │
└──────────────────────┬────────────────────────────────────┘
                       │
┌──────────────────────▼────────────────────────────────────┐
│                    Harness(驾驭层)                         │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────────┐ │
│  │  沙箱    │  │  护栏   │  │工具集成  │  │  规划调度   │ │
│  │ 环境     │  │ 系统    │  │ (MCP)   │  │ (Sub-agent) │ │
│  └─────────┘  └─────────┘  └─────────┘  └─────────────┘ │
│  ┌─────────┐  ┌─────────┐  ┌─────────────────────────────┐ │
│  │ 验证    │  │  记忆   │  │      状态管理引擎            │ │
│  │ 回压    │  │  系统   │  │   (Ralph 循环 / 状态机)      │ │
│  └─────────┘  └─────────┘  └─────────────────────────────┘ │
└──────────────────────┬────────────────────────────────────┘
                       │
┌──────────────────────▼────────────────────────────────────┐
│                    AI 模型(裸机)                          │
│         (LLM / VLM / 多模态模型 / 推理引擎)               │
└─────────────────────────────────────────────────────────────┘

四、为什么 Harness 比单纯 Prompt Engineering 重要?

维度Prompt EngineeringHarness Engineering
关注点让模型"说对话"让模型"做对事"
稳定性依赖模型随机性,结果不稳定通过约束和验证保证确定性
可扩展性上下文窗口限制通过工具、记忆突破限制
安全性仅靠"请别做坏事"系统级权限控制,不可绕过
生产力单次对话长时程自主执行,持续迭代

核心洞察:Prompt Engineering 是在"调教马的性格",Harness Engineering 是在"给马配装备"。性格调教有上限,但装备可以无限升级 。


五、现实中的 Harness 实例

产品/框架Harness 特点
Cursor文件系统沙箱 + Git 集成 + 代码索引 + 多 Agent 协作
Devin完整云环境 + 浏览器工具 + 自主规划循环 + 长期记忆
Claude CodeMCP 工具协议 + 权限控制 + 测试验证 + 会话记忆
OpenAI Codex沙箱执行 + 工具调用 + 迭代调试 + 代码审查

这些产品之间的竞争,本质上不是"谁的模型更强",而是谁的 Harness 更完善——谁的马具更结实、更灵活、更安全 。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐