Skip links
Diagrama conceptual de la arquitectura modular de LangChain con cadenas y componentes interconectados

LangChain: guía técnica completa con LCEL y agentes 2026

LangChain es el framework Python más utilizado para construir aplicaciones sobre modelos de lenguaje (LLMs): desde simples chains de prompt a agentes complejos con memoria, tools y acceso a bases de datos vectoriales. En 2026, con la explosión de los sistemas multiagente y la madurez del stack RAG, conocer LangChain en profundidad es una habilidad fundamental para cualquier AI engineer.

Esta guía cubre la arquitectura completa del framework: los modelos de abstracción de la librería, LCEL (LangChain Expression Language), el sistema de runnables, la gestión de memoria conversacional, retrieval con vector stores, y la construcción de agentes con tool calling. El código es ejecutable con las APIs actuales (langchain >= 0.2, langchain-community >= 0.2). Si buscas una implementación productiva de agentes de IA para empresas sin construir desde cero, el equipo de Baigency puede ayudarte.

Esta guía está escrita para developers senior, AI engineers y CTOs que ya han visto los tutoriales básicos y quieren entender el framework a fondo: qué ocurre bajo el capó de cada abstracción, cuándo usar Runnables frente a chains legacy, y cómo producir agentes que funcionen en producción. No es una introducción a los LLMs ni a Python; se asume familiaridad con ambos.

Tabla de contenidos

  1. ¿Qué es LangChain y por qué importa en 2026?
  2. Arquitectura: Models, Prompts, Output Parsers
  3. LCEL — LangChain Expression Language
  4. Chains tradicionales vs Runnables
  5. Memoria y conversaciones
  6. Retrieval con LangChain: embeddings + vector store
  7. Agentes en LangChain: tool calling y ReAct
  8. Construir un agente RAG completo (código)
  9. Integraciones: vector stores, LLMs, loaders
  10. LangChain vs LangGraph vs LlamaIndex
  11. Preguntas frecuentes sobre LangChain
  12. Conclusión

¿Qué es LangChain y por qué importa en 2026?

LangChain es un framework open-source lanzado en octubre de 2022 por Harrison Chase. Su objetivo inicial era sencillo: proporcionar abstracciones reutilizables para encadenar llamadas a LLMs con otros componentes (prompt templates, parsers, retrievers, memory) de forma composable. Hoy, con más de 90.000 estrellas en GitHub y un ecosistema de integraciones que cubre más de 100 proveedores, es el punto de entrada estándar para cualquier equipo que construya sobre LLMs en Python.

El repositorio principal (langchain-ai/langchain) se divide ahora en varios paquetes para controlar las dependencias: langchain-core (abstracciones base y LCEL), langchain (chains y agentes), langchain-community (integraciones de terceros) y paquetes de partner específicos como langchain-openai o langchain-anthropic. Esta modularidad resuelve el problema histórico del framework: una instalación que traía decenas de dependencias irrelevantes para la mayoría de los proyectos.

Por qué sigue siendo relevante en 2026

La proliferación de frameworks alternativos (LlamaIndex, Haystack, Semantic Kernel, OpenAI Agents SDK) ha llevado a muchos a preguntarse si LangChain sigue siendo la opción correcta. La respuesta depende del caso de uso. LangChain domina en tres escenarios concretos: aplicaciones RAG de producción donde necesitas composabilidad máxima de retrieval, agentes que combinan LLMs con herramientas externas, y equipos que quieren una base bien documentada con integraciones ya construidas. Donde LangChain pierde terreno es en workflows de agentes con estado complejo, donde LangGraph —construido sobre el mismo ecosistema— ofrece primitivas de grafos mucho más adecuadas.

El ecosistema en números

La documentación oficial de LangChain (python.langchain.com/docs) indexa actualmente más de 70 integraciones de LLMs, 50+ vector stores soportados, y más de 100 document loaders. Esto convierte al framework en una especie de «hub de conectores» para el stack de IA: si un proveedor tiene API pública, casi con certeza hay una integración ya escrita. El modelo de datos central de LangChain —los Runnable objects— es lo que hace posible esta composabilidad sin fricciones.

Desde la perspectiva de producción, el equipo de Baigency trabaja habitualmente con LangChain como capa de orquestación en proyectos de agentes de IA para clientes: la librería reduce el time-to-MVP de forma significativa, especialmente cuando se combinan múltiples fuentes de datos (PDFs, bases de datos, APIs REST) con un LLM centralizado.

Arquitectura: Models, Prompts, Output Parsers

La arquitectura de LangChain se articula en torno a tres familias de objetos que componen la cadena de llamada más simple posible: Language Models, Prompt Templates y Output Parsers. Entender cada capa es prerequisito para usar LCEL correctamente.

Language Models: Chat vs LLM

LangChain distingue entre dos interfaces de modelo. Los LLMs reciben un string y devuelven un string (interfaz texto-a-texto, heredada de los primeros modelos GPT-3 completion). Los ChatModels reciben una lista de mensajes tipados (HumanMessage, AIMessage, SystemMessage) y devuelven un AIMessage. En 2026, prácticamente todos los modelos relevantes —GPT-4o, Claude 3.5 Sonnet, Gemini 1.5 Pro— exponen la interfaz de chat, así que la interfaz LLM legacy es casi irrelevante para proyectos nuevos. Ambas implementan la misma interfaz base BaseLanguageModel, lo que las hace intercambiables en cualquier Runnable.

El objeto ChatOpenAI de langchain-openai acepta los mismos parámetros que el cliente Python oficial de OpenAI (temperature, max_tokens, model, timeout), más parámetros propios de LangChain como streaming=True para habilitar el streaming de tokens. Una ventaja de la capa de abstracción es que cambiar de proveedor —de OpenAI a Anthropic— es tan sencillo como sustituir ChatOpenAI por ChatAnthropic sin tocar el resto del pipeline.

Prompt Templates

Los Prompt Templates son objetos que formatean strings o listas de mensajes a partir de variables de entrada. PromptTemplate gestiona prompts de texto plano con placeholders {variable}; ChatPromptTemplate gestiona secuencias de mensajes con roles explícitos. La separación entre el template y los valores de las variables es fundamental para la composabilidad: permite reusar el mismo template con distintos inputs, cachearlo, versionarlo y testearlo de forma aislada. En el patrón LCEL, un ChatPromptTemplate es simplemente el primer runnable de la cadena.

Output Parsers

Los Output Parsers transforman la respuesta textual del modelo en objetos Python estructurados. El parser más básico es StrOutputParser, que convierte un AIMessage en un string. Más sofisticados son PydanticOutputParser (parsea JSON a un modelo Pydantic con validación automática), JsonOutputParser (sin schema explícito), y CommaSeparatedListOutputParser. En agentes modernos con function calling, los parsers han perdido protagonismo porque el modelo devuelve JSON estructurado de forma nativa a través de tool calls, pero siguen siendo útiles para casos de extracción de información sin function calling.

LCEL — LangChain Expression Language

LCEL (LangChain Expression Language) es el paradigma de composición actual del framework. Introducido en agosto de 2023, reemplaza a las chains legadas (LLMChain, SequentialChain, etc.) con una interfaz funcional basada en el operador pipe |. La documentación oficial de LCEL (python.langchain.com/docs/concepts/lcel) describe tres ventajas fundamentales: composabilidad, streaming nativo en todo el pipeline, y soporte automático de trazado con LangSmith.

El protocolo Runnable

El contrato central de LCEL es la interfaz Runnable: cualquier objeto que implemente invoke(input), stream(input) y batch(inputs) puede participar en una cadena LCEL. Los métodos asíncronos (ainvoke, astream, abatch) están disponibles automáticamente en todos los runnables. Esto significa que el streaming de tokens desde el LLM se propaga a través de toda la cadena sin código adicional: si el modelo hace streaming, la cadena completa hace streaming. El operador | es syntactic sugar para RunnableSequence(a, b).

Chain básica con LCEL

El ejemplo más simple —prompt, modelo y parser encadenados— muestra la sintaxis en su forma más compacta:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# Definimos los tres componentes
prompt = ChatPromptTemplate.from_messages([
    ("system", "Eres un asistente técnico experto en Python."),
    ("human", "{question}")
])

model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
parser = StrOutputParser()

# Composición LCEL con el operador pipe
chain = prompt | model | parser

# Invocación síncrona
result = chain.invoke({"question": "¿Qué diferencia hay entre list y tuple en Python?"})
print(result)

# Streaming de tokens
for chunk in chain.stream({"question": "Explica los generadores en Python"}):
    print(chunk, end="", flush=True)

Nótese que chain.stream() devuelve un generador de strings parciales directamente, sin configuración adicional. El streaming atraviesa el prompt (operación instantánea), el modelo (produce tokens de forma incremental) y el parser (convierte cada chunk de AIMessageChunk a string). Esta propagación automática del streaming es uno de los principales argumentos a favor de LCEL frente a las chains legacy.

Runnables utilitarios: RunnablePassthrough y RunnableParallel

Dos runnables utilitarios son especialmente frecuentes en pipelines reales. RunnablePassthrough pasa el input sin modificarlo, útil para inyectar el input original en una cadena sin consumirlo. RunnableParallel ejecuta múltiples runnables en paralelo sobre el mismo input y combina sus outputs en un dict:

from langchain_core.runnables import RunnablePassthrough, RunnableParallel
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

model = ChatOpenAI(model="gpt-4o", temperature=0)

# RunnableParallel: ejecuta dos operaciones sobre el mismo input
analysis_chain = RunnableParallel(
    sentiment=ChatPromptTemplate.from_template(
        "Analiza el sentimiento de este texto (positivo/negativo/neutro): {text}"
    ) | model | StrOutputParser(),
    summary=ChatPromptTemplate.from_template(
        "Resume en una frase este texto: {text}"
    ) | model | StrOutputParser(),
    original=RunnablePassthrough()  # Pasa el input sin modificar
)

result = analysis_chain.invoke({"text": "LangChain ha madurado mucho en 2025."})
# result = {
#   "sentiment": "positivo",
#   "summary": "LangChain ha mejorado significativamente en 2025.",
#   "original": {"text": "LangChain ha madurado mucho en 2025."}
# }
print(result)

# Patrón clásico RAG: combinar contexto recuperado + pregunta original
def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

rag_prompt = ChatPromptTemplate.from_messages([
    ("system", "Responde la pregunta usando únicamente el contexto provisto."),
    ("human", "Contexto:\n{context}\n\nPregunta: {question}")
])

# retriever se define aparte (ver sección de Retrieval)
# rag_chain = (
#     RunnableParallel({"context": retriever | format_docs, "question": RunnablePassthrough()})
#     | rag_prompt
#     | model
#     | StrOutputParser()
# )

El patrón RunnableParallel({"context": retriever | format_docs, "question": RunnablePassthrough()}) es el esqueleto de casi todo pipeline RAG en LangChain. Lo veremos completo en la sección de Retrieval y en el ejemplo end-to-end. Para aplicaciones que combinan recuperación de documentos con generación, es el bloque de construcción más reutilizable del ecosistema.

Chains tradicionales vs Runnables

Antes de LCEL, LangChain exponía un zoo de clases Chain: LLMChain, SequentialChain, RetrievalQA, ConversationalRetrievalChain, etc. Estas clases siguen disponibles en langchain por compatibilidad hacia atrás, pero están marcadas como deprecated y no recibirán nuevas funcionalidades. La migración a LCEL es la ruta recomendada para todo código nuevo.

Qué ganas al migrar a LCEL

Las diferencias operacionales entre las chains legacy y los runnables LCEL son concretas. Las chains legacy no soportan streaming nativo (hay que usar callbacks específicos); los runnables tienen streaming en todas las implementaciones por contrato de interfaz. Las chains legacy son difíciles de inspeccionar y depurar; los runnables exponen chain.get_graph() que devuelve el grafo de ejecución, y se integran nativamente con LangSmith para trazado. Las chains legacy tienen APIs inconsistentes entre sí (.run(), .predict(), .__call__()); los runnables tienen siempre .invoke(), .stream(), .batch() y sus variantes asíncronas.

Tabla comparativa

CaracterísticaChains legacyLCEL Runnables
Streaming nativoNo (callbacks)Sí (por defecto)
AsyncParcialSí (ainvoke, astream)
Batch con concurrenciaNoSí (batch(inputs, config={"max_concurrency": N}))
Trazado LangSmithParcialAutomático
ComposabilidadLimitadaOperador | sin límite
Estado de mantenimientoDeprecatedActivo

Si tienes código legacy con RetrievalQA.from_chain_type() o ConversationalRetrievalChain.from_llm(), la migración implica reescribir esas cadenas con LCEL y RunnableParallel. El esfuerzo compensa en proyectos de más de dos semanas de vida: el código LCEL es más corto, más legible y más fácil de extender.

Para proyectos donde la complejidad del flujo supera las capacidades de composición lineal de LCEL —por ejemplo, agentes con bucles de decisión, estado persistente entre ejecuciones, o flujos de control condicionales— la solución correcta es LangGraph, que extiende el ecosistema LangChain con grafos de estado explícitos.

Memoria y conversaciones

La memoria en LangChain gestiona el historial de una conversación y lo inyecta en el prompt de cada turno. Es uno de los aspectos del framework que más ha evolucionado: la API de memoria legacy (ConversationBufferMemory, ConversationSummaryMemory) está siendo reemplazada por langchain-core con el patrón de message history basado en BaseChatMessageHistory y el wrapper RunnableWithMessageHistory.

ConversationBufferMemory: el patrón legacy

El objeto ConversationBufferMemory almacena todos los mensajes de la conversación en memoria RAM y los serializa como string en la variable {history} del prompt. Es la implementación más simple y la más usada en tutoriales, aunque tiene limitaciones evidentes: consume el context window completo con el historial, no persiste entre ejecuciones, y está deprecated en favor del nuevo sistema. El ejemplo siguiente muestra la API legacy porque aún se encuentra en bases de código activas:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory

model = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)

# Prompt con placeholder para el historial de mensajes
prompt = ChatPromptTemplate.from_messages([
    ("system", "Eres un asistente técnico. Responde en castellano."),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{input}")
])

# Chain base sin memoria
base_chain = prompt | model

# Store en memoria para múltiples sesiones
store = {}

def get_session_history(session_id: str) -> ChatMessageHistory:
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    return store[session_id]

# Wrapper que inyecta el historial automáticamente
chain_with_history = RunnableWithMessageHistory(
    base_chain,
    get_session_history,
    input_messages_key="input",
    history_messages_key="history"
)

# Configuración de sesión
config = {"configurable": {"session_id": "user_001"}}

# Primer turno
r1 = chain_with_history.invoke(
    {"input": "¿Qué es un embedding?"},
    config=config
)
print(r1.content)

# Segundo turno — el modelo recuerda el contexto
r2 = chain_with_history.invoke(
    {"input": "¿Y cómo se calcula la similitud entre dos embeddings?"},
    config=config
)
print(r2.content)

# Tercer turno — el historial ya tiene 4 mensajes (2 human + 2 AI)
r3 = chain_with_history.invoke(
    {"input": "Dame un ejemplo en Python usando numpy"},
    config=config
)
print(r3.content)

El patrón RunnableWithMessageHistory es la forma recomendada en 2026: desacopla la lógica de almacenamiento del historial de la cadena de proceso. get_session_history puede devolver cualquier implementación de BaseChatMessageHistory: ChatMessageHistory (RAM), RedisChatMessageHistory, PostgresChatMessageHistory, o una implementación custom. Para producción, Redis o una base de datos relacional es la opción correcta: el historial persiste entre reinicios del proceso y puede recuperarse por session_id.

Gestión del context window

El problema central de la memoria es el context window: conversaciones largas pueden exceder los límites del modelo (128K tokens en GPT-4o, por ejemplo). Las estrategias para mitigarlo son truncar el historial a los N últimos mensajes (trim_messages), resumir los mensajes más antiguos con un LLM secundario (summarization memory), o extraer entidades clave y almacenarlas en un vector store (embeddings de la conversación). La elección depende del caso: para soporte técnico, truncar a los 10 últimos mensajes suele ser suficiente; para asistentes de ventas complejos, la memoria con entidades extraídas da mejores resultados.

Retrieval con LangChain: embeddings + vector store

El subsistema de retrieval es la parte de LangChain que más ha contribuido a su adopción masiva. Proporciona las abstracciones necesarias para construir pipelines RAG completos (retrieval augmented generation) sin lidiar con las particularidades de cada vector store. Los componentes clave son: document loaders, text splitters, embedding models, vector stores y retrievers.

Document Loaders y Text Splitters

Los Document Loaders cargan datos desde fuentes externas (PDFs, páginas web, bases de datos, APIs) y los convierten en objetos Document con campos page_content (el texto) y metadata (fuente, página, etc.). langchain-community incluye más de 100 loaders. El más usado en contextos empresariales es PyPDFLoader, que extrae texto de PDFs página a página. Para webs, WebBaseLoader usa beautifulsoup4 para extraer el texto del HTML.

Los Text Splitters fragmentan los documentos en chunks más pequeños antes de generar embeddings semánticos. El más robusto es RecursiveCharacterTextSplitter: intenta dividir por separadores semánticos (párrafos, frases, palabras) en orden de prioridad, hasta llegar al chunk_size objetivo. El parámetro chunk_overlap añade solapamiento entre chunks contiguos para preservar contexto en los bordes. Para documentos con estructura más rica (markdown, código), MarkdownHeaderTextSplitter y Language.PYTHON fragmentan respetando la jerarquía del documento.

Vector Stores y Retrievers

LangChain abstrae el acceso a más de 50 bases de datos vectoriales con una interfaz uniforme VectorStore: add_documents(docs), similarity_search(query, k=N) y as_retriever(). Chroma (local, in-process), Pinecone (managed, serverless), Weaviate, Qdrant y pgvector son los más usados en producción. La elección depende del volumen de datos y los requisitos de escalabilidad: para prototipos y colecciones < 100K vectores, Chroma sin servidor es suficiente; para producción con millones de vectores, Pinecone o Qdrant son más apropiados.

El método as_retriever() convierte cualquier vector store en un BaseRetriever, que implementa la interfaz Runnable. Esto significa que un retriever puede participar directamente en una cadena LCEL sin código adicional. Los parámetros de búsqueda —search_type="mmr" para Maximal Marginal Relevance, k=5 para el número de documentos— se pasan al método as_retriever(search_kwargs={"k": 5}).

Agentes en LangChain: tool calling y ReAct

Los agentes en LangChain son sistemas donde el LLM decide dinámicamente qué herramientas ejecutar y en qué orden, basándose en el objetivo dado. A diferencia de una chain LCEL donde el flujo está predefinido, el agente itera en un bucle: observa el estado actual, decide la siguiente acción (tool call o respuesta final), ejecuta la acción, incorpora el resultado y decide el siguiente paso. Esta arquitectura agéntica es el paradigma dominante en sistemas de IA agéntica en 2026.

Tool Calling vs ReAct

LangChain soporta dos estrategias de agente. El patrón ReAct (Reasoning + Acting) original usa prompting para que el modelo razone sobre qué herramienta usar, emitiendo texto en el formato «Thought / Action / Observation». Es compatible con cualquier LLM que siga instrucciones, pero es frágil con modelos débiles y no aprovecha function calling nativo. El patrón Tool Calling (o function calling) usa la capacidad nativa de los modelos modernos (GPT-4o, Claude 3.5, Gemini 1.5) de devolver structured JSON con la herramienta a llamar y sus argumentos. Es más robusto, más rápido y más fácil de depurar. Para cualquier proyecto nuevo con modelos que soporten function calling, la API recomendada es create_tool_calling_agent + AgentExecutor.

Definir tools

Una tool en LangChain es cualquier función Python decorada con @tool, o una subclase de BaseTool. El docstring de la función se convierte en la descripción que el LLM usa para decidir cuándo llamar a esa herramienta, así que debe ser claro y específico. El decorator @tool extrae automáticamente el schema de los argumentos a partir de las type annotations y los parámetros de Pydantic.

Una vez definidas las herramientas, create_tool_calling_agent crea un agente que usa function calling nativo. AgentExecutor lo envuelve con la lógica de bucle: ejecuta la acción elegida, incorpora el resultado como ToolMessage y vuelve a llamar al agente hasta que este emite una respuesta final o se alcanza el límite de iteraciones (max_iterations).

Para implementaciones que requieren workflows multi-agente o estado persistente entre llamadas, el paso natural es LangGraph, que ofrece primitivas de grafos explícitas para controlar el flujo agéntico con ciclos, condiciones y checkpointing. También puedes revisar el OpenAI Agents SDK si tu stack es 100% OpenAI y prefieres menos abstracciones.

Construir un agente RAG completo (código)

Esta sección presenta dos implementaciones completas: primero un pipeline RAG puro con LCEL (sin agente), después un agente con la herramienta de retrieval integrada. Ambos ejemplos son ejecutables con pip install langchain langchain-openai langchain-community chromadb pypdf.

RAG pipeline end-to-end con LCEL

import os
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableParallel, RunnablePassthrough

# --- 1. Carga del documento ---
loader = PyPDFLoader("documento_empresa.pdf")
pages = loader.load()  # Lista de Document, uno por página

# --- 2. Fragmentación en chunks ---
splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,       # caracteres por chunk
    chunk_overlap=200,     # solapamiento entre chunks contiguos
    separators=["\n\n", "\n", ". ", " ", ""]
)
chunks = splitter.split_documents(pages)
print(f"Chunks generados: {len(chunks)}")

# --- 3. Embeddings y vector store ---
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db",
    collection_name="empresa_docs"
)

# --- 4. Retriever ---
retriever = vectorstore.as_retriever(
    search_type="mmr",                # Maximal Marginal Relevance — diversidad
    search_kwargs={"k": 5, "fetch_k": 20}
)

# --- 5. Prompt RAG ---
rag_prompt = ChatPromptTemplate.from_messages([
    ("system", (
        "Eres un asistente experto. Responde ÚNICAMENTE con la información del contexto. "
        "Si la respuesta no está en el contexto, di 'No tengo esa información'. "
        "Contexto:\n\n{context}"
    )),
    ("human", "{question}")
])

# --- 6. LLM ---
llm = ChatOpenAI(model="gpt-4o", temperature=0)

# --- 7. Cadena RAG completa ---
def format_docs(docs):
    return "\n\n---\n\n".join(
        f"[Fuente: {doc.metadata.get('source', 'desconocida')}, "
        f"p.{doc.metadata.get('page', '?')}]\n{doc.page_content}"
        for doc in docs
    )

rag_chain = (
    RunnableParallel({
        "context": retriever | format_docs,
        "question": RunnablePassthrough()
    })
    | rag_prompt
    | llm
    | StrOutputParser()
)

# --- 8. Consulta ---
answer = rag_chain.invoke("¿Cuál es la política de devoluciones?")
print(answer)

# Streaming
for chunk in rag_chain.stream("¿Cuáles son las condiciones de garantía?"):
    print(chunk, end="", flush=True)

Agente con retrieval como tool

from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
import requests

# Asumir que vectorstore ya está creado (ver código anterior)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma(
    persist_directory="./chroma_db",
    embedding_function=embeddings,
    collection_name="empresa_docs"
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})

# --- Definir tools ---

@tool
def buscar_en_documentos(query: str) -> str:
    """
    Busca información en la base de conocimiento de la empresa.
    Usa esta herramienta cuando necesites responder preguntas sobre
    políticas, procedimientos, productos o servicios de la empresa.
    El argumento query debe ser una pregunta o frase de búsqueda en castellano.
    """
    docs = retriever.invoke(query)
    if not docs:
        return "No se encontró información relevante en los documentos."
    return "\n\n".join(
        f"[p.{doc.metadata.get('page', '?')}] {doc.page_content}"
        for doc in docs
    )

@tool
def consultar_estado_pedido(numero_pedido: str) -> str:
    """
    Consulta el estado actual de un pedido dado su número.
    El número de pedido tiene el formato: ORD-XXXXXXXX (8 dígitos).
    """
    # En producción: llamada real a la API de pedidos
    # response = requests.get(f"https://api.empresa.com/orders/{numero_pedido}")
    # return response.json()
    return f"Pedido {numero_pedido}: En tránsito. Entrega estimada: 2026-06-08."

tools = [buscar_en_documentos, consultar_estado_pedido]

# --- Prompt del agente ---
agent_prompt = ChatPromptTemplate.from_messages([
    ("system", (
        "Eres el asistente virtual de la empresa. "
        "Responde siempre en castellano. Usa las herramientas disponibles "
        "para obtener información precisa antes de responder. "
        "Si no tienes la información necesaria, dilo claramente."
    )),
    MessagesPlaceholder(variable_name="chat_history", optional=True),
    ("human", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad")
])

# --- Modelo y agente ---
llm = ChatOpenAI(model="gpt-4o", temperature=0)

agent = create_tool_calling_agent(
    llm=llm,
    tools=tools,
    prompt=agent_prompt
)

executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,           # Muestra el razonamiento interno
    max_iterations=5,       # Límite de seguridad
    handle_parsing_errors=True
)

# --- Ejecutar ---
result = executor.invoke({
    "input": "¿Cuál es la política de garantía y cuál es el estado del pedido ORD-12345678?"
})
print(result["output"])

Este patrón —RAG como una tool más del agente, junto a otras herramientas operacionales— es el que el equipo de Baigency implementa en los proyectos de agente de IA para ventas: el agente puede buscar en el catálogo de productos (RAG), consultar el CRM (API tool), enviar emails (action tool) y gestionar el flujo de la conversación de ventas, todo desde el mismo executor.

Integraciones: vector stores, LLMs, loaders

Una de las propuestas de valor más concretas de LangChain es su catálogo de integraciones. Aquí se describen las más relevantes para producción en 2026, con los packages de instalación correctos.

LLM providers

Los modelos de lenguaje se instalan como packages separados para mantener las dependencias limpias. langchain-openai cubre GPT-4o, GPT-4o-mini, o1 y los modelos de embedding text-embedding-3-*. langchain-anthropic cubre Claude 3.5 Sonnet, Claude 3 Opus y variantes. langchain-google-genai cubre Gemini 1.5 Pro y Flash. langchain-ollama cubre cualquier modelo ejecutable localmente con Ollama (Llama 3, Mistral, Phi-3, etc.). Todos exponen la misma interfaz BaseChatModel, así que el código de la aplicación no cambia al cambiar de proveedor.

Document Loaders relevantes

Para proyectos empresariales, los loaders más usados son: PyPDFLoader (PDFs), Docx2txtLoader (Word), CSVLoader (datos tabulares), WebBaseLoader (páginas web), NotionDirectoryLoader (Notion), ConfluenceLoader (Confluence), S3FileLoader (AWS S3) y GitLoader (repositorios de código). Todos devuelven listas de objetos Document con metadata estructurada que los text splitters y vector stores preservan a través del pipeline.

Vector stores en producción

La elección de base de datos vectorial depende de tres factores: volumen de vectores, latencia requerida y presupuesto de infraestructura. Para proyectos con menos de 500K vectores y latencia < 100 ms, Chroma local o Qdrant self-hosted son las opciones más económicas. Para volúmenes mayores con requisitos de alta disponibilidad, Pinecone (serverless, billed por usage) o Weaviate (managed cloud) son más apropiados. Para equipos ya en AWS, pgvector sobre RDS PostgreSQL integra el vector store en la infraestructura existente sin añadir una base de datos adicional. LangChain tiene integraciones mantenidas para todos estos.

Proyectos que conectan agente IA para WordPress con bases de conocimiento de contenidos usan habitualmente Chroma o pgvector: el contenido de WordPress se indexa con WebBaseLoader o un loader custom sobre la WP REST API, y el agente busca en ese índice para responder preguntas contextualizadas al sitio.

LangChain vs LangGraph vs LlamaIndex

La pregunta que más aparece en foros técnicos: ¿cuándo usar LangChain, cuándo LangGraph y cuándo LlamaIndex? La respuesta corta: los tres no son mutuamente excluyentes —LangGraph está construido sobre LangChain—, pero optimizan para problemas distintos.

LangChain: composición lineal y RAG

LangChain es la opción correcta cuando el flujo de ejecución es lineal o ramificado pero predeterminado: pipelines RAG, chains de transformación de datos, agentes simples donde el número de herramientas es pequeño y las iteraciones son cortas. LCEL hace que este tipo de pipelines sea muy fácil de construir y mantener. La madurez del ecosistema de integraciones es su principal ventaja competitiva: si necesitas conectar un LLM con un vector store, una API externa y un formatter de output, LangChain tiene los conectores ya escritos.

LangGraph: flujos agénticos con estado

LangGraph extiende LangChain con grafos de estado explícitos: nodos (funciones que transforman el estado), edges (transiciones condicionales) y un mecanismo de checkpointing que persiste el estado entre ejecuciones. Es la opción correcta para agentes complejos donde el flujo de control depende del estado acumulado: agentes de larga duración, sistemas multi-agente donde varios LLMs colaboran, o flujos con aprobación humana (human-in-the-loop). LangGraph implementa nativamente el patrón de IA agéntica con ciclos, condiciones y memoria persistente que AgentExecutor no puede representar de forma natural.

LlamaIndex: indexación y retrieval avanzado

LlamaIndex (antes GPT Index) está optimizado para la construcción de índices de conocimiento y retrieval sofisticado. Sus abstracciones de index (vector, tree, keyword, knowledge graph) y query engine van más allá de lo que LangChain ofrece en retrieval: soporta retrieval recursivo sobre índices jerárquicos, query decomposition automática, y síntesis de respuestas de múltiples fuentes. Para aplicaciones donde el retrieval es el componente crítico y la complejidad del índice es alta, LlamaIndex es más expresivo que LangChain. Para agentes generalistas con RAG como una tool más, LangChain suele ser suficiente.

Tabla comparativa

CriterioLangChainLangGraphLlamaIndex
Primaria paraRAG, chains, agentes simplesAgentes con estado, multi-agenteIndexación avanzada, retrieval complejo
Curva de aprendizajeMediaAltaMedia-alta
Estado persistenteVia RunnableWithMessageHistoryNativo (checkpointing)Parcial
Integraciones LLM70+ providersHereda LangChain40+ providers
Flujos condicionalesLimitadoNativo (conditional edges)Via routers
ObservabilidadLangSmithLangSmith nativoPhoenix / LlamaTrace

En la práctica, muchos proyectos de producción combinan los tres: LangChain para la capa de retrieval y tools, LangGraph para el flujo del agente, y LlamaIndex para índices de conocimiento especializados. El Model Context Protocol (MCP) está emergiendo como la capa de estandarización que permite a cualquiera de estos frameworks conectarse con herramientas externas sin integración ad-hoc, lo que reduce la presión sobre la capa de integraciones de LangChain.

Para explorar alternativas adicionales al ecosistema LangChain puro, el OpenAI Agents SDK es relevante si el stack es exclusivamente OpenAI y se prefiere menor abstracción.

Preguntas frecuentes sobre LangChain

¿Cuál es la diferencia entre LangChain y LangGraph?

LangChain es el framework base con abstracciones para modelos, prompts, retrievers y cadenas de ejecución lineal. LangGraph es una librería construida sobre LangChain que añade grafos de estado explícitos: nodos, edges condicionales y checkpointing. La diferencia práctica es que LangChain resuelve bien flujos lineales y agentes simples, mientras que LangGraph es necesario cuando el agente necesita ciclos de decisión, estado persistente entre ejecuciones, o coordinación entre múltiples LLMs. En proyectos nuevos con complejidad agéntica media-alta, lo habitual es empezar con LangChain y migrar las partes de flujo complejo a LangGraph.

¿Es LCEL compatible con la API asíncrona de FastAPI?

Sí. Todos los runnables de LCEL implementan métodos asíncronos nativos: ainvoke(), astream() y abatch(). Esto permite usarlos directamente en endpoints async def de FastAPI sin bloquear el event loop. Para streaming de tokens en un endpoint FastAPI, el patrón correcto es usar StreamingResponse de Starlette con un generador asíncrono que itera sobre chain.astream(input). El soporte de Server-Sent Events (SSE) en LangChain también está disponible via langchain-community con adaptadores para Starlette.

¿Qué versión de LangChain debo usar en 2026?

El stack recomendado en 2026 es: langchain-core >= 0.3, langchain >= 0.2, langchain-community >= 0.2 y el package de partner de tu LLM (langchain-openai >= 0.1.8, langchain-anthropic >= 0.1.15). Evita instalar solo langchain sin especificar versión: las versiones legacy 0.0.x y 0.1.x tienen APIs diferentes y muchos tutoriales online siguen usando la nomenclatura antigua (from langchain.chat_models import ChatOpenAI vs from langchain_openai import ChatOpenAI). Siempre verifica el import path en la documentación oficial.

¿Cómo depuro una chain LCEL en producción?

La herramienta principal es LangSmith: con las variables de entorno LANGCHAIN_TRACING_V2=true y LANGCHAIN_API_KEY configuradas, cada invocación de una chain se traza automáticamente con inputs, outputs, latencias y costes de tokens de cada paso. Para debugging local sin LangSmith, chain.get_graph().print_ascii() muestra la estructura del pipeline, y chain.with_config({"run_name": "debug_chain"}).invoke(input) añade metadata de trazado. Para problemas de retrieval específicos, retriever.invoke(query) de forma aislada permite inspeccionar qué documentos se recuperan antes de pasarlos al LLM.

¿LangChain funciona con modelos locales (Ollama, vLLM)?

Sí. langchain-ollama integra directamente con el servidor local de Ollama: ChatOllama(model="llama3", base_url="http://localhost:11434") es un BaseChatModel compatible con cualquier pipeline LCEL. Para vLLM, la integración se hace via ChatOpenAI(base_url="http://localhost:8000/v1", api_key="fake"), ya que vLLM expone una API compatible con OpenAI. La ventaja de usar modelos locales en LangChain es que el código de la aplicación no cambia: solo se sustituye el objeto del modelo. La desventaja principal en 2026 es el rendimiento de function calling en modelos open-source más pequeños, que sigue siendo inferior al de GPT-4o o Claude 3.5 para agentes complejos con muchas tools.

¿Cuándo tiene sentido usar el OpenAI Agents SDK en lugar de LangChain?

El OpenAI Agents SDK tiene sentido cuando el stack es exclusivamente OpenAI, el equipo no necesita las integraciones de terceros de LangChain, y se prefiere menos abstracción y más control directo sobre el loop agéntico. El SDK expone primitivas más cercanas a la API de OpenAI (handoffs, guardrails, traces nativos con la plataforma de OpenAI), lo que puede simplificar el código en proyectos con requisitos de observabilidad ya resueltos en el ecosistema OpenAI. LangChain es más apropiado cuando el proyecto mezcla múltiples proveedores de LLM, necesita las integraciones de vector store y loaders, o el equipo ya tiene experiencia en el framework.

Conclusión

LangChain sigue siendo, en 2026, el framework de referencia para construir aplicaciones sobre LLMs en Python. LCEL resuelve los problemas de composabilidad y streaming que lastraban las chains legacy; los runnables utilitarios (RunnablePassthrough, RunnableParallel) simplifican patrones que antes requerían código boilerplate; y el ecosistema de integraciones reduce de semanas a horas la conexión entre un LLM y una fuente de datos externa.

El mapa de decisión es claro. Para pipelines RAG, cadenas de transformación y agentes simples: LangChain con LCEL. Para flujos agénticos con estado complejo, ciclos y multi-agente: LangGraph. Para indexación avanzada con retrieval jerárquico: LlamaIndex. Para el estándar de interoperabilidad de tools: Model Context Protocol. Estos componentes no compiten entre sí: se combinan.

Si tu equipo está evaluando implementar agentes de IA para empresas basados en LangChain —integración con vuestro CRM, base de conocimiento corporativa, o flujos de automatización existentes— el equipo de Baigency trabaja con este stack de forma cotidiana. Podemos hacer una valoración técnica de vuestro caso sin compromiso. También puedes explorar casos de uso específicos como el chatbot de IA para WhatsApp, el agente de voz con IA o el agente de IA para Telegram, todos construidos sobre el mismo stack de orquestación.

Explore
Drag