Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# === LLM Providers ===

# Groq (free tier — different models have different rate limits)
GROQ_API_KEY=gsk_your_key_here

# OpenRouter (optional — free models also available)
OPENROUTER_API_KEY=sk-or-your-key-here

# === Model Selection ===
# LiteLLM format: provider/model-name
# Each agent uses a different model for independent rate limit pools

ENG_LEAD_MODEL=groq/llama-3.3-70b-versatile
BACKEND_ENGINEER_MODEL=groq/qwen/qwen3-32b
FRONTEND_ENGINEER_MODEL=groq/meta-llama/llama-4-scout-17b-16e-instruct
TEST_ENGINEER_MODEL=groq/llama-3.3-70b-versatile

# === LangFuse (observability — optional) ===
# Create a free account at https://cloud.langfuse.com
# LANGFUSE_PUBLIC_KEY=pk-your-key
# LANGFUSE_SECRET_KEY=sk-your-key
# LANGFUSE_HOST=https://cloud.langfuse.com
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
__pycache__/
*.pyc
.env
.venv/
output/
*.log
.DS_Store
113 changes: 113 additions & 0 deletions 3_crew/community_contributions/advanced-engineering-team/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Advanced Engineering Team

A **multi-agent software engineering team** built with [CrewAI](https://www.crewai.com/). Each agent uses a different LLM with its own rate limit pool — no paid API keys required.

## Architecture

```
┌─────────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐
│ Engineering │ ──→ │ Backend │ ──→ │ Frontend │ ──→ │ QA │
│ Lead │ │ Engineer │ │ Engineer │ │ Engineer │
│ (Design) │ │ (accounts) │ │ (Gradio) │ │ (tests) │
└─────────────┘ └──────────────┘ └──────────────┘ └────────────┘
Groq Groq Groq Groq
Llama 70B Qwen 32B Llama 4 Scout Llama 70B
```

**Sequential process:** Design → Code → Frontend → Tests. Each task feeds into the next.

## Models (all free)

| Agent | Model | Provider |
|-------|-------|----------|
| Engineering Lead | `llama-3.3-70b-versatile` | Groq (12k TPM) |
| Backend Engineer | `qwen/qwen3-32b` | Groq |
| Frontend Engineer | `meta-llama/llama-4-scout-17b-16e-instruct` | Groq |
| QA Engineer | `llama-3.3-70b-versatile` | Groq (12k TPM) |

Each model sits in a separate rate limit pool — no shared token budgets.

## Features

- **Per-role LLM config** — `.env` driven, no hardcoded models
- **Docker code execution** — custom tool replaces CrewAI's buggy built-in Code Interpreter
- **Markdown-free output** — auto-strips thinking tags and markdown from generated files
- **CLI with stdin support** — pipe in custom requirements or use the built-in trading simulator spec
- **LangFuse observability** — every agent trace logged (configure via `.env`, free at cloud.langfuse.com)

## Quick Start

```bash
# 1. Clone & enter
cd community_contributions/advanced-engineering-team

# 2. Copy env template
cp .env.example .env
# Edit .env with your API keys (Groq required, OpenRouter optional)

# 3. Install
uv sync

# 4. Run
uv run advanced-engineering-team
```

### Requirements

- Python 3.11+
- [uv](https://docs.astral.sh/uv/) package manager
- **Groq API key** (free at console.groq.com)
- **Docker Desktop** (for backend & test code execution)
- **OpenRouter API key** (optional, for additional model providers)

## Generated Output

After running, `./output/` contains:

| File | Description |
|------|-------------|
| `accounts.py` | Trading account module with `Account` class |
| `accounts.py_design.md` | Design document from the Engineering Lead |
| `app.py` | Gradio UI for interacting with the account |
| `test_accounts.py` | 16 unittest tests (all pass) |

## Custom Requirements

```bash
# Pipe in custom requirements
echo "Build a todo list API with Flask" | uv run advanced-engineering-team

# Or use CLI args
uv run advanced-engineering-team \
--module todo.py \
--class-name TodoList
```

## Project Structure

```
advanced-engineering-team/
├── pyproject.toml
├── .env.example
├── src/
│ └── advanced_engineering_team/
│ ├── crew.py # @CrewBase wiring
│ ├── main.py # CLI entry point
│ ├── config/
│ │ ├── agents.yaml # Role definitions
│ │ └── tasks.yaml # Task chain
│ ├── llm/
│ │ ├── config.py # Role→model env var mapping
│ │ └── factory.py # LiteLLM object creation
│ └── tools/
│ └── docker_executor.py # Docker code execution tool
└── output/ # Generated files
```

## LangFuse

Set the `LANGFUSE_*` env vars in `.env` to trace every agent call. Free account at [cloud.langfuse.com](https://cloud.langfuse.com).

## Acknowledgements

Built as a community contribution for [Ed Donner's Master AI Agentic Engineering course](https://github.com/ed-donner/agents).
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[project]
name = "advanced-engineering-team"
version = "0.1.0"
description = "Multi-agent AI software engineering team with Groq, OpenRouter, and LangSmith"
requires-python = ">=3.10,<3.13"
dependencies = [
"crewai[tools]>=0.108.0,<1.0.0",
"python-dotenv>=1.0.0",
"gradio>=5.0.0",
]

[project.scripts]
advanced-engineering-team = "advanced_engineering_team.main:run"
run-crew = "advanced_engineering_team.main:run"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.crewai]
type = "crew"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Advanced Engineering Team — multi-agent software engineering."""

__version__ = "0.1.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
engineering_lead:
role: >
Engineering Lead
goal: >
Take the high level requirements and produce a detailed design document.
The design should describe the classes, methods, and data structures for a single
Python module named {module_name} with a main class named {class_name}.
Requirements: {requirements}
backstory: >
You are a senior engineering lead known for producing clear, practical designs.
You think carefully about architecture before writing anything.

backend_engineer:
role: >
Backend Python Engineer
goal: >
Implement the Python module {module_name} with class {class_name}
according to the design provided by the Engineering Lead.
The module must be self-contained, production-ready, and fulfill: {requirements}
backstory: >
You write clean, well-documented Python code. You follow the design exactly
and handle edge cases properly.

frontend_engineer:
role: >
Frontend UI Engineer
goal: >
Build a simple Gradio app in app.py that demonstrates the backend class
{class_name} from {module_name}. Requirements: {requirements}
backstory: >
You specialize in building quick, clean Gradio demos that make backend
functionality easy to interact with.

test_engineer:
role: >
QA Engineer
goal: >
Write comprehensive unit tests for {module_name} in test_{module_name}
using the unittest framework. Cover happy paths, edge cases, and errors.
Requirements: {requirements}
backstory: >
You write thorough tests that catch real bugs. You use unittest and
follow best practices for test organization.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
design_task:
description: >
Review the requirements and produce a detailed design for {module_name}.
The module should contain a class {class_name} and a helper function
get_share_price(symbol). Describe every method signature and data structure.
Requirements: {requirements}
expected_output: >
A markdown design document with class diagram, method signatures, and
data descriptions.
agent: engineering_lead
output_file: output/{module_name}_design.md

code_task:
description: >
Write the Python module {module_name} containing class {class_name}
that implements the design. Include get_share_price(symbol) with mock
prices for AAPL, TSLA, GOOGL.
Requirements: {requirements}
expected_output: >
Your final answer must contain ONLY the Python code wrapped in a
```python ... ``` code block. No explanations, no thinking, no prose.
agent: backend_engineer
context:
- design_task
output_file: output/{module_name}

frontend_task:
description: >
Create a Gradio app in app.py that lets a user interact with the
{class_name} class from {module_name}. Single-user, simple UI.
Requirements: {requirements}
expected_output: >
Your final answer must contain ONLY the Python code wrapped in a
```python ... ``` code block. No explanations, no thinking, no prose.
agent: frontend_engineer
context:
- code_task
output_file: output/app.py

test_task:
description: >
Write unit tests for {module_name} in test_{module_name} using unittest.
Test all public methods of {class_name}, including edge cases and
error conditions (insufficient funds, invalid quantities).
Requirements: {requirements}
expected_output: >
Your final answer must contain ONLY the Python code wrapped in a
```python ... ``` code block. No explanations, no thinking, no prose.
agent: test_engineer
context:
- code_task
output_file: output/test_{module_name}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import os
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task

from .llm import create_llm
from .tools import DockerCodeExecutor

callbacks = []
_lf_public = os.environ.get("LANGFUSE_PUBLIC_KEY")
_lf_secret = os.environ.get("LANGFUSE_SECRET_KEY")
if _lf_public and _lf_secret:
try:
from langfuse.callback import CallbackHandler
callbacks.append(CallbackHandler())
except ImportError:
pass


@CrewBase
class AdvancedEngineeringTeam():
"""Multi-agent engineering team with per-role LLM configuration."""

agents_config = 'config/agents.yaml'
tasks_config = 'config/tasks.yaml'

@agent
def engineering_lead(self) -> Agent:
return Agent(
config=self.agents_config['engineering_lead'],
llm=create_llm("engineering_lead"),
verbose=True,
)

@agent
def backend_engineer(self) -> Agent:
return Agent(
config=self.agents_config['backend_engineer'],
llm=create_llm("backend_engineer"),
verbose=True,
tools=[DockerCodeExecutor()],
)

@agent
def frontend_engineer(self) -> Agent:
return Agent(
config=self.agents_config['frontend_engineer'],
llm=create_llm("frontend_engineer"),
verbose=True,
)

@agent
def test_engineer(self) -> Agent:
return Agent(
config=self.agents_config['test_engineer'],
llm=create_llm("test_engineer"),
verbose=True,
tools=[DockerCodeExecutor()],
)

@task
def design_task(self) -> Task:
return Task(
config=self.tasks_config['design_task']
)

@task
def code_task(self) -> Task:
return Task(
config=self.tasks_config['code_task']
)

@task
def frontend_task(self) -> Task:
return Task(
config=self.tasks_config['frontend_task']
)

@task
def test_task(self) -> Task:
return Task(
config=self.tasks_config['test_task']
)

@crew
def crew(self) -> Crew:
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
callbacks=callbacks,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .factory import create_llm
from .config import get_all_agent_models, get_model_string_for_role

__all__ = [
"create_llm",
"get_all_agent_models",
"get_model_string_for_role",
]
Loading