cloooooo
Un système d'IA entièrement local. Inférence de qualité production sans aucun appel API externe — recherche agentique profonde, RAG hybride, appel d'outils, mémoire sémantique et routage multi-modèles, tout sur votre matériel.
Installation
Requiert Python 3.10+ et un serveur SGLang tournant localement (voir ci-dessous).
pip install clovis
Prérequis
cloooooo s'appuie sur un backend SGLang pour l'inférence. Le plus simple :
# Démarrer SGLang avec Qwen3-32B-AWQ (RTX 3090 recommandé)
python -m sglang.launch_server \
--model-path Qwen/Qwen3-32B-AWQ \
--host 0.0.0.0 --port 61005 \
--quantization awq
localhost:61005, l'objet cloooooo() s'y connecte automatiquement. Aucune configuration supplémentaire n'est nécessaire.
Quickstart
from clovis import cloooooo
ai = cloooooo()
# Inférence simple
print(ai("Explique les transformeurs en 3 phrases."))
# Avec recherche web
print(ai("Dernières avancées en IA en 2026 ?", use_web=True))
# Recherche agentique profonde (MiroFlow)
result = ai.deep_thinking("Quelles sont les causes de la crise des semi-conducteurs ?")
print(result["answer"])
Inférence de base
L'objet cloooooo est l'interface principale. Appelez-le directement comme une fonction.
from clovis import cloooooo
ai = cloooooo()
# Appel de base
reponse = ai("Qu'est-ce que l'attention multi-têtes ?")
# Avec contexte et invite négative
reponse = ai(
"Résume ce texte.",
context="Le mécanisme d'attention...",
negative_prompt="Ne pas inclure de formules mathématiques."
)
# Mode thinking étendu (chain-of-thought Qwen3)
reponse = ai("Prouve que sqrt(2) est irrationnel.", thinking=True)
# Streaming token par token
for chunk in ai.stream("Raconte une histoire courte."):
print(chunk, end="", flush=True)
Paramètres
| Paramètre | Type | Description | |
|---|---|---|---|
| prompt | str | requis | La question ou instruction. |
| context | str | optionnel | Contexte additionnel préfixé au prompt. |
| negative_prompt | str | optionnel | Ce que la réponse doit éviter. |
| thinking | bool | False | Active le chain-of-thought étendu de Qwen3. Les balises <think> sont retirées automatiquement de la sortie. |
| use_web | bool | False | Préfixe les résultats SearXNG en contexte avant l'inférence. |
Modes d'inférence
Cinq modes disponibles, du plus rapide au plus puissant.
# Mode simple — réponse directe, plus rapide
ai("Bonjour !")
# Mode thinking — chain-of-thought activé
ai("Quelle est la complexité de Dijkstra ?", thinking=True)
# Mode search — recherche web locale + inférence
ai("Cours du Bitcoin aujourd'hui ?", use_web=True)
# Mode deep_thinking — pipeline agentique MiroFlow (≤20 tours, ~3-10 min)
result = ai.deep_thinking("Analyse l'impact de GPT-4 sur le marché de l'emploi.")
print(result["answer"])
# Mode ultra_deep_thinking — recherche massive multi-axes (~20-120 min)
result = ai.ultra_deep_thinking(
"Analyse complète de l'impact de l'IA sur l'économie mondiale.",
preset="deep" # "fast" | "deep" | "ultra"
)
print(result["answer"])
print(result["run_stats"]) # axes, gaps, sources, chars...
| Mode | Durée | Recherches | Cas d'usage |
|---|---|---|---|
| simple | <1 min | 0 | Questions factuelles, discussions |
| thinking | <1 min | 0 | Raisonnement, maths, code |
| search | ~1 min | 3-5 | Actualités, données récentes |
| deep_thinking | 3-10 min | 20-60 | Recherche complexe, analyse approfondie |
| ultra_deep_thinking | 20-120 min | 50-400+ | Études exhaustives, rapports complets, sujets complexes |
Mémoire sémantique
La mémoire persiste entre les conversations via LanceDB embarqué. Chaque échange est stocké sous forme de vecteur ; lors des prochains appels, les faits les plus pertinents sont injectés automatiquement dans le contexte.
from clovis import cloooooo
ai = cloooooo()
# Activer la mémoire pour un ID de conversation
reponse = ai(
"Mon nom est Clovis, je travaille sur un moteur HFT.",
conversation_id="session-1",
use_memory=True
)
# Lors du prochain appel, la mémoire est réinjectée
reponse = ai(
"Rappelle-moi sur quoi je travaille.",
conversation_id="session-1",
use_memory=True
)
# → "Tu travailles sur un moteur HFT..."
# Accès direct à la mémoire
faits = ai.memory.search("HFT", top_k=5)
ai.memory.clear(conversation_id="session-1")
RAG — Retrieval-Augmented Generation
Indexez vos propres documents (PDF, DOCX, TXT, Markdown) et interrogez-les avec une recherche hybride dense + BM25, puis reranking bge-reranker pour la précision.
from clovis import cloooooo
ai = cloooooo()
# Ingérer un fichier
n = ai.ingest("/home/user/docs/these.pdf")
print(f"{n} chunks indexés")
# Ingérer un répertoire entier
n = ai.rag_pipeline.ingest_dir("/home/user/papers/")
# Poser une question sur les documents indexés
reponse = ai.rag("Quelle méthodologie est utilisée dans le chapitre 3 ?")
print(reponse)
# Recherche sans synthèse LLM (accès aux chunks bruts)
chunks = ai.rag_pipeline.search(
"mécanisme d'attention",
top_k=5,
rerank=True
)
for chunk in chunks:
print(chunk["text"][:200], chunk["source"])
# Lister les sources indexées
sources = ai.rag_pipeline.list_sources()
print(sources) # ["these.pdf", "notes.md", ...]
Le pipeline RAG utilise nomic-embed-text-v1.5 (768d, ONNX CPU) pour les embeddings et bge-reranker-v2-m3 pour le reranking. Les chunks font environ 400 tokens avec overlap.
Appel d'outils
Le registre d'outils inclut exécution Python, shell, I/O fichiers et recherche web. L'exécution de code se fait dans un sous-processus avec timeout.
from clovis import cloooooo
ai = cloooooo()
# Lister les outils disponibles
outils = ai.tool_registry.get_schemas()
print([o["name"] for o in outils])
# ['python_exec', 'shell_exec', 'read_file', 'write_file', 'web_search', 'fetch_page']
# Exécuter un outil
result = ai.tool_registry.execute("python_exec", {
"code": "import math; print(math.factorial(10))"
})
print(result.output) # "3628800"
print(result.success) # True
print(result.execution_time_ms)
# Recherche web via outil
result = ai.tool_registry.execute("web_search", {"query": "Python 3.14 release date"})
print(result.output)
Routeur intelligent
Le routeur classifie automatiquement chaque requête en sous-milliseconde
et sélectionne le pipeline optimal. Utilisez ai.router directement
pour contrôler le routage.
from clovis import cloooooo
ai = cloooooo()
# Classifier une requête sans l'exécuter
decision = ai.router.classify("Implémente un algorithme de tri rapide.")
print(decision.task_type) # "code"
print(decision.confidence) # 0.97
# Router et exécuter
reponse = ai.router.route("Explique la complexité de l'algorithme A*.")
# → détecte "reasoning", active thinking=True automatiquement
Types de tâches détectés
| Type | Déclencheurs | Comportement |
|---|---|---|
| code | implémenter, écrire, déboguer, fonction, classe… | SGLang avec prompt système code |
| reasoning | expressions math, expliquer, analyser, pourquoi, historique… | SGLang avec thinking activé |
| search | dernier, actuel, actualité, prix, aujourd'hui… | Recherche SearXNG + inférence |
| structured | json, extraire, parser, schéma, format… | Mode JSON forcé |
| vision | image, photo fournie | Pipeline vision |
| simple | salutations, requêtes courtes | Inférence directe rapide |
Sorties structurées
Forcez une sortie JSON typée via le mode JSON SGLang + validation Pydantic v2. La conformité au schéma est garantie avec retry automatique.
from clovis import cloooooo
from clovis._structured import extract, plan, score_response
from clovis._structured import ExtractionResult, Plan, EvalScore
ai = cloooooo()
# Schéma JSON arbitraire
resultat = ai.structured(
"Apple Inc. fondée par Steve Jobs à Cupertino en 1976.",
schema={
"type": "object",
"properties": {
"entreprise": {"type": "string"},
"fondateur": {"type": "string"},
"annee": {"type": "integer"}
},
"required": ["entreprise", "fondateur", "annee"]
}
)
# → {"entreprise": "Apple Inc.", "fondateur": "Steve Jobs", "annee": 1976}
# Extraction d'entités et relations (schéma pré-défini)
res: ExtractionResult = extract(
"Marie Curie a reçu le Prix Nobel de Physique en 1903."
)
print(res.entities) # [Entity(name="Marie Curie", type="person"), ...]
print(res.relations)
# Génération de plan actionnable
p: Plan = plan("Construire un système RAG pour des documents médicaux")
for step in p.steps:
print(step.action, "→", step.expected_output)
# LLM-as-judge (évaluation de réponse)
score: EvalScore = score_response(
question="Quelle est la capitale de la France ?",
answer="Paris",
expected="Paris"
)
print(score.score, score.reasoning)
Vision
Compréhension d'images via Qwen2.5-VL-3B-Instruct (CPU, chargement paresseux ~30s au premier appel).
from clovis._vision import describe
# À partir d'une URL
texte = describe("https://example.com/graphique.png", prompt="Extrais les données de ce graphique.")
# À partir d'un fichier local
texte = describe("/home/user/screenshot.png")
# Via le SDK principal
reponse = ai.vision("/home/user/chart.png", prompt="Résume ce graphique.")
print(reponse)
Formats acceptés : URL HTTP/HTTPS, chemin absolu, image encodée en base64.
Embeddings & Reranking
Vecteurs 768d via nomic-embed-text-v1.5 (ONNX CPU, chargement paresseux).
from clovis._embed import embed, rerank
# Embeddings
vecteurs = embed(
["Bonjour le monde", "Hello world"],
prefix="search_query" # "search_document" pour les passages
)
print(len(vecteurs[0])) # 768
# Reranking
resultats = rerank(
query="mécanisme d'attention transformer",
documents=["L'auto-attention permet...", "Les CNN utilisent des filtres...", "Les transformeurs remplacent les RNN..."],
top_k=2
)
for score, doc, idx in resultats:
print(f"[{score:.3f}] {doc[:60]}")
MiroFlow — Orchestration agentique
Le moteur de recherche agentique profond. Qwen3-32B planifie, recherche, lit des pages et synthétise — avec appel d'outils complet orchestré par MiroFlow. Jusqu'à 20 tours agentiques par requête.
google_search passe par le bridge SearXNG local →
votre instance SearXNG → vrais résultats web. scrape_website utilise Trafilatura.
Zéro appel API externe, zéro clé API requise.
Pipeline
Requête utilisateur
→ Orchestrateur MiroFlow
→ Qwen3-32B planifie les recherches
→ Appels outils parallèles (google_search, wiki, scrape_website)
→ Résultats injectés dans le contexte
→ Nouveau tour si des lacunes détectées
→ Synthèse finale (jusqu'à 20 tours)
Outils disponibles
| Outil | Serveur MCP | Description |
|---|---|---|
| google_search | tool-searching | Recherche web via bridge SearXNG. Retourne titre, lien, extrait, questions associées. |
| wiki_get_page_content | tool-searching | Contenu complet d'une page Wikipedia avec résumé structuré. |
| search_wiki_revision | tool-searching | Historique de révision Wikipedia pour un mois donné. |
| search_archived_webpage | tool-searching | Récupération d'archive Wayback Machine. |
| scrape_website | tool-searching | Texte complet d'une page via Trafilatura (bridge Jina local). |
| read_file | tool-reading | Lecture de fichiers locaux. |
Mode deep_thinking
Pipeline MiroFlow complet avec intégration mémoire. Recommandé pour les tâches de recherche complexes nécessitant plusieurs sources et une synthèse longue.
from clovis import cloooooo
ai = cloooooo()
result = ai.deep_thinking(
"Quelles ont été les conséquences économiques de la crise COVID-19 en France ?",
conversation_id="recherche-covid",
use_memory=True,
use_web=True,
)
print(result["answer"]) # Réponse complète structurée
print(result["sources"]) # URLs trouvées
print(result["model_used"]) # "miroflow:Qwen/Qwen3-32B-AWQ"
print(result["fallback_used"]) # False si MiroFlow a réussi
print(result["memory_updated"]) # True si mémoire mise à jour
print(result["run_id"]) # ID unique de la session MiroFlow
Réponse
| Champ | Type | Description |
|---|---|---|
| answer | str | Réponse complète synthétisée, en Markdown. |
| sources | list[str] | URLs trouvées et consultées par l'agent. |
| model_used | str | Modèle utilisé, ex : miroflow:Qwen/Qwen3-32B-AWQ. |
| fallback_used | bool | True si MiroFlow a échoué et le pipeline interne a pris le relais. |
| memory_updated | bool | True si la mémoire a été mise à jour après la réponse. |
| run_id | str | Identifiant unique de la session MiroFlow (log JSON disponible dans MiroFlow/runs/). |
| error | str | None | Message d'erreur si le fallback a été déclenché. |
Pipeline deep_think
Pipeline de recherche itératif interne. Plus rapide que deep_thinking,
sans mémoire persistante. Idéal pour les questions ponctuelles nécessitant plusieurs
sources mais pas de suivi de conversation.
from clovis._deep_think import deep_think
reponse = deep_think(
"Comment fonctionne RLHF pour l'alignement des LLM ?",
max_iterations=4,
searches_per_step=3,
)
print(reponse)
from clovis._deep_think import deep_think_stream
for chunk in deep_think_stream(
"Analyse des stratégies de trading algorithmique en 2026.",
max_iterations=4,
searches_per_step=3,
):
print(chunk, end="", flush=True)
# Les mises à jour de progression s'affichent en temps réel
Boucle interne
Chaque itération : planifier des requêtes → recherche parallèle SearXNG →
extraire les informations clés → réfléchir aux lacunes → répéter si nécessaire.
La synthèse finale utilise thinking=True pour un raisonnement approfondi.
Les citations sont automatiquement incluses dans la réponse.
Ultra Deep Thinking
Le mode de recherche le plus puissant. Qwen3-32B décompose la question en axes indépendants, lance des recherches profondes en parallèle sur chacun, identifie les lacunes et les comble en plusieurs rounds, puis synthétise tout en une analyse exhaustive.
1. Décomposition → LLM découpe en N axes (ex: historique, technique, économique, comparatif...)
2. Recherche // → deep_think() lancé en parallèle sur chaque axe (semaphore GPU)
chaque axe = jusqu'à 6 itérations × 5 recherches web = ~30 recherches/axe
3. Analyse gaps → LLM identifie ce qui manque dans l'ensemble des axes
4. Comblement → deep_think() ciblé sur chaque lacune identifiée
5. Répéter 3→4 → jusqu'à N rounds de lacunes
6. Synthèse → contexte agrégé (120k chars max) + thinking=True → réponse définitive
Presets
| Preset | Axes | Depth/axe | Gap rounds | Recherches/step | Durée estimée | Total recherches |
|---|---|---|---|---|---|---|
| fast | 4 | 3 | 1 | 3 | 5-10 min | ~50 |
| deep | 8 | 4 | 3 | 4 | 20-40 min | ~200 |
| ultra | 12 | 6 | 5 | 5 | 60-120 min | 400+ |
from clovis import cloooooo
ai = cloooooo()
# Preset "deep" — 8 axes, 3 rounds de lacunes
result = ai.ultra_deep_thinking(
"Quel est l'impact de l'intelligence artificielle sur le marché du travail ?",
preset="deep",
)
# Contrôle fin des paramètres
result = ai.ultra_deep_thinking(
"Histoire complète de la cryptographie",
preset="ultra",
max_axes=10, # override le preset
depth_per_axis=5,
gap_rounds=4,
searches_per_step=4,
)
print(result["answer"])
print(f"Sources : {len(result['sources'])}")
print(f"Axes : {result['axes_count']}")
print(f"Rounds de lacunes : {result['gap_rounds_done']}")
print(result["run_stats"])
curl -s -X POST http://cloooooo.com/ultra_deep_thinking \
-H "Content-Type: application/json" \
-d '{
"prompt": "Analyse complète des stratégies de trading algorithmique en 2026",
"preset": "deep",
"stream": true
}'
# Affiche les événements de progression puis la réponse finale :
# [décomposition] Génération de 8 axes de recherche...
# [axe:Stratégies HFT] recherche en cours...
# [axe:Market Making] recherche en cours...
# ...
# [lacunes round 1] 5 lacunes identifiées...
# [synthèse] 12 sections, 180k chars...
#
# ===RÉPONSE===
# ## Analyse complète des stratégies de trading algorithmique...
Réponse
| Champ | Type | Description |
|---|---|---|
| answer | str | Synthèse finale exhaustive, structurée en Markdown avec références. |
| sources | list[str] | Toutes les URLs collectées (jusqu'à 100 uniques). |
| axes_count | int | Nombre d'axes de recherche réussis. |
| gap_rounds_done | int | Rounds de lacunes effectués (peut être < max si aucune lacune détectée). |
| total_chars | int | Volume total de recherche brute collectée. |
| run_stats | dict | Statistiques détaillées : axes, depth, searches, sections, sources uniques. |
stream=true pour voir la progression en temps réel.
Sans streaming, l'appel peut prendre plusieurs dizaines de minutes sans retour intermédiaire.
API HTTP
Le SDK Python est la méthode recommandée. L'API HTTP est exposée au port 8000
et accessible via http://cloooooo.com ou http://localhost:8000.
Endpoint universel. Supporte tous les modes.
curl -s -X POST http://cloooooo.com/ia \
-H "Content-Type: application/json" \
-d '{"prompt": "Explique les transformeurs.", "mode": "deep_thinking"}'
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
| prompt | string | requis | La requête. |
| mode | string | null | null = simple, "deep_thinking" = MiroFlow agentique. |
| thinking | bool | false | Active le chain-of-thought étendu. |
| use_web | bool | false | Recherche web SearXNG en contexte. |
| use_memory | bool | false | Injecte la mémoire sémantique. |
| conversation_id | string | null | ID pour la persistance mémoire. |
| stream | bool | false | Stream la réponse en texte brut. |
Autres endpoints HTTP
curl -X POST http://cloooooo.com/rag/ingest \
-H "Content-Type: application/json" \
-d '{"path": "/home/user/these.pdf"}'
# → {"chunks": 47, "source": "/home/user/these.pdf"}curl -X POST http://cloooooo.com/rag/ask \
-H "Content-Type: application/json" \
-d '{"question": "Quelle méthodologie ?", "top_k": 5}'curl -X POST http://cloooooo.com/embed \
-H "Content-Type: application/json" \
-d '{"texts": ["Bonjour le monde"], "prefix": "search_query"}'
# → {"embeddings": [[...]], "model": "nomic-embed-text-v1.5", "dim": 768}Pipeline MiroFlow complet avec mémoire.
curl -X POST http://cloooooo.com/deep_thinking \
-H "Content-Type: application/json" \
-d '{"prompt": "Analyse la bulle dotcom.", "conversation_id": "recherche-1"}'Pipeline itératif interne, sans mémoire persistante.
curl -X POST http://cloooooo.com/deep_think \
-H "Content-Type: application/json" \
-d '{"prompt": "Exlique le RLHF.", "stream": true}'curl -X POST http://cloooooo.com/route \
-H "Content-Type: application/json" \
-d '{"prompt": "Implémente une recherche binaire."}'
# → {"response": "...", "task_type": "code", "confidence": 0.97}GET /health
{
"status": "ok",
"sglang": "ok",
"model": "Qwen/Qwen3-32B-AWQ",
"version": "0.5.10",
"search": {
"searxng": {"status": "ok", "results": 10},
"trafilatura": "ok"
}
}Modèles & matériel
| Composant | Valeur |
|---|---|
| Moteur d'inférence | SGLang 0.5.9 — API OpenAI-compatible, port 61005 |
| LLM principal | Qwen3-32B-AWQ (quantification 4 bits) |
| GPU | RTX 3090 24 Go VRAM (SM86) |
| Cache KV max | 13 661 tokens (fp16) |
| Modèle d'embedding | nomic-embed-text-v1.5 (768d, ONNX CPU) |
| Reranker | bge-reranker-v2-m3 (ONNX CPU) |
| Modèle vision | Qwen2.5-VL-3B-Instruct (CPU, chargement paresseux) |
| Stockage vectoriel | LanceDB v0.33 (embarqué, fichiers locaux) |
| Recherche web | SearXNG sur le port 8888 + fallback DuckDuckGo |
Bridges de recherche locale
Deux endpoints de bridge traduisent les formats d'API payants vers les services locaux. Ils permettent aux outils MiroFlow de fonctionner sans abonnement Serper ou Jina.
Accepte le format API Serper, interroge SearXNG local, retourne JSON format Serper.
curl -X POST http://localhost:8000/serper-miro-bridge/search \
-H "Content-Type: application/json" \
-d '{"q": "Python 3.14 features", "num": 5}'Accepte le format lecteur Jina (URL en chemin), extrait avec Trafilatura, retourne Markdown.
curl http://localhost:8000/jina-miro-bridge/https://python.orgMiroFlow/.env —
SERPER_BASE_URL=http://localhost:8000/serper-miro-bridge et
JINA_BASE_URL=http://localhost:8000/jina-miro-bridge.
Aucune clé API n'est nécessaire.