Skip to content

AutoGen Integration

Overview

AutoGen (Microsoft) is a multi-agent framework for building LLM-powered applications. Tools in AutoGen are registered with agent pairs using register_for_llm and register_for_execution decorators.

The agentguard AutoGen integration lets you apply protection to tool functions before they're registered — preserving AutoGen's introspection and JSON schema generation.

Installation

pip install awesome-agentguard pyautogen
# or for AutoGen 0.4+
pip install awesome-agentguard autogen-agentchat

Quick Start

import autogen
import os
from agentguard.integrations import guard_autogen_tool, register_guarded_tools
from agentguard import GuardConfig
from agentguard.core.types import CircuitBreakerConfig, RateLimitConfig

# LLM configuration
llm_config = {
    "config_list": [{"model": "gpt-4o", "api_key": os.getenv("OPENAI_API_KEY")}],
}

# Create AutoGen agents
assistant = autogen.AssistantAgent(
    name="assistant",
    llm_config=llm_config,
)
user_proxy = autogen.UserProxyAgent(
    name="user_proxy",
    human_input_mode="NEVER",
    max_consecutive_auto_reply=10,
)

# Define your tools
def search_web(query: str) -> str:
    """Search the web for information."""
    import requests
    return requests.get(f"https://search.api.com?q={query}").text

def query_db(sql: str, limit: int = 100) -> list:
    """Query the database."""
    return db.execute(sql, limit=limit)

# Guard and register in one call
config = GuardConfig(
    validate_input=True,
    detect_hallucination=True,
    max_retries=2,
    circuit_breaker=CircuitBreakerConfig(failure_threshold=5),
    rate_limit=RateLimitConfig(calls_per_minute=60),
    record=True,
)

guarded = register_guarded_tools(
    tools=[search_web, query_db],
    llm_agent=assistant,
    executor_agent=user_proxy,
    config=config,
)

# Start the conversation
user_proxy.initiate_chat(
    assistant,
    message="Research the latest developments in quantum computing",
)

The @guard_autogen_tool Decorator

Apply directly to function definitions:

from agentguard.integrations import guard_autogen_tool
from agentguard import GuardConfig

config = GuardConfig(validate_input=True, max_retries=2)

# Decorator with config
@guard_autogen_tool(config=config)
def search_web(query: str) -> str:
    """Search the web for information."""
    return requests.get(f"https://search.api.com?q={query}").text

# Then register with AutoGen as normal
@assistant.register_for_llm(description="Search the web for current information")
@user_proxy.register_for_execution()
def search_web_tool(query: str) -> str:
    return search_web(query=query)

Or use as_function() to get a signature-preserving proxy:

@guard_autogen_tool(config=config)
def search_web(query: str) -> str:
    """Search the web."""
    return "results"

# Register the proxy directly
proxy = search_web.as_function()

@assistant.register_for_llm(description="Search the web")
@user_proxy.register_for_execution()
def search_web_tool(query: str) -> str:
    return proxy(query=query)

The register Helper

GuardedAutoGenTool.register handles the registration boilerplate:

from agentguard.integrations import GuardedAutoGenTool

def search_web(query: str) -> str:
    """Search the web."""
    return requests.get(f"...?q={query}").text

guarded = GuardedAutoGenTool(search_web, config=config)
guarded.register(
    llm_agent=assistant,
    executor_agent=user_proxy,
    description="Search the web for current information",
)

This is equivalent to:

@assistant.register_for_llm(description="Search the web for current information")
@user_proxy.register_for_execution()
def search_web_proxy(query: str) -> str:
    return guarded(query=query)

Bulk Registration with guard_autogen_tools

from agentguard.integrations import guard_autogen_tools

guarded = guard_autogen_tools(
    [search_web, query_db, send_email],
    config=config,
)

# guarded is a dict: {"search_web": GuardedAutoGenTool, ...}
for tool in guarded.values():
    tool.register(assistant, user_proxy)

# Or use register_guarded_tools which does both in one call

API Reference

guard_autogen_tool(func=None, *, config=None, description=None)

Decorator to wrap an AutoGen tool with agentguard protection.

# Without parentheses
@guard_autogen_tool
def my_tool(x: str) -> str: ...

# With config
@guard_autogen_tool(config=GuardConfig(max_retries=2))
def my_tool(x: str) -> str: ...

Returns: GuardedAutoGenTool


guard_autogen_tools(tools, config=None)

Wrap a list of callables. Returns a dict[str, GuardedAutoGenTool].

guarded = guard_autogen_tools([search_web, query_db], config=config)
guarded["search_web"](query="Python")

register_guarded_tools(tools, llm_agent, executor_agent, config=None)

Guard and register tools in one call. Returns dict[str, GuardedAutoGenTool].

guarded = register_guarded_tools(
    [search_web, query_db],
    llm_agent=assistant,
    executor_agent=user_proxy,
    config=config,
)

GuardedAutoGenTool

Attribute / Method Description
name Function name
description First docstring line (or override)
guarded_fn The underlying GuardedTool
__wrapped__ Original unwrapped function
__call__(*args, **kwargs) Execute through agentguard
acall(*args, **kwargs) Async execution
as_function() Return signature-preserving proxy
register(llm_agent, executor_agent, *, description=None) Register with an AutoGen agent pair

Preserving AutoGen Schema Generation

AutoGen uses inspect.signature to generate JSON schemas for the LLM. GuardedAutoGenTool.as_function() returns a functools.wraps-wrapped proxy that preserves the original signature:

import inspect
from agentguard.integrations import GuardedAutoGenTool

def search_web(query: str, num_results: int = 10) -> str:
    """Search the web."""
    ...

guarded = GuardedAutoGenTool(search_web)
proxy = guarded.as_function()

# AutoGen will see the correct signature
print(inspect.signature(proxy))
# (query: str, num_results: int = 10) -> str

Tracing AutoGen Agent Conversations

from agentguard import GuardConfig
from agentguard.integrations import register_guarded_tools

config = GuardConfig(
    record=True,
    trace_backend="sqlite",
    trace_dir="./autogen_traces",
    session_id="conversation_001",
)

guarded = register_guarded_tools(
    [search_web, query_db],
    assistant, user_proxy,
    config=config,
)

user_proxy.initiate_chat(assistant, message="Research quantum computing")

# Analyse what happened
from agentguard.core.trace import TraceStore
store = TraceStore("./autogen_traces", backend="sqlite")
entries = store.read_session("conversation_001")

for entry in entries:
    print(f"{entry.tool_name}: {entry.result.execution_time_ms:.0f}ms")

Multi-Agent Hierarchies

For AutoGen's nested chat and group chat patterns:

import autogen
from agentguard.integrations import guard_autogen_tool, GuardedAutoGenTool
from agentguard import GuardConfig

config = GuardConfig(validate_input=True, max_retries=2, record=True)

# Wrap tools
@guard_autogen_tool(config=config)
def search_web(query: str) -> str:
    """Search the web."""
    ...

@guard_autogen_tool(config=config)
def analyze_data(data: str) -> str:
    """Analyze the provided data."""
    ...

# Create specialized agents
researcher = autogen.AssistantAgent("researcher", llm_config=llm_config)
analyst = autogen.AssistantAgent("analyst", llm_config=llm_config)
user_proxy = autogen.UserProxyAgent("user_proxy", human_input_mode="NEVER")

# Register tools with appropriate agents
@researcher.register_for_llm(description="Search the internet")
@user_proxy.register_for_execution()
def search(query: str) -> str:
    return search_web(query=query)

@analyst.register_for_llm(description="Analyze data")
@user_proxy.register_for_execution()
def analyze(data: str) -> str:
    return analyze_data(data=data)

Troubleshooting

ImportError: autogen is not installed

Install it: pip install pyautogen (v0.2) or pip install autogen-agentchat (v0.4+).

AttributeError: 'AssistantAgent' has no attribute 'register_for_llm'

This API exists in AutoGen 0.2+. Check your AutoGen version:

pip show pyautogen | grep Version

JSON schema generation fails

AutoGen's schema generation requires type annotations. Ensure your tool functions have full annotations:

# Good
def search(query: str, limit: int = 10) -> str: ...

# Bad — missing return annotation
def search(query: str, limit: int = 10): ...

Guard not applied to all tool calls

Ensure you're calling the guarded version (or the proxy returned by as_function()), not the original function. Use repr(tool) to check: GuardedAutoGenTool(name='search_web', ...) vs just <function search_web at 0x...>.