Skip to content
指南阅读约需 9 分钟

法律文档标注最佳实践

在 Potato 中标注合同、法庭文件和监管文本:章节级条目、条款与实体方案、关键词高亮,以及面向专家标注者的质量控制。

Potato Team

在文档进入标注工具之前,先把冗长的法律文档拆成章节级的条目,用各自独立的方案来标注条款和实体,并让懂这个领域的标注者来承担这项任务。对质量影响最大的一个决定是你在哪里切分文档,因为脱离了定义和交叉引用标注出来的条款,标的就是错的。

法律文本推翻了大多数标注方案所依赖的前提。文档动辄数百页,词汇专门到未经培训的众包工作者无法套用标注指南,而含义又取决于对某些章节的交叉引用,那些章节可能在五十页之外。一个差不多对的 span 边界会改变一个条款要求当事方去做什么,所以平常对边界大致准确的那种容忍度在这里不成立。

在 Potato 看到文档之前先做的准备

分段属于数据准备的步骤,而不是某项配置设置。Potato 标注的是你交给它的条目,所以一份合同要变得可标注,得先在你自己的流水线里拆成若干章节,每一节写成一个条目,并带上标注者需要的元数据:

json
{
  "id": "contract_001_section_3.2",
  "text": "The Licensor grants to the Licensee a non-exclusive, non-transferable license...",
  "section_number": "3.2",
  "section_title": "License Grant",
  "document_id": "contract_001"
}

按文档自身的结构来切分,通常是带编号的标题,而不是按固定的词元数量,因为从中间被劈开的条款谁也标不了。每个条目都要带上章节编号和标题。标注者在判断一项义务是不是有条件的时候,需要知道自己身处哪一节;而条目里的章节编号也正是你事后把这些标签重新拼装成文档级标注的依据。

用 instance_display 声明你想显示哪些字段,它把标注者看到的内容和你要他们标注的内容分开:

yaml
instance_display:
  fields:
    - key: section_title
      type: text
    - key: text
      type: text

长合同也常常以 PDF 的形式送来。pdf 和 document 这两种展示类型可以直接渲染它们,省掉一道会把版式线索剥掉的抽取步骤,而有经验的读者正是靠那些线索阅读的。

实体方案与条款方案

法律标注通常会对同一段文字收集两类不同的信息。实体 span 标出条款指向的人和事物,条款标签则给整段文字分类。把它们放在各自独立的方案里,标注者就可以既标五个实体又标一个条款类型,两者互不干扰。

实体由 span 承载。每个标签都需要一个 name;而在两位标注者可能对"defined term"理解不同的任务里,写一条 tooltip 是划算的:

yaml
annotation_schemes:
  - annotation_type: span
    name: legal_entities
    description: "Mark the parties, defined terms, dates, amounts and obligations."
    labels:
      - name: PARTY
        color: "#FECACA"
        tooltip: "Contracting parties, including Licensor, Licensee and named companies"
      - name: DEFINED_TERM
        color: "#FDE68A"
        tooltip: "A term given a specific meaning by the definitions section"
      - name: DATE
        color: "#BBF7D0"
        tooltip: "Dates and time periods, including notice and cure periods"
      - name: MONETARY
        color: "#C4B5FD"
        tooltip: "Amounts, fees, penalties and caps"
      - name: OBLIGATION
        color: "#BFDBFE"
        tooltip: "Language creating a duty, such as shall, must or agrees to"
      - name: CONDITION
        color: "#FED7AA"
        tooltip: "Language making a duty conditional, such as if, unless or provided that"
      - name: REFERENCE
        color: "#E0E7FF"
        tooltip: "A cross-reference to another section or document"

条款类型是单选,所以它属于 radio 方案。列表要短到标注者能记在脑子里,并且在试标阶段检查标签分布,因为长列表里那些很少用到的类别正是分歧集中的地方:

yaml
  - annotation_type: radio
    name: clause_type
    description: "What type of clause is this?"
    labels:
      - Definitions
      - Grant of rights
      - Consideration and payment
      - Term and termination
      - Representations and warranties
      - Indemnification
      - Limitation of liability
      - Confidentiality
      - Intellectual property
      - Dispute resolution
      - Boilerplate

当一个条款可能带有不止一项义务时,用 multiselect 把它们全部收下,而不是逼着标注者二选一;再用一个 likert 搭配一个自由文本字段,把风险判断连同理由一起记下来:

yaml
  - annotation_type: multiselect
    name: obligation_type
    description: "Which kinds of obligation does this clause create?"
    labels:
      - Performance
      - Payment
      - Restriction
      - Conditional obligation
      - Warranty
 
  - annotation_type: likert
    name: risk
    description: "How much risk does this clause carry for the receiving party?"
    size: 5
    min_label: "Low risk"
    max_label: "High risk"
 
  - annotation_type: text
    name: risk_notes
    description: "Explain the risk factors you identified."
    rows: 4
    min_chars: 20

自由文本方案上的 min_chars 下限做的是质量方面的工作,而不是格式方面的。一个没有理由的风险评分事后无法裁定,而要求 20 个字符足以挡掉只填一个词的情况,又不至于让这个字段变成负担。

法庭文件

法庭文档需要的实体集合与合同不同,因为这里有用的单位是案件元数据和论证的结构。把它们作为独立的任务来做,而不是硬把合同方案拉过来覆盖:

yaml
annotation_schemes:
  - annotation_type: span
    name: case_entities
    description: "Mark case metadata and the parties to the proceeding."
    labels:
      - name: CASE_NUMBER
        tooltip: "The docket or case identifier"
      - name: COURT
        tooltip: "Court name and jurisdiction"
      - name: JUDGE
      - name: PLAINTIFF
      - name: DEFENDANT
      - name: ATTORNEY
      - name: LEGAL_CITATION
        tooltip: "Citations to cases, statutes and regulations"
      - name: RULING
 
  - annotation_type: span
    name: argument_structure
    description: "Mark the claim, its support, and the court's conclusion."
    labels:
      - name: CLAIM
        color: "#FECACA"
      - name: PREMISE
        color: "#BBF7D0"
      - name: EVIDENCE
        color: "#BFDBFE"
      - name: REBUTTAL
        color: "#FED7AA"
      - name: CONCLUSION
        color: "#E0E7FF"

高亮那些真正起作用的措辞

一个班次里读到第二十份合同时,表示义务和条件的词很容易被一眼扫过去,而它们恰恰是决定标签的词。Potato 会依据一份关键词文件来高亮这些词,那是一个 CSV 文件,其中 keyword 列是必需的,label、schema 和 color 列是可选的。* 匹配任意一串词字符:

text
keyword,label,schema,color
shall,OBLIGATION,legal_entities,#FEE2E2
must,OBLIGATION,legal_entities,#FEE2E2
agrees to,OBLIGATION,legal_entities,#FEE2E2
may,CONDITION,legal_entities,#DBEAFE
unless,CONDITION,legal_entities,#DBEAFE
provided that,CONDITION,legal_entities,#DBEAFE
notwithstand*,CONDITION,legal_entities,#DBEAFE

在配置里指向这个文件,路径相对于 task_dir:

yaml
keyword_highlights_file: data/legal_terms.csv

高亮会改变标注者的行为,如果你要衡量的正是人找出义务条款的能力,这就成了问题。keyword_highlight_settings 的应对办法是只显示一部分匹配项,并混入一些干扰项,这样标注记录下来的就是标注者自己发现的内容,而不是关键词列表标出来的内容:

yaml
keyword_highlight_settings:
  keyword_probability: 0.8       # show 80% of matched keywords
  random_word_probability: 0.05  # highlight ~5% of other words as distractors

专家任务的质量控制

法律标注把通常的众包经济学倒了过来。标注者稀缺而且昂贵,所以真正有用的控制手段是那些能尽早发现理解偏差的,而不是那些用来筛选大批人手的。

把资格认定放在最前面,做成一个培训阶段:标注者在接触真实数据之前,先带着反馈做一遍预先标好的例子。之后黄金标准会在整个过程中持续测量准确率;把反馈打开,它们就成了持续的培训信号,而不是一次无声的稽核:

yaml
num_annotators_per_item: 3
 
gold_standards:
  enabled: true
  items_file: data/gold_clauses.json
  mode: mixed
  frequency: 20
  accuracy:
    min_threshold: 0.85
    evaluation_count: 10
  feedback:
    show_correct_answer: true
    show_explanation: true

0.85 的准确率下限比通用任务会设的更高,这里站得住脚的理由是出错的代价,而不是标注者本身的什么属性。每个条目三位标注者值得这份开销,理由也一样。设计的另一半是你拿分歧怎么办。把有争议的条款交给律师裁定,而不是用多数投票来解决,因为在法律任务上,非专家的多数意见并不构成证据。

注意力检测在这里不如在众包任务上有用。领域专家不太可能在乱点,而你真正要防范的失效方式是对某条标注指南的一贯误读,这一点黄金条目能抓住,注意力检测抓不住。

一份完整的配置

yaml
annotation_task_name: "Contract Clause Analysis"
task_description: "Classify contract clauses and mark the entities they refer to."
 
data_files:
  - data/contract_sections.json
 
item_properties:
  id_key: id
  text_key: text
 
instance_display:
  fields:
    - key: section_title
      type: text
    - key: text
      type: text
 
keyword_highlights_file: data/legal_terms.csv
 
keyword_highlight_settings:
  keyword_probability: 0.8       # show 80% of matched keywords
  random_word_probability: 0.05  # highlight ~5% of other words as distractors
 
annotation_schemes:
  - annotation_type: radio
    name: clause_type
    description: "What type of clause is this?"
    labels:
      - Grant of rights
      - Consideration and payment
      - Term and termination
      - Indemnification
      - Limitation of liability
      - Confidentiality
      - Other
 
  - annotation_type: span
    name: legal_entities
    description: "Mark the parties, defined terms, dates, amounts and obligations."
    labels:
      - name: PARTY
        color: "#FECACA"
      - name: DEFINED_TERM
        color: "#FDE68A"
      - name: MONETARY
        color: "#C4B5FD"
      - name: DATE
        color: "#BBF7D0"
      - name: OBLIGATION
        color: "#BFDBFE"
 
  - annotation_type: likert
    name: risk
    description: "How much risk does this clause carry for the receiving party?"
    size: 5
    min_label: "Low risk"
    max_label: "High risk"
 
  - annotation_type: text
    name: issues
    description: "Note any unusual or problematic language."
    rows: 4
    min_chars: 20
 
num_annotators_per_item: 3
 
gold_standards:
  enabled: true
  items_file: data/gold_clauses.json
  mode: mixed
  frequency: 20
  accuracy:
    min_threshold: 0.85
    evaluation_count: 10
 
agreement_metrics:
  enabled: true
  min_overlap: 2
 
output_annotation_dir: annotation_output

撰写标注指南

在法律任务上,标注指南比方案本身分量更重,因为方案只给类别起了名字,而指南决定什么归入哪一类。指南里该写四样东西。

  • 范围。 哪些文档类型、哪些管辖区、适用哪一部准据法。一种条款类型在英国法下的含义未必搬得过去。
  • 术语表。 用标注者自己日常使用的词汇来定义每个标签,并说明这个标签不涵盖哪些日常用词。
  • 边界规则。 写明一个 span 从哪里开始、到哪里结束。表示义务的 span 要不要把触发它的条件从句包含进来,还是只包含义务本身?带上一个例子把这个问题一次性回答清楚,一致性数字就会变。
  • 交叉引用的处理方式。 说明什么时候要标注对其他章节的引用、什么时候忽略,因为这是合同类任务中无声分歧最常见的来源。

span 上的一致性与标签上的一致性衡量方式不同,因为两位标注者可以选中同一个实体类型,却对它从哪里开始有分歧。span 的一致性讲了精确匹配和部分匹配,而 /admin/iaa 报告会把 span_f1_exact 和 span_f1_partial 一并给出,让你看清出问题的是这两者中的哪一个。

延伸阅读