Créer une application RAG avec aqoon
La génération augmentée par récupération (RAG) est un modèle dans lequel vous récupérez du contenu pertinent depuis une base de connaissances, puis le transmettez comme contexte à un modèle de langage. Le résultat est une réponse IA fondée sur vos propres documents plutôt que sur des données d'entraînement générales.
aqoon est idéal pour la couche de récupération : il stocke, traite et indexe vos documents, et expose une API de recherche unique qui effectue une recherche hybride sémantique et par mots-clés. Votre application appelle le point d'accès de recherche, récupère les meilleurs résultats et les inclut dans le prompt que vous envoyez au LLM.
Prérequis
- An aqoon account with at least one collection containing documents
- Une clé API limitée avec accès accordé à la collection cible — voir Clés API et limites de débit
- Python 3.8+ (les exemples ci-dessous utilisent la bibliothèque standard plus deux paquets)
- Une clé API Anthropic ou OpenAI pour l'étape LLM
Étape 1 : Installer les dépendances
pip install requests anthropic
Si vous préférez OpenAI, remplacez anthropic par openai — le modèle est identique.
Étape 2 : Rechercher dans aqoon le contexte pertinent
Appelez le point d'accès de recherche avec votre requête. aqoon renvoie des résultats classés — chaque résultat contient le texte du passage (content), le titre du document (title) et un score de similarité.
import requests
AQOON_URL = "https://your-instance"
AQOON_API_KEY = "aqn_your_api_key"
def search_aqoon(query: str, limit: int = 5) -> list[dict]:
"""Search aqoon and return a list of result chunks."""
response = requests.post(
f"{AQOON_URL}/api/search/",
headers={
"Authorization": f"Bearer {AQOON_API_KEY}",
"Content-Type": "application/json",
},
json={"query": query, "limit": limit},
timeout=10,
)
response.raise_for_status()
return response.json().get("results", [])
Chaque résultat de la liste ressemble à ceci :
{
"content": "Retrieval-Augmented Generation (RAG) combines...",
"title": "AI Architecture Patterns.pdf",
"document_id": "a1b2c3d4-...",
"collection_name": "Research",
"score": 0.91
}
Étape 3 : Construire le prompt avec le contexte récupéré
Formatez les résultats de recherche comme contexte et insérez-les dans un prompt pour le LLM.
def build_prompt(query: str, chunks: list[dict]) -> str:
"""Combine retrieved chunks into a prompt."""
if not chunks:
return (
f"The user asked: {query}\n\n"
"No relevant documents were found in the knowledge base. "
"Answer based on your general knowledge and note the absence of specific context."
)
context_parts = []
for i, chunk in enumerate(chunks, start=1):
context_parts.append(
f"[Source {i}: {chunk['title']}]\n{chunk['content']}"
)
context = "\n\n---\n\n".join(context_parts)
return (
f"Use the following excerpts from the knowledge base to answer the question. "
f"Cite sources by number where relevant.\n\n"
f"{context}\n\n"
f"Question: {query}"
)
Étape 4 : Envoyer au LLM
Transmettez le prompt à Claude en utilisant le SDK Anthropic :
import anthropic
ANTHROPIC_API_KEY = "sk-ant-your-key"
def ask_claude(prompt: str) -> str:
"""Send a prompt to Claude and return the response text."""
client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY)
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
return message.content[0].text
Étape 5 : Exemple complet fonctionnel
Le tout assemblé :
import requests
import anthropic
AQOON_URL = "https://your-instance"
AQOON_API_KEY = "aqn_your_api_key"
ANTHROPIC_API_KEY = "sk-ant-your-key"
def search_aqoon(query: str, limit: int = 5) -> list[dict]:
response = requests.post(
f"{AQOON_URL}/api/search/",
headers={
"Authorization": f"Bearer {AQOON_API_KEY}",
"Content-Type": "application/json",
},
json={"query": query, "limit": limit},
timeout=10,
)
response.raise_for_status()
return response.json().get("results", [])
def build_prompt(query: str, chunks: list[dict]) -> str:
if not chunks:
return (
f"The user asked: {query}\n\n"
"No relevant documents were found. Answer based on general knowledge."
)
context_parts = [
f"[Source {i}: {c['title']}]\n{c['content']}"
for i, c in enumerate(chunks, start=1)
]
context = "\n\n---\n\n".join(context_parts)
return (
f"Use the following knowledge base excerpts to answer the question. "
f"Cite sources by number.\n\n{context}\n\nQuestion: {query}"
)
def rag_query(query: str) -> str:
chunks = search_aqoon(query, limit=5)
prompt = build_prompt(query, chunks)
client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY)
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
return message.content[0].text
if __name__ == "__main__":
answer = rag_query("What is our policy on data retention?")
print(answer)
Conseils
- Choisissez la bonne portée. Utilisez une clé API limitée et n'accordez que les collections pertinentes pour votre application. Cela empêche le LLM de recevoir du contexte provenant de documents non liés.
- Ajustez la limite de résultats. Plus de résultats donnent plus de contexte au modèle mais augmentent l'utilisation de tokens et le coût. Cinq à dix résultats est un bon point de départ ; ajustez en fonction de la longueur typique de vos documents et de la spécificité des requêtes.
- Gérez l'absence de résultats avec élégance. La fonction
build_promptci-dessus montre une approche : indiquer au modèle qu'aucun contexte n'a été trouvé et le laisser répondre à partir de ses connaissances générales ou refuser de répondre, selon votre cas d'utilisation. - Filtrez par collection. Si vos requêtes sont toujours limitées à un domaine, passez
"collection": "votre-slug-de-collection"dans le corps de la requête de recherche pour limiter les résultats à cette collection et améliorer la pertinence. - Mettez en cache les requêtes fréquentes. Les résultats de recherche aqoon sont déterministes pour un ensemble de documents donné. Envisagez de mettre en cache les résultats des requêtes courantes dans Redis pour réduire les appels API et la latence.
Bonus : Exemple JavaScript / Node.js
import Anthropic from "@anthropic-ai/sdk";
const AQOON_URL = "https://your-instance";
const AQOON_API_KEY = "aqn_your_api_key";
const ANTHROPIC_API_KEY = "sk-ant-your-key";
async function searchAqoon(query, limit = 5) {
const response = await fetch(`${AQOON_URL}/api/search/`, {
method: "POST",
headers: {
Authorization: `Bearer ${AQOON_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ query, limit }),
});
if (!response.ok) {
throw new Error(`aqoon search failed: ${response.status}`);
}
const data = await response.json();
return data.results ?? [];
}
function buildPrompt(query, chunks) {
if (chunks.length === 0) {
return `The user asked: ${query}\n\nNo relevant documents found.`;
}
const context = chunks
.map((c, i) => `[Source ${i + 1}: ${c.title}]\n${c.content}`)
.join("\n\n---\n\n");
return (
`Use the following knowledge base excerpts to answer the question. ` +
`Cite sources by number.\n\n${context}\n\nQuestion: ${query}`
);
}
async function ragQuery(query) {
const chunks = await searchAqoon(query);
const prompt = buildPrompt(query, chunks);
const client = new Anthropic({ apiKey: ANTHROPIC_API_KEY });
const message = await client.messages.create({
model: "claude-opus-4-5",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }],
});
return message.content[0].text;
}
const answer = await ragQuery("What is our refund policy?");
console.log(answer);