Une méthode pragmatique pour intégrer un LLM dans une application .NET avec des frontières claires, de la sécurité et des usages utiles en production.

Intégrer un LLM dans une application .NET
L'intégration d'un LLM dans une application .NET ne consiste pas à appeler une API et afficher du texte. En production, un modèle de langage devient une capacité supplémentaire du système. Il faut donc le traiter comme un composant applicatif avec ses limites, ses contrats et ses risques.
La bonne approche est de partir du cas d'usage, pas du modèle.
Commencer par le besoin produit
Un LLM peut servir à beaucoup de choses:
- assister la recherche documentaire
- résumer des tickets ou des emails
- classer du contenu
- extraire des données structurées
- orchestrer des actions via tool calling
Mais tous les cas d'usage ne justifient pas un LLM. Avant d'intégrer quoi que ce soit, il faut définir:
- quelle valeur métier est attendue ?
- quel niveau de précision est acceptable ?
- que se passe-t-il si la sortie est mauvaise ?
- quelles données peuvent être envoyées au modèle ?
Une bonne intégration repose sur une frontière applicative claire
Le modèle ne doit pas être appelé directement depuis un contrôleur. L'intégration doit passer par une abstraction métier explicite.
public interface ICustomerSupportAssistant
{
Task<SupportReply> DraftReplyAsync(SupportRequest request, CancellationToken ct);
}
Ensuite, une implémentation concrète peut utiliser OpenAI, Azure OpenAI ou un modèle local. L'application dépend du contrat, pas du fournisseur.
Garder la logique de prompt hors des endpoints
Le prompt est une partie du comportement applicatif. Il doit donc être structure et versionnable.
public sealed class DraftSupportReplyPrompt
{
public string Build(SupportRequest request) => $"""
You are assisting à support engineer.
Produce a concise answer.
Customer message: {request.Message}
Product area: {request.ProductArea}
Constraints: do not invent unsupported actions.
""";
}
Cela permet de tester, faire évoluer et relire les instructions du modèle comme n'importe quel autre composant.
Ne pas tout déléguer au LLM
Le LLM doit être utilisé là où il est bon:
- génération ou reformulation de texte
- extraction semi-structurée
- classement contextuel
- raisonnement souple sur du langage naturel
Il ne doit pas décider seul de tout ce qui est déterministe.
Par exemple:
- les droits d'accès restent dans le code
- les calculs de prix restent dans le code
- la validation stricte reste dans le code
- les opérations irréversibles restent sous contrôle explicite
Un pipeline simple et robuste
Une intégration saine suit souvent ce schéma:
- préparer le contexte utile
- filtrer les données sensibles
- construire le prompt
- appeler le modèle
- valider ou transformer la sortie
- journaliser les métadonnées utiles
public sealed class CustomerSupportAssistant : ICustomerSupportAssistant
{
private readonly IChatCompletionClient _client;
private readonly DraftSupportReplyPrompt _prompt;
public async Task<SupportReply> DraftReplyAsync(SupportRequest request, CancellationToken ct)
{
var complétion = await _client.CompleteAsync(
_prompt.Build(request),
température: 0.2,
cancellationToken: ct);
return new SupportReply(complétion.Text.Trim());
}
}
Le code reste compréhensible. Le modèle est encapsulé. Le comportement est observable.
Structurer la sortie du modèle
Des qu'un LLM doit alimenter une logique applicative, il faut privilégier une sortie structurée.
{
"intent": "refund_request",
"priority": "high",
"requires_human_review": true
}
En .NET, il est simple de désérialiser et valider cela:
public sealed record TicketClassification(string Intent, string Priority, bool RequiresHumanReview);
La sortie libre peut être utile pour l'UX. La sortie structurée est meilleure pour les flux applicatifs.
Gérer les risques réels
Intégrer un LLM en production pose toujours les memes sujets:
- hallucinations
- fuite d'informations sensibles
- latence
- coût
- dérive du prompt dans le temps
- manque de reproductibilité
Pour limiter ces risques:
- réduire le contexte au strict nécessaire
- imposer un format de réponse
- utiliser une température basse pour les workflows critiques
- enregistrer prompt, version du modèle et résultat lorsque c'est autorise
- définir des chemins de fallback
Le tool calling en .NET
Quand le modèle doit invoquer des actions, il faut garder un cadre strict. Le LLM propose, l'application vérifie et execute.
Exemple typique:
- récupérer le statut d'une commande
- chercher un article dans une base documentaire
- générer un brouillon à partir de données internes
Le modèle ne doit jamais avoir un accès implicite aux opérations critiques. Chaque outil doit avoir:
- un schéma d'entrée clair
- des gardes métier
- une journalisation
- une limite de profondeur ou de nombre d'appels
Observabilité et mesure
Si tu ne mesures pas le comportement du LLM, tu ne peux pas l'améliorer.
Surveille au minimum:
- temps de réponse
- volume de tokens
- taux d'erreur
- taux de fallback
- feedback utilisateur
- taux de validation humaine quand il existe
L'AI engineering devient rapidement un problème de fiabilité opérationnelle, pas seulement d'API.
Quand utiliser RAG
Le RAG n'est pas un prérequis universel. Il est utile quand le modèle doit répondre à partir d'une base documentaire actualisée ou spécialisée.
Il est moins utile quand:
- le cas d'usage est purement génératif
- le contexte tient en peu de données stables
- le coût de retrieval dépasse la valeur du cas d'usage
Il faut donc l'introduire pour une raison concrète, pas parce que c'est la pile standard du moment.
Conclusion
Intégrer un LLM dans une application .NET est un sujet d'architecture applicative, de sécurité et d'opérabilité. Le modèle doit rester encapsulé dans une frontière claire, alimente par un contexte utile et contrôle par des règles déterministes.
La question n'est pas "comment appeler un modèle ?". La vraie question est: "comment faire de l'IA une capacité fiable du système ?"