Principle:Microsoft Agent framework Function Tool Definition
Template:Microsoft Agent framework Sidebar
Overview
Function Tool Definition is a pattern in the Microsoft Agent Framework for exposing Python functions as tools that LLM agents can discover, reason about, and invoke automatically during conversations. The @tool decorator converts a typed Python function into a FunctionTool instance, complete with an automatically generated JSON schema derived from the function's type annotations and docstring.
| Property | Value |
|---|---|
| Category | Agent Architecture |
| Source | python/packages/core/agent_framework/_tools.py (lines L903-1049)
|
| API | tool(func, *, name, description, schema, approval_mode, max_invocations, max_invocation_exceptions, additional_properties)
|
| Import | from agent_framework import tool
|
| Related Implementation | Tool Decorator |
Description
Function Tool Definition bridges the gap between Python functions and LLM tool-calling APIs. The @tool decorator creates a FunctionTool by automatically generating a JSON schema from the function's type annotations and docstring. This enables LLMs to understand what the function does, what parameters it expects, and how to call it. The framework uses Pydantic's Annotated[type, Field(description=...)] pattern for parameter descriptions, providing rich metadata that the LLM consumes when deciding which tool to invoke and how to populate its arguments.
In agentic LLM applications, the model needs a structured way to invoke user-defined code. The tool-use pattern establishes a protocol where:
- The developer decorates a Python function with
@tool. - The framework introspects the function's type hints, docstring, and
Annotatedmetadata to produce a JSON schema. - The LLM receives the schema as part of its tool definitions and generates a structured tool call (function name plus JSON arguments).
- The framework intercepts the tool call, deserializes arguments, and executes the corresponding Python function.
- The function's return value is serialized and sent back to the model as a tool result.
Theoretical Basis
Type Hints to JSON Schema Pipeline
The pattern converts Python type hints into JSON Schema, which is then presented to the LLM as a tool definition. The pipeline operates in three stages:
- Python type hints (e.g.,
str,int,list[str],Annotated[str, Field(description="...")]) are introspected from the function signature. - JSON Schema generation: The type hints are transformed into a JSON Schema object that describes parameter names, types, default values, and descriptions. Pydantic's schema generation is leveraged to handle complex nested types, enums, and optional fields.
- LLM tool definition: The JSON schema is packaged into the format expected by the LLM's tool-calling API, allowing the model to understand the function's interface and produce well-formed calls.
Schema Derivation Strategy
The decorator supports three strategies for determining the tool's parameter schema:
- Automatic: When no
schemaargument is provided, the framework synthesizes a Pydantic model from the function's parameters and their type annotations. This is the most common usage path. - Explicit Pydantic model: The developer can pass a
BaseModelsubclass asschema, giving full control over validation rules and JSON schema output. - Explicit dictionary: A raw
Mapping[str, Any]can be passed asschema, providing a pre-built JSON schema without Pydantic intermediation.
Parameter Description via Annotated
The framework uses Python's Annotated type in conjunction with Pydantic's Field to attach descriptions to individual parameters:
from typing import Annotated
from pydantic import Field
def get_weather(
location: Annotated[str, Field(description="The city and state")],
unit: Annotated[str, Field(description="celsius or fahrenheit")] = "celsius",
) -> str:
...
These descriptions flow through to the JSON schema and are visible to the LLM, helping it produce correct and well-targeted tool calls.
Invocation Controls
The @tool decorator provides runtime control mechanisms:
approval_mode: A literal value of"always_require"or"never_require"that determines whether execution requires human-in-the-loop approval before proceeding.max_invocations: Limits the number of times the tool can be called within a single agent run, preventing infinite tool-call loops.max_invocation_exceptions: Limits the number of exceptions the tool can raise before the framework stops retrying, providing a safety valve against persistent failures.
Usage
The @tool decorator can be applied in two ways:
from agent_framework import tool
from typing import Annotated
# 1. Direct decoration (no options)
@tool
def get_weather(
location: Annotated[str, "The city and state"],
unit: Annotated[str, "celsius or fahrenheit"] = "celsius",
) -> str:
"""Get weather for a location."""
return f"Weather in {location}: 22 {unit}"
# 2. Decoration with explicit name and description
@tool(name="custom_weather", description="Get weather data")
def another_func(location: str) -> str:
return f"Weather in {location}"
Related Pages
- Implementation:Microsoft_Agent_framework_Tool_Decorator
- Implementation: Tool Decorator -- the concrete implementation of the
@tooldecorator - Heuristic:Microsoft_Agent_framework_Function_Invocation_Defaults
- Heuristic:Microsoft_Agent_framework_Declaration_Only_Tools_Pattern