# External Query 独立主链升级计划 ## 摘要 把外部查询从通用 AdaptiveRAG 回答链里拆出来,做成一条独立的“外部事实链”:`规划 -> 取证 -> 验证 -> 呈现`。这次升级的目标是让 `route_mode=external` 后只依赖外部证据作答,不再落到 `industry_trend / external_trend` prompt,也不再混入 `project manifest / system snapshot / 内部检索上下文`。 ## 关键改动 ### 1. 外部链路边界固定 - 保留现有 `Query Route Gateway` 作为上游拍板;一旦 `effective_source_policy=external`,后续回答链默认只走外部主链,不再回到通用 scene prompt 选择。 - `ExternalQueryPlanner` 只负责产出结构化 `ExternalQueryPlan`;planner 的 fallback 改成保守模式: - 仅复用上游 `query_semantics` - 不再用硬性词语、对象词表或正则去猜 `query_kind / time_range / location` - 结构化 planner 失败时,默认 `query_kind=generic_web`、`answer_contract=summary_with_sources`、`search_queries=[原问题]` - `ExternalQueryGateway` 只做 provider 选择与证据收集;`verifier` 只判断证据是否足够支撑回答,不再承担语义重判或 internal/external 二次裁决。 ### 2. 能力选路替代固定顺序 - 在 `backend/app/services/external_query_service/` 内把 adapter 能力声明收紧为受控合同: - `provider_type`: `fact_api | live_search | doc_search` - `supported_query_kinds` - `supports_freshness` - `supports_page_fetch` - gateway 排序固定为“能力优先”而不是“注册顺序优先”: - `fact_api` 优先处理天气/汇率/股价等结构化事实 - `live_search` 处理实时网页事实 - `doc_search` 只处理文档/说明类问题 - 当前没有专用天气 API 时,天气类默认优先 `live_search`;MCP 文档型 adapter 不再先占坑。 - MCP 和 live search 都保留“搜索结果 -> 抓目标页正文 -> chunk 打分 -> best snippet”这套正文取证链。 ### 3. 外部证据与呈现彻底分层 - 在 `schemas.py` 新增 `ExternalContextPacket`,作为 external-only 的回答输入,字段固定为: - `question` - `plan` - `adapter_attempts` - `verified_evidence` - `verifier` - `uncertainties` - 新增 `ExternalAnswerPresenter`,替代 `_generate_answer()` 里对 external route 走通用 `_select_scene_prompt()`。 - presenter 只按 `answer_contract` 选 3 类 prompt,不再使用 `industry_trend / external_trend`: - `direct_fact` - `summary_with_sources` - `compare_with_sources` - presenter 默认只喂: - 用户问题 - 外部证据片段 - 来源摘要 - 时间/范围/不确定项 - presenter 明确禁止喂: - `manifest_text` - `project_context` - `system_snapshot` - `user_snapshot` - 内部 retrieval block ### 4. verifier 改成“证据校验器”,不是“语义裁判” - 把当前 `gateway.py` 里的 bundle 校验拆成独立 verifier 组件,职责只保留: - 外部来源合法性 - 目标对象一致性 - 时间范围一致性 - 多来源是否足以支撑回答 - 对象一致性继续走通用归一化和 bundle 评分,但不允许回退到硬编码对象词表、关键词探针或正则模式。 - 证据不足时统一返回 `clarify / insufficient_evidence`,不再误落到“行业趋势回答”这种假阳性路径。 ### 5. 与现有 AdaptiveRAG 的接缝 - `mixin_answer_retrieval.py` 保留 `_execute_external_query_gateway()`,但返回值从“retrieved rows + meta”扩成 `ExternalContextPacket` 所需信息。 - `mixin_deep_guard_answer.py` 在 `effective_source_policy=external` 时直接走 `ExternalAnswerPresenter`,绕过: - `_resolve_answer_scene_semantics()` 对 external 的 `industry_trend/external_trend` 映射 - `_generate_answer()` 里默认注入 manifest 的逻辑 - `Answer Presentation Policy` 保持现有客户可见合同: - 正文前缀仍是 `外部实时查询:` - 来源只显示中文化展示字段,不暴露内部 source label/raw metadata ## 主要接口与类型 - `ExternalQueryPlan` 保留现有字段,语义收紧为“planner 产出的结构化取证计划”,不再依赖正则推断补字段。 - 新增 `ExternalContextPacket` 作为 external presenter 的唯一输入。 - adapter 注册合同新增能力字段,供 gateway 统一排序。 - external presenter 输出仍是最终中文正文,不改上层 API 响应包络。 ## 测试与验收 本期验收不绑定固定问句、固定 provider、固定 prompt 名或固定内部实现路径。 验收只看 `route_mode=external` 后,external-only 主链是否满足行为合同。 ### 验收要求 - 一旦进入 external 主链,最终回答只能基于 external evidence 生成,不能混入 `manifest_text / project_context / system_snapshot / user_snapshot / 内部 retrieval block`。 - external 证据不足时,必须明确返回 `insufficient_evidence` 或 `clarify`,不能假装已经查实。 - 对同一 external 问题的后续追问,只要语义上仍是在继续核实,就必须继续留在 external `query.answer` 主链,不能误跳到 requirement-plan、draft confirm 或内部执行链。 - external source filtering 在过滤后若无合格来源,必须按空来源或证据不足处理,不能把内部来源重新塞回 external answer。 - 当前实现可以按 adapter 能力选择不同 external 取证方式,但验收不把某一种具体 provider 顺序写死为长期真源。 - 运行时必须保留清晰审计信息,至少能看出:planner 如何产出计划、gateway 如何取证、verifier 为何通过或失败、presenter 如何生成最终回答。 ### 覆盖范围 - planner: - 结构化 planner 失败时,不使用正则或硬词表补 `weather/news/company` - fallback 仍能产出可执行 `search_queries` - gateway: - 不同类型的 external 问题都能进入受控 adapter 取证,而不是回退到旧 scene prompt 混答 - external adapter 返回搜索结果后,仍需尽量抓取目标页正文,而不是长期只依赖标题摘要 - verifier: - `湛江市 / 湛江` 这类归一化对象不再误杀 - 时间范围不匹配时明确 `insufficient_evidence` - 证据不足时返回 `clarify`,不生成假结论 - presenter: - external route 不再命中 `industry_trend / external_trend` - prompt 输入中不包含 `[M] 项目画像`、模块规模、知识图谱、system snapshot - 最终回答只基于 external evidence 生成 - 端到端: - 覆盖带时间范围或地点的公开事实问题 - 覆盖一般性的外部事实或动态问题 - 覆盖证据不足后的继续核实 - 覆盖 external 来源被过滤为空的情况 - 覆盖某一种 external 取证方式不可用、需要切换备选方式的情况 - 覆盖需要多个来源交叉支撑的对比问题 ## 假设与默认 - 这期只改“纯 external route”的主链,不在本期实现“外部事实 + 内部能力判断 + plan_mode 动作”的完整混合编排。 - 当前没有专用天气 API 时,实时公开事实默认靠 `live_search + 网页正文抓取` 承担。 - 若后续接入专用事实 API,只需要新增 adapter,不改 planner/verifier/presenter 的边界。 - 文档同步纳入本期:至少更新 `docs/architecture/RUNTIME_GUARDRAILS.md` 与 `docs/architecture/CODE_REFERENCE_INDEX.md`,明确 external-only 上下文和 presenter 边界。