← Todas las guías
Guía interactiva · 10 niveles

Tu primer agente con AWS Bedrock

De tu primer llamado a la Converse API en Python, hasta una arquitectura de producción con Bedrock Agents multi-agente, AgentCore y balanceo de carga entre regiones.

0 / 10 completado
Nivel 1 · Fundamentos

Tu primera llamada con la Converse API

Objetivo: configurar boto3, elegir un modelo en Bedrock y hacer tu primera llamada con la Converse API.

Amazon Bedrock da acceso a modelos de Anthropic, Meta, Amazon y otros bajo una sola API administrada por AWS. La Converse API es la forma moderna y recomendada de hablarle a cualquier modelo de Bedrock: una interfaz unificada, sin importar qué proveedor esté detrás.

1. Instala boto3 y configura credenciales

TERMINAL
pip install boto3 aws configure # o variables de entorno AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY # Habilita en la consola de Bedrock el acceso al modelo que vayas a usar

2. Tu primer llamado

agente.py
import boto3 bedrock = boto3.client("bedrock-runtime", region_name="us-east-1") respuesta = bedrock.converse( modelId="anthropic.claude-opus-5-v1:0", messages=[ {"role": "user", "content": [{"text": "¿Qué es un agente de IA, en una frase?"}]} ], inferenceConfig={"maxTokens": 300, "temperature": 0.3}, ) print(respuesta["output"]["message"]["content"][0]["text"])

La Converse API devuelve siempre la misma forma de respuesta sin importar el modelo — podés cambiar modelId de Claude a Llama o Nova sin tocar el resto del código.

Reto

Probá el mismo prompt con dos modelId distintos disponibles en tu cuenta y compará longitud y estilo de respuesta.

Nivel 2 · Personalidad

System prompt y parámetros de inferencia

Objetivo: controlar el comportamiento del modelo con system e inferenceConfig.

La Converse API separa el system prompt de los mensajes de conversación — así el modelo distingue claramente entre "quién sos" y "qué te están preguntando".

agente.py
respuesta = bedrock.converse( modelId="anthropic.claude-opus-5-v1:0", system=[{ "text": ( "Sos un asistente técnico de soporte. Respondé en español, " "de forma breve y con pasos numerados. Si no sabés algo, decilo." ) }], messages=[ {"role": "user", "content": [{"text": "La app se cierra al abrir la cámara"}]} ], inferenceConfig={"maxTokens": 400, "temperature": 0.2, "topP": 0.9}, )
  • temperature — precisión (bajo) vs. creatividad (alto)
  • maxTokens — límite de longitud, clave para controlar costo
  • topP — controla la diversidad del muestreo de tokens
Reto

Escribí un system prompt que obligue al modelo a responder siempre en formato JSON de una línea, sin texto extra.

Nivel 3 · Herramientas

Tool use con toolConfig

Objetivo: definir una herramienta con toolSpec y manejar el ciclo de llamada a función de la Converse API.

A diferencia de un SDK de agentes de alto nivel, con la Converse API vos manejás el bucle: el modelo devuelve un bloque toolUse, tu código ejecuta la función real, y le devolvés el resultado como toolResult en el siguiente turno.

agente_tools.py
tool_list = [{ "toolSpec": { "name": "clima_actual", "description": "Devuelve el clima actual de una ciudad", "inputSchema": {"json": { "type": "object", "properties": {"ciudad": {"type": "string", "description": "Nombre de la ciudad"}}, "required": ["ciudad"], }}, } }] mensajes = [{"role": "user", "content": [{"text": "¿Cómo está el clima en Ciudad de Guatemala?"}]}] resp = bedrock.converse( modelId="anthropic.claude-opus-5-v1:0", messages=mensajes, toolConfig={"tools": tool_list}, ) bloque = resp["output"]["message"]["content"][0] if "toolUse" in bloque: ciudad = bloque["toolUse"]["input"]["ciudad"] resultado = "22°C, parcialmente nublado" # tu función real iría aquí mensajes.append(resp["output"]["message"]) mensajes.append({ "role": "user", "content": [{"toolResult": { "toolUseId": bloque["toolUse"]["toolUseId"], "content": [{"text": resultado}], }}], }) resp = bedrock.converse(modelId="anthropic.claude-opus-5-v1:0", messages=mensajes, toolConfig={"tools": tool_list}) print(resp["output"]["message"]["content"][0]["text"])

Este patrón manual es exactamente lo que frameworks como Strands o LangChain automatizan por vos — entenderlo te ayuda a depurar cuando algo falla en capas más altas.

Reto

Agregá una segunda herramienta (una calculadora) al tool_list y probá un prompt que requiera ambas en la misma conversación.

Nivel 4 · Memoria

Historial de conversación

Objetivo: mantener contexto entre turnos manejando vos mismo la lista de messages.

La Converse API es stateless: no recuerda nada entre llamadas. La memoria conversacional es responsabilidad de tu aplicación — simplemente acumulás los mensajes anteriores en la misma lista que le mandás en cada llamada.

chat_con_memoria.py
historial = [] def hablar(texto): historial.append({"role": "user", "content": [{"text": texto}]}) resp = bedrock.converse(modelId="anthropic.claude-opus-5-v1:0", messages=historial) mensaje_modelo = resp["output"]["message"] historial.append(mensaje_modelo) return mensaje_modelo["content"][0]["text"] print(hablar("Busco una laptop para diseño gráfico")) print(hablar("¿Cuál es la más barata de las que me mencionaste?"))

Para producción, no acumulás el historial indefinidamente — lo truncás o resumís cada cierto número de turnos para no exceder la ventana de contexto ni pagar de más por tokens repetidos.

Reto

Modificá hablar() para que, cuando el historial supere 10 mensajes, resuma los primeros 6 en un solo mensaje de sistema y los reemplace.

Nivel 5 · Salida estructurada

Forzar JSON con una tool de respuesta

Objetivo: obtener datos validados en vez de texto libre, usando una herramienta como "esquema forzado".

Bedrock no tiene un parámetro nativo de "structured output" en la Converse API — el patrón estándar es definir una tool cuyo único propósito es forzar el schema de salida, y obligar al modelo a usarla con toolChoice.

salida_estructurada.py
tool_respuesta = [{ "toolSpec": { "name": "clasificar_ticket", "description": "Clasifica un ticket de soporte", "inputSchema": {"json": { "type": "object", "properties": { "categoria": {"type": "string", "enum": ["bug", "pregunta", "feature"]}, "urgencia": {"type": "string", "enum": ["baja", "media", "alta"]}, "resumen": {"type": "string"}, }, "required": ["categoria", "urgencia", "resumen"], }}, } }] resp = bedrock.converse( modelId="anthropic.claude-opus-5-v1:0", messages=[{"role": "user", "content": [{"text": "Se cierra la app al subir foto de perfil, urgente"}]}], toolConfig={"tools": tool_respuesta, "toolChoice": {"tool": {"name": "clasificar_ticket"}}}, ) datos = resp["output"]["message"]["content"][0]["toolUse"]["input"] print(datos) # {'categoria': 'bug', 'urgencia': 'alta', 'resumen': '...'}
Reto

Validá el input devuelto contra un modelo Pydantic para tener garantías de tipo además del schema JSON.

Nivel 6 · Streaming

ConverseStream para respuestas en vivo

Objetivo: usar converse_stream() para mostrar tokens a medida que llegan.

Para chats y APIs en producción, converse_stream devuelve un iterador de eventos en vez de esperar la respuesta completa.

stream.py
resp = bedrock.converse_stream( modelId="anthropic.claude-opus-5-v1:0", messages=[{"role": "user", "content": [{"text": "Explicame qué es RAG en 3 pasos"}]}], ) for evento in resp["stream"]: if "contentBlockDelta" in evento: delta = evento["contentBlockDelta"]["delta"] if "text" in delta: print(delta["text"], end="", flush=True)

Los eventos también incluyen messageStart, contentBlockStart (útil para detectar el inicio de un toolUse) y messageStop con el motivo de finalización.

Reto

Envolvé este stream en un generador async y exponelo desde un endpoint FastAPI con StreamingResponse.

Nivel 7 · Bedrock Agents

De la Converse API a Bedrock Agents

Objetivo: crear un agente administrado con el cliente bedrock-agent, que maneja el bucle de herramientas por vos.

Bedrock Agents es la capa administrada de AWS sobre todo lo que construiste a mano en los niveles anteriores: mantiene el bucle de razonamiento, ejecuta action groups (tus herramientas) y guarda sesión automáticamente.

crear_agente.py
import boto3 agent_client = boto3.client("bedrock-agent", region_name="us-east-1") respuesta = agent_client.create_agent( agentName="agente-soporte", foundationModel="anthropic.claude-opus-5-v1:0", instruction=( "Sos un agente de soporte técnico. Usá las herramientas disponibles " "para consultar el estado de tickets antes de responder." ), agentResourceRoleArn="arn:aws:iam::123456789012:role/BedrockAgentRole", ) agent_id = respuesta["agent"]["agentId"] print(f"Agente creado: {agent_id}") # Luego se agregan Action Groups (tus herramientas) y se invoca con # el cliente bedrock-agent-runtime -> invoke_agent()
Reto

Definí un Action Group con una función Lambda que consulte un estado de ticket ficticio, y probá invoke_agent() con una pregunta que lo dispare.

Nivel 8 · Orquestador

Multi-agent collaboration: supervisor + colaboradores

Objetivo: construir un agente supervisor que delega en agentes colaboradores especializados, usando la funcionalidad nativa de Bedrock.

Desde 2025, Bedrock soporta multi-agent collaboration de forma nativa: un agente supervisor coordina una red de agentes colaboradores especializados, cada uno resolviendo su parte del problema.

orquestador.py
agent_client.associate_agent_collaborator( agentId=supervisor_agent_id, agentVersion="DRAFT", agentDescriptor={"aliasArn": ventas_agent_alias_arn}, collaboratorName="especialista-ventas", collaborationInstruction="Delegar preguntas de precios y productos a este colaborador.", relayConversationHistory="TO_COLLABORATOR", ) agent_client.associate_agent_collaborator( agentId=supervisor_agent_id, agentVersion="DRAFT", agentDescriptor={"aliasArn": soporte_agent_alias_arn}, collaboratorName="especialista-soporte", collaborationInstruction="Delegar preguntas de bugs y errores técnicos a este colaborador.", relayConversationHistory="TO_COLLABORATOR", ) # El supervisor decide, en cada turno, a qué colaborador delegar

Esto es el equivalente nativo de AWS al patrón "orquestador + especialistas" que verías construir a mano con LangGraph o Strands — la diferencia es que acá AWS administra el enrutamiento, versión y ciclo de vida de cada agente colaborador.

Reto

Agregá un tercer colaborador de facturación y verificá en los logs de CloudWatch a cuál delega el supervisor ante una pregunta ambigua.

Nivel 9 · Producción

Observabilidad con AgentCore

Objetivo: instrumentar trazas de producción y entender AgentCore Runtime como capa de despliegue.

Amazon Bedrock AgentCore es el runtime serverless para desplegar agentes (construidos con Bedrock Agents, LangGraph, Strands o CrewAI) con observabilidad incorporada: cada paso de razonamiento, uso de herramienta e interacción con el modelo queda trazado.

habilitar observabilidad
# 1. Habilitar CloudWatch Transaction Search (una sola vez por cuenta) aws xray update-trace-segment-destination --destination CloudWatchLogs # 2. Desplegar el agente directamente desde código (Python 3.10-3.13) agentcore configure --entrypoint agente.py agentcore launch # AgentCore instrumenta automáticamente traces, tool calls y decisiones del modelo, # visibles en el dashboard de GenAI Observability de CloudWatch

Guardrails

  • Bedrock Guardrails para filtrar contenido dañino o fuera de tema antes/después del modelo
  • Límite de maxTokens y timeouts por invocación
  • Reintentos con backoff exponencial ante ThrottlingException
Reto

Configurá un Guardrail básico que bloquee temas fuera de tu dominio y probalo contra tu agente del Nivel 7.

Nivel 10 · Arquitectura final

AgentCore Runtime + balanceo de carga entre regiones

Objetivo: ensamblar una arquitectura de producción escalable: supervisor + colaboradores, desplegados en AgentCore, con carga distribuida.

AgentCore Runtime ya maneja el auto-escalado horizontal de cada agente por vos (es serverless). Lo que se agrega en este nivel es distribuir la carga de inferencia entre regiones y desacoplar picos de tráfico con una cola.

1. Perfiles de inferencia entre regiones

balanceo entre regiones
respuesta = bedrock.converse( # Un cross-region inference profile reparte la carga automáticamente # entre varias regiones de AWS que tengan el modelo disponible modelId="us.anthropic.claude-opus-5-v1:0", messages=[{"role": "user", "content": [{"text": "..."}]}], ) # AWS decide a qué región enviar cada request según capacidad disponible, # reduciendo throttling en picos de tráfico

2. Cola para desacoplar el supervisor de los colaboradores

arquitectura final
Cliente │ ▼ API Gateway │ ▼ Agente Supervisor (Bedrock Agents, en AgentCore Runtime) │ ▼ Cola SQS (desacopla picos de tráfico) │ ├──▶ Cross-region inference profile ──▶ [Colaborador Ventas] ├──▶ Cross-region inference profile ──▶ [Colaborador Soporte] └──▶ Cross-region inference profile ──▶ [Colaborador Facturación] │ ▼ CloudWatch + X-Ray (trazas end-to-end)

Con esto tenés el camino completo: de un converse() de una línea en el Nivel 1, a una arquitectura multi-región con supervisor, colaboradores especializados y observabilidad de punta a punta, toda administrada por AWS.

Reto final

Desplegá el supervisor del Nivel 8 en AgentCore Runtime y medí la latencia con y sin el cross-region inference profile bajo carga simulada.