Problema (el “cambio pequeño” que te cuesta una semana)
Tocas un prompt porque el agente suena raro.
En dev parece bien.
En producción:
- tool calls/run suben poco a poco (nadie mira)
- la latencia se duplica con carga
- el agente empieza a ignorar stop conditions
- un edge case raro se vuelve un incidente diario
Optimizar prompts es ingeniería, no copywriting. Si lo tratas como “edito texto hasta que suene mejor”, vas a shippear regresiones.
Por qué esto falla en producción
En prod, un prompt está pegado a:
- schemas de tools (renombras un campo y el modelo se pierde)
- budgets (inflación de tokens = loops caros)
- stop reasons (sin querer, incentivas “un intento más”)
- variación externa (search cambia, APIs flaky, rate limits)
La parte incómoda: no puedes optimizar prompts de forma segura sin un harness. No tiene que ser fancy. Tiene que ser consistente.
Diagrama: pipeline seguro de prompts
Código real: versiona prompts como código (Python + JS)
Mínimo viable:
- cada prompt tiene una
prompt_idestable (hash o versión) - cada run loguea
prompt_id - rollback = un switch de config
import hashlib
from dataclasses import dataclass
from typing import Any, Dict
def prompt_id(text: str) -> str:
return hashlib.sha256(text.encode("utf-8")).hexdigest()[:12]
@dataclass(frozen=True)
class Prompt:
name: str
version: str
text: str
@property
def id(self) -> str:
return f"{self.name}:{self.version}:{prompt_id(self.text)}"
class Logger:
def event(self, name: str, fields: Dict[str, Any]) -> None: ...
def build_system_prompt(p: Prompt) -> str:
return (
"You are a production agent. You must follow tool policies and budgets.\n"
"Always stop with a stop_reason.\n\n"
f"[prompt_id={p.id}]\n"
+ p.text.strip()
)
def run_agent(task: str, *, prompt: Prompt, logger: Logger, budgets: Dict[str, Any]) -> Dict[str, Any]:
build_system_prompt(prompt)
logger.event("agent_start", {"prompt_id": prompt.id, "budget": budgets})
return {"output": "ok", "prompt_id": prompt.id, "stop_reason": "finish"}
PROMPTS = {
"support:v12": Prompt("support", "v12", "Answer using KB. If unsure, ask a clarifying question."),
"support:v13": Prompt("support", "v13", "Answer using KB. Cite tool results. If unsure, ask a clarifying question."),
}
ACTIVE_PROMPT = PROMPTS["support:v13"]import crypto from "node:crypto";
export function promptId(text) {
return crypto.createHash("sha256").update(text, "utf8").digest("hex").slice(0, 12);
}
export function makePrompt({ name, version, text }) {
const id = `${name}:${version}:${promptId(text)}`;
return { name, version, text, id };
}
export function buildSystemPrompt(prompt) {
return [
"You are a production agent. You must follow tool policies and budgets.",
"Always stop with a stop_reason.",
"",
"[prompt_id=" + prompt.id + "]",
prompt.text.trim(),
].join("\n");
}
export function runAgent(task, { prompt, logger, budgets }) {
buildSystemPrompt(prompt);
logger.event("agent_start", { prompt_id: prompt.id, budget: budgets });
return { output: "ok", prompt_id: prompt.id, stop_reason: "finish" };
}
const PROMPTS = {
"support:v12": makePrompt({ name: "support", version: "v12", text: "Answer using KB. If unsure, ask a clarifying question." }),
"support:v13": makePrompt({ name: "support", version: "v13", text: "Answer using KB. Cite tool results. If unsure, ask a clarifying question." }),
};
const ACTIVE_PROMPT = PROMPTS["support:v13"];Fallo real (con números)
“Mejoramos” un prompt de soporte añadiendo una instrucción larga de “sé exhaustivo”.
Nada crasheó. Pero el modelo hizo lo que pedimos: se volvió exhaustivo.
Impacto en 36h:
- p95 tokens/run: 7.5k → 14.2k
- avg tool calls/run: 4 → 11
- spend: +$620
- on-call: ~2h para demostrar que era el prompt
Arreglo:
- capear budgets (steps/tool calls/tokens)
- invariantes en golden tasks: max tool calls + max tokens por run
- hacer “exhaustivo” condicional (solo si falta un tool result)
Trade-offs
- Mejor calidad suele costar más. Si no lo mides, lo pagas.
- Prompts cortos son rápidos pero a veces inseguros.
- Contratos explícitos son feos y sobrevivibles.
Cuándo NO optimizar prompts
No intentes “optimizar” para tapar:
- budgets inexistentes (
/es/governance/budget-controls) - validación de tools (
/es/tools/input-validation) - logging (
/es/observability-monitoring/agent-logging) - tests (
/es/testing-evaluation/unit-testing-agents)
Si el agente es inestable, los cambios de prompt solo mueven el problema.
Checklist (copy-paste)
- [ ]
prompt_idestable en cada run - [ ] Golden tasks (10–50) del tráfico real
- [ ] Invariantes: stop_reason, bound de tool_calls, bound de tokens
- [ ] Canary rollout + rollback switch
- [ ] Monitor: spend/run, tool_calls/run, latency/run
- [ ] 1 golden task por incidente
Config segura por defecto (YAML)
prompts:
active: "support:v13"
rollback: "support:v12"
require_prompt_id: true
testing:
golden_tasks:
- id: "kb_lookup"
expect_stop_reason: "finish"
max_tool_calls: 6
max_tokens: 9000
budgets:
max_steps: 25
max_tool_calls: 12
max_seconds: 60
observability:
log_prompt_id: true
alert_on_token_spike: true
Implementar en OnceOnly (opcional)
# onceonly-python: budgets + safe rollout guardrails
import os
from onceonly import OnceOnly
client = OnceOnly(api_key=os.environ["ONCEONLY_API_KEY"])
agent_id = "support-bot"
# Set budgets/limits before you ship prompt changes
client.gov.upsert_policy({
"agent_id": agent_id,
"max_actions_per_hour": 200,
"max_spend_usd_per_day": 50.0,
"max_calls_per_tool": {"kb.search": 6},
"allowed_tools": ["kb.search", "send_email"],
})
# After rollout, watch for spend/tool spikes
m = client.gov.agent_metrics(agent_id, period="day")
print("actions=", m.total_actions, "spend_usd=", m.total_spend_usd)
FAQ (3–5)
Usado por patrones
Fallos relacionados
- AI Agent Infinite Loop (Detectar + arreglar, con código)
- Explosión de presupuesto (cuando un agente quema dinero) + fixes + código
- Tool Spam Loops (fallo del agente + fixes + código)
- Incidentes de exceso de tokens (prompt bloat) + fixes + código
- Corrupción de respuestas de tools (schema drift + truncation) + código
Gobernanza requerida
Páginas relacionadas (3–6 links)
- Fundamentos: How agents use tools · Planning vs reactive agents
- Fallos: Hallucinated sources · Explosión de presupuesto
- Gobernanza: Budget controls · Tool permissions
- Observabilidad: Logging para agentes de IA
- Pruebas: Unit tests para agentes de IA