Google 工程团队使用 Gemini 4 Argon,结合 .agents/skills 与 /goal 模式,整夜无人值守优化开源 Python ADK。素材报告长会话中的内存会话准备开销降低 40%,冷导入速度提升 21%。
新模型发布时,大多数演示都会从一个空文件夹开始,搭建全新的应用。这些演示看着很有意思,但对于真正从事软件开发的工程师来说,它们几乎无法说明模型在已有代码库中表现如何。
为了配合 Gemini 4 Argon 的发布,我们想测试它能否在无人值守的情况下,整夜处理一个难度高得多的问题:找出并修复 google/adk-python 中跨文件的性能瓶颈。Agent Development Kit(ADK)是 Google 用于构建和部署企业级 Agent 的开源框架。
这个 Python 仓库包含近 800 个源文件,代码总量约 205,000 行,并有近 17,000 个单元测试作为保障。
性能优化对模型来说是一项严苛的考验,因为你无法只打开一个文件,就找到拖慢速度的原因。你必须跳出症状出现的位置,从其他角度排查,并在长时间运行中始终掌握整个代码库各部分之间的关系。
本文将介绍这次持续 11 小时的通宵运行中使用的 prompt、.agents/skills 规则文件,以及人工代码审查时做出的取舍。这次运行让 ADK 在长会话中的内存会话准备时间减少了约 40%,冷启动时的包导入速度提升了 21%。你将看到最终发布的两项优化、我们在审查中否决的四项优化,以及如何在自己的代码库中搭建同样的通宵工作流程。
目前,使用 coding Agent 做性能优化,大多仍然需要人类紧密参与:工程师先运行 profiler,再让模型关注某个热点函数,并明确指定修复方式。我们想看看,如果只告诉 Argon 团队关心的最终目标,它会怎么做。
第一轮,我们没有提供任何自定义的仓库指令来测试 Argon。我们只给了它一段 prompt:
第一轮运行了大约两小时。Argon 在第 7 分钟写出了 benchmark 脚本,随后花了 70 分钟进行测量和阅读代码,之后才修改第一行 ADK 源码。它找到了会话复制和包导入中确实存在的瓶颈。第一轮产出的部分代码进入了我们最终发布的 commit。
第一轮的不足在于没有遵循维护者的约定。由于 Argon 不知道 ADK 团队如何审查代码,它给 ADK 的认证模型附加了一个自定义 hook,悄然改变了对外公开的 JSON schema;它的自定义复制器遗漏了 mock event 的边界情况;它只运行了 216 个相关单元测试,也没有在 pull request 描述中列出 benchmark 数据。
第一轮证明,确实存在可以挖掘的提速空间。于是我们启动了第二轮,并做了两项调整。首先,我们把团队的维护者指南放进仓库的 .agents/skills 目录,就像给新工程师准备一份入职指南。每个 skill 都以一个简短的 SKILL.md 索引开头,按需指向 references/ 中针对具体主题的文件,避免每一轮都用大量内容塞满 Agent 的上下文窗口。Argon 在晚上 9:11 开始运行时(图 2),先阅读了 visibility.md,了解我们对以 _ 为前缀的私有模块的规定,又阅读了 imports.md,了解我们的延迟加载检查要求,然后才动手修改代码。
其次,我们在 Google Antigravity 中开启了 /goal 模式。它会在上下文压缩后保留目标,让 Agent 持续运行,直到任务完成。我们还补充了两句话,要求它提交一个尚未合并的 pull request,并附上修改前后的数据:
仓库中配置好 .agents/skills,并启用 /goal 模式后,Argon 在无人值守的情况下整夜运行了 11 小时(图 3)。
第二天早上查看通宵运行的会话日志时,有几个行为立刻引起了我们的注意。在修改源码之前,Argon 阅读了 12 份指南文件,并针对四种测试负载运行了基线 benchmark:包启动、一段包含 200 个步骤的对话、一个由 20 个 sub-agent 相互交接任务的测试应用,以及一个运行 30 次的 12 节点工作流。甚至在这次 11 小时运行结束前的最后三分钟,Argon 仍在检查自己的 diff,发现了自己实现的多 Agent 缓存中的一个 bug,并重新运行了全部 16,892 个单元测试,随后才自行停止。
更重要的是,Argon 完成了 profiler 无法替你完成的跨模块排查。profiler 会告诉你,复制会话和导入包很耗时。但它不会追踪分布在 40 个文件中的每一个调用方、mock 目标和共享引用,确保这些路径提速后不会破坏已有应用。
Argon 的 pull request 总共提出了六项优化,涉及 32 个文件。其中两项以干净利落的方式解决了 ADK 的核心瓶颈,并发布到了生产环境:
ADK 每一步运行都从加载对话历史开始。此前,ADK 的内存会话服务每次读取时,都会先深拷贝完整的已存储对话,再筛选出调用方请求的 event。即使只是列出会话、不需要其中的 event,也会先复制每一个 event。Argon 修改了这个服务,让它先筛选 event,再进行复制;同时,将 session 和 event 上 Pydantic 的通用深拷贝路径替换为一个快速、可安全处理循环引用的复制器,并保留共享状态字典和测试 mock。
此前,即使只是运行一个基础的文本 Agent,执行 import google.adk 也会引入实时音视频流、OpenTelemetry tracing,以及 Web 服务器相关模块(FastAPI 和 Starlette)。在框架中直接删除顶层 import,会破坏那些直接 mock 模块属性的下游测试。Argon 第二轮的 pull request 从 llm_agent.py 中移除了三个内部 flow import 后,全部 16,892 个开源测试都通过了,但 Google 内部的 25 个测试目标却失败了,因为它们恰好对这些属性进行了 patch。最终发布的修复使用了延迟加载的模块访问器,让重量级包仅在首次使用时加载,同时确保每个公开属性仍然可以在测试预期的位置被 patch。
我们发现,模型能提出一些我们原本不会想到的创意方案。其中一些方案会触碰框架的规则,而框架不能接受破坏兼容性的改动。
在代码审查中,我们否决了另外四项改动:
这种分工正是这套工作流程能够奏效的原因:Agent 负责探索,维护者负责做减法。我们结合了第一轮和第二轮中最好的部分,形成了一项涉及 22 个文件的改动,并新增了 17 个测试函数作为保障。经过 ADK 团队的审查,这项改动合并进了 main,commit 说明中写着:“这些改动由 Argon 生成。”
要理解 commit 信息中的数据,先了解 ADK 如何定义 turn 会更有帮助。
当工程师输入一个 prompt,并收到最终答案时,ADK 将这个过程称为一次 invocation。turn 则是 Agent 每次执行动作时,底层发生的一个内部步骤:调用一个工具、执行一批并行工具调用,或查询一个 MCP server。
使用 Agent 框架的目的,就是实现多轮工具调用。在一次运行之下,可能会发生几十个甚至几百个内部 turn。
在两轮测试开始之前,我们编写了一个独立的留出 benchmark(bench_turn.py),Argon 从未见过它。在 bench_turn.py 中,单个会话逐个 turn 增长,使用立即返回的模型和工具,因此计时中的每一毫秒都来自 ADK 框架自身的开销。每个 turn 都会执行三轮工具调用,每轮并行调用四个工具,然后返回答案;我们分别在已有 0、50 和 150 个 turn 的情况下,对接下来的 5 个 turn 计时。下文每个数据都是 6 至 12 次运行的中位数,而且在修改前后,每个 turn 中模型收到的请求都逐字节完全一致。
我们通过五项 benchmark,将合并后的 commit 与上一个发布版本进行了比较(图 5):
对于你自己的 Agent,可以这样理解这些数据:
import google.adk 提速 21%,能立即惠及每一位 ADK 用户,让 CLI 命令、本地开发和测试发现更快。由于延迟加载的模块仍会在 Agent 运行第一个 turn 时加载,从全新进程启动到发出第一次模型请求的时间基本不变(从 3.07 秒变为 3.09 秒)。在生产服务器上,应在接收真实流量前发送一次预热请求,避免让第一个用户请求承担这笔一次性的导入开销。企业开发者和应用构建者可以通过 Gemini platform 中的 API 使用 Argon,其 model ID 为 gemini-4-argon;也可以在 Google AI Studio 和 Google Antigravity 中使用它。
请查看 model card 和开发者指南,了解完整的技术规格、token 限制和迁移说明。
ADK 的 Python 快速入门。
直接在 google/adk-python 中查看已合并的 pull request 和 benchmark commit。
如果你希望 Agent 在无人值守运行之前了解仓库的架构规则和 CI 检查要求,可以复制 google/adk-python 中的 .agents/skills 目录结构。
Agent Development Kit