Introduction

For typical LLM interactions, a single prompt or a few rounds of chat are sufficient to achieve the desired result. However, some tasks require the LLM to access information beyond its internal knowledge base. For example, retrieving today’s weather information for a specific city or searching for a particular anime necessitates calling external functions.

What is Function Calling?

Function calling in LLMs empowers the models to generate JSON objects that trigger external functions within your code. This capability enables LLMs to connect with external tools and APIs, expanding their ability to perform diverse tasks.

Function Calling Execution Steps

  1. User calls LLM API with tools and a user prompt:

The user provides a prompt and specifies the available tools.

What is the weather like in San Francisco?

Define Tool Schema

tools = [
    {
        "type": "function",
        "function": {
            "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"],
            },
        },   
    }
]

Define Dummy Function

# Example function hard coded to return the same weather
def get_current_weather(location, unit="fahrenheit"):
    """Get the current weather in a given location"""
    if "tokyo" in location.lower():
        return json.dumps({"location": "Tokyo", "temperature": "10", "unit": unit})
    elif "san francisco" in location.lower():
        return json.dumps({"location": "San Francisco", "temperature": "72", "unit": unit})
    elif "paris" in location.lower():
        return json.dumps({"location": "Paris", "temperature": "22", "unit": unit})
    else:
        return json.dumps({"location": location, "temperature": "unknown"})
  1. LLM chooses tools

The LLM analyzes the prompt and available tools, then selects the appropriate tool to fulfill the request.

Create ChatCompletion with Tools

def get_completion(messages, model="gpt-4-turbo", temperature=0, max_tokens=300, tools=None):
    response = openai.chat.completions.create(
        model=model,
        messages=messages,
        temperature=temperature,
        max_tokens=max_tokens,
        tools=tools
    )
    return response.choices[0].message

Response with tools

ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='...', function=Function(arguments='{"location":"London","unit":"celsius"}', name='get_current_weather'), type='function')])
  1. Run code of chosen tools and return results

The selected tool’s code is executed on client side, and the results are returned to the LLM.

  1. LLM combines prompt and results, and returns final response

The LLM incorporates the retrieved information with the initial prompt to generate a comprehensive and informative final response.

An Example: Searching for Anime

Python Code

import json
import os
import pprint

import httpx
from openai import AzureOpenAI


def search_anime(keyword: str) -> str:
    url = "https://api.bgm.tv/v0/search/subjects"
    querystring = {"limit": "3"}
    payload = {
        "keyword": keyword,
        "filter": {
            "type": [2],
            "rating": [">=7"],
            "nsfw": False
        }
    }
    headers = {
        "Content-Type": "application/json"
    }
    with httpx.Client() as client:
        response = client.request("POST", url, json=payload, headers=headers, params=querystring)

        return response.text


client = AzureOpenAI(
    azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
    api_key=os.getenv("AZURE_OPENAI_API_KEY"),
    api_version="2024-03-01-preview"
)


def run_conversation(query: str):
    # Step 1: send the conversation and available functions to the model
    messages = [{"role": "user",
                 "content": query,
                 }]
    tools = [
        {
            "type": "function",
            "function": {
                "name": "search_anime",
                "description": "Search for an anime using the Bangumi API",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "keyword": {
                            "type": "string",
                            "description": "The keyword to search for, e.g. '攻殻機動隊' or 'EVA'",
                        },
                    },
                    "required": ["keyword"],
                },
            },
        }
    ]
    response = client.chat.completions.create(
        model=MODEL_DEPLOYMENT_NAME,
        messages=messages,
        tools=tools,
        tool_choice="auto",  # auto is default, but we'll be explicit
    )
    response_message = response.choices[0].message
    tool_calls = response_message.tool_calls
    print("------First Response------")
    pprint.pprint(response_message)

    # Step 2: check if the model wanted to call a function
    if tool_calls:
        # Step 3: call the function
        # Note: the JSON response may not always be valid; be sure to handle errors
        available_functions = {
            "search_anime": search_anime,
        }  # only one function in this example, but you can have multiple
        messages.append(response_message)  # extend conversation with assistant's reply
        # Step 4: send the info for each function call and function response to the model
        for tool_call in tool_calls:
            function_name = tool_call.function.name
            function_to_call = available_functions[function_name]
            function_args = json.loads(tool_call.function.arguments)
            function_response = function_to_call(
                keyword=function_args.get("keyword"),
            )
            messages.append(
                {
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": function_name,
                    "content": function_response,
                }
            )  # extend conversation with function response

        print("------Call Tool Messages------")
        pprint.pprint(messages)

        second_response = client.chat.completions.create(
            model=MODEL_DEPLOYMENT_NAME,
            messages=messages,
        )  # get a new response from the model where it can see the function response
        return second_response


if __name__ == "__main__":
    MODEL_DEPLOYMENT_NAME = "gpt-4"
    anime = "EVA"
    resp = run_conversation(
        f"Search for the anime and summarize its story, tags, ratings, etc. Use English.: {anime=}"
    )
    print("------Second Response------")
    pprint.pprint(resp)
    print("------Content------")
    print(resp.choices[0].message.content)

Internal Message Structure

------First Response------
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_E1s6hI3fsPNyaJH0pJfFnYmD', function=Function(arguments='{"keyword": "EVA"}', name='search_anime'), type='function')])
------Call Tool Messages------
[{'content': 'Search for the anime and summarize its story, tags, ratings, '
             "etc. Use English.: anime='EVA'",
  'role': 'user'},
 ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_E1s6hI3fsPNyaJH0pJfFnYmD', function=Function(arguments='{"keyword": "EVA"}', name='search_anime'), type='function')]),
 {'content': '{"data":[{"date":"1995-10-04","image":"https://lain.bgm.tv/pic/cover/l/e5/69/265_Z5Uou.jpg","type":2,"summary":"\u3000\u3000'
             '2000年,一个科学探险队在南极洲针对被称作“第一使徒”亚当的“光之巨人”进行探险。在对其进行接触实验时,“光之巨人”自毁,从而发生了“第二次冲击”,进而导致 世界大战。最后,人类人口减半,地轴偏转、气候改变。根据对“第二次冲击”的调查,联合国在日本箱根成立人工进化研究所(即 '
             'GEHIRN)从事EVA(指机器人)的发展研究,后GEHIRN利用在人工进化研究所下方发现的巨大空洞建造了总部。\\r\\n\u3000\u3000'
             '另一方面,联合国下属秘密组织SEELE为了使人类进化,开始实行人类补完计划,就是将所有人的灵魂汇集在一起,通过中和每个人的AT力场,使每个人回归LCL之海。\\r\\n\u3000\u3000'
             '2004年,EVA初号机进行启动试验时发生事故,碇真嗣的母亲碇唯消失,碇源渡开始执行“碇源渡版本的人类补完计划”。2010年,GEHIRN被改建成NERV。\\r\\n\u3000\u3000'
             "2015年开始,根据SEELE人类补完计划剧本的安排,一种巨型人形生物“使徒”开始在日本登陆,并向NERV总部进攻,NERV组织EVA消灭使徒。在NERV与使徒作战的同时, 碇源渡秘密地执行它自己的计划。随着时间推移,碇源渡的计划逐渐被SEELE发现,NERV与SEELE产生了矛盾并不断恶化。\\r\\nDirector's "
             'Cut版本的第21~24集由剧场版《Death》篇剪辑而成,收录在20周年纪念版的蓝光中。","name":"新世紀エヴァンゲリオン","name_cn":"新世纪福音战士","tags":[{"
name":"EVA","count":7833},{"name":"庵野秀明","count":5809},{"name":"GAINAX","count":3751},{"name":"新世纪福音战士","count":3377},{"name":"神作","count":2847},{"n
ame":"科幻","count":2635},{"name":"宗教","count":1832},{"name":"TV","count":1778},{"name":"心理","count":1414},{"name":"1995","count":1157},{"name":"骗钱神棍片的
","count":1044},{"name":"原创","count":936},{"name":"补完","count":798},{"name":"凌波","count":703},{"name":"Evangelion","count":620},{"name":"圣经","count": :
353},{"name":"神棍","count":237},{"name":"1995年10月","count":206},{"name":"机战","count":181},{"name":"萝卜","count":180},{"name":"战斗","count":141},{"name":" 
经典","count":111},{"name":"意识流","count":106},{"name":"贞本义行","count":77},{"name":"明日香","count":62},{"name":"1995","count":53},{"name":"生命中的哀伤与
","count":53},{"name":"龙之子Production","count":50},{"name":"童年","count":47},{"name":"日本","count":43}],"score":8.8,"id":265,"rank":9},{"date":"","image" ":"","type":2,"summary":"半年前,早在为《EVA新剧场版》造势的时候,Bandai '
             '就公布了以Q版COLLECTION FIGURE开端,讲述发生在NERV学院中的一段段恩怨情仇的《DEFORMER '
             'EVA(デフォルメエヴァ)》FIGURE企划第一弹,EVA2007春季攻势-校园剧《ぷちえヴぁ EVANGELION @ '
             'SCHOOL》,并拍成了动画短篇。绫波三姐妹,红龙明日香,万年受真嗣,以及越熟越可爱的葛成美里姐姐,不,老师,还有身处黑暗中的学校不良少年王 '
             '“EVA长”(友情客串:初号机)。整套玩偶共分9套,包括8套公开版本和一个SECRET版本。","name":"EVA爆笑校园","name_cn":"","tags":[{"name":"EVA","count":5}
,{"name":"额","count":2},{"name":"Q版劇","count":1}],"score":7.3,"id":3387,"rank":0},{"date":"2012-11-17","image":"https://lain.bgm.tv/pic/cover/l/69/63/61290_9O
TjL.jpg","type":2,"summary":"近第3次冲击过后的第14年世界依然血红无数类似EVA01的生命徘徊在补完未完成的世界NERV分裂Wille的出现碇源堂和Seele的计划如约 
在行。《死海文书的预言也到了尽头新轮回的开始注定源于毁灭取出卡西乌斯枪朗基努斯枪”,解除14年来的处于莉莉丝周围的结界和封印成为命运的牵绊渚熏和碇 真嗣终将驾驶EVA13与生死离别……","name":"EVA '
             ':Q","name_cn":"新世纪福音战士剧场版:Q","tags":[],"score":7,"id":61290,"rank":0}],"total":17,"limit":3,"offset":0}\n',
  'name': 'search_anime',
  'role': 'tool',
  'tool_call_id': 'call_E1s6hI3fsPNyaJH0pJfFnYmD'}]
------Second Response------
ChatCompletion(id='chatcmpl-9LS1xyK6B9Q47bSZKzBjFftIsZk27', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='
### 1. Neon Genesis Evangelion (新世紀エヴァンゲリオン)\n\n- **Original Name:** 新世紀エヴァンゲリオン\n- **English Name:** Neon Genesis Evangelion\n- **Date Rel
eased:** 1995-10-04\n- **Type:** TV Series\n- **Summary:** In the year 2000, a scientific expedition in Antarctica exploring the "Giant of Light" known as "Adam"
 triggers the "Second Impact," leading to a devastating world war, climate change, and a halved human population. GEHIRN, which later becomes NERV, is establishe
d to develop Evangelions (EVA) to combat giant beings known as "Angels." The series follows the battles of the EVAs against the Angels, interwoven with complex t
hemes of religion, psychology, and human relationships.\n- **Tags:** EVA, Hideaki Anno, GAINAX, science fiction, religion, psychology, original, combat, classic,
 existential\n- **Score:** 8.8\n- **Rank:** 9\n- [Link to more information](https://lain.bgm.tv/pic/cover/l/e5/69/265_Z5Uou.jpg)\n\n### 2. EVA Laughing Schoolyar
d (EVA爆笑校园)\n\n- **Original Name:** EVA爆笑校园\n- **Date Released:** Unspecified\n- **Type:** Project\n- **Summary:** An initiative by Bandai ahead of "EVA 
New Theatre Edition," starting with Q-version COLLECTION FIGURE, it narrates the relationships and rivalries within the NERV Academy through animated shorts. It 
features a playful and cute take on the characters from the original Evangelion series.\n- **Tags:** EVA, Q-version drama\n- **Score:** 7.3\n\n### 3. EVA :Q (新 
世纪福音战士剧场版Q)\n\n- **Original Name:** EVA :Q\n- **English Name:** Neon Genesis Evangelion: Q\n- **Date Released:** 2012-11-17\n- **Type:** Film\n- **Sum
mary:** Set 14 years after the "nearly 3rd Impact," the world is still reeling from its incomplete state. With the splintering of NERV and the emergence of Wille
, the stage is set for the fulfillment of Gendo Ikari and Seele\'s plans, alongside the prophecies of the Dead Sea Scrolls. Shinji and Kaworu navigate a world on
 the brink of a new cycle, ultimately piloting EVA Unit-13 towards a fateful confrontation.\n- **Score:** 7.0\n\nPlease note that the details provided, especiall
y for the second entry "EVA Laughing Schoolyard," are rather limited, and the focus primarily lies on toy figures and a lighter, humorous take on the original Ev
angelion universe.', role='assistant', function_call=None, tool_calls=None), content_filter_results={'hate': {'filtered': False, 'severity': 'safe'}, 'self_harm'
: {'filtered': False, 'severity': 'safe'}, 'sexual': {'filtered': False, 'severity': 'safe'}, 'violence': {'filtered': False, 'severity': 'safe'}})], created=171
4899665, model='gpt-4', object='chat.completion', system_fingerprint='fp_2f57f81c11', usage=CompletionUsage(completion_tokens=621, prompt_tokens=1736, total_toke
ns=2357), prompt_filter_results=[{'prompt_index': 0, 'content_filter_results': {'hate': {'filtered': False, 'severity': 'safe'}, 'self_harm': {'filtered': False, 'severity': 'safe'}, 'sexual': {'filtered': False, 'severity': 'safe'}, 'violence': {'filtered': False, 'severity': 'safe'}}}])

Example Output

1. Neon Genesis Evangelion (新世紀エヴァンゲリオン)

  • Original Name: 新世紀エヴァンゲリオン
  • English Name: Neon Genesis Evangelion
  • Date Released: 1995-10-04
  • Type: TV Series
  • Summary: In the year 2000, a scientific expedition in Antarctica exploring the “Giant of Light” known as “Adam” triggers the “Second Impact,” leading to a devastating world war, climate change, and a halved human population. GEHIRN, which later becomes NERV, is established to develop Evangelions (EVA) to combat gia nt beings known as “Angels.” The series follows the battles of the EVAs against the Angels, interwoven with complex themes of religion, psychology, and human relationships.
  • Tags: EVA, Hideaki Anno, GAINAX, science fiction, religion, psychology, original, combat, classic, existential
  • Score: 8.8
  • Rank: 9
  • Link to more information

2. EVA Laughing Schoolyard (EVA爆笑校园)

  • Original Name: EVA爆笑校园
  • Date Released: Unspecified
  • Type: Project
  • Summary: An initiative by Bandai ahead of “EVA New Theatre Edition,” starting with Q-version COLLECTION FIGURE, it narrates the relationships and rivalries within the NERV Academy through animated shorts. It features a playful and cute take on the characters from the original Evangelion series.
  • Tags: EVA, Q-version drama
  • Score: 7.3

3. EVA :Q (新世纪福音战士剧场版:Q)

  • Original Name: EVA :Q
  • English Name: Neon Genesis Evangelion: Q
  • Date Released: 2012-11-17
  • Type: Film
  • Summary: Set 14 years after the “nearly 3rd Impact,” the world is still reeling from its incomplete state. With the splintering of NERV and the emergence o f Wille, the stage is set for the fulfillment of Gendo Ikari and Seele’s plans, alongside the prophecies of the Dead Sea Scrolls. Shinji and Kaworu navigate a world on the brink of a new cycle, ultimately piloting EVA Unit-13 towards a fateful confrontation.
  • Score: 7.0

Please note that the details provided, especially for the second entry “EVA Laughing Schoolyard,” are rather limited, and the focus primarily lies on toy figures and a lighter, humorous take on the original Evangelion universe.

References

https://platform.openai.com/docs/guides/function-calling
https://cookbook.openai.com/examples/how_to_call_functions_with_chat_models
https://docs.anthropic.com/claude/docs/tool-use
https://www.promptingguide.ai/applications/function_calling
https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/function-calling?tabs=python