Agent de recherche LangGraph avec récupération via LlamaIndex et codage HITL
Le découpage en fonction du format, l’acheminement structuré des intentions, les récupérateurs spécialisés en parallèle et la programmation d’interface ligne de commande contrôlée par des interruptions permettent de transformer les documents en expériences exécutables de manière sécurisée.
Transformer des articles académiques en expériences fonctionnelles consiste généralement en un processus lent comprenant la lecture, la synthèse, le codage et la débogage. Un système multi-agents à état peut assumer une plus grande partie de cette charge : LangGraph pour le routage, LlamaIndex pour la recherche spécialisée, ainsi qu’un outil de codage en ligne de commande soumis à l’approbation humaine.
1. Ingestion intelligente des données : tous les fragments ne sont pas égaux
Découper aveuglément des PDF, du Python et des CSV selon une seule stratégie nuit à la qualité de la recherche. Avant d’indexer dans ChromaDB, procédez à un découpage adapté au format : segments narratifs pour le texte prosaïque, blocs logiques pour le code, et tronçons tenant compte des lignes pour les tableaux :
# 5. Setup Chunkers
pdf_chunker = SentenceSplitter(chunk_size=512, chunk_overlap=50)
python_chunker = CodeSplitter(language='python')
csv_reader = CSVReader(concat_rows=False)
# 6. Route and Chunk Data
for doc in documents:
file_name = doc.metadata.get("file_name", "")
if file_name.endswith(".pdf"):
nodes = pdf_chunker.get_nodes_from_documents([doc])
elif file_name.endswith(".py"):
nodes = python_chunker.get_nodes_from_documents([doc])
elif file_name.endswith(".csv"):
# CSVs are chunked row-by-row by our custom reader
all_nodes.append(doc)
Les embeddings (par exemple all-minilm d’Ollama) reflètent alors la structure plutôt que des fenêtres de caractères arbitraires.
2. Le cerveau LangGraph : classification des intentions
LangChain fournit des modèles, des prompts et des outils ; LangGraph gère le flux de contrôle. Un dictionnaire State partagé permet de parcourir chaque nœud. Le routage par mots-clés en texte libre est fragile, c’est pourquoi des sorties structurées via Pydantic imposent une intention Literal provenant d’un modèle local tel que llama3.2:3b:
class IntentClassifier(BaseModel):
message_intent: Literal['chat', 'code', 'knowledge'] = Field(
...,
description="Classify the user intent. 'code' for implementation, 'knowledge' for research details, 'chat' for general tasks."
)
Les arêtes conditionnelles permettent ensuite d’envoyer les données de manière fiable, sans avoir à parser du charabia.
3. Le chemin de la connaissance : récupération parallèle
Les questions de recherche complexes ne correspondent rarement à une seule recherche par similarité. On peut étendre le chemin de la connaissance à quatre agents LlamaIndex en même temps — abstract_agent, methodology_agent, limitations_agent et conclusion_agent — chacun avec une requête ciblée. Les résultats partiels sont fusionnés à l’aide du réducteur operator.add de LangGraph afin que les auteurs ne se contredisent pas :
class State(TypedDict):
messages: Annotated[list, add_messages]
message_intent: str | None
next_node: str | None
context: Annotated[list[str], operator.add] # Safely appends parallel findings
analyst_agent lit le contexte combiné et synthétise les avantages, inconvénients et lacunes.
4. Relier la recherche à l’action : codage avec intervention humaine
interrupt() pour demander une approbation :
def accept_coding(state: State):
user_prompt = state['messages'][-1].content
decision = interrupt(f'About to run Claude Code with request:\n\n{user_prompt}\n\nApprove? (yes/no, or type a revised request)')
text = str(decision).strip().lower()
if text in ['y', 'yes', 'approve', 'ok']:
return {'next_node': 'coding_agent'}
if text in ['n', 'no', 'deny', 'cancel']:
return {'messages': [{'role': 'assistant', 'content': 'Coding request denied.'}], 'next_node': 'denied'}
# Allows the user to dynamically edit the prompt mid-flight
return {'messages': [{'role': 'user', 'content': text}], 'next_node': 'accept_coding'}
Conclusion
Leçons opérationnelles
- Un découpage adapté au format se révèle utile dès que la récupération de code cesse de renvoyer des fonctions incomplètes.
Le graphe représente le produit final : les nœuds sont remplaçables, mais c’est le contrat de l’état ainsi que les mécanismes d’approbation qui rendent le processus de transformation de la recherche en code suffisamment sûr pour être exécuté quotidiennement.
Démarche de bout en bout
- Ingérez les documents et les notebooks à l’aide du séparateur adapté au format ; reconstruisez la collection Chroma lorsque les sources changent.
- Classifiez l’énoncé de l’utilisateur en catégorie Connaissances ou Programmation (ou selon des catégories plus fines à mesure que le produit évolue).
operator.add, puis on les synthétise via l’analyste.Ce cycle suffit pour remplacer une pile de cahiers de notes ad hoc par une interface d’agent fiable et durable.