大模型落地到具体业务里最先撞上的墙往往不是算力、不是并发而是那句模型答得不对。同一个通义千问接口有人写三行 prompt 就能拿到能直接入库的结构化结果有人改了两天还是时好时坏。差别不在文笔在于有没有把 prompt 调试当成一件工程活来干——先定义什么叫对再控制变量再记录再回归。这篇东西就是我这些年反复踩坑后整理出来的一套流程怎么搭一个够用的评测台怎么写出结构化的 prompt 骨架怎么调采样参数怎么定位那些明明写了却不听话的怪问题。不管你是刚接上 API 想跑通第一个 Demo 的新手还是已经在维护几十条 prompt 模板的老手下面这些内容都能直接抄走改改就用。1. 先把调试这件事拆开看1.1 prompt 调试的本质是控制变量实验很多人改 prompt 的方式是跑一次看着不对删掉一句、加一句话再跑一次又不对再加一句请务必一定要非常重要。改到最后 prompt 变成八百字模型反而更懵。这不是调试这是碰运气。真正的调试是一次只动一个变量。你手上有至少这么几个可调的旋钮system 指令、任务描述、约束条件、示例数量、示例内容、输出格式定义、temperature、top_p、max_tokens、是否开启思维链。一次动两个以上你就无法判断是哪个改动带来的收益甚至可能一个好改动被一个坏改动抵消误以为是这个方向没用。我自己的习惯是维护一张迭代记录表每行一次实验版本号、改动点只写一个、评测集得分、典型失败样本、结论。这张表看起来笨但它是唯一能在两周后让你说清为什么现在是这个版本的东西。没有这张表三个月后接手的人很可能就是你自己只能整段重写。还有一个容易被忽略的点prompt 调试的收益是有上限的。当你的评测集显示错误集中在模型确实不知道这个知识或者这个任务需要多步外部检索时再改措辞就是浪费时间该做的是补知识库、拆任务、加工具调用。判断这件事的依据只有一个——分类统计失败样本看错误类型的分布。分布告诉你瓶颈在哪而不是靠感觉。1.2 三类常见失败模型不行、prompt 不行、评测不行出了badcase第一反应总是prompt 写得不好。实际上失败来源至少分三类处理方式完全不同。第一类是模型能力边界。比如要求它从一段没有标注日期的合同里推断签署年份或者做需要精确算术的多步计算这类任务超出当前模型的能力范围prompt 怎么写都只是提高一点点命中率。识别方法很直接把同样的任务用最直白的描述给模型如果它连听懂任务都做不到那就是能力问题。第二类是 prompt 表达问题。任务模型能做但你没把约束说清楚或者约束之间互相冲突。典型的就是既要求输出简洁又要求详细说明理由模型只能二选一或者折中结果两头不讨好。第三类最隐蔽评测方式有问题。你的判分脚本用字符串完全匹配去校验模型输出而模型多输出了一句以上是分析结果全判错。你以为是模型不行其实是评测太死板。我见过最典型的案例是一个抽取任务判分时用json.loads直接解析模型输出带了 json 的代码块围栏解析全失败得分 0团队差点把整个方案推翻实际上只要加一行围栏清洗准确率就从 0 跳到 92%。所以调试的第一个动作不是改 prompt而是把失败样本捞出来人工看二十条归类。二十条样本花不了半小时但能省掉两天瞎改。1.3 通义千问的几处脾气要先摸清通义千问这个系列模型有几处特性不知道的话会在调试初期吃暗亏。一是它对 system 指令的遵循度跟具体版本强相关。同一个 prompt在轻量版和旗舰版上的表现差异可能很大轻量版更容易忽略长 system 里的后半段约束。所以你的 prompt 在轻量版上跑得通别默认在旗舰版上也一样反过来更常见。做选型时一定用两三个不同规格的模型各跑一遍评测集看性价比曲线而不是先用大的跑通了再说。二是它对输出格式的响应。当你明确要求 JSON 时通义千问支持通过参数约束返回 JSON 对象这比自己写请只输出 JSON要可靠得多。但要注意开了这个模式不等于字段一定对它只保证语法合法不保证 schema 符合你的预期字段名写错、漏字段、类型不对依然会发生所以解析后仍要做字段校验。三是思维链开关。较新的版本支持在调用时控制是否输出思考过程。开着的确能提升复杂推理的表现但会带来两个副作用token 消耗上升以及输出里混入思考段落导致你提取答案时正则匹配失败。我的做法是训练/复杂任务开线上高频简单任务关并且解析层永远做一次取最终答案的兜底逻辑。四是 chat template 的格式。如果你用开源权重自己部署必须严格按模型自带的对话模板拼 prompt多一个换行、少一个结束符都可能让效果掉一截。用托管接口就没这个烦恼但如果你要做本地化部署先用官方模板跑通再动手改别自己发明格式。2. 动手前先搭评测台没有度量就没有调试2.1 一个够用的小评测集怎么攒我最反对的做法是边改边看因为人脑记不住十次实验的结果而且人眼对小样本的偏好会严重误导判断——你刚好看到的三个例子可能完全不代表整体分布。评测集不用一上来就搞几千条。我的经验是30 到 50 条真实样本就足够支撑第一轮迭代但必须满足两个条件——来自真实业务分布而不是自己编的覆盖至少 3 到 5 种典型场景和 3 种以上的边界情况。具体攒法从线上日志、用户提问、客服工单里随机抽。抽的时候刻意分桶比如一个分类任务先按类别分层抽保证每个类别都有样本一个抽取任务先按文档长度分桶短中长各来几条。边界情况优先选这几类空输入、超长输入、格式混乱的输入、包含多个答案的输入、以及与任务无关的闲聊输入。这几类占了线上 badcase 的一大半。评测集要做版本管理且冻结。一旦用于对比实验就不要在中途往里加样本否则前后得分不可比。要扩充就新开一个版本号全量重跑。这个纪律听起来小事但实际项目里十有八九是因为中途偷偷换了评测集导致大家对着两个不可比的数字吵半天。另外补一句小评测集的分数波动大30 条样本里错 1 条就是 3.3 个百分点。所以看分数的时候别盯着小数点后一位关注的是从 62% 到 78%这种量级的差异以及具体失败样本的变化。3 个点的浮动很可能只是随机性。2.2 打分维度与判定标准单一准确率对很多任务不够用。我一般拆成四层来看。维度考察什么判定方式常见误区格式合规输出能否被程序解析脚本硬校验pass/fail用模糊匹配代替结构校验内容正确关键信息是否命中标准答案比对或人工标注只看关键词不看语义完整度该抽的字段是否都抽到字段级覆盖率统计与正确率混算成一个数冗余度是否输出了不该有的内容长度统计 人工抽检完全忽略导致回答啰嗦格式合规必须脚本硬校验这是我的底线。因为你最终是要把结果喂给下游系统格式不过关等于没产出。内容正确建议用标准化后的精确匹配 人工抽检的组合如果预算允许再用一个更强的模型做裁判打分但裁判 prompt 本身也要调别把裁判当成真理。人工标注这块要说个实话标注一致性比标注量重要。两个人标同样的 30 条如果有 5 条判断不一致说明你的判定标准写得不够细。先把标准细化到什么情况算对、什么情况算部分对再去标。我一般会在评测集旁边附一份判分说明写明边界情况的处理方式两三页纸但能省掉大量返工。2.3 用一个脚本把批量跑通有了评测集就得能一键跑完。手动一条条贴进对话框是不现实的也无法记录参数。下面这个脚本结构我用了很多年改改就能用import json, os, time from openai import OpenAI client OpenAI( api_keyos.environ[QWEN_API_KEY], base_urlos.environ[QWEN_BASE_URL], # 兼容模式接口地址 ) def run_one(prompt_tpl, item, params): user prompt_tpl[user].format(**item) resp client.chat.completions.create( modelparams[model], messages[ {role: system, content: prompt_tpl[system]}, {role: user, content: user}, ], temperatureparams[temperature], top_pparams[top_p], max_tokensparams[max_tokens], seedparams.get(seed), ) return resp.choices[0].message.content def evaluate(prompt_tpl, dataset, params, tag): rows [] for i, item in enumerate(dataset): t0 time.time() try: out run_one(prompt_tpl, item, params) err None except Exception as e: out, err , repr(e) ok_fmt check_format(out) # 你自己实现的格式校验 ok_content check_content(out, item.get(gold)) rows.append({ idx: i, input: item, output: out, fmt_pass: ok_fmt, content_pass: ok_content, err: err, cost_ms: int((time.time() - t0) * 1000), }) with open(fruns/{tag}.jsonl, w, encodingutf-8) as f: for r in rows: f.write(json.dumps(r, ensure_asciiFalse) \n) n len(rows) print(f[{tag}] fmt{sum(r[fmt_pass] for r in rows)/n:.3f} fcontent{sum(r[content_pass] for r in rows)/n:.3f}) return rows几个实操要点。把每次运行的完整结果落盘成 jsonl不要只存分数。因为分数只告诉你变差了落盘的原始输出才能告诉你为什么变差。我通常按版本号_时间戳命名跑完顺手把 diff 也存下来。给评测集固定 seed同时给你的运行也传 seed该参数在接口里受支持时。大模型采样有随机性同一个 prompt 跑两次结果可能不同固定 seed 能让对比更公平。但别指望 seed 能让结果完全确定分布式推理下仍可能有细微差异所以关键结论最好跑两次确认。把耗时也记下来。prompt 改了之后准确率涨了两个点但平均输出长度翻倍、成本涨了三倍这在业务上往往是不可接受的。成本、延迟、质量三角调试时必须同时看。3. 结构化 prompt 的骨架3.1 角色、任务、约束、格式四件套写 prompt 最稳的结构就是这四块顺序也基本固定先说身份和背景再说要做什么再说不能做什么最后说输出成什么样。身份设定这块要克制。很多人喜欢写你是一位拥有二十年经验的资深专家实测下来这类空泛的身份描述收益很小甚至有时会诱导模型输出更多套话。真正有用的身份信息是领域和视角比如你是电商售后规则审核员判断依据只有随附的规则条款这种身份带来的约束是实质性的。任务描述要具体到可执行。对比一下分析用户评论的情感和判断评论是正面、负面还是中性如果同时包含对商品和物流的评价只针对商品部分判断。后者才叫任务描述前者只是任务名称。约束条件是最容易被写废的部分。三条原则能写成可判定的规则就别写成形容词约束之间不能互相打架数量不超过五条。超过五条模型对后面几条的遵循度会明显下降这时候应该做的是拆任务把 prompt 分成两段调用而不是硬塞。输出格式部分给出一个完整的、可以直接照抄的样例比描述十句都管用。样例要包含每一个字段不要用等等其他字段同理这类省略模型会真的按省略来。提示如果你发现某条约束总是被忽略先把它从段落里提出来单独成行用必须禁止这类强词开头。位置也很关键放在任务描述之后、输出格式之前的约束遵循度通常高于埋在长段落中间的约束。3.2 few-shot 示例怎么挑、怎么排示例的作用不是教模型知识而是定调——告诉它输出的粒度、语气、格式、边界处理方式。所以示例的挑选标准不是典型而是覆盖。我的做法是3 到 5 个示例其中至少一个覆盖边界情况。比如一个信息抽取任务两个正常示例一个信息缺失时输出 null的示例一个输入与任务无关时输出空数组的示例。后者往往比前两个更重要因为模型在没见过的情况下倾向于硬编造一个答案。示例的排列顺序有影响。最后一个示例的示范效应最强所以把最希望模型模仿的那个放最后。同时注意示例之间的一致性——如果示例 A 的字段顺序是 a,b,c示例 B 是 b,a,c模型会困惑输出格式的波动会变大。还有一个反直觉的经验示例不是越多越好。超过 6 个之后边际收益迅速下降而 token 成本和过度模仿的风险上升。我遇到过示例给太多导致模型把示例里的具体值也抄进输出的情况尤其是示例里的数字、日期这类字面量。排查时先看输出里有没有出现示例中的值这是最快的判断方法。如果任务本身有很强的格式要求示例可以省直接换成一份完整的输出模板让模型填空。省下来的 token 用来放输入内容更划算。3.3 让模型先想后答的分寸思维链不是万能药。它在多步推理、需要校验、需要做取舍的任务上收益明显在简单的分类、抽取、改写上收益小甚至会带来副作用。副作用主要体现在三方面输出变长导致成本和延迟上升思考内容混进结果导致解析出错以及模型在思考过程中说服自己给出一个错误的结论——这在有倾向性的问题里特别明显。我的判断标准很简单如果这个任务一个熟练的人需要想一下才能答对就开如果需要脱口而出就关。开了之后务必在 prompt 里明确要求先分析最后用固定标记引出答案例如要求最终答案放在结论之后的行。解析时只取标记之后的内容前面的思考过程丢弃。这样既拿到了推理收益又不影响下游解析。对于支持独立控制思考开关的模型版本优先用接口参数控制而不是靠 prompt 里写请不要思考。后者经常失效因为它是在跟模型的后训练偏好较劲不如直接从机制上关掉。3.4 结构化输出的硬约束要求模型输出 JSON可靠性的层级大概是这样的接口参数级别的格式约束 prompt 里给完整 schema 样例 prompt 里描述字段。能往上走一层就走一层。即使开了接口级的 JSON 模式我仍然会在 prompt 里给一份字段说明写清每个字段的类型、取值范围、缺失时的表示方式。原因是参数只保证语法合法不保证业务语义对。字段说明里最值得花时间的是这三句缺失信息统一输出 null不要输出未知暂无N/A。数组字段若无内容输出 []不要省略该字段。不要在 JSON 之外输出任何解释性文字。然后在解析层做三重兜底先尝试直接json.loads失败则剥离 json 围栏和前后多余文本再试仍失败则取第一个{到最后一个}之间的内容再试。三重兜底能吃掉九成以上的解析失败。剩下的那部分把原始输出存下来作为 badcase 进评测集。4. 参数与调用层的那些坑4.1 采样参数不是玄学是有明确分工的temperature 和 top_p 是两套不同的截断机制同时调大或调小容易互相干扰。我的习惯是只调一个另一个保持默认或设为中性值。具体建议抽取、分类、格式转换这类任务temperature 设 0 到 0.3让输出尽量收敛创意写作、头脑风暴设 0.7 到 1.0。top_p 在 temperature 已经调低的情况下保持 0.8 左右即可不必要再压到 0.1。有个细节值得说temperature 设为 0 并不等于完全确定。后端批处理和浮点误差仍可能带来差异所以做严格对比实验时除了固定 seed还要对同一配置跑两次看两次结果的分歧率。如果分歧率超过 5%说明这个任务的输出本身对采样太敏感应该回头看 prompt 是不是约束不够。max_tokens 的设置经常被忽略。设得太小输出被硬截断JSON 不完整导致解析失败设得太大不影响成本成本按实际生成算但会让某些模型在达到长度后仍试图凑内容输出一些废话。我的做法是先用一个宽裕的值跑评测集统计输出的长度分布取 P99 的 1.5 倍作为线上值同时在 prompt 里加一句输出不要超过 N 字。4.2 长文本、截断与上下文预算上下文快到上限时的行为很多人没测过。输入加上输出逼近模型上限时有的情况是报错有的是静默截断输入有的是输出到一半停住。这三种情况在你的代码里表现完全不同必须提前测。我的处理方式是在调用前估算 token 数用模型的 tokenizer 或粗略按字符数折算中文大约 1 字 ≈ 0.6 到 0.7 个 token估个大概就行超过阈值就做处理而不是让接口去决定。处理策略按任务定摘要类任务做分段摘要再合并抽取类任务优先保留与目标字段相关的段落问答类任务先做检索筛选。还有一个高频坑把长文档放在 system 里。system 内容在很多实现中会被缓存和复用但一旦你每次请求的 system 都不同缓存失效成本和延迟都会上升。长文档应该放 user 消息里system 保持稳定。4.3 system 与 user 的分工分界线我总结成一句话system 放不变的规则user 放变化的数据。规则包括角色、任务定义、约束、输出格式数据包括本次要处理的具体文本、本次的用户提问、本次的参数。这样分的好处是同一套 system 可以复用于成千上万次请求方便做缓存也方便做 A/B 测试——你只需要换 system 版本user 侧的数据完全不动。反过来把每次变化的数据写进 system 是最常见的坏味道。它会让你的 prompt 无法做版本对比也让缓存形同虚设。我接手过一个项目system 里拼了用户昵称和订单号导致每条请求的 system 都不一样缓存命中率接近零改完之后平均延迟降了一半多。还有一点别在 user 消息里重复 system 的约束。重复不会提高遵循度反而会让模型认为这条约束特别重要过度反应。比如在 system 里说输出简洁user 里又说不要啰嗦模型可能直接砍到只剩关键词丢失必要信息。5. 一次完整的迭代实录5.1 需求拆解与初版 prompt拿一个具体场景走一遍从商品评价里抽取评分态度、问题类型、是否要求退货三个字段输出 JSON。输入是几十到几百字的自由文本。第一步拆解任务我发现三个字段的判断难度差别很大态度判断最简单问题类型需要归类到预定义的六类是否要求退货最微妙因为我想退和这个能退吗完全不同。所以约束里必须明确后者的判定标准。初版 prompt 我写得很朴素就三段任务、字段说明、一个示例。system: 你是电商评价信息抽取助手。从用户评价中抽取结构化信息。 字段定义 - attitude: 用户对商品的态度取值 positive / negative / neutral - issue_type: 问题类型取值 quality / logistics / description_mismatch / size / service / none - refund_intent: 是否明确要求退货取值 true / false 只输出 JSON不要输出任何其他内容。 user: 评价内容{text}跑 40 条评测集格式合规 100%内容全对只有 62%。捞 badcase 看错误集中在三处把物流慢但东西好判成 negativeissue_type 在涉及多个问题时只填一个把能退吗判成 refund_intenttrue。5.2 迭代记录表第一轮改动只动一处在字段定义里加多问题处理规则。版本改动点格式合规内容全对主要失败类型v1初版100%62%多问题只填一个疑问句误判退货v2attitude 改为仅针对商品本身100%71%疑问句误判退货v3issue_type 允许多值数组100%74%退货意图判定的粒度问题v4refund_intent 增加三种边界说明100%86%长文本尾部信息漏抽v5增加信息缺失输出 null示例100%89%少量长文本仍漏v2 的改动很关键把态度判断的范围从整条评价收窄到商品本身物流不满不再污染商品态度。这一条规则写清楚直接涨了 9 个点。这也印证了前面说的——约束要写成可判定的规则仅针对商品本身是可判定的准确判断态度不是。v3 把 issue_type 从单值改成数组同时更新了示例。这一步付出的代价是下游解析要改但收益是消除了多个问题只能填一个的系统性错误。类似的结构性改动一定要在早期做越晚改成本越高。v4 是收益最大的一步。我把 refund_intent 的判定标准写成三条出现我要退申请退货已经退了等明确动作表述判 true。出现能退吗可以退吗退货流程是什么等询问表述判 false并在 reason 字段说明是咨询。仅表达不满但未提及退货判 false。加完之后这一类错误基本清零。经验凡是取值只有两三个、但边界模糊的字段都值得单独写一段判定标准加反例。5.3 上线前的回归与灰度v5 之后我做了三件事才敢上线。一是换一批没参与调试的样本做验证。前面 40 条已经被我反复看着改多少有过拟合的风险。我从新一批日志里抽了 30 条只跑一次结果 87%比评测集低 2 个点在可接受范围内。差的这 2 个点我看了样本是两条超长评价尾部信息被忽略。二是做参数敏感性测试。固定 prompt把 temperature 在 0、0.3、0.7 三档各跑一遍看内容准确率的变化。如果从 0 到 0.7 掉了 10 个点说明 prompt 的约束太松靠采样收敛在撑这种 prompt 上线后遇到稍有不同的输入就会崩。三是加线上兜底。解析失败、字段缺失、取值不在枚举范围内一律走降级路径转人工或者返回默认值并打点。同时在日志里记录 prompt 版本号这样出问题时能立刻定位是哪个版本、什么时候开始出问题。灰度阶段我一般放 5% 到 10% 流量跑够样本量再看指标。看的不只是准确率还有输出长度分布、平均耗时、解析失败率。这几个指标里解析失败率是最灵敏的报警信号它通常在准确率下降之前就先抬头。6. 常见问题与排查技巧6.1 指令明明写了模型就是不执行这是最高频的困惑。排查顺序建议按这个来。先看指令位置。埋在长段落中间的约束遵循度就是低。把它提到段首或单独成行往往立刻生效。再看指令是否可判定。回答要专业这种没法判定使用行业术语不使用口语词如挺好的不错就可判定。不可判定的指令模型只能猜猜的结果就是时好时坏。然后看指令之间有没有冲突。我见过一个 prompt 同时要求输出尽可能完整和控制在 100 字以内模型在长输入上就开始随机取舍。用脚本扫一遍你的约束把互相拉扯的找出来删掉或者明确优先级。最后看数量。超过五条强约束后面的基本形同虚设。这时候正确的做法是拆成两次调用第一次做抽取第二次做格式化。多一次调用增加的那点延迟比反复调试省下的时间划算得多。还有一个偏门但有效的技巧把最重要的约束放在 user 消息的最后一行。因为模型对靠近生成位置的上下文更敏感。这个技巧在长输入场景下效果明显。6.2 同一条输入两次结果不一样先确认这是不是问题。创意类任务本来就该有差异正文类任务如果差异体现在措辞上、语义一致也可以接受。真正要修的是语义层面的漂移比如一次判 positive 一次判 negative。定位方法把 temperature 降到 0固定 seed跑同一条输入 5 次。如果还有语义漂移问题在 prompt通常是某个字段的判定标准不明确模型在边界上摇摆。如果降 temperature 后稳定了说明是采样参数问题回去调参数。另一个常见原因是输入本身的歧义。比如这个价格有点高但还能接受态度到底是 neutral 还是 negative取决于你的业务定义。这种情况不是模型的问题是标注标准的问题。解决办法是在 prompt 里显式写出这类边界情况的判定规则而不是指望模型猜。6.3 JSON 解析失败的花式原因按出现频率排序我遇到的大致是这几种。围栏包裹就是输出带了 json。这个最常见解析前统一剥离。前后有多余文字比如好的以下是抽取结果。要求模型只输出 JSON 能缓解但不彻底解析层做截取是必需的。单引号、尾逗号、未转义的引号。这类是模型生成的语法问题严格 JSON 模式下很少见非严格模式下常见。用宽容一点的解析器比如支持尾逗号的解析库能吃掉一部分。输出被截断。检查 finish_reason如果是长度导致的截断说明 max_tokens 不够或者模型在 JSON 前后写了很多废话。后者要在 prompt 里明确禁止。字段类型不对。比如要求数组给了字符串要求布尔给了 true 字符串。这个只能靠解析后的 schema 校验来发现用 pydantic 之类的工具做一层校验不通过就走重试或降级。注意加如果解析失败就重试的逻辑时一定要设重试上限我一般 2 次并且重试时把 temperature 调低。否则在模型确实无法产出合法格式的情况下会陷入无限重试把成本和延迟都拖垮。6.4 幻觉编造了输入里没有的信息抽取类任务里幻觉最典型的表现是补全——输入里没写品牌输出里给了个品牌输入里没说数量输出里给了个 1。根治手段是在 prompt 里给出明确的缺失值约定并且配上示例。前面说的缺失统一输出 null配合一个输入信息不全时输出 null的示例能消掉大部分。第二个手段是要求模型引用原文片段。让它在输出里带上一个 evidence 字段填支持该结论的原文。这一招对抑制编造效果很好因为你等于要求它为每个结论找到出处找不到出处时它更倾向于输出 null。副作用是输出变长成本上升看任务重要性权衡。第三个手段是在解析层做交叉校验。比如抽出来的日期检查是否在原文字符串里出现过做一下归一化再比。没出现过的标记为可疑走人工复核。这条规则很粗暴但实测能拦下相当一部分编造。6.5 排查速查表现象优先检查常见根因处理动作约束不生效指令位置与数量埋在长段落、超五条提前、拆任务输出格式乱是否给了完整样例只有描述没有样例补一个完整样例JSON 解析失败finish_reason被截断 / 有围栏加大 max_tokens、清洗结果忽好忽坏temperature 与 seed采样太散降温、固定种子编造信息缺失值约定无 null 规则加约定 evidence长输入漏抽输入位置关键信息在尾部分段处理或调序成本突增输出长度分布思考过程未关关思考、限字数示例内容被抄输出里的字面量示例过度模仿减少示例、换值域7. 把 prompt 当代码管7.1 目录结构与版本号prompt 存在聊天记录里、存在文档里是团队协作最大的浪费。我的做法是把它当成代码文件放在仓库里prompts/ extract_review/ system_v5.txt user_v5.txt schema_v5.json examples_v5.jsonl meta.yaml # 版本、作者、评测分、变更说明 tests/ extract_review/ dataset_v3.jsonl # 冻结的评测集 check.py # 格式与内容校验meta.yaml 里必须记录这次版本改动的内容和评测结果。改动说明要写成增加了 refund_intent 的三种边界判定而不是优化 prompt。前者半年后还能看懂后者等于没写。版本号我习惯用整数递增不用语义化版本。因为 prompt 的改动很难判断是新增功能还是修复问题硬套语义化版本只会让命名变成负担。整数递增配合变更说明够用了。7.2 让回归跑在提交前只要有评测集和一键脚本把回归挂到提交环节是顺理成章的。我的阈值设置比较松内容准确率下降超过 3 个点就拦下来格式合规率下降超过 1 个点就拦。太严会导致每次微小改动都要走特批反而让人绕过流程。回归脚本除了跑分数还要输出逐条对比这次跑的结果和上次跑的结果哪些样本从对变错、哪些从错变对。从对变错的样本是重点逐条看完再决定是否合入。我遇到过准确率持平但有三条从对变错、三条从错变对的情况看起来是等价交换实际看过之后发现变错的都是长文本说明新版本在长输入上有隐患最终没有合入。7.3 线上监控与 prompt 的老化模型服务会升级你的 prompt 不会自动跟着升级。我遇到过接口侧模型版本更新后一个原本 90% 的 prompt 掉到 78%原因是新版本对输出格式的遵循方式有细微变化。所以模型版本号要显式锁定不要用会漂移的别名同时在服务端记录每次请求实际使用的版本。监控指标我建议至少这几个解析失败率、字段缺失率、输出长度 P50/P99、平均耗时、以及一个抽样的人工评分。前四个是自动的能覆盖绝大多数突发问题人工评分每周抽几十条用来发现缓慢的质量下滑。还有一个容易被忽视的监控输入分布漂移。你的 prompt 是针对某类输入调的如果线上输入分布变了比如新增了一个商品类目评价的表述方式完全不同准确率会悄悄下降而所有技术指标都正常。做法是定期对输入做聚类看有没有新的簇出现。这个动作成本不高但能提前发现很多问题。最后分享一个我个人坚持的习惯每次大改 prompt 之前先把当前版本原样备份一份命名带上last_known_good。调试是探索性的经常会走进死胡同有一个确定的回退点能让你放心大胆地试。踩过的坑里有一半是因为改到一半发现不如以前而以前那版已经被覆盖掉了。
阅读完成 · 觉得有帮助?