☰
LangChain 工具调用(Tool Calling)实战指南
2026/10/25 16:01:16 网站建设 项目流程

1. 引言

在构建大语言模型(LLM)应用时,模型本身无法执行实时查询、调用外部 API 或操作数据库。工具调用(Tool Calling / Function Calling)正是为了解决这一痛点而生的机制:它让模型在对话过程中识别出需要外部能力才能回答的问题,并结构化地输出一个“调用请求”,由我们的应用代码去真正执行对应的函数,再把结果回传给模型,从而生成最终答案。

本文将基于 LangChain 0.3 系列,从零开始讲解工具调用的核心概念、定义方式、绑定与执行流程,并通过可运行的代码示例带你快速上手。

2. 什么是工具调用

工具调用是 LLM 的一种能力:模型在生成回复时,可以输出一个结构化的“工具调用指令”,而不是直接给出最终文本。这个指令通常包含:

  • 工具名称(tool name)
  • 传给该工具的参数(arguments,JSON 格式)

应用侧拿到这个指令后,负责真正执行对应的函数,并把执行结果作为新的消息返回给模型,模型再基于结果继续推理,最终给出面向用户的回答。

需要特别注意的是:模型本身并不执行工具,它只负责“决定调用哪个工具、传什么参数”。真正的执行逻辑始终由我们的代码完成。

3. 环境准备

在开始之前,请确保你的环境中已安装 LangChain 及对应模型的依赖包:

pipinstalllangchain langchain-openai

如果你使用 OpenAI 兼容接口(如国内大模型服务),通常还需要配置 API Key 和 Base URL:

importos os.environ["OPENAI_API_KEY"]="your-api-key"os.environ["OPENAI_BASE_URL"]="https://your-endpoint/v1"

4. 定义一个工具

在 LangChain 中,最推荐的方式是使用@tool装饰器,把一个普通的 Python 函数声明为可供模型调用的工具。

fromlangchain_core.toolsimporttool@tooldefget_weather(city:str)->str:"""查询指定城市的当前天气。 参数: city: 城市名称,例如 "北京"、"上海"。 返回: 该城市的天气描述字符串。 """# 这里仅作演示,实际可替换为真实天气 API 调用returnf"{city}今天晴,气温 26℃,微风。"

要点说明:

  • 函数的**文档字符串(docstring)**会被 LangChain 自动提取,作为模型判断“何时调用该工具”的依据,务必写清楚用途和参数含义。
  • 函数的类型注解(如city: str)会被转换为工具的参数 schema,模型据此生成合法的参数 JSON。
  • 函数返回值会被作为工具执行结果回传给模型。

docstring 的写法与作用

docstring(文档字符串)是写在函数定义第一行的三引号字符串,它不仅是给开发者看的注释,更是 LangChain 生成工具描述的核心依据。模型正是通过 docstring 来理解“这个工具是做什么的、什么时候该调用它”。

一个规范的 docstring 通常包含三部分:

  • 功能描述:一句话说明工具的作用,例如“查询指定城市的当前天气”。
  • 参数说明:逐个列出参数的含义、类型和取值范围,帮助模型生成合法的参数 JSON。
  • 返回值说明:说明函数返回什么内容,让模型知道拿到结果后该如何使用。
@tooldefget_weather(city:str)->str:"""查询指定城市的当前天气。 参数: city: 城市名称,例如 "北京"、"上海"。 返回: 该城市的天气描述字符串。 """returnf"{city}今天晴,气温 26℃,微风。"

docstring 的书写质量直接影响模型调用工具的准确率:

  • 描述越具体,模型判断越准。如果只写“查询天气”,模型可能不清楚该传什么参数;写清楚“城市名称,例如北京、上海”后,模型就能正确生成{"city": "北京"}这样的参数。
  • 参数说明要与类型注解一致。docstring 里说明的参数名必须和函数签名中的参数名完全一致,否则 LangChain 生成的 schema 会与 docstring 描述不一致,可能导致模型传错参数。
  • 避免歧义和冗余。docstring 应简洁明确,不要写与工具功能无关的内容,以免干扰模型的判断。

5. 绑定工具到模型

定义好工具后,需要把它“绑定”到聊天模型上,模型才会在推理时知道有这个工具可用。

fromlangchain_openaiimportChatOpenAI llm=ChatOpenAI(model="gpt-4o-mini",temperature=0)# 将工具绑定到模型llm_with_tools=llm.bind_tools([get_weather])

bind_tools接收一个工具列表,可以一次绑定多个工具。绑定后,模型在需要时就会输出工具调用指令。

6. 执行工具调用

下面是一个完整的调用流程示例:用户提问 → 模型决定调用工具 → 我们执行工具 → 把结果回传给模型 → 模型给出最终回答。

fromlangchain_core.messagesimportHumanMessage,ToolMessage# 第一步:用户提问messages=[HumanMessage(content="北京今天天气怎么样?")]# 第二步:模型决定调用工具response=llm_with_tools.invoke(messages)print("模型输出:",response)# 第三步:检查是否有工具调用请求ifresponse.tool_calls:tool_call=response.tool_calls[0]print(f"需要调用工具:{tool_call['name']}")print(f"参数:{tool_call['args']}")# 第四步:真正执行工具函数tool_result=get_weather.invoke(tool_call["args"])# 第五步:把工具执行结果作为 ToolMessage 追加到消息列表messages.append(response)messages.append(ToolMessage(content=tool_result,tool_call_id=tool_call["id"]))# 第六步:让模型基于工具结果生成最终回答final_response=llm_with_tools.invoke(messages)print("最终回答:",final_response.content)

执行流程可以概括为下图:

否

是

用户提问

模型推理

是否需要调用工具?

直接返回回答

模型输出工具调用指令

应用代码执行工具函数

将结果回传给模型

调用流程:

7. 多工具与参数校验

实际项目中往往需要同时提供多个工具。LangChain 支持一次绑定多个工具,模型会根据问题自动选择合适的那个。

@tooldefget_time(city:str)->str:"""查询指定城市的当前时间。 参数: city: 城市名称。 返回: 该城市的当前时间字符串。 """returnf"{city}当前时间为 14:30"llm_with_tools=llm.bind_tools([get_weather,get_time])

此外,LangChain 会自动根据函数的类型注解和 docstring 生成 JSON Schema,并在调用时对模型生成的参数做校验。如果参数不合法,会抛出异常,便于我们及时发现并处理。

下面是一个更完整的示例:定义两个工具(查询天气、查询时间),绑定到模型,并演示模型如何根据问题自动选择工具、以及参数校验失败时的处理。

fromlangchain_core.toolsimporttoolfromlangchain_core.messagesimportHumanMessage,ToolMessage@tooldefget_weather(city:str)->str:"""查询指定城市的当前天气。 参数: city: 城市名称,例如 "北京"、"上海"。 返回: 该城市的天气描述字符串。 """returnf"{city}今天晴,气温 26℃,微风。"@tooldefget_time(city:str)->str:"""查询指定城市的当前时间。 参数: city: 城市名称。 返回: 该城市的当前时间字符串。 """returnf"{city}当前时间为 14:30"# 一次绑定多个工具llm_with_tools=llm.bind_tools([get_weather,get_time])# 模型会根据问题自动选择合适的工具messages=[HumanMessage(content="北京现在几点了?")]response=llm_with_tools.invoke(messages)ifresponse.tool_calls:tool_call=response.tool_calls[0]print(f"模型选择了工具:{tool_call['name']}")print(f"参数:{tool_call['args']}")# 根据工具名动态执行对应的函数tool_map={"get_weather":get_weather,"get_time":get_time}selected_tool=tool_map[tool_call["name"]]tool_result=selected_tool.invoke(tool_call["args"])messages.append(response)messages.append(ToolMessage(content=tool_result,tool_call_id=tool_call["id"]))final_response=llm_with_tools.invoke(messages)print("最终回答:",final_response.content)

关于参数校验,LangChain 会根据函数的类型注解自动生成 JSON Schema。例如get_weather(city: str)会生成一个要求city为字符串的 schema。如果模型生成的参数不符合要求(例如缺少必填字段、类型错误),调用时会抛出异常:

# 模拟参数校验失败:缺少必填参数 citytry:get_weather.invoke({})exceptExceptionase:print("参数校验失败:",e)

通过这种方式,我们可以在开发阶段尽早发现模型生成的参数问题,从而及时修正 docstring 或类型注解,提升工具调用的稳定性。

8. 总结

本文介绍了 LangChain 工具调用的完整流程:

  • 使用@tool装饰器定义工具,docstring 和类型注解是模型理解工具的关键。
  • 通过bind_tools把工具绑定到模型。
  • 模型输出tool_calls后,由应用代码真正执行工具,并通过ToolMessage回传结果。
  • 支持一次绑定多个工具,模型会自动选择。

工具调用是构建 Agent、RAG 查询增强、自动化工作流等高级应用的基础能力。掌握它之后,你就可以让大模型“动手做事”,而不仅仅是“动嘴说话”了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询