feat: QYLAW 法律法规知识库
- 语义检索(FAISS + embedding)+ 精确查找(法规名+条号) - RAG 问答(SSE 流式,支持 thinking 折叠显示) - 法规浏览(原文阅读) - 历史记录(检索+对话持久化到 SQLite) - 设置页(系统提示词/模板/LLM 参数可配置) - 检索质量评估脚本 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
"""索引验证脚本 — 预置典型查询,抽样验证检索质量
|
||||
|
||||
用法:
|
||||
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()
|
||||
Reference in New Issue
Block a user