Skip to content

第21章 设计模式与架构决策

"Patterns are not invented — they are discovered." — Christopher Alexander

本章要点

  • 从全书 20 章的实践中提炼 10 个核心设计模式
  • 每个模式包括:问题场景、解决方案、真实案例、适用边界
  • 这些模式是跨框架的——无论你用什么技术栈都能应用

模式 1:分层架构(Layered Architecture)

问题: Agent 系统涉及模型调用、工具执行、权限控制、上下文管理等多个关注点,混在一起难以维护。

解决方案: 将系统分为清晰的层次,每层职责单一。

┌─ 交互层 ─┐  用户输入/输出、流式显示、UI
├─ 编排层 ─┤  Agent Loop、任务调度、多 Agent 协调
├─ 能力层 ─┤  工具系统、Tool Registry、执行引擎
├─ 控制层 ─┤  权限模型、沙箱、审计日志
├─ 模型层 ─┤  LLM 调用、Prompt 组装、响应解析
└─ 基础层 ─┘  配置、存储、记忆、缓存

案例: Claude Code 的架构严格分层——CLI 入口 → Query Engine → Tool System → Permission Model → LLM Client,每层通过接口通信。

适用边界: 所有 Agent 系统都应该分层。层数可以根据复杂度调整,但"关注点分离"的原则不可妥协。

模式 2:工具抽象(Tool Abstraction)

问题: Agent 的能力由工具决定,但工具的实现千差万别。

解决方案: 统一的工具接口——每个工具有 name、description、parameters schema、execute 方法。

typescript
interface Tool {
  name: string
  description: string
  parameters: JSONSchema
  execute(params: any, context: Context): Promise<ToolResult>
}

核心价值: 模型不关心工具是怎么实现的(可能是本地函数、HTTP 调用、Shell 命令),它只看到统一的 name + description + schema。这让工具系统可以无限扩展——MCP 协议正是基于这个抽象。

模式 3:观察-思考-行动循环(Observe-Think-Act Loop)

问题: Agent 需要持续与环境交互,不是一次性生成答案。

解决方案: 循环结构——观察当前状态 → 思考下一步 → 执行动作 → 回到观察。

while (!done) {
  observation = getToolResults() + getUserMessage()
  thinking = llm.chat(observation)  // 模型决策
  if (thinking.hasToolCalls) {
    results = executeTools(thinking.toolCalls)  // 行动
  } else {
    done = true  // 模型认为任务完成
  }
}

案例: 几乎所有 Agent 框架都实现了这个循环——Claude Code 的 query engine、LangGraph 的 Pregel engine、ReAct 模式。差异在于循环的控制逻辑(何时停止、如何处理错误、是否支持并行)。

模式 4:渐进式信任(Progressive Trust)

问题: Agent 有能力执行危险操作,但完全限制又使其无用。

解决方案: 从最严格的权限开始,随用户信任积累逐步放宽。

新用户 → 每个操作都需确认
        ↓ 使用一段时间后
普通用户 → 安全操作自动批准,危险操作确认
          ↓ 充分信任后
高级用户 → 大部分自动化,仅不可逆操作确认

案例: Claude Code 的五级权限模式;GitHub Copilot 从建议到自动应用的演进。

关键原则: 信任升级应由用户主动选择,而非系统自动决定。

模式 5:纵深防御(Defense in Depth)

问题: 单一安全检查可能被绕过。

解决方案: 多层独立的安全机制叠加。

请求 → 权限检查 → 参数验证 → 命令过滤 → 路径验证 → OS 沙箱 → 执行

每一层独立工作——即使某一层被攻破,后续层仍然提供保护。

案例: Claude Code 的 Bash 工具:权限模式检查 → 命令正则过滤 → 路径白名单 → Seatbelt 沙箱 → 超时限制。

模式 6:上下文即接口(Context as Interface)

问题: 模型无法直接调用 API 或读数据库——它只能通过文本"看"到信息。

解决方案: 把所有信息编码为模型能理解的上下文文本。

这不只是"把数据塞进 prompt"——而是精心设计模型看到的信息

  • 什么信息放在系统提示词(稳定的规则)
  • 什么信息动态注入(当前环境状态)
  • 什么信息按需获取(工具调用结果)
  • 什么信息不需要(节省 token)

案例: Claude Code 在会话开始时注入 git status 而非让模型自己去查——因为这个信息几乎每次都需要。CLAUDE.md 的内容被注入上下文而非作为文件读取——因为它是"隐式的"项目规则。

模式 7:失败即信号(Failure as Signal)

问题: 工具调用可能失败,但失败不等于灾难。

解决方案: 将失败信息反馈给模型,让模型自适应调整策略。

typescript
try {
  result = await tool.execute(params)
} catch (error) {
  // 不是崩溃——而是给模型一个信号
  result = {
    error: true,
    message: `Tool failed: ${error.message}`,
    suggestion: 'Try a different approach or check the file path'
  }
}
// 将错误结果送回模型,模型会调整策略

模型天然具备从错误中学习的能力——测试失败了它会修复代码,文件不存在它会搜索正确路径。把模型当作错误处理器是 Harness Engineering 的核心洞察之一。

模式 8:记忆分层(Layered Memory)

问题: Agent 需要同时处理即时信息和长期知识。

解决方案: 三层记忆架构。

┌─ 工作记忆 ─┐  当前上下文窗口中的信息
├─ 会话记忆 ─┤  当前会话的历史(可压缩)
└─ 长期记忆 ─┘  跨会话的持久化知识(文件/数据库)

每一层有不同的容量、时效性和检索方式。

模式 9:预算约束(Budget Constraints)

问题: Agent 的资源消耗(token、时间、API 调用)可能失控。

解决方案: 在每个层面设置硬性上限。

typescript
const BUDGETS = {
  maxTokensPerTask: 200_000,
  maxToolCallsPerLoop: 50,
  maxConcurrentAgents: 5,
  maxWallTimeMs: 10 * 60 * 1000,  // 10 分钟
  maxCostPerTask: 5.00,            // $5
}

关键原则: 超过预算时必须硬停止而非"尽量控制"。没有硬上限的系统迟早会出事。

模式 10:人在回路(Human in the Loop)

问题: Agent 不可能 100% 正确,尤其在高风险场景。

解决方案: 在关键决策点暂停,等待人类审批。

设计好"何时中断"比"如何中断"更重要:

中断不中断
不可逆操作只读操作
影响共享状态仅影响本地
模糊需求明确需求
首次执行某类操作已批准过的同类操作

十大模式的关联图

这 10 个模式不是孤立的——它们共同构成了 Harness 的完整骨架:

核心链路:分层架构 → OTA 循环 → 工具抽象 → 纵深防御 → 人在回路。这是从"系统骨架"到"安全兜底"的完整路径。

信息链路:上下文即接口 → 记忆分层 → 失败即信号。Agent 的决策质量完全取决于它能"看到"什么信息。

控制链路:渐进信任 → 预算约束。在"有用"和"安全"之间动态平衡。

架构决策总结

回顾全书,Harness Engineering 的核心架构决策可以归纳为:

决策 1:方法论优先于框架

框架会过时(LangChain v0.1 → v0.3 的 breaking changes),方法论不会。本书的每一个设计模式都可以在任何技术栈中实现。

决策 2:安全默认,能力可选

默认拒绝一切,然后有选择地开放。而不是默认允许一切,然后试图堵漏洞。

决策 3:可观测优先于可控制

你无法控制模型的内部推理过程,但你可以观测它的每一个外部行为。先做到看得见,再谈控得住。

决策 4:简单方案优先

能用单 Agent 解决的不用多 Agent,能用文件存储的不用向量数据库,能用正则过滤的不用训练分类器。复杂度是最大的敌人。

决策 5:为失败而设计

Agent 一定会犯错——工具会失败、模型会幻觉、用户会给出矛盾指令。好的 Harness 不是消除失败,而是让失败可恢复、可诊断、损害可控。

全书回顾

第一部分 · 认知框架
  ├── Ch 1  Harness ≠ Model: 工程层的价值
  └── Ch 2  架构模式全景

第二部分 · 核心引擎
  ├── Ch 3  Agent Loop: 决策循环
  └── Ch 4  上下文工程

第三部分 · 工具系统
  ├── Ch 5  工具设计
  ├── Ch 6  工具编排
  └── Ch 7  错误恢复

第四部分 · 提示词架构
  ├── Ch 8  分层 Prompt 设计
  ├── Ch 9  指令优先级
  └── Ch 10 动态提示策略

第五部分 · 记忆系统
  ├── Ch 11 短期记忆
  ├── Ch 12 长期记忆
  └── Ch 13 会话状态机

第六部分 · 安全工程
  ├── Ch 14 权限模型
  └── Ch 15 沙箱隔离

第七部分 · 协作系统
  ├── Ch 16 多 Agent 协调
  └── Ch 17 Human-in-the-Loop

第八部分 · 生产化
  ├── Ch 18 评估与测试
  ├── Ch 19 可观测性
  ├── Ch 20 成本与性能
  └── Ch 21 设计模式(本章)

从理论框架到生产实践,从单一工具到多 Agent 系统,Harness Engineering 的核心信念始终如一:

模型是引擎,Harness 是缰绳。好的缰绳不限制马的力量,而是让力量指向正确的方向。

感谢你读完这本书。现在,去构建你自己的 Harness 吧。

基于 VitePress 构建