Function Calling & Tool Use with Claude 3

In this guide, we look at how to use function calling and external tools with Claude 3.

22 days ago   •   6 min read

By Peter Foy
Table of contents

With the release of Claude 3, GPT-4 has a serious contender for the top LLM on the market.

Not only does Claude 3 provide a very impressive out-of-the box model, it also has some of the key features that GPT-4 has, namely function calling & tool use.

We've written about function calling with GPT-4 several times, but in case you're unfamiliar, here's how the Claude docs describe function calling:

Claude has the capability to interact with external client-side tools and functions in order to expand its capabilities beyond what it was initially trained on.
Tool use is also known as function calling. The two terms are interchangeable.

In short, this means we can augment the LLM with external information & tools, such as making API calls, searching the web, using a calculator, and so on.

In this guide, let's walk through how to get started with function calling using Claude, including a real-world example of retrieving current stock prices based on an API call.


How does Claude function calling work?

Before we jump into the code, let's walk through how function calling with Claude works.

In order to use tools with Claude, we need to provide descriptions of each function it can. Based on these descriptions and the user's input, Claude will then intelligently decide when and how to use the tool in order to complete the task at hand.

In the example below, we'll look at how to fetch real-time stock prices based on the users input using the Financial Modeling Prep API.

Here's a high-level overview of how function calling works behind the scenes from their docs:

  1. The function definition and user input query are both sent to Claude in a single prompt
  2. Claude then assesses the users' request and decided which functions, if any, to call and with which arguments
  3. Claude then constructs a properly formatted function call based on the user's request
  4. The function call is intercepted with a stop_sequence indicator, and the function is executed on the client side
  5. The function call response is then sent back to Claude
  6. Finally, Claude uses this response to generate a final response, answering the user's initial query along with the augmented information from the function call.

Alright, now that we know the high-level overview, let's jump into a simple real-world example.


Fetching real-time stock prices with Claude

Below we'll walk through each of the steps mentioned above, we'll be using Colab notebook so let's start with our installs & imports.

Step 0: Install & imports

First we can install Claude with !pip install anthropic and import the following libraries:

from anthropic import Anthropic
import os
from google.colab import userdata
import requests
import re

We'll also retreive our API keys from Colab secrets as follows. As mentioned we'll be using Financial Modeling Prep in order to fetch real-time stock prices, whcih you can get an API key for here.

FMP_API_KEY = userdata.get('FMP_API_KEY')
CLAUDE_API_KEY = userdata.get('CLAUDE_API_KEY')

Next, we can initial the Anthropic client and set our model, in this case we'll use the most advanced model, but you can use a smaller model if you'd like:

client = Anthropic(api_key=CLAUDE_API_KEY)
MODEL_NAME = "claude-3-opus-20240229"

Step 1: Defining our function call

Next, we need to define our function for retrieving stock prices, which just takes the ticker as input:

def get_stock_price(ticker):
    url = f"https://financialmodelingprep.com/api/v3/quote/{ticker}?apikey={FMP_API_KEY}"
    response = requests.get(url)
    if response.status_code == 200:
        data = response.json()
        if data:
            return data[0]['price']
    return "Price not found"

Step 2: Helper function to extract text

Next, let's define a helper function called extract_between_tags that extracts text between XML tags. This is used to extract relevant data from between the relevant XML tags and run the function on Claude's behalf.

def extract_between_tags(tag: str, string: str, strip: bool = False) -> list[str]:
    ext_list = re.findall(f"<{tag}>(.+?)</{tag}>", string, re.DOTALL)
    if strip:
        ext_list = [e.strip() for e in ext_list]
    return ext_list

Step 3: User input

Next, let's prompt the user for which ticker they're looking for. Note that the user could actually put in the company name, for example, NVIDIA and Claude will be able update this to the correct NVDA ticker in the next step:

TICKER_SYMBOL = input("Please enter the ticker symbol: ")

Step 4: Define the function description

Next, we'll go and define the function description for our get_stock_price function in XML format:

function_description = """
<tool_description>
<tool_name>get_stock_price</tool_name>
<description>
Fetches the current stock price for a given ticker symbol.
</description>
<parameters>
<parameter>
<name>ticker</name>
<type>string</type>
<description>The ticker symbol of the stock to fetch the price for.</description>
</parameter>
</parameters>
</tool_description>
"""

Step 5: Construct user & system prompts

Now let's create the user message and insert the ticker they mentioned before:

We'll then create a system message the includes the function description and instructions on how to call the function:

system_prompt = f"""In this environment, you have access to the following tool:
{function_description}
You may call it like this:
<function_calls>
    <invoke>
        <tool_name>get_stock_price</tool_name>
        <parameters>
            <ticker>$TICKER</ticker>
        </parameters>
    </invoke>
</function_calls>
To answer the question, please only call the get_stock_price function with the provided ticker symbol. Do not provide any additional information or stock price values in your response.
"""

Step 6: Call Claude with the user & system message

Now we're ready for our first Claude API call with the initial user message andd system prompt in order to get Claude's response for which function to call.

claude_response_to_function_call = client.messages.create(
    model=MODEL_NAME,
    max_tokens=1024,
    messages=[user_message],
    system=system_prompt,
    stop_sequences=["\n\nHuman:", "\n\nAssistant", "</function_calls>"]
).content[0].text
print(claude_response_to_function_call)
user_message = {
    "role": "user",
    "content": f"What's the current stock price for {TICKER_SYMBOL}?"
}

Step 7: Extract the stock ticker from Claude's response

Now, we want to extract the stock ticker from Claude's response using the extract_between_tags function we setup:

ticker_symbol = extract_between_tags("ticker", claude_response_to_function_call)[0]

Step 8: Call the function

Now, with the extracted stock ticker we will call the Financial Modeling function to fetch the price.

  • We do this by checking if the <invoke> tag is is the Claude function call response
  • If so, we call the function with the extracted stock ticker and format the function results as follows:
# Check if Claude called the get_stock_price function
if "<invoke>" in claude_response_to_function_call:
    # Call the stock price API with the extracted ticker symbol
    stock_price = get_stock_price(ticker_symbol)
    
    # Format the function results
    function_results = f"""<function_results>
        <result>
            <tool_name>get_stock_price</tool_name>
            <stdout>
            {stock_price}
            </stdout>
        </result>
    </function_results>"""
else:
    function_results = "No API call made"

Step 9: Format the function

Next, let's format the function response in order to send it back to Claude:

function_results = f"""<function_results>
    <result>
        <tool_name>get_stock_price</tool_name>
        <stdout>
            {stock_price}
        </stdout>
    </result>
</function_results>"""

Step 10: Combine messages & function response

Next, we'll combine Claude's initial response, the function call, and the function call response back into a single message:

partial_assistant_message = claude_response_to_function_call + "</function_calls>" + function_results

We're then going to use that to update the system prompt with the assistant message and instructions to provide a final response based on the user's input and function call results:

updated_system_prompt = f"""{system_prompt}
Here is the result of the function call:
{partial_assistant_message}
Based on this result, please provide a response to the original question.
"""
print(updated_system_prompt)

Step 11: Call Claude for the final response

Finally, let's call Claud again with our updated system prompt and initial user message to get the final response:

final_message = client.messages.create(
    model=MODEL_NAME,
    max_tokens=1024,
    messages=[user_message],
    system=updated_system_prompt
).content[0].text

Summary: Function Calling with Claude

That's it! We've now implemented a simple function calling with Claude to augment our queries with external API calls.

While the docs say that function calling with Claude is still experimental, you can see imagine how powerful of a feature this will be in the coming years for building end-to-end AI agents that can use tools, search the web, call APIs, and so on.

Access the code

If you'd like to access the Colab notebook for this tutorial, you can sign up for MLQ Academy here and access it below 👇

This content is only available to subscribers

Subscribe now and have access to all our stories, enjoy exclusive content and stay up to date with constant updates.

Sign up now

Spread the word

Keep reading