我们思考一个问题:大语言模型是否能帮我们做更多的事情,比如帮我们发送邮件。默认情况下让大模型帮我们发送邮件,大模型会这样回复我们:

可以看到,大模型无法发送邮件,它只会帮我们生成一个邮件模板,然后让我们自己手动发送出去。如何让大模型拥有发送邮件的能力呢?这里就引入来了一个概念:function calling

一、概念:Function calling

简单来说,Function calling让大语言模型拥有了调用外部接口的能力,使用这种能力,大模型能做一些比如实时获取天气信息、发送邮件等和现实世界交互的事情。

1、原理

在发送信息给大模型的时候,携带着“工具”列表,这些工具列表代表着大模型能使用的工具。当大模型遇到用户提出的问题时,会先思考是否应该调用工具解决问题,如果需要调用工具,和普通消息不同,这种情况下会返回“function_call”类型的消息,请求方根据返回结果调用对应的工具得到工具输出,然后将之前的信息加上工具输出的信息一起发送给大模型,让大模型整合起来综合判断给出结果。

以获取天气信息为例,官网给出了获取天气的流程图

2、案例

OpenAI官网Function calling文档:https://platform.openai.com/docs/guides/function-calling?api-mode=responses&example=get-weather

文档中给了获取天气、发送邮件、搜索本地知识库这三个例子,以获取天气为例:

from openai import OpenAI

client = OpenAI()

tools = [{
"type": "function",
"name": "get_weather",
"description": "Get current temperature for a given location.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and country e.g. Bogotá, Colombia"
}
},
"required": [
"location"
],
"additionalProperties": False
}
}] response = client.responses.create(
model="gpt-4o",
input=[{"role": "user", "content": "What is the weather like in Paris today?"}],
tools=tools
) print(response.output)

结果输出:

[{
"type": "function_call",
"id": "fc_12345xyz",
"call_id": "call_12345xyz",
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}]

可以看到,使用OpenAI的官方API调用很繁琐,而且定义工具列表需要使用json格式的字符串,非常的不友好,lagnchain则解决了这些麻烦。

二、langchain中的Tool calling

langchain中的Function calling换了个更直接的名字:Tool calling,翻译过来叫做“工具调用”,实际上底层还是使用的Function calling。

Tools概念:https://python.langchain.com/docs/concepts/tools/

Tool calling概念:https://python.langchain.com/docs/concepts/tool_calling/

1、工具定义

定义工具很简单,使用装饰器@tool,比如定义两数相乘的工具如下:

from langchain_core.tools import tool

@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b

可以看到,定义一个工具方法很简单,普通方法加上装饰器@tool即可(关于复杂方法后续再讲)。

工具定义完成,可以使用

print(
json.dumps(
multiply.args_schema.model_json_schema(),
indent=4,
ensure_ascii=False,
)
)

打印scheme信息:

{
"description": "Multiply two numbers.",
"properties": {
"a": {
"title": "A",
"type": "integer"
},
"b": {
"title": "B",
"type": "integer"
}
},
"required": [
"a",
"b"
],
"title": "multiply",
"type": "object"
}

2、工具调用

上面我们已经定义好了两数相乘的工具:

from langchain_core.tools import tool

@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b

接下来使用携带该工具访问大模型:

# Tool 创建
tools = [multiply]
# Tool 绑定
model_with_tools = model.bind_tools(tools)
# Tool 调用
response = model_with_tools.invoke("2乘以2等于多少?")

输出大模型返回的function_tool信息:

print(json.dumps(response.tool_calls, indent=4))

结果如下所示:

[
{
"name": "multiply",
"args": {
"a": 2,
"b": 3
},
"id": "chatcmpl-tool-83c83e9537ae4820bc3b1123fec3570b",
"type": "tool_call"
}
]

它告诉我们要调用multiply方法,参数是a=2和b=3,如何调用呢?

3、工具执行

大模型已经告诉我们要执行的方法以及调用的参数了,接下来如何执行呢?

第一步:转换tool列表为字典

tool_dic = {tool.name: tool for tool in tools}

第二步:依次执行tool_call列表中的方法

for tool_call in response.tool_calls:
selected_tool = tool_dic[tool_call["name"].lower()]
tool_msg = selected_tool.invoke(tool_call)
print(type(tool_msg))

这样就可以执行目标方法了。注意这里返回的tool_msg信息类型是ToolMessage。

接下来需要将上下文信息带着最后输出的工具输出的信息一起打包给大模型,让大模型整合结果输出给出最终答案。

4、整合到大模型

调用完工具之后需要将结果告诉大模型,让大模型综合上下文得到后续答案。如何告诉大模型呢?在上一篇文章《大模型开发之langchain0.3(二):构建带有记忆功能的聊天机器人》中告诉大模型上下文,也即是历史记录的方法就是构造Message列表,上一步工具执行的结果返回类型是ToolMessage,我们将它加入列表即可;最后将message列表一起发送给大模型,让大模型给出答案。

完整代码如下所示:

from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool @tool
def multiply(a: int, b: int) -> int:
"""Multiply a and b."""
print("multiply 方法被执行")
return a * b model = init_chat_model("gpt-3.5-turbo")
# Tool 创建
tools = [multiply]
# Tool 绑定
model_with_tools = model.bind_tools(tools)
# Tool 调用
history = [HumanMessage("2乘以3等于多少?")]
ai_message = model_with_tools.invoke(history)
history.append(ai_message)
tool_dic = {tool.name: tool for tool in tools}
for tool_call in ai_message.tool_calls:
selected_tool = tool_dic[tool_call["name"].lower()]
tool_msg = selected_tool.invoke(tool_call)
history.append(tool_msg) ai_message = model_with_tools.invoke(history)
print(ai_message.content)
if __name__ == '__main__':
pass

结果:

multiply 方法被执行
2乘以3等于6。

三、整合gradio

为了更直观的查看工具调用的情况,将本节内容整合到gradio是个不错的选择,同时需要兼容上篇文章《大模型开发之langchain0.3(二):构建带有记忆功能的聊天机器人》中记忆功能、Context Window限制功能,由于使用了工具调用,暂时没想好如何实现工具调用显示和正文部分流式输出的组合。

1、代码整合

核心点在于如何显示方法调,可以参考文档:https://www.gradio.app/docs/gradio/chatbot#demos 案例中的chatbot_with_tools 章节。

from gradio import ChatMessage
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, AIMessage, trim_messages
from langchain_core.tools import tool
import gradio as gr @tool
def multiply(a: int, b: int) -> int:
"""Multiply a and b."""
print("multiply 方法被执行")
return a * b model = init_chat_model("gpt-3.5-turbo")
# Tool 创建
tools = [multiply]
# Tool 绑定
model_with_tools = model.bind_tools(tools) trimmer = trim_messages(
max_tokens=300,
strategy="last",
token_counter=model,
include_system=True,
allow_partial=False,
start_on="human",
) def response(input_message, gradio_history):
# Tool 调用
history = [HumanMessage(i["content"]) if i["role"] == 'user' else AIMessage(i["content"]) for i in gradio_history]
history.append(HumanMessage(input_message))
local_gradio_history = list()
ai_message = model_with_tools.invoke(trimmer.invoke(history)) if ai_message.tool_calls:
tool_dic = {tool_item.name: tool_item for tool_item in tools}
for tool_call in ai_message.tool_calls:
tool_name = tool_call["name"].lower()
selected_tool = tool_dic[tool_name]
tool_msg = selected_tool.invoke(tool_call)
history.append(tool_msg)
local_gradio_history.append(
ChatMessage(
role="assistant",
content=f"tool '{tool_name}' invoke result is {tool_msg}",
metadata={"title": f"️ Used tool '{tool_name}'"},
)
)
yield local_gradio_history
ai_message = model_with_tools.invoke(trimmer.invoke(history)) local_gradio_history.append(
ChatMessage(
role="assistant",
content=ai_message.content,
)
)
yield local_gradio_history demo = gr.ChatInterface(
fn=response,
type="messages",
flagging_mode="manual",
flagging_options=["Like", "Spam", "Inappropriate", "Other"],
save_history=True,
) if __name__ == '__main__':
demo.launch()

2、运行界面

可以看到,大模型会根据用户请求的问题决定是否要调用相关的工具;新增加的方法调用正常发挥作用,同时以前的上下文记忆功能也没有受到影响。

四、注意事项

注意,并非所有的大模型都支持function_call,不支持function_call的大模型输出返回的AIMessage的tool_calls字段一直是空的。

最后,欢迎关注我的博客呀~

https://blog.kdyzm.cn

langchain0.3教程:聊天机器人进阶之方法调用的更多相关文章

  1. 笔记5:QQ群聊天机器人

    之前经常在别人群里看到有自动回复消息的机器人. 功能有好多,可以玩各种游戏.觉得还蛮有意思的.. 于是就去请教别人怎么弄得,但是他们都说得好复杂,好高大上,无非就是不想让别人弄 本人是个不会轻易放弃的 ...

  2. Rasa Stack:创建支持上下文的人工智能助理和聊天机器人教程

    相关概念 Rasa Stack 是一组开放源码机器学习工具,供开发人员创建支持上下文的人工智能助理和聊天机器人: • Core = 聊天机器人框架包含基于机器学习的对话管理 • NLU = 用于自然语 ...

  3. Python进阶开发之网络编程,socket实现在线聊天机器人

    系列文章 √第一章 元类编程,已完成 ; √第二章 网络编程,已完成 ; 本文目录 什么是socket?创建socket客户端创建socket服务端socket工作流程图解socket公共函数汇总实战 ...

  4. 【python】使用python十分钟创建个人聊天机器人教程

    以青云客和图灵机器人接口示范python创建个人聊天机器人教程 一.以青云客聊天机器人为例示范get请求 官方网址:http://api.qingyunke.com/ 1.接入指引 请求地址 http ...

  5. 使用Botkit和Rasa NLU构建智能聊天机器人

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 我们每天都会听到关于有能力涉及旅游.社交.法律​​.支持.销售等领域的新型机器人推出的新闻.根据我最后一次查阅的数据,单单Facebook Me ...

  6. 聊天机器人(chatbot)终极指南:自然语言处理(NLP)和深度机器学习(Deep Machine Learning)

    在过去的几个月中,我一直在收集自然语言处理(NLP)以及如何将NLP和深度学习(Deep Learning)应用到聊天机器人(Chatbots)方面的最好的资料. 时不时地我会发现一个出色的资源,因此 ...

  7. 用python玩微信(聊天机器人,好友信息统计)

    1.用 Python 实现微信好友性别及位置信息统计 这里使用的python3+wxpy库+Anaconda(Spyder)开发.如果你想对wxpy有更深的了解请查看:wxpy: 用 Python 玩 ...

  8. ChatterBot聊天机器人呢结构(五):ChatterBot对话流程

    原文地址:http://www.bugingcode.com/blog/ChatterBot_Dialogue_process.html 创建机器人 部署机器人的各种属性,根据前面的章节里聊天机器人的 ...

  9. 【翻译】用AIML实现的Python人工智能聊天机器人

    前言 用python的AIML包很容易就能写一个人工智能聊天机器人. AIML是Artificial Intelligence Markup Language的简写, 但它只是一个简单的XML. 下面 ...

  10. 3.C#面向对象基础聊天机器人

    基于控制台的简单版的聊天机器人,词库可以自己添加. 聊天机器人1.0版本 源码如下: using System; using System.Collections.Generic; using Sys ...

随机推荐

  1. ClickHouse-3引擎

    引擎 数据库引擎 index 表引擎 数据库引擎 数据库引擎允许您处理数据表. 默认情况下,ClickHouse使用Atomic数据库引擎.它提供了可配置的table engines和SQL dial ...

  2. MVCC基本原理

    在介绍MVCC概念之前,我们先来想一下数据库系统里的一个问题:假设有多个用户同时读写数据库里的一行记录,那么怎么保证数据的一致性呢?一个基本的解决方法是对这一行记录加上一把锁,将不同用户对同一行记录的 ...

  3. law Intermediate walkthrough pg

    靶场很简单分数只有10分跟平常做的20分的中级靶场比确实简单 我拿来放松的 算下来30分钟解决战斗 nmap 扫到80端口web界面 是个框架 搜exp https://www.exploit-db. ...

  4. linux实现人脸识别锁定解锁

    环境 archlinux 桌面管理器i3wm 登录管理器 slim python 3.10.4 dlib pip install --user -i https://pypi.tuna.tsinghu ...

  5. 搭建 VuePress 站点必做的 10 个优化

    前言 在 <一篇带你用 VuePress + Github Pages 搭建博客>中,我们使用 VuePress 搭建了一个博客,最终的效果查看:TypeScript 中文文档. 在搭建这 ...

  6. 天翼云VPC支持专线健康检查介绍

    本文分享自天翼云开发者社区<天翼云VPC支持专线健康检查介绍>,作者:汪****波 天翼云支持本地数据中心IDC(Internet Data Center)通过冗余专线连接到天翼云云上专有 ...

  7. Layer子域名挖掘机

    Layer子域名挖掘机 Layer子域名挖掘机是一款功能强大的域名查询工具,主要用于提供网站子域名的查询服务. 域名与子域名 域名 域名,又称网域,是互联网上用于标识特定计算机或计算机组的一串由点分隔 ...

  8. redis启停shell脚本

    启停脚本(redis-5.0.5) 一.编辑脚本 vim /u01/redis/redisServer.sh #!/bin/sh # # Simple Redis init.d script conc ...

  9. Project Euler 307 题解

    主要是规避误差.即求 \[\frac{k![x^k](1+x+\frac {x^2}2)^n}{n^k} \] 微分一下得到递推式.然后根据斯特林近似(byd 这里还需要 \(1\) 后的第一项..) ...

  10. Doris名词解释

    1.Tablet:Doris 表的逻辑分片,一个表有多个分片 2.Replica:分片的副本,默认一个分片有3个副本 3.Healthy Replica:健康副本,副本所在 Backend 存活,且副 ...