Перейти к основному содержанию

Потоковая передача + чанкинг

В OpenClaw есть два отдельных слоя «потоковой передачи»:
  • Блоковая потоковая передача (каналы): выдаёт завершённые блоки по мере того, как ассистент пишет. Это обычные сообщения канала (не дельты токенов).
  • Токеноподобная потоковая передача (только Telegram): обновляет черновой пузырёк частичным текстом во время генерации; финальное сообщение отправляется в конце.
На сегодня реальной потоковой передачи токенов во внешние сообщения каналов нет. Черновая потоковая передача Telegram — единственная поверхность частичного стриминга.

Блоковая потоковая передача (сообщения канала)

Блоковая потоковая передача отправляет вывод ассистента крупными фрагментами по мере их готовности.
Model output
  └─ text_delta/events
       ├─ (blockStreamingBreak=text_end)
       │    └─ chunker emits blocks as buffer grows
       └─ (blockStreamingBreak=message_end)
            └─ chunker flushes at message_end
                   └─ channel send (block replies)
Легенда:
  • text_delta/events: события стрима модели (могут быть редкими для моделей без стриминга).
  • chunker: EmbeddedBlockChunker с применением минимальных/максимальных границ + предпочтений разбиения.
  • channel send: фактические исходящие сообщения (блочные ответы).
Управление:
  • agents.defaults.blockStreamingDefault: "on"/"off" (по умолчанию выключено).
  • Переопределения канала: *.blockStreaming (и варианты на аккаунт) для принудительного "on"/"off" для каждого канала.
  • agents.defaults.blockStreamingBreak: "text_end" или "message_end".
  • agents.defaults.blockStreamingChunk: { minChars, maxChars, breakPreference? }.
  • agents.defaults.blockStreamingCoalesce: { minChars?, maxChars?, idleMs? } (объединять стриминговые блоки перед отправкой).
  • Жёсткий лимит канала: *.textChunkLimit (например, channels.whatsapp.textChunkLimit).
  • Режим чанкинга канала: *.chunkMode (length по умолчанию, newline разбивает по пустым строкам (границы абзацев) перед разбиением по длине).
  • Мягкий лимит Discord: channels.discord.maxLinesPerMessage (по умолчанию 17) разбивает «высокие» ответы, чтобы избежать обрезки интерфейсом.
Семантика границ:
  • text_end: стримить блоки сразу, как только чанкер их выдаёт; сбрасывать на каждом text_end.
  • message_end: ждать завершения сообщения ассистента, затем сбросить буферизованный вывод.
message_end всё ещё использует чанкер, если буферизованный текст превышает maxChars, поэтому в конце может быть выдано несколько чанков.

Алгоритм чанкинга (нижняя/верхняя границы)

Блочный чанкинг реализован через EmbeddedBlockChunker:
  • Нижняя граница: не выдавать, пока буфер < minChars (если не принудительно).
  • Верхняя граница: предпочитать разбиение до maxChars; при принуждении — разрезать на maxChars.
  • Предпочтения разрыва: paragraphnewlinesentencewhitespace → жёсткий разрыв.
  • Кодовые блоки: никогда не разрывать внутри fences; при принуждении на maxChars закрывать и заново открывать fence, чтобы Markdown оставался валидным.
maxChars ограничивается значением канала textChunkLimit, поэтому превышать лимиты конкретного канала нельзя.

Коалесцирование (объединение стриминговых блоков)

Когда включена блоковая потоковая передача, OpenClaw может объединять последовательные блочные чанки перед отправкой. Это снижает «спам из одиночных строк», сохраняя при этом поступательный вывод.
  • Коалесцирование ждёт периоды простоя (idleMs) перед сбросом.
  • Буферы ограничены maxChars и будут сброшены при превышении.
  • minChars предотвращает отправку крошечных фрагментов, пока не накопится достаточно текста (финальный сброс всегда отправляет оставшийся текст).
  • Соединитель выводится из blockStreamingChunk.breakPreference (paragraph\n\n, newline\n, sentence → пробел).
  • Переопределения канала доступны через *.blockStreamingCoalesce (включая конфиги на аккаунт).
  • Значение коалесцирования по умолчанию minChars увеличено до 1500 для Signal/Slack/Discord, если не переопределено.

Человеко-подобный темп между блоками

Когда включена блоковая потоковая передача, можно добавить рандомизированную паузу между блочными ответами (после первого блока). Это делает ответы из нескольких пузырьков более естественными.
  • Конфиг: agents.defaults.humanDelay (переопределение для агента через agents.list[].humanDelay).
  • Режимы: off (по умолчанию), natural (800–2500 мс), custom (minMs/maxMs).
  • Применяется только к блочным ответам, а не к финальным ответам или сводкам инструментов.

«Стримить чанки или всё целиком»

Это сопоставляется так:
  • Стримить чанки: blockStreamingDefault: "on" + blockStreamingBreak: "text_end" (выдавать по ходу). Для не-Telegram каналов также требуется *.blockStreaming: true.
  • Стримить всё в конце: blockStreamingBreak: "message_end" (один сброс, возможно несколькими чанками, если очень длинно).
  • Без блоковой потоковой передачи: blockStreamingDefault: "off" (только финальный ответ).
Примечание по каналам: для не-Telegram каналов блоковая потоковая передача выключена, если только *.blockStreaming явно не установлен в true. Telegram может стримить черновики (channels.telegram.streamMode) без блочных ответов. Напоминание о расположении конфига: значения по умолчанию blockStreaming* находятся в agents.defaults, а не в корневом конфиге.

Черновая потоковая передача Telegram (токеноподобная)

Telegram — единственный канал с черновой потоковой передачей:
  • Использует Bot API sendMessage (первое обновление) + editMessageText (последующие обновления).
  • channels.telegram.streamMode: "partial" | "block" | "off".
    • partial: обновления черновика с последним стрим-текстом.
    • block: обновления черновика блочными чанками (те же правила чанкинга).
    • off: без черновой потоковой передачи.
  • Конфиг чанков черновика (только для streamMode: "block"): channels.telegram.draftChunk (значения по умолчанию: minChars: 200, maxChars: 800).
  • Стриминг предпросмотра выполняется отдельно от стриминга блоков.
  • Когда активна черновая потоковая передача, OpenClaw отключает блоковую потоковую передачу для этого ответа, чтобы избежать двойного стриминга.
  • Текстовые финальные ответы применяются путем редактирования сообщения предпросмотра на месте.
  • Нетекстовые/сложные финальные ответы отправляются как обычные финальные сообщения.
  • /reasoning stream записывает рассуждения в черновой пузырёк (только Telegram).
Telegram (private + topics)
  └─ sendMessageDraft (draft bubble)
       ├─ streamMode=partial → update latest text
       └─ streamMode=block   → chunker updates draft
  └─ final reply → normal message
Легенда:
  • preview message: временное сообщение Telegram, обновляемое во время генерации.
  • final edit: редактирование на месте того же сообщения предпросмотра (только текст).