SelfRefine
from loomflow.architecture import SelfRefineIterative refinement via self-critique. Madaan et al. 2023 , Self-Refine: Iterative Refinement with Self-Feedback. The same model plays generator, critic, and refiner across rounds.
For the conceptual page see Self-Refine.
Class signature
class SelfRefine:
name: str = "self-refine"
def __init__(
self,
*,
base: Architecture | None = None,
max_rounds: int = 3,
critic_prompt: str | None = None,
refiner_prompt: str | None = None,
stop_phrase: str = "no issues",
) -> None: ...Constructor parameters
base
| Type | Architecture | None |
| Default | None (resolves to ReAct()) |
The architecture used for round 0 (initial generation). Defaults to
ReAct. Pass another architecture to compose, SelfRefine(base=PlanAndExecute(...))
generates with PlanAndExecute then refines with the critic. See
Recursive composition.
max_rounds
| Type | int |
| Default | 3 |
Maximum refinement rounds (after the initial generation). Each round
is one critic call + one refiner call. Must be >= 1.
critic_prompt
| Type | str | None |
| Default | None (uses built-in default) |
Override the critic’s system prompt. The default reviews the current
output and produces a critique; if the critique contains
stop_phrase, the loop terminates.
refiner_prompt
| Type | str | None |
| Default | None (uses built-in default) |
Override the refiner’s system prompt. The default takes the current output + the critique and produces a revised output.
stop_phrase
| Type | str |
| Default | "no issues" |
Substring (case-insensitive) the critic emits when it considers the
output good enough. Customize for non-English critics or different
output rubrics. Termination is keyword-based. For numeric-score
gating, use ActorCritic.
Methods
declared_workers
Returns {}. Single-agent (the base architecture’s workers, if any,
are reflected through the base’s own declared_workers).
run
- Round 0 (generator). Run
base.run(session, deps, prompt)to produce an initial output. If the base interrupts itself (max_turns, budget), terminate without refining. Refining a partial result would waste tokens. - Refinement rounds (1..max_rounds):
- Budget check. Block / warn as needed.
- Critic. One model call against the current output.
Terminate if the critique contains
stop_phrase. - Refiner. One model call producing a revised output. Replaces the current output.
Cost model
For an N-round refinement: base + 2 × (rounds_actually_run) LLM
calls. A base=ReAct() with max_rounds=3 is roughly 2–3× a single
ReAct run.
When to use ActorCritic instead
When the same model has the same blind spots as critic and generator,
gains plateau quickly. For asymmetric blind-spot coverage (different
prompts, ideally different models), use
ActorCritic. Actor and
critic are distinct Agent instances, possibly on different model
providers.
Example
from loomflow import Agent
from loomflow.architecture import SelfRefine
agent = Agent(
"Write a tight 3-paragraph product brief.",
model="claude-opus-4-7",
architecture=SelfRefine(max_rounds=3),
)
result = await agent.run("Brief about Acme Corp.")Or by string:
agent = Agent("...", model="...", architecture="self-refine")Wrapping a planner:
from loomflow.architecture import PlanAndExecute, SelfRefine
agent = Agent(
"...",
model="claude-opus-4-7",
architecture=SelfRefine(
base=PlanAndExecute(max_steps=5),
max_rounds=2,
),
)Source
loomflow/architecture/self_refine.py
Threshold via stop phrase, not score. SelfRefine’s critic emits
free-form text; termination is keyword-based. For numeric-score
gating (score ≥ threshold), use
ActorCritic which returns
structured JSON {score, issues, summary}.