深入理解 Strands Agents SDK:从 @tool 装饰器到多 Agent 协作的工程实践
引子
我之前花了不少时间折腾 AI Agent。遇到的核心难题就一个:工具调度。
用户说一句话,你怎么判断该调哪个工具?调完之后结果怎么回传给模型?多个工具之间有依赖关系怎么处理?
这些问题看似简单,写起来都是坑。
最近在用 Strands Agents SDK,发现它的设计思路很干脆——不做意图路由,把调度权完全交给模型。
这篇从源码层面分析一下它的工具系统设计,然后用实际代码走一遍:自定义工具、MCP 集成、多 Agent 协作。
架构概览
Strands Agents 的架构其实很简单:
用户输入
↓
Agent Loop(核心循环)
↓
模型推理 → 是否需要调用工具?
│ ↓ 是 ↓ 否
│ 执行工具函数 直接回复
│ ↓
│ 工具返回结果
│ ↓
└──── 继续推理(带上工具结果)
整个 Agent 就是一个循环。模型在每一步决定:是调工具,还是直接回复。
默认模型后端是 Amazon Bedrock(Claude 4 Sonnet,us-west-2 区域)。需要提前配好亚马逊云科技凭证。
GitHub 仓库:https://github.com/strands-agents/sdk-python
环境搭建
python -m venv .venv
source .venv/bin/activate
pip install strands-agents strands-agents-tools
配置凭证:
aws configure
# 或环境变量
export AWS_ACCESS_KEY_ID=你的AK
export AWS_SECRET_ACCESS_KEY=你的SK
export AWS_DEFAULT_REGION=us-west-2
去 Amazon Bedrock 控制台开通 Claude 4 Sonnet 模型权限。
踩坑记录:ap-northeast-1 区域报
AccessDeniedException。原因是 Claude 4 Sonnet 在该区域未开通。直接用 us-west-2。
@tool 装饰器的工作原理
这是 Strands Agents 的核心 API。看个例子:
from strands import Agent, tool
import urllib.request
import json
@tool
def get_weather(city: str) -> str:
"""查询指定城市的当前天气信息。
Args:
city: 城市名称,如 Beijing、Shanghai、Tokyo
"""
url = f"https://wttr.in/{city}?format=j1"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode())
current = data["current_condition"][0]
temp = current["temp_C"]
desc = current["weatherDesc"][0]["value"]
humidity = current["humidity"]
return f"{city}: {temp}°C, {desc}, 湿度 {humidity}%"
@tool 装饰器在背后做了三件事:
1. 从类型注解生成 JSON Schema
def get_weather(city: str) -> str:
SDK 会读这个签名,生成:
{
"name": "get_weather",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"]
}
}
这个 Schema 会随着 system message 一起发给模型。模型根据 Schema 决定怎么填参数。
2. 从 docstring 提取工具描述
模型需要知道这个工具能干嘛。SDK 直接用 docstring 作为工具的 description 字段。
所以 docstring 写得好不好,直接影响模型的调用准确率。
我做了个对比测试:
"""查天气"""→ 复杂提问时命中率大约 60%"""查询指定城市的当前天气信息。\n\nArgs:\n city: 城市名称"""→ 命中率 95%+
差距非常大。
3. 包装成标准工具接口
装饰后的函数会被包装成一个符合 Strands 工具规范的对象,可以直接传给 Agent(tools=[...])。
实战:三合一 Agent
把天气、计算、文档搜索三个工具组合:
from strands import Agent, tool
from strands_tools import calculator
import urllib.request, json
@tool
def get_weather(city: str) -> str:
"""查询指定城市的当前天气信息。
Args:
city: 城市名称,如 Beijing、Shanghai
"""
url = f"https://wttr.in/{city}?format=j1"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode())
current = data["current_condition"][0]
return f"{city}: {current['temp_C']}°C, {current['weatherDesc'][0]['value']}, 湿度 {current['humidity']}%"
@tool
def search_docs(keyword: str) -> str:
"""在技术文档中搜索关键词,返回匹配内容。
Args:
keyword: 要搜索的关键词
"""
docs = {
"bedrock": "Amazon Bedrock 是亚马逊云科技的全托管生成式 AI 服务,支持多种基础模型。",
"lambda": "AWS Lambda 是事件驱动的无服务器计算服务。",
"s3": "Amazon S3 是对象存储服务,支持无限存储容量。"
}
for key, value in docs.items():
if keyword.lower() in key:
return value
return f"未找到关于 '{keyword}' 的文档。"
agent = Agent(tools=[calculator, get_weather, search_docs])
agent("北京天气如何?2 的 10 次方是多少?什么是 Bedrock?")
模型会自动拆解这三个子任务,依次(或并行)调用对应工具。
MCP 集成:让 Agent 读真实文档
上面的 search_docs 用的是硬编码数据。实际项目中,可以用 MCP 接入真实的文档源。
MCP(Model Context Protocol)是一个开放协议。Strands Agents 原生支持。
from strands import Agent
from strands.tools.mcp import MCPClient
from mcp import stdio_client, StdioServerParameters
aws_docs_client = MCPClient(
lambda: stdio_client(
StdioServerParameters(
command="uvx",
args=["awslabs.aws-documentation-mcp-server@latest"]
)
)
)
with aws_docs_client:
agent = Agent(tools=aws_docs_client.list_tools_sync())
response = agent("Amazon Bedrock 用 Python SDK 怎么调?")
print(response)
前提是装了 uv(pip install uv),首次运行 MCP 服务器会自动下载依赖。
混合使用
自定义 tool 和 MCP tool 可以混在一起:
with aws_docs_client:
all_tools = [calculator, get_weather] + aws_docs_client.list_tools_sync()
agent = Agent(tools=all_tools)
agent("上海天气如何?查查 S3 的 Python 用法。再算 99 * 99。")
Agent 的 tool 列表就是一个 Python list。想加就加,模型自己挑。
多 Agent 协作:Agent-as-Tool
复杂系统需要拆分职责。Strands 的方案是把 Agent 包装成 tool。
from strands import Agent, tool
from strands_tools import calculator
@tool
def get_weather(city: str) -> str:
"""查询城市天气。"""
import urllib.request, json
url = f"https://wttr.in/{city}?format=j1"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode())
current = data["current_condition"][0]
return f"{city}: {current['temp_C']}°C, {current['weatherDesc'][0]['value']}"
# 专家 Agent
weather_agent = Agent(
system_prompt="你是天气查询助手。用 get_weather 工具回答天气问题。",
tools=[get_weather]
)
math_agent = Agent(
system_prompt="你是数学计算助手。用 calculator 工具解决数学问题。",
tools=[calculator]
)
# 包装成工具
@tool
def ask_weather_expert(question: str) -> str:
"""向天气专家提问。查询天气信息时使用。
Args:
question: 关于天气的问题
"""
return str(weather_agent(question))
@tool
def ask_math_expert(question: str) -> str:
"""向数学专家提问。需要数学计算时使用。
Args:
question: 数学问题
"""
return str(math_agent(question))
# 协调者
coordinator = Agent(
system_prompt="你是智能助手协调者。天气问题交给天气专家,数学问题交给数学专家。",
tools=[ask_weather_expert, ask_math_expert]
)
coordinator("北京今天多少度?123 × 456 等于多少?")
这个模式的工程意义:
- 职责隔离:每个 Agent 有自己的 system prompt 和 tools
- 可独立测试:子 Agent 可以单独跑
- 灵活组合:新需求来了加个子 Agent,注册给 coordinator 就行
自定义模型
from strands import Agent
from strands.models import BedrockModel
model = BedrockModel(
model_id="us.amazon.nova-pro-v1:0",
temperature=0.3,
streaming=True
)
agent = Agent(model=model, tools=[...])
Amazon Bedrock 支持的模型都能用。
踩坑记录
坑 1:工具参数类型不匹配
工具函数参数必须有类型注解。不写的话,SDK 没法生成 Schema,模型也就不知道怎么调。
# 错误:没有类型注解
@tool
def bad_tool(city):
...
# 正确
@tool
def good_tool(city: str) -> str:
...
坑 2:docstring 格式不规范
推荐用 Google 风格:
@tool
def my_tool(param: str) -> str:
"""一句话描述工具功能。
Args:
param: 参数说明
"""
坑 3:MCP 服务器首次启动慢
aws-documentation-mcp-server 首次运行要下载依赖。别以为卡死了,等两分钟就好。
坑 4:region 和模型权限
Amazon Bedrock 的模型需要在控制台手动开通。默认区域 us-west-2。用之前确认一下你的区域有没有目标模型的权限。
总结
Strands Agents SDK 的设计理念可以用一句话概括:工具是函数,调度交给模型。
从工程角度看:
@tool装饰器 = 零胶水代码的工具注册- MCP 支持 = 标准化的外部工具接入
- Agent-as-Tool = 可组合的多 Agent 架构
代码全部可运行,Python 3.10+,Amazon Bedrock 做模型后端。
参考资料:
- Strands Agents 官网:https://strandsagents.com
- SDK 仓库:https://github.com/strands-agents/sdk-python
- 工具包仓库:https://github.com/strands-agents/tools
- Amazon Bedrock 文档:https://docs.aws.amazon.com/bedrock/

浙公网安备 33010602011771号