第二篇:不碰模型,意图识别快 9 倍 —— P0→P1→P2 流水线设计

优化的最高境界不是换更强的模型,而是让该做的事情不需要模型来做。

延迟账单:477ms 到底花在哪了?

全量 LLM function calling:每次把所有 tool schema(5 个工具 × ~150 字描述)传给 Qwen,LLM 读完所有描述再抉择。我们用 qwen-turbo 实测了 500 次(50 条 query × 10 repeats):p50=477ms、p95=672ms、p99=1200ms。延迟分解:input token 编码(~730 tokens) + LLM 推理 + output token 解码(~24 tokens)≈ 477ms p50。

为什么准确率 92% 还不够? 因为按意图拆开,query-order 只有 80%------"我的订单到哪了"被系统性地误判为 check-shipping("到哪了"→语义上天然偏向物流)。一个错误的路由不只是延迟,是后续整个对话链路的崩塌------用户会收到错误的查询结果,然后反复纠错。qwen-max 可能更准,但会更慢(参数量翻倍),且同样存在"语义相近"的混淆问题。92% 准确率值不值 477ms?答案是不值------因为后面我们会看到,P0+P1 已经在 25ms 内达到了更高的命中率。

每天 1 万次请求,仅意图识别就花掉约 1.33 小时(477ms × 10000),年成本约 ¥2,400(qwen-turbo)。

注意 :这个 477ms 只是"意图识别→工具选择"这道工序的延迟。后面 RAG 流水线中 LLM 生成最终答案的延迟是 ~9.1s(qwen3.6-plus 最新实测),完全不同量级。这里优化的对象仅限意图识别------别搞混了。

目标是 50ms,但不想换模型、不想加 GPU、不想降准确率。


分层拦截的设计逻辑

核心思路:大部分请求在到达 LLM 之前就应该完成意图识别。不是"每一步都快",而是"只让必要的步骤发生"。

P0 规则过滤 ~5ms

用户输入包含明确关键词。"我想退掉昨天买的洗衣机"→ 关键词"退"直接识别为退款意图,映射到 request-return 工具。关键设计:关键词不是人工维护的,从 Skill YAML 的 trigger_keywords 字段自动抽取 + TF-IDF Top-3。关键词覆盖 53%,但触发后准确率仅 81%------53 条命中里 10 条判错。有效解决率 43%。剩下(如"我的东西到哪了"这种不含明确关键词的)不能指望关键词。

P1 FAISS 语义重排 ~20ms

当关键词失效时,用语义来补。整句 BGE-small-zh-v1.5 embedding + HNSW 索引,但三个工程细节让精度大幅提升:

  • 指令前缀(instruction-aware encoding):零延迟增加,精度提升 5-10%
  • 意图描述内建反向锚点:在退款意图描述末尾写"区分:纯物流咨询请走 shipping 通道",互为对比的描述在向量空间中相互推开
  • 意图词加权:关键词匹配结果 ×1.5 给语义匹配注入方向偏好

指令前缀怎么用? BGE-small-zh-v1.5 官方明确给出了指令:为这个句子生成表示以用于检索相关文章:。标准用法:文档入库时不加 前缀,查询时前缀------模型训练时就是这样对齐的。如果查询不加前缀,或者文档误加了前缀,向量空间错位,召回会烂掉。我们的实际选择:考虑到全链路有多个 embedding 消费方(P1 意图匹配 + RAG 文档检索 + 语义缓存),统一不加指令前缀,牺牲约 5-10% 精度换零运维心智负担。

结果:P0+P1 Top-2 命中率达到 85% ,Top-1 达到 75%。P1 把 P0 未覆盖的 57% 中的绝大多数兜了回来------从 43% 到 85%,增量贡献 +42%。仅剩 15% 的极端歧义 case 需要 P2 介入。

P2 本地小模型确认 ~157ms

从 P1 Top-3 意图候选里最终确认一个。不在云端跑------p99 延迟抖动(500ms+)不可接受。

本地模型明确说明 :P2 意图确认运行 Qwen2.5-1.5B-Instruct ,部署在 RTX 4070 ,p50 推理延迟 94ms(benchmark 实测),显存占用 2.88GB。为什么选 1.5B 而非 1.7B 或 3B?Qwen2.5-1.5B 在简化后的二选一确认任务上达到 92% Top-1 / 94ms p50------精度-速度-显存的甜点。完整 4 模型 × 2 设备全量对比见第六篇

所有 benchmark 均在 **RTX 4070 GPU(8GB 显存)**实测完成。2.88GB 显存门槛意味着任何主流独显都能跑。关键不是 GPU 算力------是 P0+P1 已经把 5-10 个意图筛选为 Top-2 候选,P2 只做二选一确认,问题复杂度降了一个数量级。

P2 之后的工具选择:一张映射表 ~0ms

意图一旦确认,工具选择就是 O(1) 查表。不需要 LLM,不需要 embedding。这是工具选择只需二层(P0+P1)的根本原因------它依赖的是意图识别的输出,不是独立的复杂决策。

P2 交叉校验逻辑:当 P2 的 Top-1 与 P1 的 Top-1 不一致时,同时纳入 Top-2,给后续执行器 agent 更多选择空间。

最终:P0+P1+P2 → ~99% 意图识别命中率(P1 Top-2 85% + P2 对剩余 15% 的兜底确认)。p50 延迟仅 ~25ms------85% 的请求在 P0 或 P1 阶段即命中,无需走到 P2(P0+P1 本身约 25ms,P2 的 ~157ms 仅在 p85+ 尾部触发,不影响 p50 统计量);p95 约 ~182ms(含 P2 完整路径)。


为什么是 P0→P1→P2 这个顺序?

设计逻辑:零成本先跑(P0,解决 43%)→ 语义补缺(P1,Top-2 到 85%)→ LLM 兜底(P2,仅 15% 触发,仅做候选确认)。这才是真正的"经济性设计"。


总延迟对比

方案 p50 p95 p99 年成本*
纯 LLM function calling (qwen-turbo) 477ms 672ms 1200ms ~¥2,400
纯 LLM function calling (qwen-max 估) ~700ms ~900ms ~1500ms ~¥21,000
P0+P1+P2(本项目,共享 GPU) ~25ms ~182ms ~312ms ~¥2,500

*按 qwen-turbo 实测 token 消耗 ~730 input + ~24 output 计算(500 次请求的平均值)。P0+P1+P2 方案中 P2 本地环节运行 Qwen2.5-1.5B-Instruct on GPU,详见下文 benchmark 数据。qwen-max 行标注为"估"------未实测。完整成本拆解见第十一篇。


意图识别 P0→P1→P2 三级流水线 + 工具选择一层映射
#mermaid-svg-2K0iu8zXvM79u50i{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2K0iu8zXvM79u50i .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2K0iu8zXvM79u50i .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2K0iu8zXvM79u50i .error-icon{fill:#552222;}#mermaid-svg-2K0iu8zXvM79u50i .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2K0iu8zXvM79u50i .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2K0iu8zXvM79u50i .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2K0iu8zXvM79u50i .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2K0iu8zXvM79u50i .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2K0iu8zXvM79u50i .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2K0iu8zXvM79u50i .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2K0iu8zXvM79u50i .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2K0iu8zXvM79u50i .marker.cross{stroke:#333333;}#mermaid-svg-2K0iu8zXvM79u50i svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2K0iu8zXvM79u50i p{margin:0;}#mermaid-svg-2K0iu8zXvM79u50i .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2K0iu8zXvM79u50i .cluster-label text{fill:#333;}#mermaid-svg-2K0iu8zXvM79u50i .cluster-label span{color:#333;}#mermaid-svg-2K0iu8zXvM79u50i .cluster-label span p{background-color:transparent;}#mermaid-svg-2K0iu8zXvM79u50i .label text,#mermaid-svg-2K0iu8zXvM79u50i span{fill:#333;color:#333;}#mermaid-svg-2K0iu8zXvM79u50i .node rect,#mermaid-svg-2K0iu8zXvM79u50i .node circle,#mermaid-svg-2K0iu8zXvM79u50i .node ellipse,#mermaid-svg-2K0iu8zXvM79u50i .node polygon,#mermaid-svg-2K0iu8zXvM79u50i .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2K0iu8zXvM79u50i .rough-node .label text,#mermaid-svg-2K0iu8zXvM79u50i .node .label text,#mermaid-svg-2K0iu8zXvM79u50i .image-shape .label,#mermaid-svg-2K0iu8zXvM79u50i .icon-shape .label{text-anchor:middle;}#mermaid-svg-2K0iu8zXvM79u50i .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2K0iu8zXvM79u50i .rough-node .label,#mermaid-svg-2K0iu8zXvM79u50i .node .label,#mermaid-svg-2K0iu8zXvM79u50i .image-shape .label,#mermaid-svg-2K0iu8zXvM79u50i .icon-shape .label{text-align:center;}#mermaid-svg-2K0iu8zXvM79u50i .node.clickable{cursor:pointer;}#mermaid-svg-2K0iu8zXvM79u50i .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2K0iu8zXvM79u50i .arrowheadPath{fill:#333333;}#mermaid-svg-2K0iu8zXvM79u50i .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2K0iu8zXvM79u50i .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2K0iu8zXvM79u50i .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2K0iu8zXvM79u50i .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2K0iu8zXvM79u50i .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2K0iu8zXvM79u50i .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2K0iu8zXvM79u50i .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2K0iu8zXvM79u50i .cluster text{fill:#333;}#mermaid-svg-2K0iu8zXvM79u50i .cluster span{color:#333;}#mermaid-svg-2K0iu8zXvM79u50i div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2K0iu8zXvM79u50i .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2K0iu8zXvM79u50i rect.text{fill:none;stroke-width:0;}#mermaid-svg-2K0iu8zXvM79u50i .icon-shape,#mermaid-svg-2K0iu8zXvM79u50i .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2K0iu8zXvM79u50i .icon-shape p,#mermaid-svg-2K0iu8zXvM79u50i .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2K0iu8zXvM79u50i .icon-shape .label rect,#mermaid-svg-2K0iu8zXvM79u50i .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2K0iu8zXvM79u50i .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2K0iu8zXvM79u50i .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2K0iu8zXvM79u50i :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} P2 本地小模型确认 ~157ms
P1 FAISS 语义匹配 ~20ms
P0 规则过滤 ~5ms
命中
未命中 57%

'我的东西到哪了'
命中
剩余 15% 模糊
用户输入

'我想退掉昨天买的洗衣机'
关键词匹配

trigger_keywords

来自 Skill YAML
✅ 命中 43%

意图=退款
BGE-small Embedding

  • HNSW 检索

  • 意图词加权 ×1.5
    ✅ 累计命中 85%

Top-2 意图候选
Qwen2.5-1.5B-Instruct

RTX 4070

交叉校验 P1 Top-1

不一致时纳入 Top-2
✅ 累计命中 ~99%
意图→工具映射 ~0ms

退款 → request-return
路由到执行器

三方案延迟对比
#mermaid-svg-XK1psU5tDyi903WL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XK1psU5tDyi903WL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XK1psU5tDyi903WL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XK1psU5tDyi903WL .error-icon{fill:#552222;}#mermaid-svg-XK1psU5tDyi903WL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XK1psU5tDyi903WL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XK1psU5tDyi903WL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XK1psU5tDyi903WL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XK1psU5tDyi903WL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XK1psU5tDyi903WL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XK1psU5tDyi903WL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XK1psU5tDyi903WL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XK1psU5tDyi903WL .marker.cross{stroke:#333333;}#mermaid-svg-XK1psU5tDyi903WL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XK1psU5tDyi903WL p{margin:0;}#mermaid-svg-XK1psU5tDyi903WL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 意图识别延迟对比 (p50 / p95) 纯 LLM function callingP0 + P2P0 + P1 + P2 (本项目) 10009008007006005004003002001000 延迟 (ms)


这套方法论不止适用于意图识别:RAG 流水线审计

在进入 RAG 优化之前,用同一套"砍 LLM"的眼光审视一下 RAG 流水线。RAG 的延迟里,有多少是检索造成的,有多少是不必要的 LLM 调用?

我们把 4-Step RAG 流水线逐步骤审计了一遍:

步骤 是否需要 LLM? 审计结论
Step 1 问题改写 大部分 query 不需要改写,可用 Embedding 替代
Step 2 安全检查 部分 本地小模型优先,云端仅兜底
Step 3 检索+精排 零 LLM,纯工程手段(具体优化见第三篇)
Step 4 答案生成 唯一无法替代的 LLM 调用

RAG 流水线的延迟大头不是检索,而是那些可以砍掉的 LLM 调用。 真正不可替代的只有 Step 4 的答案生成(~9.1s),而 Step 1 的问题改写每一次都在调云端 LLM------对于"洗衣机有什么功能"这种完全不需要改写的问题,纯属浪费。

审计告诉我们哪些步骤不需要 LLM ;下一篇我们聚焦唯一需要 LLM 的那一步------它的输入质量如何确保。也就是 Step 3 检索优化:混合检索、图增强、以及藏在它们背后的一堆工程细节。

相关推荐
happyprince1 小时前
07_verl-Trainer模块详解
人工智能·架构·wpf·强化学习
花骨朵轻创1 小时前
基于WeChatBot框架 API 封装的 Python SDK,提供简洁易用的接口调用方式
人工智能
deepdata_cn1 小时前
面向AI Agent标准化工作环境构建的驾驭工程(Harness Engineering)
人工智能·harness engine
沪漂阿龙1 小时前
Embedding:文本怎么变成向量?语义检索为什么能工作?
人工智能·python·embedding
me8321 小时前
【AI面试】大模型面试60问(面试速记+详解)
人工智能·学习·ai
星辰_mya1 小时前
autowired和resource区别
java·后端·spring·架构·原理
来自于狂人1 小时前
第5章 记忆管理——让Agent记住事情
人工智能·算法·语言模型·自然语言处理
生信碱移1 小时前
Vscode 连接 ipynb 选择内核无法自动显示 conda 环境对应的 python
服务器·人工智能·经验分享·vscode·python
lazy_ma1 小时前
大模型实操-Spring Boot集成LangChain4j
人工智能·后端