<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>LLM on lategege 的技术博客</title><link>https://lategege.com/tags/llm/</link><description>Recent content in LLM on lategege 的技术博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sun, 22 Mar 2026 02:30:00 +0800</lastBuildDate><atom:link href="https://lategege.com/tags/llm/index.xml" rel="self" type="application/rss+xml"/><item><title>做一套可持续的 LLM 评测体系：离线数据集、在线回放与回归基线</title><link>https://lategege.com/p/llm-eval-system-offline-online-regression/</link><pubDate>Sun, 22 Mar 2026 02:30:00 +0800</pubDate><guid>https://lategege.com/p/llm-eval-system-offline-online-regression/</guid><description>&lt;p&gt;你会发现 LLM 项目最痛的不是“第一次做出来”，而是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prompt 改了一句，效果变了&lt;/li&gt;
&lt;li&gt;模型换了个版本，线上投诉变多&lt;/li&gt;
&lt;li&gt;retriever 调了参数，某些场景突然不好用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果没有评测体系，你只能凭感觉回滚。&lt;/p&gt;
&lt;p&gt;这篇文章给一套我认为可持续的评测框架：&lt;strong&gt;离线数据集 + 线上回放 + 回归基线&lt;/strong&gt;。它适用于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;纯聊天问答&lt;/li&gt;
&lt;li&gt;RAG&lt;/li&gt;
&lt;li&gt;Agent（工具调用）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="1-明确评测对象你到底要评测什么"&gt;1. 明确评测对象：你到底要“评测什么”
&lt;/h2&gt;&lt;p&gt;建议先把任务分成三类：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;检索质量&lt;/strong&gt;（RAG）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Top-K recall、MRR、命中率&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;生成质量&lt;/strong&gt;（答案本身）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;正确性、完整性、可读性、是否引用证据&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;行为质量&lt;/strong&gt;（Agent）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;工具调用是否正确&lt;/li&gt;
&lt;li&gt;是否遵守边界（不越权、不外泄）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;很多团队把这三类混在一起，导致指标失真。&lt;/p&gt;
&lt;h2 id="2-离线数据集小而真实比大而虚更重要"&gt;2. 离线数据集：小而真实，比大而虚更重要
&lt;/h2&gt;&lt;h3 id="21-数据集来源"&gt;2.1 数据集来源
&lt;/h3&gt;&lt;p&gt;优先用真实用户日志：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;搜索 query&lt;/li&gt;
&lt;li&gt;工单问题&lt;/li&gt;
&lt;li&gt;FAQ 热点&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果没有，就让业务同学/客服给 50~200 条典型问题。&lt;/p&gt;
&lt;h3 id="22-每条样本要有什么标注"&gt;2.2 每条样本要有什么“标注”
&lt;/h3&gt;&lt;p&gt;不要一上来追求完美答案标注。&lt;/p&gt;
&lt;p&gt;更轻量但高效的标注方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RAG：标注“应该命中的文档/段落 id”（或至少 doc id）&lt;/li&gt;
&lt;li&gt;生成：标注“必须包含的要点列表”（bullet points）&lt;/li&gt;
&lt;li&gt;Agent：标注“允许的工具序列/禁止行为”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样成本低、可扩展。&lt;/p&gt;
&lt;h2 id="3-评测方法别只用一个-llm-打分"&gt;3. 评测方法：别只用一个 LLM 打分
&lt;/h2&gt;&lt;h3 id="31-检索指标是硬指标"&gt;3.1 检索指标是硬指标
&lt;/h3&gt;&lt;p&gt;RAG 的检索阶段建议用硬指标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Top-5 recall：答案证据是否在前 5 个里&lt;/li&gt;
&lt;li&gt;MRR：正确证据排第几&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这能把“检索问题”和“生成问题”拆开。&lt;/p&gt;
&lt;h3 id="32-生成评测用-rubric--结构化检查"&gt;3.2 生成评测：用 rubric + 结构化检查
&lt;/h3&gt;&lt;p&gt;如果用 LLM-as-a-judge：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;必须有 rubric（评分标准）&lt;/li&gt;
&lt;li&gt;输出结构化（JSON）：
&lt;ul&gt;
&lt;li&gt;correctness: 0-5&lt;/li&gt;
&lt;li&gt;completeness: 0-5&lt;/li&gt;
&lt;li&gt;grounded: 0-5（是否有证据）&lt;/li&gt;
&lt;li&gt;notes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同时加一些“硬规则检查”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是否包含引用链接&lt;/li&gt;
&lt;li&gt;是否输出了敏感字段&lt;/li&gt;
&lt;li&gt;是否出现禁止词（例如泄露系统提示）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;多信号比单一打分稳。&lt;/p&gt;
&lt;h2 id="4-线上回放把事故变成数据"&gt;4. 线上回放：把事故变成数据
&lt;/h2&gt;&lt;p&gt;上线后最有价值的样本来自失败案例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户追问很多次&lt;/li&gt;
&lt;li&gt;点踩/转人工&lt;/li&gt;
&lt;li&gt;明显答非所问&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你应该把这些请求“可回放化”，至少包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原始输入&lt;/li&gt;
&lt;li&gt;当时的系统提示版本&lt;/li&gt;
&lt;li&gt;检索结果（doc id、score）&lt;/li&gt;
&lt;li&gt;工具调用记录（参数、返回）&lt;/li&gt;
&lt;li&gt;最终输出&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样你能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把失败样本加入离线集&lt;/li&gt;
&lt;li&gt;做“回归基线”：以后改任何东西都不能再坏&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-回归基线评测要能挡住退化"&gt;5. 回归基线：评测要能挡住退化
&lt;/h2&gt;&lt;p&gt;实践里我会设三条线：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;质量线&lt;/strong&gt;：核心问题集的平均分不得下降&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全线&lt;/strong&gt;：越权/外泄相关用例必须 0 失败&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能线&lt;/strong&gt;：P95 TTFT/TPOT 不能超过阈值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每次改动（prompt、模型、检索、rerank、工具）都跑一遍。&lt;/p&gt;
&lt;h2 id="6-最小可行实现mvp长什么样"&gt;6. 最小可行实现（MVP）长什么样
&lt;/h2&gt;&lt;p&gt;如果你今天就要做一个评测体系 MVP，我建议：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先收集 100 条真实问题&lt;/li&gt;
&lt;li&gt;标注：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;每条一个“参考要点”&lt;/li&gt;
&lt;li&gt;RAG 场景加 doc id&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;写一个脚本：跑完整链路，输出 JSON 结果&lt;/li&gt;
&lt;li&gt;做一个简单 dashboard：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;质量分布&lt;/li&gt;
&lt;li&gt;失败样本列表&lt;/li&gt;
&lt;li&gt;版本对比&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一周内就能跑起来，然后边用边补。&lt;/p&gt;
&lt;h2 id="结语"&gt;结语
&lt;/h2&gt;&lt;p&gt;评测体系的价值不是“给领导看分数”，而是让你：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;敢改&lt;/li&gt;
&lt;li&gt;改得动&lt;/li&gt;
&lt;li&gt;改完不怕上线&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你告诉我你现在的产品形态（纯聊天/RAG/Agent）和数据源，我可以把这套评测框架进一步具体化成：字段定义、样本格式、rubric 模板与回归阈值建议。&lt;/p&gt;</description></item><item><title>LLM 推理性能优化路线图：从瓶颈定位到 KV Cache、连续批处理与吞吐/延迟权衡</title><link>https://lategege.com/p/llm-inference-performance-roadmap/</link><pubDate>Sun, 22 Mar 2026 02:10:00 +0800</pubDate><guid>https://lategege.com/p/llm-inference-performance-roadmap/</guid><description>&lt;p&gt;把 LLM 服务真正跑起来后，你会很快发现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“模型很强”不等于“服务好用”&lt;/li&gt;
&lt;li&gt;性能问题不是一个点，而是一条链路：&lt;strong&gt;请求 → 编排 → 推理 → 解码 → 传输&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这篇文章给一套我认为实用的推理优化路线图：先定位瓶颈，再按收益/风险排序做改动。重点讲清楚三个常见核心点：&lt;strong&gt;KV Cache、连续批处理（continuous batching）、吞吐与延迟的权衡&lt;/strong&gt;。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;说明：以下讨论以 Decoder-only LLM（GPT 类）为主。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="1-先把指标做对不然你永远在感觉优化"&gt;1. 先把指标做对：不然你永远在“感觉优化”
&lt;/h2&gt;&lt;p&gt;推理服务至少要同时看两类指标：&lt;/p&gt;
&lt;h3 id="11-用户体验类latency"&gt;1.1 用户体验类（Latency）
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TTFT&lt;/strong&gt;（Time To First Token）：从收到请求到吐出第一个 token 的时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TPOT&lt;/strong&gt;（Time Per Output Token）：后续每个 token 的平均时间&lt;/li&gt;
&lt;li&gt;P50/P95/P99（尤其看 P95）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TTFT 决定“有没有卡住”，TPOT 决定“输出快不快”。&lt;/p&gt;
&lt;h3 id="12-资源效率类throughputcost"&gt;1.2 资源效率类（Throughput/Cost）
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;tokens/s（整体吞吐）&lt;/li&gt;
&lt;li&gt;GPU 利用率（SM occupancy 只是其中之一）&lt;/li&gt;
&lt;li&gt;显存占用（KV cache 往往是大头）&lt;/li&gt;
&lt;li&gt;单请求平均成本（按 token 计费更贴近现实）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;一个常见误区&lt;/strong&gt;：只盯 tokens/s，然后为了吞吐把 batch 拉很大，结果 TTFT 飙升，产品体验崩掉。&lt;/p&gt;
&lt;h2 id="2-理解两个阶段prefill-与-decode"&gt;2. 理解两个阶段：Prefill 与 Decode
&lt;/h2&gt;&lt;p&gt;LLM 推理可以粗略分成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prefill&lt;/strong&gt;：把 prompt 全部喂进去，计算每层 attention 的 K/V 并写入 KV cache&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decode&lt;/strong&gt;：每步只生成 1 个 token（或少量 token），每步读取 KV cache 做 attention&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;性能瓶颈往往在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prefill 阶段：矩阵乘、attention 计算量大，吞吐与并行相关&lt;/li&gt;
&lt;li&gt;Decode 阶段：每步都要读 KV cache，常被&lt;strong&gt;显存带宽/访问模式&lt;/strong&gt;限制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此优化也要分开看：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;长 prompt&lt;/strong&gt;（RAG、工具调用）→ Prefill 压力更大&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长输出&lt;/strong&gt;（写作、代码生成）→ Decode 压力更大&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-kv-cache为什么它是显存杀手也是性能命门"&gt;3. KV Cache：为什么它是显存杀手，也是性能命门
&lt;/h2&gt;&lt;h3 id="31-kv-cache-是什么"&gt;3.1 KV cache 是什么
&lt;/h3&gt;&lt;p&gt;对每一层 self-attention，你都要保存历史 token 的 Key/Value，后续解码才能复用。&lt;/p&gt;
&lt;p&gt;因此 KV cache 大小近似与以下因素线性相关：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;batch size&lt;/li&gt;
&lt;li&gt;context length（已处理 token 数）&lt;/li&gt;
&lt;li&gt;layer 数&lt;/li&gt;
&lt;li&gt;hidden size / head 数&lt;/li&gt;
&lt;li&gt;dtype（FP16/BF16/FP8/INT8 等）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="32-你会遇到的典型问题"&gt;3.2 你会遇到的典型问题
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;显存 OOM&lt;/strong&gt;：并发上来后突然炸&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;碎片化&lt;/strong&gt;：请求长短不一，cache 分配释放频繁，显存利用率下降&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;带宽瓶颈&lt;/strong&gt;：decode 阶段每步都要从显存读取大量 KV&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="33-工程策略按常见收益排序"&gt;3.3 工程策略（按常见收益排序）
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;限制最大上下文&lt;/strong&gt;：最粗暴但最有效&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;给产品一个“最大输入长度”的硬上限&lt;/li&gt;
&lt;li&gt;对 RAG：先做“检索截断 + 摘要压缩”，而不是直接堆 context&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;KV cache 量化/压缩（有风险，需验证）&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;目标：用更低精度存 KV，省显存/带宽&lt;/li&gt;
&lt;li&gt;风险：质量回退（尤其在长上下文）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;更合理的 KV 分配策略（解决碎片）&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;思路：不要为每个请求随意 malloc/free，而是做“块化管理”&lt;/li&gt;
&lt;li&gt;这也是很多推理引擎会重点优化的点&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-连续批处理continuous-batching吞吐提升的关键"&gt;4. 连续批处理（Continuous Batching）：吞吐提升的关键
&lt;/h2&gt;&lt;h3 id="41-静态-batching-的问题"&gt;4.1 静态 batching 的问题
&lt;/h3&gt;&lt;p&gt;传统 batching：等凑够一批再跑。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对吞吐好&lt;/li&gt;
&lt;li&gt;对延迟差（TTFT 会因为排队变长）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="42-连续-batching-的核心思想"&gt;4.2 连续 batching 的核心思想
&lt;/h3&gt;&lt;p&gt;在 decode 的每一步，把“当前可执行的请求”动态拼成 batch。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新请求在 prefill 完成后可以插入 decode batch&lt;/li&gt;
&lt;li&gt;已完成的请求随时退出&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这能显著提升 GPU 利用率，同时尽量控制 TTFT。&lt;/p&gt;
&lt;h3 id="43-现实中的-trade-off"&gt;4.3 现实中的 trade-off
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;batch 越大，吞吐越高，但单步 decode 变慢（每步更重），可能拉高 TPOT&lt;/li&gt;
&lt;li&gt;请求长度差异越大，调度策略越重要（谁先跑、谁后跑）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个很实用的经验：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;把 TTFT 当成 SLO&lt;/strong&gt;（比如 P95 TTFT &amp;lt; 1.5s）&lt;/li&gt;
&lt;li&gt;在满足 TTFT 的前提下尽量追吞吐&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-请求层面的最划算优化减少无效-token"&gt;5. 请求层面的“最划算”优化：减少无效 token
&lt;/h2&gt;&lt;p&gt;很多团队上来就调 kernel、换引擎，但最便宜的优化其实是&lt;strong&gt;少算 token&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="51-prompt-预算管理"&gt;5.1 Prompt 预算管理
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;系统提示词别写成论文&lt;/li&gt;
&lt;li&gt;把固定指令改成短模板&lt;/li&gt;
&lt;li&gt;把“历史对话”做摘要而不是全量回灌&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="52-rag-的上下文压缩"&gt;5.2 RAG 的上下文压缩
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Top-K 不要盲堆（先加 rerank）&lt;/li&gt;
&lt;li&gt;召回后做“句级选择/段内抽取”&lt;/li&gt;
&lt;li&gt;对重复内容做去重&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每少 1k tokens 的 prefill，能直接省 latency 和成本。&lt;/p&gt;
&lt;h2 id="6-你应该怎么做一轮优化建议顺序"&gt;6. 你应该怎么做一轮优化（建议顺序）
&lt;/h2&gt;&lt;p&gt;我会按这个顺序做：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;建立基线&lt;/strong&gt;：记录 TTFT/TPOT、吞吐、显存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制输入&lt;/strong&gt;：最大 context，RAG 截断/压缩&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调度策略&lt;/strong&gt;：连续 batching、合理并发上限&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;显存策略&lt;/strong&gt;：KV 管理、必要时量化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更底层优化&lt;/strong&gt;：kernel/fused op、张量并行/流水并行（成本高）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;每一步都要做 A/B：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;质量是否回退（尤其长上下文与边界任务）&lt;/li&gt;
&lt;li&gt;P95 是否改善（别只看平均）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="结语"&gt;结语
&lt;/h2&gt;&lt;p&gt;LLM 推理优化的本质是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把“token”当成你的单位成本&lt;/li&gt;
&lt;li&gt;把 TTFT/TPOT 当成产品体验&lt;/li&gt;
&lt;li&gt;把 KV cache 当成核心资源&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你愿意，我可以再按你们的场景（RAG 为主？写作生成？多轮工具调用？）给一个更具体的配置建议清单：并发上限、上下文预算、检索 Top-K、rerank 以及监控指标应该怎么设。&lt;/p&gt;</description></item></channel></rss>