Créer des espaces de travail partagés pour les humains et les agents

Comment les projets Perplexity garantissent la persistance, la concurrence et la traçabilité des travaux de longue haleine.

AuteursPerplexity Engineering

Nous avons récemment lancé les projets, où humains et agents travaillent ensemble sur des tâches de longue haleine dans Perplexity Computer. Chaque projet repose sur un espace de travail partagé doté d’un système de fichiers qui accumule le contexte au fil des sessions, des agents et des utilisateurs. Une collaboration multijoueur qui s’étend sur plusieurs mois exige persistance, concurrence et traçabilité :

  • Persistance : le travail doit perdurer au-delà de toute session d’agent ou de tout bac à sable, afin que le même utilisateur ou agent puisse le poursuivre et que n’importe quel collaborateur puisse s’en servir comme base.
  • Concurrence : plusieurs utilisateurs d’un même projet peuvent chacun disposer de plusieurs agents qui effectuent des modifications en parallèle, faisant progresser un état partagé plutôt que de s’écraser mutuellement.
  • Traçabilité : les utilisateurs comme les agents doivent pouvoir consulter l’historique afin de vérifier qui a modifié quoi depuis leur dernière session, sans relire l’intégralité du projet, et annuler des modifications si nécessaire.

Ces défis sont familiers aux ingénieurs logiciels. Les forges Git sont apparues il y a plusieurs décennies pour répondre à ces exigences : un service hébergé qui enrichit le contrôle de version de fonctionnalités collaboratives afin que de nombreux contributeurs puissent converger vers une source de vérité unique. Le système de fichiers qui alimente les projets est l’une de ces forges Git, conçue pour la collaboration entre humains et agents, et entre agents.

Un seul projet : agents interactifs, agents planifiés et agents d’autres utilisateurs convergent tous vers le même dépôt.

Architecture

Git gère déjà la persistance, la concurrence et la traçabilité. Il identifie chaque fichier par son contenu : les fichiers inchangés ne sont stockés qu’une seule fois et les copies enregistrées ne deviennent jamais obsolètes. Chaque commit enregistre tous les fichiers mis à jour d’un seul coup, de sorte que les collaborateurs ne voient jamais d’état à moitié terminé. Lorsque deux contributeurs entrent en conflit, celui qui a perdu peut réappliquer ses modifications sur la nouvelle version et réessayer. La chaîne de commits montre qui a modifié quoi et permet de restaurer facilement des versions antérieures. Ce dont les agents n’ont pas besoin, c’est du reste d’une forge conçue pour les humains, comme les écrans de relecture, la gestion des branches et les notifications.

Notre architecture exécute l’ensemble du processus dans le cloud et prend en charge toutes les formes de travail intellectuel, bien au-delà du code. Chaque projet Computer s’appuie sur un dépôt Git servi par 5 composants :

  • La CLI gère les copies de travail locales, synchronise les mises à jour et soumet les modifications de l’agent dans chaque bac à sable.
  • Le plan de contrôle localise le dépôt du projet et délivre des identifiants de courte durée pour y accéder.
  • Le service Git envoie les données des dépôts aux bacs à sable, reçoit leurs soumissions et décide quelle soumission devient le dernier commit accepté.
  • Le stockage adossé à AWS S3 conserve durablement les données des dépôts.
  • Le traitement en aval extrait le texte et d’autres informations utiles des documents enregistrés et les met à disposition lorsque les agents chargent ou actualisent le projet.

Chaque agent dispose de son propre bac à sable isolé. Dans ce bac à sable, il travaille sur une copie locale du dépôt, gérée par une petite CLI. La CLI demande au plan de contrôle de localiser le dépôt, puis récupère et soumet les modifications via le service Git. Un proxy d’agent vérifie les droits d’accès des requêtes provenant des bacs à sable avant qu’elles n’atteignent le service Git. Le service Git lit et écrit les dépôts sur un système de fichiers partagé, et décide si chaque soumission devient le dernier commit accepté. Ce système de fichiers est fourni par AWS S3Files, qui rend un stockage adossé à S3 accessible sous forme de fichiers et de répertoires ordinaires. Le stockage est divisé en cellules isolées, chacune disposant de son propre système de fichiers et de ses propres réplicas du service Git. Une fois un commit accepté, des workers en arrière-plan extraient le texte et d’autres informations utiles des documents modifiés, stockent les résultats séparément de l’historique du dépôt et les mettent à disposition lorsque les agents chargent ou actualisent le projet.

Passons maintenant en revue chacun de ces composants.

La CLI contacte le plan de contrôle pour localiser son dépôt, puis effectue ses récupérations et soumissions via le service Git, en passant par le proxy d’agent. Le service Git vérifie les soumissions et met à jour la tête acceptée et la boîte d’envoi dans DynamoDB. Les réplicas locaux à chaque cellule utilisent le stockage S3Files, tandis que des workers en aval extraient le texte qui sera fourni lors de l’extraction du dépôt et de la synchronisation.

CLI : travailler avec des fichiers locaux dans les bacs à sable

Les agents s’exécutent dans SPACE, notre plateforme interne de bacs à sable. Chaque bac à sable dispose d’une petite CLI qui matérialise le dépôt et le maintient synchronisé. Pour chaque unité de travail significative réalisée par l’agent, elle soumet les modifications sous forme de commit.

Les agents ne touchent généralement qu’une petite fraction des fichiers du projet ; il n’est donc pas nécessaire de matérialiser l’intégralité du dépôt dès le départ. La CLI procède ainsi à une matérialisation à la demande : les fichiers volumineux et binaires stockés via Git Large File Storage (LFS) arrivent sous forme de petits fichiers pointeurs indiquant la taille réelle de l’objet, ce qui permet à l’agent de s’appuyer sur le nom et la taille pour décider si un téléchargement en vaut la peine. Pour les documents comme les PDF, l’agent lit d’abord le texte extrait et ne télécharge les fichiers sources qu’en cas de nécessité.

Une autre option naturelle serait d’utiliser un système de fichiers virtuel. Nous avons testé une implémentation reposant sur FUSE, mais elle était environ 400 fois plus lente que des fichiers locaux sur les charges de travail sollicitant fortement le système de fichiers, car chaque requête nécessite un aller-retour réseau. Elle exige aussi généralement des capacités privilégiées de la part de l’hôte, si bien que chaque agent devrait s’exécuter dans un bac à sable privilégié.

La taille du pointeur et le manifeste d’analyse déterminent le choix : lire le texte extrait, télécharger la source ou ignorer le fichier.

Plan de contrôle : localiser les dépôts et délivrer les accès

Le plan de contrôle localise l’emplacement de stockage de chaque dépôt et en délivre l’accès. Lors de la création d’un dépôt, le plan de contrôle l’affecte à une cellule de stockage, une unité de stockage isolée dotée de ses propres réplicas du service Git. Lorsqu’un agent commence à travailler sur un projet, la CLI demande au plan de contrôle où le dépôt est stocké. Le plan de contrôle renvoie l’emplacement ainsi que des identifiants temporaires pour le service Git. Le plan de contrôle ne lit ni n’écrit jamais les données des dépôts. C’est le service Git qui décide de ce qui entre dans un dépôt.

Service Git : déplacer les données et coordonner les mises à jour

Le service Git exécute les opérations Git et transfère le contenu des dépôts et l’historique des versions entre les bacs à sable et le stockage. Il s’agit d’une fine surcouche autour des commandes de service natives de Git. Il prend en charge la découverte des refs, pour indiquer au client où se trouve la tête du dépôt, upload-pack pour le clonage et la récupération, et receive-pack pour recevoir de nouveaux objets ainsi qu’une demande d’avancement de la tête du dépôt. Il sert également l’API Git LFS : pour les fichiers volumineux et binaires, il délivre des liens de courte durée afin que les bacs à sable puissent téléverser et télécharger ces fichiers directement vers et depuis S3.

Nous avons commencé avec un serveur de forge prêt à l’emploi, ce qui nous a permis de prototyper les interfaces des agents et des utilisateurs tout en développant en parallèle notre propre forge légère, centrée uniquement sur les opérations Git dont nous avons besoin.

Le service se compose d’une flotte de réplicas, chacun étant une instance en cours d’exécution du même serveur. Une cellule regroupe un stockage partagé, un ensemble de réplicas et leurs services d’appui. Les réplicas d’une même cellule peuvent ainsi accéder au même système de fichiers partagé, au lieu de conserver chacun des copies indépendantes de tous les dépôts.

Ce stockage partagé permet aux réplicas de rester sans état. N’importe quel réplica de la cellule peut servir n’importe lequel de ses dépôts ; remplacer ou ajouter des réplicas ne nécessite donc pas de déplacer les données des dépôts entre serveurs. Les requêtes destinées à un dépôt sont normalement dirigées vers le même réplica afin que ses caches restent utiles, mais le dépôt ne dépend pas de la disponibilité de cette instance en particulier.

L’étape d’acceptation vérifie les invariants du dépôt afin de garantir qu’un commit accepté correspond à un état valide du dépôt. Nous définissons un contrat explicite pour chaque dépôt, afin que des vérifications mécaniques l’empêchent de devenir trop volumineux. Les fichiers volumineux et binaires, comme les PDF et les images, sont stockés via Git LFS plutôt que sous forme de blobs Git bruts. Le compactage préserve l’historique récent tout en limitant la taille du dépôt. Après une soumission réussie, la CLI demande au service Git si le dépôt doit être compacté. Si le nombre de commits conservés dépasse un seuil, le service Git ne garde qu’un ensemble plus restreint des commits les plus récents. L’historique plus ancien est remplacé par un instantané de départ unique, et les commits récents sont rejoués pour mettre à jour les identifiants de commit.

Le compactage conserve les commits les plus récents, regroupe l’historique ancien dans une racine d’instantané unique et rejoue les commits récents avec de nouveaux identifiants ; la nouvelle tête conserve les mêmes fichiers.

Une simple étape de synchronisation gère les écritures concurrentes. Elle suit le dernier commit accepté, appelé tête (head). Lorsqu’elle reçoit une soumission, elle ne l’accepte que si celle-ci a été construite sur cette tête. Dans le cas contraire, elle renvoie une réponse structurée signalant une base obsolète ; le perdant doit alors rejouer sa modification sur la nouvelle tête et la soumettre à nouveau. Cette conception garantit que des agents concurrents ne s’écrasent pas mutuellement en silence, sans pour autant provoquer de ralentissements notables. Dans nos flux de travail de production, moins de 2 % des soumissions sont rejetées pour cause de base obsolète. Dans l’ensemble, la latence médiane d’une soumission est inférieure à 1,7 seconde, et la latence p99 est inférieure à 8 secondes.

Deux agents soumettent simultanément : l’un voit sa soumission acceptée, l’autre reçoit une réponse signalant une base obsolète, rejoue sa modification sur la nouvelle tête et la soumet à nouveau.

Le service Git consigne également chaque modification acceptée. Pour chaque écriture acceptée, il ajoute une entrée dans une boîte d’envoi (outbox), un journal qui répertorie le dépôt, le nouveau commit, l’utilisateur à l’origine de la modification et les chemins modifiés. Les services en aval, comme l’analyseur, lisent ce journal pour identifier les nouvelles tâches à traiter.

Ensemble, ces éléments forment une couche de gestion des dépôts, sans les parties dont les agents n’ont pas besoin. Les pull requests sont superflues, car aucun humain ne relit chaque modification. À la place, le service Git vérifie le contrat au moment de la soumission, l’agent qui perd la course réapplique sa propre modification, et l’historique des commits consigne qui a modifié quoi. Des vérifications déterministes maintiennent chaque dépôt dans les limites de son contrat, sans dépendre d’un opérateur humain pour gérer sa croissance.

Stockage : garantir la durabilité du travail

La couche de stockage enregistre durablement les données des dépôts, indépendamment des bacs à sable et des réplicas du service Git. Les dépôts résident sur AWS S3Files, qui expose un stockage adossé à S3 via une interface de système de fichiers que Git standard peut utiliser sans modification. Chacun est un dépôt Git nu (bare) sur le système de fichiers partagé, contenant les objets et les références du dépôt plutôt qu’une copie de travail.

Découpler le stockage du calcul permet aux bacs à sable de rester éphémères. Chaque agent dispose de son propre bac à sable, et de nombreux agents peuvent travailler sur le même projet sans partager de machine. Si un bac à sable plante, seul le travail non encore soumis est menacé.

Nous pourrions plutôt attribuer à chaque projet un bac à sable de longue durée partagé par tous ses agents, de sorte que les fichiers du projet résideraient sur le disque de cette machine. Cependant, cela lierait la puissance de calcul des agents à l’endroit où s’exécute la machine et imposerait de la dimensionner pour ses périodes de plus forte activité. Elle devrait en outre rester opérationnelle pendant des mois, avec des sauvegardes et une reprise gérées dans le cadre du système de stockage du projet.

Un bac à sable de longue durée partagé par les agents d’un projet, comparé à des bacs à sable éphémères propres à chaque agent, qui accèdent à un stockage partagé durable via des réplicas sans état du service Git.

Traitement en aval : rendre les documents lisibles par les agents

Le principal composant en aval est un pipeline d’analyse qui extrait le texte et les métadonnées des documents nouvellement ajoutés ou mis à jour, afin que les fichiers du projet soient facilement lisibles par les agents. Un worker d’analyse consomme les mises à jour depuis la file d’attente du flux de modifications, déduit les fichiers modifiés à partir des métadonnées du commit et récupère les octets bruts à l’aide du hash du contenu. Il analyse ensuite le document pour produire le texte extrait et les métadonnées du document.

Les résultats d’analyse résident en dehors du dépôt, dans un espace de stockage indexé par le hash du document source. Ces artefacts ne sont jamais commités dans le dépôt, car cela polluerait inutilement l’historique et augmenterait le nombre d’écritures concurrentes. Les résultats d’analyse parviennent plutôt au bac à sable via l’extraction du dépôt et la synchronisation. Chaque copie de travail comporte un répertoire réservé que la CLI utilise pour matérialiser les artefacts. L’analyse s’effectue de manière asynchrone, de sorte qu’un worker d’analyse en arrière-plan ne bloque pas les extractions du dépôt.

Comment les agents utilisent l’espace de travail

Les agents explorent la version du dépôt chargée dans le bac à sable à l’aide d’outils standard de système de fichiers. Plutôt que de suivre un pipeline figé de type recherche puis lecture, ils listent les dossiers, recherchent dans le contenu des fichiers avec grep, lisent les passages pertinents et s’appuient sur ce qu’ils trouvent pour décider où chercher ensuite.

Comme Computer, Search applique la même approche avec ses outils de fichiers standard. Un agent d’exploration distinct parcourt le projet avec un budget plus limité et renvoie les chemins des fichiers pertinents ainsi que des extraits à l’appui. Le modèle de réponse lit ensuite les fichiers sélectionnés et génère la réponse. Réutiliser un bac à sable de projet existant réduit le temps de mise en route : se rattacher à une copie de travail déjà prête prend environ 2,9 secondes, contre environ 8 secondes pour un démarrage à froid.

Les bacs à sable de Computer, le sous-agent d’exploration d’Ask, les rédacteurs de connaissances en arrière-plan et les workers d’analyse lisent et écrivent tous dans le même dépôt et la même boîte d’envoi.

Grâce au texte extrait, il est possible d’effectuer des recherches dans les documents plus volumineux, comme les PDF et les fichiers Office, avec les mêmes outils. L’agent consulte d’abord un manifeste, une liste indiquant quels documents disposent d’un texte extrait, puis recherche et lit ce texte comme des fichiers ordinaires. Il ne télécharge le document d’origine que lorsque le texte ne suffit pas, par exemple pour examiner des figures, la mise en page ou des données intégrées.

Nous avons comparé cette approche à une recherche sémantique sur un index, à partir de 150 questions financières portant chacune sur un seul document du même corpus. L’agent d’exploration a obtenu un score de 0,867 pour la récupération du bon document et de 0,627 pour l’exactitude des réponses, contre environ 0,39 et 0,37 pour la recherche sémantique, soit des résultats environ 1,7 fois meilleurs pour les réponses et 2 fois meilleurs pour la récupération, avec une latence inférieure d’environ 25 %. L’agent d’exploration travaille principalement avec le texte extrait et télécharge rarement les PDF d’origine.

Exploration et recherche sémantique de fichiers : comparaison sur le benchmark interne.

Une seule infrastructure partagée

La mémoire persistante de Computer repose sur la même infrastructure de système de fichiers. Perplexity Brain, le wiki de connaissances de Computer, stocke la mémoire dans des dépôts de connaissances dotés de leur propre historique et de leurs propres règles. Séparer les connaissances des fichiers du projet évite que les mises à jour de la mémoire en arrière-plan n’entrent en concurrence avec les modifications de ces fichiers. Une session qui a besoin des deux charge les deux dépôts.

Des agents en arrière-plan lisent les connaissances existantes, intègrent les nouvelles informations et enregistrent les pages mises à jour sous forme de commits. D’autres agents lisent ces pages avec des outils de fichiers ordinaires, et les humains peuvent aussi les modifier. Les rédacteurs partagent leur travail via le dépôt plutôt que de se coordonner directement avec chaque lecteur. L’historique des commits consigne qui a modifié quoi, tandis que la boîte d’envoi signale les mises à jour acceptées aux services en aval. Humains et agents peuvent s’appuyer sur le travail des uns et des autres, tout en gardant une trace de l’évolution des connaissances.

Conclusion

Lorsque des humains et des agents partagent un projet, l’espace de travail ne se contente pas de stocker des fichiers. Il offre un lieu commun pour combiner les contributions et suivre ce qui a changé. Git fournit déjà une grande partie de ces fondations. Nous y ajoutons de la coordination et des vérifications automatisées pour que les agents puissent soumettre leur travail sans qu’une personne approuve chaque mise à jour. Le résultat est une forge réduite à l’essentiel, car la collaboration entre agents et le développement logiciel à plusieurs contributeurs relèvent, au fond, du même problème.

Les agents travaillent dans des bacs à sable indépendants et temporaires tout en contribuant à des dépôts durables. Les limites imposées aux dépôts maintiennent leur croissance sous contrôle, les téléchargements explicites permettent aux agents de choisir ce qu’ils récupèrent, et des fichiers ordinaires leur permettent d’explorer avec des outils familiers. Les mises à jour en arrière-plan, les modifications interactives et les tâches planifiées peuvent s’appuyer sur le travail les unes des autres sans coordination directe.

À mesure que de plus en plus d’agents travaillent de manière autonome au sein des projets, leur espace de travail partagé doit rester fiable et compréhensible pour les humains. L’objectif est simple : chaque modification doit survivre à l’agent qui l’a produite, être mise à la disposition du collaborateur suivant et laisser une trace claire de ce qui a changé.

Citation

BibTeX
@online{perplexity2026BuildingSharedWorkspacesForPeopleAndAgents,
  author = {{Perplexity} and Se Won Jang and Peter Hart and Kartik Kapur and Kevin Lau and Sidhant Rajadnya and Ishbir Singh and Thomas Wang and Jarrod Bryan and Claire Beamer and Jeremy Yang},
  title = {{Building shared workspaces for people and agents}},
  date = {2026-10-12},
  url = {https://www.perplexity.ai/hub/blog/building-shared-workspaces-for-people-and-agents}
}