AI系列:大语言模型的function calling(下)- 使用LangChain

devtools/2024/11/13 10:19:07/

目录

  • 前言
  • LangChain Tool/Function calling
    • 1. Tool/function加强功能
      • LangChain的tool装饰器
      • 其他方式: Pydantic
    • 2. 绑定tools/functions
    • 3. 调用大模型(LLM)
    • 4. function calling处理流程
  • LangChain版代码
  • 与原生LLM调用的比较
  • 参考

前言

在AI系列:大语言模型的function calling(上) 中我们实现了OpenAI原生的function calling。这篇文章将继续探讨如何使用LangChain实现大语言模型(LLM)的function calling。

LangChain Tool/Function calling

LangChain提供了对LLM function calling的支持。前提是底层大模型必须支持function calling。

1. Tool/function加强功能

LangChain的tool装饰器

LangChain在langchain_core模块中的tools子模块中提供了名为tool的装饰器,将根据函数定义和注释自动生成不同LLM function calling功能需要的schema,然后传递给LLM。后续对于LLM的调用将包括这些function/tool schema。

在Python中可以通过下面这种方式为自己定义的函数导入tool装饰器:

from langchain_core.tools import tool
@tool
def multiply(first_int: int, second_int: int) -> int:"""两个整数相乘"""return first_int * second_int@tool
def add(first_add: int, second_add: int) -> int:"""两个整数相加"""return first_add + second_addtools=[multiply, add]

其他方式: Pydantic

除了tool解释器,LangChain还支持用Pydantic来定义schema的方式。比如:

from langchain_core.pydantic_v1 import BaseModel, Field# 注释很重要,会被用来生成schema。
class Add(BaseModel):"""Add two integers together."""a: int = Field(..., description="First integer")b: int = Field(..., description="Second integer")tools=[Add]

2. 绑定tools/functions

绑定tool组成的列表后,LangChain将根据函数定义和注释自动生成底层LLM的function calling功能需要的schema,并传递给LLM。以OpenAI为例,

from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo")
llm_with_tools = llm.bind_tools(tools)

3. 调用大模型(LLM)

LangChain调用LLM的接口输入参数为Message的列表。它抽象了几个不同的Message类型。以OpenAI为例,它们分别对应OpenAI的不同role属性的对话项。比如HumanMessage, AIMessage, ToolMessage分别对应OpenAI的user, assistant和tool的角色。

from langchain_core.messages import HumanMessage, ToolMessage
prompt = "一共有3个人,每个人有15个苹果,10个鸭梨,一共有多少苹果?"messagesLC = [HumanMessage(prompt)
]

调用的方法也比较直接,直接调用invoke方法即可。注意我们已经将tools绑定在LLM中,调用时,LangChain将自动将tools的schema传递给LLM。

#通过LangChain调用LLM接口,将LLM回复加入对话上下文
response = llm_with_tools.invoke(messagesLC) 
messagesLC.append(response)

返回类型为AIMessage。

4. function calling处理流程

function calling整个处理的逻辑与上篇中的介绍完全一致,这里就不累述了。具体可以参考AI系列:大语言模型的function calling(上)

整个对话上下文如下,抽象成这样,是不是感觉比OpenAI原生的更清楚一点:

[
HumanMessage(content='一共有3个人,每个人有15个苹果,10个鸭梨,一共有多少苹果?'), 
AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_LsvajoCqf1G6ZNNS8M1gildQ', 'function': {'arguments': '{"first_int":3,"second_int":15}', 'name': 'multiply'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'logprobs': None}), 
ToolMessage(content='45', tool_call_id='call_LsvajoCqf1G6ZNNS8M1gildQ'), 
AIMessage(content='一共有45个苹果。', response_metadata={'finish_reason': 'stop', 'logprobs': None})
]

LangChain版代码

以下是LangChain版function calling的实现代码,可以对比大语言模型的function calling(上) OpenAI原生版的实现代码。

__author__ = 'liyane'import json# 初始化环境
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())#定义function/tool 1: multiply,应用tool装饰器
from langchain_core.tools import tool
@tool
def multiply(first_int: int, second_int: int) -> int:"""两个整数相乘"""return first_int * second_int#定义function/tool 2: add,应用tool装饰器
@tool
def add(first_add: int, second_add: int) -> int:"""两个整数相加"""return first_add + second_add
tools=[multiply, add]#定义大模型并绑定tools
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo")
llm_with_tools = llm.bind_tools(tools)#构建对话
from langchain_core.messages import HumanMessage, ToolMessage
prompt = "一共有3个人,每个人有15个苹果,10个鸭梨,一共有多少苹果?"messagesLC = [HumanMessage(prompt)
]#通过LangChain调用LLM接口,将LLM回复加入对话上下文
response = llm_with_tools.invoke(messagesLC) 
messagesLC.append(response)#如果LLM需要function calling,调用相应的函数,并将函数结果数据加入对话上下文,继续调用LLM。
while (response.additional_kwargs.get("tool_calls") is not None):for tool_call in response.additional_kwargs["tool_calls"]:selected_tool = {"add": add, "multiply": multiply}[tool_call["function"]["name"]]args = json.loads(tool_call["function"]["arguments"])tool_output = selected_tool(args)messagesLC.append(ToolMessage(tool_output, tool_call_id=tool_call["id"]))response = llm_with_tools.invoke(messagesLC) messagesLC.append(response)print("=====最终结果=====")
print(response.content)

与原生LLM调用的比较

对于Function calling这部分功能,使用LangChain可以节省大段的手工定义tool schema的代码,也避免了未来有变动时会产生的维护问题。

同时,LangChain屏蔽了底层LLM。当LLM改变时,无需重写代码,只需要替换LangChain对应LLM的库文件即可。

目前LangChain快速迭代过程中,代码大功能上可以用,在细节上可能存在问题,遇到具体问题时可能需要看它的代码。

参考

OpenAI / function calling
LangChain / Tool/function calling
LangChain Message Types


http://www.ppmy.cn/devtools/6468.html

相关文章

esp32s3中使用双通道通信解决TCP粘包问题

在使用esp32 idf例程中的tcp_server和tcp_client通信测试时发现, 在tcp_server端,接收到一帧数据之后必须马上回复至少一个字节,才能保证每帧数据不粘包, 如果不回复操作,300ms以内的通信时延会导致tcp严重粘包&…

Android AIDL接口

一.AlDI接口简介 AIDL(Android Interface Definition Language)是一种 IDL 语言,用于生成可以在 Android 设备上两个进程之间进行进程间通信(IPC)的代码。 通过 AIDL,可以在一个进程中获取另一个进程的数据…

XiaodiSec day028 Learn Note 小迪渗透学习笔记

XiaodiSec day028 Learn Note 小迪渗透学习笔记 记录得比较凌乱,不尽详细 day 28 还是 sql 注入 知识点 提交方式的注入 在 php, spring boot, flask 都有相关的提交方式 提交方式的注入 数据以某种方式提交到后端 数据大小和数据类型和提交方式有关 如身份…

uniapp之消除图片的空白占用空间

我们在使用uniapp开发的过程中一定会遇到一个情况就是我们加载的图片总有一点空白出现在不该出现的地方代码如下 <view style"background:#ff0000;"><image style"width:100%;"src"https://t7.baidu.com/it/u1819248061,230866778&fm19…

安卓广播发送接收流程

本文基于Andorid 11。 一、registerReceiver registerReceiver(new MyRecevier(), new IntentFilter("com.example.broadcast"));动态注册广播接收器&#xff0c;参数&#xff1a;BroadcastReceiver, IntentFilter。 <receiver android:name".MyReceiver&…

ubuntu在xshell中使用快捷方式操作命令,减少命令行的数入量

第一步 第二步 然后无脑确定 第三步 在xshell的显示方式 方式一 这样就会在每个窗格中进行显示 方式二 效果显示–> 这种窗格的显示是全局的 然后你双击这个process就会自动把命令打在命令行上&#xff0c;减少你的输入量

基于改进遗传算法的配电网故障定位(matlab代码)

1 主要内容 该程序复现文章《基于改进遗传算法的配电网故障定位》&#xff0c;将改进的遗传算法应用于配电网故障定位中, 并引入分级处理思想, 利用配电网呈辐射状的特点, 首先把整个配电网划分为主干支路和若干独立区域, 再利用该算法分别对各独立区域进行故障定位, 然后进行…

pdf做批注编辑工具 最新pdf reader pro3.3.1.0激活版

PDF Reader Pro是一款功能强大的PDF阅读和编辑工具。它提供了多种工具和功能&#xff0c;帮助用户对PDF文档进行浏览、注释、编辑、转换和签名等操作。以下是PDF Reader Pro的一些主要特色&#xff1a; 最新pdf reader pro3.3.1.0激活版下载 多种查看模式&#xff1a;PDF Reade…