mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Merge branch 'main' into feature-python-foundry-agents
This commit is contained in:
@@ -38,10 +38,8 @@ Before running the examples, you need to set up your environment variables. You
|
||||
AZURE_AI_MODEL_DEPLOYMENT_NAME="your-model-deployment-name"
|
||||
```
|
||||
|
||||
3. For samples using Bing Grounding search (like `azure_ai_with_bing_grounding.py` and `azure_ai_with_multiple_tools.py`), you'll also need either:
|
||||
3. For samples using Bing Grounding search (like `azure_ai_with_bing_grounding.py` and `azure_ai_with_multiple_tools.py`), you'll also need:
|
||||
```
|
||||
BING_CONNECTION_NAME="bing-grounding-connection"
|
||||
# OR
|
||||
BING_CONNECTION_ID="your-bing-connection-id"
|
||||
```
|
||||
|
||||
@@ -49,7 +47,7 @@ Before running the examples, you need to set up your environment variables. You
|
||||
- Go to [Azure AI Foundry portal](https://ai.azure.com)
|
||||
- Navigate to your project's "Connected resources" section
|
||||
- Add a new connection for "Grounding with Bing Search"
|
||||
- Copy either the connection name or ID
|
||||
- Copy the ID
|
||||
|
||||
### Option 2: Using environment variables directly
|
||||
|
||||
@@ -58,9 +56,7 @@ Set the environment variables in your shell:
|
||||
```bash
|
||||
export AZURE_AI_PROJECT_ENDPOINT="your-project-endpoint"
|
||||
export AZURE_AI_MODEL_DEPLOYMENT_NAME="your-model-deployment-name"
|
||||
export BING_CONNECTION_NAME="your-bing-connection-name" # Optional, only needed for web search samples
|
||||
# OR
|
||||
export BING_CONNECTION_ID="your-bing-connection-id" # Alternative to BING_CONNECTION_NAME
|
||||
export BING_CONNECTION_ID="your-bing-connection-id"
|
||||
```
|
||||
|
||||
### Required Variables
|
||||
@@ -70,4 +66,4 @@ export BING_CONNECTION_ID="your-bing-connection-id" # Alternative to BING_CONNE
|
||||
|
||||
### Optional Variables
|
||||
|
||||
- `BING_CONNECTION_NAME` or `BING_CONNECTION_ID`: Your Bing connection name or ID (required for `azure_ai_with_bing_grounding.py` and `azure_ai_with_multiple_tools.py`)
|
||||
- `BING_CONNECTION_ID`: Your Bing connection ID (required for `azure_ai_with_bing_grounding.py` and `azure_ai_with_multiple_tools.py`)
|
||||
|
||||
+7
-5
@@ -5,6 +5,7 @@ import os
|
||||
|
||||
from agent_framework import ChatAgent, CitationAnnotation
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from azure.ai.agents.aio import AgentsClient
|
||||
from azure.ai.projects.aio import AIProjectClient
|
||||
from azure.ai.projects.models import ConnectionType
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
@@ -38,16 +39,17 @@ async def main() -> None:
|
||||
# Create the client and manually create an agent with Azure AI Search tool
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as client,
|
||||
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
|
||||
AgentsClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as agents_client,
|
||||
):
|
||||
ai_search_conn_id = ""
|
||||
async for connection in client.connections.list():
|
||||
async for connection in project_client.connections.list():
|
||||
if connection.type == ConnectionType.AZURE_AI_SEARCH:
|
||||
ai_search_conn_id = connection.id
|
||||
break
|
||||
|
||||
# 1. Create Azure AI agent with the search tool
|
||||
azure_ai_agent = await client.agents.create_agent(
|
||||
azure_ai_agent = await project_client.agents.create_agent(
|
||||
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
name="HotelSearchAgent",
|
||||
instructions=(
|
||||
@@ -69,7 +71,7 @@ async def main() -> None:
|
||||
)
|
||||
|
||||
# 2. Create chat client with the existing agent
|
||||
chat_client = AzureAIAgentClient(project_client=client, agent_id=azure_ai_agent.id)
|
||||
chat_client = AzureAIAgentClient(agents_client=agents_client, agent_id=azure_ai_agent.id)
|
||||
|
||||
try:
|
||||
async with ChatAgent(
|
||||
@@ -112,7 +114,7 @@ async def main() -> None:
|
||||
|
||||
finally:
|
||||
# Clean up the agent manually
|
||||
await client.agents.delete_agent(azure_ai_agent.id)
|
||||
await project_client.agents.delete_agent(azure_ai_agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+2
-3
@@ -12,8 +12,7 @@ uses Bing Grounding search to find real-time information from the web.
|
||||
|
||||
Prerequisites:
|
||||
1. A connected Grounding with Bing Search resource in your Azure AI project
|
||||
2. Set either BING_CONNECTION_NAME or BING_CONNECTION_ID environment variable
|
||||
Example: BING_CONNECTION_NAME="bing-grounding-connection"
|
||||
2. Set BING_CONNECTION_ID environment variable
|
||||
Example: BING_CONNECTION_ID="your-bing-connection-id"
|
||||
|
||||
To set up Bing Grounding:
|
||||
@@ -27,7 +26,7 @@ To set up Bing Grounding:
|
||||
async def main() -> None:
|
||||
"""Main function demonstrating Azure AI agent with Bing Grounding search."""
|
||||
# 1. Create Bing Grounding search tool using HostedWebSearchTool
|
||||
# The connection_name or ID will be automatically picked up from environment variable
|
||||
# The connection ID will be automatically picked up from environment variable
|
||||
bing_search_tool = HostedWebSearchTool(
|
||||
name="Bing Grounding Search",
|
||||
description="Search the web for current information using Bing",
|
||||
|
||||
+6
-4
@@ -5,6 +5,7 @@ import os
|
||||
|
||||
from agent_framework import ChatAgent
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from azure.ai.agents.aio import AgentsClient
|
||||
from azure.ai.projects.aio import AIProjectClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
@@ -22,16 +23,17 @@ async def main() -> None:
|
||||
# Create the client
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as client,
|
||||
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
|
||||
AgentsClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as agents_client,
|
||||
):
|
||||
azure_ai_agent = await client.agents.create_agent(
|
||||
azure_ai_agent = await project_client.agents.create_agent(
|
||||
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
# Create remote agent with default instructions
|
||||
# These instructions will persist on created agent for every run.
|
||||
instructions="End each response with [END].",
|
||||
)
|
||||
|
||||
chat_client = AzureAIAgentClient(project_client=client, agent_id=azure_ai_agent.id)
|
||||
chat_client = AzureAIAgentClient(agents_client=agents_client, agent_id=azure_ai_agent.id)
|
||||
|
||||
try:
|
||||
async with ChatAgent(
|
||||
@@ -50,7 +52,7 @@ async def main() -> None:
|
||||
print(f"Agent: {result}\n")
|
||||
finally:
|
||||
# Clean up the agent manually
|
||||
await client.agents.delete_agent(azure_ai_agent.id)
|
||||
await project_client.agents.delete_agent(azure_ai_agent.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+5
-5
@@ -7,7 +7,7 @@ from typing import Annotated
|
||||
|
||||
from agent_framework import ChatAgent
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from azure.ai.projects.aio import AIProjectClient
|
||||
from azure.ai.agents.aio import AgentsClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from pydantic import Field
|
||||
|
||||
@@ -33,16 +33,16 @@ async def main() -> None:
|
||||
# Create the client
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as client,
|
||||
AgentsClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as agents_client,
|
||||
):
|
||||
# Create an thread that will persist
|
||||
created_thread = await client.agents.threads.create()
|
||||
created_thread = await agents_client.threads.create()
|
||||
|
||||
try:
|
||||
async with ChatAgent(
|
||||
# passing in the client is optional here, so if you take the agent_id from the portal
|
||||
# you can use it directly without the two lines above.
|
||||
chat_client=AzureAIAgentClient(project_client=client),
|
||||
chat_client=AzureAIAgentClient(agents_client=agents_client),
|
||||
instructions="You are a helpful weather agent.",
|
||||
tools=get_weather,
|
||||
) as agent:
|
||||
@@ -52,7 +52,7 @@ async def main() -> None:
|
||||
print(f"Result: {result}\n")
|
||||
finally:
|
||||
# Clean up the thread manually
|
||||
await client.agents.threads.delete(created_thread.id)
|
||||
await agents_client.threads.delete(created_thread.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -44,8 +44,6 @@ async def main() -> None:
|
||||
AzureCliCredential() as credential,
|
||||
AzureAIAgentClient(async_credential=credential) as chat_client,
|
||||
):
|
||||
# enable azure-ai observability
|
||||
await chat_client.setup_azure_ai_observability()
|
||||
agent = chat_client.create_agent(
|
||||
name="DocsAgent",
|
||||
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
|
||||
|
||||
@@ -69,8 +69,6 @@ async def main() -> None:
|
||||
AzureCliCredential() as credential,
|
||||
AzureAIAgentClient(async_credential=credential) as chat_client,
|
||||
):
|
||||
# enable azure-ai observability
|
||||
await chat_client.setup_azure_ai_observability()
|
||||
agent = chat_client.create_agent(
|
||||
name="DocsAgent",
|
||||
instructions="You are a helpful assistant that can help with microsoft documentation questions.",
|
||||
|
||||
@@ -9,7 +9,9 @@ import dotenv
|
||||
from agent_framework import ChatAgent
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from agent_framework.observability import get_tracer
|
||||
from azure.ai.agents.aio import AgentsClient
|
||||
from azure.ai.projects.aio import AIProjectClient
|
||||
from azure.core.exceptions import ResourceNotFoundError
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from opentelemetry.trace import SpanKind
|
||||
from opentelemetry.trace.span import format_trace_id
|
||||
@@ -38,16 +40,36 @@ async def get_weather(
|
||||
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
|
||||
|
||||
|
||||
async def setup_azure_ai_observability(
|
||||
project_client: AIProjectClient, enable_sensitive_data: bool | None = None
|
||||
) -> None:
|
||||
"""Use this method to setup tracing in your Azure AI Project.
|
||||
|
||||
This will take the connection string from the AIProjectClient.
|
||||
It will override any connection string that is set in the environment variables.
|
||||
It will disable any OTLP endpoint that might have been set.
|
||||
"""
|
||||
try:
|
||||
conn_string = await project_client.telemetry.get_application_insights_connection_string()
|
||||
except ResourceNotFoundError:
|
||||
print("No Application Insights connection string found for the Azure AI Project.")
|
||||
return
|
||||
from agent_framework.observability import setup_observability
|
||||
|
||||
setup_observability(applicationinsights_connection_string=conn_string, enable_sensitive_data=enable_sensitive_data)
|
||||
|
||||
|
||||
async def main():
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project,
|
||||
AzureAIAgentClient(project_client=project) as client,
|
||||
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
|
||||
AgentsClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as agents_client,
|
||||
AzureAIAgentClient(agents_client=agents_client) as client,
|
||||
):
|
||||
# This will enable tracing and configure the application to send telemetry data to the
|
||||
# Application Insights instance attached to the Azure AI project.
|
||||
# This will override any existing configuration.
|
||||
await client.setup_azure_ai_observability()
|
||||
await setup_azure_ai_observability(project_client)
|
||||
|
||||
questions = ["What's the weather in Amsterdam?", "and in Paris, and which is better?", "Why is the sky blue?"]
|
||||
|
||||
|
||||
+25
-3
@@ -9,7 +9,9 @@ import dotenv
|
||||
from agent_framework import HostedCodeInterpreterTool
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from agent_framework.observability import get_tracer
|
||||
from azure.ai.agents.aio import AgentsClient
|
||||
from azure.ai.projects.aio import AIProjectClient
|
||||
from azure.core.exceptions import ResourceNotFoundError
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from opentelemetry.trace import SpanKind
|
||||
from opentelemetry.trace.span import format_trace_id
|
||||
@@ -42,6 +44,25 @@ async def get_weather(
|
||||
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
|
||||
|
||||
|
||||
async def setup_azure_ai_observability(
|
||||
project_client: AIProjectClient, enable_sensitive_data: bool | None = None
|
||||
) -> None:
|
||||
"""Use this method to setup tracing in your Azure AI Project.
|
||||
|
||||
This will take the connection string from the AIProjectClient instance.
|
||||
It will override any connection string that is set in the environment variables.
|
||||
It will disable any OTLP endpoint that might have been set.
|
||||
"""
|
||||
try:
|
||||
conn_string = await project_client.telemetry.get_application_insights_connection_string()
|
||||
except ResourceNotFoundError:
|
||||
print("No Application Insights connection string found for the Azure AI Project.")
|
||||
return
|
||||
from agent_framework.observability import setup_observability
|
||||
|
||||
setup_observability(applicationinsights_connection_string=conn_string, enable_sensitive_data=enable_sensitive_data)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Run an AI service.
|
||||
|
||||
@@ -62,13 +83,14 @@ async def main() -> None:
|
||||
]
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project,
|
||||
AzureAIAgentClient(project_client=project) as client,
|
||||
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as project_client,
|
||||
AgentsClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as agents_client,
|
||||
AzureAIAgentClient(agents_client=agents_client) as client,
|
||||
):
|
||||
# This will enable tracing and configure the application to send telemetry data to the
|
||||
# Application Insights instance attached to the Azure AI project.
|
||||
# This will override any existing configuration.
|
||||
await client.setup_azure_ai_observability()
|
||||
await setup_azure_ai_observability(project_client)
|
||||
|
||||
with get_tracer().start_as_current_span(
|
||||
name="Foundry Telemetry from Agent Framework", kind=SpanKind.CLIENT
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Never
|
||||
|
||||
from agent_framework import (
|
||||
AgentExecutorResponse,
|
||||
Executor,
|
||||
HostedCodeInterpreterTool,
|
||||
WorkflowBuilder,
|
||||
WorkflowContext,
|
||||
handler,
|
||||
)
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
"""
|
||||
This sample demonstrates how to create a workflow that combines an AI agent executor
|
||||
with a custom executor.
|
||||
|
||||
The workflow consists of two stages:
|
||||
1. An AI agent with code interpreter capabilities that generates and executes Python code
|
||||
2. An evaluator executor that reviews the agent's output and provides a final assessment
|
||||
|
||||
Key concepts demonstrated:
|
||||
- Creating an AI agent with tool capabilities (HostedCodeInterpreterTool)
|
||||
- Building workflows using WorkflowBuilder with an agent and a custom executor
|
||||
- Using the @handler decorator in the executor to process AgentExecutorResponse from the agent
|
||||
- Connecting workflow executors with edges to create a processing pipeline
|
||||
- Yielding final outputs from terminal executors
|
||||
- Non-streaming workflow execution and result collection
|
||||
|
||||
Prerequisites:
|
||||
- Azure AI services configured with required environment variables
|
||||
- Azure CLI authentication (run 'az login' before executing)
|
||||
- Basic understanding of async Python and workflow concepts
|
||||
"""
|
||||
|
||||
|
||||
class Evaluator(Executor):
|
||||
"""Custom executor that evaluates the output from an AI agent.
|
||||
|
||||
This executor demonstrates how to:
|
||||
- Create a custom workflow executor that processes agent responses
|
||||
- Use the @handler decorator to define the processing logic
|
||||
- Access agent execution details including response text and usage metrics
|
||||
- Yield final results to complete the workflow execution
|
||||
|
||||
The evaluator checks if the agent successfully generated the Fibonacci sequence
|
||||
and provides feedback on correctness along with resource consumption details.
|
||||
"""
|
||||
|
||||
@handler
|
||||
async def handle(self, message: AgentExecutorResponse, ctx: WorkflowContext[Never, str]) -> None:
|
||||
"""Evaluate the agent's response and complete the workflow with a final assessment.
|
||||
|
||||
This handler:
|
||||
1. Receives the AgentExecutorResponse containing the agent's complete interaction
|
||||
2. Checks if the expected Fibonacci sequence appears in the response text
|
||||
3. Extracts usage details (token consumption, execution time, etc.)
|
||||
4. Yields a final evaluation string to complete the workflow
|
||||
|
||||
Args:
|
||||
message: The response from the Azure AI agent containing text and metadata
|
||||
ctx: Workflow context for yielding the final output string
|
||||
"""
|
||||
target_text = "1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89"
|
||||
correctness = target_text in message.agent_run_response.text
|
||||
consumption = message.agent_run_response.usage_details
|
||||
await ctx.yield_output(f"Correctness: {correctness}, Consumption: {consumption}")
|
||||
|
||||
|
||||
async def main():
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AzureAIAgentClient(async_credential=credential) as chat_client,
|
||||
):
|
||||
# Create an agent with code interpretation capabilities
|
||||
agent = chat_client.create_agent(
|
||||
name="CodingAgent",
|
||||
instructions=("You are a helpful assistant that can write and execute Python code to solve problems."),
|
||||
tools=HostedCodeInterpreterTool(),
|
||||
)
|
||||
|
||||
# Build a workflow: Agent generates code -> Evaluator assesses results
|
||||
# The agent will be wrapped in a special agent executor which produces AgentExecutorResponse
|
||||
workflow = WorkflowBuilder().set_start_executor(agent).add_edge(agent, Evaluator(id="evaluator")).build()
|
||||
|
||||
# Execute the workflow with a specific coding task
|
||||
results = await workflow.run(
|
||||
"Generate the fibonacci numbers to 100 using python code, show the code and execute it."
|
||||
)
|
||||
|
||||
# Extract and display the final evaluation
|
||||
outputs = results.get_outputs()
|
||||
if isinstance(outputs, list) and len(outputs) == 1:
|
||||
print("Workflow results:", outputs[0])
|
||||
else:
|
||||
raise ValueError("Unexpected workflow outputs:", outputs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+4
-5
@@ -4,7 +4,6 @@ import asyncio
|
||||
from dataclasses import dataclass
|
||||
|
||||
from agent_framework import (
|
||||
AgentExecutor, # Executor that runs the agent
|
||||
AgentExecutorRequest, # Message bundle sent to an AgentExecutor
|
||||
AgentExecutorResponse, # Result returned by an AgentExecutor
|
||||
ChatMessage, # Chat message structure
|
||||
@@ -148,6 +147,7 @@ async def main() -> None:
|
||||
# response_format enforces that the model produces JSON compatible with GuessOutput.
|
||||
chat_client = AzureOpenAIChatClient(credential=AzureCliCredential())
|
||||
agent = chat_client.create_agent(
|
||||
name="GuessingAgent",
|
||||
instructions=(
|
||||
"You guess a number between 1 and 10. "
|
||||
"If the user says 'higher' or 'lower', adjust your next guess. "
|
||||
@@ -158,16 +158,15 @@ async def main() -> None:
|
||||
response_format=GuessOutput,
|
||||
)
|
||||
|
||||
# Build a simple loop: TurnManager <-> AgentExecutor.
|
||||
# TurnManager coordinates and gathers human replies while AgentExecutor runs the model.
|
||||
turn_manager = TurnManager(id="turn_manager")
|
||||
agent_exec = AgentExecutor(agent=agent, id="agent")
|
||||
|
||||
# Build a simple loop: TurnManager <-> AgentExecutor.
|
||||
workflow = (
|
||||
WorkflowBuilder()
|
||||
.set_start_executor(turn_manager)
|
||||
.add_edge(turn_manager, agent_exec) # Ask agent to make/adjust a guess
|
||||
.add_edge(agent_exec, turn_manager) # Agent's response comes back to coordinator
|
||||
.add_edge(turn_manager, agent) # Ask agent to make/adjust a guess
|
||||
.add_edge(agent, turn_manager) # Agent's response comes back to coordinator
|
||||
).build()
|
||||
|
||||
# Human in the loop run: alternate between invoking the workflow and supplying collected responses.
|
||||
|
||||
Reference in New Issue
Block a user