Browse Source

完成了 AI 执行链流程图的 5 项差异修正,并建立了三层持续同步机制(CLAUDE.md 规则 + Stop Hook + JavaDoc 标记)

TDesign-Vue-Next-1.20.6
wanghanlin 3 weeks ago
parent
commit
fc1193c4f3
  1. 20
      CLAUDE.md
  2. 50
      frontend/src/views/PipelineFlow.vue
  3. 27
      src/main/java/com/wok/supportbot/app/AssistantApp.java
  4. 6
      src/main/java/com/wok/supportbot/app/ChatPipeline.java
  5. 6
      src/main/java/com/wok/supportbot/rag/RagPipeline.java

20
CLAUDE.md

@ -179,6 +179,26 @@ catch (e) { toast(e.message || '操作失败', 'error') }
catch (e) { toast('操作失败', 'error') }
```
### 前后端:AI 执行链示意图与代码保持同步
**规则**: 对 `app/`、`rag/`、`advisor/` 包中核心编排类的**结构性变更**(新增/删除管道阶段、调整调用链、引入新组件),**必须同步更新以下两处架构图**,否则示意图与实际代码会不一致:
| 文件 | 内容 | 说明 |
|------|------|------|
| `frontend/src/views/PipelineFlow.vue` | Mermaid 流程图 DSL(`GRAPH_DEFINITION` 常量) | 管理后台「AI 执行链」页面的可视化图表 |
| `CLAUDE.md` 中的 ASCII 管道图 | 文本流程描述("统一对话管道"章节) | 供 AI 和开发者快速了解架构 |
**触发条件**(满足任一即需更新):
- `ChatPipeline.buildRequest()` 的决策分支(意图路由、FAQ、RAG、纯对话路径)发生变更
- `RagPipeline.retrieve()` 的检索流程(查询重写策略、检索方式、资料拼装)发生变更
- `AssistantApp` 的 Advisor 链成员或顺序发生变更(如新增/移除 Advisor)
- 新增管道阶段组件(如 `IntentRouter`、`SuggestionGenerator`、`SimpleCircuitBreaker` 等)或移除现有组件
- 组件间调用关系调整(如原来 A→B 改为 A→C→B)
**图表元数据**: `PipelineFlow.vue` 中 DSL 首行有 `%%graph-meta` 注释标记最后更新时间,修改图表时必须更新该日期。
**反面案例**: commit `527d9e7` 创建的流程图展示了 RAG 子图中 `VECTOR → RRF | KEYWORD → RRF | HYBRID → RRF → Reranker` 的三模式检索流程,但实际 `RagPipeline.similaritySearch()` 仅做纯向量检索,`HybridSearchService`/`RrfFusion`/`RerankerService` 尚未接入主对话流程,导致图表与代码事实不符。
## API 路由约定
- AI 对话: `/ai/*`(`AiController`)

50
frontend/src/views/PipelineFlow.vue

@ -3,8 +3,8 @@
<template #header>
<span style="font-size:16px;font-weight:600;">🔀 AI 执行链</span>
<p style="font-size:12px;color:var(--td-text-color-placeholder);margin:4px 0 0;">
下图展示从用户请求到 AI 回复的完整处理流程包含意图路由RAG 检索和 Advisor
菱形节点 = 决策分支 · 虚线框 = 独立子系统 · /绿/黄色高亮 = 入口/出口/LLM
下图展示从用户请求到 AI 回复的完整处理流程包含意图路由RAG 检索熔断保护 Advisor
菱形节点 = 决策分支 · 虚线框 = 独立子系统 · 虚线箭头 = 降级/异步路径
</p>
</template>
@ -59,19 +59,20 @@ mermaid.initialize({
// Mermaid DSL
// : []=, {}=, subgraph=
// %%graph-meta: { updated: "2026-08-04", basedOn: "ChatPipeline v3, RagPipeline v2, AssistantApp v2", mermaidVersion: "flowchart-v2" }
const GRAPH_DEFINITION = `
flowchart TD
A["<b>用户请求</b><br/>message + roleId + accountId + chatId"]
A --> B{"<b>Controller</b><br/>鉴权 / 角色解析<br/>构建 ChatContext"}
A --> B{"<b>Controller</b><br/>鉴权 / 角色解析 / KB 隔离判断<br/>构建 ChatContext"}
B --> C["<b>ChatPipeline.buildRequest</b><br/>编排决策入口"]
C --> D{"enableRag ?"}
D -- "❌ false" --> E["<b>模式: 纯对话</b><br/>systemPrompt(角色人设)<br/>不检索知识库"]
D -- "❌ false" --> E["<b>模式: 纯对话</b><br/>systemPrompt(角色人设 + 全局配置)<br/>不检索知识库"]
D -- "✅ true" --> F["<b>IntentRouter</b><br/>LLM 意图识别<br/>FAQ / RAG / CHITCHAT"]
D -- "✅ true" --> F["<b>IntentRouter</b><br/>🔹 寒暄词快速路径: 本地列表精确匹配(零 LLM)<br/>🔹 未命中则 LLM 意图分类<br/>FAQ / RAG / CHITCHAT"]
F --> G{"意图分类结果"}
@ -81,26 +82,27 @@ flowchart TD
G -- "RAG / 降级<br/>其余情况" --> J["<b>RagPipeline.retrieve</b><br/>RAG 检索流水线入口"]
subgraph RAG["📚 RAG 检索流水线"]
J --> K["<b>1. FAQ 优先匹配</b><br/>FaqMatchEngine 三级匹配<br/>命中则短路返回"]
H -- "✅ 命中标准答案" --> T
H -. "❌ 未命中 → 降级 RAG" .-> J
subgraph RAG["📚 RAG 检索流水线(当前: 纯向量检索)"]
J --> K["<b>1. FAQ 优先匹配(二次兜底)</b><br/>FaqMatchEngine 三级匹配<br/>命中则短路返回"]
K --> L["<b>2. 查询重写</b><br/>REWRITE / TRANSLATION<br/>COMPRESSION / MULTI_QUERY"]
L --> M{"<b>3. 检索模式</b>"}
M --> N["<b>VECTOR</b><br/>向量语义检索"]
M --> O["<b>KEYWORD</b><br/>全文关键词检索<br/>PostgreSQL tsvector"]
M --> P["<b>HYBRID</b><br/>向量 + 关键词<br/>双路检索"]
N --> Q["<b>4. RRF 融合排序</b><br/>Reciprocal Rank Fusion<br/>k=60"]
O --> Q
P --> Q
Q --> R["<b>5. Reranker 重排序</b><br/>DashScope / OpenAI 兼容<br/>超时 3s 自动 fallback"]
R --> S["<b>6. 构建资料块</b><br/>拼接检索文档<br/>注入 system prompt 末尾"]
L --> M["<b>3. 向量检索</b><br/>PGVector similaritySearch<br/>topK=4 + 分类过滤"]
M --> S["<b>4. 构建资料块</b><br/>拼接检索文档<br/>注入 system prompt 末尾"]
end
H --> T["<b>组装 ChatRequest</b><br/>finalMessage + finalSystemPrompt<br/>+ faqAnswer (可选)"]
I --> T
S --> T
E --> T
T --> U["<b>AssistantApp</b><br/>chat / chatStream<br/>构建 ChatClient + MCP 工具"]
T["<b>组装 ChatRequest</b><br/>finalMessage + finalSystemPrompt<br/>+ faqAnswer (可选)"]
T --> CB{"<b>🔌 AI 熔断检查</b><br/>SimpleCircuitBreaker<br/>阈值: 连续 3 次失败 / 恢复: 5 分钟"}
CB -- "熔断中" --> FALLBACK["<b>返回降级提示</b><br/>「AI 服务暂时不可用<br/>请稍后重试」"]
CB -- "正常" --> U["<b>AssistantApp</b><br/>chat / chatStream<br/>构建 ChatClient + MCP 工具"]
subgraph ADVISOR["🛡️ Advisor 链(环绕 LLM 调用)"]
U --> V["<b>ContentSafetyAdvisor</b><br/>🔽 before: DFA 敏感词检测<br/>用户输入 BLOCK/MASK"]
@ -113,9 +115,21 @@ flowchart TD
AA --> AB["<b>返回 AI 回复</b><br/>SSE 流式输出<br/>+ MCP 工具调用事件"]
FALLBACK --> AB
AB -. "异步按需触发" .-> SG
subgraph SUGGEST["💡 推荐问题(异步)"]
SG["<b>SuggestionGenerator</b><br/>独立 ChatClient(无 MCP 工具)<br/>基于最近 10 条历史<br/>生成 3 条推荐问题<br/>超时 15s · 结果缓存"]
end
style A fill:#dbeafe,stroke:#3b82f6,stroke-width:2px
style AB fill:#d1fae5,stroke:#10b981,stroke-width:2px
style Y fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
style CB fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
style FALLBACK fill:#fee2e2,stroke:#ef4444,stroke-width:2px,stroke-dasharray:5
style M fill:#e0e7ff,stroke:#a5b4fc,stroke-width:2px
style S fill:#e0e7ff,stroke:#a5b4fc,stroke-width:2px
`
const svg = ref('')

27
src/main/java/com/wok/supportbot/app/AssistantApp.java

@ -29,11 +29,28 @@ import java.util.Map;
import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;
/**
* @Classname AssistantApp
* @Description
* @Version 1.0.0
* @Date 2025/06/27 14:11
* @Author lyx
* AI 对话执行层 ChatClient 构建缓存管理与 LLM 调用执行
* <p>
* 本类负责 ChatClient 生命周期 appType + allowedMcpTools 缓存LRU 淘汰
* Advisor 链装配ContentSafetyAdvisor MessageChatMemoryAdvisor MyLoggerAdvisor
* 以及同步/流式对话执行含熔断保护对话编排决策由 {@link ChatPipeline} 完成
* <p>
* 核心方法
* <ul>
* <li>{@link #chat(ChatContext)} 同步对话返回纯文本</li>
* <li>{@link #chatWithEvents(ChatContext)} 同步对话 + MCP 工具调用事件</li>
* <li>{@link #chatStream(ChatContext)} 流式对话返回 Flux&lt;String&gt;</li>
* </ul>
* <p>
* {@code @pipeline} execution-layer order=2<br>
* {@code @pipeline-step} 熔断检查: SimpleCircuitBreaker(3次失败/5分钟恢复) 熔断时返回降级提示<br>
* {@code @pipeline-step} Advisor链: ContentSafetyAdvisor(HIGHEST) MessageChatMemoryAdvisor MyLoggerAdvisor<br>
* {@code @pipeline-step} ChatClient.call/stream: LLM 大模型调用 成功/失败记录到熔断器<br>
* 同步至: frontend/src/views/PipelineFlow.vue Advisor 子图 & 熔断节点
*
* @author lyx
* @version 1.0.0
* @date 2025/06/27 14:11
*/
@Component
@Slf4j

6
src/main/java/com/wok/supportbot/app/ChatPipeline.java

@ -27,6 +27,12 @@ import java.util.Optional;
* <p>
* 接入 {@link IntentRouter} 替代原 {@code AiController.shouldBypassKnowledgeRetrieval} 的硬编码寒暄词判断
* 寒暄词列表保留为快速路径与兜底IntentRouter 负责细粒度意图分类二者命中其一即跳过 KB 检索
* <p>
* {@code @pipeline} orchestration-layer order=0<br>
* {@code @pipeline-step} buildRequest: 意图路由 FAQ优先 RAG检索 提示词组装<br>
* {@code @pipeline-step} routeIntent: 寒暄词快速路径 IntentRouter LLM分类 降级RAG<br>
* {@code @pipeline-step} effectiveSystem: DB全局提示词 + 角色人设 动态组合<br>
* 同步至: frontend/src/views/PipelineFlow.vue, CLAUDE.md ASCII管道图
*/
@Component
@Slf4j

6
src/main/java/com/wok/supportbot/rag/RagPipeline.java

@ -44,6 +44,12 @@ import java.util.stream.Collectors;
* 消除上下文注入位置随策略不同而不同的不一致
* <p>
* 阶段一作为旁路组件存在 {@code AssistantApp} RAG 路径未改动阶段二由 {@code ChatPipeline} 接入
* <p>
* {@code @pipeline} rag-layer order=1<br>
* {@code @pipeline-step} retrieve: FAQ优先匹配 查询重写/扩展 similaritySearch(PGVector) 资料拼接<br>
* {@code @pipeline-step} similaritySearch: 纯向量检索 topK=4 + CategoryFilter 分类过滤<br>
* 注意: HybridSearchService/RrfFusion/RerankerService 尚未接入本管道当前仅单路向量检索<br>
* 同步至: frontend/src/views/PipelineFlow.vue RAG 子图
*/
@Component
@Slf4j

Loading…
Cancel
Save