Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як показувати відповідь LLM чи довгий процес у Livewire по частинах через wire:stream?

Звичайна дія Livewire повертає результат один раз, наприкінці. Для відповіді чат-бота, що генерується 20 секунд, користувач бачив би порожній екран усі 20 секунд. wire:stream дає змогу відправляти частини відповіді в браузер під час виконання дії.

new class extends Component {
    public string $prompt = '';
    public string $question = '';
    public string $answer = '';

    public function submitPrompt(): void
    {
        $this->question = $this->prompt;
        $this->prompt = '';
        $this->answer = '';

        $this->js('$wire.ask()');   // друга дія - вже після того, як поле очистилося
    }

    public function ask(): void
    {
        // streamAnswer() - генератор над будь-яким клієнтом LLM зі стримінгом
        foreach ($this->streamAnswer($this->question) as $chunk) {
            $this->answer .= $chunk;
            $this->stream(to: 'answer', content: $chunk);
        }
    }
};
<p wire:stream="answer">{{ $answer }}</p>

<form wire:submit="submitPrompt">
    <input wire:model="prompt" placeholder="Ваше питання">
</form>

Як це працює: відповідь на запит ask() стає потоковою: кожен $this->stream() одразу відправляє шматок у браузер, і Livewire дописує його в елемент з wire:stream="answer". Коли метод завершується, приходить звичайна фінальна відповідь з повним станом компонента.

Параметри stream():

  • to: - назва цілі (значення wire:stream в шаблоні);
  • content: - текст;
  • replace: true - замінити вміст замість дописування (для індикатора прогресу «Оброблено 40%»).

Чому дві дії (submitPrompt + ask): перша швидко повертає відповідь - поле введення очищується, питання з'являється на екрані. Друга вже стрімить відповідь.

Що враховувати в продакшені:

  • процес PHP зайнятий весь час стримінгу. Двадцять секунд генерації - двадцять секунд зайнятого воркера PHP-FPM. При багатьох одночасних користувачах це вичерпує пул; доречні Octane/FrankenPHP чи винесення генерації в чергу з трансляцією результату через Reverb;
  • буферизація по дорозі: проксі (Nginx proxy_buffering, CDN), стиснення відповідей можуть накопичувати шматки й віддавати все наприкінці. Потрібно вимкнути буферизацію для цих запитів;
  • тайм-аути: max_execution_time, тайм-аути проксі й балансувальника мають покривати найдовшу генерацію;
  • зберігати повний результат у властивості ($this->answer .= $chunk) - інакше після фінальної відповіді та наступного рендеру текст зникне;
  • XSS: потоковий вміст вставляється як текст, але якщо ви рендерите відповідь як Markdown/HTML, санітизуйте її на сервері.

Альтернативи: response()->eventStream() з SSE у звичайному маршруті Laravel, якщо компонентна модель не потрібна.

Докладніше в документації: wire:stream

Схожі питання