跳转到主要内容
这一页是 Coding Agent 把 NiceEval 接入一个项目的执行步骤。前提:niceeval 依赖已经装进项目、niceeval init 已经运行,你是从随包 INDEX.md 进入本页的。用用户的语言与用户交流。所有 API、字段和 CLI 行为以随包文档为准,不要凭训练记忆现编。 编写评估前,按 NiceEval Taste 确定业务判据、充分证据与权重。交付时让读者只读评估正文就能解释通过条件与计分。

第 1 步:探索项目,再和用户确认

这一步决定后面整条路径。先自己读代码探明,把探到的结论列给用户核对,探不到的再提问——不要一上来就抛一串问题,也不要没探就假设。要探明的信息:
  1. 这是个什么 Agent:读 README、package.json 依赖、路由和 agent loop 代码,判断它是用什么写的(AI SDK、LangGraph、OpenAI Agents SDK、Claude Agent SDK、自研 loop……),核心用例是什么(客服?SQL?编码任务?)。
  2. 前端和 Agent 怎么通信:HTTP 还是 gRPC / WebSocket?协议是标准的还是自己实现的——AI SDK UI Message Stream、OpenAI Responses / Chat Completions 这类标准协议,还是 SDK 原生事件流透传,还是用户自定义的 JSON/SSE 帧?这直接决定 Adapter 是用内置的(零映射)还是手写 send(要自己写事件映射)。
  3. 真实目标怎样运行:确认构建或安装命令、启动命令、就绪检查、端口、依赖服务、凭证来源和停止方式。Adapter 只连接目标,不在 send 或评估用例里临时启动一套替代实现。凭证只提供给需要它的运行边界,不写入评估源码、工作区或运行交接。
  4. 后端有没有接 OTel:搜有没有 OTel SDK 初始化、AI SDK telemetry、LangSmith / OpenLLMetry / OpenInference 这类埋点。已经有的话 Tier 2 几乎零成本。
  5. 用户自己有没有做 A/B Test / feature flag:应用里已有变体开关的话,Experiment 的 flags 可以直接透传给它(Tier 3 的现成入口)。
  6. Judge 用什么:语义评估(t.judge(material, definition))要一个与被测 Agent 分离的 Judge 模型,走 OpenAI 兼容协议。问用户手上有哪个服务的 Key、想用什么 Judge 模型。缺 Key 不会静默通过:Judge 断言会记为 unavailable。没有 Judge 配置时,先只写精确 Match。
  7. 是不是 Agent 本体要进 Sandbox:被测对象是 coding agent CLI、或给 coding agent 写的 Skill/Plugin/Hook/MCP server(要在隔离 workspace 里改文件/跑命令)的话,必须走 Sandbox,不能像 HTTP 服务那样直接 send。 默认建议 dockerSandbox({ source: { type: "image", image: "node:24-slim" } })。任务或现有配置已经指定 Provider 时沿用;只有 Provider、Docker 可用性或远程执行需求仍会影响方案时才问。Provider 声明在评估用例或 Experiment 上,没有 CLI flag、项目级默认值或自动探测——见选择 Sandbox Provider。
任务尚未指定接入等级时,向用户介绍接入等级并给出推荐(详见接入等级):
  • Tier 1(只接 send):应用一行不改,全套断言(文本、Judge、多轮、工具、HITL)都在这一档。
  • Tier 2(send + OTel):应用把 OTel span 也发 NiceEval 一份,在 niceeval view 中查看调用瀑布图。已有埋点(第 3 点探到的)就零改动。
  • Tier 3(侵入改造 + flags):把应用内部变体暴露成 flags 做 feature A/B。已有 A/B 开关(第 4 点探到的)就是现成入口。
默认推荐先 Tier 1 跑通,再升 Tier 2——尤其当第 3 点探到应用已有 OTel 时,明确告诉用户「升 Tier 2 只是把 span 多发一份,成本接近零」。Tier 3 只在用户明确要做变体对比时提。 已有明确授权时按探明的形态继续;缺少会改变目标、运行边界、凭证边界或预算的决定时才向用户确认。不要在没读对应页面的情况下直接开始写 Adapter:

第 2 步:配置 Judge

把第 1 步问到的 Judge 服务配上。在 niceeval.config.ts 里用具名 Provider 明确选择协议:
接兼容网关时 baseUrl 必须显式写。 只配 key 不配 baseUrl,NiceEval 打的是官方端点,网关凭据会被发到 OpenAI 并回一句「Incorrect API key provided」——看起来像 key 过期,实际是端点选错了。 三个要提醒用户的点:
  • 配错不会假装通过。 读不到模型或 key、请求超时时,Judge 断言记为 unavailable 并带上原因;网关拒绝请求、返回格式不对时记为 errored。结果里不会把拿不到的分数显示成不通过或零分。
  • 配完先验一次。 用 defineJudge 声明 rubric 和 anchors,再调用 t.judge(material, definition).gate(0.8)。跑完后用 pnpm exec niceeval show --run <run-id> 查看分数,步骤见配置并验证 Judge。
  • 没有用户在场(自治接入)时不要直接跳过 Judge:先看环境里是否已有与所选 Provider 对应的 key。有就验证;没有时先写精确 Match,并在收尾说明 Judge 没有配置。
  • Judge 模型要与被测 Agent 分离,避免同一个模型给自己的输出打分。执行配置从 Experiment 和项目配置的 judgeRuntime 求值;定义与材料见 Judge。

第 3 步:写 Adapter、Experiment 和评估用例

按第 1 步选中的方向读完对应文档后,依次写:
  1. Adapter(agents/*.ts 或用户项目里约定的目录)——用 defineAgent 实现 send,配置走工厂参数,不写死、不读 process.env。契约见 Adapter,API 签名见 Adapter 参考,事件映射见事件参考。两个容易踩的点:端点/模式要选被测系统核心能力的入口,不是最容易跑通的入口——比如被测平台既有「纯 LLM 聊天」又有「连库执行」两种模式,接前者等于评了个底层模型代理,没评到产品本身。evidenceCoverage 必须按实际映射如实声明——只把最终文本映射出来就不要用 completeEvidenceCoverage,声明会影响断言完整性,虚报比保守更糟。
  2. Experiment(experiments/*.ts)——引用上面的 Adapter,声明 model、flags、attempts 等。模型对比写两个实验文件,各自写一个 model。evals: (eval) => boolean 决定每个 Experiment 运行哪些评估用例。文件路径决定 Experiment ID,也决定一条命令能批量运行哪些 Experiment。
  3. 评估用例(evals/*.eval.ts)——先探明这个应用是干嘛的,再写一条贴着它真实功能的评估用例。读它的 README、路由、工具定义或系统提示,找出它的核心用例(客服机器人就问一条真实的客服问题、SQL agent 就给一个真实的查询任务),拿这个用例做第一条评估用例的输入和断言。两类输入都不合格:「你好」这种和应用无关的占位输入,以及「你是什么/你能做什么」这种问被测系统它自己的元问题——那不是用户拿它干活的用例。形式上仍从最小写起:一句输入,t.succeeded() + 一个针对预期回答的内容断言——但最小形式只是调通的脚手架,不是交付标准,收尾前还要满足两条:
    • 断言在被测系统胡编时要会变红。不要断言输入里本来就有的词(问「X 是什么」再断言回答含「X」,被测方复读题目就能通过)。断言预期回答独有的实质内容——具体事实、结构(hasSections())、真实链接(includesUrl()),或用 t.judge(material, definition) 做语义判定。
    • 至少一条负例。喂一个被测系统应该答不了的输入(不存在的表、检索不到的主题),断言它明确说查不到/做不到,而不是编造一个看似合理的结果——对连着真实数据/检索源的 agent,这是最值得先测的失败形态。 写法见编写评估用例,断言与题型见题型与断言,签名见 defineEval 参考。
参数怎么从 Experiment 流到 Adapter、静态配置和每轮动态值怎么分(工厂参数 vs ctx),见接入自己的 Agent。 架构上有两条硬规则,写 Adapter 时不要违反:
  • 不做进程内直调。就算 agent runtime 和评估用例在同一个代码库里,Adapter 也要走 HTTP(或对应传输层),不要把 fetch 换成直接 import 被测函数——原因见接入自己的 Agent 里「为什么不直调」。
  • 评估用例侧不代管被测进程。不 spawn 应用、不另开端口。应用由用户自己按平时的方式启动(pnpm dev 之类),Adapter 连不上时报「先起应用」这类明确的错误,不要自己起服务。

第 4 步:跑通并验证

先用 --dry 确认会跑哪些评估用例、每个跑几次,再正式运行。下面以 pnpm 为例,用户项目用其它包管理器时换成对应的 exec:
人想在浏览器里对比结果时,运行 pnpm exec niceeval view。 按 Coding Agent 反馈闭环完成运行、查看、修改和重跑。需要机器读取时,先执行 pnpm --silent exec niceeval query discover,再发送完整 request。查看方式见查看运行结果。 先按终态分流,再决定是否修改:
  • errored 表示运行本身没跑成,没有得出可以评分的结果。先检查目标服务、端点、凭证、依赖、超时和 Adapter 的错误映射,修好后重新运行。
  • failed 表示运行跑完了,但业务断言没有满足。先查看同一个 Attempt 的断言和证据;被测系统确实答错时,不需要把它改成绿色。
  • 计分制评估跑完后,仍要查看得分和每条断言。总览里显示跑完或通过,不代表拿到了满分。
在已有授权和预算内,主动修好导致 errored 的问题,并只复验受影响的范围。只读请求不修改或重跑。目标服务、端口、凭证、数据库或模型服务等真实外部条件缺失时,明确报告阻塞;不要用临时替代物冒充真实目标已经跑通。 需要在终端查看某个 Attempt 的细节时,先从当前总览复制它的 locator,再用同一个 locator 查看各项内容:
不要从旧输出猜 locator,也不要把另一次运行的源码和这次的执行过程拼在一起当证据。结果只能证明记录下来的内容;partial、unavailable 和 not-recorded 表示信息不全,不等于零分或失败。

第 5 步:收尾,告诉用户做了什么

总结之前先过一遍收尾自检——任何一条不满足就回第 3 步补,不要在总结里含糊带过:
  • 评估用例的输入是被测系统的核心用例,不是问它自己的元问题或占位寒暄
  • 每条内容断言在被测系统复读题目/胡编时会变红(断言的词不是输入里本来就有的)
  • 至少有一条负例(应该答不了的输入,断言它明确说做不到)
  • 有 key 时 Judge 已配置,且在 niceeval show 或 niceeval view 里看到过 Judge 分数。没 key 时总结里说明了
  • Experiment 里声明的 model / flags 确实被 Adapter 消费(没有写了没人读的死配置,也没有编造被测系统不存在的 model 值)
  • 真实目标按项目自己的方式启动并确认就绪,凭证只提供给需要它的运行边界,没有写进评估源码、工作区或交接
  • 至少有一个跑完且不是 errored 的 Attempt;业务失败如实保留,并用同一个 locator 核对分数、断言和证据是否完整
跑通之后先总结,再谈下一步。总结要说清:接了什么被测对象、Adapter、Experiment 与评估用例各在哪、niceeval exp <实验路径>、niceeval show 和 niceeval view 怎么跑、第一次运行的结果是什么样。不要在没被要求的情况下顺手重构用户已有代码,也不要在这几个文件之外新增抽象。

第 6 步:问用户要不要往深了接

总结完之后,把还能往深接的选项列给用户——每一项都说清能做什么、大概改多少代码、买到什么好处,让用户自己选,不要自作主张多做: 共同点也要讲给用户:这些全是给 Adapter 或应用加增量,已写的评估用例一行不用改。三档投入分别买到什么、什么时候值得升级,见接入等级。第 1 步探到应用已有 OTel 埋点的话,瀑布图那条要主动推荐——成本接近零。