# Essay Refinement Loop -- Loop Agent

Demonstrates a LoopAgent that iterates sub-agents until a maximum
iteration count.  The scenario: an essay refinement workflow where
a critic evaluates the draft and a reviser improves it, repeating
up to 3 times until quality standards are met.

Real-world use case: Essay refinement loop where a writer drafts and a critic
provides feedback iteratively. Used by content teams to improve quality through
structured iteration.

In other frameworks: LangGraph models loops as conditional back-edges in a
StateGraph, requiring a routing function to decide continue vs stop (~25 lines).
adk-fluent uses * N for fixed iterations or * until() for conditional loops.

Pipeline topology:
    ( critic >> reviser ) * 3

:::{admonition} Why this matters
:class: important
Quality improvement is inherently iterative. First drafts need revision. Code needs review cycles. Research needs fact-checking rounds. The `* N` operator formalizes iteration as part of the pipeline topology, making the number of refinement cycles explicit, testable, and bounded. Content teams use this pattern to guarantee minimum quality standards before publishing.
:::

:::{warning} Without this
Without structured iteration, quality loops are unbounded -- agents either stop after one pass (producing mediocre output) or loop indefinitely (burning tokens and time). In native ADK, you need a separate `LoopAgent` class with manual `max_iterations` configuration. In adk-fluent, `(critic >> reviser) * 3` is a single expression that makes the iteration count part of the topology.
:::

:::{tip} What you'll learn
How to iterate agents in a loop using the * (repeat) operator.
:::

_Source: `06_loop_agent.py`_

::::{tab-set}
:::{tab-item} adk-fluent
```python
from adk_fluent import Agent, Loop

loop_fluent = (
    Loop("essay_refiner")
    .max_iterations(3)
    .step(
        Agent("critic")
        .model("gemini-2.5-flash")
        .instruct(
            "Evaluate the essay for clarity, structure, grammar, "
            "and argument strength. Provide specific, actionable "
            "feedback. If the essay meets a high quality bar, "
            "say APPROVED."
        )
    )
    .step(
        Agent("reviser")
        .model("gemini-2.5-flash")
        .instruct(
            "Revise the essay based on the critic's feedback. "
            "Improve clarity, fix grammatical issues, and strengthen "
            "weak arguments while preserving the author's voice."
        )
    )
    .build()
)
```
:::
:::{tab-item} Native ADK
```python
from google.adk.agents.llm_agent import LlmAgent
from google.adk.agents.loop_agent import LoopAgent

loop_native = LoopAgent(
    name="essay_refiner",
    max_iterations=3,
    sub_agents=[
        LlmAgent(
            name="critic",
            model="gemini-2.5-flash",
            instruction=(
                "Evaluate the essay for clarity, structure, grammar, "
                "and argument strength. Provide specific, actionable "
                "feedback. If the essay meets a high quality bar, "
                "say APPROVED."
            ),
        ),
        LlmAgent(
            name="reviser",
            model="gemini-2.5-flash",
            instruction=(
                "Revise the essay based on the critic's feedback. "
                "Improve clarity, fix grammatical issues, and strengthen "
                "weak arguments while preserving the author's voice."
            ),
        ),
    ],
)
```
:::
:::{tab-item} Architecture
```mermaid
graph TD
    n1(("essay_refiner (loop x3)"))
    n2["critic"]
    n3["reviser"]
    n1 --> n2
    n1 --> n3
```
:::
::::

## Equivalence

```python
assert type(loop_native) == type(loop_fluent)
assert loop_fluent.max_iterations == 3
assert len(loop_fluent.sub_agents) == 2
assert loop_fluent.sub_agents[0].name == "critic"
assert loop_fluent.sub_agents[1].name == "reviser"
```

:::{seealso}
API reference: [Agent](../api/agent.md#builder-Agent)
:::
