Using OpenAI GPT-4 Function Calling for NER

Introduction to OpenAI’s Function calling

As an NLP engineer or practitioner you must have faced the challenge of handling varying output formats when working on information extraction tasks with models like ChatGPT and other LLMs.

These inconsistencies can lead to time-consuming workarounds and hamper the efficiency of your projects.

To address this issue, OpenAI has introduced the “Function Calling” feature that helps in generating responses in consistent format.

To demonstrate the capabilities of Function Calling, I will use the example of a major NLP task called named entity recognition (NER).

openai gpt-4 function calling

Source: https://openai.com/

Brief overview of Named Entity Recognition (NER)

Named Entity Recognition is a Natural Language Processing (NLP) technique that aims to identify and classify important elements, or “entities,” within a given text. These entities usually represent real-world objects, such as people, places, organizations, dates, and more.

In simpler terms, NER helps computers understand the context and meaning of text by pinpointing specific entities and categorizing them based on their type.

For example, given the below sentence:

“Elon Musk is the CEO of Tesla, and the company is based in California.”

An NER model would identify the following entities and their respective categories:

  • Elon Musk (Person)
  • Tesla (Organization)
  • California (Location)

By recognizing and classifying these entities, NER enables us to extract valuable information from unstructured text and utilize it in various applications, such as information retrieval, sentiment analysis, content recommendations, and more.

In this tutorial, we will use the OpenAI API to access the GPT Function Calling feature to extract named entities in a consistent and structured format.

How to use OpenAI API with Python?

First of all you must have access to an OpenAI API key. I am assuming you already have your API key. Now install the openai Python library to get started. I have used Google Colab for this tutorial, but you can use your own system as well.

!pip install openai

Import openai and json libraries and specify your API key.

import openai
import json

# load and set OpenAI API key
openai.api_key = "Enter Your API Key"

Now consider the following example, where the OpenAI API is being used to access the GPT-4 model by passing a prompt.

Prompt – “Generate 5 blog topics on ice cream”

response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Generate 5 blog topics on ice cream"}],
)

The object ‘response’ contains the output sent back by the GPT-4 model with respect to the query – “Generate 5 blog topics on ice cream”.

Let’s print the model’s output.

# model's response
print(response['choices'][0]['message']['content'])

Output:

1. "Exploring the Fascinating History of Ice Cream"
2. "The Science Behind Making Perfectly Creamy Ice Cream"
3. "Luxurious Ice Cream Flavors Around the World: A Taste Adventure"
4. "Creating Delicious Vegan & Dairy-free Ice Cream at Home"
5. "How the Artisanal Ice Cream Market is Revolutionizing Dessert Trends"

So, this is pretty much how we have to use the OpenAI API to get responses from the GPT models.

Perform NER using GPT-4 Function calling

Now let’s use the Function calling capability of OpenAI to extract structured data from a text passage. This structured data will be a list of dictionaries (key-value pairs), each containg a named entity as key and its category as value.

Input Text for NER

Given below is an example text passage that we will use for the task of NER. It has been taken up from Wikipedia. Feel free to use any text of your choice.

input_text = """
The members of the Council of Denmark seem to have developed from being councillors of the king to being representatives of the magnates 
and noblemen. From the 1320s it clearly appears as a force, and from the 1440s it was the permanent opponent of royal power, replacing the 
Danehof.

The Council consisted of noblemen who were appointed either by the king or their peers on the council. Until the 1536 Reformation, bishops 
were automatically members. So were the supreme officials (today the "cabinet ministers") while lower ranking "ministers" did not have any 
formal right to membership. The "backbenchers" of the council took part in daily negotiations of problems and administration, voted, and took 
on diplomatic tasks. Most of them were squires who also had to look after their lands.

As a whole, it was the role of the council to rule together with the king, to control him, and to manage the affairs of State well. The 
councillors were seen as a guarantee towards the nobility (and in theory also towards "the people") that everything was done right. The 
Council took over the rule in the space that appeared by a succession or at interregna. It led negotiations over the creation of a new 
haandfæstning, and in theory it also had to call for a rebellion against kings who did not keep their promises, a right that was used in 1523. 
However, in the 16th century, it was not quite unusual that the councillors to some degree identified with the State rejecting too extravagant 
demands from the Danish gentry. The background of this normally was that they themselves represented the Danish answer to the peerage.
"""

Define the structure for GPT4 Function calling

As you can see below, we have defined the structure of the function that will be used in Function calling along with the GPT-4 model.

The name of the function is “find_ner” and its description is “Extracts named entities and their categories from the input text.”

Adding description is quite important here. It tells the GPT-4 model what your function is supposed to do or what is the objective of this function.

The “parameters” field contains the format of the output that we want GPT-4 to follow while generating its response.

ner_gpt_function = [
        {
            "name": "find_ner",
            "description": "Extracts named entities and their categories from the input text.",
            "parameters": {
                "type": "object",
                "properties": {
                    "entities": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "entity":{"type": "string", 
                                          "description": "A Named entity extracted from text."},
                                "catrgory":{"type": "string", 
                                            "description": "Category of the named entity."}
                            }                            
                          }
                        }
                    }
                },
                "required": ["entities"]
            }
        ]

The output as per this function will be a nested dictionary or a JSON object with ‘entities’ as a key and a list of entity-category pairs as values.

Extracting named entities using OpenAI Function calling

Now we will pass the input text passage and the function defined in the previous section to extract the named entities in the desired format.

# NER detection using GPT-4
response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[{"role": "user", "content": input_text}],
        functions=ner_gpt_function,
        function_call={"name": "find_ner"},
)

Let’s print the output of GPT-4 model.

# model's response
print(response['choices'][0]['message']['function_call']['arguments'])

Output:

{
  "entities": [
    {
      "entity": "Council of Denmark",
      "catrgory": "ORGANIZATION"
    },
    {
      "entity": "the king",
      "catrgory": "TITLE"
    },
    {
      "entity": "magnates",
      "catrgory": "TITLE"
    },
    {
      "entity": "noblemen",
      "catrgory": "TITLE"
    },
    {
      "entity": "Danehof",
      "catrgory": "ORGANIZATION"
    },
    {
      "entity": "the 1320s",
      "catrgory": "DATE"
    },
    {
      "entity": "the 1440s",
      "catrgory": "DATE"
    },
    {
      "entity": "the 1536 Reformation",
      "catrgory": "EVENT"
    },
    {
      "entity": "bishops",
      "catrgory": "TITLE"
    },
    {
      "entity": "the supreme officials",
      "catrgory": "TITLE"
    },
    {
      "entity": "cabinet ministers",
      "catrgory": "TITLE"
    },
    {
      "entity": "ministers",
      "catrgory": "TITLE"
    },
    {
      "entity": "backbenchers",
      "catrgory": "TITLE"
    },
    {
      "entity": "squires",
      "catrgory": "TITLE"
    },
    {
      "entity": "nobility",
      "catrgory": "TITLE"
    },
    {
      "entity": "the people",
      "catrgory": "GROUP"
    },
    {
      "entity": "haandfæstning",
      "catrgory": "OTHER"
    },
    {
      "entity": "1523",
      "catrgory": "DATE"
    },
    {
      "entity": "the 16th century",
      "catrgory": "DATE"
    },
    {
      "entity": "the Danish gentry",
      "catrgory": "GROUP"
    },
    {
      "entity": "the Danish answer to the peerage",
      "catrgory": "GROUP"
    }
  ]
}

As you can see, the GPT-4 model has returned a structured list of entities and their categories. Even if you change the input text, you would still get the output in the same format.

This consistency in output generation is a big development in the field of large language models and NLP as it will facilitate integration of state-of-the-art AI with a wide range of applications.

Key Takeaways

  • OpenAI API’s feature “Function calling” can address output format inconsistencies in large language models.
  • Learn to perform Named Entity Recognition (NER) efficiently with consistent output using this feature.
  • Create custom output formats and seamlessly integrate NER results with other applications or APIs.

There are many other natural language tasks, such as sentiment analysis, question generation, relationship extraction and many more, where we can get the output generated in a fixed and consistent format with the help of the OpenAI Function calling.


Leave a Reply

Your email address will not be published. Required fields are marked *