Ancrer les réponses des LLM dans le code source est plus efficace que des explications hallucinées. Ce tutoriel utilise le SERP de Scavio avec site:github.com et son endpoint fetch pour intégrer le contenu du dépôt dans la boucle de l'agent sans lourde intégration de l'API GitHub.
Prérequis
- Python 3.10+
- Une clé API Scavio
- Une clé API LLM
Parcours
Étape 1: Rechercher dans un dépôt via SERP
La recherche ciblée site:github.com/ORG/REPO trouve rapidement le bon fichier.
import requests, os
API_KEY = os.environ['SCAVIO_API_KEY']
def repo_search(repo, query):
r = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY},
json={'query': f'site:github.com/{repo} {query}', 'num_results': 10})
return r.json().get('organic_results', [])Étape 2: Récupérer le fichier sélectionné
Les URLs brutes GitHub fonctionnent avec l'endpoint fetch de Scavio.
def fetch_raw(url):
raw = url.replace('github.com', 'raw.githubusercontent.com').replace('/blob/', '/')
r = requests.post('https://api.scavio.dev/api/v1/extract',
headers={'x-api-key': API_KEY},
json={'url': raw})
return r.json().get('content', '')Étape 3: Ancrer la réponse
Passer le contenu récupéré dans le prompt LLM avec citation de la source.
import anthropic
client = anthropic.Anthropic()
def grounded_answer(repo, question):
hits = repo_search(repo, question)
content = fetch_raw(hits[0]['link']) if hits else ''
msg = client.messages.create(
model='claude-sonnet-4-6',
max_tokens=1024,
messages=[{'role': 'user', 'content': f'{question}\n\nCONTEXT:\n{content[:4000]}'}])
return msg.content[0].textÉtape 4: Ajouter la composition multi-fichiers
Extraire les 3 premiers résultats, classer par pertinence, composer le contexte.
def multi_file_context(repo, question):
hits = repo_search(repo, question)[:3]
return '\n\n'.join([fetch_raw(h['link'])[:2000] for h in hits])Étape 5: Valider les citations
S'assurer que la réponse du LLM mentionne au moins une URL source.
def has_citations(answer, urls):
return any(u in answer for u in urls)Exemple Python
import os, requests
API_KEY = os.environ['SCAVIO_API_KEY']
def repo_grounded(repo, question):
r = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY},
json={'query': f'site:github.com/{repo} {question}'})
return r.json().get('organic_results', [])[:3]
print(repo_grounded('prisma/prisma', 'migrate.ts'))Exemple JavaScript
const API_KEY = process.env.SCAVIO_API_KEY;
export async function repoGrounded(repo, question) {
const r = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `site:github.com/${repo} ${question}` })
});
return ((await r.json()).organic_results || []).slice(0, 3);
}Sortie attendue
LLM answers cite exact files and code paths in the target repo. Hallucination rate drops materially versus ungrounded answers.