耗时3天整理,一篇文章学会OpenAI大杀器--function Call

1、让ChatGPT帮我买张火车票

想象下,你创建一个人工智能助手,你可以这样对他说:“帮我买北京的火车票,提前一天提醒我”!如果是ChatGPT的话,它必然会无情地拒绝你。

ChatGPT是世界上最强大的模型,不过,它虽然知道你想让它帮你买票,但它却不懂如何买票,它能力的上限就摆在那儿了。好在OpenAI在GPT模型引入了一个强大的功能–函数调用(function call)。

相信有些小伙伴应该已经用过ChatGPT的plugins功能,Plugins的功能有不少是基于function call进行的

今天,我们一起来创建一个获取最新新闻的GPT,给大家展示如何使用function call,用于深入理解函数调用的概念以及它给我们带来的可能性。

2、函数调用(function call)是啥?

函数调用(function call)是OpenAIGPT-4-0613GPT-3.5 Turbo-0613模型支持的功能,这两个模型经过训练,可以根据用户的提示检测需不需要调用用户提供的函数,并且用一个很规范的结构返回,而不是直接返回常规的文本。

函数调用(function)允许ChatGPT和其他的系统进行信息的交互,让ChatGPT回答他们原本无法回答的问题。例如,我们需要查询实时的天气,这些数据是ChatGPT没有的,所以ChatGPT需要从别的平台获取最新的天气情况。换句话就是说,函数调用,就是提供了一种方式,教AI模型怎么样和外面的系统进行交互。

3、函数调用(function-call)目的是什么?

函数调用,可以用来增强GPT模型的功能,让GPT能做到更多事情。其实还有两种方式可以增强GPT模型的能力。

  • 微调: 提供标注数据进一步训练模型,不过微调需要很多时间和精力准备训练数据。
  • 嵌入:构建机器人知识库,通过构建上下文和知识库的内容进行关联,从而让GPT获得更丰富的回答。

函数调用是第三种扩展GPT功能的方式,这种方式和其他两种不一样,它可以让我们和外部的系统进行交互!

4、怎么样使用函数调用?

在有函数调用(funciton-call)时候,我们调用GPT构建AI应用的模式非常简单。主要有几个步骤

1、用户(client)发请求给我们的服务(chat server)

2、我们的服务(chat server)给GPT提示词

3、重复执行

有了函数调用(function-call),调用的方式就比之前的复杂一些了,具体的步骤为

1、发送用户的提示词以及可以调用的函数

2、GPT模型根据用户的提示词,判断是用普通文本还是函数调用的格式响应

3、如果是函数调用格式,那么Chat Server就会执行这个函数,并且将结果返回给GPT

4、然后模型使用提供的数据,用连贯的文本响应。

5、用API完成函数调用

在调用GPT接口时,我们一般使用的是Completions接口,这个接口发送的是POST请求,发送的数据格式如下图所示:

{
  "model": "gpt-3.5-turbo",
  "messages": [
    {
      "role": "user",
      "content": "What's weather like today?"
    }
  ]
}

GPT返回的可能是下面这些内容

{
  "id": "chatcmpl-FWVo3hYwjrpAptzepU46JamvvgBzb",
  "object": "chat.completion",
  "created": 1687983115,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "I'm sorry, but I don't have access to real-time information, including current weather conditions or forecasts. To find out the weather for your location today, I recommend using a weather website, app, or a voice-activated assistant like Siri, Google Assistant, or Alexa. Simply ask one of these services for the weather in your area, and they should be able to provide you with up-to-date information."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 15,
    "completion_tokens": 44,
    "total_tokens": 59
  }
}

在这里,为了记录上下文,我们需要在每个请求上,将整个消息历史记录返回给 API。例如,如果我们想继续讨论之前的问题,那么相应的 JSON 应该将是:

{
  "model": "gpt-3.5-turbo",
  "messages": [
    {
      "role": "user",
      "content": "How many planets does the solar system have?"
    },
    {
      "role": "assistant",
      "content": "I'm sorry, but I don't have access to real-time information, including current weather conditions or forecasts. To find out the weather for your location today, I recommend using a weather website, app, or a voice-activated assistant like Siri, Google Assistant, or Alexa. Simply ask one of these services for the weather in your area, and they should be able to provide you with up-to-date information."
    {
      "role": "user",
      "content": "how do I access these apps?"
    }
  ]
}

在上面的例子中,我们明确知道了,ChatGPT查不了实时信息,接下来,我们会加上function call,让ChatGPT可以查询实时信息。

{
  "model": "gpt-3.5-turbo-0613",
  "messages": [
    {
      "role": "user",
      "content": "How is the weather in NYC?"
    }
  ],
  "functions": [
    {
      "name": "get_current_weather",
      "description": "Get the current weather in a given location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "The city and state, e.g. San Francisco, CA"
          },
          "unit": {
            "type": "string",
            "enum": [
              "celsius",
              "fahrenheit"
            ]
          }
        },
        "required": [
          "location"
        ]
      }
    }
  ]
}

当GPT模型决定调用我们提供的函数,那么我们就会收到下面类似的返回

{
  "id": "chatcmpl-7WWG94C1DCFlAk5xmUwrZ9OOhFnOq",
  "object": "chat.completion",
  "created": 1687984857,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "function_call": {
          "name": "get_current_weather",
          "arguments": "{n  "location": "New York, NY"n}"
        }
      },
      "finish_reason": "function_call"
    }
  ],
  "usage": {
    "prompt_tokens": 81,
    "completion_tokens": 19,
    "total_tokens": 100
  }
}

get_current_weather将会使用返回的参数调用。OpenAI执行该函数,我们的服务会执行这个函数,并且获取结果后解析返回给OpenAI。

一旦我们检索到天气数据,我们就会使用一种名为 的新的角色将其发送回模型function。例如:

{
    "model":"gpt-3.5-turbo-0613",
    "messages":[
        {
            "role":"user",
            "content":"How is the weather in NYC?"
        },
        {
            "role":"assistant",
            "content":null,
            "function_call":{
                "name":"get_current_weather",
                "arguments":"{n  "location": "New York, NY"n}"
            }
        },
        {
            "role":"function",
            "name":"get_current_weather",
            "content":"Temperature: 57F, Condition: Raining"
        }
    ],
    "functions":[
        {
            "name":"get_current_weather",
            "description":"Get the current weather in a given location",
            "parameters":{
                "type":"object",
                "properties":{
                    "location":{
                        "type":"string",
                        "description":"The city and state, e.g. San Francisco, CA"
                    },
                    "unit":{
                        "type":"string",
                        "enum":[
                            "celsius",
                            "fahrenheit"
                        ]
                    }
                },
                "required":[
                    "location"
                ]
            }
        }
    ]
}

这里注意下,我们将整个消息历史记录传递给了 API,包括原始提示词、模型的函数调用以及代码中执行天气函数的结果,这种方式可以让模型能够理解调用函数的上下文。

最后,模型可能会回复一个格式正确的答案,回答我们最初的问题:

{
  "id": "chatcmpl-7WWQUccvLUfjhbIcuvFrj2MDJVEiN",
  "object": "chat.completion",
  "created": 1687985498,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "The weather in New York City is currently raining with a temperature of 57 degrees Fahrenheit."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 119,
    "completion_tokens": 19,
    "total_tokens": 138
  }
}

以上,就是Function Call在调用过程中交互数据的格式,接下来,我们使用实际的例子,使用python开发function call的简单应用。

5.1 新闻机器人

为了实现这个功能,我们需要OpenAI 的key,key的获取可以在https://platform.openai.com/account/api-keys,

获取key之后,我们需要安装一些python依赖包

pip install openai tiktoken

我们需要导入一些依赖库

import openai
import tiktoken
import json
import os
import requests

接下来,将定义几个常量:

  • 指定 GPT 模型。我们将使用gpt-3.5-turbo-16k
  • 我们预设的提示词。
  • 用于对字符串和消息中的标记进行计数的编码;需要确保我们不超过语言模型的限制。
  • 调用的函数的最大数量
  • openai.api_key 从openai平台获取的key
  • zsxq_cookie 知识星球的cookie
llm_model = "gpt-3.5-turbo-16k"
llm_max_tokens = 15500
llm_system_prompt = "You are an assistant that provides news and headlines to user requests. Always try to get the lastest breaking stories using the available function calls."
encoding_model_messages = "gpt-3.5-turbo-0613"
encoding_model_strings = "cl100k_base"
function_call_limit = 3
openai.api_key = "sk-xxx" # 需要设置
zsxq_cookie="zsxq_access_token=xxx" # 需要设置
news_key = "" # 新闻key

所有 GPT模型都有token限制。如果超过此限制,API 将抛出错误而不是响应我们的请求。因此,我们需要一个函数来计算token的数量。

def num_tokens_from_messages(messages):
    """Returns the number of tokens used by a list of messages."""
    try:
        encoding = tiktoken.encoding_for_model(encoding_model_messages)
    except KeyError:
        encoding = tiktoken.get_encoding(encoding_model_strings)

    num_tokens = 0
    for message in messages:
        num_tokens += 4
        for key, value in message.items():
            num_tokens += len(encoding.encode(str(value)))
            if key == "name":
                num_tokens += -1
    num_tokens += 2
    return num_tokens

现在我们需要有一个函数来获取新闻,我们可以在https://newsapi.org/获取查询新闻的KEY

def get_top_headlines(query: str = None, country: str = None, category: str = None):
    """Retrieve top headlines from newsapi.org (API key required)"""

    base_url = "https://newsapi.org/v2/top-headlines"
    headers = {
        "x-api-key": news_key
    }
    params = { "category": "general" }
    if query is not None:
        params['q'] = query
    if country is not None:
        params['country'] = country
    if category is not None:
        params['category'] = category

    # Fetch from newsapi.org - reference: https://newsapi.org/docs/endpoints/top-headlines
    response = requests.get(base_url, params=params, headers=headers)
    data = response.json()

    if data['status'] == 'ok':
        print(f"Processing {data['totalResults']} articles from newsapi.org")
        return json.dumps(data['articles'])
    else:
        print("Request failed with message:", data['message'])
        return 'No articles found'

为了让GPT模型知道我们存在get_top_headlines函数可以调用,我们需要用JSON结构描述我们的函数

signature_get_top_headlines = {
    "name": "get_top_headlines",
    "description": "获取按国家和/或类别分类的头条新闻。",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "自由输入关键词或短语进行搜索。",
            },
            "country": {
                "type": "string",
                "description": "要获取头条新闻的国家的2位ISO 3166-1代码。",
            },
            "category": {
                "type": "string",
                "description": "要获取头条新闻的类别",
                "enum": ["business","entertainment","general","health","science","sports","technology"]
            }
        },
        "required": [],
    }
}

接下来,我们将定义complete函数,执行和GPT大模型交互的任务,主要步骤为:

  1. 在消息末尾添加系统提示。这个用于添加消息的上下文
  2. 如果token总数超过模型的限制,则删除旧消息。
  3. 将请求发送到 GPT API。
  4. 从列表末尾删除系统消息
def complete(messages, function_call: str = "auto"):
    """Fetch completion from OpenAI's GPT"""

    messages.append({"role": "system", "content": llm_system_prompt})

    # delete older completions to keep conversation under token limit
    while num_tokens_from_messages(messages) >= llm_max_tokens:
        messages.pop(0)

    print('Working...')
    res = openai.ChatCompletion.create(
        model=llm_model,
        messages=messages,
        functions=[signature_get_top_headlines, signature_get_zsxq_article],
        function_call=function_call
    )
    
    # remove system message and append response from the LLM
    messages.pop(-1)
    response = res["choices"][0]["message"]
    messages.append(response)

    # call functions requested by the model
    if response.get("function_call"):
        function_name = response["function_call"]["name"]
        if function_name == "get_top_headlines":
            args = json.loads(response["function_call"]["arguments"])
            headlines = get_top_headlines(
                query=args.get("query"),
                country=args.get("country"),
                category=args.get("category")        
            )
            messages.append({ "role": "function", "name": "get_top_headline", "content": headlines})
        elif function_name == "get_zsxq_article":
            args = json.loads(response["function_call"]["arguments"])
            headlines = get_zsxq_article(query=args.get("query"))
            messages.append({ "role": "function", "name": "get_top_headline", "content": headlines})

最后,我们添加一个Run函数,循环接受我们的请求发送给GPT API

def run():
    print("n你好,我是你的小助手,你有什么问题都可以问我噢~")
    print("你可以这样问我:n - 告诉我最近有什么技术发现?n - 最近的体育有什么新闻n - 知识星球最近有什么精彩内容n")

    messages = []
    while True:
        prompt = input("n你想知道些什么? => ")
        messages.append({"role": "user", "content": prompt})
        complete(messages)

        # the LLM can chain function calls, this implements a limit
        call_count = 0
        while messages[-1]['role'] == "function":
            call_count = call_count + 1
            if call_count < function_call_limit:
                complete(messages)
            else:
                complete(messages, function_call="none")

            # print last message
            print("nn==Response==n")
            print(messages[-1]["content"].strip())
            print("n==End of response==")

最后,我们可以运行我们的程序进行测试了,要注意,运行这个python程序的电脑一定要在国外,另外一定要设置相应的key。国内的电脑无法调用GPT模型的API

python client.py

5.2 破局精华贴机器人

在前面,我们已经添加了查询新闻的功能了,在这里,我们再加个简单的功能。让GPT模型帮我们查找知识星球的精华贴。

在前面我们应该都已经知道了,增加函数,我们需要添加一个函数描述,在这里我们只需要在原来的代码基础上添加即可

signature_get_zsxq_article = {
    "name": "get_zsxq_article",
    "description": "获取破局俱乐部知识星球的精华贴",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "自由输入关键词或短语进行搜索。",
                "enum": ["digests","all"]
            },
        },
        "required": [],
    }
}

然后,我们再实现我们的get_zsxq_article接口,获取星球的精华文章

def get_zsxq_article(query: str = None):
    url = "https://api.zsxq.com/v2/groups/15552545485212/topics?scope=" + query +"&count=20"

    payload={}
    headers = {
    'cookie': zsxq_cookie
    }
    response = requests.request("GET", url, headers=headers, data=payload)
    data = response.json()
    article=[]
    if data['succeeded'] != True:
        return "No article Found"
    if data['resp_data'] is None:
        return "No article Found"
    for item in data['resp_data']['topics']:
        if "talk" not in item or "text" not in item["talk"]:
            continue
        if  "article" not in item["talk"] or "article_url" not in item["talk"]["article"]:
            continue
        article.append({"text": item["talk"]["text"], "url": item["talk"]["article"]["article_url"]})
    return json.dumps(article)

在这里,我们还有个关键点,要设置get_zsxq_article的cookie,这个步骤也很简单,我们下载一个谷歌浏览器,然后打开知识星球的网页版本,按F12

在弹出右侧的框后,我们在刷新下知识星球的网页,然后按照红框中的指示,找到cookie即可。

在获取cookie,填充到我们的代码后,我们可以运行,看看效果

到这里,我们的实战演示就结束了。

那么,学会了function call,我们还有哪些东西可以做呢?

比如说,做一个知识星球内容搜索机器人?

发挥你们的想象力吧!

  • 58
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: tencent-ailab-embedding-zh-d200的加载速度慢可能是由多种因素造成的。 首先,加载速度慢可能是因为模型文件较大,导致加载过程需要花费较长的时间。如果网络连接较慢,下载模型文件的速度也会变慢。 其次,加载速度慢可能是因为硬件设备的性能较低,无法快速处理大型模型文件。特别是对于没有GPU支持的设备,模型加载速度会相对较慢。 此外,加载速度慢还可能与软件版本兼容性问题有关。如果使用的是较旧的软件版本,可能与模型文件不适配,导致加载速度下降。 解决这个问题的方法有几种。首先,可以尝试使用更快的网络连接,提高下载速度。其次,可以考虑升级硬件设备,使用高性能的设备来加载模型文件。同时,也可以更新软件版本,确保与模型文件兼容,提高加载速度。 总之,解决tencent-ailab-embedding-zh-d200加载速度慢的问题,需要从网络连接、硬件设备以及软件版本等多个方面进行综合优化。 ### 回答2: tencent-ailab-embedding-zh-d200是一个用于中文文本表示的预训练模型。如果加载速度慢,可能有以下几个原因: 1. 网络问题:加载预训练模型需要从远程服务器下载模型文件,如果网络连接速度较慢或不稳定,下载过程会变得很慢。可以尝试连接更稳定的网络或更换网络环境来提高加载速度。 2. 硬件性能限制:加载大型模型需要消耗大量的计算资源,如CPU、内存和硬盘。如果计算设备的性能较低,加载速度可能会受到限制。可以尝试使用更高性能的计算设备,如云服务器或GPU加速,来加快加载速度。 3. 缓存问题:加载预训练模型的过程中,一般会将模型文件缓存到本地,以便下次加载时更快。如果缓存文件已经存在,加载速度应该会更快。可以检查本地缓存是否存在或者尝试清除缓存,然后重新加载模型。 4. 模型大小:tencent-ailab-embedding-zh-d200是一个200维的模型,相对来说较大。如果计算设备的存储空间较小,加载速度可能会减慢。可以尝试在更大的存储空间上加载模型,或者选择其他维度较小的模型,以提高加载速度。 总之,加载速度慢可能是由于网络问题、硬件性能限制、缓存问题或模型大小等因素导致的。可以根据具体情况采取相应的优化措施来提高加载速度。 ### 回答3: Tencent-AILab-Embedding-ZH-D200是一个中文词向量模型,用于将中文词语转化为固定长度的向量表示。根据问题描述,它的加载速度较慢可能是由于以下几个原因所导致的。 首先,模型的大小可能较大,导致加载速度变慢。如果模型文件非常大,加载过程会耗费更多的时间。解决该问题的一个方法是使用更快的存储介质,例如SSD硬盘,以加快加载速度。 其次,在加载模型之前,可能需要进行一些预处理步骤,例如初始化依赖库、加载词典等。如果这些预处理步骤耗时较长,那么整个加载过程也会相应变慢。对于此类问题,可以尝试优化预处理步骤,减少不必要的计算和IO操作,以提高加载速度。 此外,加载模型时的硬件配置也可能对加载速度产生影响。如果使用的是较低配置的计算机或服务器,那么加载速度可能会受到限制。在这种情况下,升级硬件设备或增加计算资源可以提高加载速度。 最后,网络连接的速度也会影响加载速度。如果您是通过云端服务加载模型,则需要确保网络连接稳定且速度较快。如果网络连接存在问题,可以尝试使用其他网络连接进行加载。 综上所述,要提高Tencent-AILab-Embedding-ZH-D200加载速度,可以考虑使用更快的存储介质、优化预处理步骤、升级硬件设备、改善网络连接等方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值