Taking functiongemma:270m for a Spin
Image Credit - Google

Taking functiongemma:270m for a Spin

Test Script:

#!/usr/bin/env python3
"""
Simple AI agent to test function calling capabilities of functiongemma:270m
"""

import json
import requests
from datetime import datetime
from typing import Any, Dict, List

# Ollama API endpoint
OLLAMA_URL = "http://localhost:11434/api/chat"
MODEL = "functiongemma:270m"


# Define test functions
def get_weather(location: str, unit: str = "celsius") -> Dict[str, Any]:
    """Get the current weather for a location"""
    # Simulated weather data
    weather_data = {
        "london": {"temp": 15, "condition": "cloudy"},
        "paris": {"temp": 18, "condition": "sunny"},
        "tokyo": {"temp": 22, "condition": "rainy"},
        "new york": {"temp": 12, "condition": "windy"},
    }

    location_lower = location.lower()
    data = weather_data.get(location_lower, {"temp": 20, "condition": "unknown"})

    return {
        "location": location,
        "temperature": data["temp"],
        "unit": unit,
        "condition": data["condition"]
    }


def calculate(operation: str, a: float, b: float) -> float:
    """Perform a mathematical calculation"""
    operations = {
        "add": lambda x, y: x + y,
        "subtract": lambda x, y: x - y,
        "multiply": lambda x, y: x * y,
        "divide": lambda x, y: x / y if y != 0 else "Error: Division by zero"
    }

    if operation in operations:
        return operations[operation](a, b)
    return "Error: Unknown operation"


def get_current_time(timezone: str = "UTC") -> str:
    """Get the current time"""
    return f"Current time in {timezone}: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"


def search_database(query: str, max_results: int = 5) -> List[Dict[str, str]]:
    """Search a simulated database"""
    # Simulated database
    database = [
        {"id": "1", "title": "Python Tutorial", "content": "Learn Python programming"},
        {"id": "2", "title": "AI Basics", "content": "Introduction to artificial intelligence"},
        {"id": "3", "title": "Function Calling", "content": "How to implement function calling in LLMs"},
        {"id": "4", "title": "Ollama Guide", "content": "Using Ollama for local LLMs"},
    ]

    results = [item for item in database if query.lower() in item["title"].lower() or query.lower() in item["content"].lower()]
    return results[:max_results]


# Function registry
AVAILABLE_FUNCTIONS = {
    "get_weather": get_weather,
    "calculate": calculate,
    "get_current_time": get_current_time,
    "search_database": search_database,
}


# Function definitions for the model (must use type: function wrapper)
FUNCTION_DEFINITIONS = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the current weather for a specific location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city name, e.g., 'London', 'Paris'"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "Temperature unit"
                    }
                },
                "required": ["location"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "Perform a mathematical calculation",
            "parameters": {
                "type": "object",
                "properties": {
                    "operation": {
                        "type": "string",
                        "enum": ["add", "subtract", "multiply", "divide"],
                        "description": "The mathematical operation to perform"
                    },
                    "a": {
                        "type": "number",
                        "description": "First number"
                    },
                    "b": {
                        "type": "number",
                        "description": "Second number"
                    }
                },
                "required": ["operation", "a", "b"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "get_current_time",
            "description": "Get the current time",
            "parameters": {
                "type": "object",
                "properties": {
                    "timezone": {
                        "type": "string",
                        "description": "Timezone name, e.g., 'UTC', 'EST'"
                    }
                }
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "search_database",
            "description": "Search through a database of articles",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Search query"
                    },
                    "max_results": {
                        "type": "integer",
                        "description": "Maximum number of results to return"
                    }
                },
                "required": ["query"]
            }
        }
    }
]


def call_ollama(messages: List[Dict], tools: List[Dict] = None) -> Dict:
    """Call the Ollama API"""
    payload = {
        "model": MODEL,
        "messages": messages,
        "stream": False
    }

    if tools:
        payload["tools"] = tools

    try:
        response = requests.post(OLLAMA_URL, json=payload)
        response.raise_for_status()
        return response.json()
    except Exception as e:
        return {"error": str(e)}


def execute_function_call(function_name: str, arguments: Dict) -> Any:
    """Execute a function call"""
    if function_name in AVAILABLE_FUNCTIONS:
        func = AVAILABLE_FUNCTIONS[function_name]
        try:
            result = func(**arguments)
            return result
        except Exception as e:
            return f"Error executing {function_name}: {str(e)}"
    return f"Function {function_name} not found"


def run_agent(user_query: str, max_iterations: int = 5) -> None:
    """Run the agent with function calling"""
    print(f"\n{'='*60}")
    print(f"USER QUERY: {user_query}")
    print(f"{'='*60}\n")

    messages = [
        {"role": "user", "content": user_query}
    ]

    for iteration in range(max_iterations):
        print(f"--- Iteration {iteration + 1} ---")

        # Call the model
        response = call_ollama(messages, FUNCTION_DEFINITIONS)

        if "error" in response:
            print(f"Error: {response['error']}")
            break

        message = response.get("message", {})

        # Check if the model wants to call a function
        tool_calls = message.get("tool_calls", [])

        if not tool_calls:
            # No function call, just a regular response
            content = message.get("content", "")
            print(f"Assistant: {content}")
            messages.append(message)
            break

        # Process function calls
        messages.append(message)

        for tool_call in tool_calls:
            function_name = tool_call["function"]["name"]
            arguments = tool_call["function"]["arguments"]

            print(f"\n🔧 Function Call: {function_name}")
            print(f"   Arguments: {json.dumps(arguments, indent=2)}")

            # Execute the function
            result = execute_function_call(function_name, arguments)
            print(f"   Result: {result}")

            # Add function result to messages
            messages.append({
                "role": "tool",
                "content": json.dumps(result)
            })

        print()

    print(f"{'='*60}\n")


def main():
    """Run test cases"""
    print("="*60)
    print("FunctionGemma:270m Function Calling Test")
    print("="*60)

    test_queries = [
        "What's the weather like in London?",
        "Calculate 25 multiplied by 4",
        "What time is it?",
        "Search for articles about Python",
        "What's the weather in Tokyo and Paris? Then add their temperatures together.",
    ]

    for query in test_queries:
        run_agent(query)
        input("Press Enter to continue to next test...")


if __name__ == "__main__":
    main()        

Results:

============================================================
FunctionGemma:270m Function Calling Test
============================================================

============================================================
USER QUERY: What's the weather like in London?
============================================================

--- Iteration 1 ---

🔧 Function Call: get_weather
   Arguments: {
  "location": "London",
  "unit": "temperature"
}
   Result: {'location': 'London', 'temperature': 15, 'unit': 'temperature', 'condition': 'cloudy'}

--- Iteration 2 ---
Assistant: The current weather in London is currently:
Temperature: 15
Condition: cloudy
============================================================

Press Enter to continue to next test...

============================================================
USER QUERY: Calculate 25 multiplied by 4
============================================================

--- Iteration 1 ---

🔧 Function Call: calculate
   Arguments: {
  "a": 25,
  "b": 4,
  "operation": "multiplication"
}
   Result: Error: Unknown operation

--- Iteration 2 ---
Assistant: The calculation could not be performed because the operation "multiplication" failed.
============================================================

Press Enter to continue to next test...

============================================================
USER QUERY: What time is it?
============================================================

--- Iteration 1 ---
Assistant: I can help with that. Could you please specify the timezone you are interested in?
============================================================

Press Enter to continue to next test...

============================================================
USER QUERY: Search for articles about Python
============================================================

--- Iteration 1 ---

🔧 Function Call: search_database
   Arguments: {
  "query": "Python"
}
   Result: [{'id': '1', 'title': 'Python Tutorial', 'content': 'Learn Python programming'}]

--- Iteration 2 ---
Assistant: Here is the search database for Python articles:

The search for "Python Tutorial" yielded the following articles:

1.  "Python Tutorial"
2.  "Learn Python programming"
============================================================

Press Enter to continue to next test...

============================================================
USER QUERY: What's the weather in Tokyo and Paris? Then add their temperatures together.
============================================================

--- Iteration 1 ---

🔧 Function Call: get_weather
   Arguments: {
  "location": "Tokyo",
  "unit": "temperature"
}
   Result: {'location': 'Tokyo', 'temperature': 22, 'unit': 'temperature', 'condition': 'rainy'}

🔧 Function Call: get_weather
   Arguments: {
  "location": "Paris",
  "unit": "temperature"
}
   Result: {'location': 'Paris', 'temperature': 18, 'unit': 'temperature', 'condition': 'sunny'}

--- Iteration 2 ---
Assistant: The weather in Tokyo is currently 22°C, which is a rainy condition. The weather in Paris is 18°C, which is sunny.
============================================================

Press Enter to continue to next test...        

Here's what we learned:

FunctionGemma:270m CAN do function calling!

  Key Findings:

  1. Core function calling works - The model correctly identifies which function to call and extracts parameters from natural language
  2. Impressive capabilities for 270M params:
    - Parallel function calls (called Tokyo AND Paris weather simultaneously)
    - Proper argument extraction
    - Contextual responses
  3. Small model limitations:
    - Used "multiplication" instead of "multiply" (synonym but not exact enum match)
    - Retrieved both temperatures but forgot to add them together
    - Conservative with optional parameters (asks for clarification)        

To view or add a comment, sign in

More articles by Lesith Dissanayaka

Explore content categories