Merk
Tilgang til denne siden krever autorisasjon. Du kan prøve å logge på eller endre kataloger.
Tilgang til denne siden krever autorisasjon. Du kan prøve å endre kataloger.
Agent looping re-invokes an agent until a completion condition is satisfied. Use it for iterative refinement, todo completion, waiting for background tasks, or evaluating whether an answer meets explicit criteria.
Always bound autonomous loops. A completion condition can fail, a model can stall, and an evaluator can be probabilistic.
Important
Agent looping is experimental.
Set up looping manually
Use the direct composition API when you want looping without the other Harness Agent defaults.
Import the loop types and wrap any AIAgent with LoopAgent. Its default maximum is 10 agent invocations:
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
AIAgent baseAgent = chatClient.AsAIAgent();
AIAgent agent = new LoopAgent(
baseAgent,
new CompletionMarkerLoopEvaluator("DONE"),
new LoopAgentOptions { MaxIterations = 5 });
Import AgentLoopMiddleware and add it to a regular Agent. The default maximum is 10 agent runs:
from agent_framework import Agent, AgentLoopMiddleware
def needs_more_work(*, last_result, **kwargs):
return "DONE" not in last_result.text
agent = Agent(
client=client,
middleware=[
AgentLoopMiddleware(
needs_more_work,
max_iterations=5,
)
],
)
The predicate can be synchronous or asynchronous. Return True to continue, False to stop, or (continue, feedback) to pass feedback to the next iteration.
Note
The packaged looping capability described on this page isn't currently available in Go.
Choose a completion condition
LoopAgent accepts one evaluator or an ordered collection:
| Evaluator | Continues while |
|---|---|
CompletionMarkerLoopEvaluator |
The latest response doesn't contain the configured marker. |
TodoCompletionLoopEvaluator |
A resolved TodoProvider still has incomplete items, optionally in selected agent modes. |
BackgroundTaskCompletionLoopEvaluator |
A resolved BackgroundAgentsProvider still has running tasks. |
AIJudgeLoopEvaluator |
A separate judge client says the original request isn't fully answered. |
DelegateLoopEvaluator |
Your callback returns LoopEvaluation.Continue(...). |
When multiple evaluators are configured, they run in order. The first evaluator that requests another iteration supplies its feedback; the loop stops only when all evaluators decline to continue.
Use an AI judge
The judge receives the original request and latest agent response. If it finds a gap, its analysis becomes feedback for the next iteration:
var evaluator = new AIJudgeLoopEvaluator(
judgeClient,
new AIJudgeLoopEvaluatorOptions
{
Criteria =
[
"Answer every part of the request.",
"Support conclusions with evidence.",
],
});
AIAgent loopAgent = new LoopAgent(
agent,
evaluator,
new LoopAgentOptions { MaxIterations = 4 });
Only use a judge endpoint you trust with the original request and generated response.
Control context and output
By default, LoopAgent reuses one session and sends the winning evaluator's latest feedback as the next input. FreshContextPerIteration = true instead rebuilds each pass from the original request plus an aggregated feedback log and resets or restores the session.
Non-streaming runs return an aggregated transcript by default. Set NonStreamingReturnsLastResponseOnly = true to return only the final response. Streaming always emits every iteration and any visible on-behalf-of feedback messages.
The predicate receives keyword arguments including iteration, last_result, messages, original_messages, session, agent, progress, and feedback. The helpers todos_remaining() and background_tasks_running() provide built-in todo and background-task conditions. Pair them with todos_remaining_message or background_tasks_running_message to generate a targeted next input.
Use an AI judge
AgentLoopMiddleware.with_judge builds a judge-driven loop. Judge loops default to five iterations:
from agent_framework import Agent, AgentLoopMiddleware
loop = AgentLoopMiddleware.with_judge(
judge_client,
criteria=[
"Answer every part of the request.",
"Support conclusions with evidence.",
],
max_iterations=4,
)
agent = Agent(
client=client,
middleware=[loop],
)
The judge's reasoning is fed back to the agent when more work is required. Only use a judge endpoint you trust with the original request and generated response.
Control context, progress, and output
For advanced loops, construct AgentLoopMiddleware directly:
record_feedbackcreates a concise progress entry after each work iteration.progressexposes accumulated entries to callbacks.inject_progress=Trueadds progress to the next iteration's input.fresh_context=Truerestarts from the original task and progress log and restores an attached session to its pre-loop snapshot.return_final_only=Truereturns only the last response for non-streaming runs.
Pass max_iterations=None only when the completion predicate is guaranteed to terminate.
The packaged completion conditions and judge integration described on this page aren't currently available in Go.
Use looping with Harness Agent
Use the Harness Agent setup when you also want its preconfigured history, planning, memory, approval, and observability pipeline.
Set HarnessAgentOptions.LoopEvaluators. The harness applies LoopAgent as its outermost agent decorator:
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
var options = new HarnessAgentOptions
{
LoopEvaluators =
[
new CompletionMarkerLoopEvaluator("DONE"),
],
LoopAgentOptions = new LoopAgentOptions
{
MaxIterations = 5,
},
};
HarnessAgent agent = chatClient.AsHarnessAgent(options);
// Equivalent construction: new HarnessAgent(chatClient, options)
AgentSession session = await agent.CreateSessionAsync();
An empty or null LoopEvaluators collection leaves the harness single-shot.
Approval and session behavior
LoopAgent stops before evaluating its completion condition when an iteration returns a pending tool-approval request. It returns the request to the caller instead of hiding it behind another autonomous iteration. After the caller supplies the approval response through the normal tool approval flow, the agent can continue.
LoopAgent doesn't add approval handling itself. The Harness Agent applies the loop outside ToolApprovalAgent, allowing pending approval requests to escape the loop.
Reuse the same AgentSession across calls to continue the conversation. Loop iterations share that session by default. With FreshContextPerIteration = true, LoopAgent resets or restores caller-supplied session state where supported. Service-owned conversation storage can retain history when the serialized session contains only a remote conversation identifier.
Supply loop_should_continue to create_harness_agent; loop_max_iterations defaults to 10:
from agent_framework import create_harness_agent
def needs_more_work(*, last_result, **kwargs):
return "DONE" not in last_result.text
agent = create_harness_agent(
client=client,
loop_should_continue=needs_more_work,
loop_max_iterations=5,
)
session = agent.create_session()
loop_next_message customizes the next input. With no loop_should_continue, the factory doesn't add a loop and ignores the other loop arguments.
Approval and session behavior
AgentLoopMiddleware stops before evaluating its continuation predicate when an iteration returns a pending tool-approval request. It returns the request to the caller instead of hiding it behind another autonomous iteration. After the caller supplies the approval response through the normal tool approval flow, the agent can continue.
AgentLoopMiddleware doesn't add ToolApprovalMiddleware itself. The Harness Agent places the loop outside its approval middleware, allowing pending approval requests to escape the loop. Create and pass an AgentSession on every Harness Agent run while tool auto-approval is enabled.
Reuse the same AgentSession across calls to continue the conversation. Loop iterations share that session by default. With fresh_context=True, the middleware restores the attached session to its pre-loop snapshot between iterations. Service-owned conversation storage can retain history when the serialized session contains only a remote conversation identifier.
Note
Harness Agent looping isn't currently available in Go, so its approval and session behavior doesn't apply.