ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

法务智能知识图谱落地:20W问答与法律资讯问答实战

法务智能知识图谱落地:20W问答与法律资讯问答实战

简介:本资源面向法律科技方向的学习者与开发者,提供一套基于知识图谱与自然语言处理技术的法务智能问答完整方案,适合具备一定NLP与深度学习基础、希望切入法律智能应用场景的中高级读者。项目围绕案由知识库、法务资讯对话知识库与基础法律知识图谱展开,覆盖案由预测模型、法务问题类型分类、法务问题自动问答服务以及知识图谱知识查询四大任务,并附有完整码源可供复现与二次开发。压缩包整体约33.88MB,内含项目源码及相关数据文件,目录结构按功能模块划分,便于按任务定位代码与数据。目前已有675人学习下载,读者可借此掌握从数据收集、知识库构建到模型训练与问答服务落地的完整链路,理解知识图谱在金融、医疗、法律等垂直领域的工程化思路,并可直接在码源基础上调试与扩展。

1. 法务智能知识图谱落地:20W 法务问答与法律资讯问答到底怎么跑通

很多团队第一次做法务问答,第一反应是接个大模型直接怼法条,结果上线三天就被业务方投诉:问“试用期辞退要不要赔”,它给你背《劳动合同法》第三十九条原文,一个字不差,但没人知道到底赔不赔。问题不在模型,在于它没有一张能把「法条—情形—结论」串起来的知识图谱。这套基于法务智能知识图谱的方案,核心就是拿 20W 量级的法务问答对和法律资讯做底座,把非结构化的问答沉淀成实体和关系,再让法律资讯问答走图谱检索而不是纯向量召回。它适合两类人:一类是手上已经有几万条法务 FAQ、想让它真正能推理的工程团队;另一类是想评估「码源」这套东西值不值得投入的二线开发。下面按选型、建图、问答链路、避坑、进阶的顺序讲透。

2. 法务知识图谱的选型:为什么不用纯向量库硬扛

2.1 法务问答和通用问答的本质差别

通用问答里「苹果」既可以是水果也可以是公司,靠上下文消歧就够了。法务问答不行,同一个「赔偿」在劳动、合同、侵权三个领域里,计算基数、上限、举证责任完全不同。纯向量库把「违法解除劳动合同赔偿」和「合同违约赔偿」召回到一起,是因为它们在字面语义上高度相似,但法律结论南辕北辙。这就是为什么必须上知识图谱:图谱用实体类型和关系把领域隔离开,(劳动者)-[被违法解除]->(劳动合同)和(合同方)-[违约]->(买卖合同)走的是两条完全不同的推理路径,不会互相污染。

另一个差别是法务问答对「依据」的要求极高。用户问一句,你得能回出「根据《劳动合同法》第八十七条」这种可追溯的出处。向量库只能给你一段相似文本,图谱能给你一条从问题实体到法条实体的路径,路径本身就是依据。20W 问答对的价值不在于数量,而在于它们覆盖了足够多的「情形—结论」配对,能拿来抽关系。

2.2 图谱 schema 怎么定:实体、关系、属性三件套

schema 定错,后面全白干。法务领域我一般会先定四类核心实体:法条、法律概念、情形(事实场景)、结论(裁判或解答)。关系上至少要有依据(结论依据哪条法条)、适用(法条适用于哪种情形)、包含(概念之间的上下位)、冲突(两条法条或两个结论互斥)。属性里最关键的是生效时间和地域,法务知识有时效性和属地性,2021 年前的解答放到今天可能已经失效。

下面是一段最小可跑的 schema 定义,用 Python 字典表达,方便直接喂给图数据库:

# 法务知识图谱最小 schema,实体四类,关系四类 SCHEMA = { "entities": { "Law": {"props": ["title", "article_no", "content", "effective_date", "region"]}, "Concept": {"props": ["name", "domain", "definition"]}, # domain: 劳动/合同/侵权... "Situation": {"props": ["desc", "domain", "keywords"]}, # 事实场景 "Conclusion":{"props": ["text", "confidence", "source_id"]}, # 解答或裁判结论 }, "relations": { "依据": ("Conclusion", "Law"), # 结论引用哪条法条 "适用": ("Law", "Situation"), # 法条适用于哪种情形 "包含": ("Concept", "Concept"), # 概念上下位 "冲突": ("Conclusion", "Conclusion"),# 结论互斥,用于消歧 }, }

逻辑说明:entities里每个实体带自己的属性列表,relations用元组声明头尾实体类型,这样建图时能做类型校验,防止把Situation错连到Law的依据关系上。参数上,domain字段是后面做领域隔离的关键,检索时先按 domain 过滤再走图,能砍掉大量跨域误召回。effective_date和region别省,法务问答里「上海」和「北京」的工伤认定口径就不一样。

2.3 20W 问答对怎么变成图:抽取流水线

20W 条问答对不可能手工建图,得走抽取流水线。常见做法是三步:先做实体识别,把问答里的法条引用、法律概念、情形关键词抽出来;再做关系分类,判断这条问答的结论依据哪条法条;最后做对齐,把抽出来的实体链接到已有节点上,避免「劳动合同法」和「劳动合同法(2012修正)」变成两个节点。

import re # 第一步:从问答文本里抽法条引用,正则先兜底,模型再补 LAW_PATTERN = re.compile(r"《([^》]+)》第([一二三四五六七八九十百零\d]+)条") def extract_law_refs(text): refs = [] for name, art in LAW_PATTERN.findall(text): refs.append({"law": name.strip(), "article": art}) return refs # 第二步:实体对齐,把简称归一到标准名 ALIAS = {"劳动合同法": "中华人民共和国劳动合同法", "民法典": "中华人民共和国民法典"} def normalize(ref): ref["law"] = ALIAS.get(ref["law"], ref["law"]) return ref

逻辑说明:正则先跑一遍能覆盖大部分显式引用,剩下的隐式引用(比如只说「第八十七条」不说法名)再交给 NER 模型补。ALIAS字典做实体对齐,这是图谱质量的分水岭——对齐没做好,同一个法条会有多个节点,后面按法条聚合结论时就会漏。参数上,正则里的条号要支持中文数字和阿拉伯数字两种写法,法务文本里两种都常见。跑完这一步,20W 问答对大概能抽出几十万条依据关系,这才是图谱真正的血肉。

3. 法律资讯问答的检索链路:图谱召回加向量兜底

3.1 为什么资讯问答要单独走一条链路

法务问答(FAQ 型)和资讯问答(长文型)是两种东西。前者是「问—答」配对,直接命中结论;后者是「问—资讯」,用户想知道最近某类案件的裁判趋势、某条新规的解读。资讯是长文本,直接塞进图谱不现实,所以资讯问答走的是「图谱定位领域 + 向量召回段落 + 图谱校验结论」的混合链路。图谱在这里的作用是缩小检索范围:先根据问题里的实体定位到 domain 和相关法条节点,再只在挂在这些节点下的资讯段落里做向量召回,召回精度比全库向量高一大截。

3.2 混合检索的最小实现

def hybrid_retrieve(question, kg, vector_store, top_k=5): # 1. 图谱侧:抽实体,定位 domain 和候选法条 ents = extract_entities(question) # 复用 2.3 的抽取 domains = {e["domain"] for e in ents if "domain" in e} law_nodes = kg.query_laws_by_entities(ents) # 2. 向量侧:只在图谱圈定的范围内召回 candidates = vector_store.search( question, filter={"domain": list(domains)} if domains else None, top_k=top_k * 3, ) # 3. 图谱校验:资讯段落若引用了冲突结论,降权 scored = [] for c in candidates: penalty = 1.0 for concl in c.get("conclusions", []): if kg.has_conflict(concl): penalty *= 0.5 scored.append((c, c["score"] * penalty)) return [c for c, _ in sorted(scored, key=lambda x: -x[1])[:top_k]]

逻辑说明:第一步用图谱把检索范围从全库缩到相关 domain,这是精度提升的主要来源。第二步向量召回时带filter,只在圈定范围内搜。第三步是关键——如果召回段落里的结论和图谱里标记为冲突的结论一致,说明这条资讯可能过时或口径不一致,降权处理。参数上top_k * 3是先多召回再重排的常规做法,penalty系数 0.5 可以按业务容忍度调,法务场景我一般调到 0.3,宁可保守。

3.3 问答链路的参数怎么调

参数作用建议值调大后果
domain 过滤开关是否按领域隔离检索开关掉后跨域误召回明显上升
图谱跳数从问题实体沿关系走几跳2跳数过多引入无关法条
向量 top_k召回段落数15过大拖慢重排,噪声增多
冲突降权系数冲突结论的惩罚0.3调高会误伤正常资讯
时效过滤是否按 effective_date 过滤开关掉会召回已废止法条

这张表是上线前必调的五个旋钮。图谱跳数是最容易翻车的一个,很多人图省事设成 3 跳以上,结果从「试用期辞退」一路走到「劳动合同订立」,召回一堆不相关法条。2 跳基本够用:一跳找到直接法条,二跳找到相关概念。

4. 避坑与排查:法务图谱上线后最常见的五个坑

4.1 现象:同一法条在图上出现多个节点,聚合结论时漏数据

原因:实体对齐没做全,简称、全称、带修正年份的版本各建了一个节点。解决:建图前先跑一遍别名归一,把ALIAS字典补全,并在入库时对law + article_no做唯一约束,重复的直接 merge 而不是新建。

4.2 现象:问答结果引用了已废止的法条

原因:effective_date字段没填或没参与检索过滤。解决:抽取阶段强制要求法条节点带生效和废止时间,检索时默认加effective_date <= now且未被废止的条件。法务场景这条不能省,引用废止法条是硬伤。

4.3 现象:跨领域误召回,问劳动问题返回合同结论

原因:domain 过滤没开,或者实体抽取时没识别出 domain。解决:在 schema 里给Situation和Concept都打 domain 标签,检索第一步就按 domain 圈范围。如果问题里没抽到 domain,宁可让用户澄清,也别全库搜。

4.4 现象:图谱跳数一调大,召回法条数量爆炸

原因:关系设计里有大量包含这类传递性关系,跳数一多就沿着概念树爬满全图。解决:把依据、适用这类强关系设为可跳,包含这类弱关系限制跳数或只在特定查询里用。我一般给关系打权重,检索时按权重截断。

4.5 现象:20W 问答对建完图,问答准确率反而比纯向量低

原因:抽取噪声进了图,错误关系污染了推理路径。解决:建图后加一道人工抽检,按 domain 分层抽样,每条依据关系核对是否成立,噪声率超过 5% 就回炉重抽。图谱不是越多越好,错的关系比没有关系更糟。

5. 进阶:用图谱做结论一致性校验和增量更新

图谱建完不是终点,它最大的隐藏价值是能当「后悔药」用——校验新进来的问答和资讯结论是否和已有图谱冲突。做法很简单:新结论入库前,先沿依据关系找到它引用的法条,再看这些法条下已有哪些结论,如果新结论和已有结论在冲突关系上被标记过,就拦下来人工复核。这一步能挡住大部分口径不一致的脏数据。

def check_consistency(new_conclusion, kg): laws = kg.get_laws_of(new_conclusion) # 新结论依据的法条 for law in laws: existing = kg.get_conclusions_by_law(law) # 该法条下已有结论 for e in existing: if kg.has_conflict(new_conclusion, e): return {"ok": False, "conflict_with": e["id"]} return {"ok": True}

逻辑说明:get_laws_of走依据关系拿到法条,get_conclusions_by_law反向拿同法条下的结论,has_conflict查冲突关系。参数上,冲突判定可以先用规则(结论文本里的关键词互斥,如「需要赔偿」vs「无需赔偿」),规则覆盖不了的再上模型。这套校验跑在入库前,比事后清洗便宜得多。

增量更新是另一个进阶点。法条会修订,资讯会新增,图谱不能每次重建。常见做法是给节点和关系加version和updated_at,新法条生效时只更新受影响的子图,沿依据关系找到所有引用该法条的结论,标记为「待复核」。这样一次修订只动局部,不用全量重跑 20W 问答对的抽取。

最后说个我自己的习惯:每次 schema 改动,我都会先拿 200 条问答对跑一遍回归,看准确率和召回率有没有掉。图谱这东西改一处动全身,没有回归集就是盲改。法务问答的容错率低,宁可上线慢一点,也别让用户拿到一条引错法条的答案。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进