Reflexion admin
ReflexionAdmin<TInput, TOutput> runs an actor-critic loop. The actor
produces an output. The critic evaluates it. If the critic approves,
the actor's output is the result. If not, the actor retries with the
critic's feedback, until MaxIterations is hit.
Example — write, review, revise
using LogicGrid.Core.Admins;
using LogicGrid.Core.Agents;
using LogicGrid.Core.Llm;
var llm = LlmClientBase.Ollama("llama3.2");
IAgent actor = new Agent<string>(
name: "Actor",
description: "Writes the answer.",
systemPrompt: "Write a 100-word product description for the input. " +
"If feedback is provided, revise based on it.",
llm: llm);
IAgent critic = new Agent<string>(
name: "Critic",
description: "Reviews and approves or rejects.",
systemPrompt: "Review the description for clarity, accuracy, and persuasiveness.",
llm: llm);
var admin = new ReflexionAdmin<string, string>(
name: "ProductCopy",
llmClient: llm,
actor: actor,
critic: critic,
options: new ReflexionOptions { MaxIterations = 3 });
var ctx = new AgentContext().WithLogging();
var copy = await admin.RunAsync(
"A noise-cancelling travel pillow that supports the chin while seated.");
Console.WriteLine($"\n{copy}");
09:42:01.118 [INF] [e9f1c422] Run started — admin: ProductCopy | task: A noise-cancelling travel pillow …
09:42:04.318 [INF] [e9f1c422] [Actor] completed | output: Travel calmer with our noise-cancelling … | 3200ms | 188 tokens
09:42:06.402 [INF] [e9f1c422] [Critic] completed | output: REVISION NEEDED: mention the chin support more prominently. | 2084ms | 88 tokens
09:42:06.420 [INF] [e9f1c422] Reflexion iter 1 — revise | feedback: mention the chin support more prominently.
09:42:09.802 [INF] [e9f1c422] [Actor] completed | output: Designed for upright sleep, our travel pillow cradles the chin … | 3382ms | 192 tokens
09:42:11.901 [INF] [e9f1c422] [Critic] completed | output: APPROVED. | 2099ms | 12 tokens
09:42:11.910 [INF] [e9f1c422] Reflexion iter 2 — approved | feedback: APPROVED.
09:42:11.911 [INF] [e9f1c422] Run completed — 4 agents, 4 LLM calls | 10793ms
Notice the critic's system prompt is just "review for clarity,
accuracy, and persuasiveness" — it doesn't mention APPROVED or
REVISION NEEDED: anywhere. The framework appends a small protocol
trailer to every critic prompt so the LLM knows which tokens to
emit, freeing the user prompt to focus on the review logic.
If you ever need to change the protocol — translate it, swap the
keywords, or strip it entirely (for example, when wiring a custom
CriticPromptBuilder that already encodes its own approval
contract) — set ReflexionOptions.CriticInstructionsTrailer to your
own string (or null / empty to disable).
Constructors
public ReflexionAdmin(
string name,
LlmClientBase llmClient,
IAgent actor,
IAgent critic,
ReflexionOptions? options = null,
IAgentEventBus? eventBus = null)
public sealed class ReflexionOptions
{
public int MaxIterations { get; set; } = 3;
public decimal? MaxBudgetUsd { get; set; }
public float BudgetWarningThreshold { get; set; } = 0.8f;
public LlmOptions LlmOptions { get; set; } = new LlmOptions();
public string? CriticInstructionsTrailer { get; set; } = /* default protocol */;
public Func<string, string, int, string>? CriticPromptBuilder { get; set; }
public Func<string, string, string, string>? RetryPromptBuilder { get; set; }
}
ReflexionAdmin takes ReflexionOptions rather than AdminOptions
because it adds reflexion-specific settings — MaxIterations and the
two prompt-builder callbacks. The shared budget/LLM fields are
mirrored on ReflexionOptions so the admin can configure them
internally; you don't need to pass an AdminOptions separately.
Events
| Event | Fired when |
|---|---|
ReflexionIterationEvent | After every actor → critic round. Carries Iteration, Approved, CriticFeedback. |
ReflexionExhaustedEvent | The loop reached MaxIterations without the critic ever approving. Carries the last actor output and last critic feedback. The admin still returns the last output — subscribe to this event when you need to flag it for human review or downgrade downstream confidence. |
Use it when
- The output benefits from a second pair of eyes — drafts that need a reviewer, code that needs a linter, plans that need a sanity check.
- You want automatic revision loops without writing the loop yourself.
Don't use it when
- A single-shot answer is good enough.
- The critique is rule-based and doesn't need an LLM — write a normal
validator and use
AgentBase<T>.ValidateOutput. See OverridingAgentBase<T>.
Common pitfalls
- Critic never approves. If the critic's prompt is vague,
every output will trigger another revision until
MaxIterationsexhausts. Make the approve criteria explicit and bounded. - Cost grows linearly per iteration. 3 iterations = up to 6 LLM
calls. Set
MaxBudgetUsdfor hosted models. - Custom
CriticPromptBuilderwithout the trailer. The default trailer (seeReflexionOptions.CriticInstructionsTrailer) is what teaches the LLM to emitAPPROVEDorREVISION NEEDED:. It's appended to whatever your custom builder returns, so by default the protocol is preserved. If you setCriticInstructionsTrailertonullor empty, your custom builder must include equivalent instructions or the loop will misbehave (typically: critic never approves and the loop runs toMaxIterations).