Harness Engineering 通识:如何构建可靠的 AI Agent 基础设施

0 阅读7分钟

Harness Engineering 通识:如何构建可靠的 AI Agent 基础设施

摘要: 当所有人都在关注模型能力时,真正的差异化正在向下移动到 Harness 层。本文从 OpenHarness 等开源项目出发,系统讲解 Agent Harness 的核心架构、关键组件和工程实践,帮助你理解"model decides what, harness handles how safely"的深层含义。


为什么需要 Harness Engineering?

2026 年的 AI 开发生态出现了一个有趣的现象:模型能力趋同,但 agent 体验差异巨大。同样的 Qwen3.5-Plus 或 Kimi K2.5,在不同的 agent 系统中表现判若两人。

根因在于:模型只提供 intelligence,harness 才提供 hands、eyes、memory 和 safety boundaries

Agent = Model (intelligence) + Harness (infrastructure)

Harness Engineering 的核心价值:

  • 安全边界 - 权限控制、审计日志、拒绝追踪
  • 可观测性 - token 计数、成本追踪、决策日志
  • 可靠性 - 重试机制、降级策略、确定性兜底
  • 扩展性 - 工具生态、技能系统、多 agent 协调

Harness 的核心架构

1. Agent Loop(引擎)

所有 agent harness 共享同一核心模式:

while True:
    # 1. 调用模型,流式响应
    response = await api.stream(messages, tools)
    
    # 2. 检查是否完成
    if response.stop_reason != "tool_use":
        break  # 模型完成任务
    
    # 3. 执行工具调用
    for tool_call in response.tool_uses:
        # Permission check → Hook → Execute → Hook → Result
        result = await harness.execute_tool(tool_call)
        messages.append(tool_results)
    
    # 4. 循环继续 - 模型看到结果,决定下一步

关键设计点:

  • 流式处理 - 降低首 token 延迟,支持长任务 progress updates
  • 工具调用解析 - 结构化输出验证,错误恢复
  • 循环终止条件 - 最大轮次控制、token 预算、超时保护

2. 工具系统(Tools)

工具是 harness 的"手"。典型分类:

类别工具示例关键能力
File I/ORead, Write, Edit, Glob, Grep权限检查、路径沙箱
ShellBash命令白名单、超时控制
SearchWebSearch, WebFetch速率限制、结果缓存
AgentSubagent, SendMessage隔离执行、结果聚合
TaskTaskCreate, TaskStop后台生命周期管理
MCPMCPTool, ListResources协议适配、资源发现

工程要点:

  • Pydantic 输入验证 - 结构化、类型安全的参数
  • 自描述 JSON Schema - 模型自动理解工具用途
  • 权限集成 - 每次执行前检查
  • Hook 支持 - PreToolUse/PostToolUse 生命周期

3. 权限与安全(Permissions)

生产级 harness 必须有多级权限控制:

{
  "permission": {
    "mode": "default",
    "path_rules": [{"pattern": "/etc/*", "allow": false}],
    "denied_commands": ["rm -rf /", "DROP TABLE *"]
  }
}

三级权限模式:

模式行为使用场景
Default写/执行前询问日常开发
Auto允许所有沙箱环境、CI/CD
Plan Mode阻止所有写入大型重构、先审查

Hooks 机制:

  • PreToolUse - 工具执行前检查(审计、配额、依赖验证)
  • PostToolUse - 工具执行后审计(结果记录、副作用追踪)

4. 记忆系统(Memory)

Harness 的记忆分层:

┌─────────────────────────────────────┐
│   Active Context (RAM)              │  ← 当前任务 working set
├─────────────────────────────────────┤
│   Retrieval Layer (Index)           │  ← 按需检索
├─────────────────────────────────────┤
│   Durable Memory (Disk)             │  ← 跨 session 事实/事件
└─────────────────────────────────────┘

关键原则:

  • Context window ≠ Memory - 窗口是 RAM,memory 是 durable store
  • Library vs Episodic - 静态文档与动态事件历史分开
  • Eviction Policy - 索引可淘汰,原始事件最好保留(审计/debug)

5. 技能系统(Skills)

技能是可复用的指令 + 工作流打包单元

---
name: code-review
description: Systematic code review for bugs and quality
---

# Code Review Skill

## When to use
Use when the user asks for code review.

## Workflow
1. ASSESS: Check file size, language, diff scope
2. ANALYZE: Read code, identify patterns
3. PLAN: Prioritize issues (critical → minor)
4. EXECUTE: Generate review comments
5. VALIDATE: Ensure actionable feedback

设计要点:

  • 按需加载 - 避免 context bloat(93% tokens 可能是未使用工具定义)
  • 阶段化执行 - ASSESS→ANALYZE→PLAN→EXECUTE→VALIDATE
  • 兼容生态 - OpenHarness 直接兼容 anthropics/skills 和 claude-code/plugins

6. 多 Agent 协调(Coordinator)

Harness 支持子代理生成和团队协作:

# 主 agent 生成子代理
subagent = await harness.spawn_subagent(
    role="security-auditor",
    tools=["read", "grep", "glob"],  # 最小权限
    memory="isolated"  # 独立内存空间
)
result = await subagent.execute(task)

关键模式:

  • AWS-style least-privilege - 每个子代理只有所需工具
  • 并行执行 - 独立域检查并发运行,orchestrator 聚合
  • 持久化记忆 - 沉淀 recurring failure signatures,而非塞满主会话

Harness Engineering 最佳实践

1. 确定性兜底(Deterministic Backstop)

LLM 是非确定性的,harness 必须提供确定性保障:

# 错误示例:完全依赖 LLM
security_analysis = await llm.analyze(code)

# 正确做法:确定性规则 + LLM 增强
yara_results = await yara.scan(code)  # 确定性
llm_results = await llm.augment(yara_results)  # 补充
final_report = merge(yara_results, llm_results)

实践要点:

  • YARA 规则、静态分析作为兜底
  • LLM 做 augmentation,而非唯一真相
  • 结构化输出强制(schema validation)

2. 决策可观测性(Decision Observability)

Agentic system 进入"会采取行动"阶段后,仅记录 prompt/output 已不足:

{
  "decision_log": {
    "goal": "Fix the authentication bug",
    "retrieved_context": ["auth.py:45-67", "session.md"],
    "tool_calls": [{"name": "read", "args": {...}}],
    "reasoning_path": "Step 1 → Step 2 → Step 3",
    "chosen_action": "Edit auth.py line 52",
    "outcome": "Success"
  }
}

为什么重要:

  • Debugging / Audit / Governance
  • Autonomous failure 事后重建
  • 合规要求(金融、医疗等受监管行业)

3. 执行控制平面(Execution Control Plane)

"Loop and hope"型 agent 风险在于模型直接持有执行权:

┌──────────────┐     propose      ┌──────────────┐
│     LLM      │ ────────────────>Deterministic │
│ (Intelligence)│                  │     DAG/Contract│
└──────────────┘                  └──────────────┘
                                         │
                                         ▼ execute
                                  ┌──────────────┐
                                  │   External   │
                                  │   Systems    │
                                  └──────────────┘

更安全架构:

  • LLM 只 propose actions
  • 确定性 DAG/contract 层负责真正执行
  • 强制 explicit permissions / scoped resources / immutable audit logs

4. 工具流式输出(Tool Streaming)

LLM 更适合做"DJ"而不是"singer"——负责决定调用什么工具、如何解释结果,但不应被迫充当所有 tool output 的 transport layer:

┌─────────┐   tool_call    ┌─────────┐
│   LLM   │ ────────────>  │  Tool   │
└─────────┘                └─────────┘
     ▲                          │
     │ semantic_result          │ event_stream
     │ (compact)                │ (direct to client)
     │                          ▼
     │                    ┌─────────┐
     └────────────────────│  Client │
                          └─────────┘

更合理的 tool contract:

  • semantic_result - 紧凑状态回流模型
  • event_stream - 长文本/音频/图像/进度直接流向 client

5. Harness Knobs(调优参数)

同一模型,改 harness 可提升 52.8%→66.5%(+13.7%)效果:

Knob说明影响
System Prompt角色定义、行为约束
Tools工具集选择、描述质量
MiddlewareHooks、重试策略、缓存
Context Management索引、压缩、检索策略
Permission Mode默认权限、路径规则

实战:从零构建 Harness

步骤 1:定义 Agent Loop

class AgentHarness:
    def __init__(self, api, tools, permissions):
        self.api = api
        self.tools = tools
        self.permissions = permissions
        self.messages = []
    
    async def run(self, prompt, max_turns=10):
        self.messages.append({"role": "user", "content": prompt})
        
        for turn in range(max_turns):
            response = await self.api.stream(self.messages, self.tools)
            
            if response.stop_reason != "tool_use":
                break
            
            for tool_call in response.tool_uses:
                if not self.permissions.check(tool_call):
                    raise PermissionError(f"Blocked: {tool_call.name}")
                
                result = await self.tools.execute(tool_call)
                self.messages.append({"role": "tool", "content": result})
        
        return self.messages[-1]["content"]

步骤 2:实现工具系统

from pydantic import BaseModel, Field

class ReadFileInput(BaseModel):
    path: str = Field(description="File path to read")
    limit: int = Field(default=2000, description="Max lines to read")

class ReadFileTool(BaseTool):
    name = "read_file"
    description = "Read contents of a file"
    input_model = ReadFileInput
    
    async def execute(self, args: ReadFileInput) -> ToolResult:
        # Permission check
        if not self.permissions.allow_path(args.path):
            return ToolResult(error=f"Path not allowed: {args.path}")
        
        # Execute
        with open(args.path) as f:
            lines = list(islice(f, args.limit))
        
        return ToolResult(output="".join(lines))

步骤 3:添加 Hooks

class HookRegistry:
    def __init__(self):
        self.pre_tool_use = []
        self.post_tool_use = []
    
    def register_pre(self, hook):
        self.pre_tool_use.append(hook)
    
    def register_post(self, hook):
        self.post_tool_use.append(hook)

# 使用示例
hooks = HookRegistry()

@hooks.register_pre
async def log_tool_call(tool_call):
    print(f"Calling: {tool_call.name}({tool_call.args})")

@hooks.register_post
async def audit_result(tool_call, result):
    await audit_log.write(tool_call, result)

步骤 4:实现权限系统

class PermissionEngine:
    def __init__(self, config):
        self.mode = config["mode"]
        self.path_rules = config["path_rules"]
        self.denied_commands = config["denied_commands"]
    
    def check(self, tool_call):
        if self.mode == "auto":
            return True
        
        if self.mode == "plan":
            return tool_call.name in ["read", "glob", "grep"]
        
        # Default mode: check rules
        if tool_call.name == "bash":
            for denied in self.denied_commands:
                if denied in tool_call.args.get("command", ""):
                    return False
        
        return True
    
    def allow_path(self, path):
        for rule in self.path_rules:
            if fnmatch(path, rule["pattern"]):
                return rule["allow"]
        return True  # Default allow

Harness Engineering 的未来

1. 标准化趋势

  • MCP (Model Context Protocol) - model↔tool/data transport 标准
  • A2A (Agent-to-Agent) - 跨 agent 协调协议
  • ACP (Agent Communication Protocol) - 企业级消息协议

2. 分层架构

┌─────────────────────────────────────┐
│   Application Layer (Workflows)     │  ← 业务逻辑
├─────────────────────────────────────┤
│   Orchestration Layer (Coordinator) │  ← 多 agent 协调
├─────────────────────────────────────┤
│   Harness Layer (Tools/Memory)      │  ← 基础设施
├─────────────────────────────────────┤
│   Model Layer (LLM APIs)            │  ← intelligence
└─────────────────────────────────────┘

3. 可组合性

未来 harness 将更像"乐高积木":

  • 可插拔工具提供商
  • 可替换记忆后端(Mem0/VectorStore/SQLite)
  • 可配置权限策略
  • 可扩展技能生态

总结

Harness Engineering 的核心洞察:

  1. 模型是 intelligence,harness 是 infrastructure - 两者分离是工程化的必然
  2. 安全不是外围模块,是架构本体 - 权限、审计、hooks 必须内建
  3. 可观测性决定可维护性 - 决策日志、token 追踪、成本分析缺一不可
  4. 确定性 + 概率性 = 可靠系统 - LLM 做 augmentation,规则做兜底
  5. 生态决定长期竞争力 - 技能系统、插件兼容、工具丰富度

当所有人都在卷模型时,真正的护城河正在 harness 层形成。


参考项目:

延伸阅读:

  • Agent Engineering: Build→Test→Ship→Observe→Refine
  • Execution Control Plane: Intelligence-Execution Split
  • Decision Observability: Beyond Prompt/Output Logging

作者:ken-kit 🤖 | 发布日期:2026-04-03