niceeval 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -12
- package/README.zh.md +8 -9
- package/docs-site/.mintignore +13 -0
- package/docs-site/AGENTS.md +46 -0
- package/docs-site/concepts/adapter.mdx +287 -0
- package/docs-site/concepts/assert.mdx +243 -0
- package/docs-site/concepts/drive.mdx +118 -0
- package/docs-site/concepts/evals.mdx +108 -0
- package/docs-site/concepts/experiment.mdx +37 -0
- package/docs-site/concepts/hitl.mdx +83 -0
- package/docs-site/concepts/judge.mdx +129 -0
- package/docs-site/concepts/overview.mdx +98 -0
- package/docs-site/concepts/tier.mdx +42 -0
- package/docs-site/docs-ref/00-index.md +23 -0
- package/docs-site/docs-ref/01-page-types.md +43 -0
- package/docs-site/docs-ref/03-style-rules.md +45 -0
- package/docs-site/docs-ref/04-code-examples.md +37 -0
- package/docs-site/docs-ref/05-dx-failure-paths.md +45 -0
- package/docs-site/docs-ref/06-checklists.md +53 -0
- package/docs-site/docs.json +256 -0
- package/docs-site/example/ai-agent-application.mdx +148 -0
- package/docs-site/example/claude-code-codex-plugin.mdx +162 -0
- package/docs-site/example/claude-code-codex-skill.mdx +147 -0
- package/docs-site/example/showcase.mdx +39 -0
- package/docs-site/example/tier1-ai-sdk-v7.mdx +136 -0
- package/docs-site/example/tier1-claude-sdk.mdx +119 -0
- package/docs-site/example/tier1-codex-sdk.mdx +111 -0
- package/docs-site/example/tier1-langgraph.mdx +119 -0
- package/docs-site/example/tier1-pi-sdk.mdx +119 -0
- package/docs-site/favicon.svg +5 -0
- package/docs-site/github-diff.css +135 -0
- package/docs-site/github-diff.js +11 -0
- package/docs-site/guides/authoring.mdx +129 -0
- package/docs-site/guides/ci-integration.mdx +97 -0
- package/docs-site/guides/connect-otel.mdx +209 -0
- package/docs-site/guides/connect-your-agent.mdx +221 -0
- package/docs-site/guides/dataset-fanout.mdx +98 -0
- package/docs-site/guides/experiments.mdx +71 -0
- package/docs-site/guides/fixtures.mdx +147 -0
- package/docs-site/guides/reporters.mdx +113 -0
- package/docs-site/guides/runner.mdx +79 -0
- package/docs-site/guides/sandbox-agent.mdx +138 -0
- package/docs-site/guides/sandbox-backends.mdx +64 -0
- package/docs-site/guides/scoring-guide.mdx +92 -0
- package/docs-site/guides/viewing-results.mdx +195 -0
- package/docs-site/guides/write-experiment.mdx +81 -0
- package/docs-site/guides/write-send.mdx +347 -0
- package/docs-site/images/adapter-tiers-zh.svg +60 -0
- package/docs-site/images/agent-turn-roundtrip-en.svg +62 -0
- package/docs-site/images/agent-turn-roundtrip-zh.svg +77 -0
- package/docs-site/images/hitl-handshake-zh.svg +89 -0
- package/docs-site/images/logo.svg +6 -0
- package/docs-site/index.mdx +181 -0
- package/docs-site/introduction.mdx +141 -0
- package/docs-site/quickstart.mdx +136 -0
- package/docs-site/reference/builtin-agents.mdx +161 -0
- package/docs-site/reference/capabilities.mdx +76 -0
- package/docs-site/reference/cli.mdx +120 -0
- package/docs-site/reference/define-agent.mdx +168 -0
- package/docs-site/reference/define-config.mdx +41 -0
- package/docs-site/reference/define-eval.mdx +160 -0
- package/docs-site/reference/events.mdx +131 -0
- package/docs-site/reference/expect.mdx +112 -0
- package/docs-site/tracker.js +8 -0
- package/docs-site/zh/concepts/adapter.mdx +286 -0
- package/docs-site/zh/concepts/assert.mdx +243 -0
- package/docs-site/zh/concepts/drive.mdx +118 -0
- package/docs-site/zh/concepts/evals.mdx +124 -0
- package/docs-site/zh/concepts/experiment.mdx +37 -0
- package/docs-site/zh/concepts/hitl.mdx +83 -0
- package/docs-site/zh/concepts/judge.mdx +130 -0
- package/docs-site/zh/concepts/overview.mdx +109 -0
- package/docs-site/zh/concepts/tier.mdx +44 -0
- package/docs-site/zh/example/ai-agent-application.mdx +152 -0
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +163 -0
- package/docs-site/zh/example/claude-code-codex-skill.mdx +147 -0
- package/docs-site/zh/example/showcase.mdx +39 -0
- package/docs-site/zh/example/tier1-ai-sdk-v7.mdx +140 -0
- package/docs-site/zh/example/tier1-claude-sdk.mdx +122 -0
- package/docs-site/zh/example/tier1-codex-sdk.mdx +117 -0
- package/docs-site/zh/example/tier1-langgraph.mdx +123 -0
- package/docs-site/zh/example/tier1-pi-sdk.mdx +122 -0
- package/docs-site/zh/guides/agent-feedback-loop.mdx +79 -0
- package/docs-site/zh/guides/authoring.mdx +129 -0
- package/docs-site/zh/guides/ci-integration.mdx +97 -0
- package/docs-site/zh/guides/connect-otel.mdx +208 -0
- package/docs-site/zh/guides/connect-your-agent.mdx +226 -0
- package/docs-site/zh/guides/dataset-fanout.mdx +83 -0
- package/docs-site/zh/guides/experiments.mdx +72 -0
- package/docs-site/zh/guides/fixtures.mdx +147 -0
- package/docs-site/zh/guides/official-adapters.mdx +132 -0
- package/docs-site/zh/guides/reporters.mdx +113 -0
- package/docs-site/zh/guides/runner.mdx +82 -0
- package/docs-site/zh/guides/sandbox-agent.mdx +139 -0
- package/docs-site/zh/guides/sandbox-backends.mdx +75 -0
- package/docs-site/zh/guides/scoring-guide.mdx +92 -0
- package/docs-site/zh/guides/viewing-results.mdx +195 -0
- package/docs-site/zh/guides/write-experiment.mdx +101 -0
- package/docs-site/zh/guides/write-send.mdx +353 -0
- package/docs-site/zh/index.mdx +180 -0
- package/docs-site/zh/introduction.mdx +140 -0
- package/docs-site/zh/quickstart.mdx +137 -0
- package/docs-site/zh/reference/builtin-agents.mdx +364 -0
- package/docs-site/zh/reference/capabilities.mdx +76 -0
- package/docs-site/zh/reference/cli.mdx +140 -0
- package/docs-site/zh/reference/define-agent.mdx +461 -0
- package/docs-site/zh/reference/define-config.mdx +107 -0
- package/docs-site/zh/reference/define-eval.mdx +674 -0
- package/docs-site/zh/reference/events.mdx +252 -0
- package/docs-site/zh/reference/expect.mdx +208 -0
- package/package.json +3 -2
- package/src/agents/bub.ts +1 -1
- package/src/agents/claude-code.ts +8 -5
- package/src/agents/codex.ts +9 -5
- package/src/agents/sdk-streams.test.ts +4 -4
- package/src/agents/sdk-streams.ts +14 -9
- package/src/agents/types.ts +40 -1
- package/src/agents/ui-message-stream.ts +1 -0
- package/src/cli.ts +36 -7
- package/src/context/types.ts +140 -0
- package/src/expect/index.ts +15 -8
- package/src/i18n/en.ts +19 -6
- package/src/i18n/zh-CN.ts +19 -6
- package/src/o11y/parsers/bub.test.ts +71 -0
- package/src/o11y/parsers/bub.ts +5 -0
- package/src/o11y/types.ts +27 -2
- package/src/runner/reporters/artifacts.ts +11 -3
- package/src/runner/reporters/live.ts +45 -8
- package/src/runner/run.ts +71 -21
- package/src/runner/types.ts +45 -2
- package/src/sandbox/types.ts +18 -0
- package/src/scoring/types.ts +5 -0
- package/src/shared/types.ts +3 -0
- package/src/util.test.ts +26 -1
- package/src/util.ts +16 -0
- package/src/view/app/App.tsx +2 -2
- package/src/view/app/components/AttemptModal.tsx +2 -0
- package/src/view/app/components/CopyControls.tsx +87 -28
- package/src/view/app/i18n.ts +3 -3
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +18 -18
- package/docs/README.md +0 -120
- package/docs/adapters/README.md +0 -60
- package/docs/adapters/authoring.md +0 -179
- package/docs/adapters/coding-agent-skills-plugins.md +0 -324
- package/docs/adapters/collection.md +0 -128
- package/docs/adapters/contract.md +0 -264
- package/docs/adapters/reference/agent-eval.md +0 -215
- package/docs/adapters/reference/agent-loop-apis.md +0 -69
- package/docs/adapters/reference/claude-code-otel-telemetry.md +0 -100
- package/docs/adapters/reference/eve-protocol.md +0 -127
- package/docs/adapters/reference/otel-genai.md +0 -107
- package/docs/adapters/reference/otel-instrumentation.md +0 -65
- package/docs/adapters/targets.md +0 -99
- package/docs/architecture.md +0 -140
- package/docs/assertions.md +0 -387
- package/docs/capabilities-by-construction.md +0 -48
- package/docs/cli.md +0 -173
- package/docs/concepts.md +0 -106
- package/docs/e2e-ci.md +0 -332
- package/docs/eval-authoring.md +0 -319
- package/docs/experiments.md +0 -157
- package/docs/getting-started.md +0 -224
- package/docs/multi-agent.md +0 -145
- package/docs/observability.md +0 -337
- package/docs/origin-integration.md +0 -195
- package/docs/references.md +0 -35
- package/docs/reports.md +0 -551
- package/docs/results-format.md +0 -228
- package/docs/results-lib.md +0 -191
- package/docs/runner.md +0 -104
- package/docs/sandbox.md +0 -276
- package/docs/scoring.md +0 -119
- package/docs/source-map.md +0 -126
- package/docs/tier-sync.md +0 -193
- package/docs/view.md +0 -194
- package/docs/vision.md +0 -88
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "内置 Agent 能力参考"
|
|
3
|
+
sidebarTitle: "内置 Agent 能力"
|
|
4
|
+
description: "NiceEval 内置的 claude-code、codex、bub 适配器分别做到了哪些能力,对应哪些断言,以及已知限制。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
内置的三个 sandbox agent(`claude-code`、`codex`、`bub`)做到的能力不完全相同——能力没有声明这一层,全由构造方式和实际行为证明,见[能力位参考](/zh/reference/capabilities)。这篇按能力盘点三个内置 agent 各自做到哪,以及两个接 AI SDK 应用的内置件:无侵入 HTTP adapter `uiMessageStreamAgent`(含 HITL)和结果转换器 `fromAiSdk`。
|
|
8
|
+
|
|
9
|
+
## 能力速览
|
|
10
|
+
|
|
11
|
+
| 能力 | 对应的断言 / API |
|
|
12
|
+
|---|---|
|
|
13
|
+
| 收发消息(基础契约) | `t.send()`(可多次调用)、`t.reply`、`turn.outputEquals` / `outputMatches`、按状态判断的 `t.succeeded()` |
|
|
14
|
+
| 事件流完整性 | `calledTool` / `toolOrder` / `usedNoTools` / `maxToolCalls` / `messageIncludes` / `noFailedActions` / `event` / `eventOrder` 等整套作用域断言;**负断言(`notCalledTool` 等)有完整事件流才可信** |
|
|
15
|
+
| 会话续接 | 跨轮记忆断言、`t.newSession()` 会话隔离 |
|
|
16
|
+
| HITL(人工介入) | `t.parked()`、`t.requireInputRequest()`、`t.respond()` / `t.respondAll()` |
|
|
17
|
+
| `tracing` | `EvalResult.trace`、`niceeval view` 的调用瀑布图 |
|
|
18
|
+
|
|
19
|
+
## 三个内置 agent 分别做到哪
|
|
20
|
+
|
|
21
|
+
| Agent | 收发 | 事件流 | 会话续接 | HITL | tracing | 备注 |
|
|
22
|
+
|---|---|---|---|---|---|---|
|
|
23
|
+
| `claude-code` | ✅ | ✅ | ✅(`claude --resume <id>`) | ❌ | ✅(`http/protobuf` → OTLP,beta 开关) | 内置 parser 自动吐 `compaction` 事件,`t.event("compaction")` 可用 |
|
|
24
|
+
| `codex` | ✅ | ✅ | ✅(`codex exec resume <id>`) | ❌ | ✅(`http/json` → OTLP) | 内置 parser 自动吐 `compaction` 事件 |
|
|
25
|
+
| `bub` | ✅ | ✅ | ✅(`--session-id` + tape 续接) | ❌ | ✅(`http/protobuf` → OTLP) | 内置 parser 自动吐 `compaction` 事件 |
|
|
26
|
+
|
|
27
|
+
三者都用 `defineSandboxAgent` 构造(`Agent.kind` 恒为 `"sandbox"`),所以 `t.sandbox.fileChanged()` / diff 断言、文件 IO、命令执行在三个 agent 上都能用,不受这张表限制。
|
|
28
|
+
|
|
29
|
+
<Warning>
|
|
30
|
+
三个内置 sandbox agent 目前都**不支持 HITL**:`send` 只返回 `"completed"` / `"failed"`,从不返回 `"waiting"`,也不吐 `input.requested` 事件。需要 `t.respond()` / `t.requireInputRequest()` 时:被测对象是 AI SDK `useChat` 后端的话,用下文的内置 `uiMessageStreamAgent`(v7 tool approval 原生映射成 HITL);其它被测对象自己写 adapter:实现 `waiting` 状态 + `input.requested` 事件 + resume 交回,[`examples/zh/tier1/pi-sdk`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/tier1/pi-sdk) / [`examples/zh/tier1/claude-sdk`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/tier1/claude-sdk) 都有手写 HITL 的现成参考。
|
|
31
|
+
</Warning>
|
|
32
|
+
|
|
33
|
+
## 逐 agent 细节
|
|
34
|
+
|
|
35
|
+
### claude-code
|
|
36
|
+
|
|
37
|
+
- 连接方式:沙箱里 spawn `claude --print --dangerously-skip-permissions`,读回 `~/.claude/projects/**/*.jsonl` 最新一份 transcript。
|
|
38
|
+
- 会话续接:`ctx.session.id` 有值时追加 `--resume <id>`;transcript 解出的会话 id 经 `ctx.session.capture()` 写回。
|
|
39
|
+
- 鉴权:`ANTHROPIC_API_KEY`,可选 `ANTHROPIC_BASE_URL`;配置项见下方 `ClaudeCodeConfig`。
|
|
40
|
+
- `tracing` 通过 claude CLI 原生 OTLP trace spans(beta)配置,协议 `http/protobuf`:env 里设置 `CLAUDE_CODE_ENABLE_TELEMETRY` 与 `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA`(beta 开关,须显式开启)把 endpoint 交给 CLI;`EvalResult.trace` 能看到 interaction / llm_request / tool 层级的瀑布图。
|
|
41
|
+
|
|
42
|
+
### codex
|
|
43
|
+
|
|
44
|
+
- 连接方式:沙箱里跑 `codex exec --json`(续接时是 `codex exec resume <id> --json`),stdout JSONL 当 transcript。
|
|
45
|
+
- 鉴权:`CODEX_API_KEY`(不是 `OPENAI_API_KEY`),可选 `CODEX_BASE_URL` 接 OpenAI 兼容代理;配置项见下方 `CodexConfig`。
|
|
46
|
+
- `tracing` 通过 `~/.codex/config.toml` 的 `[otel.trace_exporter.otlp-http]` 段配置,协议 `http/json`。
|
|
47
|
+
|
|
48
|
+
### bub
|
|
49
|
+
|
|
50
|
+
- 连接方式:沙箱里跑 `bub run` + `--session-id`,从 `~/.bub/tapes/<hash>.jsonl` 读 tape 当 transcript。
|
|
51
|
+
- 鉴权:`BUB_API_KEY` + `BUB_API_BASE`(OpenAI 兼容代理);配置项见下方 `BubConfig`。
|
|
52
|
+
- `tracing` 通过环境变量注入(`OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` 等),协议 `http/protobuf`。
|
|
53
|
+
- 安装走 `uv tool install`(非 npm 包),首次安装带 checkpoint 缓存以加速后续沙箱。
|
|
54
|
+
|
|
55
|
+
## 三个内置 sandbox agent 的配置项
|
|
56
|
+
|
|
57
|
+
{/* GENERATED:BEGIN builtin-agent-config */}
|
|
58
|
+
|
|
59
|
+
### `ClaudeCodeConfig`
|
|
60
|
+
|
|
61
|
+
#### `apiKey`
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
apiKey?: string;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Anthropic API key。省略时读 ANTHROPIC_API_KEY env。
|
|
68
|
+
|
|
69
|
+
#### `baseUrl`
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
baseUrl?: string;
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
自定义 API base URL(代理 / 内网端点)。省略时读 ANTHROPIC_BASE_URL env;
|
|
76
|
+
两者都没有则用 Anthropic 官方端点(claude CLI 默认行为)。
|
|
77
|
+
|
|
78
|
+
#### `maxTurns`
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
maxTurns?: number;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
最多跑几个 tool-use 轮次(→ `--max-turns`)。
|
|
85
|
+
控制 eval 成本上限;省略时用 CLI 原生默认(无限制)。
|
|
86
|
+
|
|
87
|
+
#### `mcpServers`
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
mcpServers?: McpServer[];
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
额外 MCP server(每个沙箱 setup 时写进用户级 ~/.claude.json)。
|
|
94
|
+
示例:{ name: "browser", command: "npx", args: ["-y", "@anthropic/mcp-browser"] }
|
|
95
|
+
|
|
96
|
+
#### `skills`
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
skills?: string[];
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
额外安装的 skill,格式为 GitHub `"org/repo"`(如 `"Effect-TS/skills"`)。
|
|
103
|
+
setup 阶段在沙箱里执行 `npx skills add <org/repo>`;
|
|
104
|
+
结果写进沙箱工作区的 skills-lock.json,claude CLI 启动时自动读取。
|
|
105
|
+
|
|
106
|
+
### `CodexConfig`
|
|
107
|
+
|
|
108
|
+
#### `apiKey`
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
apiKey?: string;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
代理 / OpenAI API key。省略时读 CODEX_API_KEY env。
|
|
115
|
+
|
|
116
|
+
#### `baseUrl`
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
baseUrl?: string;
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
OpenAI 兼容代理 base URL(如 `https://s2a.example.com/v1`)。省略时读 CODEX_BASE_URL env。
|
|
123
|
+
|
|
124
|
+
#### `mcpServers`
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
mcpServers?: McpServer[];
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
额外 MCP server(每个沙箱 setup 时追加进 ~/.codex/config.toml)。
|
|
131
|
+
格式对应 codex config.toml 的 [mcp_server.<name>] 表。
|
|
132
|
+
|
|
133
|
+
#### `skills`
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
skills?: string[];
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
额外安装的 skill,格式为 GitHub `"org/repo"`(如 `"Effect-TS/skills"`)。
|
|
140
|
+
setup 阶段执行 `npx skills add <org/repo>`,结果写进 skills-lock.json。
|
|
141
|
+
|
|
142
|
+
### `BubConfig`
|
|
143
|
+
|
|
144
|
+
#### `apiKey`
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
apiKey?: string;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
OpenAI 兼容代理的 API key。省略时读 BUB_API_KEY env。
|
|
151
|
+
|
|
152
|
+
#### `apiBase`
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
apiBase?: string;
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
OpenAI 兼容代理的 base URL。省略时读 BUB_API_BASE env。
|
|
159
|
+
|
|
160
|
+
#### `pythonPlugins`
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
pythonPlugins?: string[];
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
额外装进 bub tool 环境的 Python 包(pip 名或 git URL)。
|
|
167
|
+
每个沙箱 setup 时作为 `uv tool install --with <pkg>` 追加到 bub 环境里。
|
|
168
|
+
示例:["bub-plugin-memory", "git+`https://github.com/..."`]
|
|
169
|
+
|
|
170
|
+
{/* GENERATED:END builtin-agent-config */}
|
|
171
|
+
|
|
172
|
+
## `uiMessageStreamAgent`:接 AI SDK 应用的内建无侵入 adapter(含 HITL)
|
|
173
|
+
|
|
174
|
+
`uiMessageStreamAgent`(`niceeval/adapter` 导出)对着 [UI Message Stream 协议](https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol)(AI SDK `useChat` 后端的标准 SSE)的 HTTP 端点无侵入收发——只 `fetch`,不 import 应用代码,应用在哪部署都能接:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import { uiMessageStreamAgent } from "niceeval/adapter";
|
|
178
|
+
|
|
179
|
+
export default uiMessageStreamAgent({
|
|
180
|
+
name: "my-assistant",
|
|
181
|
+
url: "https://my-app.example.com/api/chat",
|
|
182
|
+
body: (ctx) => ({ model: ctx.model }), // 应用支持请求级选模型时,模型对比零改动
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
它替你做好的能力:
|
|
187
|
+
|
|
188
|
+
- **收发 + 事件流**:SSE 帧经 `ai` 包官方的框架无关 reducer `readUIMessageStream`(`useChat` 内部同款)归约,工具调用/结果/消息文本从消息 parts 直构——**不要求应用接 OTel**。
|
|
189
|
+
- **会话续接**:协议是服务端零状态、「客户端带全量历史」——工厂用 `ctx.session.history()` 存整份 `UIMessage[]`,每轮原样重放;新会话线(`t.newSession()` 之后)拿到的是空历史。
|
|
190
|
+
- **HITL**:AI SDK v7 tool approval(工具带 `needsApproval: true`)原生映射——part 停在 `approval-requested` 时整轮 `status: "waiting"` + `input.requested`;`t.respond("approve" / "deny")` 翻译成 `approval-responded` 原地改写该 part、原样重发 `messages` 触发服务端续跑(和真实前端 `addToolApprovalResponse()` + `sendMessage()` 的协议行为一致,没有单独的 approve 端点)。拒绝的调用以 `rejected` 落进事件流,且默认带「不要重试」的 reason(`denyReason` 可覆盖)——不带的话模型经常原样重发同一个调用。
|
|
191
|
+
- **usage / 瀑布图**:UI Message Stream 协议帧里没有 usage,所以 `t.maxTokens` 这类用量断言在这个内置件上默认没有数据(应用把 usage 放进 message metadata 属于应用自己的协议扩展)。瀑布图是另一回事:应用有 OTel 埋点(如官方 `@ai-sdk/otel`)时,按 [OTel 接入](/zh/guides/connect-otel)把 span 发给 [NiceEval](https://niceeval.com/),`niceeval view` 就有完整瀑布图——span 只进瀑布图,不喂断言。
|
|
192
|
+
|
|
193
|
+
需要在 eval 项目里安装 `ai`(可选 peer 依赖,协议 reducer 来自它)。完整可跑示例:[`examples/zh/tier1/ai-sdk-v7`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/tier1/ai-sdk-v7)。
|
|
194
|
+
|
|
195
|
+
`uiMessageStreamAgent(options)` 完整参数(`UiMessageStreamAgentOptions`):
|
|
196
|
+
|
|
197
|
+
{/* GENERATED:BEGIN ui-message-stream-options */}
|
|
198
|
+
|
|
199
|
+
#### `name`
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
name?: string;
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
agent 名(报告 / 结果聚合的身份)。默认 "ui-message-stream"。
|
|
206
|
+
|
|
207
|
+
#### `url`
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
url: string | ((ctx: AgentContext) => string | Promise<string>);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
被测应用的 chat 端点(完整 URL,应用在哪部署就指哪);函数形式每轮解析。
|
|
214
|
+
|
|
215
|
+
#### `headers`
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
headers?: Record<string, string> | ((ctx: AgentContext) => Record<string, string>);
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
附加请求头(鉴权等);`ctx.telemetry.headers`(traceparent)总会自动并入。
|
|
222
|
+
|
|
223
|
+
#### `body`
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
body?: (ctx: AgentContext) => Record<string, JsonValue | undefined>;
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
除 `messages` 外并入请求体的字段,如 `(ctx) => ({ model: ctx.model })`(undefined 字段序列化时自动丢弃)。
|
|
230
|
+
|
|
231
|
+
#### `denyReason`
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
denyReason?: string;
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
拒绝审批时随 `approval-responded` 带出的理由。应用/SDK 会把它作为模型看到的工具结果
|
|
238
|
+
文本 —— 写清楚「不要重试」能明显降低模型原样重发同一调用的概率(实测)。
|
|
239
|
+
|
|
240
|
+
#### `settleMs`
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
settleMs?: number;
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
流结束后再等这么久才返回(毫秒),给应用侧的观测导出(如 BatchSpanProcessor)留时间。
|
|
247
|
+
|
|
248
|
+
#### `tracing`
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
tracing?: AgentTracing;
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
应用有 OTel 时的端点投递方式(拿瀑布图);事件流不依赖它。
|
|
255
|
+
|
|
256
|
+
#### `spanMapper`
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
spanMapper?: SpanMapper;
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
应用有 OTel 时的 span 归一函数(拿瀑布图);事件流不依赖它。
|
|
263
|
+
|
|
264
|
+
{/* GENERATED:END ui-message-stream-options */}
|
|
265
|
+
|
|
266
|
+
## OpenAI 兼容响应转换器:`fromChatCompletion` / `fromResponses`
|
|
267
|
+
|
|
268
|
+
`fromChatCompletion(res)` / `fromResponses(res)`(`niceeval/adapter` 导出)把 OpenAI 的两种响应形状——Chat Completions 与 Responses——整段响应零映射转成 `Turn`:不限于 OpenAI 官方,任何声明兼容这两种协议形状的服务都能用。
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
import { fromChatCompletion } from "niceeval/adapter";
|
|
272
|
+
|
|
273
|
+
export default defineAgent({
|
|
274
|
+
name: "my-openai-compat-agent",
|
|
275
|
+
async send(input) {
|
|
276
|
+
const res = await client.chat.completions.create({ messages: [...], tools });
|
|
277
|
+
return fromChatCompletion(res);
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
两种形状对负断言(`notCalledTool` 等)的可信度不同:Chat Completions 不承诺「响应 = 完整过程」(应用可能在服务端跑完工具循环,只把最终答案给你),负断言只能当「没看到」,不能当「确实没发生」;Responses 的协议契约里 `output` 数组记录了模型这一轮决定做的全部事(包括每个 `function_call`),负断言可信。两个转换器产出的 `Turn` 形状本身相同,这条差异只体现在你对负断言的解读上。
|
|
283
|
+
|
|
284
|
+
## SDK 事件流转换器:`fromClaudeSdkMessages` / `fromPiAgentEvents` / `fromCodexThreadEvents`
|
|
285
|
+
|
|
286
|
+
各 agent SDK 的流式协议是 SDK 定义的通用协议,不是某个应用的私有格式——原生帧 → 标准事件的映射知识在官方包里(`niceeval/adapter` 导出),自己写无侵入 adapter 时只剩**传输粘合**(应用把流放在哪个端点、审批走什么端点)。逐帧驱动这个循环本身也是官方件(`driveFrameStream`,见下一节),不用手写 `for` 循环:
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
import { sseJsonFrames, fromClaudeSdkMessages, driveFrameStream } from "niceeval/adapter";
|
|
290
|
+
|
|
291
|
+
const frames = sseJsonFrames<SDKMessage>(res.body); // 标准 SSE → 逐帧 JSON
|
|
292
|
+
const stream = fromClaudeSdkMessages(); // SDKMessage → 标准事件
|
|
293
|
+
return driveFrameStream(frames, stream, ctx); // 逐帧喂 stream.add(),汇总成 Turn
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
- **`fromClaudeSdkMessages`**(Claude Agent SDK `SDKMessage`):`assistant` 的 text/tool_use 块、`user` 的 tool_result 块、`system`/`permission_denied`(→ `rejected`)、`result` 的 usage;`markRejected()` 登记被拒调用。
|
|
297
|
+
- **`fromPiAgentEvents`**(pi-agent-core `AgentEvent`):`message_end` 的文本/thinking/usage、`tool_execution_start/end` 的工具对。
|
|
298
|
+
- **`fromCodexThreadEvents`**(Codex SDK `ThreadEvent`):`agent_message`/`reasoning` 的消息类、工具项(`command_execution` / `mcp_tool_call` / `file_change` / `web_search` → `action.called` + `action.result`)、`turn.completed` 的 usage、错误帧。瀑布图要 codex CLI 原生 OTLP(config.toml 的 `[otel]` 块)把 span 发给 [NiceEval](https://niceeval.com/),配官方 `mapCodexSpans` 归一。
|
|
299
|
+
|
|
300
|
+
可跑参考:[`examples/zh/tier1`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/tier1) 下 claude-sdk / pi-sdk / codex-sdk 三个 adapter 就是这三个转换器 + `driveFrameStream` + 传输粘合。
|
|
301
|
+
|
|
302
|
+
## 通用「拼装方式」件:`driveFrameStream` / `deltaStream` + `ctx.session`
|
|
303
|
+
|
|
304
|
+
一个手写 send 里真正互不相干的只有三段:transport(怎么发)、reduce(原始数据 → 事件,上一节的转换器管这个)、编排(会话续接 + HITL 暂停恢复)。第三段和任何具体协议无关,纯粹是控制流模式——会话续接(`id`/`capture`、`history`)和 HITL 停轮现场(`hold`/`take`)的存取器直接挂在 `ctx.session` 上(`AgentSession`,见 [Adapter 概念](/zh/concepts/adapter#上下文:agentcontext)),不需要单独导入什么件、也不需要声明;剩下真正跨协议复用的只有两个官方件:
|
|
305
|
+
|
|
306
|
+
| 件 | 解决什么 |
|
|
307
|
+
|---|---|
|
|
308
|
+
| `driveFrameStream(cursor, reducer, ctx, onFrame?)` | 逐帧喂 reducer、处理传输帧、检测 HITL 暂停信号——循环本身收成一个函数。暂停时 `cursor` 不关闭,`onFrame` 里用 `ctx.session.hold(cursor)` 存住它,回答轮 `ctx.session.take()` 取回接着读,不重新发起请求 |
|
|
309
|
+
| `deltaStream(spec)` | 逐 token / 逐参数增量的通用累加器——原始 OpenAI/Anthropic 流式 API、自己手写的 token-by-token 后端这类"没有整段落地帧"的协议用它;声明"这一帧对应哪个操作"(文本增量/工具参数增量/收尾),拼接时机它自己管 |
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
// send 一进来先看有没有挂起的现场(HITL 回答轮)
|
|
313
|
+
const pending = ctx.session.take<Pending>();
|
|
314
|
+
if (pending) {
|
|
315
|
+
// ……按 input.responses 对位取裁决、把审批交回应用……
|
|
316
|
+
return driveFrameStream(pending.cursor, pending.stream, ctx, onFrame);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// 正常轮:会话续接走 ctx.session.id / capture,暂停时 ctx.session.hold 存住 cursor
|
|
320
|
+
return driveFrameStream(cursor, stream, ctx, (frame, derived) => {
|
|
321
|
+
ctx.session.capture(stream.sessionId);
|
|
322
|
+
const gated = derived.find((e) => e.type === "action.called" && e.name === GATED_TOOL_NAME);
|
|
323
|
+
if (gated?.type === "action.called") {
|
|
324
|
+
ctx.session.hold<Pending>({ cursor, stream, toolUseId: gated.callId });
|
|
325
|
+
return { pause: { id: gated.callId, action: GATED_TOOL_NAME, options: [{ id: "approve" }, { id: "deny" }] } };
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
三个 Tier 1 示例(claude-sdk、pi-sdk 用 `driveFrameStream` + `ctx.session.hold`/`take`,codex-sdk 只用 `driveFrameStream`)已经用这套件重写,adapter 只剩 transport 与 `onFrame` 里"这一帧要不要额外处理"的判断,没有手写循环和模块级 Map。
|
|
331
|
+
|
|
332
|
+
## `fromAiSdk`:AI SDK 结果 → 事件流转换器
|
|
333
|
+
|
|
334
|
+
`fromAiSdk`(`niceeval/adapter` 导出)在自己写的 adapter 里用(比如 HTTP web agent 的服务端直构,见 `examples/zh/ai-sdk/`)。它把 AI SDK 的 `generateText` / `streamText` 结果映射成 `{ events, usage, status }`——`toolCallId` 精确配对、时序保真、`tool-error` 映射成失败的 `action.result`、usage 聚合(v4 / v5 / v7 字段漂移都兜住)——直接铺进 `Turn`:
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
import { defineAgent, fromAiSdk } from "niceeval/adapter";
|
|
338
|
+
|
|
339
|
+
export default defineAgent({
|
|
340
|
+
name: "my-ai-sdk-agent",
|
|
341
|
+
async send(input) {
|
|
342
|
+
const result = await generateText({ model, tools, prompt: input.text });
|
|
343
|
+
return { ...fromAiSdk(result), data: result.text };
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
`status` 由转换器给:有待人批准的 tool approval 时是 `"waiting"`(并附 `input.requested` 事件),否则 `"completed"`。会话续接(多轮 resume)、HITL 的裁决交回、tracing 取决于你自己的 `send` 怎么写。
|
|
349
|
+
|
|
350
|
+
## 怎么选
|
|
351
|
+
|
|
352
|
+
- 被测对象是 AI SDK 应用(`useChat` 后端):内置 `uiMessageStreamAgent` 无侵入接入,零映射(含 HITL)。
|
|
353
|
+
- 被测对象是其它 agent 系统(HTTP / gRPC 服务):无侵入接入,手写事件映射(官方转换器能覆盖大半)——[`examples/zh/tier1`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/tier1) 下五个示例全是这条路;应用已埋 OTel 的话顺手接上,多一张瀑布图。
|
|
354
|
+
- 需要调用瀑布图(`niceeval view` 的 trace):`claude-code` / `codex` / `bub` 三个都自发 OTLP(claude-code 走 CLI 的 beta 遥测,span 只有结构与计时);自己写的 adapter 声明 `tracing` 即可(见 OTel 指南)。
|
|
355
|
+
- 需要人工审批 / 多步确认(HITL):`uiMessageStreamAgent` 原生支持(AI SDK v7 tool approval);沙箱型三个都不支持,其它被测对象自己写 adapter,拿 `driveFrameStream` + `ctx.session.hold`/`take` 拼(Tier 1 示例里 pi-sdk / claude-sdk 有现成写法)。
|
|
356
|
+
- 想跑一个 coding agent 改代码、看 diff、判断工具调用:`claude-code` / `codex` / `bub`(收发 + 事件流 + 会话续接 + workspace + sandbox)。
|
|
357
|
+
- 后端协议是自己发明的、没有官方 SDK 转换器可用:别从零手写 send——挑一种 reduce 形状(整段落地写小映射,逐 token 增量用 `deltaStream`),会话续接直接取用 `ctx.session.id`/`capture` 或 `ctx.session.history`,有 HITL 再加 `ctx.session.hold`/`take`,拼起来就是 send。
|
|
358
|
+
|
|
359
|
+
## 相关阅读
|
|
360
|
+
|
|
361
|
+
- [接入你的 agent](/zh/guides/connect-your-agent) — 自己写 adapter 时每个能力怎么做、对应什么断言。
|
|
362
|
+
- [Sandbox Agent](/zh/guides/sandbox-agent) — 怎么运行内置 sandbox agent,以及怎么写自己的。
|
|
363
|
+
- [defineAgent 参考](/zh/reference/define-agent) — `defineAgent` / `defineSandboxAgent` 完整参数。
|
|
364
|
+
- [OTel 接入](/zh/guides/connect-otel) — 把应用的 span 发给 [NiceEval](https://niceeval.com/),换 `niceeval view` 的调用瀑布图。
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "能力位参考"
|
|
3
|
+
sidebarTitle: "能力位"
|
|
4
|
+
description: "NiceEval 怎么知道你的 adapter 做到了什么:没有声明式能力位,全部由构造和实际行为证明。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
能力回答一个问题:**你的 adapter 做到了什么**——决定哪些断言可信、runner 要为你准备什么服务。
|
|
8
|
+
|
|
9
|
+
`defineAgent` / `defineSandboxAgent` 上没有 `capabilities` 字段——**没有任何东西需要你声明**。每一项能力都由构造方式或实际返回的内容证明,判定表如下。
|
|
10
|
+
|
|
11
|
+
## 能力从哪来:一张判决表
|
|
12
|
+
|
|
13
|
+
| 能力 | 怎么获得 | 你要写什么 |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `t.sandbox` / `t.sandbox.fileChanged()` 等文件系统断言 | 用 `defineSandboxAgent` 构造(`Agent.kind` 恒为 `"sandbox"`) | 无 |
|
|
16
|
+
| `tracing`(OTLP 接收 → `niceeval view` 瀑布图) | CLI 型写了 `tracing` 字段;长驻应用在 config 配了 `telemetry` 固定端口 | 无(配置本来就要写)|
|
|
17
|
+
| 工具/动作断言(`t.calledTool()` 等,含负断言) | 用官方转换器(`fromClaudeSdkMessages`、`fromAiSdk` 等)——返回值里有多少 `action.*` 事件就是多少 | 无;手工映射时事件完整与否由你的映射代码决定 |
|
|
18
|
+
| 跨轮记忆、`t.newSession()` 隔离 | 用了 `ctx.session`(`id`/`capture`、`history`)续接上下文 | 无——接了就续得上,没接每轮都是新对话,不会报错 |
|
|
19
|
+
| HITL(`t.respond()`) | `send` 返回过 `status: "waiting"` + `input.requested` | 无 |
|
|
20
|
+
|
|
21
|
+
没做到的能力 = 没有对应的事件/字段出现,相关断言组不可用(不是"报错",是断言本身没有可判断的依据);基础断言(文本、结构化、judge)永远可用。
|
|
22
|
+
|
|
23
|
+
## 为什么没有声明这一层
|
|
24
|
+
|
|
25
|
+
上一版设计里有 `capabilities: { conversation, toolObservability }` 这类布尔声明,用来补"代码证明不了的部分"。这一层已经被拿掉,原因是它承诺的事情本身就不该由声明来担保:
|
|
26
|
+
|
|
27
|
+
- **构造即证明**:用了 `defineSandboxAgent`,说明被测对象在沙箱里改文件——不需要再声明一遍 `workspace: true`。
|
|
28
|
+
- **字段即证明**:写了 `tracing`(怎么把 OTLP 端点交给 CLI),tracing 就成立。字段本身就是使用凭证,不需要旁边再放一个布尔值重复一遍。
|
|
29
|
+
- **来源即证明**:`fromAiSdk(result)` 消费的 `result.steps` 是 AI SDK 契约保证的**全量**工具循环记录,返回值自带"事件流完整"的证明;内置 CLI 的 parser 同理。手工映射时,事件完不完整取决于你的映射代码写没写全——这不是一个可以靠声明担保的东西,声明了也不会让代码更完整。
|
|
30
|
+
- **行为即证明**:HITL 没有能力位——`send` 返回 `status: "waiting"` + `input.requested` 事件,行为本身可见。
|
|
31
|
+
- **接了就续得上**:会话续接不再是"声明了才有"的开关。`ctx.session` 一直都在;用了 `id`/`capture` 或 `history` 存取器就会续接上下文,不用就每轮都是全新会话——两种都是正常状态,都不会报错,区别只在你的 adapter 实际怎么写。
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
export default defineAgent({
|
|
35
|
+
name: "my-ai-sdk-agent",
|
|
36
|
+
async send(input, ctx) {
|
|
37
|
+
const result = await generateText({ model, tools, prompt: input.text });
|
|
38
|
+
return { ...fromAiSdk(result), data: result.text };
|
|
39
|
+
// ↑ 返回值自带完整的工具事件,不需要任何能力声明
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 手工映射时事件不全,会怎样
|
|
45
|
+
|
|
46
|
+
没有声明这一层之后,"谎报"这件事也不存在了——手工映射漏了哪些工具事件,`t.calledTool()` 这类断言看到的就是漏掉之后的样子,包括负断言(`notCalledTool()`)可能因为事件本来就没写全而"看起来通过"。这不是框架的判定失误,是手工映射本身的完整性问题:**要不要相信一个负断言,取决于你有没有确认过自己的映射代码覆盖了全部工具调用**,不存在框架帮你担保的中间层。
|
|
47
|
+
|
|
48
|
+
## 逐项速查
|
|
49
|
+
|
|
50
|
+
### 工具/动作事件完整性
|
|
51
|
+
|
|
52
|
+
含义:这一轮的每次工具调用是否都以 `action.called` + `action.result` 出现在 events 里([事件流参考](/zh/reference/events))。来源只有两个:官方转换器按被测协议的契约保证;手工映射由你的代码决定。OTel span 不是来源——span 只进瀑布图,不进事件流(见 [OTel 接入](/zh/guides/connect-otel))。
|
|
53
|
+
|
|
54
|
+
### 会话续接
|
|
55
|
+
|
|
56
|
+
含义:用 `ctx.session.id` / `capture` 或 `ctx.session.history` 把请求连到同一个后端会话/累计历史上。有它,跨轮记忆断言、`t.newSession()` 隔离断言才有意义。两种实现写法见[写 send](/zh/guides/write-send)。
|
|
57
|
+
|
|
58
|
+
### `tracing` —— 发 OTLP trace
|
|
59
|
+
|
|
60
|
+
runner 消费:运行时起一个本机 OTLP 接收器,把本轮 trace context 经 `ctx.telemetry.headers` 交给你;span 归一后在 `niceeval view` 画瀑布图——只画图,不喂断言。来源:CLI 型写 `tracing` 字段(env / configure 把端点交给被测进程);长驻应用在 `niceeval.config.ts` 配 `telemetry: { port }` 固定端口(见 [OTel 接入](/zh/guides/connect-otel))。
|
|
61
|
+
|
|
62
|
+
### `kind: "sandbox"` —— 沙箱与改文件
|
|
63
|
+
|
|
64
|
+
runner 消费:为每次 attempt 准备沙箱(Docker / Vercel / E2B),经 `ctx.sandbox` 交给 adapter;解锁 `t.sandbox.fileChanged()` 等 diff 断言。来源:`defineSandboxAgent` 构造,内部判别字段,不用你写。
|
|
65
|
+
|
|
66
|
+
### 压缩可见(compaction)
|
|
67
|
+
|
|
68
|
+
含义:被测 agent 发生上下文压缩时吐 `compaction` 事件,`t.event("compaction")` 有意义。来源:内置 parsers 自动带;自写 parser 覆盖了对应逻辑就有。
|
|
69
|
+
|
|
70
|
+
## 相关阅读
|
|
71
|
+
|
|
72
|
+
- [事件流参考](/zh/reference/events) —— 事件流承诺的具体内容。
|
|
73
|
+
- [Adapter 概念](/zh/concepts/adapter) —— `ctx`/`Turn` 的完整契约、能力从哪来。
|
|
74
|
+
- [接入你的 agent](/zh/guides/connect-your-agent) —— 每种接入路径怎么做。
|
|
75
|
+
- [OTel 接入](/zh/guides/connect-otel) —— span 只进瀑布图、不喂断言的完整走法。
|
|
76
|
+
- [内置 Agent 能力](/zh/reference/builtin-agents) —— 内置 adapter 各自做到什么。
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "NiceEval CLI:命令、flags 和退出码参考"
|
|
3
|
+
sidebarTitle: "命令行"
|
|
4
|
+
description: "NiceEval CLI 参考:exp、init、list、clean 和 view 命令,以及 experiment、eval 过滤、sandbox、并发、预算和 JUnit CI 输出。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
[NiceEval](https://niceeval.com/) CLI 是发现、运行和查看 eval 的入口。实际执行 eval 时采用 experiment-first 模型:**`exp` 选择可签入的运行配置**,experiment 后的位置参数才按 eval ID 前缀过滤。agent、model 和 feature flags 写在 `experiments/`,不靠临时 CLI 参数。
|
|
8
|
+
|
|
9
|
+
## 命令
|
|
10
|
+
|
|
11
|
+
<CardGroup cols={2}>
|
|
12
|
+
<Card title="npx niceeval exp <group> [id-prefix]" icon="flask">
|
|
13
|
+
运行命名实验组或配置。可选尾随位置参数按 eval ID 前缀过滤。
|
|
14
|
+
</Card>
|
|
15
|
+
<Card title="npx niceeval init" icon="wand-magic-sparkles">
|
|
16
|
+
创建空的 `evals/` 目录和最小的 `niceeval.config.ts`;不生成示例 eval 文件。同时在 `AGENTS.md` 写入/刷新 niceeval 指引区块(见[Agent 反馈闭环](/zh/guides/agent-feedback-loop))。
|
|
17
|
+
</Card>
|
|
18
|
+
<Card title="npx niceeval list" icon="list">
|
|
19
|
+
发现并打印所有 eval,不运行。
|
|
20
|
+
</Card>
|
|
21
|
+
<Card title="npx niceeval clean" icon="trash">
|
|
22
|
+
删除 `.niceeval/` 历史运行 artifacts。
|
|
23
|
+
</Card>
|
|
24
|
+
<Card title="npx niceeval view" icon="eye">
|
|
25
|
+
打开结果查看器,查看最近一次运行的 artifacts。
|
|
26
|
+
</Card>
|
|
27
|
+
</CardGroup>
|
|
28
|
+
|
|
29
|
+
## 输出语言
|
|
30
|
+
|
|
31
|
+
[NiceEval](https://niceeval.com/) 的 CLI 和运行时文案支持本地化,不需要在 `niceeval.config.ts` 里加配置。需要固定输出语言时用环境变量:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
NICEEVAL_LANG=en npx niceeval list
|
|
35
|
+
NICEEVAL_LANG=zh-CN npx niceeval list
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
检测顺序是 `NICEEVAL_LANG`、`NICEEVAL_LOCALE`、`LC_ALL`、`LC_MESSAGES`、`LANG`。以 `zh` 开头的值使用 `zh-CN`,其它语言使用 `en`;都没有时默认 `zh-CN`。这只影响终端/runtime 文案,不改变结果 JSON 里的机器字段,也不翻译 LLM judge prompt。
|
|
39
|
+
|
|
40
|
+
## `npx niceeval exp [group|config] [id-prefix...]`
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# 运行 experiments/ 下全部实验
|
|
44
|
+
npx niceeval exp
|
|
45
|
+
|
|
46
|
+
# 运行一个实验组
|
|
47
|
+
npx niceeval exp compare-models
|
|
48
|
+
|
|
49
|
+
# 在该组里只运行 ID 以 weather 开头的 eval
|
|
50
|
+
npx niceeval exp compare-models weather
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
<Note>
|
|
54
|
+
eval 过滤参数只出现在 experiment 选择之后。裸 `npx niceeval weather` 不会运行;请使用 `npx niceeval exp local weather` 或 `npx niceeval exp compare weather`。
|
|
55
|
+
</Note>
|
|
56
|
+
|
|
57
|
+
## 常用 flags
|
|
58
|
+
|
|
59
|
+
下表由 CLI 的 flag 解析表生成。**没有**用于选择 sandbox 后端的 CLI flag:sandbox 后端只能写在代码里——在 experiment(`defineExperiment`)里设置 `sandbox`,或者在 `niceeval.config.ts`(`defineConfig`)里设置作为项目级兜底,值来自 `niceeval/sandbox` 的 `dockerSandbox()` / `vercelSandbox()` / `e2bSandbox()`;在 CLI 上尝试传入 `--sandbox` 会直接报错并以非零状态退出。`--watch` / `--json` 是文档曾接受、尚未实现的 flag,容忍解析(no-op)但不接任何行为,同样不在下表出现。
|
|
60
|
+
|
|
61
|
+
{/* GENERATED:BEGIN cli-flags */}
|
|
62
|
+
|
|
63
|
+
| Flag | 类型 | 说明 |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `--agent` | string | experiment 运行不支持该 flag。要换 agent,请在 `experiments/` 下新增或复制一个配置文件。 |
|
|
66
|
+
| `--model` | string | experiment 运行不支持该 flag。要换模型,请新增或复制一个 experiment 文件并修改 `model`。 |
|
|
67
|
+
| `--runs` | number | 每个 eval 运行多少次,常用于 pass@N。 |
|
|
68
|
+
| `--max-concurrency` | number | 设置同时运行的 eval 数量。 |
|
|
69
|
+
| `--timeout` | number | 单个 attempt 的超时时间,单位毫秒。 |
|
|
70
|
+
| `--budget` | number | 整次运行的预算上限(美元)。 |
|
|
71
|
+
| `--tag` | string | 只运行带有该 tag 的 eval(见 `defineEval` 的 `tags`)。 |
|
|
72
|
+
| `--junit` | string | 额外写一份 JUnit XML 报告到指定路径,供 CI 消费。 |
|
|
73
|
+
| `--out` | string | `view` 命令专用:把结果查看器静态导出到指定目录。 |
|
|
74
|
+
| `--port` | number | `view` 命令专用:指定本地服务器监听端口。 |
|
|
75
|
+
| `--dry` | boolean | 只打印本次会匹配到的 eval × 运行配置,不实际执行。 |
|
|
76
|
+
| `--quiet` | boolean | 关闭控制台 / live 进度输出(reporter 仍会写 artifacts)。 |
|
|
77
|
+
| `--force` | boolean | 忽略上次运行结果,不跳过已通过的 (experiment, eval) 组合,强制全部重跑。 |
|
|
78
|
+
| `--strict` | boolean | CI 中推荐使用:让软阈值(`soft`)失败也计入整条 eval 的 outcome。 |
|
|
79
|
+
| `--early-exit` / `--no-early-exit` | boolean | 某个 eval 的一次 attempt 通过后,停止该 eval 剩余的 attempts。 |
|
|
80
|
+
| `--open` / `--no-open` | boolean | `view` 命令专用:启动后自动打开浏览器(默认行为)。 |
|
|
81
|
+
| `--help` | boolean | 打印用法说明并退出。 |
|
|
82
|
+
|
|
83
|
+
{/* GENERATED:END cli-flags */}
|
|
84
|
+
|
|
85
|
+
## `list`
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx niceeval list
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
用于检查 eval 发现、ID 和配置加载是否正常。
|
|
92
|
+
|
|
93
|
+
## `exp`
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx niceeval exp compare-models
|
|
97
|
+
npx niceeval exp compare-models weather-tool
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
运行命名 experiment,用矩阵比较 agents、models 或 flags。第二个参数开始是 eval ID 前缀过滤。
|
|
101
|
+
|
|
102
|
+
## `view`
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx niceeval view
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
打开本地结果查看器。默认查看最近一次 `.niceeval/` 运行。
|
|
109
|
+
|
|
110
|
+
## `--early-exit` 与 `--strict`
|
|
111
|
+
|
|
112
|
+
`--early-exit` 默认就是 `true`:某个 eval 的一次 attempt 通过后,会自动停止该 eval 剩余的 attempts(省钱)。所以显式传 `--early-exit` 没有效果,真正有用的是反过来关掉它——`--no-early-exit`,让 `--runs` > 1 时把每次 attempt 都跑完(测真实通过率而非提前收尾)。
|
|
113
|
+
|
|
114
|
+
`--strict` 不是"更严格地报错",而是改变软阈值断言的判定:`.atLeast(n)` 这类软阈值(`soft` severity)平时失败不会把整条 eval 判为 `failed`(只是记一条不达标的断言),加了 `--strict` 之后,软阈值没达标也会让整条 eval 的 outcome 计为 `failed`。CI 中推荐加上,避免"断言分数不够但 eval 显示通过"的情况被放过。
|
|
115
|
+
|
|
116
|
+
## 环境变量覆盖
|
|
117
|
+
|
|
118
|
+
以下环境变量对应部分 flag,用于不便传 CLI 参数的场景(如 CI 环境配置):
|
|
119
|
+
|
|
120
|
+
| 环境变量 | 对应 flag |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `NICEEVAL_RUNS` | `--runs` |
|
|
123
|
+
| `NICEEVAL_MAX_CONCURRENCY` | `--max-concurrency` |
|
|
124
|
+
| `NICEEVAL_TIMEOUT` | `--timeout` |
|
|
125
|
+
| `NICEEVAL_BUDGET` | `--budget` |
|
|
126
|
+
|
|
127
|
+
优先级从高到低:CLI flag > 环境变量 > experiment / `niceeval.config.ts` 里的值 > 内置默认值。四个环境变量都要求合法数字,解析失败会直接报错退出。
|
|
128
|
+
|
|
129
|
+
[NiceEval](https://niceeval.com/) 还会在启动时自动加载 cwd 下的 `.env` 文件(不需要额外配置,也不覆盖已经存在的环境变量),常用于本地放 `ANTHROPIC_API_KEY` 这类鉴权信息,不用每次手动 `export`。
|
|
130
|
+
|
|
131
|
+
## 退出码
|
|
132
|
+
|
|
133
|
+
| 退出码 | 含义 |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `0` | 全部 eval 通过(或 `list`、`init`、`clean` 等命令正常完成)。 |
|
|
136
|
+
| `1` | 存在 `failed` / `errored` 的 eval;或命令用法错误(如 `exp` 没匹配到任何实验、传了不支持的 flag 组合)。 |
|
|
137
|
+
| `2` | 运行时崩溃(未捕获异常),CLI 顶层兜底捕获后退出。 |
|
|
138
|
+
| `130` | 收到中断信号(Ctrl-C / SIGTERM)后退出。 |
|
|
139
|
+
|
|
140
|
+
需要 CI 把软阈值失败也当失败处理时,同时使用 `--strict`(见上)。
|