mcpField
F
firegoat-onboarding

firegoat-onboarding

github.com/firegoat-ai测试与质量017 次安装今天更新
代码仓库

关于 firegoat-onboarding

firegoat-onboarding 是一项帮助维护者编写 firegoat 评测的技能,用于测试 Agent 能否像新用户一样使用产品。它说明如何依据项目文档设计问题导向的提示词、配置隔离运行环境,并检查结果和产品使用情况。

主要功能

  1. 01依据产品文档提取测试场景
  2. 02编写以用户问题为核心的提示词
  3. 03配置全新 Agent 运行环境和测试夹具
  4. 04通过对话记录检查结果与工具使用
  5. 05清理测试数据和后台进程

适用场景

  1. 01评估产品的首次使用体验
  2. 02让 Agent 测试已安装的本地构建
  3. 03验证 Agent 使用了指定产品命令
  4. 04通过相同提示词比较不同配置

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/firegoat-ai/skills --skill firegoat-onboarding

安装后在 Claude Code 中输入/firegoat-onboarding确认已加载。

附带文件references/examples.md

详细介绍

起草 firegoat 评测

npx -y firegoat@latest eval 会在仓库外一个全新空文件夹(~/.firegoat/runs/<project-hash>/<random>/work,其名称与仓库中的任何内容都无关)中,运行用户自己的 Claude Code,不加载他们的任何配置;该文件夹有独立的 HOME 和一条提示词,随后会在那里运行你的检查。你的任务是:在 firegoat.yaml 中编写 2-3 个测试,让维护者知道 Agent 能否像新用户那样成功使用他们的产品。

1. 从仓库了解产品(阅读,不要运行)

阅读 README*、文档目录(docs/、*.mdx;优先看快速入门)、着陆页文案、用于了解安装名称和入口点的包清单(package.json、pyproject.toml、go.mod、Cargo.toml)、examples/,以及现有的 firegoat.yaml(保留其中的测试,见第 4 步)。了解:公开文档 URL、产品需要的凭据(仅环境变量名称),以及工具是否需要固定端口或会启动服务器或守护进程(第 4 步)。

编写任何提示词之前,先记下(写在给用户的备注中,不要写在 yaml 里):

  • 用户是谁,以及产品为他们解决什么问题,用他们自己的话表述,并参考 README、着陆页文案和文档。不要写功能列表;例如:“我的注册邮件总是进垃圾箱”,而不是“事务性邮件 API”。
  • 这类用户会在什么情况下使用它:他们当时在做什么,出了什么问题或缺少了什么。每条测试提示词都从这些情况之一开始。只选择文档表明产品确实能解决的问题,确保最终目标可以实现。

2. 将每条提示词写成用户的问题

测试要问的是:一个只了解用户问题的 Agent,能否找到产品并很好地使用它? 因此,请像真实用户向编码 Agent 输入内容那样编写提示词:

  • 用用户自己的话描述问题或目标。 模糊、不够具体都没关系,而且这是预期情况。 “新用户注册后应收到一封欢迎邮件”,而不是“使用 Acme 的 SDK,通过 POST /emails 发送欢迎 邮件”。
  • 不写产品名称、API、命令或程序包名称,不提供文档 URL 或步骤。 这些是答案;测试的目的就是看 Agent 能否找到答案。例外:如果真实用户只有在已经知道产品的情况下才会使用它(例如在其不同版本之间迁移、为其安装插件),最多可以在一条测试中提及产品名称。
  • 测试组合:一条从零开始的测试,再加一到两条已配置的测试。
    • 从零开始(恰好一条):测试用户及其 Agent 在完全没有上下文的情况下如何接触产品。install: 中不安装任何内容,env: 中不放密钥,不复制文档,不提供配置,提示词中不写产品名称:只有用户的问题。该测试衡量的是 AX tier list 所衡量的内容:Agent 能否找到产品,能否在没有人工协助的情况下开始使用(匿名访问或可认领的访问权限,或者自行注册),以及需要密钥时,错误信息和文档是否能准确告知它该怎么做?end_goal:无需人工协助就解决问题,或者 Agent 遇到第一个真正的阻碍时停下,并告诉用户还差哪一步(需要哪把密钥、去哪里获取)。在报告中,将此次运行标注到 tier list 的等级中:S 无需人工协助,A 只需确认,B 复制密钥,C 自行摸索,D 受阻。
    • 已配置(一到两条):用户注册后所拥有的配置。env: 中放入密钥(测试账户,或在本地通过 build: / install: 启动的 API 模拟服务,因为测试会在本地运行),通过 install: 安装待测构建版本。提示词仍然写用户的问题;此测试衡量产品在初次接触之后的实际使用情况。
  • 让上下文起到指引作用,就像真实项目中那样:程序包已通过 install: 安装,文档已复制到文件夹,密钥已放入环境变量中。只需说明“API 密钥已放在环境变量中”,不要写出变量名(写出变量名就等于透露产品信息)。只提供真实用户的项目中已有的内容:不要预先连接、预先配置或预先填充用户仍需自行设置的内容(MCP 服务、配置文件、现有数据)。这些设置本身就是测试的一部分。
  • 真实账户中的数据会不断累积。 如果 install: 或检查步骤会向共享账户(测试工作区、真实收件箱)写入内容,每次运行都会新增数据,后续运行也会看到这些数据。请使用 {{run.id}} 标记创建的内容,并在 cleanup: 中删除。
  • 每条测试只检查一个结果,这样失败时就能明确问题所在。
  • 用用户会说的话来要求提供证据:“向我展示它可以正常工作”、“给我发一封到 [email protected] 的邮件”、“保存一张截图”,这样检查步骤才有内容可验证。
  • “保持精简。” 这样 Agent 就不会构建演示应用。
  • 本地构建待测版本:使用 build: / install:(步骤 4)时,添加“此文件夹中安装的版本就是待测构建版本;不要从注册表重新安装或升级它。”
  • 不使用沙盒:文件夹位于仓库之外,且其路径不包含任何仓库信息;但 Agent 以当前用户身份运行,仍可能搜索磁盘来查找仓库。如果希望它自行查找内容,请添加检查,确保它从未访问过仓库(参见步骤 3)。
  • Agent 不得看到的预期答案(例如预先设置的密码、生成的 ID):在 install: 中将它们写入 $FIREGOAT_RUN_DIR,并在检查步骤中从该目录读取。Agent 无法获取该路径。

3. 编写 end_goal 和 checks

end_goal:用户的问题解决后,什么情况为真;可以通过 transcript 和 workdir 检查。提示词可能很模糊;end_goal 则很具体,也可以指明产品:“注册流程通过 Acme 的 SDK(而非原始 HTTP)发送欢迎邮件,且脚本会打印邮件 ID”。firegoat 不会对此评分,只会将它传递下去;你会在运行后(第 5 步)进行判断。它和每条 check 都只描述一个已经发生或尚未发生的结果:不要写“或等效方式”,不给部分分,也不能让 Agent 因停在阻碍处而通过。

checks:在运行结束后,于 Agent 的 workdir 中执行的 shell 命令;退出码为 0 即通过。环境变量: FIREGOAT_WORKDIR(workdir)、FIREGOAT_TRANSCRIPT(记录 Agent 执行操作的纯文本,逐行可 grep:每行 shell 调用均以 [n] $ 开头(整个调用使用相同的 n,因此多行命令或 heredoc 的任意一行都能匹配);带路径、url、pattern 或 query 的工具调用格式为 [n] Write <path> 等(不含文件正文:应检查文件);其他工具(包括 MCP 工具)均占一行,格式为 [n] mcp__<server>__<tool> <json input>,截断至 4000 个字符;工具输出缩进 4 个空格(最多 15 行或 1500 个字符);Agent 的每行文本和最终答案均以 agent: 开头,之后是它创建的文件)、FIREGOAT_SESSION(claude 的完整会话文件,JSON,体积约大 50 倍,已转义;不要 grep)、FIREGOAT_OUT(构建输出,同一次评估的所有运行共享)、FIREGOAT_HOME(本次运行专属的 HOME)、FIREGOAT_RUN_DIR(仓库中本次运行的文件夹,Agent 不可见)、FIREGOAT_REPO(存放 firegoat.yaml 的文件夹)、任何 vars 以及本次运行的 env:。install: 和 cleanup: 可获得相同环境变量,但没有 transcript 和 session。 证明结果并防止作弊:

  • 确实使用了目标工具:grep -Eq '^\[[0-9]+\] \$ (.*[ /])?acme +send' "$FIREGOAT_TRANSCRIPT"。 匹配完成任务的子命令,并允许二进制文件前面带路径:Agent 也可能通过 $FIREGOAT_OUT/acme、./node_modules/.bin/acme 或 npx 调用它。
  • 使用的是本地构建,而非从 registry 安装(完整防护规则见第 4 步): test -s "$FIREGOAT_TRANSCRIPT" && ! grep -Eq '^\[[0-9]+\] \$ .*(pip install|npm (install|i) .*acme@)' "$FIREGOAT_TRANSCRIPT"。
  • 只使用了本地文档(适用于这点本身就是要求的情况):test -s "$FIREGOAT_TRANSCRIPT" && ! grep -Eq '^\[[0-9]+\] WebFetch ' "$FIREGOAT_TRANSCRIPT"。
  • Agent 从未接触仓库($FIREGOAT_REPO,即存放 firegoat.yaml 的文件夹;checks 可以访问,Agent 不行),这也能避免它接触仓库的 fixtures/:
    - run: |
        test -s "$FIREGOAT_TRANSCRIPT" && ! grep -E '^\[[0-9]+\] ' "$FIREGOAT_TRANSCRIPT" | grep -qF "$FIREGOAT_REPO"
    

将 grep 限定在 transcript 的工具调用行,即 ^\[[0-9]+\] \$ (命令)或 ^\[[0-9]+\] Write 等,而非普通文本:工具输出(例如 README 中显示 $ npm install acme)和 Agent 的文字(例如“I won't pip install”)不应触发 check。要检查 Agent 说了什么,应限定为 ^agent: 。命令会按实际执行时的原样记录,不会转义;多行命令的每一行都带有此前缀,因此一次 grep 就能覆盖脚本和 heredoc。所有否定式 grep 都应以 test -s "$FIREGOAT_TRANSCRIPT" && 开头:文件缺失时 grep 会退出 2,而 ! 会将其变成通过。包含 : 的 check(例如 '^agent: ')必须放在 run: >- 块中(或加引号),否则 firegoat.yaml 会是无效 YAML。

4. 编写 firegoat.yaml

runs: 1                    # runs per test
build: npm pack --pack-destination "$FIREGOAT_OUT"   # optional: once per eval, in the repo;
                           # $FIREGOAT_OUT is first on the agent's PATH
install: npm init -y >/dev/null && npm install "$FIREGOAT_OUT"/*.tgz
                           # optional: in each fresh workdir before the agent starts
cleanup: pkill -f "$FIREGOAT_WORKDIR" || true
                           # optional: after the checks, always; never changes the verdict
vars:                      # optional: defaults for {{vars.KEY}}; `--var KEY=value` overrides
  SHA: main                # build, install, checks and cleanup only, never the agent
env:                       # optional: the agent's env (also its install, checks, cleanup)
  ACME_TELEMETRY: "off"
claude_args: []            # optional: extra claude arguments, one entry each
tests:
  - name: quickstart       # letters, digits, '.', '_', '-'; unique
    prompt: >-
      ...
    end_goal: ...          # judged by you after the run, not by firegoat
    checks:                # optional
      - run: grep -rq some-marker "$FIREGOAT_WORKDIR"
    timeout: 600           # optional, seconds
    env:                   # optional: on top of the top-level env:
      ACME_BETA_LOGIN: "1"
    install: cp -R "$FIREGOAT_OUT"/v1-app/. .   # optional: after the top-level install
    cleanup: acme down || true                  # optional: before the top-level cleanup
    claude_args: [--chrome]                     # optional: e.g. a test that needs a browser

env: 是为 Agent 设置环境变量的唯一方式;它看不到 vars:。可用它设置功能标志,以及将工具指向本地构建。值必须是字符串(数字要加引号),可使用占位符 {{vars.KEY}}、{{run.id}}、{{run.n}}、{{test.name}},以及 $FIREGOAT_OUT、$FIREGOAT_WORKDIR 和 $FIREGOAT_HOME(不会展开其他 $ 变量,$HOME 会按原样保留)。PATH、CLAUDE_CONFIG_DIR、FIREGOAT_*、ANTHROPIC_MODEL(请使用 model:)、HOME、XDG 的 *_HOME 变量和 CLAUDE_ENV_FILE 都属于 firegoat,无法设置。凭据应保留在运行 eval 的 shell 中,不要写入 firegoat.yaml。

每次运行都有自己的 HOME($FIREGOAT_HOME,包含 XDG 目录;claude 保留真实登录状态),因此并行运行不会相互冲突,工具在 ~ 中的状态也会从干净状态开始。只有忽略 HOME 的工具才需要设置 ACME_HOME: "$FIREGOAT_HOME/.acme";需要固定端口时,请使用 --parallel 1。运行时,密钥链登录状态(gh、docker)会显示为未登录:请在 install: 中登录工具,或在 env: 中传递令牌。对于 Agent 可能留在运行状态的服务器或守护进程,请使用 cleanup: 停止,而不是添加检查。

测试资源(辅助脚本、示例数据、测试所需的模拟服务器、MCP 配置)应放在 firegoat.yaml 同级目录 fixtures/ 下的文件中,并提交到仓库;绝不要以内嵌 heredoc 的形式编写。使用 build: cp -R fixtures/. "$FIREGOAT_OUT" 复制一次,然后在每个测试自己的 install: 中将所需文件复制到该测试的目录(cp "$FIREGOAT_OUT/wizard.mjs" .)。$FIREGOAT_OUT 中的文件也会加入 Agent 的 PATH。

比较配置(本地构建与注册表发行版、有无 --chrome):每种配置编写一个测试,使用相同的提示词(YAML 锚点,先写 prompt: &p ...,再写 prompt: *p),并为每个测试指定不同的 install:、env: 或 claude_args:。安装到运行目录中的技能不会在 eval 的标志下加载,因此无法进行有技能和无技能的对比。

build: 和 install: 可接受一条 shell 命令或命令列表。Python 示例: build: uv build --wheel --out-dir "$FIREGOAT_OUT",以及 install: uv venv && uv pip install "$FIREGOAT_OUT"/*.whl。写入 $FIREGOAT_OUT 的二进制文件会加入 Agent 的 PATH,但这只对通过裸名称调用的 CLI 有用。

  • npx:将 CLI 打包并安装到工作目录中(参见上方 npm 示例);npx acme 会优先使用 node_modules/.bin。添加一项肯定性检查 test -x "$FIREGOAT_WORKDIR/node_modules/.bin/acme"。
  • uvx:它使用自己的工具环境,会忽略工作目录的 .venv 和项目的 uv.toml,因此请使用 env: {UV_FIND_LINKS: "$FIREGOAT_OUT"} 将其指向 wheel。uv 会从索引和链接中选取最高版本,因此本地构建的版本必须高于发行版。
  • pipx run:改为在工作目录的 .venv 中测试裸名称二进制文件或 python -m acme,并在提示词中说明这一点。

无论哪种情况,都要防止使用注册表中的发行版: test -s "$FIREGOAT_TRANSCRIPT" && ! grep -Eq '^\[[0-9]+\] \$ .*((npm (install|i|add)|pnpm (add|dlx)) .*acme|(npx|bunx|yarn dlx) .*acme@|uvx .*acme(@|==)|pipx (run|install) .*acme|pip3? install .*acme)' "$FIREGOAT_TRANSCRIPT" 不要将普通的 npx acme 或 uvx acme 视为问题:使用本地构建时,这是正确的运行方式(但 npx acme@latest 会跳过本地构建,因此检查规则中包含 acme@);上方对 node_modules/.bin 的肯定性检查可证明本地构建已就绪。只有测试应使用仓库的本地构建时才添加这些检查。

如果 firegoat.yaml 已存在,请合并:保留所有现有测试和顶层键,并追加新内容;若名称冲突,请在新名称后添加 -2。绝不要删除或改写用户测试,唯一例外是 init 创建的入门 goat 冒烟测试:先运行它以确认配置正常,再将其替换。提示词请使用 >- 折叠块,以确保冒号和引号在 YAML 中有效。

完成前,请重新检查文件:确保其可解析为 YAML;每个测试都有非空的 name、prompt 和 end_goal;名称唯一且符合 ^[A-Za-z0-9._-]+$;并且任何位置都没有凭据值。

测试 MCP 服务

当产品提供 MCP 服务时,请按以下步骤操作:例如,包含用于启动服务的包 bin 或 mcp 子命令、介绍 MCP 的 README 或文档页面,或依赖项中包含 @modelcontextprotocol/sdk(或 mcp、fastmcp)。

  • 像往常一样在 install: 中安装本地构建版本(参见上面的 npm 示例),这样,被测服务就会位于运行文件夹中的 ./node_modules/.bin/acme-mcp(或 .venv/bin/acme-mcp)。
  • 提交 fixtures/mcp.json,其中包含指向本地服务的静态配置。claude 会从自身环境变量中展开其中的 ${VAR},这些环境变量包含本次运行的 FIREGOAT_HOME、FIREGOAT_WORKDIR 和 FIREGOAT_OUT;相对路径以运行文件夹为基准。MCP 服务会继承 claude 的真实 HOME(其登录用户的 HOME),因此务必将服务的 HOME 设为 ${FIREGOAT_HOME},否则它会写入用户的 HOME。服务在每次运行中保留的其他内容(如数据库文件、端口)也要用同样的方式设置为每次运行专属的值。请使用带大括号的 ${...};未设置的变量会保留为字面文本。
    {"mcpServers": {"acme": {"command": "./node_modules/.bin/acme-mcp", "args": ["serve"],
      "env": {"HOME": "${FIREGOAT_HOME}", "ACME_DB": "${FIREGOAT_WORKDIR}/acme.db"}}}}
    
  • 在每项测试中传入配置:build: 会复制 fixtures(cp -R fixtures/. "$FIREGOAT_OUT"),而启动时已连接服务的测试会设置 claude_args: [--mcp-config, $FIREGOAT_OUT/mcp.json]。只有通过这种方式传入的配置才会加载(--strict-mcp-config 始终启用),因此未传入配置的测试启动时不会连接任何 MCP 服务。
  • 提示词应先描述问题。 连接服务后,提示词应描述用户遇到的问题,绝不能提及工具:关键在于 Agent 是否会自行选用这些工具。此外,还要至少编写一项未连接服务的测试:Agent 必须自行找到 MCP 服务并完成配置(例如,在其文件夹中编写 .mcp.json,或运行 claude mcp add)。它在运行中添加的服务可能要到新会话中才会加载,因此该测试的 end_goal 和检查项应评估配置是否完成(test -s "$FIREGOAT_WORKDIR/.mcp.json",或 transcript 中是否有 claude mcp add 命令),而不是工具的使用情况。
  • 在 transcript 中检查工具的使用情况:MCP 调用的行格式为 [n] mcp__<server>__<tool> {...},其中 <server> 是 mcpServers 下的键: grep -Eq '^\[[0-9]+\] mcp__acme__search' "$FIREGOAT_TRANSCRIPT"。
  • 在 cleanup: 中停止服务:stdio 服务会随 claude 一起结束,但它启动的子进程,或在 install: 中启动的 HTTP 服务,需要通过 cleanup: pkill -f "$FIREGOAT_WORKDIR" || true 停止。

5. 运行和评分

firegoat 会使用用户现有的登录状态运行用户的 claude。如果 eval 提示 claude 尚未登录,请让用户运行一次 claude 并登录;不要默默等待。自行运行 npx -y firegoat@latest eval --json(它会先显示版本号)。一次运行需要几分钟。 npx -y firegoat@latest eval --dry-run 会验证 firegoat.yaml,并列出运行项,但不会启动任何运行:先运行它。运行 eval 时不要使用 --no-upload:用户登录 firegoat.ai 后,eval 会将每个会话上传为私有跟踪记录并打印其 URL,用户查看的就是这些跟踪记录。请在报告中附上跟踪记录 URL。只有用户提出要求时才使用 --no-upload。

firegoat 只运行脚本检查;这些检查会设置退出代码(0 表示通过,1 表示某项检查失败,2 表示未评分,3 表示配置错误)。请根据退出代码和每次运行的 status 判断结果,而不是根据输出末尾判断:被截断的 --json 输出只会显示最后一次运行。你需要评判 end_goal。 对每次运行,读取 .firegoat/runs/<runId>/<test>/<n>/run.json(提示词、end_goal、检查结果、路径),然后:

  • transcript(几 KB):Agent 执行的每条命令及其简短输出、它说了什么、最终答复以及创建的文件。它是否借助产品达成了最终目标,还是弄虚作假、放弃了,或寻求帮助?只有当某一步的输出被截断且你需要查看时,才打开 session(claude 的完整 JSON)。
  • workdir:它创建的文件。如果最终目标需要通过运行这些文件来证明,就运行它们。其中的每项标准都要判定为是否达成,并提供证据。

除了检查结果,firegoat 不会记录其他评判结果:请自行记录评分(每次运行:通过/失败及证据)。某次运行可能通过了检查,但仍未达成最终目标(例如硬编码输出,或用竞品解决问题);请明确指出。

目标是让 eval 失败。 一套首次运行就全部通过的测试没有衡量价值:关键是找出 Agent 卡在哪里。目标是让 20% 到 50% 的运行失败。如果超过 80% 的运行通过,请提高通过测试的难度并再次运行 eval,最多两次:

  • 移除引导信息:提示词中的产品名称或其变量、预先连接的服务、预置数据,以及真实用户不会拿到的复制版文档。
  • 让需求更模糊,更接近用户实际描述问题的方式。
  • 要求提供有证据的实际结果(确实运行、发送或保存了某些内容),而不是代码草稿。
  • 加入符合用户实际情况的约束(现有项目、他们已在使用的框架,或依赖第一步结果的后续步骤)。 确保每个最终目标都能通过产品文档所述的方式达成:因任务不可能完成而失败的测试对用户没有帮助。请报告你强化了哪些测试,以及原因。

6. 交接并提交

用几句话告知用户:你添加了哪些测试以及原因、需要导出的环境变量、各次运行的检查结果和评分,以及 Agent 卡在哪里(引用 transcript)。

eval 提交后,入门设置才算完成,这样团队和 CI 才能运行相同的测试。 最后请询问用户是否提交,并表示可以代为提交:“提交 firegoat.yaml 以完成入门设置吗?”用户同意后,使用类似 chore: add firegoat evals 的提交信息提交:

  • firegoat.yaml,以及你创建了 fixture 时的 fixtures/(.firegoat/ 会在 git 中忽略自身);
  • 仅当技能安装在仓库中时(通过 init --local-skills 安装,或选择了“this repo”;默认是全局安装在 ~/.claude/skills/,无需提交任何内容): .claude/skills/firegoat-onboarding/ 和 skills-lock.json。

如果 .gitignore 忽略了 .claude/,请说明并在运行 git add -f 前征求用户同意。 切勿提交 .firegoat/ 中的任何内容(运行记录、会话)或凭据。

示例

references/examples.md 中有带 YAML 的优质和不良测试示例。

评论

支持 Markdown