连 GitHub 仓库
测试会调用工具、改数据的 Agent,推荐用这种接法。你们装上我们的 GitHub App(对代码只读),选好仓库和分支。之后每次运行,平台都会开一台全新的虚拟机(沙盒),开在伦敦。沙盒克隆指定的提交、装依赖、在 Agent 旁边起好测试后端,然后跑测试。运行结束,虚拟机随即删除。
开始之前
- 一个能装 App 的 GitHub 组织或账号。
- 一个能用命令启动的 Agent(比如
node dist/agent.js或uv run python -m my_agent),它通过 HTTP 或 MCP 调用工具。 - Agent 的工具所连的测试后端:能用 Docker Compose 起来,并且能重置、能读出数据。只接测试环境和测试凭证:不要让运行连到生产系统或真实客户数据。
- Agent 需要的密钥,下面作为项目密钥保存。模型密钥可以不给:没有
OPENAI_API_KEY时,由平台的模型应答 Agent。
1. 建项目,选接法
- 在网页上点「新建项目」,选「会调用工具的 Agent」,起个名字。
- 打开目标,在接法里选「连 GitHub 仓库(推荐)」。
2. 装 GitHub App
点「去 GitHub 装 App」。在 GitHub 上选 Only select repositories,只勾要测的仓库;装完 GitHub 会把你带回向导。平台接不了这个安装时,向导会写明原因和怎么办。例如这个安装已经连在你们的另一个组织上,要先在那边第 1 步点这个账号旁的「断开」。
App 申请下面这些权限:对代码只读,只写检查和 PR 上的那一条评论。GitHub 的 App 权限是一整套一起申请的,装的时候不能单独去掉其中一项,所以 Checks 写权限在安装时就一起给了。
| 权限 | 级别 | 用来做什么 |
|---|---|---|
| Repository contents | 只读 | 把要测的那个提交克隆进沙盒 |
| Metadata | 只读 | 在向导里列出仓库和分支 |
| Pull requests | 读写 | PR 打开或更新时自动跑;打开了「GitHub 检查」的项目,在 PR 上发一条带发布门槛表格的评论,每轮更新它 |
| Checks | 写 | 只在打开了「GitHub 检查」的项目上用:每次自动测试在测过的那个提交上挂一条检查(结论和报告链接) |
平台不推代码、不建 PR,也不改你们仓库里的内容。它写的只有这些,而且只在打开了「GitHub 检查」的项目上写:那条检查,以及 PR 触发的那一轮在 PR 上的一条评论(每轮找到它更新,不会发第二条)。
App 申请「Pull requests:读写」之前装的安装还是只读,要由这个 GitHub 组织的所有者在 GitHub 上接受 App 的权限更新。在那之前 PR 那一轮只挂检查、不发评论,检查里会写明要怎样才有评论。
App 加上 Checks 权限之前装的安装没有这项权限,要由这个 GitHub 组织的所有者在 GitHub 上接受 App 的权限更新,之后才能挂检查。在那之前测试照常跑,只是不挂检查。
沙盒克隆时拿到的是一个 GitHub 安装令牌,一小时有效,只覆盖你们选的仓库。它只通过请求头传递,不写进检出目录,Agent 所用的用户也读不到。
3. 选仓库和分支
选账号、仓库和分支。账号默认是你刚装 App(或刚给它加仓库)的那个,不然是你上次连项目用的那个;仓库总是由你自己选,选好后默认分支自动填上。保存前,向导会展示数据边界:指定提交的源码会克隆进我们云上的沙盒,沙盒跑完即销毁。之后只保留运行包(证据、脱敏轨迹和日志),依赖缓存保留 30 天。勾「我知道了」,点「保存绑定」。各种接法的对照见数据边界表。
4. 测试接入文件:.reviewctl/review.yaml
平台读取分支上最新的提交,展示探测结果:运行时、锁文件、有没有 Compose 文件,以及仓库里是否已有 .reviewctl/review.yaml。
- 仓库里已有:沙盒就按仓库里的这份跑。
- 仓库里没有:向导按探测结果起草一份。填上启动 Agent 的命令,保存到平台覆盖层。覆盖层是平台替你们保存的文件,在沙盒里盖在仓库的
.reviewctl/上面。仓库里已有的文件,也可以在覆盖层里改一份副本。覆盖层不会改动你们的仓库;想把这些文件收进仓库,拷出来自己提交就行。读不通的review.yaml不会保存,向导会写明哪一行、哪里不对,比如缺启动命令、有不认识的字段、直接写了密钥、YAML 格式错了。 - 辅助文件:适配脚本(比如
.reviewctl/harness.py)、测试数据这类文件,也可以放进覆盖层。在这一步的「覆盖层里的文件」里点「加一个文件」,填.reviewctl/下的路径,再粘贴内容或从本地文件读入。沙盒里它们和review.yaml一起放在.reviewctl/下。每个文件只能是文本,最大 256 KB。
谁写的
覆盖层的文件列表有一列「谁写的」:「你们写的」(有人在这里上传、保存或恢复的)、「你们的开发机 AI 写的」(连上平台的编码 AI 存的)或「平台写的」(「让 AI 补全并检查」和它的修复写的)。只改了文件里的一项(比如平台检查前写进 runner_env 的值),或者存的内容和原来一样,「谁写的」不变。这一列加上之前存的文件,平台按审计日志补上;查不出来的写「—」。
平台的 AI 不会自己去改你们写的文件。AI 诊断说要改的接入文件里有你们写的,就不会自动交给「让 AI 补全并检查」,而是写明原因,把「让 AI 按诊断修接入」留给你点;点了照旧修。诊断说到这些文件时写「你们写的接入文件」,不写「平台写的」。它们仍然算测试接入,不算你们 Agent 的代码。
不报错的写错
有的写法读得通、检查也不报错,但跑起来和写的意思不一样。平台在保存覆盖层时、这一步的「测试接入文件」下面、「测试新版本:全部选项」的「开始前检查」里列出来:「接入文件里这些地方不会报错,但跑起来和写的意思不一样:…」。只提醒,不拦:
- 重置命令、数据读取的文件和数据查询、
scenarios.dir、版本文件的路径写成了从仓库根目录算起。这些都从.reviewctl/算起,[node, .reviewctl/seed.mjs]找的是.reviewctl/.reviewctl/seed.mjs。提醒写明是第几行、该怎么改。 agent.version的tool_config_files或prompt_files里的文件哪里都没有:平台跳过它,版本对比里看不出它变。runner_env里的变量不会传给 Agent:要传,把它加到agent.env_passthrough(见 runner_env)。
另外两件事写在别处:两条路由用逗号写在同一行时,保存会被拒,报错写明第几行、要每条路由单独写一行;backend.reset 以测试机的用户执行、它建在仓库副本外面的文件 Agent 读不到,这一句写在运行日志里(见 review.yaml 参考)。
让 AI 补全并检查
不想自己写 review.yaml,就点这一步上面的 「让 AI 补全并检查」。你只需要点这一下,剩下的由平台来做,这一步里会一项项显示进度:
- 读仓库:经 GitHub App 只读地读绑定分支最新的提交,包括目录和最多 40 个文本文件(一共最多 150 KB)。这些文件说明 Agent 怎么启动,比如 README、Dockerfile 和 Compose 文件、依赖清单、
.env.example、入口程序和它导入的模块、这些代码按文件名打开的文本文件(运行时加载的制度、提示词文件)、几个脚本和测试。它从不读.env、看起来存着密钥的文件(密钥、证书、凭证文件)和二进制文件;读到的内容里像密钥的部分会先隐藏掉。 - 写接入文件:平台的模型写
review.yaml。Agent 没有「交一句任务、拿一句回复」的入口时(比如 webhook 机器人,回复是之后才发出去的),它再写一个适配脚本(比如.reviewctl/harness.py),直接调用仓库里生成回复的函数。仓库里看得出 Agent 经 HTTP 或 MCP 调自己的工具时,它把这些调用接到工具代理上;仓库带着能重置、能读出的测试后端时,也一起接上。做不到时这次只看回复,这一步会如实写明(「这次只看回复……」「不会核对改动的数据……」)。Agent 做事前要问用户(请求权限、请用户确认)时,适配脚本把问题转给平台,由平台按测试回答,自己不替用户批准(见 Agent 要问用户时)。写的时候它可以在试用沙盒里试跑:和检查跑一次执行一样,先以测试机的身份在 Agent 要用的同一份仓库副本里跑数据重置,工具调用经平台的工具代理,Agent 问用户时一律回答「可以」。这些文件按你自己保存时的规则检查,再以你的名义存进平台覆盖层,「谁写的」是「平台写的」,审计日志里也标明是 AI 写的。 - 写测试(如需要):检查一次要跑一个确认过的测试。项目里还没有时,模型起草一两个小测试,交给 AI 自动审批。测试用 Agent 自己的语言(英文的 Agent 用英文,和默认安全测试一样判断),日期按用户的说法写(「昨天」),不写过些日子就落到 Agent 自己规则之外的固定日期。没通过的,模型按审批理由重写,最多 2 次;还没通过就停下,请你到数据集 →「全部测试(详细列表)」确认一个。这个项目的自动审批被人关掉了时,平台不替人确认,直接停下并写明。
- 检查一次,最多 10 次:以你的身份「检查一次」。检查因为测试接入没通过时,模型会读检查结果和沙盒日志(看起来出错的行连同前后几行,再加日志的最后一段),再读报错指向、它之前没读过的仓库文件,最多 5 个,同样不读存密钥的文件。它还会看这一轮前面几次检查为什么没通过、改过什么,然后改好文件再查。每点一次最多检查 10 次。只是平台自己的模型或评审模型出错(比如限流)让检查没通过时(2026 年 10 月 20 日起),这不是测试接入的问题:不算进 10 次,不让模型改什么,平台 5 分钟、再 15 分钟后自己再检查。
- 结果:「接入跑通了」和下一步(「测试新版本」);或者写清楚你要做什么:加它点名的密钥、确认一个测试,或者这个仓库为什么没法这样测、哪种接法更合适。
下面这几种情况,平台会想自己发起它。默认它先在项目的「目标」上问一句:「平台要再花约 $X、约 N 分钟修测试接入,要修吗?」,$X 和 N 是这个项目这样修一轮通常的花费和时间。点「修」,就照它要修的(诊断、草稿要的改动、没通过的那次检查)开始;点「先不要」,什么都不做,也不花钱,之后想修再点「让 AI 补全并检查」,它会带上那些草稿要的改动。你在它问的时候直接点「让 AI 补全并检查」,等于点了「修」。等着这次预跑的测试(你自己点开始的)一直等你回答;push、PR、定时或 API 发起的测试没人在页面上,照常结束,问题留在「目标」上。组织的所有者可以在「策略」里关掉「修测试接入前先问我」,平台就不问、直接修(AI 自己做的事):
- 预跑或检查没通过时(见检查一次)。
- 平台 AI 诊断一次测试、判定是测试接入的问题时,按诊断去修。要改的文件里有你们写的,就不自动交,见上面的谁写的。
- AI 审批测试草稿时,发现测试本身没问题,但要改测试接入才跑得了。这时按审核意见修,第 3 步不另写测试;检查通过后,那些草稿由 AI 自动重审。
- 一次测试里有测试因为接入缺能力(读不到数据、看不到工具调用)没测成,组织的所有者关掉了「助手改东西要我确认」、开着「平台自动重跑」时(AI 自己做的事)。检查通过后只重测这几个,见没测成以后。 「经过」下面写着是谁、因为什么发起的,以及它为哪次测试或哪些草稿在修:你在诊断旁点的「让 AI 按诊断修接入」、你在询问上点的「修」,写的是你点的(「平台先问要不要修,某某在几点点了「修」」);只有平台不问就自己开始的那一轮才写「这一轮是平台自己发起的,花的是组织的钱」。
询问还没回答时,「这一轮要修的」里后来的测试已经通过了的那件,写「后来的测试里已经通过了」,点「修」时不再交给 AI。同一个项目同时只问一件事。还没回答时平台又诊断出要修的地方,新的询问把旧的那件一起带上(旧卡片写「并进了新的一次」,在旧卡片上点「修」就开始新的那一轮);项目里已经有一轮在修时,平台不再另外问,诊断旁的「让 AI 按诊断修接入」留着,等那一轮做完再点。
交给它一件要修的事时(「平台读仓库来写」在「平台自己修」下列出的事、一次诊断、草稿要的接入改动),模型拿到的是每一件事和它的为什么、怎么做、做完的标志。模型交回的接入文件和现在的一模一样时,平台退回去让它改一次;还是什么都没改,就停在那里,写明哪几件没修、AI 为什么没改(它的原话;它什么都没说时,写它最后说的话,或者它看了几个文件、试跑了几次就停了),不跑检查,也不再花钱。「详情」里是平台退回给 AI 的话,只写要它做什么,不写给 AI 的填写说明。这一轮的「这一轮要修的」下面逐件写「改了 .reviewctl/harness.py」或「没补上:要改的 .reviewctl/harness.py 没改」。这样的一轮检查通过时,会写明这次检查测了什么:每个确认过的测试的正常情况各 1 次。交给它的是诊断时,检查还会照诊断把那几个没通过的故障、攻击情况各跑 1 次(同名的情况在别的测试里也一起跑),所以这一轮的检查比平时多几次执行。平台写的接入在这些情况里还是自己报错退出的,这次检查就不算通过(「检查跑了要修的……平台写的接入还是在这里报错退出了」),AI 照这次的日志接着改、再检查;都没再崩,就写「诊断里要修的……这次检查跑到了,接入没出问题」。检查跑不了的(比如测试已经改得没有那种情况了),写「这次检查没跑到」,要到「测试新版本」里选「只重测上次没过或没判出的」才知道修好没有,卡片上也不写「接入跑通了」,而是写「接入能进到 Agent,但要修的……这次检查没测到」。跑了但要模拟的故障或攻击没发生的(Agent 没调用挂着它的那个工具),和平台不知道是哪个测试哪种情况的那件,也算没考到;「这一轮要修的」里那一件后面写「这件这次检查没考到」和为什么。询问里的「约 $X、约 N 分钟」在这个项目自己修过两轮以上接入时按它自己的算,算上 AI 在试用沙盒里试跑的花费,和检查要多跑的那几种情况。平台自己发起的那一轮在做的时候,旁边写着这样修一轮通常的花费和时间(和询问里说的是同一个数),有「停下这一轮」;「让平台修」「再让平台修一次」和诊断旁的「让 AI 按诊断修接入」旁边也写着这个数。
平台的 AI 写接入文件时,「经过」最后一行跟着它走:「平台的 AI 正在写:到现在调用模型 N 次、看了 N 个文件、改了 N 个接入文件……」,每过一步更新一次,「最后进展」和「模型调用 N 次」也跟着变,写得久也看得出它在动;模型第一步还没回答时写「在等模型的第一步回答(一步可能要几分钟,要写长文件时更久)」。一步还在排队等平台的 AI 时,写「第 N 步在排队等平台的 AI(前面还有 N 个,已经等了 N 分钟)」(下一个就轮到时写「排在最前面」);平台的模型限流或没有正常回答、平台等一会儿再试时,写它在限流、大约多久后再试、已经试了几次。轮到以后才写「第 N 步,模型还没开始输出(已经 N 分钟……)」,这个时间从轮到时算,不算排队的时间。命令行里的 reviewctl connect --ai 和开发机 AI 的 get_connect_assist 显示的是同一行。
修测试接入只改接线,不改被测的东西:仓库自己的种子数据、示例工单和记录、fixtures 里的内容(哪怕里面有恶意指令或夹带的攻击文字)原样保留,不会换成「干净的」数据。「平台读仓库来写」列出的这类事(比如「提供不含恶意指令的干净种子数据」)归到「你的产品大概率有问题的地方」,不交给平台修。交给它要修的事、或者平台自己发起的一轮,最后一个接入文件都没改成的,不收费:卡片上写「没改成,不收费」,这一轮平台 AI 的花费(和它的试用沙盒)不算进组织的花费,用量页「不收费」下面单独列出。
平台的 AI 忙不是你的问题。组织里同时最多 4 个任务用平台的 AI(接入、计划、AI 审批、诊断……),模型服务也可能在限流;轮不到时,它在队里一直等到轮到为止,最多等 2 小时,这一步写着排第几、大概多久、最多等到几点,你不用回来再点。先来先做:「让 AI 补全并检查」和「平台读仓库来写」按点的先后轮流,组织里同时做 4 个,先点的先做完,后点的不会插到前面;排着的时候写「前面还有几个任务」、大概多久(按最近每个实际做了多久算)和最多等到几点,这个时间不会往后挪。轮到以后写「轮到了:平台的 AI 正在写(第 N 分钟)」,不再写名次;写的时候每一步也要等组织里别的 AI 调用,慢一些是正常的,某一步在等时后面接着写「这一步在排队等平台的 AI(前面还有 N 个)」。有人在等的平台 AI 调用(「让 AI 补全并检查」、「让 AI 填好并测通」、助手、对话 AI 设置时起草起步测试题)排在诊断、AI 审批、默认安全测试这些后台工作前面:组织的名额一空出来,先给它们。后台工作至少留一个名额,所以不会一直等下去。它去跑检查时把位置让给下一个,检查没过要再写,排在后点的任务前面。等的时候,它的试用沙盒如果有组织里别的测试或检查在等名额,就先让出去。排满 2 小时还没轮到才停下,写明这是平台的问题,再点一次会重新排队。
平台自己这边的别的问题也不会让它停下,比如模型这次没给出能用的回答、检查的沙盒没起来或被平台取消、平台中途重启了几次。这时平台过 5 分钟自动接着做,第二次过 15 分钟,最多 2 次,这一步里会写明什么时候再试。两次都不行才停下,并写明已经自动重试过。平台取消的检查会写明原因;撞上费用上限停下的不自动重试(再试也会撞上同一个上限)。项目里正在跑别的测试或检查时,它等那次结束再检查(每 5 分钟看一次,不算重试)。它在修的时候你点「开始测试」,不用等它:测试照常开始,试用沙盒让给这次测试,AI 接着写,等测试跑完再检查。组织暂停、额度用完时不自动重试。检查卡在准备环境(一步 15 分钟没有输出)不算平台这边的问题:照常算一次检查,模型照卡住的那一步改,见准备环境卡住。
还有一种情况:预跑没通过时平台自动修的那一轮,检查了 10 次或改了 5 次还没过;之后你改了代码(推了新提交)、接入文件或密钥,等着的测试再预跑还是没过。这时平台会再修最后一轮。
同一个问题连续 2 次没修好(同一步、同样的错误),它就停下等你,不再自动改、不再检查,也不再扣钱。停下时写明是谁这边的问题、这一轮到现在花了多少钱,旁边有「再试一次」。停下以后,平台不会自己再开一轮(预跑没通过、AI 诊断、AI 审批草稿都不会),直到你点「再试一次」、改了接入文件或密钥、或者推了新提交。以前的每一轮都还在,在按钮下面的「之前的 N 轮」里能看到怎么开始、怎么结束、花了多少。
它不做的事:
- 不改你们的仓库,不建 PR:只写平台覆盖层,它写的每个文件你都能在那里查看、修改、删除。
- 不设密钥。Agent 要用平台给不了的第三方真实密钥时,检查之前就停下,写明名字、它干什么用、去哪申请(
OPENAI_API_KEY不算:没有它时由平台的模型应答 Agent)。在「密钥」里加上,再点一次按钮:它用已经写好的文件直接接着检查。仓库的文档或代码里写着不要这个密钥也能跑的办法时(比如换一个不要密钥的搜索服务),它一并写出来,旁边有 「改用免密钥的办法」:点了以后平台把那个设置写进review.yaml的agent.env,不再要这个密钥,接着检查。测的就是改用后的 Agent,结果可能和用原来的服务时不同。平台只提出仓库自己写着的办法,你点之前不会自己改;在测试计划里选了免密钥的,也按这个办法接。还缺的密钥,「测试新版本」表单的「开始测试」上面也会提醒,写明缺了会怎样。 - 不改你们的 Agent。检查没通过是 Agent 自身行为的问题时,就停在那里并写明:平台只测不改。
- 不改被测 Agent 自己的配置。
review.yaml里agent.env和runner_env原有的变量和值、agent.env_passthrough原有的名字、agent.model,是你们要测的那个 Agent 的设置(比如关掉它的环境清理,测到的就不是同一个 Agent 了)。AI 删了或改了这些,平台改回原来的,其余照存,「经过」里写明,比如「AI 想把 agent.env 里的 MAVIS_BASH_ENV_SANITIZE 改掉,平台没让改:这是被测 Agent 自己的配置,不是测试接入」。它可以新加变量。 - 不放宽任何设置。要由人决定的设置是锁住的:它不能打开
attach.process_egress,不能改attach.enforce_forbidden_writes,不能用attach.apply: in_place,不能加cloud一段,不能换评审模型,不能调高每次执行的上限,不能设代理或预加载一类的变量(HTTP_PROXY、NODE_OPTIONS……),地址只能在沙盒里,安装命令只能是包管理器的。它写了这些时,平台改回去并列出改了什么。仓库里的文字只当数据读:写给 AI 的指令一律不照做。
模型调用算进助手的每日用量,每次调用前先预留。每次检查和手动检查一样,按沙盒时长计费。平台没有配置模型时,按钮是灰的,旁边写着原因。开始之前、进行中、结束以后,你都可以手动改。每个项目同时只能有一个在做,点「取消」就停下,正在跑的那次检查也一起停。
一个可行的仓库结构:
your-repo/
├── .reviewctl/
│ ├── review.yaml # 怎么启动、怎么测 Agent
│ └── scenarios/ # 场景和数据查询(state_queries.yaml)
├── docker-compose.test.yml # 测试后端
├── package.json / pyproject.toml / go.mod …
└── src/ …一份 review.yaml 示例:
schema_version: 1
# 在云上运行时,平台会把这个编号换成你们项目自己的
project: { id: prj_01J8ZK3Q9MXYZ0000000000000, name: expense-agent, domain: expense }
environment: # 可省略:怎么装依赖
setup: [pnpm install --frozen-lockfile]
services: # 可省略:测试后端,起在 Agent 旁边
compose: docker-compose.test.yml
agent:
driver: command
command: [node, dist/agent.js, --message, "{{task}}"]
env_passthrough: [OPENAI_API_KEY] # 值来自项目密钥
attach: # 工具代理:Agent 的工具调用经过平台
mode: http_proxy
base_url_env: EXPENSE_TOOLS_BASE
upstream_base_url: http://127.0.0.1:47591/tools
routes:
claim_list: { method: POST, path: /claim_list }
claim_submit: { method: POST, path: /claim_submit }
backend:
mode: own
reset: { type: http, url: http://127.0.0.1:47591/reset, state_ref_path: $.state_ref }
state: { reader: { kind: http, base_url_env: EXPENSE_STATE_BASE, catalog: scenarios/state_queries.yaml } }
runner_env: # 可选:给测试机自己用、不是秘密的值
EXPENSE_STATE_BASE: http://127.0.0.1:47591
judge: { model: "openai:gpt-4.1-mini" }
scenarios: { dir: scenarios }
budget: { per_attempt: { minutes: 2, model_calls: 30 } }沙盒从仓库根目录执行 Agent 命令。services 用 Docker Compose 起在同一台虚拟机上,Agent 经 127.0.0.1 访问,所以用自己的 Compose 文件时,要把 Agent 用的端口发布在 127.0.0.1 上(比如 "127.0.0.1:47591:47591")。仓库里有 Dockerfile 或 devcontainer.json 时,向导会显示「将用仓库里的 Dockerfile 构建测试环境」(或 devcontainer.json),草稿里写的是 environment.container,而不是安装命令。取消勾选,就在虚拟机上直接装依赖。每一段、每个字段见 review.yaml 参考。
5. 选规格档
规格档决定沙盒的大小;多数 Agent 用「标准」(2 个 vCPU、8 GB 内存、30 GB 盘)就够。见规格档。
推荐的规格档。 平台按测试接入和最近几次沙盒的日志推荐一档。Agent 旁边要起 4 个或更多容器(compose 服务,加上要构建仓库容器时 Agent 自己的那个)时推荐「大」,8 个或更多时推荐「特大」。日志里出现内存不够(Killed、out of memory、退出码 137)、盘满了(No space left on device)或准备环境超时,就推荐比那次大一档的。推荐的那档写在这一步和「设置 → 沙盒」里,旁边写明项目现在用的是哪档、原因和是哪次的日志;规格档的下拉框一直显示你现在的那档,点「换成「大」」才会改,点「保持「标准」」(你现在的那档)就收起推荐。测试接入写明了装什么之后,只按它装的算:依赖文件里有、接入却不装的大包不算理由。更大的档每小时更贵,所以平台从不自己换档,也从不推荐更小的。
运行位置。 项目的沙盒设置里,运行位置可以选「自动」(默认)或「伦敦」,都把沙盒开在伦敦。2026 年 10 月 24 日起不再提供「瑞典(欧盟)」(见运行位置)。数据放在哪:数据处理。
6. 加项目密钥
「密钥」一节先列出平台从 review.yaml 和确认过的测试里找到的名字(agent.env_passthrough、状态读取和数据重置的地址变量、测试的身份变量),每个写明现在由谁给:「已加(项目密钥)」「review.yaml 的 runner_env 里有」「平台提供,不用加」「不是秘密:平台可以写进 runner_env」或「还缺:检查之前要加上」。工具代理的地址(attach.base_url_env)由平台在沙盒里设,不用加。还缺的第一个已经填在表单里,点别的名字也能填进去;加上值,点「加上」。平台收到值就密封起来,只交给正在跑你们任务的那台沙盒,日志里也会遮住。平台提供的评审模型不用你们的密钥。见项目密钥。
你加的密钥要是测试接入文件没用上,这一节会提醒,因为 Agent 只拿得到 agent.env_passthrough 里列出的变量。点「写进测试接入文件」,就会把它们加进覆盖层里 review.yaml 的 agent.env_passthrough;覆盖层里还没有这个文件时,先复制仓库里那份。第 4 步的编辑框跟着显示改后的文件,不用回去手改。
不是秘密的值,比如上面示例里状态服务的地址、仓库自己起的测试后端的测试账号,放在 review.yaml 的 runner_env 里,不用加密钥;同名的密钥仍然优先。平台能从仓库的 .env.example、Compose 文件发布在 127.0.0.1 上的端口,或者测试后端自己的地址里找到这样的值时,点「写进 runner_env」,就会写进覆盖层里的 review.yaml。仓库里那份不动;覆盖层里还没有时,先复制一份过去。「检查一次」时,如果覆盖层里有 review.yaml,平台也会自己写进去,并在页面上说明。名字像密钥的,平台从不从仓库里取值。测试后端自带测试账号的仓库,可能一个密钥都不用加。见密钥还是 runner_env。
Agent 的模型密钥也可以不加。没有 OPENAI_API_KEY 时,这一节会写明 Agent 的模型调用经沙盒由平台应答,按用量计费。Agent 请求的模型平台有,就用它;没有,就换成项目的模型(见模型)。要用你们自己的密钥,加一个 OPENAI_API_KEY。见 Agent 的模型。
7. 写测试
打开数据集 →「全部测试(详细列表)」,在「让 AI 帮你写测试」里点 「平台读仓库来写」(连仓库的项目推荐这种)。平台的模型就只读地读仓库(README、入口代码、工具定义、提示词和业务规则、种子数据和 fixtures),按 review.yaml 里的名字写功能测试和能力清单。测试要用的文件,仓库里有的平台按路径拷;仓库里没有的 TXT、CSV、JSON、XML 由 AI 写样例;PDF 和图片要你上传(数据集里那一行的「附件」)。写出来的草稿照常由 AI 自动审批,没通过的平台按理由自动改。第一个功能测试确认后,平台还会自己写一套默认的安全测试。也可以让开发机 AI 读代码、在「生成攻击数据集」里写攻击测试、「新建测试集」,或者「手写一个场景」。见场景与测试集。确认要留下的测试。
8. 检查一次
回到目标下的向导,点「检查一次」。它跑一个确认过的测试。还没有确认过的测试时,平台用内置的问题检查:请 Agent 简单介绍自己。这只能说明 Agent 起得来、会回复,不能说明它能把事办成。沙盒里没有可用的身份变量时,平台会在覆盖层的 runner_env 里加一个合成的测试身份 AGENT_TEST_USER,并在页面上说明。
检查之前,平台先核对 review.yaml 和测试按名字要的值。还缺检查用得上的密钥时,检查不会开始,页面写明缺哪个、用在哪里;确定 Agent 用不着,就点「仍然检查一次」。测试的身份变量还没有时,测试旁边会提醒:沙盒里没有它,预跑会拒绝那个测试。
平台开一台沙盒,克隆仓库、装依赖、起 services,把这个测试跑一次,看测试是不是真的进到了 Agent。每个阶段和日志都能实时看到:排队、开机、准备、预跑、上传、已删除。这一步只出一份预跑结论,用来诊断,不是正式报告,也不算一次运行。也可以跳过这一步,因为「开始测试」会自己先预跑。
检查和预跑跑两次以上时,平台会在最后一次里故意让 Agent 的第一次工具调用返回超时错误(工具不执行),看测试接入能不能把这个错误交给 Agent。平台写的接入文件接不住、自己报错退出的,结论里「工具报错时接入接不接得住」写没通过,平台来修:不然正式测试里注入的故障、攻击都会让接入中途退出,测不到 Agent 怎么应对。被测的「Agent」本来就是平台写的测试外壳时(它替 Agent 跑),错误交到外壳手里之后外壳自己报错退出,也算平台写的接入接不住、没通过,平台来修,不会写成「Agent 自己的程序报错退出了」。这一次的回复不拿来判别的条件,上面各项里「N 次测试里……」的次数也不算它,后面写着「另外 1 次是平台故意让工具报错的那次」。
向导到这一步就结束了。检查通过后,它指向项目的自动化:push 和 PR 时自动测、定时和 API 令牌都在那里,见下文自动触发。最近一次检查留在目标 →「连接检查」里。
没通过时,页面会说哪里出了问题,并给出沙盒日志。连仓库的项目,平台的 AI 会接着按这次检查的结果和日志修测试接入,再检查,和「让 AI 补全并检查」一样。这次检查算第 1 次,一共最多 10 次,页面上一步步显示;修不了时,会写明要你做什么。
如果它刚放弃过,之后既没有新的提交,也没人改过接入文件或密钥,同样的检查就不再自动修,因为多半还是一样的结果。这时在页面上点「让 AI 按这次的问题修」,就从这次检查接着修。
常见的问题是缺项目密钥、端口没发布在 127.0.0.1 上、Agent 命令写错。仓库的 Compose 文件用 env_file 读 .env 时,沙盒起不了 services,因为 .env 一般不提交。测试用不着这些服务就去掉 services,要用就写成一个个服务;平台起草的接入文件这时不写 services.compose,并写明原因。出现 exec format error 或找不到 aarch64 的包,说明架构不对;包管理器跳过给别的系统的可选包(例如 bun 的 skipping …-darwin-arm64、npm 的 SKIPPING OPTIONAL DEPENDENCY)是正常的,不算。平台会自动换到另一种架构再检查一次,通过了就把项目的架构改过去,并在「设置 → 沙盒」里写明,你可以改回。更多见常见问题。
9. 开始测试
点「测试新版本」(每个分区的右上角),选要测什么、每项测几遍,点「开始测试」。它会先预跑一次,预跑通过后正式运行自动开始;每项测 1 遍、只测正常情况时,正式运行和预跑跑的一样,所以不另外预跑,它本身先当预跑。中途随时可以取消,运行会在当前这次执行结束时停下,仍会给出部分报告。
10. 看实验
这次运行变成实验下的一个实验,最上面是发布门槛,每个评分器一张卡,每个测试、每种条件一行。它的「完整报告」给出运行自己的结论:「通过」「不通过」或「没测成」,每个测试每次都通过才算通过,没有测试没通过、但还缺结果时是「没测成」。每个测试标着通过、没通过或没测成。每个问题都附上背后的对话和数据检查,还有怎么改;实验行上的「导出修复说明」把修改意见存成文件,交给你们的编码 AI。Agent 的工具调用经过工具代理时(第 4 步的 attach),还能看到每一次工具调用的参数和结果。用 attach: { mode: endpoint_only } 时,平台只看得到回复和数据,报告会写明「看不到工具调用」,只能靠工具调用判定的攻击就判断不了。见报告里有什么。云端运行的版本 = 克隆的提交 + 模型 + 机器镜像版本。
一次运行里发生了什么
- 平台建任务,签一个一次性的引导令牌(10 分钟有效),然后在沙盒网络里从机器镜像开一台虚拟机。
- 虚拟机上的测试机用引导令牌换一个只对这个任务有效的会话令牌,引导令牌随即作废。
- 测试机取覆盖层文件和项目密钥,克隆提交,恢复依赖缓存,执行
setup,起 services。项目密钥里没有OPENAI_API_KEY时,还会在本机起一个转发到平台模型的入口。 - 每次执行都以单独的、无特权的
agent用户,在自己的受限作用域和工作目录里启动 Agent。日志实时传回页面。 - 测试机上传运行包、报告完成;虚拟机关机,平台把它删掉。
虚拟机建好 12 分钟还没接上平台(第 2 步没发生,引导令牌已经过期),平台就把它删掉,自动重开一台。这还是同一次测试,不收费,页面上会写明原因,并给出第一台的串口输出。重开的也没接上,这次运行才结束;平台会把任务编号和两台的开机日志发给我们的工程师,页面上写「已经通知了平台的工程师」,你们不用做什么。云上没能建起虚拟机时也一样,平台过一分钟自动再建一次。
虚拟机在运行中途没了,运行记为「没跑完」,已经执行的几次照常判。这一轮结束后,平台自己补跑一次没跑到的那几次,结果合进本轮报告,审计日志里写「平台自动补跑了沙盒中途没了时没跑到的测试」。这是平台的问题:这次补跑不收费,那台沙盒最后一段没留下结果的时间也不收费(见平台的问题不收费)。后端可能在沙盒外面、还要人核对的失联测试,平台不补:Agent 可能已经改过测试后端里的数据,页面会提示先重置测试后端,核对后再补跑或重新发起。项目的自动化里关掉「平台自动重跑」,也就不自动补跑。
上限和白名单
云端运行受组织策略约束:默认同时 2 台沙盒,多出来的排队,单次运行最长 120 分钟。沙盒经伦敦的一个固定 IP 走 443 端口出站,你们可以把它加进测试后端的白名单。见沙盒与上限。
自动触发
在项目的自动化里,可以打开 push 到默认分支时自动跑、PR 打开或更新时自动跑(fork 来的 PR 不跑),还可以在测过的提交上挂一条带结论的 GitHub 检查。检查通过后,向导最后有到这一页的链接。同一页的「定时」和「API 令牌」让测试按时跑,或者由你们自己的 CI 发起。自动测试怎么跑、以谁的身份跑、在 GitHub 上写什么,见自动触发。