Коли я почав будувати системи LLM, всі вказували мені на LangChain. "Це стандарт," - сказали вони. "Всі приклади використовують його." і вони були праві - якщо ви знаходитесь в екосистемі Python, LangChain є скрізь.
Але ось у чому річ: я не уникаю Лангхейну, тому що це погано. Я уникаю його, тому що він вирішує проблеми, які я вже розв'язую більш явно, і для моїх випадків використання - C#, локальні висновки, конфіденційність, детермінізм - рамки додають тертя, а не цінності.
Це не повідомлення від LangCain, це допис про розуміння того, що проблеми вирішуються, і усвідомлення того, що вони можуть вам не знадобитися.
Тезис: якщо ви розумієте проблеми, розв' язані LangChain, вам не потрібен LangChain.
Спочатку будьмо справедливими.
Швидке створення прототипів - Ви можете зробити демонстрацію за лічені хвилини. getting-початкові приклади дійсно хороші.
Інтеграція з екосистемою Python - Якщо ви вже у світі Python/Jupyter/pandas, LangCain робить все разом безперешкодно.
Як зменшити бар'єр - Для людей, нових до LLM, він надає корисні абстракції: запрошення шаблонів, інструмент виклику шаблонів, керування пам'яттю, вектор DB інтеграції.
LangChain є а прискорювач інтеграціїЦе пришвидшує шлях від "У мене є ідея" до "У мене є демо."
Але проблеми також починаються для мене як виробничі системи розробки C#A.
Перш ніж звільнити систему, вам слід зрозуміти, які проблеми її розв' язання.
Це законні проблеми. Питання в тому, чи потрібна вам система для їх розв'язання?
Для моєї робочої системи .NET з місцевими LLM, строгими вимогами приватності, і детермінованою поведінкою, Лангхейн впроваджує тертя в кількох місцях.
LangChain керує пам' яттю і контекстом. Це звучить зручно, аж доки вам не потрібно з' ясувати, чому ваш запит дорівнює 10 000 жетонів довше, ніж очікувалося, або чому LLM раптом має доступ до історії розмови, яку ви думали, що очистили.
За допомогою об' єму ви можете наказати програмі виконати запити, керувати пам' яттю і керувати порядком виконання без будь- яких дій. Якщо щось розбивається, ви можете усування вад поведінки оболонки, а не поведінки вашого коду.
Після прийняття LangChain ви починаєте проектування для LangChainВаша архітектура поєднується з абстракцією системи: ланцюгами, агентами, редиссерами, буферами пам'яті.
Це не унікально для LangChain - всі оболонки роблять це, але у області швидкого пересування, на зразок LLM, де правильні абстракції ще не залагоджені, з'єднання до світогляду системи є ризикованим.
LangChain припускає:
Як розробник . NET, я припускаю:
The Порти LangCain.NET існує, але вони граються з версією Python, і абстракції все ще вважаються чужими для ідіоматичного C#.
Коли ви переходите від прототипу до виробництва, вам потрібно:
LangChain оптимізує швидкість ітерації, а не процес імітації виробництва. Це добре для демонстрації; це проблема виробництва.
Ось розумова модель, яку я використовую: LLM - це логічні рушії, а не рушії виконання.
Принцип: Причина LLM. Двигуни обчислюють.
Це розділення керує всім, що я будую.
Замість пам' яті з керуванням об' єктом, я будую контекст явно на запит:
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; }
}
Кожна негайна побудова видима. Я точно знаю, що відправляється в LLM, тому що я побудував рядок сам:
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();
}
Ніякого таємного стану, ніякого магічного контетенту, просто ясної будівлі струн, коли це не так, я знаю чому.
Замість того, щоб дозволити LLM виконати що-небудь, я використовую його для створення Мета, потім виконати цей намір через детермінуючі двигуни:
LLM створює SQL. DuckDB виконує його. LLM ніколи не бачить даних:
// 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);
Це безпечніше, швидше і знешкоджене. LLM не може випадково запустити DROP TABLE LLM не може протікати дані, тому що він ніколи не бачить дані - тільки схема.
Нещодавно я писав про Аналіз великих файлів CSV за допомогою локальних LLMАрхітектура:
Питання користувача → LLM → SQL → DuckDB → Результати
LLM отримує:
The LLM генерує:
Система тоді:
EXPLAIN (виводить синтаксичні помилки без виконання)LLM ніколи не бачить реальних даних. Він бачить лише структуру.
Це те, що LangChain назвав би "агентом" - системою, яка використовує LLM для створення дій, перевірки їх, виконання і потенційні ретакції при невдачі.
Окрім того, що я побудував його у ~200 рядках C# без оболонок:
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);
}
}
Просто явне оркестрування LLM → перевірка → виконання.
Термін "агент" прокидається навколо постійно, зазвичай, щоб мати на увазі "що-небудь пов'язане з LLM." Давайте будемо точні.
Агент:
Агентом є не бібліотекаЦе шаблон.
Шаблон мого агента у 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);
}
}
Це агент, це петля зі штатами, інструментами та зворотним зв'язком.
Щоб бути справедливим до екосистеми .NET, Microsoft випустив Microsoft Agent Framework Це зроблено для розробки систем виробництва AI.
Основа (колишня відома як Microsoft.Extensions.AI) надає:
Компоненти ключів:
IChatClient - Універсальний інтерфейс для завершення балачкиIEmbeddingGenerator - Вбудовування векторів через постачальників послугAIFunction - Виклик до безпечної функції типуПриклад:
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;
});
Навіть з шаблоном Microsoft, я вважаю за краще тримати базове оркестрування явним:
Я не хочу:
Я хочу:
Вона поважає моделі . NET, правильно використовує ін'єкції залежності і не бореться з екосистемою.
Коли використовувати рамки Microsoft Agent:
Під час обходу без обмежень:
База не усуває архітектурні рішення. Ви все ще обираєте те, що слід вкласти в контекст, як відрізати дані і коли повторювати. Це лише полегшує роботу водопровідної системи.
Бездротова система старіє з декількох причин:
Швидкодія Моя служба запитів CSV не працює через відсутність рамки між LLM і DuckDB.
Прогнозованість вартості - Я контролюю саме те, що йде до LLM.
Можливість зневаджування - Когда что-то сломается, я изображаю свой код, а не перевертаю магию карии.
Конфіденційність - Для систем с строгими стандартами по базам данных, изначально, понимая, что оставляет дело в машине.
Автономні сценарії Устройства ребра, сеть с воздухом, регульированные обстановки.
Регульований послух - Фінансами, охороною здоров'я та урядом, вам часто потрібно пояснювати та перевіряти кожне рішення.
Чим більше обмежується твоє середовище, тим більше ти хочеш мати явний контроль.
Для роззброєних критиків існують законні випадки, коли я б добився до Лангхейна.
Хакафонсlithuania_ municipalities. kgm - Швидкість до демонстрації має більше значення, ніж архітектура.
Викинути POC - Якщо ви підтверджуєте ідею і плануєте переписати її для виробництва в будь-якому випадку.
Вага Python- команди - Якщо ваша команда вже вільно працює на Python, екосистема дуже сильна.
Вчення понять Абстракти Лангхіна можуть допомогти початківцям зрозуміти модель агента, перш ніж будувати власну.
Знати коли неDescription of a condition. Do not translate key words (# V1S #, # V1 #,) використовувати щось настільки ж цінне, як знання того, коли саме ним користуватися.
Мова йде не про Лангхейн, а про компроміс між системами та інженерією першокласників.
Frameworks прискорюють знайомі проблеми. Якщо ви створюєте програмний інтерфейс 100- го CRUD, докладайте зусиль для створення фреймів сутностей або Dapper. Шаблони буде вирішено.
Але LLM-силові системи? чи "абстракціоністи" чи "справжні розумові моделі." ми все ще з"ясовуємо це.
У такому середовищі я волію будувати поруч з металом:
OllamaSharp, OpenAI SDK)Як розробник .NET, я маю тверду думку про те, як слід будувати системи: явні терміни життя, сильний друк, синхронізація до кінця, ін'єкція залежностей для перевірки.
Абстракти Лангхейн не відносяться чисто до цих поглядів, тому я не використовую їх.
Якщо ви - розробник .NET, який дивиться на LangCain і запитує: "Чи мені це потрібно?" ось моя відповідь:
Вам потрібно вирішити проблеми, пов'язані з LangCain - Керування контекстом, інструмент оркестрування, повторення логіки, невизначеність.
Вам не потрібно, щоб LangCain розв'язував їх - Особливо, якщо ви цінуєте явність, сильний друк і виробництво тверді через швидкі прототипи.
Принцип над яким я будую:
"Правила пам'яті, двигуни обчислюють. Оркестрування - ваш власний."
Або простіше:
"Якщо ви розумієте проблеми, які розв'язує система, вам часто не потрібна система."
Зібрати системи, які мають сенс у вашій екосистемі, з вашими обмеженнями, використовуючи ідіоми вашої мови. Для мене це C#, сильний друк, явний контрольний потік і детермінуючі шари виконання.
Для вас все може бути по-іншому.
Мета полягає не в тому, щоб уникнути обмежень, а в тому, щоб вибрати їх свідомо, з розумінням як того, що вони забезпечують, так і того, що вони коштують.
Подальше читання:
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.