All guides
IntermediateSelf-pacedFree GuideSection 84/95

Développer le backend et l'API

Practise development foundations: programming, web, APIs, data and AI tools. Work through sections and exercises to build your first projects.

The full lessons for this course are currently available in French. Use the section menu to navigate the French course.

💡

Free content, available without an account. Tools and models change: use the current model guide to check their versions. Models and sources

Section 11.5.6 : Développer le backend et l'API

🎯 Objectif pédagogique

Structurer le backend de l'application IA : modulariser le code, créer une couche API propre, gérer la configuration et les erreurs. Vous serez capable d'organiser le code backend d'un projet IA de manière professionnelle.


Du script au backend structuré

Marc a du code qui fonctionne. Mais tout est mélangé. Un backend professionnel est modulaire : chaque fichier a une responsabilité claire, les données circulent proprement, et les erreurs sont gérées.

Loading diagram…

config.py — Le cerveau de la configuration

# config.py — Configuration centralisée

import os
from dotenv import load_dotenv

load_dotenv()

# API Keys
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
ANTHROPIC_API_KEY = os.environ.get("ANTHROPIC_API_KEY")

# Modèles
DEFAULT_MODEL = "gpt-4o-mini"
PREMIUM_MODEL = "gpt-4o"
EMBEDDING_MODEL = "text-embedding-3-small"

# Limites
MAX_INPUT_LENGTH = 5000
MAX_HISTORY_MESSAGES = 20
SUMMARY_THRESHOLD = 15
MAX_TOKENS_RESPONSE = 1000

# ChromaDB
CHROMA_DB_PATH = "./data/chroma_db"
KNOWLEDGE_COLLECTION = "career_knowledge"

# System Prompt
SYSTEM_PROMPT = """Tu es CareerBot Pro, un assistant expert en reconversion tech/data/IA.

## Personnalité
- Ton : professionnel, chaleureux, encourageant
- Tu tutoies l'utilisateur
- Direct, concret, orienté action

## Compétences
- Analyse de profils et offres d'emploi
- Conseil en formation et montée en compétences
- Préparation aux entretiens
- Données marché (salaires, tendances)

## Règles
- Base tes réponses sur la base de connaissances quand disponible
- Cite tes sources quand tu utilises la base
- Limite tes réponses à 300 mots max
- Termine par une question ou suggestion d'action
- NE JAMAIS inventer d'offres d'emploi
- NE JAMAIS donner de conseil juridique ou médical
"""

# App Config
APP_CONFIG = \{
    "title": "CareerBot Pro — Assistant Reconversion Tech",
    "icon": "🤖",
    "theme_color": "#0891B2",
\}

knowledge.py — Gestion de la base de connaissances

# knowledge.py — Indexation et recherche

import chromadb
from config import CHROMA_DB_PATH, KNOWLEDGE_COLLECTION
from pathlib import Path

class KnowledgeBase:
    """Gestion de la base de connaissances vectorielle."""
    
    def __init__(self):
        self.client = chromadb.PersistentClient(path=CHROMA_DB_PATH)
        self.collection = self.client.get_or_create_collection(
            name=KNOWLEDGE_COLLECTION,
            metadata=\{"hnsw:space": "cosine"\}
        )
    
    def index_directory(self, directory="data/knowledge"):
        """Indexer tous les fichiers .txt d'un dossier."""
        knowledge_dir = Path(directory)
        if not knowledge_dir.exists():
            print(f"Dossier \{directory\} non trouvé.")
            return
        
        all_chunks = []
        all_ids = []
        all_metadatas = []
        
        for filepath in knowledge_dir.glob("*.txt"):
            content = filepath.read_text(encoding="utf-8")
            chunks = self._chunk_text(content)
            
            for i, chunk in enumerate(chunks):
                all_chunks.append(chunk)
                all_ids.append(f"\{filepath.stem\}_chunk_\{i\}")
                all_metadatas.append(\{
                    "source": filepath.stem,
                    "chunk_index": i
                \})
        
        if all_chunks:
            self.collection.upsert(
                documents=all_chunks,
                ids=all_ids,
                metadatas=all_metadatas
            )
            print(f"Indexé \{len(all_chunks)\} chunks depuis \{len(list(knowledge_dir.glob('*.txt')))\} fichiers.")
    
    def search(self, query, n_results=3):
        """Recherche sémantique."""
        results = self.collection.query(
            query_texts=[query],
            n_results=n_results
        )
        
        return [
            \{"text": doc, "source": meta["source"]\}
            for doc, meta in zip(results["documents"][0], results["metadatas"][0])
        ]
    
    def _chunk_text(self, text, chunk_size=500, overlap=50):
        """Découper un texte en chunks."""
        words = text.split()
        chunks = []
        for i in range(0, len(words), chunk_size - overlap):
            chunk = " ".join(words[i:i + chunk_size])
            if chunk.strip():
                chunks.append(chunk)
        return chunks
    
    def get_stats(self):
        """Statistiques de la base."""
        return \{
            "total_documents": self.collection.count(),
            "collection_name": KNOWLEDGE_COLLECTION
        \}

tools.py — Définition des outils de l'agent

# tools.py — Fonctions et définitions OpenAI

import json
from knowledge import KnowledgeBase
from openai import OpenAI
from config import OPENAI_API_KEY, DEFAULT_MODEL

client = OpenAI(api_key=OPENAI_API_KEY)
kb = KnowledgeBase()

# Définitions OpenAI format
TOOL_DEFINITIONS = [
    \{
        "type": "function",
        "function": \{
            "name": "search_knowledge",
            "description": "Recherche dans la base de connaissances carrière.",
            "parameters": \{
                "type": "object",
                "properties": \{
                    "query": \{"type": "string", "description": "Question à rechercher"\}
                \},
                "required": ["query"]
            \}
        \}
    \},
    \{
        "type": "function",
        "function": \{
            "name": "analyze_profile",
            "description": "Analyse la compatibilité d'un profil avec un poste.",
            "parameters": \{
                "type": "object",
                "properties": \{
                    "profile": \{"type": "string"\},
                    "target_role": \{"type": "string"\}
                \},
                "required": ["profile", "target_role"]
            \}
        \}
    \},
    \{
        "type": "function",
        "function": \{
            "name": "create_action_plan",
            "description": "Crée un plan d'action personnalisé.",
            "parameters": \{
                "type": "object",
                "properties": \{
                    "goal": \{"type": "string"\},
                    "timeline": \{"type": "string"\}
                \},
                "required": ["goal"]
            \}
        \}
    \}
]

# Implémentations
def search_knowledge(query):
    chunks = kb.search(query, n_results=3)
    if not chunks:
        return "Aucune information trouvée dans la base."
    return "\n".join([f"[\{c['source']\}] \{c['text']\}" for c in chunks])

def analyze_profile(profile, target_role):
    context = search_knowledge(f"compétences \{target_role\}")
    response = client.chat.completions.create(
        model=DEFAULT_MODEL,
        messages=[\{
            "role": "user",
            "content": f"Analyse profil vs poste :\nProfil: \{profile\}\nPoste: \{target_role\}\nContexte: \{context\}\nScore 1-10, Forces, Gaps, Actions."
        \}],
        max_tokens=500
    )
    return response.choices[0].message.content

def create_action_plan(goal, timeline="3 mois"):
    context = search_knowledge(f"formation \{goal\}")
    response = client.chat.completions.create(
        model=DEFAULT_MODEL,
        messages=[\{
            "role": "user",
            "content": f"Plan d'action :\nObjectif: \{goal\}\nDurée: \{timeline\}\nContexte: \{context\}\nFormat: semaine par semaine, actions concrètes."
        \}],
        max_tokens=800
    )
    return response.choices[0].message.content

# Mapping
TOOL_MAP = \{
    "search_knowledge": search_knowledge,
    "analyze_profile": analyze_profile,
    "create_action_plan": create_action_plan,
\}

Convention de noms

Chaque fichier = une responsabilité. config.py ne fait que de la configuration. knowledge.py ne fait que du RAG. tools.py ne fait que des tools. Quand un bug survient, vous savez IMMÉDIATEMENT dans quel fichier chercher.

🏋️ Exercice pratique (30 minutes)

  1. →Créez les 3 fichiers : config.py, knowledge.py, tools.py
  2. →Testez knowledge.py en isolation (indexer 5 docs, chercher)
  3. →Testez tools.py en isolation (appeler chaque outil)
  4. →Vérifiez que les imports fonctionnent entre modules
Quick Check

Pourquoi séparer config.py des autres fichiers plutôt que mettre les constantes directement dans chaque fichier ?

Your progress

Progress is self-reported and stored in your browser. The final completion record is not a qualification or an independent assessment.

View progress and completion record

Learn AI, from prompts to agents

15 free guidesQuizzes, diagrams and workshopsNo account needed

One practical AI workflow in your inbox

Methods, resources and new exercises. Free, unsubscribe at any time.