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.
20 KiB
| layout | title | parent |
|---|---|---|
| default | Especificação Técnica de Respostas de LLM em Streaming | Portuguese (Beta) |
Especificação Técnica de Respostas de LLM em Streaming
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.
Visão Geral
Esta especificação descreve a implementação do suporte a streaming para respostas de LLM no TrustGraph. O streaming permite a entrega em tempo real de tokens gerados à medida que são produzidos pelo LLM, em vez de esperar pela geração completa da resposta.
Esta implementação suporta os seguintes casos de uso:
- Interfaces de Usuário em Tempo Real: Transmita tokens para a interface do usuário à medida que são gerados, fornecendo feedback visual imediato.
- Tempo de Primeiro Token Reduzido: Os usuários veem a saída começando imediatamente em vez de esperar pela geração completa.
- Tratamento de Respostas Longas: Lidar com saídas muito longas que, de outra forma, poderiam causar timeout ou exceder os limites de memória.
- Aplicações Interativas: Permitir interfaces de bate-papo e agentes responsivas.
Objetivos
Compatibilidade com Versões Anteriores: Os clientes existentes que não utilizam streaming continuam a funcionar sem modificação. Design de API Consistente: O streaming e o uso sem streaming utilizam os mesmos padrões de esquema com mínima divergência. Flexibilidade do Provedor: Suporte ao streaming quando disponível, com uma alternativa suave quando não disponível. Implementação Gradual: Implementação incremental para reduzir o risco. Suporte de Ponta a Ponta: Streaming do provedor de LLM até as aplicações do cliente via Pulsar, Gateway API e Python API.
Contexto
Arquitetura Atual
O fluxo atual de conclusão de texto de LLM opera da seguinte forma:
- O cliente envia
TextCompletionRequestcom os campossystemeprompt. - O serviço de LLM processa a solicitação e espera pela geração completa.
- Um único
TextCompletionResponseé retornado com a stringresponsecompleta.
Esquema atual (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()
Limitações Atuais
Latência: Os usuários devem esperar pela geração completa antes de ver qualquer resultado. Risco de Timeout: Gerações longas podem exceder os limites de tempo de espera do cliente. Má Experiência do Usuário: A falta de feedback durante a geração cria a percepção de lentidão. Uso de Recursos: As respostas completas devem ser armazenadas em memória.
Esta especificação aborda essas limitações, permitindo a entrega incremental de respostas, mantendo total compatibilidade com versões anteriores.
Design Técnico
Fase 1: Infraestrutura
A Fase 1 estabelece a base para o streaming, modificando esquemas, APIs e ferramentas de linha de comando.
Alterações no Esquema
Esquema LLM (trustgraph-base/trustgraph/schema/services/llm.py)
Alterações na Requisição:
class TextCompletionRequest(Record):
system = String()
prompt = String()
streaming = Boolean() # NEW: Default false for backward compatibility
streaming: Quando true, solicita a entrega de resposta em fluxo.
Padrão: false (o comportamento existente é preservado).
Alterações na Resposta:
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: Quando true, indica que esta é a resposta final (ou única).
Para solicitações não em fluxo contínuo: Resposta única com end_of_stream=true.
Para solicitações em fluxo contínuo: Múltiplas respostas, todas com end_of_stream=false
exceto a última.
Esquema do Prompt (trustgraph-base/trustgraph/schema/services/prompt.py)
O serviço de prompt envolve a conclusão de texto, portanto, ele segue o mesmo padrão:
Alterações na Solicitação:
class PromptRequest(Record):
id = String()
terms = Map(String())
streaming = Boolean() # NEW: Default false
Alterações na Resposta:
class PromptResponse(Record):
error = Error()
text = String()
object = String()
end_of_stream = Boolean() # NEW: Indicates final message
Alterações na API Gateway
A API Gateway deve expor capacidades de streaming para clientes HTTP/WebSocket.
Atualizações da API REST:
POST /api/v1/text-completion: Aceitar o parâmetro streaming no corpo da requisição
O comportamento da resposta depende da flag de streaming:
streaming=false: Resposta JSON única (comportamento atual)
streaming=true: Fluxo de eventos enviados pelo servidor (SSE) ou mensagens WebSocket
Formato da Resposta (Streaming):
Cada bloco transmitido segue a mesma estrutura de esquema:
{
"response": "partial text...",
"end_of_stream": false,
"model": "model-name"
}
Trecho final:
{
"response": "final text chunk",
"end_of_stream": true,
"in_token": 150,
"out_token": 500,
"model": "model-name"
}
Alterações na API Python
A API do cliente Python deve suportar tanto o modo de streaming quanto o modo não-streaming, mantendo a compatibilidade com versões anteriores.
Atualizações do 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
Atualizações do PromptClient (trustgraph-base/trustgraph/base/prompt_client.py):
Padrão semelhante com o parâmetro streaming e a variante de gerador assíncrono.
Alterações na Ferramenta de Linha de Comando (CLI)
tg-invoke-llm (trustgraph-cli/trustgraph/cli/invoke_llm.py):
tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id]
Streaming habilitado por padrão para uma melhor experiência de usuário interativa.
A flag --no-streaming desabilita o streaming.
Quando o streaming está habilitado: Envie os tokens para a saída padrão (stdout) à medida que chegam.
Quando o streaming não está habilitado: Aguarde a resposta completa e, em seguida, envie.
tg-invoke-prompt (trustgraph-cli/trustgraph/cli/invoke_prompt.py):
tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id]
Mesmo padrão que tg-invoke-llm.
Alterações na Classe Base do Serviço LLM
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()
--
Fase 2: Prova de Conceito do VertexAI
A Fase 2 implementa o streaming em um único provedor (VertexAI) para validar a infraestrutura e permitir testes de ponta a ponta.
Implementação do VertexAI
Módulo: trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py
Alterações:
- Substituir
supports_streaming()para retornarTrue - Implementar gerador assíncrono
generate_content_stream() - Lidar com modelos Gemini e Claude (via API Anthropic do VertexAI)
Streaming do 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 (via VertexAI Anthropic) Streaming:
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()
Testes
Testes unitários para a montagem da resposta em streaming Testes de integração com o VertexAI (Gemini e Claude) Testes de ponta a ponta: CLI -> Gateway -> Pulsar -> VertexAI -> de volta Testes de compatibilidade com versões anteriores: as solicitações não em streaming ainda funcionam
--
Fase 3: Todos os Provedores de LLM
A Fase 3 estende o suporte a streaming para todos os provedores de LLM no sistema.
Status de Implementação do Provedor
Cada provedor deve:
- Suporte Completo a Streaming: Implementar
generate_content_stream() - Modo de Compatibilidade: Lidar com a flag
end_of_streamcorretamente (retornar uma única resposta comend_of_stream=true)
| Provedor | Pacote | Suporte a Streaming |
|---|---|---|
| OpenAI | trustgraph-flow | Completo (API de streaming nativa) |
| Claude/Anthropic | trustgraph-flow | Completo (API de streaming nativa) |
| Ollama | trustgraph-flow | Completo (API de streaming nativa) |
| Cohere | trustgraph-flow | Completo (API de streaming nativa) |
| Mistral | trustgraph-flow | Completo (API de streaming nativa) |
| Azure OpenAI | trustgraph-flow | Completo (API de streaming nativa) |
| Google AI Studio | trustgraph-flow | Completo (API de streaming nativa) |
| VertexAI | trustgraph-vertexai | Completo (Fase 2) |
| Bedrock | trustgraph-bedrock | Completo (API de streaming nativa) |
| LM Studio | trustgraph-flow | Completo (compatível com OpenAI) |
| LlamaFile | trustgraph-flow | Completo (compatível com OpenAI) |
| vLLM | trustgraph-flow | Completo (compatível com OpenAI) |
| TGI | trustgraph-flow | A ser definido |
| Azure | trustgraph-flow | A ser definido |
Padrão de Implementação
Para provedores compatíveis com 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)
--
Fase 4: API do Agente
A Fase 4 estende o streaming para a API do Agente. Isso é mais complexo porque a API do Agente já é inerentemente multi-mensagem (pensamento → ação → observação → repetir → resposta final).
Esquema Atual do Agente
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()
Alterações Propostas no Esquema do Agente
Solicitar Alterações:
class AgentRequest(Record):
question = String()
state = String()
group = Array(String())
history = Array(AgentStep())
user = String()
streaming = Boolean() # NEW: Default false
Alterações na Resposta:
O agente produz múltiplos tipos de saída durante seu ciclo de raciocínio: Pensamentos (raciocínio) Ações (chamadas de ferramentas) Observações (resultados das ferramentas) Resposta (resposta final) Erros
Como chunk_type identifica o tipo de conteúdo que está sendo enviado, os campos separados
answer, error, thought e observation podem ser combinados em
um único campo 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
Semântica dos Campos:
chunk_type: Indica o tipo de conteúdo presente no campo content
"thought": Raciocínio/pensamento do agente
"action": Ferramenta/ação sendo invocada
"observation": Resultado da execução da ferramenta
"answer": Resposta final à pergunta do usuário
"error": Mensagem de erro
content: O conteúdo transmitido, interpretado com base em chunk_type
end_of_message: Quando true, o tipo de bloco atual está completo
Exemplo: Todos os tokens para o pensamento atual foram enviados
Permite que os clientes saibam quando avançar para a próxima etapa
end_of_dialog: Quando true, toda a interação do agente está completa
Esta é a mensagem final no fluxo
Comportamento de Streaming do Agente
Quando streaming=true:
- Streaming de pensamento:
Múltiplos blocos com
chunk_type="thought",end_of_message=falseO bloco final do pensamento temend_of_message=true - Notificação de ação:
Um único bloco com
chunk_type="action",end_of_message=true - Observação:
Bloco(s) com
chunk_type="observation", o final temend_of_message=true - Repita as etapas 1-3 enquanto o agente raciocina
- Resposta final:
chunk_type="answer"com a resposta final emcontentO último bloco temend_of_message=true,end_of_dialog=true
Exemplo de Sequência de Streaming:
{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}
Quando streaming=false:
Comportamento atual preservado
Resposta única com resposta completa
end_of_message=true, end_of_dialog=true
Gateway e API Python
Gateway: Novo endpoint SSE/WebSocket para streaming de agentes
API Python: Novo método gerador assíncrono agent_stream()
--
Considerações de Segurança
Nenhuma nova superfície de ataque: O streaming usa a mesma autenticação/autorização Limitação de taxa: Aplique limites de taxa por token ou por bloco, se necessário Gerenciamento de conexão: Termine corretamente os streams em caso de desconexão do cliente Gerenciamento de tempo limite: As solicitações de streaming precisam de um tratamento de tempo limite adequado
Considerações de Desempenho
Memória: O streaming reduz o uso máximo de memória (sem bufferização completa da resposta) Latência: O tempo para o primeiro token é significativamente reduzido Sobrecarga de conexão: As conexões SSE/WebSocket têm uma sobrecarga de keep-alive Throughput do Pulsar: Múltiplas mensagens pequenas vs. uma única mensagem grande tradeoff
Estratégia de Testes
Testes Unitários
Serialização/desserialização de esquema com novos campos Compatibilidade com versões anteriores (campos ausentes usam valores padrão) Lógica de montagem de blocos
Testes de Integração
Implementação de streaming de cada provedor de LLM Pontos finais de streaming da API Gateway Métodos de streaming do cliente Python
Testes de Ponta a Ponta
Saída de streaming da ferramenta CLI Fluxo completo: Cliente → Gateway → Pulsar → LLM → de volta Cargas de trabalho mistas de streaming/não streaming
Testes de Compatibilidade com Versões Anteriores
Clientes existentes funcionam sem modificação As solicitações não de streaming se comportam de forma idêntica
Plano de Migração
Fase 1: Infraestrutura
Implante as alterações de esquema (compatível com versões anteriores) Implante as atualizações da API Gateway Implante as atualizações da API Python Lance as atualizações da ferramenta CLI
Fase 2: VertexAI
Implementar a implementação de streaming do VertexAI Validar com cargas de trabalho de teste
Fase 3: Todos os Provedores
Implementar as atualizações do provedor de forma incremental Monitorar para identificar problemas
Fase 4: API do Agente
Implementar as alterações do esquema do agente Implementar a implementação de streaming do agente Atualizar a documentação
Cronograma
| Fase | Descrição | Dependências |
|---|---|---|
| Fase 1 | Infraestrutura | Nenhum |
| Fase 2 | Prova de Conceito do VertexAI | Fase 1 |
| Fase 3 | Todos os Provedores | Fase 2 |
| Fase 4 | API do Agente | Fase 3 |
Decisões de Design
As seguintes perguntas foram resolvidas durante a especificação:
-
Contagem de Tokens no Streaming: As contagens de tokens são diferenças, não totais cumulativos. Os consumidores podem somá-las, se necessário. Isso corresponde à forma como a maioria dos provedores relata o uso e simplifica a implementação.
-
Tratamento de Erros em Streams: Se ocorrer um erro, o campo
erroré preenchido e nenhum outro campo é necessário. Um erro é sempre a comunicação final - nenhuma mensagem subsequente é permitida ou esperada após isso. um erro. Para fluxos de LLM/Prompt,end_of_stream=true. Para fluxos de Agente,chunk_type="error"comend_of_dialog=true. -
Recuperação Parcial de Respostas: O protocolo de mensagens (Pulsar) é resiliente, portanto, a repetição em nível de mensagem não é necessária. Se um cliente perder o controle do fluxo ou desconectar, ele deve repetir a solicitação completa do zero.
-
Streaming de Respostas Rápidas: O streaming é suportado apenas para respostas de texto (
text). As respostas estruturadas (object) não são suportadas. O serviço de respostas rápidas sabe, desde o início, se a saída será JSON ou texto, com base no modelo da solicitação. Se uma solicitação de streaming for feita para uma solicitação de saída JSON, o serviço deve: Retornar o JSON completo em uma única resposta comend_of_stream=true, ou Rejeitar a solicitação de streaming com um erro.
Perguntas Abertas
Nenhum neste momento.
Referências
Esquema atual do LLM: trustgraph-base/trustgraph/schema/services/llm.py
Esquema atual do prompt: trustgraph-base/trustgraph/schema/services/prompt.py
Esquema atual do agente: trustgraph-base/trustgraph/schema/services/agent.py
Serviço base do LLM: trustgraph-base/trustgraph/base/llm_service.py
Provedor VertexAI: trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py
API de gateway: trustgraph-base/trustgraph/api/
Ferramentas de linha de comando: trustgraph-cli/trustgraph/cli/