后端引擎 backend/pkg/agentcli/(纯引擎库,零业务依赖,剥离 CLI/TUI 外壳): - llm: OpenAI 兼容客户端,复用 model.LLMConfig - tools: ssh_execute(复用 pkg/remoteexec)+ analyze_output + 风险评估黑名单 - safety: 三级安全模式 + 五级风险 + WebSocket 异步确认 - prompt: 五层 System Prompt - core: ReAct 16 轮循环 + 自适应检查点 + 循环检测 - evolver: 四层记忆 + 进化循环,data/agentcli/ 文件存储 集成层: - controller/agent_cli.go: WebSocket 控制器(事件流推流 + 高危确认 + 会话持久化) - model/agent_cli.go: agent_cli_sessions/messages 表 + AutoMigrate - 路由 /ws/agent-cli + /api/v1/aiops/agent-cli/sessions - seed 权限 aiops:agent-cli / aiops:llm-config 前端: - AgentCLI.tsx: 对话流 + 工具块 + 高危确认 + 四模块 tips 面板 - LLMConfig.tsx: 大模型设置独立页 - api/agentCli.ts + Sidebar/App 菜单路由 文档: - docs/agent/ 11 篇(opsxcli 同名文档适配改写 + 00-README 映射总览) 其他: - CLAUDE.md 补充 agent-cli 模块说明 - 修正 .gitignore 根级二进制规则(前导 /,避免误伤 frontend/src/components/aiops/) Co-Authored-By: Claude <noreply@anthropic.com>
277 lines
14 KiB
Markdown
277 lines
14 KiB
Markdown
# 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
|