Recherche Sémantique de Code
Mis à jour le 29 juillet 2026
Chercher du code par signification
La recherche classique de code repose sur des mots-clés : vous tapez le nom d’une fonction ou un mot dans un commentaire. La recherche sémantique de code va plus loin : elle trouve du code par sa signification ou son intention, même si les termes exacts ne correspondent pas.
Avec codestral-embed, vous pouvez rechercher du code en langage naturel : « fonction qui trie une liste » trouvera un quicksort même si le mot « trier » n’apparaît nulle part dans le code. C’est la situation quotidienne d’un développeur qui arrive sur un projet existant : il sait ce qu’il cherche, il ignore comment l’équipe précédente l’a nommé.
Indexer un répertoire de code
La première étape est d’extraire et d’encoder tous les fichiers ou fonctions d’un projet. La fonction ci-dessous parcourt l’arborescence et écarte au passage les dossiers qui pollueraient l’index — node_modules seul peut représenter dix fois le volume du code que vous avez réellement écrit, et aucun de ses fichiers n’a d’intérêt pour votre recherche.
import os
import numpy as np
from mistralai import Mistral
client = Mistral(api_key=api_key)
def extract_code_files(directory, extensions=(".py", ".js", ".ts")):
"""Extraire tous les fichiers de code d'un répertoire."""
code_files = []
for root, dirs, files in os.walk(directory):
# Ignorer les dossiers non pertinents
dirs[:] = [d for d in dirs if d not in ("node_modules", ".git", "__pycache__", "venv")]
for f in files:
if any(f.endswith(ext) for ext in extensions):
filepath = os.path.join(root, f)
with open(filepath, "r", encoding="utf-8", errors="ignore") as fh:
content = fh.read()
if content.strip():
code_files.append({
"path": filepath,
"content": content[:4000], # Tronquer si trop long
})
return code_files
# Extraire les fichiers
code_files = extract_code_files("./mon-projet/")
print(f"{len(code_files)} fichiers de code trouvés")
Deux détails d’implémentation méritent d’être signalés. La modification dirs[:] en place n’est pas un raccourci d’écriture : c’est la seule façon d’empêcher os.walk de descendre dans ces dossiers, et remplacer la variable sans la trancher n’aurait aucun effet. Quant à la troncature à 4000 caractères, elle vous protège d’un fichier monstrueux qui ferait exploser la requête, tout en gardant l’en-tête du fichier — imports, définitions principales — qui porte l’essentiel du signal.
Encoder et indexer
L’encodage se fait par lots de vingt fichiers, avec un affichage de progression. Sur un dépôt de plusieurs centaines de fichiers, cette boucle tourne plusieurs minutes : sans compteur, vous n’avez aucun moyen de distinguer un traitement lent d’un appel bloqué.
def index_code_files(code_files, batch_size=20):
"""Créer les embeddings pour tous les fichiers de code."""
all_embeddings = []
for i in range(0, len(code_files), batch_size):
batch = code_files[i:i + batch_size]
inputs = [f["content"] for f in batch]
response = client.embeddings.create(
model="codestral-embed",
inputs=inputs,
)
all_embeddings.extend([d.embedding for d in response.data])
print(f"Encodé {min(i + batch_size, len(code_files))}/{len(code_files)}")
return np.array(all_embeddings)
embeddings = index_code_files(code_files)
print(f"Index: {embeddings.shape}")
L’ordre des embeddings dans la matrice suit exactement l’ordre de code_files. Cette correspondance implicite est le pivot de tout ce qui suit : c’est elle qui permet à un indice retourné par le classement de désigner un chemin de fichier.
Recherche en langage naturel
L’avantage majeur de codestral-embed : vous pouvez chercher avec une question en français ou en anglais. La fonction encode la requête avec le même modèle, calcule les similarités contre l’index entier, et remonte les top_k meilleurs résultats accompagnés d’un aperçu du contenu.
from sklearn.metrics.pairwise import cosine_similarity
def search_code(query, code_files, embeddings, top_k=5):
"""Rechercher du code par description en langage naturel."""
# Encoder la requête
response = client.embeddings.create(
model="codestral-embed",
inputs=[query],
)
query_emb = np.array(response.data[0].embedding)
# Calculer les similarités
sims = cosine_similarity([query_emb], embeddings)[0]
# Top-k résultats
top_indices = np.argsort(sims)[::-1][:top_k]
results = []
for idx in top_indices:
results.append({
"path": code_files[idx]["path"],
"score": float(sims[idx]),
"preview": code_files[idx]["content"][:200],
})
return results
# Recherches en langage naturel
queries = [
"fonction de validation d'email",
"connexion à la base de données",
"gestion des erreurs HTTP",
"algorithme de tri",
]
for query in queries:
print(f"\n--- Requête: '{query}' ---")
results = search_code(query, code_files, embeddings, top_k=3)
for r in results:
print(f" [{r['score']:.3f}] {r['path']}")
Le champ preview a une utilité pratique immédiate : il vous évite d’ouvrir cinq fichiers pour comprendre lequel correspond réellement. Dans une intégration éditeur, ces deux cents caractères deviennent la ligne d’aperçu affichée sous chaque résultat.
Recherche cross-langage
codestral-embed comprend la logique indépendamment du langage. Vous pouvez chercher un pattern Python et trouver l’équivalent en JavaScript :
# Chercher par exemple de code dans un langage...
query_python = "def authenticate(username, password): check credentials and return token"
# ...et trouver l'équivalent dans un autre langage
results = search_code(query_python, code_files, embeddings)
# Peut retourner un fichier .js avec une fonction similaire
Cette capacité prend tout son sens sur une application découpée entre un backend Python et un frontend TypeScript, où la même règle métier est parfois implémentée des deux côtés. Retrouver les deux implémentations à partir d’une seule requête, c’est repérer les divergences avant qu’un bug ne les révèle en production.
Recherche par signature de fonction
Vous pouvez aussi chercher par la forme attendue plutôt que par le domaine fonctionnel. Décrire la structure — une fonction asynchrone, une classe, un middleware, un test — oriente la recherche vers un type d’objet de code plutôt que vers un sujet.
queries_techniques = [
"async function that fetches data from API and handles errors",
"class with CRUD methods for database operations",
"middleware that checks authentication token",
"unit test for user registration",
]
for q in queries_techniques:
results = search_code(q, code_files, embeddings, top_k=2)
print(f"\n{q}:")
for r in results:
print(f" -> {r['path']} (score: {r['score']:.3f})")
Essayez ces quatre requêtes sur votre propre dépôt avant de passer à la suite. Vous constaterez que les résultats se dégradent nettement sur les fichiers très longs, dont la troncature à 4000 caractères a coupé la partie utile : c’est le moment de décider si vous indexez des fichiers entiers ou, mieux, des fonctions découpées une à une.
Points clés à retenir
- codestral-embed permet de chercher du code par description en langage naturel
- L’indexation consiste à encoder tous les fichiers de code en vecteurs
- La recherche cross-langage fonctionne : un pattern Python trouve l’équivalent JS
- Filtrez les dossiers non pertinents (node_modules, .git, venv) lors de l’extraction
- Tronquez les fichiers très longs pour rester dans les limites du modèle