Skip to Content
ArchitecturesReflexion

Reflexion

Reflexion retries a task and learns from its failures. After each attempt an evaluator scores the output; if the score is below the threshold, a reflector writes a one-sentence “lesson” (written advice) that the agent reads on its next attempt, and can keep for future runs. Use it for tasks with a checkable notion of success where repeated mistakes are the problem. From Shinn et al. 2023, Reflexion: Language Agents with Verbal Reinforcement Learning.

The reflector sees the attempt’s actions and observations (its tool calls and their results) as well as its output. An attempt that runs out of turns (the base’s max_turns) counts as a failed trial: it scores 0, and Reflexion reflects and retries while attempts remain. (Before 0.17 it ended the run.) A budget or guardrail stop still ends it.

Lesson storage modes

Two storage modes for the persisted lessons:

  • Monotonic block (the default). Every lesson is appended to memory.<lessons_block_name> and shown to the agent on every subsequent attempt. Simple, but every recent lesson is shown whether or not it applies to the task at hand.
  • Selective recall (recommended). Pass lesson_store= a VectorStore. Lessons are stored as embedded chunks; before each attempt, only the top-k most relevant lessons for the current task are retrieved and surfaced. Avoids context bloat and keeps tutorial advice scoped to where it applies.

Lessons quote the failing prompt, so they stay with their user: each lesson is tagged with the run’s user_id, and a run recalls only its own user’s lessons plus any tagged user_id="*" (SHARED_LESSON in loomflow.architecture.reflexion), which is how to seed curated lessons for everyone. Untagged lessons written by releases before 0.17 are no longer recalled. In the monotonic-block mode, lessons go to the run’s own memory block, one per line, and the block keeps the last max_lessons (default 10).

Usage

from loomflow import Agent, HashEmbedder from loomflow.architecture import Reflexion from loomflow.vectorstore import InMemoryVectorStore agent = Agent( "Solve the puzzle.", model="claude-opus-4-7", architecture=Reflexion( max_attempts=3, threshold=0.85, lesson_store=InMemoryVectorStore(embedder=HashEmbedder()), ), ) result = await agent.run("...")

For cross-session learning, swap InMemoryVectorStore for PostgresVectorStore and the lessons persist across processes.

Wrapping any base architecture

Reflexion(base=...) defaults to ReAct but accepts any architecture. The killer combination is Reflexion of Supervisor. The team learns across attempts which worker handles which intent best:

from loomflow import Agent from loomflow.architecture import Reflexion, Supervisor agent = Agent( "...", model="claude-opus-4-7", architecture=Reflexion( base=Supervisor(workers={"researcher": ..., "writer": ...}), max_attempts=3, threshold=0.85, lesson_store=InMemoryVectorStore(embedder=HashEmbedder()), ), )

See Recursive composition.

When Reflexion pays off

  • Tasks with a clear evaluator signal (test pass/fail, JSON schema match, factual correctness against ground truth).
  • Repeated runs of the same problem class. Lessons compound.
  • Worth roughly 1.5–3× ReAct cost; pays back when the alternative is shipping wrong answers to users.

Without an evaluator, Reflexion does nothing useful. The lesson generator only fires when evaluator(output) < threshold. Pass an evaluator that returns a meaningful score for your domain (test runner, regex match, structured-output validity, etc.).

Last updated on