搜索文章

输入关键词开始搜索

如何构建一套面向真实业务的模型能力评测框架

AI#AI#Agent

最近 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 生成脱敏起始工程:

  1. 排除 .git、依赖、缓存、构建产物和答案文件;
  2. 只做让起始工程可编译的清理,不提供布局和交互答案;
  3. 扫描已知答案文件名、实现特征和 canary;
  4. 执行基线 build、typecheck 和 test;
  5. 为所有输入生成文件哈希和 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 能通过构建和流程门禁。但人工视觉验收和同条件人效对比还没有全部完成,所以目前不应该做“哪个模型全面最好”的排名。

这次框架开发让我确定了几条后续会继续遵守的规则:

  1. 先找真实瓶颈,再设计 Case;
  2. 模糊需求按真实节奏逐步披露,不用一句 Prompt,也不一次塞完整答案;
  3. 长程任务的每个阶段都必须支持断点续跑;
  4. 第一版生成只是开始,后处理和多轮 Revision 必须成为正式流程;
  5. 先过业务质量门槛,再谈速度和费用;
  6. 模型失败、Provider 失败和 Harness 失败必须分开;
  7. 所有结论都能回到具体 Run、输入、日志、代码版本和验收证据;
  8. 视觉与业务判断保留人工责任,但把反馈做成可复用的 Revision 和回归用例。

后面新模型再出来时,不需要重新临时组织一轮测试。配置模型、选择 Case、运行、人工补充视觉评分,再生成同口径报告即可。

对我来说,这套框架让“这个模型在我们的实际工作中有没有用”变成一个可以重复验证的问题。