|
| 1 | +# Rapid Multi-Agent App Development with Orra |
| 2 | + |
| 3 | +Stop wrestling with rigid agent frameworks. Orra lets you build production-ready multi-agent systems the way you actually work - starting simple and scaling naturally. |
| 4 | + |
| 5 | +## Why Orra? |
| 6 | + |
| 7 | +As AI engineers, we've all been there: |
| 8 | +- Struggling with inflexible agent frameworks that force specific patterns |
| 9 | +- Hitting walls when moving from prototype to production |
| 10 | +- Writing endless boilerplate for agent communication |
| 11 | +- Fighting with fragile orchestration code |
| 12 | +- Dealing with frameworks that assume all agents live in one process |
| 13 | + |
| 14 | +Orra is different. It's built for AI engineers who need to: |
| 15 | +1. **Prototype Fast**: Start with everything in one file - just like you would naturally |
| 16 | +2. **Focus on Logic**: Write agents that do one thing well, Orra handles the rest |
| 17 | +3. **Stay Flexible**: No forced patterns, no rigid structures, no mandatory "crew" abstractions |
| 18 | +4. **Scale Naturally**: Same code works whether your agents are in one file or distributed globally |
| 19 | +5. **Ship Confidently**: Production-ready from day one - just split and deploy when ready |
| 20 | + |
| 21 | +## The Orra Advantage |
| 22 | + |
| 23 | +```python |
| 24 | +# This seemingly simple setup is incredibly powerful: |
| 25 | +researcher = OrraAgent( |
| 26 | + name="research-agent", |
| 27 | + description="Researches topics using web search and knowledge base" |
| 28 | +) |
| 29 | + |
| 30 | +writer = OrraAgent( |
| 31 | + name="writing-agent", |
| 32 | + description="Crafts polished content from research" |
| 33 | +) |
| 34 | + |
| 35 | +formatter = OrraService( |
| 36 | + name="format-service", |
| 37 | + description="Formats and validates final content" |
| 38 | +) |
| 39 | +``` |
| 40 | + |
| 41 | +Behind the scenes, Orra: |
| 42 | +- Dynamically figures out how agents should interact |
| 43 | +- Handles all messaging and retries |
| 44 | +- Manages state and failure recovery |
| 45 | +- Scales from local to distributed seamlessly |
| 46 | +- Requires zero orchestration code from you |
| 47 | + |
| 48 | +Let's see how this works in practice... |
| 49 | + |
| 50 | +## Quick Example |
| 51 | + |
| 52 | +```python |
| 53 | +from orra import OrraService, OrraAgent, Task |
| 54 | +from pydantic import BaseModel, Field |
| 55 | +from typing import List |
| 56 | +import asyncio |
| 57 | + |
| 58 | +# --- Models --- |
| 59 | + |
| 60 | +class ResearchInput(BaseModel): |
| 61 | + topic: str |
| 62 | + depth: str = Field(default="medium", description="Research depth: basic, medium, deep") |
| 63 | + |
| 64 | +class ResearchOutput(BaseModel): |
| 65 | + summary: str |
| 66 | + key_points: List[str] |
| 67 | + sources: List[str] |
| 68 | + |
| 69 | +class WritingInput(BaseModel): |
| 70 | + content: str |
| 71 | + style: str = Field(default="professional") |
| 72 | + |
| 73 | +class WritingOutput(BaseModel): |
| 74 | + text: str |
| 75 | + word_count: int |
| 76 | + |
| 77 | +# --- Services & Agents --- |
| 78 | + |
| 79 | +# Initialize with single API key |
| 80 | +researcher = OrraAgent( |
| 81 | + name="research-agent", |
| 82 | + description="Researches topics using web search and knowledge base", |
| 83 | + url="https://api.orra.dev", |
| 84 | + api_key="sk-orra-..." |
| 85 | +) |
| 86 | + |
| 87 | +writer = OrraAgent( |
| 88 | + name="writing-agent", |
| 89 | + description="Crafts polished content from research", |
| 90 | + url="https://api.orra.dev", |
| 91 | + api_key="sk-orra-..." # Same key, Orra handles routing |
| 92 | +) |
| 93 | + |
| 94 | +formatter = OrraService( |
| 95 | + name="format-service", |
| 96 | + description="Formats and validates final content", |
| 97 | + url="https://api.orra.dev", |
| 98 | + api_key="sk-orra-..." |
| 99 | +) |
| 100 | + |
| 101 | +# --- Handlers --- |
| 102 | + |
| 103 | +@researcher.handler() |
| 104 | +async def research(task: Task[ResearchInput]) -> ResearchOutput: |
| 105 | + """Research handler using your preferred tools (Tavily, web search, etc)""" |
| 106 | + # Your research implementation |
| 107 | + research_result = await your_research_function(task.input.topic, task.input.depth) |
| 108 | + return ResearchOutput( |
| 109 | + summary=research_result.summary, |
| 110 | + key_points=research_result.points, |
| 111 | + sources=research_result.sources |
| 112 | + ) |
| 113 | + |
| 114 | +@writer.handler() |
| 115 | +async def write(task: Task[WritingInput]) -> WritingOutput: |
| 116 | + """Writing handler using your LLM of choice""" |
| 117 | + # Your writing implementation |
| 118 | + written_content = await your_llm_function(task.input.content, task.input.style) |
| 119 | + return WritingOutput( |
| 120 | + text=written_content, |
| 121 | + word_count=len(written_content.split()) |
| 122 | + ) |
| 123 | + |
| 124 | +@formatter.handler() |
| 125 | +async def format(task: Task[WritingInput]) -> WritingOutput: |
| 126 | + """Formatting service - could be stateless language processing""" |
| 127 | + # Your formatting implementation |
| 128 | + formatted = await your_formatter(task.input.text) |
| 129 | + return WritingOutput( |
| 130 | + text=formatted, |
| 131 | + word_count=len(formatted.split()) |
| 132 | + ) |
| 133 | + |
| 134 | +# --- Run Everything --- |
| 135 | + |
| 136 | +async def main(): |
| 137 | + # Start all services concurrently |
| 138 | + await asyncio.gather( |
| 139 | + researcher.start(), |
| 140 | + writer.start(), |
| 141 | + formatter.start() |
| 142 | + ) |
| 143 | + |
| 144 | +if __name__ == "__main__": |
| 145 | + asyncio.run(main()) |
| 146 | +``` |
| 147 | + |
| 148 | +## Usage |
| 149 | + |
| 150 | +1. Run your agents: |
| 151 | +```bash |
| 152 | +python agents.py |
| 153 | +``` |
| 154 | + |
| 155 | +2. Orchestrate with CLI: |
| 156 | +```bash |
| 157 | +# Research and write about AI |
| 158 | +orra verify run 'Research and write an article about AI trends' \ |
| 159 | + --data topic:'AI in 2024' \ |
| 160 | + --data style:'technical' |
| 161 | +``` |
| 162 | + |
| 163 | +Orra automatically: |
| 164 | +- Determines the optimal execution flow |
| 165 | +- Handles all agent communication |
| 166 | +- Manages retries and failures |
| 167 | +- Scales execution based on dependencies |
| 168 | + |
| 169 | +## Best Practices |
| 170 | + |
| 171 | +1. **Model Design** |
| 172 | + - Use Pydantic for validation |
| 173 | + - Clear field descriptions |
| 174 | + - Sensible defaults |
| 175 | + |
| 176 | +2. **Error Handling** |
| 177 | + - Let agents handle retries |
| 178 | + - Throw on permanent failures |
| 179 | + - Orra manages recovery |
| 180 | + |
| 181 | +3. **Development Flow** |
| 182 | + ``` |
| 183 | + Prototype (single file) |
| 184 | + → Test & Refine |
| 185 | + → Split Services |
| 186 | + → Deploy |
| 187 | + ``` |
| 188 | + |
| 189 | +## Going to Production |
| 190 | + |
| 191 | +When ready, split into separate services: |
| 192 | +```plaintext |
| 193 | +services/ |
| 194 | + ├── researcher/ |
| 195 | + │ └── main.py # Just researcher code |
| 196 | + ├── writer/ |
| 197 | + │ └── main.py # Just writer code |
| 198 | + └── formatter/ |
| 199 | + └── main.py # Just formatter code |
| 200 | +``` |
| 201 | + |
| 202 | +Orra orchestrates them the same way! |
| 203 | + |
| 204 | +## Tips |
| 205 | + |
| 206 | +1. **Development** |
| 207 | + - Use shared utilities |
| 208 | + - Test locally first |
| 209 | + - Monitor execution logs |
| 210 | + |
| 211 | +2. **Debugging** |
| 212 | + ```bash |
| 213 | + # Watch execution |
| 214 | + orra ps |
| 215 | + |
| 216 | + # Inspect flow |
| 217 | + orra inspect -d <orchestration-id> |
| 218 | + |
| 219 | + ``` |
| 220 | + |
| 221 | +3. **Advanced Features** |
| 222 | + - Custom retries per agent |
| 223 | + - Stateful agents |
| 224 | + - Parallel execution |
| 225 | + - Webhook notifications |
| 226 | + |
| 227 | +Need help? Check out our [examples](../examples) or join our Discord! |
0 commit comments