为什么 LLM Controller 最多只允许两轮检索

LLM 可以改写、重排和请求一次补充检索,但不能覆盖确定性证据校验,也不能无限搜索。

本页目录 · 10 节

完全确定性的 Retrieval 很稳定,却不擅长理解「配置标签」和代码里的 LaunchBadge 可能指向同一业务概念;完全 Agentic 的搜索循环更灵活,却可能反复改写 Query、增加调用成本,并在没有新证据时生成越来越自信的故事。

mt_rag 的取舍是让 LLM 负责语义判断,把轮数、动作、证据和输出身份交给确定性程序。

本篇知识地图

stateDiagram-v2
  [*] --> Rewrite
  Rewrite --> RetrieveRound1
  RetrieveRound1 --> Controller
  Controller --> Answer: evidence sufficient
  Controller --> Rerank: candidates sufficient, order weak
  Controller --> RetrieveRound2: one refined query
  Controller --> Insufficient: no defensible evidence
  RetrieveRound2 --> Controller2
  Controller2 --> Answer
  Controller2 --> Rerank
  Controller2 --> Insufficient
  Controller2 --> Insufficient: third retrieval rejected
  Answer --> DeterministicGuard
  Rerank --> DeterministicGuard

核心知识点包括 Role Separation、Bounded Controller、Structured Output Validation、Deterministic Fallback、Least Privilege Bridge 和 Cost Boundary。

模型分工:Codex 不是 Embedding 模型

当前角色分配是:

能力 当前模型/程序
Query Embedding 本地 Qwen3 Embedding 0.6B,1024 维
Rewrite / Source Classification Codex CLI Bridge
Controller Decision Codex CLI Bridge + Deterministic Policy
Candidate Rerank Codex CLI Bridge,或 Deterministic Rerank Fallback
Business Summary / Final Organization Codex CLI Bridge
Verified Chain / Confidence / Citation Whitelist Deterministic Python
Manual Fallback Gemma,仅显式切换,不是默认路径

旧的 retrieval-usage.md 仍有 Gemma Rewrite/Answer 描述,但当前 README.mdlocal-llm-service.mdrag-runtime.json 和代码已经以 Codex 为主。文章以当前代码和 Active Config 为准,不把历史 Runbook 当运行事实。

Bridge 为什么只能是一个受限推理 Worker

Codex Bridge 把 Saved Codex CLI Login 适配成 Loopback OpenAI-compatible Endpoint。默认行为包括:

  • 只监听 127.0.0.1:18089;非 Loopback Host 启动即退出,因为 Bridge 本身没有网络认证;
  • codex exec --ephemeral --sandbox read-only --ignore-user-config
  • Reasoning Effort 固定为 none,保持结构化 Worker 的低延迟行为;
  • 默认并发 1,避免 Rewrite/Rerank 无界扇出;
  • 默认从子进程环境移除 OPENAI_API_KEYCODEX_API_KEY
  • Request Body 上限 1 MiB,Model 名称和 Message Role 都做白名单校验;
  • Prompt 明确禁止读文件、运行命令、使用工具、浏览或修改状态。
flowchart LR
  A["mt_rag role prompt"] --> B["loopback bridge"]
  B --> C["codex exec<br/>ephemeral / read-only"]
  C --> D["JSONL final message"]
  D --> E{"schema + policy validation"}
  E -->|valid| F["bounded decision/text"]
  E -->|invalid| G["deterministic fallback"]

这些参数缩小了 Worker 权限,不代表调用没有资源成本。真实 Codex Completion 可能消耗账户用量,因此健康检查和单元测试只验证 Bridge/Mock;未经明确授权不应为了「试一下效果」批量发 Live Query。

Controller 只有四个动作

System Shadow 的 GroundedQueryController 只接受:

  • answer:当前 Evidence 足够;
  • rerank:候选存在,但顺序或覆盖需要优化;
  • retrieve_again:第一轮生成一个具体 Refined Query;
  • insufficient:当前证据无法支撑回答。

retrieve_again 必须带非空 refined_queryMAX_RETRIEVAL_ROUNDS=2 是代码常量:第二轮再次请求 Retrieval 会触发 Policy Rejection,转入 Deterministic Fallback,而不是开始第三轮。

为什么是两轮?第一轮暴露真正缺口,第二轮允许一次有目标的纠偏;再往后,新增召回的边际收益通常下降,Latency、Token、故障面和「为了找到答案而找到相似材料」的风险却持续上升。两轮不是论文给出的最佳常数,而是这个工程系统的明确预算和停止条件。

LLM 的 answer 也没有最终决定权

Controller 返回 answer 后,程序还会检查 Verified Path:

  1. Path Confidence 必须是 VERIFIED
  2. Edge 数必须等于 Node 数减一;
  3. 每条 Edge 必须有 Evidence ID;
  4. Required Evidence 必须完整加载且 verification=verified
  5. 只有最高优先级 Verified Path 进入 Developer Answer。

LLM 在没有 Verified Path 时请求 answer,会被拒绝并改为 Refined Retrieval、Rerank 或 Insufficient。LLM 不能把 AMBIGUOUS Edge、Jira 背景或相似文本改写成调用事实。

最终组织器不能修改 Canonical Answer

确定性程序先生成 DeveloperAnswerV1:Status、Call Chain、Code、Overall Confidence、Citation、Limitation 和 Summary Facts。Codex 只拿这份 Canonical Answer 做人类可读组织,并必须满足:

  • 第一节是 业务 Summary,第二节是 简约调用链
  • Call Chain 顺序完全不变;
  • Overall Confidence 完全不变;
  • Citation ID 必须来自白名单且 System Shadow 最多 10 条;
  • 有 Chain 时每个 Identifier 必须出现在可见答案中;
  • Insufficient 时明确拒绝,不补参数、返回值或业务规则。

任何一项失败,输出回退到 Deterministic Renderer。流畅度可以降级,证据合同不能降级。

External API 与 System Shadow 的边界

当前外部 /v1/answerrun_grounded_system_query 是两个查询入口。它们都使用 Codex 做语义角色并保留 Deterministic Guard,但候选 Profile、Graph Depth、Citation 配置和 Hybrid 开关并不完全相同。

System Shadow 的两轮 Controller 与 DeveloperAnswerV1 最多 10 Citation,是本章讨论的严格合同。External API 的 top_ncode_deep Profile 和 Answer Review 有自己的上限;不能把某一个合同的数字套到所有入口。Production Cutover 前,两条路径的 Eval 也应分别记录。

失败模式与取舍

失败模式 当前行为 Trade-off
Bridge 不可用/Timeout Deterministic Decision/Answer Fallback 语义适应性下降,但 Query 仍可解释
LLM 返回非法 JSON Parser 尝试提取合法 Object,失败即 Fallback 不用自由文本猜 Action
无 Verified Path 却请求 Answer Policy Reject,补检索/Rerank/Insufficient 可能拒绝一个人类觉得「大概率正确」的答案
第二轮再请求 Retrieval Hard Stop,不进入第三轮 控制费用与延迟,可能漏掉极深问题
LLM 改 Chain/Confidence Output Reject,Deterministic Render 表达不够自然,事实不被模型覆盖
并发 Query 增多 Bridge Semaphore 默认 1,Busy 返回 429 吞吐让位于可控本地资源
API Key 意外继承 默认从 Child Env 移除 需要 API-key-backed 模式时必须显式开启并承担成本 Gate

可复核的项目证据

  • src/mt_rag/service/codex_bridge.py:Loopback、CLI Command、Environment Filter、Concurrency 和 JSONL Parser;
  • src/mt_rag/query/controller.py:四动作状态机、最高 Hit Anchor 和两轮上限;
  • src/mt_rag/query/runtime.py:Codex Decision/Answer、Policy Rejection 和 Deterministic Fallback;
  • src/mt_rag/query/answer.py:Canonical Chain、Confidence、Citation 与 Insufficient;
  • config/rag-runtime.jsonllmmodel_profilesretrieval.controller:当前角色和 Timeout;
  • docs/02-runbooks/local-llm-service.md:当前 Codex Primary / Gemma Manual Fallback 边界。

参考资料

受控 LLM 的核心不是减少模型能力,而是把模型擅长的语义判断放进一个可观察、可拒绝、有费用和轮数上限的系统里。

相关文章

在做类似的事情?

很乐意就分布式系统、交付流程和应用 AI 交换意见。

[email protected]