Function-Calling automation
Function calling introduces powerful capabilities to interact with AI models, but manually creating and maintaining function schemas is a complex and error-prone process. Developers often struggle with:
- Keeping schemas synchronized with code changes
- Ensuring type safety and input validation
- Supporting multiple AI platform formats
- Reducing repetitive boilerplate code
This cookbook demonstrates an automated approach to generating and managing function-calling schemas, streamlining the integration between your code and Language Models.
Installation and Setup¶
This cookbook requires the litellm
library for function-call generation via the Groq provider.
If you don't have an API key for Groq, you can get one at Groq Console.
%pip install orchestr8[adapter] litellm duckduckgo-search
import os, getpass
def set_env(var: str):
if not os.environ.get(var):
os.environ[var] = getpass.getpass(f"{var}: ")
set_env("GROQ_API_KEY")
import json
from typing import Any, Dict, List
from litellm import completion
INSTRUCTION = "Complete user requests using the given functions."
def generate_function_call(request: str, functions: List[Dict[str, Any]]):
response = completion(
model="groq/llama3-groq-70b-8192-tool-use-preview",
messages=[
{"role": "system", "content": INSTRUCTION},
{"role": "user", "content": request}
],
tools=functions
)
tool_call = response.choices[0].message.tool_calls[0].function
if tool_call is None:
print(response.choices[0].message.content)
raise Exception("No function call found in the response.")
return tool_call.name, json.loads(tool_call.arguments)
Creating adapters from functions¶
Creating adapters is as simple as defining a function and decorating it with @adapt
decorator.
from typing import Literal
import orchestr8 as o8
from duckduckgo_search import DDGS
ddgs = DDGS()
@o8.adapt
def search_text(
text: str,
*, # Yes it supports positional and keyword arguments
safe_search: bool = True,
backend: Literal['api', 'html', 'lite'] = 'api',
max_results: int = 1
):
"""
Search for text in the web.
:param text: Text to search for.
:param safe_search: If True, enable safe search.
:param backend: Backend to use for retrieving results.
:param max_results: Max results to return.
"""
return ddgs.text(
keywords=text,
safesearch="on" if safe_search else "off",
backend=backend,
max_results=max_results
)
@o8.adapt
def get_translation(
text: str,
to: Literal['en', 'ja', 'hi', 'es', 'fr', 'de', 'zh'] = 'en'
):
"""
Translate the given text.
:param text: Text to translate.
:param to: what language to translate.
"""
return ddgs.translate(keywords=text, to=to)
Generating function-calls¶
There are three available function-calling schema formats: OpenAI, Anthropic, and Gemini.
We'll be using OpenAI schema for this example as we're using Llama model.
function_call = generate_function_call(
"Search for the best restaurants in Kolkata.",
functions=[search_text.openai_schema, get_translation.openai_schema],
)
print(function_call)
Result
Now, we can utilize the validate_input
method to validate the function arguments generated by the LLM.
search_results = search_text.validate_input(function_call[1])
for entry in search_results:
print(entry)
Result
{'title': 'THE 10 BEST Restaurants in Kolkata (Calcutta) (Updated 2024) - Tripadvisor', 'href': 'https://www.tripadvisor.in/Restaurants-g304558-Kolkata_Calcutta_Kolkata_District_West_Bengal.html', 'body': 'Dining in Kolkata (Calcutta), Kolkata District: See 63,234 Tripadvisor traveller reviews of 5,724 Kolkata (Calcutta) restaurants and search by cuisine, price, location, and more.'}
{'title': 'The 31 Best Restaurants in Kolkata (Calcutta), India - Eater', 'href': 'https://www.eater.com/maps/best-restaurants-kolkata-calcutta-india-bengal', 'body': 'The 31 Essential Kolkata Restaurants. Deviled crabs at a midcentury cabaret, phuchka from a decades-old street vendor, and more of the best things to eat in Kolkata'}
{'title': 'The 50 best restaurants in Kolkata - Condé Nast Traveller India', 'href': 'https://www.cntraveller.in/magazine-story/kolkatas-50-best-meals/', 'body': "Explore the diverse cuisines of Kolkata, from Bengali sweet shops to Mughlai, Chinese and Continental restaurants. Discover the history, culture and flavours of the city's top dining spots, from Flurys to Kewpie's Kitchen."}
{'title': 'The 11 Best Restaurants in Kolkata - TripSavvy', 'href': 'https://www.tripsavvy.com/best-restaurants-in-kolkata-5176449', 'body': "Discover the diverse cuisines and dining scenes of Kolkata, from Bengali fine dining to modern Indian and heritage continental. Find out the best places to enjoy seafood, kebabs, biryani, and more in the city's iconic areas."}
{'title': '14 Best Restaurants in Kolkata (2024) - WanderOn', 'href': 'https://wanderon.in/blogs/best-restaurants-in-kolkata', 'body': 'Explore the diverse and vibrant food scene of Kolkata, from traditional Bengali cuisine to continental dishes, street food, and international flavors. Discover the best restaurants in Kolkata, ranging from historic institutions to quirky cafes and local eateries, and enjoy a gastronomic adventure.'}
Adapters also has as interesting property .definition
which returns the code definition of the function.
It can be useful in cases where you want to pass the function as context to the LLM.