Magentic 编排是根据 AutoGen 发明的 Magentic-One 系统设计的。 它是一种灵活的常规用途多代理模式,专为需要动态协作的复杂开放式任务而设计。 在此模式中,Magentic 管理器协调一个专门代理团队,并根据不断变化的上下文、任务进度和代理能力选择哪个代理应在接下来的步骤中采取行动。
Magentic 经理维护共享上下文、跟踪进度并实时调整工作流。 这使系统能够分解复杂的问题、委托子任务,并通过代理协作迭代优化解决方案。 编排尤其适合于在解决方案路径事先未知的场景中,可能需要多次推理、研究和计算的情况。
学习内容
- 如何设置 Magentic 管理器以协调多个专用代理
- 如何使用
AgentRunUpdateEvent来处理流事件 - 如何实现人机协作的计划评审、工具审批和阻止停滞干预
- 如何跟踪代理协作及在复杂任务中的进展
定义专用代理
即将推出。。。
在 Magentic 编排中,您定义的专用代理可以由管理器根据任务要求进行动态选择。
from agent_framework import ChatAgent, HostedCodeInterpreterTool
from agent_framework.openai import OpenAIChatClient, OpenAIResponsesClient
researcher_agent = ChatAgent(
name="ResearcherAgent",
description="Specialist in research and information gathering",
instructions=(
"You are a Researcher. You find information without additional computation or quantitative analysis."
),
# This agent requires the gpt-4o-search-preview model to perform web searches
chat_client=OpenAIChatClient(model_id="gpt-4o-search-preview"),
)
coder_agent = ChatAgent(
name="CoderAgent",
description="A helpful assistant that writes and executes code to process and analyze data.",
instructions="You solve questions using code. Please provide detailed analysis and computation process.",
chat_client=OpenAIResponsesClient(),
tools=HostedCodeInterpreterTool(),
)
# Create a manager agent for orchestration
manager_agent = ChatAgent(
name="MagenticManager",
description="Orchestrator that coordinates the research and coding workflow",
instructions="You coordinate a team to complete complex tasks efficiently.",
chat_client=OpenAIChatClient(),
)
生成 磁性 工作流
使用 MagenticBuilder 配置工作流,并使用标准管理器。
from agent_framework import MagenticBuilder
workflow = (
MagenticBuilder()
.participants(researcher=researcher_agent, coder=coder_agent)
.with_standard_manager(
agent=manager_agent,
max_round_count=10, # Maximum collaboration rounds
max_stall_count=3, # Maximum rounds without progress
max_reset_count=2, # Maximum plan resets allowed
)
.build()
)
通过事件流运行工作流
执行复杂的任务并处理流输出和编排更新的事件。
from typing import cast
from agent_framework import (
MAGENTIC_EVENT_TYPE_AGENT_DELTA,
MAGENTIC_EVENT_TYPE_ORCHESTRATOR,
AgentRunUpdateEvent,
ChatMessage,
WorkflowOutputEvent,
)
task = (
"I am preparing a report on the energy efficiency of different machine learning model architectures. "
"Compare the estimated training and inference energy consumption of ResNet-50, BERT-base, and GPT-2 "
"on standard datasets (e.g., ImageNet for ResNet, GLUE for BERT, WebText for GPT-2). "
"Then, estimate the CO2 emissions associated with each, assuming training on an Azure Standard_NC6s_v3 "
"VM for 24 hours. Provide tables for clarity, and recommend the most energy-efficient model "
"per task type (image classification, text classification, and text generation)."
)
# State for streaming callback
last_stream_agent_id: str | None = None
stream_line_open: bool = False
output: str | None = None
async for event in workflow.run_stream(task):
if isinstance(event, AgentRunUpdateEvent):
props = event.data.additional_properties if event.data else None
event_type = props.get("magentic_event_type") if props else None
if event_type == MAGENTIC_EVENT_TYPE_ORCHESTRATOR:
# Manager's planning and coordination messages
kind = props.get("orchestrator_message_kind", "") if props else ""
text = event.data.text if event.data else ""
print(f"\n[ORCH:{kind}]\n\n{text}\n{'-' * 26}")
elif event_type == MAGENTIC_EVENT_TYPE_AGENT_DELTA:
# Streaming tokens from agents
agent_id = props.get("agent_id", event.executor_id) if props else event.executor_id
if last_stream_agent_id != agent_id or not stream_line_open:
if stream_line_open:
print()
print(f"\n[STREAM:{agent_id}]: ", end="", flush=True)
last_stream_agent_id = agent_id
stream_line_open = True
if event.data and event.data.text:
print(event.data.text, end="", flush=True)
elif event.data and event.data.text:
print(event.data.text, end="", flush=True)
elif isinstance(event, WorkflowOutputEvent):
output_messages = cast(list[ChatMessage], event.data)
if output_messages:
output = output_messages[-1].text
if stream_line_open:
print()
if output is not None:
print(f"Workflow completed with result:\n\n{output}")
高级:人机循环计划评审
在执行之前启用对经理计划的人工评审和审批:
配置计划评审
from typing import cast
from agent_framework import (
MAGENTIC_EVENT_TYPE_AGENT_DELTA,
MAGENTIC_EVENT_TYPE_ORCHESTRATOR,
AgentRunUpdateEvent,
MagenticHumanInterventionDecision,
MagenticHumanInterventionKind,
MagenticHumanInterventionReply,
MagenticHumanInterventionRequest,
RequestInfoEvent,
WorkflowOutputEvent,
)
workflow = (
MagenticBuilder()
.participants(researcher=researcher_agent, coder=coder_agent)
.with_standard_manager(
agent=manager_agent,
max_round_count=10,
max_stall_count=3,
max_reset_count=2,
)
.with_plan_review() # Enable plan review
.build()
)
处理审核计划请求
pending_request: RequestInfoEvent | None = None
pending_responses: dict[str, MagenticHumanInterventionReply] | None = None
completed = False
workflow_output: str | None = None
while not completed:
# Use streaming for both initial run and response sending
if pending_responses is not None:
stream = workflow.send_responses_streaming(pending_responses)
else:
stream = workflow.run_stream(task)
async for event in stream:
if isinstance(event, AgentRunUpdateEvent):
# Handle streaming events as shown above
pass
elif isinstance(event, RequestInfoEvent) and event.request_type is MagenticHumanInterventionRequest:
request = cast(MagenticHumanInterventionRequest, event.data)
if request.kind == MagenticHumanInterventionKind.PLAN_REVIEW:
pending_request = event
if request.plan_text:
print(f"\n=== PLAN REVIEW REQUEST ===\n{request.plan_text}\n")
elif isinstance(event, WorkflowOutputEvent):
workflow_output = str(event.data) if event.data else None
completed = True
pending_responses = None
# Handle pending plan review request
if pending_request is not None:
# Collect human decision (approve/reject/modify)
# For demo, we auto-approve:
reply = MagenticHumanInterventionReply(decision=MagenticHumanInterventionDecision.APPROVE)
# Or approve with comments:
# reply = MagenticHumanInterventionReply(
# decision=MagenticHumanInterventionDecision.APPROVE,
# comments="Looks good, but prioritize efficiency metrics."
# )
# Or request revision:
# reply = MagenticHumanInterventionReply(
# decision=MagenticHumanInterventionDecision.REVISE,
# comments="Please include a comparison with newer models like LLaMA."
# )
pending_responses = {pending_request.request_id: reply}
pending_request = None
高级:通过工具审批进行代理人澄清
代理可以在执行过程中通过工具审批向用户提出澄清问题。 这使得在继续操作之前,代理可以进行人机交互(HITL),并请求更多信息。
定义需要审批的工具
from typing import Annotated
from agent_framework import ai_function
@ai_function(approval_mode="always_require")
def ask_user(question: Annotated[str, "The question to ask the user for clarification"]) -> str:
"""Ask the user a clarifying question to gather missing information.
Use this tool when you need additional information from the user to complete
your task effectively.
"""
# This function body is a placeholder - the actual interaction happens via HITL.
return f"User was asked: {question}"
使用工具创建代理
onboarding_agent = ChatAgent(
name="OnboardingAgent",
description="HR specialist who handles employee onboarding",
instructions=(
"You are an HR Onboarding Specialist. Your job is to onboard new employees.\n\n"
"IMPORTANT: When given an onboarding request, you MUST gather the following "
"information before proceeding:\n"
"1. Department (e.g., Engineering, Sales, Marketing)\n"
"2. Role/Title (e.g., Software Engineer, Account Executive)\n\n"
"Use the ask_user tool to request ANY missing information."
),
chat_client=OpenAIChatClient(model_id="gpt-4o"),
tools=[ask_user],
)
处理工具审批请求
async for event in workflow.run_stream("Onboard Jessica Smith"):
if isinstance(event, RequestInfoEvent) and event.request_type is MagenticHumanInterventionRequest:
req = cast(MagenticHumanInterventionRequest, event.data)
if req.kind == MagenticHumanInterventionKind.TOOL_APPROVAL:
print(f"Agent: {req.agent_id}")
print(f"Question: {req.prompt}")
# Get user's answer
answer = input("> ").strip()
# Send the answer back - it will be fed to the agent as the function result
reply = MagenticHumanInterventionReply(
decision=MagenticHumanInterventionDecision.APPROVE,
response_text=answer,
)
pending_responses = {event.request_id: reply}
# Continue workflow with response
async for ev in workflow.send_responses_streaming(pending_responses):
# Handle continuation events
pass
高级:人工干预应对故障停滞
当工作流检测到代理未取得进展时,启用人工干预:
配置停止干预
workflow = (
MagenticBuilder()
.participants(researcher=researcher_agent, analyst=analyst_agent)
.with_standard_manager(
agent=manager_agent,
max_round_count=10,
max_stall_count=1, # Stall detection after 1 round without progress
max_reset_count=2,
)
.with_human_input_on_stall() # Request human input when stalled
.build()
)
处理暂停干预请求
async for event in workflow.run_stream(task):
if isinstance(event, RequestInfoEvent) and event.request_type is MagenticHumanInterventionRequest:
req = cast(MagenticHumanInterventionRequest, event.data)
if req.kind == MagenticHumanInterventionKind.STALL:
print(f"Workflow stalled after {req.stall_count} rounds")
print(f"Reason: {req.stall_reason}")
if req.plan_text:
print(f"Current plan:\n{req.plan_text}")
# Choose response: CONTINUE, REPLAN, or GUIDANCE
reply = MagenticHumanInterventionReply(
decision=MagenticHumanInterventionDecision.GUIDANCE,
comments="Focus on completing the research step first before moving to analysis.",
)
pending_responses = {event.request_id: reply}
关键概念
- 动态协调:Magentic 管理器根据不断发展的上下文动态选择哪个代理应接下来执行动作
- 迭代优化:系统可以分解复杂的问题,并通过多个轮迭代优化解决方案
- 进度跟踪:内置机制,用于检测停止并根据需要重置计划
- 灵活协作:可以按经理确定的任何顺序多次调用代理
- 人工监督:可选的人机协同机制,包括计划审查、工具审批和暂停介入
-
统一事件系统:使用
AgentRunUpdateEventmagentic_event_type来处理编排器和代理流式事件
工作流执行过程
Magentic 业务流程遵循以下执行模式:
- 规划阶段:经理分析任务并创建初始计划
- 可选计划评审:如果启用,人类可以审阅和批准/修改计划
- 代理选择:管理器为每个子任务选择最合适的代理
- 执行:所选代理执行其部分任务
- 进度评估:经理评估进度并更新计划
- 停滞检测:如果进度停滞,则自动重新规划或请求人工干预
- 迭代:步骤 3-6 重复,直到任务完成或达到限制
- 最终合成:管理器将所有代理输出合成到最终结果中
完整的示例
下面是将所有概念汇集在一起的完整示例:
import asyncio
import logging
from typing import cast
from agent_framework import (
MAGENTIC_EVENT_TYPE_AGENT_DELTA,
MAGENTIC_EVENT_TYPE_ORCHESTRATOR,
AgentRunUpdateEvent,
ChatAgent,
ChatMessage,
HostedCodeInterpreterTool,
MagenticBuilder,
WorkflowOutputEvent,
)
from agent_framework.openai import OpenAIChatClient, OpenAIResponsesClient
logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)
async def main() -> None:
# Define specialized agents
researcher_agent = ChatAgent(
name="ResearcherAgent",
description="Specialist in research and information gathering",
instructions=(
"You are a Researcher. You find information without additional "
"computation or quantitative analysis."
),
chat_client=OpenAIChatClient(model_id="gpt-4o-search-preview"),
)
coder_agent = ChatAgent(
name="CoderAgent",
description="A helpful assistant that writes and executes code to process and analyze data.",
instructions="You solve questions using code. Please provide detailed analysis and computation process.",
chat_client=OpenAIResponsesClient(),
tools=HostedCodeInterpreterTool(),
)
# Create a manager agent for orchestration
manager_agent = ChatAgent(
name="MagenticManager",
description="Orchestrator that coordinates the research and coding workflow",
instructions="You coordinate a team to complete complex tasks efficiently.",
chat_client=OpenAIChatClient(),
)
# State for streaming output
last_stream_agent_id: str | None = None
stream_line_open: bool = False
# Build the workflow
print("\nBuilding Magentic Workflow...")
workflow = (
MagenticBuilder()
.participants(researcher=researcher_agent, coder=coder_agent)
.with_standard_manager(
agent=manager_agent,
max_round_count=10,
max_stall_count=3,
max_reset_count=2,
)
.build()
)
# Define the task
task = (
"I am preparing a report on the energy efficiency of different machine learning model architectures. "
"Compare the estimated training and inference energy consumption of ResNet-50, BERT-base, and GPT-2 "
"on standard datasets (e.g., ImageNet for ResNet, GLUE for BERT, WebText for GPT-2). "
"Then, estimate the CO2 emissions associated with each, assuming training on an Azure Standard_NC6s_v3 "
"VM for 24 hours. Provide tables for clarity, and recommend the most energy-efficient model "
"per task type (image classification, text classification, and text generation)."
)
print(f"\nTask: {task}")
print("\nStarting workflow execution...")
# Run the workflow
try:
output: str | None = None
async for event in workflow.run_stream(task):
if isinstance(event, AgentRunUpdateEvent):
props = event.data.additional_properties if event.data else None
event_type = props.get("magentic_event_type") if props else None
if event_type == MAGENTIC_EVENT_TYPE_ORCHESTRATOR:
kind = props.get("orchestrator_message_kind", "") if props else ""
text = event.data.text if event.data else ""
print(f"\n[ORCH:{kind}]\n\n{text}\n{'-' * 26}")
elif event_type == MAGENTIC_EVENT_TYPE_AGENT_DELTA:
agent_id = props.get("agent_id", event.executor_id) if props else event.executor_id
if last_stream_agent_id != agent_id or not stream_line_open:
if stream_line_open:
print()
print(f"\n[STREAM:{agent_id}]: ", end="", flush=True)
last_stream_agent_id = agent_id
stream_line_open = True
if event.data and event.data.text:
print(event.data.text, end="", flush=True)
elif event.data and event.data.text:
print(event.data.text, end="", flush=True)
elif isinstance(event, WorkflowOutputEvent):
output_messages = cast(list[ChatMessage], event.data)
if output_messages:
output = output_messages[-1].text
if stream_line_open:
print()
if output is not None:
print(f"Workflow completed with result:\n\n{output}")
except Exception as e:
print(f"Workflow execution failed: {e}")
logger.exception("Workflow exception", exc_info=e)
if __name__ == "__main__":
asyncio.run(main())
配置选项
管理器参数
-
max_round_count:最大协作轮数(默认值:10) -
max_stall_count:在没有进展时触发停滞处理的最大回合数(默认值:3) -
max_reset_count:允许的计划重置的最大数量(默认值:2)
人工干预类型
-
PLAN_REVIEW:查看和批准/修订初始计划 -
TOOL_APPROVAL:批准工具/函数调用(用于代理澄清) -
STALL:工作流已停止,需要指导
人工干预决策
-
APPROVE:接受计划或工具调用 as-is -
REVISE:请求修订并提供反馈(计划评审) -
REJECT:拒绝/不允许(工具批准) -
CONTINUE:继续当前状态(停止) -
REPLAN:触发重新规划过程(停顿) -
GUIDANCE:提供指导文本(停止,工具审批)
事件类型
事件通过 AgentRunUpdateEvent 发出,并且元数据在 additional_properties 中。
-
magentic_event_type:或MAGENTIC_EVENT_TYPE_ORCHESTRATORMAGENTIC_EVENT_TYPE_AGENT_DELTA -
orchestrator_message_kind:对于协调器事件,指示消息类型(例如“instruction”、“notice”、“task_ledger”) -
agent_id:对于代理增量事件,标识流式处理代理
示例输出
即将推出。。。