Skip to content
Configuration-as-Code for AI Agents: YAML, TOML, and Python Config Patterns
Learn Agentic AI11 min read14 views

Configuration-as-Code for AI Agents: YAML, TOML, and Python Config Patterns

Compare YAML, TOML, and Python-based configuration patterns for AI agents. Learn config file design, schema validation, safe loading, and default merging strategies.

Why Configuration-as-Code

Storing agent configuration in code — version-controlled config files rather than database rows or UI settings — brings the full power of software engineering to agent management. You get git history showing who changed what, pull request reviews for configuration changes, automated validation in CI, and deterministic deployments where the same commit always produces the same agent behavior.

The question is which format to use. YAML, TOML, and Python each have distinct tradeoffs for agent configuration.

YAML Configuration

YAML is the most common format in the cloud-native ecosystem. Its strength is readability and support for complex nested structures.

flowchart LR
    INPUT(["User intent"])
    PARSE["Parse plus<br/>classify"]
    PLAN["Plan and tool<br/>selection"]
    AGENT["Agent loop<br/>LLM plus tools"]
    GUARD{"Guardrails<br/>and policy"}
    EXEC["Execute and<br/>verify result"]
    OBS[("Trace and metrics")]
    OUT(["Outcome plus<br/>next action"])
    INPUT --> PARSE --> PLAN --> AGENT --> GUARD
    GUARD -->|Pass| EXEC --> OUT
    GUARD -->|Fail| AGENT
    AGENT --> OBS
    style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
    style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
    style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
    style OUT fill:#059669,stroke:#047857,color:#fff
# agent_config.yaml loaded by the application
YAML_EXAMPLE = """
agent:
  name: support-agent
  model: gpt-4o
  temperature: 0.7
  max_tokens: 2048
  system_prompt: |
    You are a customer support agent for Acme Corp.
    Always be polite and professional.
    If you cannot resolve an issue, escalate to a human agent.

  tools:
    - name: search_docs
      description: Search the knowledge base
      enabled: true
    - name: create_ticket
      description: Create a support ticket
      enabled: true
    - name: refund_order
      description: Process a refund
      enabled: false
      requires_approval: true

  guardrails:
    max_tool_calls_per_turn: 3
    block_pii_in_responses: true
    escalation_keywords:
      - "speak to a human"
      - "supervisor"
      - "complaint"
"""

import yaml

def load_yaml_config(path: str) -> dict:
    with open(path, "r") as f:
        config = yaml.safe_load(f)
    return config

The critical detail here is yaml.safe_load. Never use yaml.load with untrusted input — it can execute arbitrary Python code. safe_load restricts parsing to basic data types.

Hear it before you finish reading

Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.

Try Live Demo →

TOML Configuration

TOML is more explicit than YAML and avoids its indentation pitfalls. It is the standard for Python packaging (pyproject.toml) and has first-class support in Python 3.11 and later via tomllib.

TOML_EXAMPLE = """
[agent]
name = "support-agent"
model = "gpt-4o"
temperature = 0.7
max_tokens = 2048

system_prompt = '''
You are a customer support agent for Acme Corp.
Always be polite and professional.
If you cannot resolve an issue, escalate to a human agent.
'''

[guardrails]
max_tool_calls_per_turn = 3
block_pii_in_responses = true
escalation_keywords = ["speak to a human", "supervisor", "complaint"]

[[tools]]
name = "search_docs"
description = "Search the knowledge base"
enabled = true

[[tools]]
name = "create_ticket"
description = "Create a support ticket"
enabled = true
"""

try:
    import tomllib
except ImportError:
    import tomli as tomllib

def load_toml_config(path: str) -> dict:
    with open(path, "rb") as f:
        return tomllib.load(f)

TOML's advantage is unambiguous typing. In YAML, yes, on, true are all boolean true. In TOML, only true is boolean. This eliminates an entire class of subtle configuration bugs.

Python Configuration

Python config files offer maximum flexibility. You get type checking, computed values, and validation built into the config definition itself.

from pydantic import BaseModel, field_validator
from typing import Optional

class ToolConfig(BaseModel):
    name: str
    description: str
    enabled: bool = True
    requires_approval: bool = False

class GuardrailConfig(BaseModel):
    max_tool_calls_per_turn: int = 3
    block_pii_in_responses: bool = True
    escalation_keywords: list[str] = []

    @field_validator("max_tool_calls_per_turn")
    @classmethod
    def validate_max_calls(cls, v: int) -> int:
        if not 1 <= v <= 20:
            raise ValueError("max_tool_calls_per_turn must be 1-20")
        return v

class AgentConfig(BaseModel):
    name: str
    model: str = "gpt-4o"
    temperature: float = 0.7
    max_tokens: int = 2048
    system_prompt: str
    tools: list[ToolConfig] = []
    guardrails: GuardrailConfig = GuardrailConfig()

    @field_validator("temperature")
    @classmethod
    def validate_temp(cls, v: float) -> float:
        if not 0.0 <= v <= 2.0:
            raise ValueError("Temperature must be 0.0-2.0")
        return v

Default Merging

A common pattern is merging user-provided config with defaults. The user only specifies what they want to change.

from copy import deepcopy

def deep_merge(base: dict, override: dict) -> dict:
    result = deepcopy(base)
    for key, value in override.items():
        if (
            key in result
            and isinstance(result[key], dict)
            and isinstance(value, dict)
        ):
            result[key] = deep_merge(result[key], value)
        else:
            result[key] = deepcopy(value)
    return result

DEFAULTS = {
    "agent": {
        "model": "gpt-4o-mini",
        "temperature": 0.7,
        "max_tokens": 1024,
    },
    "guardrails": {
        "max_tool_calls_per_turn": 3,
        "block_pii_in_responses": True,
    },
}

def load_with_defaults(config_path: str) -> dict:
    user_config = load_toml_config(config_path)
    return deep_merge(DEFAULTS, user_config)

Unified Config Loader

In practice, you want a single loader that handles any format and validates the result.

Still reading? Stop comparing — try CallSphere live.

CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.

from pathlib import Path

class ConfigLoader:
    LOADERS = {
        ".yaml": lambda p: yaml.safe_load(open(p)),
        ".yml": lambda p: yaml.safe_load(open(p)),
        ".toml": lambda p: tomllib.load(open(p, "rb")),
        ".json": lambda p: json.load(open(p)),
    }

    @classmethod
    def load(cls, path: str) -> AgentConfig:
        p = Path(path)
        loader = cls.LOADERS.get(p.suffix)
        if not loader:
            raise ValueError(f"Unsupported config format: {p.suffix}")

        raw = loader(path)
        merged = deep_merge(DEFAULTS, raw)

        agent_data = merged.get("agent", {})
        agent_data["guardrails"] = merged.get("guardrails", {})
        agent_data["tools"] = merged.get("tools", [])

        return AgentConfig(**agent_data)

Format Comparison

Use YAML when your team is already in the Kubernetes ecosystem and familiar with its conventions. Use TOML when you want strict, unambiguous typing and your config is relatively flat. Use Python configs when you need computed values, complex validation, or type safety throughout. For most AI agent projects, TOML combined with Pydantic validation offers the best balance of readability and safety.

FAQ

How do I handle multi-line system prompts in TOML?

TOML supports multi-line strings with triple quotes. Use single-quoted triple quotes (''') for literal strings where backslashes are not interpreted as escapes. This is ideal for system prompts that may contain special characters.

Should I validate config files in CI?

Absolutely. Add a CI step that loads every config file through your validation layer. This catches typos, invalid values, and missing required fields before they reach any environment. The validation step should take less than a second and prevents entire classes of deployment failures.

When should I avoid configuration-as-code?

When configurations change frequently (multiple times per day) and are managed by non-technical users. In that case, a database-backed config with an admin UI is more appropriate. Configuration-as-code works best for settings that change with releases and are managed by the engineering team.


#ConfigurationAsCode #AIAgents #YAML #TOML #Python #AgenticAI #LearnAI #AIEngineering

Share

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

AI Agents

Personal AI Assistant: How to Pick One for Business in 2026

A founder's guide to the personal AI assistant market: best AI assistant apps, business-grade options, and how CallSphere's voice agent fits in.

AI Agents

Free AI Agents in 2026: When Free Wins and When It Costs You

A founder's guide to free AI agents, low-code AI agent builders, and how to know when you should pay for a real platform like CallSphere.

Agentic AI

Graphiti: How Temporal Knowledge Graphs Give AI Voice Agents Persistent Memory (2026 Guide)

Graphiti is the open-source temporal knowledge graph for AI agents in 2026. Learn how bi-temporal memory beats vector RAG for voice agents and long-running LLMs.

AI Agents

Chatbot App vs ChatGPT: What's the Difference, and Which Do I Need?

Chatbot app vs ChatGPT in 2026: a founder's clear take on the difference, when to use which, and how a real AI chatbot app development works.

HVAC

Building an HVAC After-Hours Emergency Escalation System: A Complete Engineering Guide

How we built a fault-tolerant HVAC emergency triage and tech-dispatch platform on Kubernetes — three-tier CQRS, 11 micro-agents on the OpenAI Agents SDK + LangGraph, NATS JetStream, DTMF/SMS/WebSocket acceptance, circuit breakers, and an evaluation pipeline that catches regressions before they wake a tech at 3 AM.

Enterprise AI

OpenAI Frontier vs Anthropic Managed Agents: 2026 Comparison

Head-to-head: OpenAI Frontier and Anthropic's managed agent stack — strengths, fit, and what each means for enterprise AI voice and chat deployment.