Google 的 Agent Development Kit 在 v2.14.0 里把二十六个模块升为 stable,而埋在同一份发布说明里的那句话,应当改变你读"稳定"标签的方式:stable 的 toolset 与集成功能现在一律启用,而过去用来关掉它们的那些开关不再拦得住它们。升为 stable 不是一次文档改动——它把功能打开了,并且把开关拿走了。那次发布里另有四处改动,在不碰任何一个函数签名的情况下改变了你智能体的实际行为,而这正是普遍的问题:在一个智能体框架里,版本号守的是 API,几乎守不到任何决定行为的东西。
这次发布说了什么
ADK v2.14.0 是一次分量不小的发布,changelog 头部标注 2026-11-04,而发布于 11 月 7 日。标题是成熟度:A2A 集成现为 stable;BaseEnvironment、LocalEnvironment、EnvironmentToolset、DaytonaEnvironment 与 E2BEnvironment 现为 stable;26 个 auth、environment、app、CLI 与 cache 模块升级;16 项 toolset 与集成功能获得提升,包括 Bigtable、Computer Use、Environment Simulation、GCS、MCP agent server、Pub/Sub 与 Spanner。在此之上的新东西:一个对接 Microsoft Teams 的 TeamsRunner、经 adk eval --num_runs 与 --parallelism 的多次运行评测,以及用 adk generate_agent_card 从 CLI 生成 A2A agent card。
不过,请读一读发布说明实际给出的那个定义。升级后的 API 可以"不带实验性警告"地使用。这就是全部承诺。这次发布并未作出更广的 API 兼容性保证,而且它没有列出任何弃用项——在一次升级了这么多东西的发布里,这一点值得注意,因为一个不附带弃用政策的稳定标签,是一项关于日志输出的声明,而不是关于你迁移成本的声明。
升为 stable 把功能打开了,并拿走了那个开关
行为变更的说明里有这么一条:stable 的 toolset 与集成功能一律启用,而禁用开关不再拦得住它们。请在运维层面上体会这意味着什么。一个曾明确关掉——比如说——Computer Use 或 MCP agent server 的团队,无论是因为还没审过,还是因为自家威胁模型不允许,在一次小版本升级之后会发现那些功能已经处于启用状态,而那个曾表达了这个决定的开关如今形同虚设。
这不是草率;这是"把 experimental 当作开关所把守之物"这一做法的逻辑终点。如果开关的用途是把不成熟的代码挡在默认路径之外,那么成熟就让开关退役。但这个开关还在干第二份活,而没人把它写下来:表达一项关于"智能体可以做什么"的政策。这两份活只是偶然重合,而它们恰恰在"升为 stable"这一刻分道扬镳。
后果是:在一个智能体框架里,某个功能的默认状态是一项安全控制,而在这次发布里,这项控制一次移动了十六个功能。这正是未钉定的厂商默认值的主题,也是为什么一份工具清单必须从运行中的系统推导出来,而不是从你写下的配置里来——见工具目录的生命周期。
一个只意味着"还没到时候"的"关",从来就不是一项政策。如果你需要某项能力在它成熟之后仍然保持关闭,那这项控制就必须住在框架的成熟度模型触达不到的地方。
那四处"不动 API、却动了行为"的改动
发布说明列出了三处常规意义上的破坏性变更——枚举类工具参数现在以枚举成员而非原始字符串到达、VertexAiSessionService.create_session 把额外关键字参数限制为四个名字,以及环境模式下的 RunSkillScriptTool 不再接受一个 command 字符串。这些是类型检查器或测试抓得到的那些。真正有意思的,是它抓不到的那一组。
压缩触发得更早。基于 token 阈值的压缩现在把"自上一次模型调用以来的工具输出"也计入,于是它比以前更早触发。你的代码什么都没变;变的是你智能体的上下文被重写的那个时点,也就是它在任务中途记得些什么。如果你曾对着旧阈值去调一个长时间运行的智能体,那份调参现在描述的是另一个系统了——而压缩是循环里杠杆最大的行为之一,正如上下文压缩所阐明的。
每次响应多出两个事件。带 output_schema 且有转交目标的智能体,在某些模型上现在会使用 set_model_response,于是每次响应多两个事件。每一条关于事件数量的断言、每一份以事件为键的按次成本归因、每一份链路数据量预测,都会按一个你没有选择的常数发生位移。
指标分桶移动了。若干 gen_ai 指标的直方图分桶边界变了。直方图的百分位是由分桶边界算出来的,所以在你的延迟并没有变的情况下,你的 p95 延迟可以移动——而它看起来是退步还是改善,取决于你真实分布相对于新边界落在哪里。任何跨这次升级对某个延迟百分位设告警的人,都是在比较两把不同的尺;测量上的那些坑在度量智能体延迟。
回滚不再可用了。FirestoreSessionService 现在把事件载荷存为 JSON 字符串,而这个版本写下的会话,在回滚之后无法被 2.13.0 或更早版本读取。另外,新建的 PostgreSQL JSON 列被创建为 json 而不是 jsonb,且既有表不做迁移——于是一次全新部署与一次升级过的部署,如今在存储表示上就不一样了。一次"写出前一版读不了的格式"的小版本升级,是一道单向门,而它需要配上与之相称的仪式:见发布与版本管理,以及(针对你部署期间仍在进行中的那些会话)长命会话与部署。
一次以人机工程学改动形式交付的安全修复
RunSkillScriptTool 那处改动值得单拎出来。它不再接受一个 command 字符串;它现在接受 args、short_options 与 positional_args,从 skill 目录里运行脚本,并且只允许 .py、.sh 与 .bash。说明称这堵住了一个提示注入漏洞。
这是一次实实在在的加固——用一个结构化参数列表替掉一个自由形式的命令字符串正是对的修法,因为它把 shell 从"模型输出能够触达的那条路径"上移走了。而它同时也是在发布说明里作为破坏性变更归档的,而不是作为一份安全公告宣布的,也没有引用任何 CVE。一个只读公告的团队什么都学不到;一个读变更日志的团队,把它当成一件 API 迁移的杂活学到了。
这是智能体工具链里反复出现的形状:修复与重构是同一个 commit,于是与安全相关的那处改动,是从你会略读的那条渠道到来的。底下那类 bug——一个工具的参数变成了一条 shell 命令——是提示注入触达了一个解释器,而结构性的补救正是此处所用的这一招,其一般讨论在工具 schema 与契约。
A2A 在一个 SDK 里变 stable,不等于 A2A 变 stable
这次发布把 A2A 集成标为 stable,并添了从 CLI 生成 agent card 的能力。两者都有用,而值得抓住的区分是:一个客户端实现的稳定性与一个协议的稳定性,是由不同主体就不同事情作出的不同声明。一个 SDK 承诺不改自己的 A2A 表面,对"协议自身的修订节奏是否会迫使它改"一字未言——而这正是协议修订与弃用窗口里那个普遍问题,也是为什么协议自己的版本管理比你那个库的更要紧;当前的形状在 A2A v1 深入解析与agent card 与发现。
还要注意那些 stable 的 environment 类把你绑进了什么:DaytonaEnvironment 与 E2BEnvironment 的升级意味着该框架现在对第三方沙箱厂商有了一等的、stable 的绑定,而 e2b 的最低版本在这次发布里提到了 2.29.5。框架边界上的稳定性,并不会传播到它背后的那个厂商身上。
这周就该改的事
以上没有一条是反对升级的论据——这次发布显然是一次好发布,而带 --num_runs 的多次运行评测,对任何一直在比较单次运行分数的人来说都是一项实实在在的改进。它是一则关于"该往哪儿看"的论据。
- 从运行中的智能体出发,比对升级前后你实际的工具面。不要从你的配置出发。曾因为某个开关这么说而关着的十六项功能,现在可能开着,而那个开关不会告诉你。这正是面向智能体的功能开关存在的目的,而它只在那项控制归你所有时才奏效。
- 把能力决策从框架的成熟度开关里挪出来。如果某个工具必须保持不可用,就在框架升不掉它的地方强制执行:一份归你所有的白名单,或者智能体外围而非内部的权限边界。
- 在新分桶上重新建立你的延迟百分位基线。在你的仪表盘上于升级处画一条线,不要跨过它比较。把头一周的百分位位移当作埋点现象、而不是性能现象,直到被证明为别的。
- 测回滚,不要只测升级。在新版本上写一个会话,再试着在旧版本上读它。如果这失败了——在 Firestore 上它会失败——那你的回滚计划其实是一份恢复计划,而两者的 RTO 不同;见持久状态与可恢复性。
- 在把任何变化归因到模型之前,先重跑你的评测。更早的压缩触发与每次响应多出的两个事件,都会在输出质量与成本上显形。一个在框架升级之后看起来不一样的模型,大概并没有不一样。
- 把变更日志当作安全情报源来读。这里那处提示注入修复没有附带任何公告。如果你的流程只摄入 CVE,那你就没在看你的智能体框架实际使用的那条渠道。
而那个被稳定标签掩盖的普遍教训是这样的。一个常规库的行为被它的 API 框住,所以给它的 API 做版本管理就等于给它的行为做了版本管理。而一个智能体框架的行为还取决于:它何时压缩、它默认暴露哪些工具、它往上下文里注入什么、它如何序列化状态——这些全都没有函数签名。在框架显式地给这个面做版本管理之前,你真正需要的那条升级说明是关于默认值的那条,而它会是你略过去的那一行。
常见问题
我们该跳过这次发布吗?
不该——这是一次很强的发布,而仅凭 RunSkillScriptTool 里那处加固就值得接下它。要点是把它当作一次"附带了版本号的行为变更"来对待,而不是当作一次例行的小版本提升:比对工具面、重建延迟百分位基线,并在你需要回滚之前先测一次回滚。
这里的"stable"究竟是什么意思?
按发布说明自己的说法,是指升级后的 API 可以"不带实验性警告"地使用。它没有声明更广的 API 兼容性保证,而这次发布也没有列出任何弃用项。所以请把它读作一项关于日志输出与厂商信心的声明,而不是一项关于迁移成本的承诺。
哪一处改动最可能无声地咬到我们?
是"禁用开关不再拦得住 stable 功能"那一处,因为它改变了你智能体能做什么,同时让你的配置文件看起来毫无变化。其次是更早的压缩触发,因为它改变了智能体在任务中途记得什么,并且会被读成一次模型或提示词的退步。
我们能从 2.14.0 回滚吗?
在 Firestore 上不能干净回滚:这个版本写下的会话在回滚之后无法被 2.13.0 或更早版本读取,因为事件载荷现在存为 JSON 字符串。另请注意,新建的 PostgreSQL JSON 列被创建为 json 而非 jsonb,且既有表不做迁移,于是全新部署与升级过的部署在存储表示上会分叉。
A2A 在 ADK 里变 stable,意味着 A2A 稳定了吗?
不。那是由不同主体就不同事情作出的声明——一个 SDK 的表面,与一个协议的修订节奏。一个 stable 的客户端绑定有用,而它并不能把你与一次协议修订隔开。
那处提示注入修复有分配 CVE 吗?
发布说明没有引用任何 CVE;这处改动是作为"堵住了一个提示注入漏洞"的破坏性变更呈现的。这是值得围绕它去做规划、而不是值得去批评的那种模式——在智能体工具链里,安全修复经常就装在普通的变更日志条目里交付。
延伸阅读
本站内容:
- 未钉定的厂商默认值——当一个默认值在你脚下变了,而你仓库里什么都没动。
- 发布与版本管理——升级一个持有状态的智能体。
- 长命会话与部署——你发版时仍在进行中的那些会话。
- 上下文压缩——为什么触发点是一项行为设置。
- 度量智能体延迟——百分位、分桶,以及会移动的尺。
- 工具 schema 与契约——为什么结构化参数列表胜过一条命令字符串。
来源:
- google/adk-python v2.14.0 发布说明——上文引用的每一处改动。
- google/adk-python——仓库本体。
- PyPI 上的 google-adk 2.14.0——已发布的软件包。