RSS Amplifier

Sebastian Gingter · Oct 30, 2025

SDK v2 Migration Guide: Was .NET-Entwickler jetzt tun müssen

0
Sign in to vote or save

gingter.org

Wer mit den Azure OpenAI SDKs arbeitet, hat es in den letzten Monaten sicher gemerkt: Es bewegt sich gerade viel. Azure AI Studio wurde zu Azure AI Foundry, die SDKs werden konsolidiert, APIs umbenannt — und einiges davon hat harte Deadlines. Wer seine NuGet-Pakete nicht rechtzeitig aktualisiert, hat ab Mai 2026 ein echtes Problem.

Ich bin bei Thinktecture immer wieder auf Kundenprojekte gestoßen, die noch mit der 1.0-Beta von Azure.AI.OpenAI arbeiten. Der Code funktioniert — noch. Aber die Uhr tickt, und die Migration ist weniger trivial, als man denken könnte.

In diesem Artikel zeige ich, was sich konkret ändert, wie der alte und der neue Code aussieht, welche NuGet-Pakete ersetzt werden müssen, und wie man Agents von der Assistants API zur Responses API migriert.

Was sich geändert hat — und warum

Microsoft hat die gesamte AI-Plattform umstrukturiert. Die kurze Geschichte:

  • Azure AI StudioAzure AI FoundryMicrosoft Foundry (aktuell)
  • Azure Cognitive ServicesAzure AI ServicesFoundry Tools (aktuell)

Die Namensänderungen betreffen nicht nur das Portal, sondern ziehen sich durch die gesamte SDK-Landschaft. Das Ziel: Weg von fragmentierten Azure-spezifischen SDKs, hin zu einem konsolidierten Paketmodell, das auf der standardisierten OpenAI-API aufbaut.

Für uns als .NET-Entwickler bedeutet das konkret:

  • Der OpenAIClient aus der 1.0-Beta weicht einem AzureOpenAIClient mit szenario-spezifischen Sub-Clients
  • API Keys als primäre Authentifizierung weichen DefaultAzureCredential (Entra ID / Managed Identity)
  • Die Assistants API wird durch die Responses API ersetzt (Sunset: August 2026)
  • Das Paket Azure.AI.Inference wird eingestellt (Mai 2026)
  • Azure.AI.Projects 1.x zielt auf das Classic-Portal, 2.x auf das neue Foundry-Portal

Das sind keine kosmetischen Änderungen. Das sind Breaking Changes mit festen Deadlines.

Der alte Code vs. der neue Code

Schauen wir uns die wichtigsten Änderungen im Code an. Ich zeige jeweils den alten 1.0-Beta-Code und die neue 2.x-Version.

Client-Konfiguration

Vorher — Azure.AI.OpenAI 1.0 Beta:

// Ein einzelner Client für alles, API Key als Credentials
OpenAIClient client = new(
    new Uri("https://my-resource.openai.azure.com/"),
    new AzureKeyCredential(
        Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY")));

Nachher — Azure.AI.OpenAI 2.x:

// Top-Level Azure Client, DefaultAzureCredential statt API Key
AzureOpenAIClient azureClient = new(
    new Uri("https://my-resource.openai.azure.com/"),
    new DefaultAzureCredential());

// Szenario-spezifische Clients werden vom Top-Level Client geholt
ChatClient chatClient = azureClient.GetChatClient("gpt-4o");
EmbeddingClient embeddingClient = azureClient.GetEmbeddingClient("text-embedding-3-small");

Die größte konzeptuelle Änderung: In 2.x gibt es einen Top-Level AzureOpenAIClient, von dem man sich szenario-spezifische Clients holt — ChatClient, EmbeddingClient, ImageClient, etc. Man arbeitet nicht mehr mit einem monolithischen Client, der alles kann.

Und ja: DefaultAzureCredential statt API Key ist die neue Standard-Empfehlung. Das bedeutet lokale Entwicklung mit Azure CLI Login, Managed Identity in Produktion. Wer noch API Keys in Konfigurationsdateien hat, sollte das sowieso schon längst geändert haben.

Chat Completions

Vorher:

var options = new ChatCompletionsOptions()
{
    DeploymentName = "gpt-4o",
    Messages =
    {
        new ChatRequestSystemMessage("Du bist ein hilfreicher Assistent."),
        new ChatRequestUserMessage("Was ist Azure AI Foundry?"),
    }
};

Response<ChatCompletions> response =
    await client.GetChatCompletionsAsync(options);
string reply = response.Value.Choices[0].Message.Content;

Nachher:

ChatCompletion completion = await chatClient.CompleteChatAsync(
[
    new SystemChatMessage("Du bist ein hilfreicher Assistent."),
    new UserChatMessage("Was ist Azure AI Foundry?"),
]);

string reply = completion.Content[0].Text;

Deutlich schlanker. Kein Options-Objekt mit DeploymentName mehr — das Deployment wird beim Erstellen des ChatClient angegeben. Die Message-Typen heißen jetzt SystemChatMessage, UserChatMessage und AssistantChatMessage statt ChatRequestSystemMessage und Co.

Streaming

Vorher:

await foreach (StreamingChatCompletionsUpdate update
    in client.GetChatCompletionsStreaming(options))
{
    if (!string.IsNullOrEmpty(update.ContentUpdate))
    {
        Console.Write(update.ContentUpdate);
    }
}

Nachher:

await foreach (StreamingChatCompletionUpdate update
    in chatClient.CompleteChatStreamingAsync(messages))
{
    foreach (ChatMessageContentPart part in update.ContentUpdate)
    {
        Console.Write(part.Text);
    }
}

Subtiler, aber wichtiger Unterschied: In 2.x ist ContentUpdate eine Collection von ChatMessageContentPart-Objekten, nicht mehr ein einfacher String. Das liegt daran, dass Nachrichten jetzt multimodal sein können — Text, Bilder und Tool-Aufrufe kommen als separate Parts.

Tool Definitions (Function Calling)

Vorher:

var getWeatherTool = new ChatCompletionsFunctionToolDefinition()
{
    Name = "get_current_weather",
    Description = "Aktuelles Wetter für einen Ort abfragen",
    Parameters = BinaryData.FromObjectAsJson(
        new
        {
            Type = "object",
            Properties = new
            {
                Location = new
                {
                    Type = "string",
                    Description = "Stadt und Land, z.B. Berlin, DE",
                }
            },
            Required = new[] { "location" },
        },
        new JsonSerializerOptions()
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        }),
};

Nachher:

ChatTool getWeatherTool = ChatTool.CreateFunctionTool(
    "get_current_weather",
    "Aktuelles Wetter für einen Ort abfragen",
    BinaryData.FromObjectAsJson(
        new
        {
            Type = "object",
            Properties = new
            {
                Location = new
                {
                    Type = "string",
                    Description = "Stadt und Land, z.B. Berlin, DE",
                }
            },
            Required = new[] { "location" },
        },
        new JsonSerializerOptions()
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        }));

Die Factory-Methode ChatTool.CreateFunctionTool() ersetzt das explizite Instanziieren von ChatCompletionsFunctionToolDefinition. Weniger Boilerplate, gleiche Funktionalität.

Embeddings

Vorher:

EmbeddingsOptions options = new()
{
    DeploymentName = "text-embedding-ada-002",
    Input = { "Dein Text hier" },
};

Response<Embeddings> response = await client.GetEmbeddingsAsync(options);
EmbeddingItem item = response.Value.Data[0];
ReadOnlyMemory<float> vector = item.Embedding;

Nachher:

EmbeddingClient embeddingClient =
    azureClient.GetEmbeddingClient("text-embedding-3-small");

OpenAIEmbedding embedding =
    await embeddingClient.GenerateEmbeddingAsync("Dein Text hier");

ReadOnlyMemory<float> vector = embedding.ToFloats();

Gleiches Muster: szenario-spezifischer Client, weniger Boilerplate, klarere API.

Was bricht, wenn v2-SDK-Samples gegen ein Classic-Portal laufen

Wer ein v2-SDK-Beispiel gegen ein Classic-Portal laufen lässt — oder umgekehrt ein v1-Beispiel gegen das neue Foundry-Portal — wird schnell auf Probleme stoßen. Hier die häufigsten Stolperfallen:

SymptomUrsacheLösung
Unerwartetes API-Verhalten oder fehlende MethodenSDK-Version passt nicht zum PortalSDK-Version prüfen: 1.x → Classic, 2.x → Foundry
Endpoint-VerbindungsfehlerAlte Multi-Endpoint-URLs lösen nicht mehr aufAuf neues Single-Endpoint-Format umstellen: https://<project>.services.ai.azure.com
AuthenticationError mit neuem ClientAPI Key ohne korrekten Header verwendetDefaultAzureCredential mit Bearer Token Provider verwenden
Agent-Code gibt 404 oder MethodNotAllowedAssistants-API-Aufrufe gegen Responses-API-EndpointAgent-Code auf Responses API umschreiben
Projekte fehlen im neuen PortalHub-basierte Projekte sind im neuen Portal nicht sichtbarZum Classic-Portal wechseln oder zu Foundry-Projekten migrieren

Die Kernregel: SDK-Version und Portal-Erfahrung müssen zusammenpassen. Azure.AI.Projects 1.x funktioniert nur mit dem Classic-Portal. Version 2.x funktioniert nur mit dem neuen Foundry-Portal. Mischt man das, bekommt man kryptische Fehler, die einen halben Tag kosten können.

Checkliste: Diese 5 NuGet-Pakete müssen ersetzt werden

Hier ist die konkrete Liste der NuGet-Pakete, die Migration brauchen. Ich empfehle, das nicht aufzuschieben — die Deadlines sind real.

1. Azure.AI.OpenAI 1.0 Beta → 2.x

Deadline: Jetzt. Die 1.0-Beta wird nicht weiterentwickelt.

<!-- Vorher -->
<PackageReference Include="Azure.AI.OpenAI" Version="1.0.0-beta.*" />

<!-- Nachher -->
<PackageReference Include="Azure.AI.OpenAI" Version="2.*" />

Das ist die Migration, die die meisten betrifft. Die gesamte API-Oberfläche hat sich geändert — Client-Konfiguration, Message-Typen, Response-Handling. Plant einen halben bis ganzen Tag pro Service ein, der das SDK nutzt.

2. Azure.AI.Inference → OpenAI NuGet-Paket

Deadline: 30. Mai 2026 (offiziell angekündigt)

<!-- Vorher -->
<PackageReference Include="Azure.AI.Inference" Version="*" />

<!-- Nachher -->
<PackageReference Include="OpenAI" Version="2.*" />

Azure.AI.Inference wird komplett eingestellt. Die Funktionalität geht in das Standard-OpenAI-NuGet-Paket über. Azure-spezifische Funktionalität kommt über Azure.AI.OpenAI als Erweiterung dazu.

3. Azure.AI.Projects 1.x → 2.x

Deadline: Beim Wechsel zum neuen Foundry-Portal.

<!-- Vorher -->
<PackageReference Include="Azure.AI.Projects" Version="1.0.0-beta.*" />

<!-- Nachher -->
<PackageReference Include="Azure.AI.Projects" Version="2.0.0-beta.*" />

Version 1.x zielt auf das Classic-Portal, 2.x auf das neue Foundry-Portal. Die 2.x-Linie bringt massive Breaking Changes mit: AIDeployment wird zu AssetDeployment, der AIProjectClient-Konstruktor unterstützt AuthenticationTokenProvider, und der GetOpenAIClient-Zugang wurde konsolidiert. Hier muss man die Solution einmal komplett durchgehen.

4. Azure.AI.Agents.Persistent → Responses API Patterns

Deadline: August 2026 (Assistants API Sunset)

Das Agent-SDK entwickelt sich aktiv weiter. Die aktuellen Beta-Versionen bringen Streaming MCP Tool-Support, AOT-Kompatibilität und Delta-Tool-Call-Modelle. Wer Agents nutzt, muss seinen Code auf die Responses API umstellen — dazu gleich mehr.

5. Azure.Identity → aktualisieren auf 1.16+

Deadline: So bald wie möglich.

<!-- Aktualisieren auf -->
<PackageReference Include="Azure.Identity" Version="1.16.*" />

Die neuen Versionen bringen verbesserte Claims-Challenge-Exceptions, reduzierten Probe-Traffic mit Managed Identity und Custom-Environment-Variable-Konstruktoren. Da DefaultAzureCredential jetzt der Standard für die Authentifizierung ist, will man hier unbedingt auf dem neuesten Stand sein.

Von der Assistants API zur Responses API

Das ist die Migration, die am meisten Arbeit macht — besonders für alle, die Agents mit Threads, Runs und Messages gebaut haben.

Die Konzepte mappen wie folgt:

Assistants API (alt)Responses API (neu)Anmerkung
Assistants / AgentsAgent VersionsVersioniert, mit explizitem kind
ThreadsConversationsSpeichern Items, nicht nur Messages
MessagesItemsItems sind eine Obermenge von Messages
Runs (async, gepollt)Responses (sync per Default)Kein Polling-Loop mehr nötig
create_agent()create_version()Nutzt PromptAgentDefinition

Was das in der Praxis bedeutet

Der größte Gewinn: Kein Polling mehr. Die Assistants API erforderte es, einen Run zu starten und dann in einer Schleife zu pollen, bis er fertig war. Wer das mal in Produktion hatte, kennt die Probleme — Race Conditions, Timeouts, verschluckte Fehler. Die Responses API ist synchron per Default. Man schickt eine Anfrage und bekommt eine Antwort.

Konzeptionell denkt man nicht mehr in “Ich erstelle einen Assistant, öffne einen Thread, sende eine Message, starte einen Run und warte auf das Ergebnis.” Stattdessen: “Ich erstelle eine Agent Version, arbeite mit Conversations und Items, und bekomme Responses.”

Conversations sind dabei mächtiger als die alten Threads — sie speichern nicht nur Nachrichten, sondern auch Tool-Aufrufe, Tool-Outputs und andere Interaktionen als Items.

Für bestehenden Agent-Code

  1. Polling-Loops entfernen — die Responses API ist synchron
  2. Thread-Management ersetzen durch Conversations
  3. Message-Handling umstellen auf Items (die mehr als nur Text enthalten können)
  4. create_agent() ersetzen durch create_version() mit PromptAgentDefinition
  5. Region prüfen — die Responses API ist nicht in allen Azure-Regionen verfügbar

Punkt 5 wird gerne übersehen: Wenn eure Foundry Resource in einer Region liegt, die die Responses API nicht unterstützt, müsst ihr eine neue Resource in einer unterstützten Region erstellen. Prüft das vor der Migration, nicht hinterher.

Mein Migrationsfahrplan

Wer jetzt startet, hat genug Zeit. Wer wartet, bekommt Zeitdruck. Hier ist mein empfohlener Ablauf:

  1. Sofort: Azure.AI.OpenAI von 1.0 Beta auf 2.x aktualisieren. Das ist die Basis für alles andere.
  2. Q1 2026: Azure.AI.Inference durch das OpenAI-NuGet-Paket ersetzen. Deadline Mai 2026 — aber lieber früher als später.
  3. Q1 2026: Azure.AI.Projects auf 2.x aktualisieren, wenn ihr zum neuen Foundry-Portal wechselt.
  4. Q2 2026: Agent-Code von Assistants API auf Responses API migrieren. Deadline August 2026, aber das ist die aufwändigste Migration.
  5. Laufend: Azure.Identity und Azure.Core aktuell halten.

Die SDK-Landschaft stabilisiert sich gerade. Die REST API unter /openai/v1/ hat GA erreicht, die SDK-Pakete werden folgen. Je früher man migriert, desto weniger technische Schulden akkumuliert man — und desto weniger Überraschungen gibt es, wenn die Deadlines näher rücken.

Wer bis Mai 2026 wartet und dann merkt, dass die Migration seines Agent-Codes auch noch ansteht — der hat ein Problem. Fangt jetzt an.


Weiterführende Ressourcen:

Read the original on gingter.org

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.