> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bettertoken.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Streaming e chamadas de ferramentas na API BetterToken

> Adicione streaming e chamadas de ferramentas no BetterToken. Compare eventos, esquemas de funções e resultados em Chat Completions, Responses e Messages.

Ative o streaming com `stream: true` e defina as ferramentas do cliente com o esquema exigido pela API. O suporte a streaming e chamadas de ferramentas varia conforme o modelo; teste uma solicitação pequena com seu Model ID antes de usar esses recursos em uma aplicação.

## Pré-requisitos

Primeiro, conclua uma solicitação de texto simples com os [exemplos de SDK](/pt-br/guides/sdk-examples.md). Copie da [model plaza](https://bettertoken.ai/pricing) o Model ID exato para o protocolo que você vai testar. O [guia de seleção de modelos](/pt-br/faq/model-calling/model-selection-guide.md) explica o que verificar.

Instale `openai` e `anthropic` no ambiente virtual Python do projeto e substitua os valores de exemplo no mesmo terminal:

```bash theme={null}
python -m pip install openai anthropic
export BETTERTOKEN_API_KEY="YOUR_API_KEY"
export BETTERTOKEN_MODEL_ID="YOUR_MODEL_ID"
```

Cada bloco Python abaixo é executado de forma independente. O tempo limite de 120 segundos é um exemplo para estes testes curtos; escolha o da aplicação com as [orientações de tempo limite](/pt-br/best-practices.md#set-a-generous-timeout). Confira os [limites de tokens de saída](/pt-br/faq/model-calling/max-tokens.md) do modelo antes de definir `max_tokens` ou `max_output_tokens`.

## Receba respostas de texto em streaming

O streaming envia eventos do servidor (SSE) por uma única resposta HTTP. Um evento SSE não corresponde necessariamente a uma frase completa nem a um objeto JSON de argumentos completo.

| API | Configuração da solicitação | Eventos ou fragmentos de texto | Fim da resposta |
| - | - | - | - |
| [Chat Completions](/pt-br/api-reference/chat-completions.md) | `stream: true` | `choices[].delta.content`; fragmentos de ferramentas usam `delta.tool_calls` | Cada opção informa `finish_reason`; o fluxo bruto termina com `data: [DONE]` |
| [Responses](/pt-br/api-reference/responses.md) | `stream: true` | Eventos tipados, como `response.output_text.delta` | `response.completed`; trate também eventos de falha ou resposta incompleta |
| [Messages](/pt-br/api-reference/messages.md) | `stream: true` | `content_block_delta` com `text_delta`; argumentos de ferramentas usam `input_json_delta` | `message_delta` contém o motivo de encerramento, seguido de `message_stop` |

O SDK interpreta o formato SSE. Estes exemplos imprimem os fragmentos de texto e as informações de conclusão; a aplicação também deve tratar eventos de erro.

**Chat Completions**

```python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["BETTERTOKEN_API_KEY"],
    base_url="https://bettertoken.ai/v1",
    timeout=120.0,
    max_retries=0,
)
with client.chat.completions.create(
    model=os.environ["BETTERTOKEN_MODEL_ID"],
    messages=[{"role": "user", "content": "Say hello in one sentence."}],
    stream=True,
) as stream:
    for chunk in stream:
        for choice in chunk.choices:
            if choice.delta.content:
                print(choice.delta.content, end="", flush=True)
            if choice.finish_reason:
                print("\nFinish reason:", choice.finish_reason)
```

**Responses**

```python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["BETTERTOKEN_API_KEY"],
    base_url="https://bettertoken.ai/v1",
    timeout=120.0,
    max_retries=0,
)
with client.responses.create(
    model=os.environ["BETTERTOKEN_MODEL_ID"],
    input="Say hello in one sentence.",
    stream=True,
) as stream:
    for event in stream:
        if event.type == "response.output_text.delta":
            print(event.delta, end="", flush=True)
        elif event.type in (
            "response.completed", "response.failed", "response.incomplete", "error"
        ):
            print("\n", event)
```

**Messages**

```python theme={null}
import os
from anthropic import Anthropic

client = Anthropic(
    api_key=os.environ["BETTERTOKEN_API_KEY"],
    base_url="https://bettertoken.ai",
    timeout=120.0,
    max_retries=0,
)
with client.messages.create(
    model=os.environ["BETTERTOKEN_MODEL_ID"],
    max_tokens=256,
    messages=[{"role": "user", "content": "Say hello in one sentence."}],
    stream=True,
) as stream:
    for event in stream:
        if event.type == "content_block_delta" and event.delta.type == "text_delta":
            print(event.delta.text, end="", flush=True)
        elif event.type == "message_delta":
            print("\nStop reason:", event.delta.stop_reason)
```

## Defina uma ferramenta de clima para cada protocolo

O modelo solicita uma chamada de função; sua aplicação valida os argumentos, executa a função e devolve o resultado. Os exemplos usam uma função `get_weather` com o argumento `location` e retornam **dados fixos de demonstração, não informações meteorológicas em tempo real**. Não é necessário contratar um serviço de clima nem obter outra Key.

| Campo de solicitação ou resposta | Chat Completions | Responses | Messages |
| - | - | - | - |
| Prompt de entrada | `messages` | `input` | `messages` |
| Declaração da ferramenta em `tools[]` | `type: "function"`, com `name`, `description` e `parameters` dentro de `function` | `type: "function"`, com `name`, `description` e `parameters` na raiz da ferramenta | `name`, `description` e `input_schema` |
| Chamada retornada | `choices[].message.tool_calls[]` | Item de `output[]` com `type: "function_call"` | Bloco de `content[]` com `type: "tool_use"` |
| Argumentos | String JSON em `function.arguments` | String JSON em `arguments` | Objeto em `input` |
| Devolução do resultado | Mensagem com `role: "tool"`, `tool_call_id` e `content` | Item de entrada com `type: "function_call_output"`, `call_id` e `output` como string | Bloco de conteúdo do usuário com `type: "tool_result"`, `tool_use_id` e `content` |

O suporte varia conforme o modelo e o protocolo. Teste esta solicitação pequena com seu Model ID mesmo que o texto simples já funcione. Declarar uma ferramenta não ativa busca hospedada nem outras ferramentas executadas pelo provedor.

## Execute a chamada e devolva o resultado

Estes exemplos sem streaming mostram um ciclo completo de chamada e resultado para você inspecionar os argumentos completos. Cada exemplo trata todas as chamadas de ferramentas da primeira resposta e permite uma solicitação de continuação. Um fluxo de agente mais longo precisa de um laço com limites e uma condição de parada.

**Chat Completions**

```python theme={null}
import json
import os
from openai import OpenAI

def get_weather(location):
    if not isinstance(location, str) or not location.strip():
        raise ValueError("location must be a non-empty string")
    return {"location": location, "temperature_c": 20, "source": "demo"}

client = OpenAI(
    api_key=os.environ["BETTERTOKEN_API_KEY"],
    base_url="https://bettertoken.ai/v1", timeout=120.0, max_retries=0,
)
model = os.environ["BETTERTOKEN_MODEL_ID"]
schema = {
    "type": "object",
    "properties": {"location": {"type": "string"}},
    "required": ["location"], "additionalProperties": False,
}
tools = [{"type": "function", "function": {
    "name": "get_weather", "description": "Get demonstration weather for a location.",
    "parameters": schema,
}}]
messages = [{"role": "user", "content": "Call get_weather for Paris and report the demo result."}]
first = client.chat.completions.create(model=model, messages=messages, tools=tools)
message = first.choices[0].message
calls = message.tool_calls or []
if not calls:
    print("No tool call returned:", message.content)
else:
    messages.append(message.model_dump(exclude_none=True))
    for call in calls:
        if call.type != "function" or call.function.name != "get_weather":
            raise ValueError("Unexpected tool")
        args = json.loads(call.function.arguments)
        result = get_weather(**args)
        messages.append({
            "role": "tool", "tool_call_id": call.id,
            "content": json.dumps(result),
        })
    final = client.chat.completions.create(model=model, messages=messages, tools=tools)
    print(final.choices[0].message.model_dump(exclude_none=True))
```

**Responses**

```python theme={null}
import json
import os
from openai import OpenAI

def get_weather(location):
    if not isinstance(location, str) or not location.strip():
        raise ValueError("location must be a non-empty string")
    return {"location": location, "temperature_c": 20, "source": "demo"}

client = OpenAI(
    api_key=os.environ["BETTERTOKEN_API_KEY"],
    base_url="https://bettertoken.ai/v1", timeout=120.0, max_retries=0,
)
model = os.environ["BETTERTOKEN_MODEL_ID"]
schema = {
    "type": "object",
    "properties": {"location": {"type": "string"}},
    "required": ["location"], "additionalProperties": False,
}
tools = [{
    "type": "function", "name": "get_weather",
    "description": "Get demonstration weather for a location.", "parameters": schema,
}]
history = [{"role": "user", "content": "Call get_weather for Paris and report the demo result."}]
first = client.responses.create(model=model, input=history, tools=tools)
calls = [item for item in first.output if item.type == "function_call"]
if not calls:
    print("No tool call returned:", first.output)
else:
    history.extend(first.output)
    for call in calls:
        if call.name != "get_weather":
            raise ValueError("Unexpected tool")
        args = json.loads(call.arguments)
        result = get_weather(**args)
        history.append({
            "type": "function_call_output", "call_id": call.call_id,
            "output": json.dumps(result),
        })
    final = client.responses.create(model=model, input=history, tools=tools)
    print(final.output)
```

**Messages**

```python theme={null}
import json
import os
from anthropic import Anthropic

def get_weather(location):
    if not isinstance(location, str) or not location.strip():
        raise ValueError("location must be a non-empty string")
    return {"location": location, "temperature_c": 20, "source": "demo"}

client = Anthropic(
    api_key=os.environ["BETTERTOKEN_API_KEY"],
    base_url="https://bettertoken.ai", timeout=120.0, max_retries=0,
)
model = os.environ["BETTERTOKEN_MODEL_ID"]
schema = {
    "type": "object",
    "properties": {"location": {"type": "string"}},
    "required": ["location"], "additionalProperties": False,
}
tools = [{
    "name": "get_weather", "description": "Get demonstration weather for a location.",
    "input_schema": schema,
}]
messages = [{"role": "user", "content": "Call get_weather for Paris and report the demo result."}]
first = client.messages.create(model=model, max_tokens=1024, messages=messages, tools=tools)
calls = [block for block in first.content if block.type == "tool_use"]
if first.stop_reason == "max_tokens":
    raise RuntimeError("Response truncated; inspect it before executing tools")
if not calls:
    print("No tool call returned:", first.content)
else:
    messages.append({"role": "assistant", "content": first.content})
    results = []
    for call in calls:
        if call.name != "get_weather":
            raise ValueError("Unexpected tool")
        result = get_weather(**call.input)
        results.append({
            "type": "tool_result", "tool_use_id": call.id,
            "content": json.dumps(result),
        })
    messages.append({"role": "user", "content": results})
    final = client.messages.create(model=model, max_tokens=1024, messages=messages, tools=tools)
    print(final.content)
```

Preserve a resposta completa do assistente antes de adicionar os resultados das ferramentas. Em Responses, mantenha todos os itens de `output`, incluindo os de raciocínio, quando retornados. Em Messages, preserve os blocos de conteúdo e sua ordem. Associe os resultados aos IDs de chamada recebidos, sem inventar IDs.

## Perguntas frequentes

### Posso executar os argumentos conforme chegam?

Acumule os fragmentos por índice da chamada ou ID do item, depois interprete e valide os argumentos completos. Um JSON parcial pode ser inválido. Comece pelos exemplos sem streaming antes de combinar streaming e ferramentas.

### Por que o texto simples funciona, mas as ferramentas falham?

O suporte varia conforme o modelo e o protocolo; verifique uma solicitação pequena com seu Model ID. Confira o esquema, os argumentos retornados, o ID do resultado e a ordem das mensagens. Para validar JSON com tipos, consulte as [perguntas sobre saída estruturada](/pt-br/faq/model-calling/structured-json-pydantic.md).

### Devo repetir uma solicitação com streaming interrompido?

Verifique o registro da solicitação antes de reenviá-la. Uma desconexão não confirma se a solicitação terminou. A repetição inicia outra tentativa e não pode executar novamente uma ação de ferramenta já concluída. Consulte as [orientações sobre erros e novas tentativas](/pt-br/api-reference/errors.md).

## Conteúdo relacionado

* [Configuração de SDK e autenticação](/pt-br/guides/sdk-examples.md)
* [Visão geral da referência da API](/pt-br/api-reference/introduction.md)
* [Limites de tokens de saída](/pt-br/faq/model-calling/max-tokens.md)
* [JSON estruturado e Pydantic](/pt-br/faq/model-calling/structured-json-pydantic.md)
* [Configurações de tempo limite](/pt-br/best-practices.md#set-a-generous-timeout)
* [Erros e limites](/pt-br/api-reference/errors.md)

## Referências oficiais

Estas referências definem os campos dos protocolos de origem. Verifique o recurso com seu Model ID do BetterToken antes de usá-lo.

* [Chamadas de funções da OpenAI](https://developers.openai.com/api/docs/guides/function-calling)
* [Respostas em streaming da OpenAI](https://developers.openai.com/api/docs/guides/streaming-responses)
* [Definição de ferramentas da Anthropic](https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools)
* [Resultados de ferramentas da Anthropic](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls)
* [Messages em streaming da Anthropic](https://platform.claude.com/docs/en/build-with-claude/streaming)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.