Overview
Reminix allows you to serve multiple agents from a single project. This page covers when and why to use multiple agents, architecture patterns, and best practices.
Single vs Multiple Agents
Single Agent
Best for:
- Simple, focused use cases
- One task or domain
- Minimal complexity
from reminix_langchain import serve_agent
serve_agent(agent, name="my-agent", port=8080)
Multiple Agents
Best for:
- Specialized agents for different tasks
- Shared infrastructure and dependencies
- Multi-agent orchestration
- Microservice-style architecture
from reminix_langchain import wrap_agent
from reminix_runtime import serve
research = wrap_agent(research_chain, name="research")
writer = wrap_agent(writing_chain, name="writer")
serve(agents=[research, writer], port=8080)
Use Cases
Task Specialization
Different agents optimized for specific tasks:
| Agent | Purpose | Model/Config |
|---|
summarizer | Condense long documents | Fast model, low tokens |
researcher | Deep analysis with tools | Powerful model, web search |
translator | Language translation | Multilingual model |
classifier | Categorization | Fine-tuned classifier |
Multi-Step Workflows
Orchestrate multiple agents for complex workflows:
A/B Testing
Run different agent versions side-by-side:
agent_v1 = wrap_agent(chain_v1, name="assistant-v1")
agent_v2 = wrap_agent(chain_v2, name="assistant-v2")
serve(agents=[agent_v1, agent_v2], port=8080)
Gradual Migration
Migrate from one framework to another incrementally:
from reminix_runtime import agent, serve
# Old agent (LangChain)
legacy = wrap_langchain(old_chain, name="assistant")
# New agent (custom)
@agent(name="assistant-beta")
async def new_agent(prompt: str) -> str:
return "New implementation"
# Serve both during migration
serve(agents=[legacy, new_agent], port=8080)
Architecture Patterns
Monolithic Multi-Agent
All agents in one project, one deployment:
Pros:
- Shared dependencies
- Simple deployment
- Low latency between agents
Cons:
- Coupled scaling
- Single point of failure
- Larger deployments
Distributed Agents
Separate projects for each agent:
Pros:
- Independent scaling
- Isolated failures
- Team autonomy
Cons:
- More infrastructure
- Network latency
- Dependency management
Hybrid Approach
Group related agents, separate unrelated ones:
Best Practices
Naming Conventions
Use clear, descriptive names:
# Good
@agent(name="document-summarizer")
async def summarizer(text: str) -> str: ...
@agent(name="email-classifier")
async def classifier(text: str) -> dict: ...
# Avoid
@agent(name="agent1")
async def agent1(x: str) -> str: ...
Consistent Framework
Use a single framework per project for best results:
# Recommended - single framework
from reminix_langchain import wrap_agent
agent1 = wrap_agent(chain1, name="agent-1")
agent2 = wrap_agent(chain2, name="agent-2")
Mixing agents from different frameworks is technically possible but not officially supported.
Resource Sharing
Share expensive resources across agents:
from reminix_runtime import agent, serve
# Shared across all agents
llm = ChatOpenAI(model="gpt-4o")
embeddings = OpenAIEmbeddings()
# Each agent uses shared resources
@agent
async def researcher(query: str) -> str:
return await llm.ainvoke(query)
@agent
async def writer(prompt: str) -> str:
return await llm.ainvoke(prompt)
Error Isolation
Handle errors per-agent to prevent cascading failures:
@agent
async def my_agent(prompt: str) -> str:
try:
result = await process(prompt)
return result
except Exception as e:
# Log and return graceful error
logger.error(f"Agent error: {e}")
raise
Calling Multiple Agents
Sequential Calls
# Step 1: Research
research_result = client.agents.invoke(
"researcher",
query="AI trends"
)
# Step 2: Write using research
article = client.agents.invoke(
"writer",
prompt=f"Write about: {research_result['output']}"
)
Parallel Calls
import asyncio
async def process():
# Run agents in parallel
summary, translation = await asyncio.gather(
client.agents.invoke_async("summarizer", text=doc),
client.agents.invoke_async("translator", text=doc, target="es")
)
return summary, translation
Next Steps