# How to Build Declarative Agents Using YAML Definitions in the Microsoft Agent Framework

> Learn to build declarative agents using YAML definitions in the Microsoft Agent Framework. Use AgentFactory to parse YAML and create agents without Python code. Get started today!

- Repository: [Microsoft/agent-framework](https://github.com/microsoft/agent-framework)
- Tags: how-to-guide
- Published: 2026-04-05

---

**You can build declarative agents entirely in YAML by using the `AgentFactory` class to parse the definition and return a fully configured `Agent` instance without writing Python agent logic.**

The Microsoft Agent Framework enables developers to build declarative agents using YAML definitions that specify models, tools, instructions, and output schemas in a single configuration file. This data-driven approach allows teams to version, share, and deploy agent configurations through CI pipelines or external configuration services while the framework handles the runtime instantiation.

## Understanding the Declarative Agent Architecture

The declarative subsystem in `python/packages/declarative/agent_framework_declarative/` separates agent definition from implementation. Instead of subclassing `Agent` in Python, you describe a **Prompt Agent** through a structured YAML document that the framework validates and executes.

### The AgentFactory Entry Point

In [`python/packages/declarative/agent_framework_declarative/_loader.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/declarative/agent_framework_declarative/_loader.py), the **`AgentFactory`** class serves as the primary entry point for converting YAML definitions into executable agents. The factory parses the YAML, resolves model providers, constructs chat clients, binds tools, and returns an initialized `Agent` object ready for execution.

The workflow follows six discrete steps:

1. **Parse YAML** using `yaml.safe_load` to produce a plain dictionary
2. **Dispatch to `PromptAgent`** via `agent_schema_dispatch` for Pydantic-style validation
3. **Resolve provider configuration** through `_retrieve_provider_configuration`
4. **Instantiate the chat client** with model IDs, endpoints, and API keys
5. **Parse tools** using `_parse_tool` (line 333) to convert declarative definitions into `AFFunctionTool` objects
6. **Create the Agent** with assembled instructions, tools, and response schemas

### The PromptAgent Model Schema

The **`PromptAgent`** model in [`python/packages/declarative/agent_framework_declarative/_models.py`](https://github.com/microsoft/agent-framework/blob/main/python/packages/declarative/agent_framework_declarative/_models.py) defines the Pydantic-style schema that validates your YAML structure. This schema enforces the `kind: Prompt` contract and accepts fields for `name`, `description`, `instructions`, `model` configuration, `tools`, and `outputSchema`.

### Provider Mapping and Chat Client Resolution

The factory uses a dictionary called **`PROVIDER_TYPE_OBJECT_MAPPING`** to translate YAML model definitions into concrete chat client classes. When you specify `model.provider` and `model.apiType` in your YAML, the factory looks up the corresponding Python class, determines which field receives the model ID, and injects optional endpoint or API-key arguments.

### Tool Parsing and Runtime Binding

At line 333 in [`_loader.py`](https://github.com/microsoft/agent-framework/blob/main/_loader.py), the `_parse_tool` method converts each declarative `Tool` entry—whether `function`, `web_search`, or `file_search`—into the `AFFunctionTool` objects expected by the underlying `agent_framework` runtime. This allows your YAML-defined tools to interface seamlessly with the agent's execution engine.

## Creating Agents from YAML Definitions

The framework provides multiple pathways for instantiating agents depending on whether your definition lives in a file, a string, or a dictionary.

### Loading from a YAML File

Use `create_agent_from_yaml_path` when your agent definition resides in a version-controlled file or external configuration store.

```python
from agent_framework_declarative import AgentFactory
import asyncio

factory = AgentFactory()  # safe_mode=True by default

agent = factory.create_agent_from_yaml_path(
    "python/samples/02-agents/declarative/openai_agent.yaml"
)

async def chat():
    async for event in agent.run("What is the weather in Paris?", stream=True):
        print(event)

asyncio.run(chat())

```

This approach is implemented in [`python/samples/02-agents/declarative/openai_agent.py`](https://github.com/microsoft/agent-framework/blob/main/python/samples/02-agents/declarative/openai_agent.py) and supports full async streaming responses.

### Using Inline YAML Strings

For dynamic generation or testing scenarios, use `create_agent_from_yaml` to pass the YAML definition directly as a string.

```python
from agent_framework_declarative import AgentFactory
import asyncio

yaml_def = """
kind: Prompt
name: GreetingAgent
description: Greets the user politely.
instructions: |
  You are a friendly assistant. Reply with a greeting.
model:
  id: gpt-4o
  provider: AzureOpenAI
outputSchema:
  type: object
  properties:
    greeting:
      type: string
"""

factory = AgentFactory()
agent = factory.create_agent_from_yaml(yaml_def)
response = asyncio.run(agent.run("Hi!"))
print(response)

```

This pattern appears in [`python/samples/02-agents/declarative/inline_yaml.py`](https://github.com/microsoft/agent-framework/blob/main/python/samples/02-agents/declarative/inline_yaml.py) and eliminates the need for external files when prototyping.

### Async Creation from Dictionaries

When loading configurations from databases or external APIs, use `create_agent_from_dict_async` (or the synchronous `create_agent_from_dict`) to bypass YAML parsing entirely and work with Python dictionaries.

```python
from agent_framework_declarative import AgentFactory
import asyncio

agent_def = {
    "kind": "Prompt",
    "name": "AsyncWeatherAgent",
    "instructions": "Answer weather queries concisely.",
    "model": {"id": "gpt-4o", "provider": "AzureOpenAI"},
    "tools": [
        {
            "kind": "function",
            "name": "get_weather",
            "description": "Fetch weather for a city.",
            "bindings": [{"name": "get_weather"}],
        }
    ],
}

async def build_and_chat():
    factory = AgentFactory()
    agent = await factory.create_agent_from_dict_async(agent_def)
    async for event in agent.run("Weather in Tokyo?", stream=True):
        print(event)

asyncio.run(build_and_chat())

```

The async variants at line 74 in [`_loader.py`](https://github.com/microsoft/agent-framework/blob/main/_loader.py) mirror every synchronous method, enabling seamless integration with async web frameworks like FastAPI or Quart.

## Security and Configuration Options

The `AgentFactory` constructor at line 81 in [`_loader.py`](https://github.com/microsoft/agent-framework/blob/main/_loader.py) implements **safe mode** by default. When `safe_mode=True`, PowerFx expressions in your YAML cannot read environment variables directly, protecting against untrusted configuration injection.

You can still inject variables safely through:

- **`client_kwargs`**: Pass additional arguments to the chat client constructor
- **`env_file_path`**: Specify a `.env` file for loading environment variables securely
- **`custom_providers`**: Extend the `PROVIDER_TYPE_OBJECT_MAPPING` with private model endpoints

## Extending with Declarative Workflows

Beyond single agents, the framework supports orchestrating multiple actions through declarative workflows. The workflow engine reads YAML definitions describing sequences of actions like `SetValue`, `SendActivity`, or `RunAgent`.

```yaml

# python/samples/03-workflows/declarative/simple_workflow/workflow.yaml

name: simple-greeting-workflow
description: A simple workflow that greets the user

actions:
  - kind: SetValue
    id: set_greeting
    path: Local.greeting
    value: Hello
  - kind: SetValue
    id: set_name
    path: Local.name
    value: =If(IsBlank(inputs.name), "World", inputs.name)
  - kind: SendActivity
    id: send_greeting
    activity:
      text: =Concat(Local.greeting, ", ", Local.name, "!")

```

This example from [`python/samples/03-workflows/declarative/simple_workflow/workflow.yaml`](https://github.com/microsoft/agent-framework/blob/main/python/samples/03-workflows/declarative/simple_workflow/workflow.yaml) demonstrates how declarative definitions can coordinate complex interactions without Python glue code.

## Summary

- **Use `AgentFactory`** in [`agent_framework_declarative/_loader.py`](https://github.com/microsoft/agent-framework/blob/main/agent_framework_declarative/_loader.py) to convert YAML into executable agents without writing Python agent classes.
- **Define agent structure** through the `PromptAgent` schema, specifying models, tools, instructions, and output schemas in a single YAML document.
- **Load configurations** from files (`create_agent_from_yaml_path`), strings (`create_agent_from_yaml`), or dictionaries (`create_agent_from_dict`) depending on your deployment needs.
- **Enable safe mode** by default to prevent PowerFx expressions from accessing environment variables directly, using `client_kwargs` or `env_file_path` for secure configuration injection.
- **Leverage async variants** of all factory methods for high-throughput applications using modern Python async patterns.

## Frequently Asked Questions

### What is the difference between a Prompt Agent and a programmatic Agent?

A **Prompt Agent** is defined entirely through YAML configuration using the `kind: Prompt` schema, while a programmatic Agent requires subclassing the base `Agent` class and implementing logic in Python. Prompt Agents rely on `AgentFactory` to handle instantiation, tool binding, and chat client configuration automatically based on the YAML definition.

### How do I add custom tools to a declarative agent?

Define tools in the YAML `tools` array using the appropriate `kind` (such as `function`, `web_search`, or `file_search`), then ensure the function implementations are available in your Python environment. The `_parse_tool` method at line 333 in [`_loader.py`](https://github.com/microsoft/agent-framework/blob/main/_loader.py) converts these declarations into `AFFunctionTool` objects that the runtime executes when the agent invokes them.

### Can I use declarative agents with Azure OpenAI or other private endpoints?

Yes. Specify the provider as `AzureOpenAI` in your YAML model configuration and pass endpoint and API key information through the `client_kwargs` parameter when initializing `AgentFactory`. The provider mapping dictionary translates these configurations into the appropriate Azure-specific chat client classes without modifying your YAML definition.

### Is it safe to load YAML definitions from untrusted sources?

By default, yes. When `safe_mode=True` (the default setting), PowerFx expressions in the YAML cannot access environment variables or execute arbitrary code. You can further restrict capabilities by validating YAML content before passing it to the factory or by using the dictionary-based creation methods after sanitizing external input.