Недавно мы запустили Projects, где люди и агенты совместно работают над долгосрочными задачами в Perplexity Computer. Каждый проект располагается в общем рабочем пространстве с файловой системой, которая накапливает контекст между сеансами, агентами и пользователями. Многопользовательское сотрудничество, длящееся месяцами, требует постоянства, параллельности и прозрачности:
- Постоянство: работа должна сохраняться дольше любого отдельного сеанса агента или песочницы, чтобы будущую работу мог продолжить тот же пользователь или агент, а также использовать любые соавторы.
- Параллельность: несколько пользователей в рамках одного проекта могут иметь по несколько агентов, выполняющих правки параллельно и развивающих общее состояние, а не перезаписывающих друг друга.
- Прозрачность: как пользователи, так и агенты должны иметь возможность видеть историю, чтобы проверять, кто и что изменил с момента их последнего сеанса, без необходимости перечитывать весь проект целиком, а также при необходимости откатывать правки.
Эти проблемы хорошо знакомы инженерам-программистам. Системы контроля версий на базе Git появились десятилетия назад для удовлетворения именно этих требований: размещенный сервис, который объединяет контроль версий с функциями совместной работы, позволяя множеству участников сходиться на едином источнике истины. Файловая система, лежащая в основе Projects, представляет собой именно такое хранилище Git, созданное для взаимодействия человека с агентом и агента с агентом.
Архитектура
Git уже справляется с постоянством, параллельностью и прозрачностью. Он идентифицирует каждый файл по его содержимому, поэтому неизмененные файлы хранятся в единственном экземпляре, а сохраненные копии никогда не устаревают. Каждый коммит сохраняет каждый обновленный файл целиком, поэтому соавторы никогда не видят полуготового состояния. Когда два автора сталкиваются лбами, проигравший может применить свои изменения заново к новой версии и попробовать снова. Цепочка коммитов показывает, кто и что изменил, и позволяет легко восстанавливать предыдущие версии. Чего агентам не нужно, так это остальной части систем для людей, такой как экраны ревью, управление ветками и уведомления.
Наша архитектура запускает весь процесс в облаке и поддерживает все формы интеллектуальной работы, выходящие за рамки программирования. Каждый проект Computer обеспечивается репозиторием Git, обслуживаемым 5 компонентами:
- CLI поддерживает локальные чекауты, синхронизирует обновления и отправляет изменения агента в каждой песочнице.
- Control plane определяет местоположение репозитория проекта и выдает недолговечные учетные данные для доступа к нему.
- Git-сервис отправляет данные репозитория в песочницы, принимает их отправления (submit) и определяет, какое отправление становится последним принятым коммитом.
- Хранилище на базе AWS S3 надежно хранит данные репозитория.
- Нисходящая обработка извлекает текст и другую полезную информацию из сохраненных документов и делает ее доступной, когда агенты загружают или обновляют проект.
У каждого агента есть своя изолированная песочница. Внутри этой песочницы он работает с локальной копией репозитория, управляемой небольшим CLI. CLI запрашивает у control plane местоположение репозитория, а затем получает и отправляет изменения через Git-сервис. Прокси агента проверяет доступ для запросов из песочницы до того, как они достигнут Git-сервиса. Git-сервис читает и записывает репозитории в общую файловую систему и решает, становится ли каждое отправление последним принятым коммитом. Эта файловая система предоставляется AWS S3Files, что делает хранилище на базе S3 доступным в виде обычных файлов и каталогов. Хранилище делится на изолированные ячейки, каждая из которых имеет собственную файловую систему и реплики Git-сервиса. После принятия коммита фоновые воркеры извлекают текст и другую полезную информацию из измененных документов, сохраняя результаты отдельно от истории репозитория и делая их доступными при загрузке или обновлении проекта агентами.
Далее мы рассмотрим компоненты по очереди.
CLI: работа с локальными файлами в песочницах
Агенты работают в SPACE, нашей собственной платформе песочниц. Каждая песочница имеет небольшой CLI, который материализует репозиторий и поддерживает его синхронизацию. Для каждой единицы значимой работы, проделанной агентом, он отправляет изменения в виде коммита.
Агенты обычно затрагивают лишь малую часть файлов проекта, поэтому нет необходимости материализуть весь репозиторий заранее. В результате CLI выполняет материализацию лениво: крупные и бинарные файлы, хранящиеся через Git Large File Storage (LFS), поступают в виде небольших файлов-указателей, содержащих реальный размер объекта, поэтому агент может использовать имя и размер, чтобы решить, стоит ли загрузка того. Для таких документов, как PDF, агент сначала читает разобранный текст и загружает исходные файлы только при необходимости.
Другим естественным вариантом было бы использование виртуальной файловой системы. Мы протестировали реализацию на базе FUSE, но она работала примерно в 400 раз медленнее на нагрузках с интенсивным использованием файловой системы по сравнению с локальными файлами, так как каждый запрос требует сетевого кругового пути (roundtrip). Кроме того, обычно для этого требуются привилегированные возможности от хоста, поэтому каждому агенту пришлось бы работать в привилегированной песочнице.
Control plane: определение местоположения репозиториев и выдача доступа
Control plane определяет, где хранится каждый репозиторий, и выдает к нему доступ. Когда репозиторий создается, control plane назначает его в ячейку хранения — изолированную единицу хранения с собственными репликами Git-сервиса. Когда агент начинает работу над проектом, CLI спрашивает у control plane, где хранится репозиторий. Control plane возвращает местоположение и временные учетные данные для Git-сервиса. Control plane никогда не читает и не записывает данные репозитория. Git-сервис решает, что попадает в репозиторий.
Git-сервис: перемещение данных и координация обновлений
Git-сервис выполняет операции Git и передает содержимое репозитория и историю версий между песочницами и хранилищем. Он представляет собой тонкую обертку над собственными командами обслуживания Git. Он поддерживает обнаружение ссылок (ref discovery), чтобы сообщать клиенту, где находится head репозитория, upload-pack для клонирования и получения, а также receive-pack для получения новых объектов и запроса на продвижение head репозитория вперед. Он также обслуживает API Git LFS: для крупных и бинарных файлов он выдает недолговечные ссылки, чтобы песочницы могли загружать эти файлы напрямую из S3 и выгружать их туда.
Мы начали с готового серверного ПО для хостинга репозиториев, чтобы иметь возможность прототипировать интерфейсы агента и пользователя параллельно с созданием собственного легковесного решения, ориентированного только на необходимые нам операции Git.
Сервис состоит из парка реплик, каждая из которых представляет собой запущенный экземпляр одного и того же сервера. Ячейка группирует общее хранилище с набором реплик и поддерживающих их служб. Реплики в рамках ячейки могут затем обращаться к одной и той же общей файловой системе, вместо того чтобы поддерживать независимые копии каждого репозитория.
Это общее хранилище позволяет репликам оставаться беззасистемными (stateless). Любая реплика в ячейке может обслуживать любой из своих репозиториев, поэтому замена или добавление реплик не требуют перемещения данных репозитория между серверами. Запросы к репозиторию обычно направляются на ту же реплику, чтобы ее кэши оставались полезными, однако репозиторий не зависит от доступности именно этого конкретного экземпляра.
Этап проверки проверяет инварианты репозитория, чтобы гарантировать, что принятый коммит является допустимым состоянием репозитория. Мы определяем явный контракт для каждого репозитория, чтобы механические проверки не позволяли ему разрастаться. Большие и бинарные файлы, такие как PDF и изображения, хранятся через Git LFS, а не в виде необработанных объектов Git. Уплотнение сохраняет недавнюю историю доступной, ограничивая при этом размер репозитория. После успешной отправки CLI спрашивает у службы Git, требуется ли репозиторию уплотнение. Если количество сохраненных коммитов превышает пороговое значение, служба Git оставляет только меньший набор самых свежих коммитов. Старая история заменяется одним начальным снимком, а недавние коммиты воспроизводятся повторно для обновления идентификаторов коммитов.
Простой шаг синхронизации контролирует одновременную запись. Он отслеживает последний принятый коммит, или head. Когда он получает отправку, он принимает ее только в том случае, если отправка была создана на основе этого head. Если нет, он отправляет структурированный ответ об устаревшей базе; проигравшему агенту после этого необходимо повторно применить свое изменение поверх нового head и выполнить отправку снова. Такая конструкция гарантирует, что параллельно работающие агенты не будут перезаписывать друг друга незаметно, без возникновения значительных задержек. В наших рабочих процессах менее 2% отправок отклоняются как устаревшие. В целом медианная задержка отправки составляет менее 1,7 секунды, а задержка p99 — менее 8 секунд.
Служба Git также регистрирует каждое принятое изменение. Для каждой принятой записи она добавляет элемент в outbox — лог, в котором перечисляются репозиторий, новый коммит, пользователь, внесший изменение, и измененные пути. Нисходящие службы, такие как парсер, читают этот лог для поиска новой работы.
В совокупности эти элементы образуют уровень управления репозиторием без тех частей, которые агентам не нужны. Запросы на слияние (pull requests) не нужны, поскольку ни один человек не проверяет каждое изменение. Вместо этого служба Git проверяет контракт во время отправки, агент, проигравший гонку, повторно применяет свое собственное изменение, а история коммитов фиксирует, кто и что изменил. Детерминированные проверки удерживают каждый репозиторий в рамках его контракта, вместо того чтобы полагаться на оператора-человека, управляющего ростом.
Хранение: Обеспечение долговечности работы
Уровень хранения надежно сохраняет данные репозитория независимо от песочниц и реплик службы Git. Репозитории размещаются на AWS S3Files, которая предоставляет хранилище на базе S3 через интерфейс файловой системы, который стандартный Git может использовать без модификаций. Каждое хранилище представляет собой «голый» (bare) репозиторий Git в общей файловой системе, содержащий объекты и ссылки репозитория, а не рабочую копию (working checkout).
Отделение хранилища от вычислений позволяет песочницам оставаться эфемерными. Каждый агент получает собственную песочницу, и множество агентов могут работать над одним проектом, не разделяя одну машину. Если песочница аварийно завершает работу, риску подвергается только та работа, которая еще не была отправлена.
Вместо этого мы могли бы выделить каждому проекту долгоживущую песочницу, которую используют все его агенты, так что файлы проекта находились бы на диске этой машины. Однако это привязало бы вычисления агентов к тому месту, где работает машина, и потребовало бы подбора ресурсов под периоды наибольшей нагрузки. Кроме того, она должна была бы оставаться исправной в течение месяцев, а резервное копирование и восстановление управлялись бы как часть системы хранения проекта.
Нисходящая обработка: Чтение документов агентами
Основным нисходящим компонентом является конвейер парсера, который извлекает текст и метаданные из недавно добавленных или обновленных документов, чтобы сделать файлы проекта легко читаемыми для агентов. Воркер парсера обрабатывает обновления из очереди потока изменений, определяет измененные файлы из метаданных коммита и извлекает исходные байты с использованием хеша содержимого. Затем он парсит документ для получения извлеченного текста и метаданных документа.
Результаты парсинга хранятся вне репозитория в хранилище, ключом для которого служит хеш исходного документа. Эти артефакты никогда не коммитятся обратно в репозиторий, так как это ненужным образом засорило бы историю и увеличило количество одновременных записей. Вместо этого результаты парсинга попадают в песочницу посредством извлечения (checkout) и синхронизации. Каждое извлечение содержит зарезервированный каталог, который CLI использует для материализации артефактов. Парсинг происходит асинхронно, поэтому фоновый воркер парсера не блокирует операции извлечения.
Как агенты используют рабочее пространство
Агенты исследуют версию репозитория, загруженную в песочницу, используя стандартные инструменты файловой системы. Вместо того чтобы следовать фиксированному конвейеру «поиск — чтение», они перечисляют папки, ищут содержимое файлов с помощью grep, читают релевантные фрагменты и используют найденное для принятия решения о том, куда смотреть дальше.
Подобно Computer, Search использует тот же подход с помощью стандартных файловых инструментов. Отдельный агент-разведчик выполняет поиск по проекту в рамках более ограниченного бюджета и возвращает релевантные пути к файлам и подтверждающие фрагменты. Затем отвечающая модель читает выбранные файлы и генерирует ответ. Повторное использование существующей проектной песочницы сокращает время настройки: подключение к прогретой рабочей копии занимает около 2,9 секунды по сравнению с примерно 8 секундами для холодного запуска.
Разобранный текст делает более крупные документы, такие как файлы PDF и Office, доступными для поиска с помощью тех же инструментов. Сначала агент проверяет манифест — список, показывающий, для каких документов доступен извлеченный текст, а затем ищет и читает этот текст как обычные файлы. Он загружает исходный документ только тогда текста недостаточно, например, для изучения графиков, макета или встроенных данных.
Мы провели сравнительное тестирование этого подхода со семантическим поиском по индексу на 150 финансовых вопросах по одному документу на том же корпусе. Агент-разведчик набрал 0,867 по извлечению правильного документа и 0,627 по правильности ответов против примерно 0,39 и 0,37 для семантического поиска — примерно в 1,7 раза лучше по ответам и в 2 раза лучше по поиску при примерно на 25% меньшей задержке. Агент-разведчик работает в основном с извлеченным текстом и редко скачивает исходные PDF-файлы.
Единая инфраструктура
Постоянная память Computer использует ту же инфраструктуру файловой системы. PerplexityBrain, база знаний (wiki) Computer, хранит память в репозиториях знаний со своей собственной историей и политиками. Хранение знаний отдельно от файлов проекта означает, что фоновые обновления памяти не конкурируют с правками этих файлов. Сеанс, которому требуется и то, и другое, загружает оба репозитория.
Фоновые агенты читают существующие знания, включают новую информацию и сохраняют обновленные страницы в виде коммитов. Другие агенты читают эти страницы с помощью обычных файловых инструментов, и люди тоже могут их редактировать. Авторы делятся своей работой через репозиторий, а не координируют свои действия напрямую с каждым читателем. История коммитов фиксирует, кто и что изменил, а outbox сообщает об принятых обновлениях в нисходящие службы. Люди и агенты могут опираться на работу друг друга благодаря истории эволюции знаний.
Заключение
Когда люди и агенты работают над общим проектом, рабочее пространство не просто хранит файлы. Оно предоставляет общее место для объединения результатов и отслеживания изменений. Git уже предоставляет большую часть этой основы. Мы добавляем координацию и автоматические проверки, чтобы агенты могли отправлять работу без одобрения каждого обновления человеком. В результате получается хранилище, сведенное к самому необходимому, поскольку межведомственное сотрудничество и разработка программного обеспечения с участием нескольких авторов по своей сути представляют собой одну и ту же задачу.
Агенты работают в независимых временных песочницах, внося свой вклад в постоянные репозитории. Ограничения репозитория позволяют контролировать рост, явные загрузки позволяют агентам выбирать, что именно нужно получить, а обычные файлы позволяют им исследовать окружение с помощью привычных инструментов. Фоновые обновления, интерактивные правки и запланированные задачи могут опираться на результаты работы друг друга без прямой координации.
Поскольку все больше агентов работают автономно в рамках проектов, их общее рабочее пространство должно оставаться надежным и понятным для людей. Цель проста: каждое изменение должно быть более долговечным, чем создавший его агент, стать доступным для следующего соавтора и оставить четкую запись о том, что изменилось.
Цитирование
bibtex











