Workflow Templates
Because a Workflow.run() is plain Python, common orchestration patterns are
just code. The templates below are complete Workflow subclasses that call real
agents — adapt them to your task.
Patterns, not primitives
buddy-ai does not provide if_step/loop/parallel operators. Each pattern
here is implemented with ordinary if, while, for and (for fan-out)
threads. See Definition and Execution.
Sequential pipeline
Each stage feeds the next.
from buddy.workflow import Workflow, RunResponse
from buddy import Agent
from buddy.models.openai import OpenAIChat
class Pipeline(Workflow):
researcher = Agent(model=OpenAIChat(id="gpt-4o-mini"))
writer = Agent(model=OpenAIChat(id="gpt-4o"))
editor = Agent(model=OpenAIChat(id="gpt-4o-mini"))
def run(self, topic: str) -> RunResponse:
research = self.researcher.run(f"Research: {topic}").content
draft = self.writer.run(f"Write an article:\n{research}").content
final = self.editor.run(f"Polish this:\n{draft}").content
return RunResponse(content=final)
Conditional branching
Pick a path based on a classification step.
class SupportWorkflow(Workflow):
classifier = Agent(model=OpenAIChat(id="gpt-4o-mini"))
billing = Agent(model=OpenAIChat(id="gpt-4o"))
technical = Agent(model=OpenAIChat(id="gpt-4o"))
def run(self, question: str) -> RunResponse:
kind = self.classifier.run(
f"Reply with one word, 'billing' or 'technical':\n{question}"
).content.strip().lower()
if "billing" in kind:
answer = self.billing.run(question).content
else:
answer = self.technical.run(question).content
return RunResponse(content=answer)
Loop / iterative refinement
Repeat until a critic is satisfied or a budget is exhausted.
class RefineWorkflow(Workflow):
writer = Agent(model=OpenAIChat(id="gpt-4o"))
critic = Agent(model=OpenAIChat(id="gpt-4o-mini"))
def run(self, brief: str, max_iters: int = 3) -> RunResponse:
draft = self.writer.run(f"Draft:\n{brief}").content
for _ in range(max_iters):
review = self.critic.run(
f"Reply 'APPROVED' or give specific fixes:\n{draft}"
).content
if "APPROVED" in review.upper():
break
draft = self.writer.run(f"Revise using feedback:\n{review}\n\n{draft}").content
return RunResponse(content=draft)
Fan-out / fan-in (parallel)
Run independent agents concurrently with a thread pool, then combine.
from concurrent.futures import ThreadPoolExecutor
class FanOutWorkflow(Workflow):
analyst = Agent(model=OpenAIChat(id="gpt-4o-mini"))
synthesizer = Agent(model=OpenAIChat(id="gpt-4o"))
def run(self, topics: list[str]) -> RunResponse:
# Fan-out: analyze each topic in parallel
with ThreadPoolExecutor(max_workers=len(topics)) as pool:
parts = list(pool.map(
lambda t: self.analyst.run(f"Analyze: {t}").content, topics
))
# Fan-in: synthesize the parts into one answer
joined = "\n\n".join(parts)
summary = self.synthesizer.run(f"Synthesize these analyses:\n{joined}").content
return RunResponse(content=summary)
Delegating to a team
A workflow stage can be a whole Team, combining deterministic control flow with
LLM-driven coordination.
from buddy import Team
class HybridWorkflow(Workflow):
research_team = Team(
members=[web_agent, paper_agent],
mode="coordinate",
model=OpenAIChat(id="gpt-4o-mini"),
)
writer = Agent(model=OpenAIChat(id="gpt-4o"))
def run(self, topic: str) -> RunResponse:
research = self.research_team.run(f"Research: {topic}").content
article = self.writer.run(f"Write an article:\n{research}").content
return RunResponse(content=article)
Combine patterns
Real workflows mix these freely — e.g. a sequential pipeline whose middle
stage branches, with a refinement loop at the end. Keep run() readable by
extracting helper methods for each stage.