· nervico-team · arquitectura-cloud  · 11 min read

AWS Bedrock para IA: integración con agentes y aplicaciones

Guía técnica de AWS Bedrock: cómo integrar modelos fundacionales en aplicaciones, construir agentes de IA, implementar RAG y gestionar costes de inferencia en producción.

Guía técnica de AWS Bedrock: cómo integrar modelos fundacionales en aplicaciones, construir agentes de IA, implementar RAG y gestionar costes de inferencia en producción.

Integrar IA generativa en una aplicación de producción no es llamar a una API y mostrar la respuesta. Es gestionar latencia, costes, alucinaciones, seguridad de datos y disponibilidad. Y hacerlo en una infraestructura que ya tienes en AWS, sin mover datos a proveedores externos y sin gestionar GPUs.

AWS Bedrock es el servicio que resuelve ese problema. Ofrece acceso a modelos fundacionales de Anthropic (Claude), Meta (Llama), Mistral, Amazon (Titan) y otros, a través de una API unificada, sin necesidad de aprovisionar infraestructura de ML. Los datos no salen de tu cuenta de AWS. No se usan para entrenar los modelos. Y el escalado es automático.

Este artículo explica cómo funciona Bedrock en la práctica, cómo integrar modelos en aplicaciones, cómo construir agentes que ejecutan acciones, cómo implementar RAG con datos de tu empresa, y cuánto cuesta realmente.

Qué es AWS Bedrock

Servicio gestionado de modelos fundacionales

Bedrock no es un modelo de IA. Es una plataforma que da acceso a múltiples modelos a través de una API estándar. No necesitas entrenar modelos, gestionar GPUs ni instalar frameworks de ML.

Modelos disponibles (principales):

ProveedorModeloContextoFortaleza
AnthropicClaude 3.5 Sonnet200K tokensRazonamiento, código, análisis
AnthropicClaude 3 Haiku200K tokensVelocidad, coste bajo
MetaLlama 3.1 70B128K tokensOpen source, personalizable
MetaLlama 3.1 8B128K tokensTareas ligeras, coste mínimo
MistralMistral Large128K tokensMultilingue, europeo
AmazonTitan Text Express8K tokensCoste bajo, tareas simples

Lo que Bedrock gestiona por ti:

  • Infraestructura de inferencia (GPUs, escalado, disponibilidad)
  • Versionado de modelos
  • Seguridad y compliance (datos en tu VPC, cifrado en tránsito y en reposo)
  • Logging y monitorización con CloudWatch
  • Rate limiting y throttling automático

Lo que Bedrock no hace

  • No entrena modelos custom desde cero. Permite fine-tuning de algunos modelos, pero no entrenamiento completo.
  • No garantiza latencia constante. Los tiempos de respuesta varían entre 1-30 segundos según el modelo y la longitud del prompt.
  • No elimina alucinaciones. Los modelos siguen generando información incorrecta. Bedrock proporciona guardrails, pero la responsabilidad de la verificación es tuya.

Integración básica con la API

Invocación de modelos

La forma más directa de usar Bedrock es la API InvokeModel:

import boto3
import json

bedrock_runtime = boto3.client(
    service_name='bedrock-runtime',
    region_name='us-east-1'
)

def invoke_claude(prompt, max_tokens=1024):
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": max_tokens,
        "messages": [
            {
                "role": "user",
                "content": prompt
            }
        ],
        "temperature": 0.3
    })

    response = bedrock_runtime.invoke_model(
        modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
        body=body,
        contentType="application/json",
        accept="application/json"
    )

    result = json.loads(response['body'].read())
    return result['content'][0]['text']

# Ejemplo de uso
respuesta = invoke_claude(
    "Analiza este log de errores y sugiere la causa raíz: "
    "ERROR 2025-10-01 14:23:45 ConnectionPool exhausted, "
    "max connections: 50, active: 50, waiting: 127"
)
print(respuesta)

Streaming para respuestas largas

Para respuestas largas, el streaming reduce la latencia percibida:

def invoke_claude_streaming(prompt, max_tokens=2048):
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": max_tokens,
        "messages": [
            {"role": "user", "content": prompt}
        ],
        "temperature": 0.3
    })

    response = bedrock_runtime.invoke_model_with_response_stream(
        modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
        body=body,
        contentType="application/json",
        accept="application/json"
    )

    full_response = ""
    for event in response['body']:
        chunk = json.loads(event['chunk']['bytes'])
        if chunk['type'] == 'content_block_delta':
            text = chunk['delta'].get('text', '')
            full_response += text
            print(text, end='', flush=True)

    return full_response

Converse API: interfaz unificada

La Converse API es la forma recomendada de interactuar con Bedrock desde 2024. Proporciona una interfaz consistente independientemente del modelo:

def converse_with_model(messages, model_id, system_prompt=None):
    kwargs = {
        "modelId": model_id,
        "messages": messages,
        "inferenceConfig": {
            "maxTokens": 2048,
            "temperature": 0.3,
            "topP": 0.9
        }
    }

    if system_prompt:
        kwargs["system"] = [{"text": system_prompt}]

    response = bedrock_runtime.converse(**kwargs)
    return response['output']['message']['content'][0]['text']

# Uso con conversación multi-turno
messages = [
    {
        "role": "user",
        "content": [{"text": "Soy CTO de una startup SaaS con 50K usuarios. Estamos en AWS."}]
    },
    {
        "role": "assistant",
        "content": [{"text": "Entendido. Puedo ayudarte con arquitectura, costes u operaciones en AWS."}]
    },
    {
        "role": "user",
        "content": [{"text": "Nuestra base de datos RDS está al 85% de CPU. Opciones?"}]
    }
]

respuesta = converse_with_model(
    messages=messages,
    model_id="anthropic.claude-3-5-sonnet-20241022-v2:0",
    system_prompt="Eres un arquitecto AWS senior. Responde con opciones concretas y costes estimados."
)

Bedrock Agents: IA que ejecuta acciones

Qué son los Bedrock Agents

Los Bedrock Agents van más allá de generar texto. Pueden razonar sobre una tarea, decidir qué acciones ejecutar y llamar a APIs externas para completar el trabajo. El agente recibe una instrucción en lenguaje natural, descompone la tarea en pasos, ejecuta cada paso llamando a las herramientas disponibles, y devuelve el resultado.

Usuario: "Busca los pedidos del cliente ACME del último mes
          y genera un resumen con el total facturado"

Agente:
  1. Llama a la API de pedidos con filtro: cliente=ACME, fecha=último mes
  2. Recibe la lista de pedidos
  3. Calcula el total facturado
  4. Genera un resumen en lenguaje natural
  5. Devuelve el resultado al usuario

Configuración de un agente

Un Bedrock Agent se compone de:

  • Instrucciones: El prompt de sistema que define el comportamiento del agente.
  • Action Groups: Las herramientas que el agente puede usar, definidas como API schemas (OpenAPI).
  • Knowledge Bases: Bases de conocimiento (RAG) que el agente puede consultar.
import boto3

bedrock_agent = boto3.client('bedrock-agent', region_name='us-east-1')

# Crear agente
response = bedrock_agent.create_agent(
    agentName='customer-support-agent',
    agentResourceRoleArn='arn:aws:iam::123456789:role/bedrock-agent-role',
    foundationModel='anthropic.claude-3-5-sonnet-20241022-v2:0',
    instruction="""
    Eres un agente de soporte técnico para una plataforma SaaS.
    Tu objetivo es ayudar a los clientes a resolver problemas técnicos.

    Reglas:
    - Consulta el historial del cliente antes de responder.
    - Si el problema requiere escalado, crea un ticket en el sistema.
    - Nunca compartas información de un cliente con otro.
    - Responde siempre en el idioma del cliente.
    """,
    idleSessionTTLInSeconds=1800
)

Action Group con OpenAPI schema:

openapi: 3.0.0
info:
  title: Customer API
  version: 1.0.0
paths:
  /customers/{customerId}/orders:
    get:
      summary: Get customer orders
      operationId: getCustomerOrders
      parameters:
        - name: customerId
          in: path
          required: true
          schema:
            type: string
        - name: dateFrom
          in: query
          schema:
            type: string
            format: date
        - name: dateTo
          in: query
          schema:
            type: string
            format: date
      responses:
        '200':
          description: List of orders
  /tickets:
    post:
      summary: Create support ticket
      operationId: createTicket
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                customerId:
                  type: string
                subject:
                  type: string
                priority:
                  type: string
                  enum: [low, medium, high, critical]
                description:
                  type: string

El agente decide cuándo y cómo llamar a cada endpoint basándose en la conversación con el usuario. No necesitas programar la lógica de decisión: el modelo fundacional la gestiona.

RAG con Bedrock Knowledge Bases

Qué es RAG y por qué importa

RAG (Retrieval-Augmented Generation) es el patrón que permite a un modelo de IA responder preguntas sobre los datos de tu empresa. En lugar de depender solo del conocimiento con el que fue entrenado, el modelo busca información relevante en tus documentos y la usa como contexto para generar la respuesta.

Sin RAG, el modelo alucinará sobre datos que no conoce. Con RAG, el modelo basa sus respuestas en documentos reales que tú controlas.

Configuración de Knowledge Base

Bedrock Knowledge Bases gestiona el pipeline completo de RAG:

  1. Ingestión: Carga documentos desde S3 (PDF, Word, HTML, texto plano, CSV).
  2. Chunking: Divide los documentos en fragmentos de tamaño configurable.
  3. Embedding: Convierte cada fragmento en un vector numérico usando un modelo de embedding.
  4. Almacenamiento: Guarda los vectores en una base de datos vectorial (OpenSearch Serverless, Aurora PostgreSQL con pgvector, Pinecone).
  5. Consulta: Cuando el usuario hace una pregunta, Bedrock busca los fragmentos más relevantes y los incluye en el prompt del modelo.
# Crear Knowledge Base
response = bedrock_agent.create_knowledge_base(
    name='product-documentation',
    description='Documentación técnica del producto',
    roleArn='arn:aws:iam::123456789:role/bedrock-kb-role',
    knowledgeBaseConfiguration={
        'type': 'VECTOR',
        'vectorKnowledgeBaseConfiguration': {
            'embeddingModelArn': 'arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v2:0'
        }
    },
    storageConfiguration={
        'type': 'OPENSEARCH_SERVERLESS',
        'opensearchServerlessConfiguration': {
            'collectionArn': 'arn:aws:aoss:us-east-1:123456789:collection/my-collection',
            'vectorIndexName': 'product-docs-index',
            'fieldMapping': {
                'vectorField': 'embedding',
                'textField': 'text',
                'metadataField': 'metadata'
            }
        }
    }
)

Estrategias de chunking

La forma en que divides los documentos afecta directamente a la calidad de las respuestas:

Fixed-size chunking: Divide en fragmentos de N tokens (300-500 es el rango óptimo para la mayoría de casos). Simple pero puede cortar información a mitad de una idea.

Hierarchical chunking: Crea chunks padre (secciones completas) y chunks hijo (párrafos). La búsqueda opera sobre los chunks hijo, pero el contexto incluye el chunk padre. Mejora la coherencia de las respuestas.

Semantic chunking: Divide en puntos donde el significado cambia. Más complejo de implementar pero produce fragmentos más coherentes.

# Configurar data source con chunking jerárquico
response = bedrock_agent.create_data_source(
    knowledgeBaseId='kb-123456',
    name='technical-docs',
    dataSourceConfiguration={
        'type': 'S3',
        's3Configuration': {
            'bucketArn': 'arn:aws:s3:::my-docs-bucket',
            'inclusionPrefixes': ['docs/']
        }
    },
    vectorIngestionConfiguration={
        'chunkingConfiguration': {
            'chunkingStrategy': 'HIERARCHICAL',
            'hierarchicalChunkingConfiguration': {
                'levelConfigurations': [
                    {'maxTokens': 1500},  # Chunks padre
                    {'maxTokens': 300}    # Chunks hijo
                ],
                'overlapTokens': 60
            }
        }
    }
)

Guardrails: control de la IA

Bedrock Guardrails

Los guardrails permiten definir políticas que el modelo debe cumplir. Filtran contenido no deseado, bloquean temas sensibles y verifican que las respuestas cumplen tus criterios.

Tipos de guardrails:

  • Content filters: Bloquean contenido violento, sexual, discriminatorio o de odio.
  • Denied topics: Impiden que el modelo hable sobre temas específicos (competidores, información financiera no pública, opiniones políticas).
  • Word filters: Bloquean palabras o frases específicas en la respuesta.
  • Sensitive information filters: Detectan y redactan PII (nombres, emails, números de teléfono, números de tarjeta de crédito).
  • Contextual grounding: Verifican que la respuesta se basa en el contexto proporcionado (reduce alucinaciones en RAG).
# Crear guardrail
response = bedrock_agent.create_guardrail(
    name='production-guardrail',
    description='Guardrail para producción',
    contentPolicyConfig={
        'filtersConfig': [
            {'type': 'SEXUAL', 'inputStrength': 'HIGH', 'outputStrength': 'HIGH'},
            {'type': 'VIOLENCE', 'inputStrength': 'HIGH', 'outputStrength': 'HIGH'},
            {'type': 'HATE', 'inputStrength': 'HIGH', 'outputStrength': 'HIGH'}
        ]
    },
    topicPolicyConfig={
        'topicsConfig': [
            {
                'name': 'competitor-information',
                'definition': 'Información sobre productos o servicios de competidores',
                'examples': [
                    'Que opinas de [Competidor X]?',
                    'Es mejor tu producto o el de [Competidor Y]?'
                ],
                'type': 'DENY'
            }
        ]
    },
    sensitiveInformationPolicyConfig={
        'piiEntitiesConfig': [
            {'type': 'EMAIL', 'action': 'ANONYMIZE'},
            {'type': 'PHONE', 'action': 'ANONYMIZE'},
            {'type': 'CREDIT_DEBIT_CARD_NUMBER', 'action': 'BLOCK'}
        ]
    }
)

Costes de Bedrock

Modelo de facturación

Bedrock cobra por tokens procesados. La facturación separa tokens de entrada (prompt) y tokens de salida (respuesta):

ModeloInput (1M tokens)Output (1M tokens)
Claude 3.5 Sonnet3,00 $15,00 $
Claude 3 Haiku0,25 $1,25 $
Llama 3.1 70B2,65 $3,50 $
Llama 3.1 8B0,22 $0,22 $
Titan Text Express0,20 $0,60 $

Provisioned Throughput

Para cargas de trabajo predecibles, Provisioned Throughput ofrece capacidad reservada:

  • Garantiza un número mínimo de tokens por minuto.
  • Coste fijo por hora (independiente del uso).
  • Útil si procesas más de 100.000 peticiones al día con el mismo modelo.

Ejemplo de coste mensual

Caso de usoModeloPeticiones/mesTokens promedio (in/out)Coste mensual
Chatbot soporte (bajo)Haiku10.000500/2003,75 $
Chatbot soporte (medio)Sonnet50.0001.000/500525 $
Análisis de documentosSonnet5.0005.000/2.000225 $
RAG empresarialSonnet + embedding20.0002.000/1.000420 $

Optimización de costes:

  1. Usa el modelo más pequeño que funcione: Para clasificación de texto o extracción simple, Haiku es 12 veces más barato que Sonnet y responde en milisegundos.
  2. Reduce el prompt: Cada token innecesario en el system prompt se multiplica por el número de peticiones. Un system prompt de 500 tokens con 100.000 peticiones/mes cuesta 150 dolares adicionales con Sonnet.
  3. Cachea respuestas para consultas repetitivas: Si el 20% de las preguntas se repiten, una caché en ElastiCache o DynamoDB reduce costes un 20%.

Arquitectura de producción

Patrón completo

Cliente → API Gateway → Lambda → Bedrock Runtime
                                     |
                           ┌─────────┼─────────┐
                           │         │         │
                      Guardrails  Knowledge  Agent
                                   Base     Actions
                                     |         |
                                OpenSearch   Lambda
                                  (RAG)    (tools)

Componentes:

  • API Gateway: Punto de entrada con autenticación y rate limiting.
  • Lambda: Orquesta la llamada a Bedrock, gestiona el contexto de la conversación y aplica lógica de negocio.
  • Bedrock Runtime: Ejecuta la inferencia del modelo.
  • Guardrails: Filtra entrada y salida.
  • Knowledge Base: Proporciona contexto RAG.
  • Agent Actions: Ejecuta herramientas (consultas a base de datos, llamadas a APIs internas).

Gestión del estado de conversación

Bedrock no mantiene estado entre llamadas. Tu aplicación debe gestionar el historial de la conversación:

import boto3
from datetime import datetime

dynamodb = boto3.resource('dynamodb')
conversations_table = dynamodb.Table('conversations')

def get_conversation_history(session_id, max_messages=20):
    response = conversations_table.get_item(
        Key={'session_id': session_id}
    )
    if 'Item' in response:
        messages = response['Item'].get('messages', [])
        return messages[-max_messages:]
    return []

def save_message(session_id, role, content):
    conversations_table.update_item(
        Key={'session_id': session_id},
        UpdateExpression='SET messages = list_append(if_not_exists(messages, :empty), :msg), updated_at = :now',
        ExpressionAttributeValues={
            ':msg': [{'role': role, 'content': content, 'timestamp': datetime.utcnow().isoformat()}],
            ':empty': [],
            ':now': datetime.utcnow().isoformat()
        }
    )

Errores comunes al integrar IA con Bedrock

Error 1: no gestionar la latencia

Una llamada a Claude 3.5 Sonnet con un prompt de 2.000 tokens tarda 3-8 segundos. Si tu API tiene un timeout de 3 segundos, las peticiones fallarán intermitentemente. Configura timeouts generosos (30-60 segundos) y usa streaming para mejorar la experiencia percibida.

Error 2: prompts de sistema demasiado largos

Cada token del system prompt se procesa en cada invocación. Un system prompt de 3.000 tokens con 50.000 peticiones al mes cuesta 450 dolares adicionales solo en tokens de entrada con Sonnet. Sé conciso.

Error 3: no implementar fallbacks

Si Bedrock devuelve un error (throttling, timeout, error del modelo), tu aplicación no debería mostrar un error genérico. Implementa:

  • Retry con backoff exponencial para errores transitorios.
  • Fallback a un modelo más ligero si el modelo principal no está disponible.
  • Respuestas predefinidas para preguntas frecuentes que no necesitan IA.

Error 4: ignorar la seguridad de los prompts

Los usuarios pueden intentar inyectar instrucciones en el prompt para manipular el comportamiento del modelo. Usa guardrails, valida la entrada del usuario y nunca incluyas datos sensibles en el prompt que no quieras que el modelo pueda repetir.

Conclusión

AWS Bedrock simplifica la integración de IA generativa en aplicaciones de producción. Elimina la gestión de infraestructura de ML, mantiene los datos dentro de tu cuenta de AWS y proporciona herramientas de seguridad como guardrails y cifrado nativo.

Pero no es magia. Los modelos alucinan, la latencia es variable, y los costes se acumulan rápido si no optimizas los prompts y los modelos. La clave es empezar simple (una llamada API con el modelo adecuado), añadir RAG cuando necesites respuestas basadas en datos propios, y construir agentes solo cuando la tarea requiera ejecutar acciones.

Si estás evaluando cómo integrar IA en tu producto o necesitas ayuda para diseñar una arquitectura de IA en AWS, nuestro equipo tiene experiencia directa con Bedrock en producción. Solicita una auditoría gratuita para evaluar las oportunidades de IA en tu aplicación.

Back to Blog

Related Posts

View All Posts »