【OpenAI】ChatGPT Function Calling Practice | JD Cloud Technical Team

On June 13, OpenAI added a new function calling (Function Calling) capability to the Chat Completions API to help developers implement data interaction capabilities similar to the ChatGPT plug-in through the API.

Based on the author's previous article " Private Framework Code Generation Practice ", this article still uses natural language low-code construction scenarios as a case, and replaces the method of embedding vector search (Embedding) to obtain private knowledge bases with function calls. We are more familiar with structured data structures and relational databases for knowledge base management. At the same time, the flexibility and scalability of the function call capability can also help users use natural language to build more complex page content and perform richer interactive operations.

1. What is a function call

Function Calling is a new capability released by OpenAI on June 13. According to the official blog description, the function call capability allows the model to output a message requesting to call a function, which contains the function information to be called and the parameter information carried when calling the function. This is a new way of connecting GPT capabilities with external tools/APIs.

The new model that supports function calls can judge when and which functions need to be called according to the user's input, and can generate request parameters that meet the requirements according to the description of the target function.

Developers can use the function call capability to implement through GPT:

  • When communicating in natural language, answer questions by calling external tools (similar to ChatGPT plugins);
  • Convert natural language into parameters used when calling the API, or conditions used when querying the database;
  • Extract structured data from text. wait

2. How to use function calls

The function call capability can be used through Chat API (Chat Completion). In order to realize the function call capability, OpenAI has modified the chat API, adding new request parameters, response types, and message roles. Application developers need to:

  1. Pass information to the chat API in the request parameters, describing the information of the callable functions provided by the application.
  2. Analyze the message type of the chat API response. If the model determines that a function needs to be called, then call the function according to the function information returned by the model and the function parameters, and obtain the returned result.
  3. Add the result returned by the function to the message list and call the chat API again.

1. Add request parameters to describe the supported function information

Two new request body parameters have been added to the chat API:

functions

A list of functions that the current application can call. The function information includes the name of the function, a natural language description, and the parameter information supported by the function.

functionsThe format of the parameters is as follows:

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']
      }
    },
    // ...
  ]
})




functionsThe parameter supports entering multiple groups of function information in the form of an array, among which:

  • name: Function name. Subsequent models will return this name when they need to call the function.

  • description: function description. The model understands the capability of the function through this description, and judges whether it needs to call the function.

  • parameters.properties: The parameters required by the function. Describe the parameters required by the function in the form of objects, where the key of the object is the parameter name.

    • type:Parameter Type. Support JSON Schema protocol.
    • description:Parameter Description.
  • required: A list of parameter names for required parameters.

function_call

Controls how the model should respond to function transpositions. Several inputs are supported:

  1. "none": The model does not call the function, but directly returns the content. Default value when no callable is provided.
  2. "auto": The model makes its own decision on whether to call a function and which function to call based on user input. Default value when a callable is provided.
  3. {"name": "function_name"}: Forces the model to call the specified function.

2. Identify the response parameters and describe the function information that needs to be called

choicesThe chat API provides two response parameters in the optional ( ) of the response content :

finish_reason

The reason for the end of the response content.

Possible causes include:

  • stop: Complete message returned.
  • lengthmax_tokens: The token limit or cap set by a parameter has been reached .
  • function_call: The model decides that a function needs to be called.
  • content_filter: The content triggers the blocking policy, and the returned content is ignored.
  • null: The API response is still being executed.

Among them, if it returns function_call, it means that the model needs to call the function. At this time, messagethe parameter will additionally return function information and function parameter information.

message.function_call

If the reason for the end of the response content is that the model needs to call a function, messagea parameter describing the function information will be added to the parameter function_call, and its format is as follows:

  • name: Function name.
  • arguments: Function parameter information. JSON string format.

3. Add dialogue role, add function return value to message list

After the function is executed, the returned content of the function can be appended to the message list, and carry the complete message list to request the chat API again to obtain the subsequent response of GPT.

In the message list, in addition to the original system ( system), user ( user), and assistant ( assistant), the optional value of the role is a new type of function ( function), which is used to identify the return content of the function call when the message is issued.

Note: Before adding the function call response message to the message list, you need to add the message returned by the model in the previous step to the message list to ensure the integrity of the context in the message list.

full usage code

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
    }
  }
}




3. Low-code natural language construction case

In the author's previous article, the "retrieval-question solution" provided by embedded vector search was used for low-code private protocol access. In this article, function calls will be used instead.

At the same time, based on the ability to call functions, some more complex page building capabilities and low-code platform functions have also been explored.

1. Private protocol access

Based on our low-code platform private protocol, when building CMS type pages, we divide the knowledge of the protocol into several levels, and provide functions for GPT to call on demand to realize access to private protocols.

System description information

const systemPropmpt = `使用CCMS协议编写页面的配置信息。

                       CCMS协议所支持的页面类型包括:
                       - *form*:表单页
                       - *table*:表格页
                       - *detail*:详情页`;




Function information description

const functionsPrompt = [
  {
    name: 'get_elements',
    description: '获取CCMS协议在指定页面类型下,所支持的元素类型。',
    parameters: {
      type: 'object',
      properties: {
        page: {
          type: 'array',
          description: '页面类型',
          items: { type: 'string' }
        }
      }
    },
    required: ['page']
  },
  {
    name: 'get_features',
    description: '获取CCMS协议在指定元素类型下,所支持的配置化特性。',
    parameters: {
      type: 'object',
      properties: {
        element: {
          type: 'array',
          description: '元素类型',
          items: { type: 'string' }
        }
      }
    },
    required: ['element']
  },
  {
    name: 'get_descriptions',
    description: '获取CCMS协议下,指定页面类型、元素类型以及配置化特性的详细信息。',
    parameters: {
      type: 'object',
      properties: {
        page: {
          type: 'array',
          description: '页面类型',
          items: { type: 'string' }
        },
        element: {
          type: 'array',
          description: '元素类型',
          items: { type: 'string' }
        },
        feature: {
          type: 'array',
          description: '配置化特性',
          items: { type: 'string' }
        }
      }
    }
  }
]




Remarks: Although the GPT model supports cyclic calls of functions, in order to reduce the frequency of API calls and save Token consumption, we recommend that in the function of querying private protocol information, batch queries are performed in the form of keyword arrays.

function content

const functionsCalls = {
  get_elements: (args: { page: string[] }) => {
    const { page } = args;
    // 请自行实现信息查询,下列返回内容仅为示例。
    return page.map((pageType) => {
      switch (pageType) {
        case 'form':
          return `# **form**表单页所支持的元素类型包括:

                  - *form_text*:文本输入框
                  - *form_number*: 数值输入框`;
        default:
          return `# **${pageType}**没有支持的元素。`
      }
    }).join("\n\n");
  },
  get_features: (args: { element: string[] }) => {
    const { element } = args
    // 请自行实现信息查询,下列返回内容仅为示例。
    return element.map((elementKey) => {
      const [ pageType, elementType ] = elementKey.split('_');
      switch (pageType) {
        case 'form':
          switch (elementType) {
            case 'text':
              return `# **form_text**(文本输入框)所支持的配置化特性包括:

                      - *form_text_maxLength*: 文本最大长度限制
                      - *form_text_minLength*: 文本最小长度限制
                      - *form_text_regExp*: 文本正则表达式校验`
            default:
              return `# **${elementKey}**没有支持的配置化特性。`
          }
        default:
          return `# **${elementKey}**没有支持的配置化特性。`
      }
    }).join("\n\n");
  },
  get_descriptions: (args: { page: string[], element: string[], feature: string[] }) => {
    const {
      page = [],
      element = [],
      feature = []
    } = args
    // 请自行实现信息查询,下列返回内容仅为示例。
    return [
      ...page.map((pageType) => `# **${pageType}**的详细描述如下:...`),
      ...element.map((elementType) => `# **${elementType}**的详细描述如下:...`),
      ...feature.map((featureType) => `# **${featureType}**的详细描述如下:...`)
    ].join("\n\n")
  }
}




call example

A list of messages for a complete call:

For readability, the indentation of the message content in the message list has been adjusted, and the JSON string representing the parameter of the function call has been parsed into an object form.

[
  // 第一次请求聊天API
  { role: 'system', 
    content: `使用CCMS协议编写页面的配置信息。
              
              CCMS协议所支持的页面类型包括:
              - *form*: 表单页
              - *table*: 表格页
              - *detail*: 详情页` },
  { role: 'user',
    content: '创建一个课程报名页面' },
  { role: 'assistant',
    content: null,
    function_call: { name: 'get_elements',
                     arguments: { page: ["form"] } } },

  // 第二次请求聊天API
  { role: 'function',
    name: 'get_elements',
    content: `# **form**表单页所支持的元素类型包括:

              - *form_text*:文本输入框
              - *form_number*: 数值输入框` },
  { role: 'assistant',
    content: null,
    function_call: { name: 'get_features',
                     arguments: { element: ["form_text", "form_number"] } } },

  // 第三次请求聊天API
  { role: 'function',
    name: 'get_features',
    content: `# **form_text**(文本输入框)所支持的配置化特性包括:

              - *form_text_maxLength*: 文本最大长度限制
              - *form_text_minLength*: 文本最小长度限制
              - *form_text_regExp*: 文本正则表达式校验
              
              # **form_number**没有支持的配置化特性。` },
  { role: 'assistant',
    content: null,
    function_call: { name: 'get_descriptions',
                     arguments: { page: ["form"],
                                  element: ["form_text", "form_number"],
                                  feature: ["form_text_maxLength", "form_text_minLength", "form_text_regExp"] } } },

  // 第四次请求聊天API
  { role: 'function',
    name: 'get_descriptions',
    content: `# **form**的详细描述如下:...
              
              # **form_text**的详细描述如下:...
              
              # **form_number**的详细描述如下:...
              
              # **form_text_maxLength**的详细描述如下:...
              
              # **form_text_minLength**的详细描述如下:...
              
              # **form_text_regExp**的详细描述如下:...` },
  { role: 'assistant',
    content: '课程报名页面的配置信息如下:\n\n...' }
]




2. Expanded page building capabilities: page context jump scene

When building a low-code page, it is sometimes necessary to add some contextual information to the page configuration.

For example, you need to add a button to the page, and when the user clicks the button, it jumps to another page. At this point we can pass a function that allows the model to get a list of related pages.

Protocol content such as buttons and jump operations can be obtained through the method in the previous chapter:

## button
 
按钮。

支持的配置项包括:

- *label*:按钮标签
- *action*:操作类型,支持:
  - *none*:无操作
  - *redirect*:页面重定向
- *redirectTo*:页面标识




Function information description

const functionsPrompt = [
  // ...
  {
    name: 'get_page_id',
    description: '查询页面标识列表。其中包含页面标识(`id`)、页面名称(`name`)',
    parameters: {
      type: 'object',
      properties: {
        page: {
          type: 'string',
          description: '页面'
        }
      }
    }
  }
]




function content

const functionsCalls = {
  // ...
  get_page_id: (args: {}) => {
    // 请自行实现信息查询,下列返回内容仅为示例。
    return JSON.stringify([
      {
        id: 'page_list',
        name: '列表页'
      },
      {
        id: 'page_create',
        name: '新增页',
        description: '用于新增内容'
      },
      {
        id: 'page_preview',
        name: '预览页'
      }
    ])
  }
}




call example

A list of messages for a complete call:

For ease of reading, the indentation of the message content in the message list has been adjusted, and the configuration information returned by GPT and the JSON string representing the function call parameters have been parsed into an object form.

[
  // 已省略系统角色信息以及私有协议访问信息。
  // ...
  { role: 'user',
    content: '添加一个预览按钮,点击后跳转至预览页。'
  },
  // ...
  { role: 'assistant',
    content: { type: "button",
               label: "预览",
               action: "redirect",
               redirectTo: "preview" },
    function_call: { name: 'get_page_id',
                     arguments: { page: "preview" } } },
  { role: 'function',
    name: 'get_page_id',
    content: [ { id: "page_list", name: "列表页" },
               { id: "page_create", name: "新增页" },
               { id: "page_preview", name: "预览页"} ] },
  { role: 'assistant',
    content: { type: "button",
               label: "预览",
               action: "redirect",
               redirectTo: "page_preview" }
]




3. Capability expansion of the low-code platform: Adjust the visible area of ​​the building window

When building natural language low-code, we want the visible area of ​​the building window to automatically scroll to the changed area. At this time, we can call the page scrolling method when the page configuration is changed through the system role requirement, and automatically scroll to the configuration change. element position.

System description information

Add the relevant description in the system description information:

const systemPropmpt = `//...

                       每次对页面内容进行调整时,需要滚动页面至目标元素位置。
                       
                       CCMS页面配置信息为一个数组,每个页面元素为数组中的一项,如:

                       ```json
                       [
                         {
                           "id": "input",
                           "type": "text",
                           "label": "文本输入框"
                         }
                       ]
                       ```
                       
                       // ...
                       `;




Function information description

const functionsPrompt = [
  // ...
  {
    name: 'scroll_to',
    description: '滚动页面至指定元素位置',
    parameters: {
      type: 'object',
      properties: {
        element_id: {
          type: 'string',
          description: '指定元素ID'
        }
      }
    }
  }
]




function content

const functionsCalls = {
  // ...
  scroll_id: (args: { element_id: string }) => {
    const { element_id } = args
    // 自行实现页面滚动逻辑
    return '滚动完成'
  }
}




4. Summary

The function call function provided by OpenAI provides richer possibilities for applications using GPT capabilities. Application developers can call functions through functions, allowing users to interact with natural language, obtain real-time data, structured data, and also perform various interactions with applications. The several case scenarios described in this article are just for starters. You are welcome to discuss more and try more application scenarios.

Author: JD Retail Niu Xiaoguang

Source: JD Cloud Developer Community

Graduates of the National People’s University stole the information of all students in the school to build a beauty scoring website, and have been criminally detained. The new Windows version of QQ based on the NT architecture is officially released. The United States will restrict China’s use of Amazon, Microsoft and other cloud services that provide training AI models . Open source projects announced to stop function development LeaferJS , the highest-paid technical position in 2023, released: Visual Studio Code 1.80, an open source and powerful 2D graphics library , supports terminal image functions . The number of Threads registrations has exceeded 30 million. "Change" deepin adopts Asahi Linux to adapt to Apple M1 database ranking in July: Oracle surges, opening up the score again
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4090830/blog/10086510