# 为什么仍然需要 Bridge 适配层 ## 1. 结论先行 即使当前项目已经确认: - 后续应使用 `leaudit` 原生 `AuditCtx` - 后续不应继续由平台自己手写主流程编排 - 正式执行入口应收敛到 `AuditService.audit(ctx)` **也仍然需要保留 Bridge / 适配层。** 原因不是因为不用原生 CTX,而恰恰是因为: > **要正确使用原生 CTX,就更应该把它封装在 Bridge 里。** 也就是说,正确架构不是: ```text 平台层 -> 直接调用 leaudit AuditCtx / AuditService ``` 而是: ```text 平台层 -> Bridge 适配层 -> leaudit AuditCtx / AuditService ``` --- ## 2. 误区澄清 一个很容易出现的误区是: - 既然 `leaudit` 已经有原生 `AuditCtx` - 那平台直接调用它就好了 - Bridge 似乎没有必要 这个判断看起来简化了结构,但实际上会把平台和 `leaudit` 深度耦合起来,后续维护成本更高。 **真正应该取消的是:** - 平台自己重写 7 阶段编排 **不应该取消的是:** - 平台和 `leaudit` 之间的正式边界层 所以: - **不要自己编排** - **但要保留适配层** --- ## 3. 适配层到底在适配什么 Bridge 的本质,是把“平台世界”翻译成“引擎世界”,再把“引擎结果”翻译回“平台世界”。 ## 3.1 平台世界 平台里实际关心的是这些对象: - `document_id` - `document_file_id` - `rule_set_id` - `rule_version_id` - `oss_url` - `run_id` - 用户触发信息 - 权限信息 - 数据库记录 - 前端 DTO / VO ## 3.2 引擎世界 `leaudit` 原生执行关心的是这些对象: - `file_path` - `rules_file` - `AuditServices` - `AuditConfig` - `AuditCtx` - `AuditService.audit(ctx)` 这两套概念体系并不相同,因此天然需要一层转换。 --- ## 4. 为什么不能让平台层直接碰 leaudit 原生对象 ## 4.1 会导致架构边界失守 如果 Controller / Service / Model 层直接构造 `AuditCtx`,那就意味着: - 平台业务代码开始直接依赖 `leaudit` - `leaudit` 的内部概念会渗透到整个项目 - 后面任何原生字段调整都会扩散到平台层 这会破坏当前项目一直强调的边界原则: - 平台层不直接感知 `leaudit` 内核细节 - `leaudit_bridge/` 是唯一正式桥接层 --- ## 4.2 会让平台逻辑和引擎逻辑搅在一起 平台侧还必须处理这些事情: - 文档文件从哪里取 - OSS 文件如何下载 - 规则版本从哪里查 - run 如何创建 - run 如何更新状态 - 结果如何写回 `leaudit_*` 表 - 前端如何查询结果 这些都不是 `leaudit` 原生 CTX 的职责。 如果平台层直接碰 `AuditCtx`,这些平台职责和引擎职责就会混在同一个 service 里,结构会越来越乱。 --- ## 4.3 会让未来升级风险更大 如果以后 `leaudit` 升级: - `AuditCtx` 字段变更 - `AuditService` 签名调整 - `AuditServices` 装配方式变化 - `AuditConfig` 配置项增加 那么: - 如果只有 bridge 感知这些对象,改动范围很小 - 如果平台层很多地方直接依赖这些对象,改动会扩散全项目 因此,适配层的价值就在于: > 把 `leaudit` 变化锁死在边界层里。 --- ## 5. Bridge 的正确职责 确认使用原生 CTX 后,Bridge 的职责应该重新定义为: ## 5.1 输入适配 - 根据 `document_id` 找到待执行文档 - 根据 `document_file_id` 找到文件真源 - 如有需要,从 OSS 下载文档到本地临时路径 - 根据 `type_id` / `rule_type_binding` 找到本次评查规则版本 - 从 OSS 下载规则 YAML - 解析出 `RulesFile` ## 5.2 运行装配 - 创建 `AuditServices` - 创建 `AuditConfig` - 创建原生 `AuditCtx` - 调用 `AuditService.audit(ctx)` ## 5.3 输出适配 - 从最终 `ctx` 读取: - `normalized_doc` - `extraction` - `phase` - `evaluation` - `fallback_tasks` - `timing` - 写入: - `leaudit_audit_runs` - `leaudit_rule_results` - `leaudit_field_results` - `leaudit_artifacts` - `leaudit_run_metrics` - `leaudit_run_errors` ## 5.4 边界保护 - 平台 Controller / Service 不直接 import `leaudit.services.*` - 只有 `leaudit_bridge/` 感知原生 `AuditCtx`、`AuditService`、`AuditServices` --- ## 6. 三层结构图 推荐的结构应该是三层,而不是两层: ```text ┌────────────────────────────────────────────┐ │ 平台层 │ │ Controller / Service / Model / API / DB │ │ 文档、规则、权限、任务、结果查询 │ └──────────────────┬─────────────────────────┘ │ ▼ ┌────────────────────────────────────────────┐ │ Bridge 适配层 │ │ file resolve / rules resolve / ctx build │ │ AuditServices / AuditConfig / AuditCtx │ │ persist ctx outputs to leaudit_* │ └──────────────────┬─────────────────────────┘ │ ▼ ┌────────────────────────────────────────────┐ │ leaudit 原生内核层 │ │ AuditCtx / AuditService / Evaluation / │ │ Extraction / Rescue / DSL loader │ └────────────────────────────────────────────┘ ``` 这个结构的关键点是: - 平台层不直接碰 `leaudit` 细节 - `leaudit` 不直接感知平台数据库和 OSS - 所有翻译工作都集中在 Bridge --- ## 7. 为什么这比“平台直接调原生 CTX”更稳 ### 优势 1:边界清晰 - 平台只管业务 - `leaudit` 只管评查 - Bridge 只管适配 ### 优势 2:变化可控 - `leaudit` 升级时改 Bridge - 平台结构基本不动 ### 优势 3:便于替换 将来如果评查引擎变化: - 平台不需要全面改造 - 只需替换适配层实现 ### 优势 4:测试更容易 Bridge 可以单独测试: - 是否正确组装 `AuditCtx` - 是否正确调用 `AuditService.audit(ctx)` - 是否正确写回平台结果表 --- ## 8. 对当前项目的直接要求 既然已经确认: - 必须使用原生 `AuditCtx` - 不能继续自己编排主流程 那么当前项目应该同步修正为: ### 不再推荐的方向 - 在 `fastapi_modules/fastapi_leaudit/leaudit_bridge/pipeline.py` 中继续手写 7 阶段流程 - 在平台侧继续直接串联: - OCR - Extract - Phase - Evaluate - Rescue ### 推荐的方向 - `pipeline.py` 改造成薄包装器 - 新增 `audit_ctx_builder.py` - 新增 `audit_service_factory.py` - 由 bridge 统一: - build ctx - run audit - persist result --- ## 9. 最终结论 确认使用原生 `AuditCtx` 之后,不是 Bridge 就没用了,反而说明: > **Bridge 不该负责重写编排,但必须负责原生编排的接入适配。** 所以最终应该坚持这条原则: - **主流程执行:交给 `leaudit` 原生 `AuditService.audit(ctx)`** - **平台边界控制:交给 `leaudit_bridge/`** 这才是当前项目最稳妥、最可维护的长期方案。