自带镜像(开发中)
开发中
这种接法正在开发,暂时不能在平台上选用,现在请连 GitHub 仓库或用本地测试机。已经用它接好的项目照常可用,下面的说明照旧适用。
Agent 以容器镜像交付时用这种接法,镜像放在哪个镜像仓库都行。每次运行,平台都开一台全新的虚拟机,我们叫它沙盒,开在伦敦。平台按读到的摘要拉取你们的镜像,在旁边起好测试后端,再让 Agent 在容器里跑测试。运行结束,虚拟机随即删除。你们不用为我们重新构建任何东西。
开始之前
- 一个放在任意镜像仓库里的镜像(Docker Hub、GitHub Container Registry、Google Artifact Registry、自建的镜像仓库……),为
linux/amd64、linux/arm64或两者构建。 - Agent 能在镜像里用一条命令启动(比如
python -m my_agent.review_entry),通过 HTTP 或 MCP 调用工具。 - Agent 的工具所连的测试后端,并且能重置、能读出数据。只接测试环境和测试凭证,不要让运行连到生产系统或真实的客户数据。
- 私有镜像:镜像仓库的用户名和一个只读令牌(GitHub Container Registry 用带
read:packages权限的令牌)。
1. 建项目,选接法
- 在网页上点「新建项目」,选「会调用工具的 Agent」,起个名字。
- 打开目标,选「自带镜像」。
2. 镜像地址和数据边界
按 docker pull 的写法填镜像地址,带标签或摘要,不带 https://:ghcr.io/acme/agent:1.4、registry.example.com:5000/team/agent@sha256:…,Docker Hub 上的写 python:3.12 就行。
向导会展示数据边界。镜像拉进我们云上的沙盒,跑完随虚拟机一起删除。留下来的只有运行包,也就是证据、脱敏后的轨迹和日志。拉取凭证和项目密钥只保存密文。看完勾「我知道了」。
3. 拉取凭证(只有私有镜像要填)
填镜像仓库(按镜像地址自动填好,Docker Hub 是 docker.io)、用户名和只读令牌,点「保存凭证」。平台收到凭证就把它密封起来,存成一个项目密钥。页面上只显示镜像仓库、用户名和令牌的末四位,看不到令牌本身。公开镜像不用填。见拉取凭证。
4. 检查镜像
点「检查镜像」。平台执行器从镜像仓库读一次镜像的清单(不拉取镜像),显示:
- 摘要:镜像地址现在指向的
sha256:…。 - 架构:镜像是为哪些平台构建的(多平台镜像读它的索引,单平台镜像读它的配置)。
- 镜像自己的配置:启动命令(
ENTRYPOINT加CMD)、工作目录、运行用户、端口、环境变量和标签里写的源码仓库。多平台镜像读其中一个平台的配置,有linux/amd64就读它。环境变量只显示名字。名字或值看起来像密钥的(…_KEY、…_TOKEN、…PASSWORD、带账号密码的地址……),执行器只留名字,值不会离开执行器,平台也不保存。
镜像的 USER 是 root 或没写(没写就是 root)时,这一步会提醒你。沙盒总是用 uid 1500 这个非 root 用户运行容器,所以 Agent 往镜像里属于 root 的目录写东西(比如它的工作目录)会失败。可以让它改写 $HOME 或 /tmp,也可以在构建镜像时把那个目录交给 1500(chown -R 1500 /app),或者直接用 USER 1500。
读不到时会说明原因:镜像仓库要登录,或者拒绝了你们的凭证;镜像或标签不存在;连不上镜像仓库;清单格式太旧(用新版 docker 或 buildx 重新推一次)。执行器不会替镜像仓库去访问内网地址或云元数据地址。
每次运行都按摘要固定版本。发起运行时,平台用它读到的摘要;那次读取已经超过 10 分钟的话,先重新读一次。所以标签挪到新镜像以后,下一次运行测的就是新镜像。报告里的版本就是这个摘要。
5. 规格档和架构
规格档决定沙盒的大小。架构按镜像来:「自动」时镜像有 x86 就跑在 x86 上,否则跑在 ARM 上;只能选镜像有的架构。见规格档和架构。
运行位置。 项目的沙盒设置里,运行位置可以选「自动」(默认)或「伦敦」,都把沙盒开在伦敦。2026 年 10 月 24 日起不再提供「瑞典(欧盟)」(见运行位置)。数据放在哪,见数据处理。
6. 加项目密钥
在「密钥」一节,把 review.yaml 里按环境变量名引用的值都加上。它们以环境变量进入容器,日志里会被遮住。见项目密钥。
Agent 的模型密钥可以不加。不加 OPENAI_API_KEY 时,Agent 的模型调用由平台模型应答,按用量计费,这一节会写明用的是哪些模型。容器会拿到 OPENAI_BASE_URL 和一个占位的 OPENAI_API_KEY,经沙盒调用平台的模型,因为容器用的是沙盒的主机网络。见 Agent 的模型。
7. 测试接入文件
镜像里没有 .reviewctl/ 目录,所以它的 review.yaml 保存在平台覆盖层里。向导打开时已经有一份起步文件。读到镜像的配置后,agent.command 就是镜像自己的启动命令,任务原话作为最后一个参数交给它(sh -c 形式的命令按 "$1" 交)。如果镜像的启动命令起的是一个服务,比如 Web 框架或开了端口的程序,它不从命令行收任务,起步文件就留着示例命令,并写明原因。确认或改好命令后点「保存到覆盖层」,也可以点「让 AI 补全并检查」(见下文):
schema_version: 1
project: { id: prj_01J8ZK3Q9MXYZ0000000000000, name: expense-agent, domain: expense }
services: # 可选:测试后端,起在容器旁边
db:
image: postgres:16
env: { POSTGRES_PASSWORD: test }
ports: [5432]
ready: pg_isready -U postgres
agent:
driver: command
command: [python, -m, my_agent.review_entry, "{{task}}"] # 在镜像里运行
env_passthrough: [OPENAI_API_KEY] # 值来自项目密钥
attach: { mode: endpoint_only } # 或 http_proxy / mcp_wrap,和连仓库时一样
backend: { mode: own }
judge: { model: "openai:gpt-4.1-mini" }
scenarios: { dir: scenarios }
budget: { per_attempt: { minutes: 10, model_calls: 40 } }- 不用写
environment段:镜像本身就是环境。命令在镜像自己的WORKDIR里执行。 - 覆盖层里的文件只读挂在容器的
/reviewctl。适配脚本(比如.reviewctl/harness.py)、测试数据这类辅助文件,在这一步的「覆盖层里的文件」里点「加一个文件」加上(粘贴内容或从本地文件读入),在容器里就是/reviewctl/harness.py。每个文件最大 256 KB,只放文本。 - Agent 经
127.0.0.1访问你们的services。每一段、每个字段见 review.yaml 参考。
让 AI 补全并检查
不想自己写 review.yaml,就点这一步里的 「让 AI 补全并检查」。和连 GitHub 仓库时一样,只要你点这一下,之后的事都由平台做完,一项项显示出来:
- 读镜像:读的是「检查镜像」读到的镜像配置(启动命令、工作目录、运行用户、环境变量名、端口和标签)。如果镜像的
org.opencontainers.image.source标签写的是一个 GitHub 仓库,而这个组织装的 GitHub App 读得到它,平台还会只读地读这个仓库,读法和连仓库时一样,从不读.env和存密钥的文件。标签org.opencontainers.image.revision写了提交就读那个提交,没写就读默认分支的最新提交。仓库读不到,就只按镜像的配置写,这一步会写明。 - 写接入文件:平台的模型写
review.yaml,需要时再写适配脚本。因为命令在镜像的容器里跑,接入文件只用driver: command,覆盖层里的文件写成容器里的路径/reviewctl/…(.reviewctl/harness.py写成/reviewctl/harness.py)。它不写environment段,因为镜像就是环境,写了也会被去掉。测试后端写成一个个服务,不写 Compose 文件。镜像起的是服务时,适配脚本在同一个进程里直接调用生成回复的函数。镜像要以 root 运行时,它会写明。 - 写测试(如需要)、检查一次,最多 10 次、结果:和连仓库时一样。
它不改你们的镜像,也不设密钥,要由人决定的设置它放宽不了。镜像里的文字(标签、环境变量)和仓库里的一样,只当数据读。费用也和连仓库时一样:模型调用算进助手的每日用量,每次检查按沙盒时长计费。
8. 写测试,检查一次,然后开始测试
和连仓库一样,先在数据集 →「全部测试(详细列表)」里写测试(场景与测试集),至少确认一个。再回到目标下的向导点「检查一次」。它要跑一个确认过的测试,所以还没有确认过的测试时,按钮是灰的。平台开一台沙盒,拉取镜像,起 services,把这个测试跑一次,看测试是不是真的到了你们的 Agent。每个阶段和日志都能实时看到。
出现 exec format error,说明镜像和虚拟机的架构不配。镜像两种架构都有时,平台会自动换到另一种再检查一次,通过了就把项目的架构改过去(可以改回)。设置里选了镜像没有的架构时,「检查一次」直接在镜像有的那种上跑。
之后点「测试新版本」开始测试,这一轮变成一个实验。开始测试会自己先预跑(每项测 1 遍、只测正常情况时,测试本身先当预跑),所以检查一次可以跳过。
你们的 CI 可以在推了新镜像之后用项目 API 令牌(项目的自动化 →「API 令牌」)发起一次运行:POST /v1/projects/:id/jobs,带 {"image_ref": "ghcr.io/acme/agent:pr-7"}。这个镜像只为这次运行读取,并按摘要固定。见 API 与令牌。
Agent 怎么运行
- 沙盒用你们的凭证登录镜像仓库,按摘要拉取镜像,结束时退出登录。
- 每次执行都开一个新容器,执行结束容器随即删除,不会有进程留下来。
- Agent 和连仓库时一样以无特权用户运行(uid 1500),去掉全部 Linux capabilities,禁止提权,最多 512 个进程,内存按规格档限制;从不挂 Docker socket。请确认你们的镜像能以非 root 用户运行。
- 容器用虚拟机的网络,受同样的按用户防火墙规则约束:访问不了元数据服务和控制面,只能访问
127.0.0.1上的 services 和外网 443 端口。
白名单
沙盒经 443 端口拉镜像、访问外网,出口是伦敦的一个固定 IP。你们的镜像仓库或测试后端只放行已知地址的话,发邮件到 admin@nice2.io 问这个地址。
什么会进我们的云
| 进我们云的东西 | 运行结束后留下什么 |
|---|---|
| 镜像(拉进沙盒)、测试文件、项目密钥(密封) | 运行包。镜像随虚拟机删除。 |
| 镜像的配置(检查镜像时读:启动命令、工作目录、运行用户、端口、环境变量名、标签;像密钥的值不保存) | 保存在项目上,下次检查镜像时更新;停用这个镜像时删掉。 |
各种接法的对照见数据边界表。