Conceptos básicos de ingeniería de prompts y contexto
9 ejemplos para empezar con la ingeniería de prompts y contexto: 6 básicos y 3 intermedios.
Prerrequisitos
- Instala el SDK oficial:
pip install anthropic. - Configura tu clave API como variable de entorno:
export ANTHROPIC_API_KEY=sk-ant-.... - Todos los ejemplos usan
client.messages.create(...)del paquete Pythonanthropic.
Ejemplos básicos
1. El prompt ingenuo y voluminoso
El punto de partida que la mayoría de los equipos envían accidentalmente: pegar un archivo completo cuando solo importan unas pocas líneas.
import anthropic
client = anthropic.Anthropic()
with open("user_service.py") as f:
entire_file = f.read() # podría tener más de 2000 líneas
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=300,
messages=[{
"role": "user",
"content": f"¿Valida esta función el formato del correo electrónico?\n\n{entire_file}",
}],
)- Se envía todo el archivo aunque la pregunta sea sobre una sola función.
- Cada línea adicional en
entire_filese factura como un token de entrada en cada llamada. - Este patrón es el modo de fallo predeterminado, no un caso extremo, porque requiere cero pensamiento adicional para escribirlo.
- Nada aquí es sintácticamente incorrecto, por eso es fácil pasarlo por alto en una revisión.
2. Recortar al fragmento relevante
La misma pregunta, respondida enviando solo la función en cuestión.
import anthropic
client = anthropic.Anthropic()
relevant_function = '''
def validate_email(address: str) -> bool:
return "@" in address and "." in address.split("@")[-1]
'''
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=300,
messages=[{
"role": "user",
"content": f"¿Valida esta función el formato del correo electrónico?\n\n{relevant_function}",
}],
)- El prompt ahora contiene exactamente el código sobre el que trata la pregunta, nada más.
- Menos tokens de entrada significan un menor costo para esta misma pregunta exacta.
- Extraer el fragmento relevante es el único paso manual que requiere este enfoque.
- Esto es prompting de contexto mínimo: envía solo lo que la tarea necesita.
3. Medir la diferencia de tokens
Antes de confiar en que el recorte realmente ayudó, mídelo.
import anthropic
client = anthropic.Anthropic()
def count_tokens(text: str, model: str = "claude-sonnet-5") -> int:
result = client.messages.count_tokens(
model=model,
messages=[{"role": "user", "content": text}],
)
return result.input_tokens
full_file_tokens = count_tokens(open("user_service.py").read())
snippet_tokens = count_tokens(relevant_function)
print(f"Archivo completo: {full_file_tokens} tokens")
print(f"Fragmento: {snippet_tokens} tokens")count_tokensinforma los tokens de entrada sin generar una respuesta, por lo que medir es casi gratuito.- Comparar el antes y el después convierte "esto se siente más pequeño" en un número real que puedes incluir en un informe de costos.
- Ejecuta esto una vez por plantilla de prompt durante el desarrollo, no en cada llamada de producción.
- Si el fragmento no es significativamente más pequeño que el archivo completo, el paso de recorte no está haciendo su trabajo.
4. Una plantilla de prompt reutilizable
Las instrucciones de plantilla repetidas en cada llamada desperdician tokens tanto como un documento sobredimensionado.
SYSTEM_PROMPT = "Eres un revisor de código. Responde en un párrafo corto."
def review(snippet: str, question: str) -> str:
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=200,
system=SYSTEM_PROMPT,
messages=[{"role": "user", "content": f"{question}\n\n{snippet}"}],
)
return response.content[0].text- Corregir el prompt del sistema en un solo lugar mantiene las instrucciones de cada llamada cortas y consistentes.
- La parte variable del prompt (
snippet,question) es lo único que cambia en cada llamada. - Esta separación también hace obvio, de un vistazo, cuál es el costo fijo frente al costo por llamada.
- Una plantilla ordenada es un prerrequisito para las técnicas de resumen y categorización que se cubren más adelante en esta sección.
5. Excluir el historial de conversación obsoleto
En un chat de múltiples turnos, los turnos antiguos que ya no importan siguen costando tokens si sigues reenviándolos.
def trimmed_history(messages: list[dict], keep_last: int = 4) -> list[dict]:
# Conserva solo los turnos más recientes; descarta todo lo anterior.
return messages[-keep_last:]
full_history = [
{"role": "user", "content": "¿Qué hace este repositorio?"},
{"role": "assistant", "content": "Es un servicio de facturación..."},
{"role": "user", "content": "Añade una reintentos al manejador de webhooks."},
{"role": "assistant", "content": "Aquí está la función actualizada..."},
{"role": "user", "content": "Ahora añade una prueba unitaria para ello."},
]
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=400,
messages=trimmed_history(full_history, keep_last=4),
)- Cada turno anterior en
messagesse reenvía como tokens de entrada en la siguiente llamada, por lo que el historial se vuelve más caro cuanto más tiempo dura una conversación. trimmed_historyes una herramienta contundente: conserva la recencia, no la relevancia, así que úsala cuando los turnos más antiguos dejen de importar genuinamente.- Para conversaciones donde un turno temprano sigue siendo relevante durante todo el proceso, recortar solo por recencia puede eliminar algo que todavía necesitas.
- Esta es la misma idea de contexto mínimo aplicada al estado de la conversación en lugar de a un solo documento.
6. Excluir campos irrelevantes de datos estructurados
La misma disciplina se aplica a JSON o filas de bases de datos, no solo a archivos de código fuente.
raw_record = {
"id": "usr_9f2",
"email": "a@example.com",
"created_at": "2024-01-02T00:00:00Z",
"internal_flags": {"beta": True, "region_shard": "us-east-2"},
"last_login_ip": "10.0.4.12",
"support_notes": "..." * 500, # campo de texto largo
}
def trim_for_prompt(record: dict) -> dict:
return {k: record[k] for k in ("id", "email", "created_at")}
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=100,
messages=[{
"role": "user",
"content": f"Resume esta cuenta: {trim_for_prompt(raw_record)}",
}],
)- Los datos estructurados tienen el mismo problema que los archivos de código fuente: es fácil pasar el objeto completo en lugar de los campos que la tarea necesita.
trim_for_promptes una lista explícita de permitidos, que es más segura que una lista de denegados ad hoc que silenciosamente mantiene los nuevos campos añadidos más tarde.- Los campos de texto largos como
support_notesson exactamente el tipo de cosas que inflan silenciosamente el recuento de tokens. - Este patrón se generaliza a cualquier respuesta de API o fila de base de datos que un pipeline alimente en un prompt.
Ejemplos intermedios
7. Un selector de fragmentos de contexto mínimo
En lugar de seleccionar manualmente un fragmento, clasifica los candidatos por relevancia y conserva solo los pocos principales.
import anthropic
client = anthropic.Anthropic()
def select_relevant_snippets(question: str, candidates: list[str], keep: int = 2) -> list[str]:
# Un pase de relevancia barato: pide a un modelo rápido que puntúe cada candidato.
scored = []
for snippet in candidates:
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=5,
messages=[{
"role": "user",
"content": f"Pregunta: {question}\nFragmento:\n{snippet}\n\nRelevancia 0-10, solo número:",
}],
)
score = int(response.content[0].text.strip() or 0)
scored.append((score, snippet))
scored.sort(reverse=True, key=lambda pair: pair[0])
return [snippet for _, snippet in scored[:keep]]
top_snippets = select_relevant_snippets(
"¿Cómo se reintenta un pago fallido?",
candidates=[billing_module_src, auth_module_src, retry_queue_src],
keep=2,
)- Un modelo barato como Haiku 4.5 puntúa la relevancia de forma mucho más económica que pagar para enviar cada candidato al modelo caro.
- Solo los fragmentos con las puntuaciones más altas van al prompt real enviado al modelo más potente que realiza la tarea real.
- Esto es una categorización de modelos aplicada al propio paso de selección, no solo a la respuesta final.
- Para una base de código, un grafo de dependencias es una versión más rápida y precisa de esta misma idea; consulta la página dedicada a esa técnica.
8. Combinar recorte con presupuesto de tokens
Un presupuesto de ventana de contexto limita la cantidad que se puede enviar, y el recorte es cómo te mantienes dentro de él.
MAX_CONTEXT_TOKENS = 4000
def build_prompt_within_budget(question: str, snippets: list[str]) -> str:
prompt = question
used = count_tokens(prompt)
for snippet in snippets:
snippet_tokens = count_tokens(snippet)
if used + snippet_tokens > MAX_CONTEXT_TOKENS:
break # deja de añadir fragmentos una vez alcanzado el presupuesto
prompt += f"\n\n{snippet}"
used += snippet_tokens
return prompt
final_prompt = build_prompt_within_budget(
"Resume los cambios recientes en la lógica de reintentos.",
snippets=[retry_queue_diff, billing_module_diff, changelog_excerpt],
)- Establecer un
MAX_CONTEXT_TOKENSexplícito convierte "mantén el prompt pequeño" en una regla que el código aplica, no en un hábito que los ingenieros deben recordar. - Los fragmentos se añaden en orden de prioridad, por lo que el material más relevante sobrevive si el presupuesto obliga a un corte.
- Esta misma idea de presupuesto, aplicada a un agente de larga duración en lugar de a una sola llamada, es lo que un ADR de ventana de contexto documenta formalmente.
- Un presupuesto demasiado ajustado omite silenciosamente material relevante, así que elígelo basándote en las necesidades medidas, no en un número redondo.
9. Medir el ahorro en un pipeline completo
Junta las piezas anteriores y reporta el impacto real en costos del recorte.
def compare_strategies(question: str, full_document: str, trimmed_snippet: str) -> dict:
return {
"full_document_tokens": count_tokens(f"{question}\n\n{full_document}"),
"trimmed_tokens": count_tokens(f"{question}\n\n{trimmed_snippet}"),
}
result = compare_strategies(
"¿Maneja correctamente los reintentos este archivo?",
full_document=open("billing_service.py").read(),
trimmed_snippet=relevant_function,
)
savings_pct = 100 * (1 - result["trimmed_tokens"] / result["full_document_tokens"])
print(f"Reducción de tokens: {savings_pct:.0f}%")- Esta es la misma llamada a
count_tokensdel ejemplo 3, aplicada a nivel de pipeline en lugar de a un prompt a la vez. - Reportar un porcentaje de reducción, en lugar de un recuento de tokens en bruto, hace que los ahorros sean significativos para las partes interesadas no técnicas.
- Ejecuta esta comparación cada vez que cambies la forma en que se ensambla el contexto, para que una regresión en el tamaño del prompt se detecte de la misma manera que una regresión de rendimiento.
- Los ahorros de tokens se acumulan en cada llamada que realiza una carga de trabajo, por lo que una reducción modesta por llamada puede sumar una gran diferencia mensual.
Versiones de la pila: Escrito contra la línea de modelos Claude actual a partir de ~junio de 2026: Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (el predeterminado) y Claude Haiku 4.5, y el SDK oficial de Python
anthropic(última versión 0.x). Los nombres de los modelos, los precios y las versiones del SDK cambian rápidamente; verifica los detalles actuales en platform.claude.com/docs antes de confiar en ellos.