# Pourquoi ne pas utiliser la chaîne Lang (et ce que je fais au lieu de celle-ci

<!--category-- AI, Architecture, LLM, Agents, Systems Design, C# -->
<datetime class="hidden">2025-12-18T10:00</datetime>

I'je suis un .développer NETM SK2 Lorsque j’ai commencé à construire des systèmes à l’aide d’un LLM, -d’une puissance électrique,,tous m’ont fait pointer vers LangChain,. "Il est la norme de 'MSC8ils me ont dit:\".\", ""\". Tous les exemples en font usage.

Mais ici ' c'est la chose : je ne l'évite pas ' il n'y a pas de LangChain parce qu'il est mauvais ' je le évite parce que cela résout les problèmes que j'ai déjà résolus plus explicitement , et pour mes cas d'utilisation

Il ne s’agit pas d’un post anti--, de long chaine, de ., mais d’une post sur la compréhension des cadres qui régissent les problèmes et sur le fait que vous n’en avez peut-être pas besoin.

**Thèse: Si vous comprenez les problèmes résolus par LangChain, vous n’avez pas besoin de LangeChain**

[TOC]

## Ce que LangChain fait bien en réalité

Let's be fair firstM SK1 LangChain excelle à plusieurs égards:

**Production de prototypes rapides** - Vous pouvez avoir une démonstration de travail en quelques minutes.

**Intégration de l'écosystème Python** - Si vous ' êtes déjà dans le PythonMSC2Jupyter/le monde des pandasM SK4La LangChain colle tout ensemble sans écrasement

**Réduction de la barrière** - Pour les nouveaux utilisateurs de LLMs, il fournit des abstractions utiles : templates d'appel prompts

La LangChain est une **Accélérateur d'intégration**, ne s'agit pas d'une exigence en matière de savoir-faire . Il accélère le cheminement de "J'ai une idée" vers M"Je possède une démonstrationM SK5 C'est ce qui est valable pour '

Mais c’est aussi là que les problèmes commencent pour moi comme développeur de systèmes de construction et de production.

## Les problèmes résolus par la chaîne Lang

Avant de rejeter un cadre, vous devez comprendre les problèmes qu’il doit résoudre.

1. **Contexte** - Établissement de prompts cohérents à partir du schéma , échantillons M SK2 histoire , et contraintes
2. **Orchestrement des outils** - Gestion de plusieurs appels d'outils en séquence avec logique conditionnelle
3. **Gestion de l'État** - Maintenir le contexte de conversation à plusieurs tours
4. **Essayer de nouveau et traiter les erreurs** - Récupération gracieuse lorsque le LLM génère une sortie invalide
5. **Rationalisation à plusieurs étapes** - Diviser les tâches complexes en étapes séquentielles (le "agentM SK3patterne)
6. **Observabilité** - Surveillance de ce qui s’est réellement passé pendant l’exécution

Il s’agit de problèmes légitimes.

## Où la LangChain commence à s'affaiblir

Pour mon travail - la production de bâtiments . les systèmes NET avec des LLM locaux, les exigences strictes en matière de protection de la vie privéeM SK3 et le comportement déterministe MSC4 LangChain introduit une friction dans plusieurs domainesMSC5

### État caché et flux de contrôle implicite

LangChain gère la mémoire et le contexte pour vous. Cela semble convenable jusqu’à ce que vous ayez besoin de débuger les raisons pour lesquelles votre prompt est plus long que prévu |10,000 |Tokens | , | ou pourquoi le LLM a soudainement accès à l’histoire des conversations que vous croyez avoir |

Le cadre concatenate les prompts, gère la mémoire, et manipule implicitement l'ordre d'exécutionM SK2 Lorsque quelque chose se défectue , vousMSC4 vous débuisez le cadreMST5 son comportementMst6 non votre codeMSt7 son behaviorM st8

### Cadre-Thématiques couplées

Une fois que vous adoptez LangChain,, vous commencez à concevoir **pour LangChain**. Votre architecture est couplée au cadre ' ses abstractions M SK2 chaînes , agents

Cela n’est pas unique à LangChain.

### L'incompatibilité entre les répercussions de Python

LangChain suppose:

- Processus longs-procédures vivantes M SK1livre de notes-flows de travail en style )
- État global mutable
- Python's de type dynamique et duck typing
- bloquer les modèles I/O

En tant que .développer NETM SK1 je suppose:

- Demande-durée de vie étudiée (ASP.NET Patterns de baseM SK3
- État de gestion immuable ou explicite-
- Efficacité du type et de la compilation-sécurité en temps
- Async/attendre partout

L'article 5 de la Loi sur l'immigration et le statut des réfugiés [Ports LangChain .NET](https://github.com/tryAGI/LangChain) existent, mais ils're jouant catchM SK2up avec la version Python , et les abstractions se sentent encore étrangères à l’anglophone CMSC4

### Les lacunes dans la réalité de la production

Lorsque vous passerez du prototype à la production, vous avez besoin

- **Déterminisme** - La même entrée devrait produire un comportement prévisible
- **Validation** - Assurez-vous que la sortie du LLM' est sûre avant de l'exécuter
- **Sandboxing** - Limiter ce que le code généré peut réellement faire
- **Contrôle des coûts** - Utilisation des tokens de piste et imposition de limites
- **Inférence locale** - Faire fonctionner les modèles en mode offline sans dépendance de la nuage

LangChain optimise la vitesse d’iteration, non le durcissement de la production . QueM SK2 est bon pour les démos; c’est un problème pour la production

## Ce que je construis plutôt

Voici le modèle mental que j’utilise : **Les LLM sont des moteurs de raisonnement, et non des engines d’exécution.**

### LLMs Do:

- **Interprétation** - Comprendre l’intention des utilisateurs à partir de la langue naturelle
- **Planification** - Transformer des tâches complexes en étapes
- **Traduction** - Conversion de l'intention en formats structurés

### LLMs ne font pas :

- **Calcul des agrégats** - Sommaire des lignes
- **Détecter les ensembles de données** - Recherche de fichiers importants
- **État propre** - Maintenir une mémoire à long terme

Le principe: **LLMs raison. Calcul des moteurs.**

Cette séparation conduit tout ce que je construit.

### Contexte explicite, Non mémoire magique

Au lieu de cadres-mémoire géré , Je construise le contexte explicitement par demande:

```csharp
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; }
}
```

Chaque construction rapide est visible. Je sais exactement ce qu’on envoie à l’LM, parce que j’ai construit la chaîne moi-même:

```csharp
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();
}
```

Aucun état caché. Aucune concaténation magique . Juste construction explicite de chaînes. Quand il est incorrectMSC3M SK4 Je sais pourquoi

### Layers d'exécution déterministes

Au lieu de laisser le LLM exécuter quelque chose, je l'utilise pour générer **Intention**, puis exécuter cette intention par le biais de moteurs déterministes

- **Les moteurs SQL** (DuckDBM SK1 - Pour les demandes de données
- **Les moteurs de recherche** (LuceneM SK1 Postgres complet-texteMSC3 - Pour la recherche de documents
- **Mécanismes de régulation** - Pour la logique commerciale
- **Services de domaine** - Pour les opérations validées

Le LLM génère SQL. DuckDB l'execute. Le LL ne voit jamais les donnéesM SK2

```csharp
// 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);
```

Cela est plus sûr, plus rapide, et débugableM SK2 Le LLM ne peut pas fonctionner accidentellement `DROP TABLE` parce que j’approuve la première fois l’ SQL. Le LLM ne peut 't détruire les données car il n’ voit jamais les données - seulement le schémaM SK3

## Exemple concrète: Analyse CSV sans cadres

J'ai récemment écrit sur [Analyse de grandes fichiers CSV avec des LLM locaux](https://mostlylucid.net/blog/analysing-large-csv-files-with-local-llms). L'architecture

**Question de l'utilisateur → LLM → SQL MSC2 DuckDB MSC3 Résultats**

Le LLM reçoit:

- Le schéma CSV ( noms et types de colonnesM SK1
- 3 lignes d'échantillonnage (pour comprendre le format des donnéesM SK2
- La question de l'utilisateur'

Le LLM génère:

- Une demande SQL DuckDB

Le système alors:

- Validation de l' SQL en utilisant `EXPLAIN` (obtient des erreurs de syntaxe sans exécuter
- Exécute la demande contre le fichier CSV
- Retourne les résultats à l'utilisateur

Le LLM ne voit jamais les données réelles. Il ne voit que la structure.

C'est ce que LangChain appelerait un "agent" - un système qui utilise un LLM pour produire des actionsM SK3 les valideMST4 les exécuteM ST5 et peut-être les répéter sur le défaillanceM st6

Sauf que je l’ai construite dans des lignes ~200 de C# sans cadreM SK2

```csharp
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);
    }
}
```

Que'c'est-à-dire, . Pas de chaînes, non de cadre d'agents, pas de magique, non d'organisation explicite du LLM, mais seulement de validation, de mise en oeuvre et d'exécution.

## Qu’est-ce qu’un agent?

L’expression « agent » est répandue constamment.

Un agent est:

- **Un cercle** - Il fait plusieurs iterations
- **Avec l'État** Il se souvient de ce qu’il a essayé
- **Avec les outils** - Il peut agir dans le monde
- **Avec la rétroaction** - Il observe les résultats et les ajuste

Un agent est **n'est pas une bibliothèque**. C’est un modèle.

Mon modèle d'agent dans C#:

```csharp
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);
    }
}
```

Il s’agit d’un agent.

## Si le cadre d'agent de Microsoft ' convient

Pour être juste à l’égard de .NET ecosystem, Microsoft a publié le [Cadre d'agents Microsoft](https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview) qu’il a été construit pour les développeurs du NET qui construisent des systèmes d’AI de production;

### Ce que le Cadre d'agents de Microsoft obtient correctement

Le cadre (anciennement connu sous le nom de Microsoft .Extensions.AIM SK3 fournit

- **Orchestrement explicite** - Vous contrôlez la boucle d'agents , non le cadre
- **Taille forte** - Compiler- Sécurité du temps pour les définitions d'outils et l'appel de fonctions
- **Observabilité de la première classe** - Établissement de - dans la télémétrie,, signalement,, et traçage distribué par OpenTelemetry
- **Limites de l'entreprise** - Conçue pour la production . Systèmes NET avec configuration DI, et gestion du cycle de vie
- **Multi-appui au modèle** - Abstractions sur OpenAI, Azure OpenAI≥, OllamaM SK3 et autres fournisseurs
- **Intégration du noyau sémantique** - fonctionne avec l’ensemble d’AI plus large de Microsoft'

Composantes clés:

- `IChatClient` - Interface unifiée pour l'achèvement du chat
- `IEmbeddingGenerator` - Emplacements vecteurs à l'échelle des fournisseurs
- `AIFunction` - Type-appel de fonction sûre
- Middleware pipeline - Pour l'enregistrement, pour la réessaiM SK2 caching , télémétrie

**Exemple:**

```csharp
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;
});
```

### Où suis-je encore plus bas-Level

Même avec Microsoft's framework, Je préfère garder l’orchestre explicite

**Je ne veux pas**

- **Planificateurs opaques** - Le cadre qui décide autonomement quel outil appeler
- **Choix de l'outil implicite** - Routage magique fondé sur des descriptions de langue naturelle
- **Logique de réessai cachée** - Cadre -Récupération d'erreurs gérées Je peux inspecter

**Je veux:**

- **Liens visibles** - Je vois toutes les iterations dans mon code
- **Étapes testables** - Je peux tester la logique de décision par unité
- **Composantes remplaçables** - Je peux échanger le LLM, les outilsM SK2 la couche de validation
- **État explicite** - Je sais exactement ce qui est dans le contexte

Microsoft's Agent Framework est plus proche de ce que je pense que LangChain . Il respecte . Patterns NETM SK3 utilise correctement l’injection de dépendance

**Quand utiliser le Cadre d'agent Microsoft:**

- Établissement d'applications de chat avec appel de fonction
- Besoin d'un support multimodèle- (switch entre OpenAI , AzureM SK3 OllamaMSC4
- Besoin de fonctionnalités pour l'entreprise (telemétrie,logageM SK2tractation répartie )
- Travailler dans une équipe qui préfère la cohérence du cadre
- Établissement au-dessus du noyau sémantique

**Quand aller le cadre-moins:**

- Vous avez besoin du contrôle complet de la boucle d'agents
- Vous construisez des modèles de raisonnement personnalisés
- Vous voulez l'abstraction zéro à la tête
- Vous' vous optimisez pour des usages particuliers ( comme l’analyse CSV ou le scraping de web)
- Vous voulez comprendre exactement comment il fonctionne

Le cadre ne permet pas d’éliminer les décisions architecturales.

## Pourquoi cette échelle est-elle plus longue-Term

Cadre-Les systèmes sans système vieillissent mieux pour plusieurs raisons:

**Rendement** - Aucune abstraction à l’extrême-plan . Mon service de demande CSV fonctionne sous -100ms parce qu’il n’y a pas de cadre entre le LLM et DuckDB.

**Prévisibilité des coûts** - Je contrôle exactement ce qui va au LLM. Aucune inflation imprégnée cachée du cadreM SK2mémoire géré .

**Débuggingbilité** - Lorsque quelque chose se détruisit, , Je m’attaque à mon code.

**Protection des renseignements personnels** - Pour les systèmes ayant des exigences strictes en matière de résidence des donnéesM SK1 sachant exactement ce qui laisse à la machine une importance

**Systèmes hors ligne** - Dispositifs de bordM SK1 aérospatiale - réseaux réservés M SK3 environnements réglementés . Les cadres prévoient l’accès à Internet et les services dans la numérisation

**Respect de la réglementation** - Dans le domaine des finances, , dans les soins de santé, M SK2 et dans l’administration publique, , vous devez souvent expliquer et vérifier chaque décision.

Plus votre environnement est restreint, plus vous voulez un contrôle explicite.

## Quand je vais utiliser LangChain

Pour désarmer les critiques, il y a des cas légitimes où I'd s’adresse à LangChain.

**Hackathons** - La vitesse d’exécution de la démonstration est plus importante que l’architecture

**POCs à jeter** - Si vous ' validez une idée et planifiez de la réécrire pour la production en tout état de cause

**Python-équipes lourdes** - Si votre équipe est déjà fluente en Python, l’adaptabilité de l’écosystème est forteM SK2

**Concepts d'enseignement** Les abstractions de -, LangChain et ' peuvent aider les débutants à comprendre le modèle d’agent avant de créer leur propre.

Sachant quand **non pas** utiliser quelque chose est aussi précieux que savoir quand l'utiliser.

## Le modèle plus large: Cadre vs. Premiers principes

Il ne s’agit pas vraiment de la LangChain, mais du compromis entre les cadres et le premier, l’ingénierie des principes.

Les cadres accélèrent les problèmes familiers. Si vous ' construisez la 100th CRUD APIM SK3 reached for Entity Framework or DapperMSC4 Les patrons sont réglésMST5

Mais LLM-systèmes à moteur? Les abstractions appropriées ne sont pas encore réglées 'M SK3 Nous ne savons pas ' si les MSC5chaînesMNK6 ou MNK7agentsPNK8 ou PNK9rétrieursMMK10 sont les modèles mentals appropriésSNK11 NousMRK12en sommes toujours à la recherche d’une solution.

Dans ce contexte, je préfère construire près du métal.

- LLM par appels directs API (`OllamaSharp`, OpenAI SDK)
- Construction rapide par l'intermédiaire d'une construction explicite de chaînes
- Validation par le biais du domaine- logique spécifique
- Exécution par voie de but- moteurs généraux (SQL, rechercheM SK3 etc.

En tant que développeur .NET, Je suis fortement d'avis sur la façon dont les systèmes devraient être construits : durée de vie explicite M SK3 typographie robuste

LangChain Les abstractions de ' ne permettent pas à ' d’apparaître clairement ces opinions.

## Le voyage d'affaires

Si vous êtes un développeur .NET qui regarde LangChain et se demande :

**Vous devez résoudre les problèmes que LangChain résout** - gestion du contexte , orchestration de l'outilM SK2 logique de retry, observabilitéMSC4

**Vous n’avez pas besoin de LangChain pour les résoudre** - Plus particulièrement si vous valorisez l’explicité , typographie forte M SK2 et durcissement de la production par rapport à un prototype rapide .

Le principe que je fonde sur:

**"LLMs raisonM SK1 Compute des moteurs . L'orchestre est votres à vous**

Ou plus simplement:

**"Si vous comprenez les problèmes qu’un cadre permet de résoudre , vous n’avez souvent pas besoin de ce cadre**

Construisez des systèmes qui ont sens dans votre écosystème, avec vos contraintes, en utilisant votre langueM SK2 ses idiomes . Pour moiMSC4 queMNK5 sa C MNK6 un type fortMRK7 le flux de contrôle expliciteMMK8 et les couches d’exécution déterministesMEK9

Pour vous, ce serait peut-être différent.

L’objectif n’est pas d’éviter les cadres; l’objectif est de les choisir conscientement.

---


**Lire plus:**

- [Analyse des fichiers de grande taille CSV avec les LLM locaux en C#](/blog/analysing-large-csv-files-with-local-llms) - Un exemple concret de LLM + SQL sans cadres
- [Extraire et analyser le contenu Web avec les LLM](/blog/fetching-and-analysing-web-content-with-llms) - Traitement et analyse Web sans cadres
- [Documentation du Cadre d'agents de Microsoft](https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview) - Cadre d'agent officiel de Microsoft pour .NET
- [Microsoft.Extensions.AI](https://devblogs.microsoft.com/dotnet/introducing-microsoft-extensions-ai-preview/) - Abstraktions fondamentales de l'AI pour .NET
- [Kernel sémantique](https://github.com/microsoft/semantic-kernel) - Microsoft's LLM orchestration SDK
- [Documentation LangChain](https://python.langchain.com/) - Pour comprendre ce que vous choisissez de ne pas utiliser
- [OllamaSharp](https://github.com/awaescher/OllamaSharp) - C# client pour l'inférence locale de LLM