Pasando de una sola llamada al LLM a una aplicación LangChain
Desarrolla una aplicación LangChain capa por capa a partir de una LLM invoke: prompts, cadenas, analizadores, salida estructurada, RAG, herramientas, agentes, MCP, observabilidad y seguridad.
Fuentes: From One LLM Call to a Real AI Application with LangChain
La primera integración con un LLM suele hacer pensar que lo más difícil será lograr que el modelo genere alguna respuesta. Por lo general, no es así. Con un prompt, una clave API y un SDK, unas pocas líneas de código ya producen una respuesta razonable. Eso es suficiente para un prototipo.
Las aplicaciones no permanecen como prototipos. A continuación vienen prompts editables sin necesidad de volver a implementar código empresarial, modelos alternativos, respuestas estructuradas y acceso a datos propios de la aplicación. Con el tiempo, el modelo necesita poder llamar a APIs y herramientas. Es entonces cuando una simple llamada mediante SDK se convierte en una verdadera aplicación de IA, y es ahí donde LangChain llama la atención.
No porque llamar a un modelo sea difícil; de hecho, ya es sencillo. El valor real radica en todo lo que rodea a esa llamada: prompts, composición, análisis de datos, servicios, recuperación de información, herramientas y controles de producción.
Comenzando con el ejemplo más sencillo posible
El verbo fundamental de LangChain es invoke(). Con un modelo de chat de OpenAI:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(
model="gpt-4o-mini",
temperature=0
)response = model.invoke(
"Explain microservices to a software developer who is new to distributed systems."
)print(response.content)
Crea un modelo, llama a invoke() con la entrada y lee el texto de response.content. No hay nada mágico en ello.
Si el producto solo envía una solicitud y muestra una respuesta, a menudo basta con el SDK del proveedor. El problema surge cuando la aplicación crece.
Las solicitudes codificadas de antemano no duran mucho
Incluir una pregunta directamente en el lugar de la llamada no es escalable:
response = model.invoke(
"Explain event-driven architecture to a beginner."
)
El tema y el público objetivo deben ser valores dinámicos. ChatPromptTemplate lo hace sencillo:
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
(
"system",
"You are a helpful software engineering assistant."
),
(
"human",
"Explain {topic} to a {audience}."
)
])
Proporciona variables al invocar:
messages = prompt.invoke({
"topic": "event-driven architecture",
"audience": "beginner"
})
response = model.invoke(messages)print(response.content)
La solicitud se convierte en un componente independiente. Las solicitudes determinan el comportamiento y merecen la misma atención que la configuración y las reglas de negocio.
Conectar la instrucción y el modelo
La composición es donde LangChain difiere de un SDK básico. En lugar de conectar cada paso manualmente:
chain = prompt | model
Luego:
response = chain.invoke({
"topic": "event-driven architecture",
"audience": "software engineer"
})
print(response.content)
La notación de tuberías crea una cadena: la salida de la instrucción alimenta al modelo. Dicha composición escala a medida que aparecen más etapas.
Obtener algo útil del modelo
Los objetos de modelo devuelven envoltorios de mensaje. Las aplicaciones suelen querer una cadena de texto simple. StrOutputParser ayuda con esto:
chain = prompt | model | parser
from langchain_core.output_parsers import StrOutputParser
parser = StrOutputParser()chain = prompt | model | parser
Invocar con variables:
response = chain.invoke({
"topic": "Docker",
"audience": "beginner"
})
print(response)
El resultado es una cadena de texto que el resto del sistema puede utilizar. La comodidad aumenta a medida que las cadenas se vuelven más complejas.
Aquí es donde la arquitectura comienza a ser importante
Incluir llamadas directas a LangChain en los controladores de API funciona solo por poco tiempo:
def endpoint():
# business logic
# prompt
# model configuration
# database call
# response formatting
Meses después, el endpoint se vuelve inaccesible. Es mejor utilizar un límite de servicio:
class LLMService:
def __init__(self, chain):
self.chain = chain def generate(self, topic, audience):
return self.chain.invoke({
"topic": topic,
"audience": audience
})
La API solicita al servicio que genere el contenido; no es necesario que sepa qué modelo está detrás. De esta manera, la separación se mantiene clara.
Los equipos que omiten el límite de servicio suelen terminar con configuraciones de temperatura duplicadas, claves API dispersas y un registro incoherente en los diferentes endpoints. Centralizar la construcción de la cadena también permite detectar fácilmente cuando dos funcionalidades envían accidentalmente dos dialectos diferentes de prompts para el mismo dominio. Por lo general, un LLMService (o una pequeña familia de servicios por dominio) es suficiente hasta que los límites de tráfico o de propiedad obliguen a realizar una división.
¿Qué sucede cuando quiero cambiar el modelo?
Las cadenas de abstracciones facilitan los cambios en los proveedores. El desarrollo puede comenzar con OpenAI y, posteriormente, evaluarse otro proveedor, modelos alojados en Azure o Bedrock. El producto no debe reescribirse cada vez que se realice un cambio.
Un modelo de chat de Anthropic, por ejemplo:
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-3-5-sonnet-latest"
)
La estructura de la cadena puede mantenerse igual:
chain = prompt | model | parser
La abstracción no implica que todos los modelos sean idénticos: sus capacidades, ventanas de contexto, precios, latencia y comportamiento difieren; sin embargo, la evaluación y el cambio de proveedor se vuelven prácticos.
El momento en que el texto ya no es suficiente
Los productos de planificación de eventos ilustran este cambio. Un usuario escribe que necesita una carpa de 40x60, 150 sillas y mesas para el sábado. Un chatbot podría responder en prosa, pero la aplicación necesita datos:
{
"tent_size": "40x60",
"chairs": 150,
"tables": true,
"event_date": "next Saturday"
}
Defina un esquema con Pydantic:
from pydantic import BaseModel
class EventRequest(BaseModel):
tent_size: str
chairs: int
tables: bool
event_date: str
Configure el modelo para que devuelva datos que coincidan con ese esquema (los detalles dependen de la integración). La solicitud pasa de “dame texto” a “analiza esta petición en lenguaje natural y conviértela en una estructura conocida”. Ese patrón es mucho más eficaz para el software.
Luego está el problema del contexto
Los usuarios hacen preguntas que el modelo no puede responder solo con la indicación proporcionada; por ejemplo, si una reserva se puede modificar. El estado de la reserva es datos de la aplicación. Es necesario proporcionar contexto.
La generación mejorada por recuperación de información (RAG) es un patrón común. Con grandes corpus de políticas, no envíe cada documento en cada llamada; primero obtenga los fragmentos relevantes. Para:
question = "What is your cancellation policy?"
La aplicación encuentra pasajes coincidentes y los adjunta como contexto. El modelo responde a partir de ese material. No está “aprendiendo” la política de la empresa; la aplicación obtiene pruebas en tiempo de ejecución y se las entrega. Ese modelo mental aclara el concepto de RAG.
El LLM no necesita hacerlo todo
Un LLM no es un sustituto del software ordinario. Operaciones aritméticas como:
total = quantity * price
pertenecen al código. La búsqueda de pedidos:
SELECT *
FROM orders
WHERE order_id = ?
pertenecen a la base de datos. La autenticación no debe delegarse a un modelo. Los LLMs destacan en la comprensión del lenguaje, el razonamiento, la clasificación, la resumen, la generación y la toma de decisiones dentro de ciertos límites. Mantén las tareas deterministas como tales. Esa separación hace que los sistemas de IA sean más fáciles de comprender.
Proporcionar al modelo acceso a herramientas
Cuando un usuario pregunta dónde se encuentra un pedido, el modelo no lo sabe, pero la aplicación podría mostrarlo:
def get_order_status(order_id: str):
...
Registre esa función como una herramienta. El modelo puede decidir que necesita información, llamar a la herramienta, recibir un resultado y integrar ese resultado en la respuesta final. La generación de texto se convierte así en una participación en un flujo de trabajo. Aquí las conversaciones sobre agentes comienzan a tener sentido.
Pero los agentes no siempre son necesarios
Calificar cada flujo de trabajo como “agente” no es útil. Un camino predecible —entender la pregunta, obtener datos del cliente, generar una respuesta— puede requerir únicamente una cadena de operaciones. Los agentes son útiles cuando el modelo debe elegir dinámicamente herramientas para completar una tarea. Una solicitud para verificar un pedido, informar sobre el estado del envío y actualizar la dirección si es necesario puede requerir obtener → verificar → confirmar → actualizar → explicar. Ese es un candidato más adecuado para ser un agente.
No introduzca un agente solo porque esté disponible. Prefiera la arquitectura más simple que resuelva el problema.
Dónde encaja MCP en este panorama
A medida que los sistemas crecen, el Model Context Protocol (MCP) se vuelve útil: es una forma estándar para que las aplicaciones de IA comuniquen con herramientas y datos externos. En lugar de que cada integración sea personalizada, MCP permite exponer de manera uniforme clientes, pedidos, calendarios, bases de datos, documentos y APIs empresariales. LangChain y MCP operan en capas diferentes: LangChain orquesta los prompts, modelos, procesos de recuperación, herramientas y flujos de trabajo; MCP estandariza la forma en que se exponen las capacidades. Esta combinación es importante a medida que el chat se convierte en un flujo de trabajo empresarial.
La observabilidad se vuelve importante con sorprendente rapidez
Los prototipos suelen ignorar la observabilidad. Las APIs tradicionales suelen seguir un patrón de solicitud → consulta → respuesta. Una solicitud a un LLM puede implicar la construcción de prompts, recuperación de información, múltiples llamadas a modelos, uso de herramientas, análisis de datos, intentos de reintentar y más llamadas a modelos. El registro solo incluye:
LLM request failed
es inútil. Los operadores necesitan la instrucción de entrada, el modelo, la latencia, las herramientas utilizadas, el lugar donde ocurre el fallo y cómo cada paso contribuyó a la respuesta. La instrumentación al estilo de LangSmith y OpenTelemetry ayuda en esto. El comportamiento probabilístico hace que la observabilidad sea aún más importante, no menos.
La seguridad es un problema distinto cuando el modelo cuenta con herramientas
Nunca considere una llamada a una herramienta elegida por el modelo como una autorización automática. Un camino como este:
LLM → get_customer(12345) → Database
todavía debe pasar por autenticación, autorización, validación, control de acceso, límites de tasa y registro de auditoría. El modelo puede proponer; la aplicación decide qué está permitido. El LLM no debe convertirse en el límite de seguridad.
Así es mi progreso típico en la actualidad
Las nuevas funciones de los LLM comienzan de forma sencilla. Primero, ¿se puede llamar al modelo?
model.invoke(...)
Luego, ¿se necesita una instrucción de entrada reutilizable?
prompt | model
Agregue una salida estructurada cuando los datos predecibles sean importantes. Agregue mecanismos de recuperación cuando el modelo necesite datos propios. Agregue herramientas cuando sea necesario interactuar con otros sistemas. Considere los agentes únicamente cuando se requieran decisiones dinámicas con múltiples herramientas. Cuando la funcionalidad sea importante en el entorno de producción, agregue capacidades de observabilidad, evaluación, seguridad y control de costos. Esa estructura evita el sobrediseño.
La lección más importante
Llamar al modelo es la opción más sencilla:
model.invoke(...)
Después comienza la ingeniería: gestión de prompts, estructura de respuestas, contexto fiable, conexiones API, mantenimiento de la lógica empresarial fuera del modelo, monitoreo, control de permisos y sustitución de modelos sin necesidad de reescribirlos. Esas cuestiones convierten un experimento en software. LangChain debe verse no como “una forma de llamar a un LLM”, sino como bloques de construcción que conectan modelos probabilísticos con sistemas deterministas. El modelo es solo un componente; el verdadero trabajo está en todo lo que lo rodea.
Pensamiento final
No comience con el agente más elaborado que pueda imaginar. Empiece con una sola llamada al modelo, luego un prompt reutilizable, después una salida estructurada, seguida de datos propios y herramientas; los agentes solo cuando el problema lo exija. Esa progresión es más fácil de entender, probar, depurar y desplegar. La ingeniería de software sigue siendo la disciplina, ahora con un nuevo tipo de componente en su caja de herramientas.
Los equipos de producción también descubren que la versionado de los prompts debe ir junto con el versionado del código. Tratar el texto del prompt como una cadena invisible dentro de un manejador hace que los retrocesos sean problemáticos cuando un cambio en la redacción empeora silenciosamente las respuestas. Almacene las plantillas en archivos revisables, etiquete las versiones en los registros junto a las trazas de invoke(), y mantenga un conjunto ideal de entradas de evaluación que deben seguir funcionando bien después de cada edición del prompt. Esa disciplina es la higiene habitual del software aplicada a los componentes probabilísticos.
El costo y la latencia merecen la misma atención desde el principio. Una cadena que parece elegante a nivel local puede generar un gasto excesivo de tokens una vez que se acumulan las operaciones de recuperación, los bucles de herramientas y los intentos de reintentar. Se debe medir el número de tokens por resultado exitoso del usuario, y no solo por cada llamada al modelo. Es necesario cachear los fragmentos de información recuperados de forma estable, limitar los bucles de herramientas y fallar rápidamente cuando una herramienta devuelve resultados vacíos, en lugar de pedir al modelo que invente hechos ausentes. Estos controles están fuera del flujo óptimo de LangChain, pero determinan si la funcionalidad puede soportar un aumento repentino en el tráfico.
La evaluación cierra el ciclo. Las pruebas unitarias permiten verificar los analizadores y esquemas. Los conjuntos de evaluación sin conexión pueden medir el grado de fidelidad con respecto al contexto recuperado. La supervisión en línea permite monitorear las tasas de errores de las herramientas y la frecuencia con la que se realizan modificaciones manuales. Sin evaluación, los cambios de modelo y las ajustes en los prompts se convierten en meras prácticas informales. Con ella, LangChain deja de ser simplemente un conjunto de componentes interconectados y se transforma en un subsistema mantenible con criterios claros de calidad.
Cuando algo falla en producción, es preferible utilizar registros estructurados en lugar de capturas de pantalla de la interfaz de chat. Debe registrarse la versión del prompt, el ID del modelo, los IDs de los documentos recuperados, los nombres de las herramientas utilizadas y el resultado final del analizador. Ese registro convierte la afirmación de que “el modelo tuvo alucinaciones” en un incidente reproducible que se puede solucionar ajustando el prompt, mejorando los filtros de recuperación o reforzando el esquema, en lugar de ser una queja vaga sobre la imprevisibilidad de la IA.
Mantenga los cambios de forma gradual, mida lo que realmente importa y trate al modelo como uno más entre muchos colaboradores dentro de un sistema determinista más amplio.
Lecturas relacionadas
- De un chatbot de un nodo a un agente respaldado por MCP en LangGraph — Construye una aplicación de LangGraph capa por capa: estado y reductores, aristas, bucles de herramientas, hilos con puntos de control, tres modos de transmisión en tiempo real y herramientas proporcionadas a través de MCP.
- LangChain 1.x en la práctica: Cadenas, RAG, herramientas y agentes de forma local — Aprende a crear cadenas, generación mejorada mediante recuperación de información, herramientas y agentes RAG con LangChain 1.x utilizando una configuración local gratuita de Ollama, sin necesidad de claves API.