> ## 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.

# 把配置和密钥各放到该放的地方

> 跑几次、超时、并发、judge 这些值写进代码的哪一层，API key 和 provider token 用哪些环境变量。

export const ConfigLayers = () => <div className="ne-w ne-cfg">
    <div className="ne-hd">
      timeoutMs 写在哪一层
      <span className="ne-hd-hint">选一种写法，看最终生效的是谁</span>
    </div>

    <input className="ne-pick-in" type="radio" name="ne-cfg-layers" id="ne-cfg-0" defaultChecked />
    <input className="ne-pick-in" type="radio" name="ne-cfg-layers" id="ne-cfg-1" />
    <input className="ne-pick-in" type="radio" name="ne-cfg-layers" id="ne-cfg-2" />
    <input className="ne-pick-in" type="radio" name="ne-cfg-layers" id="ne-cfg-3" />

    <div className="ne-tabs">
      <label className="ne-tab" htmlFor="ne-cfg-0">
        只写 config
      </label>
      <label className="ne-tab" htmlFor="ne-cfg-1">
        这道题自己声明
      </label>
      <label className="ne-tab" htmlFor="ne-cfg-2">
        实验压过它
      </label>
      <label className="ne-tab" htmlFor="ne-cfg-3">
        这一次再压一遍
      </label>
    </div>

    <div className="ne-panels">
      <div className="ne-panel ne-cfg-panel">
        <div className="ne-cfg-row">
          <span className="ne-cfg-layer">CLI flag</span>
          <span className="ne-cfg-src">--timeout</span>
          <span className="ne-cfg-val ne-dim">未写</span>
          <span className="ne-cfg-mark ne-dim">—</span>
        </div>
        <div className="ne-cfg-row">
          <span className="ne-cfg-layer">experiment</span>
          <span className="ne-cfg-src">experiments/ci.ts</span>
          <span className="ne-cfg-val ne-dim">未写</span>
          <span className="ne-cfg-mark ne-dim">—</span>
        </div>
        <div className="ne-cfg-row">
          <span className="ne-cfg-layer">eval</span>
          <span className="ne-cfg-src">defineEval</span>
          <span className="ne-cfg-val ne-dim">未写</span>
          <span className="ne-cfg-mark ne-dim">—</span>
        </div>
        <div className="ne-cfg-row ne-cfg-win">
          <span className="ne-cfg-layer">config</span>
          <span className="ne-cfg-src">niceeval.config.ts</span>
          <span className="ne-cfg-val">300_000</span>
          <span className="ne-cfg-mark">✓ 生效</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">内置默认</span>
          <span className="ne-cfg-src">NiceEval</span>
          <span className="ne-cfg-val">无上限</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <p className="ne-why">整个项目共享的值写这里，没有别的层声明时每道题都按它跑。</p>
      </div>

      <div className="ne-panel ne-cfg-panel">
        <div className="ne-cfg-row">
          <span className="ne-cfg-layer">CLI flag</span>
          <span className="ne-cfg-src">--timeout</span>
          <span className="ne-cfg-val ne-dim">未写</span>
          <span className="ne-cfg-mark ne-dim">—</span>
        </div>
        <div className="ne-cfg-row">
          <span className="ne-cfg-layer">experiment</span>
          <span className="ne-cfg-src">experiments/ci.ts</span>
          <span className="ne-cfg-val ne-dim">未写</span>
          <span className="ne-cfg-mark ne-dim">—</span>
        </div>
        <div className="ne-cfg-row ne-cfg-win">
          <span className="ne-cfg-layer">eval</span>
          <span className="ne-cfg-src">defineEval</span>
          <span className="ne-cfg-val">2_100_000</span>
          <span className="ne-cfg-mark">✓ 生效</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">config</span>
          <span className="ne-cfg-src">niceeval.config.ts</span>
          <span className="ne-cfg-val">300_000</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">内置默认</span>
          <span className="ne-cfg-src">NiceEval</span>
          <span className="ne-cfg-val">无上限</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <p className="ne-why">
          config 是默认来源，不是覆盖层：一道要装 35 分钟环境的题自己声明了上限，在写着 5 分钟的项目里仍按 35 分钟跑。
        </p>
      </div>

      <div className="ne-panel ne-cfg-panel">
        <div className="ne-cfg-row">
          <span className="ne-cfg-layer">CLI flag</span>
          <span className="ne-cfg-src">--timeout</span>
          <span className="ne-cfg-val ne-dim">未写</span>
          <span className="ne-cfg-mark ne-dim">—</span>
        </div>
        <div className="ne-cfg-row ne-cfg-win">
          <span className="ne-cfg-layer">experiment</span>
          <span className="ne-cfg-src">experiments/ci.ts</span>
          <span className="ne-cfg-val">600_000</span>
          <span className="ne-cfg-mark">✓ 生效</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">eval</span>
          <span className="ne-cfg-src">defineEval</span>
          <span className="ne-cfg-val">2_100_000</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">config</span>
          <span className="ne-cfg-src">niceeval.config.ts</span>
          <span className="ne-cfg-val">300_000</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">内置默认</span>
          <span className="ne-cfg-src">NiceEval</span>
          <span className="ne-cfg-val">无上限</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <p className="ne-why">
          要整批压短，用 experiment 显式写一个值——只有显式声明能压过题目自己的声明，config 的默认值不行。
        </p>
      </div>

      <div className="ne-panel ne-cfg-panel">
        <div className="ne-cfg-row ne-cfg-win">
          <span className="ne-cfg-layer">CLI flag</span>
          <span className="ne-cfg-src">--timeout 900000</span>
          <span className="ne-cfg-val">900_000</span>
          <span className="ne-cfg-mark">✓ 生效</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">experiment</span>
          <span className="ne-cfg-src">experiments/ci.ts</span>
          <span className="ne-cfg-val">600_000</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">eval</span>
          <span className="ne-cfg-src">defineEval</span>
          <span className="ne-cfg-val">2_100_000</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">config</span>
          <span className="ne-cfg-src">niceeval.config.ts</span>
          <span className="ne-cfg-val">300_000</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <div className="ne-cfg-row ne-cfg-under">
          <span className="ne-cfg-layer">内置默认</span>
          <span className="ne-cfg-src">NiceEval</span>
          <span className="ne-cfg-val">无上限</span>
          <span className="ne-cfg-mark">被上层盖住</span>
        </div>
        <p className="ne-why">只想这一次不一样就写在命令上，下一次不带它就回到 experiment 的值。</p>
      </div>
    </div>

    <div className="ne-ft">
      顺序固定：CLI flag → experiment → eval → config → 内置默认，前面有值就不看后面。
      <code>agent</code>、<code>model</code>、<code>flags</code> 只有 experiment 那一层。
    </div>
  </div>;

[NiceEval](https://niceeval.com/) 里的值只有两个家：

* **配置写进代码**——CLI flag、`experiments/` 下的 experiment 文件、根目录的 `niceeval.config.ts`。跑几次、超时多久、并发多少、judge 用哪个模型、默认看哪份报告，全都在这里，没有对应的环境变量。
* **密钥放环境变量**——API key、provider token。再加上 `NO_COLOR` 这类描述"输出到哪个终端"的事实。

所以同一个值只有一条来路。`niceeval exp --dry` 打印出来的就是真正生效的值，不用担心某个环境变量在背后改了它。CLI 与运行时文案是英语；浏览器 view 自己提供中英切换。

## 配置：想让这个值活多久，就写在哪一层

同一个值出现在多层时，按 **CLI flag → experiment → eval → config → 内置默认** 取，前面有值就不看后面。config 是默认来源，不是覆盖层——评估用例自己声明的 `timeoutMs` 不会被项目默认压掉。

<ConfigLayers />

**只想这一次不一样**——写在命令上：

```bash theme={null}
npx niceeval exp ci --attempts 5 --timeout 600000
```

**这个实验一直这样**——写进 experiment 文件：

```ts theme={null}
// experiments/ci.ts
import { defineExperiment } from "niceeval";
import { codexAgent } from "niceeval/agents";

export default defineExperiment({
  agent: codexAgent(),
  model: "gpt-5.4",
  attempts: 3,
  timeoutMs: 600_000,
  budget: 5,
});
```

`agent`、`model`、`flags` 只能写在这里，没有对应的 flag——换 agent 或换模型是复制一个 experiment 文件的事，这样每次运行对着谁跑都记在快照里，事后能复现。

**整个项目共享**——写进 `niceeval.config.ts`：

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

export default defineConfig({
  judge: { model: "gpt-5.4-mini" },
  maxConcurrency: 4,
  timeoutMs: 300_000,
});
```

### `niceeval.config.ts` 能放什么

| 字段               | 放什么                                                                                       |
| ---------------- | ----------------------------------------------------------------------------------------- |
| `name`           | 项目名，显示在 `niceeval view` 顶部。可按语言给多份                                                        |
| `report`         | 默认报告定义，不带 `--report` 的 `show` / `view` 装载它（见[自定义报告](/docs/zh/tutorials/custom-reports#设成项目默认)） |
| `judge`          | 默认裁判配置：`model`、`baseUrl`、`apiKeyEnv`、`timeoutMs`（判分调用等待上限，默认 180\_000）                    |
| `workspace`      | 上传进 Sandbox 的工作区根目录                                                                       |
| `reporters`      | 默认 reporter 列表（落盘、上报实验平台）                                                                 |
| `maxConcurrency` | 默认并发上限                                                                                    |
| `timeoutMs`      | 默认单次 attempt 超时                                                                           |
| `telemetry`      | OTLP 接收配置（`host` / `port`），OTel 接入只从这里配                                                   |
| `pricing`        | 价格表覆盖，按 model 名或 `provider/*` 通配                                                          |

每个字段的类型和完整说明在 [defineConfig 参考](/docs/zh/reference/define-config)。flag 全表在 [CLI 参考](/docs/zh/reference/cli)。

## 环境变量：只有密钥和终端两类

下面就是 NiceEval 会读的全部环境变量。每个 agent、Sandbox 和 Judge 只认自己那几个名字，不会在环境里翻找别的 key。

| 变量                                       | 谁在用                 | 备注                                                   |
| ---------------------------------------- | ------------------- | ---------------------------------------------------- |
| `ANTHROPIC_API_KEY`                      | `claudeCodeAgent()` | 工厂参数 `apiKey` 可覆盖                                    |
| `ANTHROPIC_BASE_URL`                     | `claudeCodeAgent()` | 网关地址，工厂参数 `baseUrl` 可覆盖                              |
| `CODEX_API_KEY`                          | `codexAgent()`      | 不是 `OPENAI_API_KEY`。工厂参数 `apiKey` 可覆盖                |
| `CODEX_BASE_URL`                         | `codexAgent()`      | OpenAI 兼容代理地址，工厂参数 `baseUrl` 可覆盖                     |
| `BUB_API_KEY`                            | `bubAgent()`        | 工厂参数 `apiKey` 可覆盖                                    |
| `BUB_API_BASE`                           | `bubAgent()`        | 工厂参数 `apiBase` 可覆盖                                   |
| `OPENCLAW_API_KEY` / `OPENCLAW_BASE_URL` | `openClawAgent()`   | key 省略时回落 `ANTHROPIC_API_KEY`                        |
| `OPENCODE_API_KEY` / `OPENCODE_BASE_URL` | `openCodeAgent()`   | key 省略时回落 `ANTHROPIC_API_KEY`                        |
| `HERMES_API_KEY` / `HERMES_API_BASE`     | `hermesAgent()`     | key 省略时依次回落 `OPENROUTER_API_KEY`、`ANTHROPIC_API_KEY` |
| `NICEEVAL_JUDGE_KEY`                     | Judge               | Judge 的默认 key 变量，用 `judge.apiKeyEnv` 指到别的名字          |
| `E2B_API_KEY`                            | `e2bSandbox()`      |                                                      |
| `VERCEL_API_TOKEN`                       | `vercelSandbox()`   |                                                      |
| `VERCEL_TEAM_ID`                         | `vercelSandbox()`   |                                                      |
| `VERCEL_PROJECT_ID`                      | `vercelSandbox()`   |                                                      |
| `NO_COLOR`                               | CLI 输出              | 设了就不画颜色和框线                                           |

judge 想用别的变量名装 key，在配置里指过去：

```ts theme={null}
export default defineConfig({
  judge: {
    model: "gpt-5.4-mini",
    baseUrl: "https://gateway.example.com/v1",   // 网关地址是配置，写在这里
    apiKeyEnv: "MY_GATEWAY_KEY",                  // key 是密钥，读这个环境变量
  },
});
```

网关地址本身也不方便签入仓库时，不需要 niceeval 提供什么环境变量——配置是代码，自己读就行（`.env` 在这之前已经加载完）：

```ts theme={null}
export default defineConfig({
  judge: {
    model: "gpt-5.4-mini",
    baseUrl: process.env.MY_GATEWAY_URL,   // 变量名自己起，自己读
    apiKeyEnv: "MY_GATEWAY_KEY",
  },
});
```

区别只在于：变量名是你的项目定的，不是 NiceEval 内置一个名字然后到环境里猜。

本地把密钥放进 cwd 下的 `.env`，CLI 启动时自动加载（不覆盖已经存在的环境变量），不用每次 `export`：

```bash theme={null}
# .env
ANTHROPIC_API_KEY=sk-ant-...
NICEEVAL_JUDGE_KEY=sk-...
```

`.env` 是投递密钥的地方，不是第二个配置文件——往里写 `NICEEVAL_TIMEOUT` 这种东西不会有任何效果。CI 里同样只传密钥：

```yaml theme={null}
- run: npx niceeval exp ci --junit .niceeval/junit.xml
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
```

## 想调这些值时写到哪一层

配置项没有环境变量层，所以下面每一项都只有一条来路：

| 要调什么           | 写在哪                                             |
| -------------- | ----------------------------------------------- |
| 每条评估用例跑几次      | `--attempts`，或 experiment 的 `attempts`          |
| 单次 Attempt 的超时 | `--timeout`，或 experiment / config 的 `timeoutMs` |
| 花费上限           | `--budget`，或 experiment 的 `budget`              |
| 并发上限           | `--max-concurrency`，或 config 的 `maxConcurrency` |
| Judge 模型与端点    | config 或评估用例的 `judge.model` / `judge.baseUrl`   |
| OTel 接收地址      | config 的 `telemetry: { host, port }`            |

Judge 的 key 只从 `NICEEVAL_JUDGE_KEY`（或 `judge.apiKeyEnv` 指定的变量）读，端点只从 `judge.baseUrl` 读。被测应用把标准的 `OPENAI_*` 挪作它用时，Judge 不会跟着串味。

## 接着看

<CardGroup cols={2}>
  <Card title="defineConfig 参考" icon="gear" href="/docs/zh/reference/define-config">
    每个配置字段的类型与完整说明。
  </Card>

  <Card title="CLI 参考" icon="terminal" href="/docs/zh/reference/cli">
    命令、flag 全表与退出码。
  </Card>

  <Card title="写 experiment" icon="flask" href="/docs/zh/tutorials/write-experiment">
    哪些值属于一次具体运行。
  </Card>

  <Card title="CI 集成" icon="circle-play" href="/docs/zh/tutorials/ci-integration">
    在 CI 里传 secrets。
  </Card>
</CardGroup>
