mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: (samples): adopt AzureOpenAIResponsesClient, reorganize orchestration examples, and fix workflow/orchestration bugs (#3873)
* adopt AzureOpenAIResponsesClient, reorganize orchestration examples, and fix workflow/orchestration bugs * Updates * add comment
This commit is contained in:
committed by
GitHub
Unverified
parent
8457533c69
commit
1b10b051fd
@@ -1,19 +1,21 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
|
||||
from agent_framework import (
|
||||
AgentExecutor, # Wraps a ChatAgent as an Executor for use in workflows
|
||||
AgentExecutorRequest, # The message bundle sent to an AgentExecutor
|
||||
AgentExecutorResponse, # The structured result returned by an AgentExecutor
|
||||
AgentResponseUpdate,
|
||||
Executor, # Base class for custom Python executors
|
||||
Message, # Chat message structure
|
||||
WorkflowBuilder, # Fluent builder for wiring the workflow graph
|
||||
WorkflowContext, # Per run context and event bus
|
||||
handler, # Decorator to mark an Executor method as invokable
|
||||
)
|
||||
from agent_framework.azure import AzureOpenAIChatClient
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from azure.identity import AzureCliCredential # Uses your az CLI login for credentials
|
||||
from typing_extensions import Never
|
||||
|
||||
@@ -29,8 +31,9 @@ Show how to construct a parallel branch pattern in workflows. Demonstrate:
|
||||
- Fan in by collecting a list of AgentExecutorResponse objects and reducing them to a single result.
|
||||
|
||||
Prerequisites:
|
||||
- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint.
|
||||
- Familiarity with WorkflowBuilder, executors, edges, events, and streaming runs.
|
||||
- Azure OpenAI access configured for AzureOpenAIChatClient. Log in with Azure CLI and set any required environment variables.
|
||||
- Azure OpenAI access configured for AzureOpenAIResponsesClient. Log in with Azure CLI and set any required environment variables.
|
||||
- Comfort reading AgentExecutorResponse.agent_response.text for assistant output aggregation.
|
||||
"""
|
||||
|
||||
@@ -87,13 +90,31 @@ class AggregateInsights(Executor):
|
||||
await ctx.yield_output(consolidated)
|
||||
|
||||
|
||||
def render_live_streams(buffers: dict[str, str], order: list[str], completed: set[str]) -> None:
|
||||
"""Render concurrent agent streams in separate sections."""
|
||||
# Clear terminal and move cursor to top-left for a live dashboard effect.
|
||||
print("\033[2J\033[H", end="")
|
||||
print("=== Expert Streams (Live) ===")
|
||||
print("Concurrent agent updates are shown below as they stream.\n")
|
||||
for agent_id in order:
|
||||
state = "completed" if agent_id in completed else "streaming"
|
||||
print(f"[{agent_id}] ({state})")
|
||||
print(buffers.get(agent_id, ""))
|
||||
print("-" * 80)
|
||||
print("", end="", flush=True)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# 1) Create executor and agent instances
|
||||
dispatcher = DispatchToExperts(id="dispatcher")
|
||||
aggregator = AggregateInsights(id="aggregator")
|
||||
|
||||
researcher = AgentExecutor(
|
||||
AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
|
||||
AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
credential=AzureCliCredential(),
|
||||
).as_agent(
|
||||
instructions=(
|
||||
"You're an expert market and product researcher. Given a prompt, provide concise, factual insights,"
|
||||
" opportunities, and risks."
|
||||
@@ -102,7 +123,11 @@ async def main() -> None:
|
||||
)
|
||||
)
|
||||
marketer = AgentExecutor(
|
||||
AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
|
||||
AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
credential=AzureCliCredential(),
|
||||
).as_agent(
|
||||
instructions=(
|
||||
"You're a creative marketing strategist. Craft compelling value propositions and target messaging"
|
||||
" aligned to the prompt."
|
||||
@@ -111,7 +136,11 @@ async def main() -> None:
|
||||
)
|
||||
)
|
||||
legal = AgentExecutor(
|
||||
AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
|
||||
AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
credential=AzureCliCredential(),
|
||||
).as_agent(
|
||||
instructions=(
|
||||
"You're a cautious legal/compliance reviewer. Highlight constraints, disclaimers, and policy concerns"
|
||||
" based on the prompt."
|
||||
@@ -128,18 +157,32 @@ async def main() -> None:
|
||||
.build()
|
||||
)
|
||||
|
||||
# 3) Run with a single prompt and print progress plus the final consolidated output
|
||||
# 3) Run with a single prompt and render live expert streams plus final consolidated output.
|
||||
expert_order = ["researcher", "marketer", "legal"]
|
||||
expert_buffers: dict[str, str] = {expert_id: "" for expert_id in expert_order}
|
||||
completed_experts: set[str] = set()
|
||||
final_output: str | None = None
|
||||
|
||||
async for event in workflow.run(
|
||||
"We are launching a new budget-friendly electric bike for urban commuters.", stream=True
|
||||
):
|
||||
if event.type == "executor_invoked":
|
||||
# Show when executors are invoked and completed for lightweight observability.
|
||||
print(f"{event.executor_id} invoked")
|
||||
elif event.type == "executor_completed":
|
||||
print(f"{event.executor_id} completed")
|
||||
if event.type == "executor_completed" and event.executor_id in expert_buffers:
|
||||
completed_experts.add(event.executor_id)
|
||||
render_live_streams(expert_buffers, expert_order, completed_experts)
|
||||
elif event.type == "output":
|
||||
print("===== Final Aggregated Output =====")
|
||||
print(event.data)
|
||||
if isinstance(event.data, AgentResponseUpdate):
|
||||
executor_id = event.executor_id or ""
|
||||
if executor_id in expert_buffers:
|
||||
expert_buffers[executor_id] += event.data.text
|
||||
render_live_streams(expert_buffers, expert_order, completed_experts)
|
||||
continue
|
||||
|
||||
if event.executor_id == "aggregator":
|
||||
final_output = str(event.data)
|
||||
|
||||
if final_output:
|
||||
print("\n=== Final Consolidated Output ===\n")
|
||||
print(final_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user