Llama-3 Function Calling Demo

Function calling with llama-3 with prompting only.

Inference code with prompt is located here.

This page is rendered by nbsanity from this notebook on GitHub

Setup

import replicate
from pydantic import create_model
import inspect, json, re
from inspect import Parameter
from fastcore.foundation import L
from functools import partial
from pprint import pprint

The following collapsible element contains helper functions for the Replicate inference API and parsing the response:

Unhide to see code
def parse(text):
    """Use regular expressions to find content within the tags."""
    
    function_call_search = re.search(r"<function-call>\s*(.*?)\s*</function-call>", text, re.DOTALL)
    answer_search = re.search(r"<answer>\s*(.*?)\s*</answer>", text, re.DOTALL)
    function_call = function_call_search.group(1).strip() if function_call_search else None
    answer = answer_search.group(1).strip() if answer_search else None
    
    if function_call and function_call != "None": return {"type": "function-call", "content": function_call}
    elif answer: return {"type": "text", "content": answer}
    else: return {"type": "text", "content": text}


def run(prompt:str, tools:str=None):
    inp = {"prompt": f"{prompt}", "temperature": 0}
    if tools: inp['tools'] = tools
    output = replicate.run(
        "hamelsmu/llama-3-70b-instruct-awq-with-tools:b6042c085a7927a3d87e065a9f51fb7238ef6870c7a2ab7b03caa3c0e9413e19",
        input=inp
        )
    txt = ''.join(output)
    return parse(txt) 

A helper to help turn functions into a schema from fastai/llm-hackers

def schema(f):
    kw = {n:(o.annotation, ... if o.default==Parameter.empty else o.default)
          for n,o in inspect.signature(f).parameters.items()}
    s = create_model(f'Input for `{f.__name__}`', **kw).schema()
    return dict(name=f.__name__, description=f.__doc__, parameters=s)

Lets define two tools:

def get_exchange_rate(base_currency:str, target_currency:str):
    """
    Get the exchange rate between two currencies.
    
    Parameters:
    - base_currency (str): The currency to convert from.
    - target_currency (str): The currency to convert to.
    
    Returns:
    float: The exchange rate from base_currency to target_currency.
    """
    ...

def create_contact(name:str, email:str):
    """
    Create a new contact.
    
    Parameters:
    - name (str): The name of the contact.
    - email (str): The email address of the contact.
    
    Returns:
    dict: Confirmation of the created contact.
    """
    ...

tools = json.dumps(list(L([get_exchange_rate, create_contact]).map(schema)))

The Demo

Scenario 1A: No tool required to answer question

even though tool is provided

o1a = run(prompt="Write a very short sentence about SEO.",
          tools=tools)
pprint(o1a)
{'content': 'Search Engine Optimization (SEO) is crucial for online '
            'visibility.',
 'type': 'text'}

Scenario 1B: No tool required to answer question

no tools are provided

o1b = run(prompt="Write a very short sentence about SEO.",
          tools=None)
pprint(o1b)
{'content': 'Here is a very short sentence about SEO:\n'
            '\n'
            '"Optimizing website content with relevant keywords improves '
            'search engine rankings."',
 'type': 'text'}

Scenario 2: Tool is reqiured to answer question

o2 = run(prompt="How many Japenese Yen are there in 1000 USD?",
        tools=tools)
pprint(o2)
{'content': 'get_exchange_rate(base_currency="USD", target_currency="JPY")',
 'type': 'function-call'}

Scenario 3A: Tool reqiured but not enough info in the prompt for the params

o3a = run(prompt="Can you help me add a Hamel Husain to my address book?",
        tools=tools)
pprint(o3a)
{'content': "I'd be happy to help you add Hamel Husain to your address book! "
            'However, I need more information from you. Could you please '
            "provide Hamel's email address? Once I have that, I can assist you "
            'in adding the contact.',
 'type': 'text'}

Scenario 3B: Tool required, there is enough info in the prompt

o3b = run(prompt="Can you help me add a Hamel Husain to my address book?\
                  His email address is [email protected]",
        tools=tools)
pprint(o3b)
{'content': 'create_contact(name="Hamel Husain", email="[email protected]")',
 'type': 'function-call'}