Commit f5da42e6183981b750601214ee0fc351682079ae

Authored by tangwang
1 parent ccbdf870

标注提示词优化

docs/issues/issue-2026-04-03-reranker特征工程&FM拟合.md 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +
  2 +加非线性映射:
  3 +参考 @docs/LTR-特征非线性映射.md
  4 +
docs/issues/issue-2026-04-03-按指定字段排序-TODO.md 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +现在,如果前端指定按某个字段排序,以价格为例,那么ES搜索条件会加上
  2 + "sort": [
  3 + {
  4 + "min_price": {
  5 + "order": "asc"
  6 + }
  7 + }
  8 + ],
  9 +但是,存在以下问题:
  10 +1. 存在多重漏斗,粗排&重排,这里又把顺序搞乱了。
  11 +2. 如果前端有指定排序、不走后面漏斗的话,那么,因为有knn召回,文本匹配也为了扩大召回有很多不相关召回(只有部分term匹配的),这些差结果因为强制按价格排序,不相关结果被排到了上面。
  12 +3. 如果还是走重排,那么最后要加一轮截取topN再按价格排序,但是topN阈值不好定。
  13 +
  14 +我的思路是:
  15 +1. ES阶段,因为有宽泛召回,不加min_price排序
  16 +2. 按价格排序的方案:在重排(final rank阶段),加一个“按指定字段排序”的处理流程。假设重排输出条数为K,那么看2/K~K之间是否有抖降点,从中选择一个合适的点进行重排。
0 \ No newline at end of file 17 \ No newline at end of file
docs/issues/issue-2026-04-04-LLM推理用于query分析定制优化-TODO.md 0 → 100644
@@ -0,0 +1,578 @@ @@ -0,0 +1,578 @@
  1 +基于LLM的AI应用,通常尽量让前缀相同,这样可以利于跨session的KVcache(而不是常规的单次会内内部的kvcache)。
  2 +这个已经有一些成熟的手段支持。
  3 +但如果要进一步做极致的优化,用于搜索引擎的query分析,对耗时要求极高,有哪些优化的方向?耗时主要体现在哪?,希望连 KV cache的加载也省去了,能再节省多少时间? Analyze the category intent of the given query. Output exactly one label from: Dress, Jeans, Shirt, Trench Coat, Skirt, T-shirt, Hoodie, Knitwear, Other. Output nothing else query:{query} 比如这个提示词是做一个query分类,前缀相同,最后的 query 不同,并且 decoder 只 decoder 一个 token,其实这个输出也不用 decode 整个词表,而是对总统的N分类算打分(不要概率)即可,这也是一个极致的优化点,除了这些,我更希望找到,如何做定制化的GPU编程,来极致的提高性能。 请搜索相关的技术资料,特别是以LLM inference方面的,深度定制化的
  4 +
  5 +
  6 +# 一、chatgpt
  7 +
  8 +我查了一圈最新的 LLM inference 资料后,先给一个直接结论:
  9 +
  10 +**对你这个场景,继续在“通用生成引擎 + prefix KV cache”上抠,收益很快会见顶。真正的大头不是 decode,而是 query 部分的 prefill、attention 访存、kernel launch、以及最后一步不必要的 vocab head。**
  11 +更激进一点说:这已经不像“生成任务”,而更像**超短文本分类任务伪装成生成**。如果目标是搜索引擎里的 query analysis、极低时延,那最值得做的是把它改造成**专用推理路径**,甚至专用 GPU kernel。([NVIDIA GitHub][1])
  12 +
  13 +---
  14 +
  15 +## 1)你这个场景里,耗时主要在哪
  16 +
  17 +你给的 prompt:
  18 +
  19 +```text
  20 +Analyze the category intent of the given query. Output exactly one label from: Dress, Jeans, Shirt, Trench Coat, Skirt, T-shirt, Hoodie, Knitwear, Other. Output nothing else
  21 +query:{query}
  22 +```
  23 +
  24 +它的特征是:
  25 +
  26 +* 前缀几乎固定
  27 +* `{query}` 很短
  28 +* 最终只需要 1 个类别
  29 +* decoder 实际只需要 1 step,甚至不该走完整 decode
  30 +
  31 +所以时延通常拆成这几块:
  32 +
  33 +### A. 请求侧固定开销
  34 +
  35 +包括 tokenizer、请求路由、RPC/HTTP、张量准备、H2D、小量 CPU 调度。
  36 +在“只出 1 个 token”的场景里,这些固定开销会变得很显眼;TensorRT-LLM 甚至专门做了 **Overlap Scheduler** 来把 CPU 工作和 GPU 计算重叠,说明这部分在低时延场景里确实值得抠。([NVIDIA GitHub][2])
  37 +
  38 +### B. suffix/query 的 prefill
  39 +
  40 +即使 prefix 命中 KV cache,**query token 仍然要完整过所有层**。
  41 +这是你现在的主要计算开销之一。
  42 +
  43 +### C. attention 对 prefix KV 的读取
  44 +
  45 +这是很多人容易忽略的一点:
  46 +
  47 +**prefix 复用只省掉了“prefix 自己重新计算 K/V”这部分。**
  48 +但 query 的每个 token 仍然要对已有上下文做 attention,也就是仍然要访问 prefix 的 K/V。
  49 +所以 prefix 越长,query prefill 的 attention 成本仍然越高。FlashAttention/FlashInfer 这类工作一直强调 attention 是 LLM inference 的核心瓶颈,FlashAttention-3 在 H100 上就是围绕 attention 的访存与流水做了深度优化。([arXiv][3])
  50 +
  51 +### D. 最后一层输出头(lm_head)+ softmax / sampling
  52 +
  53 +对你这种只需要 9 类标签的任务,走完整 vocab head 很浪费。
  54 +TensorRT-LLM 提供了自定义 logits processor,但那还是在**完整 logits 出来之后再处理**;对你而言,更极致的做法应该是**根本不算全词表 logits**。([NVIDIA GitHub][4])
  55 +
  56 +---
  57 +
  58 +## 2)prefix KV cache 还能省多少?“连加载都省掉”值不值
  59 +
  60 +这里要分情况。
  61 +
  62 +### 情况 1:KV cache 已经常驻 GPU HBM
  63 +
  64 +这时“加载 KV cache”本身,通常**不是最大头**。
  65 +
  66 +KV cache 每 token 大小可以近似写成:
  67 +
  68 +[
  69 +\text{bytes/token} \approx 2 \times L \times H_{kv} \times D \times \text{bytes_per_elem}
  70 +]
  71 +
  72 +其中:
  73 +
  74 +* (2) 表示 K 和 V
  75 +* (L) 是层数
  76 +* (H_{kv}) 是 KV heads
  77 +* (D) 是 head dim
  78 +
  79 +例如一个典型 GQA 模型,假设:
  80 +
  81 +* 32 层
  82 +* 8 个 KV heads
  83 +* head dim = 128
  84 +* BF16(2 bytes)
  85 +
  86 +则每 token 的 KV 大约是:
  87 +
  88 +[
  89 +2 \times 32 \times 8 \times 128 \times 2 = 131072 \text{ bytes} \approx 128 \text{KB/token}
  90 +]
  91 +
  92 +那么:
  93 +
  94 +* 200 token prefix ≈ 25 MB
  95 +* 1000 token prefix ≈ 125 MB
  96 +
  97 +H100 官方给出的 HBM 带宽是 **3 TB/s**。按理想顺序读估算:
  98 +
  99 +* 25 MB / 3 TB/s ≈ **8 微秒**
  100 +* 125 MB / 3 TB/s ≈ **42 微秒**
  101 +
  102 +实际不会这么理想,因为还有 page table、访存不连续、kernel 组织、调度开销,但结论还是一样:
  103 +
  104 +> **如果 KV cache 已经在 GPU 上,单纯“把 cache 从 HBM 读出来”这件事,通常只值几十到几百微秒级,往往不到 1 ms。**
  105 +
  106 +所以你说“希望连 KV cache 的加载也省去”,**如果这里的“加载”指 GPU 内部读取常驻 KV**,那收益通常不大。更大的头往往在 query prefill、attention 访问 prefix、kernel launch、和最后的 vocab head。([NVIDIA][5])
  107 +
  108 +### 情况 2:KV cache 需要跨 GPU / 跨实例 / CPU-offload / 网络传输
  109 +
  110 +这时就不一样了。
  111 +TensorRT-LLM 的 disaggregated serving 文档专门提到 KV cache transmission,并且要做 device-to-device 直传和 transmission overlap,说明**一旦 cache 不在本地 HBM**,传输本身会显著影响时延。这个时候省掉“加载/传输”可能就是**毫秒到十几毫秒**级别。([NVIDIA GitHub][6])
  112 +
  113 +所以一句话总结:
  114 +
  115 +* **本地 GPU 常驻 KV**:再抠“cache 加载”通常只剩 **sub-ms**
  116 +* **跨设备/跨实例/CPU-offload**:可能还能省 **ms~10ms+**
  117 +
  118 +---
  119 +
  120 +## 3)对你这个任务,最值得做的优化方向
  121 +
  122 +我按“收益/工程代价比”排序。
  123 +
  124 +### 方向 1:别再把它当生成,改成“最后 token hidden state → 分类头”
  125 +
  126 +这是最重要的。
  127 +
  128 +Causal LLM 做 sequence classification,本来就常用“最后 token hidden state + 线性层”来分类,Hugging Face 的 `OPTForSequenceClassification` 也是这么干的。TensorRT-LLM 也支持拿额外输出,如 `hidden_states`。([Hugging Face][7])
  129 +
  130 +对你这个任务,最优形态应该是:
  131 +
  132 +1. 输入只保留 query 或极短模板
  133 +2. 跑 transformer 得到最后位置 hidden state
  134 +3. 接一个 **9 类线性头**
  135 +4. 直接输出 9 个 score 的 argmax
  136 +
  137 +这样你能一次性省掉:
  138 +
  139 +* 整个 lm_head 对全词表的投影
  140 +* softmax
  141 +* 采样
  142 +* label tokenization 的不确定性
  143 +* 多 token label 问题(比如 `Trench Coat` / `T-shirt`)
  144 +
  145 +这往往比“限制 decode 只出 1 token”更本质。
  146 +
  147 +---
  148 +
  149 +### 方向 2:如果还想保留生成范式,至少把 9 个类别映射成 9 个单 token
  150 +
  151 +如果你暂时不改模型结构,至少别让类别是自然语言短语。
  152 +
  153 +做法是引入 9 个专用 special tokens,例如:
  154 +
  155 +* `<CAT_DRESS>`
  156 +* `<CAT_JEANS>`
  157 +* ...
  158 +* `<CAT_OTHER>`
  159 +
  160 +然后:
  161 +
  162 +* 训练/蒸馏只输出这些 token
  163 +* decode 时只允许这 9 个 token
  164 +* 最后直接 argmax,不做采样
  165 +
  166 +这会比现在用 `Dress / Trench Coat / T-shirt` 这种自然词好很多,因为后者可能是多 token,且受 tokenizer 影响。
  167 +
  168 +---
  169 +
  170 +### 方向 3:不要算完整 vocab logits,只算 9 类 score
  171 +
  172 +你已经意识到这一点了,而且这是对的。
  173 +
  174 +如果还沿用 LM head 权重 (W \in \mathbb{R}^{V \times H}),那现在做的是:
  175 +
  176 +[
  177 +\text{logits} = h W^T
  178 +]
  179 +
  180 +其中 (V) 可能是 50k、100k、甚至更大。
  181 +但你只关心 9 类,那就只取 9 行:
  182 +
  183 +[
  184 +\text{scores} = h W_{\text{class}}^T
  185 +]
  186 +
  187 +这本质上是一个 **9-way GEMV**,而不是 full-vocab GEMM/GEMV。
  188 +
  189 +进一步还能做成一个 fused kernel:
  190 +
  191 +* last-token gather
  192 +* final layernorm
  193 +* 9-row projection
  194 +* argmax
  195 +
  196 +一次 kernel 做完,连中间 logits buffer 都不落地。
  197 +
  198 +这个方向在工程上非常“值”,因为它精准切中你场景里最浪费的一步。
  199 +
  200 +---
  201 +
  202 +### 方向 4:把自然语言前缀蒸馏进权重,彻底消灭长 instruction prefix
  203 +
  204 +这个收益经常被低估。
  205 +
  206 +现在即使 prefix KV cache 命中,query token 仍然要对这个 prefix 做 attention。
  207 +如果你把这条 instruction 蒸馏掉,例如:
  208 +
  209 +* SFT/LoRA 成一个专用分类模型
  210 +* 或者把 instruction 变成很短的 learned prompt / soft prompt
  211 +* 或者直接训成 encoder-style / sequence-classification head
  212 +
  213 +那么你不仅省掉 prefix prefill,还省掉了**query 对 prefix 的 attention 成本**。
  214 +这通常比继续抠“prefix cache 加载”更有价值。
  215 +
  216 +我的判断是:
  217 +
  218 +> **对搜索 query 分类,最大收益往往不是“更聪明地复用长 prompt”,而是“让模型根本不需要那段长 prompt”。**
  219 +
  220 +---
  221 +
  222 +### 方向 5:为“短 query + 单步输出”做专用 execution path
  223 +
  224 +通用引擎通常为“大上下文 + 多 token decode + 动态 batch”设计。
  225 +而你的 workload 更像:
  226 +
  227 +* batch 可控
  228 +* 形状集中
  229 +* query 很短
  230 +* 输出固定 1 步
  231 +* 类别数固定
  232 +
  233 +这非常适合做专用路径:
  234 +
  235 +* 固定或分桶后的静态 shape
  236 +* 全流程 CUDA Graph capture
  237 +* persistent kernel
  238 +* 预分配所有 buffer
  239 +* 避免动态分配/释放 KV page
  240 +* 避免 host 端参与每一步调度
  241 +
  242 +TensorRT-LLM 的 Piecewise CUDA Graph 就是在减少 launch overhead,尤其 context phase 的 launch overhead。对你这种超短请求,这类优化会比较敏感。([NVIDIA GitHub][8])
  243 +
  244 +---
  245 +
  246 +## 4)如果要做“深度定制化 GPU 编程”,最值得下手的点
  247 +
  248 +你提到更希望找 **定制化 GPU 编程** 的方向。这个我建议按三层来做。
  249 +
  250 +### 第一层:先复用现成高性能 attention backend
  251 +
  252 +优先看:
  253 +
  254 +* **FlashAttention-3**:针对 Hopper,核心是 warp specialization、TMA、matmul/softmax 交叠、FP8 等,H100 上较前代有 **1.5–2.0x** 提升。([arXiv][3])
  255 +* **FlashInfer**:核心卖点就是 **customizable attention template + JIT compilation**,而且已经集成进 SGLang、vLLM、MLC-Engine。论文里给了 **29–69% inter-token latency reduction**。虽然这个数字更偏通用 serving,但它最适合你拿来当“自定义 attention backend”的基座。([arXiv][9])
  256 +
  257 +这一步的意义是:先把 attention kernel 做到接近硬件上限,不要从零手搓全部注意力算子。
  258 +
  259 +---
  260 +
  261 +### 第二层:在 attention 之外手写你自己的“小尾巴”
  262 +
  263 +这是我最推荐你自己写 Triton/CUDA 的部分,因为最贴近你的任务特征。
  264 +
  265 +#### 2.1 fused last-token classification kernel
  266 +
  267 +把这几步融合:
  268 +
  269 +* 取最后非 padding token hidden state
  270 +* RMSNorm / LayerNorm
  271 +* 9 类投影
  272 +* 可选 bias
  273 +* argmax
  274 +
  275 +这一步非常适合手写 Triton kernel,因为:
  276 +
  277 +* 数据很小
  278 +* shape 固定
  279 +* 全词表 head 被你砍掉了
  280 +* 可以彻底避免多余内存读写
  281 +
  282 +#### 2.2 prefix-aware short-query prefill kernel
  283 +
  284 +你的 query 很短,通用 prefill kernel 往往为更一般的长序列设计。
  285 +可以做一个专门针对:
  286 +
  287 +* `T_query` 很短
  288 +* `T_prefix` 固定/分桶
  289 +* batch 较小
  290 +* causal mask 形状固定
  291 +
  292 +的 kernel 版本,减少通用路径里的分支和元数据处理。
  293 +
  294 +#### 2.3 persistent kernel / resident weights
  295 +
  296 +对“超短输入 + 高频请求”,可以考虑把部分小尾部算子做 persistent 化,减少 launch 与调度开销。
  297 +这类场景里,kernel launch overhead 占比会比大 batch 长序列高得多。TensorRT-LLM 做 CUDA Graph / overlap,本质上也是在解决这个问题。([NVIDIA GitHub][8])
  298 +
  299 +---
  300 +
  301 +### 第三层:改 KV layout 和请求调度
  302 +
  303 +如果你是自己做 engine,下面这些值得认真做:
  304 +
  305 +#### 3.1 prefix 常驻 + 热前缀 pin 住,不参与普通 eviction
  306 +
  307 +TRT-LLM 的 KV cache 系统支持跨请求复用和优先保留。对于你的固定 prompt,应该把它当“超级热前缀”对待。([NVIDIA GitHub][10])
  308 +
  309 +#### 3.2 query 长度分桶
  310 +
  311 +例如按 4/8/16/32 token 分桶。
  312 +这样更容易:
  313 +
  314 +* 静态 shape
  315 +* CUDA Graph capture
  316 +* 避免 padding 浪费
  317 +* 避免 kernel 形状抖动
  318 +
  319 +#### 3.3 专用队列,不和长文本请求混部
  320 +
  321 +你的 workload 和普通 chat workload 的最优调度策略不一样。
  322 +一旦混部,长请求会把你的 tail latency 拖坏。
  323 +
  324 +---
  325 +
  326 +## 5)你这个任务里,哪些“常见优化”其实不太重要
  327 +
  328 +### Speculative decoding
  329 +
  330 +对你帮助很小。
  331 +因为你本来就只出 1 个 token,decode 几乎不是瓶颈。
  332 +
  333 +### Continuous batching / 大 batch 吞吐优化
  334 +
  335 +如果你的目标是单请求极低延时,而不是 QPS 最大化,这不是第一优先级。
  336 +
  337 +### 更复杂的 constrained decoding / grammar decoding
  338 +
  339 +SGLang 的 compressed FSM 很强,能把结构化输出做得很快,甚至比普通 decoding 还快;但它更适合 JSON/regex 类任务。你这种 **9 类单标签**,直接分类头会更彻底。([LMSYS Org][11])
  340 +
  341 +---
  342 +
  343 +## 6)一个更现实的性能判断
  344 +
  345 +我给一个实战判断,按收益从大到小:
  346 +
  347 +### 第一梯队
  348 +
  349 +1. **把任务改成 sequence classification,而不是生成**
  350 +2. **把 instruction prefix 蒸馏进模型,去掉长 prompt**
  351 +3. **只算 9 类 score,不算全词表**
  352 +4. **固定 shape + CUDA Graph + 预分配内存**
  353 +
  354 +### 第二梯队
  355 +
  356 +5. **prefix KV 常驻 GPU,不跨设备传**
  357 +6. **短 query 分桶**
  358 +7. **attention backend 换成 FlashAttention-3 / FlashInfer 路线**
  359 +
  360 +### 第三梯队
  361 +
  362 +8. **再去抠“KV cache 的 GPU 内部读取”**
  363 +9. **再去做更复杂的 decode 优化**
  364 +
  365 +也就是说:
  366 +
  367 +> 你最该优化的,不是“如何更快地做一次生成”,而是“如何避免把这个问题当生成来做”。
  368 +
  369 +---
  370 +
  371 +## 7)我建议你重点读的资料
  372 +
  373 +按“最贴近你要做的事”排序:
  374 +
  375 +1. **TensorRT-LLM: KV cache reuse / KV cache system / Piecewise CUDA Graph / Overlap Scheduler**
  376 + 看工程系统怎么压 TTFT、launch overhead、CPU-GPU overlap、KV 复用。([NVIDIA GitHub][1])
  377 +
  378 +2. **FlashInfer (MLSys 2025)**
  379 + 这是最像“为 serving 场景做可定制 attention engine”的资料,尤其适合你想走 JIT + custom backend + custom layout 的路线。([arXiv][9])
  380 +
  381 +3. **FlashAttention-3**
  382 + 如果你想往 Hopper/Blackwell 上深挖 kernel,这篇最值得精读。([arXiv][3])
  383 +
  384 +4. **SGLang / RadixAttention / compressed FSM**
  385 + 主要看 prefix 复用和受限输出的 runtime 设计思路。([LMSYS Org][12])
  386 +
  387 +---
  388 +
  389 +## 8)最后给你一个最适合落地的技术路线
  390 +
  391 +如果我是你,会这么做:
  392 +
  393 +### 方案 A:最快落地
  394 +
  395 +* 继续用现有 LLM
  396 +* 加 9 个 special label tokens
  397 +* 只允许这 9 个 token
  398 +* prefix cache 常驻
  399 +* 短 query 分桶
  400 +* CUDA Graph
  401 +* 自定义 logits path,只算 9 个 token 对应分数
  402 +
  403 +### 方案 B:更极致
  404 +
  405 +* 把任务改成 `last_hidden_state -> 9-class head`
  406 +* 不再走生成
  407 +* 用 TensorRT-LLM / TensorRT engine 导出专用模型
  408 +* 手写 fused classification tail kernel
  409 +* attention 走 FlashAttention-3 / FlashInfer backend
  410 +* instruction 蒸馏进模型,删除自然语言 prefix
  411 +
  412 +### 方案 C:最极致、最像搜索引擎专用算子
  413 +
  414 +* 单独做一个 query-classification engine
  415 +* tokenizer 前移并缓存
  416 +* query 长度严格分桶
  417 +* prefix 完全蒸馏掉
  418 +* BF16/FP8 主干
  419 +* 末端 9-way 头自定义 Triton/CUDA kernel
  420 +* 固定 batch/shape 的全图 capture
  421 +* 与通用 chat serving 完全隔离
  422 +
  423 +---
  424 +
  425 +如果你愿意,我下一步可以直接给你一版更工程化的东西:
  426 +**把这个场景拆成“通用 vLLM 路线 / TensorRT-LLM 路线 / 自研 Triton kernel 路线”的优化清单和预估收益表。**
  427 +
  428 +[1]: https://nvidia.github.io/TensorRT-LLM/advanced/kv-cache-reuse.html "KV cache reuse — TensorRT-LLM"
  429 +[2]: https://nvidia.github.io/TensorRT-LLM/1.1.0rc4/features/overlap-scheduler.html "Overlap Scheduler — TensorRT-LLM"
  430 +[3]: https://arxiv.org/abs/2407.08608 "[2407.08608] FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision"
  431 +[4]: https://nvidia.github.io/TensorRT-LLM/latest/examples/llm_logits_processor.html "Control generated text using logits processor — TensorRT LLM"
  432 +[5]: https://www.nvidia.com/en-us/data-center/h100/ "H100 GPU | NVIDIA"
  433 +[6]: https://nvidia.github.io/TensorRT-LLM/features/disagg-serving.html "Disaggregated Serving — TensorRT LLM"
  434 +[7]: https://huggingface.co/docs/transformers/model_doc/opt "OPT · Hugging Face"
  435 +[8]: https://nvidia.github.io/TensorRT-LLM/latest/features/torch_compile_and_piecewise_cuda_graph.html "Torch Compile & Piecewise CUDA Graph — TensorRT LLM"
  436 +[9]: https://arxiv.org/abs/2501.01005 "[2501.01005] FlashInfer: Efficient and Customizable Attention Engine for LLM Inference Serving"
  437 +[10]: https://nvidia.github.io/TensorRT-LLM/latest/features/kvcache.html?utm_source=chatgpt.com "KV Cache System — TensorRT LLM - nvidia.github.io"
  438 +[11]: https://www.lmsys.org/blog/2024-02-05-compressed-fsm/ "Fast JSON Decoding for Local LLMs with Compressed Finite State Machine - LMSYS Blog | LMSYS Org"
  439 +[12]: https://www.lmsys.org/blog/2024-01-17-sglang/ "Fast and Expressive LLM Inference with RadixAttention and SGLang - LMSYS Blog | LMSYS Org"
  440 +
  441 +# 二、kimi
  442 +基于搜索结果,我来为你详细分析LLM推理极致优化的方向,特别是针对搜索引擎query分析这种对延迟极其敏感的场景。
  443 +
  444 +## 核心耗时分析
  445 +
  446 +对于query分类这类任务(单token输出),耗时主要集中在:
  447 +
  448 +| 阶段 | 占比 | 优化方向 |
  449 +|------|------|----------|
  450 +| **Prefill (前缀计算)** | 60-80% | Prefix Caching、Kernel Fusion |
  451 +| **KV Cache加载/准备** | 10-20% | 常驻显存、零拷贝、内存预分配 |
  452 +| **Decode (单token)** | 5-15% | 分类头直接打分、跳过完整解码 |
  453 +| **Kernel Launch开销** | 5-10% | CUDA Graphs、算子融合 |
  454 +
  455 +## 极致优化方向
  456 +
  457 +### 1. **Prefix Caching的极致化**
  458 +
  459 +vLLM已支持Automatic Prefix Caching (APC),但要做到极致:
  460 +
  461 +- **跨Session持久化**:将KV Cache写入CPU内存甚至NVMe SSD(通过LMCache),实现服务重启后仍能复用
  462 +- **Block Size调优**:根据query长度分布选择16/32/64,减少内部碎片
  463 +- **命中率优化**:对固定前缀(如你的分类prompt模板)做哈希预热,确保100%命中
  464 +
  465 +**收益**:TTFT可降低5-10倍,对于长前缀(如你的分类prompt)几乎消除prefill时间。
  466 +
  467 +### 2. **跳过KV Cache加载 - 常驻显存方案**
  468 +
  469 +你希望"连KV Cache加载也省去",这可以通过以下方式实现:
  470 +
  471 +```
  472 +方案A: 前缀KV常驻显存
  473 +- 将固定前缀的KV Cache预分配并锁定在GPU HBM中
  474 +- 新请求直接复用这些物理块,无需任何加载/拷贝
  475 +- 配合vLLM的block table机制,实现零开销引用
  476 +
  477 +方案B: 权重+KV合并存储
  478 +- 对于超短query分类,可将前缀KV视为"扩展的模型权重"
  479 +- 使用TensorRT-LLM的weight streaming技术
  480 +```
  481 +
  482 +**时间节省估算**:
  483 +- 传统:从CPU/GDRAM加载KV → 10-50ms
  484 +- 常驻显存:直接指针引用 → <0.1ms
  485 +- **节省:10-50ms(对于短query分类,这可能是总延迟的50-80%)**
  486 +
  487 +### 3. **单Token分类的极致优化**
  488 +
  489 +你提到的"不对整个词表decode,只对N分类算打分"是关键优化点:
  490 +
  491 +**实现方案**:
  492 +```python
  493 +# 标准做法(浪费):
  494 +logits = model.forward(input_ids) # [batch, vocab_size=50000]
  495 +probs = softmax(logits)
  496 +
  497 +# 极致做法:
  498 +# 1. 只计算分类头的输出投影到N个标签token的logits
  499 +# 2. 使用Gather + MatMul融合kernel,跳过完整LM Head
  500 +# 3. 直接argmax,无需采样
  501 +```
  502 +
  503 +**技术细节**:
  504 +- 修改模型最后一层,只输出N个分类token的logits
  505 +- 使用CUTLASS或Triton编写定制kernel,融合`gather + matmul + argmax`
  506 +- 配合CUDA Graphs消除kernel launch开销
  507 +
  508 +**收益**:从50000维softmax降到10维分类打分,计算量减少**5000倍**。
  509 +
  510 +### 4. **GPU深度定制化编程**
  511 +
  512 +#### A. **Kernel Fusion**
  513 +将以下操作融合为单个CUDA kernel:
  514 +- RoPE位置编码(针对可变query长度)
  515 +- Attention计算(Q@K^T, softmax, @V)
  516 +- 分类头投影(仅限N个输出token)
  517 +- Argmax
  518 +
  519 +**关键优化点**:
  520 +- 使用共享内存缓存前缀KV,避免全局内存访问
  521 +- Warp-level并行处理N分类打分
  522 +- 针对A100/H100 Tensor Cores优化WMMA指令
  523 +
  524 +#### B. **Flash Attention变体**
  525 +- **FlashDecoding++**:针对decode阶段优化flat GEMM,在小batch场景比cuBLAS快17-52%
  526 +- **Split-KV**:对于GQA模型,优化KV Cache访问模式
  527 +
  528 +#### C. **TensorRT-LLM Plugin开发**
  529 +```cpp
  530 +// 自定义Plugin结构
  531 +class QueryClassifierPlugin : public BasePlugin {
  532 + // 1. 实现enqueue接口,融合所有计算
  533 + // 2. 跳过标准attention,直接读取常驻前缀KV
  534 + // 3. 只计算分类头N个输出
  535 + int enqueue(...) override {
  536 + // 融合kernel: attention + classifier_head + argmax
  537 + launch_fused_classifier_kernel(...);
  538 + }
  539 +};
  540 +```
  541 +
  542 +#### D. **CUDA Graphs固化**
  543 +- 对于固定前缀+可变query的场景,使用CUDA Graphs捕获执行流
  544 +- 消除CPU调度开销,实现确定性延迟
  545 +
  546 +### 5. **推测解码的反向应用**
  547 +
  548 +虽然推测解码通常用于长输出,但对于分类任务可以**预计算**:
  549 +- 使用极小draft模型(甚至规则引擎)预生成分类结果
  550 +- 主模型只做验证(单token forward)
  551 +- 配合EAGLE-3技术,实现2-3倍加速
  552 +
  553 +## 推荐技术栈
  554 +
  555 +| 层级 | 技术 | 适用场景 |
  556 +|------|------|----------|
  557 +| **推理引擎** | TensorRT-LLM + 自定义Plugin | 极致延迟优化 |
  558 +| **Kernel库** | CUTLASS / FlashAttention | Attention优化 |
  559 +| **缓存管理** | vLLM Prefix Caching + LMCache | 跨session KV复用 |
  560 +| **编译优化** | Torch.compile + CUDA Graphs | 消除launch开销 |
  561 +| **硬件调度** | MPS (Multi-Process Service) | 多query并行 |
  562 +
  563 +## 预期性能收益
  564 +
  565 +对于你的query分类场景(假设前缀512 tokens,分类10个类别):
  566 +
  567 +| 优化项 | 延迟降低 | 实现难度 |
  568 +|--------|----------|----------|
  569 +| Prefix Caching (100%命中) | 5-10x | 低(vLLM开箱即用) |
  570 +| KV常驻显存 | 1.5-2x | 中(需修改内存管理) |
  571 +| 分类头裁剪 | 100-1000x | 中(需修改模型结构) |
  572 +| Kernel Fusion | 1.2-1.5x | 高(需CUDA编程) |
  573 +| CUDA Graphs | 1.1-1.3x | 中 |
  574 +| **综合优化** | **10-50x** | - |
  575 +
  576 +**终极目标**:将TTFT从典型的50-100ms降至**1-5ms**级别,接近网络RTT水平。
  577 +
  578 +建议先从vLLM的prefix caching和TensorRT-LLM的plugin开发入手,逐步深入到CUDA kernel定制。对于搜索引擎query分析这种高频、低延迟要求的场景,这些投入是值得的。
0 \ No newline at end of file 579 \ No newline at end of file
scripts/evaluation/eval_framework/prompts.py
@@ -209,8 +209,20 @@ _CLASSIFY_TEMPLATE_ZH = &quot;&quot;&quot;雿銝銝芣弘揣蝟餌葉批 @@ -209,8 +209,20 @@ _CLASSIFY_TEMPLATE_ZH = &quot;&quot;&quot;雿銝銝芣弘揣蝟餌葉批
209 - 霂V掩銝箄砲蝐餃 209 - 霂V掩銝箄砲蝐餃
210 - 霂W掩 + 撅把蝐餃&撅找泵 210 - 霂W掩 + 撅把蝐餃&撅找泵
211 211
  212 +
  213 +葉抒霂V葉扯
  214 +
  215 +霂g鋆/"
  216 + 掩撅改說頞喃霂V葉
  217 +
  218 +
  219 +霂g耨頨怎ㄓ蝑凝撕ㄓ"
  220 + 掩撕摰靽株澈說頞喃霂Y隞改蝑凝蛹憸縑嚗霂U
  221 +
  222 +霂g絲皛拙漲撣血漲仄憌﹝鋆
  223 +
212 ### 224 ###
213 -說頞喟蜓閬嚗敹掩霂V葉&縑銝凋&霈歹頧餃凝榆 / 榆砲皛∟雲敹瘙憟賣 225 +說頞喟蜓閬嚗敹掩霂V葉&縑銝凋&霈歹頧餃凝榆 / 榆嚗雿餈皛∟雲敹瘙末
214 226
215 隞乩雿輻 227 隞乩雿輻
216 - 敹掩抒撩憭晞&霈扎 228 - 敹掩抒撩憭晞&霈扎
@@ -218,10 +230,14 @@ _CLASSIFY_TEMPLATE_ZH = &quot;&quot;&quot;雿銝銝芣弘揣蝟餌葉批 @@ -218,10 +230,14 @@ _CLASSIFY_TEMPLATE_ZH = &quot;&quot;&quot;雿銝銝芣弘揣蝟餌葉批
218 - 揚銝鋡怨蛹隞 230 - 揚銝鋡怨蛹隞
219 231
220 232
  233 +扳榆雿頝餈
  234 +
  235 +扯&霈扎雿瓷瘙嚗撅皛∟雲漣
221 - 霂g滯靽株澈T戊憯俊 236 - 霂g滯靽株澈T戊憯俊
222 憸&霈扎 237 憸&霈扎
223 -- 霂g滯靽株澈T靽株澈T  
224 - 掩銝 238 +
  239 +- 霂g部瘜∟鋡鋡部瘜∟
  240 + &霈斗鋡瘜⊥部鋡扳撉銝霂X&蝒改之璁
225 241
226 霂衣 242 霂衣
227 - 霂g捶鋡′銵徉 243 - 霂g捶鋡′銵徉
@@ -253,12 +269,21 @@ _CLASSIFY_TEMPLATE_ZH = &quot;&quot;&quot;雿銝銝芣弘揣蝟餌葉批 @@ -253,12 +269,21 @@ _CLASSIFY_TEMPLATE_ZH = &quot;&quot;&quot;雿銝銝芣弘揣蝟餌葉批
253 - 霂Z葉葵扯◤餈◤ 269 - 霂Z葉葵扯◤餈◤
254 270
255 271
  272 +蝐餃 + 撅扯榆嚗隡潦雿漣抒艇蝒
  273 +- 霂g滯TT
  274 + 撅嚗銝
  275 +- 霂g葵摮餈﹝鋆迤摰賣餈﹝鋆
  276 + 撅﹝鋆皛∟雲葵摮誑
  277 +
  278 +蝐餃 + 憌/餈
  279 +- 霂gT滲蝘‵
  280 + T‵掩銝舅捶忽銝虜餈嚗隞
256 - 霂g銝剝澈鋆甈暸V憸葉甈曇﹝鋆 隡暺扳﹝鋆 281 - 霂g銝剝澈鋆甈暸V憸葉甈曇﹝鋆 隡暺扳﹝鋆
257 敹掩澈鋆﹝鋆舅狡撘蛹葉甈撾蝛踵銝餈迨撅摹 282 敹掩澈鋆﹝鋆舅狡撘蛹葉甈撾蝛踵銝餈迨撅摹
258 -  
259 - 霂gㄓ鋆手 283 - 霂gㄓ鋆手
260 敹掩ㄓ鋆之蝐鳴忽餈雿蛹颲摹隞 284 敹掩ㄓ鋆之蝐鳴忽餈雿蛹颲摹隞
261 285
  286 +
262 ### 銝 287 ### 銝
263 皛∟雲蜓閬揚嚗 288 皛∟雲蜓閬揚嚗
264 289