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
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
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."""
= re.search(r"<function-call>\s*(.*?)\s*</function-call>", text, re.DOTALL)
function_call_search = re.search(r"<answer>\s*(.*?)\s*</answer>", text, re.DOTALL)
answer_search = function_call_search.group(1).strip() if function_call_search else None
function_call = answer_search.group(1).strip() if answer_search else None
answer
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):
= {"prompt": f"{prompt}", "temperature": 0}
inp if tools: inp['tools'] = tools
= replicate.run(
output "hamelsmu/llama-3-70b-instruct-awq-with-tools:b6042c085a7927a3d87e065a9f51fb7238ef6870c7a2ab7b03caa3c0e9413e19",
input=inp
)= ''.join(output)
txt return parse(txt)
A helper to help turn functions into a schema from fastai/llm-hackers
def schema(f):
= {n:(o.annotation, ... if o.default==Parameter.empty else o.default)
kw for n,o in inspect.signature(f).parameters.items()}
= create_model(f'Input for `{f.__name__}`', **kw).schema()
s 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.
"""
...
= json.dumps(list(L([get_exchange_rate, create_contact]).map(schema))) tools
The Demo
Scenario 1A: No tool required to answer question
even though tool is provided
= run(prompt="Write a very short sentence about SEO.",
o1a =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
= run(prompt="Write a very short sentence about SEO.",
o1b =None)
tools 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
= run(prompt="How many Japenese Yen are there in 1000 USD?",
o2 =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
= run(prompt="Can you help me add a Hamel Husain to my address book?",
o3a =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
= run(prompt="Can you help me add a Hamel Husain to my address book?\
o3b His email address is [email protected]",
=tools)
tools pprint(o3b)
{'content': 'create_contact(name="Hamel Husain", email="[email protected]")',
'type': 'function-call'}