Soy desarrollador de .NET. Cuando empecé a construir sistemas alimentados por LLM, todos me apuntaron hacia LangChain. "Es el estándar", dijeron. "Todos los ejemplos lo usan". Y tenían razón - si estás en el ecosistema de Python, LangChain está en todas partes.
Pero esto es lo que pasa: no evito a LangChain porque es malo. Lo evito porque resuelve problemas que ya resolvo más explícitamente, y para mis casos de uso - C#, inferencia local, privacidad, determinismo - los marcos añaden fricción en lugar de valor.
Este no es un post anti-LangChain. Es un post sobre entender qué marcos de problemas resuelven, y darse cuenta de que es posible que no los necesite.
Tesis: Si entiendes los problemas que LangChain resuelve, no necesitas LangChain.
Seamos justos primero. LangChain sobresale en varias cosas:
Prototipado rápido Los ejemplos de cómo empezar son realmente buenos.
Integración del ecosistema de Python - Si ya estás en el mundo Python/Jupyter/pandas, LangChain pega todo sin problemas.
Bajar la barrera - Para las personas nuevas en LLMs, proporciona abstracciones útiles: plantillas de prompt, patrones de llamada de herramientas, gestión de memoria, integraciones vectoriales de DB.
LangChain es un acelerador de integración, no un requisito de IA. Acelera el camino de "Tengo una idea" a "Tengo una demostración". Eso es valioso.
Pero también es donde los problemas comienzan para mí como un desarrollador de C# construyendo sistemas de producción.
Antes de descartar un marco, usted necesita entender qué problemas está resolviendo. LangChain aborda estos problemas reales:
Se trata de problemas legítimos. La pregunta es: ¿necesita un marco para resolverlos?
Para mi trabajo - construcción de sistemas .NET con LLM locales, estrictos requisitos de privacidad y comportamiento determinista - LangChain introduce fricción en varias áreas.
LangChain gestiona la memoria y el contexto para usted. Eso suena conveniente hasta que necesite depurar por qué su prompt es 10.000 tokens más de lo esperado, o por qué el LLM de repente tiene acceso al historial de conversación que pensó que había despejado.
El framework concatena, gestiona la memoria y maneja el orden de ejecución implícitamente. Cuando algo se rompe, estás depurando el comportamiento del framework, no el comportamiento de tu código.
Una vez que adoptes LangChain, empiezas a diseñar por LangChain. Su arquitectura se acopla a las abstracciones del marco: cadenas, agentes, retrievers, buffers de memoria.
Esto no es exclusivo de LangChain - todos los marcos hacen esto. Pero en un campo de movimiento rápido como LLMs, donde las abstracciones correctas todavía no están establecidas, el acoplamiento a la visión del mundo de un marco es arriesgado.
LangChain asume:
Como desarrollador de .NET, asumo:
Los LangChain .NET puertos existen, pero están jugando a ponerse al día con la versión de Python, y las abstracciones todavía se sienten extrañas a C# idiomático.
Cuando pasas del prototipo a la producción, necesitas:
LangChain optimiza la velocidad de iteración, no el endurecimiento de la producción. Está bien para las demostraciones; es un problema para la producción.
Aquí está el modelo mental que utilizo: Los LLM son motores de razonamiento, no motores de ejecución.
El principio: Los motores computan.
Esta separación conduce todo lo que construyo.
En lugar de la memoria administrada por framework, construyo un contexto explícitamente por petición:
public class QueryContext
{
public List<ColumnInfo> Schema { get; set; }
public List<Dictionary<string, string>> SampleRows { get; set; }
public List<ConversationTurn> History { get; set; }
public string UserQuestion { get; set; }
}
Cada construcción rápida es visible. Sé exactamente lo que se está enviando a la LLM porque construí la cuerda yo mismo:
private string BuildPrompt(QueryContext context)
{
var sb = new StringBuilder();
sb.AppendLine("You are a SQL expert. Generate a query based on:");
sb.AppendLine();
// Schema
sb.AppendLine("Schema:");
foreach (var col in context.Schema)
sb.AppendLine($" - {col.Name}: {col.Type}");
// History (if any)
if (context.History.Any())
{
sb.AppendLine("\nPrevious conversation:");
foreach (var turn in context.History.TakeLast(3))
sb.AppendLine($" Q: {turn.Question} → SQL: {turn.Sql}");
}
// Current question
sb.AppendLine($"\nQuestion: {context.UserQuestion}");
sb.AppendLine("Generate SQL (no explanation, just the query):");
return sb.ToString();
}
No hay estado oculto, no hay concatenación mágica, sólo construcción explícita de cuerdas, cuando está mal, sé por qué.
En lugar de dejar que el LLM ejecute cualquier cosa, lo uso para generar intención, a continuación, ejecutar esa intención a través de motores deterministas:
El LLM genera SQL. DuckDB lo ejecuta. El LLM nunca ve los datos:
// LLM generates intent
var sql = await GenerateSqlAsync(context);
// Validate before execution
var error = ValidateSql(connection, sql);
if (error != null)
{
// Retry with error feedback
sql = await GenerateSqlAsync(context, previousError: error);
}
// Execute in sandboxed engine
var results = ExecuteQuery(connection, sql);
Esto es más seguro, más rápido y desmontable. El LLM no puede correr accidentalmente. DROP TABLE porque valido el SQL primero. El LLM no puede filtrar datos porque nunca ve los datos - sólo el esquema.
Hace poco escribí sobre análisis de archivos CSV grandes con LLM locales. La arquitectura:
Pregunta de usuario → LLM → SQL → DuckDB → Resultados
El LLM recibe:
El LLM genera:
El sistema entonces:
EXPLAIN (atrapa errores de sintaxis sin ejecutar)El LLM nunca ve los datos reales. Sólo ve la estructura.
Esto es lo que LangChain llamaría un "agente" - un sistema que utiliza un LLM para generar acciones, validarlas, ejecutarlas, y potencialmente reinicia en caso de fallo.
Excepto que lo construí en ~200 líneas de C# sin marco:
public class CsvQueryService
{
private readonly OllamaApiClient _ollama;
private readonly string _model;
public async Task<QueryResult> QueryAsync(string csvPath, string question)
{
using var connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();
// 1. Build context
var context = BuildContext(connection, csvPath, question);
// 2. Generate SQL
var sql = await GenerateSqlAsync(context);
// 3. Validate
var error = ValidateSql(connection, sql);
if (error != null)
{
// Retry once with error feedback
sql = await GenerateSqlAsync(context, error);
}
// 4. Execute
return ExecuteQuery(connection, sql);
}
}
Eso es todo. Sin cadenas, sin marco de agentes, sin magia. Sólo orquestación explícita de LLM → validación → ejecución.
El término "agente" se lanza constantemente, normalmente significa "cualquier cosa que involucre un LLM". Seamos precisos.
Un agente es:
Un agente es no una bibliotecaEs un patrón.
Mi patrón de agente en C#:
public class Agent
{
private readonly List<ConversationTurn> _history = new();
public async Task<string> RunAsync(string goal)
{
while (!IsGoalAchieved(goal))
{
// 1. Generate next action based on history
var action = await GenerateActionAsync(goal, _history);
// 2. Validate before executing
if (!IsActionSafe(action))
{
_history.Add(new ConversationTurn
{
Action = action,
Result = "REJECTED: Unsafe action"
});
continue;
}
// 3. Execute through deterministic tool
var result = await ExecuteActionAsync(action);
// 4. Record and continue
_history.Add(new ConversationTurn { Action = action, Result = result });
}
return GenerateSummary(_history);
}
}
Esto es un agente. Es un bucle con estado, herramientas, y retroalimentación. Lo escribí en 30 líneas. No necesitaba un marco.
Para ser justos con el ecosistema .NET, Microsoft ha lanzado el Microsoft Agent Framework que está diseñado especialmente para los desarrolladores de .NET construyendo sistemas de producción de IA.
El framework (anteriormente conocido como Microsoft.Extensions.AI) proporciona:
Componentes clave:
IChatClient - Interfaz unificada para completar el chatIEmbeddingGenerator - Incrustaciones vectoriales entre proveedoresAIFunction - Llamada de función seguraEjemplo
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddChatClient(builder =>
builder.UseOllama("llama3.2")
.UseOpenTelemetry()
.UseLogging());
var app = builder.Build();
app.MapPost("/chat", async (IChatClient client, string message) =>
{
var response = await client.CompleteAsync(message);
return response.Content;
});
Incluso con el marco de Microsoft, prefiero mantener la orquestación central explícita:
No quiero:
Quiero:
Microsoft's Agent Framework está más cerca de cómo pienso que LangChain. Respeta los patrones .NET, utiliza la inyección de dependencia correctamente, y no lucha contra el ecosistema. Pero todavía prefiero escribir la orquestación yo mismo.
Cuándo usar el Microsoft Agent Framework:
Cuándo ir framework-less:
El marco no elimina las decisiones arquitectónicas. Usted todavía elige qué poner en contexto, cómo trocear los datos, y cuándo volver a intentarlo. Simplemente hace la plomería más fácil.
Los sistemas sin marco envejecen mejor por varias razones:
Desempeño Mi servicio de consulta CSV ejecuta sub-100ms porque no hay marco entre el LLM y DuckDB.
Predecibilidad de los costos - Controlo exactamente lo que va a la LLM. No hay inflación rápida oculta de la memoria administrada por framework.
Defugabilidad - Cuando algo se rompe, estoy depurando mi código, no la ingeniería inversa de la magia de un marco.
Privacidad - Para sistemas con estrictos requisitos de residencia de datos, saber exactamente lo que deja la máquina importa.
Escenarios fuera de línea - Dispositivos de borde, redes aerotransportadas, entornos regulados. Los marcos asumen acceso a Internet y servicios en la nube.
Cumplimiento de la normativa - En finanzas, salud y gobierno, a menudo necesitas explicar y auditar cada decisión. "El marco lo hizo" no es una respuesta aceptable.
Cuanto más limitado sea su entorno, más desea un control explícito.
Para desarmar a los críticos: hay casos legítimos en los que buscaría a LangChain.
Hackathons - La velocidad de demostración importa más que la arquitectura.
POC de desecho - Si estás validando una idea y planeas reescribir para la producción de todos modos.
Equipos Python-pesados - Si su equipo ya tiene fluidez en Python, el ajuste del ecosistema es fuerte.
Conceptos de enseñanza - Las abstracciones de LangChain pueden ayudar a los principiantes a entender el patrón de agente antes de construir el suyo propio.
Saber cuándo no usar algo es tan valioso como saber cuándo usarlo.
Esto no se trata realmente de LangChain, sino de la compensación entre los marcos y la ingeniería de los primeros principios.
Los frameworks aceleran los problemas familiares. Si está construyendo la 100a API CRUD, alcance a Entity Framework o Dapper. Los patrones están arreglados.
No sabemos si las "cadenas" o "agentes" o "recompensas" son los modelos mentales correctos.
En ese ambiente, prefiero construir cerca del metal:
OllamaSharp, OpenAI SDK)Como desarrollador de .NET, tengo fuertes opiniones sobre cómo se deben construir los sistemas: vidas explícitas, mecanografía fuerte, async todo el camino hacia abajo, inyección de dependencia para la prueba.
Las abstracciones de LangChain no hacen un mapa limpio de esas opiniones, así que no las uso.
Si usted es un desarrollador de .NET mirando a LangChain y preguntándose "¿Necesito esto?", aquí está mi respuesta:
Tienes que resolver los problemas que LangChain resuelve - gestión de contextos, orquestación de herramientas, lógica de reintento, observabilidad.
No necesitas a LangChain para resolverlos. - Especialmente si valoras la explicitación, la escritura fuerte, y el endurecimiento de la producción sobre el prototipado rápido.
El principio sobre el que me baso:
"La razón de los LLMs, los motores computan, la orquestación es tuya para poseer".
O más simplemente:
"Si entiendes los problemas que resuelve un marco, a menudo no necesitas el marco".
Construye sistemas que tengan sentido en tu ecosistema, con tus limitaciones, usando las expresiones de tu idioma. Para mí, eso es C#, fuerte mecanografía, flujo de control explícito y capas de ejecución determinista.
Para ti, podría ser diferente y está bien.
El objetivo no es evitar los marcos, sino elegirlos conscientemente, entendiendo tanto lo que proporcionan como lo que cuestan.
Más información:
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.