Skip to main content

Turns a Python function into dictionary in the OpenAI standard you can attach as a tool to a LLM request.

Project description

func2llmtool - Python function to LLM tool

Usage

from func2llmtool.core import FuncInfo  # this library
import litellm  # or other LLM library
fi = FuncInfo.from_func(my_function)  # your def my_function()
litellm.completion(model='inference/mymodel', messages=[], tools=[fi()])

Installation

Install latest from the GitHub repository:

$ pip install git+https://github.com/NumesSanguis/func2llmtool.git

or from pypi

$ pip install func2llmtool

Documentation

How to use

Let’s turn our weather function into a tool a LLM can use. The default output format is “litellm”. Supported:

# define our tool function with docstring and variable annotations
def get_weather(
    city: str  # City name
) -> str:  # Returns the weather in a city, e.g. "rainy"
    """Get the current weather for a city."""

    if city.lower() == "tokyo": weather = "sunny"
    elif city.lower() == "amsterdam": weather = "cloudy"
    else: weather = "rainy"

    return weather

Extract the required data:

fi = FuncInfo.from_func(get_weather)
fi  # same as print(fi)
{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a city. Return type: string (Returns the weather in a city, e.g. \"rainy\")",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "City name"
                }
            },
            "required": [
                "city"
            ],
            "additionalProperties": false
        }
    }
}

Return the data without pretty printing:

fi()  # same as: fi.to_tool_dict()
{'type': 'function',
 'function': {'name': 'get_weather',
  'description': 'Get the current weather for a city. Return type: string (Returns the weather in a city, e.g. "rainy")',
  'parameters': {'type': 'object',
   'properties': {'city': {'type': 'string', 'description': 'City name'}},
   'required': ['city'],
   'additionalProperties': False}}}

Format output dict according to OpenAI standard:

fi.to_tool_dict(format="openai")
{'type': 'function',
 'name': 'get_weather',
 'description': 'Get the current weather for a city. Return type: string (Returns the weather in a city, e.g. "rainy")',
 'parameters': {'type': 'object',
  'properties': {'city': {'type': 'string', 'description': 'City name'}},
  'required': ['city'],
  'additionalProperties': False},
 'strict': True}

We can also provide the function name as long as it is in your Python globals:

FuncInfo.from_func('get_weather')()
{'type': 'function',
 'function': {'name': 'get_weather',
  'description': 'Get the current weather for a city. Return type: string (Returns the weather in a city, e.g. "rainy")',
  'parameters': {'type': 'object',
   'properties': {'city': {'type': 'string', 'description': 'City name'}},
   'required': ['city'],
   'additionalProperties': False}}}

Other docstring styles - Numpy

# define our tool function with numpy-style docstring
def get_weather_numpy_style(city: str) -> str:
    """
    Get the current weather for a city.

    Parameters
    ----------
    city : str
        City name

    Returns
    -------
    str
        The weather in a city, e.g. "rainy"
    """

    if city.lower() == "tokyo": weather = "sunny"
    elif city.lower() == "amsterdam": weather = "cloudy"
    else: weather = "rainy"

    return weather
FuncInfo.from_func(get_weather_numpy_style)()
{'type': 'function',
 'function': {'name': 'get_weather_numpy_style',
  'description': 'Get the current weather for a city. Return type: string (The weather in a city, e.g. "rainy")',
  'parameters': {'type': 'object',
   'properties': {'city': {'type': 'string', 'description': 'City name'}},
   'required': ['city'],
   'additionalProperties': False}}}

LiteLLM example - Attach tool info to LLM

Here we show how to attach the tool info to a LLM request, handle its tool request, return our tool output, and get our question about the weather answered.

import os
import litellm
from litellm.caching.caching import Cache
# set ENV variables for LLM usage; https://console.groq.com/keys
# os.environ["GROQ_API_KEY"] = "your-api-key"

Prepare our LLM call:

# groq is a fast inference provider (not to be confused with grok by X), which offers a free tier
MODEL = 'groq/llama-3.1-8b-instant'  # any model supported by LiteLLM and for which you set a key
MESSAGES = []
TOOLS = [fi()]
litellm.cache = Cache(type="disk")
litellm.suppress_debug_info = True  # prevent "Provider List: https://docs.litellm.ai/docs/providers" spam
# optional instructions
# MESSAGES.append({"role": "system", "content": "Use the results from tool calls to answer questions."})
MESSAGES.append({"role": "user", "content": "What is the weather in city Tokyo?"})

Call model with our Python function available as tool:

resp = litellm.completion(model=MODEL, messages=MESSAGES, tools=TOOLS, caching=True)
print(resp.choices[0].message.model_dump())
{'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{"city":"Tokyo"}', 'name': 'get_weather'}, 'id': 'hjgzy4gz9', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': None}

Note the 'tool_calls': [{'function': {'arguments': '{"city":"Tokyo"}', 'name': 'get_weather'}, ... part. This is the tool call that the LLM made. Let’s execute it and inform the LLM.

# example only shows how to handle 1 tool call (multiple can be requested in parallel)
tc = resp.choices[0].message.tool_calls[0]
tc
ChatCompletionMessageToolCall(function=Function(arguments='{"city":"Tokyo"}', name='get_weather'), id='hjgzy4gz9', type='function')
# The id associated to the tool call, so the LLM knows which output is associated to which tool call
tc.id
'hjgzy4gz9'
# The arguments are a JSON string, so we need to convert them before calling our function
import json

func_args = json.loads(tc.function.arguments)
func_args
{'city': 'Tokyo'}

Add tool call and usage to message history:

# keep track of the tool call by the LLM in our message history
MESSAGES.append({k:v for k,v in resp.choices[0].message.model_dump().items() if v is not None})
# Add tool call result to message history
MESSAGES.append({'role': 'tool', 'tool_call_id': tc.id, 'content': get_weather(**func_args)})
# We now have all info to query the LLM again
print(MESSAGES)
[{'role': 'user', 'content': 'What is the weather in city Tokyo?'}, {'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{"city":"Tokyo"}', 'name': 'get_weather'}, 'id': 'hjgzy4gz9', 'type': 'function'}]}, {'role': 'tool', 'tool_call_id': 'hjgzy4gz9', 'content': 'sunny'}]

Give our LLM back the tool execution results and ask it to answer our initial question.

resp2 = litellm.completion(model=MODEL, messages=MESSAGES, tools=TOOLS, caching=True)
print(resp2.choices[0].message.content)
It's currently sunny in Tokyo.

Alternatives to this library

# LiteLLM has a build-in function, but it is not as flexible what is supported.
# Note the missing parameter description and nothing about what's returned
litellm.utils.function_to_dict(get_weather)
{'name': 'get_weather',
 'description': 'Get the current weather for a city.',
 'parameters': {'type': 'object',
  'properties': {'city': {'type': 'string'}},
  'required': ['city']}}
# gets the 'city' description, but nothing about what's returned
litellm.utils.function_to_dict(get_weather_numpy_style)
{'name': 'get_weather_numpy_style',
 'description': 'Get the current weather for a city.',
 'parameters': {'type': 'object',
  'properties': {'city': {'type': 'string', 'description': 'City name'}},
  'required': ['city']}}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

func2llmtool-0.0.2.tar.gz (19.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

func2llmtool-0.0.2-py3-none-any.whl (16.4 kB view details)

Uploaded Python 3

File details

Details for the file func2llmtool-0.0.2.tar.gz.

File metadata

  • Download URL: func2llmtool-0.0.2.tar.gz
  • Upload date:
  • Size: 19.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for func2llmtool-0.0.2.tar.gz
Algorithm Hash digest
SHA256 c88adee2eaecbdd3df347c5f08b4540eea3adf4ef59c8ea6b2ca6a23062e37aa
MD5 035fc1e19d8e1bfab6f8d60447499adb
BLAKE2b-256 f7d0deae885f60fa36c8e2993c33c1d4358edaee9e976d22f73e9e5ecdd45547

See more details on using hashes here.

File details

Details for the file func2llmtool-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: func2llmtool-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 16.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for func2llmtool-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 94927427d1c7485a47c0e046252f0cbdb43486ac8b999e2b9f1c52ea61715380
MD5 944aa55e203c582d00f7604271b07f7b
BLAKE2b-256 1c1ee1f12f07f54ff31f913fd88c757b7d85559a4cd4aab9bf9d968a871e4567

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page