Auto-hébergement d'un LLM Open Source pour DiscourseAI

Le plugin Discourse AI propose de nombreuses fonctionnalités qui nécessitent un LLM pour être activées — résumé, AI Helper, recherche sémantique, robot IA et ses agents. Vous pouvez utiliser une API tierce, comme Configurer les clés d’API pour OpenAI ou Configurer les clés d’API pour Anthropic, mais Discourse AI a été conçu dès le départ pour que vous ne soyez pas prisonnier de ces solutions.

Ce guide explique comment exécuter vous-même un modèle à poids ouverts et le connecter à Discourse.

Modèle utilisé ici : Qwen/Qwen3.8-27B — un modèle dense de 27B sorti en août 2026 avec une fenêtre de contexte native de 256K, la compréhension d’images/vidéos, l’appel d’outils et le mode de réflexion activé par défaut. C’est actuellement le point d’équilibre idéal pour l’auto-hébergement : assez performant pour des tâches réelles de résumé/d’agent, mais assez petit pour tenir sur un seul GPU. Vous pouvez remplacer par n’importe quel autre modèle ; les indicateurs à modifier sont mentionnés ci-dessous.

Ce que Discourse attend de votre serveur d’inférence

  • Un point de terminaison POST /v1/chat/completions compatible OpenAI (avec prise en charge du streaming).
  • L’appel d’outils/fonctions natif si vous souhaitez que le robot IA, les agents ou la sortie structurée fonctionnent bien. Sans cela, Discourse revient aux appels d’outils basés sur XML, que les modèles moins performants gèrent mal.
  • Une véritable fenêtre de contexte — visez un minimum de 16K tokens, idéalement 32K et plus. La taille des invites de Discourse pour le résumé et le RAG augmente rapidement.
  • Optionnel : entrée d’image, si vous souhaitez que le modèle lise les images jointes aux messages.

Tout serveur respectant les trois premiers points fonctionne, donc le choix ci-dessous dépend réellement de votre matériel.

Configuration Convient bien à
vLLM Serveur GPU dédié, ≥24 Go de VRAM (quantifié) / 80 Go (pleine précision), trafic soutenu, utilisateurs multiples
llama.cpp GPU grand public, puces Apple silicon, machines uniquement CPU, petits forums
Géré / cloud Vous voulez que le modèle ne soit pas sur votre ordinateur portable, mais pas sur votre matériel : tout point de terminaison compatible OpenAI

Exécution avec vLLM

vLLM est le moteur recommandé pour les serveurs GPU : licence Apache, serveur compatible OpenAI inclus, et prise en charge de premier plan de la famille Qwen.

mkdir -p /opt/vllm-cache
export VLLM_API_KEY="$(openssl rand -hex 24)"

docker run -d --name vllm \
  --runtime nvidia --gpus all \
  -v /opt/vllm-cache:/root/.cache/huggingface \
  -e HF_HOME=/root/.cache/huggingface \
  -e "HF_TOKEN=${HF_TOKEN}" \
  -p 8080:8000 \
  --ipc=host \
  vllm/vllm-openai:latest \
  Qwen/Qwen3.8-27B \
  --host 0.0.0.0 \
  --port 8000 \
  --max-model-len 32768 \
  --reasoning-parser qwen3 \
  --enable-auto-tool-choice \
  --tool-call-parser qwen3_xml \
  --api-key "$VLLM_API_KEY"

Notes sur les indicateurs :

  • --max-model-len définit la limite de contexte invite+sortie, et donc du cache KV. Le modèle prend en charge nativement 256K ; 32K est largement suffisant pour les besoins d’un forum et garantit une VRAM prévisible. Augmentez-la (ou utilisez auto) si vous avez la mémoire.
  • --reasoning-parser qwen3 sépare la réflexion du modèle dans un champ reasoning distinct au lieu de l’injecter dans la réponse. Vous devez refléter ce choix dans les paramètres LLM de Discourse (voir ci-dessous).
  • --enable-auto-tool-choice --tool-call-parser ... active l’appel de fonctions natif. Les noms des parseurs changent entre les versions de vLLM — vérifiez python3 -m vllm.entrypoints.openai.api_server --help dans votre image si les appels d’outils reviennent sous forme de texte brut.
  • HF_TOKEN n’est nécessaire que pour les modèles protégés ; --api-key protège votre propre point de terminaison. Mise en garde de la documentation vLLM : --api-key ne protège que les itinéraires /v1, alors gardez toujours le serveur hors d’internet public.
  • Contraint en VRAM ? Essayez --quantization fp8 (ou un point de contrôle pré-quantifié AWQ) avant de réduire le contexte. Multi-GPU : ajoutez --tensor-parallel-size N.

Testez-le :

curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $VLLM_API_KEY" \
  -d '{
    "model": "Qwen/Qwen3.8-27B",
    "messages": [{"role": "user", "content": "What is Discourse?"}],
    "max_tokens": 200
  }'

Vous devriez recevoir un corps JSON de complétion de chat classique, avec message.reasoning à côté de message.content.

Exécution avec llama.cpp

llama.cpp est l’outil adéquat lorsque le modèle doit tenir dans moins de VRAM que ce que vLLM souhaite, ou si vous êtes sur Apple silicon, AMD, Vulkan ou CPU. Son llama-server expose également une API compatible OpenAI.

Téléchargez et exécutez la build GGUF officielle en utilisant l’image de conteneur pour votre backend (server-cuda ici ; server, server-rocm, server-vulkan et d’autres existent également) :

export LLAMA_API_KEY="$(openssl rand -hex 24)"

docker run -d --name llama-server \
  --gpus all \
  -p 8080:8080 \
  -v /opt/llama-models:/models \
  ghcr.io/ggml-org/llama.cpp:server-cuda \
  -hf ggml-org/Qwen3.8-27B-GGUF:Q4_K_M \
  --host 0.0.0.0 \
  --port 8080 \
  --alias qwen3.8-27b \
  --api-key "$LLAMA_API_KEY" \
  --ctx-size 16384 \
  --n-gpu-layers auto \
  --flash-attn auto \
  --jinja \
  --reasoning auto
  • Q4_K_M représente environ 16 Go de poids ; environ 18,4 GiB de VRAM mesurés avec un contexte de 8K et ~20 GiB à 32K, donc une carte de 24 Go fonctionne avec un --ctx-size modeste. unsloth/Qwen3.8-27B-GGUF:UD-Q4_K_M d’Unsloth est une alternative populaire.
  • --jinja utilise le modèle de chat propre au modèle — c’est ce qui permet à l’appel d’outils natif de fonctionner.
  • --alias définit le nom renvoyé par l’API, afin que le nom du modèle que vous saisissez dans Discourse corresponde.
  • --reasoning auto signale la réflexion séparément, correspondant au comportement du --reasoning-parser de vLLM.
  • L’entrée d’image nécessite le projecteur multimodal ; avec -hf, il est généralement récupéré automatiquement, sinon passez --mmproj /models/mmproj-...gguf (ou --no-mmproj pour économiser de la VRAM en ne servant que du texte).

Testez-le :

curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $LLAMA_API_KEY" \
  -d '{
    "model": "qwen3.8-27b",
    "messages": [{"role": "user", "content": "What is Discourse?"}],
    "max_tokens": 200
  }'

Exécution d’autre chose

Tout serveur qui parle les complétions de chat OpenAI — SGLang, TensorRT-LLM, LM Studio, une passerelle d’entreprise, un déploiement dédié dans le cloud — fonctionne tel quel : configurez-le dans Discourse avec le fournisseur vLLM, qui est notre client compatible OpenAI générique avec prise en charge native des outils.

Si vous préférez ne pas exécuter l’inférence vous-même mais souhaitez tout de même éviter le verrouillage des grandes API, les points de terminaison d’inférence Hugging Face (qui utilisent désormais vLLM par défaut comme moteur) fonctionnent avec le fournisseur Hugging Face — indiquez-lui l’URL /v1/chat/completions du point de terminaison.

Le rendre disponible à votre instance Discourse

Vous l’exécuterez normalement sur une machine dédiée en raison de l’exigence GPU. Lorsque vous le faites :

  1. Placez un proxy inverse devant le serveur et terminez le TLS là — Discourse parlera joyeusement en HTTPS avec lui.
  2. Restreignez le point de terminaison par pare-feu ou certificat client afin que seules vos hôtes Discourse puissent se connecter. Une clé d’API est une authentification, pas une limite réseau.
  3. Gardez le cache du modèle sur un volume persistant afin que les redémarrages ne retéléchargent pas des dizaines de gigaoctets.

Configuration de Discourse AI

Les connexions LLM sont configurées via l’interface d’administration plutôt que via les paramètres du site. Allez sur /admin/plugins/discourse-ai/ai-llms et ajoutez un nouveau LLM :

  1. Nom d’affichage — ce que vos administrateurs et utilisateurs voient.
  2. Nom — envoyé dans la requête API ; il doit correspondre à ce que le serveur attend (Qwen/Qwen3.8-27B pour vLLM, votre --alias pour llama.cpp).
  3. Fournisseur — vLLM pour vLLM, llama.cpp et tout autre serveur compatible OpenAI ; Hugging Face pour les points de terminaison hébergés sur HF.
  4. URL — l’URL complète du point de terminaison incluant le chemin, par ex. https://llm.example.com/v1/chat/completions.
  5. Clé d’API — tapez-la, ou référez une clé stockée depuis la page des Secrets IA.
  6. Tokeniseur — Qwen pour Qwen3.8 (choisissez le tokeniseur correspondant à la famille de votre modèle).
  7. Max prompt tokens / max output tokens — gardez la somme égale ou inférieure au --max-model-len / --ctx-size de votre serveur. Par exemple, avec un serveur de 32768 tokens : 28000 pour l’invite et 4096 pour la sortie. Les modèles de réflexion consomment une partie de ce budget de sortie pour la réflexion, donc ne serrez pas trop.
  8. Vision — activez la vision native si vous avez servi le modèle avec prise en charge des images et souhaitez qu’il les lise.
  9. Options du fournisseur (vLLM) : définissez vLLM reasoning parser sur qwen3 afin que cela corresponde à l’indicateur du serveur, et utilisez les champs de substitution de la réflexion / effort de réflexion / budget de tokens de réflexion si vous souhaitez que Discourse pilote la réflexion par requête. Laissez « disable native tools » décoché sauf si l’appel de fonctions du modèle est cassé.

Cliquez sur Exécuter le test avant d’enregistrer : il envoie une requête en streaming et une non-streaming et vous indique laquelle a échoué.

Une fois enregistré, définissez-le comme défaut du site avec le paramètre ai_default_llm_model, ou attribuez-le par fonctionnalité dans /admin/plugins/discourse-ai/ai-features. Les agents individuels sont configurés sur la page Agents.

Une mise en garde : les embeddings de recherche sémantique ne proviennent pas de ce modèle. Les embeddings utilisent leur propre modèle d’embedding, configuré séparément (un modèle d’embedding API, ou un serveur Text Embeddings Inference auto-hébergé via les paramètres ai_hugging_face_tei_endpoint). Si vous souhaitez que la Recherche IA soit entièrement auto-hébergée, exécutez un petit modèle d’embedding tel que bge-m3 à côté de votre LLM.

Dépannage

Symptôme Cause probable
404 depuis le point de terminaison L’URL manque /v1/chat/completions
model not found Le Nom ne correspond pas à l’ID du modèle servi / --alias
401 / 403 Clé d’API non concordante entre --api-key et l’enregistrement LLM
Les appels d’outils apparaissent sous forme de texte JSON dans le message Le serveur a été lancé sans analyse d’appels d’outils ; Discourse est revenu aux outils XML
Du texte de réflexion fuit dans la réponse --reasoning-parser manquant sur le serveur, ou le paramètre reasoning parser de Discourse ne correspond pas
Erreur de mémoire CUDA Diminuez --max-model-len, ajoutez --quantization fp8, ou diminuez --gpu-memory-utilization
Les requêtes expirent lors de longs résumés Les modèles de réflexion sont lents ; notre délai HTTP est de 6 minutes — réduisez le contexte, diminuez l’effort de réflexion, ou désactivez la réflexion
Réponses tronquées Le max output tokens dans Discourse est trop petit une fois les tokens de réflexion comptés
17 « J'aime »

Pour toute personne recherchant ce sujet avec/pour :
#Llava-Api-keys

J’utilise également vLLM. Je recommanderais également le modèle openchat v3.5 0106, qui est un modèle de 7 milliards de paramètres et qui fonctionne très bien.

Je l’exécute en fait en 4 bits quantifiés pour qu’il s’exécute plus rapidement.

J’attribue cette tâche à un stagiaire. Y a-t-il des recommandations de qui que ce soit sur le service spécifique à souscrire ? Ceci est pour un test. Le stagiaire a actuellement un test configuré avec OpenAI. Cela fonctionne bien. Il/elle souhaite essayer le TGI HuggingFace, mais il semble que je doive lui fournir un serveur dédié avec GPU ? Quelles sont les spécifications minimales pour un test ?

Existe-t-il des liens que je peux donner au stagiaire ?

Je n’ai pas encore examiné ce projet en profondeur. J’anticipe simplement que le stagiaire aura besoin de certaines ressources et j’essaie de faire des recommandations raisonnables sur les services pour que le stagiaire fasse des recherches.

Salut, en exposant avec un certificat auto-signé dans un conteneur vllm sur une boîte GPU sur site, je n’ai pas trouvé de bon moyen d’ajouter le CA racine au conteneur discourse afin qu’il puisse accéder en toute sécurité à ce service sur site via HTTPS.

Par exemple :

./launcher enter app
curl -L https://vllm.infra.example.com/v1/models
curl: (60) Problème de certificat SSL : impossible d'obtenir le certificat de l'émetteur local
Plus de détails ici : https://curl.se/docs/sslcerts.html

curl n'a pas pu vérifier la légitimité du serveur et n'a donc pas pu
établir de connexion sécurisée avec lui. Pour en savoir plus sur cette situation et
comment la résoudre, veuillez visiter la page Web mentionnée ci-dessus.

Existe-t-il un bon moyen d’ajouter un certificat racine auto-signé dans le conteneur discourse qui survivrait aux mises à jour de l’image du conteneur ?

Pour autant que je sache, l’ajouter dans le fichier app.yml

run:
  - exec: wget ... && update-ca-certificates

ne fonctionnerait bien que lors de la construction/reconstruction de l’application.

Toute suggestion est la bienvenue.

14 messages ont été déplacées vers un nouveau sujet : Faire fonctionner discourse ai avec ollama localement

Y aurait-il un moyen d’ajouter un en-tête HTTP personnalisé aux requêtes Discourse AI ? Nous avons un serveur équipé de GPU que nous utilisons à diverses fins, il dispose d’une API compatible avec OpenAI, mais pour des raisons de sécurité, nous l’avons placé derrière une passerelle de gestion d’API, qui nécessite un en-tête HTTP personnalisé (quelque chose comme SubscriptionKey) et nous fournissons notre clé d’authentification ici.

Il est à noter que cette clé d’authentification sert à passer par l’APIM et est différente de la clé d’API que l’on fournirait pour un service tel que l’API OpenAI.

Ce serait formidable s’il existait un moyen d’ajouter des en-têtes personnalisés lors de la configuration de chaque LLM sur la page de configuration admin/plugins/discourse-ai/ai-llms. Peut-être une option « Personnalisée » dans le menu déroulant « Fournisseur », avec des options supplémentaires pour des cas d’utilisation comme celui-ci ?

1 « J'aime »

La réponse rapide est un plugin pour ajouter cet en-tête. Une solution de contournement pourrait être un serveur proxy local que vous atteindriez depuis Discourse et qui ajouterait l’en-tête et renverrait les données à Discourse. Une source non fiable suggère que vous pourriez être en mesure de demander à NGINX de faire cela pour vous avec quelque chose comme

server {
    listen 80;
    
    location / {
        proxy_pass https://api.example.com;
        proxy_set_header SubscriptionKey xyz;
        proxy_set_header Host $host;
    }
}

Il pourrait y avoir une façon astucieuse d’ajouter cela à la configuration nginx de Discourse à un chemin secret (qui n’écouterait également que votre serveur).

1 « J'aime »

Bonjour,

Je ne parviens pas à trouver ces paramètres :

Avez-vous des suggestions pour tester la fonctionnalité de traduction IA avec un backend Ollama ?

Créez un nouveau LLM à /admin/plugins/discourse-ai/ai-llms/new?llmTemplate=none, sélectionnez OpenAI comme fournisseur car Ollama prend en charge la compatibilité avec l’API OpenAI : OpenAI compatibility - Ollama.

1 « J'aime »

Merci ! J’ai également remarqué que l’URL ne fonctionne que lorsque le plugin IA est activé :person_facepalming:

Pour le fournisseur nouvellement ajouté, avez-vous des suggestions sur ce qu’il faut choisir/configurer pour les paramètres obligatoires suivants ?

  1. Tokenizer
  2. Fenêtre de contexte

Pour le modèle, je pensais peut-être utiliser stablelm2:1.6b ou translategemma:4b, mais je ne suis pas encore sûr.
Dans le README de ce dernier, il y a une description d’un prompt d’entrée. Je me demande quelle est la requête que la fonctionnalité de traduction IA envoie à Ollama. cf. /admin/plugins/discourse-ai/ai-agents/-28/edit

:sweat_smile:

Le plus proche du modèle que vous choisirez. Pour Gemma, vous pouvez choisir celui de Gemini.

Ici, vous définissez le contexte maximal de votre déploiement.

S’il vous plaît, ne le faites pas. Ce modèle est très très très très très ancien. C’est le pire choix que vous puissiez faire.

Ce modèle est d’une génération en retard et a des exigences de prompt très strictes qui ne sont pas compatibles avec Discourse. Nous attendons un LLM d’utilisation générale plus standard.

Pour ces tailles, je recommande soit Qwen 3.5, soit Gemma 4.

3 « J'aime »

Merci encore. J’ai configuré les paramètres, récupéré le modèle, ajusté l’agent et activé la fonctionnalité de traduction IA. On verra bien ce que ça donne.

Autre question. Nous utilisions auparavant le plugin de traduction avec une instance LibreTranslate mise à disposition de manière très généreuse. Est-il impossible de connecter la fonctionnalité de traduction IA de Discourse à ce point de terminaison LibreTranslate ? Au final, ce serait bien plus simple que d’héberger une instance Ollama sur un serveur sans véritables capacités de LLM.

Pourquoi ne pas continuer à l’utiliser ? Nous ne le mettons plus à jour, mais il continuera de fonctionner tel quel.

La traduction de Discourse AI fonctionne avec un ensemble de contraintes entièrement différent de celui du plugin de traduction original, nous l’avons donc reconstruite de zéro pour répondre à ce nouveau monde, où les traductions basées sur les LLM sont meilleures et moins chères que ce qui était possible auparavant avec les API de traduction ML.

1 « J'aime »