Agent 测试使用指南
明确要测什么、怎样算好 → 准备 Case → 运行多组 Input → 按标准评审实际产物 → 必要时回查 Session。 设计依据见测试与迭代。
一个 Case 对应一道任务,以该目录为测试根目录 ROOT:criteria.md 是共同评判标准,inputs/ 下是不同实验条件的输入。一个 Input 含任务请求、可选工作区及 Agent 配置;同一 Input 可以重复执行,每次称为 Run。
直接使用 scripts/run-pi-test.py 运行 Pi + Docker 测试。它负责隔离工作副本、构建镜像、执行预算和保存会话;准备者负责题目、判据和评审。内置镜像固定使用 Pi 0.87.1,下文配置示例与该版本对齐。
1. 准备根目录与运行环境
在知识库(vault)外为每道任务建一个 Case 目录,例如 D:/agent-tests/cases/001-bookmark-design,并把它用作 --root。宿主需有 Python 3.12+、Docker CLI 和已启动的 Linux 容器引擎;宿主不必安装 Pi。Docker 引擎须能访问本机绑定路径,首次构建可能需要网络。
需要给容器传环境变量时,在 Case 根目录创建可选的 .env(使用 Git 时加入 .gitignore)。运行器只读取当前 --root 下的 .env,不继承父目录;变量名须与 Input 配置中的引用一致。
.env 示例(将占位值换成实际值):
MODEL_API_KEY=your-token
后续 Input 中的 models.json 可通过 ${MODEL_API_KEY} 引用同名变量。.env 使用 Docker --env-file 格式:UTF-8、每行 NAME=VALUE,允许空行和整行 # 注释;不要写 export、多行值或重复变量。值按原样传入,不展开 $VAR,引号也属于值;含空格的值不必加引号。HOME、PATH、PI_CODING_AGENT_DIR、PI_CODING_AGENT_SESSION_DIR 由运行器管理,不能在此覆盖。
.env 不放进 Input 或 Git。运行器通过 Docker --env-file 注入,不保存变量值;但它仍是明文文件,Docker 管理员可以查看容器环境。运行中不要修改 .env,检测到变化会停止后续派发。
下文运行命令均在本 Skill 根目录执行,并将示例路径替换为实际 ROOT。
2. 手动准备 Input
按测试与迭代确定本轮目的、输入与标准后,准备以下文件:criteria.md 保存共同评判标准;inputs/ 保存各组执行者实际获得的请求、工作区与配置。
批量准备或核查材料可用短脚本;批次驱动与状态管理复用现有运行器。
每次执行从 Input 建立独立工作副本,修改保存在 Run 中,不改变源 Input。按条件创建多份 Input,例如:
ROOT/
├─ criteria.md 同一道题的共同评判标准
└─ inputs/
├─ with-skill/
│ ├─ request.md 必填,内容非空
│ ├─ workspace/ 可选,初始任务文件
│ ├─ agent-config/ 可选,Pi 原生配置与资源
│ └─ Dockerfile 可选,自定义执行环境
└─ without-skill/ 同题另一条件,结构相同
├─ request.md
├─ workspace/
├─ agent-config/
└─ Dockerfile
同一道任务可以有多组 Input。比较某个 Skill 的增益时,两组除目标 Skill 外保持相同的请求、工作区、模型和预算。
request.md 是发给 Agent 的第一条用户消息,以 UTF-8 保存。请求与附件如何取舍,见按信息来源准备材料。例如:
帮我设计一个新标签页,我想快速找到我的书签,然后点击
workspace/保存初始任务文件。其副本挂载到容器/workspace并作为工作目录,Agent 在这里读取、创建和修改文件;省略时从空工作区开始。工具会完整复制目录,包括.git和旧产物,准备时检查实际复制范围,排除本轮不允许读取的历史答案、评审材料和密钥。agent-config/是本次测试使用的 Pi 配置与资源。运行时,其副本挂载到容器的 Pi Agent 目录/root/.pi/agent,Pi 从这里读取models.json、settings.json,并加载skills/、extensions/等资源。按任务需要准备;只有模型选择与认证已由环境变量、命令行等其他途径满足时,才可省略整个目录。运行器不继承宿主 Pi 的登录与配置。配置中的路径和插件依赖须适合容器 Linux 环境,资源需自包含,不能依赖宿主绝对路径。Dockerfile定义运行 Agent 的容器环境,例如所需的语言、工具和依赖。工具据此构建镜像,再用镜像启动各次运行;省略时使用内置环境。
运行器只装载选中 Input 的请求、工作区、配置和 Dockerfile,不会把 ROOT/criteria.md 提供给被测 Agent。准备记录和评审材料放在 Input 之外,按材料与证据归属保存。
认证引用第一步 .env 中的同名变量,不在 Input 写真实密钥,也不直接复制宿主整个 .pi 或历史会话。
Skill 按 Pi 的作用域放置:项目级可放 workspace/.agents/skills/<name>/ 或 workspace/.pi/skills/<name>/,用户级可放 agent-config/skills/<name>/。扩展可放 workspace/.pi/extensions/ 或 agent-config/extensions/。资源发现和加载遵循 Pi 原生规则。
对照某个 Skill 时,检查项目级与用户级位置是否都正确控制了该 Skill,避免残留影响比较。
首次配置模型
内置供应商的认证方式见 Pi 0.87.1 模型文档。下面以兼容 OpenAI Chat Completions 的服务为例,将文件放入每组 Input 的 agent-config/。两组只比较 Skill 时,模型配置保持一致。
models.json:
{
"providers": {
"test-endpoint": {
"baseUrl": "https://api.example.com/v1",
"api": "openai-completions",
"apiKey": "${MODEL_API_KEY}",
"models": [
{
"id": "replace-with-model-id",
"contextWindow": 32768,
"maxTokens": 8192
}
]
}
}
}
settings.json:
{
"defaultProvider": "test-endpoint",
"defaultModel": "replace-with-model-id"
}
替换 baseUrl、两处模型 ID 和两个容量数值,依据所选服务的文档填写。test-endpoint 是这组服务在 Pi 中的名称,两份文件必须一致。apiKey 引用 Case 根目录 .env 中的 MODEL_API_KEY;真实密钥只填入 .env。若服务在宿主本机,Docker Desktop 中使用 host.docker.internal 及实际端口,避免把容器内的 127.0.0.1 当成宿主。
示例字段已对照上述模型文档及 Pi 0.87.1 设置文档核对。两份 JSON 可解析,默认模型与服务名称一致,models.json 已通过 Pi 0.87.1 配置解析器校验;尚未连接实际服务验证。配置完成后,按下一节运行;模型注册、认证或请求报错时,查本批终端输出和日志。
启动前按输入设计与结论边界核对输入,再检查目录、路径和资源是否完整。只要求准备时,到这里交付,不启动任务、构建或安装;输入冻结时点见下文“名称与版本规则”。
名称与版本规则
Input 名和批次名必须是单段名称:允许中文、字母、数字、连字符、下划线和点;不能以点或连字符开头,不能是路径或 Windows 设备名,不能以点或空格结尾。Input 名按 casefold 比较,不能仅靠大小写区分;批次不能覆盖已有目录。
未登记的 Input 可以直接修改。提交批次时,运行器先写入 batch.json 并记录 Input 指纹;之后改动该 Input 必须换名称,即使批次构建或模型预检失败也一样。
criteria.md 不由运行器复制或归档。评审前应保留本轮使用的标准版本,避免结果出来后改变判断依据。
运行时由工具创建批次目录和各 Run 的工作副本。
3. 用 CLI 运行批次
开始前确认 Input 中配置、扩展与构建文件可信(Pi 以 --approve 加载资源),且模型服务能从容器访问。Docker Desktop 访问宿主服务可用 host.docker.internal,容器内的 127.0.0.1 不是宿主。
仓库基线检查按需进行,不是每批必经门禁。 需要区分既存失败与模型新增缺陷时,优先复用同版本、同环境的已有证据;证据不足且已获执行授权时,在隔离副本中直接运行仓库现有检查命令,不默认另建预检驱动。发现失败先判断它是否妨碍本轮能力的观察:无关的既存失败可记录并在评审中排除,不能仅因基线非零就阻断整批;影响安全或使本轮测试无法有效观察的,再暂停相关执行、说明原因。只要求准备时仍不构建或安装。
确认两组 Input 使用同一可用的默认模型并已配置凭据后,运行两个 Input、各两次:
python -B -X utf8 scripts/run-pi-test.py run --root D:/agent-tests/cases/001-bookmark-design --input with-skill --input without-skill --batch comparison-01 --repeat 2 --jobs 1
--input选择ROOT/inputs/下的名称,可重复;不是任意目录路径。--repeat 2是每个 Input 两次;--jobs 1串行,按 A1、B1、A2、B2 排列。改成--jobs 2最多两个在途 Run,不保证启动和结束顺序。模型服务未必支持相同并发;推理并发为 1 时推荐串行。- 命令前台阻塞到整批结束,终端显示容器名、结果位置和退出码。
- 单次任务失败、达到步数上限或超时,保留结果并继续其他已安排任务,不自动重试。Docker 连接、创建、等待或本地文件操作等基础设施错误会停止派发,并尝试停止在途容器;停止失败会直接报告。
只跑一个 Input 一次时,传一个 --input 并省略 --repeat、--jobs。每次默认最多 12 步;需要更低预算可加 --max-steps 10,需要超时可加 --timeout SECONDS。
批次生成的文件
ROOT/ 一个 Case
├─ criteria.md 评判标准,运行器不复制
├─ inputs/ 本题多组源 Input,工具不修改
└─ sessions/
└─ comparison-01/ 批次根目录
├─ batch.json 所选输入路径与指纹
├─ build/ 各 Input 的构建日志
└─ sessions/
├─ with-skill-run-001/
│ ├─ session.jsonl Pi 原生会话
│ ├─ workspace/ 本次工作副本 → /workspace
│ ├─ agent-config/ 本次配置副本 → /root/.pi/agent
│ ├─ home/ 本次 home → /root
│ ├─ request.md 本次请求副本
│ ├─ invocation.json 实际运行条件
│ ├─ pi-entry.py
│ ├─ Dockerfile
│ └─ .dockerignore
├─ without-skill-run-001/
├─ with-skill-run-002/
└─ without-skill-run-002/
工具在任何容器启动前备齐所有 Run 的隔离工作副本,每次从输入独立准备,不续接上一次产物。准备或构建失败时可能只留下部分文件;预建的 session.jsonl 可能仍为空,此时 Web 不显示会话。没有会话不代表没有尝试运行,应结合终端报错和日志检查。
会话名称与 Run 目录名一致(如 with-skill-run-001),保存在对应的 session.jsonl。batch.json 和 invocation.json 记录输入及运行条件;状态与退出码通过 Docker 查询。
4. 查看和对照结果
运行结束后,先看终端退出码,再查看本批各 Run 的会话与产物。根据使用者选择下述读取方式。
Agent:直接读取文件
在 ROOT/sessions/BATCH/sessions/ 下按运行目录名找到目标 Run,直接读取 session.jsonl 中的请求、回答、思考和工具调用,并结合 workspace/ 的实际产物判断。例如,第一批带 Skill 的首次运行在:
ROOT/sessions/comparison-01/sessions/with-skill-run-001/session.jsonl
JSONL 每行是一条原生 JSON 记录,可按需要解析和筛选。若会话包含分支,需结合记录的 id、parentId 辨认执行路径,不能把不同分支简单拼接。
人:用 Pi Web 浏览会话
需要可视化查看时,启动 Pi Web。宿主需有 Node >=22.19 和 npm(含 npx);在单独的 PowerShell 窗口执行(路径指向本 Case 的实际批次):
$env:PI_CODING_AGENT_DIR = 'D:\agent-tests\cases\001-bookmark-design\sessions\comparison-01'
npx @agegr/pi-web@0.10.0 --port 30142 --hostname 127.0.0.1
运行脚本结束时也会打印一份 Bash 语法的命令;Windows PowerShell 使用上面的 $env: 写法。PI_CODING_AGENT_DIR 必须指向当前 Case 的 ROOT/sessions/BATCH,而非 Case 根目录或里面的单个 Run。该环境变量只影响当前 PowerShell 窗口及其子进程。
首次 npx 可能联网下载到 npm 缓存;若已有兼容的 pi-web 命令,也可直接用它替换 npx @agegr/pi-web@0.10.0。已验证版本为 0.10.0。服务仅监听本机,浏览器地址为 http://127.0.0.1:30142;加 --no-open 可禁止自动打开浏览器。端口占用时换一个端口,退出按 Ctrl+C。
在列表按 Run 名选择会话,例如 with-skill-run-001,查看回答、工具调用和 Skill 加载过程。若当前终端设置了 PI_WEB_PASSWORD,浏览器需要使用该密码登录,未登录的 API 请求返回 401;认证设置仍按 Pi Web 原生方式管理。
这是查看入口,不保证原始会话只读。 UI 的操作可能修改原会话;保留证据时不要在原会话中续聊或编辑,必要时先备份。会话中的容器路径 /workspace 不会映射成宿主产物链接,文件须从对应 Run 的 workspace/ 打开。
核对证据与判断结果
| 要查什么 | 查看位置或方式 |
|---|---|
| 回答、工具调用、Skill 加载 | Agent 直接读取 session.jsonl;人可用 Pi Web 浏览同一份会话 |
| 实际请求、配置与运行条件 | Run 中的 request.md、agent-config/、invocation.json;批次 batch.json |
| 生成或修改的代码、文档 | Run 的 workspace/ |
| 容器状态、退出码、标准输出和错误 | docker inspect、docker logs |
| 构建失败 | ROOT/sessions/BATCH/build/INPUT.log |
用终端或 invocation.json 中的实际容器名检查:
docker inspect --format '{{json .State}}' CONTAINER_NAME
docker logs --tail 100 CONTAINER_NAME
| 容器退出码 | 含义 |
|---|---|
0 |
正常结束,不代表任务质量通过 |
123 |
达到步数上限,仍有继续执行意图,已停止 |
124 |
任务超时 |
130 |
适配器收到中断信号并结束 |
1 |
执行或模型错误 |
2 |
模型预检等配置错误 |
| 其他非零值 | Pi、系统信号或容器错误,结合状态与日志检查 |
整批全部正常结束返回 0;有失败、截断或基础设施问题返回非零;Ctrl+C 中断返回 130。
运行器不自动调用额外模型评审。自行检查或交给评审 Agent 时,按评审实际结果选择检查方式;退出码只表示执行状态。
需要保存判断时,在 Run 下另建 review/。不改写原始会话和产物;会修改文件的检查另取副本。比较多份产物所需的匿名副本与组别映射放在源 Input 之外,分别限制评审者可见范围。
比较同一 Case 的两个 Input 时,从 ROOT/criteria.md 留存本轮标准版本,将共同请求与双方实际产物复制到不暴露组别的评审目录。Run 目录名可能包含组别,不能直接作为匿名材料路径。成对盲选、原票冻结、解盲及核查要求统一见成对盲选与独立评审和冻结、解盲与核查。
5. 调整输入,再跑一批
依据前批证据决定下一轮要验证什么,再调整相关输入:可以是请求、Workspace 中的文件、Agent 配置、Skill 或执行环境。
例如,怀疑 workspace/README.md 中的过时说明误导了 Agent,可以在同一个 Case 的 inputs/ 下,将 with-skill 复制为新 Input clean-workspace,只在副本中修正那段说明,其余条件保持不变。此时比较的是工作区信息变化,不是目标 Skill 的效果。用新批次并排运行原输入与调整后的输入:
python -B -X utf8 scripts/run-pi-test.py run --root D:/agent-tests/cases/001-bookmark-design --input with-skill --input clean-workspace --batch comparison-02 --repeat 2 --jobs 1
按本轮标准比较产物,必要时回查本批 JSONL 核实预期行为;需要可视化查看时,用上节命令将 Pi Web 指向新批次。
未登记的 Input 可直接修改;已登记的 Input 改内容须另取名称(见名称与版本规则)。只改命令行中的重复次数、预算,或通过 --model、--thinking 覆盖模型设置时,可复用原 Input,但批次名始终要换新;修改 Input 内的配置文件仍须另取名称。修改外部 Skill 源不会自动更新已有 Input;需要测试新版本时更新未登记输入或新建对照组。保留旧批次原始证据,不改写会话或 batch.json。
比较时核对请求、工作区、模型、参数和其他配置,将结论限定在证据支持的范围;多个条件同时变化时,不能直接归因于其中某一项。
中断、失败与容器保留
- 正常完成、失败或预算截断后,容器不自动删除,Run 下的 home、工作区、配置和会话也保留。
- Ctrl+C 停止派发并尝试停止在途容器,必要时使用 Docker kill;不会删除容器、恢复或重跑队列。单独停止一个 Run 可在核对名字后执行
docker stop --time 5 CONTAINER_NAME,其他任务继续按当前安排推进。 - 强杀编排进程、终端异常关闭、Docker 失联或机器重启后,不能保证任务已停止;直接用 Docker 核对,不凭陈旧文件猜测。
- 停止后不能
docker exec,但仍可 inspect、logs、cp。不要随手docker start原容器:会再次执行任务并可能改写证据。 调试时另取副本,启动独立环境。 - Docker 不会因停止或资源紧张自动删除这些容器。确认不再需要后,对明确的容器执行
docker rm CONTAINER_NAME;工具不自动 prune。
参数、预算与安全边界
| 参数 | 作用 |
|---|---|
--root ROOT |
必填;知识库外的当前 Case 目录,读取其中可选的 .env 和 inputs/ |
--batch NAME |
必填;新建批次,不覆盖已有目录 |
--input NAME |
run 必填,可重复;选择具名输入,按 casefold 唯一 |
--repeat N / --jobs N |
每个输入的次数 / 最大在途运行数,均默认 1 |
--model PROVIDER/MODEL |
可选,覆盖 Pi 默认模型;提供时先做原生注册检查,不模糊回退 |
--thinking LEVEL |
可选,覆盖 Pi 默认思考等级 |
--max-steps N |
默认 12;一次模型响应及其引出的全部工具执行计一步 |
--timeout SECONDS |
可选;限制每次推理任务及输出流等待,不含构建和模型注册预检 |
步数是进程外的尽力限制,不是严格费用上限:检测到第 N 步时下一次请求可能已发出,客户端停止也不保证远端立即取消推理。最终答复恰好在第 N 步结束时可正常退出。
Input 可提供独立 Dockerfile;省略则使用内置 Node、Python 3.12、Pi 0.87.1 环境。自定义镜像必须提供 Linux、PATH 上的 python(3.12+)及 pi,并允许容器用户读写挂载目录。输入准备不接受链接或目录重定向。
构建上下文只含 Dockerfile 与工具提供的 .dockerignore,不包含任务、配置或工作区。每个输入在一批中构建一次,重复运行使用固定镜像 ID;Docker 管理构建缓存,工具不维护缓存或清理镜像。严格复现应固定镜像、语言与 Pi 版本;构建没有独立超时。
容器不挂载宿主 home、知识库、Docker socket 或其他 Run,只得到本次所需副本;网络保持可用,可信扩展可执行代码。这是避免意外读取历史的隔离,不是对抗恶意代码的强安全沙箱。保留的容器配置可见转发的环境变量(包括凭据),文件和插件状态也可能含敏感信息;Docker 管理员可访问,须按需保管和清理。
维护与验证
在 Skill 根目录运行无需 Docker 的检查:
python -B -X utf8 -m unittest discover -s test -p "test_*.py"
需要实容器检查时,先构建测试镜像:
docker build -t pi-test:local scripts/resources/docker/
在当前 shell 设置 PI_TEST_DOCKER_IMAGE=pi-test:local,再运行同一 unittest 命令。假 Pi 检查用于验证编排、预算、退出与保留行为;真实 Pi 的推理前探针不能替代真实模型任务验证。检查后只清理测试专用容器及临时镜像,不清理正式运行。
以上是验证方法,是否通过须以对应版本实际执行的测试结果为准。固定响应、假 Pi 与无推理探针验证的是执行及查看流程,不代表真实模型任务或 Skill 效果通过。