SDK 与自定义 Block
第2周收官。开发者如何用 SDK 写一个新 Block、用 ProviderBuilder 声明第三方集成、AutoRegistry 自动注册。看"声明式"如何让扩展变简单。
👶 小白:我写完一个新 Block,要去哪个文件里手动"注册"它,平台才认识?
👨🏫 老师:哪都不用去改。只要你的类继承了 Block 并放进 blocks 目录,AutoRegistry 会在启动时自动扫描、发现、登记它——就像报名表交上去,花名册自动多了你一行。这就是"声明式"的威力:你只声明"我是一个什么样的块",繁琐的注册接线由框架代劳。回味 Day 02 的"自动发现注册",正是同一招。
SDK 一站式入口
写 Block 的开发者用 backend/sdk/。sdk/__init__.py 是统一入口,一行 import 就能拿到一切:
from backend.sdk import *
# 导出:Block、BlockSchemaInput/Output、SchemaField、
# 各种 Credentials、ProviderBuilder、cost、AutoRegistry ...
from backend.sdk import * 齐活。SDK 目录只有 4 个文件:builder.py、provider.py、registry.py、cost_integration.py——精简。data/model.py、blocks/_base.py 等多处。如果每个 Block 作者都要记住"SchemaField 在哪、Credentials 在哪",很烦。SDK 把这些集中成一个"给 Block 作者的工具箱"——降低写块的门槛,让社区更容易贡献。好的 SDK = 降低扩展门槛。写一个块的最小骨架
StoreValueBlock(blocks/basic.py:70)是入门模板,套路(Day 07 总结过):
from backend.sdk import Block, BlockSchemaInput, BlockSchemaOutput, SchemaField, BlockCategory
class MyBlock(Block):
class Input(BlockSchemaInput):
text: str = SchemaField(description="...")
class Output(BlockSchemaOutput):
result: str = SchemaField(description="...")
def __init__(self):
super().__init__(id="<新 UUID>", description=..., categories={BlockCategory.BASIC},
input_schema=MyBlock.Input, output_schema=MyBlock.Output,
test_input={"text": "hi"}, test_output=[("result", "HI")])
async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "result", input_data.text.upper()
ProviderBuilder:声明第三方集成
.build() 后交给 AutoRegistry——它自动把这段声明注入平台各子系统。你声明"是什么",平台负责"怎么接"。这就是声明式扩展。对接外部服务(含 API key / OAuth / 计费),用 ProviderBuilder 流式 API(sdk/builder.py:27)。真实例子(blocks/exa/_config.py):
exa = (
ProviderBuilder("exa")
.with_description("Neural web search")
.with_api_key("EXA_API_KEY", "Exa API Key") # 声明需要 API key
.with_webhook_manager(ExaWebhookManager)
.with_base_cost(100, BlockCostType.COST_USD) # 声明基础成本
.build()
)
.with_oauth(...)(自动推导 {NAME}_CLIENT_ID/SECRET 环境变量)。.with_xxx().with_yyy().build() 读起来就像在描述"这个服务有这些特性"。和 crewAI Flow 的装饰器、eino 的 Chain builder 一样——流式/声明式 API 让配置意图一目了然。一次配置,多块共享
配好 provider 后,该服务的每个 Block 用 exa.credentials_field(...) 声明凭证字段(blocks/exa/search.py:49),run 签名带 credentials(search.py:135):
class Input(BlockSchemaInput):
credentials = exa.credentials_field(...) # 复用 provider 配置
async def run(self, input_data, *, credentials: APIKeyCredentials, **kwargs):
api_key = credentials.api_key.get_secret_value() # 拿到真 key
exa/_config.py 里 ProviderBuilder("exa")…build() 只写一次(配好凭证类型、环境变量 EXA_API_KEY、基础成本)。然后
exa/search.py、exa/contents.py、exa/find_similar.py…共 ~45 个块,每个只写一行 credentials = exa.credentials_field(...) 就复用了这份配置。改 Exa 的成本?只动 _config.py 一处,45 个块同时生效。_config.py 注释说明:"一个 provider 配置一次,~45 个兄弟 block 共享"。Exa 有 45 个 Block(搜索、抓取、相似查找…),它们共享同一份 provider 配置(凭证、成本规则)——不用每个块重复声明。这就是 ProviderBuilder 的价值:DRY(不重复自己)——服务级配置写一次,块级复用。AutoRegistry:自动注册中枢
AutoRegistry(sdk/registry.py:49)是中央注册表(线程安全),保存所有 SDK 注册的 provider、默认凭证、OAuth handler、webhook manager、成本配置、API key 映射。
patch_integrations()(registry.py:166)用猴子补丁(monkey patch)把 SDK 注册的东西注入到平台既有的集成点。意思是:你用 ProviderBuilder 声明了一个新服务,AutoRegistry 会"悄悄地"把它接进平台的凭证系统、成本系统、OAuth 系统——作者只需"声明",平台自动"感知",不用改平台核心代码。这让"加一个新的第三方集成"变成纯声明式的、零侵入的操作。约定优于配置 + 自动注册——扩展性拉满。声明式的威力(回味)
整个 Block/SDK 系统贯穿一个理念:声明,而非命令。你只需声明:"这个块有这些输入输出""这个服务需要这种凭证""这个块这样计费"——平台自动把它接入发现、注册、凭证、成本、UI 各个系统。
前端画布怎么映射到后端
回扣 Day 03:前端可视化画布和后端 Graph 模型一一对应——画布上一个方块 = 一个 Node(绑 block_id);连线 = 一条 Link;整个画布 = 一个 Graph。
jsonschema()(Day 02)自动渲染出"这个块长什么样:有哪些输入框、哪些输出引脚"。用户拖它到画布 = 创建一个 Node,连线 = 创建 Link。从你写的 Python 类,到用户能在画布上拖拽的可视化积木——这条链完全自动。你只写后端块定义,前端 UI 白送。🎓 第 2 周收官 + 动手
第 2 周(Day 06-10)你已吃透 Block 系统
- Day 06 Block 基类:ABC+泛型、_execute 生命周期、类型分类
- Day 07 真实 Block:纯计算/IO/状态/AI 四种范例
- Day 08 凭证:引用vs实体、discriminator、加锁刷新
- Day 09 成本:六种类型、静态/动态、cost_filter
- Day 10 SDK:ProviderBuilder、AutoRegistry、声明式扩展
你已理解"积木怎么定义、怎么被集成"。下周(Day 11-15)进入 执行引擎——图模型、manager、数据流、定时、WebSocket。
✋ 动手
P=autogpt_platform/backend/backend
sed -n '120,171p' $P/sdk/__init__.py # SDK 导出
sed -n '27,90p' $P/sdk/builder.py | head -40 # ProviderBuilder
sed -n '49,180p' $P/sdk/registry.py | head -50 # AutoRegistry
cat $P/blocks/exa/_config.py # provider 实战