【ChatGPT】之 函数调用:打破界限,开创未来

ChatGPT 函数调用:解锁自然语言搭建新维度,打破低代码平台创作局限!

在本文中,展示如何将嵌入向量搜索方式获取私有知识库的方式替换为函数调用方式。同时,我们将结合结构化数据和关系型数据库,以更熟悉的方式进行知识库管理,实现更灵活、可扩展的功能。以下是文章的内容:

一、函数调用简介

函数调用是 OpenAI 在 6 月 13 日发布的新能力,允许模型输出一个请求调用函数的消息,包含所需调用的函数信息和参数信息。这为将 GPT 能力与外部工具/API 连接提供了新的方式。支持函数调用的模型可以根据用户输入自行判断何时需要调用哪些函数,并生成符合要求的请求参数。

开发人员可以使用函数调用能力,通过 GPT 实现:

  • 在进行自然语言交流时,通过调用外部工具回答问题(类似于 ChatGPT 插件);
  • 将自然语言转换为调用 API 时使用的参数,或者查询数据库时使用的条件;
  • 从文本中提取结构化数据。等

二、如何使用函数调用

函数调用能力可以通过聊天 API(Chat Completion)实现。为了使用函数调用能力,应用开发者需要在请求参数中描述可调用函数的信息,并解析响应中的函数信息以及函数参数信息。以下是使用函数调用的步骤:

1. 添加请求参数,描述支持的函数信息
openai.createChatCompletion({
  model: "gpt-3.5-turbo-0613",
  messages: [
    // 用户和助理的对话历史
  ],
  functions: [
    {
      name: 'function_name',
      description: '函数功能的自然语言描述',
      parameters: {
        type: 'object',
        properties: {
          argument_name: {
            type: 'string',
            description: '该参数的自然语言描述'
          },
          // ...
        },
        required: ['argument_name']
      }
    },
    // ...
  ]
})

functions 参数支持以数组形式录入多组函数信息,其中:

  • name:函数名称。后续模型会在需要调用函数时返回此名称。

  • description:函数功能描述。模型通过该描述理解函数能力,并判断是否需要调用该函数。

  • parameters.properties:函数所需的参数。以对象的形式描述函数所需的参数,其中对象的 key 即为参数名。

    • type:参数类型。支持 JSON Schema 协议。
    • description:参数描述。
  • required:必填参数的参数名列表。

function_call

控制模型应该如何响应函数调换。支持几种输入:

  1. "none":模型不调用函数,直接返回内容。没有提供可调用函数时的默认值。
  2. "auto":模型根据用户输入自行决定是否调用函数以及调用哪个函数。提供可调用函数时的默认值。
  3. {"name": "function_name"}:强制模型调用指定的函数。
2、识别响应参数, 描述需要调用的函数信息

聊天 API 在响应内容的可选项(choices)中提供了两个响应参数:

finish_reason响应内容结束的原因。

可能的原因包括:

  • stop:已返回完整消息。
  • length:已达到令牌限制或由 max_tokens 参数设置的上限。
  • function_call:模型决定需要调用一个函数。
  • content_filter:内容触发了拦截策略,忽略返回内容。
  • null:API 响应仍在执行。

其中,若返回 function_call 则表示模型需要调用函数。此时 message 参数会额外返回函数信息以及函数参数信息。

message.function_call

若响应内容结束的原因是模型需要调用函数,则 message 参数中会增加一个用于描述函数信息的 function_call 参数,其格式如下:

  • name:函数名称。
  • arguments:函数参数信息。JSON 字符串格式。
3、添加对话角色, 向消息列表中添加函数返回值

在函数执行完成后,将函数的返回内容追加到消息列表中,然后再次调用聊天 API,以获得 GPT 的后续响应。

在消息列表中,角色的可选值除了原有的系统system)、用户user)、助理assistant)外,新增了函数function)类型,用来标识该消息时函数调用的返回内容。

注意:向消息列表中追加函数调用响应消息前,还需要首先将上一步模型返回的消息追加到消息列表中,以保证消息列表中的上下文完整。

完整使用代码

const { Configuration, OpenAIApi } = require("openai");
const openai = new OpenAIApi(new Configuration({ /** OpenAI 配置 */ }));

/** 系统角色信息 **/
const systemPrompt: string = "系统角色prompt";

/** 支持函数信息 **/
const functionsPrompt: unknow[] = [
  {
    name: 'function_name',
    description: '函数功能的自然语言描述',
    parameters: {
      type: 'object',
      properties: {
        argument_name: {
          type: 'string',
          description: '该参数的自然语言描述'
        },
        // ...
      }
    }
  },
  // ...
];

/** 支持函数逻辑 **/
const functionsCalls: { [name: string]: Function } = {
  function_name: (args: { argument_name: string }) => {
    const { argument_name } = args;
    // ...
    return '函数调用结果'
  },
  // ...
}

/** 开始聊天 **/
const chat = async (userPrompt: string) => {
  const messages: unknow[] = [
    { role: 'system', content: systemPrompt },
    { role: 'user', content: userPrompt }
  ];
  
  let maxCall = 6;
  while (maxCall--) {
    const responseData = await openai.createChatCompletion({
      model: "gpt-3.5-turbo-0613",
      messages,
      functions,
      function_call: maxCall === 0 ? 'none' : 'auto'
    }).then((response) => response.data.choices[0]);
  
    const message = responseData.message
    messages.push(message)

    const finishReason = responseData.finish_reason
    if (finishReason === 'function_call') {
      const functionName = message.function_call.name
      const functionCall = functionCalls[functionName]
      const functionArguments = JSON.parse(message.function_call.arguments)
      const functionResponse = await functionCall(functionArguments)
      messages.push({
        role: 'function',
        name: functionName,
        content: functionResponse
      })
    } else {
      return message.content
    }
  }
}

在响应中,检查 finish_reason 是否为 “function_call”,若是,则解析 message.function_call 获取需要调用的函数信息和参数信息。代码如下:

const finishReason = responseData.finish_reason;

if (finishReason === 'function_call') {
  const functionName = message.function_call.name;
  const functionCall = functionCalls[functionName];
  const functionArguments = JSON.parse(message.function_call.arguments);
  const functionResponse = await functionCall(functionArguments);

  messages.push({
    role: 'function',
    name: functionName,
    content: functionResponse
  });
} else {
  // 处理其他情况
}

三、总结

通过函数调用的能力,我们在自然语言低代码搭建场景中实现了更灵活的知识库管理和更复杂的页面内容搭建。函数调用使得用户能够以更自然的语言方式与应用进行交互,获取实时数据和结构化数据。这一功能为应用的交互性和可扩展性带来了新的可能性,拓宽了自然语言处理在低代码平台中的应用领域。

你可能感兴趣的:(AI,大模型,chatgpt)