Critic agent should optionally read the style guide to avoid degrading aesthetics across rounds
Observation
When running the demo_full (or demo_planner_critic) pipeline with multiple Critic rounds, the first-round image is consistently the most visually coherent, and successive Critic rounds progressively degrade the aesthetic — re-rendered images become more cluttered, lose colour discipline, and drift away from the Stylist's choices.
Setting --max_critic_rounds=0 (or 1) and skipping the Critic gives the best output for many use cases. This suggests the issue isn't the Critic per se but a missing input to it.
Diagnosis
The Stylist agent (agents/stylist_agent.py) and Polish agent (agents/polish_agent.py) both load style_guides/{prefix}_{task}_style_guide.md and feed it to their model calls. The Critic agent (agents/critic_agent.py) does not — it only sees the raw content + caption + image and is prompted to identify fidelity gaps ("which named components are missing or wrong in the rendered figure?").
This means:
- The Stylist makes deliberate aesthetic choices guided by the style guide (palette, typography, shape language, whitespace, illustration register).
- The Critic, blind to those choices, flags every named-but-not-prominent component as a fidelity violation and asks the Visualizer to add it back.
- The Visualizer's revision is applied destructively and erodes the aesthetic the Stylist set up.
- After 2–3 rounds the figure is "more faithful" by the Critic's metric but visibly worse by the Stylist's.
Reproducible test
- Generate a figure in
demo_fullmode withmax_critic_rounds=3. - Inspect the per-round images saved to disk:
target_{task}_stylist_desc0_base64_jpg(round 0, post-Stylist) vs.target_{task}_critic_desc0_base64_jpg,target_{task}_critic_desc1_base64_jpg, etc. - The post-Stylist image is typically cleaner and more on-brand than the post-Critic ones, especially for icon-rich diagrams or editorial-style illustrations where label density should be intentionally low.
Proposed fix
Have the Critic load the same style guide the Stylist did and prepend it to the system prompt. The Critic's job description shifts from "find fidelity gaps" to "find fidelity gaps that don't break the style guide" — its suggestions reinforce the Stylist's choices instead of fighting them.
Concrete sketch (mirrors the existing pattern in agents/stylist_agent.py:62):
# agents/critic_agent.py
import os
...
class CriticAgent(BaseAgent):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.model_name = self.exp_config.main_model_name
style_prefix = os.environ.get("PAPERBANANA_STYLE_GUIDE_PREFIX", "neurips2025")
task = "plot" if self.exp_config.task_name == "plot" else "diagram"
guide_path = self.exp_config.work_dir / f"style_guides/{style_prefix}_{task}_style_guide.md"
try:
with open(guide_path, "r", encoding="utf-8") as f:
self.style_guide = f.read()
except FileNotFoundError:
self.style_guide = ""
...Then include self.style_guide in the user prompt the Critic sends to the model, with instructions like:
Before suggesting changes, verify each suggestion would not violate the style guide below. If a fidelity gap can only be closed by violating the style guide (e.g., by adding more text labels than the guide allows), prefer to leave the figure as-is.
Why this is worth doing upstream
- It's a small, contained change (one agent, ~30 lines) that doesn't break the existing API.
- The Critic-vs-Stylist conflict is structural — anyone using
demo_fullwith non-default style guides will hit it. - It removes a class of "the Critic made my figure worse" complaints that currently can only be worked around by lowering
max_critic_roundsto 0–1. - Optional: gate it behind a flag (
--critic-uses-style-guide) for backwards compatibility.
Adjacent observations
While digging into this, two other small things in the same area:
- The Streamlit UI in
demo.pyhasmin_value=1on the Max Critic Rounds input, which prevents users from setting it to 0 even though the pipeline supports it (for round_idx in range(max_rounds)withmax_rounds=0is a clean no-op). Lowering the min would give users an immediate workaround. - The Critic loop has no quality regression check — it only rolls back if the Visualizer fails to return an image (
utils/paperviz_processor.py:88-97). It assumes monotonic improvement across rounds, which the above issue undermines. A "did the new image actually score better than the previous?" gate (using e.g. CLIP similarity to the Stylist's first render or a separate VLM eval) would let the loop self-correct.
Happy to send a PR for the style guide change if helpful — let me know if the maintainers would prefer a particular approach (always-on vs. flag-gated, prompt wording, etc.) before I start.
Source: dwzhu-pku/PaperBanana