Зареєструватися Консоль
21 вересня 2026 р.
автори: Vi Tran і Boris Tane

Як ми не даємо мотлоху потрапити в продакшн

Explore with AI

Ви, ймовірно, або будуєте фабрику програмного забезпечення, або орендуєте її в провайдера. У вас є система, яка проводить вас від промпту до pull request. Вона обробляє тести, лінтинг, форматування та автоматизовані рев’ю коду.

Але у вас усе ще немає відповіді на найважливіше питання: чи можна цю зміну випускати в продакшн?.

graph TB
    W["Agent writes the code"] --> T["Types and tests"]
    T --> L["Linter and formatter"]
    L --> R["Code review"]
    R --> Q(["Is this okay for prod?"])
    Q --> D["Deploy"]
    style Q fill:#fee2e2,stroke:#fca5a5,color:#7f1d1d

Усі ваші поточні перевірки дивляться на diff, але ніщо у вашій фабриці не знає нічого про продакшн-систему, на яку цей diff незабаром потрапить. Ніщо насправді не може завадити мотлоху потрапити в продакшн.

Ми реалізували цю можливість у Polylane, і цей пост про технічні деталі того, як ми це зробили.

Як це працює

Єдине питання, на яке ця система має відповісти:

Чи матиме ця зміна, після злиття та розгортання, негативний вплив на продакшн?

Нас насправді не цікавлять типові речі, які перевіряє агент рев’ю коду, такі як стиль, назви, покриття тестами тощо. І ми вирішили відповідати на це питання на етапі pull request, поряд з усіма вашими існуючими тестами.

Зрештою, Polylane залишає коментар до pull request із простим повідомленням «go» / «no-go» та доказами зі свого розслідування.

Процес доволі простий:

  • Чи торкається цей pull request файлів, які можуть вплинути на продакшн?
  • Які хмарні ресурси потенційно зачеплені?
  • Зібрати контекст про поточний стан продакшну для цих ресурсів
  • Оцінити кілька потенційних режимів збою, які може спричинити ця зміна
  • Спрогнозувати, як продакшн може змінитися після розгортання цих змін
  • Попередити розробників про ймовірні потенційні режими збою
polylane bot commented 2 minutes ago ···
Caution

Merging this pull request may degrade production (high impact).

Merging this blocks every write to orders while the index builds. migrations/0114_order_search_trgm.sql:3 adds CREATE INDEX … USING gin (search_text gin_trgm_ops) without CONCURRENTLY, and a plain CREATE INDEX takes a full write lock on orders for the whole build. Checkout sustains ~38 writes/s on that table; each one queues behind the lock until the build finishes.

To make this safe: build the index with CREATE INDEX CONCURRENTLY outside the transactional migration.

orders-db · writes per second · last 48h
0 20 40
-48h -24h now
every one of these writes blocks while the index builds
Висновок no-go: механізм у першому рядку, доказ під ним і те, що зробило б зміну безпечною.

Усе це спирається на контекстний граф, який ми безперервно будуємо, з’єднуючи всі хмарні ресурси у ваших різних хмарних облікових записах.

graph TB
    P["Open pull request"] --> Q(["Meaningful code change?"])
    Q -->|"docs, tests, comments"| C["Conclude the check"]
    Q -->|"yes"| R["Find affected resources<br/>in the context graph"]
    R -->|"none"| C
    R -->|"yes"| E["Gather context"]
    E --> X["Build failure trajectories"]
    X --> F["Forecast the affected series"]
    F --> V["Verdict"]
    V --> C
    style X fill:#fef3c7,stroke:#fcd34d,color:#78350f
    style F fill:#fef3c7,stroke:#fcd34d,color:#78350f
    style V fill:#d1fae5,stroke:#6ee7b7,color:#065f46

Збирання контексту

Наш контекстний граф є ключовим для роботи цієї системи: він будує реєстр усіх ваших хмарних ресурсів, усіх ваших репозиторіїв, команд тощо. Наприклад, обчислювальний вузол, такий як функція Lambda, з’єднаний з базою даних, з якої він читає, і черга, яка його запускає. Ми також додаємо репозиторії до графа. Це робиться шляхом аналізу типових файлів-маніфестів у репозиторії, наприклад файлів terraform, Cloudformation чи Wrangler. Це уможливлює зв’язок між репозиторіями та хмарними ресурсами.

graph LR
    Q["SQS queue<br/>orders-events"] -->|"triggers"| A["Lambda function<br/>checkout-api"]
    R["Repository<br/>checkout-edge"] -->|"deploys_to"| A
    A -->|"connects_to"| D["RDS instance<br/>orders-db"]
    style R fill:#d1fae5,stroke:#6ee7b7,color:#065f46

Коли pull request надсилається до репозиторію, ми проходимо шляхами контекстного графа, щоб зібрати всі хмарні ресурси, потенційно зачеплені зміною. Ми використовуємо малу модель для фільтрації ресурсів, оскільки з одного репозиторію може розгортатися велика кількість ресурсів. Ми передаємо агенту цей контекст разом із diff, описом PR та комітами в PR.

graph LR
    R["Repository"] -->|"deploys_to"| C["Candidate resources"]
    C --> F(["Small model filters"])
    F --> A["Agent"]
    D["Diff, description, commits"] --> A
    style A fill:#d1fae5,stroke:#6ee7b7,color:#065f46

Ми також пропускаємо diff через набір детерміністичних евристик, щоб швидко спрямувати увагу агента на речі, які зазвичай можуть негативно вплинути на продакшн:

  • міграція, яку потрібно застосувати вручну або у певному порядку відносно розгортання
  • CREATE INDEX без CONCURRENTLY, або ADD COLUMN ... NOT NULL без значення за замовчуванням: обидва варіанти блокують таблицю на весь час виконання
  • ендпоінт, який видаляється, тоді як поточна розгорнута версія його все ще читає
  • код, який починає читати змінну середовища, секрет або binding, які нічого в diff не створює

Це рекомендації, які спрямовують агента до ймовірних ризиків розгортання.

Траєкторії збою

З урахуванням наданого вище контексту модель формулює різні режими збою, які новий diff може внести в продакшн, і розслідує кожен з них.

Її результат: реєстр траєкторій збою. Траєкторія є одним причинно-наслідковим ланцюгом від тригера через змінений код до спостережуваного погіршення конкретної метрики, і кожна ланка в ньому має посилання: файл і рядок, шаблон логу з його кількістю, значення метрики, ключ конфігурації, ребро графа.

Перед тим як дійти висновку, агент намагається як підтвердити, так і спростувати кожну траєкторію. Кожна завершується одним із трьох станів:

  • confirmed, коли траєкторію підтверджено на основі продакшну.
  • plausible, коли ланцюг конкретний, але одну або кілька ланок можна було лише «припустити» без даних телеметрії, що це підтверджують.
  • refuted, коли дані телеметрії продакшну надали достатньо доказів, що ця траєкторія навряд чи станеться в продакшні.

Ми дотримуємося консервативного підходу, і будь-яка траєкторія confirmed призводить до негативної оцінки.

export function deriveTrajectoryVerdict(trajectories: Trajectory[]): "pass" | "fail" {
  return trajectories.some((entry) => entry.status === "confirmed") ? "fail" : "pass";
}

graph LR
    D["The diff"] --> T1["Dropped index still<br/>used by checkout"]
    D --> T2["Retry change amplifies<br/>load on orders-db"]
    D --> T3["Removed binding<br/>breaks the worker"]
    T1 --> C1["confirmed"]
    T2 --> C2["plausible"]
    T3 --> C3["refuted"]
    C1 --> V["No-go"]
    C2 --> V
    C3 --> V
    style C1 fill:#fee2e2,stroke:#fca5a5,color:#7f1d1d
    style C2 fill:#dbeafe,stroke:#93c5fd,color:#1e3a8a
    style C3 fill:#d1fae5,stroke:#6ee7b7,color:#065f46
    style V fill:#fee2e2,stroke:#fca5a5,color:#7f1d1d

Прогнозування впливу

Ми надаємо агенту інструмент для прогнозування часових рядів на основі історичних даних із врахуванням потенційних зовнішніх факторів.

Скажімо, траєкторія стверджує, що якась зміна вдвічі зменшує таймаут на шляху, де відбуваються повторні спроби. Чи це має значення, залежить від трафіку, а трафік насправді не одне число, у нього є форма. Черга, яка тримається на рівні 60% заповненості й лишається там, це нормально. Та ж черга на рівні 60%, але яка зростає щотижня, це вже інша ситуація, і читання метрик за останню годину не скаже вам, яку саме ситуацію ви бачите.

Тож перед тим як агент формулює висновок щодо траєкторії, він отримує історичні ряди для зачеплених ресурсів і прогнозує їх разом. Наразі ми самостійно хостимо модель Toto-2.0-22m.

graph LR
    A["Agent"] -->|"telemetry query"| P["Provider"]
    P -->|"aligned series"| A
    A -->|"up to 16 series"| M["Forecasting model"]
    M -->|"p10, p50, p90"| A
    style M fill:#fef3c7,stroke:#fcd34d,color:#78350f

Причина використання окремої багатовимірної моделі, а не ще одного промпту, у тому, що ряди не є незалежними. Частота запитів, частота помилок, латентність і глибина черги для одного ресурсу рухаються разом, і прогнозування кожного окремо відкидає кореляцію, яка робить прогноз цінним. Усі ряди в одному викликі спільно використовують одну групу уваги.

Це найбільш експериментальна можливість, яку ми недавно додали, і ми досі вимірюємо її вплив. Але вона вже проходить vibes-eval.

checkout-api request forecast
Hourly observations from the latest 64 complete buckets, followed by a 24-hour probabilistic forecast.
observed p10–p90 forecast
20,000 25,000 30,000 35,000 Forecast starts Sep 18 00:00 Sep 18 20:00 Sep 19 16:00 Sep 20 12:00 Sep 21 08:00 Time (UTC) Requests per hour
Рисунок 2
Приклад того, як працює прогноз
На вхід подаються 64 погодинні спостереження одного зачепленого ресурсу, а на виході отримуємо 24 години медіани та p10-p90. Смуга розширюється з горизонтом, і агент читає саме смугу, а не лише медіану: p10, що лишається вище порогу, від якого залежить траєкторія, це інша відповідь, ніж той, що його перетинає.

Обмеження латентності

Запуск оцінки впливу на продакшн у процесі pull request означає, що вона має бути швидкою. Нікому не потрібен крок, який додає 15 хвилин до CI-пайплайну. Наприклад, у наших власних репозиторіях ця оцінка є обов’язковим кроком CI, і якщо вона повільна, весь наш SDLC застрягає.

У нас фактично є бюджет від 2 до 3 хвилин, щоб отримати точну оцінку впливу. Усе, що виходить за ці межі, неприйнятне в CI/CD-пайплайні.

Наш перший прототип повністю не вкладався в це обмеження. Наша медіана становила майже 7 хвилин, і було звичним бачити запуски, що тривали до 20 хвилин.

0 s 60 s 120 s 180 s 240 s 300 s Пролог webhook, записи, diff 7.4 s Пісочниця клонування head 16.5 s Раунд рев'ю 242.4 s Доставка check run, коментар 3 s Неврахований час 38.6 s
Рисунок 3
Медіанна латентність кожного з кроків запуску оцінки впливу на продакшн
Медіани в продакшні, 15 вересня 2026, за 325 запусків. Кожна фаза має власну медіану, тож неврахований блок наприкінці це очікування між фазами плюс арифметика додавання медіан.

Метою стало з’ясувати, як зменшити кількість кроків моделі, щоб увести весь процес у межі 3 хвилин. Зазвичай ми виконували від 30 до 40 послідовних кроків моделі, а в найгірших сценаріях до майже 600 кроків, кожен з яких споживав 17 секунд нашого бюджету, і переважна більшість їхнього виводу становили токени міркування.

За останні 3 тижні ми внесли чимало змін із різним впливом на продуктивність. Ось найважливіші з них.

Встановлення бюджету кроків і повідомлення про нього агенту

Ми впровадили бюджет кроків, обмежений 30 кроками на хід агента, і на кожному кроці чітко повідомляємо моделі, скільки кроків вона вже витратила. Розміщення лічильника в промпті дозволяє моделі планувати навколо нього, і виявляється, що це має більше значення, ніж саме число.

graph TB
    A["Turn starts, 30 steps"] --> B["Model step"]
    B --> T["Tool call"]
    T --> C(["Steps left?"])
    C -->|"1"| E["Record the verdict now"]
    C -->|"more"| R["Next step, carrying<br/>the count in the prompt"]
    R --> B
    style R fill:#fef3c7,stroke:#fcd34d,color:#78350f
    style E fill:#d1fae5,stroke:#6ee7b7,color:#065f46

Запуск нових рев’ю замість додавання до наявного

Типовий pull request продовжує отримувати нові коміти після відкриття. У першому прототипі ми додавали весь новий diff у той самий тред рев’ю як спрямовуюче повідомлення користувача. Це спрямування сильно збивало модель з пантелику і призводило до повторного читання файлів, які вона вже перевірила, і повторного запуску запитів телеметрії, які вона вже виконала.

Тепер новий коміт скасовує попередній запуск оцінки і запускає повністю новий тред. Це може здатися нелогічним, але в результаті це знизило латентність повних рев’ю.

Повторне використання попередньої роботи

Коли новий коміт з’являється в pull request після того, як рев’ю вже було завершено, раніше ми наївно починали нову оцінку впливу з нуля.

Ми впровадили можливість повторно використовувати попередню оцінку і запускати нову оцінку лише для меншого diff між двома послідовними комітами.

Ми розгортали ці зміни протягом вересня і поступово покращували латентність, і тепер латентність комфортно вкладається в бюджет.

0 с 150 с 300 с 450 с 600 с 27 Aug 31 Aug 4 Sep 8 Sep 12 Sep 16 Sep 94
Рисунок 4
Медіанна латентність ходу оцінки впливу

Чи це взагалі має значення?

Який сенс спалювати всі ці токени, якщо ми не бачимо жодних значущих результатів? Наша метрика успіху це кількість інцидентів, які ми запобігаємо щотижня для кожного з наших клієнтів. Запобіжений інцидент це pull request, де:

  • ми позначаємо потенційний ризик для продакшну
  • інженер пушить один або кілька комітів
  • нова оцінка робить висновок, що потенційний ризик усунено
  • pull request зливається
2.3
Запобігнутих інцидентів у продакшні на клієнта щотижня

Це вже досить значуще число, і ми очікуємо, що воно продовжить зростати. Ми безперервно ітеруємо і проводимо evals, щоб покращити продуктивність та якість нашого агента.

Ніхто не має бути на чергуванні. Polylane стежить за вашою інфраструктурою, розслідує і виправляє те, що ламається.

Зареєструватися

Читати далі

14 вер. 2026 р. Sub-agents are just wrong Polylane's autofix used to be a workflow of multiple agents, each responsible for a single task, with an orchestrator managing state between them. We moved to a single agent which does the entire job, from evidence gathering, hypothesis testing to pull request. 26 серп. 2026 р. Як ми виправили помилки перевищення пам'яті в наших Cloudflare Durable Objects Cloudflare Durable Objects працюють в ізолятах V8 із жорстким лімітом 128 МБ. Наші в простої займали ~140 МБ і скидалися ~300 разів на день. 130 МБ схем zod будувалися під час завантаження модулів, більшість із них кодом, який ніколи не викликався. Як ми профілювали продакшн-бандл, два виправлення і цифри: з 218 МБ до 82 МБ і скидання до нуля. 5 лип. 2026 р. Я ставлю свою компанію на проактивних агентів Агенти можуть зробити майже все, про що ви попросите. У цьому й проблема, вам усе одно треба просити. Наступна еволюція: агенти, які самі з'ясовують, яку роботу треба зробити. Я почав з експлуатації, бо у 2026 році ніхто не має бути на чергуванні.