Módulo 3: Agents con create_agent
System Prompts Estáticos y Dinámicos
Descripción de la cápsula
Los system prompts definen quién es tu agente y cómo se comporta. Son la primera instrucción que recibe el modelo antes de procesar cualquier mensaje del usuario — establecen el rol, las restricciones, el formato de respuesta, y las guías de uso de herramientas.
En esta cápsula aprenderás dos formas de configurar system prompts con create_agent. La primera es el prompt estático: un string fijo que no cambia entre ejecuciones. La segunda es el prompt dinámico: una función que recibe el estado actual y genera el prompt en runtime, adaptándose al contexto (nombre del usuario, permisos, hora del día, historial de conversación).
Al terminar, sabrás cuándo usar cada tipo, cómo escribir prompts efectivos para agentes, y cómo aprovechar prompt caching para reducir costos con Anthropic.
El parámetro prompt en create_agent
En la cápsula anterior creaste agentes con create_agent(model, tools). El tercer parámetro clave es prompt — define el system message que el agente recibe antes de cualquier interacción:
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
@tool
def search_web(query: str) -> str:
"""Busca información actualizada en internet."""
return f"Resultados para: {query}"
model = ChatOpenAI(model="gpt-4.1-mini")
tools = [search_web]
agent = create_agent(
model,
tools,
prompt="Eres un asistente de investigación. Siempre busca información antes de responder."
)
result = agent.invoke({
"messages": [("user", "¿Qué es LangGraph?")]
})
print(result["messages"][-1].content)
# Output esperado: [Respuesta del agente basada en la búsqueda realizada]
Sin prompt, el agente usa un system message genérico por defecto. Con prompt, controlas exactamente cómo se comporta.
Prompts estáticos: string fijo
Un prompt estático es un string que no cambia entre ejecuciones. Es la forma más directa y la que usarás en la mayoría de agentes. Para agentes con un rol específico, estructura el prompt con secciones claras:
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
@tool
def search_documentation(query: str) -> str:
"""Busca en la documentación técnica del producto."""
docs = {
"instalación": "pip install nuestro-sdk>=2.0",
"autenticación": "Usa API key en el header Authorization: Bearer <key>",
"rate limits": "100 requests/minuto en plan free, 1000 en pro",
}
for key, value in docs.items():
if key in query.lower():
return value
return "No se encontró documentación relevante."
@tool
def create_ticket(title: str, priority: str) -> str:
"""Crea un ticket de soporte. priority: 'low', 'medium', 'high'."""
return f"Ticket creado: '{title}' (prioridad: {priority}) — ID: TK-{hash(title) % 10000}"
model = ChatOpenAI(model="gpt-4.1")
SUPPORT_PROMPT = """Eres un agente de soporte técnico de ACME Corp.
ROL:
- Ayudas a clientes con problemas técnicos del producto ACME SDK.
- Respondes en español con tono profesional pero amigable.
COMPORTAMIENTO:
- Siempre busca en la documentación antes de responder preguntas técnicas.
- Si el problema no se puede resolver con documentación, crea un ticket de soporte.
- Nunca inventes información técnica — usa solo lo que encuentres en la documentación.
FORMATO DE RESPUESTA:
- Respuestas concisas (máximo 3 párrafos).
- Usa bullet points para pasos de solución.
- Incluye el ID del ticket si creaste uno.
RESTRICCIONES:
- No puedes modificar cuentas de usuario ni hacer reembolsos.
- Si el cliente pide algo fuera de tu alcance, explícale a quién contactar."""
agent = create_agent(model, [search_documentation, create_ticket], prompt=SUPPORT_PROMPT)
result = agent.invoke({
"messages": [("user", "¿Cómo instalo el SDK?")]
})
print(result["messages"][-1].content)
# Output esperado: [Respuesta con instrucciones de instalación obtenidas de la documentación]
El prompt se inyecta como SystemMessage al inicio de la conversación. Cada vez que el agente procesa un mensaje, este prompt está presente.
Escribir prompts efectivos para agentes
Un buen system prompt para agentes tiene 4 componentes. Aquí tienes un ejemplo que los integra todos:
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
@tool
def search_web(query: str) -> str:
"""Busca información actualizada en internet."""
return f"Resultados para '{query}': [datos simulados]"
@tool
def calculate(expression: str) -> str:
"""Evalúa una expresión matemática."""
try:
return str(eval(expression))
except Exception as e:
return f"Error: {e}"
model = ChatOpenAI(model="gpt-4.1-mini")
ANALYST_PROMPT = """Eres un analista de datos especializado en métricas de producto.
RESTRICCIONES:
- No des predicciones sin datos que las respalden.
- No inventes métricas — si no tienes el dato, dilo.
- Máximo 5 herramientas por consulta.
FORMATO:
- Responde en español.
- Usa tablas markdown para comparaciones.
- Incluye cálculos intermedios cuando hagas análisis numéricos.
USO DE HERRAMIENTAS:
- Usa search_web para obtener métricas actualizadas del mercado.
- Usa calculate para todos los cálculos — no hagas aritmética mental.
- Si puedes responder con tu conocimiento sin buscar, hazlo directamente."""
agent = create_agent(model, [search_web, calculate], prompt=ANALYST_PROMPT)
result = agent.invoke({
"messages": [("user", "¿Cuál es el crecimiento porcentual de 150 a 195?")]
})
print(result["messages"][-1].content)
# Output esperado: [Respuesta con cálculo de (195-150)/150 * 100 = 30%]
Los 4 componentes son:
- Rol — Quién es el agente. Cuanto más específico, mejor: "analista de datos especializado en métricas" >> "asistente"
- Restricciones — Qué NO debe hacer. Sin ellas, el agente puede salirse de su dominio
- Formato — Cómo estructurar las respuestas (idioma, longitud, estilo)
- Guías de herramientas — Cuándo y cómo usar cada tool. Refuerza las descripciones de las tools
Tips para prompts efectivos:
- ✅ Instrucciones más importantes al inicio y al final del prompt (el modelo presta más atención)
- ✅ Sé específico: "Responde en máximo 3 párrafos" >> "Sé breve"
- ❌ Evita contradicciones entre el prompt y las descripciones de las tools
- ❌ Evita prompts excesivamente largos que diluyan las instrucciones clave
Prompts dinámicos: funciones que generan prompts
Por qué necesitas prompts dinámicos
Los prompts estáticos son suficientes cuando el contexto no cambia. Pero en aplicaciones reales, el agente necesita adaptarse:
- ✅ Incluir el nombre del usuario actual
- ✅ Cambiar el comportamiento según permisos o rol
- ✅ Ajustar instrucciones según la hora del día
- ✅ Modificar el prompt basado en el historial de conversación
Un prompt dinámico es una función que recibe el estado actual y retorna un string:
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
@tool
def search_web(query: str) -> str:
"""Busca información actualizada en internet."""
return f"Resultados para '{query}': [datos simulados]"
model = ChatOpenAI(model="gpt-4.1-mini")
def dynamic_prompt(state):
"""Genera el prompt basado en el estado actual."""
message_count = len(state.get("messages", []))
if message_count <= 2:
style = "Da respuestas detalladas con ejemplos."
else:
style = "Sé conciso — la conversación ya lleva varios turnos."
return (
f"Eres un asistente de investigación. "
f"Esta es la interacción #{message_count} de esta sesión. "
f"{style} Responde siempre en español."
)
agent = create_agent(model, [search_web], prompt=dynamic_prompt)
result = agent.invoke({
"messages": [("user", "¿Qué es LangChain?")]
})
print(result["messages"][-1].content)
# Output esperado: [Respuesta detallada — es la primera interacción]
Cada vez que el agente procesa un mensaje, llama a dynamic_prompt(state) para obtener el system message actualizado.
Prompt dinámico con información del usuario
El caso más común es personalizar el agente para el usuario actual. Campos custom como user_name y user_role requieren state_schema (que verás en detalle en la próxima cápsula):
from typing import TypedDict, Annotated
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import AnyMessage
from datetime import datetime
import operator
class BankState(TypedDict):
messages: Annotated[list[AnyMessage], operator.add]
user_name: str
user_role: str
@tool
def get_account_balance(account_id: str) -> str:
"""Consulta el saldo de una cuenta bancaria."""
balances = {"ACC-001": "$5,230.00", "ACC-002": "$12,750.50"}
return balances.get(account_id, "Cuenta no encontrada")
@tool
def transfer_money(from_account: str, to_account: str, amount: float) -> str:
"""Transfiere dinero entre cuentas."""
return f"Transferencia de ${amount:.2f} de {from_account} a {to_account} — completada"
model = ChatOpenAI(model="gpt-4.1")
def banking_prompt(state):
"""Prompt personalizado con datos del usuario y hora actual."""
user_name = state.get("user_name", "cliente")
user_role = state.get("user_role", "basic")
hour = datetime.now().hour
greeting = "Buenos días" if hour < 12 else ("Buenas tardes" if hour < 18 else "Buenas noches")
base = f"{greeting}, estás atendiendo a {user_name}. Eres un asistente bancario profesional. Responde en español."
if user_role == "premium":
base += " Este es un cliente premium — ofrece servicio prioritario. Puedes realizar transferencias sin límite."
else:
base += " Este es un cliente básico. Las transferencias están limitadas a $1,000 por operación."
return base
agent = create_agent(model, [get_account_balance, transfer_money], prompt=banking_prompt, state_schema=BankState)
result = agent.invoke({
"messages": [("user", "¿Cuál es mi saldo en ACC-001?")],
"user_name": "María García",
"user_role": "premium",
})
print(result["messages"][-1].content)
# Output esperado: [Respuesta personalizada con saldo de la cuenta ACC-001]
El prompt cambia completamente dependiendo de quién sea el usuario y cuándo acceda al sistema.
Prompt dinámico con historial de conversación
Puedes analizar el historial de mensajes para ajustar el comportamiento conforme avanza la conversación:
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
@tool
def search_docs(query: str) -> str:
"""Busca en la documentación técnica."""
return f"Documentación encontrada para: {query}"
model = ChatOpenAI(model="gpt-4.1-mini")
def adaptive_prompt(state):
"""Adapta el prompt según el historial de la conversación."""
messages = state.get("messages", [])
question_count = sum(1 for m in messages if isinstance(m, HumanMessage))
if question_count == 0:
return "Eres un tutor de programación. Primera pregunta del estudiante — sé detallado y acogedor. Da ejemplos con código."
elif question_count <= 3:
return "Eres un tutor de programación. El estudiante ya tiene contexto. Puedes ser más directo — no repitas conceptos ya explicados."
else:
return "Eres un tutor de programación. La conversación lleva varios turnos. Sé conciso. Sugiere un ejercicio práctico en vez de más teoría."
agent = create_agent(model, [search_docs], prompt=adaptive_prompt)
result = agent.invoke({
"messages": [("user", "¿Qué es una función en Python?")]
})
print(result["messages"][-1].content)
# Output esperado: [Respuesta detallada y acogedora — primera interacción]
Prompt caching con Anthropic
Cuando usas modelos de Anthropic, puedes aprovechar prompt caching para reducir costos. Los system prompts largos se cachean en el servidor, y las invocaciones subsecuentes reutilizan el cache.
Para activar el cache, pasa el prompt como SystemMessage con el header de cache:
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
from langchain_core.tools import tool
from langchain_core.messages import SystemMessage
@tool
def search_knowledge_base(query: str) -> str:
"""Busca en la base de conocimiento interna."""
return f"Resultado para: {query}"
model = ChatAnthropic(model="claude-sonnet-4-20250514")
long_system_prompt = SystemMessage(
content=(
"Eres un experto en soporte técnico de ACME Corp. "
"Conoces toda la documentación del producto, incluyendo: "
"API Reference v3.2, Guía de Integración, FAQ de clientes, "
"Troubleshooting Guide, y el changelog de las últimas 10 versiones. "
"Responde en español. "
"Sigue el protocolo de soporte: 1) Identifica el problema, "
"2) Busca en la documentación, 3) Proporciona solución paso a paso, "
"4) Ofrece crear ticket si no se resuelve."
),
additional_kwargs={"cache_control": {"type": "ephemeral"}}
)
agent = create_agent(model, [search_knowledge_base], prompt=long_system_prompt)
result = agent.invoke({
"messages": [("user", "¿Cómo configuro la autenticación OAuth?")]
})
print(result["messages"][-1].content)
# Output esperado: [Respuesta siguiendo el protocolo de soporte]
Claves del prompt caching:
- ✅ Prompts de >=1024 tokens se cachean automáticamente
- ✅ Reduce latencia (~80% más rápido para el prompt) y costos (~90% menos para tokens cacheados)
- ⚠️ Solo disponible con modelos de Anthropic
- ⚠️ El cache expira después de 5 minutos sin uso
Comparación: estático vs dinámico
| Criterio | Prompt estático | Prompt dinámico |
|---|---|---|
| Definición | String fijo | Función que retorna string |
| Cuándo cambia | Nunca | Cada invocación (basado en state) |
| Complejidad | Baja | Media |
| Casos de uso | Agentes de propósito general | Agentes personalizados por contexto |
| Prompt caching | ✅ Funciona siempre | ⚠️ Solo si el output es estable |
| Debugging | Fácil — siempre sabes qué prompt se usó | Requiere logging del prompt generado |
Usa prompt estático cuando:
- ✅ El agente tiene un rol fijo que no cambia
- ✅ No necesitas personalización por usuario
- ✅ Quieres máximo beneficio de prompt caching
Usa prompt dinámico cuando:
- ✅ Necesitas personalizar por usuario (nombre, permisos, preferencias)
- ✅ El comportamiento cambia según hora, fecha, o contexto externo
- ✅ Quieres adaptar el prompt según el historial de conversación
Conexión con el proyecto
En el Agente de Investigación con Tools (proyecto de este módulo):
- Usarás un prompt estático detallado que define el rol de investigador
- El prompt incluirá guías de herramientas para que el agente sepa cuándo buscar vs. cuándo sintetizar
- En el Módulo 4 (Middleware), aprenderás
@dynamic_promptcomo middleware — una forma más avanzada de prompts dinámicos
Todo lo que aprendes aquí se aplica directamente en la Cápsula 08.
Troubleshooting
Problema 1: El agente ignora las instrucciones del prompt
Causa: El prompt es demasiado largo o las instrucciones contradicen las descripciones de las tools. Solución:
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
# ❌ Tool dice "cualquier tema", prompt dice "solo tecnología" — contradicción
@tool
def search(query: str) -> str:
"""Busca información en internet sobre cualquier tema."""
return f"Resultados: {query}"
# ✅ Tool y prompt alineados
@tool
def search_tech(query: str) -> str:
"""Busca información técnica sobre software, hardware y programación."""
return f"Resultados técnicos: {query}"
model = ChatOpenAI(model="gpt-4.1-mini")
agent = create_agent(
model, [search_tech],
prompt="Eres un asistente técnico. Usa search_tech para buscar información. Si la pregunta no es técnica, indica que solo puedes ayudar con temas de tecnología."
)
Problema 2: El prompt dinámico no recibe los campos custom del state
Causa: Los campos custom no están definidos en state_schema, o no se pasan en invoke().
Solución: Siempre define los campos en state_schema con TypedDict y pasa todos los valores en invoke(). Usa state.get("field", default) para evitar KeyError.
Problema 3: El prompt es demasiado largo y el agente pierde el foco
Causa: Prompts con demasiadas instrucciones diluyen la atención del modelo. Solución: Prioriza las instrucciones más importantes al inicio y al final del prompt:
# ❌ Instrucción crítica perdida en el medio
prompt_malo = """Eres un asistente. Puedes responder en varios idiomas.
Tienes herramientas de búsqueda. El clima es importante.
NUNCA inventes datos. Usa tablas markdown. Sé amigable."""
# ✅ Instrucción crítica al inicio
prompt_bueno = """NUNCA inventes datos — usa siempre las herramientas disponibles.
Eres un asistente de investigación que responde en español.
Formato: tablas markdown para comparaciones. Tono: profesional pero amigable."""
Problema 4: Prompt caching no funciona
Causa: El prompt tiene menos de 1024 tokens, no estás usando un modelo de Anthropic, o falta cache_control.
Solución: Verifica que usas ChatAnthropic, que el contenido del SystemMessage tiene >=1024 tokens, y que incluyes additional_kwargs={"cache_control": {"type": "ephemeral"}}.
Ejercicios
Ejercicio 1: Prompt estático para un asistente de cocina (Fácil)
Crea un agente con un prompt estático que lo convierta en un asistente de cocina. Debe tener una tool search_recipes y el prompt debe definir los 4 componentes (rol, restricciones, formato, guías de tools).
Ver solución
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
@tool
def search_recipes(ingredient: str) -> str:
"""Busca recetas que usen un ingrediente específico."""
recipes = {
"pollo": "Pollo al horno con limón (30 min), Pollo teriyaki (25 min)",
"pasta": "Pasta carbonara (20 min), Pasta al pesto (15 min)",
"arroz": "Arroz con verduras (25 min), Arroz frito (20 min)",
}
return recipes.get(ingredient.lower(), f"No encontré recetas con '{ingredient}'")
model = ChatOpenAI(model="gpt-4.1-mini")
CHEF_PROMPT = """Eres un chef asistente especializado en cocina latinoamericana y mediterránea.
RESTRICCIONES:
- Solo recomiendas recetas con los ingredientes que el usuario mencione.
- Si no encuentras recetas, sugiere ingredientes alternativos.
FORMATO:
- Responde en español. Incluye tiempo de preparación.
- Usa bullet points para los pasos.
USO DE HERRAMIENTAS:
- Usa search_recipes para buscar recetas por ingrediente antes de recomendar."""
agent = create_agent(model, [search_recipes], prompt=CHEF_PROMPT)
result = agent.invoke({"messages": [("user", "Tengo pollo, ¿qué puedo cocinar?")]})
print(result["messages"][-1].content)
# Output esperado: [Respuesta con recetas de pollo encontradas via tool]
Explicación: El prompt sigue los 4 componentes. La tool description y el prompt están alineados — ambos se enfocan en búsqueda por ingrediente.
Ejercicio 2: Prompt dinámico con hora del día (Fácil)
Crea un agente con un prompt dinámico que cambie el tono según la hora: formal por la mañana, casual por la tarde, breve por la noche.
Ver solución
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from datetime import datetime
@tool
def get_news(topic: str) -> str:
"""Obtiene noticias recientes sobre un tema."""
return f"Últimas noticias sobre {topic}: [noticias simuladas]"
model = ChatOpenAI(model="gpt-4.1-mini")
def time_aware_prompt(state):
hour = datetime.now().hour
if 6 <= hour < 12:
return "Buenos días. Eres un asistente de noticias con tono formal. Presenta datos de forma estructurada. Responde en español."
elif 12 <= hour < 20:
return "¡Buenas tardes! Eres un asistente de noticias casual. Resume de forma conversacional. Responde en español."
else:
return "Buenas noches. Eres un asistente de noticias breve. Solo puntos clave. Responde en español."
agent = create_agent(model, [get_news], prompt=time_aware_prompt)
result = agent.invoke({"messages": [("user", "¿Qué está pasando con la IA?")]})
print(result["messages"][-1].content)
# Output esperado: [Respuesta cuyo tono varía según la hora actual]
Explicación: No necesita state_schema custom porque solo usa datetime.now(), no datos del estado.
Ejercicio 3: Prompt dinámico con permisos de usuario (Medio)
Crea un agente bancario con state_schema que incluya user_role ("admin" o "viewer"). El prompt debe habilitar transferencias solo para admins y rechazarlas para viewers.
Ver solución
from typing import TypedDict, Annotated
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import AnyMessage
import operator
class BankState(TypedDict):
messages: Annotated[list[AnyMessage], operator.add]
user_role: str
@tool
def check_balance(account_id: str) -> str:
"""Consulta el saldo de una cuenta."""
return f"Saldo de {account_id}: $5,230.00"
@tool
def make_transfer(from_acc: str, to_acc: str, amount: float) -> str:
"""Realiza una transferencia bancaria."""
return f"Transferencia de ${amount:.2f} de {from_acc} a {to_acc} completada."
model = ChatOpenAI(model="gpt-4.1")
def role_based_prompt(state):
role = state.get("user_role", "viewer")
base = "Eres un asistente bancario profesional. Responde en español."
if role == "admin":
return f"{base} El usuario es ADMINISTRADOR — puede consultar saldos y realizar transferencias. Confirma cada operación."
return f"{base} El usuario es VIEWER — solo lectura. Si pide transferencia, explica que necesita permisos de administrador."
agent = create_agent(model, [check_balance, make_transfer], prompt=role_based_prompt, state_schema=BankState)
result_viewer = agent.invoke({
"messages": [("user", "Transfiere $100 de ACC-001 a ACC-002")],
"user_role": "viewer",
})
print("Viewer:", result_viewer["messages"][-1].content)
# Output esperado: [Rechazo — necesita permisos de administrador]
Explicación: El state_schema define user_role. Mismo agente, diferente comportamiento según el rol.
Ejercicio 4: Prompt que se adapta al historial (Medio)
Crea un agente tutor que cambie su estilo según cuántas preguntas ha hecho el usuario: detallado para las primeras 2, directo para las siguientes, y sugerencia de práctica después de 5.
Ver solución
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
@tool
def search_python_docs(topic: str) -> str:
"""Busca documentación de Python sobre un tema específico."""
docs = {
"listas": "Las listas son secuencias mutables: my_list = [1, 2, 3]",
"funciones": "Se definen con def: def my_func(arg): return arg * 2",
}
for key, value in docs.items():
if key in topic.lower():
return value
return f"Documentación sobre '{topic}' no encontrada."
model = ChatOpenAI(model="gpt-4.1-mini")
def tutor_prompt(state):
messages = state.get("messages", [])
question_count = sum(1 for m in messages if isinstance(m, HumanMessage))
if question_count <= 2:
return "Eres un tutor de Python para principiantes. Da explicaciones detalladas con analogías y ejemplos. Muestra output esperado. Responde en español."
elif question_count <= 5:
return "Eres un tutor de Python. Da respuestas directas con código. No repitas conceptos ya explicados. Responde en español."
else:
return "Eres un tutor de Python. Sugiere un ejercicio práctico en vez de más teoría. Da enunciado y pistas, no la solución. Responde en español."
agent = create_agent(model, [search_python_docs], prompt=tutor_prompt)
result = agent.invoke({"messages": [("user", "¿Qué son las listas en Python?")]})
print(result["messages"][-1].content)
# Output esperado: [Explicación detallada con analogías — primera pregunta]
Explicación: El contador de HumanMessage determina la fase del tutor, creando una experiencia progresiva dentro de la sesión.
Ejercicio 5: Prompt con SystemMessage para prompt caching (Difícil)
Crea un agente usando ChatAnthropic con un SystemMessage largo que tenga cache_control. El prompt debe describir un rol de soporte con protocolo detallado.
Ver solución
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
from langchain_core.tools import tool
from langchain_core.messages import SystemMessage
@tool
def search_kb(query: str) -> str:
"""Busca en la base de conocimiento del producto."""
kb = {
"login": "Para login: POST /api/auth/login con {email, password}",
"registro": "Para registro: POST /api/auth/register con {name, email, password}",
"api key": "Genera API keys en Dashboard > Settings > API Keys",
}
for key, value in kb.items():
if key in query.lower():
return value
return "No encontré información relevante."
@tool
def create_support_ticket(title: str, severity: str) -> str:
"""Crea un ticket de soporte. severity: 'low', 'medium', 'high', 'critical'."""
return f"Ticket #{abs(hash(title)) % 100000} creado — '{title}' (severidad: {severity})"
model = ChatAnthropic(model="claude-sonnet-4-20250514")
SUPPORT_PROMPT = SystemMessage(
content="""Eres un agente de soporte técnico de nivel 2 para DataFlow Pro.
IDENTIDAD: Ingeniero de soporte con 5 años de experiencia. Conoces la API REST, el dashboard web, y los SDKs (Python, Node.js, Go).
PROTOCOLO DE ATENCIÓN:
1. IDENTIFICAR: Categoría del problema (autenticación, API, dashboard, deployment, billing).
2. BUSCAR: Consulta la base de conocimiento antes de responder.
3. DIAGNOSTICAR: Si la búsqueda no resuelve, haz preguntas específicas.
4. RESOLVER: Solución paso a paso con código cuando sea relevante.
5. ESCALAR: Si no puedes resolver, crea ticket con toda la información.
RESTRICCIONES:
- NUNCA inventes endpoints ni configuraciones que no estén en la KB.
- No puedes modificar cuentas, cambiar planes ni procesar reembolsos.
- Máximo 3 búsquedas por consulta — si no encuentras, escalas.
FORMATO: Español, tono profesional y empático. Bloques de código con syntax highlighting.
Al final de cada respuesta, pregunta si el problema se resolvió.
SEVERIDADES: low (preguntas generales), medium (bug con workaround), high (bug sin workaround), critical (servicio caído).""",
additional_kwargs={"cache_control": {"type": "ephemeral"}}
)
agent = create_agent(model, [search_kb, create_support_ticket], prompt=SUPPORT_PROMPT)
result = agent.invoke({"messages": [("user", "No puedo hacer login, me da error 401")]})
print(result["messages"][-1].content)
# Output esperado: [Respuesta siguiendo el protocolo: busca en KB, da pasos de solución]
Explicación: El SystemMessage con cache_control permite que Anthropic cachee este prompt largo. Las invocaciones subsecuentes serán más rápidas y baratas.
Resumen
En esta cápsula aprendiste:
- El parámetro
promptencreate_agentdefine el system message del agente - Los prompts estáticos son strings fijos — ideales para agentes con rol constante
- Un buen prompt tiene 4 componentes: rol, restricciones, formato, y guías de herramientas
- Los prompts dinámicos son funciones que reciben
statey retornan un string — se adaptan al contexto - Puedes personalizar prompts dinámicos con información del usuario, hora del día, o historial
- Los campos custom del state requieren definir un
state_schemaconTypedDict(más en la siguiente cápsula) - Con Anthropic, puedes usar prompt caching con
SystemMessage+cache_controlpara reducir costos - Las instrucciones más importantes van al inicio y al final del prompt
Próxima cápsula: Estado y Memoria del Agente — aprenderás a definir schemas de estado custom, manejar el historial de conversación, y hacer que el agente recuerde información entre turnos.
Recursos adicionales
- Agents Conceptual Guide — Cómo funcionan los agentes internamente
- How to create agents — Guía oficial de create_agent
- Anthropic Prompt Caching — Documentación oficial de prompt caching
- System Prompts Best Practices (OpenAI) — Guía de system messages
- LangChain Messages — Tipos de mensajes en LangChain
- ReAct Pattern Paper — Paper original del patrón ReAct
- LangGraph State Management — Cómo funciona el estado en LangGraph
Módulo 3 — LangChain & LangGraph: From Chains to Agents