trustgraph/docs/tech-specs/streaming-llm-responses.ru.md
Alex Jenkins 8954fa3ad7 Feat: TrustGraph i18n & Documentation Translation Updates (#781)
Native CLI i18n: The TrustGraph CLI has built-in translation support
that dynamically loads language strings. You can test and use
different languages by simply passing the --lang flag (e.g., --lang
es for Spanish, --lang ru for Russian) or by configuring your
environment's LANG variable.

Automated Docs Translations: This PR introduces autonomously
translated Markdown documentation into several target languages,
including Spanish, Swahili, Portuguese, Turkish, Hindi, Hebrew,
Arabic, Simplified Chinese, and Russian.
2026-04-14 12:08:32 +01:00

28 KiB
Raw Blame History

layout title parent
default Техническая спецификация потоковой передачи ответов LLM Russian (Beta)

Техническая спецификация потоковой передачи ответов LLM

Beta Translation: This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.

Обзор

Эта спецификация описывает реализацию поддержки потоковой передачи для ответов LLM в TrustGraph. Потоковая передача обеспечивает доставку сгенерированных токенов в режиме реального времени по мере их создания LLM, а не после завершения полной генерации ответа.

Эта реализация поддерживает следующие сценарии использования:

  1. Интерфейсы пользователя в реальном времени: Передавайте токены в пользовательский интерфейс по мере их генерации, обеспечивая немедленную визуальную обратную связь.
  2. Сокращение времени до первого токена: Пользователи видят вывод сразу, а не после полной генерации.
  3. Обработка очень длинных ответов: Обрабатывайте очень длинные ответы, которые в противном случае могли бы привести к таймаутам или превышению лимитов памяти.
  4. Интерактивные приложения: Обеспечьте отзывчивые чат-интерфейсы и интерфейсы агентов.

Цели

Обратная совместимость: Существующие клиенты, не использующие потоковую передачу, продолжают работать без изменений. Согласованный дизайн API: Потоковая передача и не потоковая передача используют одни и те же схемы с минимальными отклонениями. Гибкость для поставщиков: Поддержка потоковой передачи, где это возможно, и плавный переход к не потоковой передаче, где это невозможно. Поэтапное внедрение: Постепенная реализация для снижения рисков. Комплексная поддержка: Потоковая передача от поставщика LLM до клиентских приложений через Pulsar, Gateway API и Python API.

Обзор

Текущая архитектура

Текущий процесс текстового завершения LLM работает следующим образом:

  1. Клиент отправляет TextCompletionRequest с полями system и prompt.
  2. Сервис LLM обрабатывает запрос и ожидает полной генерации.
  3. Возвращается один TextCompletionResponse с полной строкой response.

Текущая схема (trustgraph-base/trustgraph/schema/services/llm.py):

class TextCompletionRequest(Record):
    system = String()
    prompt = String()

class TextCompletionResponse(Record):
    error = Error()
    response = String()
    in_token = Integer()
    out_token = Integer()
    model = String()

Текущие ограничения

Задержка: Пользователи должны ждать завершения генерации, прежде чем увидеть какой-либо результат. Риск превышения времени ожидания: Длительная генерация может превысить лимиты времени ожидания клиента. Плохой пользовательский опыт: Отсутствие обратной связи во время генерации создает ощущение медленной работы. Использование ресурсов: Полные ответы должны быть буферизованы в памяти.

Эта спецификация решает эти ограничения, обеспечивая постепенную передачу ответа, при этом сохраняя полную обратную совместимость.

Техническое проектирование

Фаза 1: Инфраструктура

Фаза 1 закладывает основу для потоковой передачи путем изменения схем, API и инструментов командной строки.

Изменения в схемах

Схема LLM (trustgraph-base/trustgraph/schema/services/llm.py)

Изменения в запросах:

class TextCompletionRequest(Record):
    system = String()
    prompt = String()
    streaming = Boolean()  # NEW: Default false for backward compatibility

streaming: Когда true, запрашивается потоковая доставка ответа. По умолчанию: false (сохранено существующее поведение).

Изменения в ответе:

class TextCompletionResponse(Record):
    error = Error()
    response = String()
    in_token = Integer()
    out_token = Integer()
    model = String()
    end_of_stream = Boolean()  # NEW: Indicates final message

end_of_stream: Когда true, указывает на то, что это окончательный (или единственный) ответ. Для нестриминговых запросов: Один ответ с end_of_stream=true. Для стриминговых запросов: Множественные ответы, все с end_of_stream=false, за исключением последнего.

Схема запроса (trustgraph-base/trustgraph/schema/services/prompt.py)

Сервис запросов оборачивает завершение текста, поэтому он следует той же схеме:

Изменения в запросе:

class PromptRequest(Record):
    id = String()
    terms = Map(String())
    streaming = Boolean()  # NEW: Default false

Изменения в ответе:

class PromptResponse(Record):
    error = Error()
    text = String()
    object = String()
    end_of_stream = Boolean()  # NEW: Indicates final message

Изменения API шлюза

API шлюз должен предоставлять возможности потоковой передачи данных для клиентов HTTP/WebSocket.

Обновления REST API:

POST /api/v1/text-completion: Принимать параметр streaming в теле запроса Поведение ответа зависит от флага потоковой передачи: streaming=false: Одиночный ответ в формате JSON (текущее поведение) streaming=true: Поток событий от сервера (SSE) или сообщения WebSocket

Формат ответа (потоковая передача):

Каждый фрагмент, передаваемый потоком, имеет одинаковую структуру схемы:

{
  "response": "partial text...",
  "end_of_stream": false,
  "model": "model-name"
}

Заключительный раздел:

{
  "response": "final text chunk",
  "end_of_stream": true,
  "in_token": 150,
  "out_token": 500,
  "model": "model-name"
}

Изменения в API Python

API клиента Python должен поддерживать как потоковый, так и не потоковый режимы, при этом сохраняя обратную совместимость.

Обновления LlmClient (trustgraph-base/trustgraph/clients/llm_client.py):

class LlmClient(BaseClient):
    def request(self, system, prompt, timeout=300, streaming=False):
        """
        Non-streaming request (backward compatible).
        Returns complete response string.
        """
        # Existing behavior when streaming=False

    async def request_stream(self, system, prompt, timeout=300):
        """
        Streaming request.
        Yields response chunks as they arrive.
        """
        # New async generator method

Обновления PromptClient (trustgraph-base/trustgraph/base/prompt_client.py):

Аналогичный шаблон с параметром streaming и вариантом асинхронного генератора.

Изменения инструмента командной строки

tg-invoke-llm (trustgraph-cli/trustgraph/cli/invoke_llm.py):

tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id]

По умолчанию включен режим потоковой передачи для улучшения интерактивного пользовательского опыта. Флаг --no-streaming отключает режим потоковой передачи. В режиме потоковой передачи: выводите токены в стандартный вывод по мере их поступления. В режиме, когда потоковая передача отключена: дождитесь получения полного ответа, а затем выведите его.

tg-invoke-prompt (trustgraph-cli/trustgraph/cli/invoke_prompt.py):

tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id]

Такой же шаблон, как у tg-invoke-llm.

Изменения базового класса LLM Service.

LlmService (trustgraph-base/trustgraph/base/llm_service.py):

class LlmService(FlowProcessor):
    async def on_request(self, msg, consumer, flow):
        request = msg.value()
        streaming = getattr(request, 'streaming', False)

        if streaming and self.supports_streaming():
            async for chunk in self.generate_content_stream(...):
                await self.send_response(chunk, end_of_stream=False)
            await self.send_response(final_chunk, end_of_stream=True)
        else:
            response = await self.generate_content(...)
            await self.send_response(response, end_of_stream=True)

    def supports_streaming(self):
        """Override in subclass to indicate streaming support."""
        return False

    async def generate_content_stream(self, system, prompt, model, temperature):
        """Override in subclass to implement streaming."""
        raise NotImplementedError()

--

Фаза 2: Проверка концепции VertexAI

Фаза 2 реализует потоковую передачу данных в одном провайдере (VertexAI) для проверки инфраструктуры и обеспечения сквозного тестирования.

Реализация VertexAI

Модуль: trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py

Изменения:

  1. Переопределить supports_streaming() для возврата True
  2. Реализовать асинхронный генератор generate_content_stream()
  3. Поддержка моделей Gemini и Claude (через VertexAI Anthropic API)

Потоковая передача данных Gemini:

async def generate_content_stream(self, system, prompt, model, temperature):
    model_instance = self.get_model(model, temperature)
    response = model_instance.generate_content(
        [system, prompt],
        stream=True  # Enable streaming
    )
    for chunk in response:
        yield LlmChunk(
            text=chunk.text,
            in_token=None,  # Available only in final chunk
            out_token=None,
        )
    # Final chunk includes token counts from response.usage_metadata

Claude (через VertexAI Anthropic) в режиме потоковой передачи:

async def generate_content_stream(self, system, prompt, model, temperature):
    with self.anthropic_client.messages.stream(...) as stream:
        for text in stream.text_stream:
            yield LlmChunk(text=text)
    # Token counts from stream.get_final_message()

Тестирование

Юнит-тесты для сборки потоковых ответов Интеграционные тесты с VertexAI (Gemini и Claude) Комплексные тесты: CLI -> Gateway -> Pulsar -> VertexAI -> back Тесты обратной совместимости: Непотоковые запросы по-прежнему работают

--

Фаза 3: Все провайдеры LLM

Фаза 3 расширяет поддержку потоковой передачи для всех провайдеров LLM в системе.

Статус реализации для каждого провайдера

Каждый провайдер должен либо:

  1. Полная поддержка потоковой передачи: Реализовать generate_content_stream()
  2. Режим совместимости: Правильно обрабатывать флаг end_of_stream (возвращать единый ответ с end_of_stream=true)
Провайдер Пакет Поддержка потоковой передачи
OpenAI trustgraph-flow Полная (нативная API потоковой передачи)
Claude/Anthropic trustgraph-flow Полная (нативная API потоковой передачи)
Ollama trustgraph-flow Полная (нативная API потоковой передачи)
Cohere trustgraph-flow Полная (нативная API потоковой передачи)
Mistral trustgraph-flow Полная (нативная API потоковой передачи)
Azure OpenAI trustgraph-flow Полная (нативная API потоковой передачи)
Google AI Studio trustgraph-flow Полная (нативная API потоковой передачи)
VertexAI trustgraph-vertexai Полная (Фаза 2)
Bedrock trustgraph-bedrock Полная (нативная API потоковой передачи)
LM Studio trustgraph-flow Полная (совместима с OpenAI)
LlamaFile trustgraph-flow Полная (совместима с OpenAI)
vLLM trustgraph-flow Полная (совместима с OpenAI)
TGI trustgraph-flow Будет определено
Azure trustgraph-flow Будет определено

Шаблон реализации

Для провайдеров, совместимых с OpenAI (OpenAI, LM Studio, LlamaFile, vLLM):

async def generate_content_stream(self, system, prompt, model, temperature):
    response = await self.client.chat.completions.create(
        model=model,
        messages=[
            {"role": "system", "content": system},
            {"role": "user", "content": prompt}
        ],
        temperature=temperature,
        stream=True
    )
    async for chunk in response:
        if chunk.choices[0].delta.content:
            yield LlmChunk(text=chunk.choices[0].delta.content)

--

Фаза 4: API агента

Фаза 4 расширяет потоковую передачу на API агента. Это более сложный процесс, поскольку API агента изначально предназначен для работы с несколькими сообщениями (мысль → действие → наблюдение → повтор → окончательный ответ).

Текущая схема агента

class AgentStep(Record):
    thought = String()
    action = String()
    arguments = Map(String())
    observation = String()
    user = String()

class AgentRequest(Record):
    question = String()
    state = String()
    group = Array(String())
    history = Array(AgentStep())
    user = String()

class AgentResponse(Record):
    answer = String()
    error = Error()
    thought = String()
    observation = String()

Предлагаемые изменения схемы агента

Запрос изменений:

class AgentRequest(Record):
    question = String()
    state = String()
    group = Array(String())
    history = Array(AgentStep())
    user = String()
    streaming = Boolean()  # NEW: Default false

Изменения в ответах:

Агент генерирует несколько типов выходных данных в процессе рассуждения: Мысли (рассуждения) Действия (вызовы инструментов) Наблюдения (результаты работы инструментов) Ответ (окончательный ответ) Ошибки

Поскольку chunk_type указывает на тип передаваемого контента, отдельные поля answer, error, thought и observation можно объединить в одно поле content:

class AgentResponse(Record):
    chunk_type = String()       # "thought", "action", "observation", "answer", "error"
    content = String()          # The actual content (interpretation depends on chunk_type)
    end_of_message = Boolean()  # Current thought/action/observation/answer is complete
    end_of_dialog = Boolean()   # Entire agent dialog is complete

Семантика полей:

chunk_type: Указывает, какой тип содержимого находится в поле content "thought": Рассуждения/мысли агента "action": Используемый инструмент/действие "observation": Результат выполнения инструмента "answer": Окончательный ответ на вопрос пользователя "error": Сообщение об ошибке

content: Фактическое потоковое содержимое, интерпретируемое на основе chunk_type

end_of_message: Когда true, текущий тип фрагмента завершен Пример: Все токены для текущей мысли были отправлены Позволяет клиентам знать, когда переходить к следующему этапу

end_of_dialog: Когда true, все взаимодействие с агентом завершено Это последнее сообщение в потоке

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

Когда streaming=true:

  1. Потоковая передача мыслей: Несколько фрагментов с chunk_type="thought", end_of_message=false Последний фрагмент мысли содержит end_of_message=true
  2. Уведомление о действии: Один фрагмент с chunk_type="action", end_of_message=true
  3. Наблюдение: Один или несколько фрагментов с chunk_type="observation", последний содержит end_of_message=true
  4. Повторяйте шаги 1-3, пока агент рассуждает
  5. Окончательный ответ: chunk_type="answer" с окончательным ответом в content Последний фрагмент содержит end_of_message=true, end_of_dialog=true

Пример последовательности потоковой передачи:

{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false}
{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false}
{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false}
{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false}
{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false}
{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false}
{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true}

Когда streaming=false: Текущее поведение сохранено Единый ответ с полным ответом end_of_message=true, end_of_dialog=true

Шлюз и Python API

Шлюз: Новый SSE/WebSocket endpoint для потоковой передачи данных от агента Python API: Новый асинхронный генератор agent_stream()

--

Соображения безопасности

Отсутствие новых уязвимостей: Потоковая передача использует ту же аутентификацию/авторизацию Ограничение скорости: При необходимости применяйте ограничения скорости на токен или на фрагмент Обработка соединений: Правильно завершайте потоки при отключении клиента Управление временем ожидания: Запросы потоковой передачи требуют соответствующей обработки времени ожидания

Соображения производительности

Память: Потоковая передача снижает пиковое использование памяти (без полной буферизации ответа) Задержка: Время до первого токена значительно сокращено Накладные расходы на соединение: Соединения SSE/WebSocket имеют накладные расходы на поддержание соединения Производительность Pulsar: Несколько небольших сообщений против одного большого сообщения - компромисс tradeoff

Стратегия тестирования

Юнит-тесты

Сериализация/десериализация схемы с новыми полями Обратная совместимость (отсутствующие поля используют значения по умолчанию) Логика сборки фрагментов

Интеграционные тесты

Реализация потоковой передачи каждого поставщика LLM Потоковые конечные точки API шлюза Методы потоковой передачи клиента на Python

Комплексные тесты

Вывод потоковой передачи инструмента командной строки Полный поток: Клиент → Шлюз → Pulsar → LLM → обратно Смешанные потоковые и не потоковые рабочие нагрузки

Тесты обратной совместимости

Существующие клиенты работают без изменений Запросы без потоковой передачи ведут себя идентично

План миграции

Фаза 1: Инфраструктура

Развертывание изменений схемы (обратная совместимость) Развертывание обновлений API шлюза Развертывание обновлений Python API Выпуск обновлений инструмента командной строки

Фаза 2: VertexAI

Развернуть поточную реализацию VertexAI. Проверить с помощью тестовых нагрузок.

Фаза 3: Все провайдеры

Постепенно внедрять обновления для провайдеров. Отслеживать наличие проблем.

Фаза 4: API агента

Развернуть изменения схемы агента. Развернуть поточную реализацию агента. Обновить документацию.

График

Фаза Описание Зависимости
Фаза 1 Инфраструктура Отсутствуют
Фаза 2 VertexAI, пилотный проект Фаза 1
Фаза 3 Все провайдеры Фаза 2
Фаза 4 API агента Фаза 3

Принятые решения по проектированию

В процессе разработки спецификации были решены следующие вопросы:

  1. Количество токенов в потоке: Количество токенов указывается как разница, а не как текущая сумма. Потребители могут суммировать их, если это необходимо. Это соответствует тому, как большинство провайдеров сообщают об использовании и упрощает реализацию.

  2. Обработка ошибок в потоках: В случае возникновения ошибки, поле error заполняется, и другие поля не требуются. Ошибка всегда является последним сообщением - после ошибки не допускаются и не ожидаются последующие сообщения. Для потоков LLM/Prompt: end_of_stream=true. Для потоков Agent: chunk_type="error" с end_of_dialog=true.

  3. Восстановление после частичного ответа: Протокол обмена сообщениями (Pulsar) устойчив, поэтому повторная отправка сообщений на уровне отдельных сообщений не требуется. Если клиент теряет отслеживание потока или отключается, он должен повторить полный запрос с самого начала.

  4. Быстрая потоковая передача: Потоковая передача поддерживается только для текстовых ответов (text). ответы, а не для структурированных (object) ответов. Сервис запросов знает заранее, будет ли вывод в формате JSON или текста, в зависимости от шаблона запроса. Если выполняется запрос на потоковую передачу для запроса, предназначенного для вывода JSON, сервис должен либо: Вернуть полный JSON в одном ответе с end_of_stream=true, или Отклонить запрос на потоковую передачу с ошибкой.

Открытые вопросы

На данный момент их нет.

Ссылки

Текущая схема LLM: trustgraph-base/trustgraph/schema/services/llm.py Текущая схема запросов: trustgraph-base/trustgraph/schema/services/prompt.py Текущая схема агента: trustgraph-base/trustgraph/schema/services/agent.py Базовый URL службы LLM: trustgraph-base/trustgraph/base/llm_service.py Провайдер VertexAI: trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py API шлюза: trustgraph-base/trustgraph/api/ Инструменты CLI: trustgraph-cli/trustgraph/cli/