调 prompt 最怕的不是改了没效果是改这处、悄悄崩了那处。你为了修 A 问题动了一句话结果 B、C 两类问题的回答跟着变差了自己还没察觉就上线了。我治这个的办法很土但很顶用给 Agent 套一层快照测试——把一批固定输入的输出存成快照每次改完 prompt 重跑diff 一看就知道哪些答案变了。快照测试是个啥借的是前端 snapshot 测试的思路。准备一组代表性输入第一次跑把每条的输出拍照存下来当基准。以后每改一次 prompt/模型/工具重新跑同一批输入把新输出和基准 diff。没变的略过变了的人工看一眼是我想要的改进还是误伤的回归跟评测打分不一样——评测告诉你分多高快照告诉你具体哪几条变了、变成啥样了排查回归特别直观。怎么落import json, os, difflib CASES snapshot/cases.jsonl # 固定输入集 SNAP snapshot/baseline.json # 基准输出 def run_all(): out {} for line in open(CASES): c json.loads(line) out[c[id]] call_agent(c[input]).strip() return out def update_baseline(): # 确认无误后把当前输出固化为新基准 json.dump(run_all(), open(SNAP, w), ensure_asciiFalse, indent2) def check(): # 改完 prompt 跑这个 base json.load(open(SNAP)) cur run_all() changed [] for cid, new in cur.items(): old base.get(cid, ) if old ! new: changed.append(cid) print(f\n {cid} 输出变化 ) for d in difflib.unified_diff(old.splitlines(), new.splitlines(), lineterm): print(d) print(f\n共 {len(changed)}/{len(cur)} 条输出发生变化) return changed几个让它真正好用的细节输入集要覆盖各类问题不是越多越好。我每个意图类别挑 3-5 个代表 case正常问、边界问、容易触发幻觉的问、该转人工的问。几十条精挑的比几百条重复的有用。大模型有随机性输出每次都不完全一样咋办两招压测试用例时把temperature调到 0 减少抖动diff 不要求字符级完全一致可以加一层语义是否一致的宽松判断或人工只看明显变化的那几条别被标点差异淹没。快照不是测对不对是测变没变。它不替代正确性评测。一条 case 一直是错的快照只会显示没变化——所以基准本身得是你认可的好输出垃圾基准只会保护垃圾。一个真实场景我改一句让客服回答更简洁的 prompt跑 check发现 32 条里变了 9 条。8 条确实更简洁了第 9 条——一条怎么退货——被简洁过头把退货必须的7天内、吊牌完整两个关键条件给删了。要不是 diff 标出来这种改好了大部分、漏了一个关键的回归上线后得等用户投诉才发现。说点不好的快照测试有维护成本prompt 大改一版可能几十条全变得逐条确认再更新基准有点烦。所以它适合小步快调大重构时它帮不上太多忙。还有随机性这个老问题再怎么压温度长输出还是会有细微抖动得接受diff 里有噪声靠人去分辨真回归和假变化没法全自动。模型推理我用讯飞星辰 MaaS 现成 API跑快照时把温度压到 0、固定模型版本输出稳定多了diff 噪声小这套测试才跑得顺。你们调 prompt 怎么防回归纯靠人眼看还是有自动化评论区说说你们的做法。
给Agent写快照测试,改一版prompt一眼看出回归
调 prompt 最怕的不是改了没效果是改这处、悄悄崩了那处。你为了修 A 问题动了一句话结果 B、C 两类问题的回答跟着变差了自己还没察觉就上线了。我治这个的办法很土但很顶用给 Agent 套一层快照测试——把一批固定输入的输出存成快照每次改完 prompt 重跑diff 一看就知道哪些答案变了。快照测试是个啥借的是前端 snapshot 测试的思路。准备一组代表性输入第一次跑把每条的输出拍照存下来当基准。以后每改一次 prompt/模型/工具重新跑同一批输入把新输出和基准 diff。没变的略过变了的人工看一眼是我想要的改进还是误伤的回归跟评测打分不一样——评测告诉你分多高快照告诉你具体哪几条变了、变成啥样了排查回归特别直观。怎么落import json, os, difflib CASES snapshot/cases.jsonl # 固定输入集 SNAP snapshot/baseline.json # 基准输出 def run_all(): out {} for line in open(CASES): c json.loads(line) out[c[id]] call_agent(c[input]).strip() return out def update_baseline(): # 确认无误后把当前输出固化为新基准 json.dump(run_all(), open(SNAP, w), ensure_asciiFalse, indent2) def check(): # 改完 prompt 跑这个 base json.load(open(SNAP)) cur run_all() changed [] for cid, new in cur.items(): old base.get(cid, ) if old ! new: changed.append(cid) print(f\n {cid} 输出变化 ) for d in difflib.unified_diff(old.splitlines(), new.splitlines(), lineterm): print(d) print(f\n共 {len(changed)}/{len(cur)} 条输出发生变化) return changed几个让它真正好用的细节输入集要覆盖各类问题不是越多越好。我每个意图类别挑 3-5 个代表 case正常问、边界问、容易触发幻觉的问、该转人工的问。几十条精挑的比几百条重复的有用。大模型有随机性输出每次都不完全一样咋办两招压测试用例时把temperature调到 0 减少抖动diff 不要求字符级完全一致可以加一层语义是否一致的宽松判断或人工只看明显变化的那几条别被标点差异淹没。快照不是测对不对是测变没变。它不替代正确性评测。一条 case 一直是错的快照只会显示没变化——所以基准本身得是你认可的好输出垃圾基准只会保护垃圾。一个真实场景我改一句让客服回答更简洁的 prompt跑 check发现 32 条里变了 9 条。8 条确实更简洁了第 9 条——一条怎么退货——被简洁过头把退货必须的7天内、吊牌完整两个关键条件给删了。要不是 diff 标出来这种改好了大部分、漏了一个关键的回归上线后得等用户投诉才发现。说点不好的快照测试有维护成本prompt 大改一版可能几十条全变得逐条确认再更新基准有点烦。所以它适合小步快调大重构时它帮不上太多忙。还有随机性这个老问题再怎么压温度长输出还是会有细微抖动得接受diff 里有噪声靠人去分辨真回归和假变化没法全自动。模型推理我用讯飞星辰 MaaS 现成 API跑快照时把温度压到 0、固定模型版本输出稳定多了diff 噪声小这套测试才跑得顺。你们调 prompt 怎么防回归纯靠人眼看还是有自动化评论区说说你们的做法。