Files
ai-contract-platform/project-docs/V2-database-pgvector-hnsw-query-shape-2026-06-24.md
T
yuqei a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
release: freeze V2 release candidate
2026-07-12 15:32:24 +08:00

6.8 KiB
Raw Blame History

AI 合同平台 V2 数据库优化:pgvector HNSW 查询形态收口

日期:2026-06-24

本轮目标

按照《AI 合同平台 V2 重构版开发方案》和《AI 合同平台 V2 数据库优化重构方案》的 DB-5 性能基线推进,本轮聚焦 AI 中台知识库检索:

  • 将知识库向量检索从可用的 pgvector 查询,收口为稳定命中 HNSW 索引的查询形态。
  • 避免 pgvector 成功执行但返回空结果时回退到 Python 全量扫描。
  • 保留合同系统和 AI 中台职责边界:合同系统只调用 AI 中台,知识库、向量检索、法条依据仍在 yuqei-ai-platform 内部完成。

已完成代码

1. pgvector 查询形态对齐 HNSW 表达式索引

文件:

  • yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api/repository.py

核心变化:

  • 默认 64 维 embedding 查询使用:
CAST(embedding AS vector(64)) <=> CAST(:query_vector AS vector(64))
  • 与迁移中已创建的 HNSW 表达式索引保持一致:
CREATE INDEX ix_knowledge_chunks_embedding_hnsw
ON knowledge_chunks USING hnsw ((embedding::vector(64)) vector_cosine_ops)
WHERE embedding IS NOT NULL AND embedding_dimension = 64;
  • 非默认维度仍保留兼容查询:
embedding <=> CAST(:query_vector AS vector)

这样做的原因是当前生产级默认 embedding 维度已经统一为 64,查询必须与表达式索引形态一致,PostgreSQL 才能使用 HNSW,而不是退化为顺序扫描。

2. pgvector 成功执行后不再误回退全量扫描

之前逻辑里,pgvector 查询返回空列表时会继续走 repository 的 Python 全量排序路径。真实数据量上这会造成慢查询,也会掩盖向量检索本身的问题。

已调整为:

  • None 表示 pgvector 执行失败,可以回退。
  • [] 表示 pgvector 成功执行但没有命中,不再回退全量扫描。

3. 向量候选池收口

新增候选池范围:

  • 最小候选数:100
  • 最大候选数:500
  • 默认按 limit * 25 计算后夹紧

这样既保留混合排序的候选空间,又避免无限拉取候选造成接口变慢。

4. 中文法律核心词检索修正

文件:

  • yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api/embeddings.py
  • yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api/main.py

调整:

  • 不再把“合同”“风险”作为 embedding 检索泛词过滤掉。
  • 知识库检索接口现在可以正常搜索“合同”“风险”“押金”“租赁”。
  • 法律问答层增加“泛合同问题”保护:例如“这个合同需要注意什么?”不强行召回某条不相干的劳动合同法,而是回到默认合同风险回答和民法典兜底依据。

这保持了两个目标:

  • 知识库检索要能搜领域核心词。
  • 法律问答不能因为泛词而错误引用不相关法条。

本地验证

命令:

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\main.py yuqei-ai-platform\services\ai-platform-api\src\yuqei_ai_platform_api\repository.py yuqei-ai-platform\services\ai-platform-api\src\yuqei_ai_platform_api\embeddings.py

结果:

  • 39 passed
  • compileall 通过

新增测试覆盖:

  • 默认 64 维 pgvector 查询表达式必须包含 CAST(embedding AS vector(64)) 和 CAST(:query_vector AS vector(64))。
  • 非默认维度仍走兼容查询表达式。
  • “合同”“风险”作为中文法律核心词必须可搜索。

V2 smoke 部署验证

部署命令:

$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-03-01

远端数据库状态:

  • ai_platform_alembic_version = 20260624_0015
  • knowledge_chunks = 60002
  • embedding 非空数量:60002
  • embedding_dimension:最小 64,最大 64
  • HNSW 索引存在:ix_knowledge_chunks_embedding_hnsw

EXPLAIN ANALYZE 结果

验证 SQL:

EXPLAIN (ANALYZE, BUFFERS)
SELECT id
FROM knowledge_chunks
WHERE embedding IS NOT NULL
  AND embedding_dimension = 64
ORDER BY CAST(embedding AS vector(64)) <=> CAST(:query_vector AS vector(64))
LIMIT 10;

关键结果:

Index Scan using ix_knowledge_chunks_embedding_hnsw on knowledge_chunks
Execution Time: 1.668 ms

结论:

  • 代码当前使用的 CAST(embedding AS vector(64)) 可以命中迁移创建的 embedding::vector(64) HNSW 表达式索引。
  • pgvector 查询已经从原来的顺序扫描风险,收口为 HNSW 索引扫描。

API 抽样验证

远端 smoke 环境接口:

  • GET /api/v1/knowledge-chunks/search
  • POST /api/v1/legal/qa

知识库搜索抽样:

关键词 策略 结果数 首条分数 说明
合同 hybrid 3 0.5711 中文核心词可检索
风险 hybrid 3 0.5365 中文核心词可检索
押金 hybrid 3 0.6326 租赁押金场景命中
租赁 hybrid 3 0.55 租赁场景命中
deposit refund vector 3 0.2281 纯向量路径返回候选

法律问答抽样:

问题 首条依据 结果
这个合同需要注意什么? 中华人民共和国民法典 第五百零九条 泛合同问题回到默认兜底
房屋租赁合同押金退还应注意什么? 租赁押金法条片段 具体问题走知识库命中
劳动合同试用期最长可以约定多久? 知识库片段 具体问题走知识库命中

当前边界

  • 本轮已经解决 pgvector/HNSW 查询形态,不继续扩大为全文检索重写。
  • chunk 的 title/reference/content 已有 pg_trgm GIN 索引,但当前 SQL 使用 lower(...) LIKE,对部分泛词仍可能不是最优。后续如要继续压缩“合同/风险”这类超高频词耗时,可以单独做关键词 SQL 形态优化或生成列索引。
  • 当前 smoke 数据中存在大量性能样本 chunk,返回的法条标题会带有测试数据特征。生产数据导入后需要结合真实法规库重新跑质量抽样。

下一步建议

DB-5 的 pgvector 查询形态已经收口。下一步更自然进入:

  1. 关键词检索 SQL 形态优化:将 lower(...) LIKE 调整为更容易命中 trigram/tsvector 的查询方式,并做高频中文词基线。
  2. RAG 可解释接口增强:在 explain 中显示是否走 HNSW、候选数量、关键词候选补充数量和最终混合排序原因。
  3. 真实法规库导入质量验证:用民法典、劳动合同法、公司法等真实文本重新跑“主要依据”命中质量和延迟基线。