strands-py 移植指南:从 TypeScript SDK 到 Python SDK 的逐条映射规则与实现解析

发布时间:2026/9/29 5:24:17

strands-py 移植指南:从 TypeScript SDK 到 Python SDK 的逐条映射规则与实现解析 人工智能大模型AI AgentAgent 框架多智能体工具调用MCP 服务【免费下载链接】harness-sdkBuild 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-py/docs/PORTING.md 整理Strands 以 TypeScript SDKstrands-ts为规范canonical实现Python SDKstrands-py以复刻 TypeScript 行为、用地道 Python 表达为移植原则。文章逐条展开该文档定义的构造级映射规则construct-to-construct mappings并辅以strands-py源码与测试中的实际实现佐证帮助你在为 strands-py 贡献功能时准确完成跨语言移植。移植总则TypeScript 是规范Python 是复刻移植的核心立场只有一句话TypeScript SDK 是规范canonical一个移植port就是复现 TypeScript 的行为并以地道的 Python 表达出来。strands-py与strands-ts属于同一仓库下的双实现 SDK见 strands-py 与 strands-ts两者的对外能力、事件模型、工具系统与模型接口必须保持行为一致这正是 PORTING.md 存在的原因。PORTING.md 只收录构造到构造construct-to-construct的映射规则即一个 TypeScript 语法结构应该翻译成哪种 Python 结构至于通用语言惯用法例如循环、异常处理、命名习惯默认读者已经掌握文档不赘述。此外凡是因为 Python或当前代码库限制而不得不做的让步统一收敛在 Workarounds 一节中——这类映射并非自由选择而是受既有代码约束的结果。下面按文档顺序逐条展开。一个 TypeScriptinterface按角色映射为三种 Python 形态之一TypeScript 的interface一个结构往往身兼数职而 Python 用不同的构造表达不同角色。因此映射规则取决于该 interface是拿来干什么的1. 行为契约含方法成员→Protocol如果 interface 只声明了方法、描述一段行为契约就映射为 Python 的Protocol隐式实现不需要显式继承# interface Extractor { extract() } - class Extractor(Protocol): def extract(self) - ...: ...strands-py中大量使用此模式。例如 agent/base.py 中的AgentBase(Protocol)定义了所有 Agent 实现必须满足的最小契约invoke_async、stream_async等types.py 中的ContextStrategy(Protocol)声明了name属性与async def apply(context) - bool方法任何实现了这两个成员的对象都能作为上下文削减策略传入管线无需继承任何基类。2. 任意数据形态纯字段、构造后传递→dataclass如果 interface 只是承载数据字段被构造出来、传来传去映射为dataclass其中readonly字段对应dataclass(frozenTrue)# interface ExtractionResult { readonly text: string; ... } - dataclass(frozenTrue) class ExtractionResult: text: str3. 纯构造配置解构一次用于建对象、不作为整体保留→ 显式__init__参数如果 interface 只是构造参数被解构一次用来创建别的对象之后不再整体保留则不引入任何类型直接写成__init__的显式参数字段变成实例属性。必填字段尤其是必填回调用位置参数可选字段放在裸*,之后强制 keyword-only# interface ContextInjectorConfig { render_content: ...; name?: ...; trigger?: ... } - class ContextInjector: def __init__(self, render_content, *, nameNone, triggerNone): self.render_content render_content self.name name self.trigger trigger这样既避免了为一次性配置创建冗余数据类又通过*,让可选参数无法被位置误传语义与 TypeScript 的 destructuring 可选属性完全对齐。带字符串标签的对象字面量联合成员 → frozen dataclass当一个联合union成员是带字符串标签的 TypeScript 对象字面量时映射为 frozen dataclass标签用非 init 默认字段表示# type Deny { type: deny; reason: string } - dataclass(frozenTrue) class Deny: type: str field(defaultdeny, initFalse) reason: str 关键映射点readonly→frozenTrue字面量type:标签 →field(default..., initFalse)运行时存在该字段但不是构造参数工厂函数function deny(reason): Deny坍缩进构造函数deny(x)变成Deny(reasonx)联合别名直接照搬type X A | B→X A | B下游按标签分发switch (action.type)→isinstance判断isinstance(action, Deny)。这个模式在strands-py的干预intervention系统中得到完整落地。interventions/actions.py 中定义了Proceed、Deny、Guide、Confirm、Transform五个 frozen dataclass每个都带有type: str field(default..., initFalse)标签字段并在文件末尾聚合为联合别名InterventionAction Proceed | Deny | Guide | Confirm | Transformactions.py#L117。分发端同样印证了isinstance取代switch的规则interventions/registry.py 中_apply_before_invocation用一连串if isinstance(action, Deny) / elif isinstance(action, Guide) / elif isinstance(action, Transform) / elif isinstance(action, Proceed)完成事件处置Deny 直接设置event.cancel fDENIED: {action.reason}并短路后续 handler与 actions.py 文档字符串中给出的兼容性矩阵一一对应。tool({...})对象字面量 →tool装饰的函数TypeScript SDK 用tool({...})对象字面量声明工具Python 端则用tool装饰一个函数。对象字面量的每个字段都落到函数的一个特定位置TypeScripttool({...})字段Pythontool函数name: summarize_context函数名def summarize_contextdescription: ...函数 docstringinputSchema: z.object({ keepRecent: z.number().int().optional() })类型化参数keep_recent: int \| None None每个字段的.describe(...)docstring 中对应的Args:条目callback: (input, context) {...}函数体context第二个回调参数tool(contextTrue)加上tool_context: ToolContext参数也就是说声明式 schema 及其描述全部坍缩进函数签名 Google 风格 docstring不再有单独 schema 对象。源码实现印证了这一设计的全部细节。tools/decorator.py 是整个映射的落地处docstring 解析FunctionToolMetadata在构造时用docstring_parser.parse(inspect.getdoc(func))解析 docstringdecorator.py#L109-L114Args:条目被提取为param_descriptions字典描述即 description_extract_description_from_docstring会剔除Args:段、保留Returns:/Raises:/Examples:等段作为工具描述decorator.py#L235-L261签名即 inputSchema_create_input_model遍历函数签名把类型注解含Annotated元数据、处理 PEP 563 字符串注解与默认值合成为 Pydantic 模型作为输入校验 schemadecorator.py#L192-L233context 注入tool(contextTrue)默认把tool_context作为注入参数名tool(contextmy_name)可改名decorator.py#L822-L829。_validate_signature会在函数签名中出现ToolContext却未声明context时抛出ValueError(tool(context) must be set if passing in ToolContext param)decorator.py#L177-L190_is_special_parameter则把self、cls、agent与配置的 context 参数排除出输入校验模型decorator.py#L434-L454。一个同时演示签名映射与 context 映射的官方示例decorator.py#L813-L819tool(namecustom_tool, descriptionA tool with a custom name and description, contextTrue) def my_tool(name: str, count: int 1, tool_context: ToolContext) - str: tool_id tool_context[tool_use][toolUseId] return fProcessed {name} {count} times with tool ID {tool_id}ToolContext与ToolSpec类型定义位于 types/tools.pyToolSpec含name、description、inputSchema、可选outputSchema与 MCPannotations这些键与 TypeScript 侧一致。相应的校验测试可见 tests/strands/tools/test_decorator.py例如tool(context)缺失即报错的用例在 test_decorator.py#L1839。外部协议线键wire keys原样保留不做大小写转换凡是属于外部 API 或协议、不属于 SDK 自有表面的键必须逐字符复制不能重新改大小写re-case。max_tokens、input_tokens、tool_use、stop_reason都是第三方拼写照抄即可。这条规则同样延伸到在 docstring 与注释中提及这些键的文本——注释里写键名时也要保持第三方拼写便于按协议文档检索与对照。这一点在源码中有直接体现strands-py的工具类型定义文件开头明确写着These types are modeled after the Bedrock APItypes/tools.py#L1-L6因此toolUseId、inputTokens等 Bedrock 拼写保留原样模型层返回的流式事件与停止原因也使用stop_reason这类第三方拼写。Workarounds兼容性让步与桥接方案以下两条是受 Python或现有代码库限制而做出的让步——与前面的规则不同如果是从头移植你不会这样设计但既然要复用既有代码与生态就只能这样桥接。Python 表面是异步的用工作线程桥接仅同步客户端strands-py对外暴露的方法始终是异步生成器async def stream(...) - AsyncGenerator[...]。底层客户端具体怎么驱动取决于它提供什么能力有异步客户端可用例如 Anthropic 的AsyncAnthropic直接使用配合async with/async for。当 TypeScript API 同时暴露同步与异步两种形态时Python 移植取异步形态。源码证据models/anthropic.py 用anthropic.AsyncAnthropic(**client_args)构造客户端stream()内部async with self.client.messages.stream(**request) as stream:加async for event in stream:消费事件anthropic.py#L936-L944。仅有同步客户端boto3 没有异步客户端保持异步生成器的表面但把阻塞调用放进asyncio.to_thread通过asyncio.Queue加一个回调把事件回传给事件循环并用哨兵值None表示结束。阻塞工作绝不能跑在事件循环线程上。这条规则在 Bedrock 模型中有完整实现。models/bedrock.py 中工作线程侧_stream在独立线程中调用 boto3 的converse_stream/converse注释明确说明This method operates in a separate thread to avoid blocking the async event loop见 bedrock.py#L1419-L1422桥接侧stream()中定义callback(event)用loop.call_soon_threadsafe(queue.put_nowait, event)把事件从工作线程安全投递到事件循环bedrock.py#L1362-L1368asyncio.Queue[StreamEvent | None]承载事件None即结束哨兵消费侧_next_stream_event负责取下一个事件若取消先到则放弃等待并用asyncio.wait(..., return_whenFIRST_COMPLETED)在queue.get()与取消轮询 Future 之间竞争bedrock.py#L99-L133主循环读到None即退出bedrock.py#L1387-L1401。同一桥接手法也用在其他同步后端上例如 storage/s3_storage.py 中put_object/get_object/delete_object全部经asyncio.to_thread包装。共享类型按目标侧既有名称查找绝不改名异常类、内容块类型、流事件类型在两侧各自集中在中央 types 模块里。当源码引用其中一个时使用目标侧已有的名称不要转换标识符。没有统一的后缀规则ProviderTokenCountError在两种语言中保持这个精确名称而ContextWindowOverflowError在 Python 侧叫ContextWindowOverflowException——因为各侧本来就各自这样拼写。逐个对照实际情况解析而不是机械地套用Error一律改名Exception的规则。这与仓库现状完全吻合TypeScript 侧中央错误模块是 strands-ts/src/errors.ts其中export class ProviderTokenCountErrorerrors.ts#L181与export class ContextWindowOverflowErrorerrors.ts#L39并存Python 侧中央错误模块是 strands-py/src/strands/types/exceptions.pyProviderTokenCountError同名保留exceptions.py#L89而上下文溢出异常拼写为ContextWindowOverflowExceptionexceptions.py#L41。即便同名的异常其语义也保持对齐ProviderTokenCountError在两侧都作为模型提供方原生 token 计数 API 失败的内部控制流使用捕获后回退到启发式估算。Python 侧 Bedrock 实现中raise ProviderTokenCountError(Bedrock count_tokens returned None for inputTokens)后由except Exception兜底并return await super().count_tokens(...)回退估算bedrock.py#L1287-L1324与 errors.ts#L175-L186 的文档注释所述机制一一对应。移植对照速查表与落地清单TypeScript 结构Python 目标结构strands-py 落地位置示例interface行为契约Protocol隐式实现agent/base.py、_context_manager/types.pyinterface数据形态dataclassfrozenTrue对应readonlyinterventions/actions.pyinterface纯构造配置显式__init__参数可选参数置于*,后—带标签对象字面量联合成员frozen dataclass field(initFalse)标签字段interventions/actions.pyDenyswitch (x.type)分发isinstance(x, ...)判断interventions/registry.pytool({...})对象字面量tool装饰函数docstring 即 schematools/decorator.py外部协议 wire keys逐字符照抄不改大小写types/tools.py仅同步客户端asyncio.to_threadasyncio.Queue 回调 None哨兵models/bedrock.py共享类型名按目标侧既有名称解析不统一改名types/exceptions.py 对照 strands-ts/src/errors.ts移植一份功能时可以按此清单逐项核对先判定每个 interface 的角色选对 Python 形态再处理联合成员与工具对象随后把 wire keys 原样保真最后检查是否命中两条 Workarounds同步客户端桥接、共享类型名称解析。除此之外参考 STYLE_GUIDE.md 与 TESTING.md 保持代码风格与测试规范与现有strands-py模块一致即可让移植结果既行为等价、又读起来像原生 Python。赞分享人工智能大模型AI AgentAgent 框架多智能体工具调用MCP 服务【免费下载链接】harness-sdkBuild 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 TypeScript SDK 依赖治理指南peerDependencies 边界规则与 package-lock 可复现构建Strands TypeScript SDK 依赖治理指南peerDependencies 边界规则与 package lock 可复现构建 导读 本文基于人工智能大模型AI AgentAgent 框架多智能体工具调用MCP 服务Strands TypeScript SDK 开发指南从编码规范到模型 Provider 的完整实践Strands TypeScript SDK 开发指南从编码规范到模型 Provider 的完整实践 本文是面向在 Strands Agents 仓库中开发人工智能大模型AI AgentAgent 框架多智能体工具调用MCP 服务Strands SDK 模型路由Model Routing设计解析从设计文档到 Python SDK 落地实现Strands SDK 模型路由Model Routing设计解析从设计文档到 Python SDK 落地实现 模型路由Model Routing是人工智能大模型AI AgentAgent 框架多智能体工具调用MCP 服务上一篇如何永久备份微信聊天记录免费开源工具WeChatMsg终极使用指南下一篇CANN/catlass INT8转FP16反量化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/29 5:19:17

【GitHub项目实战】DINet 实现音频驱动的数字人口型同步

视频对口型生成技术已成为数字人内容合成中的关键环节。DINet 项目以逐步细化的生成架构和同步感知训练策略,在口型同步度与视觉真实感之间找到良好平衡,适用于低资源环境下的高质量人脸驱动场景。 围绕 DINet 的完整训练与推理流程,本文解析其环境搭建、数据预处理、模型训…

2026/9/29 6:24:19

深入浅出 DeepSeek MoE:EP 与 FSDP 经典二次开发实战指南

文档教程人工智能大模型RLHF 【免费下载链接】Awesome-ML-SYS-Tutorial My learning notes for ML SYS. 项目地址: https://gitcode.com/gh_mirrors/aw/Awesome-ML-SYS-Tutorial 点击查看 免费下载 本指南以当前仓库 rlhf/sys-design/readme-4.md 为骨架&#xff0…

2026/9/28 3:03:23

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/28 6:05:15

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/28 6:07:41

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/29 0:04:04

AI Evals实战指南:从零搭建LLM应用评估体系与CI/CD集成

1. 为什么AI Evals值得你花时间搞明白做LLM应用的人,迟早会撞上同一堵墙:模型输出飘忽不定,今天答得好好的,明天换个问法就胡说八道。你改了一版提示词,感觉好像好了点,但到底好了多少?说不清。…

2026/9/29 0:04:04

Java采购管理系统实战:从数据库设计到事务一致性

简介:这是一套面向Java Web初学者与课程设计者的采购管理系统完整源码,采用JSP技术搭建,配合MySQL数据库,用于解决企业采购信息的管理问题,适合作为毕业设计、课程大作业或进销存类项目的参考模板。系统实现了用户登录…

2026/9/29 3:53:39

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/26 19:58:38

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/28 1:59:25

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑