工具调用在后面学习智能体的时候会重点讲到,现在只做了解即可
大模型工具调用(Tool Calling)可以扩展模型能力,使模型突破纯文本生成的限制,与外部系统和功能进行交互。
在 LangChain 框架中,这一功能也被称为函数调用(Function Calling),两种术语可以互换使用。
📖 术语说明
| 术语 | 含义 |
|---|---|
| Tool Calling | 工具调用 |
| Function Calling | 函数调用 |
两者在 LangChain 中通常表示同一类能力。
2.4.1 模型调用工具步骤 🔧
🌦️ 1. 定义查询天气工具
下面定义一个查询天气工具,工具名称为get_weather。具体工具创建方式可参考 Agent 章节部分。
@tooldefget_weather(location:str)->str:"""获取指定位置的天气"""returnf"{location}的天气是晴朗的。"🔗 2. 将工具绑定到模型
大模型使用工具前,需要通过bind_tools()方法将工具与模型绑定,让模型能够识别可用工具。
绑定后,模型会根据输入内容自动判断是否需要调用工具。
frominit_llmimportdeepseek_llm model_with_tools=deepseek_llm.bind_tools([get_weather])# 查询触发工具调用response=model_with_tools.invoke("北京今天天气如何?")print(type(response))response.pretty_print()运行后,response对象是一个AIMessage。
如果大模型判断需要调用工具,该对象输出内容中只会包含调用工具的参数请求信息,并不会主动调用工具。
示例输出:
================================== Ai Message ================================== 我来帮您查询北京的天气情况。 Tool Calls: get_weather (call_00_KSFvPw6CQnMrR97Cp6y65k5v) Call ID: call_00_KSFvPw6CQnMrR97Cp6y65k5v Args: location: 北京🧭 3. 完整调用流程
如果真正要让大模型根据工具调用结果进行回复,完整调用流程包括以下四个步骤:
- 模型绑定工具:通过
model.bind_tools([...])绑定一个或多个工具。 - 模型生成工具调用请求:用户输入问题,如果触发工具调用,模型返回工具调用信息,如工具名称和参数。
- 开发者手动执行工具:从响应中提取工具调用信息,并手动调用对应工具。
- 将工具执行结果传递给模型生成最终结果:把用户提问内容和工具执行结果返回模型,模型最终生成回复。
完整实现代码如下:
fromlangchain.toolsimporttoolfromlangchain_core.messagesimportHumanMessagefrominit_llmimportdeepseek_llm@tooldefget_weather(location:str)->str:"""获取指定位置的天气"""returnf"{location}的天气是晴朗的。"# 1. 模型绑定工具model_with_tools=deepseek_llm.bind_tools([get_weather])messages=[]human_message=HumanMessage(content="北京的天气")# human_message = HumanMessage(content="海水为什么是咸的?")messages.append(human_message)# 2. 模型生成调用工具请求response=model_with_tools.invoke(messages)print("response",response)messages.append(response)# 3. 开发者根据模型的响应,调用工具并获取结果fortool_callinresponse.tool_calls:iftool_call["name"]=="get_weather":# 调用工具并获取结果tool_result=get_weather.invoke(tool_call)messages.append(tool_result)# 4. 模型根据工具调用结果生成最终响应final_response=model_with_tools.invoke(messages)print("final_response",final_response)print(final_response.content)代码运行后,可能输出:
根据查询结果,北京目前的天气是晴朗的。⚠️特别注意
大模型调用工具是单次推理,直接响应。需要开发者手动执行工具并管理循环,适合简单、确定的任务。
2.4.2 模型多工具调用 🧩
大模型调用工具是单次推理。
当调用多个工具时,需要用户自己管理多次调用循环。
📈📰 案例:模型调用多个工具进行回复
fromlangchain_core.toolsimporttoolfromlangchain_core.messagesimportHumanMessagefrominit_llmimportdeepseek_llm# 定义股票查询工具@tooldefget_stock_price(company:str,timeframe:str="today")->str:"""获取指定公司的股票价格信息 Args: company: 公司名称(如:苹果公司, 微软公司, 谷歌公司) timeframe: 时间范围(today-今日, week-本周, month-本月) """# 模拟股票数据mock_data={"苹果公司":{"today":185.20,"week":183.50,"month":180.75},"微软公司":{"today":415.86,"week":412.30,"month":405.42},"谷歌公司":{"today":15.42,"week":15.20,"month":14.85}}ifcompanyinmock_data:price=mock_data[company].get(timeframe,"未知时间范围")returnf"{company}{timeframe}价格:{price}美元"else:returnf"未找到股票代码{company}的数据"# 定义新闻搜索工具@tooldefsearch_news(company:str)->str:"""搜索指定公司的财经新闻 Args: company: 公司名称 Return: 公司的财经新闻,每个新闻占一行 """# 模拟新闻数据mock_news={"苹果公司":["苹果发布新款iPhone,股价上涨3%","苹果与欧盟达成反垄断和解协议","苹果将在印度扩大生产规模"],"微软公司":["微软Azure云业务季度增长超预期","微软完成对Nuance的收购","微软推出新一代AI助手Copilot"],"谷歌公司":["谷歌发布新AI模型,性能提升20%","谷歌与OpenAI合作,开发新的AI助手","谷歌在欧洲展开AI研究项目"]}news_list=mock_news.get(company,[f"未找到{company}的相关新闻"])return"\n".join(news_list)# 1. 初始化模型并绑定工具tools=[get_stock_price,search_news]model_with_tools=deepseek_llm.bind_tools(tools)messages=[]# human_message = HumanMessage(content="苹果公司今天的股价是多少?最近有什么新闻?")# human_message = HumanMessage(content="比较一下微软和苹果的股价")human_message=HumanMessage(content="腾讯最近有什么重大新闻?")# human_message = HumanMessage(content="海水为什么是咸的?")messages.append(human_message)# 2. 工具调用循环whileTrue:response=model_with_tools.invoke(messages)messages.append(response)# 如果有调用工具,处理工具调用响应# 3. 开发者根据模型的响应,调用工具并获取结果ifresponse.tool_calls:fortool_callinresponse.tool_calls:iftool_call["name"]=="get_stock_price":stock_result=get_stock_price.invoke(tool_call)print("stock_result",stock_result)messages.append(stock_result)eliftool_call["name"]=="search_news":news_result=search_news.invoke(tool_call)print("news_result",news_result)messages.append(news_result)else:print("没有工具调用,直接返回答案")breakprint("response",response)print(response.content)🔄 多工具调用逻辑说明
以上示例中有两个工具:
get_stock_price:获取公司股票价格search_news:获取公司新闻
当用户提问:
苹果公司今天的股价是多少?最近有什么新闻?显然需要调用两个工具。此时:
- 第一次
model_with_tools.invoke(message)调用,可能触发get_stock_price工具。AIMessage对象中的tool_calls会包含工具调用信息。 - 第二次
model_with_tools.invoke(message)调用,可能触发search_news工具。AIMessage对象中的tool_calls同样会包含工具调用信息。 - 当模型不再调用工具时,返回的
AIMessage对象中的tool_calls为空。 - 因此可以使用一个
while循环来自行管理工具多次调用循环。 - 最终将所有消息交给大模型后,得到最终结果。
✅ 小结
| 步骤 | 作用 | 关键代码 |
|---|---|---|
| 1 | 绑定工具 | model.bind_tools([...]) |
| 2 | 生成工具调用请求 | model_with_tools.invoke(messages) |
| 3 | 开发者执行工具 | tool.invoke(tool_call) |
| 4 | 生成最终回复 | model_with_tools.invoke(messages) |
📌核心记忆点
大模型只负责“决定调用哪个工具、传什么参数”,真正执行工具的是开发者。
多工具调用时,需要开发者使用循环管理完整的工具调用过程。