DEV Community

Cover image for Gouvernez votre agent IA : NestJS et Mistral en 30 lignes
Martin-Bruel
Martin-Bruel

Posted on

Gouvernez votre agent IA : NestJS et Mistral en 30 lignes

Gouverner un agent IA, c'est maîtriser deux choses : le modèle qu'il utilise, et ce qu'il fait dans votre application. Ce tutoriel couvre les deux en une trentaine de lignes de TypeScript, de nest new à un endpoint POST /ask : un modèle Mistral, européen et open source, et un agent déclaré comme un module NestJS avec nestjs-langchain.

Le modèle n'est pas déterministe, mais tout ce qui l'entoure peut l'être : l'agent est configuré en un seul endroit, vérifié au démarrage, et chaque exécution dit ce qu'il a fait.

Testé avec NestJS 12, LangChain 1.x, nestjs-langchain 2.0, @langchain/mistralai 1.2 et Node 22.

Comment ajouter LangChain et Mistral à un projet NestJS ?

Créez l'application, puis installez la bibliothèque et l'intégration Mistral de LangChain :

npx @nestjs/cli new my-app --package-manager npm
cd my-app
npm install nestjs-langchain @langchain/mistralai
Enter fullscreen mode Exit fullscreen mode

npm installe aussi langchain, @langchain/core et zod, les dépendances pairs de la bibliothèque. @langchain/mistralai est le fournisseur : @langchain/openai, @langchain/anthropic ou toute autre intégration de chat LangChain s'utilise de la même façon.

Le fournisseur lit sa clé dans l'environnement. Créez-la dans la console de Mistral AI, puis :

export MISTRAL_API_KEY=...
Enter fullscreen mode Exit fullscreen mode

Comment déclarer l'agent avec un modèle Mistral ?

Importez LangChainModule dans app.module.ts :

import { Module } from '@nestjs/common';
import { LangChainModule } from 'nestjs-langchain';
import { AppController } from './app.controller.js';
import { AppService } from './app.service.js';
import { AskController } from './ask.controller.js';

@Module({
  imports: [
    LangChainModule.register({
      // `fournisseur:modèle` ; le fournisseur lit MISTRAL_API_KEY.
      model: { model: 'mistralai:mistral-small-latest' },
      systemPrompt: 'Tu es un assistant utile. Réponds en un paragraphe.',
    }),
  ],
  controllers: [AppController, AskController],
  providers: [AppService],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

model nomme le fournisseur et le modèle. mistral-small-latest suffit pour commencer et sait appeler des outils, ce qui servira plus loin ; mistralai:mistral-large-latest donne le plus grand modèle de Mistral. Passer à OpenAI, c'est openai:gpt-5-mini avec @langchain/openai installé.

Pourquoi Mistral pour gouverner le modèle ?

Parce que vous choisissez où il tourne, et sous quelle licence :

  • Un éditeur européen. Mistral AI est une société française, et par défaut les données envoyées à son API sont hébergées dans l'Union européenne.
  • Des poids ouverts. Mistral Small est publié sous licence Apache 2.0 : vous pouvez l'exécuter sur vos propres serveurs.

Avec Ollama, seule la ligne model change : plus de clé d'API, et vos données restent sur votre infrastructure.

npm install @langchain/ollama
ollama pull mistral-small3.2
Enter fullscreen mode Exit fullscreen mode
model: { model: 'ollama:mistral-small3.2' },
Enter fullscreen mode Exit fullscreen mode

Le reste de la chaîne est open source aussi : NestJS, LangChain et nestjs-langchain sont sous licence MIT.

Comment appeler l'agent depuis un contrôleur ?

Injectez Agent comme n'importe quel provider, dans un nouveau ask.controller.ts :

import { Body, Controller, Post } from '@nestjs/common';
import { Agent } from 'nestjs-langchain';

@Controller('ask')
export class AskController {
  constructor(private readonly agent: Agent) {}

  @Post()
  async ask(@Body('question') question: string): Promise<string> {
    const { output } = await this.agent.run(question);
    return output;
  }
}
Enter fullscreen mode Exit fullscreen mode

En plus de output, la réponse, run() renvoie les outils appelés par le modèle, les tokens utilisés et la durée de l'exécution.

Démarrez l'application et posez une question :

npm run start:dev

curl -X POST http://localhost:3000/ask \
  -H 'Content-Type: application/json' \
  -d '{"question": "À quoi sert un module NestJS ?"}'
Enter fullscreen mode Exit fullscreen mode

La réponse est celle de Mistral, en texte brut.

Comment gouverner ce que fait l'agent ?

En le traitant comme le reste du backend : nestjs-langchain le range dans un module Nest, avec les mêmes règles.

  • Une configuration, vérifiée au démarrage. Fournisseur, modèle et prompt sont dans le module, et registerAsync les lit dans ConfigService. Une clé manquante bloque le démarrage, comme plus haut.
  • Un agent par usage. Chaque agent a son nom, son prompt et ses outils, et s'injecte avec @InjectAgent() : le chatbot public et l'agent du back-office restent séparés.
  • Seulement les outils que vous déclarez. L'agent n'appelle que les méthodes @Tool() des modules listés dans tools, et vérifie leurs arguments avant chaque appel.
  • Chaque exécution se lit. run() renvoie les outils appelés, les tokens et la durée ; un observer les envoie dans vos logs.
  • Des tests sans clé Mistral. Le fakeModel() de LangChain remplace le modèle en CI.

Pour un simple appel à un modèle, LangChain seul suffit. Le module sert dès que l'agent touche votre application et que vous devez savoir ce qu'il fait.

Ensuite : donner des outils à l'agent

Un agent devient utile quand il agit sur votre application. Avec @Tool(), une méthode de service devient un outil que Mistral peut appeler :

@Injectable()
export class MathService {
  @Tool({ description: 'Additionne deux nombres.' })
  add(
    @ToolParam({ name: 'a' }) a: number,
    @ToolParam({ name: 'b' }) b: number,
  ): number {
    return a + b;
  }
}
Enter fullscreen mode Exit fullscreen mode

Puis tools: [MathModule] dans register() le donne à l'agent. Les détails se trouvent dans la série complète : AI agents with NestJS.

Top comments (0)