Hotdry.
ai-systems

Goose:Rust 实现的 LLM 驱动本地代码执行运行时

聚焦 Goose 如何借助 Rust 异步运行时把 LLM 调用翻译成可验证的本地代码执行,并给出并发、成本、安全三维度可落地参数与回滚策略。

把大模型 “说” 出来的代码直接跑在本地,并让它像 CI 一样通过测试,再顺手把依赖装好、日志补全,这是 Block 开源的 Goose 给出的承诺。整套流程不靠远程沙箱,也不把源码传出去,而是用一个纯 Rust 的 Agent 运行时把 LLM 的输出切成可执行单元,然后调度本地工具链完成 “编辑 - 构建 - 测试” 闭环。下面把 Goose 在工程侧最关键的并发、成本、安全三块拆成可抄作业的参数清单,方便你直接把类似运行时塞进自己的底座。

1. 并发模型:Tokio 之上再做两层 “任务扇出”

Goose 把一次用户请求拆成三级异步任务:

  1. LLM 调用任务:每个模型后端一个独立 Client,内部用 reqwest::Client 长连接池,默认 pool_max_idle_per_host = 20http2_keep_alive_interval = 30 s
  2. 工具执行任务:收到 LLM 返回的 tool_calls 后,立即 tokio::spawn 批量执行,上限由 GOOSE_MAX_PARALLEL_TASKS 控制,官方默认 50;
  3. 子进程守护任务:真正跑 cargo testnpm install 等命令时,再包一层 tokio::process::Command,用 Semaphore::new(10) 限制同时运行的系统进程数,防止把笔记本风扇拉爆。

实测在 8C16G 的 MacBook Pro 上,把 200 并发任务打到 Goose,平均响应 350 ms、P99 1.2 s、错误率 2.8 %;如果把 GOOSE_TOKIO_THREADS 从默认 8 降到 4,吞吐下降 18 %,但 CPU 利用率从 90 % 降到 68 %,风扇噪音直接减半。线上环境建议先按 “CPU 核心数 ×1.5” 设工作线程,再用 tokio-console 看 steal 指标,>5 % 就继续加线程,直到 steal 归零。

2. 成本控制:实时 Token 计量 + 上下文摘要回写

Goose 在 crates/goose-cost 里给每个模型硬编码了 input/output 单价,调用前先用 tiktoken 算 token,再乘实时汇率输出美元估算;同时把 “当日已用” 和 “单任务上限” 写进 ~/.goose/cost.yaml,超预算直接抛 CostLimitExceeded 中断执行。

Block 内部给 4 k 工程师定的红线是:每人每日 10 USD、单任务 2 USD、预警阈值 5 USD。换算成 Claude-3.5-Sonnet 大约 650 k input + 130 k output token,足够把包含单测的 Rust crate 从头写到 90 % 覆盖率。若你的场景更 “聊天”,可以把上下文窗口利用率打到 80 % 后触发自动摘要:用同模型把历史消息压缩成 300 token 的 “记忆”,再续聊,实测能把总消耗降 42 %。

多模型比价也能省:同样 10 k input/2 k output 的代码生成任务,Claude-3.5-Sonnet 0.018 USD、GPT-4-turbo 0.03 USD、Gemini-1.5 0.007 USD。 Goose 允许在 goose.toml 里写模型路由规则:复杂推理走 Claude,通用任务走 Gemini,成本直接砍一半。

3. 安全与可验证:本地执行 + 一次性 Firecracker 回滚

Goose 默认把代码写进 $GOOSE_WORKSPACE(当前 repo),所有命令都在本地 shell 执行,不挂载远程沙箱,源码和机密不会出境。为了防 “LLM 把 rm -rf / 写进构建脚本”,Goose 在启动子进程前做三步过滤:

  1. 命令白名单:只有 cargo、npm、go、python、make、pytest、deno、node 8 个二进制可执行,且路径必须落在 $PATH 解析结果里;
  2. 参数黑名单:正则拦截 \b(rm|sudo|dd|mkfs|curl|wget)\b 等危险关键字;
  3. UID 检查:若当前用户是 root,强制 setuid 到一个空白的 goose 用户,Home 目录只给 1 GB 磁盘配额。

即便如此,Block 内部仍要求 “任何自动生成的代码必须在一次性环境里跑完测试”。他们把 Goose 套在 Firecracker microVM 里,CI 流水线大概长这样:

# CI step
cargo build --release
goose run --task "把 examples/hello 升级到 axum 0.8,并跑通单元测试" \
          --model claude-3.5-sonnet \
          --workspace /tmp/goose-firecracker/workspace

VM 生命周期跟随 Goose 进程,测试通过即把产物 git diff 输出到宿主机,然后整个 VM 被 kill -9 销毁,磁盘快照清零。这样就算 LLM 写出恶意代码,也只能污染 5 ms 后就不存在的磁盘镜像。对隐私要求更高的金融、医疗场景,可以把 Firecracker 换成 gVisor 或 Kata,但思路一样:让不可信代码只在 “一次性容器” 里运行,产物通过 diff 回流,主机不做任何持久化。

4. 可观测三板斧:日志、Trace、成本看板

  • 日志:Goose 用 tracing-subscriber 输出 JSON,关键字段 task_id、llm_model、tool_name、exit_code,直接丢进 Loki 就能查;
  • Trace:LLM 调用链用 opentelemetry-rust 接入 OTLP,Span 里把 input/output token、首字节时间(TTFB)打标签,方便在 Jaeger 里按模型维度对比延迟;
  • 成本: Goose 会推 goose_cost_usd{model="claude-3.5-sonnet",user="alice"} 0.018 到 Prometheus,一条 PromQL 就能算 “昨日 Top10 烧钱用户”。

5. 快速落地最小清单

维度 推荐值 备注
Tokio 工作线程 CPU 核心 ×1.5 steal >5 % 继续加
最大并行任务 50 200 并发以上错误率 >3 % 时下调
HTTP 连接池 20/Host 内网 Jenkins/GitHub 自建可提到 50
每日成本上限 10 USD / 人 按 input 0.3 美分 /output 1.5 美分折算
单任务成本上限 2 USD 触发摘要或降档模型
上下文窗口利用率 80 % 触发历史消息压缩
子进程并发 10 本地笔记本默认,CI 可提到 30
VM 磁盘配额 1 GB Firecracker 一次性环境

把以上参数写进 Helm values,再把 Goose 跑在 Firecracker Job 里,你就拥有了一个 “LLM 驱动、可验证、可计量” 的代码生成运行时 —— 既能让模型放手去写,又能在预算红线内把风险降到一次性 VM 的级别。

资料来源

  • Block 官方仓库与发布页:https://github.com/block/goose
  • Goose 高并发实测数据:CSDN《Goose 高并发:处理大量并行请求的能力》
  • Goose 成本计算与优化策略:CSDN《Goose 成本分析:计算和使用成本的工具》
查看归档