Home .NET Intégrer de l’IA dans une application .NET

Intégrer de l’IA dans une application .NET

  Gilles, Architecte technique .NET 15 min 19 février 2025

 

L’Intelligence Artificielle est de plus en plus présente dans notre quotidien, que ce soit pour accompagner un développeur, améliorer la qualité des photos ou même pour laver plus efficacement le linge. Tout le monde connait l’IA, qui vit actuellement un vrai « boom » depuis quelques années, et dont les états et entreprises technologiques investissement par dizaine voir centaine de milliards.

Elle devient aujourd’hui incontournable pour aussi bien améliorer la productivité que la qualité, mais aussi en tant que vrai argument commercial. En tant que développeur .NET nous avons la chance que GitHub Copilot soit utilisable gratuitement au sein de Visual Studio et que Microsoft y propose déjà tout un écosystème.

Mais au juste, est-ce compliqué de fournir des services basés sur l’IA ?

 

Cas d’usage

Nous travaillons pour une compagnie d’assurance et nous souhaitons mettre en place un simple formulaire qui permette aux utilisateurs d’envoyer tout type de demande, comme des réclamations.

Le formulaire doit être simple et ne contenir qu’un unique champ de contenu qui est une zone de saisie de texte.

Une fois envoyée, la demande doit ensuite pouvoir être traité « intelligemment », c’est-à-dire qu’en fonction de son contenu il devra être automatiquement assigné aux bons interlocuteurs et priorisé. Cette simplicité pour l’utilisateur (simple saisie) ne doit donc pas être un frein pour son intégration au sein des process de la compagnie d’assurance.

 

Aspects techniques

Dans le cadre de cet article, le « moteur IA » sera développé en C# et exécuté au sein d’une application console.

L’entreprise souhaite avoir la possibilité de changer de modèle IA au besoin, et sans nécessité de modifier l’application. Elle pourra ainsi à sa guise changer de partenaire, par exemple sur des aspects financiers ou sécuritaires, voir intégrer un système de fallback pour pallier à l’indisponibilité éventuelle d’un service. Il est donc plus pertinent de privilégier ici un SDK générique plutôt que d’appeler directement les API de chaque service.

 

Principe de fonctionnement

Lorsque l’utilisateur transmettra sa demande, l’IA analysera automatiquement le contenu pour :

  • Ajouter un titre résumé
    • afin d’avoir un aperçu du contenu
  • Assigner au service interne le plus compétent pour traitement
    • afin d’améliorer la qualité d’assignation
  • Extraire toute information de contact ou nominative
    • afin de pouvoir assigner individuellement en base de données
  • Détecter les éventuelles références à des numéros de dossier
    • afin de pouvoir les associer en base de données
  • Déterminer le degré de priorisation de la requête
    • afin de répondre au plus vite à celles jugées importantes
  • Convertir le contenu en markdown
    • afin d’améliorer le visuel

La réponse de l’IA devra respecter un format de retour bien précis afin de correctement exploiter le résultat produit, mais aussi pour qu’il soit toujours identique quel que soit le modèle utilisé.

 

Rédaction du prompt

Voici le prompt générique envoyé à l’IA afin de le guider sur son rôle précis et le résultat attendu qui sera au format JSON :

Tu es un assistant et vas devoir aider à interpréter une demande d’un client d’une compagnie d’assurance.
Tu renverras les résultats de ton analyse au format JSON en respectant la structure C# ci-dessous, dont tu y trouveras dans le code la description des règles
pour chaque champ afin de t’aider à produire le meilleur résultat.
Tu dois insérer les balises <JSON> et </JSON> pour délimiter le JSON à renvoyer.
Pour les propriétés enums (TypeService, CategorieProbleme et Priorisation) tu dois absolument renvoyer leur valeur entière.

A la suite de ces consignes sera automatiquement ajouté le contenu des fichiers techniques. On guide donc l’IA sur le contexte, ce qu’il doit faire, et le résultat attendu.

 

Obtention d’une clé

Notre application C# utilisera la bibliothèque Microsoft.Extensions.AI (MEAI), qui nous permettra d’utiliser et d’abstraire différents services et modèles populaires comme Mistral, Llama ou encore DeepSeek. Les démos utiliseront :

  • Ministral-3B
  • Mistral-Large-2411
  • Meta-Llama-3.1-405B-Instruct
  • Phi-3-medium-128k-instruct

Pour éviter d’exécuter l’IA localement sur sa machine et l’essayer gratuitement, nous allons utiliser GitHub Models. Connectez-vous à votre compte GitHub puis générez un jeton d’accès personnel. Vous devrez y sélectionner une durée de validité, les information de nommage et du scope d’accès étant facultatives pour notre utilisation.

Si vous le préférez, vous pouvez également déployer vos propres modèles sur Azure AI Foundry, qui permet par ailleurs de rechercher et de comparer un très grand nombre de modèles, aussi bien niveau performance que tarification.

 

Code C#

Créer une simple application console C#.

Dépendances

Ajouter la librairie NuGet Microsoft.Extensions.AI.AzureAIInference :

dotnet add package Microsoft.Extensions.AI.AzureAIInference

AI runner

Il permet la séparation de la logique utilisant l’IA en l’intégrant au sein d’un service dédié et facilement injectable.

Ici le code va extraire le JSON et le désérialiser en C# afin de pouvoir l’exploiter.

using AI.DeepSeekR1.Metier;
using Microsoft.Extensions.AI;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;

namespace AI.DeepSeekR1;
public class AiRunner
{
    private readonly IChatClient _chatClient;
    private readonly string PromptReclamation = @"Tu es un assistant et vas devoir aider à interpréter une demande d'un client d'une compagnie d'assurance.
Tu renverras les résultats de ton analyse au format JSON en respectant la structure C# ci-dessous, dont tu y trouveras dans le code la description des règles 
pour chaque champ afin de t'aider à produire le meilleur résultat.
Tu dois insérer les balises <JSON> et </JSON> pour délimiter le JSON à renvoyer.
Pour les propriétés enums (TypeService, CategorieProbleme et Priorisation) tu dois absolument renvoyer leur valeur entière.";

    private string ContenuFichiersTechniques { get; set; }

    public AiRunner(IChatClient chatClient)
    {
        _chatClient = chatClient;
    }

    public async Task<Reclamation?> DeterminerReclamationAsync(string question)
    {
        var prompt = await GetReclamationPromptAsync(question);
        var response = await _chatClient.CompleteAsync(prompt);
        Console.WriteLine($"\n> REPONSE :\n" + response);
        var json = ExtractJsonContent(response.ToString());
        Console.WriteLine($"\n> JSON :\n" + json);

        return !string.IsNullOrEmpty(json)
            ? JsonSerializer.Deserialize<Reclamation>(json)
            : null;
    }

    private async Task<string> GetReclamationPromptAsync(string question)
    {
        return PromptReclamation + Environment.NewLine
            + "Fichiers techniques : " + Environment.NewLine
            + await GetContenuFichiersTechniquesAsync() + Environment.NewLine
            + "A partir d'ici débute le message de réclamation reçu : " + Environment.NewLine
            + question;
    }

    private async Task<string> GetContenuFichiersTechniquesAsync()
    {
        //Les fichiers techniques sont automatiquement chargés, et une seule fois
        if (string.IsNullOrEmpty(ContenuFichiersTechniques))
        {
            var promptFiles = new StringBuilder();
            foreach (var file in Directory.GetFiles("../../../Metier"))
            {
                var code = await File.ReadAllTextAsync(file);
                promptFiles.AppendLine(code);
            }
            ContenuFichiersTechniques = promptFiles.ToString();
        }
        return ContenuFichiersTechniques;
    }

    private static string? ExtractJsonContent(string input)
    {
        var pattern = @"<JSON>(.*?)</JSON>";
        var match = Regex.Match(input, pattern, RegexOptions.Singleline);
        return match.Success
            ? match.Groups[1].Value.Trim()
            : null;
    }
}

Programme

Application console utilisant l’AI runner pour traiter plusieurs requêtes :

using AI.DeepSeekR1;
using Azure;
using Azure.AI.Inference;
using Microsoft.Extensions.AI;
using System.Text;
using System.Text.RegularExpressions;

var endpoint = "https://models.inference.ai.azure.com";
var token = "..."; //Renseigner ici son token depuis https://github.com/settings/tokens/new
//Liste des modèles : https://ai.azure.com/explore/models
//var model = "DeepSeek-R1";
//var model = "Ministral-3B";
var model = "Mistral-Large-2411";
//var model = "Meta-Llama-3.1-405B-Instruct";
//var model = "Phi-3-medium-128k-instruct";

IChatClient chatClient = new ChatCompletionsClient(new Uri(endpoint), new AzureKeyCredential(token))
    .AsChatClient(model);
var runner = new AiRunner(chatClient);

Console.WriteLine("\n\n################## Cas 1 : Virement non-reçu ##################");
var input1 = @"Bonjour,
Suite à mon dernier échange téléphonique de la semaine dernière avec Mr Martin, je n'ai toujours pas reçu votre virement qui était censé être versé sous 48h.
Je n'ai pas réussi à vous joindre, merci de revenir vers moi au 0601020304 ou [email protected].
Cordialement,
Pierre Martin";
var reclamation1 = await runner.DeterminerReclamationAsync(input1);

Console.WriteLine("\n\n################## Cas 2 : Personne impatiente ##################");
var input2 = @"Ca commence à bien faire, quand mon dossier sera traité ?!?";
var reclamation2 = await runner.DeterminerReclamationAsync(input2);

Console.WriteLine("\n\n################## Cas 3 : Suivi de dossier ##################");
var input3 = @"Bonjour,
J'aimerais savoir où en est mon dossier de sinistre F12345.
Bien à vous,
Jacques";
var reclamation3 = await runner.DeterminerReclamationAsync(input3);

Console.WriteLine("\n\n################## Cas 4 : Candidature spontanée (langue anglaise) ##################");
var input4 = @"Hello,
I would like to apply to the job offer 'Senior software developer'.
I am available and highly motivated, at which address can I send you my resume?
Kind regards,
John SMith
[email protected]
+44 (0) 123 456 789
1 East Street SE125EM London (UK)";
var reclamation4 = await runner.DeterminerReclamationAsync(input4);

Console.WriteLine("\n\n################## Cas 5 : Demande incompréhensible ##################");
var input5 = @"Gros bisous les amis";
var reclamation5 = await runner.DeterminerReclamationAsync(input5);

Console.WriteLine("\n\nFIN");

 

Classes métiers

Voici les classes métiers utilisées et transmises aux modèles IA :

public class Reclamation
{
    [Description("Numéros de dossier détectés. Les numéros de dossier sont toujours du même format, ils commencent toujours par une lettre suivie de 5 chiffres")]
    public List<string> NumeroDossiers { get; set; }
    [Description("Titre déterminé pour le contenu, synthétisé en maximum 20 mots")]
    public string Titre { get; set; }
    [Description("Message envoyé par l'utilisateur, convertit au format Markdown")]
    public string Contenu { get; set; }
    [Description("Servive interne le plus apte à traiter la demande")]
    public TypeService TypeService { get; set; }
    [Description("Catégorisation la plus appropriée à la demande")]
    public CategorieProbleme CategorieProbleme { get; set; }
    [Description("Degré de priorisation déterminé")]
    public Priorisation Priorisation { get; set; }
    [Description("Tout nom de personne physique ou morale")]
    public List<string> InformationsNominatives { get; set; }
    [Description("Les coordonnées peuvent être des numéros de téléphone, emails ou encore des adresses postales")]
    public List<string> CoordonneesContact { get; set; }
}
public enum TypeService
{
    [Description("Traitement des factures, devis et paiement")]
    Comptabilité,
    [Description("Tout problème lié à son utilisation des outils informatiques, comme un bug")]
    Informatique,
    [Description("Concerne le recrutement")]
    RessourcesHumaines,
    [Description("Concerne les publications sur les réseaux sociaux et campagnes publicitaires")]
    Communication,
    [Description("Litige concernant son assurance")]
    Litige,
    [Description("Problème d'ordre jurique")]
    Juridique,
    [Description("Tout autre type")]
    Autre
}
public enum CategorieProbleme
{
    [Description("Nouvelle réclamation nécessitant l'ouverture d'un nouveau dossier")]
    OuvertureNouveauDossier,
    [Description("Ajout d'informations complémentaires au dossier existant")]
    AjoutInformationDossierExistant,
    [Description("Le client n'a pas reçu son paiement")]
    PaiementNonRecu,
    [Description("Le montant reçu est incorrect")]
    MontantRecuIncorrect,
    [Description("Toute autre catégorie")]
    Autre
}
public enum Priorisation
{
    [Description("Le client n'évoque pas de numéro de dossier, et les dates sont inférieures à 48h")]
    Faible,
    [Description("Par défaut")]
    Moyenne,
    [Description("Le client évoque des dates supérieures à 1 mois, ou montre une forme d'aggressivité")]
    Elevee
}

 

Démo et résultats

Voici les résultats des 5 inputs traités par les 4 différentes IA :

Cas 1 : Virement non-reçu

Bonjour,
Suite à mon dernier échange téléphonique de la semaine dernière avec Mr Martin, je n’ai toujours pas reçu votre virement qui était censé être versé sous 48h.
Je n’ai pas réussi à vous joindre, merci de revenir vers moi au 0601020304 ou [email protected].
Cordialement,
Pierre Martin

Voici les résultats des 4 modèles utilisés :

Ministral-3B
```json
{
    "NumeroDossiers": [],
    "Titre": "Non réception du virement",
    "Contenu": "# Non réception du virement\nSuite à mon dernier échange téléphonique de la semaine dernière avec Mr Martin, je n'ai toujours pas reçu votre virement qui était censé être versé sous 48h.\nJe n'ai pas réussi à vous joindre, merci de revenir vers moi au 0601020304 ou [email protected].",
    "TypeService": 2, //Informatique
    "CategorieProbleme": 2, //AjoutInformationDossierExistant
    "Priorisation": 1, //Faible
    "InformationsNominatives": ["Pierre Martin"],
    "CoordonneesContact": ["0601020304", "[email protected]"]
}
```

Mistral-Large-2411
<JSON>
{
    "NumeroDossiers": [],
    "Titre": "Non-réception de virement après échange téléphonique",
    "Contenu": "Bonjour,\n\nSuite à mon dernier échange téléphonique de la semaine dernière avec Mr Martin, je n'ai toujours pas reçu votre virement qui était censé être versé sous 48h.\n\nJe n'ai pas réussi à vous joindre, merci de revenir vers moi au 0601020304 ou [email protected].\n\nCordialement,\nPierre Martin",
    "TypeService": 1, //Comptabilité
    "CategorieProbleme": 3, //PaiementNonRecu
    "Priorisation": 2, //Moyenne
    "InformationsNominatives": ["Pierre Martin", "Mr Martin"],
    "CoordonneesContact": ["0601020304", "[email protected]"]
}
</JSON>

Meta-Llama-3.1-405B-Instruct
<JSON>
{
  "NumeroDossiers": [],
  "Titre": "Paiement non reçu suite à échange téléphonique",
  "Contenu": "Suite à mon dernier échange téléphonique de la semaine dernière avec Mr Martin, je n'ai toujours pas reçu votre virement qui était censé être versé sous 48h.\nJe n'ai pas réussi à vous joindre, merci de revenir vers moi au 0601020304 ou [email protected].",
  "TypeService": 5, //Litige
  "CategorieProbleme": 3, //PaiementNonRecu
  "Priorisation": 2, //Moyenne
  "InformationsNominatives": ["Pierre Martin", "Mr Martin"],
  "CoordonneesContact": ["0601020304", "[email protected]"]
}
</JSON>

Phi-3-medium-128k-instruct
<JSON>
{
   "NumeroDossiers":[],
   "Titre":"Non applicable",
   "Contenu":"Bonjour, Suite à mon dernier échange téléphonique de la semaine dernière avec Mr Martin, je n'ai toujours pas reçu votre virement qui était censé être versé sous 48h. Je n'ai pas réussi à vous joindre, merci de revenir vers moi au 0601020304 ou [email protected]. Cordialement, Pierre Martin",
   "TypeService":2, //Informatique
   "CategorieProbleme":3, //PaiementNonRecu
   "Priorisation":1, //Faible
   "InformationsNominatives":["Pierre Martin"],
   "CoordonneesContact":["0601020304", "[email protected]"]
}
</JSON>

Les 4 savent parfaitement extraire les informations, en revanche ils ne sont pas tous aussi efficace pour :

  • déterminer les bonnes catégorisations du message
  • définir un titre
  • le contenu est parfois tronqué (il faudrait surement affiner le prompt)

Cas 2 : Personne impatiente

Ca commence à bien faire, quand mon dossier sera traité ?!?

Voici les résultats des 4 modèles utilisés :

Ministral-3B
<JSON>
{
    "NumeroDossiers": ["Y12345"],
    "Titre": "Dossier de traitement",
    "Contenu": "Ca commence à bien faire, quand mon dossier sera traité ?!?",
    "TypeService": 0, //?
    "CategorieProbleme": 1, //OuvertureNouveauDossier
    "Priorisation": 2, //Moyenne
    "InformationsNominatives": ["Nom du client"],
    "CoordonneesContact": ["[email protected]"]
}
</JSON>

Mistral-Large-2411
<JSON>
{
  "NumeroDossiers": [],
  "Titre": "Réclamation concernant le traitement d'un dossier",
  "Contenu": "Ca commence à bien faire, quand mon dossier sera traité ?!?",
  "TypeService": 5, //Litige
  "CategorieProbleme": 1, //OuvertureNouveauDossier
  "Priorisation": 3, //Elevée
  "InformationsNominatives": [],
  "CoordonneesContact": []
}
</JSON>

Meta-Llama-3.1-405B-Instruct
<JSON>
{
  "NumeroDossiers": [],
  "Titre": "Demande de traitement de dossier",
  "Contenu": "Ca commence à bien faire, quand mon dossier sera traité ?!?",
  "TypeService": 5, //Litige
  "CategorieProbleme": 2, //AjoutInformationDossierExistant
  "Priorisation": 2, //Moyenne
  "InformationsNominatives": [],
  "CoordonneesContact": []
}
</JSON>

Phi-3-medium-128k-instruct
<JSON>
{
   "NumeroDossiers":[],
   "Titre":"Quand sera traité mon dossier ?",
   "Contenu":"Ca commence à bien faire, quand mon dossier sera traité ?!?",
   "TypeService":2, //Informatique
   "CategorieProbleme":1, //OuvertureNouveauDossier
   "Priorisation":2, //Moyenne
   "InformationsNominatives":[],
   "CoordonneesContact":[]
}
</JSON>

Etrangement Ministral-3B invente ici des données d’extraites.

Cas 3 : Suivi de dossier

Bonjour,
J’aimerais savoir où en est mon dossier de sinistre F12345.
Bien à vous,
Jacques

Voici les résultats des 4 modèles utilisés :

Ministral-3B
<JSON>
{
  "NumeroDossiers": ["F12345"],
  "Titre": "Statut de mon dossier de sinistre",
  "Contenu": "Bonjour, j'aimerais savoir où en est mon dossier de sinistre F12345. Bien à vous, Jacques",
  "TypeService": 5, //Litige
  "CategorieProbleme": 1, //OuvertureNouveauDossier
  "Priorisation": 1, //Faible
  "InformationsNominatives": ["Jacques"],
  "CoordonneesContact": ["Jacques"]
}
</JSON>

Mistral-Large-2411
<JSON>
{
  "NumeroDossiers": ["F12345"],
  "Titre": "Demande de suivi du dossier de sinistre F12345",
  "Contenu": "Bonjour,\n\nJ'aimerais savoir où en est mon dossier de sinistre F12345.\n\nBien à vous,\nJacques",
  "TypeService": 5, //Litige
  "CategorieProbleme": 1, //OuvertureNouveauDossier
  "Priorisation": 2, //Moyenne
  "InformationsNominatives": ["Jacques"],
  "CoordonneesContact": []
}
</JSON>

Meta-Llama-3.1-405B-Instruct
<JSON>
{
  "NumeroDossiers": ["F12345"],
  "Titre": "Suivi dossier de sinistre F12345",
  "Contenu": "Bonjour,\nJ'aimerais savoir où en est mon dossier de sinistre F12345.\nBien à vous,\nJacques",
  "TypeService": 5, //Litige
  "CategorieProbleme": 2, //AjoutInformationDossierExistant
  "Priorisation": 2, //Moyenne
  "InformationsNominatives": ["Jacques"],
  "CoordonneesContact": []
}
</JSON>

Phi-3-medium-128k-instruct
<JSON>
{
  "NumeroDossiers": ["F12345"],
  "Titre": "Demande de connaissance de l'état du dossier de sinistre",
  "Contenu": "Bonjour,\nJ'aimerais savoir où en est mon dossier de sinistre F12345.\nBien à vous,\nJacques",
  "TypeService": 1, //Comptabilité
  "CategorieProbleme": 1, //OuvertureNouveauDossier
  "Priorisation": 1, //Faible
  "InformationsNominatives": ["Jacques"],
  "CoordonneesContact": []
}
</JSON>

Ministral-3B utilise le prénom de la personne comme une information de contact.

Cas 4 : Candidature spontanée (langue anglaise)

Hello,
I would like to apply to the job offer ‘Senior software developer’.
I am available and highly motivated, at which address can I send you my resume?
Kind regards,
John SMith
[email protected]
+44 (0) 123 456 789
1 East Street SE125EM London (UK)

Voici les résultats des 4 modèles utilisés :

Ministral-3B
<JSON>
{
    "NumeroDossiers": [],
    "Titre": "Demande réclamation pour l'ouverture d'un nouveau dossier pour un candidat",
    "Contenu": "L'utilisateur John SMith souhaite postuler à l'offre d'emploi de 'Senior software developer' et souhaite savoir à quel endroit envoyer sa candidature. Il est disponible et très motivé.",
    "TypeService": 3, //RessourcesHumaines
    "CategorieProbleme": 1, //OuvertureNouveauDossier
    "Priorisation": 2, //Moyenne
    "InformationsNominatives": ["John SMith"],
    "CoordonneesContact": ["[email protected]", "+44 (0) 123 456 789", "1 East Street SE125EM London (UK)"]
}
</JSON>

Mistral-Large-2411
<JSON>
{
  "NumeroDossiers": [],
  "Titre": "Candidature pour le poste de 'Senior Software Developer'",
  "Contenu": "Hello,\n\nI would like to apply to the job offer 'Senior software developer'.\nI am available and highly motivated, at which address can I send you my resume?\n\nKind regards,\nJohn SMith\n\[email protected]\n+44 (0) 123 456 789\n1 East Street SE125EM London (UK)",
  "TypeService": 3, //RessourcesHumaines
  "CategorieProbleme": 5, //Autre
  "Priorisation": 2, //Moyenne
  "InformationsNominatives": ["John SMith"],
  "CoordonneesContact": ["[email protected]", "+44 (0) 123 456 789", "1 East Street SE125EM London (UK)"]
}
</JSON>

Meta-Llama-3.1-405B-Instruct
<JSON>
{
  "NumeroDossiers": [],
  "Titre": "Candidature pour l'offre d'emploi 'Senior software developer'",
  "Contenu": "Bonjour,\nJe souhaite postuler à l'offre d'emploi 'Senior software developer'.\nJe suis disponible et très motivé, à quelle adresse puis-je envoyer mon CV ?\nCordialement,\nJohn Smith",
  "TypeService": 3, //RessourcesHumaines
  "CategorieProbleme": 5, //Autre
  "Priorisation": 2, //Moyenne
  "InformationsNominatives": ["John Smith"],
  "CoordonneesContact": ["[email protected]", "+44 (0) 123 456 789", "1 East Street SE125EM London (UK)"]
}
</JSON>

Phi-3-medium-128k-instruct
<JSON>
{
  "NumeroDossiers": [],
  "Titre": "Demande d'emploi Senior software developer",
  "Contenu": "Je souhaite m'inscrire à l'offre d'emploi 'Senior software developer'. Je suis disponible et très motivé. Où puis-je vous envoyer ma CV?",
  "TypeService": 7, //Autre
  "CategorieProbleme": 5, //Autre
  "Priorisation": 1, //Faible
  "InformationsNominatives": ["John Smith"],
  "CoordonneesContact": ["[email protected]", "+44 (0) 123 456 789", "1 East Street SE125EM London (UK)"]
}
</JSON>

La plupart des résultats sont cohérents malgré la demande formulée en langue anglaise, bien que certains traduisent le contenu original en Français. Un affinage du prompt devrait permettre de gérer ce cas.

Cas 5 : Demande incompréhensible

Gros bisous les amis

Voici les résultats des 4 modèles utilisés :

Ministral-3B
<JSON>
{
    "NumeroDossiers": [],
    "Titre": "Gros bisous les amis",
    "Contenu": "Gros bisous les amis",
    "TypeService": 7, //Autre
    "CategorieProbleme": 5, //Autre
    "Priorisation": 1, //Faible
    "InformationsNominatives": [],
    "CoordonneesContact": []
}
</JSON>

Mistral-Large-2411
<JSON>
{
  "NumeroDossiers": [],
  "Titre": "Message sans contenu pertinent",
  "Contenu": "Gros bisous les amis",
  "TypeService": 7, //Autre
  "CategorieProbleme": 5, //Autre
  "Priorisation": 1, //Faible
  "InformationsNominatives": [],
  "CoordonneesContact": []
}
</JSON>

Meta-Llama-3.1-405B-Instruct
<JSON>
{
  "NumeroDossiers": [],
  "Titre": "Message de réclamation sans contenu précis",
  "Contenu": "Gros bisous les amis",
  "TypeService": 7, //Autre
  "CategorieProbleme": 5, //Autre
  "Priorisation": 2, //Moyenne
  "InformationsNominatives": [],
  "CoordonneesContact": []
}
</JSON>

Phi-3-medium-128k-instruct
<JSON>
{
  "NumeroDossiers": [],
  "Titre": "",
  "Contenu": "Gros bisous les amis",
  "TypeService": 7, //Autre
  "CategorieProbleme": 5, //Autre
  "Priorisation": 2, //Moyenne
  "InformationsNominatives": [],
  "CoordonneesContact": []
}
</JSON>

Les résultats sont un peu près identiques, bien que certains n’arrivent pas à définir un titre. Encore une fois, le lui imposer dans le prompt devrait suffire.

Conclusion

Utiliser de l’IA peut donc se faire très simplement en quelques lignes de code, sans pour autant avoir à investir sans un modèle spécifique et y resté enfermé.

Tous les modèles n’ont pas la même expertise (génération de texte, d’image…), qualité ni tarification, c’est pourquoi il est important de choisir celui qui est le plus adapté à son besoin et de les tester dans ses propres conditions d’utilisation.

Le prompt utilisé ici est assez simple et facilement compréhensible pour l’IA, bien que le cas d’usage soit trop générique. Ils ont tous excellé dans l’extraction d’information pertinentes ce qui les rendent précieux pour détecter des informations associables par exemple en base de données (numéro de dossier, nom de la personne, emails…).

 

Aller plus loin

Streamer le retour de l’IA

Dans cet article nous avons attendu la réponse complète de l’IA avant de la traiter. Il est également possible de streamer sa réponse au fur et à mesure de sa réflexion, et donc d’avoir un début de retour au plus vite :

Exemple de streaming :

var content = new StringBuilder();
var response = _chatClient.CompleteStreamingAsync(message);
await foreach (var item in response)
{
    content.Append(item);
    Console.Write(item.ToString().Replace("<think>", "> Réflexion :\n").Replace("</think>", "> Résultat :\n"));
}

//Extraction du résultat typé
var match = Regex.Match(content.ToString(), @"<think>(.*?)</think>\s*(.*)", RegexOptions.Singleline);
if (match.Success)
{
    //...
}

Comprendre la réponse et les choix effectués

Les réponses du modèle DeepSeek-R1 intègrent également son raisonnement complet afin de comprendre son raisonnement voir ses suppositions. Il est disponible au sein des balises <think></think>.

Exemple de prompt avec une certaine complexité d’interprétation :

Je possède 10 Euros et j'en dépense 5 pour acheter un sandwich.
Combien ai-je de pomme et combien de Dollars il me reste en portefeuille ?
Donne pour dans ta réponse ton pourcentage de confiance quant au résultat.
Renvoi seulement les valeurs au format Valeur1;Valeur2;PourcentageConfiance, par exemple 50;14,30;20

Réflexion associée de DeepSeek-R1 :

Okay, let's see what this user is asking here. So they start by saying they have 10 euros and spend 5 on a sandwich. Then they ask how many apples they have and how many dollars are left in their wallet. Hmm, wait a second.
First, the initial part is straightforward: 10 euros minus 5 euros spent leaves 5 euros remaining. But the question is about dollars left. Oh, right, the user didn't mention converting euros to dollars anywhere. So there's a currency conversion missing here. Unless they had dollars in their wallet along with euros, but the problem states they had 10 euros initially. So the money left should still be in euros unless there's an exchange involved, which isn't mentioned. So maybe the answer assumes they have 5 euros left, but the question asks for dollars, so we need to convert. But without knowing the exchange rate, that's impossible. Unless we use the current rate, but the problem doesn't specify a date, so that's an assumption. That's one uncertainty.
Then, the question about how many apples they have. The problem doesn't mention buying or having any apples. They bought a sandwich, not apples. So unless there's a trick or a play on words, the number of apples should be zero. Unless the sandwich had apples in it, but that's not stated either. So probably zero apples. But why would the user ask that? Maybe a trick question to test attention.
So putting it all together. Apples: 0. The remaining money is 5 euros, but the question asks for dollars. Without an exchange rate, we can't accurately convert. But if we have to answer, maybe use a rough estimate like 1 euro = 1.07 dollars (current approx rate as of 2023), so 5*1.07=5.35 dollars. But this is a big assumption, and the user didn't provide the rate, so this introduces uncertainty. Therefore, the confidence percentage would be lower for the dollars part because of the missing rate, but higher for the apples since it's not mentioned.
Wait, but the user might not even have dollars. They only mentioned euros. So maybe the answer is 0 apples and 5 euros, but the question asks for dollars. That's a problem. So the answer might be that there are 0 apples and the remaining euros can't be converted to dollars without the rate. However, the user might expect assuming conversion, but that's unclear. So this ambiguity affects confidence.
So final answer: 0 apples, 5 euros remaining which is approximately 5.35 dollars (but this is an assumption). However, since the problem doesn't mention exchange, maybe the answer is 5 euros, but the question asks for dollars. That inconsistency makes the dollars part invalid. So maybe the answer is 0 apples and the euros remaining is 5, but dollars isn't applicable. But the user insists on dollars. This confusion lowers confidence.
Alternatively, maybe the user made a mistake and meant euros. In that case, 5 euros. But they asked for dollars. So I have to make a choice here. Either state that without exchange rate, can't compute, but proceed with an estimated conversion. Confidence for apples is high (0) and for dollars is low due to assumptions. So maybe 0;5.35;70 (assuming 70% confidence because apples are certain, dollars are an estimate). But I need to check the exchange rate. Let me verify the current rate. As of October 2023, 1 euro is about 1.06 dollars. So 5 euros ~ 5.30 dollars. But again, the user might not be aware of the current rate. So maybe 0 apples, 5.30 dollars, but with low confidence on the dollar part. So perhaps confidence is 50% because the question has two parts: apples (100% sure) and dollars (0% sure if rate not given). Wait, but if the user didn't convert, maybe the answer is 5 euros, not dollars, so the dollars part is zero. Wait, maybe the user didn't convert, so they have 5 euros left, which is not dollars. So the answer is 0 apples and 0 dollars, which is incorrect. But that's not right either. The user has 5 euros, which they haven't converted, so in their wallet, they still have euros. If the question is about dollars, maybe the answer is 0 dollars because they didn't exchange. So this is really confusing.
Alternatively, perhaps the user intended a trick question where the answer is 0 apples and 5 euros, but since the question asks for dollars, the answer is 0 apples and 5 euros, but the user didn't specify conversion, so maybe the answer is there's no dollars left. Wait, that's possible. If the user only had euros, then after spending, they still have 5 euros, so dollars remaining would be zero. But that's assuming the wallet only had euros. The problem states "j'en dépense 5 pour acheter un sandwich" (spent 5 of them (euros) to buy a sandwich), so the remaining is 5 euros. The question asks how many dollars are left. If the wallet had only euros, then dollars left is zero. But that's maybe the intended answer. So 0 apples and 0 dollars, 5 euros. But the user didn't ask for euros. Hmm. Wait, the problem says "combien de Dollars il me reste en portefeuille?" So how many dollars are left in the wallet. If the wallet originally had euros, then after spending euros, there are still euros left, not dollars. So the answer is 0 dollars. Unless the user converted, but no info. So maybe the answer is 0 apples and 0 dollars, with high confidence because there's no mention of dollars initially. So the euros are still there, but the dollars part is zero.
So apples: 0. Dollars remaining: 0. Confidence: let's say apples are 100%, dollars are 100% if that's the case. But maybe the user thinks that 5 euros is equivalent to dollars, but without conversion, technically it's zero. But maybe the user expects a conversion. So uncertainty here. If we go with 0 dollars and 0 apples, confidence for apples is 100%, dollars is 80% (since they might have dollars but it's not mentioned). Or perhaps split the confidence. Maybe overall confidence is 90% because the apple part is certain, but the dollar part is ambiguous. Wait, this is getting complicated. Let me structure.
Possible interpretations:
1. Apples: 0 (since not mentioned). Dollars remaining: If wallet had only euros, then 0. Confidence for apples: 100%. Confidence for dollars: depends on whether wallet had dollars. But problem states starting with 10 euros, so maybe no dollars. So confidence for dollars being 0 is high, say 90%. So total confidence might be average, but the user asked for a single percentage. Maybe 95% because apples are certain, dollars likely 0.
But the user might think that the answer is 5 euros converted to dollars, which is a different approach. In that case, without exchange rate, we can't answer, but if forced, maybe use approximate. But the problem didn't mention conversion, so that's an assumption. So confidence for that would be low.
Alternatively, the question is a trick, so apples:0, dollars:0, confidence 100%? But maybe the user intended something else.
Alternatively, maybe the user made a mistake in the question, mixing apples and oranges (literally). The problem mentions a sandwich, not apples, so apples are 0. The money part: 5 euros left, which is about 5.30 dollars, but since it's not specified, maybe the answer is 5 euros, but the question asked for dollars, so that's a problem. Hence, the answer is unanswerable for dollars, but with assumptions, maybe 5.30. But confidence is low.
So combining apples (0) with 100% confidence, dollars with 5.30 (approx) with 50% confidence. Overall confidence maybe 75%? Because half right, half assumption. But the user wants a single confidence percentage for the entire answer. So if both parts are considered, apples are certain, dollars are uncertain, maybe average confidence is (100 + 50)/2 = 75%.
But I think the correct answer is 0 apples and 5 euros, but since the user asked for dollars, which they don't have, the dollars remaining is 0. Hence, answer is 0;0;95%. But maybe that's too confident. Alternatively, 0 apples, 5 euros, but user asked for dollars, so answer can't be given. But the user insists on dollars, so perhaps 0 apples and the euros converted to dollars with an assumed rate. But without the rate, it's impossible, leading to an answer with low confidence.
In conclusion, based on the problem as stated:
- Apples: 0 (100% confidence)
- Dollars remaining: Since the wallet had euros, and no conversion done, dollars remaining is 0 (but maybe 90% confidence here because the question might have a typo)
- Overall confidence: Let's average to 95% perhaps, since both parts are logical but the dollars part might be misinterpreted.
Alternatively, if the user intended to trick by asking dollars, but the answer is 5 euros, which is not dollars, so 0 dollars. Hence, the answer is 0;0;95%.
But maybe the user expects the conversion, but since no rate is given, the answer is 0;5;50% confidence, assuming they meant euros. But the question says dollars. This is really ambiguous.
Alternatively, maybe the user thinks that after spending 5 euros, they have 5 euros left, which is equivalent to dollars, but since the problem is in French, maybe they use euros, so the answer is 0 apples and 5 euros, but the user asked for dollars, which is a mistake. So confidence is 100% for apples, 0% for dollars, but since the user insists, maybe answer 0;5;50% (assuming maybe they meant euros). But the user specified dollars.
This is really tricky. I think the safest answer is 0 apples (100% sure) and 0 dollars (assuming no conversion, 90% sure), total confidence 95%. But the format requires a single percentage. So combining both parts, maybe 95% confidence.
> Résultat :
0;0;95


**Explication :**
- **Nombre de pommes :** Le problème ne mentionne pas l'achat ou la possession de pommes, donc **0** (confiance 100%).
- **Dollars restants :** La transaction est en euros, et rien n'indique une conversion en dollars ou la présence initiale de dollars. Ainsi, **0** dollars restants (confiance ~90%).
- **Confiance globale :** 95% (combinaison de certitude sur les pommes et d'une hypothèse raisonnable sur les dollars).

La réponse est plutôt impressionnante, il ne reste pas bloqué sur un problème et montre qu’il est capable de déterminer son propre niveau de confiance. En revenant à notre cas d’usage, on pourrait par exemple utiliser ce niveau de confiance pour basculer les demandes avec une fiabilité incertaine vers un workflow avec intervention manuelle, en y glissant par exemple en note les raisons concernant les doutes de l’IA.

 

Accéder au code source complet.

 

Lire les articles similaires

Laisser un commentaire

Social Share Buttons and Icons powered by Ultimatelysocial