Principle:Microsoft Agent framework Declarative Tool Binding
Overview
Declarative Tool Binding is the pattern in the Microsoft Agent Framework for connecting plain Python functions to YAML-defined tool specifications without using the @tool decorator. Instead of decorating functions, the developer writes ordinary Python functions and maps them to YAML tool names via the AgentFactory bindings parameter. The key in the bindings dictionary must match the bindings key declared in the YAML tool definition.
This is a user-defined pattern. The framework provides the YAML loading infrastructure and the AgentFactory binding mechanism; the user supplies the Python function implementations that fulfill the tool contracts defined in YAML.
| Property | Value |
|---|---|
| Category | Declarative Systems |
| Source | Sample: python/samples/getting_started/declarative/get_weather_agent.py
|
| API | AgentFactory(client=client, bindings={"key": callable})
|
| Import | from agent_framework_declarative import AgentFactory
|
| Related Implementation | Declarative Tool Function Pattern |
Problem Statement
The @tool decorator approach tightly couples Python functions to the framework's tool registration system. In declarative agent architectures, the agent's structure, instructions, and tool definitions live in YAML files, enabling non-code configuration changes. A mechanism is needed to bridge plain Python callables into the YAML-defined tool graph without requiring decorator-based registration. The Declarative Tool Binding pattern solves this by using a dictionary-based mapping at agent creation time.
Description
In the declarative approach, the tool-use protocol operates differently from the decorator-based pattern:
- The developer authors a YAML agent definition that declares tools by kind, name, and a
bindingskey. - The developer writes plain Python functions with standard type annotations and docstrings -- no
@tooldecorator is required. - At agent creation time, the developer passes a bindings dictionary to
AgentFactory, where each key matches the YAML tool'sbindingskey and each value is the corresponding Python callable. - The
AgentFactoryresolves the YAML tool definitions against the bindings, wiring each tool name to its implementation. - At runtime, when the LLM generates a tool call, the framework dispatches it to the bound Python function.
Theoretical Basis
Separation of Definition and Implementation
The declarative approach separates what a tool is (its name, description, and parameter schema in YAML) from how it works (the Python function body). This separation enables:
- Non-developer configuration -- YAML files can be authored and modified by non-programmers to adjust agent behavior.
- Environment-specific binding -- The same YAML definition can be bound to different Python implementations depending on the deployment context (e.g., mock functions for testing, real implementations for production).
- Late binding -- Tool implementations are resolved at agent creation time rather than at module import time, providing flexibility in dependency injection.
Binding Key Contract
The critical invariant in this pattern is the key match:
# The bindings dictionary key...
bindings = {"get_weather": get_weather}
# ...must match the YAML tool's bindings key:
# tools:
# - kind: function
# name: GetWeather
# bindings:
# get_weather: get_weather
If the binding key in Python does not match the key declared in the YAML bindings section, the tool will not be wired and the agent will fail to resolve the tool at runtime.
No Decorator Required
Unlike the @tool decorator pattern (see Function Tool Definition), declarative tool functions are plain Python functions. The framework does not need to introspect them for schema generation at decoration time because the schema is already defined in the YAML file. The function only needs to:
- Accept the parameters defined in the YAML tool schema.
- Return a value that the framework can serialize back to the LLM.
Contrast with @tool Decorator
| Aspect | @tool Decorator | Declarative Binding |
|---|---|---|
| Registration | At import time via decorator | At agent creation time via bindings dict |
| Schema source | Generated from Python type hints | Defined in YAML tool definition |
| Function requirements | Must be decorated with @tool |
Plain Python function, no decorator |
| Configuration coupling | Code and schema are co-located | Schema in YAML, implementation in Python |
| Flexibility | Fixed at decoration time | Swappable at factory instantiation |
Usage
Step 1: Define the YAML Tool
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: City name
unit:
type: string
enum: ["celsius", "fahrenheit"]
default: "celsius"
required:
- location
Step 2: Implement the Python Function
from typing import Literal
# 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}."
Step 3: Bind via AgentFactory
from agent_framework_declarative import AgentFactory
factory = AgentFactory(
client=client,
bindings={"get_weather": get_weather}, # key matches YAML bindings
)
agent = factory.create_agent_from_yaml(yaml_str)
Usage Guidelines
- Match binding keys exactly -- The key in the Python
bindingsdictionary must be identical to the key in the YAMLbindingssection. Mismatches will cause runtime errors. - Keep functions self-contained -- Since the YAML defines the schema, the Python function should focus on implementation logic. Type hints and docstrings are still recommended for developer documentation.
- Use typing for clarity -- Even though the schema lives in YAML, annotating the Python function with proper types (
str,Literal, etc.) improves code readability and enables IDE support. - Test bindings independently -- Because the function is a plain callable, it can be unit-tested in isolation without involving the YAML loading or agent creation machinery.
Related
- Implementation:Microsoft_Agent_framework_Declarative_Tool_Function_Pattern -- The implementation-level documentation for declarative tool functions.