chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,405 @@
|
||||
# Semantic Kernel to Agent Framework Migration Guide
|
||||
|
||||
## What's Changed?
|
||||
- **Namespace Updates**: From `Microsoft.SemanticKernel.Agents` to `Microsoft.Agents.AI`
|
||||
- **Agent Creation**: Single fluent API calls vs multi-step builder patterns
|
||||
- **Thread Management**: Built-in thread management vs manual thread creation
|
||||
- **Tool Registration**: Direct function registration vs plugin wrapper systems
|
||||
- **Dependency Injection**: Simplified service registration patterns
|
||||
- **Invocation Patterns**: Streamlined options and result handling
|
||||
|
||||
## Benefits of Migration
|
||||
- **Simplified API**: Reduced complexity and boilerplate code
|
||||
- **Better Performance**: Optimized object creation and memory usage
|
||||
- **Unified Interface**: Consistent patterns across different AI providers
|
||||
- **Enhanced Developer Experience**: More intuitive and discoverable APIs
|
||||
|
||||
## Key Changes
|
||||
|
||||
### 1. Namespace Updates
|
||||
|
||||
#### Semantic Kernel
|
||||
|
||||
```csharp
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Agents;
|
||||
```
|
||||
|
||||
#### Agent Framework
|
||||
|
||||
Agent Framework namespaces are under `Microsoft.Agents.AI`.
|
||||
Agent Framework uses the core AI message and content types from `Microsoft.Extensions.AI` for communication between components.
|
||||
|
||||
```csharp
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Agents.AI;
|
||||
```
|
||||
|
||||
### 2. Agent Creation Simplification
|
||||
|
||||
#### Semantic Kernel
|
||||
|
||||
Every agent in Semantic Kernel depends on a `Kernel` instance and will have
|
||||
an empty `Kernel` if not provided.
|
||||
|
||||
```csharp
|
||||
Kernel kernel = Kernel
|
||||
.AddOpenAIChatClient(modelId, apiKey)
|
||||
.Build();
|
||||
|
||||
ChatCompletionAgent agent = new() { Instructions = ParrotInstructions, Kernel = kernel };
|
||||
```
|
||||
|
||||
Azure AI Foundry requires an agent resource to be created in the cloud before creating a local agent class that uses it.
|
||||
|
||||
```csharp
|
||||
PersistentAgentsClient azureAgentClient = AzureAIAgent.CreateAgentsClient(azureEndpoint, new AzureCliCredential());
|
||||
|
||||
PersistentAgent definition = await azureAgentClient.Administration.CreateAgentAsync(
|
||||
deploymentName,
|
||||
instructions: ParrotInstructions);
|
||||
|
||||
AzureAIAgent agent = new(definition, azureAgentClient);
|
||||
```
|
||||
|
||||
#### Agent Framework
|
||||
|
||||
Agent creation in Agent Framework is made simpler with extensions provided by all main providers.
|
||||
|
||||
```csharp
|
||||
AIAgent openAIAgent = chatClient.CreateAIAgent(instructions: ParrotInstructions);
|
||||
AIAgent azureFoundryAgent = await persistentAgentsClient.CreateAIAgentAsync(instructions: ParrotInstructions);
|
||||
AIAgent openAIAssistantAgent = await assistantClient.CreateAIAgentAsync(instructions: ParrotInstructions);
|
||||
```
|
||||
|
||||
Additionally for hosted agent providers you can also use the `GetAIAgent` to retrieve an agent from an existing hosted agent.
|
||||
|
||||
```csharp
|
||||
AIAgent azureFoundryAgent = await persistentAgentsClient.GetAIAgentAsync(agentId);
|
||||
```
|
||||
|
||||
### 3. Agent Thread Creation
|
||||
|
||||
#### Semantic Kernel
|
||||
|
||||
The caller has to know the thread type and create it manually.
|
||||
|
||||
```csharp
|
||||
// Create a thread for the agent conversation.
|
||||
AgentThread thread = new OpenAIAssistantAgentThread(this.AssistantClient);
|
||||
AgentThread thread = new AzureAIAgentThread(this.Client);
|
||||
AgentThread thread = new OpenAIResponseAgentThread(this.Client);
|
||||
```
|
||||
|
||||
#### Agent Framework
|
||||
|
||||
The agent is responsible for creating the thread.
|
||||
|
||||
```csharp
|
||||
// New
|
||||
AgentThread thread = agent.GetNewThread();
|
||||
```
|
||||
|
||||
### 4. Hosted Agent Thread Cleanup
|
||||
|
||||
This case applies exclusively to a few AI providers that still provide hosted threads.
|
||||
|
||||
#### Semantic Kernel
|
||||
|
||||
Threads have a `self` deletion method
|
||||
|
||||
i.e: OpenAI Assistants Provider
|
||||
```csharp
|
||||
await thread.DeleteAsync();
|
||||
```
|
||||
|
||||
#### Agent Framework
|
||||
|
||||
> [!NOTE]
|
||||
> OpenAI Responses introduced a new conversation model that simplifies how conversations are handled. This simplifies hosted thread management compared to the now deprecated OpenAI Assistants model. For more information see the [OpenAI Assistants migration guide](https://platform.openai.com/docs/assistants/migration).
|
||||
|
||||
Agent Framework doesn't have a thread deletion API in the `AgentThread` type as not all providers support hosted threads or thread deletion and this will become more common as more providers shift to responses based architectures.
|
||||
|
||||
If you require thread deletion and the provider allows this, the caller **should** keep track of the created threads and delete them later when necessary via the provider's sdk.
|
||||
|
||||
i.e: OpenAI Assistants Provider
|
||||
```csharp
|
||||
await assistantClient.DeleteThreadAsync(thread.ConversationId);
|
||||
```
|
||||
|
||||
### 5. Tool Registration
|
||||
|
||||
#### Semantic Kernel
|
||||
|
||||
In semantic kernel to expose a function as a tool you must:
|
||||
|
||||
1. Decorate the function with a `[KernelFunction]` attribute.
|
||||
2. Have a `Plugin` class or use the `KernelPluginFactory` to wrap the function.
|
||||
3. Have a `Kernel` to add your plugin to.
|
||||
4. Pass the `Kernel` to the agent.
|
||||
|
||||
```csharp
|
||||
KernelFunction function = KernelFunctionFactory.CreateFromMethod(GetWeather);
|
||||
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("KernelPluginName", [function]);
|
||||
Kernel kernel = ... // Create kernel
|
||||
kernel.Plugins.Add(plugin);
|
||||
|
||||
ChatCompletionAgent agent = new() { Kernel = kernel, ... };
|
||||
```
|
||||
|
||||
#### Agent Framework
|
||||
|
||||
In agent framework in a single call you can register tools directly in the agent creation process.
|
||||
|
||||
```csharp
|
||||
AIAgent agent = chatClient.CreateAIAgent(tools: [AIFunctionFactory.Create(GetWeather)]);
|
||||
```
|
||||
|
||||
### 6. Agent Non-Streaming Invocation
|
||||
|
||||
Key differences can be seen in the method names from `Invoke` to `Run`, return types and parameters `AgentRunOptions`.
|
||||
|
||||
#### Semantic Kernel
|
||||
|
||||
The Non-Streaming uses a streaming pattern `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>` for returning multiple agent messages.
|
||||
|
||||
```csharp
|
||||
await foreach (AgentResponseItem<ChatMessageContent> result in agent.InvokeAsync(userInput, thread, agentOptions))
|
||||
{
|
||||
Console.WriteLine(result.Message);
|
||||
}
|
||||
```
|
||||
|
||||
#### Agent Framework
|
||||
|
||||
The Non-Streaming returns a single `AgentRunResponse` with the agent response that can contain multiple messages.
|
||||
The text result of the run is available in `AgentRunResponse.Text` or `AgentRunResponse.ToString()`.
|
||||
All messages created as part of the response is returned in the `AgentRunResponse.Messages` list.
|
||||
This may include tool call messages, function results, reasoning updates and final results.
|
||||
|
||||
```csharp
|
||||
AgentRunResponse agentResponse = await agent.RunAsync(userInput, thread);
|
||||
```
|
||||
|
||||
### 7. Agent Streaming Invocation
|
||||
|
||||
Key differences in the method names from `Invoke` to `Run`, return types and parameters `AgentRunOptions`.
|
||||
|
||||
#### Semantic Kernel
|
||||
|
||||
```csharp
|
||||
await foreach (StreamingChatMessageContent update in agent.InvokeStreamingAsync(userInput, thread))
|
||||
{
|
||||
Console.Write(update);
|
||||
}
|
||||
```
|
||||
|
||||
#### Agent Framework
|
||||
|
||||
Similar streaming API pattern with the key difference being that it returns `AgentRunResponseUpdate` objects including more agent related information per update.
|
||||
|
||||
All updates produced by any service underlying the AIAgent is returned. The textual result of the agent is available by concatenating the `AgentRunResponse.Text` values.
|
||||
|
||||
```csharp
|
||||
await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(userInput, thread))
|
||||
{
|
||||
Console.Write(update); // Update is ToString() friendly
|
||||
}
|
||||
```
|
||||
|
||||
### 8. Tool Function Signatures
|
||||
|
||||
**Problem**: SK plugin methods need `[KernelFunction]` attributes
|
||||
|
||||
```csharp
|
||||
public class MenuPlugin
|
||||
{
|
||||
[KernelFunction] // Required for SK
|
||||
public static MenuItem[] GetMenu() => ...;
|
||||
}
|
||||
```
|
||||
|
||||
**Solution**: AF can use methods directly without attributes
|
||||
|
||||
```csharp
|
||||
public class MenuTools
|
||||
{
|
||||
[Description("Get menu items")] // Optional description
|
||||
public static MenuItem[] GetMenu() => ...;
|
||||
}
|
||||
```
|
||||
|
||||
### 9. Options Configuration
|
||||
|
||||
**Problem**: Complex options setup in SK
|
||||
|
||||
```csharp
|
||||
OpenAIPromptExecutionSettings settings = new() { MaxTokens = 1000 };
|
||||
AgentInvokeOptions options = new() { KernelArguments = new(settings) };
|
||||
```
|
||||
|
||||
**Solution**: Simplified options in AF
|
||||
|
||||
```csharp
|
||||
ChatClientAgentRunOptions options = new(new() { MaxOutputTokens = 1000 });
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This example shows passing implementation specific options to a `ChatClientAgent`. Not all `AIAgents` support `ChatClientAgentRunOptions`.
|
||||
> `ChatClientAgent` is provided to build agents based on underlying inference services, and therefore supports inference options like `MaxOutputTokens`.
|
||||
|
||||
### 10. Dependency Injection
|
||||
|
||||
#### Semantic Kernel
|
||||
|
||||
A `Kernel` registration is required in the service container to be able to create an agent
|
||||
as every agent abstractions needs to be initialized with a `Kernel` property.
|
||||
|
||||
Semantic Kernel uses the `Agent` type as the base abstraction class for agents.
|
||||
|
||||
```csharp
|
||||
services.AddKernel().AddProvider(...);
|
||||
serviceContainer.AddKeyedSingleton<SemanticKernel.Agents.Agent>(
|
||||
TutorName,
|
||||
(sp, key) =>
|
||||
new ChatCompletionAgent()
|
||||
{
|
||||
// Passing the kernel is required
|
||||
Kernel = sp.GetRequiredService<Kernel>(),
|
||||
});
|
||||
```
|
||||
|
||||
### 11. **Agent Type Consolidation**
|
||||
|
||||
#### Semantic Kernel
|
||||
|
||||
Semantic kernel provides specific agent classes for various services, e.g.
|
||||
|
||||
- `ChatCompletionAgent` for use with chat-completion-based inference services.
|
||||
- `OpenAIAssistantAgent` for use with the OpenAI Assistants service.
|
||||
- `AzureAIAgent` for use with the Azure AI Foundry Agents service.
|
||||
|
||||
#### Agent Framework
|
||||
|
||||
The agent framework supports all the abovementioned services via a single agent type, `ChatClientAgent`.
|
||||
|
||||
`ChatClientAgent` can be used to build agents using any underlying service that provides an SDK implementing the `Microsoft.Extensions.AI.IChatClient` interface.
|
||||
|
||||
#### Agent Framework
|
||||
|
||||
The Agent framework provides the `AIAgent` type as the base abstraction class.
|
||||
|
||||
```csharp
|
||||
services.AddKeyedSingleton<AIAgent>(() => client.CreateAIAgent(...));
|
||||
```
|
||||
|
||||
## Migration Samples
|
||||
|
||||
This folder contains **separate console application projects** demonstrating how to transition from **Semantic Kernel (SK)** to the new **Agent Framework (AF)**.
|
||||
|
||||
Each project shows side-by-side comparisons of equivalent functionality in both frameworks and can be run independently.
|
||||
|
||||
Each sample code contains the following:
|
||||
1. **SK Agent** (Semantic Kernel before)
|
||||
2. **AF Agent** (Agent Framework after)
|
||||
|
||||
### Running the samples from Visual Studio
|
||||
|
||||
Open the solution in Visual Studio and set the desired sample project as the startup project. Then, run the project using the built-in debugger or by pressing `F5`.
|
||||
|
||||
You will be prompted for any required environment variables if they are not already set.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before you begin, ensure you have the following:
|
||||
|
||||
- [.NET 10.0 SDK or later](https://dotnet.microsoft.com/download)
|
||||
- For Azure AI Foundry samples: Azure OpenAI service endpoint and deployment configured
|
||||
- For OpenAI samples: OpenAI API key
|
||||
- For OpenAI Assistants samples: OpenAI API key with Assistant API access
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Set the appropriate environment variables based on the sample type you want to run:
|
||||
|
||||
**For Azure AI Foundry projects:**
|
||||
```powershell
|
||||
$env:AZURE_FOUNDRY_PROJECT_ENDPOINT = "https://<your-project>-resource.services.ai.azure.com/api/projects/<your-project>"
|
||||
```
|
||||
|
||||
**For OpenAI and OpenAI Assistants projects:**
|
||||
```powershell
|
||||
$env:OPENAI_API_KEY = "sk-..."
|
||||
```
|
||||
|
||||
**For Azure OpenAI and Azure OpenAI Assistants projects:**
|
||||
```powershell
|
||||
$env:AZURE_OPENAI_ENDPOINT = "https://<your-project>.cognitiveservices.azure.com/"
|
||||
$env:AZURE_OPENAI_DEPLOYMENT_NAME = "gpt-4o" # Optional, defaults to gpt-4o
|
||||
```
|
||||
|
||||
**Optional debug mode:**
|
||||
```powershell
|
||||
$env:AF_SHOW_ALL_DEMO_SETTING_VALUES = "Y"
|
||||
```
|
||||
|
||||
If environment variables are not set, the demos will prompt you to enter values interactively.
|
||||
|
||||
### Samples
|
||||
|
||||
The migration samples are organized into different categories, each demonstrating different AI service integrations and orchestration patterns:
|
||||
|
||||
|Category|Description|
|
||||
|---|---|
|
||||
|[AzureAIFoundry](./AzureAIFoundry/)|Azure OpenAI service integration samples|
|
||||
|[AzureOpenAI](./AzureOpenAI/)|Direct Azure OpenAI API integration samples|
|
||||
|[AzureOpenAIAssistants](./AzureOpenAIAssistants/)|Azure OpenAI Assistants API integration samples|
|
||||
|[AzureOpenAIResponses](./AzureOpenAIResponses/)|Azure OpenAI Responses API integration samples|
|
||||
|[OpenAI](./OpenAI/)|Direct OpenAI API integration samples|
|
||||
|[OpenAIAssistants](./OpenAIAssistants/)|OpenAI Assistants API integration samples|
|
||||
|[OpenAIResponses](./OpenAIResponses/)|OpenAI Responses API integration samples|
|
||||
|[AgentOrchestrations](./AgentOrchestrations/)|Agent orchestration patterns including concurrent, sequential, and handoff workflows|
|
||||
|
||||
## Running the samples from the console
|
||||
|
||||
To run any migration sample, navigate to the desired sample directory:
|
||||
|
||||
```powershell
|
||||
# Azure AI Foundry Examples
|
||||
cd "AzureAIFoundry\Step01_Basics"
|
||||
dotnet run
|
||||
|
||||
# Azure OpenAI Examples
|
||||
cd "AzureOpenAI\Step01_Basics"
|
||||
dotnet run
|
||||
|
||||
# Azure OpenAI Assistants Examples
|
||||
cd "AzureOpenAIAssistants\Step01_Basics"
|
||||
dotnet run
|
||||
|
||||
# Azure OpenAI Responses Examples
|
||||
cd "AzureOpenAIResponses\Step01_Basics"
|
||||
dotnet run
|
||||
|
||||
# OpenAI Examples
|
||||
cd "OpenAI\Step01_Basics"
|
||||
dotnet run
|
||||
|
||||
# OpenAI Assistants Examples
|
||||
cd "OpenAIAssistants\Step01_Basics"
|
||||
dotnet run
|
||||
|
||||
# OpenAI Responses Examples
|
||||
cd "OpenAIResponses\Step01_Basics"
|
||||
dotnet run
|
||||
|
||||
# Agent Orchestrations Examples
|
||||
cd "AgentOrchestrations\Step01_Concurrent"
|
||||
dotnet run
|
||||
|
||||
cd "AgentOrchestrations\Step02_Sequential"
|
||||
dotnet run
|
||||
|
||||
cd "AgentOrchestrations\Step03_Handoff"
|
||||
dotnet run
|
||||
```
|
||||
Reference in New Issue
Block a user