agentensemble 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentensemble-0.2.0/PKG-INFO +570 -0
- agentensemble-0.2.0/README.md +517 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/__init__.py +34 -1
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/__init__.py +3 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/base.py +31 -19
- agentensemble-0.2.0/agentensemble/agents/hybrid_agent.py +265 -0
- agentensemble-0.2.0/agentensemble/agents/react_agent.py +300 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/structured_agent.py +9 -1
- agentensemble-0.2.0/agentensemble/core/__init__.py +9 -0
- agentensemble-0.2.0/agentensemble/core/protocol.py +36 -0
- agentensemble-0.2.0/agentensemble/graph/__init__.py +9 -0
- agentensemble-0.2.0/agentensemble/graph/workflow.py +91 -0
- agentensemble-0.2.0/agentensemble/llm/__init__.py +34 -0
- agentensemble-0.2.0/agentensemble/llm/interface.py +142 -0
- agentensemble-0.2.0/agentensemble/llm/mistral_provider.py +207 -0
- agentensemble-0.2.0/agentensemble/memory/__init__.py +15 -0
- agentensemble-0.2.0/agentensemble/memory/session.py +54 -0
- agentensemble-0.2.0/agentensemble/memory/sqlite_session.py +104 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/__init__.py +4 -4
- agentensemble-0.2.0/agentensemble/orchestration/debate.py +102 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/ensemble.py +73 -40
- agentensemble-0.2.0/agentensemble/planner/__init__.py +9 -0
- agentensemble-0.2.0/agentensemble/planner/planner_agent.py +78 -0
- agentensemble-0.2.0/agentensemble/router/__init__.py +10 -0
- agentensemble-0.2.0/agentensemble/router/router_agent.py +175 -0
- agentensemble-0.2.0/agentensemble/runner.py +125 -0
- agentensemble-0.2.0/agentensemble/testing/comparison.py +117 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/__init__.py +7 -0
- agentensemble-0.2.0/agentensemble/tools/adapters.py +118 -0
- agentensemble-0.2.0/agentensemble/tools/function_tool.py +82 -0
- agentensemble-0.2.0/agentensemble/tools/protocol.py +115 -0
- agentensemble-0.2.0/agentensemble/tools/validator.py +120 -0
- agentensemble-0.2.0/agentensemble/tracing/__init__.py +10 -0
- agentensemble-0.2.0/agentensemble/tracing/hooks.py +82 -0
- agentensemble-0.2.0/agentensemble.egg-info/PKG-INFO +570 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble.egg-info/SOURCES.txt +29 -1
- {agentensemble-0.1.0 → agentensemble-0.2.0}/pyproject.toml +2 -2
- {agentensemble-0.1.0 → agentensemble-0.2.0}/setup.py +1 -4
- agentensemble-0.2.0/tests/test_agents.py +115 -0
- agentensemble-0.2.0/tests/test_comparison.py +107 -0
- agentensemble-0.2.0/tests/test_memory.py +65 -0
- agentensemble-0.2.0/tests/test_orchestration.py +99 -0
- agentensemble-0.2.0/tests/test_react_session.py +34 -0
- agentensemble-0.2.0/tests/test_runner.py +82 -0
- agentensemble-0.2.0/tests/test_tools.py +81 -0
- agentensemble-0.1.0/PKG-INFO +0 -407
- agentensemble-0.1.0/README.md +0 -354
- agentensemble-0.1.0/agentensemble/agents/hybrid_agent.py +0 -147
- agentensemble-0.1.0/agentensemble/agents/react_agent.py +0 -118
- agentensemble-0.1.0/agentensemble/testing/comparison.py +0 -82
- agentensemble-0.1.0/agentensemble/tools/validator.py +0 -51
- agentensemble-0.1.0/agentensemble.egg-info/PKG-INFO +0 -407
- {agentensemble-0.1.0 → agentensemble-0.2.0}/MANIFEST.in +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/rag_agent.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/stategraph_agent.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/pipeline.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/supervisor.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/swarm.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/py.typed +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/testing/__init__.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/testing/benchmark.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/testing/metrics.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/rag.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/registry.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/scraper.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/search.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/utils/__init__.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/utils/llm.py +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble.egg-info/dependency_links.txt +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble.egg-info/requires.txt +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble.egg-info/top_level.txt +0 -0
- {agentensemble-0.1.0 → agentensemble-0.2.0}/setup.cfg +0 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentensemble
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Orchestrate AI agents in perfect harmony - A comprehensive Python framework for building, testing, and orchestrating multi-agent AI systems
|
|
5
|
+
Author-email: Irfan Ali <irfanali29@hotmail.com>
|
|
6
|
+
Maintainer-email: Irfan Ali <irfanali29@hotmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/irfanalidv/AgentEnsemble
|
|
9
|
+
Project-URL: Documentation, https://github.com/irfanalidv/AgentEnsemble#readme
|
|
10
|
+
Project-URL: Repository, https://github.com/irfanalidv/AgentEnsemble
|
|
11
|
+
Project-URL: Issues, https://github.com/irfanalidv/AgentEnsemble/issues
|
|
12
|
+
Keywords: ai-agents,multi-agent,orchestration,langgraph,langchain,rag,agent-testing,agentic-ai,state-graph,react-agent
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
Requires-Dist: langchain>=0.1.0
|
|
25
|
+
Requires-Dist: langchain-core>=0.1.0
|
|
26
|
+
Requires-Dist: langchain-community>=0.0.20
|
|
27
|
+
Requires-Dist: langchain-mistralai>=0.1.0
|
|
28
|
+
Requires-Dist: langgraph>=0.0.20
|
|
29
|
+
Requires-Dist: pydantic>=2.0.0
|
|
30
|
+
Requires-Dist: typing-extensions>=4.5.0
|
|
31
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
35
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
37
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
39
|
+
Provides-Extra: observability
|
|
40
|
+
Requires-Dist: langsmith>=0.1.0; extra == "observability"
|
|
41
|
+
Requires-Dist: opentelemetry-api>=1.20.0; extra == "observability"
|
|
42
|
+
Provides-Extra: rag
|
|
43
|
+
Requires-Dist: chromadb>=0.4.0; extra == "rag"
|
|
44
|
+
Requires-Dist: sentence-transformers>=2.2.0; extra == "rag"
|
|
45
|
+
Requires-Dist: langchain-text-splitters>=0.0.1; extra == "rag"
|
|
46
|
+
Requires-Dist: beautifulsoup4>=4.12.0; extra == "rag"
|
|
47
|
+
Requires-Dist: langchain-mistralai>=0.1.0; extra == "rag"
|
|
48
|
+
Provides-Extra: search
|
|
49
|
+
Requires-Dist: duckduckgo-search>=4.0.0; extra == "search"
|
|
50
|
+
Requires-Dist: google-search-results>=2.4.2; extra == "search"
|
|
51
|
+
Provides-Extra: all
|
|
52
|
+
Requires-Dist: agentensemble[dev,observability,rag,search]; extra == "all"
|
|
53
|
+
|
|
54
|
+
# AgentEnsemble
|
|
55
|
+
|
|
56
|
+
**Production-ready multi-agent orchestration for Python**
|
|
57
|
+
|
|
58
|
+
AgentEnsemble is a modern framework for building and orchestrating AI agent systems. Designed for clarity, extensibility, and production use—comparable to LangGraph, CrewAI, and AutoGen.
|
|
59
|
+
|
|
60
|
+
[](https://www.python.org/downloads/)
|
|
61
|
+
[](LICENSE)
|
|
62
|
+
[](https://pypi.org/project/agentensemble/)
|
|
63
|
+
[](https://pepy.tech/projects/agentensemble)
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Design Philosophy
|
|
68
|
+
|
|
69
|
+
- **Modular** — Agents, tools, orchestration, and memory are decoupled
|
|
70
|
+
- **Async-first** — `run()` and `arun()` on all agents; parallel execution via `asyncio.gather`
|
|
71
|
+
- **Provider-agnostic** — LLM interface supports Mistral (OpenAI/Anthropic-ready)
|
|
72
|
+
- **Production patterns** — Runner, retries, hooks, tracing, session memory
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Architecture
|
|
77
|
+
|
|
78
|
+
<p align="center">
|
|
79
|
+
<img src="docs/agentensemble-architecture.png" alt="AgentEnsemble Architecture" width="800"/>
|
|
80
|
+
</p>
|
|
81
|
+
|
|
82
|
+
*Architecture, functionalities, and use cases — what AgentEnsemble is capable of.*
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
86
|
+
│ AgentEnsemble │
|
|
87
|
+
├─────────────┬─────────────┬─────────────┬───────────────────────┤
|
|
88
|
+
│ Agents │ Orchestration│ Tools │ Memory & Runner │
|
|
89
|
+
├─────────────┼─────────────┼─────────────┼───────────────────────┤
|
|
90
|
+
│ ReActAgent │ Ensemble │ SearchTool │ Session (InMemory, │
|
|
91
|
+
│ StateGraph │ Supervisor │ RAGTool │ SQLite) │
|
|
92
|
+
│ RAGAgent │ Swarm │ @function_ │ Runner + RunConfig │
|
|
93
|
+
│ HybridAgent │ Pipeline │ tool │ TraceHooks │
|
|
94
|
+
│ RouterAgent │ Debate │ Validation │ │
|
|
95
|
+
│ PlannerAgent│ │ │ │
|
|
96
|
+
└─────────────┴─────────────┴─────────────┴───────────────────────┘
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Quick Start
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pip install agentensemble
|
|
105
|
+
# Optional: pip install agentensemble[search,rag]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from agentensemble import ReActAgent, SearchTool, Runner
|
|
110
|
+
|
|
111
|
+
agent = ReActAgent(name="research", tools=[SearchTool()], max_iterations=5)
|
|
112
|
+
result = Runner.run(agent, "What are the latest AI breakthroughs in 2024?")
|
|
113
|
+
print(result["result"])
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Setup:** Copy `.env.example` to `.env` and add your keys. Use `KEY=value` format (no spaces around `=`).
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Examples — Code + Output
|
|
121
|
+
|
|
122
|
+
Each example is runnable. Requires `.env` with `MISTRAL_API_KEY` and `SERPER_API_KEY` (see `.env.example` for format).
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### 1. ReActAgent — LLM decides when to search
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from agentensemble import ReActAgent, SearchTool
|
|
130
|
+
|
|
131
|
+
agent = ReActAgent(name="research", tools=[SearchTool()], max_iterations=5)
|
|
132
|
+
result = agent.run("Who won the 2024 Nobel Prize in Physics?")
|
|
133
|
+
print(result["result"])
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Output:**
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
The 2024 Nobel Prize in Physics was awarded jointly to John J. Hopfield and
|
|
140
|
+
Geoffrey E. Hinton for their foundational discoveries and inventions that
|
|
141
|
+
enable machine learning with artificial neural networks.
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### 2. Custom @function_tool — Add your own tools
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from agentensemble import ReActAgent, SearchTool, function_tool
|
|
150
|
+
|
|
151
|
+
@function_tool(description="Get current weather for a city")
|
|
152
|
+
def get_weather(city: str) -> str:
|
|
153
|
+
return f"Weather in {city}: 72°F, partly cloudy"
|
|
154
|
+
|
|
155
|
+
agent = ReActAgent(tools=[SearchTool(), get_weather], max_iterations=4)
|
|
156
|
+
result = agent.run("What is the weather in Paris?")
|
|
157
|
+
print(result["result"])
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Output:**
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
The current weather in Paris is 72°F (22°C) with partly cloudy conditions.
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### 3. HybridAgent — LLM routes SEARCH → RAG → VALIDATE → ANSWER
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from agentensemble import HybridAgent, SearchTool
|
|
172
|
+
|
|
173
|
+
agent = HybridAgent(tools=[SearchTool()], max_iterations=5)
|
|
174
|
+
result = agent.run("What are the key trends in AI agents in 2024?")
|
|
175
|
+
print(result["result"][:300], "...")
|
|
176
|
+
print("Actions:", result["metadata"]["actions_taken"])
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Output:**
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
1. Multi-Modal AI Models Redefined Possibilities · 2. AI Agents Stepping Into
|
|
183
|
+
the Spotlight · 3. AI's Bold Move into Video Creation · 4. Rise of Open-Source AI...
|
|
184
|
+
Actions: ['SEARCH', 'SEARCH', 'RAG', 'VALIDATE', 'ANSWER']
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### 4. Swarm — Parallel agents (multiple perspectives)
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from agentensemble import ReActAgent, SwarmOrchestrator, SearchTool
|
|
193
|
+
|
|
194
|
+
researcher = ReActAgent(name="researcher", tools=[SearchTool()], max_iterations=2)
|
|
195
|
+
fact_checker = ReActAgent(name="fact_checker", tools=[SearchTool()], max_iterations=2)
|
|
196
|
+
|
|
197
|
+
swarm = SwarmOrchestrator(agents={"researcher": researcher, "fact_checker": fact_checker})
|
|
198
|
+
result = swarm.perform("What is the capital of France?")
|
|
199
|
+
for name, r in result["results"].items():
|
|
200
|
+
print(f"{name}: {r['result'][:80]}...")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Output:**
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
researcher: The capital of France is Paris.
|
|
207
|
+
fact_checker: The capital of France is Paris.
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
### 5. Pipeline — Sequential (search → summarize)
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from agentensemble import ReActAgent, PipelineOrchestrator, SearchTool
|
|
216
|
+
|
|
217
|
+
searcher = ReActAgent(name="searcher", tools=[SearchTool()], max_iterations=2)
|
|
218
|
+
summarizer = ReActAgent(name="summarizer", tools=[], max_iterations=1)
|
|
219
|
+
|
|
220
|
+
pipeline = PipelineOrchestrator(agents={"searcher": searcher, "summarizer": summarizer})
|
|
221
|
+
result = pipeline.perform("Summarize the top 3 AI breakthroughs in 2024")
|
|
222
|
+
print(result["final_result"]["previous_result"][:250], "...")
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Output:**
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
1. Multimodal AI Advancements (GPT-4o, Gemini 1.5) · 2. AI Agents Stepping Into
|
|
229
|
+
the Spotlight · 3. AI's Bold Move into Video Creation...
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
### 6. Debate — Multi-agent consensus for reasoning
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
from agentensemble import ReActAgent, DebateOrchestrator
|
|
238
|
+
|
|
239
|
+
solver1 = ReActAgent(name="solver_1", tools=[], max_iterations=1)
|
|
240
|
+
solver2 = ReActAgent(name="solver_2", tools=[], max_iterations=1)
|
|
241
|
+
aggregator = ReActAgent(name="aggregator", tools=[], max_iterations=1)
|
|
242
|
+
|
|
243
|
+
debate = DebateOrchestrator(solvers=[solver1, solver2], aggregator=aggregator, rounds=2)
|
|
244
|
+
result = debate.debate("What is 15 * 7?")
|
|
245
|
+
print("Proposals:", result["proposals"])
|
|
246
|
+
print("Final:", result["result"])
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Output:**
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
Proposals: ['15 × 7 = 105', '15 × 7 equals 105']
|
|
253
|
+
Final: 15 × 7 equals 105.
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### 7. Router + Ensemble — LLM picks the best agent
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
from agentensemble import ReActAgent, RouterAgent, Ensemble, SearchTool
|
|
262
|
+
|
|
263
|
+
researcher = ReActAgent(name="researcher", tools=[SearchTool()], max_iterations=2)
|
|
264
|
+
validator = ReActAgent(name="validator", tools=[SearchTool()], max_iterations=2)
|
|
265
|
+
|
|
266
|
+
router = RouterAgent(agents={"researcher": researcher, "validator": validator})
|
|
267
|
+
ensemble = Ensemble(conductor="supervisor", agents={"researcher": researcher, "validator": validator}, router=router)
|
|
268
|
+
result = ensemble.perform("Latest developments in quantum computing")
|
|
269
|
+
for name, r in result["results"].items():
|
|
270
|
+
print(f"Routed to {name}: {r['result'][:120]}...")
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Output:**
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
Routed to researcher: Here are the latest developments in quantum computing:
|
|
277
|
+
1. Hardware Advances · 2. Fault-tolerant quantum computing...
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
### 8. Planner — Decompose task → executor runs subtasks
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
from agentensemble import PlannerAgent, StateGraphAgent
|
|
286
|
+
|
|
287
|
+
def worker(state):
|
|
288
|
+
return {"result": f"Processed: {state.query}"}
|
|
289
|
+
|
|
290
|
+
executor = StateGraphAgent(name="worker", nodes={"start": worker})
|
|
291
|
+
executor._route = lambda s, c: "end"
|
|
292
|
+
|
|
293
|
+
planner = PlannerAgent(executor=executor, max_subtasks=3)
|
|
294
|
+
result = planner.run("Research and compare LangGraph vs CrewAI")
|
|
295
|
+
print("Subtasks:", result["metadata"]["subtasks"])
|
|
296
|
+
print("Result:", result["result"][:200], "...")
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Output:**
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
Subtasks: ['Search for information about: Research and compare LangGraph vs CrewAI',
|
|
303
|
+
'Summarize key findings from: Research and compare LangGraph vs CrewAI']
|
|
304
|
+
Result: Processed: Search for information... --- Processed: Summarize key findings...
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
### 9. WorkflowGraph — Custom DAG with nodes and edges
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
from agentensemble import WorkflowGraph
|
|
313
|
+
|
|
314
|
+
def analyze(s):
|
|
315
|
+
return {"context": {**s.get("context", {}), "done": True}, "current_node": "summarize"}
|
|
316
|
+
|
|
317
|
+
def summarize(s):
|
|
318
|
+
return {"result": f"Summary for: {s['query']}", "current_node": "end"}
|
|
319
|
+
|
|
320
|
+
graph = (
|
|
321
|
+
WorkflowGraph(entry="start", exit_nodes=["end"])
|
|
322
|
+
.add_node("start", lambda s: {"current_node": "analyze"})
|
|
323
|
+
.add_node("analyze", analyze)
|
|
324
|
+
.add_node("summarize", summarize)
|
|
325
|
+
.add_edge("start", "analyze")
|
|
326
|
+
.add_edge("analyze", "summarize")
|
|
327
|
+
.add_edge("summarize", "end")
|
|
328
|
+
)
|
|
329
|
+
result = graph.run("What is multi-agent AI?")
|
|
330
|
+
print(result["result"])
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Output:**
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
Summary for: What is multi-agent AI?
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
### 10. Runner + RunHooks + InMemorySession — Production-ready execution
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
from agentensemble import ReActAgent, Runner, RunConfig, RunHooks, InMemorySession, SearchTool
|
|
345
|
+
|
|
346
|
+
session = InMemorySession(session_id="chat-1")
|
|
347
|
+
agent = ReActAgent(name="chatbot", tools=[SearchTool()], session=session, max_iterations=3)
|
|
348
|
+
|
|
349
|
+
def on_start(q, _): print(f"→ User: {q[:50]}...")
|
|
350
|
+
def on_end(r): print(f"← Agent: {r['result'][:80]}...\n")
|
|
351
|
+
|
|
352
|
+
config = RunConfig(hooks=RunHooks(on_start=on_start, on_end=on_end))
|
|
353
|
+
|
|
354
|
+
Runner.run(agent, "What is the capital of Japan?", config=config)
|
|
355
|
+
Runner.run(agent, "What about its population?", config=config) # Remembers context
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Output:**
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
→ User: What is the capital of Japan?...
|
|
362
|
+
← Agent: The capital of Japan is Tokyo.
|
|
363
|
+
|
|
364
|
+
→ User: What about its population?...
|
|
365
|
+
← Agent: Tokyo's population is approximately 14 million...
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
### 11. RAGAgent — Document Q&A (optional: `pip install agentensemble[rag]`)
|
|
371
|
+
|
|
372
|
+
```python
|
|
373
|
+
from agentensemble import RAGAgent, RAGTool
|
|
374
|
+
|
|
375
|
+
rag_tool = RAGTool()
|
|
376
|
+
rag_tool.index_documents(["https://example.com/doc"]) # Index from URLs
|
|
377
|
+
|
|
378
|
+
agent = RAGAgent(name="doc_qa", tools=[rag_tool], fallback_strategies=2)
|
|
379
|
+
result = agent.run("What is task decomposition?")
|
|
380
|
+
print(result["result"][:200], "...")
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**Output:**
|
|
384
|
+
```
|
|
385
|
+
Task decomposition is the process of breaking complex tasks into smaller,
|
|
386
|
+
manageable subtasks that can be executed by specialized agents...
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
### 12. StructuredAgent — Pydantic output (optional: `langchain>=1.1`)
|
|
392
|
+
|
|
393
|
+
```python
|
|
394
|
+
from pydantic import BaseModel, Field
|
|
395
|
+
from agentensemble import StructuredAgent
|
|
396
|
+
|
|
397
|
+
class ProductReview(BaseModel):
|
|
398
|
+
product: str = Field(description="Product name")
|
|
399
|
+
rating: int = Field(description="1-5 stars")
|
|
400
|
+
summary: str = Field(description="Brief summary")
|
|
401
|
+
|
|
402
|
+
agent = StructuredAgent(response_format=ProductReview)
|
|
403
|
+
result = agent.run("Review: iPhone 15 Pro - 5 stars, excellent camera and battery")
|
|
404
|
+
print(result["structured_response"])
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**Output:**
|
|
408
|
+
```
|
|
409
|
+
ProductReview(product='iPhone 15 Pro', rating=5, summary='Excellent camera and battery')
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
### Creative combo — Research pipeline (Planner + Swarm + Debate + Runner)
|
|
415
|
+
|
|
416
|
+
```python
|
|
417
|
+
from agentensemble import (
|
|
418
|
+
ReActAgent, PlannerAgent, StateGraphAgent,
|
|
419
|
+
SwarmOrchestrator, DebateOrchestrator,
|
|
420
|
+
Runner, RunConfig, RunHooks, SearchTool,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
# 1. Executor: ReActAgent with search
|
|
424
|
+
executor = ReActAgent(name="researcher", tools=[SearchTool()], max_iterations=3)
|
|
425
|
+
|
|
426
|
+
# 2. Planner decomposes → runs subtasks via executor
|
|
427
|
+
planner = PlannerAgent(executor=executor, max_subtasks=2)
|
|
428
|
+
plan_result = planner.run("Compare LangGraph vs CrewAI vs AutoGen")
|
|
429
|
+
|
|
430
|
+
# 3. Swarm: parallel research + fact-check
|
|
431
|
+
researcher = ReActAgent(name="r", tools=[SearchTool()], max_iterations=2)
|
|
432
|
+
checker = ReActAgent(name="c", tools=[SearchTool()], max_iterations=2)
|
|
433
|
+
swarm = SwarmOrchestrator(agents={"r": researcher, "c": checker})
|
|
434
|
+
swarm_result = swarm.perform("Top 3 AI agent frameworks 2024")
|
|
435
|
+
|
|
436
|
+
# 4. Debate: consensus on a fact
|
|
437
|
+
s1 = ReActAgent(name="s1", tools=[], max_iterations=1)
|
|
438
|
+
s2 = ReActAgent(name="s2", tools=[], max_iterations=1)
|
|
439
|
+
agg = ReActAgent(name="agg", tools=[], max_iterations=1)
|
|
440
|
+
debate = DebateOrchestrator(solvers=[s1, s2], aggregator=agg, rounds=2)
|
|
441
|
+
debate_result = debate.debate("What is 12 * 8?")
|
|
442
|
+
|
|
443
|
+
# 5. Runner with hooks
|
|
444
|
+
hooks = RunHooks(on_start=lambda q, _: print(f"Running: {q[:40]}..."))
|
|
445
|
+
result = Runner.run(executor, "Who won 2024 Nobel Physics?", RunConfig(hooks=hooks))
|
|
446
|
+
|
|
447
|
+
print("Planner:", plan_result["result"][:100], "...")
|
|
448
|
+
print("Swarm agents:", list(swarm_result["results"].keys()))
|
|
449
|
+
print("Debate answer:", debate_result["result"])
|
|
450
|
+
print("Runner:", result["result"][:80], "...")
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**Output:**
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
Running: Who won 2024 Nobel Physics?...
|
|
457
|
+
Planner: Processed: Search for information... --- Processed: Summarize key findings...
|
|
458
|
+
Swarm agents: ['r', 'c']
|
|
459
|
+
Debate answer: 12 × 8 equals 96.
|
|
460
|
+
Runner: The 2024 Nobel Prize in Physics was awarded to John J. Hopfield and Geoffrey E. Hinton...
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Run full showcase
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
pip install agentensemble[search]
|
|
469
|
+
PYTHONPATH=. python examples/showcase_all.py
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Runs all 10 demos with real API calls.
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Core Components
|
|
477
|
+
|
|
478
|
+
### Agents
|
|
479
|
+
|
|
480
|
+
| Agent | Use Case | LLM |
|
|
481
|
+
| ------------------- | ----------------------------- | -------- |
|
|
482
|
+
| **ReActAgent** | Research, tool use, reasoning | Yes |
|
|
483
|
+
| **StateGraphAgent** | Custom node workflows | No |
|
|
484
|
+
| **RAGAgent** | Document Q&A | Optional |
|
|
485
|
+
| **HybridAgent** | Search → RAG → Validate | Optional |
|
|
486
|
+
| **RouterAgent** | Route to best agent | Optional |
|
|
487
|
+
| **PlannerAgent** | Task decomposition | No |
|
|
488
|
+
|
|
489
|
+
### Orchestration
|
|
490
|
+
|
|
491
|
+
| Pattern | Description |
|
|
492
|
+
| -------------- | -------------------------------------------------------------------- |
|
|
493
|
+
| **Supervisor** | Central coordinator; optional `router` for LLM-based agent selection |
|
|
494
|
+
| **Swarm** | Parallel execution via `asyncio.gather` |
|
|
495
|
+
| **Pipeline** | Sequential agent workflow |
|
|
496
|
+
| **Debate** | Solvers propose → feedback → aggregator votes |
|
|
497
|
+
|
|
498
|
+
### Tools
|
|
499
|
+
|
|
500
|
+
- `@function_tool` — Decorate functions for automatic schema
|
|
501
|
+
- `SearchTool` — Serper or DuckDuckGo
|
|
502
|
+
- `RAGTool` — Document indexing and retrieval
|
|
503
|
+
- `ValidationTool` — Quality checks
|
|
504
|
+
- `ToolRegistry` — Dynamic tool management
|
|
505
|
+
|
|
506
|
+
### Memory & Runner
|
|
507
|
+
|
|
508
|
+
- **Session** — `InMemorySession`, `SQLiteSession` for multi-turn context
|
|
509
|
+
- **Runner** — `Runner.run()`, `Runner.arun()` with `RunConfig`, `RunHooks`, retries
|
|
510
|
+
- **TraceHooks** — Observability for runs, LLM calls, tools
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Project Structure
|
|
515
|
+
|
|
516
|
+
```
|
|
517
|
+
agentensemble/
|
|
518
|
+
├── agents/ # ReAct, StateGraph, RAG, Hybrid, Structured
|
|
519
|
+
├── core/ # AgentProtocol, RunnableProtocol
|
|
520
|
+
├── llm/ # LLMProvider, MistralLLMProvider
|
|
521
|
+
├── memory/ # Session, InMemorySession, SQLiteSession
|
|
522
|
+
├── orchestration/ # Ensemble, Supervisor, Swarm, Pipeline, Debate
|
|
523
|
+
├── tools/ # Tool protocol, @function_tool, built-ins
|
|
524
|
+
├── router/ # RouterAgent (LLM-based routing)
|
|
525
|
+
├── planner/ # PlannerAgent (task decomposition)
|
|
526
|
+
├── graph/ # WorkflowGraph (composable workflows)
|
|
527
|
+
├── tracing/ # TraceHooks, TraceEvent
|
|
528
|
+
├── testing/ # Benchmark, AgentComparison, Metrics
|
|
529
|
+
└── runner.py # Runner, RunConfig, RunHooks
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
## Comparison
|
|
535
|
+
|
|
536
|
+
| Feature | AgentEnsemble | LangGraph | CrewAI | AutoGen |
|
|
537
|
+
| ------------------ | ------------------------- | ------------ | ------ | ------- |
|
|
538
|
+
| Multi-provider LLM | Mistral (extensible) | Any | Any | Any |
|
|
539
|
+
| Async API | `arun()` everywhere | Yes | Yes | Yes |
|
|
540
|
+
| Router agents | RouterAgent | Manual | Yes | Manual |
|
|
541
|
+
| Planner pattern | PlannerAgent | Manual | Yes | Manual |
|
|
542
|
+
| Graph workflows | WorkflowGraph, StateGraph | Native | No | No |
|
|
543
|
+
| Debate pattern | DebateOrchestrator | Manual | Yes | Yes |
|
|
544
|
+
| Session memory | InMemory, SQLite | Checkpointer | No | No |
|
|
545
|
+
| Observability | TraceHooks | LangSmith | No | No |
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## Production Use
|
|
550
|
+
|
|
551
|
+
- **Retries**: `RunConfig(max_retries=2, retry_on=(RateLimitError, TimeoutError))`
|
|
552
|
+
- **Session**: `Runner.run(agent, query, config=RunConfig(session=SQLiteSession()))`
|
|
553
|
+
- **Tracing**: Attach `TraceHooks` to capture run/LLM/tool events
|
|
554
|
+
- **Benchmarks**: `AgentComparison`, `Benchmark.research_tasks()`, `Metrics`
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## Documentation
|
|
559
|
+
|
|
560
|
+
- **[Showcase](examples/showcase_all.py)** — Run all 10 features with real API output
|
|
561
|
+
- [Examples](examples/) — `quickstart`, `react_llm`, `swarm`, `pipeline`, `streaming`, `debate`, `rag`, `research_agent`, `graph_workflow`, `runner`, `structured_output`
|
|
562
|
+
- [Roadmap](docs/ROADMAP_2025.md) — Planned improvements
|
|
563
|
+
|
|
564
|
+
> **Note:** Ensure `docs/agentensemble-architecture.png` is committed so the architecture diagram renders on GitHub.
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## License
|
|
569
|
+
|
|
570
|
+
MIT — see [LICENSE](LICENSE).
|