Перейти до вмісту

Інференс на PHP: RAG без Python-сервісу

Інференс на PHP: RAG без Python-сервісу

Клієнт просить семантичний пошук по каталогу з сорока тисяч товарів. Відповідь приходить раніше за запитання: підняти Python-сервіс, завантажити sentence-transformer, обгорнути все в HTTP, викликати з PHP.

Код: FerryAI, ліцензія MIT.

План робочий. Він же додає ще один рантайм, окремий конвеєр викладки, менеджер процесів, перевірку живучості й мережевий перехід на кожен запит. Для функції, яка повертає дванадцять товарів, інфраструктура більша за функцію.

Інференс на PHP прибирає посередника. FerryAI завантажує ONNX Runtime і llama.cpp через FFI у тому самому процесі, який віддає сторінку, і виклик моделі стає викликом функції.

Скільки коштує окремий сервіс

Рахунок іде не за модель, а за все навколо неї.

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

Пам’ять тихо дорожча за все. Сервіс на вісім воркерів PHP або масштабує свій пул, або вибудовує запити в чергу за одним екземпляром моделі. В обох випадках за модель платять двічі: у Python і в сторінці, яка її покликала.

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

Що працює всередині процесу

Ембединги дає ONNX Runtime. Підходить будь-яка модель .onnx, а sentence-transformer на кшталт all-MiniLM-L6-v2 повертає вектори розмірності 384 для семантичного пошуку. GPU-провайдери підхоплюються, коли вони є, і виклик відкочується на CPU, якщо встановлення CUDA неповне. Тихе відкочування це правильна поведінка для веб-запиту: повільна відповідь краща за п’ятисоту помилку.

Генерація йде з llama.cpp через бібліотеку-обгортку з тим самим мостом FFI. Чат, потокова видача по токенах і вивід за граматикою працюють локально на CPU або CUDA. Граматика важливіша, ніж здається: передана JSON-схема обмежує семплер, і модель не може повернути невалідний JSON. Це знімає клас помилок парсингу, який регулярка з повторенням не лікує ніколи.

Вектори лежать у SQLite або в PostgreSQL із pgvector. SQLite використовує sqlite-vec для нативного індексу найближчих сусідів, де розширення доступне, і перебір інакше, що нормально до кількох сотень тисяч рядків. PostgreSQL із pgvector тримає індекси HNSW і паралельний запис, і це варіант для бойового каталогу.

Ніщо з переліченого не потребує Python у рантаймі.

Де інференс на PHP зазвичай ламається

Перший бар’єр це нативні бібліотеки. Об’єкт, зібраний під іншу архітектуру, відсутня бібліотека CUDA, токенізатор, який чекає не той формат, що лежить у теці моделі. У комплекті є діагностика ferry-ai check: вона показує версію PHP, розширення, доступні бекенди й стан кешу до того, як перший запит упаде на бойовому сервері.

Другий це завантаження моделей. Скачувати 90 мегабайт під час старту неприпустимо, тому модель забирається один раз із HuggingFace, перевіряється за SHA-256 і лежить у кеші з обмеженням розміру. Обірване завантаження повторюється за замовчуванням, а не як виняток.

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

Коли окремий сервіс усе ще правильний

Донавчання на великих даних, важкі пакетні задачі на GPU або команда, яка вже веде Python-сервіси з нормальним моніторингом. Якщо моделі потрібен розподілений конвеєр навчання, PHP не те місце.

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

Що отримує клієнт

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

FerryAI поширюється за MIT, вимагає PHP 8.3 і розширення FFI, показує 793 тести, що проходять, і PHPStan рівня 8. Це ранній реліз: фіксуйте версію й читайте список змін під час оновлення.

Докладніше про те, як ми збираємо пошукову частину: RAG-розробка. Про стек під нею: розробка на PHP. Найменша версія тієї самої архітектури, одне дерево JSON за ендпоінтом MCP, розібрана в статті про біо сторінку на власному сервері.

Що почитати: ONNX Runtime і llama.cpp.