本教程演示如何通过 .NET 或 Python 和代理框架使用 AG-UI 协议生成服务器和客户端应用程序。 你将学习如何创建一个托管 AI 智能代理的 AG-UI 服务器,以及一个与之连接进行交互式对话的客户端。
你将构建的内容
在本教程结束时,你将拥有:
- 托管可通过 HTTP 访问的 AI 代理的 AG-UI 服务器
- 连接到服务器并流式传输响应的客户端应用程序
- 了解 AG-UI 协议如何与代理框架协作
先决条件
在开始之前,请确保具有以下各项:
- .NET 8.0 或更高版本
- 已配置 Azure OpenAI 服务终结点和部署
- 已安装的Azure CLI并且已进行身份验证
- 用户在 Azure OpenAI 资源中具有
Cognitive Services OpenAI Contributor角色
注释
这些示例使用 Azure OpenAI 模型。 有关详细信息,请参阅 如何使用 Azure AI Foundry 部署 Azure OpenAI 模型。
注释
这些示例使用 DefaultAzureCredential 进行身份验证。 确保通过 Azure 进行身份验证(例如,通过 az login)。 有关详细信息,请参阅 Azure 标识文档。
警告
AG-UI 协议仍在开发中,可能会发生更改。 随着协议的发展,我们将不断更新这些示例。
步骤 1:创建 AG-UI 服务器
AG-UI 服务器托管您的 AI 代理,并使用 ASP.NET Core 通过 HTTP 终结点提供访问。
注释
服务器项目需要 Microsoft.NET.Sdk.Web SDK。 如果要从头开始创建新项目,请使用 dotnet new web,或者确保 .csproj 文件使用 <Project Sdk="Microsoft.NET.Sdk.Web"> 而不是 Microsoft.NET.Sdk。
安装所需的包
安装服务器所需的包:
dotnet add package Microsoft.Agents.AI.Hosting.AGUI.AspNetCore --prerelease
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease
注释
所需的Microsoft.Extensions.AI.OpenAI包用于AsIChatClient()扩展方法,该方法将OpenAI的ChatClient转换为代理框架预期的IChatClient接口。
服务器代码
创建名为 Program.cs: 的文件
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;
using Microsoft.Extensions.AI;
using OpenAI.Chat;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient().AddLogging();
builder.Services.AddAGUI();
WebApplication app = builder.Build();
string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");
// Create the AI agent
ChatClient chatClient = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName);
AIAgent agent = chatClient.AsIChatClient().AsAIAgent(
name: "AGUIAssistant",
instructions: "You are a helpful assistant.");
// Map the AG-UI agent endpoint
app.MapAGUI("/", agent);
await app.RunAsync();
关键概念
-
AddAGUI:向依赖注入容器注册 AG-UI 服务 -
MapAGUI:扩展方法用于注册 AG-UI 终端,并进行自动请求/响应处理以及 SSE 流式传输 -
ChatClient和AsIChatClient():AzureOpenAIClient.GetChatClient()返回 OpenAI 的类型ChatClient。AsIChatClient()扩展方法(源自Microsoft.Extensions.AI.OpenAI)将其转换为 Agent Framework 所需的IChatClient接口 -
AsAIAgent:从IChatClient创建一个Agent Framework代理 - ASP.NET Core 集成:使用 ASP.NET Core 的原生异步支持来进行数据流式响应
- 说明:代理是使用默认指令创建的,客户端消息可以覆盖默认指令
-
配置:
AzureOpenAIClient提供DefaultAzureCredential安全身份验证
配置并运行服务器
设置所需的环境变量:
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"
运行服务器:
dotnet run --urls http://localhost:8888
服务器将开始侦听 http://localhost:8888。
注释
在步骤 2 中设置并运行客户端时,请保持此服务器运行。 服务器和客户端都需要同时运行,才能运行完整的系统。
步骤 2:创建 AG-UI 客户端
AG-UI 客户端连接到远程服务器并显示流式响应。
重要
在运行客户端之前,请确保步骤 1 中的 AG-UI 服务器正在运行 http://localhost:8888。
安装所需的包
安装 AG-UI 客户端库:
dotnet add package Microsoft.Agents.AI.AGUI --prerelease
dotnet add package Microsoft.Agents.AI --prerelease
注释
包 Microsoft.Agents.AI 提供 AsAIAgent() 扩展方法。
客户端代码
创建名为 Program.cs: 的文件
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AGUI;
using Microsoft.Extensions.AI;
string serverUrl = Environment.GetEnvironmentVariable("AGUI_SERVER_URL") ?? "http://localhost:8888";
Console.WriteLine($"Connecting to AG-UI server at: {serverUrl}\n");
// Create the AG-UI client agent
using HttpClient httpClient = new()
{
Timeout = TimeSpan.FromSeconds(60)
};
AGUIChatClient chatClient = new(httpClient, serverUrl);
AIAgent agent = chatClient.AsAIAgent(
name: "agui-client",
description: "AG-UI Client Agent");
AgentSession session = await agent.CreateSessionAsync();
List<ChatMessage> messages =
[
new(ChatRole.System, "You are a helpful assistant.")
];
try
{
while (true)
{
// Get user input
Console.Write("\nUser (:q or quit to exit): ");
string? message = Console.ReadLine();
if (string.IsNullOrWhiteSpace(message))
{
Console.WriteLine("Request cannot be empty.");
continue;
}
if (message is ":q" or "quit")
{
break;
}
messages.Add(new ChatMessage(ChatRole.User, message));
// Stream the response
bool isFirstUpdate = true;
string? threadId = null;
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(messages, session))
{
ChatResponseUpdate chatUpdate = update.AsChatResponseUpdate();
// First update indicates run started
if (isFirstUpdate)
{
threadId = chatUpdate.ConversationId;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"\n[Run Started - Thread: {chatUpdate.ConversationId}, Run: {chatUpdate.ResponseId}]");
Console.ResetColor();
isFirstUpdate = false;
}
// Display streaming text content
foreach (AIContent content in update.Contents)
{
if (content is TextContent textContent)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write(textContent.Text);
Console.ResetColor();
}
else if (content is ErrorContent errorContent)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"\n[Error: {errorContent.Message}]");
Console.ResetColor();
}
}
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"\n[Run Finished - Thread: {threadId}]");
Console.ResetColor();
}
}
catch (Exception ex)
{
Console.WriteLine($"\nAn error occurred: {ex.Message}");
}
关键概念
- Server-Sent 事件(SSE):协议使用 SSE 进行流式传输响应
-
AGUIChatClient:连接到 AG-UI 服务器的客户端类并实现
IChatClient -
AsAIAgent:用于从客户端创建代理的扩展方法
AGUIChatClient -
RunStreamingAsync:将响应流式传输为
AgentResponseUpdate对象 -
AsChatResponseUpdate:用于访问聊天特定属性的扩展方法,例如
ConversationId和ResponseId -
会话管理:
AgentSession维护跨请求的会话上下文 -
内容类型:响应包括
TextContent用于消息和ErrorContent用于错误
配置并运行客户端
(可选)设置自定义服务器 URL:
export AGUI_SERVER_URL="http://localhost:8888"
在单独的终端中运行客户端(确保步骤 1 中的服务器正在运行):
dotnet run
步骤 3:测试完整系统
运行服务器和客户端后,现在可以测试完整的系统。
预期输出
$ dotnet run
Connecting to AG-UI server at: http://localhost:8888
User (:q or quit to exit): What is 2 + 2?
[Run Started - Thread: thread_abc123, Run: run_xyz789]
2 + 2 equals 4.
[Run Finished - Thread: thread_abc123]
User (:q or quit to exit): Tell me a fun fact about space
[Run Started - Thread: thread_abc123, Run: run_def456]
Here's a fun fact: A day on Venus is longer than its year! Venus takes
about 243 Earth days to rotate once on its axis, but only about 225 Earth
days to orbit the Sun.
[Run Finished - Thread: thread_abc123]
User (:q or quit to exit): :q
颜色编码输出
客户端显示具有不同颜色的不同内容类型:
- 黄色:运行开始通知
- 蓝绿色:代理文本响应(实时流式传输)
- 绿色:运行完成通知
- 红色:错误消息
工作原理
服务器端流程
- 客户端发送包含消息的 HTTP POST 请求
- ASP.NET Core 终结点通过
MapAGUI接收请求 - 代理使用代理框架处理消息
- 响应将转换为 AG-UI 事件
- 事件以服务器发送事件(SSE)的形式流式传输回
- 运行完成后,连接将关闭
客户端流
-
AGUIChatClient将 HTTP POST 请求发送到服务器终结点 - 服务器使用 SSE 流进行响应
- 客户端将传入事件分析为
AgentResponseUpdate对象 - 每个更新都基于其内容类型显示
-
ConversationId捕获以保持会话连续性 - 运行完成后,数据流才结束
协议详细信息
AG-UI 协议使用:
- 用于发送请求的 HTTP POST
- 用于流式处理响应的服务器传送事件(SSE)
- 使用 JSON 进行事件序列化
- 用于维护会话上下文的线程 ID(as
ConversationId) - 运行 ID(as
ResponseId)以跟踪单个执行
后续步骤
了解 AG-UI 的基础知识后,可以:
- 添加后端工具:为域创建自定义函数工具
其他资源
先决条件
在开始之前,请确保具有以下各项:
- Python 3.10 或更高版本
- 已配置 Azure OpenAI 服务终结点和部署
- 已安装的Azure CLI并且已进行身份验证
- 用户在 Azure OpenAI 资源中具有
Cognitive Services OpenAI Contributor角色
注释
这些示例使用 Azure OpenAI 模型。 有关详细信息,请参阅 如何使用 Azure AI Foundry 部署 Azure OpenAI 模型。
注释
这些示例使用 DefaultAzureCredential 进行身份验证。 确保通过 Azure 进行身份验证(例如,通过 az login)。 有关详细信息,请参阅 Azure 标识文档。
警告
AG-UI 协议仍在开发中,可能会发生更改。 随着协议的发展,我们将不断更新这些示例。
步骤 1:创建 AG-UI 服务器
AG-UI 服务器运行和托管你的智能代理,并使用 FastAPI 通过 HTTP 端点公开它。
安装所需的包
安装服务器所需的包:
pip install agent-framework-ag-ui --pre
或使用紫外线:
uv pip install agent-framework-ag-ui --prerelease=allow
这将自动安装 agent-framework-core、fastapi 和 uvicorn 作为依赖项。
服务器代码
创建名为 server.py: 的文件
"""AG-UI server example."""
import os
from agent_framework import Agent
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework_ag_ui import add_agent_framework_fastapi_endpoint
from azure.identity import AzureCliCredential
from fastapi import FastAPI
# Read required configuration
endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT")
deployment_name = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME")
if not endpoint:
raise ValueError("AZURE_OPENAI_ENDPOINT environment variable is required")
if not deployment_name:
raise ValueError("AZURE_OPENAI_DEPLOYMENT_NAME environment variable is required")
chat_client = AzureOpenAIChatClient(
credential=AzureCliCredential(),
endpoint=endpoint,
deployment_name=deployment_name,
)
# Create the AI agent
agent = Agent(
name="AGUIAssistant",
instructions="You are a helpful assistant.",
chat_client=chat_client,
)
# Create FastAPI app
app = FastAPI(title="AG-UI Server")
# Register the AG-UI endpoint
add_agent_framework_fastapi_endpoint(app, agent, "/")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8888)
关键概念
-
add_agent_framework_fastapi_endpoint:注册 AG-UI 端点,具有自动请求/响应处理功能和 SSE 流式传输功能 -
Agent:将处理传入请求的 Agent Framework 代理 - FastAPI 集成:使用 FastAPI 的本机异步支持进行响应流式处理
- 说明:代理是使用默认指令创建的,客户端消息可以覆盖默认指令
-
配置:
AzureOpenAIChatClient从环境变量读取或直接接受参数
配置并运行服务器
设置所需的环境变量:
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"
运行服务器:
python server.py
或者直接使用 uvicorn:
uvicorn server:app --host 127.0.0.1 --port 8888
服务器将开始侦听 http://127.0.0.1:8888。
步骤 2:创建 AG-UI 客户端
AG-UI 客户端连接到远程服务器并显示流式响应。
安装所需的包
已安装 AG-UI 包,其中包括 AGUIChatClient:
# Already installed with agent-framework-ag-ui
pip install agent-framework-ag-ui --pre
客户端代码
创建名为 client.py: 的文件
"""AG-UI client example."""
import asyncio
import os
from agent_framework import Agent
from agent_framework_ag_ui import AGUIChatClient
async def main():
"""Main client loop."""
# Get server URL from environment or use default
server_url = os.environ.get("AGUI_SERVER_URL", "http://127.0.0.1:8888/")
print(f"Connecting to AG-UI server at: {server_url}\n")
# Create AG-UI chat client
chat_client = AGUIChatClient(server_url=server_url)
# Create agent with the chat client
agent = Agent(
name="ClientAgent",
chat_client=chat_client,
instructions="You are a helpful assistant.",
)
# Get a thread for conversation continuity
thread = agent.create_session()
try:
while True:
# Get user input
message = input("\nUser (:q or quit to exit): ")
if not message.strip():
print("Request cannot be empty.")
continue
if message.lower() in (":q", "quit"):
break
# Stream the agent response
print("\nAssistant: ", end="", flush=True)
async for update in agent.run(message, session=thread, stream=True):
# Print text content as it streams
if update.text:
print(f"\033[96m{update.text}\033[0m", end="", flush=True)
print("\n")
except KeyboardInterrupt:
print("\n\nExiting...")
except Exception as e:
print(f"\n\033[91mAn error occurred: {e}\033[0m")
if __name__ == "__main__":
asyncio.run(main())
关键概念
-
Server-Sent 事件(SSE):协议使用 SSE 格式(
data: {json}\n\n) -
事件类型:不同的事件提供元数据和内容(带下划线的大写):
-
RUN_STARTED:代理已开始处理 -
TEXT_MESSAGE_START:来自代理的短信开头 -
TEXT_MESSAGE_CONTENT:从代理流式传输的增量文本(包含delta字段) -
TEXT_MESSAGE_END:短信结束 -
RUN_FINISHED:成功完成 -
RUN_ERROR:错误信息
-
-
字段命名:事件字段使用 camelCase(例如,
threadId、runId、messageId) -
线程管理:在跨
threadId的请求中维护会话上下文 - 客户端说明:系统消息从客户端发送
配置并运行客户端
(可选)设置自定义服务器 URL:
export AGUI_SERVER_URL="http://127.0.0.1:8888/"
运行客户端(在单独的终端中):
python client.py
步骤 3:测试完整系统
运行服务器和客户端后,现在可以测试完整的系统。
预期输出
$ python client.py
Connecting to AG-UI server at: http://127.0.0.1:8888/
User (:q or quit to exit): What is 2 + 2?
[Run Started - Thread: abc123, Run: xyz789]
2 + 2 equals 4.
[Run Finished - Thread: abc123, Run: xyz789]
User (:q or quit to exit): Tell me a fun fact about space
[Run Started - Thread: abc123, Run: def456]
Here's a fun fact: A day on Venus is longer than its year! Venus takes
about 243 Earth days to rotate once on its axis, but only about 225 Earth
days to orbit the Sun.
[Run Finished - Thread: abc123, Run: def456]
User (:q or quit to exit): :q
颜色编码输出
客户端显示具有不同颜色的不同内容类型:
- 黄色:运行开始通知
- 蓝绿色:代理文本响应(实时流式传输)
- 绿色:运行完成通知
- 红色:错误消息
使用 curl 进行测试(可选)
在运行客户端之前,可以使用 curl 手动测试服务器:
curl -N http://127.0.0.1:8888/ \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"messages": [
{"role": "user", "content": "What is 2 + 2?"}
]
}'
您将会看到服务器发送事件的流处理:
data: {"type":"RUN_STARTED","threadId":"...","runId":"..."}
data: {"type":"TEXT_MESSAGE_START","messageId":"...","role":"assistant"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"...","delta":"The"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"...","delta":" answer"}
...
data: {"type":"TEXT_MESSAGE_END","messageId":"..."}
data: {"type":"RUN_FINISHED","threadId":"...","runId":"..."}
工作原理
服务器端流程
- 客户端发送包含消息的 HTTP POST 请求
- FastAPI 终结点接收请求
-
AgentFrameworkAgent封装器管理执行 - 代理使用代理框架处理消息
-
AgentFrameworkEventBridge将代理更新转换为 AG-UI 事件 - 响应作为服务器发送事件(SSE)被流式传输回
- 运行完成后,连接将关闭
客户端流
- 客户端将 HTTP POST 请求发送到服务器终结点
- 服务器使用 SSE 流进行响应
- 客户端将传入
data:行分析为 JSON 事件 - 每个事件都根据其类型显示
-
threadId捕获以保持会话连续性 - 当
RUN_FINISHED事件到达时,流完成
协议详细信息
AG-UI 协议使用:
- 用于发送请求的 HTTP POST
- 用于流式处理响应的服务器传送事件(SSE)
- 使用 JSON 进行事件序列化
- 用于维护会话上下文的线程 ID
- 运行 ID 以跟踪单个执行
- 事件类型命名:使用大写并用下划线分隔(例如,
RUN_STARTED,TEXT_MESSAGE_CONTENT) - 字段命名:camelCase(例如,
threadId、runId、messageId)
常见模式
自定义服务器配置
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# Add CORS for web clients
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
add_agent_framework_fastapi_endpoint(app, agent, "/agent")
多个代理
app = FastAPI()
weather_agent = Agent(name="weather", ...)
finance_agent = Agent(name="finance", ...)
add_agent_framework_fastapi_endpoint(app, weather_agent, "/weather")
add_agent_framework_fastapi_endpoint(app, finance_agent, "/finance")
错误处理
try:
async for event in client.send_message(message):
if event.get("type") == "RUN_ERROR":
error_msg = event.get("message", "Unknown error")
print(f"Error: {error_msg}")
# Handle error appropriately
except httpx.HTTPError as e:
print(f"HTTP error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
Troubleshooting
连接被拒绝
在启动客户端之前,请确保服务器正在运行:
# Terminal 1
python server.py
# Terminal 2 (after server starts)
python client.py
身份验证错误
确保使用 Azure 进行身份验证:
az login
验证 Azure OpenAI 资源上是否分配了正确的角色。
流媒体无法播放
检查你的客户端程序的超时设置是否足够:
httpx.AsyncClient(timeout=60.0) # 60 seconds should be enough
对于长时间运行的软件代理,请相应地增加超时。
线程上下文丢失
客户端会自动管理线程连续性。 如果上下文丢失:
- 请检查
threadId是否正在从RUN_STARTED事件中捕获 - 确保跨消息使用相同的客户端实例
- 验证服务器是否在后续请求中接收
thread_id
后续步骤
了解 AG-UI 的基础知识后,可以:
- 添加后端工具:为域创建自定义函数工具