Archive pre-refactor interview notes and add current deep-dives on architecture evolution, issue-derived stories, and evidence gates.
128 lines
4.9 KiB
Markdown
128 lines
4.9 KiB
Markdown
# RAG 重构故事
|
||
|
||
## 1. 起点
|
||
|
||
原始 RAG 实现已经能支撑 MVP:
|
||
|
||
- 文档可以上传、切片、向量化,并写入 Milvus/Zilliz。
|
||
- Agent 可以显式调用 `lookup_knowledge`。
|
||
- AIOps 诊断能在告警流程里检索排障知识。
|
||
- 工具调用会落到 `tool_invocation`,检索步骤可见。
|
||
|
||
但它有几个工程问题:
|
||
|
||
- 检索实现过于依赖 Milvus SDK,业务代码承担了太多底层搜索细节。
|
||
- L0 和 L1 职责不清,L0 关键词命中容易被当作最终召回决策。
|
||
- chunk 级检索容易丢失章节上下文。
|
||
- `breadcrumb` 存在 metadata 中,但没有充分参与 embedding、filter 和上下文重建。
|
||
- 检索质量主要靠手工接口和日志判断,缺少可重复的 golden cases。
|
||
|
||
所以重构目标不是“全盘替换成框架”,而是:
|
||
|
||
```text
|
||
通用 RAG 基础设施交给 Spring AI,
|
||
业务可观测链路保留在项目里。
|
||
```
|
||
|
||
## 2. 我如何拆解问题
|
||
|
||
我把迁移拆成几个阶段,因为 RAG 同时影响 Agent 工具层、AIOps、向量检索、证据打包和 Trace。
|
||
|
||
第一步是建立 baseline。`eval/rag-retrieval/` 中的 golden cases 用来对比后续改动,而不是只靠直觉判断检索有没有变好。
|
||
|
||
第二步是明确职责:
|
||
|
||
```text
|
||
L0 = domain/entity hint
|
||
L1 = semantic retrieval
|
||
postprocess = evidence shaping + trace-friendly output
|
||
```
|
||
|
||
L0 仍然有价值,但不再默认绕过语义检索。它更适合提取服务名、告警名、错误码、领域和 metadata filter。
|
||
|
||
第三步是增强 evidence 输出。Agent 不应该只拿到 raw chunk,而应该拿到带 source、title、breadcrumb、score、hit reason 的证据块。
|
||
|
||
最后,我把 Spring AI `VectorStore` 接入为读取主路径,同时保留原 Milvus SDK 作为 fallback。
|
||
|
||
## 3. 当前架构
|
||
|
||
```text
|
||
Agent / API
|
||
-> lookup_knowledge or /api/search/similar
|
||
-> L0 domain/entity hint
|
||
-> VectorSearchService
|
||
-> Spring AI VectorStore
|
||
-> Milvus SDK fallback
|
||
-> relevance normalization
|
||
-> tool_invocation trace
|
||
```
|
||
|
||
`VectorSearchService` 仍然是公共检索门面。Agent 工具层不需要知道底层是 SDK 还是 Spring AI。
|
||
|
||
支持三种模式:
|
||
|
||
```text
|
||
auto -> 优先 Spring AI VectorStore,失败后 fallback 到 SDK
|
||
spring-ai -> 强制 Spring AI VectorStore
|
||
sdk -> 强制 Milvus SDK
|
||
```
|
||
|
||
## 4. 关键取舍
|
||
|
||
### 保留显式工具
|
||
|
||
我没有把检索藏进 Spring AI Advisor。原因是这个项目强调 Agent 执行可见性:`lookup_knowledge` 的 query、命中文档、相关性和证据预览都要进入 Trace。
|
||
|
||
### 保留 SDK fallback
|
||
|
||
SDK fallback 不是废代码,而是迁移安全网。实际验证时,第一次 VectorStore 指向了错误 collection,`auto` 模式 fallback 到 SDK 后仍能返回结果。修正 collection 后,Spring AI 路径成为主路径。
|
||
|
||
### L0 降权
|
||
|
||
生产事故中经常有精确标识:错误码、告警名、服务名、指标名。L0 适合做 hint,但不应该做最终裁判。
|
||
|
||
### 分数语义拆开
|
||
|
||
SDK 使用 L2 distance,Spring AI 暴露 similarity。混在一个字段里会让 relevance normalization 出错。
|
||
|
||
当前拆成:
|
||
|
||
```text
|
||
score -> 兼容旧逻辑的距离型分数
|
||
rawScore -> 底层原始分数
|
||
scoreLabel -> rawScore 的语义
|
||
```
|
||
|
||
### 暂不迁移写入
|
||
|
||
写入和索引仍走 SDK。这是有意分阶段:先验证读路径,再评估 `VectorStore.add(...)` 是否适合现有 metadata 和 chunk 模型。
|
||
|
||
## 5. 验证方式
|
||
|
||
我用了三层验证:
|
||
|
||
- 单元测试:SDK mode、Spring AI mode、auto fallback、category filter、distance metadata mapping。
|
||
- Live API:`GET /api/search/similar?query=ERR_TIMEOUT&topK=3`。
|
||
- 代表性 query 对比:错误码、支付超时、MySQL 连接池、AIOps 告警式 query、抽象 RAG 设计问题。
|
||
|
||
核心排障和 AIOps query 在 SDK 与 VectorStore 下 top3 一致。差异主要集中在抽象设计类问题和 metadata taxonomy,这些被记录为后续质量工作。
|
||
|
||
## 6. 面试短版
|
||
|
||
```text
|
||
这个 RAG 系统最初是基于 Milvus SDK 的自研 MVP。它能跑,但底层检索细节过多地散落在业务代码里,L0/L1 职责也不够清晰。
|
||
我按阶段重构:先加 retrieval baseline,再把 L0 降级为 domain/entity hint,再增强 evidence postprocess,最后把读取主路径切到 Spring AI VectorStore,并保留 SDK fallback。
|
||
我没有把 lookup_knowledge 替换成隐式 Advisor,因为这个项目的核心是可追踪 Agent:面试官可以看到什么时候检索、检索了什么、证据如何支撑诊断。
|
||
```
|
||
|
||
## 7. 可主动承认的不足
|
||
|
||
- metadata taxonomy 还需要清理,例如 `database` 与 `infrastructure`。
|
||
- 抽象设计问题可能需要 query rewrite 或更好的文档索引。
|
||
- 邻居 chunk / 同章节上下文扩展还不完整。
|
||
- rerank、RRF、BM25、hybrid retrieval 还没有接入。
|
||
- 写入路径仍使用 SDK。
|
||
|
||
这些不是当前迁移阻塞项,而是后续检索质量优化方向。
|
||
|