Langchain 工具Tool使用
发布时间:2026/10/20 11:09:25 锦皓数字建站

1. Tools 概述工具 Tool 是赋予大语言模型与外部世界交互能力的关键组件从而能让智能体执行搜索、计算、数据库查询、邮件发送或调用第三方API等进而构建功能强大的AI应用1.1 工具调用方式在 LangChain 中工具Tools实际上是指明确定义了输入和输出的可调用函数因此 工具调用 (Tool Calling) 也被称为函数调用(Function Calling)方式1直接调用适合测试时使用from langchain_core.tools import tool tool def get_current_weather(city: str) - str: 获取指定城市的天气信息 paras: city: 城市 returns:str, 天气信息 return city 晴天, 温度15度, 风力3级 get_current_weather.invoke({city: 上海})方式2绑定到模型调用开发中让AI来调用主流方式from langchain.chat_models import init_chat_model from dotenv import load_dotenv import os from rich import print as rprint from langchain_core.tools import tool tool def get_current_weather(city: str) - str: 获取指定城市的天气信息 paras: city: 城市 returns: str: 天气信息 return city 晴天, 温度15度, 风力3级 # 1.加载配置信息 load_dotenv(overrideTrue) # 加载.env文件中的环境变量 api_key os.getenv(BAILIAN_API_KEY) # 获取BAILIAN_API_KEY环境变量 base_url os.getenv(BAILIAN_API_BASE) # 获取BAILIAN_API_BASE环境 # 2.初始化模型 llm init_chat_model( model_provideropenai, # 模型提供商 modeldeepseek-v4.1-flash, # 模型名称 api_keyapi_key, # API Key base_urlbase_url, # API Base URL ) # 3.将工具绑定在模型上 llm_tools llm.bind_tools([get_current_weather]) # 4.调用模型 response llm_tools.invoke(今天北京的天气如何) # 5.检查AI是否调用了工具 if response.tool_calls: rprint(AI调用了工具:,response.tool_calls) else: rprint(AI没有调用工具:,response.tool_calls)结果如下1.2 工具调用流程大模型能根据对话上下文决定何时调用工具以及传递哪些参数流程如下目前我们编写的 LangChain 应用对应上图中的AI助手或应用1.3 从 Message 流转看工具的调用前提准备from langchain.chat_models import init_chat_model from dotenv import load_dotenv import os from rich import print as rprint # 1.加载配置信息 load_dotenv(overrideTrue) # 加载.env文件中的环境变量 api_key os.getenv(BAILIAN_API_KEY) # 获取BAILIAN_API_KEY环境变量 base_url os.getenv(BAILIAN_API_BASE) # 获取BAILIAN_API_BASE环境 # 2.初始化模型 llm init_chat_model( model_provideropenai, # 模型提供商 modeldeepseek-v4.1-flash, # 模型名称 api_keyapi_key, # API Key base_urlbase_url, # API Base URL )不使用tool修饰def get_current_weather(city: str) - str: 获取指定城市的天气信息 paras: city: 城市 returns: str: 天气信息 return city 晴天, 温度15度, 风力3级 # 1.将工具绑定到大模型中 llm_tools llm.bind_tools([get_current_weather]) # 2.第一次调用大模型 messages [ HumanMessage(content今天北京天气如何) ] # 3.大模型返回第一次结果 response llm_tools.invoke(messages) messages.append(response) # 4.根据大模型返回结果的tool_calls, 调用工具 for tool_call in response.tool_calls: if tool_call[name] get_current_weather: # 拼接出ToolMessage实例 tool_message ToolMessage( content get_current_weather(**tool_call[args]), tool_call_id tool_call[id], nametool_call[name] ) messages.append(tool_message) # 5.第二次调用大模型 response_finnal llm_tools.invoke(messages) rprint(response_finnal.content)参考2使用 tool 修饰tool def get_current_weather(city: str) - str: 获取指定城市的天气信息 paras: city: 城市 returns: str: 天气信息 return city 晴天, 温度15度, 风力3级 # 1.将工具绑定到大模型中 llm_tools llm.bind_tools([get_current_weather]) # 2.第一次调用大模型 messages [ HumanMessage(content今天北京天气如何) ] # 3.大模型返回第一次结果 response llm_tools.invoke(messages) messages.append(response) # 4.根据大模型返回结果的tool_calls, 调用工具 for tool_call in response.tool_calls: if tool_call[name] get_current_weather: # 调用工具, 返回 ToolMessage tool_message get_current_weather.invoke(tool_call) messages.append(tool_message) # 5.第三次调用大模型 response_finnal llm_tools.invoke(messages) rprint(response_finnal.content)说明被 tool 修饰的函数可以调用 工具名.invoke 接收接收返回 ToolMessage 实例我们不再需要手动拼接 ToolMessage工具调用流程总结所以如果真正要大模型根据工具调用结果进行回复完整的调用流程包括如下四个步骤模型绑定工具通过 model.bind_tools[ ]绑定一个或者多个工具模型生成工具调用请求用户输入问题调用模型比如 invoke如果需要调用工具模型返回包含工具调用信息如工具名称和参数的 AIMessage开发者手动执行工具用户从响应中提取工具调用信息并手动调用对应的工具比如工具.invoke将工具执行结果 ToolMessage 传递给模型生成最终结果将之前用户提问内容和手动执行工具结果 ToolMessage 返回模型模型最终生成回复注意大模型调用工具是单次推理直接响应需要开发者手动执行工具并管理循环适合简 单、确定的任务2. 工具 Tool 的定义方式不使用tool2.1 工具描述的各部分详解2.1.1 convert_to_openai_tool执行model.bind_tools[ ]底层最终会调用convert_to_openai_tool生成工具描述结果字段说明type定义当前数据节点必须是什么数据类型。常见类型有 string, number, integer, boolean, object, array, null。object 即是 json 对象properties用于定义 JSON 对象Object中可以包含哪些属性键以及每个属性对应的值类型和说明required当 type 为 object 时使用是一个数组列出了对象中必须存在的属性名2.1.2 description说明convert_to_openai_tool 会从 docstring(文档字符串) 加载工具的描述信息上面的案例中 docstring 为空所以抽取的 description 为空docstring文档字符串使用三个双引号表示开始和结束实质是函数的说明信息案例from langchain_core.utils.function_calling import convert_to_openai_function from rich import print as rprint def get_current_weather(city: str) - str: 获取当前天气 Args: city (str): _description_ Returns: str: _description_ return f{city}天气晴朗 rprint(convert_to_openai_function(get_current_weather))2.1.3 参数说明convert_to_openai_tool 会从 docstring 加载参数说明这里的 docstring 必须遵循Google 风格Google 风格 docstring 说明Google Style Guides | Style guides for Google-originated open-source projectsGoogle 风格 docstring 示例Example Google Style Python Docstrings — Sphinx documentation注意LangChain 的 tool 装饰器会自动解析 Google 风格 docstring提取函数描述、参数说明自动生成对应的 JSON Schema传给大模型做工具调用2.1.4 参数类型说明参数类型来源于函数的类型注解删除了参数类型注解则工具描述中不包含参数类型说明注意如果 docstring 中包含参数说明则对应的参数必须有类型注解否则报错案例2.1.5 参数默认值说明如果参数没有默认值则会包含 在 required 对应的列表 中。 反之则参数的描述信息会包含 default 字段并且 不会出现在 required 列表中3. 工具的定义方式2使用tool装饰器(推荐)使用 tool 装饰器修饰可以自动将普通 Python 函数转化为智能体可调用的工具此方式最直接 代码量极少3.1 自定义工具描述description情况1仅提供docstring信息在bind_tools( )调用时先将函数封装为 BaseTool 类型的对象再传递给 convert_to_openai_tool 函数生成工具的描述注意tool 会从 docstring 生成描述信息同样要求遵循 Google docstring 规范如果没有 docstring 则报错情况2添加工具描述descriptiontool 的参数 description 可以更改工具描述优先级高于 docstring 的函数说明情况3解析docstringparse_docstring当我们没有向 tool 传递 description 参数时默认情况下 tool 会将 docstring 整体视为 description 如下输出如下因此我们可以通过将 parse_docstring 设置为Truedocstring 会被解析填充到相应的字段描述中输出如下注意不使用 tool 装饰器时docstring 不合法会被视为普通文本作为 description 但如果使用了 tool 时 docstring 不合法将会抛出异常3.2 更改工具名称name_or_callable默认情况使用函数名作为工具名称但可以向 tool 传参 name_or_callable 以更改工具名称案例注意tool中参数 name_or_callable 名称可以省略不要使用 config 或 runtime 作为参数名这些是 LangChain 内部保留的3.3 自定义 args_schema3.3.1 方式1使用 Pydantic 模型定义当工具的参数变得复杂需要枚举值 、 范围限制或更复杂的业务逻辑验证时Pydantic 模型是理想的选择提供强大的类型检查和数据验证1.pydantic 类型的定义① BaseModel基类通过继承核心基类 BaseModel 定义数据模型从而声明字段结构、类型约束、默认值以0及校验规则注意BaseModel 子类初始化时不接收位置参数字段值必须以关键字参数的形式传入否则报错② FieldField( )用来“ 定制字段 ”的函数可用于设置默认值、描述等案例设置参数的默认值和描述信息③ LiteralLiteral[ ]表示字段不能是任意某种类型的值而只能是几个固定字面量之一输出如下2. 使用 Pydantic 定义 args_schema通过tool(args_schemaPydanticModelCls)将 Pydantic 模型与工具函数关联利用 Pydantic 的类型系统进行参数验证当大模型需要调用工具前Pydantic 会自动验证参数的类型 和有效性案例from pydantic import BaseModel, Field from langchain.tools import tool from langchain_core.utils.function_calling import convert_to_openai_tool class WeatherInput(BaseModel): city: str Field( default 北京, description城市 ) unit: Literal[celsius, fahrenheit] Field( defaultcelsius, description气温单位 ) include_forecast: bool Field( defaultFalse, description是否包含未来五日天气预报 ) tool(args_schemaWeatherInput) def get_weather(city: str, unit: str celsius, include_forecast: bool False) - str: 获取当日天气可选未来五日天气预报 temp 22 if unit celsius else 72 result f{city}当天气温: {temp} {摄氏度 if unit celsius else 华氏度} if include_forecast: result \n未来五天都是晴天 return result convert_to_openai_tool(get_weather)输出如下3.3.2 方式2使用 Json Schema 定义在 LangChain 中还可以直接使用JSON Schema 字典来定义工具的参数模式这种方式提供了极大的灵活性。 因为工具参数模式可以基于数据库配置或用户输入在运行时动态生成 所以这种方式特别适合参数结构需要动态生成的场景注意应该传递给 args_schema 的只有parameters 对应的JSON字符串案例from pydantic import BaseModel, Field from langchain.tools import tool from langchain_core.utils.function_calling import convert_to_openai_tool json_scheme { properties: { city: {default: 北京,description: 城市,type: string}, unit: {default: celsius,description: 气温单位,enum: [celsius, fahrenheit],type: string}, include_forecast: {default: False,description: 是否包含未来五日天气预报,type: boolean} }, type: object } tool(args_schemajson_scheme) def get_weather(city: str, unit: str celsius, include_forecast: bool False) - str: 获取当日天气可选未来五日天气预报 temp 22 if unit celsius else 72 result f{city}当天气温: {temp} {摄氏度 if unit celsius else 华氏度} if include_forecast: result \n未来五天都是晴天 return result convert_to_openai_tool(get_weather)输出如下4.拓展强制使用工具——tool_choice 参数bind_tools 可以传递参数 tool_choice用于控制是否强制使用工具。 该字段最终会作为 payload 的 tool_choice 字段传递给模型tool_choice 的参数如下none模型不会调用任何工具auto 默认值模型可以自主决定不调用或调用任意数量的工具required模型必须调用工具数量不限注意tool_choice 还支持传递 any 等价于 required当参数为 required 时通过 { typefunction, function{namemy_function}} 来指定特定的 tool会强制模型调用该 tool案例1模型初始化from langchain.chat_models import init_chat_model from dotenv import load_dotenv import os from rich import print as rprint from langchain_core.tools import tool from langchain_core.messages import SystemMessage, HumanMessage, AIMessage # 1.加载配置信息 load_dotenv(overrideTrue) # 加载.env文件中的环境变量 api_key os.getenv(BAILIAN_API_KEY) # 获取BAILIAN_API_KEY环境变量 base_url os.getenv(BAILIAN_API_BASE) # 获取BAILIAN_API_BASE环境 # 2.初始化模型 llm init_chat_model( model_provideropenai, # 模型提供商 modeldeepseek-v4.1-flash, # 模型名称 api_keyapi_key, # API Key base_urlbase_url, # API Base URL )2、调用工具tool def get_current_weather(city: str) - str: 获取指定城市的天气信息。 Args: city : 城市名称 Returns: str : 天气信息 return city 晴天, 温度15度, 风力3级 # 1.将工具绑定到大模型中 llm_tools llm.bind_tools([get_current_weather], tool_choiceauto) # 2.第一次调用大模型 messages [ HumanMessage(content今天北京天气如何) ] # 3.大模型返回第一次结果 response llm_tools.invoke(messages) messages.append(response) # 4.根据大模型返回结果的tool_calls, 调用工具 for tool_call in response.tool_calls: if tool_call[name] get_current_weather: # 调用工具, 返回 ToolMessage tool_message get_current_weather.invoke(tool_call) messages.append(tool_message) # 5.第二次调用大模型 response_finnal llm_tools.invoke(messages) rprint(response_finnal.content)注意某些场景下我们希望强制调用特定的工具仍然可以用 tool_choice 解决这时只需指明特定工具名称即可llm_tools llm.bind_tools([get_current_weather], tool_choiceget_current_weather)5. 实践经验总结1. 清晰的描述2.功能单一3.工具失败处理三层防护第1层工具内部处理tool def divide(a: float, b: float) - str: 除法计算 Args: a: 被除数 b: 除数 try: if b 0: return 错误除数不能为零 result a / b return f{a} / {b} {result} except Exception as e: return f计算错误{e}第2层Agent 级重试使用 promptagent create_agent( modelmodel, tools[...], prompt如果工具失败尝试使用其他方法解决问题。 )第3层调用级重试在大模型应用如 LangChain中网络请求和外部工具调用是最容易掉链子的地方 retry 就是一个容错保险from tenacity import retry, stop_after_attempt # 1. 配置重试规则如果失败最多尝试 3 次即第 1 次正常调用 2 次重试 retry(stopstop_after_attempt(3)) def call_agent(question): # 2. 核心业务逻辑调用 LangChain 的 Agent return agent.invoke({messages: [{role: user, content:question}]})它的工作流程① 调用 call_agent你好② 程序进入函数执行 agent.invoke...③ 如果执行成功正常返回结果retry 什么都不做④ 如果执行失败报错retry 会拦截这个错误不让程序直接崩溃。它会默默地帮你再次触发 agent.invoke...⑤ 如果连续 3 次都报错它终于放弃了把第 3 次的报错真正抛出来程序此时才会报错中止4. 返回字符串5. 选择同步 vs 异步同步工具 简单场景CPU 密集型任务异步工具 IO 密集型API 调用、数据库、文件操作
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。