A Guide to OpenAI and Microsoft Agent Framework in .NET
This article demonstrates how to securely handle your OpenAI API Key and use it within a .NET 10 console application to break down complex human tasks into actionable steps — using the Microsoft Agent Framework (Microsoft.Agents.AI).
1. The Security Layer: Windows Environment Variables
Before writing code, you must store your API key in a location that is not tracked by version control systems like Git. On Windows, the most effective way is using Environment Variables.
How to set the variable
- Open PowerShell or Command Prompt.
- Run the following command (replace the placeholder with your actual key):
- Crucial Step: Restart your IDE (Visual Studio, Rider, or VS Code) after running this command. Applications only "see" new environment variables when they are first launched.
2. Project Setup
Create a new .NET 10 console application and add the required NuGet packages:
Your .csproj should look like this:
Key Packages
| Package | Purpose |
|---|---|
Microsoft.Agents.AI | The Microsoft Agent Framework — provides ChatClientAgent, ChatClientAgentOptions, and the AsAIAgent() extension method. |
Microsoft.Extensions.AI.OpenAI | Bridges the OpenAI SDK with the IChatClient abstraction from Microsoft.Extensions.AI. |
3. The Implementation: Task Decomposition with the Agent Framework
In this example, we create a ChatClientAgent named "TaskOrganizer." The goal is to take a complex request — like preparing breakfast — and have the AI generate a sequence of simple instructions.
The .NET Code
Step-by-Step Breakdown
Step 1 — Retrieve the API Key securely.
The key is read from a Windows environment variable using Environment.GetEnvironmentVariable. This keeps secrets out of source code and version control.
Step 2 — Create an IChatClient.
The OpenAIClient from the official OpenAI SDK is used to get a ChatClient for the gpt-4o model. The .AsIChatClient() extension method (from Microsoft.Extensions.AI.OpenAI) wraps it into the vendor-neutral IChatClient abstraction.
Step 3 — Build a ChatClientAgent.
The .AsAIAgent() extension method (from Microsoft.Agents.AI) transforms the IChatClient into a full agent. The ChatClientAgentOptions configures:
Name— A logical name for the agent.Description— What the agent does (useful in multi-agent scenarios).ChatOptions.Instructions— The system prompt that defines the agent's behavior. This is the equivalent of the "system message" in a chat completion call.
Step 4 — Run the agent.
agent.RunAsync(string message) sends a user message to the agent. The agent automatically prepends its system instructions and calls the underlying IChatClient. The result is an AgentResponse with a .Text property containing the AI's response.
4. Troubleshooting: Why is the Key Returning Null?
If you run the code and see the "Please set the environment variable" message, check these three common issues:
- The Typo Trap: Ensure the string in
Environment.GetEnvironmentVariable("OPEN_AI_KEY")matches your Windows variable name exactly. If you saved it asOPENAI_API_KEYin Windows but called itOPEN_AI_KEYin C#, it will returnnull. - The Restart Requirement: If you added the variable while your IDE was open, the IDE is still running on the "old" environment state. Restart the IDE completely.
- Scope Issues: Ensure you added it to User Variables (specific to you) rather than System Variables if you don't have Administrator rights.
5. Why Use the Microsoft Agent Framework?
While you could use a raw IChatClient or even a plain HttpClient to call OpenAI, the Microsoft Agent Framework provides several professional advantages:
| Advantage | Description |
|---|---|
| Abstraction | The IChatClient interface lets you swap between OpenAI, Azure OpenAI, or any other provider without changing your agent logic. |
| Agent Identity | Each agent has a Name, Description, and Instructions — making it a first-class, reusable component rather than a one-off prompt call. |
| Separation of Concerns | System instructions (agent behavior) are decoupled from user messages. The same TaskOrganizer agent can handle any task without modifying the prompt. |
| Built-in Tool Calling | ChatClientAgent supports automatic function invocation, allowing agents to call your C# methods as tools. |
| Composability | Agents can be wrapped with logging (UseLogging), OpenTelemetry (UseOpenTelemetry), or custom middleware via the AIAgentBuilder pipeline. |
| Multi-Agent Ready | Any agent can be exposed as an AIFunction via .AsAIFunction(), enabling orchestration scenarios where agents delegate work to each other. |
6. Semantic Kernel vs. Microsoft Agent Framework
For those familiar with Semantic Kernel, here is a quick comparison:
| Aspect | Semantic Kernel | Microsoft Agent Framework |
|---|---|---|
| Chat service | OpenAIChatCompletionService | IChatClient via Microsoft.Extensions.AI |
| System prompt | Embedded in the prompt string | ChatOptions.Instructions (structured) |
| Invocation | GetChatMessageContentAsync(prompt) | agent.RunAsync(message) |
| Agent concept | Kernel + plugins | ChatClientAgent with options |
| Tool calling | Kernel functions / plugins | AIFunction + automatic invocation |
| Middleware | Filters | AIAgentBuilder pipeline (UseLogging, UseOpenTelemetry) |
| Multi-agent | Semantic Kernel Agent Framework | .AsAIFunction() composition |
The Microsoft Agent Framework builds on the Microsoft.Extensions.AI abstractions — the same abstractions that the broader .NET ecosystem is converging on — giving you a clean, composable, and vendor-neutral foundation for building AI agents.