起因:不是“要调优”,而是被线上bug逼到墙角
那是个周三下午,我们刚给「Claude Code」插件上线了 v1.2 版本——主打“更懂 SQL 语义”,加了 3 条新 prompt 规则、2 个字段类型约束示例。不到 4 小时,DBA 老张甩来一条报错截图:
[ERROR] PostgreSQL: WHERE user_id = NULL → invalid syntax
奇怪的是,本地跑 50 次全绿;CI 流水线里 HumanEval SQL 子集得分还涨了 2.1%;日志里只零星出现,复现率稳定在 3.2%(后来发现是用户删掉 prompt 里某句“请勿生成 NULL 比较”的瞬间触发的)。
我们第一反应是 prompt 不够“狠”。于是开始疯狂迭代:
- 第1版:加
-- 严禁使用 '=NULL',必须用 IS NULL - 第3版:改成
IF field IS NULL THEN ... ELSE ... END IF的强制模板 - 第17版:甚至把 PostgreSQL 的
IS [NOT] DISTINCT FROM语法都塞进 system message…
结果呢?A/B 测试跑完,v1.2 新 prompt 的 SQL 首次可用率反降 8%,编辑率从 39% 涨到 47%。更讽刺的是,运维小哥泡咖啡路过,随口问:“你们看过用户删 prompt 的行为数据没?昨天有 217 人手动删了‘请严格遵循字段类型’那行。”
那一刻我后背一凉——我们盯着模型输出的 token,却对用户怎么 撕 它、改 它、扔 它一无所知。
💡 关键转折点:线上 bug 不是模型能力问题,而是人机协作断点。当错误无法稳定复现时,别急着调 temperature,先去查「用户放弃生成前最后删了哪段 prompt」。
我们立刻拉出埋点表,发现一个扎心事实:编辑率 >15% 的会话中,73% 的用户在生成前手动清空了整个 context 示例块。原来他们根本不想看“参考样例”,只想喂个表名,拿条能跑的 SQL。

建议方向:把“故障驱动”换成“行为驱动”。把以下三类信号设为一级监控指标:
sql_validity_flag(执行是否报错)prompt_edit_ratio(用户删/改 prompt 字符数 / 原 prompt 总长)abandon_after_3s(点击生成后 3 秒内关闭弹窗)
它们比任何离线 benchmark 都诚实——用户不会骗你,但会默默删掉你不该写的那行 prompt。
搭建闭环:别搞花哨架构,先让数据流跑通
我们最初设计的监控链路像交响乐团:前端埋点 → Kafka → Flink 实时清洗 → DataDog 告警 → Slack 机器人推送。结果第一次真实告警,延迟 12 分钟 37 秒。而 DBA 已经手动修完第 3 条报错 SQL。
痛定思痛,砍掉所有“实时”幻想。现在生产环境的数据链路就三步:
// 前端埋点(精简到极致)
window.analytics.track('code_generate', {
prompt: truncate(prompt, 200), // 防敏感信息,但保留关键字段
model_version: 'claude-3-haiku-20240307',
role_tag: getUserRole(), // 'backend', 'analyst', 'pm'
session_id: getLocalSessionId()
});
→ 后端记录 Claude 响应 + 元数据(耗时、input_tokens、output_tokens)
→ 用户操作日志(onEdit, onDelete, onCopy, onSkip 事件)
所有原始日志走 S3 归档,每天凌晨 2 点由 Lambda 触发聚合脚本,写入 ClickHouse 表:
CREATE TABLE claude_behavior_daily (
session_id String,
edit_ratio Float32,
abandon_after_3s UInt8,
sql_validity_flag UInt8,
dt Date
) ENGINE = MergeTree() ORDER BY (dt, session_id);
血泪教训:
- DataDog 告警延迟高,是因为它要等所有 pipeline 组件 flush buffer;而 S3+Lambda 是“存完即算”,5 分钟粒度下,99% 的异常当天就能定位。
- 成本从每月 $1,200 降到 $120,省下的钱买了 3 台测试数据库。
- 更重要的是:A/B 平台直接读 ClickHouse 表,实验配置和效果分析在同一个 SQL 里完成,再也不用跨 4 个系统导数据。
✅ 记住这个公式:
prompt → 行为 → 指标三段数据必须能用session_id串起来。其他都是装饰。
A/B测试设计:别拿“模型版本”当实验组,要拆解决策点
我们翻车最惨的一次 A/B,是把 v1.2 和 v2.0 当成两个黑盒对撞。跑了 7 天,p-value 卡在 0.11,置信度 89% ——差 1% 就不敢上线。
后来把 Claude Code 的决策链拆开,发现它其实只做三件事:
- 读上下文(截多长?2k 还是 4k tokens?)
- 决定随机性(temperature=0.3 还是 0.7?)
- 包装输出(加不加注释?注释写多细?)
于是我们做了正交实验:
| 变量 | Level A | Level B | 关键观测指标 |
|---|---|---|---|
context_window | 2048 tokens | 4096 tokens | edit_ratio, abandon_after_3s |
temperature | 0.3 | 0.7 | WHERE 1=1 出现率, NULL in WHERE 错误率 |
output_format_hint | 无 | -- 注释说明逻辑 | onCopy 率, sql_validity_flag |
结果令人震惊:temperature=0.7 在文案生成里创意分+15%,但在 SQL 场景下,冗余条件 WHERE 1=1 激增 37%,且 user_id = NULL 类错误翻倍——因为模型在“不确定字段是否可为空”时,用 1=1 兜底了。

建议方向:SQL 类任务,永远优先保确定性(temperature ≤ 0.4),宁可少点“聪明”,不能多点“脑补”。
自适应调优:不是动态换模型,而是动态换“提示策略”
上线自适应 prompt 前,我们试过 LSTM 预测用户编辑意图:收集 2 周标注数据(开发自己标了 1,842 条会话),训练模型,F1 0.79。但上线后发现:规则引擎响应更快、更稳、更好 debug。
现在生产环境跑的是纯规则:
# 每次生成前实时计算
edit_ratio = get_sliding_window_edit_ratio(session_id, window=5)
abandon_flag = get_abandon_flag(session_id)
if edit_ratio > 0.15:
prompt += "\n-- 请严格遵循以下字段类型:user_id(INT), status(ENUM), created_at(TIMESTAMP)"
elif edit_ratio < 0.03 and abandon_flag:
prompt = f"输入表名:{table_name}\n输出SQL:" # 砍掉所有示例、注释、约束
else:
prompt = original_prompt # 保持原样
运维同事验收时说:“这代码我 grep 一下就懂,比看 PyTorch 模型图清爽多了。”
踩坑实录:
- LSTM 模型上线后延迟 120ms,而规则引擎 <50ms;
- 某天用户反馈“为什么删了示例还给我加注释?”,我们
grep -r "output_format_hint"30 秒定位到配置漏更新; - LSTM 模型出错?得翻 tensorboard、查特征工程、重训……
🚨 真相:对 LLM 工具链而言,“策略自适应”比“模型自适应”更靠谱——业务指标(如编辑率)本身就是最好的 prompt 调节器。
效果验证:别只看准确率,盯住“省了多少人工时间”
技术同学最爱提 BLEU、HumanEval、SQL-Eval 分数。但我们最终说服老板的,是这张表:
| 指标 | 上线前 | 上线后 | 变化 | 折算价值 |
|---|---|---|---|---|
| SQL 人工修正率 | 41% | 19% | ↓22% | DBA 每周少救火 11 次 |
| 单次生成平均耗时 | 4.7min | 2.4min | ↓2.3min | 团队 12 人 × 22 天 = 月省 326 小时 |
首次生成可用率(不编辑直接复制) | 28% | 63% | ↑35% | 运营需求文档新增条款:“此 SQL 需 Claude 生成” |
避坑提醒:
- 我们曾用 HumanEval-SQL 跑出 82.3 分(+12%),但线上编辑率反而升了 5%——因为 benchmark 里全是理想字段名(
user_id,order_date),而真实业务里是t_user.uid,t_order.create_tm,模型在 benchmark 里“装懂”,在线上露馅。 - 真正的“信任阈值”是
首次生成可用率:用户愿意不改就复制,才代表真的省力。

建议方向:把技术语言翻译成业务语言。比如:
❌ “BLEU 提升 12%”
✅ “DBA 每周少处理 11 条报错 SQL,相当于释放 0.8 个 FTE”
给后来者的三条土办法
最后分享我们团队血泪总结的三条“土办法”,不用学算法,明天就能用:
土办法1:每天早会 5 分钟「最惨 top3 prompt」复盘
- 导出昨日
edit_ratio最高的 3 条 prompt(带 session_id 和用户角色) - 产品讲“为什么运营要删这行”,开发讲“为什么这句约束导致 NULL 比较”,QA 讲“为什么 DBA 改了字段类型但没同步到 prompt”
- 比开周会高效,且问题当场闭环
土办法2:Prompt 末尾加 [DEBUG_INFO: {session_id}]
- 出问题时,DBA 直接
grep "DEBUG_INFO:" app.log,30 秒定位完整链路 - 我们省掉 80% 的“你当时点的哪个按钮?”“你输的什么表名?”这类无效沟通
土办法3:永远保留 baseline_branch
- Git 里建个分支叫
prompt-baseline,内容就是 Claude 官方文档里抄的第一行:You are a helpful SQL assistant. - 所有优化都基于它做 diff。当新人问“为什么加这行注释?”,直接
git diff baseline_branch——锚点在,判断才有依据。

LLM 工具不是魔法棒,是把人从重复劳动里解放出来的杠杆。而杠杆支点,从来不在模型参数里,而在你敢不敢直视用户删掉的那行 prompt。
毕竟——
用户删掉的,才是你真正该写的。