Skip to content

Text generation

The first call, the message roles and the path from test to production.

Updated on Aug 09, 2026

The models generate text from messages: prose, Markdown, JSON, code. The call is always the same — POST https://api.hinow.ai/v1/chat/completions with the list of messages — and it is stateless: the model sees exactly what you sent, nothing else.

The first call

curl https://api.hinow.ai/v1/chat/completions \
  -H "Authorization: Bearer $HINOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hinow/hinova",
    "messages": [
      {"role": "user", "content": "Explique em uma frase o que é streaming de tokens."}
    ]
  }'

The response to this call, exactly as the API returned it:

{
  "id": "chatcmpl-R2dSu3p8...",
  "object": "chat.completion",
  "created": 1786238029,
  "model": "hinow/hinova",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Streaming de tokens é a técnica de transmitir a resposta de uma inteligência artificial palavra por palavra (ou token por token) em tempo real, permitindo que o usuário veja o texto sendo gerado instantaneamente, em vez de esperar que a resposta completa seja concluída antes de exibir qualquer conteúdo."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 132, "completion_tokens": 60, "total_tokens": 192 }
}

Three fields matter day to day:

  • choices[0].message.content — the generated text.
  • finish_reason — why the generation stopped: stop (it finished on its own), length (it hit max_tokens) or tool_calls (the model requested a function).
  • usage — the token count for the input and the output. It is what multiplies the price; log it from day one.

Message roles

Each message has a specific role:

  • system — persistent instructions from the application, such as goal, tone, format and limits.
  • user — the request from the person using it.
  • assistant — the model's previous responses. This is how history enters a stateless API.

Think of system as the definition of a function and of user as the arguments: one fixes the behavior, the other varies with each call.

{
  "model": "hinow/hinova",
  "messages": [
    {
      "role": "system",
      "content": "Você é o assistente de suporte do HiNow. Comece pela resposta direta em uma frase. Máximo de 60 palavras."
    },
    { "role": "user", "content": "por que minha chamada volta 429?" }
  ]
}

The response to that call: "Error 429 means that you have exceeded the allowed request limit. Wait a moment or adjust how often you call the API to stay within your quota." — 27 words, starting with the direct answer. Both system instructions were followed without reinforcement in user.

Instructions guide; your code validates

System instructions greatly increase the chance of compliance, but they are not a guarantee. Every rule that cannot be broken — format, content, limit — has to be validated in code, after the response. For format, use JSON mode or function calling.

Conversations with history

The API does not store the conversation: every call carries the entire history, with the model's turns in the assistant role. That is what lets you edit the past — correct a response, summarize old turns, remove what no longer matters:

{
  "model": "hinow/hinova",
  "messages": [
    { "role": "system", "content": "Você é o assistente de suporte do HiNow." },
    { "role": "user", "content": "por que minha chamada volta 429?" },
    { "role": "assistant", "content": "O erro 429 indica que você excedeu o limite de requisições. Aguarde o tempo do cabeçalho Retry-After." },
    { "role": "user", "content": "e como eu descubro qual é o meu limite?" }
  ]
}

The history is resent — and counted as input — on every call. In long sessions, summarize old turns and keep the instructions, decisions and facts that can still change the response. Check the model's current limit before sending long documents.

Controlling the output

temperature

Controls how much the sampling can vary. Lower values are useful in classification, extraction and code; higher values allow more diverse responses. Even with temperature: 0, the output is not guaranteed to be identical across calls. Validate the behavior with evaluations.

Response length

Two mechanisms, with different roles:

  • The limit requested in the prompt ("no more than 60 words", "exactly 3 bullets") guides the style and the intended length. Validate the amount in code when it is mandatory.
  • max_tokens cuts the generation at the limit, mid-sentence if necessary, and sets finish_reason: "length". It is a safety net against runaway spending — not a length control. Always check finish_reason: a truncated response looks complete to the naked eye.

Streaming

With stream: true, the response arrives as server-sent events, one chunk at a time, as the model generates. Each event is a data: line with a chat.completion.chunk; the text comes in delta.content and is concatenated on your side:

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":""}}]}
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"ol"}}]}
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"á, mundo"}}]}
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":""},"finish_reason":"stop"}],"usage":{"prompt_tokens":128,"completion_tokens":5,"total_tokens":133}}
data: [DONE]

Two practical rules:

  • usage comes only in the last event, together with finish_reason. Whoever closes the connection on seeing enough text loses the token count.
  • The stream ends with the line data: [DONE] — that is what closes it, not the absence of data.

Use streaming in interactive experiences to reduce perceived latency. In backend tasks that need the complete result before continuing, a response without streaming usually simplifies processing and error handling.

Image input

Use a model with the image_to_text modality, such as hinow/higenesis, to combine text instructions with an image. Check category in GET https://api.hinow.ai/v1/models before enabling the feature in your application:

{
  "model": "hinow/higenesis",
  "messages": [
    {
      "role": "user",
      "content": [
        { "type": "text", "text": "O que este gráfico mostra?" },
        { "type": "image_url", "image_url": { "url": "https://exemplo.com/grafico.png" } }
      ]
    }
  ]
}

url accepts an address reachable by the API or a data: URL with the image in base64. For predominantly visual workflows, compare HiGenesis with the specialized model hinow/hivision.

From test to production

The output is non-deterministic: the same input produces different responses. That changes the way you work:

  • Build an evaluation set with real cases and the expected answer. It is what tells you whether a prompt change improved the result or only changed it.
  • In automated tests, check properties, not equality — is it JSON? does it have the fields? is it within the length limit? — because the exact text varies.
  • Version the prompt in the code, next to whoever uses it: a prompt is code, and review, diff and rollback apply to it.
  • Log the usage of every call. It is your real cost account — and the first place where a bloated prompt shows up.

Next steps