如何构建一套面向真实业务的模型能力评测框架
最近 Kimi K3 模型发布了。我想验证一下,它在我们真实的数据可视化业务中到底能做到什么程度。
我们现在已经在使用 Codex、Claude Code 等 AI Coding 工具,所以这次测试不能只回答“Kimi K3 会不会写前端”或者“能不能生成一个 3D Demo”。真正需要回答的是:和目前的开发方式相比,它能不能完成那些实际消耗我们时间的工作,能不能减少需求澄清、上下文准备、视觉微调、测试和返工。
但模型更新越来越频繁。如果每出来一个新模型,都临时找几个 Prompt、跑几次代码、人工看一下截图,再手工写一份报告,这件事本身就会消耗很多时间,而且不同批次的结果也无法比较。
所以这次我没有只做一次 Kimi K3 测试,而是开始开发一个可重复运行的评测项目 vis-agent-bench。目标是把真实 Case、模型调用、过程记录、自动验收、人工评审和报告生成串起来。后面模型升级以后,修改模型配置就可以重新跑。
这里记录一下这个框架是怎么设计的,以及实际运行以后发现了哪些问题。

先确定我们测的到底是什么
一开始最容易犯的错误,是把模型能力理解成一次回答的质量。
在真实开发中,最后结果实际上由很多部分共同决定:
实际交付能力
= 模型
+ CLI / 客户端 / API
+ 可使用的工具
+ 权限和网络
+ 提供给它的上下文
+ 需求反馈过程
+ 测试与验收环境
同一个模型放在不同的 CLI 里,能读取的文件、能否调用终端、是否支持浏览器、会话能否恢复都可能不同。使用 Claude Code 调第三方模型时,还要确认实际 Provider 和返回的模型,不能只相信命令行里的模型别名。
因此框架中的评测对象不是一个模型名称,而是一个 ModelProfile。它要记录模型版本、运行工具、Provider、CLI 版本、权限、联网状态、Token 和费用来源、超时、重试方式以及隔离等级。
最终报告比较的也是这些完整组合。例如:
GPT 模型 + Codex CLI + workspace-write + 联网
Kimi K3 + Kimi Code + noninteractive-auto + 联网
GLM / DeepSeek + Claude Code + auto permission
DeepSeek + Pi + 指定工具白名单
如果这些条件没有记录,最后很难判断一次失败是模型不行、工具不行,还是运行配置不对。
Case 必须来自真实开发瓶颈
最初我准备从现有图表组件库里选几个需求,例如产业链双向树、一个存量交互 TODO,再加一个页面截图还原。我还花了不少时间整理这些候选。
第二天早上通勤路上,我通过语音和 ChatGPT 聊了几句怎么测模型。它很快把问题拉回到了真正的目标:我们不是要证明模型能写一个组件,而是要判断它能不能解决真实开发中的高成本问题。
这几句对话几乎推翻了我前一天的 Case 设计。我当时甚至觉得自己有点傻乎乎的:为什么不早点直接和 GPT 聊?前一天做了不少工作,但方向本身没有讨论透,后面做得再快也是浪费。
这个过程对我的触动很大。以前容易把 AI 当成执行工具,需求想得差不多以后再让它干活。实际上在任务定义、目标判断和方案选择阶段,更应该先跟它不断讨论。它不一定每次都对,但它可以快速挑战我的假设,让我更早发现自己已经走偏。
需求讨论和确认太重要了。自己一个人闷头设计,很容易把“方便执行”误认为“值得执行”。以后遇到这种方向还没有完全想清楚的任务,我会先和 AI 多聊几轮,把目的、判断标准和可能的反例聊透,再开始建设。
这次 ChatGPT 给出的 Case 模板,帮助我确定了一个很重要的原则:如果需求本身很容易,测试结果再好,也回答不了真实业务能否提效。
一个普通图表、少量 CSS 或简单交互,现在很多模型都能快速完成。这类任务适合作为开发阶段的 smoke case,用来验证整个流程能不能跑通,但不应该成为判断模型业务价值的主 Case。
正式 Case 应该从过去真正消耗过团队时间的工作中提取。我们最后选择了:
- 一个从真实运营项目中抽取的 3D 因子关系场景;
- 一个最近开发过的股权关系叙事可视化组件;
- 一个已经上线的市场热力地图还原任务。
3D Case 包含数百节点和大量关系、双层球面结构、3D/2D 模式切换、桌面与触控操作、主题切换、性能统计和 WebGL context lost 恢复。
股权关系 Case 包含复杂层次布局、节点与边标签避让、章节时间线、并行动画、播放暂停、章节跳转、音频和图片素材、组件 API、Resize,以及重复挂载卸载后的资源清理。
这些要求不是为了把题目写得很长,而是它们过去确实会引起讨论、返工或线上问题。
我现在判断一个 Case 是否值得进入正式评测,至少看几件事:
- 是否来自真实产品、代码、提交或历史缺陷;
- 是否包含过去明显耗时的环节;
- 是否能定义业务可接受的质量门槛;
- 是否能记录 Agent 和人工分别花了多少时间;
- 是否能区分模型,而不是所有模型都轻松满分。
如果一个 Case 被多个模型一次通过,人工也几乎不需要介入,它就应该降级成 smoke case。
需求不能太粗,也不能一次给完
Case 确定以后,下一个问题是需求怎么交给模型。
只给一句自然语言,模型可以自由发挥,结果有很大偶然性。失败时也无法判断是能力不够,还是我们根本没有提供必要信息。
但把完整需求、实现细节和验收点一次性全部交给模型也有问题。它会把测试变成照着说明书写代码,而且上下文一多,模型容易忘掉早期的关键约束。
这个问题在我们的实际开发中已经出现过:前面花很多时间和 AI 一起写 Spec、拆任务,文档越来越长;真正一次执行时,还是有不少小地方不符合预期。信息都给了,但重点被稀释了。
因此框架没有把 requirement.md 直接作为唯一 Prompt,而是把需求拆成三层。
第一层是初始业务 Brief。它只包含业务目的、使用者、输入和当前已经确认的少量行为,保留真实项目初期会存在的模糊。
第二层是分阶段反馈。Agent 做完第一版以后,再按照固定剧本追加数据契约、视觉走查、复杂交互、性能和生产化要求。
第三层是内部完整需求和隐藏验收。它包含模型不可见的边界样例、业务规则、视觉容差、性能阈值和评分权重。
一次完整运行大致是:
S0 模糊 Brief
→ S1 需求对齐与 POC
→ S2 布局和视觉反馈
→ S3 动画与复杂交互
→ S4 生产化
→ S5 验收
不同模型收到相同阶段、相同信息和相同反馈,结果才有可比性。
每个阶段还要求 Agent 更新一个简短的 requirement-ledger.yaml,只记录已经确认的要求、设计决策、假设和待确认问题。这个文件用于检查模型后面有没有忘掉前面的要求,不能代替代码和测试证据。
这里要测的不是模型能记住多少文字,而是它能否在需求不断增加时,自己压缩上下文并保住真正重要的约束。
Runner 负责把不同 AI 工具收敛成同一流程
目前几个 AI 工具的命令行方式差异很大。
Codex 使用 codex exec,Kimi Code 使用非交互 --prompt,Claude Code 使用 --print,Pi 使用 --mode print。它们的会话恢复、事件格式、权限参数、费用上限和 Token 数据都不一样。
框架为每个工具实现一个 Adapter,但对上层暴露同一套生命周期:
detect
→ prepare
→ preflight
→ start_session
→ send_stage
→ checkpoint
→ resume_session
→ collect
网页设置页和 CLI 最终都生成同一份 RunSpec。它包含 Case、模型、Provider、权限、联网、预算、超时、输入附件和停止条件。网页只是配置入口,不能再写一套独立运行逻辑。
无人值守运行时还要提前处理两个问题。
第一个是工具审批。白名单内的低风险操作自动执行,白名单外直接拒绝并记录,不能让 Agent 在半夜停下来等人点确认。
第二个是业务澄清。Agent 如果缺少关键信息,应把问题写进 Requirement Ledger。标准回归模式由 Runner 提供固定答复;只有无法安全继续时才停止,不能无限等待。
长程测试必须支持断点续跑
这次实际运行后,我个人感受最强烈的一点,就是断点续传太重要了。它不是后续优化,而是模型自动化测试的基础能力。
复杂 Case 一次可能运行几个小时。有些模型会触发五小时额度限制,有些阶段会因网络、Provider 限流或 CLI 异常失败。如果每次中断都从头运行,前面已经完成的需求分析、代码、Token 和时间会全部浪费。
因此评测流程不能只在整个 Run 结束时保存结果,而要在每个阶段都形成可恢复的 checkpoint。至少需要保留:
- 已经完成的阶段和验收结果;
- Agent 当前 workspace;
- 原生 CLI Session 或可恢复的阶段摘要;
- 失败阶段的 Prompt、日志和错误原因;
- 当前运行使用的模型、权限和版本,避免恢复时混入另一套配置。
现在每个 Run 都保留阶段状态、workspace 和原生 Session。额度恢复后执行:
npm run bench:case -- --resume-run <run-id>
Runner 只执行未完成阶段,不重跑已经通过的部分。等待额度恢复的时间也不计入新的运行窗口。
我现在对长程 Agent 流程的要求是:每一步中断以后都应该能够接着执行。做不到这一点,测试规模一上来,Token 和自然时间的浪费会非常严重。
隔离和日志决定结果是否可信
有些 Case 是从我们已经完成的项目中提取的。如果直接把原代码库交给 Agent,它很可能搜索到现成实现,评测就失去意义。
所以框架会先通过 Fixture Builder 生成脱敏起始工程:
- 排除
.git、依赖、缓存、构建产物和答案文件; - 只做让起始工程可编译的清理,不提供布局和交互答案;
- 扫描已知答案文件名、实现特征和 canary;
- 执行基线 build、typecheck 和 test;
- 为所有输入生成文件哈希和 manifest。
目前为了先把流程跑起来,使用的是独立目录加 CLI Sandbox 的文件级软隔离。它可以防止误改源仓库,也能证明工作区中没有复制答案,但不能从操作系统层阻止进程读取主机上的其他目录。
因此当前 Run 必须明确标记:
file-isolated-development
leaderboard_eligible = false
以后如果要做正式排行榜,需要升级到容器、虚拟机或专用低权限用户,只挂载当前 Run 的 workspace。
日志也不能只保存模型最后一句“已经完成”。每个阶段都要留下:
- 实际执行的脱敏命令和环境;
- 原始 stdout、stderr 和归一化事件;
- 阶段前后的文件树和 Git diff;
- Requirement Ledger 和 checkpoint;
- 构建、测试、截图和性能结果;
- Session、超时、权限拒绝和 Provider 错误。
这些日志后来确实解决了很多问题。
例如 Pi 的 JSON 事件会在长工具调用中反复携带完整消息,最终触发 Node.js 字符串长度上限。我们根据日志把它改成普通 print 模式,并为单阶段输出设置硬上限。
还有模型运行到一半额度耗尽的情况。如果没有阶段日志和状态文件,我们甚至无法判断应该从哪里继续。
自动验收和人工评审必须分开
一次 Run 的验收分为几层:
Build / Typecheck / Test
→ DOM、Canvas、WebGL 和交互断言
→ 截图、性能和资源释放
→ 业务规则
→ 人工视觉与业务评审
能够确定判断的部分尽量自动化。例如数据契约是否满足、节点是否重叠、边是否穿过节点、章节跳转状态是否一致、重复挂载后是否残留监听器,这些都应该由程序检查。
但自动脚本不能可靠判断动画手感、视觉层级、信息密度和业务表达是否舒服。最终是否愿意交给业务方使用,仍然需要人工看真实页面。
我们第一次完整跑完 3D Case 后,模型从 S0 推进到了 S4,构建、类型检查和测试也通过了。打开页面以后仍能看到选中态箭头过大、局部关系拥挤、2D ego 视图接近 hairball 等问题。
这次 Run 可以证明模型能独立完成复杂 POC,不能证明业务已经接受。
评测框架还需要防止 Agent 修改裁判。有一次 Agent 为了完成修订测试,改了原有测试脚本。它未必是故意作弊,但基线脚本一旦可修改,绿色结果就没有意义。
现在 Fixture 原有的 build、typecheck、test 配置和 scripts/*.mjs 都会记录哈希并受到保护。Agent 可以新增独立测试,不能改写基线。
门禁自己同样会出错。另一次运行中,所有构建和测试都通过了,模型只是把 limitations.md 写进了 docs/,平台却把整个阶段判成失败。后来检查日志才确认这是 checkpoint 协议不明确,不是模型失败。
所以报告必须区分:
- 模型或产物失败;
- Provider、额度和 CLI 失败;
- Harness 自身失败;
- 证据缺失,暂时无法判断。
不做这个区分,评测框架本身会制造错误结论。
后处理是模型开发流程的一部分
股权关系 Case 第一轮完成后,纯文字反馈很难说清楚视觉差异。
例如我们实际想要的是:进入章节以后,当前叙事相关节点成为画面中心,同时出现章节说明卡、字幕和时间线。模型实现的却可能只是把全图其他元素统一淡化。功能上都可以叫“聚焦”,实际效果差异很大。
如果因为视觉结果不理想就从头重跑,已经完成的代码和 Token 都浪费了。真实开发也不会这么做。
这也是我这次得到的另一条重要经验:模型生成结束以后,必须允许不断追加后处理。
模型很可能不会一次满足需求,尤其是视觉、动画和交互细节。人需要看实际结果,再通过 Prompt、截图和补充约束进行指导。我把这个过程理解成针对生成产物的“微调”:它不是训练模型参数,而是在保留已有代码的基础上,用一轮轮真实反馈让结果继续收敛。
如果框架只支持“提交初始 Prompt,然后等待最终答案”,它测到的仍然只是 one-shot 生成能力。真实业务更关心的是,第一版不符合预期以后,这个 Agent 能不能低成本地继续修改,能不能记住原来的要求,又会不会在修一处时破坏另一处。
因此框架增加了 Visual Feedback Revision:
选择一个已完成 Run
→ 保留其 workspace
→ 输入 feedback.md 和参考图片
→ 先做视觉理解记录
→ 定向修改
→ 回归与人工对照
Revision 是一个新的子 Run,保存父 Run ID、补充反馈、参考图片、代码变化和前后证据。它不会覆盖原结果,也不会丢掉原来的实现。后续如果还有新反馈,可以继续基于当前结果追加 Revision,而不是把任务退回起点。
R0 阶段要求 Agent 先区分图片中的可观察事实、自己的推断和无法确认的内容;R1 才修改代码;R2 再运行构建、测试和视觉验收。
这个功能不只适合可视化。任何需要在已有产物上追加产品反馈、测试缺陷或设计参考的任务,都可以使用相同机制。
所以后处理能力也应该进入模型评测:需要记录追加了几轮反馈、每轮人工准备了多少上下文、模型修复了多少问题、引入了多少回归,以及最终还需要人重做多少内容。这些数据比“第一次生成用了几分钟”更接近真实开发效率。
最终报告要回答人效,而不是代码量
评测框架最后要回答的是:某个模型是否值得在团队中推广。
主基线不能只选纯人工手写。我们现在真实的开发方式已经是工程师配合 Codex 和主力 GPT 模型,所以候选模型应该与当前 AI 协作方式比较。
时间需要分桶记录:
- 需求澄清;
- 查找代码、整理数据和准备上下文;
- 首版 POC 走查;
- 视觉、布局、文案和交互微调;
- 功能错误和回归修复;
- 最终业务与代码验收;
- Agent 运行和等待时间;
- 外部接口、数据和业务确认的等待时间。
只有结果先通过 P0 业务质量门槛,才计算有效提效:
Effective Speedup
= 当前 AI 协作基线的 Human Touch Time
/ 候选模型路径的 Human Touch Time
同时还要展示 Accepted Delivery Rate。一个模型运行十次只成功一次,即使那一次人工投入很少,也不能说明它适合自主交付。
报告中还应该保留首次可评审 POC 时间、需求保持率、反馈轮数、微调时间、返工比例和每次成功交付的费用。
Token 和费用拿不到时就写 unavailable。不同 CLI 的遥测能力不同,不能为了图表完整自己估算一个精确数字。
目前的结果和下一步
现在 vis-agent-bench 已经能够用 Codex、Kimi Code、Claude Code 和 Pi 执行指定 Case,支持阶段日志、断点恢复、视觉反馈 Revision,并生成中文 HTML 和 Markdown 报告。
实际运行已经证明,多个模型可以完成复杂可视化 POC,部分 Run 能通过构建和流程门禁。但人工视觉验收和同条件人效对比还没有全部完成,所以目前不应该做“哪个模型全面最好”的排名。
这次框架开发让我确定了几条后续会继续遵守的规则:
- 先找真实瓶颈,再设计 Case;
- 模糊需求按真实节奏逐步披露,不用一句 Prompt,也不一次塞完整答案;
- 长程任务的每个阶段都必须支持断点续跑;
- 第一版生成只是开始,后处理和多轮 Revision 必须成为正式流程;
- 先过业务质量门槛,再谈速度和费用;
- 模型失败、Provider 失败和 Harness 失败必须分开;
- 所有结论都能回到具体 Run、输入、日志、代码版本和验收证据;
- 视觉与业务判断保留人工责任,但把反馈做成可复用的 Revision 和回归用例。
后面新模型再出来时,不需要重新临时组织一轮测试。配置模型、选择 Case、运行、人工补充视觉评分,再生成同口径报告即可。
对我来说,这套框架让“这个模型在我们的实际工作中有没有用”变成一个可以重复验证的问题。