What is the agent loop?

What is the agent loop?

Every agent demo looks like magic.

You ask a question, the agent reads a file, calls an API, and comes back with an answer, all on its own.

Strip the magic away and there’s one small mechanism doing the work: the agent loop.

In this article, I’ll walk through what the loop is and how the Microsoft Agent Framework runs it for you in .NET, so you never write it by hand.

What Actually Is the Agent Loop

A language model, on its own, does one thing: text in, text out. It doesn’t read your database or call your API. The agent loop is the code around the model that fixes that. It hands the model a set of tools, notices when the model wants one, runs it, and feeds the result back so the model can keep going, repeating until the task is done.

That’s the line between a chatbot and an agent. A chatbot reacts and stops. An agent loops: think, act, observe, repeat.

Conceptually, the loop is just this:

C#
				while (true)
{
    var response = await SendToLlmAsync(context, availableTools);

    if (response.ContainsToolCalls)
    {
        foreach (var call in response.ToolCalls)
            await ExecuteAsync(call); // execute each tool

        context.AppendResults(response); // append results to context
        continue;
    }

    if (response.IsDone)
        break;
}
			

Each pass does one of two things: if the model asked for tools, it runs them, appends the results to the context, and loops again; if the model says it’s done, it breaks out. And because every tool result is appended back, the loop builds on itself, which is also what eventually fills the context window.

The Loop in the Microsoft Agent Framework

The Microsoft Agent Framework hit version 1.0 (GA) on April 2, 2026, with stable APIs. Its default agent runs the loop internally, when the model calls a tool, the framework executes the matching C# method, appends the result, and re-invokes the model, no iteration code from you.

Worth saying up front: a single, known step doesn’t need an agent, that’s just a function call. The loop earns its cost when the path isn’t fixed, when the model has to choose and chain tools based on what each one returns. Here’s an example that actually justifies it: a support agent answering “where’s my order?”

				dotnet add package Microsoft.Agents.AI
dotnet add package Azure.AI.OpenAI
dotnet add package Azure.Identity
			
C#
				var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!;
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-5.4-mini";

// Three tools the model chains on its own — each just delegates to your service.
[Description("Gets a customer id from their email.")]
async Task<string> GetCustomerAsync([Description("The customer's email.")] string email)
    => await orders.GetCustomerIdAsync(email);

[Description("Gets the customer's most recent order id.")]
async Task<string> GetLatestOrderAsync([Description("The customer id.")] string customerId)
    => await orders.GetLatestOrderIdAsync(customerId);

[Description("Gets the shipping status of an order.")]
async Task<string> GetShippingStatusAsync([Description("The order id.")] string orderId)
    => await orders.GetShippingStatusAsync(orderId);

// AsAIAgent turns the chat client into an agent with the loop built in.
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetChatClient(deploymentName)
    .AsAIAgent(
        name: "SupportAgent",
        instructions: """
            You are a customer-support assistant. You help with orders, returns,
            billing, and general account questions. Use the available tools to look
            up real data instead of guessing, and keep answers short and clear.
            """,
        tools: [
            AIFunctionFactory.Create(GetCustomerAsync),
            AIFunctionFactory.Create(GetLatestOrderAsync),
            AIFunctionFactory.Create(GetShippingStatusAsync)
        ]);

// One call. The model chains all three tools inside the loop.
Console.WriteLine(await agent.RunAsync("What's the status of the latest order for ana@acme.com?"));
			

Here’s what runs inside that single call, and this time the loop genuinely loops: the model calls GetCustomerAsync, gets the id, then on the next pass calls GetLatestOrderAsync with it, then GetShippingStatusAsync with the order id, and only then has enough to answer. Each result is appended to the context, so every pass knows what the previous one found. You never coded that order, the model derived it from each result. That’s the part you can’t easily write by hand, and the reason it’s an agent and not a function.

AIFunctionFactory.Create reads the method signature and [Description] attributes to generate the tool schema automatically. You write a normal C# method, here each one just delegates to your service, which is exactly where your database query or external API lives.

Why the Loop Matters for Architecture

Three things to keep on your radar in production: the context window grows every iteration, so tool-heavy agents need a compaction strategy; stop conditions need limits (max iterations, a cancellation token) so a misbehaving agent doesn’t spin forever; and permissions / human-in-the-loop belong in the gap between “the model asked for a tool” and “run the tool”, a specific point in the loop, not a vague wrapper around it.

Final Thoughts

The agent loop is the cycle of think, act, append the result, repeat, until the task is done.

That’s the whole idea.

Everything that makes agents impressive comes down to that loop running cleanly, and in the Microsoft Agent Framework it’s one RunAsync away.

Share the Post:
plugins premium WordPress