Merge pull request 'feat: add autogen — expert skill for conversational multi-agent AI (SkillOpt 3 epochs)' (#86) from feat/autogen-skillopt into main

This commit is contained in:
Jasper (AI Assistant)
2026-07-09 14:57:36 -04:00
11 changed files with 468 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
---
name: autogen
description: >-
Expert skill for conversational multi-agent AI with Microsoft AutoGen.
AssistantAgent, UserProxyAgent, GroupChat, code execution, nested chats,
cancellation tokens, tool integration, and MCP support. Use when building
conversation-driven multi-agent systems or comparing agent frameworks.
license: MIT
metadata:
author: Magnus Hedemark
version: 1.0.3
source: https://microsoft.github.io/autogen
---
# AutoGen Expert Skill
AutoGen (by Microsoft Research) is a framework for **conversational multi-agent AI**. Unlike LangGraph's explicit graph topology or CrewAI's role-based crews, AutoGen uses **agent-to-agent conversations as the orchestration primitive**. Agents communicate through structured chat, with built-in patterns for nested conversations, group chat with routing, and code execution.
## Core Paradigm
```python
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient
model_client = OpenAIChatCompletionClient(model="gpt-4o-mini")
assistant = AssistantAgent(
name="assistant",
system_message="You are a helpful assistant.",
model_client=model_client,
)
```
> **⚠️ UserProxyAgent is NOT a human user.** It is an automated proxy that can execute code. Despite the name, it runs autonomously unless `human_input_mode` is set to `ALWAYS`.
## Core Principles
1. **Conversations are the orchestration primitive.** Agents send messages, receive replies, and the conversation structure determines the workflow.
2. **UserProxyAgent is a code executor, not a human.** Despite the name, it runs autonomously by default. Set `human_input_mode="ALWAYS"` for actual human-in-the-loop.
3. **GroupChat routes between agents.** RoundRobinGroupChat cycles fixed-order. SelectorGroupChat uses an LLM to pick the next speaker.
4. **Nested chats delegate work.** An agent can spawn a sub-conversation between specialist agents and return the result.
5. **Docker is the safe code execution mode.** Local code execution (`LocalCommandLineCodeExecutor`) runs LLM-generated code on your machine — use Docker in production.
6. **Cancellation tokens stop runaway agents.** Always pass `CancellationToken` for long-running tasks.
## Where to Start
| You already have... | Start here |
|---|---|
| Nothing — exploring AutoGen | Create a two-agent chat (Assistant + UserProxy) |
| Agents that need to coordinate | Build a GroupChat with multiple agents |
| Agents that need code execution | Configure Docker code executor |
| A complex multi-step task | Use nested chats for sub-tasks |
## Quick Reference
| Task | Approach | Reference |
|------|----------|-----------|
| Two-agent chat | AssistantAgent + UserProxyAgent | `references/agent-types.md` |
| Multi-agent group | GroupChat with RoundRobinGroupChat | `references/group-chat.md` |
| Code execution | DockerCommandLineCodeExecutor | `references/code-execution.md` |
| Tool integration | `register_function()` or @tool | `references/tool-integration.md` |
| Nested chat | `initiate_chat()` from within a tool | `references/conversation-patterns.md` |
| Cancellation | `CancellationToken` | `references/conversation-patterns.md` |
| MCP tools | `McpWorkbench` | `references/tool-integration.md` |
## Framework Routing Guide
| Scenario | Reach for | Why |
|----------|-----------|-----|
| Conversation-driven multi-agent | **AutoGen** | Native agent-to-agent chat as orchestration |
| Role-based multi-agent teams | **CrewAI** | Role/Goal/Backstory is the native abstraction |
| State-machine multi-agent | **LangGraph** | Graph topology, subgraphs, human-in-the-loop |
| Chain/agent composition | **LangChain** | LCEL pipe operator for general chains |
## Reference Files
| Reference | Load when | File |
|-----------|-----------|------|
| Agent Types | AssistantAgent, UserProxyAgent | `references/agent-types.md` |
| Conversation Patterns | Send/receive, nested chats, cancellation | `references/conversation-patterns.md` |
| Group Chat | RoundRobin, Selector, MagenticOne | `references/group-chat.md` |
| Code Execution | Docker, local, cancellation tokens | `references/code-execution.md` |
| Tool Integration | register_function, @tool, MCP integration | `references/tool-integration.md` |
| FAQ & Troubleshooting | Common errors and fixes | `references/faq-and-troubleshooting.md` |
## Templates
| Template | When to use | File |
|----------|-------------|------|
| Two-Agent Chat | Simple assistant + code executor | `templates/two-agent-chat.py` |
| Group Chat | Multi-agent team with speaker routing | `templates/group-chat.py` |
| Code Execution Agent | Agent with Docker code execution | `templates/code-execution.py` |
## Troubleshooting
| Symptom | Likely cause | Fix | Reference |
|---------|-------------|-----|-----------|
| Agent loops forever | No termination condition | Add `is_termination_msg` or `max_turns` | `references/conversation-patterns.md` |
| Code execution fails | Docker not running | Start Docker or use LocalCommandLineCodeExecutor | `references/code-execution.md` |
| Nested chat never returns | Cancellation token not passed | Pass `CancellationToken` with timeout | `references/conversation-patterns.md` |
| v0.2 code doesn't work | v0.4 API changed | Follow migration guide | `references/faq-and-troubleshooting.md` |
| GroupChat speaker selection loops | SelectorGroupChat with no clear next | Use RoundRobinGroupChat for fixed order | `references/group-chat.md` |
| UserProxyAgent asking for input | `human_input_mode="ALWAYS"` | Set to `"NEVER"` for automated execution | `references/agent-types.md` |
## When NOT to Use AutoGen
- Simple single-agent task — overkill, use direct API call
- Need fine-grained graph control — use LangGraph
- Need role-based teams with fixed processes — use CrewAI
- Need chain composition — use LangChain LCEL
+45
View File
@@ -0,0 +1,45 @@
# AutoGen Agent Types
## AssistantAgent
The primary AI agent. Uses an LLM to generate responses.
```python
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
model_client = OpenAIChatCompletionClient(model="gpt-4o-mini")
assistant = AssistantAgent(
name="assistant",
system_message="You are a helpful AI assistant.",
model_client=model_client,
)
```
## UserProxyAgent
Automated proxy that can execute code. Despite the name, NOT a human user by default.
```python
from autogen_agentchat.agents import UserProxyAgent
proxy = UserProxyAgent(
name="proxy",
human_input_mode="NEVER", # "ALWAYS" for human-in-the-loop, "TERMINATE" to stop
is_termination_msg=lambda msg: "TERMINATE" in (msg.get("content", "") or ""),
code_executor=code_executor,
)
```
## Key Parameters
| Parameter | Description |
|-----------|-------------|
| `name` | Unique agent name |
| `system_message` | System prompt defining agent behavior |
| `human_input_mode` | "NEVER", "ALWAYS", or "TERMINATE" |
| `is_termination_msg` | Function to detect termination messages |
| `code_executor` | CodeExecutor for running generated code |
| `model_client` | LLM client (AssistantAgent only) |
| `tools` | Tools the agent can call |
+45
View File
@@ -0,0 +1,45 @@
# AutoGen Code Execution
## Docker (Recommended)
Safe execution of LLM-generated code in isolated containers:
```python
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
executor = DockerCommandLineCodeExecutor(work_dir="coding")
async with executor:
# Use within GroupChat
proxy = UserProxyAgent(
name="proxy",
code_executor=executor,
human_input_mode="NEVER",
)
```
## Local (Development Only)
Runs generated code on your machine — use only for trusted environments:
```python
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
executor = LocalCommandLineCodeExecutor(work_dir="coding")
```
## Cancellation
```python
from autogen_core import CancellationToken
token = CancellationToken()
result = await executor.execute_code_blocks(code_blocks, cancellation_token=token)
# Cancel via: token.cancel()
```
## Best Practices
- Use Docker for any untrusted code execution
- Set a `work_dir` to isolate generated files
- Always pass a `CancellationToken` for long-running tasks
- Monitor `max_turns` to prevent runaway code generation
@@ -0,0 +1,56 @@
# AutoGen Conversation Patterns
## Two-Agent Chat
```python
from autogen_agentchat.agents import AssistantAgent, UserProxyAgent
assistant = AssistantAgent(name="assistant", model_client=model_client)
proxy = UserProxyAgent(name="proxy", human_input_mode="NEVER")
result = proxy.initiate_chat(assistant, message="What is AutoGen?", max_turns=2)
print(result.summary)
```
## Termination Conditions
Prevent infinite loops:
```python
proxy = UserProxyAgent(
name="proxy",
human_input_mode="NEVER",
is_termination_msg=lambda msg: "TERMINATE" in (msg.get("content", "") or ""),
max_consecutive_auto_reply=5,
)
# Or limit turns at chat level
result = proxy.initiate_chat(assistant, message="Hello", max_turns=10)
```
## Cancellation Tokens
```python
from autogen_core import CancellationToken
token = CancellationToken()
# Token can be used to cancel long-running operations
```
## Nested Chats
Agent delegates work to a sub-conversation:
```python
async def research_topic(query: str) -> str:
researcher = AssistantAgent(name="researcher", model_client=model_client)
fact_checker = AssistantAgent(name="fact_checker", model_client=model_client)
proxy = UserProxyAgent(name="proxy", human_input_mode="NEVER")
result = await proxy.initiate_chat(
researcher, message=f"Research: {query}", max_turns=5
)
return result.summary
# Register as a function the main agent can call
assistant.register_function(function_map={"research": research_topic})
```
@@ -0,0 +1,36 @@
# AutoGen FAQ and Troubleshooting
## Installation
**Q: Which version should I install?**
A: `pip install autogen-agentchat` for the current v0.4+ API. The older `pip install pyautogen` installs v0.2 (deprecated).
**Q: Docker not available?**
A: Use `LocalCommandLineCodeExecutor` for development, but understand the security risks.
## Migration
**Q: Code from v0.2 doesn't work?**
A: v0.4 has breaking API changes. See the migration guide at https://microsoft.github.io/autogen/stable/user-guide/agentchat-user-guide/migration-guide.html.
## Common Errors
**Q: Agent loops forever?**
A: Set `is_termination_msg` or `max_turns`. The agent needs a termination condition.
**Q: UserProxyAgent keeps asking for input?**
A: `human_input_mode` defaults differently. Set to "NEVER" for automated execution.
**Q: Nested chat never returns?**
A: Ensure `CancellationToken` is passed and not already cancelled.
**Q: Code execution fails?**
A: Docker must be running for Docker executor. Use `LocalCommandLineCodeExecutor` for local dev.
**Q: GroupChat speaker selection is wrong?**
A: Use `RoundRobinGroupChat` for fixed order if `SelectorGroupChat` picks poorly.
## Performance
**Q: High token usage?**
A: Each agent-to-agent message consumes tokens. Set `max_turns` conservatively.
+43
View File
@@ -0,0 +1,43 @@
# AutoGen Group Chat
## RoundRobinGroupChat
Fixed-order conversation. Each agent speaks in turn.
```python
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.ui import Console
agent1 = AssistantAgent(name="researcher", model_client=model_client)
agent2 = AssistantAgent(name="analyst", model_client=model_client)
agent3 = AssistantAgent(name="writer", model_client=model_client)
team = RoundRobinGroupChat([agent1, agent2, agent3])
result = await team.run(task="Research and write about AI trends")
```
## SelectorGroupChat
LLM-driven speaker selection. Uses a model to decide who speaks next.
```python
from autogen_agentchat.teams import SelectorGroupChat
team = SelectorGroupChat(
[agent1, agent2, agent3],
model_client=model_client, # LLM used for speaker selection
)
```
## MagenticOneGroupChat
Magentic-One orchestrator pattern — a lead agent coordinates specialist agents.
## Key Parameters
| Parameter | Description |
|-----------|-------------|
| `participants` | List of agents in the group |
| `model_client` | LLM for speaker selection (SelectorGroupChat) |
| `max_turns` | Max conversation turns before termination |
+36
View File
@@ -0,0 +1,36 @@
# AutoGen Tool Integration
## register_function
Bind Python functions as agent tools:
```python
def search_web(query: str) -> str:
"""Search the web for information."""
return f"Results for: {query}"
assistant.register_function(function_map={"search_web": search_web})
```
## MCP Tool Integration
Connect MCP servers as agent tools:
```python
from autogen_ext.tools.mcp import McpWorkbench, StdioServerParams
server_params = StdioServerParams(command="npx", args=["@playwright/mcp@latest"])
async with McpWorkbench(server_params) as mcp:
agent = AssistantAgent(
"web_browsing_assistant",
model_client=model_client,
workbench=mcp,
)
```
## Key Guidelines
- Tool functions need clear docstrings (become tool descriptions)
- Tools should handle errors gracefully and return strings
- For complex integrations, wrap external APIs with error handling
- MCP tools enable browser automation, databases, and external services
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env python3
"""Verify AutoGen installation."""
import sys
REQUIRED = ["autogen_agentchat", "autogen_ext"]
OPTIONAL = ["autogen_core"]
for pkg in REQUIRED:
try:
__import__(pkg.replace("-", "_"))
print(f" [OK] {pkg}")
except ImportError:
print(f" [FAIL] {pkg} — install with pip install {pkg}")
sys.exit(1)
for pkg in OPTIONAL:
try:
__import__(pkg.replace("-", "_"))
print(f" [OK] {pkg} (optional)")
except ImportError:
print(f" [—] {pkg} (optional, not installed)")
from autogen_agentchat.agents import AssistantAgent
print(" [OK] AutoGen imports work")
print("\nAutoGen setup check: ALL REQUIRED PACKAGES OK")
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
"""Agent with Docker code execution."""
import asyncio
from autogen_agentchat.agents import AssistantAgent, UserProxyAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
async def main():
model_client = OpenAIChatCompletionClient(model="gpt-4o-mini")
async with DockerCommandLineCodeExecutor(work_dir="coding") as executor:
assistant = AssistantAgent(name="assistant", model_client=model_client,
system_message="Write Python code to solve problems.")
proxy = UserProxyAgent(name="proxy", code_executor=executor,
human_input_mode="NEVER")
team = RoundRobinGroupChat([assistant, proxy])
result = await team.run(task="Calculate pi to 10 decimal places using Python")
print(result.messages[-1].content)
asyncio.run(main())
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env python3
"""Group chat with RoundRobin speaker selection."""
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient
async def main():
model_client = OpenAIChatCompletionClient(model="gpt-4o-mini")
researcher = AssistantAgent(name="researcher", model_client=model_client,
system_message="You research and find information.")
analyst = AssistantAgent(name="analyst", model_client=model_client,
system_message="You analyze findings for insights.")
writer = AssistantAgent(name="writer", model_client=model_client,
system_message="You write clear summaries.")
team = RoundRobinGroupChat([researcher, analyst, writer])
result = await team.run(task="Research and report on AI agents")
print(result.messages[-1].content)
asyncio.run(main())
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python3
"""Two-agent chat with AssistantAgent and UserProxyAgent."""
from autogen_agentchat.agents import AssistantAgent, UserProxyAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
model_client = OpenAIChatCompletionClient(model="gpt-4o-mini")
assistant = AssistantAgent(
name="assistant",
system_message="You are a helpful assistant.",
model_client=model_client,
)
proxy = UserProxyAgent(
name="proxy",
human_input_mode="NEVER",
is_termination_msg=lambda msg: "TERMINATE" in (msg.get("content", "") or ""),
)
result = proxy.initiate_chat(assistant, message="What is AutoGen?", max_turns=2)
print(result.summary)