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.
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.
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
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.