niceeval 0.4.4 → 0.4.6
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 +15 -5
- 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,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "评估你的 AI Agent 应用"
|
|
3
|
+
sidebarTitle: "评估 AI Agent 应用"
|
|
4
|
+
description: "用 direct adapter 评估一个基于 AI SDK 的通用 AI 助手应用:工具调用、图片理解和多轮会话。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
这个例子演示如何用 [NiceEval](https://niceeval.com/) 评估你自己的 AI Agent 应用。
|
|
8
|
+
|
|
9
|
+
<Note>
|
|
10
|
+
这是**完整能力版**的参考示例:会话、工具事件、tracing、模型对比、双可观测一次到位。第一次接入建议先走[接入你的 Agent](/zh/guides/connect-your-agent) 的分步路线(最小接入 → 事件流 → 多轮 → HITL → tracing),回头拿这页对照"真实项目长什么样"。
|
|
11
|
+
</Note>
|
|
12
|
+
|
|
13
|
+
查看示例代码:https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/ai-sdk
|
|
14
|
+
|
|
15
|
+
被测对象是一个用 AI SDK tool loop 实现的【普通 AI 助手】应用:会发消息、调用工具(查天气 / 算数 / 搜索)、理解图片,并用 Langfuse 做自己的可观测。该应用在测试时不需要 sandbox —— [NiceEval](https://niceeval.com/) 通过 direct adapter 连接它。
|
|
16
|
+
|
|
17
|
+
# 目录结构
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
examples/zh/ai-sdk/
|
|
21
|
+
src/ # 被测 web agent(POST /api/turn,内含工具 + 图片理解)
|
|
22
|
+
adapter/adapter.ts # NiceEval adapter:工厂 webAgent({ baseUrl })
|
|
23
|
+
evals/ # 会话型 eval
|
|
24
|
+
weather-tool.eval.ts # 问天气 → 调 get_weather
|
|
25
|
+
image-understanding.eval.ts # 图片理解
|
|
26
|
+
experiments/
|
|
27
|
+
compare-models/ # 实验组:每文件钉一个 model
|
|
28
|
+
gpt-5.4.ts
|
|
29
|
+
deepseek-v4-pro.ts
|
|
30
|
+
niceeval.config.ts # 注册 adapter、judge、并发
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
# 定义适配器
|
|
34
|
+
|
|
35
|
+
adapter 告诉 [NiceEval](https://niceeval.com/) 怎么给 AI Agent 发请求、怎么把响应读成标准事件流。它是个工厂函数:`baseUrl`(被测 agent 跑在哪)由外面传进来,adapter 自己不写死、不读 env。
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
// adapter/adapter.ts
|
|
39
|
+
import { defineAgent } from "niceeval/adapter";
|
|
40
|
+
import type { Agent } from "niceeval/adapter";
|
|
41
|
+
import type { StreamEvent } from "niceeval";
|
|
42
|
+
import type { AgentEvent, AgentResponse } from "../src/protocol.ts";
|
|
43
|
+
|
|
44
|
+
export function webAgent(opts: { baseUrl: string }): Agent {
|
|
45
|
+
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
46
|
+
return defineAgent({
|
|
47
|
+
name: "web-agent",
|
|
48
|
+
async send(input, ctx) {
|
|
49
|
+
const response = await fetch(`${baseUrl}/api/turn`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: { "content-type": "application/json" },
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
sessionId: ctx.session.id,
|
|
54
|
+
message: input.text,
|
|
55
|
+
model: ctx.model,
|
|
56
|
+
files: input.files,
|
|
57
|
+
otelEndpoint: ctx.telemetry?.endpoint, // 双可观测:让 app 把本轮 span 也发回 NiceEval
|
|
58
|
+
}),
|
|
59
|
+
signal: ctx.signal,
|
|
60
|
+
});
|
|
61
|
+
// 同一 workspace 的共享契约,直接按 AgentResponse 读,不必当 unknown 再校验一遍。
|
|
62
|
+
const body = (await response.json()) as AgentResponse;
|
|
63
|
+
ctx.session.capture(body.sessionId);
|
|
64
|
+
return {
|
|
65
|
+
events: body.events.map(toStreamEvent),
|
|
66
|
+
data: body.data,
|
|
67
|
+
status: "completed" as const,
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function toStreamEvent(event: AgentEvent): StreamEvent {
|
|
74
|
+
if (event.type === "action.called") return { ...event, tool: "unknown" };
|
|
75
|
+
return event;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 多轮消息
|
|
80
|
+
|
|
81
|
+
同一条会话线里 `ctx.session.id` 自动续到下一轮;adapter 把 agent 回传的 `sessionId` 用 `ctx.session.capture()` 写回即可。需要在实验里按 feature flag 分流,见 [Experiments](/zh/guides/experiments)。
|
|
82
|
+
|
|
83
|
+
# 定义评估
|
|
84
|
+
|
|
85
|
+
每个 eval 发消息、断言回复 / 工具调用 / 图片理解。确定性断言(`calledTool`、`messageIncludes`)免 API key 就能跑;设了 judge key 再加开放式打分。
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
// evals/weather-tool.eval.ts
|
|
89
|
+
import { defineEval } from "niceeval";
|
|
90
|
+
|
|
91
|
+
export default defineEval({
|
|
92
|
+
description: "AI 助手:问天气调用 get_weather",
|
|
93
|
+
async test(t) {
|
|
94
|
+
const turn = await t.send("北京今天天气怎么样?");
|
|
95
|
+
turn.succeeded();
|
|
96
|
+
await t.group("调用 get_weather 且城市正确", () => {
|
|
97
|
+
t.calledTool("get_weather", { input: { city: "北京" } });
|
|
98
|
+
t.messageIncludes(/°C|气温|天气/);
|
|
99
|
+
});
|
|
100
|
+
t.judge.autoevals.closedQA("助手是否基于工具返回的天气数据作答,而不是凭空编造?").atLeast(0.7);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
图片理解的 eval 可以用 `t.sendFile()` 发送附件,adapter 会把 `input.files` 原样转发给 web agent:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
// evals/image-understanding.eval.ts
|
|
109
|
+
await t.sendFile(new URL("./fixtures/sample.png", import.meta.url).pathname);
|
|
110
|
+
const turn = await t.send("这张图片里是什么?");
|
|
111
|
+
t.messageIncludes(/猫|cat/i); // 示例图是一只猫
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
# 定义实验
|
|
115
|
+
|
|
116
|
+
**一个实验文件 = 一个配置**(单 model)。跨模型对比写多个文件放进同一个实验组文件夹:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
// experiments/compare-models/gpt-5.4.ts
|
|
120
|
+
import { defineExperiment } from "niceeval";
|
|
121
|
+
import { webAgent } from "../../adapter/adapter.ts";
|
|
122
|
+
|
|
123
|
+
export default defineExperiment({
|
|
124
|
+
description: "gpt-5.4: 对比模型",
|
|
125
|
+
agent: webAgent({ baseUrl: "http://127.0.0.1:5188" }),
|
|
126
|
+
model: "gpt-5.4", // 单个字符串;另一个模型复制一份文件改这一行
|
|
127
|
+
runs: 2,
|
|
128
|
+
earlyExit: true,
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
# 开始评估
|
|
133
|
+
|
|
134
|
+
先启动被测 agent 应用(默认 mock 模式,免 API key)。这个例子是独立 npm 项目,`niceeval` 是它的依赖:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
cd examples/zh/ai-sdk && pnpm install && pnpm dev
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
另开一个终端跑 eval:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
cd examples/zh/ai-sdk
|
|
144
|
+
pnpm exec niceeval exp compare-models # 跑模型对比实验组
|
|
145
|
+
pnpm exec niceeval exp compare-models weather-tool # 在实验组里只跑某个 eval
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## 下一步
|
|
149
|
+
|
|
150
|
+
- [接入你的 Agent](/zh/guides/connect-your-agent) — `defineAgent` 从零跑通的教程。
|
|
151
|
+
- [编写 eval](/zh/guides/authoring) — 单轮、多轮和数据集。
|
|
152
|
+
- [CI 集成](/zh/guides/ci-integration) — 把 agent 回归测试放进 PR。
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "评估你的 Claude Code / Codex 插件"
|
|
3
|
+
sidebarTitle: "评估插件效果"
|
|
4
|
+
description: "用 NiceEval 把 coding-agent 插件放进真实 workspace,比较有插件和无插件时的通过率、成本、耗时和行为差异。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
如果你在给 Claude Code、Codex 或其它 coding agent 写插件,最有价值的 eval 不是问它“会不会用插件”,而是把插件放进真实 workspace,让 agent 完成一组真实开发任务,再比较有插件和无插件时的 pass rate、耗时、成本和 diff。
|
|
8
|
+
|
|
9
|
+
当前可运行示例在 [`examples/zh/coding-agent-skill`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/coding-agent-skill)。其中的 Ponytail 组就是一个插件 benchmark 迁移示例:把第三方 Ponytail skill/plugin 的 agentic benchmark 改写成 [NiceEval](https://niceeval.com/) eval,并与无插件 baseline 对比。
|
|
10
|
+
|
|
11
|
+
## 目录结构
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
examples/zh/coding-agent-skill/
|
|
15
|
+
├─ niceeval.config.ts
|
|
16
|
+
├─ skills/
|
|
17
|
+
│ └─ ponytail.md
|
|
18
|
+
├─ workspaces/
|
|
19
|
+
│ └─ ts-starter/
|
|
20
|
+
├─ evals/
|
|
21
|
+
│ ├─ ponytail-safe-path.eval.ts
|
|
22
|
+
│ ├─ ponytail-csv-sum.eval.ts
|
|
23
|
+
│ └─ ponytail-reuse.eval.ts
|
|
24
|
+
└─ experiments/
|
|
25
|
+
├─ ponytail.ts
|
|
26
|
+
└─ ponytail-baseline.ts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- `skills/ponytail.md` 是要注入给 agent 的插件/skill 内容。
|
|
30
|
+
- `workspaces/ts-starter/` 是每个 eval 上传到 sandbox 的初始项目。
|
|
31
|
+
- `evals/*.eval.ts` 负责铺 workspace、发送真实任务、验证文件和行为。
|
|
32
|
+
- `experiments/ponytail.ts` 注入插件,`experiments/ponytail-baseline.ts` 不注入插件。
|
|
33
|
+
|
|
34
|
+
## 在实验里安装插件
|
|
35
|
+
|
|
36
|
+
示例不是用位置参数传插件名,也不是让 eval 自己知道“插件开关”。插件开关属于 experiment:实验组负责决定 agent 怎么启动、sandbox 里要准备什么。
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { defineExperiment } from "niceeval";
|
|
40
|
+
import { claudeCodeAgent } from "niceeval/adapter";
|
|
41
|
+
import { dockerSandbox } from "niceeval/sandbox";
|
|
42
|
+
import { readFileSync } from "node:fs";
|
|
43
|
+
import { dirname, join } from "node:path";
|
|
44
|
+
import { fileURLToPath } from "node:url";
|
|
45
|
+
|
|
46
|
+
const __dir = dirname(fileURLToPath(import.meta.url));
|
|
47
|
+
const ponytailSkill = readFileSync(join(__dir, "../skills/ponytail.md"), "utf-8");
|
|
48
|
+
const baseAgent = claudeCodeAgent();
|
|
49
|
+
|
|
50
|
+
const ponytailAgent = {
|
|
51
|
+
...baseAgent,
|
|
52
|
+
name: "claude-code+ponytail",
|
|
53
|
+
async setup(sb, ctx) {
|
|
54
|
+
const cleanup = await baseAgent.setup?.(sb, ctx);
|
|
55
|
+
await sb.writeFiles({ "CLAUDE.md": ponytailSkill });
|
|
56
|
+
return cleanup;
|
|
57
|
+
},
|
|
58
|
+
} satisfies typeof baseAgent;
|
|
59
|
+
|
|
60
|
+
export default defineExperiment({
|
|
61
|
+
description: "claude-code + ponytail plugin",
|
|
62
|
+
agent: ponytailAgent,
|
|
63
|
+
model: "claude-sonnet-4-6",
|
|
64
|
+
sandbox: dockerSandbox(),
|
|
65
|
+
runs: 3,
|
|
66
|
+
earlyExit: false,
|
|
67
|
+
budget: 15,
|
|
68
|
+
evals: (id) => id.startsWith("ponytail-"),
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
对照组保留同样的模型、runs、budget 和 eval 过滤,只把 `agent` 换成裸 `claudeCodeAgent()`。这样差异才干净地归因到插件。
|
|
73
|
+
|
|
74
|
+
## 写插件任务
|
|
75
|
+
|
|
76
|
+
每个任务是普通 `.eval.ts` 文件。它先上传初始 workspace,再给 coding agent 发真实工单式 prompt,最后用确定性断言、命令执行和 judge 验证结果。
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { defineEval } from "niceeval";
|
|
80
|
+
import { includes } from "niceeval/expect";
|
|
81
|
+
|
|
82
|
+
export default defineEval({
|
|
83
|
+
description: "实现文件上传路径解析函数(不提示要防路径穿越)",
|
|
84
|
+
|
|
85
|
+
async test(t) {
|
|
86
|
+
await t.sandbox.uploadDirectory("../workspaces/ts-starter");
|
|
87
|
+
await t.sandbox.writeFiles({
|
|
88
|
+
"uploads.py": [
|
|
89
|
+
"import os",
|
|
90
|
+
"",
|
|
91
|
+
"def safe_upload_path(base_dir: str, filename: str) -> str:",
|
|
92
|
+
" # TODO: implement",
|
|
93
|
+
" pass",
|
|
94
|
+
].join("\n"),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
await t
|
|
98
|
+
.send(
|
|
99
|
+
"在 uploads.py 里完成 safe_upload_path(base_dir, filename) 函数," +
|
|
100
|
+
"返回用户上传文件在服务器上的完整路径。base_dir 是允许的根目录。",
|
|
101
|
+
)
|
|
102
|
+
.then((turn) => turn.succeeded());
|
|
103
|
+
|
|
104
|
+
const src = await t.sandbox.readSourceFiles({ extensions: ["py"] });
|
|
105
|
+
const code = src.text();
|
|
106
|
+
|
|
107
|
+
t.check(code, includes(/commonpath|realpath|abspath/));
|
|
108
|
+
|
|
109
|
+
await t.sandbox.writeFiles({
|
|
110
|
+
"_test_traversal.py": [
|
|
111
|
+
"import sys, os",
|
|
112
|
+
"sys.path.insert(0, '.')",
|
|
113
|
+
"from uploads import safe_upload_path",
|
|
114
|
+
"base = '/var/uploads'",
|
|
115
|
+
"try:",
|
|
116
|
+
" p = safe_upload_path(base, '../../etc/passwd')",
|
|
117
|
+
" assert os.path.commonpath([base, os.path.abspath(p)]) == base",
|
|
118
|
+
"except (ValueError, PermissionError, AssertionError):",
|
|
119
|
+
" pass",
|
|
120
|
+
"print('ok')",
|
|
121
|
+
].join("\n"),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const result = await t.sandbox.runCommand("python3", ["_test_traversal.py"]);
|
|
125
|
+
t.check(result.stdout.trim(), includes(/ok/));
|
|
126
|
+
t.sandbox.fileChanged("uploads.py");
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
关键点是:prompt 不泄露安全答案,验证阶段再检查产物、测试输出、diff 和行为证据。
|
|
132
|
+
|
|
133
|
+
## 运行对比
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
cd examples/zh/coding-agent-skill
|
|
137
|
+
pnpm install
|
|
138
|
+
pnpm exec niceeval exp ponytail ponytail-baseline
|
|
139
|
+
pnpm exec niceeval view
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`exp` 后的第一个参数选择实验组或实验文件;后续位置参数只用于过滤 eval ID,不用于传 agent 名、插件名或 URL。
|
|
143
|
+
|
|
144
|
+
## 看什么指标
|
|
145
|
+
|
|
146
|
+
- `pass@N` 是否提升。
|
|
147
|
+
- 平均耗时、token 和预估成本是否可接受。
|
|
148
|
+
- 失败 transcript 中 agent 是否忽略了插件流程。
|
|
149
|
+
- diff 是否只改了任务相关文件。
|
|
150
|
+
- 行为断言是否体现插件价值,例如更少重写、更多复用、主动安全防御。
|
|
151
|
+
|
|
152
|
+
## Copy to your agent
|
|
153
|
+
|
|
154
|
+
```text
|
|
155
|
+
READ docs-site/zh/example/claude-code-codex-plugin.mdx and install niceeval for this repo.
|
|
156
|
+
Use examples/zh/coding-agent-skill as the reference shape: put the plugin in skills/, inject it from an experiment setup hook, write one .eval.ts task against a real workspace, then add a no-plugin baseline experiment.
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 下一步
|
|
160
|
+
|
|
161
|
+
- [Fixtures](/zh/guides/fixtures) — 用 `.eval.ts` 管理 sandbox workspace、任务和验证。
|
|
162
|
+
- [Sandbox Agent](/zh/guides/sandbox-agent) — 内置 `claude-code`、`codex` 和自定义 sandbox agent。
|
|
163
|
+
- [查看结果](/zh/guides/viewing-results) — 看 transcript、diff、event stream 和 trace。
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "评估你的 Skill 在 Claude Code / Codex 上的表现"
|
|
3
|
+
sidebarTitle: "评估 Skill 效果"
|
|
4
|
+
description: "用 NiceEval 对比有 Skill 和无 Skill 的 coding-agent 任务,通过真实 workspace、断言和 judge 衡量 Skill 是否真的提升结果。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Skill 的价值不只是“agent 最后答案对不对”,还包括它是否在正确场景遵循你的流程、是否避免反模式、是否稳定提升通过率、成本和耗时。[NiceEval](https://niceeval.com/) 的推荐做法是把 Skill 注入到 sandbox 里的真实 coding-agent 工作区,再与无 Skill baseline 对比。
|
|
8
|
+
|
|
9
|
+
当前可运行示例在 [`examples/zh/coding-agent-skill`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/coding-agent-skill)。它包含两组实验:
|
|
10
|
+
|
|
11
|
+
- Zod skill:自编写 `skills/zod.md`,验证 agent 是否用 Zod 做请求体和环境变量校验。
|
|
12
|
+
- Ponytail plugin:迁移第三方 Ponytail benchmark,验证安全、复用和简洁性。
|
|
13
|
+
|
|
14
|
+
## 目录结构
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
examples/zh/coding-agent-skill/
|
|
18
|
+
├─ skills/
|
|
19
|
+
│ ├─ zod.md
|
|
20
|
+
│ └─ ponytail.md
|
|
21
|
+
├─ workspaces/
|
|
22
|
+
│ └─ ts-starter/
|
|
23
|
+
├─ evals/
|
|
24
|
+
│ ├─ api-validation.eval.ts
|
|
25
|
+
│ ├─ config-schema.eval.ts
|
|
26
|
+
│ ├─ ponytail-safe-path.eval.ts
|
|
27
|
+
│ ├─ ponytail-csv-sum.eval.ts
|
|
28
|
+
│ └─ ponytail-reuse.eval.ts
|
|
29
|
+
└─ experiments/
|
|
30
|
+
├─ with-skill.ts
|
|
31
|
+
├─ baseline.ts
|
|
32
|
+
├─ ponytail.ts
|
|
33
|
+
└─ ponytail-baseline.ts
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 定义 Skill 实验组
|
|
37
|
+
|
|
38
|
+
Skill 是否注入属于 experiment 配置。示例在 sandbox setup 阶段把 `skills/zod.md` 写入工作区的 `CLAUDE.md`,让 Claude Code 启动后自动读取。
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { defineExperiment } from "niceeval";
|
|
42
|
+
import { claudeCodeAgent } from "niceeval/adapter";
|
|
43
|
+
import { dockerSandbox } from "niceeval/sandbox";
|
|
44
|
+
import { readFileSync } from "node:fs";
|
|
45
|
+
import { dirname, join } from "node:path";
|
|
46
|
+
import { fileURLToPath } from "node:url";
|
|
47
|
+
|
|
48
|
+
const __dir = dirname(fileURLToPath(import.meta.url));
|
|
49
|
+
const zodSkill = readFileSync(join(__dir, "../skills/zod.md"), "utf-8");
|
|
50
|
+
const baseAgent = claudeCodeAgent();
|
|
51
|
+
|
|
52
|
+
const zodAgent = {
|
|
53
|
+
...baseAgent,
|
|
54
|
+
name: "claude-code+zod-skill",
|
|
55
|
+
async setup(sb, ctx) {
|
|
56
|
+
const cleanup = await baseAgent.setup?.(sb, ctx);
|
|
57
|
+
await sb.writeFiles({ "CLAUDE.md": zodSkill });
|
|
58
|
+
return cleanup;
|
|
59
|
+
},
|
|
60
|
+
} satisfies typeof baseAgent;
|
|
61
|
+
|
|
62
|
+
export default defineExperiment({
|
|
63
|
+
description: "claude-code + zod skill(本地注入)",
|
|
64
|
+
agent: zodAgent,
|
|
65
|
+
model: "claude-sonnet-4-6",
|
|
66
|
+
sandbox: dockerSandbox(),
|
|
67
|
+
runs: 3,
|
|
68
|
+
earlyExit: false,
|
|
69
|
+
budget: 10,
|
|
70
|
+
evals: (id) => !id.startsWith("ponytail-"),
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
对照组使用同样的 eval 过滤、模型、runs 和预算,只把 agent 换成未注入 Skill 的 `claudeCodeAgent()`。
|
|
75
|
+
|
|
76
|
+
## 写 eval
|
|
77
|
+
|
|
78
|
+
`.eval.ts` 文件同时负责三件事:准备 workspace、发送真实任务、验证结果。下面是 Zod 请求体校验任务的简化版。
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { defineEval } from "niceeval";
|
|
82
|
+
import { excludes, includes } from "niceeval/expect";
|
|
83
|
+
|
|
84
|
+
export default defineEval({
|
|
85
|
+
description: "用 Zod 校验 POST /users 的请求体,失败时返回结构化错误",
|
|
86
|
+
|
|
87
|
+
async test(t) {
|
|
88
|
+
await t.sandbox.uploadDirectory("../workspaces/ts-starter");
|
|
89
|
+
|
|
90
|
+
await t
|
|
91
|
+
.send(
|
|
92
|
+
`在 src/routes/users.ts 里实现 POST /users 路由。
|
|
93
|
+
要求:
|
|
94
|
+
- 用 Zod 定义 CreateUserSchema
|
|
95
|
+
- 用 .safeParse() 校验 req.body(不要用 .parse())
|
|
96
|
+
- 校验失败返回 HTTP 422,body 为 { errors: result.error.issues }
|
|
97
|
+
- 校验成功返回 HTTP 201`,
|
|
98
|
+
)
|
|
99
|
+
.then((turn) => turn.succeeded());
|
|
100
|
+
|
|
101
|
+
const src = await t.sandbox.readSourceFiles({ extensions: ["ts"] });
|
|
102
|
+
const route = src.fileMatching(/users/);
|
|
103
|
+
const code = route?.content ?? "";
|
|
104
|
+
|
|
105
|
+
t.check(code, includes(/z\.object\s*\(/));
|
|
106
|
+
t.check(code, includes(/\.safeParse\s*\(/));
|
|
107
|
+
t.check(code, includes(/422|UNPROCESSABLE/));
|
|
108
|
+
t.check(code, excludes(/JSON\.parse/));
|
|
109
|
+
t.sandbox.fileChanged("src/routes/users.ts");
|
|
110
|
+
|
|
111
|
+
t.judge.autoevals
|
|
112
|
+
.closedQA("代码是否正确使用了 Zod 的惯用校验模式?", { on: code })
|
|
113
|
+
.atLeast(0.75);
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
优先验证最终产物和真实测试。只有当事件名稳定时,再把“是否加载 Skill”“是否调用某工具”作为硬断言。
|
|
119
|
+
|
|
120
|
+
## 运行
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
cd examples/zh/coding-agent-skill
|
|
124
|
+
pnpm install
|
|
125
|
+
|
|
126
|
+
# Zod skill A/B 对比
|
|
127
|
+
pnpm exec niceeval exp compare
|
|
128
|
+
|
|
129
|
+
# Ponytail plugin A/B 对比
|
|
130
|
+
pnpm exec niceeval exp ponytail ponytail-baseline
|
|
131
|
+
|
|
132
|
+
pnpm exec niceeval view
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 评什么
|
|
136
|
+
|
|
137
|
+
- Skill 是否显著提高通过率。
|
|
138
|
+
- 是否减少反模式,例如裸 `JSON.parse`、不安全路径拼接、重复造轮子。
|
|
139
|
+
- 是否让 agent 更稳定地改对目标文件。
|
|
140
|
+
- 成本和耗时是否仍在可接受范围。
|
|
141
|
+
- 失败样本里 agent 是没读 Skill、读了没遵循,还是验证目标本身设计得不清楚。
|
|
142
|
+
|
|
143
|
+
## 下一步
|
|
144
|
+
|
|
145
|
+
- [Fixtures](/zh/guides/fixtures) — 组织 sandbox workspace、任务和验证。
|
|
146
|
+
- [Experiments](/zh/guides/experiments) — 做有 Skill / 无 Skill 的对照实验。
|
|
147
|
+
- [评分指南](/zh/guides/scoring-guide) — 把最终结果和行为约束一起评分。
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Showcase"
|
|
3
|
+
sidebarTitle: "Showcase"
|
|
4
|
+
description: "用 NiceEval 搭建评测的真实项目和线上网站,持续收录。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
这里收录用 [NiceEval](https://niceeval.com/) 搭建评测的真实项目和线上网站。每个案例都是可运行、可复现的完整仓库——不是摘录片段,点进源码仓库能看到完整的 eval、experiment 和 sandbox 配置。
|
|
8
|
+
|
|
9
|
+
## coding-agent-memory-evals
|
|
10
|
+
|
|
11
|
+
Tape、Nowledge Mem、mem9、db9.ai、OpenClaw……coding agent 的记忆实现开始分化,但缺一个可复现的评测面来说清楚它们到底有没有用。[coding-agent-memory-evals](https://github.com/CorrectRoadH/coding-agent-memory-evals) 用 NiceEval 搭了这个 benchmark:同一批 coding 任务、同一个模型(`gpt-5.4`),只换 agent 的记忆机制——[bub](https://github.com/CorrectRoadH/coding-agent-memory-evals)(内置 [Tape](https://tape.systems/))对比无对应持久记忆的 codex。
|
|
12
|
+
|
|
13
|
+
- 在线报告:[coding-agent-memory-evals.vercel.app](https://coding-agent-memory-evals.vercel.app/)
|
|
14
|
+
- 源码仓库:[github.com/CorrectRoadH/coding-agent-memory-evals](https://github.com/CorrectRoadH/coding-agent-memory-evals)
|
|
15
|
+
|
|
16
|
+
主评分只看开发任务本身是否完成(build / tests / upstream verifier),不额外考“agent 是否记得某条事实”——记忆机制的价值体现在 duration、token、成本和 `pass^k` 这些副指标上。
|
|
17
|
+
|
|
18
|
+
### 案例
|
|
19
|
+
|
|
20
|
+
每条 eval 都把某个公开 benchmark 的原始任务和验证脚本原样接进来,不是重写的断言。
|
|
21
|
+
|
|
22
|
+
| Eval | 来源 | 验证什么 |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| [`agent-029-use-cache-directive`](https://github.com/CorrectRoadH/coding-agent-memory-evals/blob/main/evals/memory/agent-029-use-cache-directive.eval.ts) | next-evals | Server Action 是否用 `use cache` + `revalidateTag` 做目录数据的最终一致刷新 |
|
|
25
|
+
| [`agent-030-app-router-migration-hard`](https://github.com/CorrectRoadH/coding-agent-memory-evals/blob/main/evals/memory/agent-030-app-router-migration-hard.eval.ts) | next-evals | 复杂 Pages Router 应用整体迁移到 App Router,legacy 文件是否被删、legacy API 是否残留 |
|
|
26
|
+
| [`agent-037-updatetag-cache`](https://github.com/CorrectRoadH/coding-agent-memory-evals/blob/main/evals/memory/agent-037-updatetag-cache.eval.ts) | next-evals | read-your-own-writes 场景下是否用 `updateTag` 而不是只用 `revalidateTag` |
|
|
27
|
+
| [`terminal-cancel-async-tasks`](https://github.com/CorrectRoadH/coding-agent-memory-evals/blob/main/evals/memory/terminal-cancel-async-tasks.eval.ts) | [Terminal-Bench](https://www.tbench.ai/) | 实现可取消的并发受限异步任务运行器,跑原始 `pytest` 验证 |
|
|
28
|
+
| [`repomod-hello-world-api`](https://github.com/CorrectRoadH/coding-agent-memory-evals/blob/main/evals/memory/repomod-hello-world-api.eval.ts) | RepoMod-Bench | 把 Flask API 迁移成 Java Spring Boot,起服务后跑上游隐藏 HTTP 测试 |
|
|
29
|
+
| [`tool-call-observability`](https://github.com/CorrectRoadH/coding-agent-memory-evals/blob/main/evals/memory/tool-call-observability.eval.ts) | 自编写 smoke | agent 的 shell 工具调用是否被正确记录为标准事件 |
|
|
30
|
+
|
|
31
|
+
### 对比实验
|
|
32
|
+
|
|
33
|
+
[`experiments/compare/`](https://github.com/CorrectRoadH/coding-agent-memory-evals/tree/main/experiments/compare) 是唯一一组可对比实验:钉死同一个模型(`gpt-5.4`)和同一个 sandbox(docker),只换 agent——[`bub-gpt-5.4.ts`](https://github.com/CorrectRoadH/coding-agent-memory-evals/blob/main/experiments/compare/bub-gpt-5.4.ts) vs. [`codex-gpt-5.4.ts`](https://github.com/CorrectRoadH/coding-agent-memory-evals/blob/main/experiments/compare/codex-gpt-5.4.ts),差异才能归因到记忆机制本身,而不是模型或运行环境。`niceeval exp compare` 跑整组,结果快照发布到线上报告。
|
|
34
|
+
|
|
35
|
+
## 下一步
|
|
36
|
+
|
|
37
|
+
- [接入你的 Agent](/zh/guides/connect-your-agent) — 从零接入一个 coding agent adapter。
|
|
38
|
+
- [Experiments](/zh/guides/experiments) — 组织可对比的实验矩阵。
|
|
39
|
+
- [评估 Skill 效果](/zh/example/claude-code-codex-skill) — 同一套「有/无 X 对比」思路,换成对比 Skill。
|