Saltar al contenido principal

Decisiones de Diseño en Sistemas IA

¿REST, GraphQL, o gRPC? ¿API de OpenAI o self-hosted? ¿SQL o vector database?

Las decisiones arquitectónicas en sistemas IA no son opcionales. Un error aquí multiplica los problemas downstream. Esta guía te ayuda a tomar decisiones fundamentadas.

🏗️ API Design: ¿Cómo Expones tus Agentes?

REST: Simple pero Limitado

// Para agentes simples con llamadas directas
POST /api/agents/analyze
Content-Type: application/json

{
"task": "analyze codebase",
"files": ["src/**/*.ts"],
"output": "summary"
}

Cuándo usar REST:

  • Agentes con interfaces predecibles
  • Equipos pequeños (< 5 personas)
  • Prototipos rápidos
  • Integración con sistemas legacy

Tradeoffs: ✅ Simple de entender y debuggear ✅ Herramientas maduras (Postman, curl) ❌ Streaming limitado para respuestas largas ❌ Schema evolution complicado

GraphQL: Flexible pero Complejo

# Para agentes que necesitan queries complejas
query AnalyzeRepository($owner: String!, $repo: String!) {
agent(task: "security_audit") {
findings(type: VULNERABILITY) {
file
line
severity
description
}
metrics {
complexity
coverage
}
}
}

Cuándo usar GraphQL:

  • Interfaces dinámicas según el tipo de agente
  • Equipos medianos (5-15 personas)
  • Productos con múltiples consumidores
  • Evolución frecuente de requirements

Tradeoffs: ✅ Queries precisas, menos over/under-fetching ✅ Schema fuerte con type safety ❌ Complejidad inicial alta ❌ Caching más complicado

gRPC: Performance pero Verbose

// Para agentes de alta performance
service AgentService {
rpc AnalyzeStream(stream AnalysisRequest) returns (stream AnalysisResponse);
}

message AnalysisRequest {
string task = 1;
repeated string files = 2;
AnalysisOptions options = 3;
}

Cuándo usar gRPC:

  • Agentes con streaming en tiempo real
  • Microservicios con agentes especializados
  • Equipos grandes (> 15 personas)
  • Requisitos de baja latencia

Tradeoffs: ✅ Mejor performance que REST/GraphQL ✅ Streaming nativo bidireccional ❌ Debugging más difícil ❌ Herramientas menos maduras

🗄️ Storage: ¿Dónde Guardas el Conocimiento?

Vector Databases: Para Contexto Semántico

// Pinecone, Weaviate, Qdrant
const vectorStore = new PineconeStore({
apiKey: process.env.PINECONE_API_KEY,
indexName: 'agent-knowledge'
});

// Embedding del código para búsqueda semántica
const embedding = await openai.embeddings.create({
model: "text-embedding-3-small",
input: codeSnippet
});

await vectorStore.addDocuments([
new Document({
pageContent: codeSnippet,
metadata: { file: 'src/agent.ts', type: 'function' },
embedding
})
]);

Cuándo usar Vector DB:

  • RAG (Retrieval-Augmented Generation)
  • Búsqueda semántica en código/documentos
  • Agentes que necesitan contexto amplio
  • Sistemas de recomendación

SQL Databases: Para Datos Estructurados

-- PostgreSQL con pgvector para híbrido
CREATE TABLE agent_memories (
id UUID PRIMARY KEY,
agent_id VARCHAR(50) NOT NULL,
type VARCHAR(20) NOT NULL, -- 'conversation', 'learning', 'error'
content TEXT NOT NULL,
embedding vector(1536), -- OpenAI ada-002
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX ON agent_memories USING ivfflat (embedding vector_cosine_ops);

Cuándo usar SQL:

  • Datos relacionales (usuarios, proyectos, permisos)
  • Queries complejas con joins
  • Transacciones ACID
  • Reporting y analytics

Redis: Para Cache y Sesiones

// Cache de embeddings frecuentes
const cacheKey = `embedding:${hash(codeSnippet)}`;
const cached = await redis.get(cacheKey);
if (!cached) {
const embedding = await openai.embeddings.create({...});
await redis.setex(cacheKey, 3600, JSON.stringify(embedding)); // 1 hora
}

Cuándo usar Redis:

  • Cache de resultados costosos
  • Sesiones de agentes
  • Rate limiting
  • Pub/sub entre agentes

🤖 LLM Selection: ¿API o Self-Hosted?

API Services: Fácil pero Dependiente

// OpenAI/Claude APIs
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});

const response = await client.chat.completions.create({
model: "gpt-4-turbo-preview",
messages: [{ role: "user", content: task }],
tools: agentTools,
temperature: 0.1 // Baja para consistencia
});

Cuándo usar APIs:

  • Prototipos y MVPs
  • Equipos pequeños sin infra expertise
  • Presupuesto flexible
  • Modelos actualizados automáticamente

Tradeoffs: ✅ Cero mantenimiento de modelos ✅ Modelos state-of-the-art ❌ Costos variables impredecibles ❌ Dependencia de terceros ❌ Rate limits y downtime

Self-Hosted: Control pero Complejidad

# Docker Compose para vLLM
version: '3.8'
services:
vllm:
image: vllm/vllm-openai:latest
ports:
- "8000:8000"
environment:
- MODEL_NAME=meta-llama/Llama-2-70b-chat-hf
- TOKENIZERS_PARALLELISM=false
volumes:
- ./models:/root/.cache/huggingface
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 2
capabilities: [gpu]

Cuándo usar Self-Hosted:

  • Aplicaciones críticas con SLA estrictos
  • Datos sensibles (compliance)
  • Costos predecibles a largo plazo
  • Equipos con expertise en MLOps

Tradeoffs: ✅ Control total sobre modelos y datos ✅ Costos predecibles ❌ Mantenimiento complejo ❌ Hardware costoso (GPUs) ❌ Model updates manuales

🚀 Deployment: ¿Serverless o Containers?

Serverless: Escalado Automático

# AWS Lambda para agentes simples
functions:
analyzeCode:
handler: src/handlers/analyze.handler
runtime: nodejs20.x
timeout: 900 # 15 minutos máximo
memorySize: 2048
environment:
OPENAI_API_KEY: ${env:OPENAI_API_KEY}

Cuándo usar Serverless:

  • Agentes con carga variable
  • Equipos sin DevOps
  • Costos basados en uso real
  • Prototipos rápidos

Tradeoffs: ✅ Escalado automático ✅ Cero mantenimiento de servers ❌ Timeouts estrictos (15 min Lambda) ❌ Cold starts ❌ Vendor lock-in

Containers: Control Completo

# Multi-stage para agentes optimizados
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:20-alpine AS runtime
RUN apk add --no-cache dumb-init
USER node
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist

EXPOSE 3000
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/server.js"]

Cuándo usar Containers:

  • Agentes complejos con dependencias
  • Equipos con Kubernetes expertise
  • Aplicaciones stateful
  • Requisitos de compliance específicos

Tradeoffs: ✅ Control total del runtime ✅ Portabilidad entre clouds ❌ Orquestación compleja (Kubernetes) ❌ Costos de gestión de infraestructura

🎯 Decision Tree: ¿Qué Elegir Según tu Caso?

¿Equipo pequeño (< 5 devs) Y prototipo?
├── SÍ → REST + API services + Serverless
└── NO → ¿Datos sensibles o compliance?
├── SÍ → gRPC + Self-hosted + Containers
└── NO → ¿Performance crítica?
├── SÍ → GraphQL + Vector DB + Self-hosted + Containers
└── NO → REST + SQL + API services + Serverless

⚠️ Decisiones que te Arrepentirás

  • Empezar con API sin plan de migración: Los costos se disparan
  • Vector DB para todo: No todo es búsqueda semántica
  • Serverless para agentes stateful: Pierdes estado entre llamadas
  • Self-hosted sin MLOps: Actualizaciones de modelos son un infierno

Recuerda: Las decisiones arquitectónicas se pagan caro cambiar después. Toma tiempo para evaluar tradeoffs antes de comprometerte.