PMFlow/docs/superpowers/specs/2026-04-15-internal-query-d...

8.5 KiB
Raw Blame History

Internal Query DSL Plan Design

Goal

为 query.answer 的内部只读查询引入一条受控、可审计、可校验的查询计划链,让大模型只负责“理解问题并产出结构化计划”,数据库与执行器只负责“按白名单模板取证”,最后再由 verifier 检查“回答是否真的对上了用户的问题”。

Why Now

当前链路已经能先判 internal / external / uncertain,但一旦进入内部问答,rag_query_semantics 对问句类型的表达仍然过粗,且执行层缺少“问法合同”和“结果校验”这两道边界。

直接表现就是:

  • “有没有 A 股项目”会被压扁成 count + project
  • 执行层随后直接进入“项目总数”分支
  • 最终返回一个真实但答非所问的数字

这不是单点 existence 漏洞,而是内部查询缺少统一查询计划与回答合同的系统性问题。

Confirmed Baseline

  • 方案 1 是内部查询的第一道必经步骤。
  • route_mode=internal 的 non-plan query.answer 在真正查库前,必须先生成 Query DSL Plan。
  • 大模型禁止自由写 SQL;只能输出受控 DSL。
  • 受控执行器只能命中白名单实体、白名单字段映射、白名单查询模板。
  • 协议短回复、模式控制、执行动作请求不得进入 DSL 规划;必须在 ingress / followup gate 提前拦住。
  • 执行结果必须经过 answer verifier;如果 verifier 发现“问的是 existence,答的是 total count”这类合同漂移,必须显式失败或重试,不得直接出站。

Scope

In Scope

  • query.answer 的内部只读查询路径
  • rag_query_semantics 的问句类型收口
  • Query DSL Plan 结构定义
  • 受控执行器与回答合同
  • verifier 校验与审计字段
  • 与 Query Route Gateway、后续 semantic_facts 读模型的衔接

Out Of Scope

  • plan mode、requirement-plan、draft confirm 主链
  • 外部实时检索链
  • 自由 SQL agent、多轮自反思 text-to-SQL
  • 内部写操作或自动入库

Query Taxonomy Baseline

内部只读查询的 query_type 基线统一为:

query_type 用户真实意图 典型问法 默认回答合同
existence 某对象/语义是否存在 有没有 A 股项目 yes_no_with_evidence
count 数量、总数、人数 现在有多少个项目 count_scalar
list 枚举、有哪些、分别是什么 系统里有哪些项目 entity_list
status 状态、属性、配置值、快照 项目 64 现在什么状态 entity_snapshot
explain 原理、用途、调用链、定义 当前系统架构是什么 explanation_with_citations
diagnose 异常原因、根因、证据链 为什么刚才答错了 diagnosis_with_evidence
compare 差异、对比、谁更适合 现在接的和最新模型差别 comparison_with_basis
unknown 无法可靠归类 低信息量或语义不足 clarify_or_fail

下面这些不属于 query_type,必须在进入 rag_query_semantics 之前处理掉:

  • 协议回复:A/B/C、确认、继续
  • 模式控制:退出需求模式
  • 执行动作:接入外部来源继续核实
  • 草稿/需求收敛动作:再出一版草稿

Query DSL Plan Contract

Query DSL Plan 建议统一为单一结构化对象:

字段 说明
plan_version DSL 版本号,便于平滑演进
query_type 上表中的标准问句类型
entity_type project/task/signal/user/doc/config/run/...
answer_contract 最终回答必须满足的合同
filters[] 结构化过滤条件,支持 field/operator/value/value_source
scope tenant_id/project_id/thread_anchor/referenced_objects 等上下文限定
projection 回答所需字段或摘要目标
sort 列表/比较类排序意图
limit 列表上限
retrieval_policy facts_first / allow_fallback_text / require_fresh_fact 等
verifier_checks[] 出站前必须通过的校验项
clarify_on_empty 命中为空时是澄清还是直接回“未找到”

示例:用户问“帮我看看系统里面有没有 A 股项目。”

{
  "plan_version": "v1",
  "query_type": "existence",
  "entity_type": "project",
  "answer_contract": "yes_no_with_evidence",
  "filters": [
    {
      "field": "market_theme",
      "operator": "equals_or_alias",
      "value": "A股",
      "value_source": "user_text"
    }
  ],
  "scope": {
    "tenant_bound": true
  },
  "projection": ["project_id", "title", "matched_evidence"],
  "retrieval_policy": {
    "facts_first": true,
    "allow_fallback_text": true
  },
  "verifier_checks": [
    "contract_matches_query_type",
    "evidence_backed",
    "no_total_count_substitution"
  ],
  "clarify_on_empty": false
}

Mandatory Execution Flow

route_mode=internal 后的内部问答链路统一为:

  1. Query Route Gateway 决定本轮必须走内部查询。
  2. rag_query_semantics 只产出标准 query_type、entity_type 与 DSL 所需槽位,不再直接决定最终回答。
  3. Query DSL Normalizer 做 schema 校验、枚举收口、上下文补足与黑名单清洗。
  4. Bounded Executor 根据 entity_type + query_type + filters 选择白名单模板执行。
  5. 若 semantic_facts 可用,则先走 facts-first;证据不足时再走受控 fallback 检索。
  6. Answer Verifier 校验“问法合同、证据合同、来源合同”是否一致。
  7. verifier 通过后再进入回答渲染;不通过则显式失败或重试,不允许静默出错。

Bounded Executor Rules

执行器必须遵守以下硬边界:

  • 不接收自由 SQL 字符串
  • 不允许 LLM 决定 join 路径、表名、排序字段白名单之外的内容
  • 只允许已声明的实体模板,如 project existence/count/list/status
  • 所有执行都必须自动绑定 tenant_id
  • facts-first 命中时,回答证据必须能回指到具体 fact 或原始证据对象
  • fallback 文本检索只能在 DSL 明确允许时触发

Answer Verifier Contract

verifier 至少检查:

  • query_type 与 answer_contract 是否一致
  • 回答正文是否覆盖了用户真正问的对象和条件
  • 是否误把 existence / status / compare 问题答成 total count
  • 回答所引用的证据是否真实命中本次执行结果
  • reply_contract 是否与 route_mode=internal 一致

verifier 不通过时,统一返回三类结果之一:

  • retry_with_same_plan
  • retry_with_clarified_plan
  • explicit_insufficient_evidence

Failure Semantics

  • DSL 结构化失败:显式失败,不回退自由回答
  • 执行器无模板支持:显式返回“当前内部查询模板未覆盖”
  • 命中为空但证据不足:按 clarify_on_empty 澄清或返回“当前未确认到”
  • verifier 判定合同漂移:拒绝出站并写审计日志

Rollout

Phase A

先把本设计写入架构基线,不动运行时代码。

Phase B

实现 Query DSL Plan + Bounded Executor + Answer Verifier,先止住“答非所问”的问题。

Phase C

接入 semantic_facts 读模型后,内部查询默认走 facts-first,再做受控 fallback。

计划改动文件清单(基线确认后)

方案 1 运行时主链

  • backend/app/config/ai_prompts.py
  • backend/app/services/adaptive_rag_service/shared_part_02.py
  • backend/app/services/adaptive_rag_service/mixin_core_intent.py
  • backend/app/services/adaptive_rag_service/mixin_query_route_gateway.py
  • backend/app/services/adaptive_rag_service/mixin_answer_mainline.py
  • backend/app/services/adaptive_rag_service/mixin_answer_payload.py
  • backend/app/services/adaptive_rag_service/mixin_deterministic_query_core.py
  • backend/app/services/adaptive_rag_service/mixin_deterministic_query_count.py
  • backend/app/services/adaptive_rag_service/mixin_deterministic_query_list.py
  • backend/app/services/adaptive_rag_service/mixin_fast_answer_project_main.py
  • backend/app/services/adaptive_rag_service/mixin_retrieval_router_db.py
  • backend/app/services/adaptive_rag_service/service.py

方案 1 回归测试

  • backend/tests/test_adaptive_rag_mainline_contract.py
  • backend/tests/test_ai_pmo_ingress_mainline.py
  • backend/tests/test_rag_route_contract.py
  • backend/tests/test_runtime_structured_semantics_contract.py

本轮文档基线

  • AGENTS.md
  • CLAUDE.md
  • docs/architecture/RUNTIME_GUARDRAILS.md
  • docs/architecture/DATAFLOW.md
  • docs/architecture/ARCHITECTURE_INVENTORY.md
  • docs/superpowers/specs/2026-04-15-internal-query-dsl-plan-design.md
  • docs/superpowers/specs/2026-04-15-semantic-facts-read-model-design.md