🎨 带有 GitHub 模型的代理设计模式 (.NET)

📋 学习目标

此示例演示了使用 .NET 中的 Microsoft Agent Framework 与 GitHub Models 集成构建智能代理的企业级设计模式。您将学习专业的模式和架构方法,使代理可用于生产、可维护和可扩展。

企业设计模式

  • 🏭 工厂模式:通过依赖注入标准化代理创建
  • 🔧 构建器模式:流畅的代理配置和设置
  • 🧵 线程安全模式:并发对话管理
  • 📋 存储库模式:有组织的工具和能力管理

🎯 .NET 特定的架构优势

企业特色

  • 强类型:编译时验证和 IntelliSense 支持
  • 依赖注入:内置 DI 容器集成
  • 配置管理:IConfiguration 和选项模式
  • Async/Await:一流的异步编程支持

生产就绪模式

  • 日志集成:ILogger 和结构化日志支持
  • 健康检查:内置监控和诊断
  • 配置验证:带有数据注释的强类型
  • 错误处理:结构化异常管理

🔧 技术架构

核心 .NET 组件

  • Microsoft.Extensions.AI:统一人工智能服务抽象
  • Microsoft.Agents.AI:企业代理编排框架
  • GitHub 模型集成:高性能 API 客户端模式
  • 配置系统:appsettings.json 和环境集成

设计模式实现

1
2
3
4
5
graph LR
A[IServiceCollection] --> B[Agent Builder]
B --> C[Configuration]
C --> D[Tool Registry]
D --> E[AI Agent]

🏗️企业模式展示

1. 创作模式

  • 代理工厂:具有一致配置的集中代理创建
  • 构建器模式:用于复杂代理配置的流畅 API
  • 单例模式:共享资源和配置管理
  • 依赖注入:松耦合和可测试性

2. 行为模式

  • 策略模式:可互换的工具执行策略
  • 命令模式:带有撤消/重做的封装代理操作
  • 观察者模式:事件驱动的代理生命周期管理
  • 模板方法:标准化代理执行工作流程

3. 结构模式

  • 适配器模式:GitHub Models API 集成层
  • 装饰器模式:Agent能力增强
  • 外观模式:简化的代理交互界面
  • 代理模式:延迟加载和缓存以提高性能

📚 .NET 设计原则

坚实的原则

  • 单一职责:每个组件都有一个明确的目的
  • 开放/封闭:无需修改即可扩展
  • 里氏替换:基于接口的工具实现
  • 界面隔离:集中、有凝聚力的界面
  • 依赖倒置:依赖于抽象,而不是具体

干净的架构

  • 领域层:核心代理和工具抽象
  • 应用层:代理编排和工作流程
  • 基础设施层:GitHub 模型集成和外部服务
  • 表示层:用户交互和响应格式

🔒 企业考虑因素

安全

  • 凭证管理:使用 IConfiguration 进行安全 API 密钥处理
  • 输入验证:强类型和数据注释验证
  • 输出清理:安全响应处理和过滤
  • 审计日志:全面的操作跟踪

性能

  • 异步模式:非阻塞 I/O 操作
  • 连接池:高效的 HTTP 客户端管理
  • 缓存:响应缓存以提高性能
  • 资源管理:正确的处置和清理模式

可扩展性

  • 线程安全:并发代理执行支持
  • 资源池:资源高效利用
  • 负载管理:速率限制和背压处理
  • 监控:性能指标和运行状况检查

🚀 生产部署

  • 配置管理:特定于环境的设置
  • 日志记录策略:具有相关 ID 的结构化日志记录
  • 错误处理:具有适当恢复的全局异常处理
  • 监控:应用程序洞察和性能计数器
  • 测试:单元测试、集成测试和负载测试模式

准备好使用 .NET 构建企业级智能代理了吗?让我们构建一些健壮的东西! 🏢✨

🚀 开始使用

先决条件

所需的环境变量

1
2
3
4
# zsh/bash
export GH_TOKEN=<your_github_token>
export GH_ENDPOINT=https://models.github.ai/inference
export GH_MODEL_ID=openai/gpt-5-mini
1
2
3
4
# PowerShell
$env:GH_TOKEN = "<your_github_token>"
$env:GH_ENDPOINT = "https://models.github.ai/inference"
$env:GH_MODEL_ID = "openai/gpt-5-mini"

示例代码

要运行代码示例,

1
2
3
# zsh/bash
chmod +x ./03-dotnet-agent-framework.cs
./03-dotnet-agent-framework.cs

或者使用 dotnet CLI:

1
dotnet run ./03-dotnet-agent-framework.cs

有关完整代码,请参阅 03-dotnet-agent-framework.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/dotnet run

#:package Microsoft.Extensions.AI@10.*
#:package Microsoft.Agents.AI.OpenAI@1.*-*

using System.ClientModel;
using System.ComponentModel;

using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

using OpenAI;

// Tool Function: Random Destination Generator
// This static method will be available to the agent as a callable tool
// The [Description] attribute helps the AI understand when to use this function
// This demonstrates how to create custom tools for AI agents
[Description("Provides a random vacation destination.")]
static string GetRandomDestination()
{
// List of popular vacation destinations around the world
// The agent will randomly select from these options
var destinations = new List<string>
{
"Paris, France",
"Tokyo, Japan",
"New York City, USA",
"Sydney, Australia",
"Rome, Italy",
"Barcelona, Spain",
"Cape Town, South Africa",
"Rio de Janeiro, Brazil",
"Bangkok, Thailand",
"Vancouver, Canada"
};

// Generate random index and return selected destination
// Uses System.Random for simple random selection
var random = new Random();
int index = random.Next(destinations.Count);
return destinations[index];
}

// Extract configuration from environment variables
// Retrieve the GitHub Models API endpoint, defaults to https://models.github.ai/inference if not specified
// Retrieve the model ID, defaults to openai/gpt-5-mini if not specified
// Retrieve the GitHub token for authentication, throws exception if not specified
var github_endpoint = Environment.GetEnvironmentVariable("GH_ENDPOINT") ?? "https://models.github.ai/inference";
var github_model_id = Environment.GetEnvironmentVariable("GH_MODEL_ID") ?? "openai/gpt-5-mini";
var github_token = Environment.GetEnvironmentVariable("GH_TOKEN") ?? throw new InvalidOperationException("GH_TOKEN is not set.");

// Configure OpenAI Client Options
// Create configuration options to point to GitHub Models endpoint
// This redirects OpenAI client calls to GitHub's model inference service
var openAIOptions = new OpenAIClientOptions()
{
Endpoint = new Uri(github_endpoint)
};

// Initialize OpenAI Client with GitHub Models Configuration
// Create OpenAI client using GitHub token for authentication
// Configure it to use GitHub Models endpoint instead of OpenAI directly
var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions);

// Define Agent Identity and Comprehensive Instructions
// Agent name for identification and logging purposes
var AGENT_NAME = "TravelAgent";

// Detailed instructions that define the agent's personality, capabilities, and behavior
// This system prompt shapes how the agent responds and interacts with users
var AGENT_INSTRUCTIONS = """
You are a helpful AI Agent that can help plan vacations for customers.

Important: When users specify a destination, always plan for that location. Only suggest random destinations when the user hasn't specified a preference.

When the conversation begins, introduce yourself with this message:
"Hello! I'm your TravelAgent assistant. I can help plan vacations and suggest interesting destinations for you. Here are some things you can ask me:
1. Plan a day trip to a specific location
2. Suggest a random vacation destination
3. Find destinations with specific features (beaches, mountains, historical sites, etc.)
4. Plan an alternative trip if you don't like my first suggestion

What kind of trip would you like me to help you plan today?"

Always prioritize user preferences. If they mention a specific destination like "Bali" or "Paris," focus your planning on that location rather than suggesting alternatives.
""";

// Create AI Agent with Advanced Travel Planning Capabilities
// Initialize complete agent pipeline: OpenAI client → Chat client → AI agent
// Configure agent with name, detailed instructions, and available tools
// This demonstrates the .NET agent creation pattern with full configuration
AIAgent agent = openAIClient
.GetChatClient(github_model_id)
.CreateAIAgent(
name: AGENT_NAME,
instructions: AGENT_INSTRUCTIONS,
tools: [AIFunctionFactory.Create(GetRandomDestination)]
);

// Create New Conversation Thread for Context Management
// Initialize a new conversation thread to maintain context across multiple interactions
// Threads enable the agent to remember previous exchanges and maintain conversational state
// This is essential for multi-turn conversations and contextual understanding
AgentThread thread = agent.GetNewThread();

// Execute Agent: First Travel Planning Request
// Run the agent with an initial request that will likely trigger the random destination tool
// The agent will analyze the request, use the GetRandomDestination tool, and create an itinerary
// Using the thread parameter maintains conversation context for subsequent interactions
await foreach (var update in agent.RunStreamingAsync("Plan me a day trip", thread))
{
await Task.Delay(10);
Console.Write(update);
}

Console.WriteLine();

// Execute Agent: Follow-up Request with Context Awareness
// Demonstrate contextual conversation by referencing the previous response
// The agent remembers the previous destination suggestion and will provide an alternative
// This showcases the power of conversation threads and contextual understanding in .NET agents
await foreach (var update in agent.RunStreamingAsync("I don't like that destination. Plan me another vacation.", thread))
{
await Task.Delay(10);
Console.Write(update);
}