Autoalojamiento de un LLM de código abierto para DiscourseAI

El complemento Discourse AI tiene muchas funciones que necesitan un LLM para estar habilitadas: resumen, Asistente de IA, búsqueda semántica, Bot de IA y sus agentes. Puede usar una API de terceros, como Configurar claves de API para OpenAI o Configurar claves de API para Anthropic, pero Discourse AI se diseñó desde el primer día para que no quede atado a ellas.

Esta guía cubre cómo ejecutar usted mismo un modelo de pesos abiertos y conectarlo a Discourse.

Modelo utilizado aquí: Qwen/Qwen3.8-27B — un modelo denso de 27B lanzado en agosto de 2026 con una ventana de contexto nativa de 256K, comprensión de imágenes/video, llamadas a herramientas y modo de pensamiento activado por defecto. Actualmente es el punto óptimo para el autoalojamiento: lo suficientemente potente para tareas reales de resumen/agentes, y lo bastante pequeño para una sola GPU. Sustitúyalo por cualquier otro modelo que prefiera; las banderas que cambian se indican a continuación.

Lo que Discourse necesita de su servidor de inferencia

  • Un endpoint POST /v1/chat/completions compatible con OpenAI (con soporte para streaming).
  • Llamadas nativas a herramientas/funciones si desea que el Bot de IA, los agentes o la salida estructurada funcionen bien. Sin esto, Discourse recurre a llamadas a herramientas basadas en XML, que los modelos más débiles manejan mal.
  • Una ventana de contexto real — apunte a un mínimo de 16K tokens, 32K+ preferiblemente. El tamaño de las indicaciones de Discourse para el resumen y RAG crece rápidamente.
  • Opcional: entrada de imágenes, si desea que el modelo lea las imágenes adjuntas a las publicaciones.

Cualquier cosa que cumpla con los tres primeros requisitos funcionará, por lo que la elección a continuación depende realmente de su hardware.

Configuración Adecuado para
vLLM Servidor GPU dedicado, ≥24GB de VRAM (cuantizado) / 80GB (precisión completa), tráfico sostenido, múltiples usuarios
llama.cpp GPUs de consumo, Apple silicon, equipos solo con CPU, un foro pequeño único
Gestionado / nube Desea tener el modelo fuera de su portátil pero no en su hardware: cualquier endpoint compatible con OpenAI

Ejecución con vLLM

vLLM es el motor recomendado para servidores GPU: licencia Apache, servidor compatible con OpenAI listo para usar y soporte de primera clase para la familia 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"

Notas sobre las banderas:

  • --max-model-len limita el contexto de la indicación + salida y, por lo tanto, la caché KV. El modelo soporta 256K nativamente; 32K es suficiente para el trabajo de un foro y mantiene la VRAM predecible. Aumente el valor (o use auto) si tiene memoria.
  • --reasoning-parser qwen3 divide el pensamiento del modelo en un campo reasoning separado en lugar de volcarlo en la respuesta. Debe reflejar esta elección en la configuración del LLM de Discourse (vea más abajo).
  • --enable-auto-tool-choice --tool-call-parser ... activa las llamadas nativas a funciones. Los nombres de los analizadores cambian entre las versiones de vLLM: revise python3 -m vllm.entrypoints.openai.api_server --help dentro de su imagen si las llamadas a herramientas vuelven como texto sin formato.
  • HF_TOKEN solo es necesario para modelos restringidos; --api-key protege su propio endpoint. Advertencia de los documentos de vLLM: --api-key protege solo las rutas /v1, por lo que debe mantener el servidor fuera de Internet público.
  • ¿VRAM ajustada? Intente --quantization fp8 (o un checkpoint AWQ pre-cuantizado) antes de reducir el contexto. Multi-GPU: añada --tensor-parallel-size N.

Pruébalo:

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
  }'

Debería obtener un cuerpo JSON normal de chat-completions, con message.reasoning junto a message.content.

Ejecución con llama.cpp

llama.cpp es la herramienta adecuada cuando el modelo debe caber en menos VRAM de la que vLLM querría, o cuando está en Apple silicon, AMD, Vulkan o CPU. Su llama-server también expone una API compatible con OpenAI.

Extraiga y ejecute la compilación oficial de GGUF usando la imagen del contenedor para su backend (server-cuda aquí; también existen server, server-rocm, server-vulkan y otros):

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 tiene unos 16GB de pesos; se midieron alrededor de 18.4 GiB de VRAM con un contexto de 8K y ~20 GiB con 32K, por lo que una tarjeta de 24GB funciona con un --ctx-size modesto. unsloth/Qwen3.8-27B-GGUF:UD-Q4_K_M de Unsloth es una alternativa popular.
  • --jinja usa la plantilla de chat del propio modelo — esto es lo que hace que las llamadas nativas a herramientas funcionen.
  • --alias establece el nombre reportado por la API, por lo que el nombre del modelo que escribe en Discourse coincide.
  • --reasoning auto reporta el pensamiento por separado, igualando el comportamiento de --reasoning-parser de vLLM.
  • La entrada de imágenes necesita el proyector multimodal; con -hf generalmente se obtiene automáticamente, de lo contrario pase --mmproj /models/mmproj-...gguf (o --no-mmproj para ahorrar VRAM para el servicio solo de texto).

Pruébalo:

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
  }'

Ejecutando otra cosa

Cualquier servidor que hable completaciones de chat compatibles con OpenAI — SGLang, TensorRT-LLM, LM Studio, una puerta de enlace empresarial, un despliegue dedicado en la nube — funciona tal cual: configúrelo en Discourse con el proveedor vLLM, que es nuestro cliente genérico compatible con OpenAI con soporte nativo para herramientas.

Si prefiere no ejecutar la inferencia usted mismo pero aún desea evitar el bloqueo con las grandes APIs, Hugging Face Inference Endpoints (que ahora usan vLLM como motor por defecto) funcionan con el proveedor Hugging Face — apúntelo a la URL /v1/chat/completions del endpoint.

Hacerlo disponible para su instancia de Discourse

Normalmente ejecutará esto en una máquina dedicada debido al requisito de GPU. Cuando lo haga:

  1. Ponga un proxy inverso frente al servidor y termine TLS allí — Discourse hablará HTTPS con él felizmente.
  2. Restrinja el endpoint mediante firewall o certificado de cliente para que solo sus hosts de Discourse puedan conectarse. Una clave de API es autenticación, no un límite de red.
  3. Mantenga la caché del modelo en un volumen persistente para que los reinicios no vuelvan a descargar decenas de gigabytes.

Configurando Discourse AI

Las conexiones LLM se configuran a través de la interfaz de administración en lugar de los ajustes del sitio. Vaya a /admin/plugins/discourse-ai/ai-llms y añada un nuevo LLM:

  1. Nombre para mostrar — lo que verán sus administradores y usuarios.
  2. Nombre — enviado en la solicitud API; debe coincidir con lo que espera el servidor (Qwen/Qwen3.8-27B para vLLM, su --alias para llama.cpp).
  3. Proveedor — vLLM para vLLM, llama.cpp y cualquier otro servidor compatible con OpenAI; Hugging Face para endpoints alojados en HF.
  4. URL — la URL del endpoint completa, incluyendo la ruta, por ejemplo: https://llm.example.com/v1/chat/completions.
  5. Clave de API — escríbala, o haga referencia a una clave almacenada desde la página AI Secrets.
  6. Tokenizador — Qwen para Qwen3.8 (elija el tokenizador que coincida con la familia de su modelo).
  7. Tokens máximos de indicación / tokens máximos de salida — mantenga la suma en o por debajo del --max-model-len / --ctx-size de su servidor. Por ejemplo, con un servidor de 32768 tokens: 28000 de indicación y 4096 de salida. Los modelos de razonamiento gastan parte de ese presupuesto de salida en el pensamiento, así que no lo apriete demasiado.
  8. Visión — habilite la visión nativa si entregó el modelo con soporte para imágenes y quiere que lea imágenes.
  9. Opciones de proveedor (vLLM): establezca el analizador de razonamiento de vLLM a qwen3 para que coincida con la bandera del servidor, y use los campos de anulación de pensamiento / esfuerzo de razonamiento / presupuesto de tokens de pensamiento si desea que Discourse dirija el pensamiento por solicitud. Deje “desactivar herramientas nativas” sin marcar a menos que las llamadas a funciones del modelo estén rotas.

Haga clic en Ejecutar prueba antes de guardar: dispara tanto una solicitud con streaming como una sin streaming y le dice cuál falló.

Una vez guardado, hágalo el valor predeterminado del sitio con el ajuste del sitio ai_default_llm_model, o asígnelo por función en /admin/plugins/discourse-ai/ai-features. Los agentes individuales se configuran en la página de Agentes.

Una advertencia: las incrustaciones de búsqueda semántica no provienen de este modelo. Las incrustaciones usan su propio modelo de incrustación, configurado por separado (un modelo de incrustación API, o un servidor Text Embeddings Inference autoalojado mediante los ajustes ai_hugging_face_tei_endpoint). Si desea que la Búsqueda IA esté totalmente autoalojada, ejecute un pequeño modelo de incrustación como bge-m3 junto a su LLM.

Solución de problemas

Síntoma Causa probable
404 desde el endpoint Falta /v1/chat/completions en la URL
model not found El Nombre no coincide con el ID del modelo servido / --alias
401 / 403 Incompatibilidad de la clave de API entre --api-key y el registro LLM
Las llamadas a herramientas aparecen como texto JSON en la publicación El servidor se inició sin análisis de llamadas a herramientas; Discourse recurrió a las herramientas XML
El texto de pensamiento se filtra en la respuesta Falta --reasoning-parser en el servidor, o el ajuste de analizador de razonamiento de Discourse no coincide
CUDA se quedó sin memoria Reduzca --max-model-len, añada --quantization fp8, o reduzca --gpu-memory-utilization
Las solicitudes agotan el tiempo de espera en resúmenes largos Los modelos de razonamiento son lentos; nuestro tiempo de espera HTTP es de 6 minutos — reduzca el contexto, baje el esfuerzo de pensamiento o deshabilite el pensamiento
Respuestas truncadas Los tokens máximos de salida en Discourse son demasiado pequeños una vez que se cuentan los tokens de pensamiento
17 Me gusta

Para cualquiera que busque este tema con/para:
#Llava-Api-keys

Yo también uso vLLM. También recomendaría el modelo openchat v3.5 0106, que es un modelo de 7B parámetros que funciona muy bien.

De hecho, lo estoy ejecutando en 4 bits cuantizados para que funcione más rápido.

Estoy asignando esta tarea a un pasante. ¿Hay alguna recomendación de alguien sobre qué servicio específico contratar? Esto es para una prueba. El pasante actualmente tiene una prueba configurada con OpenAI. Funciona bien. Están interesados en probar HuggingFace TGI, pero parece que necesito darles un servidor dedicado con GPU. ¿Cuáles son las especificaciones mínimas para una prueba?

¿Hay enlaces que pueda dar al pasante?

Aún no he analizado este proyecto en profundidad. Solo anticipo que el pasante necesitará algunos recursos y estoy tratando de hacer algunas recomendaciones razonables sobre servicios para que el pasante investigue.

Hola, al exponer con un certificado autofirmado el contenedor vllm en una caja de GPU on-prem, no encontré una buena manera de agregar la CA raíz al contenedor de discourse para que pueda acceder de forma segura a este servicio on-prem a través de https.

por ejemplo:

./launcher enter app
curl -L https://vllm.infra.example.com/v1/models
curl: (60) problema de certificado SSL: no se puede obtener el certificado del emisor local
Más detalles aquí: https://curl.se/docs/sslcerts.html

curl no pudo verificar la legitimidad del servidor y, por lo tanto, no pudo
establecer una conexión segura con él. Para obtener más información sobre esta situación y
cómo solucionarlo, visite la página web mencionada anteriormente.

¿Hay alguna buena manera de agregar un certificado de CA raíz autofirmado en el contenedor de discourse que sobreviva a las actualizaciones de la imagen del contenedor?

Hasta donde sé, agregarlo en el app.yml

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

solo funcionaría bien durante la compilación/recompilación de la aplicación.

Cualquier pista es bienvenida.

14 publicaciones se dividieron en un nuevo tema: Hacer que discourse ai funcione con ollama localmente

¿Habría alguna manera de añadir una cabecera HTTP personalizada a las solicitudes de Discourse AI? Tenemos un servidor equipado con GPU que utilizamos para una variedad de propósitos, tiene una API compatible con OpenAI, pero por seguridad la hemos puesto detrás de un portal de gestión de API (API Management gateway), el cual requiere una cabecera HTTP personalizada (algo como SubscriptionKey) y proporcionamos nuestra clave de autenticación aquí.

Tenga en cuenta que esta clave de autenticación es para pasar el APIM y es diferente de la clave API que se proporcionaría para un servicio como la API de OpenAI.

Sería genial si hubiera una forma de añadir cabeceras personalizadas en la configuración de cada LLM en la página de configuración admin/plugins/discourse-ai/ai-llms. ¿Quizás una opción ‘Personalizada’ en el menú desplegable ‘Proveedor’, con opciones adicionales para casos de uso como este?

1 me gusta

La respuesta rápida es un complemento para agregar esa cabecera. Una solución alternativa podría ser un servidor proxy local al que se accedería desde Discourse y que agregaría la cabecera y enviaría los datos de vuelta a Discourse. Una fuente no confiable sugiere que podrías lograr que NGINX hiciera eso por ti con algo como

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

Podría haber una forma ingeniosa de agregar eso a la configuración de nginx de Discourse en alguna ruta secreta (que también solo escuchara a tu servidor).

1 me gusta

Hola,

No consigo encontrar estas configuraciones:

¿Alguna sugerencia para probar la función de traducción con IA utilizando un backend de Ollama?

Crea un nuevo LLM en /admin/plugins/discourse-ai/ai-llms/new?llmTemplate=none, selecciona OpenAI como proveedor ya que Ollama tiene OpenAI compatibility - Ollama.

1 me gusta

¡Gracias! También noté que la URL solo funciona cuando el plugin de IA está activado :person_facepalming:

Para el proveedor recién añadido, ¿alguna sugerencia sobre qué elegir/configurar para los siguientes ajustes obligatorios?

  1. Tokenizador
  2. Ventana de contexto

Para el modelo, estaba pensando en usar stablelm2:1.6b o translategemma:4b, pero aún no lo sé.
En el README de este último hay una descripción de un prompt de entrada. Me pregunto cuál es la consulta que la función de traducción de IA envía a Ollama. c.f. /admin/plugins/discourse-ai/ai-agents/-28/edit

:sweat_smile:

El más cercano al modelo que elijas. Para Gemma, puedes elegir el de Gemini.

Aquí configuras el contexto máximo de tu implementación.

Por favor, no lo hagas. Ese modelo es muy, muy, muy, muy, muy antiguo. Es la peor opción que puedes tomar.

Ese modelo es de una generación anterior y tiene requisitos de prompt muy estrictos que no son compatibles con Discourse. Esperamos un LLM de uso general más estándar.

En esos tamaños, recomiendo usar Qwen 3.5 o Gemma 4.

3 Me gusta

Gracias de nuevo. He configurado los ajustes, descargado el modelo, ajustado el agente y activado la función de traducción con IA. Ahora a ver qué sale.

Otra pregunta. Antes estábamos usando el plugin de traducción con una instancia de LibreTranslate amablemente proporcionada. ¿No es posible conectar la función de traducción de Discourse AI a ese endpoint de LibreTranslate? Al final, eso sería mucho más fácil que tener que alojar una instancia de Ollama en un servidor sin capacidades reales de LLM.

¿Por qué no siguen usándolo? Ya no lo actualizamos, pero seguirá funcionando tal como está.

La traducción de Discourse AI opera con un conjunto de restricciones completamente diferente al del plugin Translator original, por lo que lo construimos desde cero para abordar este nuevo entorno, donde las traducciones basadas en LLM son mejores y más baratas que lo que era posible antes con las API de traducción ML.

1 me gusta