"""索引验证脚本 — 预置典型查询,抽样验证检索质量 用法: python scripts/verify_index.py 输出每个查询的 Top-5 结果,供人工评估命中率。 """ import asyncio import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent.parent)) from app.services.retriever import Retriever from app.services.embedding import embed_text # 预置典型查询(20 个,覆盖各类别) TEST_QUERIES = [ # 法律 "个人信息保护", "个人信息跨境传输", "竞业协议补偿金", "民法典婚姻家庭", "合同违约责任", "知识产权侵权赔偿", "公司股东权利", # 行政法规 "不动产登记流程", "专利申请条件", # 司法解释 "公益诉讼办案规则", "刑事诉讼证据规则", # 监察法规 "监察工作信息公开", # 地方性法规 "垃圾分类管理", "烟花爆竹禁放", "物业管理规定", "生态环境保护", "城市市容管理", "食品安全监管", "道路交通管理", "未成年人保护", ] async def verify(): """执行验证""" # 加载索引 retriever = Retriever.get_instance() retriever.load() if not retriever.is_ready(): print("索引未加载,请先执行构建") return print("=" * 70) print(" QYLAW 索引验证") print("=" * 70) hit_count = 0 total = len(TEST_QUERIES) for i, query in enumerate(TEST_QUERIES, 1): print(f"\n[{i}/{total}] 查询: {query}") try: query_vec = await embed_text(query) results = retriever.search(query_vec, top_k=5) if results: print(f" Top-5 结果:") for j, r in enumerate(results, 1): score = r["score"] law = r["law_name"] clause = r.get("clause_no", "") chapter = r.get("chapter", "") content_preview = r["content"][:80].replace("\n", " ") print(f" {j}. [{score:.4f}] {law} {clause} ({chapter})") print(f" {content_preview}...") # 简单命中率判断:Top-1 分数 > 0.5 视为命中 if results[0]["score"] > 0.5: hit_count += 1 print(f" ✅ 命中") else: print(f" ⚠️ 分数偏低") else: print(f" ❌ 无结果") except Exception as e: print(f" ❌ 错误: {e}") print("\n" + "=" * 70) print(f" 验证完成: {hit_count}/{total} 命中 (Top-1 score > 0.5)") print("=" * 70) def main(): asyncio.run(verify()) if __name__ == "__main__": main()