function-calling初体验

news2024/11/24 17:37:51

课程地址:https://learn.deeplearning.ai/courses/function-calling-and-data-extraction-with-llms/lesson/1/introduction
github notebook地址:https://github.com/kingglory/LLMs-function-calling/tree/main


Function-Calling 介绍

函数调用(Function-Calling)允许使用自定义功能扩展LLM,使它们能够根据自然语言指令形成对外部函数的调用。结构化数据提取使LLM能够从非结构化文本中提取可用信息。
在这里插入图片描述
Function-calling is the capability of an LLM to take in a natural language query, along with a description of the function,and output a string that can be used to call that function.
Function-calling是LLM接收自然语言查询以及函数描述,并输出可用于调用该函数的字符串的能力。
在这里插入图片描述
在这里插入图片描述

先使用NexusRavenV2-13B 大模型,一个针对函数调用(function-calling)和数据提取进行了微调的开源模型。该模型可在Hugging Face上使用,在一些函数调用任务中表现优于GPT-4,并且具有130亿个参数,因此可以在本地托管。

写一个python tool

from matplotlib import pyplot as plt

def plot_some_points(x : list, y : list):
  """
  Plots some points!
  """
  plt.plot(x, y)
  plt.show()
USER_QUERY = "Hey can you plot y=10x where x=1, 2, 3 for me?"

plot_some_points(x=[1, 2, 3], y=[10, 20, 30])

在这里插入图片描述

想让大模型帮我们做上面的事,首先要给出一个tool 描述(description)和user query 给LLM。

  • 你首先要提供前面使用的函数的原型。
  • 你将要使用的LLM使用python格式的函数。
  • 你还将添加一些关于工具功能的描述。LLM会根据描述来判断是否应该使用该工具来回答用户查询的推理。
  • 你还需要提供LLM 用户的输入(user query)
prompt = \
f'''
Function:
def plot_some_points(x : list, y : list):
  """
  Plots some points!
  """
  plt.plot(x, y)
  plt.show()

User Query: {USER_QUERY}<human_end>
'''
# 这个大模型是训练过的,专门针对function-calling ,这里是接口调用,返回function-calling字符串
# def raven_post(payload):
#     """
#     Sends a payload to a TGI endpoint.
#     """
#     # Now, let's prompt Raven!
#     API_URL = "http://nexusraven.nexusflow.ai"
#     headers = {
#             "Content-Type": "application/json"
#     }
#     import requests
#     response = requests.post(API_URL, headers=headers, json=payload)
#     return response.json()

# def query_raven(prompt):
# 	"""
# 	This function sends a request to the TGI endpoint to get Raven's function call.
# 	This will not generate Raven's justification and reasoning for the call, to save on latency.
# 	"""
# 	import requests
# 	output = raven_post({
# 		"inputs": prompt,
# 		"parameters" : {"temperature" : 0.001, "stop" : ["<bot_end>"], "return_full_text" : False, "do_sample" : False, "max_new_tokens" : 2048}})
# 	call = output[0]["generated_text"].replace("Call:", "").strip()
# 	return call
from utils import query_raven
function_call = query_raven(prompt)

LLM function-calling 的结果是一个字符串: 函数名被调用的状态,并包含输入参数,然后exec 执行一下就会执行这个函数(tool)

print (function_call)
plot_some_points(x=[1, 2, 3], y=[10, 20, 30])

exec 执行储存在字符串或文件中的 Python 语句,相比于 eval,exec 可以执行更复杂的 Python 代码。https://www.runoob.com/python3/python3-func-exec.html

exec 的语法: exec(object[, globals[, locals]])

  • object:必选参数,表示需要被指定的 Python 代码。它必须是字符串或 code 对象。如果 object 是一个字符串,该字符串会先被解析为一组 Python 语句,然后再执行(除非发生语法错误)。如果 object 是一个 code 对象,那么它只是被简单的执行。
  • globals:可选参数,表示全局命名空间(存放全局变量),如果被提供,则必须是一个字典对象。
  • locals:可选参数,表示当前局部命名空间(存放局部变量),如果被提供,可以是任何映射对象。如果该参数被忽略,那么它将会取与 globals 相同的值。

exec 返回值永远为 None。

>>>exec('print("Hello World")')
Hello World
# 单行语句字符串
>>> exec("print ('runoob.com')")
runoob.com
 
#  多行语句字符串
>>> exec ("""for i in range(5):
...     print ("iter time: %d" % i)
... """)
iter time: 0
iter time: 1
iter time: 2
iter time: 3
iter time: 4
exec(function_call)

在这里插入图片描述

再试一个
USER_QUERY = "帮我画个y=x**3, 其中 x = 1,2,3, 4, 5"
prompt = \
f'''
Function:
def plot_some_points(x : list, y : list):
  """
  Plots some points!
  """
  plt.plot(x, y)
  plt.show()

User Query: {USER_QUERY}<human_end>
'''
from utils import query_raven
function_call = query_raven(prompt)
exec(function_call)

在这里插入图片描述
在这里插入图片描述

试一个复杂的例子

定义一个函数
#  提供 脸的颜色, 眼睛的颜色, 鼻子的颜色 画一个笑脸
import matplotlib.pyplot as plt
import matplotlib.patches as patches

def draw_clown_face(face_color='yellow', eye_color='black', 
                    nose_color='red'):
    """
    Draws a customizable, simplified clown face using matplotlib.

    Parameters:
    - face_color (str): Color of the clown's face. Default is 'yellow'.
    - eye_color (str): Color of the clown's eyes. Default is 'black'.
    - nose_color (str): Color of the clown's nose. Default is 'red'.

    This function creates a plot displaying a simplified clown face, where essential facial features' size, position, and color can be customized. 
    """
    # Constants
    face_radius = 0.4
    nose_radius = 0.1
    nose_x, nose_y = 0.5, 0.5
    mouth_x, mouth_y = 0.5, 0.3
    mouth_color = 'black'
    eye_size = 0.05
    mouth_size = (0.3, 0.1)
    eye_offset=(0.15, 0.15)
    mouth_theta = (200, 340)

    fig, ax = plt.subplots()
    # Face
    face = patches.Circle((0.5, 0.5), face_radius, color=face_color, fill=True)
    ax.add_patch(face)
    # Eyes
    eye_left = patches.Circle((0.5-eye_offset[0], 0.5+eye_offset[1]), eye_size, color=eye_color, fill=True)
    eye_right = patches.Circle((0.5+eye_offset[0], 0.5+eye_offset[1]), eye_size, color=eye_color, fill=True)
    ax.add_patch(eye_left)
    ax.add_patch(eye_right)
    # Nose
    nose = patches.Circle((nose_x, nose_y), nose_radius, color=nose_color, fill=True)
    ax.add_patch(nose)
    # Mouth
    mouth = patches.Arc((mouth_x, mouth_y), mouth_size[0], mouth_size[1], angle=0, 
                        theta1=mouth_theta[0], theta2=mouth_theta[1], color=mouth_color, linewidth=2)
    ax.add_patch(mouth)
    # Setting aspect ratio to 'equal' to ensure the face is circular
    ax.set_aspect('equal')
    # Remove axes
    ax.axis('off')
    plt.show()
定义一个Prompt
USER_QUERY = \
"画一个白色的小丑脸和红色的鼻子吗" 

raven_prompt = \
'''
Function:
def draw_clown_face(face_color='yellow', 
                    eye_color='black',
                    nose_color='red'):
    """
    Draws a customizable, simplified clown face using matplotlib.

    Parameters:
    - face_color (str): Color of the clown's face.
    - eye_color (str): Color of the clown's eyes.
    - nose_color (str): Color of the clown's nose.
    """

User Query: {query}<human_end>
'''
raven_prompt_with_query = raven_prompt.format(query=USER_QUERY)

print (raven_prompt_with_query)
Function:
def draw_clown_face(face_color='yellow', 
                    eye_color='black',
                    nose_color='red'):
    """
    Draws a customizable, simplified clown face using matplotlib.

    Parameters:
    - face_color (str): Color of the clown's face.
    - eye_color (str): Color of the clown's eyes.
    - nose_color (str): Color of the clown's nose.
    """

User Query: 画一个白色的小丑脸和红色的鼻子吗<human_end>
from utils import query_raven
raven_call = query_raven(raven_prompt_with_query)
print (raven_call)
draw_clown_face(face_color='white', nose_color='red')
Run The Call
exec(raven_call)

在这里插入图片描述

再画一个笑脸
USER_QUERY = "画一个小丑的笑脸,眼睛是白色的,脸是黑色的,嘴巴是粉色的,鼻子是大红色,耳朵就跟米老鼠一样的"
raven_prompt_with_query = raven_prompt.format(query=USER_QUERY)

from utils import query_raven
raven_call = query_raven(raven_prompt_with_query)
print (raven_call)
exec(raven_call)
draw_clown_face(face_color='black', eye_color='white', nose_color='red')

在这里插入图片描述

试一下 chatgpt的function-calling

import json
from openai import OpenAI
from dotenv import load_dotenv
import os

_ = load_dotenv()

def query_openai(msg, functions=None):
  load_dotenv()
  GPT_MODEL = "gpt-3.5-turbo"

  openai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
  openai_response = openai_client.chat.completions.create(
    model = GPT_MODEL,
    messages = [{'role': 'user', 'content': msg}],
    tools = functions)
  return openai_response

需要以json格式提供tool的描述(description)和参数(arguments)

openai_function = {
  "type": "function",
  "function": {
    "name": "draw_clown_face",
    "description": "Draws a customizable, simplified clown face using matplotlib.",
    "parameters": {
      "type": "object",
      "properties": {
        "face_color": {
          "type": "string",
          "description": "Color of the clown's face."
        },
        "eye_color": {
          "type": "string",
          "description": "Color of the clown's eyes."
        },
        "nose_color": {
          "type": "string",
          "description": "Color of the clown's nose."
        }
        }
      }
    }
  }

openai_msg = \
"Hey can you draw a pink clown face with a red nose"
result = query_openai(openai_msg, functions=[openai_function])

print (result.choices[0].message.tool_calls[0].function)
Function(arguments='{"face_color": "pink", "eye_color": "black", "nose_color": "red"}', name='draw_clown_face')

注意!返回的结果跟之前不一样,这样的字符串是不能直接用exec执行的,所以需要一个归一化处理

tool_name = result.choices[0].message.tool_calls[0].function.name
tool_args = result.choices[0].message.tool_calls[0].function.arguments

function_call = f"{tool_name}(**{tool_args})"

print (function_call)
draw_clown_face(**{"face_color": "pink", "eye_color": "black", "nose_color": "red"})
exec(function_call)

在这里插入图片描述

使用训练过的LLM在非结构化数据和高度结构化的code之间搭建了桥梁!!

在这里插入图片描述


辅助函数:utils.py

import inspect
def raven_post(payload):
    """
    Sends a payload to a TGI endpoint.
    """
    # Now, let's prompt Raven!
    API_URL = "http://nexusraven.nexusflow.ai"
    headers = {
            "Content-Type": "application/json"
    }
    import requests
    response = requests.post(API_URL, headers=headers, json=payload)
    return response.json()

def call_functioncalling_llm(prompt, api_to_call):
    """
    This function sends a request to the TGI endpoint to get Raven's function call.
    This will not generate Raven's justification and reasoning for the call, to save on latency.
    """
    signature = inspect.signature(api_to_call)
    docstring = api_to_call.__doc__
    prompt = f'''Function:\n{api_to_call.__name__}{signature}\n"""{clean_docstring(docstring)}"""\n\n\nUser Query:{prompt}<human_end>'''
    import requests
    output = raven_post({
        "inputs": prompt,
        "parameters" : {"temperature" : 0.001, "stop" : ["<bot_end>"], "do_sample" : False, "max_new_tokens" : 2048, "return_full_text": False}})
    call = output[0]["generated_text"].replace("Call:", "").strip()
    return call

def query_raven(prompt):
	"""
	This function sends a request to the TGI endpoint to get Raven's function call.
	This will not generate Raven's justification and reasoning for the call, to save on latency.
	"""
	import requests
	output = raven_post({
		"inputs": prompt,
		"parameters" : {"temperature" : 0.001, "stop" : ["<bot_end>"], "return_full_text" : False, "do_sample" : False, "max_new_tokens" : 2048}})
	call = output[0]["generated_text"].replace("Call:", "").strip()
	return call

def clean_docstring(docstring):
    if docstring is not None:
        # Remove leading and trailing whitespace
        docstring = docstring.strip()
    return docstring

def build_raven_prompt(function_list, user_query):
    import inspect
    raven_prompt = ""
    for function in function_list:
        signature = inspect.signature(function)
        docstring = function.__doc__
        prompt = \
f'''
Function:
def {function.__name__}{signature}
    """
    {clean_docstring(docstring)}
    """
    
'''
        raven_prompt += prompt
        
    raven_prompt += f"User Query: {user_query}<human_end>"
    return raven_prompt

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1888688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GAMES104:04游戏引擎中的渲染系统1:游戏渲染基础-学习笔记

文章目录 概览&#xff1a;游戏引擎中的渲染系统四个课时概览 一&#xff0c;渲染管线流程二&#xff0c;了解GPUSIMD 和 SIMTGPU 架构CPU到GPU的数据传输GPU性能限制 三&#xff0c;可见性Renderable可渲染对象提高渲染效率Visibility Culling 可见性裁剪 四&#xff0c;纹理压…

格式化选NTFS还是exFAT 格式化NTFS后Mac不能用怎么办 移动硬盘格式化ntfs和exfat的区别

面对硬盘、U盘或移动硬盘的格式化决策&#xff0c;NTFS与exFAT作为主流的文件系统&#xff0c;用户在选择时可以根据它们的不同特点来选择适用场景。下面我们来看看格式化选NTFS还是exFAT&#xff0c;格式化NTFS后Mac不能用怎么办的相关内容。 一、格式化选NTFS还是exFAT 在数…

网络基础:EIGRP

EIGRP&#xff08;Enhanced Interior Gateway Routing Protocol&#xff09;是由思科开发的一种高级距离矢量路由协议&#xff0c;结合了距离矢量和链路状态路由协议的优点&#xff1b;EIGRP具有快速收敛、高效带宽利用、负载均衡等特点&#xff0c;适用于各种规模的网络。EIGR…

面试题springboot面试

文章目录 Spring的依赖注入构造器注入stetter注入属性注入 springboot的优势第一开箱即用约定大于配置内嵌tomcat服务器 javaweb的三大组件springboot的自动配置原理SpringIoc的实现机制springmvcspring如何简化开发 Spring的依赖注入 构造器注入 stetter注入 属性注入 使用…

python小练习04

三国演义词频统计与词云图绘制 import jieba import wordcloud def analysis():txt open("三国演义.txt",r,encodingutf-8).read()words jieba.lcut(txt)#精确模式counts {}for word in words:if len(word) 1:continueelif word "诸葛亮" or word &q…

环保管理新篇章:智慧环保引领制造业走向绿色未来

环保领域作为当代社会焦点之一&#xff0c;其重要性不言而喻&#xff0c;直接关系到人类生存环境的可持续发展&#xff0c;因此吸引了政府、企业及社会各界的深切关注。然而&#xff0c;在环保行业蓬勃发展的背后&#xff0c;亦浮现出一系列亟待解决的痛点&#xff1a;融资渠道…

PyTorch MNIST手写体识别:SwanLab可视化训练

MNIST手写体识别是深度学习、CV的“Hello World”&#xff0c;无数人从这个任务入门&#xff0c;进入深度学习的世界&#xff5e; 进阶请看&#xff1a;PyTorch猫狗分类 这篇文章我将带大家使用SwanLab&#xff08;训练可视化&#xff09;、PyTorch&#xff08;深度学习框架&…

Hive常用的内置函数

文章目录 聚合类1.指定列值的数目2.指定列值求和3.最大值4.最小值5.平均值6.中位数函数7.分位数函数 数值类1.取整函数Round(a)2.指定精度取整ROUND(double a,int b)3.向上取整FLOOR()4.向下取整CEIL()5.随机数 rand()6.绝对值函数 日期类获取当前日期获取当前时间戳日期前后日…

【Java环境配置过程详解(包括IDEA配置Java)】

目录 一、JDK下载安装 1. 官网下载JDK 2. 本地安装JDK 3. 配置环境变量 4. 验证是否安装成功 ​编辑二、IDEA进行安装下载 1. 官网下载 IDEA 2、IDEA进行Java开发 1. 创建Java项目 2. 程序测试 一、JDK下载安装 1. 官网下载JDK 1&#xff09;官网链接: https://www.o…

IT行业入门,如何假期逆袭,实现抢跑

目录 前言 1.IT行业领域分类 2.基础课程预习指南 3.技术学习路线 4.学习资源推荐 结束语 前言 IT&#xff08;信息技术&#xff09;行业是一个非常广泛和多样化的领域&#xff0c;它包括了许多不同的专业领域和职业路径。如果要进军IT行业&#xff0c;我们应该要明确自己…

keyclock实现三方登录

公司希望我把公司的keycloak作为新项目的一种第三方登录方式时&#xff0c;就像微信&#xff0c;google&#xff0c;github&#xff0c;使用keycloak上的账户资源 因此&#xff0c;先需要跟公司keyclock管理员联系&#xff0c;让他把各个端点url&#xff0c;keycloak颁发的cli…

MATLAB将两个折线图画在一个图里

界面如图 输入行数和列数&#xff0c;点击开始填入数据&#xff0c;其中第一列为x值&#xff0c;后面几列&#xff0c;每一列都是y坐标值&#xff0c;填好后点击画在同一张图里即可。点击置零就把所有数变成0&#xff0c;另外也可以选择节点样式。 .mlapp格式的文件如下 夸克…

AI时代的产品经理的成长指南_pdca循环理论制定ai学习成长计划

一、人人不都是产品经理 大多数人听到“产品经理”这个词&#xff0c;总会联想到“人人都是产品经理”这句话。但实际上产品经理这个岗位并没有那么简单。 用一句话概括产品经理的职责就是“帮助团队交付正确产品给用户的人”。也就是说&#xff0c;产品经理要能凝聚团队的力…

归并排序-MergeSort (C语言详解)

目录 前言归并排序的思想归并排序的递归法归并排序的非递归法归并排序的时间复杂度与适用场景总结 前言 好久不见, 前面我们了解到了快速排序, 那么本篇旨在介绍另外一种排序, 它和快速排序的思想雷同, 但又有区别, 这就是归并排序, 如下图, 我们对比快速排序与归并排序. 本…

在线JSON可视化工具--改进

先前发布了JSON格式化可视化在线工具&#xff0c;提供图形化界面显示结构关系功能&#xff0c;并提供JSON快速格式化、JSON压缩、快捷复制、下载导出、对存在语法错误的地方能明确显示&#xff0c;而且还支持全屏&#xff0c;极大扩大视野区域。 在线JSON格式化可视化工具 但…

[Labview] 二维数组写入表格

就一个二维数组写表&#xff0c;CSDN天天让我改进质量 简直是迫害完美主义 天知道Labview有什么思路好写&#xff0c;就一个破连连看(ˉ▽ˉ&#xff1b;)... 随便写点什么碎碎念占字数好了

Linux源码阅读笔记09-进程NICE案例分析1

task_nice task_nice函数功能&#xff1a;获取某个进程的nice值&#xff0c;其中nice值为进程的优先级&#xff0c;与静态优先级有关&#xff08;nicestatic_prio-120&#xff09;。 nice的取值范围&#xff1a;-20 ~ 19 内核源码 根据内核的注释可以知道&#xff1a;task_n…

时间12小时和24时转换方法

24小时时间转为12小时制 function convertTo12Hour(time24h){let [hours, minutes] time24h.split(:);let modifier 上午;if (parseInt(hours, 10) > 12) {modifier 下午;hours (parseInt(hours, 10) - 12).toString();}if (parseInt(hours, 10) 12) {modifier 下午;}…

Arduino 与树莓派常用的 IMU 传感器

惯性测量单元&#xff08;IMU&#xff09;是一种高度集成的传感器系统&#xff0c;广泛应用于需要高精度运动和姿态信息的领域。某些高精度要求下&#xff0c;还需要辅以温度、气压等其他传感器信息。 一、组成与功能 1. 组成 9 轴 IMU 由三个主要部分组成&#xff1a;3 轴加…

系留无人机+自组网+单兵图传:低空集群组网指挥系统技术详解

低空无人机集群的控制、调度、信息回传需要有高度可靠和稳定的无线通信链路来保障。我国发达的公网基础设施为上述应用创造了良好的条件&#xff0c;但低空应用必须要考虑到在极端情况下公网瘫痪造成的通信链路中断带来的影响&#xff0c;因此有必要在公网之外&#xff0c;寻求…