大模型function calling:让AI函数调用更智能、更高效

大模型function calling:让AI函数调用更智能、更高效

5e5a6b93-1b1f-425a-b01d-d15e85720563

随着大语言模型(LLM)的快速发展,其在实际应用中的能力越来越受到关注。Function Calling 是一种新兴的技术,允许大模型与外部工具或API进行交互,从而扩展了模型的功能边界。本文将深入探讨 Function Calling 的原理、应用场景以及如何通过优化实现更智能、高效的函数调用。

1. 什么是 Function Calling?

unction Calling 是一种机制,允许大语言模型动态调用外部函数或API,以完成特定任务。例如,当用户提问“今天的天气如何?”时,模型可以通过调用天气API获取实时数据并返回结果。这种方式不仅提升了模型的实用性,还使其能够处理复杂的多步骤任务。

  • 关键特点:
    • 动态调用:根据用户需求调用合适的函数。
    • 上下文感知:结合对话上下文选择最佳函数。
    • 扩展性强:支持多种API和服务集成。

2. Function Calling 的核心原理

workflow

  1. 用户输入问题或指令。
  2. 模型分析输入,生成 JSON 格式的函数调用请求。
  3. 后端解析请求,调用对应函数或API。
  4. 将函数返回的结果传递回模型。
  5. 模型基于结果生成最终回答。

3.基本操作

llm使用的是llama3.2:3b的模型,有一些模型是不支持tools的。

# 安装依赖包
pip isntall ollama
pip install yfinance
"""
1.将问题输出到llm模型中
2.模型解析问题中参数,将需要回调的函数和参数输出。
3.将回调结果作为上下文输入llm模型中验证
"""
import ollama
from ollama import Client

client = Client(
    host='http://192.168.3.203:11434/',
    headers={'x-some-header': 'some-value'}
)


def add_two_numbers(a: int, b: int) -> int:
    """
    Add two numbers

    Args:
      a (int): The first number
      b (int): The second number

    Returns:
      int: The sum of the two numbers
    """
    return int(a) + int(b)


def subtract_two_numbers(a: int, b: int) -> int:
    """
    Subtract two numbers
    """
    return int(a) - int(b)


# Tools can still be manually defined and passed into chat
subtract_two_numbers_tool = {
    'type': 'function',
    'function': {
        'name': 'subtract_two_numbers',
        'description': 'Subtract two numbers',
        'parameters': {
            'type': 'object',
            'required': ['a', 'b'],
            'properties': {
                'a': {'type': 'integer', 'description': 'The first number'},
                'b': {'type': 'integer', 'description': 'The second number'},
            },
        },
    },
}

messages = [{'role': 'user', 'content': 'What is three plus one?'}]
print('Prompt:', messages[0]['content'])

available_functions = {
    'add_two_numbers': add_two_numbers,
    'subtract_two_numbers': subtract_two_numbers,
}


def main():
    response = client.chat(
        'llama3.2:3b',
        messages=messages,
        tools=[add_two_numbers, subtract_two_numbers_tool],
    )

    if response.message.tool_calls:
        # There may be multiple tool calls in the response
        for tool in response.message.tool_calls:
            # Ensure the function is available, and then call it
            if function_to_call := available_functions.get(tool.function.name):
                print('Calling function:', tool.function.name)
                print('Arguments:', tool.function.arguments)
                output = function_to_call(**tool.function.arguments)
                print('Function output:', output)
            else:
                print('Function', tool.function.name, 'not found')

    # Only needed to chat with the model using the tool call results
    if response.message.tool_calls:
        # Add the function response to messages for the model to use
        messages.append(response.message)
        messages.append({'role': 'tool', 'content': str(output), 'name': tool.function.name})

        # Get final response from model with function outputs
        final_response = client.chat('llama3.2:3b', messages=messages)
        print('Final response:', final_response.message.content)

    else:
        print('No tool calls returned from model')


if __name__ == '__main__':
    main()

"""
结果
Prompt: What is three plus one?
Calling function: add_two_numbers
Arguments: {'a': 3, 'b': 1}
Function output: 4
"""
"""
1.通过llm模型获取解析回调函数和函数的参数
2.通过yfinance库获取公司最新股票信息
"""
from ollama import Client
import yfinance as yf

client = Client(
    host='http://192.168.3.203:11434',
    headers={'x-some-header': 'some-value'}
)


def get_current_stock_price(ticker_symbol):
    # 定义函数
    stock = yf.Ticker(ticker_symbol)
    current_price = stock.history(period='1d')['Close'].iloc[0]
    return current_price


# 本地测试
# data = get_current_stock_price("MSFT")
# print(data)

# 工具函数请求参数
tools = [{'type': 'function',
          'function': {
              'name': 'get_current_stock_price',
              'description': 'Get the current price for a stock',
              'parameters': {
                  'type': 'object',
                  'properties': {
                      'ticker_symbol': {
                          'type': 'string',
                          'description': 'The ticker symbol of the stock'
                      }
                  }
              },
              'required': ['ticker_symbol']
          }
          }]
response = client.chat(model='llama3.2:3b',
                       messages=[{
                           'role': 'user',
                           'content': 'What is the current price of MSFT'
                       }],
                       # provide a tool to get the current price of a stock
                       tools=tools
                       )
print(response['message']['tool_calls'])
# [ToolCall(function=Function(name='get_current_stock_price', arguments={'ticker_symbol': 'MSFT'}))]

# 模拟函数库
function_map = {'get_current_stock_price': get_current_stock_price}


def call_function_safely(response, function_map):
    # 模型结果回调函数
    tool_call = response['message']['tool_calls'][0]
    function_name = tool_call['function']['name']
    arguments = tool_call['function']['arguments']
    function_to_call = function_map.get(function_name)
    if function_to_call:
        try:
            result = function_to_call(**arguments)
            print(f"The current price of {arguments['ticker_symbol']} is : {result}")
        except TypeError as e:
            print(f"Argument error: {e}")
    else:
        print(f"{function_name} is not a recognized function")


call_function_safely(response, function_map)

4.实现自动发送邮件

import os
from dotenv import load_dotenv

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

import json
from openai import OpenAI


GPT_MODEL = "llama3.2:3b"

load_dotenv(dotenv_path="/Users/wuzhibin/workspace/pythonDemo/ollama_demo/.env")
# 大模型密钥
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
# 邮箱授权码
AUTHORIZATION_CODE = os.getenv("AUTHORIZATION_CODE")
print("1111", OPENAI_API_KEY, AUTHORIZATION_CODE)
client = OpenAI(base_url="http://192.168.3.203:11434/v1", api_key=OPENAI_API_KEY)

tools = [
    {
        "type": "function",
        "function": {
            "name": "send_email",
            "description": "Send an email to the specified email with the subject and content",
            "parameters":{
                "type": "object",
                "properties": {
                    "FromEmail": {
                        "type": "string",
                        "description": "The email address, eg., rememeber0101@126.com",
                    },
                    "Subject": {
                        "type": "string",
                        "description": "Subject of the email",
                    },
                    "Body": {
                        "type": "string",
                        "description": "The content of the email",
                    },
                    "Recipients": {
                        "type": "string",
                        "description": "The recipients' email addresses",
                    }
                },
                "required": ["FromEmail", "Subject", "Body", "Recipients"],
            },
        }
    }
]


def chat_completion_request(messages, tools=None, tool_choice=None, model=GPT_MODEL):
    try:
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            tools=tools,
            tool_choice=tool_choice,
        )
        return response
    except Exception as e:
        print("Unable to generate ChatCompletion response")
        print(f"Exception: {e}")
        return e


def send_email(sender_email, sender_authorization_code, recipient_email, subject, body):
    # 创建 MIMEMultipart 对象
    message = MIMEMultipart()
    message["From"] = sender_email
    message["To"] = recipient_email
    message["Subject"] = subject

    message.attach(MIMEText(body, "plain"))

    # 创建 SMTP_SSL 会话
    with smtplib.SMTP_SSL("smtp.126.com", 465) as server:
        server.login(sender_email, sender_authorization_code)
        text = message.as_string()
        server.sendmail(sender_email, recipient_email, text)


def main():
    messages = []
    
    while True:
        msg = input("【You】: ")
        messages.append({"role": "user", "content": msg})
        response = chat_completion_request(
            messages=messages,
            tools=tools
        )
        print(response)
        if content := response.choices[0].message.content:
            print(f"【AI】: {content}")
            messages.append({"role": "assistant", "content": content})
        else:
            fn_name = response.choices[0].message.tool_calls[0].function.name
            fn_args = response.choices[0].message.tool_calls[0].function.arguments
            # print(f"【Debug info】: fn_name - {fn_name}")
            # print(f"【Debug info】: fn_args - {fn_args}")
        
            if fn_name == "send_email":
                try:
                    args = json.loads(fn_args)
                    # 返回将要发送的邮件内容给用户确认
                    print("【AI】: 邮件内容如下:")
                    print(f"发件人: {args['FromEmail']}")
                    print(f"收件人: {args['Recipients']}")
                    print(f"主题: {args['Subject']}")
                    print(f"内容: {args['Body']}")
                    
                    confirm = input("AI: 确认发送邮件吗? (yes/no): ").strip().lower()
                    if confirm == "yes":
                        send_email(
                            sender_email=args["FromEmail"],
                            sender_authorization_code=AUTHORIZATION_CODE, 
                            recipient_email=args["Recipients"], 
                            subject=args["Subject"], 
                            body=args["Body"],
                        )
                        print("邮件已发送,还需要什么帮助吗?")
                        messages.append({"role": "assistant", "content": "邮件已发送,还需要什么帮助吗?"})
                    else:
                        print("邮件发送已取消,还需要什么帮助吗?")
                        messages.append({"role": "assistant", "content": "邮件发送已取消,还需要什么帮助吗?"})
                except Exception as e:
                    print(f"发送邮件时出错:{e}")
                    messages.append({"role": "assistant", "content": "抱歉,功能异常!"})    


if __name__ == "__main__":
    main()


# 帮我发送一封邮件 发件人: xxxxxxx@126.com, 收信人:xxxxxxx@qq.com, 发送内容:写着一封来自未来胖虎的问候邮件,主题:来自未来的问候

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

图像分类项目1:基于卷积神经网络的动物图像分类

一、选题背景及动机 在现代社会中,图像分类是计算机视觉领域的一个重要任务。动物图像分类具有广泛的应用,例如生态学研究、动物保护、农业监测等。通过对动物图像进行自动分类,可以帮助人们更好地了解动物种类、数量和分布情况,…

在 Ansys Maxwell 中分析磁场

在 Ansys Maxwell 中分析磁场 分析磁场的能力对于理解电磁系统至关重要。Ansys Maxwell 为工程师提供了强大的工具,帮助他们探索磁场数据并从中提取有价值的见解。在本指南中,我将深入研究 Ansys Maxwell 中的几种基本技术和方法,以有效地分…

[Lc滑动窗口_1] 长度最小的数组 | 无重复字符的最长子串 | 最大连续1的个数 III | 将 x 减到 0 的最小操作数

目录 1. 长度最小的字数组 题解 代码 ⭕2.无重复字符的最长子串 题解 代码 3.最大连续1的个数 III 题解 代码 4.将 x 减到 0 的最小操作数 题解 代码 1. 长度最小的字数组 题目链接:209.长度最小的字数组 题目分析: 给定一个含有 n 个 正整数 的数组…

数据库Redis数据库

目录 一、数据库类型 1、关系型数据库 2、非关系型数据库 3、关系型非关系型区别 二、Redis数据库 1、什么是Redis 3、Redis特点 4、Redis为什么读写快 5、部署Redis数据库 6、redis管理 7、Redis数据库五大类型 8、Redis数据库基础使用 9、redis五大类型增删查?…

蓝桥备赛(四)- 数组(下)

一 、 字符数组 1.1 介绍 数组的元素如果是字符类型 , 这种数组就是字符数组 , 字符数组可以是一维数组 , 可以是二维数组 (多维数组)。 接下来主要讨论一维的字符数组 : char arr1[5] //一维数组 char arr2[3][5] // 二维数组 C语言 中…

数据图表ScottPlot.WPF用法示例

目录 一、添加 NuGet 程序包&#xff08;5.0.47&#xff09; 二、MainWindow.xaml中添加引用 三、MainWindow.xaml.cs 具体使用代码 图表示例&#xff1a; 一、添加 NuGet 程序包&#xff08;5.0.47&#xff09; 二、MainWindow.xaml中添加引用 <Window x:Class"…

AtCoder Beginner Contest 001(A - 積雪深差、B - 視程の通報、C - 風力観測、D - 感雨時刻の整理)题目翻译

由于我发现网上很少有人会发很久之前AtCoder Beginner Contes的题&#xff0c;所以我打算从AtCoder Beginner Contest 001开始写。大约两周一更&#xff0c;需要的可以订阅专栏&#xff0c;感谢支持Thanks♪(&#xff65;ω&#xff65;)&#xff89; →题目讲解 A - 積雪深差 …

Windows 11【1001问】查看Windows是否激活的11种方法

在使用Windows 11的过程中&#xff0c;确保系统已正确激活是非常重要的一步。未激活的系统可能会限制某些功能的使用&#xff0c;并且无法获得最新的安全更新和支持。本文将详细介绍多种判断Windows 11是否已激活的11种方法&#xff0c;帮助用户快速了解自己的系统状态&#xf…

秒杀系统的常用架构是什么?怎么设计?

架构 秒杀系统需要单独部署&#xff0c;如果说放在订单服务里面&#xff0c;秒杀的系统压力太大了就会影响正常的用户下单。 常用架构&#xff1a; Redis 数据倾斜问题 第一步扣减库存时 假设现在有 10 个商品需要秒杀&#xff0c;正常情况下&#xff0c;这 10 个商品应该均…

USRP7440-通用软件无线电平台

1、产品描述 USRP7440基于第三代XILINX Zynq UltraScale RFSoC架构&#xff0c;它将射频ADC、DAC、ARM、FPGA等集成一体&#xff0c;瞬时带宽可以达到2.5GHz&#xff0c;尤其适合于射频直采应用&#xff0c;比如通信与雷达。 第一代RFSOC高达4GHz • 8x 或 16x 6.554GSPS DAC…

【Python机器学习】1.1. 机器学习(Machine Learning)介绍

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 1.1.1. 什么是机器学习&#xff1f; 举个例子&#xff1a; 小明1月工资1000&#xff0c;每月增长10%&#xff0c;第10月是多少&#xff…

协议-Airkiss

是什么&#xff1f; 设备 A 与外界没有建立任何实质性连接&#xff0c;可以称之为信息孤岛。设备 B 通过路由 或者直接 将 Wifi 的 ssid 与密码 UDP广播 传递给 A 为什么&#xff1f; 解决将无线网络的 ssid 与密码传输到设备难题 怎么做&#xff1f; 芯片自带AT指令开启Air…

python第十一课:并发编程 | 多任务交响乐团

&#x1f3af; 本节目标 理解多线程/多进程/协程的应用场景掌握threading与multiprocessing核心用法学会使用asyncio进行异步编程开发实战项目&#xff1a;高并发爬虫引擎破解GIL锁的性能迷思 1️⃣ 并发编程三剑客 &#x1f3bb; 生活化比喻&#xff1a; 多线程 → 餐厅多个…

linux中断调用流程(arm)

文章目录 ARM架构下Linux中断处理全流程解析&#xff1a;从硬件触发到驱动调用 ⚡**一、中断触发与硬件层响应** &#x1f50c;**1. 设备触发中断** &#x1f4e1; **二、CPU阶段&#xff1a;异常入口与上下文处理** &#x1f5a5;️**1. 异常模式切换** &#x1f504;**2. 跳转…

Deepseek 模型蒸馏

赋范课堂&#xff1a; https://www.bilibili.com/video/BV1qUN8enE4c/

商城系统单商户开源版源码

环境配置 1.软件安装 宝塔安装系统软件:Nginx、MySQL5.6、PHP( PHP用7.1-7.4版本)、phpMyAdmin(Web端MySQL管理工具)。 2.配置mysql 设置mysql&#xff0c;在已安装的软件里面找到 mysql点击进行设置 3.修改sql-mode 选择左侧配置修改&#xff0c;找到里面的sql-mode&…

登录日志管理:通用分页和排序封装、 查询登录日志列表、删除登录日志、清空登录日志、解锁用户登录状态(解锁密码错误次数超限)

文章目录 引言I 登录日志管理接口列表II 通用分页和排序封装Java 分页和排序封装vue前端排序页面III 工具类字段名转换 : 驼峰转下划线命名引言 I 登录日志管理 接口列表 import request from @/utils/request// 查询登录日志列表 export function list(query) {return

Java内存管理与性能优化实践

Java内存管理与性能优化实践 Java作为一种广泛使用的编程语言&#xff0c;其内存管理和性能优化是开发者在日常工作中需要深入了解的重要内容。Java的内存管理机制借助于垃圾回收&#xff08;GC&#xff09;来自动处理内存的分配和释放&#xff0c;但要实现高效的内存管理和优…

Flutter_学习记录_实现列表上拉加载更多的功能

可以用ScrollController组件来实现这样列表上拉加载更多的功能: 1. 定义变量 在StatefulWidget 的组件内&#xff0c;添加三个属性&#xff1a; // 滚动视图的控制器final ScrollController _scrollController ScrollController();// 是否已显示了上拉加载中bool _isShowM…

使用DeepSeek+KIMI生成高质量PPT

一、使用DeepSeek DeepSeek官网&#xff1a;DeepSeek 点击“开始对话”&#xff0c;进入交互页面。 在上图中&#xff0c;输入问题&#xff0c;即可获取AI生成的结果。 基础模型&#xff08;V3&#xff09;&#xff1a;通用模型&#xff08;2024.12&#xff09;&#xff0c;高…