AuditCtx(src/leaudit/services/audit_ctx.py)是一次评查运行的不可变骨架。@dataclass(frozen=True),构造一次,跨 service 流转;每个 stage 用 with_xxx() 派生新 ctx,旧 ctx 不变。
| 字段 | 类 | 类型 | 说明 |
|---|---|---|---|
document_id | 身份 | str | 这次 run 的 ID |
rules_file | 身份 | RulesFile | None | 评查规则;None 时由分类器决定 |
file_path | 身份 | str | None | 本地文件路径 |
page_range | 身份 | tuple[int,...] | None | 子文档页面范围 |
services | 装配 | AuditServices | 所有 service / client 的容器 |
config | 装配 | AuditConfig | 运行期旋钮 |
normalized_doc | 产物 | NormalizedDocument | None | OCR + 分类 + 分段 |
extraction | 产物 | ExtractionBundle | None | 抽取字段 / 多实体 / 派生 |
phase | 产物 | str | None | draft 或 executed |
evaluation | 产物 | EvaluationResult | None | 每条规则的评查结论 |
fallback_tasks | 产物 | tuple[RescueTask,...] | 失败规则的修救任务 |
extraction_errors | 诊断 | tuple[str,...] | 抽取错误日志 |
timing | 诊断 | Mapping[str,float] | 每阶段耗时 |
frozen=True 防字段重绑;__post_init__ 把 list/dict 强转 tuple / MappingProxyType,防 ctx.timing["x"] = 1 这种穿透改写。from leaudit.services.audit_ctx import AuditCtx
from leaudit.services.audit_services import AuditServices
from leaudit.config.audit_config import AuditConfig
services = AuditServices(
llm_client=llm, vlm_client=vlm, ocr_client=ocr,
normalization=norm_svc, extraction=ext_svc, evaluation=eval_svc,
)
ctx = AuditCtx(
document_id="my_doc",
rules_file=rules,
services=services,
file_path="/path/to/doc.pdf",
config=AuditConfig(group_size=8),
)
ctx = ctx.with_normalized_doc(ocr_result) # Stage 1
ctx = ctx.with_extraction(extraction) # Stage 3
ctx = ctx.with_phase("executed") # Stage 4
ctx = ctx.with_evaluation(evaluation) # Stage 5
ctx = ctx.with_fallback_task(task) # Stage 6(每条失败规则一次)
ctx = ctx.with_timing(ocr=1.2, total=8.5) # 累加耗时
所有 with_xxx() 都是 dataclasses.replace() 的薄包装——返回新对象,旧 ctx 不变。要用 ctx = ctx.with_...() 接住返回值。
ocr_result = ctx.normalized_doc
fields = ctx.extraction.fields
phase = ctx.phase
score = ctx.evaluation.total_score
ocr_secs = ctx.timing.get("ocr", 0.0)
text = ctx.source_text # 派生属性 = ctx.extraction.source_text
| API | 用途 |
|---|---|
ctx.effective_config |
合并 ctx.config + Settings。业务代码统一只读这个,禁止 get_settings() / os.getenv(架构 guard 在 tests/architecture/) |
ctx.as_rescue_inputs() |
转成 engine 旧的 RescueInputs 形状,桥接 engine._try_ai_rescue,不用改 engine |
所有 stage 已经在 AuditService.audit() 里编排好了(src/leaudit/services/audit_service.py:152)。普通用法只要构造 ctx 然后调它:
ctx = AuditCtx(document_id="...", rules_file=rules, services=services,
file_path="...", config=cfg)
ctx = await audit_service.audit(ctx)
# 跑完 ctx 已经被填满 normalized_doc / extraction / phase / evaluation / fallback_tasks / timing
七个 stage 顺序:Normalize → Resolve rules → Extract → Phase 判定 → Evaluate → Rescue → Finalize。
audit_ctx.py 加字段 + 一个 with_xxx helperctx.effective_config,不要直接 get_settings()