Define and execute complex workflows using YAML configuration files
from praisonaiagents import Agentagent = Agent(name="pipeline-runner", instructions="Execute multi-step YAML workflows.")agent.start("Run my workflow.yaml with sequential and parallel steps.")
The user authors YAML once; PraisonAI loads steps, routing, and parallel blocks at runtime.Define complex multi-agent workflows in YAML files with support for advanced patterns like routing, parallel execution, loops, and more.
name: My Workflowinput: "Your input here" # The data passed INTO the workflow (accessed via {{input}})agents: my_agent: role: Assistant goal: Help with the task instructions: "You are a helpful assistant"steps: - agent: my_agent action: "Process this: {{input}}"
Field
Required
Default
Description
agents
✅
-
At least one agent definition
agents.*.role
✅
-
Agent’s job title
steps
✅
-
At least one step
steps.*.agent
✅
-
Agent to execute the step
name
❌
“Workflow”
Workflow identifier
input
❌
""
Data passed INTO the workflow (accessed via {{input}})
goal
❌
“Complete the task”
Agent’s objective
instructions
❌
Generic
Agent behavior/persona
action
❌
{{input}}
What the step does
input vs topic: Use input (canonical) for clarity. topic still works for backward compatibility but input better conveys that this is the data going INTO your workflow.
Action templating — every action string supports three placeholders, processed in order:
{{your_variable}} — replaced with values from variables: or earlier output_variable fields.
{{previous_output}} — replaced in place or auto-appended as "Context from previous step: …" if the token is absent and a previous output exists.
{{input}} — replaced with the top-level input: value, available in every step.
Both agents.yaml and workflow.yaml now support the same features:
Feature
agents.yaml
workflow.yaml
Workflow patterns (route, parallel, loop, repeat)
✅
✅
All agent fields
✅
✅
All step/task fields
✅
✅
Framework support (praisonai, crewai, autogen)
✅
✅
Process types (sequential, hierarchical, workflow)
✅
✅
Planning & Reasoning
✅
✅
Task names must be unique across agents (roles). With the CrewAI framework, two agents defining a task with the same name (e.g. both agents.alice.tasks.write_report and agents.bob.tasks.write_report) raise:
ValueError: Duplicate CrewAI task name: 'write_report'. Task names must be unique across roles so context wiring resolves to the correct task.
Rename one of the tasks (e.g. write_report_bob). Before PraisonAI #2471 the duplicate silently overwrote the earlier task and context=[...] lookups resolved to the wrong task — the new error catches this fast.
# Run a YAML workflowpraisonai workflow run research.yaml# Run with variablespraisonai workflow run research.yaml --var topic="AI trends"# Validate a workflowpraisonai workflow validate research.yaml# Create from templatepraisonai workflow template routing --output my_workflow.yaml# Auto-generate a workflowpraisonai workflow auto "Research AI trends" --pattern parallel
from praisonaiagents import YAMLWorkflowParser, WorkflowManager# Option 1: Parse and executeparser = YAMLWorkflowParser()workflow = parser.parse_file("research.yaml")result = workflow.start("Research AI trends")# Option 2: Use WorkflowManagermanager = WorkflowManager()result = manager.execute_yaml( "research.yaml", input_data="Research AI trends", variables={"topic": "Machine Learning"})
# Option 3: AgentsGenerator (auto-detects workflow YAML)from praisonai.agents_generator import AgentsGenerator# Sync pathgen = AgentsGenerator(agent_file="research.yaml")result = gen.generate_crew_and_kickoff()# Async path (works the same as sync)import asyncioasync def main(): gen = AgentsGenerator(agent_file="research.yaml") return await gen.agenerate_crew_and_kickoff()result = asyncio.run(main())
Programmatic Routing: The AgentsGenerator wrapper auto-detects workflow YAML and routes to the appropriate engine:
Discriminator in YAML
Routed to
process: workflow
YAMLWorkflowParser
steps: + workflow:
YAMLWorkflowParser
type: job
YAMLWorkflowParser
type: hybrid
YAMLWorkflowParser
(none of the above)
Framework adapter
This means calling AgentsGenerator(agent_file="release.yaml").generate_crew_and_kickoff() with a job/hybrid YAML now routes correctly to the workflow runner instead of falling through to the framework adapter.
Async parity (extended in PR #2738):agenerate_crew_and_kickoff() now initializes observability and adapter setup the same way generate_crew_and_kickoff() does — Langfuse / AgentOps traces are wired on both paths. Both paths also share a single _build_yaml_workflow builder, so config validation, merge, and dump logic live in exactly one place — sync and async behavior is guaranteed identical.
Workflow YAML framework: is validated. Workflow dispatch requires an adapter whose SUPPORTS_WORKFLOW = True (the built-in praisonai adapter has it). Declaring a framework without that flag (e.g. framework: crewai) raises ValueError:
ValueError: framework='crewai' in workflow YAML is not supported for workflow execution.The workflow engine requires an adapter whose SUPPORTS_WORKFLOW flag is set (the native 'praisonai' adapter does).Use a non-workflow agents.yaml with a supported registered framework, or set framework: praisonai. Frameworks supporting workflow execution: praisonai.
For non-praisonai execution, use an agents.yaml-style file via AgentsGenerator. See Workflow YAML Framework Field for details.
Execute multiple steps sequentially for each item in the loop. This is perfect for pipelines where each item needs to go through several processing stages (e.g., research → write → publish).
Context Isolation: Each loop iteration is isolated - context doesn’t leak between iterations. Within an iteration, {{previous_output}} chains between steps.
name: Multi-Step Loop Workflowvariables: topics: - Machine Learning - Natural Language Processing - Computer Visionagents: researcher: role: Research Analyst goal: Research topics thoroughly instructions: "Provide comprehensive research" tools: - tavily_search writer: role: Content Writer goal: Write engaging articles instructions: "Write in British English, include code examples" publisher: role: WordPress Publisher goal: Publish content to WordPress instructions: "Validate content before publishing" tools: - create_wp_poststeps: # Multi-step loop: research → write → publish for EACH topic - loop: over: topics parallel: true # Process topics in parallel max_workers: 4 # Limit concurrent executions steps: - agent: researcher action: "Research {{item}} thoroughly" - agent: writer action: "Write article based on: {{previous_output}}" - agent: publisher action: "Publish: {{previous_output}}"# Enable context management to prevent token overflowcontext: enabled: true max_tool_output_tokens: 5000
Get structured JSON responses from agents using output_json (inline schema) or output_pydantic (reference to Pydantic model in tools.py).
Inline JSON Schema (Option A)
Pydantic Reference (Option B)
name: Structured Output Workflowagents: topic_finder: role: Topic Finder goal: Find AI topics instructions: "Return topics as structured JSON"steps: - agent: topic_finder action: "Find 3 AI topics" output_json: type: array items: type: object properties: title: type: string url: type: string required: - title - url output_variable: topics # Loop over the structured output - agent: researcher action: "Research: {{item.title}}" loop: over: topics
# agents.yamlname: Structured Output Workflowagents: topic_finder: role: Topic Finder goal: Find AI topics instructions: "Return topics as structured JSON"steps: - agent: topic_finder action: "Find 3 AI topics" output_pydantic: TopicList # Reference to class in tools.py output_variable: topics
# tools.py (in same directory)from pydantic import BaseModelfrom typing import Listclass Topic(BaseModel): title: str url: strclass TopicList(BaseModel): items: List[Topic]
How it works: When output_json or output_pydantic is specified, PraisonAI automatically uses the LLM’s native structured output feature (response_format) for supported models.Supported Models: GPT-4o, GPT-4o-mini, Claude 3.5 Sonnet, Gemini 2.0 FlashFlow:
Agent checks if model supports native structured output
If supported → uses response_format with JSON schema (clean output)
If not supported → falls back to prompt injection (schema in prompt)
Force Native Mode: In Python, use native_structured_output=True on the Agent to force native mode:
name: Parent Workflowtopic: "AI Code & Tools 2026"variables: today: "January 2026"agents: writer: role: Content Writer goal: Write content instructions: "Write engaging content"steps: # Include a modular recipe - it receives parent's variables - include: ai-topic-gatherer # Or with explicit configuration - include: recipe: ai-research-pipeline input: "{{previous_output}}" # Continue with local steps - agent: writer action: "Write blog post about: {{previous_output}}"
Variable Passing: When you include a recipe, the parent’s topic, variables, and other fields are automatically passed to the child recipe. The child can use {{topic}} in its actions.