> ## Documentation Index
> Fetch the complete documentation index at: https://niceeval.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Coding Agent 从零接入项目

> 给 Coding Agent 的完整接入流程：探索项目、与用户确认路径、配置 Judge、写出 Adapter / Experiment / 评估用例并跑通第一个实验。

这一页是 Coding Agent 把 NiceEval 接入一个项目的执行步骤。前提：`niceeval` 依赖已经装进项目、`niceeval init` 已经运行，你是从随包 `INDEX.md` 进入本页的。用用户的语言与用户交流；所有 API、字段和 CLI 行为以随包文档为准，不要凭训练记忆现编。

## 第 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. **后端有没有接 OTel**：搜有没有 OTel SDK 初始化、AI SDK telemetry、LangSmith / OpenLLMetry / OpenInference 这类埋点。已经有的话 Tier 2 几乎零成本。
4. **用户自己有没有做 A/B Test / feature flag**：应用里已有变体开关的话，Experiment 的 `flags` 可以直接透传给它（Tier 3 的现成入口）。
5. **Judge 用什么**：语义评分（`t.judge.autoevals.*`）要一个**与被测 Agent 分离的 Judge 模型**，走 OpenAI 兼容的 `/chat/completions` 协议——OpenAI 官方、DeepSeek、任何兼容该协议的网关都行。问用户手上有哪个服务的 key、想用什么 Judge 模型（没有内置默认模型，必须显式指定）。用户暂时没有 key 也不阻塞：Judge 断言会静默跳过，先用精确断言跑通。
6. **是不是 Agent 本体要进 Sandbox**：被测对象是 coding agent CLI、或给 coding agent 写的 Skill/Plugin/Hook/MCP server（要在隔离 workspace 里改文件/跑命令）的话，必须走 Sandbox，不能像 HTTP 服务那样直接 `send`。默认建议 `dockerSandbox()`，但**要先跟用户确认**——本机/CI 有没有 Docker、要不要 Vercel Sandbox 或其它远程 Provider；用户没有异议就默认走 Docker。Provider 只能写在代码里（Experiment 或 `niceeval.config.ts` 的 `sandbox` 字段），没有 CLI flag，也不会自动探测——见[选择 Sandbox Provider](/docs/zh/tutorials/sandbox-providers)。

探完之后，向用户**介绍接入等级**并给出推荐（详见[接入等级](/docs/zh/explanation/tier)）：

* **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：

| 被测对象                                                    | 去读                                                                                                     |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| 用 Vercel AI SDK（`useChat` 后端）写的应用                       | [内置 Agent 参考](/docs/zh/reference/builtin-agents)：内置 `uiMessageStreamAgent` 无侵入接入，不用手写事件映射                   |
| coding agent CLI（claude-code / codex / bub 等改文件的任务）     | [在 Sandbox 中评测 Agent](/docs/zh/tutorials/sandbox-agent)：要配 `sandbox`，默认 `dockerSandbox()`，先跟用户确认 Provider   |
| 给 Claude Code / Codex 写的 Skill、Plugin、Hook 或 MCP server | [评测 Coding Agent 扩展](/docs/zh/examples/coding-agent-extensions)：同样跑在 Sandbox 里，Provider 确认方式同上              |
| 其它自研 agent loop、LangGraph、OpenAI Agents SDK、已部署 Agent   | [接入自己的 Agent](/docs/zh/tutorials/connect-your-agent) 起步，手写 `send` 的完整教程在[编写 send](/docs/zh/tutorials/write-send) |
| 纯函数、没有独立服务的场景                                           | 先读[接入自己的 Agent](/docs/zh/tutorials/connect-your-agent) 里「为什么不直调」那段，跟用户确认这确实是他们要的边缘用法，再继续                    |

## 第 2 步：配置 Judge

把第 1 步问到的 Judge 服务配上。Judge 走 **OpenAI 兼容的 `/chat/completions`** 协议，在 `niceeval.config.ts` 里配：

```ts theme={null}
import { defineConfig } from "niceeval";

export default defineConfig({
  judge: {
    model: "gpt-5.4-mini",                // 必填：没有内置默认模型
    // 用非 OpenAI 官方的兼容服务（DeepSeek、网关等）时再加这两项：
    // baseUrl: "https://api.deepseek.com/v1",
    // apiKeyEnv: "DEEPSEEK_API_KEY",     // key 从这个环境变量读；不配默认读 OPENAI_API_KEY
  },
});
```

两个要提醒用户的点：

* **key 解析不到时 Judge 断言会静默跳过**（不报错、不记分）——评估用例全绿不代表 Judge 真的跑了。所以配完先跑一条带 `t.judge` 的评估用例，在 `niceeval view` 里确认有 Judge 分数。
* Judge 模型要**与被测 Agent 分离**，避免同一个模型给自己打分。模型解析优先级（单次调用 → 评估用例级 → 全局配置）和三种评分形状见 [Judge](/docs/zh/explanation/judge)，`judge` 字段全集见 [defineConfig 参考](/docs/zh/reference/define-config)。

## 第 3 步：写三件套

按第 1 步选中的方向读完对应文档后，依次写：

1. **Adapter**（`agents/*.ts` 或用户项目里约定的目录）——只填 `defineAgent` 的 `send`，配置走工厂参数，不写死、不读 `process.env`。契约见 [Adapter](/docs/zh/explanation/adapter)，API 签名见 [defineAgent 参考](/docs/zh/reference/define-agent)，事件映射见[事件参考](/docs/zh/reference/events)。
2. **Experiment**（`experiments/*.ts`）——引用上面的 Adapter，声明 `model`、`flags`、`runs` 等。模型对比写两个实验文件，各自钉一个 `model`；`evals: (eval) => boolean` 决定各自运行哪些评估用例。路径只负责 id 和批量运行，报告读取每份快照的 `selectedEvalIds`。
3. **评估用例**（`evals/*.eval.ts`）——**先探明这个应用是干嘛的，再写一条贴着它真实功能的评估用例**：读它的 README、路由、工具定义或系统提示，找出它的核心用例（客服机器人就问一条真实的客服问题、SQL agent 就给一个真实的查询任务），拿这个用例做第一条评估用例的输入和断言，不要写「你好」这种和应用无关的占位输入。形式上仍从最小写起：一句输入，`t.succeeded()` + 一个针对预期回答的内容断言，跑通再加断言密度。写法见[编写评估用例](/docs/zh/tutorials/authoring)，断言与评分见[评分指南](/docs/zh/tutorials/scoring-guide)，签名见 [defineEval 参考](/docs/zh/reference/define-eval)。

参数怎么从 Experiment 流到 Adapter、静态配置和每轮动态值怎么分（工厂参数 vs `ctx`），见[接入自己的 Agent](/docs/zh/tutorials/connect-your-agent)。

架构上有两条硬规则，写 Adapter 时不要违反：

* **不做进程内直调**。就算 agent runtime 和评估用例在同一个代码库里，Adapter 也要走 HTTP（或对应传输层），不要把 `fetch` 换成直接 `import` 被测函数——原因见[接入自己的 Agent](/docs/zh/tutorials/connect-your-agent) 里「为什么不直调」。
* **评估用例侧不代管被测进程**。不 spawn 应用、不另开端口；应用由用户自己按平时的方式启动（`pnpm dev` 之类），Adapter 连不上时报「先起应用」这类明确的错误，不要自己起服务。

## 第 4 步：跑通并验证

```sh theme={null}
<包管理器> exec niceeval exp models   # 按路径运行两个模型配置
<包管理器> exec niceeval view                 # 查看器里看对比结果
```

按 [Coding Agent 反馈闭环](/docs/zh/tutorials/agent-feedback-loop)用 `niceeval show`、`--transcript`、`--trace` 和 `--diff` 完成运行、观察、修改和重跑；查看器用法见[查看结果](/docs/zh/tutorials/viewing-results)。没跑通分三类定位：`fetch` 直接抛错 → 应用没起来或 URL 不对；`t.succeeded()` 不过 → 应用回了非成功状态；只有内容断言不过 → 接入已经通了，调断言或调应用。

## 第 5 步：收尾，告诉用户做了什么

跑通之后先总结，再谈下一步。总结要说清：接了什么被测对象、生成了哪几个文件（Adapter / Experiment / 评估用例各在哪）、`niceeval exp compare-models` 和 `niceeval view` 怎么跑、第一次运行的结果是什么样。不要在没被要求的情况下顺手重构用户已有代码，也不要在这几个文件之外新增抽象。

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

总结完之后，把还能往深接的选项列给用户——每一项都说清**能做什么、大概改多少代码、买到什么好处**，让用户自己选，不要自作主张多做：

| 能做什么                       | 改动量                                                                   | 好处                                                       | 文档                                                                      |
| -------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------- |
| 工具调用断言（`t.calledTool()` 等） | 只改 Adapter：把应用响应映射成标准事件流，约 10–30 行映射代码                                | 评估用例能断言「Agent 有没有调对工具、参数对不对」，不再只看最终回复                    | [编写 send](/docs/zh/tutorials/write-send)、[事件参考](/docs/zh/reference/events)        |
| 多轮对话、会话隔离                  | 只改 Adapter：接上 `ctx.session`（`history()` 或 `id` + `capture()`），几行到十几行  | 评估用例能写多轮场景、`t.newSession()` 验证会话间不串味                     | [驱动多轮交互](/docs/zh/explanation/drive)、[编写 send](/docs/zh/tutorials/write-send)     |
| 人工审批流（HITL）                | 只改 Adapter：停轮返回 `waiting` + `input.requested`，回答轮续跑，约 10–20 行         | 评估用例能覆盖「批准/拒绝之后 Agent 行为对不对」这类审批场景                       | [HITL](/docs/zh/explanation/hitl)                                            |
| 调用瀑布图（升 Tier 2）            | 应用已有 OTel 埋点（第 1 步探过）：只是把 span 多发一份给 NiceEval，几行配置；没埋点：补一段通用 OTel 初始化 | `niceeval view` 里看到应用内部每次模型调用、工具执行的耗时和 token 时间线；不影响任何断言 | [配置 OTel](/docs/zh/tutorials/connect-otel)                                   |
| feature A/B 对比（升 Tier 3）   | 改应用：把变体暴露成 `flags` 可切换的配置，改动量取决于应用；已有 A/B 开关（第 1 步探过）就是现成入口           | Experiment 层面直接对比「改 prompt / 换工具集 / 开关 feature 谁更好」      | [组织 Experiment](/docs/zh/tutorials/experiments)、[接入等级](/docs/zh/explanation/tier) |

共同点也要讲给用户：这些全是给 Adapter 或应用加增量，**已写的评估用例一行不用改**。三档投入分别买到什么、什么时候值得升级，见[接入等级](/docs/zh/explanation/tier)。第 1 步探到应用已有 OTel 埋点的话，瀑布图那条要主动推荐——成本接近零。
