用 GLM-Legal 读判决书,能不能直接引用它给出的争议焦点和裁判要旨,取决于每条摘要能不能回到原文的某一句话。稳妥的做法是:先把判决书按段落切出可定位的结构位置,再让模型只做指认、不做改写,最后逐条回原文比对,把增加、遗漏、改写三类偏差分别标出来。凡是回不到原句的条目,先不要放进对外使用的摘要。
判决摘要在检索、归类、初步判断时可用,直接引用风险偏高。可执行的做法是:先按段落建立位置编号,要求 GLM-Legal 输出的每条争议焦点和裁判要旨都带段落编号与原句索引;再用脚本或人工把摘要逐条贴回原文核对,原文没有的内容标为增加,原文有而未提取的标为遗漏,换了说法的标为改写。金额、日期、姓名、案号一律以原文为准,核对状态未置为已核的条目不要进入正式摘要。
在判决书里切出当事人、诉请、争议焦点、裁判理由
结构化输入的目的不是把判决书改写成另一种文体,而是给每一段文字一个可以回指的坐标。段落编号加字符起止位置,就足以支撑后面的核对;结构标签只是让模型知道这段属于哪一类,减少它自由概括的空间。判决书常见的结构块包括首部(当事人、案号、审理经过)、诉请与答辩、经审理查明的事实、争议焦点、本院认为部分、裁判依据、判决结果,但具体文书的分段方式差异较大,规则匹配只能打底,标签仍需人工抽查修正。
下面这段 Python 只做两件事:按行切段并记录 start/end 字符位,再按关键词给段落打结构标签。把 raw_text 换成实际读取到的判决书全文即可。关键词列表要结合手上的文书样本调整,不要指望一套规则覆盖所有法院的写法。
import json
def segment(raw_text):
blocks, cursor = [], 0
for line in raw_text.split('\n'):
s = line.strip()
if not s:
continue
start = raw_text.find(s, cursor)
end = start + len(s)
cursor = end
blocks.append({'pid': 'P%04d' % (len(blocks) + 1),
'start': start, 'end': end, 'text': s})
return blocks
LABELS = [
('首部', ['原告', '被告', '上诉人', '被上诉人', '第三人']),
('诉请与答辩', ['诉讼请求', '请求判令', '答辩称', '上诉请求']),
('查明事实', ['经审理查明', '本院查明', '一审法院查明']),
('争议焦点', ['争议焦点', '本案争议焦点为']),
('裁判理由', ['本院认为', '本院经审查认为']),
('裁判依据', ['依照', '根据《']),
('裁判结果', ['判决如下', '裁定如下']),
]
def label(blocks):
current = '首部'
for b in blocks:
for name, keys in LABELS:
if any(k in b['text'] for k in keys):
current = name
break
b['section'] = current
return blocks
blocks = label(segment(raw_text))
print(len(blocks), blocks[0], blocks[-1])运行后先看首尾两条的 start/end 能否用 raw_text[start:end] 原样切回该段文字,再抽几段人工确认结构标签。切不回去,说明分段逻辑有问题,后面的核对全部不可信。
| 结构块 | 识别线索 | 是否允许改写 | 建议引用方式 |
|---|---|---|---|
| 首部 | 当事人、案号、审理经过 | 不允许 | 照抄,含姓名与案号 |
| 诉请与答辩 | 请求判令、答辩称 | 可压缩,不可换意 | 带段落编号 |
| 查明事实 | 经审理查明 | 谨慎压缩 | 带段落编号与原句 |
| 争议焦点 | 争议焦点、本院归纳 | 不允许 | 原句加段落编号 |
| 裁判理由 | 本院认为 | 可摘要,须能回指 | 原句加段落编号 |
| 裁判结果 | 判决如下、裁定如下 | 不允许 | 照抄 |
让 GLM-Legal 按结构提取争议焦点和裁判要旨
这一步的目标是拿到候选摘要,而不是拿到最终结论。关键在于把原文位置变成硬性输出字段:每条争议焦点和裁判要旨都必须给出段落编号、原句索引和字符区间,缺一项就不接收。提示词里要明确禁止扩写和同义替换,找不到原句的条目直接省略,而不是让模型自行补一个看起来合理的说法。
system:
你是判决书信息提取器,只做指认,不做改写。
用户输入为带编号的段落,每段形如 [P0012] 正文。
输出要求:
1. 只输出 JSON,不要解释文字。
2. issues 为争议焦点,holdings 为裁判要旨(本院认为部分的核心判断)。
3. 每条必须包含 para_ids、quote、source_span 三个字段。
4. quote 为原文连续截取,不超过 40 字,不得改写、不得补字。
5. 涉及金额、日期、姓名、案号,原样照抄。
6. 原文没有直接表述的内容不生成;找不到原句的条目直接省略。
输出示例:
{'issues': [{'issue_id': 'I1', 'para_ids': ['P0012'],
'quote': '本案争议焦点为合同解除时间',
'source_span': [1234, 1250]}],
'holdings': [{'holding_id': 'H1', 'para_ids': ['P0031'],
'quote': '本院认为,合同自通知到达时解除',
'source_span': [3120, 3145]}]}接入层可以用通用的对话补全骨架,字段名以实际使用的 SDK 或网关为准,temperature 调低以抑制改写。system 提示词和拼接后的段落文本放在同一次请求里,段落编号必须随文本一起送入,否则模型给出的原句索引无从对应。
POST {base_url}/chat/completions
Content-Type: application/json
{
'model': 'glm-legal',
'temperature': 0.1,
'messages': [
{'role': 'system', 'content': SYSTEM_PROMPT},
{'role': 'user', 'content': '[P0001] ...\n[P0002] ...'}
],
'response_format': {'type': 'json_object'}
}返回后先做格式校验再进下一步:JSON 能否解析、每条 para_ids 是否存在于分段表、source_span 是否落在全文长度范围内、quote 是否为空。任一项不通过就重跑该段,不要带着坏数据往下走。
回原文核对提取内容是否偏离判决表述
核对是整条链路上最不能省的一步。做法很直接:把每条摘要的 quote 拿去和原文对应区间做字符串比对,能精确命中就通过,命中不了再决定是偏移问题还是概括问题。核对结果要落到一张对照表里,逐条记录增加、遗漏和改写三类情况,方便后面复核和留痕。
def check(item, raw_text):
span = item.get('source_span')
quote = item.get('quote', '')
if not quote:
return 'EMPTY_QUOTE'
if span and quote in raw_text[span[0]:span[1]]:
return 'OK'
if quote in raw_text:
return 'SPAN_OFFSET_MISMATCH'
return 'QUOTE_NOT_FOUND'| 条目 | 模型摘要 | 段落编号 | 原文原句 | 判定 | 差异类型 |
|---|---|---|---|---|---|
| I1 | 合同解除时间存在争议 | P0012 | 本案争议焦点为合同解除时间 | OK | 无 |
| H1 | 合同自通知到达时解除且无需催告 | P0031 | 本院认为,合同自通知到达时解除 | QUOTE_NOT_FOUND | 增加(无需催告) |
| — | 未提取违约金调整的论述 | P0044 | 本院认为,违约金过分高于损失应予调整 | — | 遗漏 |
QUOTE_NOT_FOUND 不一定是编造,也可能是模型把两段合成了一句,需要人工读原文判断是改写还是无中生有。遗漏类要靠通读裁判理由段落反向补,脚本本身发现不了。判定为增加或改写的条目,不要就地修正后静默通过,要保留原始输出。
标出模型概括与原文不一致的句子
差异记录的作用是留痕,不是给人看的热闹。每条记录同时保存模型原句、判决原句、差异类型和段落编号,加上处理人和处理时间占位,便于后续追溯是哪一版提示词、哪一次请求产生的偏差。建议用 JSONL 按行追加,方便逐条筛。
{'item_id': 'H1',
'para_ids': ['P0031'],
'model_text': '合同自通知到达时解除且无需催告',
'source_text': '本院认为,合同自通知到达时解除',
'source_span': [3120, 3145],
'diff_type': 'ADDED',
'reviewer': '<处理人>',
'reviewed_at': '<时间>',
'status': 'pending'}- ADDED:模型写出了原文没有的限定、条件或结论,常见于把多段观点合并。
- MISSING:原文有明确表述但未进入摘要,多发生在裁判理由的后半段。
- REWRITTEN:意思接近但用词被替换,金额、日期、主体名称一旦被换就必须回改。
- SPAN_OFFSET_MISMATCH:quote 能在全文找到但字符区间对不上,通常说明分段或拼接环节有偏移。
记录不要覆盖原值。同一段落多次提取出现的差异,可以按 para_ids 聚类,反过来看是提示词问题还是这一版模型对某类表述不稳定。
输出可溯源的判决摘要
最终交付的摘要,每条都要带段落编号和核对状态,读的人能据此决定是否回查原文。核对状态建议只保留三种:已核(quote 命中且语义一致)、待确认(格式或偏移存疑、需人工判读)、已剔除(判定为增加或无法回指原文)。状态由回原文核对脚本和人工共同置定,模型自己声明的可信度不作数。
[争议焦点-1] 本案争议焦点为合同解除时间
原文:本案争议焦点为合同解除时间
位置:P0012 source_span [1234, 1250]
状态:已核
[裁判要旨-1] 合同自通知到达时解除
原文:本院认为,合同自通知到达时解除
位置:P0031 source_span [3120, 3145]
状态:已核
[裁判要旨-2] 违约金过分高于损失应予调整
原文:本院认为,违约金过分高于损失应予调整
位置:P0044 source_span [4010, 4032]
状态:待确认交付前做一次回查验证:随机抽几条已核摘要,用 pid 从分段表取回原文,确认文字与摘要一致;把全部待确认条目单独列一份清单交给复核人。需要把摘要用于对外文书、检索库或问答内容时,只放已核条目,待确认和已剔除的留在内部记录里。判决书版本变更或补充裁定时,重新跑一遍分段和提取,旧记录按 para_ids 标记失效,不要直接沿用上一版摘要。