M6 — AI / Agentic
Outcome del módulo: un mini-RAG o agente demostrable, con evals, integrado como feature real (no demo aislada). Explicar por qué cada decisión (chunking, modelo, retrieval) y probarlo con una eval.
Regla del módulo: cualquiera llama a un LLM; el valor está en lo que lo rodea — retrieval, evals, control de costo/latencia y confiabilidad. Ahí está el diferenciador de backend, no en el prompt.
Concepto 1 — Fundamentos LLM (tokens, context, structured output, tool calling)
Idea núcleo: un LLM predice tokens dado un contexto acotado. Para backend, lo que importa es controlar entrada/salida: límites de contexto, salida estructurada y llamadas a funciones.
Entender (capa 1)
Texto:
- Tokens: el modelo no ve palabras sino tokens (~¾ de palabra). Costo y límites se miden en tokens.
- Context window: cuántos tokens entran (prompt + respuesta). Excederlo = truncamiento/error → por eso RAG (traer solo lo relevante).
- Structured output: forzar que la respuesta cumpla un schema (JSON/pydantic) en vez de texto libre — clave para integrar en código.
- Function/tool calling: el modelo pide ejecutar una función (con args tipados) y vos la corrés; base de los agentes.
Visual:
flowchart LR
P[prompt + contexto] --> LLM[LLM]
LLM -->|texto| T[respuesta libre]
LLM -->|schema| S[JSON/pydantic validado]
LLM -->|tool call| F[pide ejecutar función args]
Video: How LLMs Work - Tokens, Context Windows, and API Costs Explained — Data Whisperer Academy
Ejemplo (structured output):
from pydantic import BaseModel
class Extraction(BaseModel):
name: str
amount: float
currency: str
# pedir al LLM que devuelva EXACTA esta estructura → parseable, integrable
result: Extraction = llm.extract(text, schema=Extraction)
Fijar (capa 2)
Nota atómica:
- Front: ¿por qué structured output es clave en backend con LLMs?
- Back: porque el texto libre no es parseable de forma confiable; forzar un schema (JSON/pydantic) hace la salida determinista de forma, integrable en código y validable — convierte al LLM en un componente, no en una caja de texto.
Feynman: “Texto libre es pedirle a alguien que te cuente algo y transcribirlo a mano. Structured output es darle un formulario: llena los campos exactos que tu sistema espera.”
Aplicar (capa 3)
Hacé una extracción con structured output (pydantic) sobre un texto. Contá los tokens de entrada/salida. Definí una tool y hacé que el modelo la invoque.
Límites
- Más contexto no es mejor: cuesta más, agrega latencia y puede “perderse en el medio”. Contexto relevante > contexto largo.
Concepto 2 — RAG (Retrieval-Augmented Generation)
Idea núcleo: en vez de meter todo al prompt, recuperás solo los fragmentos relevantes de tu base de conocimiento y se los das al modelo. Respuestas fundadas en tus datos, sin reentrenar.
Entender (capa 1)
Texto: pipeline: (1) chunking — partir documentos en fragmentos; (2) embeddings — convertir cada chunk en un vector; (3) guardarlos en un vector store; (4) en la query, embeber la pregunta y traer los chunks más cercanos (retrieval); (5) opcional reranking para ordenar mejor; (6) pasar esos chunks como contexto al LLM.
Visual:
flowchart LR
subgraph Ingesta
D[docs] --> CH[chunking] --> EMB[embeddings] --> VS[(vector store)]
end
subgraph Query
Q[pregunta] --> QE[embedding] --> RET[retrieve top-k] --> RR[rerank] --> CTX[contexto] --> LLM[LLM] --> A[respuesta fundada]
end
VS --> RET
Video: What is Retrieval-Augmented Generation (RAG)? — IBM Technology
Ejemplo (conceptual):
# ingesta
for chunk in chunk_document(doc, size=500, overlap=50):
store.add(embed(chunk), metadata={"source": doc.id})
# query
hits = store.search(embed(pregunta), top_k=5)
contexto = "\n".join(h.text for h in hits)
respuesta = llm.answer(pregunta, context=contexto) # fundada en TUS datos
Fijar (capa 2)
Nota atómica:
- Front: ¿qué problema resuelve RAG frente a meter todo en el prompt o reentrenar?
- Back: el context window es limitado y reentrenar es caro/lento. RAG trae solo los chunks relevantes en runtime → respuestas fundadas en datos propios/actualizados, barato, sin tocar el modelo. El chunking y el retrieval son donde se gana o se pierde calidad.
Feynman: “RAG es un examen a libro abierto: no memorizás toda la enciclopedia (reentrenar) ni la cargás entera al escritorio (prompt gigante). Buscás las 3 páginas que necesitás y respondés con eso a la vista.”
Aplicar (capa 3)
Armá un mini-RAG sobre un set de docs público: chunking + embeddings + pgvector + retrieval top-k. Probá con 5 preguntas y observá qué chunks trae.
Límites
- Garbage in, garbage out: mal chunking (muy grande/chico) o embeddings pobres = retrieval malo = respuesta mala. El LLM no arregla un mal retrieval.
Concepto 3 — Vector stores
Idea núcleo: una DB especializada en búsqueda por similitud de vectores (nearest neighbor), no por igualdad exacta.
Entender (compacto):
- pgvector: extensión de Postgres — vectores en tu DB relacional. Ideal si ya usás Postgres (una sola DB, menos infra).
- Pinecone / Weaviate: vector DBs dedicadas, gestionadas, para escala grande.
- Chroma: liviana, buena para prototipos/local.
- Búsqueda = distancia (coseno/euclidiana) entre el vector de la query y los almacenados; índices ANN (HNSW) para que sea rápido a escala. Video: Vector Search in PostgreSQL Using pgvector: A Complete Tutorial — InterviewBuddies Nota atómica: Front: ¿cuándo pgvector y cuándo una vector DB dedicada? Back: pgvector si ya usás Postgres y el volumen es moderado (una sola DB, menos operación). Dedicada (Pinecone/Weaviate) cuando el volumen/latencia a escala lo justifica. Empezar por pgvector suele ser lo pragmático. Feynman: “Una DB normal busca coincidencias exactas (‘dame el usuario con id 7’). Un vector store busca lo más parecido (‘dame los 5 textos que significan algo similar a esto’), aunque no compartan ni una palabra.” Aplicar: guardá embeddings en pgvector y hacé una búsqueda top-k por similitud coseno. Límites: la calidad depende del modelo de embeddings; cambiar de modelo obliga a re-embeber todo.
Concepto 4 — Agentes (LangGraph, tool-calling, estado)
Idea núcleo: un agente es un LLM en un loop que decide acciones (llamar tools), observa resultados y sigue, hasta cumplir un objetivo. LangGraph modela ese loop como un grafo de estados.
Entender (capa 1)
Texto: a diferencia de una llamada única, el agente itera: piensa → elige una tool → ejecuta → observa → decide el siguiente paso. LangGraph te da un grafo explícito (nodos = pasos, edges = transiciones) con estado compartido, en vez de un loop implícito difícil de controlar/debuggear.
Visual:
flowchart TD
START[objetivo] --> THINK[LLM decide]
THINK -->|usar tool| TOOL[ejecuta tool] --> OBS[observa resultado] --> THINK
THINK -->|listo| END[respuesta final]
Video: Introduction to LangGraph — LangChain (oficial)
Ejemplo (conceptual):
# nodos con estado compartido; el grafo controla el flujo
from langgraph.graph import END # sentinel real del nodo terminal (no el string "END")
graph.add_node("plan", plan_step)
graph.add_node("act", call_tool)
graph.add_edge("plan", "act")
graph.add_conditional_edges("act", lambda s: "plan" if not s.done else END)
Fijar (capa 2)
Nota atómica:
- Front: ¿qué ventaja da LangGraph sobre un loop de agente casero?
- Back: modela el flujo como grafo explícito con estado (nodos/edges/condiciones), lo que hace el comportamiento controlable, inspeccionable, reanudable y testeable — en vez de un while-loop implícito con prompts, difícil de debuggear y con riesgo de loops infinitos.
Feynman: “Una llamada al LLM es preguntarle algo una vez. Un agente es un empleado con tareas: prueba una herramienta, ve el resultado, decide el siguiente paso. LangGraph es el organigrama que define qué puede hacer y cuándo parar, para que no se quede dando vueltas.”
Aplicar (capa 3)
Armá un agente mínimo con 1-2 tools (ej: buscar en tu RAG + una calculadora) usando LangGraph. Ponele un límite de pasos para evitar loops.
Límites
- Los agentes multiplican costo/latencia (varias llamadas) y pueden loopear; límites de pasos + observabilidad (M5) son obligatorios.
Concepto 5 — MCP (Model Context Protocol)
Idea núcleo: estándar para exponer tools/recursos a modelos/agentes de forma interoperable, en vez de integrar cada tool a mano por proveedor.
Entender (compacto):
- Un servidor MCP expone herramientas y datos con un contrato estándar; cualquier cliente/agente compatible las consume.
- Desacopla las tools del agente: escribís la tool una vez, la usan varios agentes/clientes.
Nota atómica: Front: ¿qué problema resuelve MCP? Back: estandariza cómo un modelo/agente accede a tools y datos externos; en vez de integraciones ad-hoc por proveedor, exponés un servidor MCP y cualquier cliente compatible lo usa. Interoperabilidad y reuso de tools.
Feynman: “MCP es el USB de las herramientas de IA: en vez de un cable propietario por cada aparato, un puerto estándar donde enchufás cualquier tool.”
Aplicar: exponé una tool simple vía un servidor MCP y consumila desde un cliente compatible.
Límites: ecosistema joven y en movimiento —
[verificar]estado/versiones antes de fijarlo como estándar de producción.
Concepto 6 — Evals (medir que no alucina)
Idea núcleo: sin evals, “funciona” es una opinión. Las evals miden la calidad de las respuestas de forma repetible — el paso que separa un demo de un producto.
Entender (capa 1)
Texto: una eval = un dataset de casos (pregunta → respuesta esperada / criterios) + una métrica. Para RAG: relevancia del contexto recuperado, fidelidad (la respuesta se apoya en el contexto, no inventa), correctitud. La técnica central es LLM-as-judge (otro modelo puntúa) — y frameworks como RAGAS la automatizan (faithfulness, answer relevancy, context precision/recall son LLM-as-judge por dentro). Combinalo con métricas deterministas (exact match, similitud de embeddings) donde apliquen.
Visual:
flowchart LR
DS[dataset de casos] --> RUN[correr el sistema] --> SCORE[métricas: relevancia / fidelidad / correctitud] --> GATE{¿supera umbral?}
GATE -->|sí| SHIP[deploy]
GATE -->|no| FIX[mejorar chunking/prompt/modelo]
Video: AI Agent Evaluation with RAGAS — James Briggs
Fijar (capa 2)
Nota atómica:
- Front: ¿por qué las evals son lo que separa un demo de un producto en IA?
- Back: porque sin medición repetible no sabés si un cambio (de prompt/modelo/chunking) mejora o empeora, ni podés detectar alucinaciones/regresiones. La eval convierte “parece que anda” en un número con umbral que gatea el deploy — igual que los tests en código.
Feynman: “Sin evals, evaluás tu IA como quien prueba la sopa una vez y dice ‘buena’. Las evals son la receta con medidas: probás 50 platos con criterio y sabés si esta tanda salió peor que la anterior.”
Aplicar (capa 3)
Armá un dataset chico (10 preguntas con respuesta esperada) para tu mini-RAG y corré una eval de fidelidad/relevancia. Cambiá el chunk size y volvé a medir para ver el efecto.
Límites
- LLM-as-judge tiene sesgo y costo; combiná con métricas automáticas y revisión humana en los casos límite.
Concepto 7 — Costo y latencia
Idea núcleo: en producción, un LLM es un componente con costo por token y latencia real que hay que gestionar y defender ante el negocio.
Entender (compacto):
- Elección de modelo: el más grande no siempre; modelos chicos/rápidos para tareas simples, grandes solo donde hace falta (routing).
- Prompt caching: cachear prefijos/contexto repetido para no pagarlo cada vez.
- Batching: agrupar requests cuando el caso lo permite.
- Medir: tokens y latencia por request (cruza con M5 — observabilidad del pipeline LLM). Nota atómica: Front: ¿cómo se baja el costo/latencia de un feature LLM sin perder calidad? Back: routing de modelos (chico para lo simple, grande para lo difícil), prompt caching del contexto repetido, batching donde se pueda, y reducir contexto al relevante (mejor retrieval). Todo se decide midiendo tokens/latencia, no a ojo. Feynman: “Usar el modelo más grande para todo es contratar a un cirujano para poner una curita. Enrutás: la curita la pone la enfermera (modelo chico), el cirujano solo opera lo grave.” Aplicar: medí tokens y latencia de tu RAG; probá un modelo más chico para la parte simple y compará costo/calidad. Límites: optimizar de más antes de tener el caso andando = premature optimization; primero que funcione y tenga evals, después optimizás con datos.
Concepto 8 — AI-native development workflow
Idea núcleo: las herramientas de IA asistida (Cursor, Copilot, Claude Code, Devin, agent frameworks) son velocidad real de ingeniería cuando reemplazan trabajo mecánico verificable — scaffolding, refactors, schemas, migraciones — y cuando además se usan para construir agentes internos que automatizan tareas repetitivas del propio equipo; son un juguete cuando se usan para generar código que nadie revisa o para tareas donde el costo de un error supera el tiempo ahorrado.
Entender (capa 1)
Texto:
- Scaffolding con IA: generar la estructura repetitiva (endpoints CRUD, tests boilerplate, configs) a partir de un patrón existente en el repo — la IA copia convenciones, vos definís el contrato.
- Refactor asistido: renombrar/mover/extraer con contexto de todo el repo (no solo regex) — útil para refactors grandes que a mano tomarían horas.
- Schemas y migraciones: generar el modelo (pydantic/SQLAlchemy) y la migración (Alembic) a partir de una descripción o de un schema existente — reduce el trabajo mecánico, no la responsabilidad de revisar la migración antes de correrla en producción.
- Agentes internos: además de usar la IA como asistente interactivo, el salto senior es construir agentes que corren solos y automatizan tareas repetitivas de ingeniería del propio equipo — ej: un agente que lee un PR, corre linters/tests, resume el diff y comenta hallazgos; uno que triagea issues y les pone labels; uno que genera el changelog desde los commits. Son “pegamento” entre sistemas ya existentes (CI, tracker, repo), no productos nuevos.
- Criterio “velocidad real vs juguete”: velocidad real = el output se integra directo (pasa tests/lint/review) y el tiempo total (generar + verificar) es menor que hacerlo a mano. Juguete = generar código vistoso que igual hay que reescribir, o automatizar algo que raramente se repite (el costo de mantener el agente supera el ahorro).
Visual:
flowchart TD
T[tarea repetitiva de eng] --> D{es scaffolding/refactor/schema puntual, o se repite seguido?}
D -->|puntual| A[asistente interactivo: Cursor/Copilot/Claude Code]
D -->|se repite seguido| B[agente interno: corre solo, pega sistemas]
A --> V[verificar output: tests + lint + review humano]
B --> V
V -->|pasa| M[merge / velocidad real]
V -->|falla| F[descartar o corregir manual]
Video: Coding Agents Explained: How Claude Code, Codex & Cursor Actually Work — ByteByteAI
Ejemplo (agente interno mínimo — bot de revisión de PR):
# agente que corre en CI: lee el diff, corre checks, comenta resumen en el PR
def review_pr(pr_number: int) -> None:
diff = github.get_diff(pr_number)
lint_result = run_linter(diff.changed_files)
test_result = run_tests(diff.changed_files)
summary = llm.summarize(
diff=diff,
context={"lint": lint_result, "tests": test_result},
schema=PRReviewSummary, # structured output (Concepto 1)
)
github.comment(pr_number, summary.to_markdown())
# el humano decide el merge; el agente solo acelera el triage
Fijar (capa 2)
Nota atómica:
- Front: ¿qué separa usar IA como “velocidad real” de usarla como “juguete” en ingeniería?
- Back: que el output se verifique con el mismo rigor que código escrito a mano (tests, lint, review) y que la tarea automatizada sea lo bastante repetitiva/mecánica como para que el ahorro supere el costo de generar + verificar + mantener. Generar código sin verificar, o automatizar algo que casi no se repite, no es velocidad — es deuda técnica disfrazada de productividad.
Feynman: “Un asistente de IA es un aprendiz muy rápido: le das la tarea repetitiva (armar el CRUD, mover el schema) y la entrega en minutos, pero un ingeniero senior sigue revisando el trabajo antes de firmarlo. Un agente interno es contratar a ese aprendiz de planta para una tarea que se repite todos los días — solo tiene sentido si esa tarea realmente se repite lo suficiente como para justificar el sueldo.”
Aplicar (capa 3)
Elegí una tarea repetitiva real de tu flujo (ej: generar el boilerplate de un endpoint nuevo siguiendo el patrón del repo, o resumir diffs de PR). Hacela una vez con un asistente IA (Cursor/Copilot/Claude Code) midiendo tiempo total (generar + verificar) contra hacerla a mano. Si se repite seguido, prototipá un agente interno simple (script + LLM call) que la automatice y corré structured output para que el resultado sea consumible por otro sistema (Concepto 1).
Límites
- Nunca confiar ciego en schemas/migraciones generados: correrlos primero contra una DB de staging, revisar el SQL generado antes de aplicar en producción — una migración mal generada puede ser destructiva.
- Refactors grandes generados por IA necesitan test suite sólida como red de seguridad; sin tests, el refactor “silencioso” puede romper comportamiento no cubierto.
- Un agente interno mal alcanzado (sin límite de acciones, sin revisión humana en el punto correcto) puede propagar errores más rápido de lo que un humano los detecta — aplican los mismos límites de pasos/observabilidad que en agentes de producto (Concepto 4).
- No automatizar tareas de baja frecuencia: el costo de construir y mantener el agente puede superar el ahorro; medir antes de invertir.
Concepto 9 — Producción rigurosa: golden datasets, prompt injection y control del loop
Idea núcleo: en 2025-2026 esto ya se pregunta en entrevistas de backend general, no solo roles ML — medir calidad no determinística, defenderse de input hostil, y poder auditar/pausar un agente son responsabilidades de arquitectura, no detalles de implementación.
Entender (capa 1)
Texto — golden dataset (la base real de una eval, no solo “10 preguntas”): un dataset versionado construido con 4 buckets: muestra estratificada de tráfico real, casos adversariales, edge cases deliberados, y replays de fallos que ya llegaron a producción. Tamaños de referencia: 50-100 (mínimo viable) · 200-500 (producción) · 1000+ (sistema maduro). El LLM-as-judge (Concepto 6) no se usa “porque sí” — se valida primero contra ese dataset exigiendo 75-90% de acuerdo con etiquetas humanas antes de confiar en sus scores. El mismo evaluador corre en dev, en gate de pre-release y en producción para que los números sean comparables entre etapas.
Texto — prompt injection, mitigación de arquitectura (no “sanitizar el input”): el patrón de referencia es el Dual LLM (Simon Willison): un LLM privilegiado tiene acceso a las tools pero nunca lee contenido no confiable directamente. Un segundo LLM “en cuarentena” procesa ese contenido (un email, una página web, un doc) pero no tiene acceso a ninguna tool. Un controlador de código convencional media entre los dos: el LLM en cuarentena devuelve referencias simbólicas ($VAR1) en vez de texto crudo, y el controlador sustituye el valor real recién al ejecutar la tool — así la instrucción inyectada nunca llega al modelo que puede actuar. El propio autor del patrón lo llama defensa “bastante deficiente” — quedan vectores de ingeniería social y de encadenar outputs. Es una capa de defense-in-depth, no reemplazo de scopes mínimos de tool ni de aprobación humana en acciones destructivas.
Texto — auditoría/replay y estados explícitos del loop: se loguea cada llamada al LLM (prompt + versión de modelo), cada tool call con su respuesta, diffs de estado y un correlation ID por ejecución — con eso se reproduce exactamente una secuencia fallida para depurarla. Los estados explícitos (PLANNING → EXECUTING → WAITING_FOR_APPROVAL) no son un patrón con nombre fijo — es aplicar máquina de estados a un loop de agente: enumerar estados y transiciones fuerza a definir casos no considerados, y da el punto natural para pausar antes de una acción irreversible (transacción, borrado) y esperar aprobación humana.
Visual:
flowchart TD
UNTRUSTED[contenido no confiable<br/>email/web/doc] --> Q[LLM en cuarentena<br/>SIN acceso a tools]
Q -->|devuelve $VAR1, no texto crudo| CTRL[controlador de código]
CTRL -->|sustituye valor real solo al ejecutar| PRIV[LLM privilegiado<br/>CON tools]
PRIV --> ACT[ejecuta tool]
S1[PLANNING] --> S2[EXECUTING]
S2 -->|acción irreversible detectada| S3[WAITING_FOR_APPROVAL]
S3 -->|humano aprueba| S2
S2 -->|termina| DONE[fin]
Video: The Dual LLM pattern for building AI assistants that can resist prompt injection — Simon Willison (artículo, no video)
Fijar (capa 2)
Nota atómica:
- Front: ¿por qué “sanitizar el input” no alcanza contra prompt injection?
- Back: porque la instrucción maliciosa viene disfrazada de contenido legítimo (un email, una página) — no hay forma confiable de distinguir “dato” de “instrucción” con un filtro de texto. La mitigación real es de arquitectura: aislar qué modelo puede leer contenido no confiable de qué modelo puede actuar, con un controlador de código en el medio.
Feynman: “El LLM en cuarentena es un traductor que solo puede señalar objetos con el dedo, nunca describirlos con palabras que el que manda pueda malinterpretar como una orden. Los estados del agente son semáforos en una avenida: sin ellos, el agente cruza cualquier intersección a la velocidad que traía; con ellos, hay un punto obligado donde frena y mira antes de cruzar donde de verdad importa.”
Aplicar (capa 3)
Tomá tu agente del Concepto 4 y agregale un estado WAITING_FOR_APPROVAL antes de cualquier tool que escriba/borre datos — que el grafo pause y solo continúe con una señal externa. Por separado, diseñá (no hace falta implementar) cómo aplicarías el patrón Dual LLM si tu agente tuviera que leer el contenido de una página web para resumirla y luego actuar con esa info.
Límites
- Golden datasets chicos (menos de 50 casos) dan una falsa sensación de cobertura — no capturan la cola larga de casos raros que sí llegan en producción.
- El patrón Dual LLM agrega latencia (una llamada extra) y complejidad — se justifica cuando el agente realmente procesa contenido no confiable con tools de por medio, no en un chatbot de solo lectura.
[unverified]el mecanismo exacto de checkpointing/replay de LangGraph (“Time Travel”) — confirmar contra la doc oficial antes de citarlo como feature específica en una entrevista.
Checklist de dominio M6
Marcás cuando podés explicar (Feynman) + aplicar:
- Fundamentos LLM (tokens, context, structured output, tool calling)
- RAG (chunking, embeddings, retrieval, reranking)
- Vector stores (pgvector vs dedicadas)
- Agentes (LangGraph, tool-calling, estado, límites de pasos)
- MCP
- Evals (dataset, fidelidad/relevancia, LLM-as-judge)
- Costo y latencia (routing, caching, batching, medición)
- AI-native development workflow (scaffolding/refactor/schemas asistidos, agentes internos, verificación de output, velocidad real vs juguete)
- Producción rigurosa: golden datasets, prompt injection (Dual LLM), auditoría/replay, estados del loop
Salida verificable del módulo: un mini-RAG sobre docs públicos (pgvector) con structured output, un dataset de eval (10 casos) que mide fidelidad/relevancia, y medición de tokens/latencia. Bonus: un agente con 1-2 tools y límite de pasos.