Le but : comprendre exactement ce que fait la synchro, la régler, la surveiller, et savoir quoi faire quand quelque chose cloche.
1. Une passe de synchro, pas à pas
Le job rag-kit-sync exécute python sync_job.py (fichier app/kit.py, fonction run_sync) :
- Lit la liste des dossiers dans
gs://<bucket>/config.json. - Pour chaque dossier : lit le dossier lui-même (s'il est illisible → avertissement, et aucune suppression pendant cette passe), puis liste tous ses fichiers, sous-dossiers compris (hors corbeille).
- Liste les fichiers déposés (
gs://<bucket>/uploads/). - Souhaité = (2) + (3). Présent = fichiers du corpus, chacun identifié par son ID Drive ou son URI
gs://. - Supprime du corpus ce qui est présent mais plus souhaité.
- Importe, avec les mêmes réglages (découpage 512/100, layout parser) :
- Drive : seulement les fichiers nouveaux ou modifiés dans Drive depuis leur dernière indexation (date
modifiedTimede Drive comparée à la date d'indexation du corpus), par lots de 25. Raison (vérifiée) : RAG Engine réimporte tout fichier Drive à chaque import, même inchangé ; sans ce filtre, chaque passe re-parserait (et refacturerait) tout le dossier. - Dépôts : le préfixe
uploads/entier ; là, RAG Engine ignore lui-même l'inchangé (vérifié).
- Drive : seulement les fichiers nouveaux ou modifiés dans Drive depuis leur dernière indexation (date
- Contrôle : un dossier dont aucun fichier n'est dans le corpus → « Le dossier est-il partagé avec l'agent RAG ? ».
- Écrit le rapport
gs://<bucket>/sync/last.json(lu par l'interface) ; le détail par fichier est dansgs://<bucket>/sync/runs/<horodatage>-<n>.ndjson(gardé 30 jours).
Un seul import à la fois par corpus (vérifié : sinon FailedPrecondition: There are other operations running).
Chaque action (dépôt, suppression, dossier, bouton) lance une nouvelle exécution du job, même si une autre
tourne. Une passe qui trouve le corpus occupé attend 15 s et recommence entièrement (listing frais), jusqu'à
15 min : la dernière passe lancée voit donc toujours le dernier état, sans rapport écrasé (statut occupe non
écrit). (Une première version posait une demande « à refaire » pendant la passe : elle se perdait quand la passe
finissait au même instant — vérifié en test navigateur, d'où ce choix plus simple.)
2. Quand elle tourne
| Déclencheur | Délai |
|---|---|
Cloud Scheduler rag-kit-sync | SYNC_SCHEDULE (défaut toutes les 10 min, fuseau Europe/Paris) |
| Ajout/retrait d'un dossier, dépôt ou suppression d'un fichier dans l'interface | immédiat |
| Bouton « Synchroniser maintenant » | immédiat |
| À la main | gcloud run jobs execute rag-kit-sync --region=europe-west4 --wait |
Changer la fréquence : modifiez SYNC_SCHEDULE dans le .env, rechargez (source scripts/config.sh …) puis
terraform apply (ou relancez deployer_shell.sh). Une passe sans changement coûte quelques secondes de Cloud Run
et de listing ; toutes les 5 min est raisonnable, toutes les minutes non (passes qui se chevauchent).
Mettre en pause : gcloud scheduler jobs pause rag-kit-sync --location=europe-west4 (et resume).
3. Surveiller
# Le dernier rapport
gcloud storage cat gs://$BUCKET/sync/last.json
# Les 5 dernières exécutions du job et leur état
gcloud run jobs executions list --job=rag-kit-sync --region=$REGION --limit=5
# Les journaux d'une passe (le rapport JSON est la dernière ligne)
gcloud logging read 'resource.type="cloud_run_job" AND resource.labels.job_name="rag-kit-sync"' --limit=20 \
--format='value(textPayload)'
# Les fichiers en échec de la dernière passe
gcloud storage cat "gs://$BUCKET/sync/runs/*.ndjson" | grep -v '"Status": "OK"'Alerte conseillée : dans Cloud Monitoring, une alerte sur les exécutions en échec du job
(run.googleapis.com/job/completed_execution_count avec result = failed).
4. Opérations courantes
| Besoin | Comment |
|---|---|
| Tout réindexer (après changement de parsing, par exemple) | Supprimer les fichiers du corpus puis synchroniser : la passe réimporte tout. Avec Terraform : terraform apply -replace=google_vertex_ai_rag_corpus.docs (nouveau corpus vide) puis « Synchroniser » |
| Changer le modèle de réponse | MODEL / MODEL_LOCATION dans le .env puis apply : pas de réindexation |
| Changer le modèle d'embeddings | Impossible sur un corpus existant : nouveau corpus (-replace, voir au-dessus) |
| Désactiver le layout parser | LAYOUT_PARSER=false puis apply ; tout est réindexé à la passe suivante |
| Ajouter des collègues | USERS="user:a@x.com group:equipe@x.com" puis apply |
| Mettre à jour le code | Modifier app/… puis apply : nouvelle image (hachage du code), nouvelle révision |
5. Limites
| Limite | Valeur | Au-delà |
|---|---|---|
| Fichiers par dossier (listing complet à chaque passe) | quelques milliers | API changes de Drive (jeton stocké dans le bucket) |
| Taille d'un dépôt par l'interface | 30 Mo | Mettre le fichier dans le dossier Drive |
| Durée d'une passe | 1 h (timeout du job) | Plusieurs corpus, ou passes plus fréquentes |
| Conversations | en mémoire, 1 instance | Base de sessions (Cloud SQL) via SESSION_SERVICE_URI, puis plus d'instances |
| Décalage Drive → index | ≤ SYNC_SCHEDULE | Bouton « Synchroniser » |
6. Sources « Google Drive connecté » (v2)
Pour un compte connecté (04-bis), la passe (fichier app/gdrive.py) :
- Prend le verrou de la source (
locks/<source>dans le bucket : une seule passe à la fois par source, sinon deux canaux push seraient ouverts — vérifié). - Incrémental : lit seulement les changements depuis le dernier jeton de page (
changes.list), même sur un Drive entier. Complet (1re fois, changement de périmètre, une fois par jour, ou dossier déplacé en mode « dossiers ») : liste tout et réconcilie. - Recopie le nouveau et le modifié dans
gs://<bucket>/mirror/<source>/<fileId>/<nom>(Docs → .docx, Slides → .pptx, Sheets et Dessins → .pdf), supprime du miroir ce qui a disparu, est sorti du périmètre ou a été renommé. - Ouvre ou renouvelle le canal push (
changes.watch, 7 jours) si la source est en « auto ».
Puis la passe commune indexe uploads/ et mirror/ (RAG Engine saute l'inchangé) et retire du corpus ce qui n'est
plus dans le miroir. Une source en panne (jeton expiré…) garde son miroir tel quel : rien n'est retiré de l'index.
Déclencheurs : notification push (TRIGGER=auto), planification (TRIGGER=auto, toutes les 5 min), bouton et
actions de l'interface (TRIGGER=manuel). Une source dont l'« auto » est décochée n'est traitée qu'en manuel
(vérifié : passe auto → document absent ; « Synchroniser maintenant » → présent).
État par source : gs://<bucket>/state/<source>.json (jeton de page, fichiers suivis, canal).