mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-13 18:34:44 +02:00
feat(rag): RAG Hermes — Qdrant + rag-ingest/rag-query + skill funk-ai
Indexation de admin/ (284 chunks) dans Qdrant via embeddings Qwen3-8B. rag-query utilisable en CLI et depuis le profil funk-ai de Hermes. Note: modèle d'embedding générique — qualité limitée, voir admin/ia/rag.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3a013834aa
commit
eae6e76645
9 changed files with 687 additions and 0 deletions
76
ansible/roles/rag/files/rag-query
Normal file
76
ansible/roles/rag/files/rag-query
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Interroge la base vectorielle Qdrant avec une question en langage naturel.
|
||||
Usage: rag-query "ma question" [--top N]
|
||||
Retourne les passages de documentation les plus pertinents.
|
||||
"""
|
||||
import sys
|
||||
import json
|
||||
import os
|
||||
import urllib.request
|
||||
|
||||
QDRANT_URL = os.environ.get("QDRANT_URL", "http://127.0.0.1:6333")
|
||||
EMBED_URL = os.environ.get("EMBED_URL", "http://192.168.10.20:1234/v1/embeddings")
|
||||
EMBED_MODEL = os.environ.get("EMBED_MODEL", "qwen3-8b")
|
||||
COLLECTION = os.environ.get("RAG_COLLECTION", "funk-docs")
|
||||
MIN_SCORE = 0.60
|
||||
|
||||
|
||||
def _post(url, data):
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(data).encode(),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST"
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=60) as r:
|
||||
return json.loads(r.read())
|
||||
|
||||
|
||||
def embed(text):
|
||||
result = _post(EMBED_URL, {"model": EMBED_MODEL, "input": text})
|
||||
return result["data"][0]["embedding"]
|
||||
|
||||
|
||||
def search(question, top=5):
|
||||
vector = embed(question)
|
||||
result = _post(f"{QDRANT_URL}/collections/{COLLECTION}/points/search", {
|
||||
"vector": vector,
|
||||
"limit": top,
|
||||
"with_payload": True,
|
||||
"score_threshold": MIN_SCORE,
|
||||
})
|
||||
return result["result"]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: rag-query \"question\" [--top N]", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
question = sys.argv[1]
|
||||
top = 5
|
||||
if "--top" in sys.argv:
|
||||
idx = sys.argv.index("--top")
|
||||
try:
|
||||
top = int(sys.argv[idx + 1])
|
||||
except (IndexError, ValueError):
|
||||
pass
|
||||
|
||||
try:
|
||||
results = search(question, top)
|
||||
except Exception as e:
|
||||
print(f"ERREUR: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if not results:
|
||||
print(f"Aucun résultat pertinent pour : {question}")
|
||||
sys.exit(0)
|
||||
|
||||
print(f"=== Contexte RAG — {len(results)} résultat(s) pour : {question} ===\n")
|
||||
for i, r in enumerate(results, 1):
|
||||
p = r["payload"]
|
||||
score = r["score"]
|
||||
print(f"--- [{i}] {p['file']} § {p['section']} (score: {score:.3f}) ---")
|
||||
print(p["text"][:700])
|
||||
print()
|
||||
Loading…
Add table
Add a link
Reference in a new issue