diff --git a/ansible/roles/llama_server/defaults/main.yml b/ansible/roles/llama_server/defaults/main.yml index 0c8d583..c2a0688 100644 --- a/ansible/roles/llama_server/defaults/main.yml +++ b/ansible/roles/llama_server/defaults/main.yml @@ -23,6 +23,11 @@ llama_embed_model_path: "" # chemin GGUF sur /mnt/models (NFS) llama_embed_model_url: "" # URL de téléchargement (HuggingFace) — get_url si absent llama_embed_model_alias: "nomic-embed-text" llama_embed_ctx_size: 2048 +# Batch physique (ubatch) = contexte : en mode --embeddings avec pooling, toute l'entrée doit +# tenir dans UN seul ubatch. Le défaut llama.cpp (512) fait échouer en HTTP 500 tout chunk +# > 512 tokens (« input too large to process. increase the physical batch size ») — c'est ce +# qui faisait rater ~46 chunks du RAG (CHUNK_MAX=2000 chars ≈ 700 tokens). Aligné sur ctx-size. +llama_embed_ubatch_size: 2048 # CPU par défaut (0 couche GPU). nomic-embed-text est minuscule (137M) → ~100 ms en CPU, # DÉTERMINISTE. Sur GPU (99) il partage la RX 6700XT avec le chat qwen3-8b (:1234) et tombe # dans la file derrière une génération → latence BIMODALE (16 ms ou 9-12 s, voire timeout) → diff --git a/ansible/roles/llama_server/templates/llama-embed.service.j2 b/ansible/roles/llama_server/templates/llama-embed.service.j2 index 5bbf7a5..dd93932 100644 --- a/ansible/roles/llama_server/templates/llama-embed.service.j2 +++ b/ansible/roles/llama_server/templates/llama-embed.service.j2 @@ -13,6 +13,8 @@ ExecStart=/opt/llama.cpp/build/bin/llama-server \ --host {{ llama_server_host }} \ --port {{ llama_embed_port }} \ --ctx-size {{ llama_embed_ctx_size }} \ + --batch-size {{ llama_embed_ubatch_size }} \ + --ubatch-size {{ llama_embed_ubatch_size }} \ --n-gpu-layers {{ llama_embed_n_gpu_layers }} \ --alias {{ llama_embed_model_alias }} \ --embeddings \ diff --git a/ansible/roles/rag/defaults/main.yml b/ansible/roles/rag/defaults/main.yml index c89b513..947fbcf 100644 --- a/ansible/roles/rag/defaults/main.yml +++ b/ansible/roles/rag/defaults/main.yml @@ -3,6 +3,10 @@ rag_data_dir: /srv/data/rag rag_docs_dir: /srv/data/rag/docs qdrant_url: "http://127.0.0.1:6333" -embed_url: "http://192.168.10.20:1234/v1/embeddings" -embed_model: "qwen3-8b" +# Embeddings : instance dédiée nomic-embed-text (gpu-01 :1238, dim 768), pas le modèle de chat. +# NB : ces deux vars ne sont PAS injectées dans les scripts (le handler lance rag-ingest sans env) — +# les scripts files/rag-ingest et files/rag-query hardcodent ces mêmes valeurs par défaut. +# Conservées ici pour documenter la cible et éviter toute régression vers qwen3-8b/:1234. +embed_url: "http://192.168.10.20:1238/v1/embeddings" +embed_model: "nomic-embed-text" rag_collection: "funk-docs" diff --git a/ansible/roles/rag/files/rag-ingest b/ansible/roles/rag/files/rag-ingest index f01e4c3..42db8b3 100644 --- a/ansible/roles/rag/files/rag-ingest +++ b/ansible/roles/rag/files/rag-ingest @@ -7,6 +7,7 @@ Usage: rag-ingest [docs_dir] import os import sys import json +import time import hashlib import re import urllib.request @@ -57,8 +58,22 @@ def ensure_collection(): def embed(text): - result = _request("POST", EMBED_URL, {"model": EMBED_MODEL, "input": text}) - return result["data"][0]["embedding"] + # L'instance llama-embed (:1238) renvoie occasionnellement des 500 transitoires sous charge + # soutenue (slot saturé) → retry avec backoff. Les chunks sont bornés (CHUNK_MAX=2000) donc + # un 500 n'est pas dû à un dépassement de contexte. + last = None + for attempt in range(5): + try: + result = _request("POST", EMBED_URL, {"model": EMBED_MODEL, "input": text}) + return result["data"][0]["embedding"] + except (urllib.error.HTTPError, urllib.error.URLError) as e: + last = e + code = getattr(e, "code", None) + # Ne réessaie que sur erreurs transitoires (5xx) ou réseau + if code is not None and code < 500: + raise + time.sleep(0.5 * (attempt + 1)) + raise last def chunk_markdown(rel_path, content):