☰
strands-agents Python SDK v1.13.0 技术解析:invocation_state 迁移、OTel 语义约定升级与工具层可靠性增强
2026/9/26 23:43:50 网站建设 项目流程
  • 人工智能
  • 大模型
  • AI Agent
  • Agent 框架
  • 多智能体
  • 工具调用
  • MCP 服务

【免费下载链接】harness-sdk

Build an agent harness and control it end-to-end. Open-source SDK for production AI agents in Python & TypeScript - any model, any cloud.

项目地址:https://gitcode.com/GitHub_Trending/sdkpython13/harness-sdk
点击查看免费下载

本篇文章基于 strands-agents Python SDK 的 v1.13.0 版本变更记录(site/src/content/changelog/sdk/python-v1.13.0.md)展开,聚焦该版本在 Agent 调用 API、OpenTelemetry 可观测性语义、工具装饰器校验与中断(Interrupt)机制上的核心改动。读完本文,你将掌握invocation_state的用法与迁移要点、timeToFirstByteMs等新指标在 span/metrics 中的落点、ToolContext参数命名约束,以及"工具调用前中断"这一人机协作模式的实现原理,并能直接对照仓库源码理解每条变更的底层逻辑。

一、版本概览:一次以"调用状态收敛 + 可观测性升级"为主的迭代

v1.13.0(发布于 2025-10-17)共包含 9 条变更,全部为非破坏性(breaking: false),覆盖agent、telemetry/otel、tool/decorator、structured-output、multiagents五个关注域,可归为四条主线:

主线涉及条目影响面
Agent 调用 API 收敛用invocation_state取代散落的kwargs(PR 966)所有调用入口
可观测性语义升级语义约定更新、新增timeToFirstByteMs(PR 997)、新增gen_ai.tool.description/gen_ai.tool.json_schema(PR 1027)OTel span 与指标
工具层可靠性ToolContext参数名校验(PR 1028)、Python 3.10 异常注解(PR 1034)、装饰工具的中断支持(PR 1041)工具开发与执行
生命周期/集成修复工具调用前钩子支持中断(PR 987)、多智能体中断时抛异常(PR 1038)、结构化输出集成测试去 flaky(PR 1030)钩子与多智能体编排

其中other类型的条目(PR 987/1030/1038/1041)虽然不计入"新功能",但它们在钩子中断、多智能体异常语义上同样承载了实质行为变更,本文一并覆盖。

二、核心变更:Agent 调用 API 全面引入 invocation_state

2.1 变更内容与动机

PR 966(作者 JackYPCOnline)将 Agent 调用 API 中依赖**kwargs透传的机制,正式替换为显式的invocation_state参数。在旧实现中,调用方需要依赖"额外关键字参数会被直接透传给事件循环"这一隐式约定;新实现把这类透传数据收敛为一个类型明确、可文档化、可校验的dict[str, Any],从而让事件循环、中间件、工具执行器都能以统一的方式读取调用级上下文。

2.2 源码中的实际签名

以同步入口Agent.__call__为例,在 strands-py/src/strands/agent/agent.py 中:

def __call__( self, prompt: AgentInput = None, *, invocation_state: dict[str, Any] | None = None, structured_output_model: type[BaseModel] | None = None, structured_output_prompt: str | None = None, idempotency_token: Any = None, limits: Limits | None = None, cancel_signal: threading.Event | None = None, **kwargs: Any, ) -> AgentResult:

invoke_async与stream_async采用了完全一致的签名(见 agent.py),且invoke_async内部通过self.stream_async(prompt, invocation_state=invocation_state, ...)将其显式传递给流式事件循环。docstring 中明确标注:**kwargs仍被保留但已标记为[Deprecating]——这意味着旧代码短期内依然可运行,但新代码应优先使用invocation_state。

2.3 invocation_state 的实际消费方

从仓库源码结构看,invocation_state并非仅停留在签名层面,而是贯穿事件循环与工具执行链:

  • 事件循环:event_loop/event_loop.py 与 event_loop/streaming.py 将其作为透传上下文;
  • 工具执行:tools/_caller.py、tools/executors/sequential.py 与 tools/executors/concurrent.py 会把它带入工具调用;
  • 钩子事件:BeforeToolCallEvent/AfterToolCallEvent中直接暴露invocation_state字段(见下文第五节的 hooks/events.py);
  • 模型层:models/model.py 与多智能体的 multiagent/base.py、multiagent/graph.py、multiagent/swarm.py 同样读取该字段;
  • 中间件:_middleware/stages.py 将其纳入中间件阶段的上下文。

2.4 迁移建议

对于 v1.13.0 的使用者:

from strands.agent import Agent # 新写法:显式传递调用状态 agent = Agent(model=model) result = agent("查询一下库存", invocation_state={"request_id": "req-42", "tenant": "demo"}) # 旧写法(仍可用,但已标记 Deprecating): # result = agent("查询一下库存", request_id="req-42")

在工具函数中通过ToolContext读取该状态,即可实现"调用级元数据(如请求 ID、租户、用户身份)随一次调用流转到工具内部"的透传,无需再依赖全局变量或线程局部存储。

三、可观测性升级:语义约定更新与 timeToFirstByteMs 落地

3.1 变更内容

PR 997(作者 poshinchen)更新了 GenAI 语义约定(semantic conventions),并新增timeToFirstByteMs指标,同时写入 span 属性与 OTel 指标;PR 1027 则进一步补充了gen_ai.tool.description与gen_ai.tool.json_schema两个工具级语义属性。

3.2 timeToFirstByteMs 在 span 中的落点

在 strands-py/src/strands/telemetry/tracer.py 的_add_optional_usage_and_metrics_attributes中,模型调用的耗时指标被映射为 GenAI 语义属性:

if metrics.get("timeToFirstByteMs", 0) > 0: attributes["gen_ai.server.time_to_first_token"] = metrics["timeToFirstByteMs"] if metrics.get("latencyMs", 0) > 0: attributes["gen_ai.server.request.duration"] = metrics["latencyMs"]

也就是说,timeToFirstByteMs(首字节/首 token 到达耗时)对应语义属性gen_ai.server.time_to_first_token,而整体延迟latencyMs对应gen_ai.server.request.duration。这一定义在 types/event_loop.py 与 event_loop/streaming.py 中由事件循环产出,并被 telemetry/metrics.py 同步记录为指标:

if metrics.get("timeToFirstByteMs") is not None: self._metrics_client.model_time_to_first_token.record(metrics["timeToFirstByteMs"])

对应的单测位于 strands-py/tests/strands/telemetry/test_tracer.py 与 strands-py/tests/strands/telemetry/test_metrics.py,可用于验证属性名与指标名的实际映射。

3.3 语义约定稳定性开关与工具属性

v1.13.0 之前的版本已支持通过环境变量OTEL_SEMCONV_STABILITY_OPT_IN选择语义约定稳定性级别(tracer.py):

  • gen_ai_latest_experimental:启用最新的 GenAI 语义约定;
  • gen_ai_tool_definitions:在 span 中记录gen_ai.tool.definitions(工具定义集合);
  • gen_ai_use_latest_invocation_tokens:使用最新的 invocation token 命名;
  • gen_ai_span_attributes_only:把消息内容直接记录为 span 属性而非 span 事件(适用于无法读取 span 事件的后端,如 Langfuse);
  • gen_ai_unredacted_attributes=<list>:按;分隔、支持尾部*通配的敏感属性白名单,未命中白名单的gen_ai.input.messages、gen_ai.output.messages、gen_ai.system_instructions、gen_ai.tool.call.arguments、gen_ai.tool.call.result等敏感属性会被脱敏(默认不启用脱敏,向后兼容)。

PR 1027 补充的gen_ai.tool.description与gen_ai.tool.json_schema属于工具定义维度。结合 tracer.py 中已有的工具 span 实现(gen_ai.tool.name、gen_ai.tool.call.id、按最新约定记录的gen_ai.tool.call.arguments/gen_ai.tool.call.result,以及gen_ai.tool.status),工具的描述与 JSON Schema 属性让可观测后端能更完整地重建"模型看到了哪些工具、工具长什么样",对调试工具选择与参数生成错误尤其有价值。

配置建议:若你的后端(如 Langfuse 或自建 OTLP Collector)已支持最新 GenAI 语义约定,可设置OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental,gen_ai_tool_definitions以获得工具定义、TTFT、工具调用参数等更丰富的信息;若对敏感内容有合规要求,再追加gen_ai_unredacted_attributes=(空值表示全部敏感属性脱敏)并显式放行需要的属性。

四、工具装饰器加固:ToolContext 参数名强校验

4.1 变更内容

PR 1028(作者 Ratish1)为@tool装饰器增加了签名校验:当函数参数标注了ToolContext类型时,若未通过@tool(context=...)声明上下文参数名,或参数名与声明不一致,会在装饰阶段直接抛出带有明确信息的ValueError,避免运行时才暴露"上下文未被注入"的隐性错误。

4.2 源码实现

校验逻辑位于 strands-py/src/strands/tools/decorator.py:

def _validate_signature(self) -> None: """Verify that ToolContext is used correctly in the function signature.""" for param in self.signature.parameters.values(): annotation = self.type_hints.get(param.name) if annotation is ToolContext or get_origin(annotation) is ToolContext: if self._context_param is None: raise ValueError("@tool(context) must be set if passing in ToolContext param") if param.name != self._context_param: raise ValueError( f"param_name=<{param.name}> | ToolContext param must be named '{self._context_param}'" ) break

同时,decorator.py 中ToolContext参数名本身也不允许为空(ValueError("Context parameter name cannot be empty"))。

4.3 正确用法示例

from strands.tools import tool from strands.types.tools import ToolContext @tool(context="tool_context") # 必须显式声明上下文参数名 def my_tool(name: str, count: int = 1, tool_context: ToolContext) -> str: # tool_context.invocation_state / tool_context.agent 等可直接使用 return f"{name} x {count}"

常见错误与报错对照:

错误写法报错信息
参数名为ctx但声明为@tool(context="tool_context")param_name=<ctx> \| ToolContext param must be named 'tool_context'
有ToolContext参数但未传context=@tool(context) must be set if passing in ToolContext param
@tool(context="")Context parameter name cannot be empty

这一校验让"上下文参数漏配/误配"从难以排查的运行时注入失败,前置为装饰阶段的清晰报错,显著降低了工具开发者的排障成本。

五、工具调用前钩子支持中断:BeforeToolCallEvent 的人机协作能力

5.1 变更内容

PR 987(作者 pgrayy)为"工具调用前"事件引入了中断(interrupt)能力:钩子回调在执行BeforeToolCallEvent时可以直接抛出InterruptException,从而在工具真正执行前暂停整个 Agent 事件循环,等待外部(通常是人类)介入。

5.2 事件定义与中断语义

事件定义位于 strands-py/src/strands/hooks/events.py:

@dataclass class BeforeToolCallEvent(HookEvent[_LocalAgentT], _Interruptible): selected_tool: AgentTool | None # 即将执行的工具,钩子可替换 tool_use: ToolUse # 工具调用参数 invocation_state: dict[str, Any] # 调用级状态 cancel_tool: bool | str = False # 置为非空字符串可取消本次工具调用
  • 钩子可以修改selected_tool/tool_use以替换将要执行的工具;
  • 设置cancel_tool会在不执行工具的情况下返回一个 error 状态的工具结果;
  • 继承自_Interruptible意味着钩子可抛出中断(Interrupt/InterruptException),事件的中断 ID 为f"v1:before_tool_call:{tool_use['toolUseId']}:{uuid5(...)}",保证同一工具调用上可区分不同命名的中断。

中断的聚合逻辑在 strands-py/src/strands/hooks/registry.py:invoke_callbacks会捕获回调抛出的中断异常、按名字去重聚合,返回给事件循环,由上层实现 human-in-the-loop 流程。

5.3 装饰工具的中断支持

PR 1041 进一步将中断能力扩展到了@tool装饰器生成的工具上:装饰工具的执行链路同样支持在调用前/过程中抛出中断并让事件循环暂停,与钩子事件形成互补——钩子用于"调用前拦一道",装饰工具则可在工具自身逻辑中触发暂停。

5.4 多智能体场景的行为约定

PR 1038 规定:在多智能体编排中,如果子智能体被中断,当前实现会临时抛出异常(temporarily raise exception when interrupted),而不是静默吞掉中断或返回空结果。这意味着在 multiagent/graph.py 或 multiagent/swarm.py 这类编排器中,父级需要感知子任务的暂停状态并决定是继续、等待还是终止,这一行为约定在集成测试中得到了固化(见 strands-py/tests_integ/test_multiagent_graph.py 与 strands-py/tests_integ/test_multiagent_swarm.py)。

六、Python 3.10 兼容:异常注解(Exception Notes)能力补齐

6.1 变更内容

BaseException.add_note()是 Python 3.11 才引入的 API。PR 1034(作者 zastrowm)为 SDK 增加了 Python 3.10 下的等价实现:当运行环境不支持add_note时,将注解文本追加到异常消息中,从而让 SDK 内部(尤其是中断与错误传播路径)在 3.10 上也能携带结构化注解信息。

6.2 实现细节

工具函数位于 strands-py/src/strands/_exception_notes.py:

# add_note was added in 3.11 - we hoist to a constant to facilitate testing supports_add_note = hasattr(Exception, "add_note") def add_exception_note(exception: Exception, note: str) -> None: if supports_add_note: exception.add_note(note) # Python 3.11+ else: # For Python 3.10, append note to the exception message if hasattr(exception, "args") and exception.args: exception.args = (f"{exception.args[0]}\n{note}",) + exception.args[1:] else: exception.args = (note,)

实现要点:

  • supports_add_note被提升为模块级常量,便于测试(对应的测试位于 strands-py/tests/strands/test_exception_notes.py);
  • 3.10 回退路径通过改写exception.args实现,注解以\n换行追加,尽量保持str(exception)的可读性;
  • 由于是运行时能力探测而非版本号判断,3.11 之后的所有版本都会自然走原生add_note()路径。

七、质量保障:结构化输出集成测试去 flaky

PR 1030(作者 pgrayy)修复了结构化输出(structured output)集成测试的偶发失败。这类 flaky 通常来自模型响应不稳定或时序竞争,修复方式是让测试对模型输出做更宽容的断言或引入确定性重试。相关的集成测试位于 strands-py/tests_integ/test_structured_output_agent_loop.py,可结合 tools/structured_output/ 目录下的实现(structured_output_tool.py与_structured_output_context.py)理解结构化输出工具的整体链路。

八、升级清单与兼容性说明

综合 v1.13.0 全部变更,从旧版本升级时的核对清单如下:

  1. 调用 API:将依赖**kwargs透传的调用逐步迁移到invocation_state参数(旧写法仍可用但已标记 Deprecating);
  2. 可观测性:确认后端是否兼容最新 GenAI 语义属性(gen_ai.server.time_to_first_token、gen_ai.server.request.duration、gen_ai.tool.description、gen_ai.tool.json_schema),并按需设置OTEL_SEMCONV_STABILITY_OPT_IN;
  3. 工具开发:为所有带ToolContext参数的@tool函数补齐context=声明,且参数名必须一致,否则装饰阶段即报错;
  4. 钩子与中断:若在BeforeToolCallEvent中实现审批/拦截逻辑,可利用cancel_tool或抛出中断实现工具执行前的暂停;多智能体场景注意子智能体被中断时父级会收到异常;
  5. Python 版本:SDK 在 3.10 上同样能携带异常注解,无需在应用层做版本分支。

所有变更均为非破坏性(breaking: false),可在不修改既有业务代码的前提下平滑升级;对应的版本记录与仓库根目录下各子项目的源码、测试可直接对照查阅(如 strands-py/src/strands/agent/agent.py、strands-py/src/strands/telemetry/tracer.py、strands-py/src/strands/tools/decorator.py、strands-py/src/strands/hooks/events.py)。

  • 人工智能
  • 大模型
  • AI Agent
  • Agent 框架
  • 多智能体
  • 工具调用
  • MCP 服务

【免费下载链接】harness-sdk

Build an agent harness and control it end-to-end. Open-source SDK for production AI agents in Python & TypeScript - any model, any cloud.

项目地址:https://gitcode.com/GitHub_Trending/sdkpython13/harness-sdk
点击查看免费下载

相关推荐

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

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

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

立即咨询