<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Evaluation on Khari Z's LogBook</title><link>https://n571e.github.io/tags/evaluation/</link><description>Recent content in Evaluation on Khari Z's LogBook</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Fri, 24 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://n571e.github.io/tags/evaluation/index.xml" rel="self" type="application/rss+xml"/><item><title>从 Prompt 到可审计系统：结构化 LLM 决策的工程笔记</title><link>https://n571e.github.io/p/structured-llm-decision-system-review/</link><pubDate>Fri, 24 Jul 2026 00:00:00 +0000</pubDate><guid>https://n571e.github.io/p/structured-llm-decision-system-review/</guid><description>&lt;p&gt;最近一个月，我一直在整理一类结构化 LLM 决策系统。它接收自然语言和结构化字段，在有限标签中做选择；证据不足时，系统要能转人工或者明确放弃自动判断。&lt;/p&gt;&#10;&lt;p&gt;这篇只保留能公开讨论的方法，不涉及具体行业、业务字段、数据规模和实测数字。真正让我花时间的也不是某一句 Prompt，而是几个更基础的问题：候选从哪里来，怎样限制模型输出，第二次调用为什么可能和第一次不同，服务变快以后质量会不会发生变化。&lt;/p&gt;&#10;&lt;h2 id="一先把生成答案改成受限决策"&gt;&lt;a href="#%e4%b8%80%e5%85%88%e6%8a%8a%e7%94%9f%e6%88%90%e7%ad%94%e6%a1%88%e6%94%b9%e6%88%90%e5%8f%97%e9%99%90%e5%86%b3%e7%ad%96" class="header-anchor"&gt;&lt;/a&gt;一、先把“生成答案”改成“受限决策”&#10;&lt;/h2&gt;&lt;p&gt;开放式生成很灵活，直接放进业务流程却容易出问题：模型可能编出不存在的标签，也可能忽略方向、阶段之类的约束。即使返回了合法 JSON，字段值仍然可能选错。&lt;/p&gt;&#10;&lt;p&gt;我更习惯把流程拆成下面这样：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;原始输入&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 清洗和确定性规则&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 检索候选&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; LLM 提取受控事实&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 在候选 ID 中选择&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 程序检查 + 必要时语义复核&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 自动通过 / 人工复核 / 放弃自动判断&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;这类结构可以用在文档分类、工单路由、内容审核或其他高风险分类任务中。模型只负责一个边界清楚的局部判断：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;decision = model(facts, candidates, policy)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;code&gt;facts&lt;/code&gt; 是当前样本中可验证的事实，&lt;code&gt;candidates&lt;/code&gt; 是允许选择的集合，&lt;code&gt;policy&lt;/code&gt; 描述决策边界。三者最好分开组织。全塞进一段自然语言里，后面很难知道模型到底忽略了哪一部分。&lt;/p&gt;&#10;&lt;h3 id="json-合法只解决了第一层问题"&gt;&lt;a href="#json-%e5%90%88%e6%b3%95%e5%8f%aa%e8%a7%a3%e5%86%b3%e4%ba%86%e7%ac%ac%e4%b8%80%e5%b1%82%e9%97%ae%e9%a2%98" class="header-anchor"&gt;&lt;/a&gt;JSON 合法，只解决了第一层问题&#10;&lt;/h3&gt;&lt;p&gt;结构化输出有两种常见做法。一种是在 Prompt 里要求返回 JSON，解析失败后重试；另一种是在解码阶段按照 JSON Schema 屏蔽非法 token，也就是 constrained decoding。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://openai.com/index/introducing-structured-outputs-in-the-api/" target="_blank" rel="noopener"&#10; &gt;OpenAI 对 Structured Outputs 的说明&lt;/a&gt;提到，约束解码可以保证输出符合 schema，却不能保证对象里的值正确。一个答案可以格式完美，同时语义完全错误。&lt;/p&gt;&#10;&lt;p&gt;所以校验至少要分成两层：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;结构校验：字段是否齐全、类型是否正确、枚举是否合法&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;领域校验：候选是否存在、事实是否冲突、决策是否越过业务边界&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;模型最好返回候选里的稳定 ID，不要重新生成标签名称。解释可以是一小段文本，真正参与程序路由的状态尽量使用枚举、布尔值和受控数组。&lt;/p&gt;&#10;&lt;p&gt;还有一个常被漏掉的分支：模型拒绝回答，或者因为长度限制没有生成完整对象。结构化输出接口通常会单独暴露 refusal 和 finish reason，程序必须处理，不能把缺失字段补成一个看似正常的结果。&lt;/p&gt;&#10;&lt;h2 id="二检索的价值是把问题变小"&gt;&lt;a href="#%e4%ba%8c%e6%a3%80%e7%b4%a2%e7%9a%84%e4%bb%b7%e5%80%bc%e6%98%af%e6%8a%8a%e9%97%ae%e9%a2%98%e5%8f%98%e5%b0%8f" class="header-anchor"&gt;&lt;/a&gt;二、检索的价值，是把问题变小&#10;&lt;/h2&gt;&lt;p&gt;在分类系统里，检索的任务不只是补充知识。它还负责缩小模型的选择空间。&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;环节&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;目标&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;常用观察指标&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;确定性规则&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;接住边界清楚的输入&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;覆盖率、冲突率&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;候选召回&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;让正确标签进入 top-k&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Recall@K&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;候选排序&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;把更相关的候选排在前面&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;MRR、NDCG&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;LLM 决策&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;结合事实做最终选择&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;自动决策精度、放弃率&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;召回决定了系统的理论上限。正确答案没有进入候选池，后面的 LLM 再强也选不到。反过来，Recall@K 很高也不代表最终结果一定更好。候选太多会增加 token，相近标签之间也会互相干扰。&lt;/p&gt;&#10;&lt;p&gt;候选数量还会影响上下文利用率。&lt;a class="link" href="https://arxiv.org/abs/2307.03172" target="_blank" rel="noopener"&#10; &gt;Lost in the Middle&lt;/a&gt; 发现，相关信息位于长上下文中部时，模型表现可能明显下降。“窗口装得下”和“模型用得好”并不是一回事。&lt;/p&gt;&#10;&lt;p&gt;因此 top-k 应该被当作需要评测的超参数：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k 太小：正确答案可能没有被召回&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k 太大：上下文变长，候选彼此干扰&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;合适的 k：兼顾 Recall@K 和最终决策质量&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;BM25、Embedding 和 Reranker 适合解决不同的问题。BM25 对关键词、编号和专有名词敏感；Embedding 能处理同义表达；Reranker 在较小的候选集上做更细的 query-document 交互。常见做法是先用便宜的检索器召回，再把少量候选交给 Reranker 或 LLM。&lt;/p&gt;&#10;&lt;p&gt;候选来源也值得保留。某个候选来自规则、稀疏检索还是向量检索，应该跟着结果进入 trace。误判发生时，这能帮助判断该调整召回还是决策节点。&lt;/p&gt;&#10;&lt;h2 id="三中间状态也是接口"&gt;&lt;a href="#%e4%b8%89%e4%b8%ad%e9%97%b4%e7%8a%b6%e6%80%81%e4%b9%9f%e6%98%af%e6%8e%a5%e5%8f%a3" class="header-anchor"&gt;&lt;/a&gt;三、中间状态也是接口&#10;&lt;/h2&gt;&lt;p&gt;多节点流程里，一个事实分析节点可能先把原文压缩成摘要，后续节点再根据摘要做判断。这样很方便，也很容易积累漂移。&lt;/p&gt;&#10;&lt;p&gt;自然语言摘要是一种有损压缩。它可能省略否定和范围，也可能把推断写成事实。后续模型并不知道这句话来自原始输入还是上一个模型的猜测，只会把它当作新的上下文继续推理。&lt;/p&gt;&#10;&lt;p&gt;更稳的中间协议可以写成：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;direction&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;outbound&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;entity_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;organization&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;stage&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;execution&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;has_supporting_document&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;evidence&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;原文片段 A&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;输入字段 B&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;uncertain_fields&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;这里最重要的不是字段叫什么，而是把“输入事实”“模型推断”和“不确定项”分开。自由文本仍然可以留在 &lt;code&gt;reason&lt;/code&gt; 中供人阅读，但不要让它悄悄控制程序分支。&lt;/p&gt;&#10;&lt;p&gt;从工程角度看，LLM 节点和普通服务没有区别：输入、输出、版本和失败行为都需要契约。模型生成的文字很顺，所以接口漂移有时比普通类型错误更难发现。&lt;/p&gt;&#10;&lt;h2 id="四critic-能用但要先告诉它查什么"&gt;&lt;a href="#%e5%9b%9bcritic-%e8%83%bd%e7%94%a8%e4%bd%86%e8%a6%81%e5%85%88%e5%91%8a%e8%af%89%e5%ae%83%e6%9f%a5%e4%bb%80%e4%b9%88" class="header-anchor"&gt;&lt;/a&gt;四、Critic 能用，但要先告诉它查什么&#10;&lt;/h2&gt;&lt;p&gt;多轮反思看起来很自然：先生成答案，再让模型审查，发现问题后重新生成。研究对这种方法给出了不同结果。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://arxiv.org/abs/2303.17651" target="_blank" rel="noopener"&#10; &gt;Self-Refine&lt;/a&gt; 在多种任务上观察到自反馈和迭代改写带来的提升；&lt;a class="link" href="https://arxiv.org/abs/2310.01798" target="_blank" rel="noopener"&#10; &gt;Large Language Models Cannot Self-Correct Reasoning Yet&lt;/a&gt; 则发现，没有外部反馈时，模型可能找不到自己的推理错误，修改后表现甚至会下降。&lt;/p&gt;&#10;&lt;p&gt;这两个结论并不冲突。润色文本、补充遗漏，和定位一个未知的逻辑错误不是同一道题。Critic 如果只收到一句“请严格审查”，很可能重复第一次判断，也可能为了表现得更严格而修改原本正确的答案。&lt;/p&gt;&#10;&lt;p&gt;我更认可有边界的审查：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;程序先检查 ID、枚举、互斥条件等硬约束。&lt;/li&gt;&#10;&lt;li&gt;规则无法判断时，再调用一次语义 Critic。&lt;/li&gt;&#10;&lt;li&gt;Critic 只检查预先定义的错误类型。&lt;/li&gt;&#10;&lt;li&gt;高风险状态变化需要独立证据或短确认。&lt;/li&gt;&#10;&lt;li&gt;达到调用上限后转人工，不允许无限反思。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;Critic 真正需要的是外部锚点。程序规则、候选约束、错误位置和独立检索证据都算锚点。什么都不给，只让模型“再想想”，效果很难预测。&lt;/p&gt;&#10;&lt;p&gt;还可以把“发现错误”和“修正错误”拆成两个节点。已有研究表明，模型可能具备修正已定位错误的能力，却不擅长自己找到错误位置。拆开后，每个节点的评测也更清楚。&lt;/p&gt;&#10;&lt;h2 id="五评测不能只留一个-accuracy"&gt;&lt;a href="#%e4%ba%94%e8%af%84%e6%b5%8b%e4%b8%8d%e8%83%bd%e5%8f%aa%e7%95%99%e4%b8%80%e4%b8%aa-accuracy" class="header-anchor"&gt;&lt;/a&gt;五、评测不能只留一个 accuracy&#10;&lt;/h2&gt;&lt;p&gt;高风险分类中，不同错误的代价差很多。自动给出错误结果和把正确样本转给人工，不能算成同一种失败。&lt;/p&gt;&#10;&lt;p&gt;一组更实用的指标包括：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;总体准确率；&lt;/li&gt;&#10;&lt;li&gt;自动决策精度和错误自动放行数；&lt;/li&gt;&#10;&lt;li&gt;人工复核率与错误放弃数；&lt;/li&gt;&#10;&lt;li&gt;最终状态分布；&lt;/li&gt;&#10;&lt;li&gt;各节点调用数、P50/P95 延迟、输入与输出 token；&lt;/li&gt;&#10;&lt;li&gt;schema retry、服务 retry、超时和错误类型。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;如果业务更重视避免错误自动决策，就应该给自动决策精度设置独立门槛，而不是让总体 accuracy 把它平均掉。可以把目标写成简单的成本函数：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;total_cost&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; = false_accept * 高风险成本&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + false_abstain * 机会成本&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + manual_review * 人工成本&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + latency * 服务成本&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;这些权重来自业务风险，不应由模型指标替代。&lt;/p&gt;&#10;&lt;h3 id="全链路评测和冻结回放回答不同问题"&gt;&lt;a href="#%e5%85%a8%e9%93%be%e8%b7%af%e8%af%84%e6%b5%8b%e5%92%8c%e5%86%bb%e7%bb%93%e5%9b%9e%e6%94%be%e5%9b%9e%e7%ad%94%e4%b8%8d%e5%90%8c%e9%97%ae%e9%a2%98" class="header-anchor"&gt;&lt;/a&gt;全链路评测和冻结回放回答不同问题&#10;&lt;/h3&gt;&lt;p&gt;全链路评测回答“这个版本能不能用”。冻结回放回答“变化从哪里产生”。&lt;/p&gt;&#10;&lt;p&gt;冻结回放会保存某个节点的完整输入，固定 Prompt、候选和依赖，只替换模型或推理参数。如果冻结输入仍然漂移，问题更可能在模型或运行时；如果冻结后稳定、全链路却不稳定，就应检查上游状态。&lt;/p&gt;&#10;&lt;p&gt;同一实验也需要重复运行。除了均值，还应观察最差轮次、方差和变化样本交集。一直失败的样本容易定位；偶尔正确、偶尔自信做错的样本更值得警惕。&lt;/p&gt;&#10;&lt;h2 id="六推理优化要分清-prefill-和-decode"&gt;&lt;a href="#%e5%85%ad%e6%8e%a8%e7%90%86%e4%bc%98%e5%8c%96%e8%a6%81%e5%88%86%e6%b8%85-prefill-%e5%92%8c-decode" class="header-anchor"&gt;&lt;/a&gt;六、推理优化要分清 prefill 和 decode&#10;&lt;/h2&gt;&lt;p&gt;一个 LLM 请求大致有两个阶段：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prefill：处理整段输入，建立 KV cache 或模型状态&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;decode：逐 token 生成输出，过程更串行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;上下文、候选和示例过长，主要增加 prefill；输出理由太长、反复 repair，主要增加 decode 和调用次数。优化前先拆开这些指标，不然很容易在错误的阶段花时间。&lt;/p&gt;&#10;&lt;h3 id="prefix-cache-只节省共享前缀的-prefill"&gt;&lt;a href="#prefix-cache-%e5%8f%aa%e8%8a%82%e7%9c%81%e5%85%b1%e4%ba%ab%e5%89%8d%e7%bc%80%e7%9a%84-prefill" class="header-anchor"&gt;&lt;/a&gt;Prefix cache 只节省共享前缀的 prefill&#10;&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://docs.vllm.ai/en/v0.15.0/features/automatic_prefix_caching/" target="_blank" rel="noopener"&#10; &gt;vLLM 的 Automatic Prefix Caching 文档&lt;/a&gt;明确说明，APC 会复用相同前缀的 KV cache，从而跳过共享部分的 prefill，但不会减少新 token 的 decode 时间。&lt;/p&gt;&#10;&lt;p&gt;它更适合长公共前缀、多轮对话，或者对同一文档的重复查询。如果瓶颈是长输出或重复调用，prefix cache 的帮助有限。&lt;/p&gt;&#10;&lt;p&gt;Prompt 的排列也会影响缓存命中。稳定的系统指令、schema 和公共规则可以放在前面，动态事实与候选放在后面。不过这个建议仍需在具体运行时上验证。Prefix cache、推测解码、模型架构和并发调度可能互相影响，任何组合都不能只凭单项基准上线。&lt;/p&gt;&#10;&lt;h3 id="mtp-和推测解码"&gt;&lt;a href="#mtp-%e5%92%8c%e6%8e%a8%e6%b5%8b%e8%a7%a3%e7%a0%81" class="header-anchor"&gt;&lt;/a&gt;MTP 和推测解码&#10;&lt;/h3&gt;&lt;p&gt;普通自回归解码一次只确定一个 token。推测解码先草拟多个 token，再由目标模型一次验证。经典的 &lt;a class="link" href="https://proceedings.mlr.press/v202/leviathan23a.html" target="_blank" rel="noopener"&#10; &gt;Speculative Decoding&lt;/a&gt; 使用接受/拒绝采样保持目标模型的输出分布，因此草拟模型不会直接替代目标模型。&lt;/p&gt;&#10;&lt;p&gt;MTP 使用模型自带的 multi-token prediction head 预测后续 token。vLLM 的 &lt;a class="link" href="https://docs.vllm.ai/projects/speculators/en/stable/user_guide/algorithms/mtp/" target="_blank" rel="noopener"&#10; &gt;MTP 文档&lt;/a&gt;也把它归在 speculative decoding 中。&lt;/p&gt;&#10;&lt;p&gt;评估 MTP 时至少要记录：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;draft acceptance rate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mean accepted length&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;inter-token latency&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;request throughput&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;P50 / P95 latency&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;端到端质量指标&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;接受率高不等于服务一定更快。草拟和验证本身也有计算成本；高并发下，普通 decode 已经能组成较大的 batch，MTP 的相对收益可能缩小。&lt;/p&gt;&#10;&lt;h3 id="并发不是越大越好"&gt;&lt;a href="#%e5%b9%b6%e5%8f%91%e4%b8%8d%e6%98%af%e8%b6%8a%e5%a4%a7%e8%b6%8a%e5%a5%bd" class="header-anchor"&gt;&lt;/a&gt;并发不是越大越好&#10;&lt;/h3&gt;&lt;p&gt;vLLM 使用 PagedAttention 和连续批处理提高显存利用率与吞吐。&lt;a class="link" href="https://arxiv.org/abs/2309.06180" target="_blank" rel="noopener"&#10; &gt;PagedAttention 论文&lt;/a&gt; 讨论了如何减少动态 KV cache 的碎片和重复保存，从而容纳更有效的 batch。&lt;/p&gt;&#10;&lt;p&gt;但 batch 增大后，每一步 decode 会有更多序列竞争计算和内存带宽。&lt;code&gt;max-num-seqs&lt;/code&gt;、客户端并发和吞吐之间通常不是单调关系，需要逐档压测。&lt;/p&gt;&#10;&lt;p&gt;排查服务瓶颈时，可以先做这样的判断：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;队列高：检查调度容量、限流或服务副本&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prefill 高：检查上下文、候选数量和前缀复用&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;decode 高：检查输出长度、MTP 和重复调用&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GPU 不忙但流程慢：检查网络、串行节点和任务编排&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;GPU 利用率本身说明不了请求是否高效。它需要和队列、延迟、吞吐、KV cache 使用量一起看。&lt;/p&gt;&#10;&lt;h2 id="七一次结果需要保存哪些版本"&gt;&lt;a href="#%e4%b8%83%e4%b8%80%e6%ac%a1%e7%bb%93%e6%9e%9c%e9%9c%80%e8%a6%81%e4%bf%9d%e5%ad%98%e5%93%aa%e4%ba%9b%e7%89%88%e6%9c%ac" class="header-anchor"&gt;&lt;/a&gt;七、一次结果需要保存哪些版本&#10;&lt;/h2&gt;&lt;p&gt;模型版本只是复现条件的一部分。结果还会受到检索索引、标签集合、参考数据、策略配置、Prompt、采样参数和运行时版本影响。&lt;/p&gt;&#10;&lt;p&gt;对外部依赖，可以先规范化 JSON，再计算内容哈希；一次任务只引用不可变的快照 ID 和哈希，不在执行中途重新获取可能变化的数据。&lt;/p&gt;&#10;&lt;p&gt;我现在会把一次 LLM 实验看成下面这个元组：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;span class="lnt"&gt;9&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;run = (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; code_commit,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; model_and_runtime,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; prompt_version,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; decoding_config,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dependency_snapshot,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; evaluation_dataset,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; random_and_request_metadata&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;少了其中一项，复现失败时都可能说不清原因。即使温度设为 0，也不要假设系统绝对确定。并行归约、批处理顺序、服务版本和上游自然语言状态仍可能产生差异。&lt;/p&gt;&#10;&lt;p&gt;运行配置可以进入版本控制，密钥不可以。可复现实验和 secret 管理是两件事。&lt;/p&gt;&#10;&lt;h2 id="八通用-prompt-不应该保存本地政策"&gt;&lt;a href="#%e5%85%ab%e9%80%9a%e7%94%a8-prompt-%e4%b8%8d%e5%ba%94%e8%af%a5%e4%bf%9d%e5%ad%98%e6%9c%ac%e5%9c%b0%e6%94%bf%e7%ad%96" class="header-anchor"&gt;&lt;/a&gt;八、通用 Prompt 不应该保存本地政策&#10;&lt;/h2&gt;&lt;p&gt;领域示例经常不只是在教模型怎样推理，还可能暗中携带业务政策。直接删掉示例，模型失去的也许不是语言能力，而是决策边界。&lt;/p&gt;&#10;&lt;p&gt;更清楚的拆法是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;通用推理层：怎样阅读事实、比较候选、处理冲突&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;领域知识层：常见概念、关系和表达方式&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;本地政策层：允许的边界、例外规则和风险阈值&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;推理方法可以复用，政策应显式配置和版本化。所谓泛化，也需要在新的标签集合、独立标注和不同输入分布上验证。把特定词汇从 Prompt 里删掉，只能说明文本变得更抽象，不能说明系统更通用。&lt;/p&gt;&#10;&lt;h2 id="以后再做类似系统我会先检查这些"&gt;&lt;a href="#%e4%bb%a5%e5%90%8e%e5%86%8d%e5%81%9a%e7%b1%bb%e4%bc%bc%e7%b3%bb%e7%bb%9f%e6%88%91%e4%bc%9a%e5%85%88%e6%a3%80%e6%9f%a5%e8%bf%99%e4%ba%9b" class="header-anchor"&gt;&lt;/a&gt;以后再做类似系统，我会先检查这些&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;正确答案不在候选里时，系统是否会明确停止？&lt;/li&gt;&#10;&lt;li&gt;模型返回的是稳定 ID，还是重新生成标签名称？&lt;/li&gt;&#10;&lt;li&gt;schema 合法后，是否还有领域校验？&lt;/li&gt;&#10;&lt;li&gt;中间节点传递的是受控状态，还是会漂移的摘要？&lt;/li&gt;&#10;&lt;li&gt;Critic 是否知道具体要检查哪类错误？&lt;/li&gt;&#10;&lt;li&gt;自动做错和转人工是否使用不同门槛？&lt;/li&gt;&#10;&lt;li&gt;能否冻结任意节点输入，单独回放模型与运行时？&lt;/li&gt;&#10;&lt;li&gt;性能数据是否拆开 queue、prefill、decode 和调用次数？&lt;/li&gt;&#10;&lt;li&gt;每次实验能否还原代码、模型、Prompt、依赖和评测集？&lt;/li&gt;&#10;&lt;li&gt;通用方案是否在新的数据分布上验证过？&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;一个月前，我更关注模型能不能给出正确答案。现在我更在意，当模型给出答案时，系统有没有足够证据决定自动接受、转给人工，或者承认信息不足。这个问题没什么神秘的，却决定了 LLM 能不能进入真实流程。&lt;/p&gt;&#10;&lt;h2 id="延伸阅读"&gt;&lt;a href="#%e5%bb%b6%e4%bc%b8%e9%98%85%e8%af%bb" class="header-anchor"&gt;&lt;/a&gt;延伸阅读&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://openai.com/index/introducing-structured-outputs-in-the-api/" target="_blank" rel="noopener"&#10; &gt;Introducing Structured Outputs in the API&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://arxiv.org/abs/2307.03172" target="_blank" rel="noopener"&#10; &gt;Lost in the Middle: How Language Models Use Long Contexts&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://arxiv.org/abs/2303.17651" target="_blank" rel="noopener"&#10; &gt;Self-Refine: Iterative Refinement with Self-Feedback&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://arxiv.org/abs/2310.01798" target="_blank" rel="noopener"&#10; &gt;Large Language Models Cannot Self-Correct Reasoning Yet&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://proceedings.mlr.press/v202/leviathan23a.html" target="_blank" rel="noopener"&#10; &gt;Fast Inference from Transformers via Speculative Decoding&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.vllm.ai/en/v0.15.0/features/automatic_prefix_caching/" target="_blank" rel="noopener"&#10; &gt;vLLM Automatic Prefix Caching&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://arxiv.org/abs/2309.06180" target="_blank" rel="noopener"&#10; &gt;Efficient Memory Management for Large Language Model Serving with PagedAttention&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item></channel></rss>