需要 Python >= 3.11;需按模型厂商安装对应 extra 并设置 OPENAI_API_KEY 等环境变量;v1.0 不再提供 autogen 命名空间,旧代码需改装 ag2-classic
ag2
ag2aiApache-2.0活跃维护开源多智能体编排框架,前身是 AutoGen,支持构建、协作和调度多个 LLM 智能体,并集成 MCP、A2A 等协议。
AG2 (formerly AutoGen): The Open-Source AgentOS.Join us at: https://discord.gg/sNGSwQME3x
AG2 是开源 AgentOS,用异步 Agent 和 Network 编排多智能体协作
开源多智能体编排框架,前身是 AutoGen,支持构建、协作和调度多个 LLM 智能体,并集成 MCP、A2A 等协议。
核心能力
- 用 Agent.ask 发起对话轮次并保留历史上下文
- 用 @tool 装饰 Python 函数,自动完成工具调用循环
- 通过 Network 的 hub 与类型化 channel 编排多智能体
- 用 context.input 与 hitl_hook 实现人工介入审批
- 提供知识持久化、上下文组装与历史压缩的 harness 原语
容易踩的坑
- v1.3.0最新正式版2026-11-04 · 2026-11-04 09:21 UTC
AG2 1.3 adds observation across delegation trees, explicit variable scopes, dynamic model context, and a shared task lifecycle.
Deprecations and migration to 1.4
The following APIs continue to work in 1.3 with deprecation warnings and will be removed in 1.4.0:
Deprecated API Replacement and migration guide TaskConfig,Agent(tasks=...),Agent.tasks, and the automatically injectedrun_subtask/run_subtaskstoolsConstruct workers explicitly and delegate through Agent.as_tool(). Migration guideAgent(assembly=...)Register AssemblerMiddlewarethroughmiddleware=; addHaltCheckMiddlewarewhen usingAlertPolicy. Assembly guideAgent(knowledge=...)Use plugins=[KnowledgePlugin(...)]. Migration guideAgent.task()Construct Task(owner_id=..., spec=TaskSpec(...))directly for standalone work. Task APIKnowledgeConfig, assembly policies, andTaskremain supported; the deprecations apply to the entry points above.As previously announced,
OpenAIConfigwill become an alias forOpenAIResponsesConfigin 1.4. UseOpenAIResponsesConfigorOpenAICompletionsConfigexplicitly. Model configuration.Python requirement
AG2 1.3 requires Python 3.11 or newer. Upgrade Python before updating an environment that still uses 3.10.
The examples below use
OpenAIResponsesConfig. Installag2[openai]and setOPENAI_API_KEYas described in the Quick Start. Run statements containingawaitinside an async function. Later fragments reuseconfigfrom the first example.Observe the entire delegation tree
Ancestors now receive events from every descendant, including streamed chunks. Operational events arrive as
ChildEventobservations: they do not enter the ancestor's model transcript or trigger its tools, model loop, or HITL handlers.Typed
@observer(...)callbacks let a coordinator monitor the whole tree. An observed event's liveevent.originaddresses the invocation that authored it; useawait event.origin.send(...)to deliver an event back through that invocation's normal handlers. Handles expire when the invocation ends and are not available when replaying saved history.Documentation: event observation and addressed delivery.
Explicit variable scopes
ScopedValuedefines how state crosses a delegation boundary:Scope Behavior COPIEDDeep-copied for each branch; the default for plain values LOCALNot inherited by descendants SHAREDOne binding across the invocation's tree, including replacement of its value Declare shared names at the root. Applications provide synchronization for concurrent updates; locks, clients, and connections belong in dependencies. Fresh root invocations copy their input values, so read results from
reply.context.variablesrather than the caller's original containers.Documentation: variable scopes.
Use event observation and scoped state together:
from ag2 import Agent, Context, Scope, ScopedValue, observer, tool from ag2.config import OpenAIResponsesConfig from ag2.events import ChildEvent, ModelMessageChunk config = OpenAIResponsesConfig(model="gpt-5", streaming=True) @tool def save_finding(finding: str, context: Context) -> str: """Save a finding and update this worker's draft.""" context.variables["findings"].append(finding) context.variable - v1.2.22026-10-27 · 2026-10-27 20:53 UTC
查看更新说明
Highlights
- Timeouts for code that can hang:
@tool(timeout=...)limits each function tool call, andtimeout=on stream subscribers,@observer,BaseObserver,LoopDetectorandTokenMonitorlimits each callback. A timed-out tool returns aTimeoutErrorto the model, which can continue. - Anthropic SDK 2.x support, plus new
AnthropicConfigoptions: a typedspeedandopen_telemetryto configure or disable the SDK's own OpenTelemetry spans. OpenAIDecisionsConfigacceptsquestion_instructions(strings, ag2 inputs or SDK parts), appended to the agent prompt.- A2UI v1.0 updated to the current spec, including
callAgentFunction/agentFunctionResponseand renderer capabilities. - New
Glasserpaid-data toolkit extension. - More accurate token usage: Anthropic continuation tokens, Gemini thinking tokens and xAI reasoning tokens are now counted, and OpenAI
cache_write_tokensmaps tocache_creation_input_tokens. - Fixes for Mistral streaming, A2A empty text artifacts, eval dataset tags and failure attribution,
SKILL.mdfiles with a BOM, andupdate_filewith emptyold_content.
Upgrade notes
OpenAIConfigis deprecated and becomes the Responses API in 1.4.0. The current Chat Completions behavior is nowOpenAICompletionsConfig;OpenAIConfigstill works unchanged but emits aDeprecationWarningfromcreate(). Switch toOpenAICompletionsConfigto keep Chat Completions, or toOpenAIResponsesConfigto move now. Renaming the class does not translate API-specific options.temperature,top_pandtop_konAnthropicConfigare deprecated until 1.4.0. The API version used byanthropic2.x rejects them, so with SDK 2.x they warn and are dropped; with 1.x they warn and are still sent. The extra now requiresanthropic>=1.15.0,<3.- OpenAI now requires
openai>=3.37.0,<4.
What's Changed
- feat: add Glasser paid-data toolkit by @glasserai in https://github.com/ag2ai/ag2/pull/3462
- fix(mistral): isolate streamed completion choices by @ch-z-hc in https://github.com/ag2ai/ag2/pull/3471
- test(tools): keep the tight switch interval off under a tracer in the… by @vvlrff in https://github.com/ag2ai/ag2/pull/3481
- fix(anthropic): count continuation token usage by @ch-z-hc in https://github.com/ag2ai/ag2/pull/3472
- feat(a2ui): update A2UI v1.0 to the current spec by @vvlrff in https://github.com/ag2ai/ag2/pull/3469
- chore(deps): bump gitpython from 3.1.62 to 3.2.1 by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3485
- chore(deps): bump opentelemetry-api from 1.45.0 to 1.45.1 by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3486
- fix(a2a): preserve empty text artifact type by @fallintoplace in https://github.com/ag2ai/ag2/pull/3451
- fix(gemini): include thinking tokens in completion usage by @original4422 in https://github.com/ag2ai/ag2/pull/3446
- fix(filesystem): reject empty old_content in update_file on non-empty files by @BichengWang in https://github.com/ag2ai/ag2/pull/3303
- fix(textual): use correct optional import module by @fallintoplace in https://github.com/ag2ai/ag2/pull/3497
- fix(stream): preserve explicitly provided empty storage by @fallintoplace in https://github.com/ag2ai/ag2/pull/3498
- fix(openai): map cache_write_tokens to cache_creation_input_tokens by @rome-xi in https://github.com/ag2ai/ag2/pull/3499
- fix(eval): reject non-string dataset tags by @fallintoplace in https://github.com/ag2ai/ag2/pull/3496
- feat(anthropic): add typed speed option to AnthropicConfig by @its-amann in https://github.com/ag2ai/ag2/pull/3495
- fix(a2ui): keep v1.0 validation linear in nested function calls by @vvlrff in https://github.com/ag2ai/ag2/pull/3492
- fix(xai): include reasoning tokens in completion usage by @vvlrff in https://github.com/ag2ai/ag2/pull/3493
- test(openai): fix usage expectations after cache-write mapping by @Lancetnik in https://github.com/ag2ai/ag2/pull/3510
- chore(deps): bump the github
- Timeouts for code that can hang:
- v1.2.12026-10-21 · 2026-10-21 20:18 UTC
查看更新说明
Highlights
- Mistral voice for
ag2.live: offline and realtime speech-to-text (MistralTranscriber,MistralRealtimeTranscriber) and text-to-speech (MistralTTSConfig,MistralStreamingTTSConfig), on top ofmistralai3.2 with its new chat parameters. OpenAIResponsesConfigaccepts areasoningoption for effort and summaries.- New search toolkits:
FirecrawlToolkitandKeenableSearchToolkit. - New
compaction_verifierextension: measures whether aCompactStrategymakes the agent's next actions worse, not just how many tokens it saves. - TypeSafe can locate objects in images:
ResponseSchema(BoundingBox)sends a Box question. - ACP and the network layer keep multimodal input parts instead of flattening them to text.
- Fixes for Ollama, Gemini and xAI history, paginated file listings, and atomic SQLite and Redis knowledge appends.
Upgrade notes
- Mistral uses
httpx2.mistralai3.x moved fromhttpxtohttpx2, soMistralConfig.async_clientis now anhttpx2.AsyncClientand the extra requiresmistralai>=3.2.0,<4. Anhttpx.AsyncClientstill works at runtime but no longer type-checks, andhttpx.HTTPErrordoes not catchhttpx2errors. - ElevenLabs now requires
elevenlabs>=2.73.0,<3. - Input parts are no longer joined into one string in ACP and the network layer. ACP sends each part as its own content block, based on what the agent advertises; before, every non-text part was dropped.
ChannelAdapter.render_envelopeandextract_turn_inputcan now return anInputor a sequence of them, so check custom channel adapters. - MCP tool calls are pinned to the configuration used for discovery, so a
Variable(default_factory=...)can no longer route a call to a different server than the one that advertised the tool. - OpenAI Chat Completions rejects files uploaded to another provider with
UnsupportedInputError, like the Responses, Anthropic and Gemini mappers.
What's Changed
- chore(deps): bump j178/prek-action from 3.0.0 to 3.0.1 in the github-actions group by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3405
- chore(deps): bump the uv group with 16 updates by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3406
- fix(ollama): serialize multipart tool results as text by @ch-z-hc in https://github.com/ag2ai/ag2/pull/3374
- feat(openai): add reasoning option to OpenAIResponsesConfig by @vvlrff in https://github.com/ag2ai/ag2/pull/3407
- feat(mistral): bump mistralai to 3.2 and expose new chat parameters by @vvlrff in https://github.com/ag2ai/ag2/pull/3408
- fix: keep input parts separate instead of joining them into a string by @vvlrff in https://github.com/ag2ai/ag2/pull/3413
- fix(annotations): resolve falsy Variable and Inject values from context by @kabishou11 in https://github.com/ag2ai/ag2/pull/3414
- fix(events): fall back to media type for unknown binary kinds in sizing by @kabishou11 in https://github.com/ag2ai/ag2/pull/3416
- fix(eval): apply threshold keys to passthrough feedback by @BichengWang in https://github.com/ag2ai/ag2/pull/3423
- fix(gemini): preserve function call IDs in history by @ch-z-hc in https://github.com/ag2ai/ag2/pull/3417
- fix(shell): check paths after '=' against the ignore list by @kabishou11 in https://github.com/ag2ai/ag2/pull/3415
- fix(xai): preserve conversation history order by @ch-z-hc in https://github.com/ag2ai/ag2/pull/3418
- feat(extensions/search): add Firecrawl search and scrape toolkit by @JuampiHernandez in https://github.com/ag2ai/ag2/pull/3362
- feat(live): add MistralTranscriber for offline speech-to-text by @vvlrff in https://github.com/ag2ai/ag2/pull/3419
- feat(live): add Mistral TTS configs by @vvlrff in https://github.com/ag2ai/ag2/pull/3420
- fix(typesafe): bump typesafe-sdk to 0.7.5 and handle unexpected answe… by @vvlrff in https://github.com/ag2ai/ag2/pull/3424
- fix(elevenlabs): support elevenlabs 2.73 and expose Scribe/TTS options by @vvlrff in https://g
- Mistral voice for
- v1.2.02026-10-11 · 2026-10-11 09:26 UTC
查看更新说明
Highlights
- OpenAI Decisions API support with
OpenAIDecisionsConfigand shared decision schemas using theQuestionmarker. - A2A servers can run on multiple replicas, with cacheable agent cards, opt-in input media type validation, and configurable push notification URL validation.
- Anthropic cache diagnostics and explicit API keys for OpenAI voice configs.
- Ollama API keys, custom HTTP clients, tool names, and fixes for duplicate streaming tool-call IDs.
- Fixes for MCP discovery, knowledge stores, evaluation suite loading, skills, A2UI, and network graph loading.
Toolkit composition
left | rightnow creates an independent toolkit collection containing the original tool objects and their existing middleware. Tools from the right no longer receive middleware from the left, and later additions to the combined toolkit do not inherit either source's middleware. Replacement by name still uses the right-hand tool.If you relied on composition to attach middleware, attach it explicitly through toolkit construction or per-tool configuration.
What's Changed
- docs(ag-ui): update CopilotKit quickstart for the AG-UI 1.0 sample by @vvlrff in https://github.com/ag2ai/ag2/pull/3340
- docs: fix observer and knowledge store examples that fail to run by @BichengWang in https://github.com/ag2ai/ag2/pull/3337
- fix(knowledge): match SqliteKnowledgeStore prefixes literally by @kabishou11 in https://github.com/ag2ai/ag2/pull/3339
- fix(shell): refuse ignored files named through a wildcard by @vvlrff in https://github.com/ag2ai/ag2/pull/3350
- feat(a2a): expose push notification URL validation by @BichengWang in https://github.com/ag2ai/ag2/pull/3348
- fix(test): ensure sibling call is announced before asking human by @vvlrff in https://github.com/ag2ai/ag2/pull/3357
- refactor(typing): bring a2a and a2ui into the type-checked set by @vvlrff in https://github.com/ag2ai/ag2/pull/3351
- refactor(typing): bring mcp_ui, mcp and acp into the type-checked set by @vvlrff in https://github.com/ag2ai/ag2/pull/3356
- refactor(typing): bring the Z.AI, Gemini and OpenAI providers into th… by @vvlrff in https://github.com/ag2ai/ag2/pull/3358
- feat(a2a): let A2AServer run on several replicas by @vvlrff in https://github.com/ag2ai/ag2/pull/3354
- chore(deps): bump the uv group with 16 updates by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3360
- chore(deps): bump github/codeql-action/upload-sarif from 4.38.1 to 4.38.2 in the github-actions group by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3359
- fix(eval): handle null and single-string tags/metadata in Suite items by @kabishou11 in https://github.com/ag2ai/ag2/pull/3353
- fix(knowledge): allow DiskKnowledgeStore.on_change to watch a file path by @kabishou11 in https://github.com/ag2ai/ag2/pull/3352
- feat(anthropic): add cache diagnostics support to client and config by @vvlrff in https://github.com/ag2ai/ag2/pull/3364
- chore(deps): bump multidict from 6.7.1 to 6.9.1 by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3367
- feat(live): accept explicit API keys in OpenAI voice configs by @carey-bk in https://github.com/ag2ai/ag2/pull/3338
- chore(live): cover ag2.live with strict mypy by @vvlrff in https://github.com/ag2ai/ag2/pull/3370
- refactor(config): cover ag2.config with strict mypy by @vvlrff in https://github.com/ag2ai/ag2/pull/3372
- feat(a2a): cacheable agent card and opt-in input media type validation by @vvlrff in https://github.com/ag2ai/ag2/pull/3366
- refactor(types): put ag2/tools under strict mypy by @vvlrff in https://github.com/ag2ai/ag2/pull/3371
- fix(mcp): refresh toolkit discovery when resolved configuration changes by @asts-top in https://github.com/ag2ai/ag2/pull/3385
- fix(typesafe): bump typesafe-sdk to 0.7.4 and fix mypy errors by @vvlrff in https://github.com/ag2ai/ag2/pull/3392
- Openai decisions API implementation + examples by @stepacool in https://github.com/ag2ai/ag2/pull/3382
- fix: avoid duplicate Ollama streaming tool call
- OpenAI Decisions API support with
- v1.1.22026-10-03 · 2026-10-03 06:25 UTC
查看更新说明
What's Changed
- fix(mcp): derive model output schemas from serialization by @asts-top in https://github.com/ag2ai/ag2/pull/3317
- fix(tenki): upgrade sdk and preserve timeout failures by @camcalaquian in https://github.com/ag2ai/ag2/pull/3329
- chore(deps): bump gitpython from 3.1.59 to 3.1.62 by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3332
- fix(skills): check local skill ownership before validating arguments by @carey-bk in https://github.com/ag2ai/ag2/pull/3328
- chore(deps): bump pyjwt from 2.14.0 to 2.15.0 by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3331
- chore(deps): bump urllib3 from 2.7.0 to 2.8.0 by @dependabot[bot] in https://github.com/ag2ai/ag2/pull/3330
- feat(ag-ui)!: serve AG-UI 1.0 by @vvlrff in https://github.com/ag2ai/ag2/pull/3314
- fix(skills): execute nested scripts from declared paths by @Whxuan0701 in https://github.com/ag2ai/ag2/pull/3181
- refactor(types): put ten more modules under strict mypy by @vvlrff in https://github.com/ag2ai/ag2/pull/3334
- fix: port provider, live and MCP bug fixes out of #3275 by @vvlrff in https://github.com/ag2ai/ag2/pull/3333
- feat(agent): support invocation-scoped plugins by @Lancetnik in https://github.com/ag2ai/ag2/pull/3335
- chore: bump version to 1.1.2 by @vvlrff in https://github.com/ag2ai/ag2/pull/3336
Security:
- fix shell command-filter bypasses in SandboxShellTool / ShellAdapter (GHSA-42mf-vpmr-gw5r).
New Contributors
- @carey-bk made their first contribution in https://github.com/ag2ai/ag2/pull/3328
Full Changelog: https://github.com/ag2ai/ag2/compare/v1.1.1...v1.1.2
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
[!IMPORTANT] Looking for
ConversableAgent,GroupChat, orimport autogen? That's now AG2 Classic.As of AG2 v1.0, the protocol-driven framework is the top-level package, imported as
ag2. The classic framework has moved to its own repository — ag2ai/ag2-classic, documented at classic.docs.ag2.ai. It is still maintained and installable; nothing you have built stops working.This repository (
pip install ag2) no longer ships theautogenimport name or the classic agent classes.
AG2: Open-Source AgentOS for AI Agents
AG2 is an open-source programming framework for building AI agents and facilitating cooperation among multiple agents to solve tasks. AG2 aims to streamline the development and research of agentic AI. It offers features such as agents capable of interacting with each other, facilitates the use of various large language models (LLMs) and tool use support, autonomous and human-in-the-loop workflows, and multi-agent conversation patterns.
The project is currently maintained by a dynamic group of volunteers from several organizations. Contact project administrators Chi Wang and Qingyun Wu via [email protected] if you are interested in becoming a maintainer.
Table of contents
- AG2: Open-Source AgentOS for AI Agents
AG2 Classic (the autogen.* namespace)
AG2 Classic is the original AutoGen-derived framework: the autogen.* import namespace and its agent classes — ConversableAgent, AssistantAgent, UserProxyAgent, GroupChat / GroupChatManager, swarms, register_function, LLMConfig / OAI_CONFIG_LIST, and the nested- and sequential-chat patterns.
It now lives in its own repository and has its own documentation site:
| AG2 Classic | AG2 (this repo) | |
|---|---|---|
| Repository | ag2ai/ag2-classic | ag2ai/ag2 |
| Documentation | classic.docs.ag2.ai | docs.ag2.ai |
| Import | import autogen | import ag2 |
| Core agent | ConversableAgent | Agent |
| Multi-agent | GroupChat, swarms, nested chats | Network (hub + channels) |
Are you using AG2 Classic?
If any of the following appear in your code, you are on Classic — stay on it, and use classic.docs.ag2.ai:
import autogen # the autogen.* namespace
from autogen import ConversableAgent, GroupChat # classic agent classes
from autogen import AssistantAgent, UserProxyAgent
Classic remains maintained and installable. Your existing code keeps working — pin the classic distribution instead of ag2>=1.0:
pip install ag2-classic
[!NOTE] AG2 v1.0 (
pip install ag2) is not a drop-in upgrade from Classic. The agent model, orchestration, and imports all changed. See the group chat migration guide.
The rest of this README covers AG2 v1.0 (import ag2).
Getting started
For a step-by-step walk through of AG2 concepts and code, see the Quick Start in our documentation.
Installation
AG2 requires Python version >= 3.11. AG2 is available as ag2 on PyPI.
Windows/Linux:
pip install ag2[openai]
Mac:
pip install 'ag2[openai]'
Minimal dependencies are installed by default. Install the extra that matches your model provider — ag2[openai], ag2[anthropic], ag2[gemini], ag2[ollama], and so on.
Setup your API keys
Each provider config reads its standard environment variable, so keys never need to be hardcoded or checked in:
export OPENAI_API_KEY="<your-api-key>" # or ANTHROPIC_API_KEY, GEMINI_API_KEY, ...
You can also pass a key explicitly with OpenAICompletionsConfig(model="gpt-4o-mini", api_key=...) — useful when each request brings its own key.
Run your first agent
AG2 is async throughout. Agent.ask(...) starts a turn and returns an AgentReply; the text is in reply.body.
import asyncio
from ag2 import Agent
from ag2.config import OpenAICompletionsConfig
agent = Agent(
"assistant",
prompt="You are a helpful assistant.",
config=OpenAICompletionsConfig(model="gpt-4o-mini"),
)
async def main() -> None:
reply = await agent.ask("Summarize the main differences between Python lists and tuples.")
print(reply.body)
asyncio.run(main())
Example applications
We maintain both a live playground and a dedicated repository with a wide range of applications to help you get started with various use cases, and a set of runnable code examples in the documentation.
Introduction of different agent concepts
We have several agent concepts in AG2 to help you build your AI agents. We introduce the most common ones here.
- Agents:
Agentis the core building block — it talks to a model provider, calls tools, and returns a reply. - Tools: Plain Python functions, decorated with
@tool, that the agent can invoke. - Human in the loop: Pause a run to collect confirmation or missing information from a person.
- Orchestrating multiple agents: Coordinate several agents over a hub and typed channels using the Network.
- The agent harness: Opt-in primitives layered onto an agent — persistent knowledge, context assembly, and history compaction.
- Advanced Concepts: Structured outputs, middleware, observers, telemetry, evaluation, and more.
Agents
The Agent is the fundamental building block of AG2. ask() runs a turn; calling ask() on the returned reply continues the same conversation, preserving its history.
import asyncio
from ag2 import Agent
from ag2.config import OpenAICompletionsConfig
reviewer = Agent(
"reviewer",
prompt=(
"You are a code reviewer. Analyze the provided code and suggest improvements. "
"Do not generate code, only suggest improvements."
),
config=OpenAICompletionsConfig(model="gpt-4o-mini"),
)
async def main() -> None:
reply = await reviewer.ask("def fib(n): return n if n < 2 else fib(n-1) + fib(n-2)")
print(reply.body)
# Continue the same conversation — prior turns stay in scope.
follow_up = await reply.ask("Which of those matters most for large n?")
print(follow_up.body)
asyncio.run(main())
Tools
Agents gain significant utility through tools, which extend their capabilities with external data, APIs, or functions. Decorate a Python function with @tool and pass it to the agent — AG2 runs the full tool-calling loop: the model decides when to call it, AG2 executes it, and the result is fed back.
import asyncio
from datetime import datetime
from ag2 import Agent, tool
from ag2.config import OpenAICompletionsConfig
@tool
async def get_weekday(date_string: str) -> str:
"""Get the day of the week for a given date, formatted as YYYY-MM-DD."""
return datetime.strptime(date_string, "%Y-%m-%d").strftime("%A")
date_agent = Agent(
"date_agent",
prompt="You find the day of the week for a given date.",
config=OpenAICompletionsConfig(model="gpt-4o-mini"),
tools=[get_weekday],
)
async def main() -> None:
reply = await date_agent.ask("I was born on 1995-03-25, what day was it?")
print(reply.body)
asyncio.run(main())
Human in the Loop
Human oversight is often essential for validating or guiding AI outputs. Call context.input(...) inside a tool to pause the run and ask a person — your hitl_hook decides how that question is answered (CLI prompt, web UI, queue, …).
import asyncio
from ag2 import Agent, Context, tool
from ag2.config import OpenAICompletionsConfig
from ag2.events import HumanInputRequest, HumanMessage
@tool
async def publish_lesson_plan(context: Context, plan: str) -> str:
"""Publish a lesson plan, once a human educator has approved it."""
answer = await context.input(f"Approve this lesson plan?\n\n{plan}")
if answer.strip().lower().startswith("y"):
return "Published."
return f"Rejected by the educator: {answer}"
def hitl_hook(event: HumanInputRequest) -> HumanMessage:
# Block here for real input — a CLI prompt, a web UI, a queue.
return HumanMessage(content=input(f"{event.content}\n> "))
teacher = Agent(
"teacher",
prompt=(
"Draft a short lesson plan, then call the publish_lesson_plan tool to have it published. "
"Approval is collected by the tool — never ask for approval in plain text."
),
config=OpenAICompletionsConfig(model="gpt-4o-mini"),
tools=[publish_lesson_plan],
hitl_hook=hitl_hook,
)
async def main() -> None:
reply = await teacher.ask("Let's introduce our kids to the solar system.")
print(reply.body)
asyncio.run(main())
Orchestrating Multiple Agents
When two or more agents need to work together, AG2 uses the Network: a Hub that owns the registry, the write-ahead log, and the audit trail, with agents talking over typed channels. This replaces the classic GroupChat / swarm / nested-chat patterns.
Here a conversation channel — a free-form two-party session where either side may speak at any time — connects a planner and a reviewer:
import asyncio
from ag2 import Agent
from ag2.config import OpenAICompletionsConfig
from ag2.knowledge import MemoryKnowledgeStore
from ag2.network import EV_TEXT, Hub
MAX_MESSAGES = 4
async def wait_for_messages(hub: Hub, channel_id: str, expected: int, timeout: float = 120.0) -> None:
"""Poll the hub's write-ahead log until `expected` messages have been exchanged."""
deadline = asyncio.get_event_loop().time() + timeout
while asyncio.get_event_loop().time() < deadline:
wal = await hub.read_wal(channel_id)
if sum(1 for e in wal if e.event_type == EV_TEXT) >= expected:
return
await asyncio.sleep(0.05)
raise TimeoutError(f"only reached {expected} messages before timing out")
async def main() -> None:
config = OpenAICompletionsConfig(model="gpt-4o-mini")
hub = await Hub.open(MemoryKnowledgeStore(), ttl_sweep_interval=0)
planner = await hub.register(
Agent("planner", prompt="You plan school lessons. Reply in one short sentence.", config=config),
)
reviewer = await hub.register(
Agent("reviewer", prompt="You critique lesson plans. Reply in one short sentence.", config=config),
)
# Free-form 2-party channel: either side may speak at any time.
channel = await planner.open(type="conversation", target="reviewer")
await channel.send("What should a fourth-grade solar system lesson lead with?", audience=[reviewer.agent_id])
# Both default handlers reply to every inbound message, so the conversation
# auto-drives. `conversation` never auto-closes — we bound it and close it.
await wait_for_messages(hub, channel.channel_id, expected=MAX_MESSAGES)
await channel.close()
# Replay the exchange from the hub's write-ahead log.
names = {planner.agent_id: "planner", reviewer.agent_id: "reviewer"}
for envelope in await hub.read_wal(channel.channel_id):
if envelope.event_type == EV_TEXT:
print(f"{names[envelope.sender_id]}: {envelope.event_data['text']}")
await hub.close()
asyncio.run(main())
Channels come in several shapes — conversation (free-form, two parties), consulting (strict one-question-one-reply, auto-closing), discussion (round-robin across N agents), and workflow (a declarative TransitionGraph for conditional handoffs, which is the closest analogue to a classic GroupChat). See the Network guide.
The agent harness: knowledge and compaction
A bare Agent is just a model loop. The harness is the set of opt-in primitives you compose onto it. Two of the most useful:
KnowledgePlugin— aKnowledgeStorethe agent can read and write, so it remembers across runs.compact=— a strategy that caps history growth.SummarizeCompactfolds the dropped turns into a summary rather than discarding them outright.
Pair the store with a WorkingMemoryPolicy through AssemblerMiddleware and the agent's memory is injected into the system prompt on every turn — recall no longer depends on the model choosing to look it up.
import asyncio
from pathlib import Path
from ag2 import Agent, MemoryStream
from ag2.assembly import AssemblerMiddleware
from ag2.compact import CompactTrigger, SummarizeCompact
from ag2.config import OpenAICompletionsConfig
from ag2.events import CompactionCompleted, CompactionFailed
from ag2.knowledge import KnowledgePlugin, DiskKnowledgeStore
from ag2.middleware import Middleware
from ag2.policies import WorkingMemoryPolicy
config = OpenAICompletionsConfig(model="gpt-4o-mini")
# Disk-backed, so anything the agent remembers survives the process exiting.
STORE_DIR = Path("./knowledge_demo")
store = DiskKnowledgeStore(STORE_DIR)
agent = Agent(
"tutor",
prompt=(
"You are a science tutor for a fourth-grade teacher. "
"Whenever you learn a durable fact about the teacher or their class, use the knowledge "
"tool to `read` `memory/working.md`, then `write` it back with the new fact appended as "
"a bullet. Never drop a fact that is already there. "
"Keep every reply to one or two sentences."
),
config=config,
plugins=[
KnowledgePlugin(
store=store,
# Summarize the dropped history instead of forgetting it outright.
compact=SummarizeCompact(target=4, config=config),
compact_trigger=CompactTrigger(max_events=8),
)
],
# Injects memory/working.md into the system prompt on every turn, so recall
# does not depend on the model choosing to call the knowledge tool.
middleware=[Middleware(AssemblerMiddleware, policies=[WorkingMemoryPolicy()])],
)
stream = MemoryStream()
# Subscribe to both outcomes — watching only Completed would hide a failing strategy.
@stream.where(CompactionCompleted).subscribe()
async def on_compacted(event: CompactionCompleted) -> None:
print(f" [compacted: {event.events_before} -> {event.events_after} events via {event.strategy}]")
@stream.where(CompactionFailed).subscribe()
async def on_compaction_failed(event: CompactionFailed) -> None:
print(f" [compaction FAILED: {event.strategy}]")
async def main() -> None:
# A returning session: no conversation history at all, so anything the agent
# recalls here came off disk, via the knowledge store.
if STORE_DIR.exists():
reply = await agent.ask("What do you remember about me and my class?", stream=stream)
print(f"tutor: {reply.body}")
return
reply = await agent.ask("I'm Dana. I teach 4th grade at Rosewood Elementary, 26 students.", stream=stream)
print(f"tutor: {reply.body}")
for turn in ["My class struggles most with why we have seasons.", "Suggest one hands-on demo for that."]:
reply = await reply.ask(turn)
print(f"tutor: {reply.body}")
asyncio.run(main())
Run it twice. The first run fills memory/working.md and trips compaction; the second starts with an empty history and still knows who Dana is:
[compacted: 18 -> 3 events via SummarizeCompact]
tutor: I remember that you, Dana, teach 4th grade at Rosewood Elementary with 26 students,
and your class struggles the most with understanding why we have seasons.
See the Agent Harness guide for context policies, delegation, aggregation, and the full turn lifecycle.
Advanced agentic design patterns
AG2 supports more advanced concepts to help you build your AI agent workflows. You can find more information in the documentation.
Code style and linting
This project uses prek hooks to maintain code quality. Before contributing:
- Install prek:
pip install prek
prek install
- The hooks will run automatically on commit, or you can run them manually:
prek run --all-files
Contributors Wall
License
This project is licensed under the Apache License, Version 2.0 (Apache-2.0).
- Modifications and additions made in this fork are licensed under the Apache License, Version 2.0. See the LICENSE file for the full license text.
We have documented these changes for clarity and to ensure transparency with our user and contributor community. For more details, please see the NOTICE file.