Implementation:Microsoft Agent framework Declarative Tool Function Pattern
| Property | Value |
|---|---|
| Implementation Name | Declarative Tool Function Pattern |
| SDK | Microsoft Agent Framework |
| Repository | Microsoft Agent Framework |
| Type | Pattern Doc (user-defined interface) |
| Domains | Declarative_Systems, Agent_Architecture |
| Sample | python/samples/getting_started/declarative/get_weather_agent.py, Lines L12-14
|
| Interface | def func(param: type, ...) -> ReturnType: (plain callable, no decorator)
|
Overview
The Declarative Tool Function Pattern describes the user-defined callable interface used to implement tool functions for declarative (YAML-defined) agents in the Microsoft Agent Framework. Unlike the @tool decorator approach, declarative tool functions are plain Python functions with no framework-specific decoration. They are connected to YAML tool definitions at agent creation time through the AgentFactory bindings parameter.
This is a Pattern Doc -- it documents a user-defined interface rather than a specific framework API. The framework defines the binding contract; users provide the function implementation.
Interface Contract
Function Signature
Declarative tool functions are ordinary Python callables. The function's parameters must correspond to the parameter schema defined in the YAML tool definition:
def function_name(param1: type1, param2: type2 = default) -> ReturnType:
"""Docstring describing the tool's purpose."""
...
Binding Mechanism
The function is bound to its YAML tool definition via the AgentFactory constructor's bindings parameter:
from agent_framework_declarative import AgentFactory
factory = AgentFactory(
client=client,
bindings={"binding_key": function_name},
)
The binding_key string must match the key declared under bindings: in the YAML tool definition:
tools:
- kind: function
name: ToolDisplayName
bindings:
binding_key: binding_key
Code Reference
Sample Source
From python/samples/getting_started/declarative/get_weather_agent.py, lines L12-14:
# Plain Python function - no @tool decorator needed
def get_weather(
location: str,
unit: Literal["celsius", "fahrenheit"] = "celsius",
) -> str:
"""A simple function tool to get weather information."""
return f"The weather in {location} is 22 degrees {unit}."
Full Wiring Example
from typing import Literal
from agent_framework_declarative import AgentFactory
# Step 1: Define the plain Python function
def get_weather(
location: str,
unit: Literal["celsius", "fahrenheit"] = "celsius",
) -> str:
"""A simple function tool to get weather information."""
return f"The weather in {location} is 22 degrees {unit}."
# Step 2: Create AgentFactory with bindings
factory = AgentFactory(
client=client,
bindings={"get_weather": get_weather}, # key matches YAML bindings
)
# Step 3: Load YAML and create agent
agent = factory.create_agent_from_yaml(yaml_str)
# Step 4: Run the agent
response = await agent.run("What is the weather in Seattle?")
Corresponding YAML Definition
type: prompt
name: WeatherAgent
instructions: You help users check the weather.
tools:
- kind: function
name: GetWeather
description: Get weather for a location
bindings:
get_weather: get_weather
parameters:
type: object
properties:
location:
type: string
description: The city name
unit:
type: string
enum: ["celsius", "fahrenheit"]
default: "celsius"
required:
- location
I/O Contract
Inputs
| Parameter | Type | Description |
|---|---|---|
| Function parameters | As defined by YAML schema | The parameters the function accepts must match the tool's parameter schema declared in YAML. Standard Python type hints (str, int, Literal[...], etc.) should be used for clarity.
|
bindings dict key |
str |
The string key used in AgentFactory(bindings={"key": func}). Must match the YAML tool's bindings key exactly.
|
Outputs
| Return Type | Description |
|---|---|
str (typical) |
The function's return value is serialized and sent back to the LLM as the tool result. String return types are most common. |
| Other serializable types | Any type that the framework can serialize to a string representation for the LLM. |
Data Flow
The declarative tool function sits within the following execution flow:
| Step | Component | Action |
|---|---|---|
| 1 | YAML Definition | Declares the tool's name, description, parameter schema, and binding key. |
| 2 | AgentFactory | Receives the bindings dictionary mapping keys to Python callables. Resolves YAML tool definitions against bindings at agent creation time. |
| 3 | LLM | Generates a structured tool call based on the tool schema provided. |
| 4 | Agent Runtime | Intercepts the tool call, deserializes arguments, and invokes the bound Python function. |
| 5 | Tool Function | Executes with the deserialized arguments and returns a result. |
| 6 | Agent Runtime | Serializes the return value and sends it back to the LLM as a tool result. |
Contrast with @tool Decorator
| Aspect | @tool Decorator Pattern | Declarative Binding Pattern |
|---|---|---|
| Function decoration | Required (@tool) |
Not required (plain function) |
| Schema generation | Automatic from type hints at decoration time | Defined externally in YAML |
| Registration timing | Module import time | Agent creation time via AgentFactory
|
| Configuration location | Co-located in Python code | Split between YAML (schema) and Python (logic) |
| Swappability | Fixed at decoration | Swappable by changing bindings dict |
Implementation Guidelines
- Match binding keys exactly -- A mismatch between the Python bindings dictionary key and the YAML
bindingskey will cause the tool to be unresolved at runtime. - Use type hints for documentation -- Although the schema is defined in YAML, type-annotating the Python function improves readability and enables IDE autocompletion.
- Keep functions pure when possible -- Tool functions that are free of side effects are easier to test and reason about.
- Test independently of YAML -- Because the function is a plain callable, it can be unit-tested by invoking it directly without the YAML loading or agent creation machinery.
- Support both sync and async -- The binding mechanism supports both synchronous and asynchronous functions. Use async when the tool implementation involves I/O operations.
Error Handling
| Scenario | Behavior |
|---|---|
| Binding key mismatch | The AgentFactory cannot resolve the YAML tool to a Python callable. An error is raised during agent creation.
|
| Function raises an exception | The agent runtime handles the exception according to its error handling policy (typically returning an error message to the LLM). |
| Parameter type mismatch | The framework deserializes LLM-provided arguments according to the YAML schema. If the Python function expects different types, a runtime error may occur. |
Related Pages
- Principle:Microsoft_Agent_framework_Declarative_Tool_Binding -- The principle-level documentation for declarative tool binding.