Writer + critic
Un writer hace draft, un critic encuentra problemas específicos, y el writer reescribe para arreglarlos — se muestran las tres etapas. La mejora que aporta el paso de crítica es el argumento a favor de roles enfocados por encima de un solo prompt que lo hace todo.
Showcase — Writer + critic
Un writer hace draft, un critic encuentra problemas específicos, y el writer reescribe para arreglarlos — se muestran las tres etapas. La mejora que aporta el paso de crítica es el argumento a favor de roles enfocados por encima de un solo prompt que lo hace todo.
Córrelo
bash bootstrap-secrets.sh # reads ../../../../.env, writes secrets/
docker compose up --build # default: PROVIDER=openai
Abre http://localhost:3000. Gemini: PROVIDER=gemini docker compose up --build.
Qué hay aquí
backend/ai_openai.py/backend/ai_gemini.py— system prompts del writer + critic, compuestos en Python.frontend/app/page.tsx— caja de tema; final, crítica y draft.
Detenlo
docker compose down
Ejecútalo en tu máquina
Descarga el proyecto como ZIP y córrelo con Docker. Levanta un backend FastAPI y un frontend Next.js en localhost:3000.
unzip writer-critic.zip
cd writer-critic
bash bootstrap-secrets.sh # one-time: pulls API keys into ./secrets
docker compose up --build # default provider: openai
# or: PROVIDER=gemini docker compose up --build
Escribe algo, elige un proveedor y ejecuta el mismo código de Código contra la API real. Requiere iniciar sesión.
Los mismos módulos que ejecuta el botón Run. El proyecto completo (frontend, Dockerfile, compose) está en el ZIP, pestaña README.
backend/ai_openai.py
"""Showcase 1 (OpenAI): a writer/critic pipeline.
Three roles, one output: a writer drafts an explanation, a critic finds specific
problems, the writer rewrites to fix them. You see all three stages, so the
improvement from the critique pass is visible — which is the argument for
splitting the work across focused agents instead of one do-everything prompt.
"""
from openai import OpenAI
_client = OpenAI()
_MODEL = "gpt-5.4-nano"
_WRITER = "You are a concise technical writer. Write a short, clear explanation for a beginner."
_CRITIC = ("You are a sharp editor. List 2-3 specific, actionable problems with the draft "
"(accuracy, clarity, or missing context). If it's already excellent, say so briefly.")
def _agent(system: str, user: str) -> str:
return _client.responses.create(model=_MODEL, instructions=system, input=[{"role": "user", "content": user}]).output_text
def run(task: str) -> str:
t = task.strip()
if not t:
return "Give a topic to explain (e.g. 'explain what an API is')."
draft = _agent(_WRITER, t)
critique = _agent(_CRITIC, f"TASK: {t}\n\nDRAFT:\n{draft}")
final = _agent(_WRITER, f"TASK: {t}\n\nYour draft was critiqued:\n{critique}\n\nRewrite it, fixing every issue.")
return f"FINAL:\n{final}\n\n--- critique that shaped it ---\n{critique}\n\n--- first draft ---\n{draft}"
backend/ai_gemini.py
"""Showcase 1 (Gemini): a writer/critic pipeline.
Same three-stage draft/critique/revise, on Gemini.
"""
import os
from google import genai
from google.genai import types
_client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
_MODEL = "gemini-3.1-flash-lite"
_WRITER = "You are a concise technical writer. Write a short, clear explanation for a beginner."
_CRITIC = ("You are a sharp editor. List 2-3 specific, actionable problems with the draft "
"(accuracy, clarity, or missing context). If it's already excellent, say so briefly.")
def _agent(system: str, user: str) -> str:
r = _client.models.generate_content(
model=_MODEL,
contents=[types.Content(role="user", parts=[types.Part(text=user)])],
config=types.GenerateContentConfig(system_instruction=system),
)
return r.text or ""
def run(task: str) -> str:
t = task.strip()
if not t:
return "Give a topic to explain (e.g. 'explain what an API is')."
draft = _agent(_WRITER, t)
critique = _agent(_CRITIC, f"TASK: {t}\n\nDRAFT:\n{draft}")
final = _agent(_WRITER, f"TASK: {t}\n\nYour draft was critiqued:\n{critique}\n\nRewrite it, fixing every issue.")
return f"FINAL:\n{final}\n\n--- critique that shaped it ---\n{critique}\n\n--- first draft ---\n{draft}"
Archivos del proyecto
.gitignoreREADME.es.mdREADME.mdbackend/Dockerfilebackend/ai_gemini.pybackend/ai_openai.pybackend/main.pybackend/requirements.txtbootstrap-secrets.shdocker-compose.ymlfrontend/Dockerfilefrontend/app/layout.tsxfrontend/app/page.tsxfrontend/next.config.tsfrontend/package.jsonfrontend/tsconfig.json