Skip to content

Taxonomy.yml

Jack J Burleson // Lucius Morningstar edited this page Aug 16, 2026 · 2 revisions

CORE TAXONOMY

# Mailroom Document Taxonomy — prompt experiment loop task specification.
# Same taxonomy as llm-mailroom/config/taxonomy.yaml (sibling repo).
# Adding a new doc class: add an entry below + a matching specialist schema in
# agents/specialist_agents.py. Adjusting thresholds: edit the numbers here —
# no code changes needed.

confidence:
  # high is the auto-continue gate for classification: confidence >= high -> extract -> archive.
  # Recalibrated to 0.95 from observed sorter behavior (pilot, Aug 2026): every unambiguously
  # classifiable document scored >= 0.95, while the deliberately multi-topic memo (ambiguous_01)
  # scored 0.90 — which must route to human review, not archive.
  high: 0.95
  low: 0.70        # below this -> retry; still below after retry -> human review
  retry_max: 1     # max retries before routing to review
  conflict_threshold: 0.3  # extraction confidence gap below this -> potential conflict

# Deterministic field-type-aware extraction scoring. The scorer normalizes each
# field by its type (date/money/id exact-after-normalize, name fuzzy match,
# free-text token F1, entity-list bipartite matching). `ambiguous_band` is the
# judge escalation gate: fields scoring inside the band trigger the LLM judge.
field_scoring:
  ambiguous_band: [0.5, 0.85]
  bipartite_match_threshold: 0.6  # minimum pairwise similarity for a list match
  embedding_enabled: true
  embedding_model: sentence-transformers/all-MiniLM-L6-v2
  embedding_rescue_below: 0.7  # only consult embeddings when string score is below this
  # Fields whose ground truth is a PARTIAL SAMPLE of the document's content
  # (CUAD clause-QA answer snippets, not exhaustive lists). The model is
  # usually MORE complete than the label set, so list fields here are scored
  # by GROUND-TRUTH COVERAGE (recall over matched labels; role-word labels
  # like "Shipper." match whenever any party is named) instead of F1, which
  # penalized correct extractions.
  partial_gt_fields: ["parties", "key_obligations", "termination_clauses"]
  # Verbatim-clause fields whose label is one sentence of a longer passage:
  # scored by EXPECTED-WITHIN-PREDICTED token containment, so returning the
  # expected sentence plus its riders/citations no longer zeroes the field.
  containment_fields: ["governing_law", "term_length", "renewal_terms"]
  # Factuality guard ("everything the model reports must be TRUE"): every
  # predicted list item must match a ground-truth label OR have its content
  # present in the source document (normalized token coverage >= token_coverage).
  # Items that are neither are counted as HALLUCINATED and drive the
  # verified_precision tracker down.
  factuality_verification:
    enabled: true
    token_coverage: 0.7

# Approximate per-1M-token pricing used for estimated_cost_usd scoring.
cost_models:
  qwen/qwen3.7-flash:
    input_per_million: 0.03
    output_per_million: 0.13
  deepseek/deepseek-v4-flash:
    input_per_million: 0.05
    output_per_million: 0.25
  deepseek/deepseek-v4-pro:
    input_per_million: 0.435
    output_per_million: 0.87

doc_classes:
  - key: contract
    label: "Contract / Agreement"
    schema: ContractExtraction
    specialist: contracts_specialist
    description: "Formal agreements between parties: M&A, vendor, employment, NDAs, etc."
    field_types:
      document_name: name
      parties: entity_list:name
      effective_date: date
      term_length: free_text
      termination_clauses: entity_list:free_text
      governing_law: name
      key_obligations: entity_list:free_text
      contract_value: money
      renewal_terms: free_text

  - key: merger_agreement
    label: "Merger / Acquisition Agreement"
    schema: ContractExtraction
    specialist: contracts_specialist
    description: "Merger and acquisition agreements: agreements and plans of merger, share/asset purchase agreements (MAUD corpus)"
    # Subclass: consideration type (MAUD expert GT) — all_cash / all_stock /
    # mixed_cash_stock / mixed_cash_stock_election / other. No tertiary level
    # (data-necessity rule): MAUD categories are metadata.

  - key: corporate_record
    label: "Corporate Record"
    schema: CorporateRecordExtraction
    specialist: corporate_records_specialist
    description: "Bylaws, resolutions, board minutes, cap table entries, incorporation docs"
    field_types:
      entity_name: name
      record_type: name
      effective_date: date
      key_provisions: entity_list:free_text
      signatories: entity_list:name
      jurisdiction: name
      filing_number: id

  - key: due_diligence
    label: "Due Diligence"
    schema: DueDiligenceExtraction
    specialist: due_diligence_specialist
    description: "Checklists, disclosure schedules, diligence memos, risk assessments"
    field_types:
      target_entity: name
      diligence_type: name
      material_findings: entity_list:free_text
      risk_flags: entity_list:free_text
      outstanding_items: entity_list:free_text
      document_date: date
      prepared_by: name

  - key: correspondence
    label: "Correspondence"
    schema: CorrespondenceExtraction
    specialist: correspondence_specialist
    description: "Letters, emails, memos, notices between parties or with regulators"
    field_types:
      sender: name
      recipient: name
      additional_recipients: entity_list
      communication_type: name
      communication_date: date
      key_points: entity_list
      demand_amount: money
      action_items: entity_list
      urgency: name
      referenced_communications: entity_list

  - key: compliance_filing
    label: "Compliance Filing"
    schema: ComplianceFilingExtraction
    specialist: compliance_specialist
    description: "SEC filings, state registrations, regulatory submissions, annual reports"
    field_types:
      filing_type: name
      regulatory_body: name
      filing_date: date
      due_date: date
      entity_name: name
      key_requirements: entity_list:free_text
      status: name
      reference_number: id

  - key: court_opinion
    label: "Court Opinion"
    schema: CourtOpinionExtraction
    specialist: court_opinions_specialist
    description: "Judicial opinions and orders: published decisions, memorandum opinions, rulings by federal and state courts"
    field_types:
      case_name: name
      court: name
      date_decided: date
      docket_number: id
      opinion_type: name
      parties: entity_list:name
      holding: free_text
      legal_issues: entity_list:free_text
      outcome: free_text
      citations: entity_list:id
      authored_by: name

# === Agent -> model mapping ===
# Each agent list entry: provider, model, temperature, optional max_tokens
# (caps output/reasoning-token generation) and optional max_input_chars
# (input-text budget per call; defaults to 25000). The evaluation loops read
# this file, so model cut-overs are YAML edits, not code changes.
agents:
  sorter:
    provider: openrouter
    model: qwen/qwen3.7-flash
    temperature: 0.1
    max_tokens: 2048
    max_input_chars: 12000

  contracts_specialist:
    provider: openrouter
    model: qwen/qwen3.7-flash
    temperature: 0.1
    max_tokens: 4096
    max_input_chars: 100000

  corporate_records_specialist:
    provider: openrouter
    model: qwen/qwen3.7-flash
    temperature: 0.1
    max_tokens: 4096
    max_input_chars: 40000

  due_diligence_specialist:
    provider: openrouter
    model: qwen/qwen3.7-flash
    temperature: 0.1
    max_tokens: 4096
    max_input_chars: 40000
    reasoning_effort: none

  correspondence_specialist:
    provider: openrouter
    model: qwen/qwen3.7-flash
    temperature: 0.1
    max_tokens: 4096
    max_input_chars: 40000

  compliance_specialist:
    provider: openrouter
    model: qwen/qwen3.7-flash
    temperature: 0.1
    max_tokens: 4096
    max_input_chars: 60000

  court_opinions_specialist:
    provider: openrouter
    model: qwen/qwen3.7-flash
    temperature: 0.1
    max_tokens: 4096
    max_input_chars: 60000

  # Offline LLM-as-a-judge used by scripts/eval and scripts/reporting.
  judge:
    provider: openrouter
    model: deepseek/deepseek-v4-flash
    temperature: 0.1
    max_tokens: 2048
    reasoning_effort: none

Clone this wiki locally