Files

18 KiB
Raw Permalink Blame History

Agent 架构设计(MVP 版)

一、MVP 全景

用户输入
    ↓
┌──────────────────────────────────────────┐
│      意图识别(Intent Recognition) 🆕     │
│      "用户想干什么?"                      │
│                                           │
│  诊断意图   → 路由到诊断 Skill             │
│  文档意图   → 路由到文档问答               │
│  案例意图   → 路由到案例查询               │
│  闲聊       → 快速响应(不启动 Agent)     │
│  模糊/无关   → 提示用户,直接中断           │
└──────────────┬───────────────────────────┘
               │ 诊断意图
               ↓
┌──────────────────────────────────────────┐
│        Supervisor Agent(调度者)          │
│        "谁来干?什么时候停?"             │
└──────────────┬───────────────────────────┘
               ↓
┌──────────────────────────────────────────┐
│        Planner Agent(规划者)             │
│        分析问题 → 制定策略 → 生成报告      │
└──────────────┬───────────────────────────┘
               ↓
┌──────────────────────────────────────────┐
│        Executor Agent(执行者)             │
│        调用工具收集证据                    │
└──────────────┬───────────────────────────┘
               ↓
┌──────────────────────────────────────────┐
│        Verifier Agent(验证者)             │
│        事实核查 → 判定通过/修正/驳回       │
└──────────────┬───────────────────────────┘
               ↓
         诊断报告输出
               ↓
         用户反馈(有用/无用)
               ↓
      案例沉淀 + BadCase 优化

二、意图识别(入口层)🆕

2.1 设计理念

定位:独立模块,不嵌入任何单一 Agent

分层策略(不是二选一,而是组合):

L0: 正则规则 —— 0 成本,毫秒级 ✅ MVP
├─ 处理 80%+ 的结构化查询
├─ 正则匹配订单号/traceId/错误码格式
└─ 关键词匹配("报错"/"异常"/"失败")

L1: 小模型 Agent —— 低成本,百毫秒级 ✅ MVP
├─ L0 未命中时触发
├─ 处理灵活的模糊表达("系统有点慢"、"怎么查不到了")
├─ 不启动全链路 Agent,只做意图分类
└─ 判断为诊断意图 → 路由到诊断 Skill

L2: 兜底策略 —— 极少使用
├─ L0+L1 都无法判断 → 意图不明 → 中断
└─ Phase 2 增强

2.2 意图分类与路由

┌────────────────────────────────────────────────────┐
│ 意图            │ 说明                    │ 路由      │
├────────────────────────────────────────────────────┤
│ 诊断意图         │ 包含结构化标识或错误描述  │ → 诊断Skill│
│ 文档问答         │ "XX接口的参数有哪些"       │ → 直接RAG  │
│ 案例查询         │ "之前有类似的问题吗"       │ → 案例检索  │
│ 闲聊             │ "你好"/"谢谢"             │ → 快速响应  │
│ 意图不明         │ 无法识别                 │ → 中断+提示 │
└────────────────────────────────────────────────────┘

关键原则:
- 只有诊断意图才启动 Agent 全链路
- 非诊断意图走轻量路径或直接中断

2.3 L0:正则规则(MVP,处理 80%)

为什么先做 L0?
→ 0 成本(不调 LLM),毫秒级响应
→ 结构化查询占比最大(订单号、traceId、错误码、关键词)
→ L0 命中直接路由,不需要走后续逻辑

规则配置(可扩展):
┌────────────────────────────────────────────────┐
│ 规则                          │ 意图  │ 方式  │
├────────────────────────────────────────────────┤
│ 匹配 \d{12,}                  │ 诊断  │ 正则  │
│ 匹配 trace[-_]?\w{8,}          │ 诊断  │ 正则  │
│ 包含"报错‖失败‖异常‖挂了‖超时"  │ 诊断  │ 关键词│
│ 包含"文档‖接口‖参数‖字段‖API"  │ 文档  │ 关键词│
│ 包含"案例‖之前‖类似‖历史"      │ 案例  │ 关键词│
│ 长度 <= 5 字符                │ 闲聊  │ 规则  │
└────────────────────────────────────────────────┘

命中 → 直接路由,不调 L1
未命中 → 进入 L1

2.4 L1:小模型 Agent(MVP,处理剩余 20%)

为什么用小模型 Agent 而非嵌入到 Supervisor?
→ 意图识别是独立职责,不应耦合到任何业务 Agent
→ 轻量 Agent:单一职责,只分类不执行
→ 成本低(~50 token),延迟低(~200ms)

何时触发:L0 规则未命中

System Prompt:
"你是意图分类器,判断用户想做什么。
 只返回一个词:[诊断 / 文档查询 / 案例查询 / 闲聊 / 意图不明]
 
 诊断:用户描述了故障、报错、异常
 文档查询:用户询问接口文档、字段含义
 案例查询:用户询问历史案例、类似问题
 闲聊:简单的问候、感谢
 意图不明:无法判断用户意图"

输入:用户原始输入
输出:意图类型 + 置信度

2.5 L2:兜底策略

L0+L1 都无法判断 → L2 兜底

中断规则:
├─ 意图不明 → 提示用户 + 中断
│   "无法判断您的意图,请提供订单号或错误码"
├─ 闲聊 → 快速响应 + 中断
│   "我是故障诊断助手,请描述您遇到的问题"
└─ 不启动 Agent,直接返回

路由规则:
├─ 诊断意图 → 启动 Supervisor + 4 Agent 全链路
├─ 文档意图 → 不启动 Agent,直接 RAG 检索
└─ 案例意图 → 不启动 Agent,直接查询 case_library

2.5 架构位置

用户输入
    ↓
┌──────────────────────────────────────────┐
│        意图识别模块(独立)                │
│                                           │
│  L1: 小模型 Agent ─→ 诊断意图?           │
│       │             文档意图?           │
│       │             案例意图?           │
│       │             闲聊?             │
│       ↓                                 │
│  L2: 兜底 ─────────→ 意图不明 → 中断     │
│                      闲聊 → 快速响应      │
└───────────────┬──────────────────────────┘
                │ 诊断意图
                ↓
    Supervisor → Planner → Executor → Verifier

2.6 MVP vs Phase 2

MVP         L0(正则)+ L1(小模型Agent)     覆盖 95%+ 场景
Phase 2     L2(兜底增强)                   细化中断提示,支持多轮澄清

三、4 个 Agent 设计

2.1 Supervisor Agent(调度者)

职责:总指挥,协调工作流

调度规则:
├─ 接收任务 → 发给 Planner 分析
├─ Planner 完成 → 发给 Executor 执行
├─ Executor 完成 → 发给 Verifier 校验
└─ Verifier PASS → 输出报告 / REJECT → 返回 Planner 重新规划

不做:
- 不直接调用工具
- 不直接生成报告

2.2 Planner Agent(规划者 + 分诊)

职责:分析问题、制定策略、生成报告草稿

分析规则:
├─ 有 errorCode + 接口 URL → EXTERNAL_API(外部接口故障)
├─ 有堆栈信息 → INTERNAL_ERROR(系统内部错误)
├─ 有数据库错误码(如 1213)→ DATABASE(数据库问题)
└─ 其他 → 通用排查

规划流程:
1. 确定 fault_category
2. 制定排查步骤(每步:工具名 + 参数 + 预期)
3. 生成决策:EXECUTE(继续执行)| FINISH(生成报告)

Replanner 职责:
├─ Executor 每次返回结果后 → 评估证据是否充分
├─ 需要补充?→ 调整步骤,继续执行
├─ 证据齐全?→ FINISH,生成报告草稿
└─ 连续 3 次失败?→ 降级

禁止:
- 编造数据
- 引用未经工具返回的内容

2.3 Executor Agent(执行者)

职责:调用工具收集证据

工具清单:
├─ queryOrder:查询订单/业务数据(MySQL 只读)
├─ searchDoc:检索接口文档(混合检索 Milvus + MySQL)
├─ recommendCase:推荐相似案例(精确匹配 + 语义检索)
└─ getCurrentTime:获取当前时间

执行规则:
├─ 每次只执行 Planner 指定的一个步骤
├─ 返回结构化的执行结果
├─ 失败时返回错误详情(便于 Planner 调整)
└─ 禁止编造结果

扩展预留:
// 代码中 Executor 是接口,后续可扩展为 SubAgent
public interface Executor {
    ExecutionResult execute(Step step);
}

2.4 Verifier Agent(验证者)

职责:验证诊断报告,防止编造

验证流程:

1️⃣ 事实核查(最重要)
├─ 报告中的错误码 → 在 tool_calls 中存在?
├─ 根因结论 → 有日志/文档证据支撑?
├─ 修复方案 → 引用了文档或案例?
└─ 发现编造数据 → 直接 REJECT

2️⃣ 完整性检查
├─ 根因分析章节不能为空
├─ 证据链章节不能为空
└─ 修复方案章节不能为空

判决结果:
├─ PASS:报告成立,直接输出
├─ REVISE:小问题可修正,返回 Planner 微调
└─ REJECT:编造数据或严重错误,返回 Planner 重新分析

四、RAG 两层加载策略

4.1 设计理念

问题:
❌ 全前置:启动时把所有文档塞给 Agent → 信息过载,推理变慢
❌ 纯被动:等到需要才查 → Planner 没有全局视野,可能跑偏
❌ 固定步骤:每次都调 → 内部错误查接口文档浪费

正确做法:两层互补

L1 预加载(Planner 启动时)
→ 通用领域知识:系统架构、通用错误码、业务流程
→ 给 Planner 全局视野,避免方向性错误

L2 按需加载(Executor 执行中)
→ 具体接口文档:字段定义、错误码含义、调用规范
→ 给 Executor 精准证据,定位具体问题

4.2 两层对比

L1 预加载 L2 按需加载
触发时机 意图识别后,Planner 启动前 Executor 拿到具体信息后
内容 通用知识(架构、流程、高频错误码) 具体接口文档(字段、错误码含义)
目的 让 Planner 有全局视野 让 Executor 有精准证据
成本 固定,每次诊断 1 次 按需,最多 2-3 次
谁负责 Supervisor 注入 Executor 自主调用

4.3 实现方式

L1 预加载:
Supervisor 在启动 Planner 前:
  searchDoc(keyword="系统架构 通用错误码 业务流程")
  → 注入到 Planner 的 System Prompt 中
  → Planner 拥有"领域背景知识"

L2 按需加载:
Executor 执行 Step 2 时:
  拿到 errorCode=40003, faultSource="广东"
  → 自主调用 searchDoc(errorCode="40003", faultSource="广东")
  → 获取该接口的具体字段定义和错误码说明
  → 作为证据写入诊断报告

五、Skill 设计(1 个)

/diagnose-by-orderid(按订单号诊断)

输入:orderId

工作流(6 步):

Step 1: 查询订单信息
  工具:queryOrder
  失败:ABORT(订单不存在则终止)

Step 2: 检索接口文档
  工具:searchDoc
  参数:errorCode + faultSource
  失败:SKIP(标注"文档缺失")

Step 3: 查询日志
  工具:queryLogs(Mock)
  参数:traceId
  失败:SKIP(标注"日志缺失")

Step 4: 检索相似案例
  工具:recommendCase
  参数:errorCode + faultCategory
  失败:SKIP(标注"无相似案例")

Step 5: 生成诊断报告
  汇总所有证据,按模板生成报告

Step 6: Verifier 验证
  事实核查 → 判决

门禁规则:
├─ Step 1 失败 → 终止,返回"订单不存在"
├─ Step 2-4 失败 → 跳过,标注缺失信息
├─ 任意步骤超时 30s → 终止
└─ Verifier REJECT → 返回 Planner 重新规划

六、Harness 控制层(精简版)

4.1 5 个 Quality Gates

输入门禁(2 个):
├─ Gate 1: 输入参数非空校验
└─ Gate 2: 5 分钟内同一订单 → 返回缓存

执行门禁(1 个):
└─ Gate 3: 工具调用超时(10 秒)

输出门禁(2 个):
├─ Gate 4: 报告章节完整性(3 章节不全 → 不通过)
└─ Gate 5: 置信度阈值(< 60 → 标记"低置信度")

4.2 中断规则

自动中断:
├─ 工具连续失败 3 次 → 终止,降级输出
└─ 全局超时 30 秒 → 终止

条件降级:
├─ 文档检索为空 → 跳过继续
├─ 案例推荐为空 → 跳过继续
└─ 日志查询失败 → 跳过继续

降级输出:
"无法自动诊断,请人工介入"
+ 已收集的证据(订单信息 + 部分日志 + 已知错误码)

七、技术实现

5.1 基于 Spring AI Alibaba

// Supervisor - 框架提供
SupervisorAgent supervisor = SupervisorAgent.builder()
    .name("diagnosis_supervisor")
    .model(chatModel)
    .subAgents(List.of(planner, executor, verifier))
    .build();

// Planner
ReactAgent planner = ReactAgent.builder()
    .name("planner_agent")
    .model(chatModel)
    .systemPrompt(plannerPrompt)
    .outputKey("planner_plan")
    .build();

// Executor(代码中预留 SubAgent 扩展接口)
ReactAgent executor = ReactAgent.builder()
    .name("executor_agent")
    .model(chatModel)
    .systemPrompt(executorPrompt)
    .methodTools(diagnosisTools)
    .tools(new ToolCallback[]{queryOrder, searchDoc, recommendCase, getCurrentTime})
    .build();

// Verifier
ReactAgent verifier = ReactAgent.builder()
    .name("verifier_agent")
    .model(chatModel)
    .systemPrompt(verifierPrompt)
    .outputKey("verifier_result")
    .build();

5.2 工具注册

@Component
public class DiagnosisTools {
    
    @Tool(description = "查询订单/业务数据(只读)")
    public OrderInfo queryOrder(@ToolParam(description = "订单号") String orderId) {
        // MySQL 只读 + SQL 注入防护
    }
    
    @Tool(description = "检索接口文档")
    public List<DocChunk> searchDoc(
        @ToolParam(description = "错误码") String errorCode,
        @ToolParam(description = "省份/服务名") String faultSource
    ) {
        // 混合检索:精确匹配 + 向量检索
    }
    
    @Tool(description = "推荐相似历史案例")
    public List<CaseResult> recommendCase(
        @ToolParam(description = "错误码") String errorCode,
        @ToolParam(description = "故障类别") String faultCategory
    ) {
        // 精确匹配 MySQL + 语义检索 Milvus
    }
}

八、闭环机制

诊断报告输出
    ↓
用户反馈(useful / not_useful)
    ↓
├─ useful → 自动生成 case_library
└─ not_useful → 记录 BadCase
    ↓
每周 BadCase 分析
    ↓
Prompt / Skill 优化
    ↓
准确率验证(测试集重跑)

九、MVP vs 扩展方向

维度 MVP 扩展方向
Agent 4 个 Agent SubAgent 模式(专科医生)
Skill 1 个 渐进式披露(3 层知识)
工具 @Tool 注解 MCP 独立 Server
回退 2 级(失败→降级) 4 级路由
Gates 5 个 15 个全流程门禁
隔离 单 JVM K8s Pod 进程隔离
进化 案例自动生成 模式识别 + Prompt 自优化

十、面试话术(精简版)

"我用 Spring AI Alibaba 实现了一个故障诊断 Agent 系统。

入口层是意图识别:先判断用户想干什么——诊断故障、查文档、查案例还是闲聊。 非诊断意图直接走轻量路径,只有诊断意图才启动 Agent 全链路,节省资源。

4 Agent 协作:Supervisor 调度、Planner 制定策略、 Executor 调用工具收集证据、Verifier 验证报告防止编造。

诊断流程封装成了 Skill,标准化 6 个步骤和异常处理。 Harness 层 5 个门禁保证质量——最关键的是输出门禁, Verifier 会对比报告数据和工具返回数据,发现编造就驳回。

闭环机制:用户反馈 → BadCase 分析 → Prompt 优化。 案例自动沉淀,系统越用越智能。"