Files
geo/docs/qdrant-rag-architecture-v1.md
T
root de30497f59 feat: add tenant and user management with migrations, handlers, and tests
- Implemented tenant and user management features including:
  - Tenant creation and management with associated migrations.
  - User creation and management with associated migrations.
  - Tenant membership management with associated migrations.
  - Platform user roles management with associated migrations.
  - Quota management with associated migrations.
  - Article and template management with associated migrations.
- Added HTTP handlers for templates and workspaces.
- Created tests for protected and public routes.
- Introduced a script to check tenant scope in SQL queries.
- Documented task plan for backend completion and frontend foundation.
2026-04-01 00:58:42 +08:00

651 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GEO 平台 Qdrant 版 RAG 架构设计 V1
## 1. 文档信息
| 项目 | 内容 |
| --- | --- |
| 文档名称 | GEO 平台 Qdrant 版 RAG 架构设计 V1 |
| 文档版本 | V1.0 |
| 文档状态 | 待评审 |
| 创建日期 | 2026-03-25 |
| 适用范围 | GEO 平台 V1 知识库与高精度 RAG 检索 |
| 关联文档 | `docs/geo-platform-tech-architecture-v1-50k.md` |
| 关联文档 | `docs/geo-platform-prd-v1.md` |
## 2. 设计目标
本文档用于定义 GEO 平台在 V1 阶段的 RAG 技术方案,目标是:
- 让知识库检索结果足够精准,支持品牌内容生成和问答增强。
- 将事务型业务数据与向量检索能力解耦。
- 在 5 万在线用户前提下,保证知识库查询链路稳定、可扩展。
- 为后续多品牌、多租户、多知识源、多平台内容生成打好基础。
## 3. 设计结论
V1 的 RAG 主方案建议为:
- `PostgreSQL` 负责知识元数据、权限、品牌、分组、任务状态
- `Qdrant` 负责向量索引和向量检索
- `对象存储` 负责原始文档和解析中间产物
- `Worker` 负责解析、切片、Embedding、写入、重建索引
检索链路建议为:
1. 查询预处理
2. 过滤条件构造
3. Qdrant dense / hybrid 检索
4. rerank 精排
5. 上下文拼装
6. 提交给大模型生成
## 4. 为什么选 Qdrant
### 4.1 业务需求决定
GEO 平台的 RAG 检索不是简单的“全文找相似段落”,而是带强业务约束的检索:
- 只检索当前租户数据
- 只检索当前品牌或选定品牌数据
- 只检索指定知识分组或文档类型
- 需要按更新时间、来源、文档权重做过滤或排序
- 后续要支持 hybrid search 和 rerank
因此检索系统必须同时擅长:
- 高效向量召回
- 高效 payload filter
- 后续高精度搜索演进
### 4.2 相比 pgvector 的优势
Qdrant 更适合做 V1 主方案,原因如下:
- 向量检索从 PostgreSQL 主交易链路中解耦
- metadata filter 能力更适合 RAG 场景
- 后续扩容路径清晰
- 更方便演进到 hybrid search、多向量和 rerank 方案
### 4.3 pgvector 的角色
`pgvector` 仍可作为轻量备选方案:
- 数据量较小
- 团队只有单数据库运维能力
- 只是验证 MVP
但如果目标是“RAG 要精准好用”,Qdrant 更适合作为长期主方案。
## 5. RAG 场景定义
### 5.1 主要使用场景
#### A. 文章生成增强
在生成品牌文章时,从品牌知识库中召回相关背景材料、产品说明、FAQ、历史内容和网页资料,为模型生成提供高质量上下文。
#### B. 品牌问答增强
当系统生成“问题集答案”“趋势分析”“竞品分析”类内容时,先检索品牌知识和文档片段,再交给模型组织答案。
#### C. 内容优化增强
对已有文章做优化时,检索品牌标准话术、产品卖点、平台规范、历史高质量文章片段。
### 5.2 不适合 V1 的场景
- 跨品牌全局开放检索
- 实时抓取网页后秒级入库并立刻高质量检索
- 十亿级向量规模
- 强知识图谱推理
## 6. 数据分层设计
## 6.1 PostgreSQL 存储内容
PostgreSQL 中保存:
- `knowledge_bases`
- `knowledge_groups`
- `knowledge_items`
- `knowledge_parse_tasks`
- `knowledge_chunks_meta`
- `brand`
- `tenant`
- `document_acl`
- `retrieval_logs`
- `rag_eval_cases`
### PostgreSQL 的职责
- 保存业务主数据
- 控制权限与租户隔离
- 提供后台列表页查询
- 保存 chunk 元数据和状态
- 保存评测数据和命中日志
## 6.2 Qdrant 存储内容
Qdrant 中保存:
- chunk 向量
- chunk payload
- 文档级过滤字段
- chunk 排序辅助字段
### Qdrant 的职责
- 相似度召回
- filter + ANN 检索
- hybrid search
- rerank 前候选集召回
## 6.3 对象存储内容
- 原始 PDF / DOCX / TXT / HTML
- 提取后的 Markdown / 纯文本
- 清洗后的中间文件
## 7. Collection 设计
## 7.1 设计原则
V1 不建议每个品牌一个 collection,也不建议每个租户大量拆 collection。
推荐策略:
- 按业务域建立少量 collection
- 通过 payload filter 做租户、品牌、分组隔离
- 避免 collection 数量过多导致管理复杂
## 7.2 推荐 collection
### collection 1: `kb_chunk_main`
用途:
- 存放知识库标准 chunk
- 支撑文章生成、优化、品牌问答等主要检索
### collection 2: `content_example_main`
用途:
- 存放历史优质文章片段
- 支撑风格参考、结构参考、示例生成
V1 如果要尽量简单,也可以先只保留一个 `kb_chunk_main`
## 7.3 向量字段建议
### 主向量
- `dense_vector`
- 维度按所选 embedding 模型决定
- 距离建议优先 `Cosine`
### 预留向量
后续可扩展:
- `title_vector`
- `summary_vector`
- `sparse_vector`
V1 可以先只落一个 dense vector。
## 8. Payload 设计
## 8.1 必须字段
每个 chunk 在 Qdrant 中建议至少带以下 payload
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `tenant_id` | keyword | 租户隔离 |
| `brand_id` | keyword | 品牌过滤 |
| `kb_id` | keyword | 知识库 ID |
| `group_id` | keyword | 分组过滤 |
| `item_id` | keyword | 文档 ID |
| `chunk_id` | keyword | chunk 唯一 ID |
| `doc_type` | keyword | 文档类型 |
| `source_type` | keyword | 来源类型,如上传文档/网页/手输 |
| `language` | keyword | 语言 |
| `status` | keyword | 是否可检索 |
| `priority` | integer | 文档优先级 |
| `published_at` | integer | 发布时间时间戳 |
| `updated_at` | integer | 更新时间时间戳 |
| `token_count` | integer | chunk token 数 |
| `title` | text/keyword | 文档标题 |
| `tags` | keyword[] | 标签 |
## 8.2 推荐扩展字段
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `is_official_doc` | bool | 是否官方资料 |
| `is_product_doc` | bool | 是否产品文档 |
| `author` | keyword | 作者 |
| `source_url` | keyword | 来源链接 |
| `quality_score` | float | 文档质量分 |
| `freshness_score` | float | 时效性分 |
| `manual_boost` | float | 人工加权 |
## 8.3 索引建议
Qdrant 中对高频 filter 字段建立 payload index,优先包括:
- `tenant_id`
- `brand_id`
- `group_id`
- `doc_type`
- `status`
- `source_type`
如果查询高频使用时间和标签,也可以增加:
- `updated_at`
- `tags`
## 9. Chunk 设计
## 9.1 核心原则
RAG 准确率很多时候不是输在向量库,而是输在 chunk 切分。
切分原则:
- 按语义结构切,不按固定字数硬切
- 保持 chunk 语义完整
- 控制 chunk 粒度不要过大
- 保留上下文关联信息
## 9.2 推荐切分策略
### 文档型内容
优先按以下结构切分:
- 一级标题
- 二级标题
- 段落簇
- 列表块
- 表格说明块
### 网页型内容
优先清洗掉:
- 导航
- 页脚
- 广告
- 无意义重复区域
保留:
- 标题
- 摘要
- 正文
- FAQ
- 参数表
## 9.3 V1 chunk 参数建议
- 目标 token`300 ~ 600`
- overlap`50 ~ 100`
- 对 FAQ 场景可更短:`100 ~ 250`
- 对长报告场景可按标题段落聚合到 `500 ~ 800`
### 说明
- 太短会导致上下文碎片化,召回噪音高
- 太长会导致 embedding 表达不准,且浪费上下文窗口
## 9.4 特殊处理建议
### FAQ 文档
`问题 + 答案` 成对切 chunk,不要拆开。
### 产品参数文档
按“模块 + 参数块”切分,并保留型号、版本、发布时间。
### 品牌官网介绍
品牌介绍、品牌故事、产品卖点、售后说明应分开切分。
## 10. 入库流程设计
## 10.1 标准流程
1. 用户上传文档或录入网页。
2. 文件进入对象存储。
3. 创建解析任务。
4. Worker 提取文本并清洗。
5. 按规则切 chunk。
6. 为每个 chunk 生成 embedding。
7. chunk 写入 PostgreSQL 元数据表。
8. 向量和 payload 写入 Qdrant。
9. 更新知识条目状态为可用。
## 10.2 幂等要求
- 同一文档重复上传要可识别
- chunk 重建时采用版本号或软删除策略
- 文档更新后需支持全量替换对应 chunk
## 10.3 文档版本策略
推荐方案:
- `knowledge_item` 保存文档主记录
- `knowledge_item_version` 保存版本记录
- `knowledge_chunk_meta` 带 version 字段
- Qdrant payload 中写入 `item_version`
检索时仅查询当前生效版本。
## 11. 检索流程设计
## 11.1 标准检索链路
1. 接收用户查询或文章生成任务上下文
2. 做 query rewrite
3. 构造 filter 条件
4. 从 Qdrant 召回 topK 候选 chunk
5. 使用 reranker 精排
6. 去重与多样性控制
7. 拼接最终上下文
8. 返回给大模型
## 11.2 查询预处理
建议包含:
- 去除无意义词
- 标准化品牌名、产品名、简称
- 同义词扩展
- 根据任务类型追加意图词
例如:
- “帮我写某品牌数字时尚趋势文章”
- 可以扩展为:
- “数字时尚 品牌趋势 新趋势 消费者关注点 产品风格 设计趋势”
## 11.3 filter 策略
RAG 结果想精准,必须优先加 filter,而不是裸搜。
推荐默认过滤条件:
- `tenant_id = 当前租户`
- `status = active`
可选过滤条件:
- `brand_id in 当前品牌集合`
- `group_id in 指定知识分组`
- `doc_type in 允许文档类型`
- `updated_at > 某时间`
## 11.4 召回策略
### V1 基础版
- dense retrieval
- topK = 30 ~ 50
### V1 推荐版
- dense retrieval + BM25 或 sparse retrieval
- hybrid merge
- rerank top 30
- 最终输出 top 5 ~ 10
## 11.5 去重与多样性
召回后应做:
- 同文档 chunk 去重
- 相邻 chunk 合并
- 标题级去重
- 不同来源混排
防止最终上下文全部来自同一篇文档的连续片段。
## 12. rerank 设计
## 12.1 为什么必须 rerank
向量召回解决的是“先找一批可能相关的候选”,不是最终最准排序。
如果不做 rerank,常见问题包括:
- 语义相近但不回答问题
- 命中了品牌,但不是当前主题
- 召回结果太泛
## 12.2 V1 rerank 方案
推荐两级:
### 方案 A:轻量版
- dense topK 召回
- 用 cross-encoder reranker 排序
- 取前 5 到 8 个 chunk
### 方案 B:增强版
- dense + sparse hybrid
- rerank
- 基于来源权重、官方文档权重、时效权重做分数融合
## 12.3 打分建议
最终分数建议由以下部分组成:
- semantic_score
- rerank_score
- quality_score
- freshness_score
- manual_boost
可采用线性融合,V1 不必一开始做复杂学习排序。
## 13. 上下文拼装策略
## 13.1 拼装原则
- 少而准优于多而杂
- 优先保留完整意义块
- 优先官方和高质量来源
- 记录引用来源,方便可解释
## 13.2 推荐拼装方式
每个返回 chunk 建议带:
- 文档标题
- 来源类型
- 来源 URL
- chunk 正文
- 更新时间
拼装给模型时,建议按主题分组,而不是简单拼接长文本。
## 13.3 token 控制
不同任务控制不同上下文预算:
- 短文章生成:`1000 ~ 2000 tokens`
- 长文章生成:`2000 ~ 5000 tokens`
- 问答增强:`800 ~ 1500 tokens`
## 14. 多租户与权限设计
## 14.1 隔离原则
所有检索必须带 `tenant_id` 过滤,不允许裸查询。
## 14.2 品牌隔离
如果一个用户一次只操作一个品牌,检索时默认加:
- `brand_id = current_brand`
如果是跨品牌分析,再显式放开。
## 14.3 文档权限
如果后续支持团队协作,可增加:
- 可见范围
- 部门范围
- 角色范围
V1 可以先在 PostgreSQL 中控制可见性,再把最终允许检索的 payload 写入 Qdrant。
## 15. 性能设计
## 15.1 查询延迟目标
| 项目 | 目标 |
| --- | --- |
| query rewrite | < 50ms |
| Qdrant topK 检索 | < 100ms |
| rerank | < 200ms |
| 检索总耗时 | < 400ms |
### 说明
以上是服务端目标,前端或模型生成耗时不包含在内。
## 15.2 并发策略
- 热门品牌查询走缓存
- 高频 filter 字段建立 payload index
- rerank 单独走线程池或独立服务
- query rewrite 和 rerank 限并发,避免放大成本
## 15.3 写入策略
- 文档上传与知识学习异步处理
- 向量写入批量提交
- 文档更新采用分批重建
## 16. 精准度评测体系
## 16.1 为什么必须做评测
RAG 不评测,精准度一定会失控。
V1 至少需要建立一套小型评测集。
## 16.2 评测集构成
每个品牌至少准备:
- 20 个高频问题
- 20 个内容生成主题
- 10 个产品对比问题
- 10 个品牌介绍问题
总计每品牌建议至少 50 条评测 query。
## 16.3 评测指标
推荐指标:
- Recall@5
- Recall@10
- Precision@5
- MRR
- NDCG
- Answer groundedness
- 人工满意度
## 16.4 人工评测维度
每条 query 至少看:
- 是否命中正确文档
- 是否命中正确片段
- 是否出现品牌错配
- 是否出现过期内容
- 是否出现无关噪音
## 16.5 评测流程
1. 固定查询集
2. 固定期望命中文档
3. 跑召回与 rerank
4. 输出命中率报表
5. 低分案例人工复盘
6. 调整 chunk、payload、topK、rerank 策略
## 17. 监控与日志
## 17.1 监控指标
- Qdrant 查询延迟
- Qdrant 查询 QPS
- payload filter 命中比例
- topK 平均耗时
- rerank 平均耗时
- 检索空结果率
- 检索后回答满意度
## 17.2 日志记录
每次检索建议记录:
- query
- rewrite_query
- filter 条件
- topK 召回结果
- rerank 结果
- 最终返回 chunk
- 生成任务 ID 或问答 ID
方便后续做 badcase 分析。
## 18. 风险与边界
### 18.1 常见风险
- chunk 切分不合理,导致检索效果差
- payload 设计不完整,导致过滤能力不足
- 只做召回不做 rerank,结果不稳定
- 知识库内容脏乱,导致“检索准但答案差”
### 18.2 V1 边界
- V1 不要求做复杂多跳推理
- V1 不要求做全自动 query rewrite 学习
- V1 不要求做复杂学习排序
## 19. V1 最终建议
如果你的目标是“RAG 精准好用”,V1 建议采用这套最实用组合:
- `PostgreSQL` 做业务主存储和知识元数据
- `Qdrant` 做向量检索
- `RabbitMQ` 做知识学习与检索相关任务队列
- `对象存储` 做原始文档存储
- `dense + filter + rerank` 做主检索链路
同时一定要配套以下机制:
- 合理 chunk 切分
- 完整 payload 字段
- payload index
- rerank
- 评测集
- badcase 回放
没有这些,单纯换向量库也不可能让 RAG 自动变得精准。