Skip to Content

SelfRefine

from loomflow.architecture import SelfRefine

Iterative 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

TypeArchitecture | None
DefaultNone (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

Typeint
Default3

Maximum refinement rounds (after the initial generation). Each round is one critic call + one refiner call. Must be >= 1.

critic_prompt

Typestr | None
DefaultNone (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

Typestr | None
DefaultNone (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

Typestr
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

  1. 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.
  2. 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}.

Last updated on