两个 PoC 都做了,A 组说"新方案快 40%",B 组说"更慢"。两份表格数字都对,谁也说服不了谁,最后拍板靠职级——两周人月换来的是两份互相抵消的意见。
问题不在技术,在评估没被设计。评估是工程活动,需要判据、对照组、口径和记录,缺一项,结论只能算个人主张。
1. 评估失效的三个根源
| 根源 | 现场表现 | 修法 |
|---|---|---|
| 判据事后才定 | 先跑 PoC,出数再想"算不算好" | 评估卡先写,数字后填 |
| 对照组缺失 | 只测新方案,不与现方案同条件比 | 现方案永远进对照组 |
| 来源不可复核 | 结论引用没人能重跑的截图 | 记脚本、参数、样本 |
第三条最隐蔽。一张"QPS 从 1200 到 3800"的截图,三个月后既没人能证明也没人能反驳,却会被下次选型当前提引用。不可复核的数字比没有数字更危险。
2. 判据先写:评估卡
评估卡把"想证明什么"在开工前锁死,避免出数后重新定义成功。
// eval-card.yaml —— 开工前冻结,改动记原因
question: 检索层是否改自研封装
decide_by: 2026-12-05 // 到期无结论按"不换"处理
criteria:
- {id: p95, pass: 不劣于 baseline*1.05, weight: 0.35}
- {id: ops_cost, pass: 年维护人月 <= baseline, weight: 0.30}
- {id: migration, pass: 无状态调用点 >= 80%, weight: 0.35}
fail_if: // 命中任一即失败,不再加权
- 停机超一个维护窗口;索引重写且历史无法回溯
| 字段 | 必写原因 | 常见错法 |
|---|---|---|
decide_by |
无截止日的评估会一直评下去 | 只写"本季度内" |
pass |
阈值须是可比的表达式 | 写"性能明显提升" |
fail_if |
一票否决要在看数据前定 | 事后追加,救偏好方案 |
权重不是算总分,是逼人在开工前说出"最在意什么"。每项都 0.2 的卡说明问题还没想清。
3. 对照组与基线
| 对照组 | 回答的问题 | 设置要点 |
|---|---|---|
| 现状基线 | 换不换 | 原样跑,不优化不调参 |
| 同族竞品 | 选哪个 | 各由熟悉的人配置 |
| 最小实现 | 这层是否必要 | 常被忽略,往往能砍一层 |
| 人工基线 | 值不值得自动化 | 人做一遍计时,含复核 |
"新方案 8ms"没有意义,除非知道现方案在同机器、同数据、同并发下是多少。基线要同期同环境;跨期时逐项列出内核、参数、数据量差异并标注未受控项。另一条反直觉:给现方案公平的调优机会——"老方案没调过所以慢"常是伪结论,它把调优任务包装成迁移。
4. PoC 的规模陷阱
| 维度 | 小规模 | 规模化后 | 分界提示 |
|---|---|---|---|
| 索引/缓存 | 全量进内存,命中近 100% | 换入换出,长尾拉开 | 超可用内存即突变 |
| 锁竞争 | 并发 10 无冲突 | 临界区排队 | 看吞吐随并发的拐点 |
| 句柄 | 单机撑得住 | fd、连接池先到顶 | 用 ulimit -n 反推 |
// 固定吞吐注入,避免客户端先成为瓶颈
wrk -t4 -c64 -d60s --latency -R 2000 http://TARGET/ENDPOINT
// 分界点探测:并发逐档抬升,看拐点与 P99
for c in 8 16 32 64 128; do wrk -t4 -c$c -d30s --latency http://TARGET/ENDPOINT; done
// 注入跨区延迟
tc qdisc add dev eth0 root netem delay 10ms
外推前先把规模效应人为注入:数据不够大就按比例放大并报系数,延迟太低就注入延迟。报告须写清覆盖区间,否则"性能良好"只能被重做一遍。
5. 测试数据的选择与污染
| 来源 | 偏差 | 合规成本 | 适用 |
|---|---|---|---|
| 生产样本脱敏 | 分布真实 | 高,脱敏破坏特征 | 检索、排序 |
| 生产样本原样 | 分布真实 | 最高,不出生产域 | 只读测量 |
| 合成数据 | 偏乐观 | 低 | 功能与边界 |
| 公开数据集 | 与业务不符 | 低 | A vs B 比较 |
两个必须承认的偏差:脱敏改变分布(掩码改变长度与熵,压缩率和索引选择性都变);合成数据偏均匀(真实数据常是 1% 的键承担 40% 访问)。评估压缩、去重、分词、检索时,脱敏结论都要打折。
// 三切分,留出集只跑一次;否则 B 组就在测试集上被评估
tune = 60% // 允许反复迭代
valid = 20% // 用于选型对比
holdout = 20% // 最终结论,跑完换新;seed 固定 20261201
6. 成本与收益的口径
// 五年总成本,全折人月,避免单位混算
introduce = 接入改造 + 数据迁移 + 双跑期运维
run = 每月运维(巡检、告警处置、补丁)
upgrade = 每年大版本跟进 × 每次人天
exit = 退出成本,通常为接入的 0.8–1.5 倍
total_5y = introduce + run*60 + upgrade*5 + incident*5 + exit
| 成本项 | 常被漏算 | 估算方式 |
|---|---|---|
| 接入 | 监控改造、文档、培训 | 改动点数 × 单点人天 |
| 运维 | 告警噪音、值班负担 | 告警条数 × 处理时长 |
| 故障 | 不熟悉而延长的定位 | 与熟悉度负相关 |
| 退出 | 迁移与双跑 | 引入时就要估,事后必低估 |
收益也要按口径写。"查询快 3 倍"折不成现;"P95 由 800ms 到 260ms,折算每天少等 X 小时"才能进决策表,其余归入前提假设。
7. 不可量化因素:写成前提假设
// 前提假设清单,与卡同页;结论须标依赖哪几条
A1 4 人中 2 人有新栈生产经验 // 支撑 ops_cost 不劣于 baseline
A2 上游两年内不要求双向同步 // 支撑 migration 可接受
A3 不会成为核心链路唯一依赖 // 支撑 exit 成本可承受
失效条件:A1 不足 2 人时,ops_cost 按新人期系数上调
写成假设就可被质询,失效时也能定位哪条结论要重算,而非整份重做。
8. 结论的表达
| 表达方式 | 示例 | 问题 |
|---|---|---|
| 点值 | "P95 快 42%" | 隐含精度,被当精确事实 |
| 区间 + 条件 | "50 万文档下改善 25%–45%" | 可复核,可被下区间检验 |
| 无条件区间 | "改善 25%–45%" | 缺条件,跨场景误用 |
| 判据结论 | "满足全部 pass 项,migration 踩线" | 最适合决策会议 |
结论必须附三个字段:适用条件(规模、并发量级、读写比)、有效期(默认 6–12 个月,超期按当时版本核对)、推翻条件。缺有效期是知识库最常见的债:三年前的基准被当成今天的事实。
9. 可复核性
eval/2026-12-es8/
card.yaml // 冻结版 + 改动原因
env.md // 规格、内核、运行时版本、RTT
dataset.md // 来源、规模、脱敏方式、切分与种子
scripts/ // 压测与采集脚本,含种子
raw/ // 原始输出,不改不删
report.md // 结论 + 区间 + 条件 + 有效期 + 假设依赖
| 检查项 | 合格标准 |
|---|---|
| 环境可重建 | 版本齐全,含易漏内核参数 |
| 数据可获取 | 样本、脱敏脚本、种子都在 |
| 步骤可执行 | 无未注明的手工 GUI 步骤 |
| 原始数据在 | 留原始输出,不只留汇总图 |
| 结论有边界 | 写明适用区间与推翻条件 |
判断标准很朴素:另一个人能否不问你就重跑出同量级数字。缺边界项,复核者仍只能得出"确实有提升"这种用不上的判断。
10. 评估还是直接试
| 情形 | 决策成本 | 试错成本 | 选择 |
|---|---|---|---|
| 可逆、单点、当天回滚 | 高 | 低 | 直接试,事后记录 |
| 成熟社区共识(配置格式) | 极高 | 极低 | 直接用,写进规范 |
| 数据迁移、不可逆 | 中 | 极高 | 必须评估,写退出条件 |
| 跨团队、超一季度 | 中 | 高 | 必须评估 |
判据核心是可逆性:可逆不必评估,要的是记录与回滚;不可逆必须评估,账单在后面。这条能砍掉七成以上"要不要做对比测试"的争论。
11. 同一评估为什么被反复做
| 原因 | 表现 | 修法 |
|---|---|---|
| 结论只在会议纪要 | 新人不知道做过 | 进知识库,带有效期 |
| 没写适用条件 | 场景稍变即失效 | 附区间与条件 |
| 判据没留下 | 只留"选了 A" | 卡与结论同存 |
| 不认前任结论 | 组织问题 | 用记录替代职级背书 |
真正省钱的不是"评估做得快",而是"做一次就够":带判据、原始数据、有效期与推翻条件的记录,复用价值高于结论。
12. 度量
| 指标 | 定义 | 典型量级 |
|---|---|---|
| 评估到决策时长 | 卡冻结到签字 | 2–6 周,超一季说明判据没定 |
| 复现成功率 | 第三方重跑得同量级结论 | 目标 > 70% |
| 结论被推翻比例 | 被后续数据否定 | 10%–25% 属正常 |
量级参照,按自己历史数据定基线。
13. 排错:评估翻车的五种现场
| 现象 | 原因 | 处理 |
|---|---|---|
| 两组结论相反且都"有数据" | 判据事后定,各取有利指标 | 用同一组 pass 项重判 |
| PoC 全胜,上线变差 | 规模未覆盖,基线未调优 | 补分界点测试,重设基线 |
| 复核者跑不出同样数字 | 数据未固定、脚本缺失 | 补 dataset 与 scripts |
| 加权赢家团队不认 | 权重少数人拍定 | 权重须在 PoC 前过评审 |
| 收益漂亮但预算过不了 | 口径只算硬件 | 按五年口径重算 |
加权评分常不是决策工具,而是把已做好的决定包装成量化过程;它的价值在逼出分歧:打分差很远时,问题常不在数字。
14. 边界:正式评估反而是浪费
| 场景 | 判断 | 做法 |
|---|---|---|
| 可逆、单点、当天回滚 | 评估贵于试错 | 直接试,留回滚步骤 |
| 成本极低(一个库、几百行) | 影响小于评估开销 | 先采用后观察,出问题再换 |
| 社区共识且无争议 | 事实问题,非取舍 | 直接用,写进规范 |
| 系统一年内重写 | 投资无法回收 | 只做维持性改动 |
另一端:不可逆的数据结构变更、跨团队契约、五年以上的基础设施选择,无论多简单都值得写一张卡——一页纸的成本,换三年后有人读得懂。
15. 自测
- 两组 PoC 结论相反,除重做测试外,最先该回到哪份材料?
- 为什么"给现方案公平的调优机会"能改变结论方向?
- 小规模结论外推失败,除数据量外还有哪些非线性变化的量?
- 脱敏破坏性能评估有效性,机制是什么?
fail_if为何必须在看到数据之前写?- 记录前四项齐全、结论写"性能提升明显",复核者能得出什么?