Files
QMDSearch/.trae/specs/add-hierarchical-rag-pipeline/tasks.md
T
kplam 51dc8dc4f6 Initial commit: QMDSearch 分层信息检索服务
- FastAPI + Qdrant + Redis + Ollama 技术栈
- L1→L2→L3→chunk 四层分层检索(dense + sparse RRF 融合)
- 文档三级总结与 2.5 级回退
- query 解析路由与分类
- /admin 管理页面
2026-07-29 21:24:40 +08:00

5.9 KiB
Raw Blame History

Tasks

  • Task 1: 扩展配置与数据模型:config 增加 taxonomy/各层 top-k/sparse 开关/缓存 TTL 等参数;新建 app/models/knowledge.pyTaxonomyCategory、CategoryResult)与 app/models/search.pySearchRequest/SearchResponse/SearchHit);app/models/document.py 增加 ChunkModeldoc_id、text、section_path、chunk_index
    • SubTask 1.1: config.py 增加 taxonomy_path、classify_confidence_threshold、l1_doc_top_n、l2_section_top_n、l3_top_n、sparse_enabled、cache_ttl 等配置项,同步更新 .env.example
    • SubTask 1.2: 新建 taxonomy 默认配置文件(内置通用类目集 + uncategorized),提供加载与校验函数
    • SubTask 1.3: 新建 knowledge.py / search.py 模型,document.py 增加 ChunkModel 与 CategoryResult 引用
  • Task 2: 向量服务:app/core/embeddings.pydenseopenai | local 双 provider 统一异步接口,批量编码)+ app/core/sparse.py(本地分词 + 特征哈希 BM25 稀疏向量,输出 Qdrant sparse vector 格式,不依赖外部模型)
    • SubTask 2.1: EmbeddingService 抽象 + openai provider 实现 + local providerOllama embedding 接口)实现
    • SubTask 2.2: SparseEncoder(中文分词 + BM25 权重 + 特征哈希到固定维度),单测验证输出稀疏格式合法
  • Task 3: Qdrant 服务封装 app/services/qdrant.py:启动时初始化 4 个集合(doc_l1 / doc_l2 / doc_l3 / chunkschunks 与 doc_l1 带 sparse 向量配置),建立 category/tags/doc_id/section_path payload 索引;提供 upsert 与按层检索(支持 payload 过滤 + dense/sparse/hybrid 查询)接口
    • SubTask 3.1: 集合初始化与 payload 索引(幂等,应用启动时执行)
    • SubTask 3.2: upsert 接口(按层写入,chunk 携带 dense+sparse
    • SubTask 3.3: 分层查询接口(dense 过滤查询 / hybrid 查询)
  • Task 4: summarizer 改造 + chunk 切分器:L2 大纲优先解析原生标题树(Markdown 标题 + 编号标题正则),无结构回退现有 LLM 生成;新建 app/core/chunker.py 按标题树切分 chunk(超长 section 按长度二次切分,短文本整篇单 chunk),chunk 记录 section_path 与 L2 节点对应关系
    • SubTask 4.1: 标题树解析器(Markdown ATX 标题 + 中文编号标题),输出 section 树
    • SubTask 4.2: summarizer 接入标题树:有结构时 L2 直接用标题树生成大纲文本,无结构走原 prompt;L3 保持不变
    • SubTask 4.3: Chunker 实现与单测(结构化/非结构化/短文本三种输入)
  • Task 5: 分类器 + ingestion 全链路补全:app/core/classifier.py(基于 L1 总结,Ollama JSON 约束输出主类+多标签+置信度,低置信归 uncategorized);改造 app/core/ingestion.py 串起 总结→分类→chunk 切分→双向量化→Qdrant 写入,返回真实 document_id 与集合信息
    • SubTask 5.1: Classifier 实现(taxonomy 注入 prompt,JSON 解析容错,置信度阈值判兜底)
    • SubTask 5.2: Ingester 全链路串联(总结→分类→切 chunk→embedding→sparse→upsert 四层)
    • SubTask 5.3: 入库失败处理:Qdrant 写入失败不丢已生成总结,返回明确错误码与可重试标识
  • Task 6: 入库与类目 APIapp/api/v1/document.pyPOST /api/v1/documents)、app/api/v1/knowledge.pyGET /api/v1/knowledge/categories),统一响应包装与错误码,main.py 注册路由
  • Task 7: query 解析与分类路由:app/core/query_parser.pyOllama 小模型 JSON 约束输出:命中类目+置信度、rewrite query、关键词;解析失败/低置信/命中过多类目→全库兜底)
    • SubTask 7.1: QueryParser 实现与 JSON 容错解析
    • SubTask 7.2: 路由决策函数(主类硬过滤 + 多标签软召回合并为 Qdrant payload filter + 兜底判定),单测覆盖三类分支
  • Task 8: 分层检索引擎 + 重排 + 检索 API:app/core/retriever.pyL1→L2→L3→chunk 逐层剪枝,2.5 级文档跳过 L2,空召回回退上一层直搜 chunk)+ app/core/ranker.pyRRF 融合 + final_k 截断)+ app/api/v1/search.pyPOST /api/v1/search
    • SubTask 8.1: Retriever 逐层 drill-down 主流程
    • SubTask 8.2: 降级路径(2.5 级跳层、空召回回退、路由兜底直通)
    • SubTask 8.3: Ranker RRF 融合与单测
    • SubTask 8.4: 检索 API 与统一响应
  • Task 9: Redis 缓存 app/services/redis.py:query 解析结果与检索结果缓存(短 TTL 可配置),缓存键含 query 与路由类目;Redis 不可用时降级直连不报错
  • Task 10: 评测脚本骨架 scripts/eval/:回归集 JSON 格式定义与样例(≥5 篇文档、每篇 35 条应检出 query + 12 条不应检出 query,标注 golden doc/section/chunk);指标实现 Entity Recall、Routing F1、Pruning Loss、Precision@5/Recall@10Hallucination Rate 用 Ollama LLM-as-judge 反查;支持平铺 chunk baseline 对比并输出 Markdown 报告(含门槛标红:L1 Entity Recall≥0.85、L3≥0.9、幻觉率<2%、Pruning Loss<8%
    • SubTask 10.1: 回归集 schema + 样例数据
    • SubTask 10.2: 摘要质量指标(Entity Recall / Hallucination Rate
    • SubTask 10.3: 检索效用指标(Routing F1 / Pruning Loss / Precision@5+ baseline 对比报告
  • Task 11: 端到端验证:docker compose 起 Qdrant/Redis/Ollama,走通 入库→检索→评测 全链路;uv run pytest 全绿;修复发现的问题

Task Dependencies

  • [Task 2] depends on [Task 1]
  • [Task 3] depends on [Task 1]
  • [Task 4] depends on [Task 1]
  • [Task 5] depends on [Task 2, Task 3, Task 4]
  • [Task 6] depends on [Task 5]
  • [Task 7] depends on [Task 1]
  • [Task 8] depends on [Task 3, Task 7]
  • [Task 9] depends on [Task 7, Task 8]
  • [Task 10] depends on [Task 5, Task 8]
  • [Task 11] depends on [Task 6, Task 9, Task 10]

Parallelizable

  • Task 2 / Task 3 / Task 4 / Task 7 互相独立,可并行
  • Task 6 与 Task 8 可并行(依赖均已满足后)