# 03 - Harness 工程化与反馈回路 > 本文由 opsxcli 同名设计文档适配改写,结合 aiops Agent CLI 的 Web 实现(`backend/pkg/agentcli/`)。 > Harness Engineering 是与具体语言/形态无关的理论框架,原文的思想性内容(控制论、Steering Loop、四类调节 Harness)几乎完全保留;落地实例部分从「opsxcli CLI + golangci-lint」改写为「aiops 后端库 + WebSocket 反馈回路 + Evolver 自进化」。 --- ## 1. 核心定义:Agent = Model + Harness ### 1.1 什么是 Harness > **Agent = Model + Harness** — LangChain Harness 是 Agent 中除 Model 本身之外的一切。在大模型运维 Agent 的有界上下文中,Harness 分为两个层次: - **内置 Harness(built-in harness)**:引擎作者构建的部分 —— System Prompt、工具注册机制、ReAct 编排循环 - **外部 Harness(outer harness)**:业务方为自身场景构建的部分 —— 安全模式、确认机制、记忆注入、审计落库 Model 是「大脑」,Harness 是「身体 + 环境 + 工具 + 规则」。大脑决定智能,但身体和环境决定智能能否被正确、可靠、持续地发挥。 ### 1.2 两个目标 > 一个构建良好的 Harness 服务于两个目标: > 1. **提高智能体首次就做对的概率**(feedforward) > 2. **提供反馈回路,在问题到达人类前尽可能自我纠正**(feedback) > — Martin Fowler / Birgitta Böckeler 这两个目标分别对应**前馈指导**和**反馈传感器**,是 Harness 的双引擎。 ### 1.3 核心理念 > **Humans steer. Agents execute.** — OpenAI 人类的工作重心从「敲每一条命令」,转向**设计环境、明确意图和构建反馈回路**。在 aiops Agent CLI 中,运维人员的角色从「亲自 SSH 排障」变为「在 Web 上描述任务、审阅高危确认、监督 Agent 执行」。 --- ## 2. 控制论基础:前馈与反馈 ### 2.1 前馈指导 vs 反馈传感器 | 维度 | 前馈指导(Feedforward Guides) | 反馈传感器(Feedback Sensors) | |------|-------------------------------|-------------------------------| | **时机** | 智能体行动**之前** | 智能体行动**之后** | | **目的** | 预期行为并加以引导 | 观察产出并帮助自我纠正 | | **效果** | 提高首次做对的概率 | 在问题到达人类前自我纠正 | | **aiops 实例** | 五层 System Prompt、工具描述、安全规则文本 | 安全 Check 拦截、循环检测、连续失败追踪、自适应检查点 | > 仅有前馈,规则永远无法验证是否奏效;仅有反馈,智能体会重复同样的错误。两者缺一不可。 ### 2.2 计算型 vs 推理型 | 类型 | 特点 | 例子 | |------|------|------| | **计算型(Computational)** | 确定性、快速、CPU 执行 | 黑名单匹配、命令风险分级、循环检测、token 估算 | | **推理型(Inferential)** | 语义分析、AI 审查、LLM 调用 | Evolver 用 LLM 提炼经验、LLM 决定下一步工具 | 计算型传感器成本低、速度快,适合每次工具调用都运行(如 `safety.Controller.Check`、`AssessBashRisk`)。推理型传感器更强大但更贵、不确定,适合关键节点(如任务完成后的经验提炼)。 推理型传感器的特别威力:当反馈信号被优化为 LLM 可消费的格式时(如把「连续失败」翻译为「请换一种思路」的中文提示注入对话),形成一种**积极的 prompt injection** —— 这正是 aiops 自适应检查点的设计依据。 ### 2.3 Steering Loop 掌舵循环 Steering Loop 是 Harness Engineering 的元过程 —— 通过迭代改进 Harness 来引导智能体。 ``` ┌──────────┐ Agent 工作 ┌──────────┐ 系统改进 ┌──────────┐ │ Harness │ ──────────► │ 观察问题 │ ──────────► │ 更新Harness│ │ (当前版本) │ │(多次发生) │ │ (新版本) │ └──────────┘ └──────────┘ └──────────┘ ▲ │ └────────────────────────────────────────────────────┘ 循环往复 ``` 在 aiops Agent CLI 中,Steering Loop 有两种实现: 1. **人工 Steering**:管理员在「大模型设置」调整 SystemPrompt、温度等 → 影响 Agent 下次行为 2. **自动 Steering**:Evolver 引擎观察任务执行 → 自动学习经验 → 注入下次 Prompt(详见第 08 篇) 后者是 opsxcli 设计思想的核心延伸 —— 用代码自动化 Steering Loop。 ### 2.4 Keep Quality Left — 把质量左移 在 aiops Agent CLI 的执行链路中,反馈传感器按成本分布: | 阶段 | 应运行的传感器 | 特点 | |------|---------------|------| | **工具执行前** | 黑名单硬拒、`AssessBashRisk` 分级、安全模式阈值 | 毫秒级,每次必跑 | | **工具执行中** | context 超时(`ToolTimeout` 120s 兜底) | 防卡死 | | **轮次间** | 自适应检查点(Round 4/8/12)、循环检测(>3 次拒绝)、连续失败追踪 | 防 LLM 跑偏 | | **任务完成后** | Evolver 异步学习(30s 超时) | 较贵,异步 | --- ## 3. 三类调节 Harness > Agent Harness 如同一个控制论调节器(governor),通过前馈和反馈将系统调节到期望状态。 ### 3.1 可维护性 Harness(Maintainability) - 计算型:文件大小红线(Go handler ≤400 行、组件 ≤700 行)、`go vet`、`tsc --noEmit` - 推理型:代码审查(review) - 在 Agent CLI 代码中体现为「引擎库零业务依赖」「单文件 ≤300 行」等约束 ### 3.2 架构适应度 Harness(Architecture Fitness) - 前馈:分层依赖约定(controller → model + pkg/agentcli,引擎库不反向 import) - 反馈:编译失败即拦截(Go 强类型天然传感器) ### 3.3 行为 Harness(Behaviour)— 本项目的重点 如何引导和感知 Agent 是否按预期功能运行: - 前馈:五层 System Prompt(角色 + 安全规则 + 工作方式 ReAct 范式) - 反馈: - 安全层硬拦截 + 高危确认(防破坏性操作) - ReAct 循环中的自适应检查点(防 LLM 死循环或编造输出) - WebSocket 事件流的可观测性(人类可随时观察思考与命令) - Evolver 经验学习(成功的工具序列被强化,失败的被记录为「换法」提示) --- ## 4. Harnessability 与设计启示 ### 4.1 可 Harness 性 aiops 后端是 Go 强类型 + 清晰的包边界,天然适合被 Harness: - 强类型使 LLM 工具的 JSON Schema 可以严格约束参数 - 清晰的 controller / model / pkg 分层使「引擎库零业务依赖」可行 - 复用 aiops 既有的凭证系统、SSH 包、DB,大幅缩减 Harness 代码量 ### 4.2 Ashby 必要多样性定律 > 调节器必须拥有至少与被调节系统相同的多样性。 aiops Agent CLI 通过两层多样性缩减: 1. **工具集精简**(6 → 2):只保留 `ssh_execute` + `analyze_output`,把「在远程主机做任何事」收敛为「执行 shell + 分析输出」,让 LLM 的决策空间可控 2. **Prompt 工作方式约束**:明确告诉 LLM「一次只做关键的、可验证的一步」「优先只读命令」「失败要换法重试」 这是把潜在的「无限可能的 Agent」收敛为「可控的运维 Agent」的关键策略。 ### 4.3 Harness 模板 aiops Agent CLI 本身就是一个「Web 版运维 Agent Harness 模板」—— 它的前馈(五层 Prompt)、反馈(安全 + 检查点 + Evolver)、工具协议(Tool 接口)可以被视为同类产品的参考实现。 --- ## 5. 反馈回路设计 ### 5.1 多轮自我评审循环 aiops ReAct 循环本质就是一种多轮自我评审: ``` Round 1:LLM 思考 + 决定工具 │ Round 2:执行工具 → 观察输出(exit_code 是关键信号) │ Round 3:根据输出判断 → 继续排障或修复 │ ═══ 检查点 Round 4 ═══ ├─ 若重复调用率 >50% 或连续失败 ≥3 → 注入「换思路」提示 │ Round N:… 直到 LLM 不再返回 tool_calls │ ═══ 检查点 Round 8 ═══ 强制中间总结 ═══ 检查点 Round 12 ═══ 敦促收尾 │ 最终答案 + Evolver 学习(后台) ``` ### 5.2 黄金原则 从 OpenAI Codex 实践提炼的四条原则在 aiops Agent CLI 中的体现: 1. **优先使用共享抽象**:`pkg/remoteexec`(SSH)、`pkg/agentcli/tools`(Tool 接口)、`pkg/agentcli/llm`(Client 接口),将不变式集中管理 2. **不使用「YOLO 式」探测**:所有命令先经 `AssessBashRisk` 评估,黑名单硬拒、高危确认,绝不盲目执行 3. **统一错误处理**:工具返回 `Result{Success, Output, Error}`,错误信息以中文回到对话供 LLM 理解;Evolver 失败优雅降级不阻断主循环 4. **避免全局状态**:`Engine` 每次任务一个实例,`Registry` 通过 `sync.RWMutex` 保护;会话状态走 DB 不走全局变量 --- ## 6. aiops Agent CLI 代码对照 ### 6.1 前馈指导实例 | 理论概念 | aiops 实现 | 代码位置 | |----------|-----------|----------| | 角色与能力引导 | 五层 System Prompt | `pkg/agentcli/prompt/prompt.go` | | 工具能力披露 | Registry 动态生成工具描述 | `core/agent.go: buildToolDescriptions` | | 工作范式引导 | ReAct 范式文本(思考-行动-观察-循环-收尾) | `prompt.go` Layer 4 | | 安全规则文本 | 黑名单 + 优先只读 + 高危确认 | `prompt.go` Layer 2 | ### 6.2 反馈传感器实例 | 理论概念 | aiops 实现 | 代码位置 | |----------|-----------|----------| | 计算型反馈(执行前) | 黑名单硬拒 + 风险分级 | `tools/risk.go` + `safety/safety.go: Check` | | 计算型反馈(轮次间) | 循环检测(同参 >3 拒绝) | `core/agent.go: processToolCalls` | | 计算型反馈(轮次间) | 连续失败追踪 | `core/agent.go: updateConsecutiveFailures` | | 结构化反馈 | 自适应检查点(Round 4/8/12 注入提示) | `core/agent.go: checkAdaptiveCheckpoint` | | 上下文保护 | 消息裁剪 + tool 消息完整性修复 | `core/agent.go: trimMessages` + `ensureToolMessageIntegrity` | | 安全反馈 | 三级模式阈值 + 高危确认 | `safety/safety.go` | ### 6.3 Steering Loop 实例 aiops 的 **Evolver 自进化引擎**是自动 Steering Loop 的代码级实现: ``` EvolverEngine (pkg/agentcli/evolver/) │ ├── engine.go 精简进化循环(OBSERVE→CLASSIFY→LEARN→STORE→MEMORIZE→PREDICT) └── memory.go 四层记忆(experience/factual/procedural/environment) ``` 每次任务执行后,Evolver 异步学习并存储经验;下次任务开始时,`GetContextForPrompt()` 把相关历史经验注入 System Prompt 的 Layer 5 —— 这就是「观察问题 → 改进 Harness」的自动化实现。 ### 6.4 品味不变式实例 | 类别 | 不变式 | 理由 | |------|--------|------| | 语言 | 注释和错误信息使用中文,署名 `// Logan.Li` | 项目规范 | | 命名 | 导出函数 PascalCase,包名全小写 | Go 标准 | | 错误 | `Result.Error` 携带中文错误,Evolver 失败降级不 panic | 保留错误链,不阻断主流程 | | 依赖 | controller → model + pkg/agentcli(单向) | 引擎库零业务依赖 | | 日志 | 引擎 emit Event,由 controller 决定落库还是推 WS | 引擎不直接依赖 DB/WS | | 安全 | 黑名单硬拒不可被确认放行 | 安全红线 | --- ## 7. Web 可观测性 > opsxcli 是 CLI 工具,可观测性 = slog + 审计日志 + `--debug`。 > aiops Agent CLI 是 Web 服务,可观测性 = **WebSocket 事件流 + DB 持久化 + 会话历史回放**。 ### 7.1 事件流(实时) 引擎通过 `EventCallback` 推送结构化事件,controller 序列化为 `wsEvent` 后推 WebSocket: | Event.Type | 含义 | 前端渲染 | |------------|------|----------| | `progress` | 轮次 + token | 顶部进度条 | | `thought` | AI 思考文本 | 思考气泡 | | `tool_call` | 即将执行的工具 + 风险 | 工具调用卡片(含风险标签) | | `tool_result` | 工具输出 + 成败 + 耗时 | 工具结果卡片 | | `confirm` | 高危确认请求 | useConfirm 弹框 | | `done` | 最终答案 | 完成气泡 | | `error` | 错误(含达到最大轮次) | 错误气泡 | ### 7.2 持久化(事后审计) 每条事件(除 progress)落库 `agent_cli_messages`,前端「会话历史」页面可按 session_id 回放完整 ReAct 推理过程: ```go // controller/agent_cli.go: persistMsg // 每条消息记录:round / type / role / content / tool_name / tool_args / // tool_output / risk / success / duration / tokens ``` > 与 opsxcli 的差异:opsxcli 把审计日志写到 `~/.opsxcli/audit/audit.log`(文件),aiops 直接走 DB(多用户、可查询、可关联用户与主机)。 --- ## 8. 参考资源 | 资源 | 说明 | |------|------| | [Martin Fowler — Harness Engineering](https://martinfowler.com/articles/harness-engineering.html) | 理论框架,控制论视角 | | [OpenAI — Harness Engineering](https://openai.com/zh-Hans-CN/index/harness-engineering) | 实践报告,Codex 实战经验 | | [LangChain — Agent = Model + Harness](https://blog.langchain.com/the-anatomy-of-an-agent-harness/) | 术语定义 | | [Anthropic — Effective Harnesses for Long-Running Agents](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents) | 长时间运行 Agent 的 Harness 设计 | > 作者:Logan.Li