Metadata-Version: 2.4
Name: routed-confidence
Version: 0.1.6
Summary: Field-level confidence evaluator SDK for routed extraction results
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: pyyaml>=6.0.2
Requires-Dist: requests>=2.31.0

# routed-confidence

字段级置信度评估 SDK。

`routed-confidence` 输入一条抽取结果，输出每个字段的置信度分数。它默认不写文件、不启动服务、不计算检出率/误伤率/日报统计。只有显式传入 `collection_dir` 时，才会把评估输入和输出收集到本地 JSON 文件。

Python 包名：

```bash
pip install routed-confidence
```

Python 导入名：

```python
from routed_confidence import ConfidenceEvaluator
```

## 核心能力

SDK 有三类使用模式：

| 模式 | 入口 | 适用场景 |
| --- | --- | --- |
| 内置评估器 | `ConfidenceEvaluator.from_infotype(...)`、`from_builtin(...)` 或 `from_name(..., evaluators_dir=None)` | 使用 SDK 包内置 evaluator，包括股东大会召开情况规则和上市公司公告类别配置包 |
| 直接 LLM 评估 | `ConfidenceEvaluator(model=..., api_key=..., base_url=...)` 或 `use_llm=True` | 没有 schema、关系规则、历史数据时，直接让模型判断任意字段置信度 |
| 构建后的命名评估器 | `EvaluatorBuilder(...).build(...)` 后用 `ConfidenceEvaluator.from_name(...)` | 针对某类数据构建专用 schema、字段关系和 historical/Wilson 维度后长期复用 |

### 模式选择

- 只配置模型，且不传 `rules_file`、`weights`、`historical_data_file`、`wilson_scores` 时，会自动进入直接 LLM 评估模式。
- 传 `use_llm=True` 时，会强制进入直接 LLM 评估模式。
- 想使用 SDK 已内置的 evaluator 时，使用 `ConfidenceEvaluator.from_infotype(...)`、`ConfidenceEvaluator.from_builtin(...)` 或 `ConfidenceEvaluator.from_name(..., evaluators_dir=None)`。
- 想构建某类数据专用 evaluator 时，使用 `EvaluatorBuilder.build(...)`，构建完成后再通过 `ConfidenceEvaluator.from_name(...)` 或 `ConfidenceEvaluator.from_config(...)` 加载。
- 使用 `ConfidenceEvaluator.from_name(...)` 或 `ConfidenceEvaluator.from_config(...)` 时，会加载构建后的配置化评估器。
- `ConfidenceEvaluator()` 仍保留为兼容旧用法，等价于加载包内置的 `LegacyMeetingEvaluator` 股东大会召开情况规则。

也就是说：

```text
只想马上评估任意字段       -> 直接 LLM 模式
想使用内置 evaluator      -> from_infotype / from_builtin
想针对某类数据沉淀规则     -> 先 build，再按 evaluator_name 加载
想使用内置股东大会规则     -> from_infotype("股东大会-股东大会召开情况")
```

## 安装

本地开发安装：

```bash
pip install -e .
```

从本地 wheel 安装：

```bash
python3 -m pip wheel . --no-deps --no-build-isolation -w dist
pip install dist/routed_confidence-*.whl
```

从 PyPI 或私有 PyPI 安装：

```bash
pip install routed-confidence
```

## 快速开始

### 内置评估器

```python
from routed_confidence import ConfidenceEvaluator

record = {
    "extraction_result": {
        "会议召开时间": {
            "value": "2026-05-20 14:00:00",
            "content": "会议召开时间为2026年5月20日14:00",
            "type": "text",
            "title_path": ["一、会议基本情况"],
        }
    },
    "input_text": "会议召开时间为2026年5月20日14:00。",
}

evaluator = ConfidenceEvaluator.from_infotype("股东大会-股东大会召开情况")
result = evaluator.evaluate(record)
print(result)
```

也可以用 evaluator 名称加载同一个内置评估器：

```python
evaluator = ConfidenceEvaluator.from_builtin("LegacyMeetingEvaluator")
```

`ConfidenceEvaluator()` 仍可使用，但它只是兼容旧写法；新代码建议统一使用 `from_infotype(...)` 或 `from_builtin(...)`。

一次性评估：

```python
from routed_confidence import evaluate_confidence

result = evaluate_confidence(record)
```

SDK 也内置了从 `methods/100_kinds/evaluator_generator/output` 迁移来的上市公司公告类别配置包。调用时同样优先按 `infotype` 加载：

```python
from routed_confidence import ConfidenceEvaluator

record = {
    "input_text": "公司将于2025年9月19日15:00-17:00通过网络远程方式举行上市公司集体接待日活动。",
    "extraction_result": {
        "原文_举行方式": {
            "value": "网络远程",
            "content": "通过网络远程方式举行",
            "type": "text",
            "title_path": ["活动安排"],
        },
        "原文_活动时间": {
            "value": "2025年9月19日15:00-17:00",
            "content": "2025年9月19日15:00-17:00",
            "type": "text",
            "title_path": ["活动安排"],
        },
    },
}

evaluator = ConfidenceEvaluator.from_infotype("临时公告-上市公司集体接待日")
result = evaluator.evaluate(record)
```

也可以按 evaluator 名称加载：

```python
evaluator = ConfidenceEvaluator.from_builtin("TN_LCRDEvaluator")
result = evaluator.evaluate(record)
```

或用 `from_name(..., evaluators_dir=None)` 表示从 SDK 内置目录加载：

```python
evaluator = ConfidenceEvaluator.from_name("TN_LCRDEvaluator", evaluators_dir=None)
```

#### 内置类别查询

内置 evaluator 的字段名以 SDK 内置配置为准。调用前不要手写或猜测字段名；请统一通过查询接口确认 `infotype`、`evaluator_name` 和该类别接收的字段名。

完整类别和字段清单见 [docs/builtin_evaluators.md](docs/builtin_evaluators.md)。

查看当前内置类别：

```python
from routed_confidence import list_builtin_infotypes

for item in list_builtin_infotypes():
    print(item)
```

当前内置 evaluator 数量为 109 个；其中 `LegacyMeetingEvaluator` 是包内置的股东大会召开情况规则，其余为上市公司公告类别配置包。`infotype` 支持完整名称和常见别名，例如 `临时公告-上市公司集体接待日` 与 `上市公司集体接待日` 都可以匹配。

`list_builtin_infotypes()` 返回示例：

```python
[
    {
        "infotype": "股东大会-股东大会召开情况",
        "evaluator_name": "LegacyMeetingEvaluator",
        "aliases": ["股东大会-股东大会召开情况", "股东大会召开情况", "股东大会", "meeting"],
        "field_count": 15,
        "score_scaling": False,
    },
    {
        "infotype": "临时公告-发生重大债务或重大债权到期未清偿",
        "evaluator_name": "TN_MDOCDEvaluator",
        "aliases": ["临时公告-发生重大债务或重大债权到期未清偿"],
        "field_count": 8,
        "score_scaling": True,
    },
]
```

查询某个类别接收的字段名和输入格式：

```python
from routed_confidence import get_builtin_evaluator_info

info = get_builtin_evaluator_info("临时公告-发生重大债务或重大债权到期未清偿")

print(info["evaluator_name"])
print(info["field_names"])
print(info["fields"]["原文_证券代码"])
print(info["input_shape"])
```

`get_builtin_evaluator_info(...)` 返回示例：

```python
{
    "evaluator_name": "TN_MDOCDEvaluator",
    "infotype": "临时公告-发生重大债务或重大债权到期未清偿",
    "field_count": 8,
    "field_names": [
        "原文_公司名称",
        "原文_证券代码",
        "原文_证券简称",
        "原文_重要内容提示",
        "原文_债务未清偿原因",
        "原文_未清偿债务本息金额",
        "原文_公告日期_不包括年份",
        "原文_未清偿债务利息和违约金合计金额",
    ],
    "score_scaling": {
        "enabled": True,
        "mode": "legacy_display_score",
        "field_thresholds": {"原文_证券代码": 0.41533266205276875},
    },
    "input_shape": {
        "record": {
            "input_text": "公告全文或相关原文，可选但建议提供",
            "extraction_result": {
                "原文_证券代码": {
                    "value": "<抽取值>",
                    "content": "<字段证据文本，可选>",
                    "type": "string",
                    "title_path": "<标题路径，可选>",
                }
            },
        },
        "field_value_keys": ["value", "content", "type", "title_path"],
    },
}
```

`input_shape` 描述 SDK 接收的记录结构。核心格式是：

```python
record = {
    "input_text": "公告全文或相关原文",
    "extraction_result": {
        "原文_证券代码": {
            "value": "600466",
            "content": "证券代码：600466",
            "type": "string",
            "title_path": ["公告标题"],
        }
    },
}
```

字段值也可以简写成原始值：

```python
record = {
    "input_text": "证券代码：600466",
    "extraction_result": {
        "原文_证券代码": "600466",
    },
}
```

### 批量工作流与续写输出

如果希望一次跑直接 LLM、临时构建 evaluator、内置 evaluator，并把过程完整保存到本地目录，可以使用 `ConfidenceWorkflowRunner`。用户只需要提供模型配置、输入文件和输出目录；SDK 会负责：

- 每条成功后立即保存 partial/final 结果
- 再次运行时跳过已经成功的 `index + uuid`
- 中断后续跑
- 跳过 live LLM 时保留已有 direct LLM 成功结果
- 构建 evaluator 包已存在时自动复用

```python
from routed_confidence import ConfidenceWorkflowRunner, WorkflowRunConfig

config = WorkflowRunConfig(
    output_dir="tmp_routed_confidence_prompt_test",
    input_file="methods/100_kinds/collect_dataset_match_confidence_10/O_临时公告_发生重大债务或重大债权到期未清偿_corrected.json",
    limit=10,
    infotype="临时公告-发生重大债务或重大债权到期未清偿",
    evaluator_name="sdk_mdocd_smoke",
    model="qwen3-14b",
    api_key="your-api-key",
    base_url="http://your-openai-compatible-endpoint/v1",
    llm_timeout=600,
)

summary = ConfidenceWorkflowRunner(config, progress=print).run()
print(summary)
```

默认是续写模式。需要清空输出目录重新开始时设置：

```python
config.reset_output = True
```

### 直接 LLM 评估

只配置模型时，SDK 会进入通用 LLM 评估模式。这个模式不限制字段名，适合开放式字段。

```python
from routed_confidence import ConfidenceEvaluator

record = {
    "input_text": "公司计划在上海建设新项目，总投资10亿元。",
    "extraction_result": {
        "项目地点": "上海",
        "总投资金额": "10亿元",
    },
}

evaluator = ConfidenceEvaluator(
    model="qwen3-14b",
    api_key="your-api-key",
    base_url="http://your-openai-compatible-endpoint/v1",
)

result = evaluator.evaluate(record)
print(result)
```

环境变量：

```bash
export ROUTED_CONFIDENCE_LLM_MODEL="qwen3-14b"
export ROUTED_CONFIDENCE_LLM_API_KEY="your-api-key"
export ROUTED_CONFIDENCE_LLM_BASE_URL="http://your-openai-compatible-endpoint/v1"
```

兼容常见项目环境变量：

```bash
export MODEL_NAME="qwen3-14b"
export API_KEY="your-api-key"
export BASE_URL="http://your-openai-compatible-endpoint/v1"
```

直接 LLM 模式会在 SDK 内部处理模型交互的稳定性：默认关闭思考输出，模型请求超时、连接错误、5xx/429、JSON 解析失败等可恢复错误会自动重试；多次失败后会为每个字段返回中性兜底分 `0.5` 和失败原因，调用方不需要自己写重试或跳过逻辑。

可选环境变量：

```bash
export ROUTED_CONFIDENCE_LLM_MAX_RETRIES=2
export ROUTED_CONFIDENCE_LLM_RETRY_DELAY=2
export ROUTED_CONFIDENCE_LLM_FAIL_ON_ERROR=false
```

需要严格失败而不是兜底时，可以传：

```python
evaluator = ConfidenceEvaluator(
    model="qwen3-14b",
    api_key="your-api-key",
    base_url="http://your-openai-compatible-endpoint/v1",
    llm_fail_on_error=True,
)
```

如果同时传入 `rules_file`、`weights`、`historical_data_file` 或 `wilson_scores`，SDK 会认为用户要使用多维评估器，不会自动切到 LLM-only 模式。需要强制使用 LLM-only 时，可以传：

```python
evaluator = ConfidenceEvaluator(
    model="qwen3-14b",
    api_key="your-api-key",
    base_url="http://your-openai-compatible-endpoint/v1",
    use_llm=True,
)
```

## 构建命名评估器

命名评估器适合某类固定业务数据。构建后，目录里保存的是配置包，不是 Python 代码；通用执行逻辑在 SDK 内部，具体业务差异由 `schema.json`、`relation_rules.json`、`wilson_scores.json` 决定。

因此 build 后看到目录里都是 JSON/YAML 是正常的。SDK 不是为每个数据类型生成一份新的 Python 文件，而是用同一套通用评估执行器读取不同配置：

```text
人员留置 evaluator -> 人员留置 schema / 关系 / Wilson
股东大会 evaluator -> 股东大会 schema / 关系 / Wilson
其他数据类型       -> 对应类型自己的 schema / 关系 / Wilson
```

运行时通过 evaluator 名字选择配置包：

```python
evaluator = ConfidenceEvaluator.from_name(
    "personnel_retention_v1",
    evaluators_dir="./confidence_evaluators",
)
```

### 构建

```python
from routed_confidence import EvaluatorBuilder

builder = EvaluatorBuilder(
    model="qwen3-14b",
    api_key="your-api-key",
    base_url="http://your-openai-compatible-endpoint/v1",
)

builder.build(
    evaluator_name="personnel_retention_v1",
    infotype="O_临时公告_人员留置",
    historical_data_file="./data/O_临时公告_人员留置_preprocessed.json",
    output_dir="./confidence_evaluators",
    schema_file=None,
    schema_edit_mode="suggest",
    relation_mode="llm",
    wilson_adjustment="suggest",
    overwrite=False,
)
```

`evaluator_name` 必须以英文字母开头，只能包含英文字母、数字和下划线：

```text
^[A-Za-z][A-Za-z0-9_]{0,63}$
```

如果 `output_dir/evaluator_name` 已存在且 `overwrite=False`，构建会直接报错。传 `overwrite=True` 才会重建。

### 输出目录

```text
confidence_evaluators/
  registry.json
  personnel_retention_v1/
    evaluator.yaml
    schema.json
    relation_rules.json
    wilson_scores.json
    field_statistics.json
    build_report.json
    prompts/
      relation_prompt.md
```

这些文件共同定义一个可复用 evaluator：

- `evaluator.yaml`：评估器元信息、权重、文件路径、fallback 策略。
- `schema.json`：字段类型、必填、枚举、格式、长度等规则。
- `relation_rules.json`：字段间关系规则。
- `wilson_scores.json`：historical/Wilson 字段先验。
- `field_statistics.json`：历史数据字段统计。
- `build_report.json`：构建报告、warning、来源说明。

### 加载

按名字加载：

```python
from routed_confidence import ConfidenceEvaluator

evaluator = ConfidenceEvaluator.from_name(
    "personnel_retention_v1",
    evaluators_dir="./confidence_evaluators",
)

result = evaluator.evaluate(record)
```

按目录加载：

```python
evaluator = ConfidenceEvaluator.from_config(
    "./confidence_evaluators/personnel_retention_v1"
)
```

### Schema

如果不传 `schema_file`，构建器会根据历史数据生成 schema。

如果传入 `schema_file`，必须符合 SDK schema v1.0 格式：

```json
{
  "format_version": "1.0",
  "fields": {
    "原文_姓名": {
      "type": "string",
      "required": true,
      "description": "被留置或解除留置的人员姓名"
    }
  }
}
```

支持的字段类型：

```text
string, number, integer, datetime, date, enum, boolean
```

`schema_edit_mode` 控制构建器是否处理用户 schema：

- `none`：只校验，不补充、不修改。
- `suggest`：不修改 schema，只在构建报告里写建议。
- `augment`：允许补充缺失字段、examples、description 等。
- `modify`：允许根据历史数据调整字段类型和 required。

如果用户传入 schema，建议先用 `schema_edit_mode="suggest"`。这样不会改 schema，只会在 `build_report.json` 里记录模型和统计分析给出的建议。

### 字段关系

字段关系由模型根据 `infotype`、schema、字段统计和样例梳理生成。输出文件是 `relation_rules.json`。

第一版支持的关系类型：

```text
date_lte, date_gte, number_lte, number_gte, same_value, required_together, mutually_exclusive
```

如果模型不可用或输出不合法，会使用启发式规则兜底，并在 `build_report.json` 里记录 warning。

### Historical / Wilson

`wilson_scores.json` 根据历史数据自动判断来源：

- 有 `is_correct` / `is_match`：使用 Wilson 下界，标记为 `wilson_from_ground_truth`。
- 没有正确性但有 `confidence` / `total_score`：使用历史置信度估计，标记为 `estimated_from_confidence`。
- 只有字段值：使用字段分布生成弱先验，标记为 `weak_prior_from_distribution`。

`wilson_adjustment` 可选值：

- `none`：完全使用统计结果。
- `suggest`：只在 metadata/build report 中给出建议。
- `bounded`：允许按字段分布做有限幅调整。

## 输入格式

评估输入可以是直接字段字典：

```python
record = {
    "input_text": "原文内容",
    "extraction_result": {
        "字段A": "抽取值A",
        "字段B": {
            "value": "抽取值B",
            "content": "字段附近上下文",
            "type": "text",
            "title_path": ["章节标题"],
        },
    },
}
```

Builder 的 `historical_data_file` 支持常见结构：

- SDK collector 输出的 `{ "records": {...} }`
- `{ "code": "...", "message": "...", "data": [...] }`
- 普通 `list[record]`
- 以 uuid 为 key 的对象

## 返回格式

默认返回简洁格式，每个字段只包含 `total_score` 和 `reason`：

```json
{
  "field_scores": {
    "会议召开时间": {
      "total_score": 0.75,
      "reason": "字段符合 schema"
    }
  }
}
```

本地测试或排查时可以打开详细输出：

```python
evaluator = ConfidenceEvaluator.from_infotype(
    "临时公告-发生重大债务或重大债权到期未清偿",
    include_details=True,
)
result = evaluator.evaluate(record)
```

`include_details=True` 时返回完整调试信息：

```json
{
  "field_scores": {
    "原文_证券代码": {
      "source_value": "600000",
      "total_score": 0.9297,
      "raw_total_score": 0.8357,
      "dimension_scores": {
        "schema": 1.0,
        "similarity": 0.82,
        "historical": 0.5,
        "relation": 1.0
      },
      "reason": "字段符合 schema",
      "score_scaling": {
        "threshold": 0.4153,
        "direction": "low",
        "triggered": false,
        "is_match": true,
        "calibrated_score": 0.7946
      },
      "violations": [],
      "suggestions": []
    }
  },
  "summary": {
    "total_fields": 1,
    "average_score": 0.75
  }
}
```

直接 LLM 评估器在默认模式下同样只返回 `total_score` 和 `reason`。`include_details=True` 时会包含：

```json
{
  "dimension_scores": {
    "llm": 0.91
  }
}
```

注意：SDK 不返回 `is_correct`。`is_correct` 属于“标注数据 vs 提取数据”的评测逻辑，不属于置信度 SDK。

### 字段阈值缩放

内置公告配置包 evaluator 中，带旧版字段阈值配置的类别会启用字段级缩放。缩放发生在多维加权分之后：

```text
schema / similarity / wilson / relation -> raw_total_score -> 字段阈值缩放 -> total_score
```

缩放规则沿用旧 evaluator 的展示分语义：

```text
通过字段：映射到 [0.8, 1.0]
未通过字段：映射到 [0.0, 0.4]
```

默认输出只返回缩放后的 `total_score`。需要查看原始加权分、字段阈值和是否触发时，使用 `include_details=True`。

## 可选数据收集

如果想保存评估过的数据，初始化时传入 `collection_dir`：

```python
from routed_confidence import ConfidenceEvaluator

evaluator = ConfidenceEvaluator(
    collection_dir="./collected_data",
)

result = evaluator.evaluate(
    record,
    uuid="doc-001",
    infotype="股东大会-股东大会召开情况",
)
```

生成文件：

```text
./collected_data/evaluated_records_collected.json
```

收集文件格式：

```json
{
  "collection_info": {
    "description": "routed_confidence SDK collected evaluations",
    "format_version": "1.0"
  },
  "summary": {
    "total_records": 1,
    "updated_at": "2026-05-13T12:00:00"
  },
  "records": {
    "doc-001": {
      "uuid": "doc-001",
      "timestamp": "2026-05-13T12:00:00",
      "infotype": "股东大会-股东大会召开情况",
      "input": {
        "extraction_result": {}
      },
      "output": {
        "field_scores": {},
        "summary": {}
      }
    }
  }
}
```

说明：

- 只有传入 `collection_dir` 才会开启收集。
- `uuid` 用于去重；同一个 `uuid` 重复评估时只保留第一次收集的数据。
- 如果不传 `uuid`，SDK 会尝试从 `record["uuid"]`、`record["met_uuid"]`、`record["id"]` 或 `record["metadata"]` / `record["met_meta"]` 中读取；都没有时会自动生成一个 UUID。
- `infotype` 只作为记录元数据保存，不影响输出文件名。
- 收集失败不会影响评估结果返回。

这是一种轻量、可选、默认关闭的收集能力。没有 `collection_dir` 参数时，SDK 不会写任何收集文件。

## 自定义规则和权重

使用 legacy 股东大会规则评估器时，也可以直接传入自定义规则和权重：

```python
from routed_confidence import ConfidenceEvaluator

evaluator = ConfidenceEvaluator(
    rules_file="/path/to/meeting_ruler.json",
    weights={
        "schema": 0.1,
        "sim": 0.2,
        "wilson": 0.1,
        "relation": 0.6,
    },
)
```

如果不传 `rules_file`，SDK 会优先寻找当前项目里的 `schema/ruler/meeting_ruler.json`，找不到时使用包内置的默认规则。

## Embedding 相似度

`similarity` 维度默认会尝试调用 OpenAI-compatible embedding 接口。

开源包不会内置任何 embedding 服务地址、模型名或 API Key。不显式配置时，SDK 会提示并自动使用本地 fuzzy 相似度，评估流程不会中断。

如果显式配置了 embedding，但服务不可用，SDK 也会提示并自动回退到本地 fuzzy 相似度。

显式配置：

```python
from routed_confidence import ConfidenceEvaluator

evaluator = ConfidenceEvaluator(
    embedding_api_base_url="http://your-embedding-service:8191",
    embedding_model="qwen3-embedding-0.6b",
    embedding_api_key="your-api-key",
)
```

环境变量：

```bash
export ROUTED_CONFIDENCE_EMBEDDING_API_BASE_URL="http://your-embedding-service:8191"
export ROUTED_CONFIDENCE_EMBEDDING_MODEL="qwen3-embedding-0.6b"
export ROUTED_CONFIDENCE_EMBEDDING_API_KEY="your-api-key"
```

本地 fallback 使用 fuzzy 相似度：

```text
0.6 * jaccard_similarity + 0.4 * sequence_similarity
```

## 包结构

主要入口：

```text
routed_confidence/evaluator.py
routed_confidence/builder.py
routed_confidence/configured_evaluator.py
routed_confidence/llm_evaluator.py
routed_confidence/builtin.py
routed_confidence/builtin_importer.py
routed_confidence/collection.py
```

构建器内部模块：

```text
routed_confidence/builder_parts/
```

内置规则和默认 historical/Wilson 数据：

```text
routed_confidence/rules/meeting_ruler.json
routed_confidence/data/default_wilson_scores.json
routed_confidence/builtin_evaluators/
```

## 当前边界

- 只做单条/字段级置信度评估。
- 可选收集评估过的数据，但默认关闭。
- 不计算检出率。
- 不计算误伤率。
- 不包含 Web/API 服务。
- 不自动生成 Python validator 代码。
- 不要求用户导入内部四维组件。
