Metadata-Version: 2.4
Name: routed-confidence
Version: 0.2.3
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
Provides-Extra: reflect-agent
Requires-Dist: pydantic-ai>=1.0.0; extra == "reflect-agent"

# routed-confidence

字段级置信度评估 SDK。

`routed-confidence` 输入一条抽取结果，输出每个字段的置信度分数。

## 建议开启用户本地采集

为了持续查看置信度评估效果，建议在用户本地开启评估输入/输出留存。用户端只需要配置 `local_collection_dir`：

```python
from routed_confidence import ConfidenceEvaluator

evaluator = ConfidenceEvaluator.from_infotype(
    "股东大会-股东大会召开情况",
    local_collection_dir="/path/to/routed_confidence_collection",
)
```

开启后，SDK 会把每次评估的输入和输出写入用户自己的本地目录，用于查看字段分数分布、低置信度字段、类别覆盖和数据质量情况。采集行为不会改变当前这次评估结果。

如果不设置 `local_collection_dir`，SDK 默认不写采集文件。

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，包括股东大会召开情况规则和上市公司公告类别配置包 |
| 通用评估器 | `ConfidenceEvaluator.general(...)` | 只有原文和抽取字段/字段值时，自动使用 SDK 内置经验库并按通用证据、类型、schema 模版评估任意字段 |
| 直接 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
只有原文和字段值，想本地通用评估 -> general
只想让模型判断任意字段       -> 直接 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",
    },
}
```

### 通用评估器

通用评估器适合这种输入：只有公告原文和抽取字段/字段值，没有类别专用 evaluator，也不想每条都调用 LLM。它是本地评估器，会自动使用 SDK 内置字段经验库，并基于全文证据检索、字段值一致性、通用类型检查和可选 schema 给出字段置信度。

```python
from routed_confidence import ConfidenceEvaluator

record = {
    "input_text": "证券代码：002645，证券简称：华宏科技。公司与中信银行签署了《保证合同》。",
    "extraction_result": {
        "证券代码": {"value": "002645"},
        "证券简称": {"value": "华宏科技"},
        "交易事项进展或完成情况": {"value": "公司与中信银行签署了《保证合同》"},
    },
}

evaluator = ConfidenceEvaluator.general()
result = evaluator.evaluate(record)
```

传入 schema 时，schema 是评估器配置，不是抽取字段信息；字段输入仍只需要 `value`。schema 可以帮助评估器理解字段类型、枚举、日期格式、字段别名、证据关键词和编码映射。

```python
schema = {
    "version": "general_eval_schema_v1",
    "fields": {
        "证券代码": {
            "type": "code",
            "required": True,
            "nullable": False,
            "pattern": "^\\d{6}$",
        },
        "股东大会类别编码": {
            "type": "enum",
            "required": True,
            "nullable": False,
            "enum_values": ["043001", "043002"],
            "description": "股东大会类别编码，043001表示年度股东大会，043002表示临时股东大会",
            "aliases": ["股东大会类别", "股东会类型"],
            "evidence_keywords": ["年度股东大会", "临时股东大会", "年度股东会", "临时股东会"],
            "value_map": {
                "043001": "年度股东大会 年度股东会",
                "043002": "临时股东大会 临时股东会",
            },
            "empty_policy": "penalize",
        },
    },
}

evaluator = ConfidenceEvaluator.general(schema=schema, evidence_mode="verify_then_retrieve")
result = evaluator.evaluate(record)
```

`ConfidenceEvaluator.general_text(...)` 仍保留为兼容旧代码的别名，新代码建议使用 `ConfidenceEvaluator.general(...)`。

通用评估器内置了常见日期/时间等价判断，例如 `2026-05-25`、`2026年5月25日`、`2026-05-25 14:00:00`、`2026年5月25日14点00分`。合理空值也会按字段经验处理，例如公告不涉及 B 股时，`B股股东资格登记日期=None` 可以被识别为合理空值。

#### 通用 schema 模版查询

不要手写猜 schema 字段。SDK 提供查询函数，可以拿到通用 schema 的完整模版、单字段模版和支持的 `type` 列表。

```python
from routed_confidence import (
    get_general_eval_schema_template,
    get_general_eval_field_template,
    list_general_eval_supported_types,
)

print(get_general_eval_schema_template())
print(get_general_eval_schema_template("证券代码"))
print(get_general_eval_field_template())
print(list_general_eval_supported_types())
```

也可以通过 `ConfidenceEvaluator` 查询：

```python
from routed_confidence import ConfidenceEvaluator

schema_template = ConfidenceEvaluator.get_general_eval_schema_template()
field_template = ConfidenceEvaluator.get_general_eval_field_template()
supported_types = ConfidenceEvaluator.list_general_eval_supported_types()
```

模版字段含义：

| 字段 | 用途 |
| --- | --- |
| `type` | 必填。字段值类型，例如 `text`、`entity`、`amount`、`percent`、`date`、`datetime`、`code`、`number`、`integer`、`boolean`、`enum`、`list` |
| `required` | 字段是否必填 |
| `nullable` | 字段是否允许为空 |
| `enum_values` | 枚举字段允许值，`type=enum` 时必填 |
| `date_formats` | 日期/时间格式约束，只用于 `date` 或 `datetime` |
| `pattern` | 正则格式约束 |
| `description` | 给写 schema 的人看的字段说明，也会作为弱查询文本帮助证据检索 |
| `aliases` | 字段在原文里的常见别名 |
| `evidence_keywords` | 检索原文证据时使用的关键词 |
| `value_map` | 抽取值到原文表达的映射，例如 `043002 -> 临时股东大会 临时股东会` |
| `empty_policy` | 空值策略：`penalize`、`neutral`、`allow_if_absent` |

#### 内置经验库

通用评估器会默认在内部使用 SDK 已沉淀的内置 evaluator 经验库。用户不需要、也不应该读取这些字段规则；只需要调用 `ConfidenceEvaluator.general()`。

```python
from routed_confidence import ConfidenceEvaluator

record = {
    "input_text": "证券代码：600466，证券简称：蓝光发展。公司部分债务未能如期清偿。",
    "extraction_result": {
        "原文_证券代码": {"value": "600466"},
        "原文_证券简称": {"value": "蓝光发展"},
        "原文_债务未清偿原因": {"value": "部分债务未能如期清偿"},
    },
}

evaluator = ConfidenceEvaluator.general(evidence_mode="verify_then_retrieve")
result = evaluator.evaluate(record)
```

如果确实想限定某一类内置经验，也可以传 `prior`、`infotype` 或 `builtin`。这不是必需用法：

```python
ConfidenceEvaluator.general(prior="临时公告-发生重大债务或重大债权到期未清偿")
ConfidenceEvaluator.general(infotype="临时公告-发生重大债务或重大债权到期未清偿")
ConfidenceEvaluator.general(builtin="TN_MDOCDEvaluator")
```

注意：这是通用评估器对内置经验库的内部复用，不是公开的字段规则查询接口，也不是直接调用原来的专用 evaluator 打分。需要查看正式内置类别和接收字段时，仍使用“内置类别查询”里的 `list_builtin_infotypes()` 和 `get_builtin_evaluator_info()`。

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

如果希望一次跑直接 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,
    evidence_mode="auto",
    retrieval_top_k=5,
)

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` 和失败原因，调用方不需要自己写重试或跳过逻辑。

长文本会自动走字段级证据模式：`field.content` 只作为候选证据，SDK 会先校验它是否可追溯到 `input_text`，再从全文检索每个字段相关的 top-k 证据片段。模型收到的是证据包，不是整篇一两百页的长文。

证据模式参数：

```python
evaluator = ConfidenceEvaluator(
    model="qwen3-14b",
    api_key="your-api-key",
    base_url="http://your-openai-compatible-endpoint/v1",
    evidence_mode="auto",          # auto / verify_then_retrieve / raw
    retrieval_top_k=5,
    chunk_size=1200,
    chunk_overlap=150,
    max_evidence_chars=8000,
)
```

行为：

- `auto`：有字段 `content` 或 `input_text` 超过约 20000 字符时启用证据解析。
- `verify_then_retrieve`：总是启用证据解析。
- `raw`：保留旧行为，直接传截断后的 `input_text` 和字段 `content`。

默认输出仍只包含 `total_score` 和 `reason`。排查证据检索时使用 `include_details=True`，每个字段会额外包含 `evidence`，例如：

```json
{
  "candidate_content": {
    "text": "证券代码：600466",
    "found_in_input_text": true,
    "match_score": 1.0
  },
  "retrieved_evidence": [
    {
      "text": "证券代码：600466 证券简称：*ST蓝光",
      "match_score": 0.97,
      "source": "input_text"
    }
  ],
  "evidence_summary": {
    "has_verified_content": true,
    "has_retrieved_evidence": true,
    "value_found_in_retrieved_evidence": true
  }
}
```

可选环境变量：

```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`。

## 用户本地采集和 HTML 查看

如果希望数据保留在用户本地，并用一个命令查看数据情况，使用 `local_collection_dir`：

```python
from routed_confidence import ConfidenceEvaluator

evaluator = ConfidenceEvaluator.from_infotype(
    "股东大会-股东大会召开情况",
    local_collection_dir="/path/to/routed_confidence_collection",
)

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

SDK 会在该目录写入本地采集文件：

```text
/path/to/routed_confidence_collection/evaluated_records_collected.json
```

查看本地收集数据的整体情况，运行一个命令生成 HTML：

```bash
python -m routed_confidence.collection_report /path/to/routed_confidence_collection
```

安装为命令行工具后也可以使用：

```bash
routed-confidence-report /path/to/routed_confidence_collection
```

默认输出文件是采集目录下的 `collection_report.html`；也可以指定位置：

```bash
routed-confidence-report /path/to/routed_confidence_collection -o /path/to/collection_report.html
```

说明：

- `uuid` 用于去重；同一个 `uuid` 重复评估时只保留第一次收集的数据。
- 如果不传 `uuid`，SDK 会尝试从 `record["uuid"]`、`record["met_uuid"]`、`record["id"]` 或 `record["metadata"]` / `record["met_meta"]` 中读取；都没有时会自动生成一个 UUID。
- `infotype` 只作为记录元数据保存。
- 收集失败不会影响评估结果返回。
- 采集数据包含评估输入、抽取结果和置信度输出，部署方应在用户授权、脱敏和权限控制满足要求后再开启。

## 本地反思分析

如果本地采集数据里包含人工标注字段，例如 `is_match` 或 `is_correct`，可以显式运行反思 agent，分析置信度分数和匹配状态不一致的原因：

```bash
routed-confidence-reflect \
  /path/to/routed_confidence_collection \
  -o /path/to/reflect_output \
  --model qwen3-14b \
  --base-url http://127.0.0.1:8000/v1 \
  --model-timeout 300
```

未安装命令行脚本时，也可以使用模块入口：

```bash
python -m routed_confidence.reflect_agent \
  /path/to/routed_confidence_collection \
  -o /path/to/reflect_output
```

Python 代码中也可以直接调用：

```python
from routed_confidence import reflect_collection

result = reflect_collection(
    "/path/to/routed_confidence_collection",
    "/path/to/reflect_output",
    model="qwen3-14b",
    base_url="http://127.0.0.1:8000/v1",
    model_timeout=300,
)

print(result.mismatch_dashboard_path)
```

反思分析的原则：

- 不改变 SDK 原有评分结果，也不写回 evaluator 配置。
- 不影响 `local_collection_dir` 的本地采集能力。
- 模型只在用户主动运行 `routed-confidence-reflect` 或 `reflect_collection(...)` 时调用。
- 采集数据仍在用户本地；模型地址和 key 由用户配置。
- 如果不想调用模型，可以加 `--no-model`，使用本地规则基线生成报告。

输出目录包含：

```text
/path/to/reflect_output/
  mismatch_root_causes.json
  mismatch_root_causes.html
  dashboard.html
  artifacts/
```

其中 `mismatch_root_causes.html` 展示模型反思出的错误原因、证据、建议修复方向和覆盖情况；`dashboard.html` 展示本地采集数据的分数分布和字段统计。

## 自定义规则和权重

使用 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/
```

## 当前边界

- 只做单条/字段级置信度评估。
- 可选采集评估样本给 SDK/evaluator 开发者分析使用，但默认关闭。
- 不计算检出率。
- 不计算误伤率。
- 不包含 Web/API 服务。
- 不自动生成 Python validator 代码。
- 不要求用户导入内部四维组件。
