4.3 LangChain 中的 Tool 修饰器#

在上一节内容中,我们详细介绍了如何基于 Function Calling 来完成用户的提问,不过相信大家都发现了一个共同的问题,那就是太繁琐了,整个过程要我们介入和实现的内容太多。进一步,如果是多轮问答,那整个过程将会更为繁杂。那有没有什么好的方法呢?在本节内容中,我们将会介绍如何基于 LangChain 来快速完成整个流程的构建。

根据第4.1节内容可知,整体过程的繁琐主要体现在两个方面:工具的定义以及与大模型的多次交互。首先,来看如何快速实现工具的定义。

4.3.1 工具自动化生成#

在 LangChain 框架中,我们可以通过一行简单的代码来实现工具的定义,示例代码如下:

1 @tool
2 def get_weather(location: str) -> str:
3     """获取指定城市的天气情况, 可以通过该工具返回天气结果。
4     Args:
5         location: 城市名称,例如:北京、上海
6     """
7     weather_conditions = ["晴天", "多云", "雨天"]
8     random_weather = random.choice(weather_conditions)
9     return f"{location}今天是{random_weather}。"

在上述代码中,我们只需要使用 @tool 修饰器,就可以将一个函数转换为工具使用,并同样可以将其放到一个列表中作为工具集合供大模型使用,如 tools = [get_weather, get_current_date]。所以 @tool 修饰器的本质就是把 Python 函数变成 LLM 可以调用的能力模块。对于更为个性化以及不使用 @tool 修饰器来封装工具的方法将在第5.6节中进行介绍。

4.3.2 输出 Schema 及测试#

通过 @tool 修饰器,定义好一个工具以后,我们可以通过如下方式来输出整个 Schema 信息,示例代码如下:

 1 if __name__ == '__main__':
 2     tool_schema = {
 3         "type": "function",
 4         "function": {
 5             "name": get_weather.name,
 6             "description": get_weather.description,
 7             "parameters": get_weather.args_schema.model_json_schema()
 8         }
 9     }
10     print(json.dumps(tool_schema, ensure_ascii=False, indent=2))

上述代码运行结束以后将会得到如下结果:

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "获取指定城市的天气情况, 可以通过该工具返回天气结果。\n Args:\n  location: 城市名称,如:北京、上海",
    "parameters": {
      "description": "获取指定城市的天气情况, 可以通过该工具返回天气结果。\nArgs:\n location: 城市名称,如:北京、上海",
      "properties": {
        "location": {
          "title": "Location",
          "type": "string"
        }
      },
      "required": [
        "location"
      ],
      "title": "get_weather",
      "type": "object"
    }
  }
}

从上述结果可以看出,这里的 Schema 信息和上一节我们手动拼接的稍微有些差异,但是这并不重要。因为这些 Schema 信息也是作为普通输入喂给大模型的,我们只需要将 descriptionparameters 信息写准确,大模型便可以理解。

同时,还可以通过如下方式在测试工具的输出内容:

1 if __name__ == '__main__':
2     result = get_weather.invoke({'location':'北京'})
3     print(result) # 北京今天是雨天。

以上完整示例代码可参见 Code/Chapter04/C03_tool_usage.py 文件。

4.3.3 编排自动化#

使用 LangChain 进行大模型开发的最大优势就是它集成了整个大模型调用的编排流程,不需要每一次调用大模型都通过我们自己来编码实现。在定义好工具以后,对于上一节内容中的示例,通过如下示例代码即可完成:

 1 def main():
 2     model = ChatOpenAI(api_key=os.getenv('DASHSCOPE_API_KEY'),
 3                        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
 4                        model="qwen-plus")
 5     tools = [get_weather, get_current_date]
 6     prompt = (
 7         "你是一个助手,可以查询天气和日期信息。"
 8         "当用户询问天气时,必须调用 get_weather 工具。"
 9         "当用户询问日期时,必须调用 get_current_date 工具。"
10         "最终回答必须基于工具返回的结果进行回答,不要自己编造,请以友好的语气回答问题。")
11     agent = create_agent(model, tools, system_prompt=prompt)
12     queries = ["今天是什么日期?上海的天气如何?"]
13     for query in queries:
14         events = []  
15         for event in agent.stream(
16                 {"messages": [{"role": "user", "content": query}]},
17                 stream_mode="values"):
18             events.append(event)
19         for value in events[-1]["messages"]:
20             value.pretty_print()

在上述代码中,第2~4行是借用 ChatOpenAI 的 SDK 来调用千问大模型,这里需要注意的是一定要使用支持工具的大模型,否则在整个过程中大模型并不会使用工具。对于千问系列大模型来说,可以参见 [1]。第5行是定义工具集合。第6~10行是定义系统提示词。第 11 行是创建整个调用及交互过程所要用到的智能体。第15行则是开始完成与大模型的多轮交互过程。第19~20行输出整个过程的详细结果。

上述代码运行结束以后将会得到类似如下结果:

 1 ================================ Human Message =================================
 2 今天是什么日期上海的天气如何
 3 ================================== Ai Message ==================================
 4 Tool Calls:
 5   get_current_date (call_54857756adb046c1b64bbe)
 6  Call ID: call_54857756adb046c1b64bbe
 7   Args:
 8   get_weather (call_db00241c4e2146ba89ca8f)
 9  Call ID: call_db00241c4e2146ba89ca8f
10   Args:
11     location: 上海
12 ================================= Tool Message =================================
13 Name: get_current_date
14 随便写一个测试时间2025年3月5日
15 ================================= Tool Message =================================
16 Name: get_weather
17 上海今天是多云
18 ================================== Ai Message ==================================
19 今天是2025年3月5日上海的天气是多云希望您有愉快的一天

根据上述结果,我们可以清晰地看到大模型或工具每一步的输出结果。

到此,我们就把 LangChain 中@tool 修饰器和基于 Function Calling 智能体的使用方法介绍清楚了,以上完整示例代码可参见 Code/Chapter04/C04_tool_function_calling.py 文件。

引用#

[1] https://help.aliyun.com/zh/model-studio/qwen-function-calling#7891b265ac24u