Section 11.5.7 : Intégrer le composant IA (chatbot/agent)
🎯 Objectif pédagogique
Assembler le composant IA central : agent RAG avec function calling, mémoire, et guardrails. Vous serez capable de connecter tous les modules backend en un agent fonctionnel et robuste.
L'assemblage — Connecter toutes les pièces
Marc a chaque composant testé individuellement. Maintenant, il assemble le tout dans agent.py : le cerveau de l'application qui orchestre guardrails, mémoire, RAG, et tools.
agent.py — L'assemblage final
# agent.py — Agent RAG complet
import json
from openai import OpenAI
from config import (
OPENAI_API_KEY, DEFAULT_MODEL, SYSTEM_PROMPT,
MAX_HISTORY_MESSAGES, SUMMARY_THRESHOLD, MAX_TOKENS_RESPONSE
)
from tools import TOOL_DEFINITIONS, TOOL_MAP
from knowledge import KnowledgeBase
client = OpenAI(api_key=OPENAI_API_KEY)
class CareerAgentRAG:
"""Agent IA complet avec RAG, tools, et mémoire."""
def __init__(self, model=None, temperature=0.7, user_profile=None):
self.model = model or DEFAULT_MODEL
self.temperature = temperature
self.user_profile = user_profile or \{\}
self.history = []
self.summary = ""
self.kb = KnowledgeBase()
def _build_system_prompt(self):
"""Construire le system prompt enrichi."""
parts = [SYSTEM_PROMPT]
# Ajouter le profil utilisateur
if self.user_profile:
parts.append("\n## Profil de l'utilisateur :")
for key, value in self.user_profile.items():
if value:
parts.append(f"- \{key\}: \{value\}")
# Ajouter le résumé de conversation
if self.summary:
parts.append(f"\n## Résumé des échanges précédents :\n\{self.summary\}")
return "\n".join(parts)
def _summarize_old_messages(self, messages):
"""Résumer les anciens messages."""
text = "\n".join([
f"\{'User' if m['role']=='user' else 'Bot'\}: \{m['content'][:200]\}"
for m in messages
])
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[\{
"role": "user",
"content": f"Résume en 5 bullet points concis :\n\{text\}"
\}],
max_tokens=300
)
return response.choices[0].message.content
def _manage_memory(self):
"""Gérer la mémoire (résumé si nécessaire)."""
if len(self.history) > SUMMARY_THRESHOLD:
old = self.history[:-MAX_HISTORY_MESSAGES]
self.summary = self._summarize_old_messages(old)
self.history = self.history[-MAX_HISTORY_MESSAGES:]
def chat(self, user_message):
"""Point d'entrée principal."""
self.history.append(\{"role": "user", "content": user_message\})
self._manage_memory()
messages = [
\{"role": "system", "content": self._build_system_prompt()\}
] + self.history
# Boucle agent avec function calling
max_iterations = 5
for _ in range(max_iterations):
response = client.chat.completions.create(
model=self.model,
messages=messages,
tools=TOOL_DEFINITIONS,
tool_choice="auto",
temperature=self.temperature,
max_tokens=MAX_TOKENS_RESPONSE
)
msg = response.choices[0].message
messages.append(msg)
# Pas de tool call → réponse finale
if not msg.tool_calls:
self.history.append(\{"role": "assistant", "content": msg.content\})
return msg.content
# Exécuter les tools
for tc in msg.tool_calls:
func_name = tc.function.name
func_args = json.loads(tc.function.arguments)
if func_name in TOOL_MAP:
result = TOOL_MAP[func_name](**func_args)
else:
result = f"Outil '\{func_name\}' non disponible."
messages.append(\{
"role": "tool",
"tool_call_id": tc.id,
"content": str(result)
\})
# Fallback si max iterations atteint
fallback = "Je n'ai pas pu terminer l'analyse. Peux-tu reformuler ta question ?"
self.history.append(\{"role": "assistant", "content": fallback\})
return fallback
def get_stats(self):
"""Statistiques de l'agent."""
return \{
"history_length": len(self.history),
"has_summary": bool(self.summary),
"model": self.model,
"kb_stats": self.kb.get_stats()
\}
Test d'intégration
# test_integration.py — Vérifier que tout fonctionne ensemble
def test_full_pipeline():
"""Test end-to-end : user question → agent → response."""
agent = CareerAgentRAG(
user_profile=\{"background": "Finance 8 ans", "target": "Data Analyst"\}
)
# Question simple
response1 = agent.chat("Bonjour ! Quelles compétences dois-je apprendre ?")
assert len(response1) > 50, "Réponse trop courte"
assert "Python" in response1 or "SQL" in response1 or "données" in response1
# Question nécessitant RAG
response2 = agent.chat("Quel salaire puis-je espérer ?")
assert len(response2) > 50
# Vérifier la mémoire (devrait se souvenir de la finance)
response3 = agent.chat("Comment valoriser mon expérience précédente ?")
assert "finance" in response3.lower() or "financ" in response3.lower()
print("✅ Tests d'intégration OK")
if __name__ == "__main__":
test_full_pipeline()
L'intégration est la phase la plus critique
Chaque composant peut fonctionner seul mais casser une fois connecté : un format de retour inattendu, un import circulaire, un type incompatible. Testez l'intégration dès que possible — pas la veille du déploiement.
🏋️ Exercice pratique (25 minutes)
- →Implémentez
agent.pyen assemblant tous les modules - →Exécutez
test_integration.py— tout passe ? - →Testez une conversation de 10 messages en terminal
- →Vérifiez que l'agent utilise les bons outils (observez les logs)
Pourquoi limiter le nombre d'itérations de l'agent (max_iterations=5) ?