localGPT Triage 路由系统深度解析:从 Fast-path 启发式到 LLM 仲裁的查询分级决策 📅 发布时间:2026/9/13 17:56:32 👁 浏览次数: localGPT Triage 路由系统深度解析从 Fast-path 启发式到 LLM 仲裁的查询分级决策【免费下载链接】localGPTChat with your documents on your local device using GPT models. No data leaves your device and 100% private.项目地址: https://gitcode.com/GitHub_Trending/lo/localGPT导读本文聚焦 localGPT 项目中负责查询该走哪条路的核心子系统——Triage / Routing System。它的职责是为每一条进入系统的用户查询判断应该走直接 LLM 生成更快、更省还是检索增强生成 RAG需要文档上下文从而在不牺牲回答质量的前提下显著降低延迟与算力消耗。读完本文你将掌握 Triage 系统在backend/server.py与rag_system/agent/loop.py中的完整决策链路、四级路由信号的设计动机、每个环节的 Prompt 与阈值细节以及索引缺失、路由失败等异常场景下的降级策略。Triage 系统的设计目标与定位在 rag_system/DOCUMENTATION.md 中Triage 被列为 Agent 处理查询的第一步先判断查询能否直接回答还是必须从知识库检索。其核心动机是成本与延迟的双重优化直接 LLM 生成不触发任何检索仅调用生成模型响应最快、开销最低适合问候语、常识问答等与文档无关的查询RAG检索增强生成当答案大概率依赖用户上传的私有文档时走完整的检索管线混合检索、重排、验证等保证回答有据可依。从源码结构看Triage 并非单一函数而是分布在两个层级的一组协作机制后端快速通道backend/server.py 中的_should_use_rag()、_route_using_overviews()与_simple_pattern_routing()在进入重量级 Agent 代码之前先做一次低成本预判Agent 内部重评估rag_system/agent/loop.py 中的_triage_query_async()与_route_via_overviews()利用更丰富的特征对话历史、token 量、查询类型做二次裁决。四级决策信号Triage 系统并非依赖单一规则而是由下表中的四类信号逐级组合、层层过滤信号来源说明关键词 / 正则检查backend/server.py 快速通道硬编码的快捷命中what time、define等问候/闲聊模式索引是否存在SQLite会话 → 索引关联若会话未关联任何索引直接走 LLM 生成文档概览路由_route_using_overviews()利用文档概览 增强模型预测查询与文档的相关性LLM 路由 Promptagent/loop.py最终仲裁者Ollama 调用JSON 输出这四级信号的执行顺序遵循越便宜的先判断越贵的最后裁决原则正则检查零成本索引检查是本地 SQLite 查询概览路由仅调用小模型而完整 LLM 路由 Prompt 作为兜底仲裁。高层决策流程流程的核心思想是逐步收紧会话没有索引则必然走直接 LLM索引存在但命中快速正则问候、闲聊也走直接 LLM只有携带文档概览且相关性评估高于阈值 τ 的查询才值得调用 LLM 路由做最终裁决。每一步向下传递都意味着更高的计算成本也意味着更高的决策置信度。代码级详细执行序列第一步backend/server.py 快速通道handle_session_chat()backend/server.py是 HTTP 层的入口。它先读取会话关联的索引列表再检查请求中是否携带force_rag标志idx_ids db.get_indexes_for_session(session_id) force_rag bool(data.get(force_rag, False)) use_rag True if force_rag else self._should_use_rag(message, idx_ids)force_rag true时绕过 Triage 强制走 RAG这个字段在 Documentation/api_reference.md 的 API 参考中被标注为可选——绕过 triage强制 RAG否则调用_should_use_rag()backend/server.py做第一轮预判无索引直接返回 Falseif not idx_ids: return False这是成本最低的剪枝加载文档概览_load_document_overviews(idx_ids)尝试按索引读取概览文件聚合成功后交给_route_using_overviews()做智能路由加载失败则降级任何异常都会回退到_simple_pattern_routing()的纯模式匹配。概览文件加载策略_load_document_overviews()backend/server.py实现了三级查找优先按索引读取对每个索引依次尝试../index_store/overviews/{idx}.jsonl、index_store/overviews/{idx}.jsonl、./index_store/overviews/{idx}.jsonl三个候选路径找到第一个存在的即停止回退到全局旧文件若按索引文件一个都没找到回退到index_store/overviews/overviews.jsonl对应 rag_system/agent/loop.py 中 Agent 初始化时加载的_global_overview_path性能上限聚合后的概览列表被截断为前 40 条aggregated[:40]避免超长 Prompt 拖慢路由。每条 JSONL 记录通过record.get(overview, )提取概览文本格式由 rag_system/indexing/overview_builder.py 在索引阶段生成——该 Builder 负责把文档前 N 个 chunk 摘要成概览并写入index_store/overviews/目录。这也印证了 Documentation/indexing_pipeline.md 的描述First-N chunks summarised for triage routing且在 rag_system/pipelines/indexing_pipeline.py 中明确注释Overview builder always enabled for triage routing——概览生成是 Triage 的前置依赖默认始终开启。概览路由 Prompt第一层 LLM 判断_route_using_overviews()backend/server.py将概览拼装进 Prompt调用qwen3:0.6b小模型做快速判断enable_thinkingFalse关闭思考链以提速。该 Prompt 的核心规则如下强偏好 RAG当知识库存在文档时除非查询纯属闲聊或与文档内容完全无关否则一律倾向USE_RAG明确的触发词查询涉及实体公司、数字、地址、日期、金额、技术术语或文档操作类动词summarize / analyze / explain / extract / find→USE_RAG明确的豁免纯问候Hi、Hello、Thanks与纯数学/世界常识What is 22?→DIRECT_LLM兜底原则When in doubt → USE_RAG即不确定时宁可多检索也不漏检索。响应解析同样是容错的响应文本大写化后包含USE_RAG即返回 True包含DIRECT_LLM返回 False解析不明确时默认走 RAG若 LLM 调用抛异常则降级到_simple_pattern_routing()纯模式匹配。纯模式匹配兜底零 LLM 成本_simple_pattern_routing()backend/server.py是概览不可用时的最后一层保障由三组启发式构成问候/闲聊黑名单hello、hi、hey、thanks、test、ping、ok等 20 余个模式命中即直接 LLMRAG 强指示词document、pdf、according to、based on、summarize、analyze、quote、extract等命中即走 RAG长度 疑问词启发以what/how/when/where/why/who/which开头且消息长度 40 字符 → RAG消息 20 字符 → 直接 LLM其余默认直接 LLM。第二步Agent 内的 Triage 重评估当请求被判定需要 RAG 后会通过http://localhost:8001/chat转发给 RAG APIbackend/server.py最终进入 rag_system/agent/loop.py 的_run_async()。此时_triage_query_async()rag_system/agent/loop.py会利用 Agent 侧更丰富的上下文做二次裁决其优先级是概览快速路由先调用_route_via_overviews(query)对话历史启发若存在历史history非空说明当前查询大概率是追问直接默认rag_query——源码注释明确说明如果有历史查询很可能是后续追问因此默认走 RAG更高级的实现可以用 LLM 判断新查询是否完全切换了话题LLM 兜底分类无历史时调用生成模型Prompt 要求从三个类别中选一输出 JSON{category: choice}rag_query——关于用户上传文档内容的查询direct_answer——常识问答、问候、与文档无关的查询graph_query——知识图谱的事实关系查询当前使用有限。值得注意的是Agent 侧_route_via_overviews()rag_system/agent/loop.py与后端_route_using_overviews()是两套并存的实现前者读取 Agent 初始化时加载的内存self.doc_overviews同样截取前 40 条使用主生成模型并强制formatjson输出后者使用专用小模型qwen3:0.6b且不要求 JSON。两者共享相同的设计理念——用概览让路由决策见过文档内容而不仅仅是依赖静态关键词。第三步LLM 路由最终仲裁当概览路由无法给出明确结论返回 None且存在历史时agent/loop.py 中的路由 Prompt 作为最终仲裁出场Task: Route query to correct system. Documents available: Invoices, DeepSeek-V3 research papers Query: {query} Is this query asking about: A) Greetings/social: Hi, Hello, Thanks, Whats up, How are you B) General knowledge: CEO of Tesla, capital of France, what is 22 C) Document content: invoice amounts, DeepSeek-V3 details, companies mentioned If A or B → {category: direct_answer} If C → {category: rag_query}响应被强制为 JSON 格式formatjson解析后取category字段JSON 解析失败时同样默认rag_query保证宁可多检索、不漏检索的保守策略贯穿始终。接口与依赖关系组件调用 / 数据SQLitechat_sessions读取indexes列获取会话关联的索引 IDbackend/server.pyLanceDB / 概览文件读取index_store/overviews/idx.jsonl按索引与overviews.jsonl全局回退OllamaClient生成 LLM 路由决策后端用小模型qwen3:0.6bAgent 侧用主生成模型概览数据的生命周期是索引阶段由OverviewBuilder写入 → 后端/Agent 启动或查询时加载进内存 → 路由阶段拼装进 Prompt。此外 rag_system/utils/ollama_client.py 的注释提到会并发执行 triage、verification 等 LLM 调用说明路由决策可与其他 LLM 任务并行进一步摊薄延迟。配置开关与阈值配置项类型默认值作用PIPELINE_CONFIGS.triage.enabled全局开关—Triage 系统的总开关环境变量TRIAGE_OVERVIEW_THRESHOLD环境变量0.35概览相关性分数的最低阈值超过才偏向 RAG其中PIPELINE_CONFIGS定义于 rag_system/main.py包含default生产级混合检索 AI 重排 验证与fast速度优先纯向量检索、关闭重排/验证/查询分解两套完整管线配置是 Triage 决策之后实际执行检索时的参数来源。threshold 类参数的意义在于控制漏检与误检的平衡——阈值越低越倾向走 RAG检索开销越大但漏答风险越小。关于阈值与路由的调优方向Documentation/improvement_plan.md 还提出了Session-level routing memo会话级路由备忘录的改进计划即对追问类查询缓存路由结论避免对每条追问都重复做 LLM triage——这从侧面说明当前实现里有历史默认走 RAG是一个刻意简化的启发式。失败与降级模式Triage 系统对每一层失败都设计了显式的降级路径这是其生产可用性的关键概览文件缺失_load_document_overviews()找不到任何概览文件 → 打印警告并返回空列表 →_should_use_rag()落入_simple_pattern_routing()纯模式匹配概览加载异常读取过程中抛异常 →try/except捕获后同样降级到模式匹配LLM 路由出错_route_using_overviews()中 Ollama 调用抛异常 → 降级模式匹配_route_via_overviews()中 JSON 解析失败 →默认rag_query并记录警告解析不明确模型返回了无法识别的单词/类别 → 默认走 RAG更安全同时打印⚠️ Unclear routing decision ... defaulting to RAGRAG API 不可达_handle_rag_query()中连接localhost:8001失败 → 返回明确的错误提示Could not connect to the RAG API server并剥离响应中可能残留的think标签。可以看出整套系统的降级方向高度一致任何不确定都朝 RAG 倾斜。这在本地私有化部署场景中是合理的取舍——检索多花一点时间但不会因为漏检索而给出脱离文档的答案符合项目100% 私密、数据不出设备的定位。调试与观测源码中保留了完整的路由决策日志全部以ROUTING DEBUG为前缀方便在生产环境追踪每次查询的决策路径 ROUTING DEBUG: Starting triage for query: ...——triage 开始✅ ROUTING DEBUG: Overview routing decided: rag_query——概览路由命中 ROUTING DEBUG: History exists, defaulting to rag_query——历史启发生效 ROUTING DEBUG: Final triage decision: rag_query——最终结论❌ ROUTING DEBUG: Overview routing JSON parsing failed, defaulting to rag_query——降级触发。后端侧则以 Overview-based routing: USE_RAG for query: ...、⚡ Overview-based routing: DIRECT_LLM for query: ...、⚠️ No overviews found for indices ...等日志标识路由结果。排查为什么我的问题没走 RAG或为什么闲聊也触发了检索时直接检索这些日志即可快速定位是哪一层信号做了裁决。小结localGPT 的 Triage 系统是一套四级递进、成本递增、失败必降级的查询路由方案索引检查完成最粗粒度的剪枝正则/模式匹配兜住零成本的快捷命中概览路由用文档摘要让小模型先睹为快最后 LLM 路由 Prompt 以 JSON 格式做保守仲裁。它同时存在于后端快速通道与 Agent 深度评估两层并以不确定即走 RAG的统一策略保证回答质量。对想要在本地私有化 RAG 系统中平衡响应速度与答案质量的开发者而言这套架构提供了一个完整、可直接借鉴的分级路由模板——从决策信号设计、Prompt 措辞到降级路径均可在 Documentation/triage_system.md 与上述源码文件中一一对照验证。【免费下载链接】localGPTChat with your documents on your local device using GPT models. No data leaves your device and 100% private.项目地址: https://gitcode.com/GitHub_Trending/lo/localGPT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考