PostHog 沙箱化 Agent Evals 运行指南:本地 Docker 与远程 Modal 的完整实战
2026/9/10 1:30:46 网站建设 项目流程

PostHog 沙箱化 Agent Evals 运行指南:本地 Docker 与远程 Modal 的完整实战

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

PostHog 的 Agent Eval 评测体系在独立评测(eval harness)中运行真实编码 Agent,让其在沙箱内操作种子化的 Hedgebox 项目并对其行为打分。本指南围绕仓库内 running-evals.md 的完整实战说明展开,结合 eval_harness 源码 深入讲解如何准备评测机器、配置环境变量,并在本地 Docker 沙箱与远程 Modal 沙箱两种运行时之间做出正确选择。读完本文,你将掌握从零跑通第一个 eval case、正确配置凭证与网络、以及快速诊断各类 setup 失败的完整能力。

两种沙箱运行时:架构与选择依据

独立评测 harness 的设计核心是"主次分离":无论选择哪个沙箱 provider,评测数据库、Django 服务器、LLM 网关、MCP 服务器、Temporal、personhog、案例(case)的团队与数据设置、以及最终的评分,全部运行在本地执行hogli evals的这台机器上;provider 改变的仅仅是"编码 Agent 的沙箱运行在哪里"。

  • 远程 Modal(推荐):适用于多案例的沙箱化评测。远程沙箱并行运行,不消耗本地 Docker 内存,通常能显著缩短整体运行时间。当 Modal 凭证和具备 Funnel 能力的 tailnet 可用时优先选择。
  • 本地 Docker:适用于单个案例的冒烟测试(smoke test)、离线工作,或 Modal 凭证 / Funnel tailnet 不可用的场景。

从 providers.py 源码可见两种策略的默认并发能力差异:Docker 策略default_max_sandboxes = 4,而 Modal 策略默认为None(无上限),这一差异直接影响后续--max-sandboxes参数的使用策略。

共享设置:所有运行的前置条件

在 flox shell 中运行

评测必须从仓库根目录、在 flox shell 内执行。personhog 的构建依赖 flox 提供的 Rust 工具链、pkg-config和 OpenSSL。如果当前没有激活 flox shell,不要进入交互式激活,而是把整条命令包进flox activate

flox activate -- bash -c "hogli evals --list"

日常运行统一使用hogli evals命令。它会自动加载仓库根目录的.env.env.local.env.development.env.services文件,且已存在的 shell 环境变量优先。个人凭证应保存在已被 gitignore 的.env.local中,或直接放在 shell 环境里。

如果绕过 hogli 直接调用底层模块入口python -m products.posthog_ai.eval_harness.harness,则只加载.env文件,其余凭证需要自行 export。这也解释了为什么 env_preflight.py 的报错信息中会提示"把变量放进.env.local并通过hogli evals运行"。

必需的环境变量

所需的变量取决于选中的套件(suite)类型与运行时:

选择必需变量
所有套件BRAINTRUST_API_KEYLLM_GATEWAY_ANTHROPIC_API_KEY
任何沙箱化套件以上变量之外,还需SANDBOX_JWT_PRIVATE_KEY
Codex 运行时以上变量之外,还需LLM_GATEWAY_OPENAI_API_KEY

其中SANDBOX_JWT_PRIVATE_KEY用于签发沙箱内 Agent 的 API 令牌。本地开发用的沙箱 JWT 私钥随仓库根目录的 .env.example 提供,通常会在仓库初始化时被复制进.env该密钥仅供本地开发使用,绝不能用于生产环境。

Preflight(预检)会在启动数据库或任何服务之前,报告每一个缺失的变量。BRAINTRUST_API_KEY其实是 Braintrust 评测引擎自身的required_env(),而非核心 harness 变量;沙箱化套件则额外要求SANDBOX_JWT_PRIVATE_KEYLLM_GATEWAY_ANTHROPIC_API_KEY,one-shot 套件只要求LLM_GATEWAY_ANTHROPIC_API_KEY(直接使用,不经网关)。只有被选中套件对应类型的环境模型才会被检查,因此一次不含沙箱套件的运行不会强索沙箱变量。

发现套件:--list

正式运行前先用--list列出已发现的套件 ID:

hogli evals --list

套件发现基于约定而非注册表:内置套件位于products/posthog_ai/evals/ /(如sqlexperimentssurveysproduct_analytics等),产品自有套件位于products/<product>/evals/。产品归属的套件 ID 形如<product>/<module>::<function>。选择器是子串匹配,未匹配的选择器会在任何资源被分配之前立即失败。

从单套件单案例起步

先跑一个套件、一个案例,让 setup 错误变得廉价且易于诊断:

hogli evals '<product>/eval_example::eval_my_thing' --eval '<case-name>'

--eval只运行名称中包含该子串的案例。

one-shot 套件与沙箱标志的约束

纯 one-shot(一次进程内模型调用)的套件不使用沙箱 provider。不要为这类运行传入--provider--max-sandboxes等沙箱专属标志——preflight 会直接拒绝这些标志而不是静默忽略。cli.py 中通过sandbox_flags_set机制追踪哪些沙箱标志被显式传入,一旦发现当前选择不含沙箱套件便报错,避免"用户以为限制了并发、实际被忽略"的误导。

团队克隆与案例播种的独立并发限制

harness 将"团队克隆 + 案例播种"阶段与沙箱并发分开限制:普通本地机器上该限制为 1,而当设置了CODERCI环境变量时自动提升到 4。这样托管的开发环境与 CI 环境可以并行准备案例,同时让本地机器的 ClickHouse 内存占用保持保守。团队设置阶段可能产生大型 ClickHouse 拷贝或直接插入,独立限制可以防止 ClickHouse 内存耗尽——即使 Modal 沙箱容量无上限。

本地设置:Docker 沙箱

本地沙箱化评测默认使用 Docker。安装 Docker、启动守护进程并确认 CLI 可访问:

docker info

无需手动构建沙箱镜像。每次运行前,harness 会检查posthog-sandbox-base镜像是否最新:当 Dockerfile 或已发布的 Agent 版本发生变化时自动重建。首次 personhog 构建和必要的镜像构建可能耗时数分钟,后续运行会复用其产物(personhog 的首次构建需要编译rust/下的personhog-replicapersonhog-routercrate)。

先跑一个案例、一个活跃沙箱:

hogli evals '<suite-selector>' \ --eval '<case-name>' \ --provider docker \ --max-sandboxes 1

--provider docker是可选的,因为 Docker 就是默认值。本地默认并发上限是 4 个沙箱,每个沙箱最多配置 16 GB 内存。除非宿主机内存足够支撑目标并发,否则尽量保持较低的--max-sandboxes(在 providers.py 中 Docker 策略的默认上限即为 4,且每个容器默认 16 GB)。

正常 teardown 会移除每个案例的容器并清扫本次运行的残留。如果某个失败案例需要检查容器,用--keep-sandbox-containers重跑,调试完毕后手动删除保留的容器。只有当强制重建镜像本身就是诊断的一部分时,才使用--rebuild-sandbox-image(该参数仅对 Docker 有效,cli.py 会拒绝在非 Docker provider 下使用)。

Notebook 内核沙箱(Docker 专属)

需要额外注意:含 python 或 duckdb 单元格的 notebook 案例,其内核会通过 Temporal workflow 申请第二个沙箱(约 2 GB,与 Agent 的 16 GB 并存)。这一通道仅支持 Docker provider——Modal provider 将SANDBOX_PROVIDER设为MODAL_EVALS,不在内核后端的取值集合中,端口映射与存活检查都会失效。因此含 python/duckdb 单元格的套件请使用--provider docker;纯 SQL 套件不受影响,可在任何 provider 下运行。

远程设置:Modal 沙箱(推荐)

远程沙箱化评测使用专用的posthog-sandbox-evalsModal 应用(与生产环境、本地开发沙箱完全隔离)。首先在 flox 环境内安装modaltailscaleCLI,并确保两者都在PATH上。

一次性认证

认证 Modal:

modal token new

这通常会写入~/.modal.toml。非交互式环境则需同时设置MODAL_TOKEN_IDMODAL_TOKEN_SECRET

连接 tailnet(一次性):

tailscale up

Funnel 还需要:在 Tailscale 管理控制台的 ACL 中为 tailnet 和当前节点授予funnel节点属性,并为 tailnet 启用 HTTPS 证书。之后 harness 会在运行期间通过 Tailscale Funnel 暴露本地 Django API、LLM 网关和 MCP 服务器,每个服务占用一个 Funnel 公共端口(443844310000)。不要手动设置SANDBOX_API_URLSANDBOX_LLM_GATEWAY_URLSANDBOX_MCP_URL——这些由 harness 自行生成。

Funnel 只服务这三个公共端口,所以当 tailnet 节点已占用其中任意一个时,harness 会拒绝启动而不是抢占端口。先释放端口:tailscale funnel --https=443 off844310000同理。

第一个远程案例

用一个远程沙箱验证凭证、Funnel 和远程镜像构建:

hogli evals '<suite-selector>' \ --eval '<case-name>' \ --provider modal \ --max-sandboxes 1

首次 Modal 运行会在远端构建评测镜像;后续运行复用该镜像,直到其 Dockerfile、构建上下文或打包的本地 skills 发生变化。保持本地进程和网络连接存活——远程沙箱需要回调到本地运行的服务。Modal 的沙箱回收策略包括按 workflow 终止逐个清理 + 按任务标签(task_id)的全局清扫,中断或崩溃的运行不会让沙箱一直计费到 TTL。

并发:Modal 默认无上限

Modal 并发默认无上限(providers.py 中default_max_sandboxes = None),因此在运行多案例产品域之前,务必主动选择一个有意的--max-sandboxes值:

hogli evals '<product-or-domain>' --provider modal --max-sandboxes 4

teardown 与中断后的安全检查

harness 在 teardown 阶段会关闭自己的 Funnel 映射,并终止每个案例的任务标签沙箱、清扫本次运行的残留。但Funnel 配置存在于tailscaled中,生命周期比 harness 进程更长——被SIGKILL杀掉的运行可能让三个端口继续保持公开状态。用tailscale serve status检查,并手动关闭。运行期间 Funnel URL 对任何得知该地址的互联网用户都可达,因此不要分享这些 URL,中断后也不要让运行处于无人值守状态。

诊断 setup 失败

先读 preflight 错误——它会点名缺失的可执行文件、凭证或环境变量,并给出预期修复方式。常见原因:

  • 在 flox 之外运行,导致 personhog 的 Rust 构建在工具链或 OpenSSL 依赖上失败;
  • 本地模式下 Docker 守护进程已停止;
  • 远程模式下缺少~/.modal.toml,或MODAL_TOKEN_ID/MODAL_TOKEN_SECRET不完整;
  • tailscaled未运行、节点未登录,或 tailnet 缺少funnel节点属性 / HTTPS 证书,导致 Funnel 无法提供三个远程可达的服务;
  • Funnel 公共端口(443844310000)已被其他服务占用,harness 拒绝覆盖;
  • 向 one-shot 套件传入了 provider 标志;
  • 选择--agent-runtime codex时遗漏了LLM_GATEWAY_OPENAI_API_KEY(codex 运行时默认模型为gpt-5.5,需要 OpenAI 密钥经 LLM 网关代理调用)。

日志与转录文件

每一次真实评测调用都会把完整 stdout/stderr 镜像到:

products/posthog_ai/eval_harness/logs/harness/<timestamp>_<id>.log

终端最后一行是该转录文件的绝对路径,且logs/harness/latest.log指向最新一次运行。eval_harness 的 logs 目录 就是排查入口。--list和参数错误不会生成转录文件。

案例启动后,其 Agent 日志目录中会包含<case>.jsonl<case>.artifacts.json<case>.summary.txt,用于更深入的调试——这些原始 Agent 日志通常是查看 Agent 实际做了什么的最快途径。

补充:完整 CLI 参数与运行语义

harness/cli.py 定义了全部参数,与 eval_harness 的 README 中的表格一致:

参数含义
--eval <substr>只运行名称包含该子串的案例
--provider {docker,modal}沙箱运行位置,默认docker
--max-sandboxes N跨所有套件的活跃沙箱上限
--agent-model <model>Agent 使用的模型,默认 claude 为claude-opus-5、codex 为gpt-5.5,固定以支持跨运行对比
--agent-runtime {claude,codex}服务模型的运行时,默认claude
--skill-delivery {bundled,exec}skill 投递方式,默认bundledexec会移除沙箱内原生 skills
--reasoning-effort <effort>Agent 推理强度,合法值取决于运行时 + 模型
--keep-sandbox-containers跳过运行结束的 Docker 清扫(仅 Docker)
--rebuild-sandbox-image强制重建posthog-sandbox-base镜像(仅 Docker)
--create-db重建评测测试数据库而非复用
--case-timeout <seconds>Agent 运行预算(最少 1 秒),从案例团队设置完成后开始计时
--trials N每个案例运行 N 次(Braintrust trials),用于度量随机 Agent 的方差
--fail-under <fraction>平均分低于该比例(0-1)时以非零码退出
--list打印发现的套件 ID(含类型)并退出

几个关键语义值得注意:

  • Agent 模型默认值claude运行时默认claude-opus-5codex运行时默认gpt-5.5,且必须使用裸模型 ID(无anthropic/openai/前缀),否则 LLM 网关会以 403 拒绝。若模型前缀与运行时不匹配,CLI 会在运行前报错而不是等到运行几分钟后以模糊的网关 403 失败。
  • 并发模型:所有选中套件在同一事件循环上并发运行,全局信号量跨套件限制活跃沙箱数;--max-sandboxes只覆盖"团队设置 + Agent 运行"窗口,日志解析、Braintrust span 构建、trace 发射和评分都在槽位释放后进行。case 的超时也从团队设置完成后才开始,排队不消耗 Agent 预算。Sandbox-only 标志(--provider--max-sandboxes--agent-runtime--skill-delivery--reasoning-effort--keep-sandbox-containers--rebuild-sandbox-image)在无沙箱套件被选中时会被 preflight 拒绝。
  • 输出语义:进度行使用稳定标签(SUITE STARTEXPERIMENT STARTCASE DONEEXPERIMENT DONESUITE DONE),只有整体运行使用PASS/FAIL;崩溃的套件标记为CRASH并附 traceback,使运行以非零码退出但不影响其他套件。设置EXPORT_EVAL_RESULTS=1可额外在每个实验后向eval_results.jsonl追加一条结构化 JSON 摘要。

结语

从单案例冒烟测试到大规模并行评测,PostHog 的 eval harness 把"基础设施留在本地、沙箱按需伸缩"做到了清晰的分层:Docker 适合快速验证与离线开发,Modal + Tailscale Funnel 则把多案例评测扩展到无本地内存压力的大规模并行。牢记环境变量矩阵与 Funnel 端口的独占约束,善用 preflight 报错与logs/harness/latest.log转录,即可稳定复现、对比与调试每一次 Agent 评测。更深入的架构细节(套件发现约定、新增套件的完整工作流、评分器模式)可继续阅读 eval_harness 的 README 与 writing-evals 技能文档。

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询