Бэкенд для асинхронной обработки документов и ответов через retrieval-augmented generation (RAG).
Сервис решает две задачи:
- прием и обработка документов (разбиение на чанки, генерация эмбеддингов, индексация);
- ответы на вопросы с опорой на релевантные фрагменты документов.
- PHP 8.4, Laravel 12
- MySQL 8 (основные сущности и метаданные очередей)
- PostgreSQL 16 + pgvector (векторы и поиск похожих фрагментов)
- Redis (очереди и кэш ответов)
- Nginx + PHP-FPM
- Supervisor (воркеры очередей)
- OpenAI API через Laravel HTTP Client (без SDK)
- L5 Swagger (OpenAPI-документация)
Код разделен по слоям:
app/Domain— контракты и value objects;app/Application— application services и use-case логика;app/Infrastructure— внешние адаптеры (OpenAI, pgvector, queue jobs);app/Http— API-контроллеры и middleware.
Ключевые зависимости инвертированы через интерфейсы:
AIClientInterface->OpenAIClientEmbeddingRepositoryInterface->PgVectorEmbeddingRepository
Привязки находятся в app/Providers/AppServiceProvider.php.
documents:id,title,path,status,error, timestampsdocument_chunks:id,document_id,position,content, timestamps- уникальность чанка:
(document_id, position)
Жизненный цикл документа: queued -> processing -> ready или failed.
Таблица embeddings:
id(bigserial primary key)document_id(bigint)chunk_id(bigint unique)dim(smallint)embedding(vector(<dimension>))- timestamps
Индексы:
- HNSW по
embeddingсvector_cosine_ops - btree по
document_id
POST /api/v1/documentsсохраняет файл и создает запись вdocumentsсо статусомqueued.ProcessDocumentJobпереводит документ вprocessing, читает файл, режет текст на чанки, выполняет upsert вdocument_chunks.- Для документа удаляются старые записи
embeddingsв PostgreSQL. - Создается batch из
GenerateEmbeddingForChunkJob(очередьembeddings). - Каждый job получает эмбеддинг через
AIClientInterfaceи делает upsert поchunk_id. - Batch завершает документ статусом
readyилиfailed(с текстом ошибки).
Реализован в app/Application/Services/RagAnswerService.php:
- валидация входа;
- проверка кэша Redis;
- генерация эмбеддинга вопроса;
searchTopKпо cosine similarity (опционально с фильтрацией поdocument_id);- загрузка контента чанков из MySQL и сборка контекста;
- chat completion;
- кэширование ответа на короткий TTL.
Базовый префикс: /api/v1
| Метод | Путь | Назначение |
|---|---|---|
POST |
/documents |
Загрузка файла и постановка в очередь обработки |
GET |
/documents/{id}/status |
Получение статуса обработки документа |
POST |
/chat/query |
RAG-запрос к документам |
Коды ответов:
POST /documents:202,422GET /documents/{id}/status:200,404,422POST /chat/query:200,422
Интеграция реализована через darkaonline/l5-swagger.
- аннотации:
app/OpenApi/V1Documentation.php - конфигурация:
config/l5-swagger.php - UI:
/api/documentation
Генерация спецификации:
php artisan l5-swagger:generate
# или
composer swagger:generateОсновные группы:
- Core DB:
DB_* - Vector DB:
VECTORS_DB_*(есть fallback наEMBEDDINGS_DB_*) - OpenAI:
OPENAI_* - RAG:
RAG_* - Queue/Cache:
QUEUE_CONNECTION,REDIS_*,CACHE_STORE - Swagger:
L5_SWAGGER_*
Полный перечень — в .env.example.
Требования:
- PHP 8.4+
- Composer 2+
- MySQL 8+
- PostgreSQL 16+ с расширением pgvector
- Redis 7+
Подготовка:
cp .env.example .env
composer install
php artisan key:generateВ PostgreSQL должен быть включен pgvector:
CREATE EXTENSION IF NOT EXISTS vector;Миграции (MySQL + vectors connection):
php artisan migrate --forceЗапуск API и воркера:
php artisan serve --host=0.0.0.0 --port=8000
php artisan queue:work redis --queue=documents,embeddings --sleep=1 --tries=3 --timeout=120Подготовка:
cp .env.example .envУкажите APP_KEY в .env (формат base64:...), затем:
docker compose up -d --build
docker compose exec app php artisan migrate --force
docker compose exec app php artisan l5-swagger:generateПроверка:
- API:
http://localhost:${APP_PORT:-8080}/api/v1/... - Swagger UI:
http://localhost:${APP_PORT:-8080}/api/documentation - health endpoint:
http://localhost:${APP_PORT:-8080}/up
Операционные команды:
docker compose ps
docker compose logs -f app queue nginx
docker compose exec app php artisan test
docker compose down- backend очередей: Redis (
QUEUE_CONNECTION=redis); - очереди:
documentsиembeddings; - fan-out/fan-in реализован через Laravel batch processing;
- в Docker
queueконтейнер запускает workers через Supervisor (docker/supervisor/queue-worker.conf).
Горизонтальное масштабирование:
- увеличивать число workers для
embeddings; - держать ограниченную конкуренцию для
documents(CPU/IO bound задачи); - разделять HTTP runtime и queue runtime.
Набор тестов:
- feature: загрузка документа, статус, RAG endpoint;
- unit:
RagAnswerService; - test doubles:
tests/Fakes/FakeAIClient.php,tests/Fakes/FakeEmbeddingRepository.php.
Тесты не делают внешних API-вызовов и выполняются детерминированно.
Запуск локально:
php artisan testЗапуск в Docker:
docker compose exec app php artisan testApiRequestLoggingMiddleware логирует:
- HTTP-метод;
- путь;
- IP клиента;
- время выполнения (мс).
Middleware подключен к API в bootstrap/app.php.