Skip to main content

Making LLM Tool-Calling Simpler.

Project description

Making LLM Tool-Calling Simpler.


tool-parse version tool-parse build status tool-parse codecov tool-parse license

🚀 Installation

pip install tool-parse
  • with pydantic support

    pip install "tool-parse[pydantic]"
    
  • with langchain based integration

    pip install "tool-parse[langchain]"
    

🌟 Key Features

  1. Versatile Tool Management:

    • Support for functions (both synchronous and asynchronous)
    • Compatible with pydantic.BaseModel, typing.TypedDict, and typing.NamedTuple
    • Supports any docstring format recognized by the docstring_parser library
    • @tool decorator for creating independent, standalone tools
    • ToolRegistry class for managing multiple tools
      • Multiple registration methods:
        • Decorators (@tr.register)
        • Direct passing (tr.register(func))
        • Key-value pairs (tr[key] = func)
        • Bulk registration (register_multiple)
      • Customizable tool naming and description
  2. Extensive Parameter Type Support:

    • Handles a wide range of parameter types: str, int, float, bool, set, list, dict, pathlib.Path, typing.Set, typing.List, typing.Dict, typing.NamedTuple, typing.TypedDict, pydantic.BaseModel, typing.Literal, enum.Enum
    • Supports optional parameters: typing.Optional[<type>], typing.Union[<type>, None], <type> | None
    • Handles forward references and complex nested types
  3. Robust Schema Generation:

    • Generates schemas in both 'base' and 'claude' formats
    • Extracts and includes parameter descriptions from docstrings
    • Handles recursive type definitions gracefully
  4. Flexible Tool Invocation:

    • Supports tool invocation from call expressions or metadata
    • Handles argument parsing and type conversion
    • Manages both positional and keyword arguments
  5. Error Handling and Validation:

    • Comprehensive error checking for type mismatches, invalid arguments, and unsupported types
    • Validates enum and literal values against allowed options
    • Handles recursive parameter exceptions

Cookbooks

Usage 🤗

Creating independent tools

from tool_parse import tool
from typing import Optional

@tool
def search_web(query: str, max_results: Optional[int]):
    """
    Search the web for given query
    :param query: The search query string
    :param max_results: Maximum number of results to return
    """
    print(f"{query=}, {max_results=}")
    ...

# Get tool schema
schema = search_web.marshal('base') # `base` and `claude` schema are available

# Invoke tool from LLM generated arguments
output = search_web.compile(arguments={"query": "Transformers"})

Creating a tool registry

from tool_parse import ToolRegistry

tr = ToolRegistry()

Defining tools and registering them

There are multiple ways of registering tools:

Adding a docstring is optional, but it's good practice to include descriptions for parameters. The library supports any format recognized by the docstring_parser library, with sphinx format being a personal preference.

  1. Decorating the object:
from typing import TypedDict

@tr.register
class UserInfo(TypedDict):
    """
    User information schema
    :param name: The user's full name
    :param age: The user's age in years
    """
    name: str
    age: int

# Override name and description
@tr.register(name="search_web", description="Performs a web search")
def search_function(query: str, max_results: int = 10):
    """
    Search the web for given query
    :param query: The search query string
    :param max_results: Maximum number of results to return
    """
    ...
  1. Passing the object directly:
from typing import NamedTuple

class ProductInfo(NamedTuple):
    """
    Product information
    :param name: The product name
    :param price: The product price
    :param in_stock: Whether the product is in stock
    """
    name: str
    price: float
    in_stock: bool

tr.register(ProductInfo)

async def fetch_data(url: str, timeout: int = 30):
    """
    Fetch data from a given URL
    :param url: The URL to fetch data from
    :param timeout: Timeout in seconds
    """
    ...

tr.register(fetch_data, name="fetch_api_data", description="Fetches data from an API")
  1. Using key-value pair:

Note: This method doesn't allow overriding the description.

from pydantic import BaseModel

class OrderModel(BaseModel):
    """
    Order information
    :param order_id: Unique identifier for the order
    :param items: List of items in the order
    :param total: Total cost of the order
    """
    order_id: str
    items: list[str]
    total: float

tr['create_order'] = OrderModel
  1. Registering multiple tools at once:

Note: This method doesn't allow overriding the name and description

tr.register_multiple(UserInfo, search_function, ProductInfo)

Check if a name has already been registered

'search_web' in tr  # Returns True if 'search_web' is registered, False otherwise

Get registered tools as schema

base and claude formats are available. The default base format works with almost all providers.

  • As a list of dictionaries:

    tools = tr.marshal('base')  # list[dict]
    
  • As a JSON string:

    tools = tr.marshal(as_json=True)  # str
    
  • Saving as a JSON file:

    tools = tr.marshal('claude', persist_at='/path/to/tools_schema.json')  # list[dict]
    
  • Get a single tool schema:

    tool = tr['search_web']  # dict
    

Invoking a tool

  • From a call expression:

    result = tr.compile('search_web("Python programming", max_results=5)')
    
  • From call metadata:

    result = tr.compile(name='fetch_api_data', arguments={'url': 'https://api.example.com', 'timeout': 60})
    

Important: The tool-parse library does not interact directly with LLM-specific APIs. It cannot make requests to any LLM directly. Its primary functions are generating schemas and invoking expressions or metadata generated from LLMs. This design provides developers with more flexibility to integrate or adapt various tools and libraries according to their project needs.

Combining two registries

Note: A single ToolRegistry instance can hold as many tools as you need. Creating a new ToolRegistry instance is beneficial only when you require a distinct set of tools. This approach is particularly effective when deploying agents to utilize tools designed for specific tasks.

new_registry = ToolRegistry()

@new_registry.register
def calculate_discount(
    original_price: float,
    discount_percentage: float = 10
):
    """
    Calculate the discounted price of an item
    :param original_price: The original price of the item
    :param discount_percentage: The discount percentage to apply
    """
    ...

combined_registry = tr + new_registry

Third Party Integrations

Langchain

Define the tools

from tool_parse.integrations.langchain import ExtendedStructuredTool

async def search_web(query: str, safe_search: bool = True):
    """
    Search the web.
    :param query: Query to search for.
    :param safe_search: If True, enable safe search.
    """
    return "not found"

class UserInfo(NamedTuple):
    """User information"""
    name: str
    age: int
    role: Literal['admin', 'tester'] = 'tester'

tools = [
    ExtendedStructuredTool(func=search_web),
    ExtendedStructuredTool(func=UserInfo, name="user_info", schema_spec='claude'),
]
# OR
tools = ExtendedStructuredTool.from_objects(search_web, UserInfo, schema_spec='base')

Patch the chat model

from langchain_ollama.chat_models import ChatOllama

from tool_parse.integrations.langchain import patch_chat_model

model = patch_chat_model(ChatOllama(model="llama3-groq-tool-use")) # Patch the instance
# OR
model = patch_chat_model(ChatOllama)(model="llama3-groq-tool-use") # Patch the class and then instantiate it

Bind the tools

model.bind_tools(tools=tools)

For langgraph agent usage, refer Langgraph+Ollama Example cookbook

🤝 Contributing

Contributions, issues, and feature requests are welcome! Feel free to check the issues page.


Made with ❤️ by synacktra

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

tool_parse-1.1.3.tar.gz (22.9 kB view details)

Uploaded Source

Built Distribution

tool_parse-1.1.3-py3-none-any.whl (23.2 kB view details)

Uploaded Python 3

File details

Details for the file tool_parse-1.1.3.tar.gz.

File metadata

  • Download URL: tool_parse-1.1.3.tar.gz
  • Upload date:
  • Size: 22.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.11.10 Linux/6.8.0-1014-azure

File hashes

Hashes for tool_parse-1.1.3.tar.gz
Algorithm Hash digest
SHA256 a5051c0debb7a9cbd4685cd603f6aeeaf1c934377e56bf9465a640b0252d4ef4
MD5 bdcba99e5d29d5fedc300687486b4747
BLAKE2b-256 1c3b31db8693bc29706c240487d7cc3b1805300d792132ab02fcf1206a3aeb7e

See more details on using hashes here.

File details

Details for the file tool_parse-1.1.3-py3-none-any.whl.

File metadata

  • Download URL: tool_parse-1.1.3-py3-none-any.whl
  • Upload date:
  • Size: 23.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.11.10 Linux/6.8.0-1014-azure

File hashes

Hashes for tool_parse-1.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 017e102bbb3b80fa2cce9247995f0426f21e4ffa926749a1aa6b596a5565cbfa
MD5 366b1b4e216198e9ff2c5c297cbc4aa1
BLAKE2b-256 0c32734a57a7ddfbbde6f663f3f121c248c910adda5e7d838e4d18006cb72c2d

See more details on using hashes here.

Supported by

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