工具
工具让智能体能够执行操作:例如获取数据、运行代码、调用外部 API,甚至进行计算机操作。在 Agents SDK 中有三类工具:
- 托管工具:这些工具运行在与 AI 模型相同的 LLM 服务上。OpenAI 提供检索、网络检索和计算机操作等托管工具。
- 工具调用:这些允许你将任意 Python 函数用作工具。
- 将智能体用作工具:这允许你将一个智能体当作工具使用,使智能体在不进行任务转移的情况下调用其他智能体。
托管工具
使用OpenAIResponsesModel 时,OpenAI 提供一些内置工具:
WebSearchTool让智能体进行网络检索。FileSearchTool允许从你的 OpenAI 向量存储中检索信息。ComputerTool允许自动化计算机操作任务。CodeInterpreterTool让 LLM 在沙盒环境中执行代码。HostedMCPTool将远程 MCP 服务的工具暴露给模型。ImageGenerationTool从提示词生成图像。LocalShellTool在你的机器上运行 shell 命令。
fromagentsimportAgent,FileSearchTool,Runner,WebSearchToolagent=Agent(name="Assistant",tools=[WebSearchTool(),FileSearchTool(max_num_results=3,vector_store_ids=["VECTOR_STORE_ID"],),],)asyncdefmain():result=awaitRunner.run(agent,"Which coffee shop should I go to, taking into account my preferences and the weather today in SF?")print(result.final_output)工具调用
你可以将任意 Python 函数作为工具使用。Agents SDK 会自动为你设置该工具:
- 工具名称将是该 Python 函数的名称(或者你也可以提供一个名称)
- 工具描述将取自函数的 docstring(或者你也可以提供描述)
- 函数输入的模式会根据函数参数自动创建
- 每个输入的描述将取自函数的 docstring,除非你禁用该行为
我们使用 Python 的inspect 模块提取函数签名,使用griffe 解析 docstring,并使用pydantic 创建模式。
importjsonfromtyping_extensionsimportTypedDict,AnyfromagentsimportAgent,FunctionTool,RunContextWrapper,function_toolclassLocation(TypedDict):lat:floatlong:float@function_tool# (1)!asyncdeffetch_weather(location:Location)->str:# (2)!"""Fetch the weather for a given location. Args: location: The location to fetch the weather for. """# In real life, we'd fetch the weather from a weather APIreturn"sunny"@function_tool(name_override="fetch_data")# (3)!defread_file(ctx:RunContextWrapper[Any],path:str,directory:str|None=None)->str:"""Read the contents of a file. Args: path: The path to the file to read. directory: The directory to read the file from. """# In real life, we'd read the file from the file systemreturn"<file contents>"agent=Agent(name="Assistant",tools=[fetch_weather,read_file],# (4)!)fortoolinagent.tools:ifisinstance(tool,FunctionTool):print(tool.name)print(tool.description)print(json.dumps(tool.params_json_schema,indent=2))print()- 你可以在函数参数中使用任意 Python 类型,函数可以是同步或异步的。
- 如果存在 docstring,将用于提取描述和参数说明。
- 函数可以选择性地接收
context(必须是第一个参数)。你也可以设置覆盖项,例如工具名称、描述、docstring 风格等。 - 你可以将装饰后的函数传入工具列表。
展开以查看输出
```fetch_weatherFetch the weather for a given location.{"$defs": { "Location": { "properties": { "lat": { "title": "Lat", "type": "number" }, "long": { "title": "Long", "type": "number" } }, "required": [ "lat", "long" ], "title": "Location", "type": "object" }},"properties": { "location": { "$ref": "#/$defs/Location", "description": "The location to fetch the weather for." }},"required": [ "location"],"title": "fetch_weather_args","type": "object"}
fetch_dataRead the contents of a file.{"properties": { "path": { "description": "The path to the file to read.", "title": "Path", "type": "string" }, "directory": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "The directory to read the file from.", "title": "Directory" }},"required": [ "path"],"title": "fetch_data_args","type": "object"}```
从工具调用返回图像或文件
除了返回文本输出,你还可以将一个或多个图像或文件作为函数工具的输出。为此,你可以返回以下任意类型:
- 图像:
ToolOutputImage(或其 TypedDict 版本ToolOutputImageDict) - 文件:
ToolOutputFileContent(或其 TypedDict 版本ToolOutputFileContentDict) - 文本:字符串或可转为字符串的对象,或
ToolOutputText(或其 TypedDict 版本ToolOutputTextDict)
自定义函数工具
有时,你可能不想使用 Python 函数作为工具。如果你愿意,可以直接创建一个FunctionTool。你需要提供:
namedescriptionparams_json_schema,即参数的 JSON 模式on_invoke_tool,这是一个异步函数,接收ToolContext和作为 JSON 字符串的参数,并且必须以字符串形式返回工具输出。
fromtypingimportAnyfrompydanticimportBaseModelfromagentsimportRunContextWrapper,FunctionTooldefdo_some_work(data:str)->str:return"done"classFunctionArgs(BaseModel):username:strage:intasyncdefrun_function(ctx:RunContextWrapper[Any],args:str)->str:parsed=FunctionArgs.model_validate_json(args)returndo_some_work(data=f"{parsed.username} is{parsed.age} years old")tool=FunctionTool(name="process_user",description="Processes extracted user data",params_json_schema=FunctionArgs.model_json_schema(),on_invoke_tool=run_function,)自动参数与 docstring 解析
如前所述,我们会自动解析函数签名以提取工具的模式,并解析 docstring 以提取工具和各个参数的描述。注意事项:
- 使用
inspect模块进行签名解析。我们使用类型注解来理解参数类型,并动态构建一个 Pydantic 模型来表示整体模式。支持大多数类型,包括 Python 基本类型、Pydantic 模型、TypedDict 等。 - 我们使用
griffe解析 docstring。支持的 docstring 格式包括google、sphinx和numpy。我们会尝试自动检测 docstring 格式,但这只是尽力而为;你也可以在调用function_tool时显式设置。你还可以通过将use_docstring_info设为False来禁用 docstring 解析。
用于模式提取的代码位于agents.function_schema。
将智能体用作工具
在某些工作流中,你可能希望由一个中心智能体编排一组专用智能体,而不是进行任务转移。你可以通过将智能体建模为工具来实现。
fromagentsimportAgent,Runnerimportasynciospanish_agent=Agent(name="Spanish agent",instructions="You translate the user's message to Spanish",)french_agent=Agent(name="French agent",instructions="You translate the user's message to French",)orchestrator_agent=Agent(name="orchestrator_agent",instructions=("You are a translation agent. You use the tools given to you to translate.""If asked for multiple translations, you call the relevant tools."),tools=[spanish_agent.as_tool(tool_name="translate_to_spanish",tool_description="Translate the user's message to Spanish",),french_agent.as_tool(tool_name="translate_to_french",tool_description="Translate the user's message to French",),],)asyncdefmain():result=awaitRunner.run(orchestrator_agent,input="Say 'Hello, how are you?' in Spanish.")print(result.final_output)自定义工具化智能体
agent.as_tool 函数是一个便捷方法,可轻松将智能体转换为工具。但它不支持所有配置;例如,你无法设置max_turns。对于高级用例,请在你的工具实现中直接使用Runner.run:
@function_toolasyncdefrun_my_agent()->str:"""A tool that runs the agent with custom configs"""agent=Agent(name="My agent",instructions="...")result=awaitRunner.run(agent,input="...",max_turns=5,run_config=...)returnstr(result.final_output)自定义输出提取
在某些情况下,你可能希望在将工具化智能体的输出返回给中心智能体之前对其进行修改。这在以下情况有用:
- 从子智能体的对话历史中提取特定信息(例如 JSON 负载)。
- 转换或重新格式化智能体的最终答案(例如将 Markdown 转为纯文本或 CSV)。
- 当智能体的响应缺失或格式错误时,验证输出或提供回退值。
你可以通过向as_tool 方法提供custom_output_extractor 参数来实现:
asyncdefextract_json_payload(run_result:RunResult)->str:# Scan the agent’s outputs in reverse order until we find a JSON-like message from a tool call.foriteminreversed(run_result.new_items):ifisinstance(item,ToolCallOutputItem)anditem.output.strip().startswith("{"):returnitem.output.strip()# Fallback to an empty JSON object if nothing was foundreturn"{}"json_tool=data_agent.as_tool(tool_name="get_data_json",tool_description="Run the data agent and return only its JSON payload",custom_output_extractor=extract_json_payload,)条件启用工具
你可以在运行时使用is_enabled 参数有条件地启用或禁用智能体工具。这允许你根据上下文、用户偏好或运行时条件动态筛选对 LLM 可用的工具。
importasynciofromagentsimportAgent,AgentBase,Runner,RunContextWrapperfrompydanticimportBaseModelclassLanguageContext(BaseModel):language_preference:str="french_spanish"deffrench_enabled(ctx:RunContextWrapper[LanguageContext],agent:AgentBase)->bool:"""Enable French for French+Spanish preference."""returnctx.context.language_preference=="french_spanish"# Create specialized agentsspanish_agent=Agent(name="spanish_agent",instructions="You respond in Spanish. Always reply to the user's question in Spanish.",)french_agent=Agent(name="french_agent",instructions="You respond in French. Always reply to the user's question in French.",)# Create orchestrator with conditional toolsorchestrator=Agent(name="orchestrator",instructions=("You are a multilingual assistant. You use the tools given to you to respond to users. ""You must call ALL available tools to provide responses in different languages. ""You never respond in languages yourself, you always use the provided tools."),tools=[spanish_agent.as_tool(tool_name="respond_spanish",tool_description="Respond to the user's question in Spanish",is_enabled=True,# Always enabled),french_agent.as_tool(tool_name="respond_french",tool_description="Respond to the user's question in French",is_enabled=french_enabled,),],)asyncdefmain():context=RunContextWrapper(LanguageContext(language_preference="french_spanish"))result=awaitRunner.run(orchestrator,"How are you?",context=context.context)print(result.final_output)asyncio.run(main())is_enabled 参数接受:
- 布尔值:
True(始终启用)或False(始终禁用) - 可调用函数:接收
(context, agent)并返回布尔值的函数 - 异步函数:用于复杂条件逻辑的异步函数
被禁用的工具在运行时对 LLM 完全隐藏,适用于:
- 基于用户权限的功能开关
- 特定环境的工具可用性(开发环境 vs 生产环境)
- 不同工具配置的 A/B 测试
- 基于运行时状态的动态工具筛选
在工具调用中处理错误
当你通过@function_tool 创建函数工具时,可以传入一个failure_error_function。这是一个在工具调用崩溃时向 LLM 提供错误响应的函数。
- 默认情况下(即你不传入任何值),会运行
default_tool_error_function,告知 LLM 发生了错误。 - 如果你传入自己的错误函数,则会运行该函数,并将其响应发送给 LLM。
- 如果你显式传入
None,则任何工具调用错误都会被重新抛出供你处理。若模型生成了无效 JSON,这可能是ModelBehaviorError;若你的代码崩溃,则可能是UserError,等等。
fromagentsimportfunction_tool,RunContextWrapperfromtypingimportAnydefmy_custom_error_function(context:RunContextWrapper[Any],error:Exception)->str:"""A custom function to provide a user-friendly error message."""print(f"A tool call failed with the following error:{error}")return"An internal server error occurred. Please try again later."@function_tool(failure_error_function=my_custom_error_function)defget_user_profile(user_id:str)->str:"""Fetches a user profile from a mock API. This function demonstrates a 'flaky' or failing API call. """ifuser_id=="user_123":return"User profile for user_123 successfully retrieved."else:raiseValueError(f"Could not retrieve profile for user_id:{user_id}. API returned an error.")如果你是手动创建FunctionTool 对象,则必须在on_invoke_tool 函数内部处理错误。