Skip to content

An educational project to understand how function calling and tool calling work in LLM models, from low-level implementations to modern native support.

Notifications You must be signed in to change notification settings

juanje/llm-tool-calling

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

10 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Tool Calling Educational Project

An educational project to understand how function calling and tool calling work in language models, from low-level implementations to modern native support.

🎯 Objective

This project explores two approaches for language models to "call functions":

  1. Pseudo Tool Calling: Simulating tool calling in models without native support
  2. Real Tool Calling: Using native support from modern models

πŸ“š What you'll learn

  • How tool calling works "under the hood"
  • Differences between structured JSON Schema vs native tool calling
  • Limitations of older models vs modern capabilities
  • How to process and execute function calls manually
  • Best practices for validation and error handling

πŸ”¬ Approaches Explored

1. Pseudo Tool Calling (pseudo_tool_calling.py)

Model: llama2 (without native tool calling support)

Method:

  • ✨ JSON Schema to force structured output
  • 🎯 Detailed system prompt explaining expected format
  • πŸ”§ Manual parsing of JSON result
  • ⚑ Manual function execution
# Approach: Structured Output
response = chat(
    model='llama2',
    messages=messages,
    format=tools_schema,  # JSON Schema
)

# Manual parsing
result = json.loads(response.message.content)

Advantages:

  • πŸ“– You understand exactly how it works
  • πŸ› οΈ Total control over the process
  • πŸ”§ Works with any model
  • πŸŽ“ Educational for understanding fundamentals

Limitations:

  • πŸ“ Complex system prompts
  • πŸ› Limited JSON Schema in older models
  • ⚠️ No format guarantees
  • πŸ”„ More manual code

2. Real Tool Calling (real_tool_calling.py)

Model: llama3.2 (with native tool calling support)

Method:

  • πŸš€ Standard tool definitions (OpenAI format)
  • πŸ’¬ Simple system prompt
  • πŸ€– Model decides when and how to use tools
  • ⚑ Native tool calls in response
# Approach: Native Tool Calling
response = chat(
    model='llama3.2',
    messages=messages,
    tools=tools,  # Native definitions
    # No need for temperature=0 with native tool calling
)

# Native tool calls
if response.message.tool_calls:
    # Process tool_calls directly

Advantages:

  • 🎯 More reliable and accurate
  • πŸ“ Simpler prompts
  • πŸ”§ Better integration
  • πŸš€ Advanced features

Limitations:

  • πŸ“¦ Requires modern models
  • πŸŽ›οΈ Less granular control
  • πŸ”’ Depends on model implementation

πŸ› οΈ Implemented Functions

Both approaches implement the same basic functions:

def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b

πŸ“‹ Test Cases

The scripts include tests covering:

Simple Operations

  • "Multiply 2 by 3"
  • "Add 15 and 25"

Multiple Independent Operations

  • "Multiply 4 by 5 and add 6 to 7"
  • "Calculate 8*9 and also 10+15"
  • "I need both 3*6 and 12+8"
  • "Find 7*8 and 20+25"

Note: Examples focus on independent operations, not sequential ones, to avoid dependency problems between results.

πŸ”„ Processing Flow

Both approaches follow the same general flow:

User Request β†’ Model Processing β†’ Tool Calls β†’ Function Execution β†’ Natural Response

Pseudo Tool Calling Flow:

"Multiply 2 by 3" 
β†’ llama2 + JSON Schema 
β†’ {"tool_calls": [{"name": "multiply", "arguments": {"a": 2, "b": 3}}]}
β†’ Manual parsing + execution
β†’ "The result of multiplying 2 by 3 is 6."

Real Tool Calling Flow:

"Multiply 2 by 3"
β†’ llama3.2 + tools definition
β†’ response.message.tool_calls[0].function.name = "multiply"
β†’ Native tool call processing + execution  
β†’ "The result of multiplying 2 by 3 is 6."

πŸ“¦ Requirements

# Install Ollama
curl -fsSL https://ollama.ai/install.sh | sh

# Install required models
ollama pull llama2      # For pseudo tool calling
ollama pull llama3.2    # For real tool calling

# Install Python dependencies
pip install ollama

πŸš€ How to Use

1. Pseudo Tool Calling

python3 pseudo_tool_calling.py

2. Real Tool Calling

python3 real_tool_calling.py

Both scripts run the same tests automatically and show the complete process.

🧠 Key Concepts Learned

JSON Schema vs Tool Definitions

# Pseudo (JSON Schema)
tools_schema = {
    "type": "object",
    "properties": {
        "tool_calls": {
            "type": "array",
            "items": {...}
        }
    }
}

# Real (OpenAI format)
tools = [{
    "type": "function",
    "function": {
        "name": "multiply",
        "description": "Multiply two numbers",
        "parameters": {...}
    }
}]

Validation and Error Handling

Pseudo Tool Calling:

  • Manual validation of function names
  • Defensive JSON parsing
  • Handling of unrespected schemas

Real Tool Calling:

  • Type conversion (strings β†’ integers)
  • Handling different argument formats
  • Native tool_calls validation

Important Limitations

Sequential Operations: Neither approach handles well "What is 2*3 plus 4?" because it requires using the result of one function as input to another.

Workaround: Use independent operations like "Calculate 2*3 and 4+5".

πŸ€” Reflections

When to use each approach?

Pseudo Tool Calling:

  • πŸ“š Educational projects
  • πŸ”§ Maximum process control
  • πŸ“¦ Models without native support
  • 🎯 Simple and controlled cases

Real Tool Calling:

  • πŸš€ Production applications
  • 🎯 Better user experience
  • πŸ“¦ When you have modern models
  • πŸ”§ Advanced features

Lessons Learned

  1. Fundamentals matter: Understanding pseudo tool calling helps better use the real one
  2. JSON Schema has limitations: Old models don't always respect advanced constraints
  3. Validation is key: Always validate and handle errors, regardless of approach
  4. Simplicity: Simple independent cases work better than complex operations

πŸ”— Additional Resources

πŸ‘¨β€πŸ’» Author

πŸ€– AI Tools Disclaimer

This project was developed with the assistance of artificial intelligence tools:

Tools used:

  • Cursor: Code editor with AI capabilities
  • Claude-4-Sonnet: Anthropic's language model

Division of responsibilities:

AI (Cursor + Claude-4-Sonnet):

  • πŸ”§ Initial code prototyping
  • πŸ“ Generation of examples and test cases
  • πŸ› Assistance in debugging and error resolution
  • πŸ“š Documentation and comments writing
  • πŸ’‘ Technical implementation suggestions

Human (Juanje Ojeda):

  • 🎯 Specification of objectives and requirements
  • πŸ” Critical review of code and documentation
  • πŸ’¬ Iterative feedback and solution refinement
  • πŸ“‹ Definition of project's educational structure
  • βœ… Final validation of concepts and approaches

Collaboration philosophy: AI tools served as a highly capable technical assistant, while all design decisions, educational objectives, and project directions were defined and validated by the human.


This project is an educational exploration of function calling in LLMs, from fundamentals to modern implementations.

About

An educational project to understand how function calling and tool calling work in LLM models, from low-level implementations to modern native support.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages