# This page will use the following imports:
from lasagna import Model, EventCallback, AgentRun
from lasagna import (
recursive_extract_messages,
override_system_prompt,
noop_callback,
extraction,
parallel_runs,
)
from lasagna import known_models
from lasagna.tui import tui_input_loop
from pydantic import BaseModel, Field
import os
import asyncio
from dotenv import load_dotenvParallelizing
Lasagna AI is built on asyncio, so parallelization (cough, concurrency) is easy.
Also, the AgentRun type can accurately capture which agents you ran in parallel!
We need to set up our βbinderβ (see the quickstart guide for what this is).
load_dotenv()
if os.environ.get('ANTHROPIC_API_KEY'):
print('Using Anthropic')
binder = known_models.anthropic_claude_sonnet_4_5_binder
elif os.environ.get('OPENAI_API_KEY'):
print('Using OpenAI')
binder = known_models.openai_gpt_5_mini_binder
else:
assert False, "Neither OPENAI_API_KEY nor ANTHROPIC_API_KEY is set! We need at least one to do this demo."Using Anthropic
WarningAPI Limits!
Be careful not to exceed your API request (or token count) limits!
A Common Example
A common example of wanting to run agents in parallel is when you want to extract different independent information. You can do those independent extractions in parallel!
class NameOutput(BaseModel):
thoughts: str = Field(description='your free-form thoughts')
name_is_known: bool = Field(description="true if the user has indicated their name; false otherwise")
name: str = Field(description="the user's name (if known); an empty string otherwise")
@binder
async def name_extractor(
model: Model,
event_callback: EventCallback,
prev_runs: list[AgentRun],
) -> AgentRun:
messages = recursive_extract_messages(prev_runs, from_tools=False, from_extraction=False)
messages = override_system_prompt(messages, "You extract the user's name from the conversation.")
message, result = await model.extract(
noop_callback,
messages = messages,
extraction_type = NameOutput,
)
return extraction('name_extractor', [message], result)class AgeOutput(BaseModel):
thoughts: str = Field(description='your free-form thoughts')
age_is_known: bool = Field(description="true if the user has indicated their age; false otherwise")
age: int = Field(description="the user's age (if known); zero otherwise")
@binder
async def age_extractor(
model: Model,
event_callback: EventCallback,
prev_runs: list[AgentRun],
) -> AgentRun:
messages = recursive_extract_messages(prev_runs, from_tools=False, from_extraction=False)
messages = override_system_prompt(messages, "You extract the user's age from the conversation.")
message, result = await model.extract(
noop_callback,
messages = messages,
extraction_type = AgeOutput,
)
return extraction('age_extractor', [message], result)@binder
async def root_agent(
model: Model,
event_callback: EventCallback,
prev_runs: list[AgentRun],
) -> AgentRun:
name_coro = name_extractor(event_callback, prev_runs)
age_coro = age_extractor(event_callback, prev_runs)
name_run, age_run = await asyncio.gather(name_coro, age_coro)
assert name_run['type'] == 'extraction'
assert age_run['type'] == 'extraction'
print(name_run['result'])
print(age_run['result'])
return parallel_runs('root_agent', [name_run, age_run])await tui_input_loop(root_agent) # type: ignore[top-level-await]> Hi
thoughts='The user has just said "Hi" which is a simple greeting. They haven\'t provided their name or any identifying information in this message.' name_is_known=False name='' thoughts='The user just said "Hi" which is a simple greeting. They haven\'t provided any information about their age, so I don\'t know how old they are.' age_is_known=False age=0
> I'm Ryan. Who are you?
thoughts='The user has clearly stated their name is Ryan in their greeting "Hi I\'m Ryan." They then ask who I am, but my task is to extract their name from the conversation.' name_is_known=True name='Ryan' thoughts='The user introduced themselves as Ryan but did not mention their age at all. I need to indicate that the age is not known and set it to zero as specified.' age_is_known=False age=0
> I was born in 1945. It's now 2025.
thoughts='The user has clearly stated "I\'m Ryan" so their name is Ryan and they have indicated their name to me. They also provided some additional information about being born in 1945 and that it\'s now 2025, and asked who I am, but the main task is to extract their name.' name_is_known=True name='Ryan' thoughts="The user Ryan mentioned he was born in 1945 and that it's now 2025. I can calculate his age by subtracting his birth year from the current year: 2025 - 1945 = 80 years old. The user has clearly indicated his birth year, so I know his age." age_is_known=True age=80
> exit
NoteWhy Different Invocations?
Like humans, an AI model often does better when it focuses on a single task. As such, invoking it twice, once for each independent task, often yields better results (as opposed to prompting once and asking for two tasks in your prompt).