a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
208 lines
5.2 KiB
Markdown
208 lines
5.2 KiB
Markdown
# AI 合同平台 V2:RAG 检索 Explain 增强
|
||
|
||
日期:2026-06-24
|
||
|
||
## 本轮目标
|
||
|
||
在完成 pgvector HNSW 和关键词 `search_vector` SQL 优化后,本轮补齐 RAG 检索可解释性:
|
||
|
||
- 说明一次检索是否使用 HNSW。
|
||
- 说明一次检索是否使用 `search_vector`。
|
||
- 返回向量候选数、关键词候选数、融合去重后的候选数。
|
||
- 给每条候选返回来源和排序原因,帮助管理员判断“为什么命中这条依据”。
|
||
|
||
这属于 AI 中台能力,不把检索细节塞回合同系统,仍符合 V2 重构方案中“合同系统只做业务、AI 中台负责模型/知识库/RAG/审计”的边界。
|
||
|
||
## 已完成代码
|
||
|
||
文件:
|
||
|
||
- `yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api/repository.py`
|
||
- `yuqei-ai-platform/services/ai-platform-api/tests/test_platform_data.py`
|
||
|
||
### 1. Explain 响应新增字段
|
||
|
||
`KnowledgeSearchExplain` 新增:
|
||
|
||
- `vector_backend`
|
||
- `keyword_backend`
|
||
- `used_hnsw`
|
||
- `used_search_vector`
|
||
- `vector_candidate_count`
|
||
- `keyword_candidate_count`
|
||
- `merged_candidate_count`
|
||
|
||
`KnowledgeSearchExplainItem` 新增:
|
||
|
||
- `candidate_source`
|
||
- `ranking_reason`
|
||
|
||
### 2. PostgreSQL explain 走真实检索路径
|
||
|
||
SQLAlchemy/PostgreSQL 仓库的 explain 不再只用“最近 N 条内存候选”模拟,而是按策略走真实数据库路径:
|
||
|
||
- `hybrid`:
|
||
- pgvector HNSW 取向量候选
|
||
- `search_vector @@ plainto_tsquery(...)` 取关键词候选
|
||
- 合并去重后计算关键词分、向量分、混合分
|
||
- `vector`:
|
||
- 只走 pgvector HNSW
|
||
- 与正式搜索保持一致:即使低于阈值,也解释 top vector 候选
|
||
- `keyword`:
|
||
- 只走 `search_vector`
|
||
|
||
### 3. 排序原因
|
||
|
||
每条结果返回类似:
|
||
|
||
```text
|
||
hybrid score 0.6326 = keyword 1.0000 * 0.55 + vector 0.1835 * 0.45; source=vector; matched_terms=押金
|
||
```
|
||
|
||
或:
|
||
|
||
```text
|
||
vector score 0.2293; source=vector
|
||
```
|
||
|
||
或:
|
||
|
||
```text
|
||
keyword score 1.0000; source=keyword; matched_terms=租赁
|
||
```
|
||
|
||
这样管理员可以直接看到命中来源、分数构成和匹配词。
|
||
|
||
## 本地验证
|
||
|
||
命令:
|
||
|
||
```powershell
|
||
python -m pytest yuqei-ai-platform\services\ai-platform-api\tests -q
|
||
python -m compileall yuqei-ai-platform\services\ai-platform-api\src\yuqei_ai_platform_api\repository.py
|
||
```
|
||
|
||
结果:
|
||
|
||
- `41 passed`
|
||
- compileall 通过
|
||
|
||
新增/更新测试:
|
||
|
||
- 内存 explain 仍返回基础字段,兼容原 explain 行为。
|
||
- explain 模型可以表达 `postgres-pgvector`、`pgvector-hnsw`、`search_vector`、候选数和排序原因。
|
||
|
||
## V2 smoke 部署验证
|
||
|
||
部署命令:
|
||
|
||
```powershell
|
||
$env:SSHPASS='YOUR_REMOTE_PASSWORD'
|
||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File yuqei-infra\scripts\deploy-v2-smoke-docker.ps1 -UseSshpass -AllowDirtyWorktree -SkipSmoke
|
||
```
|
||
|
||
最终结果:
|
||
|
||
- `V2_SMOKE_DOCKER_DEPLOY_PASS`
|
||
- 产物目录:`project-docs/qa-artifacts/v2-smoke-docker-deploy/2026-06-24T21-53-40`
|
||
|
||
中间情况:
|
||
|
||
- 第一次部署失败原因仍是 Docker 镜像代理 TLS 超时,不是代码问题。
|
||
- 重跑后部署通过。
|
||
|
||
## 远端接口抽样
|
||
|
||
接口:
|
||
|
||
```http
|
||
GET /api/v1/knowledge-chunks/search/explain
|
||
```
|
||
|
||
### hybrid:押金
|
||
|
||
结果摘要:
|
||
|
||
```json
|
||
{
|
||
"retrieval_backend": "postgres-pgvector",
|
||
"vector_backend": "pgvector-hnsw",
|
||
"keyword_backend": "search_vector",
|
||
"used_hnsw": true,
|
||
"used_search_vector": true,
|
||
"vector_candidate_count": 100,
|
||
"keyword_candidate_count": 100,
|
||
"merged_candidate_count": 200,
|
||
"included_count": 3,
|
||
"first_source": "vector"
|
||
}
|
||
```
|
||
|
||
排序原因:
|
||
|
||
```text
|
||
hybrid score 0.6326 = keyword 1.0000 * 0.55 + vector 0.1835 * 0.45; source=vector; matched_terms=押金
|
||
```
|
||
|
||
### vector:deposit refund
|
||
|
||
结果摘要:
|
||
|
||
```json
|
||
{
|
||
"retrieval_backend": "postgres-pgvector",
|
||
"vector_backend": "pgvector-hnsw",
|
||
"keyword_backend": "none",
|
||
"used_hnsw": true,
|
||
"used_search_vector": false,
|
||
"vector_candidate_count": 100,
|
||
"keyword_candidate_count": 0,
|
||
"merged_candidate_count": 100,
|
||
"included_count": 3
|
||
}
|
||
```
|
||
|
||
排序原因:
|
||
|
||
```text
|
||
vector score 0.2293; source=vector
|
||
```
|
||
|
||
### keyword:租赁
|
||
|
||
结果摘要:
|
||
|
||
```json
|
||
{
|
||
"retrieval_backend": "postgres-pgvector",
|
||
"vector_backend": "not_used",
|
||
"keyword_backend": "search_vector",
|
||
"used_hnsw": false,
|
||
"used_search_vector": true,
|
||
"vector_candidate_count": 0,
|
||
"keyword_candidate_count": 100,
|
||
"merged_candidate_count": 100,
|
||
"included_count": 3
|
||
}
|
||
```
|
||
|
||
排序原因:
|
||
|
||
```text
|
||
keyword score 1.0000; source=keyword; matched_terms=租赁
|
||
```
|
||
|
||
## 当前边界
|
||
|
||
- explain 现在能说明数据库检索路径和排序原因,但还没有记录每次 explain 的 SQL `EXPLAIN ANALYZE` 原文。
|
||
- 目前候选来源以 `vector`、`keyword`、`keyword+vector` 表达。对于同一 chunk 同时出现在两边的情况,可以进一步展示两边原始排名。
|
||
- explain 接口是管理员/调试用能力,正式法律问答仍通过 AI Trace 记录命中来源和质量标签。
|
||
|
||
## 下一步建议
|
||
|
||
下一步可以继续做:
|
||
|
||
1. 在 AI Trace 详情页展示 RAG explain 摘要,让每次法律问答能回看“为什么引用这些依据”。
|
||
2. 给 explain 增加向量原始排名、关键词原始排名、去重前后候选数。
|
||
3. 用真实法规库问题集跑“依据命中率 / 错误引用率”质量基线。
|