langchain 尚硅谷day4-5 Tool工具调用部分(function calling)

我们现在拥有了大模型,但只有大模型的话我们是独木难支的。光有灵魂没有躯体也是一事无成的。大模型本质上是一种语言模型,本质上是没有交互的属性的。纯大模型:

下面这句话我觉得非常的好:LLM本身并不执行函数,它只是指示应该调用哪个函数以及如何调用。说明的意思就是大语言模型不干任何的活,他是领导,把任务分发给具体的人去执行完成后再对返回的结果做处理。

其中领导的小弟就是通过ToolCalling被召集的哈哈哈哈,下面是具体的定义:ToolCalling(也称为FunctionCalling)它允许大模型与一组API或工具进行交互,将 LLM 的智能与外部工具或 API无缝连接,从而增强大模型其功能。

下面这个泳道图其实很好的说明了整个大模型工作的流程:

我们需要知道的就是具体来说有四个角色:用户,程序,工具,大模型。

整体的流程简单来说就是:用户发出一个询问,然后程序打包好用户的问题与有的工具的内容信息给大模型,大模型进行判断这个东西要不要调用工具?如果不用直接返回程序结果,程序再返回到用户的身上。但如果需要工具的话,大模型会先去生成调用工具的文本包含各种调用信息与参数,然后传递给程序,程序再分发给对应的工具。工具执行对应的操作后将结果返回给程序,然后我们的程序再去把具体的内容返回给大模型,大模型再根据相应的内容进行下一步操作!

下面这个是一个如何调用工具的代码:

我们通过@tool实现了对add_number()方法的装饰。

python 复制代码
from langchain.tools import tool

@tool
def add_number(a: int, b: int) -> int:
    """两个整数相加"""
    return a + b

result = add_number.invoke({"a": 1, "b": 12})
print(result)

print()

print(f"{add_number.name=}\n{add_number.description=}\n{add_number.args=}")

上面的代码其实包含了很多信息:1.我们需要调用langchain.tools 2.我们实现装饰之后可以用invoke方法字典传参!

当然强中自有强中手:下面这个pro版本的更进一步地去对我们的参数进行描述与定义。

要弄清楚我们这里在干啥首先需要去理解Field到底在干啥。Field有三个作用

1.把我们传入的description参数以及对应描述的内容组织好语言

2.数据校验与约束,我们可以去设置一些规则,符合规则如何,不符合又可以巴拉巴拉。

3.BaseModel 会利用 Field 提供的信息生成一个标准化的 JSON 结构。这个结构是 LLM 理解函数接口的"通用语言"。

python 复制代码
from langchain_core.tools import tool
from loguru import logger
from pydantic import BaseModel, Field
class FieldInfo(BaseModel):
    """
    定义加法运算所需的参数信息
    """
    a: int = Field(description="第1个参数")
    b: int = Field(description="第2个参数")


# 通过args_schema定义参数信息,也可以定义name、description、return_direct参数
@tool(args_schema=FieldInfo)
def add_number(a: int, b: int) -> int:
    return a + b

res = add_number.invoke({"a": 1, "b": 2})

OK知道了Field这个方法后我们可以这样去理解:很多东西可能只是我们自己知道,但是没有传递给大模型,比如说我们这个参数有什么限制之类的,然后这个Field就可以去实现调用把我们定义的参数内容以大模型的可以读懂的格式书写。然后我们args_schema=FieldInfo这一行代码其实就是把参数代的一些文本塞进了大模型里面。

下面开始我们最后一个内容:就是天气查询助手的一个编写:

我们需要知道的是,一般来说我们每个工具都要写一个代码去包装:

然后再在有大模型的地方去调用。

下面这个首先是一个函数。有几点需要注意就是1.@tool 2.就是返回的内容

python 复制代码
@tool
def get_weather(loc):
    """
    查询即时天气函数

    :param loc: 必要参数,字符串类型,用于表示查询天气的具体城市名称。
                注意,中国的城市需要用对应城市的英文名称代替,例如如果需要查询北京市天气,
                则 loc 参数需要输入 'Beijing'/'shanghai'。
    :return: OpenWeather API 查询即时天气的结果。具体 URL 请求地址为:
             https://home.openweathermap.org/users/sign_in。
             返回结果对象类型为解析之后的 JSON 格式对象,并用字符串形式进行表示,
             其中包含了全部重要的天气信息。
    """
    # Step 1. 构建请求 URL
    url = "https://api.openweathermap.org/data/2.5/weather"

    # Step 2. 设置查询参数,包括城市名、API Key、单位和语言
    params = {
        "q": loc,
        "appid": ,  # 从环境变量中读取 API Key
        "units": "metric",  # 使用摄氏度
        "lang": "zh_cn"  # 输出语言为简体中文
    }

    # Step 3. 发送 GET 请求获取天气数据
    response = httpx.get(url, params=params, timeout=30)

    # Step 4. 解析响应内容为 JSON 并序列化为字符串返回
    data = response.json()
    #print(json.dumps(data))
    return json.dumps(data)

然后这里主要就是要知道这里到底转变了什么内容:

为什么不直接传回data?而是要去传回json.dumps(data)?因为其实本质上data还是一个字典。我们想要给大模型输入的不是一个字典,而应该是字符串。大模型读不懂字典。所以这里需要进行一步内容的转换。还有就是一些乱码的问题。这里的中文换成了计算机能读懂的非乱码格式的内容。

OK,我们现在知道了这个模型其实就是发送请求得出参数返回 一个json字符串。

然后我们去构建我们的主函数工具。

这里的绑定工具还是比较有意思的。流水线是这样的,

首先我们需要完成天气调用的流水线的构建!首先我们需要的是一个参数解析的大模型,就是能把我们的问题变成参数输入的形式的一个大模型。这个模型需要绑定我们的那个函数,不然他都不知道有啥参数哈哈哈哈,这就是llm_with_tools = llm.bind_tools([get_weather])这行代码的作用了。然后我们需要去解析出大模型生成的参数。所以我们需要利用Json解析器,去解析成可以输入到函数中的方法:parser = JsonOutputKeyToolsParser(key_name=get_weather.name, first_tool_only=True) ok,现在是第三步就是直接调用函数了,因为我们@tool所以函数也可以LCEL也可以用管道符去链接执行。

第二步就是创建一个老生常用的普通LLM去实现对话返回的功能。还是要注意的那点就是两个链在串在一起的时候我们需要去实现:(lambda x: {"weather_json": x}) 去传参到Prompt里面。

python 复制代码
import os
from langchain_core.output_parsers import JsonOutputKeyToolsParser, StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from loguru import logger
from QueryWeatherTool import get_weather

# 初始化大语言模型实例
llm = ChatOpenAI(
    model="qwen-plus",
    api_key=,
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 将模型与工具绑定,使其能够调用 get_weather 工具
llm_with_tools = llm.bind_tools([get_weather])

# 创建解析器,用于提取工具调用结果中的 JSON 数据
parser = JsonOutputKeyToolsParser(key_name=get_weather.name, first_tool_only=True)

# 构建工具调用链:模型 -> 解析器 -> 调用天气工具
get_weather_chain = llm_with_tools | parser | get_weather
# print(get_weather_chain.invoke("你好, 请问北京的天气怎么样?"))
# 定义输出提示模板,将 JSON 天气数据转换为自然语言描述
output_prompt = PromptTemplate.from_template(
    """你将收到一段 JSON 格式的天气数据{weather_json},请用简洁自然的方式将其转述给用户。
    以下是天气 JSON 数据:
    请将其转换为中文天气描述,例如:
    "北京现在天气:多云,气温 28℃,体感有点闷热(约 32℃),湿度 75%,微风(东南风 2 米/秒),
    能见度很好,大约 10 公里。建议穿短袖短裤。适合做户外运动。"
    """
)

# 创建字符串输出解析器
output_parser = StrOutputParser()

# 构建最终输出链:提示模板 -> 模型 -> 输出解析器
output_chain = output_prompt | llm | output_parser

# 构建完整的处理链:天气查询链 ->将天气数据包装为字典格式 -> 输出链
full_chain = get_weather_chain | (lambda x: {"weather_json": x}) | output_chain

# 执行完整链路,查询上海天气并打印结果
result = full_chain.invoke("请问北京今天的天气如何?")
logger.info(result)

OK,这就是工具调用的整体流程了,虽然阳哥说简单但是还是需要一些学习才能比较清楚!

免费打广告,尚硅谷周阳讲的langchain很不错啊!

相关推荐
小陈的进阶之路3 小时前
LangChain/LangGraph对比
langchain
Flittly3 小时前
【LangGraph新手村系列】(3)PostgreSQL 持久化检查点:让状态跨越进程与重启
人工智能·python·langchain
JAVA面经实录9173 小时前
企业级java+LangChain4j-RAG系统 限流熔断降级
java·开发语言·分布式·langchain
hjxu20164 小时前
【LangGraph入门 3】精细控制之图的运行时配置和map-reduce
langchain·langgraph
hrhcode6 小时前
【LangGraph】二.State 和 Node 的设计细节
python·ai·langchain·langgraph·ai框架
Trouvaille ~6 小时前
零基础入门 LangChain 与 LangGraph(八):真正让 Agent“活起来”——持久化、记忆、人机交互与时间旅行
langchain·人机交互·agent·python3.11·持久化机制·langgraph·ai应用开发
abigale037 小时前
LangChain:自定义模型・RAG 检索・Agent 原理笔记
langchain·llm·prompt·agent·rag·lcel
tangweiguo030519878 小时前
AI图生图完整实战:基于阿里云百炼通义万相
人工智能·langchain