Implémenter les Citations en Python
Le pipeline complet de citations
Dans cette leçon, vous allez implémenter un pipeline RAG avec citations de bout en bout. Vous verrez comment configurer les outils de référence, envoyer les sources au modèle, et parser la réponse pour extraire les citations structurées.
Étape 1 : Initialiser le client et les messages
from mistralai import Mistral
import json
client = Mistral(api_key="votre-clé-api")
# Message système qui encourage les citations
system_message = {
"role": "system",
"content": (
"Vous êtes un assistant documentaire. "
"Répondez aux questions en vous appuyant sur les sources fournies. "
"Citez systématiquement vos sources. "
"Si l'information ne figure dans aucune source, dites-le explicitement."
)
}
user_message = {
"role": "user",
"content": "Quelles sont les bonnes pratiques pour déployer un LLM en production ?"
}
messages = [system_message, user_message]
Étape 2 : Définir l’outil de référence
reference_tool = {
"type": "function",
"function": {
"name": "search_documentation",
"description": "Recherche dans la base documentaire",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Requête de recherche"
}
},
"required": ["query"]
}
}
}
# Premier appel : le modèle demande à utiliser l'outil
response = client.chat.complete(
model="mistral-large-latest",
messages=messages,
tools=[reference_tool]
)
Étape 3 : Fournir les résultats avec les références
Quand le modèle demande l’exécution de l’outil, vous fournissez les résultats via un ToolMessage contenant les Reference Objects :
from mistralai.models import ToolMessage
# Simuler les résultats de recherche documentaire
tool_results = {
"content": "Voici les sources trouvées.",
"references": [
{
"type": "reference",
"reference_id": "ref-001",
"url": "https://docs.example.com/deployment-guide",
"title": "Guide de déploiement LLM",
"snippets": [
"Toujours configurer des rate limits pour protéger le service.",
"Monitorer la latence P99 et le taux d'erreur en continu."
]
},
{
"type": "reference",
"reference_id": "ref-002",
"url": "https://docs.example.com/security",
"title": "Sécurité des applications IA",
"snippets": [
"Filtrer les entrées utilisateur pour prévenir les injections.",
"Ne jamais exposer les clés API côté client."
]
},
{
"type": "reference",
"reference_id": "ref-003",
"url": "https://docs.example.com/scaling",
"title": "Scalabilité et performance",
"snippets": [
"Utiliser le caching sémantique pour réduire les appels API.",
"Dimensionner les instances selon le trafic de pointe."
]
}
]
}
# Ajouter le tool call et la réponse à l'historique
tool_call = response.choices[0].message.tool_calls[0]
messages.append(response.choices[0].message)
messages.append(
ToolMessage(
tool_call_id=tool_call.id,
name="search_documentation",
content=json.dumps(tool_results, ensure_ascii=False)
)
)
Étape 4 : Obtenir la réponse citée
# Deuxième appel : le modèle génère une réponse avec citations
final_response = client.chat.complete(
model="mistral-large-latest",
messages=messages
)
Étape 5 : Parser les citations
La réponse du modèle contient un mélange de texte et de références. Vous les séparez avec les classes TextChunk et ReferenceChunk :
from mistralai.models import TextChunk, ReferenceChunk
def parse_cited_response(response):
"""Extrait le texte et les références d'une réponse citée."""
content_parts = response.choices[0].message.content
text_parts = []
cited_refs = set()
for chunk in content_parts:
if isinstance(chunk, TextChunk):
text_parts.append(chunk.text)
elif isinstance(chunk, ReferenceChunk):
for ref_id in chunk.reference_ids:
cited_refs.add(ref_id)
return {
"text": "".join(text_parts),
"references_used": list(cited_refs)
}
result = parse_cited_response(final_response)
print("=== Réponse ===")
print(result["text"])
print("\n=== Sources citées ===")
for ref_id in result["references_used"]:
print(f" - {ref_id}")
Afficher les citations dans une interface
Pour votre application frontend, structurez les citations de manière exploitable :
def format_for_frontend(response, reference_map):
"""Formate la réponse avec citations pour le frontend."""
content_parts = response.choices[0].message.content
formatted = []
for chunk in content_parts:
if isinstance(chunk, TextChunk):
formatted.append({
"type": "text",
"content": chunk.text
})
elif isinstance(chunk, ReferenceChunk):
refs = []
for ref_id in chunk.reference_ids:
if ref_id in reference_map:
refs.append({
"id": ref_id,
"title": reference_map[ref_id]["title"],
"url": reference_map[ref_id]["url"]
})
formatted.append({
"type": "citation",
"references": refs
})
return formatted
Ce format permet à votre frontend d’afficher des liens cliquables vers les sources, des tooltips avec les titres, ou des numéros de citation interactifs.
Points clés à retenir
- Le pipeline suit un flux en deux appels : tool call puis réponse citée
- Les références sont passées via
ToolMessageavec les Reference Objects - La réponse contient un mix de
TextChunketReferenceChunkà parser - Structurez la sortie pour que votre frontend puisse afficher des citations interactives
- Testez avec 3-5 sources pour valider le comportement avant de passer en production