Cómo construir un agente IA de producción con AWS Strands Agents y Python
Tutorial ejecutable para construir en 30 minutos un agente de soporte al cliente con memoria de sesión persistente, tools personalizadas y protocolo MCP usando Strands Agents 1.0, el SDK open source de AWS que soporta Bedrock, Anthropic, Ollama y más.
Strands Agents es el SDK open source de AWS que permite construir agentes de IA de producción con Python en pocas líneas de código. En Cognitiva, agencia chilena de IA, lo usamos para proyectos donde el cliente necesita flexibilidad de proveedor: el mismo código funciona con Amazon Bedrock, Anthropic Claude, Ollama o cualquier proveedor compatible con LiteLLM, sin migrar la lógica del agente. Este tutorial es completamente ejecutable. En menos de 30 minutos tendrás un agente de soporte al cliente con memoria de sesión persistente entre conversaciones, tools personalizadas que resuelven consultas de inventario y precios, e integración con el protocolo MCP para consumir herramientas externas. Al final del tutorial añades las cuatro primitivas multi-agente que trae la versión 1.0: agents-as-tools, handoffs, swarms y graphs. Los requisitos son Python 3.10 o superior, una cuenta de AWS con Bedrock habilitado —o una API key de Anthropic— y conexión a internet para instalar las dependencias.
Prerrequisitos y entorno de trabajo
Para completar este tutorial necesitas Python 3.10 o superior y un proveedor de modelos configurado. La opción más directa para producción es Amazon Bedrock: configura las credenciales AWS con el comando aws configure o mediante las variables de entorno AWS_ACCESS_KEY_ID y AWS_SECRET_ACCESS_KEY. Si prefieres empezar sin cuenta de AWS, usa la API key de Anthropic con el modelo AnthropicModel —la cobertura de funcionalidades es equivalente—. Para pruebas locales también funciona Ollama con cualquier modelo Llama descargado. El proyecto no requiere Docker ni infraestructura adicional para seguir el tutorial.
# Crear entorno virtual e instalar el SDK
python -m venv .venv
source .venv/bin/activate
pip install strands-agents strands-agents-toolsTu primer agente con Strands
Strands Agents sigue un enfoque orientado al modelo: el agente recibe un prompt y una lista de tools, y el LLM decide por sí mismo qué herramientas invocar y en qué orden. No defines un grafo explícito de pasos; la orquestación la resuelve el modelo en cada llamada. Esto simplifica el código considerablemente: un agente funcional cabe en diez líneas y el comportamiento escala con el modelo que elijas sin cambios en el código del agente.
from strands import Agent, tool
from strands_tools import calculator
@tool
def consultar_precio(producto: str) -> str:
'''Consulta el precio de un producto en el catalogo de la tienda.'''
precios = {'laptop': 899990, 'monitor': 249990, 'teclado': 59990}
precio = precios.get(producto.lower())
if precio is None:
return 'Producto no encontrado en catalogo.'
return 'Precio de ' + producto + ': $' + str(precio)
agent = Agent(tools=[calculator, consultar_precio])
respuesta = agent('Cual es el precio de un laptop y cuanto es 899990 * 0.19 de IVA?')
print(str(respuesta))El decorador @tool transforma cualquier función Python en una herramienta que el agente puede invocar. La docstring de la función es la descripción que el LLM usa para decidir cuándo llamarla: escríbela con precisión. Los tipos de los parámetros se infieren del type hint y se exponen al modelo como parte del esquema de la tool. Si la función lanza una excepción, el agente la recibe como mensaje de error y puede reintentar con otros argumentos.
# Opcion A: Amazon Bedrock (proveedor por defecto)
from strands import Agent
from strands.models import BedrockModel
model_bedrock = BedrockModel(
model_id='anthropic.claude-sonnet-5',
region_name='us-east-1',
temperature=0.3
)
agent = Agent(model=model_bedrock)
# Opcion B: Anthropic directo
from strands.models import AnthropicModel
model_anthropic = AnthropicModel(
client_args={'api_key': '<TU_ANTHROPIC_API_KEY>'},
model_id='claude-sonnet-5'
)
agent = Agent(model=model_anthropic)Memoria de sesión persistente
En un agente de soporte, la memoria de sesión es la diferencia entre un bot que olvida todo al cerrar cada llamada y uno que recuerda el número de pedido que el cliente mencionó hace tres mensajes. Strands incluye un sistema de persistencia de historial que se activa pasando un SessionManager al constructor del Agent. La persistencia es automática: el SDK guarda el estado después de cada invocación y lo restaura al crear un nuevo Agent con el mismo session_id.
from strands import Agent
from strands.session.file_session_manager import FileSessionManager
session_manager = FileSessionManager(
session_id='cliente-001',
storage_dir='./sessions'
)
agent = Agent(
model='anthropic.claude-sonnet-5',
session_manager=session_manager
)
# Primera consulta: el agente registra el numero de pedido
agent('Hola, tengo un problema con el pedido 4521')
# Segunda consulta en la misma sesion: el agente recuerda el contexto
respuesta = agent('Cuando llega mi pedido?')
print(str(respuesta))Cada vez que creas un Agent con el mismo session_id y storage_dir, el SDK restaura el historial completo de la conversación anterior. Esto funciona correctamente en servicios de instancia única. En entornos con múltiples réplicas del servicio —por ejemplo, detrás de un balanceador de carga— los archivos locales no se comparten entre instancias.
from strands import Agent
from strands.session.s3_session_manager import S3SessionManager
import boto3
boto_session = boto3.Session(region_name='us-west-2')
session_manager = S3SessionManager(
session_id='cliente-001',
bucket='mi-bucket-de-sesiones',
prefix='produccion/',
boto_session=boto_session
)
agent = Agent(session_manager=session_manager)
agent('Continuemos con el pedido 4521')Tools personalizadas y protocolo MCP
El paquete strands-agents-tools incluye más de treinta tools preconstruidas para tareas frecuentes: cálculo, búsqueda en la web, ejecución de código Python, lectura de archivos y consultas HTTP, entre otras. Para las tools específicas de tu dominio —consultar una base de datos, llamar a un endpoint interno, buscar en tu catálogo de productos— usas el decorador @tool sobre cualquier función Python regular. La docstring actúa como la descripción que el LLM lee para decidir cuándo invocar la tool.
from strands import Agent, tool
@tool
def consultar_pedido(numero_pedido: str) -> str:
'''Consulta el estado actual de un pedido por su numero.
Retorna el estado y la fecha estimada de entrega.'''
estados = {
'4521': 'En camino. Entrega estimada el 5 de julio.',
'3890': 'Entregado el 1 de julio a las 14:32.',
'5100': 'En preparacion en bodega. Sale manana.'
}
resultado = estados.get(numero_pedido)
if resultado is None:
return 'Pedido ' + numero_pedido + ' no encontrado en el sistema.'
return resultado
agent = Agent(tools=[consultar_pedido])
print(str(agent('Estado del pedido 4521')))El protocolo MCP (Model Context Protocol) es el estándar abierto que permite a servidores externos exponer herramientas que un agente puede consumir. Strands integra MCP mediante MCPClient, que admite tres transportes: stdio para procesos locales, Streamable HTTP para servicios remotos y SSE para conexiones de larga duración. El MCPClient gestiona el ciclo de vida de la conexión y se pasa directamente en la lista de tools del Agent sin código adicional.
from mcp import stdio_client, StdioServerParameters
from strands import Agent
from strands.tools.mcp import MCPClient
# Conectar al servidor MCP de documentacion de AWS
mcp_docs = MCPClient(lambda: stdio_client(
StdioServerParameters(
command='uvx',
args=['awslabs.aws-documentation-mcp-server@latest']
)
))
# El MCPClient se pasa directamente como tool del agente
agent = Agent(tools=[mcp_docs])
respuesta = agent('Que servicios de AWS se usan para alojar agentes de IA?')
print(str(respuesta))Las cuatro primitivas multi-agente de Strands 1.0
Strands Agents 1.0 incorpora cuatro primitivas para coordinar múltiples agentes en un mismo sistema. Cada una aborda un patrón distinto de coordinación: se elige la que se ajusta al flujo del caso de uso. En sistemas de soporte al cliente, la primitiva más frecuente es agents-as-tools, donde un orquestador delega tareas específicas a agentes especializados y devuelve al usuario una sola respuesta coherente.
| Primitiva | Patrón | Caso de uso ideal |
|---|---|---|
| agents-as-tools | Delegación jerárquica | Orquestador con agentes especializados por dominio |
| handoffs | Traspaso de control | Escalamiento a agente humano con historial completo |
| swarms | Coordinación autónoma colectiva | Investigación paralela sin orquestador central |
| graphs | Flujo determinista con rutas | Pipelines complejos con decisiones condicionales auditables |
Agents-as-tools: delegación jerárquica
Cada agente especializado se expone como una tool del orquestador mediante el método as_tool(). El orquestador recibe la consulta del usuario y decide qué agente especializado invocar según el tipo de pregunta. El historial interno de cada delegación queda transparente para el usuario: ve una sola respuesta integrada.
from strands import Agent
agente_inventario = Agent(
system_prompt='Especialista en inventario. Consulta disponibilidad de productos.'
)
agente_precios = Agent(
system_prompt='Especialista en precios y descuentos del catalogo.'
)
orquestador = Agent(
system_prompt='Orquestador de soporte al cliente. Delega al especialista correcto segun la consulta.',
tools=[
agente_inventario.as_tool(
name='consultar_inventario',
description='Consulta si un producto esta disponible en inventario'
),
agente_precios.as_tool(
name='consultar_precios',
description='Consulta el precio y descuentos actuales de un producto'
)
]
)
respuesta = orquestador('Hay laptops disponibles y cuanto cuestan con descuento?')
print(str(respuesta))Agente de soporte completo: todo junto
El siguiente código integra los cuatro componentes del tutorial en un agente de soporte al cliente ejecutable: proveedor Bedrock, dos tools personalizadas (estado de pedido y precio de producto), memoria de sesión por usuario y un system prompt con instrucciones de comportamiento. Adapta las tools a tus propias fuentes de datos —una base de datos PostgreSQL, un endpoint REST de tu ERP o una hoja de cálculo— con la misma estructura de @tool.
from strands import Agent, tool
from strands.models import BedrockModel
from strands.session.file_session_manager import FileSessionManager
@tool
def consultar_pedido(numero_pedido: str) -> str:
'''Consulta el estado de un pedido por su numero.'''
estados = {
'4521': 'En camino. Entrega estimada el 5 de julio.',
'3890': 'Entregado el 1 de julio a las 14:32.',
'5100': 'En preparacion en bodega. Sale manana.'
}
return estados.get(numero_pedido, 'Pedido no encontrado.')
@tool
def consultar_precio(producto: str) -> str:
'''Consulta el precio de un producto en el catalogo.'''
precios = {'laptop': 899990, 'monitor': 249990, 'teclado': 59990}
precio = precios.get(producto.lower())
if precio is None:
return 'Producto no encontrado en catalogo.'
return 'Precio de ' + producto + ': $' + str(precio)
model = BedrockModel(
model_id='anthropic.claude-sonnet-5',
region_name='us-east-1'
)
PROMPT_SISTEMA = (
'Eres un agente de soporte al cliente de una tienda de tecnologia. '
'Responde siempre en espanol con tono amable y profesional. '
'Usa las herramientas disponibles para consultar pedidos y precios.'
)
if __name__ == '__main__':
session_id = input('ID de sesion del cliente: ')
session_manager = FileSessionManager(
session_id=session_id,
storage_dir='./sessions'
)
agent = Agent(
model=model,
tools=[consultar_pedido, consultar_precio],
session_manager=session_manager,
system_prompt=PROMPT_SISTEMA
)
print('Agente listo. Escribe salir para terminar.')
while True:
consulta = input('Cliente: ')
if consulta.lower() == 'salir':
break
respuesta = agent(consulta)
print('Agente: ' + str(respuesta))Para ejecutar el agente desde la terminal, guarda el archivo como agente_soporte.py, configura las credenciales AWS y ejecuta python agente_soporte.py. El agente solicita un ID de sesión al inicio —usa el identificador del cliente o de la conversación— y mantiene el historial entre preguntas dentro de la misma sesión.
Checklist de producción Cognitiva para Strands
Antes de llevar un agente Strands a producción, en Cognitiva aplicamos un checklist de siete puntos que cubre los escollos más frecuentes en los primeros despliegues. No es obligatorio en un prototipo, pero sí en cualquier agente que atienda usuarios reales.
- El session_id es único por usuario: no compartas el mismo session_id entre usuarios distintos o mezclarás sus historiales de conversación.
- En entornos multi-réplica, usa S3SessionManager con un bucket S3 dedicado al servicio en lugar de FileSessionManager.
- Define un system_prompt explícito que incluya el idioma de respuesta esperado, el tono y el alcance del agente.
- Limita las tools disponibles al mínimo necesario: exponer tools innecesarias aumenta el riesgo de invocaciones incorrectas por parte del modelo.
- Implementa un timeout en cada @tool para evitar que el agente quede bloqueado en una llamada externa lenta o que no responde.
- Activa los logs del namespace 'strands' en nivel INFO antes del despliegue: registran cada invocación de tool y ayudan a diagnosticar problemas en producción.
- Prueba el agente con entradas adversariales —preguntas ambiguas, datos fuera de rango, idiomas distintos al esperado— antes de exponerlo a usuarios finales.
La fortaleza de Strands Agents no está en la cantidad de primitivas que ofrece, sino en que todas comparten la misma interfaz: puedes pasar de un agente simple a un sistema de orquestación multi-agente cambiando tres líneas de configuración.
Cómo construir un agente de soporte al cliente con Strands Agents y Python
Tutorial paso a paso para crear en 30 minutos un agente con memoria de sesión persistente, tools personalizadas y protocolo MCP usando Strands Agents 1.0 de AWS.
Configurar el entorno
Construir el agente base con tools
Añadir memoria de sesión
Integrar MCP y orquestación multi-agente
Preguntas frecuentes
Da el siguiente paso
Hablemos
Cuéntanos sobre tu negocio. Respondemos en 24 horas.
Otros canales
Escríbenos por WhatsApp o agenda una llamada de 30 minutos.