为什么 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.md、local-llm-service.md、rag-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_KEY和CODEX_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_query。MAX_RETRIEVAL_ROUNDS=2 是代码常量:第二轮再次请求 Retrieval 会触发 Policy Rejection,转入 Deterministic Fallback,而不是开始第三轮。
为什么是两轮?第一轮暴露真正缺口,第二轮允许一次有目标的纠偏;再往后,新增召回的边际收益通常下降,Latency、Token、故障面和「为了找到答案而找到相似材料」的风险却持续上升。两轮不是论文给出的最佳常数,而是这个工程系统的明确预算和停止条件。
LLM 的 answer 也没有最终决定权
Controller 返回 answer 后,程序还会检查 Verified Path:
- Path Confidence 必须是
VERIFIED; - Edge 数必须等于 Node 数减一;
- 每条 Edge 必须有 Evidence ID;
- Required Evidence 必须完整加载且
verification=verified; - 只有最高优先级 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/answer 和 run_grounded_system_query 是两个查询入口。它们都使用 Codex 做语义角色并保留 Deterministic Guard,但候选 Profile、Graph Depth、Citation 配置和 Hybrid 开关并不完全相同。
System Shadow 的两轮 Controller 与 DeveloperAnswerV1 最多 10 Citation,是本章讨论的严格合同。External API 的 top_n、code_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.json的llm、model_profiles、retrieval.controller:当前角色和 Timeout;docs/02-runbooks/local-llm-service.md:当前 Codex Primary / Gemma Manual Fallback 边界。
参考资料
- OpenAI Codex Non-interactive Mode;
- OpenAI Codex Configuration Reference;
- OpenAI Codex Security;
- Self-RAG;
- FLARE:Active Retrieval Augmented Generation;
- Corrective Retrieval Augmented Generation。
受控 LLM 的核心不是减少模型能力,而是把模型擅长的语义判断放进一个可观察、可拒绝、有费用和轮数上限的系统里。
相关文章
RAG 不是一条必经流水线,而是一种按需取证的能力
先理解目标、先看当前源码,只有跨来源信息真的能改善判断时,才调用 Local RAG 去找证据候选。
一次代码命中为什么还不算答案
工程检索必须把结果绑到仓库、commit 和 symbol 上;缺失、过期或来自错误仓库的命中,只能当定位线索。