Skip to main content

AutoGen Tools & Code Execution

AutoGen agents are not limited to generating text—they can invoke tools (APIs, databases, custom functions) and execute dynamically generated Python code to accomplish real‑world tasks. This article is a practical, implementation‑focused guide to extending your agents with tools and code execution: how to define and register them, how the runtime manages the execution lifecycle, how to run code safely in sandboxes, and how to design robust automation workflows.

What Are Tools and Code Execution in AutoGen

AutoGen agents gain their power from two complementary mechanisms:

  • Tools – pre‑defined, callable functions that an agent can invoke to fetch data, call APIs, query databases, or perform a specific, safe operation. They are declared with a schema (name, description, parameters) and executed by the runtime when the agent requests them.
  • Code execution – the ability for an agent to generate and run arbitrary Python code (or other languages) to solve tasks that require dynamic computation, data analysis, file manipulation, or complex logic that can’t be expressed as a static tool.

Both are accessed through a consistent interface: the agent receives a conversation, uses an LLM to decide to “call a tool” or “write code”, the runtime dispatches the request, captures the result, and injects it back into the conversation so the agent can continue.

A minimal example combining both:

from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_core.tools import FunctionTool
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from pydantic import BaseModel

# 1. Define a tool
def get_stock_price(ticker: str) -> str:
# In real code, call an API
return f"Price of {ticker}: $150.25"

stock_tool = FunctionTool(get_stock_price, description="Get current stock price")

# 2. Set up a code executor
code_executor = LocalCommandLineCodeExecutor(work_dir="./coding")

# 3. Create agent with both tool and code executor
agent = AssistantAgent(
name="analyst",
system_message="You are a financial analyst. Use tools and code when needed.",
model_client=OpenAIChatCompletionClient(model="gpt-4o"),
tools=[stock_tool],
code_executor=code_executor
)

Now the agent can call get_stock_price and execute arbitrary Python code to analyse the result.

Why Tools Matter

Tools are the bridge between language understanding and real‑world action:

  • Real‑world actions – send emails, create tickets, write to databases.
  • Data retrieval – query APIs, search the web, read files.
  • Automation – chain multiple operations without human intervention.
  • Computation – offload deterministic calculations to reliable functions.
  • System integration – connect to CRMs, ERPs, and internal microservices.

Without tools, agents are limited to what they already know. With tools, they become operational.

How Tool Calling Works

The lifecycle of a tool call is orchestrated entirely by the AutoGen runtime.

  1. The agent receives a message and builds a prompt that includes the tool definitions.
  2. The LLM decides to invoke a tool and returns a structured request with the tool name and arguments.
  3. The agent emits a ToolCallRequestEvent; the runtime picks it up and dispatches to the appropriate ToolExecutor.
  4. The executor runs the function (locally or in a sandbox) and returns the output.
  5. The result is wrapped as a ToolCallExecutionEvent and fed back to the agent as an observation.
  6. The agent continues reasoning, possibly calling more tools, until it produces a final answer.

This cycle is fully asynchronous and can be intercepted for human approval or logging via event handlers.

Core Concepts Overview

ConceptRole
ToolA callable function wrapped with FunctionTool, exposing a name, description, and JSON schema.
FunctionThe Python callable that implements the tool’s logic.
Code ExecutorAn environment that runs code blocks from agent messages and returns output.
Execution ResultThe output of a tool or code block, serialised as a string and injected into the conversation.
Validation LayerThe schema enforcement that ensures arguments match the expected types.

Together, these concepts allow an agent to act, not just talk.

Tool Types in AutoGen

AutoGen supports any Python function as a tool. You simply wrap it in FunctionTool and (optionally) define a Pydantic model for its arguments.

1. Function Tools

Arbitrary Python logic—calculations, string transformations, local file operations.

from autogen_core.tools import FunctionTool
from pydantic import BaseModel

class AddInput(BaseModel):
a: float
b: float

def add(a: float, b: float) -> float:
return a + b

add_tool = FunctionTool(add, description="Add two numbers", args_type=AddInput)

2. API Tools

Wrap external REST/GraphQL calls. Use requests or httpx inside the function.

def get_weather(city: str) -> str:
import requests
resp = requests.get(f"https://api.weather.com/v1/current?city={city}")
return resp.json()["condition"]["text"]

weather_tool = FunctionTool(get_weather, description="Get current weather")

3. Database Tools

Query databases safely using parameterised queries.

def query_customers(customer_id: int) -> str:
# Use safe SQL parameterization
...

4. Search Tools

Integration with search engines (Tavily, Serper) or internal search APIs.

5. Custom Tools

Any business logic that needs to be exposed to the agent. The key is a clear description so the LLM knows when to use it.

Tool Registration

Tools are attached to an agent at creation time via the tools parameter. The agent serialises the tool schemas (name, description, parameters) and passes them to the LLM in each turn. The LLM then uses the provided descriptions to decide when and how to call a tool.

agent = AssistantAgent(
name="assistant",
model_client=model_client,
tools=[stock_tool, weather_tool, add_tool]
)

The runtime handles the execution; the developer does not need to write any dispatching logic. For advanced cases, you can also register a tool as a standalone resource in the runtime and let any agent use it by name.

Tool Selection Process

The LLM receives the conversation history plus a list of tool definitions. It determines:

  • Whether a tool is needed – If the answer can be given from internal knowledge, the LLM may not call any tool.
  • Which tool to use – Based on the descriptions and the user’s request. The LLM performs a semantic match.
  • How arguments are generated – The LLM fills the parameters according to the tool’s JSON schema, using context from the conversation.

If the generated arguments are invalid (e.g., missing required fields), the runtime may catch the error and feed it back to the agent for correction. This self‑correcting loop is built‑in.

What Is Code Execution

Sometimes a task cannot be solved by a pre‑defined tool. The agent needs to write and run code dynamically—for example, to perform a statistical analysis, process a CSV file, or generate a chart. AutoGen provides code executors that:

  • Receive a code block from the agent (typically inside a message with language annotation).
  • Execute it in a controlled environment (local process, Docker container, or custom sandbox).
  • Collect the standard output and error streams.
  • Return the result as a string that the agent can interpret.

Code execution is treated like a special, multi‑purpose tool—but with additional safety constraints.

Python Code Execution

Python is the default language for AutoGen agents. The agent may emit a code block like:

```python
import yfinance as yf
data = yf.download("AAPL", period="1d")
print(data)

The code executor runs this in a Python subprocess and returns:

[*******************100%%********************] 1 of 1 completed Open High ... Date 2026-06-11 215.0 217.2 ...


The agent then reads this output and formulates a plain‑language answer.

**Setting up a local code executor:**

```python
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor

executor = LocalCommandLineCodeExecutor(
work_dir="./agent_work",
timeout=30 # seconds
)
agent = AssistantAgent(..., code_executor=executor)

For production, you almost always want a Docker‑based executor to provide strong isolation.

Code Execution Lifecycle

  1. Task analysis – The agent decides code is the best way to solve the task (prompted by its system message).
  2. Code generation – The LLM writes the code and wraps it in a markdown code fence.
  3. Validation – The runtime optionally checks for dangerous imports or patterns before execution.
  4. Execution – The code runs in the configured environment with resource limits.
  5. Result collection – stdout, stderr, and return code are captured.
  6. Response generation – The agent interprets the result and replies to the user.

If the code fails, the error message is returned; the agent can attempt to fix the code and re‑run it.

Execution Environments

EnvironmentDescriptionUse case
Local ExecutionRun code directly on the host machine (Python subprocess).Development, trusted code.
Docker ContainerExecute inside an isolated Docker container with limited resources.Production, untrusted code, reproducible environments.
Remote ExecutionOffload code to a remote server or cloud function.High‑security, specialised hardware (GPUs).
Custom SandboxIntegrate with sandboxing services (e.g., gVisor, Firecracker).Enterprise security requirements.

Docker executor example:

from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor

executor = DockerCommandLineCodeExecutor(
image="python:3.11-slim",
timeout=60,
work_dir="/workspace"
)

This runs the generated code in an ephemeral container with no access to the host network or filesystem unless explicitly granted.

Security Considerations

Code execution is the most dangerous capability you can give an agent. Mitigations are mandatory.

  • Sandboxing – Use Docker or a dedicated sandbox. Never run code directly on the host in production.
  • Permission control – Drop all unnecessary capabilities: no network, limited filesystem access, read‑only volumes.
  • Resource limits – Set CPU and memory limits on containers; use timeout to prevent runaway processes.
  • Network restrictions – Block external network access unless the agent explicitly needs to call an API. Prefer pass‑through tools instead of letting code open arbitrary sockets.
  • File system restrictions – Mount only the directories the agent needs, and use temporary volumes that are cleaned after execution.
  • Input validation – Scan generated code for dangerous patterns (e.g., os.system, subprocess with shell=True, __import__) and reject them before execution.

A common pattern is to use a tool‑first approach: expose only pre‑approved operations as tools, and reserve code execution for genuinely dynamic, non‑sensitive computation within a locked‑down container.

Error Handling

Failures are common and must be handled gracefully.

  • Syntax errors – The agent receives the traceback and can rewrite the code. Limit the number of retries (e.g., 3).
  • Runtime errors – Same as syntax errors; the error message is fed back. Ensure the code executor catches exceptions and returns them as output, not just non‑zero exit codes.
  • Tool failures – Wrap tool functions in try/except and return a descriptive error string. The LLM can then try an alternative approach.
  • Execution timeouts – Set a timeout on the code executor. If the code exceeds it, kill the process and return a timeout error. The agent can try to optimise or ask for help.
  • Retry strategies – Implement a loop in your agent’s logic (or via a group chat) that allows a few correction attempts before falling back to a human or a safe default.

Tool Calling vs Code Execution

FeatureTool CallingCode Execution
PurposeInvoke a known, pre‑defined capabilityPerform arbitrary, dynamic computation
ComplexityLow – simple function callHigh – agent writes code
RiskLower – deterministic, auditableHigher – arbitrary code execution
FlexibilityModerate – limited to what’s definedVery high – can adapt to any task
Use caseFetch data, API calls, simple actionsData analysis, file processing, complex math
ControlDeveloper‑defined; easy to secureRequires sandboxing and restrictions

A good agent uses both: tools for safe, repeatable actions, and code execution for open‑ended problem solving, always with the strictest security possible.

Performance Optimization

  • Tool caching – If a tool is deterministic and called repeatedly with the same arguments, cache its result in memory or Redis. Use a decorator.
  • Result reuse – The agent can store intermediate results in the conversation and avoid re‑computation.
  • Efficient execution – Keep tool functions fast; offload heavy processing to background tasks if needed.
  • Reduce unnecessary runs – Instruct the agent to check if the answer is already available before writing code.
  • Optimize code – The LLM might generate inefficient code; a review step can flag and optimise.

Common Tool Patterns

PatternDescriptionExample
LookupFetch a single value from a key.get_order_status(order_id)
RetrievalSearch and return multiple results.search_knowledge_base(query)
ActionPerform a side‑effect (send, write, create).send_email(recipient, body)
TransformationConvert data from one format to another.json_to_csv(json_string)
ValidationCheck if data meets rules, return boolean.is_valid_credit_card(number)

Each tool should be atomic and self‑contained. Combine them in conversation, not inside a single monolithic function.

Common Code Execution Patterns

  • Data processing – Read a file, clean data, transform.
  • File automation – Rename, compress, or move files.
  • Data analysis – Compute statistics, generate plots (saved as images and returned).
  • Report generation – Compile a PDF or Markdown report from data.
  • API integration – Write code that calls multiple APIs and merges results (if tools can’t handle the logic).

Common Beginner Mistakes

  • Unsafe code execution – Running agent‑generated code without a sandbox. Always sandbox.
  • No sandboxing – Using LocalCommandLineCodeExecutor in production. Switch to Docker.
  • Excessive tool usage – Creating a tool for every single operation instead of letting code handle variations.
  • Missing validation – Not checking tool outputs before using them in downstream logic.
  • Large execution payloads – Returning huge data blobs from tools bloats the conversation and costs.
  • Ignoring timeouts – A runaway loop in generated code can hang the agent indefinitely.

Best Practices

  • Keep tools atomic – One tool, one clear action.
  • Validate all inputs – Use Pydantic models for tool arguments; reject invalid requests before execution.
  • Sandbox execution – Always use the most restrictive environment possible.
  • Limit permissions – Docker: --network=none, read‑only root, no privilege escalation.
  • Monitor execution costs – Track tool call latency and code execution time; set budgets.
  • Log all executions – Record tool names, arguments (sanitised), code snippets, and outputs for debugging and audit.
  • Use tools for sensitive operations – Prefer a tool over code execution for anything that modifies databases or sends emails.
  • Test with adversarial prompts – Verify that the agent cannot escape the sandbox.

Practical Example: Data Analysis Agent

We’ll build an agent that fetches stock data (via a tool), performs a moving‑average analysis using generated Python code, and returns a summary report.

1. Define the tool and code executor

from autogen_core.tools import FunctionTool
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient

def fetch_stock_prices(ticker: str, days: int = 30) -> str:
# Simulate fetching historical data (in production, call yfinance or an API)
return f"{ticker} prices: day1:100, day2:102, day3:101 ... (30 days)"

stock_tool = FunctionTool(fetch_stock_prices, description="Fetch stock price history")

# Docker executor for safe Python execution
code_executor = DockerCommandLineCodeExecutor(
image="python:3.11-slim",
timeout=30,
work_dir="/analysis"
)

2. Create the agent

analyst = AssistantAgent(
name="StockAnalyst",
system_message="""You are a financial data analyst.
Use the stock price tool to get data, then write Python code to analyse it.
Always output a final summary in plain language.
""",
model_client=OpenAIChatCompletionClient(model="gpt-4o"),
tools=[stock_tool],
code_executor=code_executor
)

3. Run the workflow

user_message = "Analyse the last 30 days of AAPL stock and give me a summary of the trend."
response = await analyst.on_messages(
[TextMessage(content=user_message, source="user")],
cancellation_token=None
)
print(response.chat_message.content)

What happens step by step:

  1. The agent receives the message. The LLM decides to call fetch_stock_prices("AAPL", 30).
  2. The tool is executed, returning a string of simulated prices.
  3. The agent sees the result, and the LLM writes Python code to compute a simple moving average and detect the trend. It outputs a code block.
  4. The Docker code executor runs the code. The output (e.g., “The 5‑day moving average shows a slight uptrend.”) is captured.
  5. The agent reads the code output and composes a final user‑friendly summary.

The entire process is autonomous, secure, and fully observable through the event stream.

Production Considerations

  • Monitoring – Emit custom metrics or log events for each tool call and code execution. Use Azure Monitor, Prometheus, or OpenTelemetry.
  • Logging – Record the full conversation and all intermediate outputs for debugging. Sanitise sensitive data.
  • Security – Regularly update Docker images, scan for vulnerabilities, and apply resource limits.
  • Cost Management – Code execution and tool calls consume compute; set usage quotas per user.
  • Reliability – Implement retries for tool failures; for code execution, if it fails repeatedly, escalate to a human.

Tools & Code Execution and Other AutoGen Concepts

  • Core Concepts – Agents and messages are the foundation; tools extend them.
  • Conversation Patterns – Tools can trigger handoffs or group discussion; code output can be reviewed by a human.
  • Workflows – Complex automation chains rely on tools and code execution as the primary action components.
  • Production – Production environments must harden these capabilities.
  • MCP – MCP servers expose tools in a standardized way; AutoGen can consume them as FunctionTool instances.

For other frameworks, see the LangGraph and CrewAI guides and the framework comparison.

FAQ

1. What are tools in AutoGen?

Tools are callable Python functions wrapped with FunctionTool that expose a name, description, and parameter schema to the agent. The agent can invoke them via tool call requests.

2. How does code execution work in AutoGen?

The agent generates a code block (typically Python), and the configured CodeExecutor runs it in a sandboxed environment. The output (stdout, stderr) is returned to the agent for interpretation.

3. Can AutoGen run Python code?

Yes, using local, Docker, or custom code executors. The environment can be fully isolated for safety.

4. How do I secure code execution?

Use Docker containers with restricted permissions (no network, limited filesystem, resource limits), scan code for dangerous patterns, and set timeouts.

5. What is sandbox execution?

Running generated code in an isolated environment (e.g., Docker container) that prevents access to the host system and limits potential damage.

6. How are tools selected by the agent?

The LLM receives the tool definitions in its prompt. It uses the tool descriptions to decide which tool is appropriate and generates arguments that conform to the tool’s schema.

7. Is code execution production‑ready?

Yes, with proper sandboxing (Docker), monitoring, and error handling, code execution can be safely used in production.

8. Can I use multiple tools in the same agent?

Yes, pass a list of FunctionTool instances to the agent’s tools parameter. The LLM will choose among them.

9. How do I handle errors in tool calls?

Inside your tool function, catch exceptions and return a descriptive error string. The agent can then try an alternative or ask for clarification.

10. What’s the difference between a tool and a code executor?

A tool is a pre‑defined, static function; a code executor runs dynamically generated code. Tools are safer and faster; code executors are more flexible.

11. Can I combine tools and code execution in one workflow?

Yes. An agent can call a tool to fetch data, then write and run code to analyse it, all within the same conversation.

12. How do I limit the execution time of code?

Set the timeout parameter on the code executor (e.g., timeout=30). The process will be killed if it exceeds the limit.

13. Are there built‑in tools in AutoGen?

AutoGen provides a few examples, but the framework is designed for you to bring your own tools. The ecosystem includes community tools and integrations.

14. Can I use code execution with non‑Python languages?

AutoGen’s code executors can, in principle, run any language if the environment is set up. Python is the primary supported language.

15. How do I monitor tool usage?

Subscribe to ToolCallRequestEvent and ToolCallExecutionEvent events and log them, or use the runtime’s telemetry hooks.

Conclusion

AutoGen Tools & Code Execution transform agents from passive text generators into active problem‑solvers. By defining tools for safe, repeatable actions and using code executors for dynamic computation, you can build powerful automation pipelines that are secure, observable, and production‑ready.

Key takeaways:

  • Tools are wrapped Python functions with schemas; agents call them via the runtime.
  • Code execution allows agents to write and run Python code in sandboxes.
  • Security is paramount: always sandbox code execution and validate tool inputs.
  • Error handling and monitoring are essential for production reliability.
  • The right mix of tools and code execution gives you both safety and flexibility.

Continue your AutoGen journey:

For standardised tool ecosystems, explore the MCP Guide. For cross‑framework comparisons, check the LangGraph and CrewAI guides, and the complete comparison.

Now, equip your agents with the tools they need—and let them write the code that gets the job done.