68 lines
7.5 KiB
Markdown
68 lines
7.5 KiB
Markdown
# Chunk 关键词与 RRF 混合检索
|
||
|
||
本阶段基于已合入 `dev` 的文本/向量发布,增加可独立调用的 chunk BM25 和 RRF。既有条目关键词接口继续保留。三个 chunk 模式使用相同的当前文本版本、原文 chunk 与分类范围;比较时应固定发布版本、分类和 `top_k`,同时记录混合检索的 `candidate_k`。
|
||
|
||
| 接口 | 请求 mode | 排序/证据单元 | 前置条件 |
|
||
|---|---|---|---|
|
||
| `POST /api/retrieval` | `keyword` | 知识条目,标题权重 2、正文权重 1 | 当前有效审核语料 |
|
||
| `POST /api/retrieval/chunks` | `keyword_chunks` | chunk 正文 BM25,标题不参与打分 | 当前有效文本发布;无需模型或向量发布 |
|
||
| `POST /api/retrieval/vector` | `vector` | chunk 精确余弦 | 当前有效文本/向量发布,运行模型空间匹配 |
|
||
| `POST /api/retrieval/hybrid` | `hybrid` | 同一批 chunk 的两路 RRF | 与向量模式相同 |
|
||
|
||
`mode` 可省略,由接口固定;传入其他模式或未知字段返回 422。公开检索无需登录;历史分页及详情继续限管理员。问答接口仍为占位,当前响应不生成 LLM 答案。
|
||
|
||
## 请求与排名
|
||
|
||
```json
|
||
{"query":"合成资料中的交通查询入口","mode":"hybrid","top_k":5,"candidate_k":50,"category":"交通"}
|
||
```
|
||
|
||
- `query` 去除首尾空白后 1–500 字符,`top_k` 默认 5、范围 1–20,`category` 可省略。chunk 关键词请求不接收 `candidate_k`。
|
||
- 混合检索每路最多取 `candidate_k` 条候选,默认 50、范围 1–200,并须不小于 `top_k`。这是固定排名后的候选截断,不会改变文本或输入 token。最终从候选并集返回最多 `top_k` 条。
|
||
- chunk BM25 只对正文分词。沿用固定 Jieba 0.42.1 搜索分词、NFKC/casefold、HMM 关闭、项目词与 `zh-small-v1` 停用词表;查询词去重,`k1=1.2`、`b=0.75`,正值平滑 IDF。语料长度和词频在分类过滤后的全部 chunks 上计算,只将正分候选纳入关键词一路。标题仅作为出处字段。
|
||
- 向量一路复用精确余弦排序,同样先按分类筛选,不设置相似度阈值。负分和零分仍可能进入候选,分数不是事实置信度,`status=ok` 只表示存在排序结果。
|
||
- 两路先按各自原始分数排序;同分按 `knowledge_id, chunk_ordinal, chunk_id` 升序,排名从 1 开始。RRF 使用等权、固定 `k=60`:`score(c) = sum(1 / (60 + rank_leg(c)))`。不在某路候选列表中的 chunk,该路贡献为 0。原始 BM25 和余弦分数不直接相加;融合分数同分沿用相同 ID 次序。排序与日志使用未预先四舍五入的分数。
|
||
- 融合以 chunk ID 去重。同一知识的不同片段(含重叠片段)保留各自排名和原文偏移,不做条目折叠或多样性重排。条目基线与 chunk 模式的分数、命中数、语料数及评测单元不同,不能直接混算指标。
|
||
|
||
RRF 方法与常数参考 [Cormack、Clarke、Büttcher,SIGIR 2009 原论文](https://cormack.uwaterloo.ca/cormacksigir09-rrf.pdf)。这里把 `k=60` 作为首版可复现配置,并未通过本项目领域问题集调优。
|
||
|
||
## 响应与复核
|
||
|
||
全部模式保留原文、字符偏移(左闭右开)、知识/文档/来源 ID 及版本、URL、排名与耗时。chunk 关键词和混合响应另含:
|
||
|
||
| 字段 | 含义 |
|
||
|---|---|
|
||
| `mode` | `keyword_chunks` 或 `hybrid`,可用于历史类型判别 |
|
||
| `text_index_version_id`, `text_generation`, `catalog_revision` | 本次文本发布和目录修订 |
|
||
| `corpus_fingerprint` | 整份已审核语料的指纹,分类筛选不改变它 |
|
||
| `corpus_size` | 分类范围内参与两路打分的 chunk 数 |
|
||
| `total_hits` | 关键词模式为全部正分 chunk 数;混合模式为两路截断后的候选并集大小,可能大于返回条数 |
|
||
| `query_terms`, `config.lexical`, `config.chunking`, `config.tie_break` | 实际分词、BM25 参数、切分配置、稳定排序规则 |
|
||
| `elapsed_ms` | 语料检查、模型编码(混合模式)、排序及响应组装耗时;不含记录写入及网络时间 |
|
||
|
||
混合模式还保存:
|
||
|
||
- `vector_version_id`、`generation`:向量发布版本与代数;`config.space` 包含完整模型 revision、维度、token 预算、指令、实现/池化/归一化与权重格式身份;与向量契约一致。
|
||
- `config.rrf_k/weights/candidate_k/vector_scorer`:融合与候选预算,不允许请求覆盖固定算法参数。
|
||
- `lexical_candidates/vector_candidates`:两路完整的截断候选列表,每条为 `chunk_id/rank/score`,即使未进最终前 `top_k` 也保留。
|
||
- `lexical_total_hits/vector_total_hits`:截断前正分关键词候选数、分类范围内向量候选总数。
|
||
- 命中的 `lexical_rank/lexical_score/vector_rank/vector_score` 和两路 `*_contribution`:缺席的排名/原始分数为 `null`、贡献为 0。`score` 等于两路贡献之和。
|
||
|
||
结果完整写入现有 `retrieval_runs`,历史接口联合类型支持四种 mode,不需要新增迁移,当前 Schema 仍为 `0006_vectors`。修改依据后历史保持原样,只代表当时快照;重查须通过当前性验证。原始查询和运行记录属于数据库数据,不应提交到仓库。
|
||
|
||
## 一致性、失败与容量
|
||
|
||
混合检索先检查发布版本与模型空间,然后提交只读事务释放发布锁,再真实编码查询;编码后重新获取目录/向量状态锁,复核目录修订、文本/向量代数、审核指纹、实际 chunks、完整向量集及空间身份。变化时 409,且不保存部分结果。两路排名及写入检索历史在同一个受锁保护的事务内完成。
|
||
|
||
关键词一路没有命中或没有分词时,混合模式明确保留空候选列表,可仅有向量一路;纯关键词模式没有可检索词则 422。分类无资料或空的有效发布返回 `no_evidence`。模型 token 超限/输出校验失败返回 422,运行环境不可用或编码忙返回 503;模型失败不降级成一份声称成功的混合结果。
|
||
|
||
两种新接口均沿用向量阶段最多 2000 chunks、5000 条知识/200 万字符的整体核验预算,超限明确 503。只在分类范围内打分,但当前性及容量检查针对整份发布。文本快照允许的 20000 chunks 不等同于本接口容量。同步精确排序及 BM25 在锁内运行,会短暂串行化目录写入;当前没有 ANN、后台队列或生产吞吐量结论。
|
||
|
||
运行依赖、固定缓存、默认关闭的本地模型、构建/发布步骤见 [VECTOR_API.md](VECTOR_API.md)。前端新增 `services/hybrid.ts` 两个调用及历史类型;模式切换页面、Docker/浏览器端和真实领域验收仍待交接。
|
||
|
||
## 验证与回滚
|
||
|
||
轻量测试使用明确的合成正文及坐标 fixture,覆盖手算 BM25/RRF、原始分数与融合的独立性、候选边界、两路缺席、稳定排序、chunk 偏移、分类、权限、历史、失效/破坏快照、编码期间版本竞争、无部分日志及容量拒绝。真实模型专项沿用 `test_vector_runtime.py` 的显式 opt-in,增加固定 BGE small 的 HTTP 混合检索和进程重启后的两路排名/历史复核。运行命令见 [VECTOR_API.md](VECTOR_API.md)。这些用例验证实际模型/数据库/API 贯通,合成问题不代表领域质量或论文实验结论。
|
||
|
||
撤回本功能代码即可撤回两个新增接口;数据库无需降级。旧后端历史响应模型不认识 `keyword_chunks/hybrid`,回滚时应限制旧历史端点或先以备份保留新模式记录,避免把新记录交给旧模型解析;不要为回滚而无备份删除检索历史。
|