Embeddings
Transforme texto em vetores para comparar significado: a chamada, o que a resposta traz, os limites e o custo.
Atualizado em 10 de ago. de 2026
O hinow/hiembed transforma texto em uma lista de números — o embedding. Textos que querem dizer a mesma coisa produzem listas parecidas, mesmo sem uma palavra em comum. É isso que permite procurar por significado em vez de procurar por termo exato.
Ele responde em POST https://api.hinow.ai/v1/embeddings, com a mesma chave e a mesma base URL do resto da API. O preço é por token de entrada — US$ 0,05 por milhão.
Embedding não responde perguntas nem escreve texto: ele mede proximidade de sentido. Todo uso nasce daí.
- Busca semântica — encontrar a resposta certa mesmo quando o usuário escreve com outras palavras.
- RAG — selecionar os trechos que vão no contexto do modelo de linguagem antes de ele responder.
- Recomendação — "parecido com este" sobre produtos, artigos, vagas ou tíquetes.
- Agrupamento e triagem — juntar mensagens que falam do mesmo assunto, sem lista de categorias escrita à mão.
- Duplicidade — achar o chamado que já foi aberto, o cadastro repetido, a pergunta que já tem resposta.
O texto vai em input e o id do modelo em model:
curl https://api.hinow.ai/v1/embeddings \
-H "Authorization: Bearer $HINOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "hinow/hiembed",
"input": "Como redefinir minha senha?"
}'import os, requests
resposta = requests.post(
"https://api.hinow.ai/v1/embeddings",
headers={"Authorization": f"Bearer {os.environ['HINOW_API_KEY']}"},
json={"model": "hinow/hiembed", "input": "Como redefinir minha senha?"},
).json()
vetor = resposta["data"][0]["embedding"]
print(len(vetor), resposta["usage"]["prompt_tokens"]) # 1024 10const resposta = await fetch("https://api.hinow.ai/v1/embeddings", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HINOW_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "hinow/hiembed",
input: "Como redefinir minha senha?",
}),
});
const { data, usage } = await resposta.json();
console.log(data[0].embedding.length, usage.prompt_tokens); // 1024 10package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
type respostaEmbeddings struct {
Data []struct {
Embedding []float64 `json:"embedding"`
Index int `json:"index"`
} `json:"data"`
Usage struct {
PromptTokens int `json:"prompt_tokens"`
} `json:"usage"`
}
func main() {
corpo, _ := json.Marshal(map[string]any{
"model": "hinow/hiembed",
"input": "Como redefinir minha senha?",
})
req, _ := http.NewRequest("POST", "https://api.hinow.ai/v1/embeddings", bytes.NewReader(corpo))
req.Header.Set("Authorization", "Bearer "+os.Getenv("HINOW_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var r respostaEmbeddings
if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
panic(err)
}
fmt.Println(len(r.Data[0].Embedding), r.Usage.PromptTokens) // 1024 10
}A resposta, com o vetor cortado para caber na página:
{
"object": "list",
"model": "hinow/hiembed",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [-0.006066, 0.021058, -0.054192, -0.038931, "... mais 1020 números"]
}
],
"usage": { "prompt_tokens": 10, "total_tokens": 10 }
}Três campos importam:
data[].embedding— o vetor, com 1024 números.data[].index— a posição do texto noinputque gerou aquele vetor. É por ele que se reencontra a ordem quando se manda um lote.usage.prompt_tokens— o que foi cobrado.
O custo não vem na resposta
Diferente de /v1/images, o /v1/embeddings não devolve o campo cost. A conta sai do usage.prompt_tokens multiplicado pelo preço do modelo: US$ 0,05 por milhão de tokens. Registre o usage de cada chamada se você precisa reconciliar consumo.
Já usa o SDK da OpenAI?
O endpoint é compatível: troque a baseURL para https://api.hinow.ai/v1, use a sua chave HINOW e o model para hinow/hiembed. O resto do código continua igual. Veja os SDKs de cliente.
São 1024 números entre -1 e 1. Nenhum deles quer dizer nada sozinho: não existe "a posição 42 é o assunto financeiro". O vetor só ganha sentido quando comparado com outro vetor do mesmo modelo.
Os vetores do hiembed já vêm normalizados — a norma é exatamente 1. Isso tem uma consequência prática que economiza código: o produto escalar entre dois vetores já é a similaridade de cosseno, sem precisar dividir por norma nenhuma.
vetor = resposta["data"][0]["embedding"]
len(vetor) # 1024
vetor[:4] # [-0.006066, 0.021058, -0.054192, -0.038931]
sum(x * x for x in vetor) ** 0.5 # 1.0 -> já normalizadoO mesmo texto não devolve o mesmo vetor
Vinte chamadas com a mesma frase produziram vetores levemente diferentes — a maior diferença em um componente foi de 0,00016, e a similaridade entre eles ficou em 0,999999. Para comparação isso é irrelevante; para igualdade, não: não use o vetor como chave de cache, nem procure duplicata testando se dois vetores são iguais. Compare pelo texto, ou pela similaridade com um limite.
A similaridade de cosseno vai de -1 a 1: quanto maior, mais próximos os sentidos. Como os vetores chegam normalizados, a função inteira cabe em uma linha:
def similaridade(a, b):
return sum(x * y for x, y in zip(a, b))
# Com numpy, sobre muitos vetores de uma vez:
# import numpy as np
# scores = np.array(vetores) @ np.array(consulta)const similaridade = (a: number[], b: number[]) =>
a.reduce((soma, valor, i) => soma + valor * b[i], 0);func similaridade(a, b []float64) float64 {
var soma float64
for i := range a {
soma += a[i] * b[i]
}
return soma
}Os números abaixo são a saída real dessas chamadas — vale olhar a distância entre as faixas, não os valores em si:
| Par de textos | Similaridade |
|---|---|
| "O prazo de entrega é de 3 a 5 dias úteis." × "A entrega leva de três a cinco dias úteis." | **0,9598** |
| "cartão de crédito" × "cartao de credito" | 0,8950 |
| "O prazo de entrega é de 3 a 5 dias úteis." × "Aceitamos Pix e boleto." | 0,4872 |
A paráfrase completa fica acima de 0,95 sem repetir uma palavra na mesma forma. O acento perdido quase não muda o resultado — o que resolve boa parte da busca em português sem nenhum tratamento de texto. E dois assuntos diferentes caem para perto de 0,48.
O que o embedding não captura
"O gato subiu no telhado" e "O telhado subiu no gato" têm similaridade 0,9558: as mesmas palavras, papéis trocados, sentido oposto. Embedding mede assunto, não afirmação. Não use para verificar fatos, para distinguir uma negação da frase afirmativa correspondente, nem para comparar números, datas e identificadores — para isso existe filtro exato, e ele é mais barato.
O input aceita uma lista. A resposta traz um item por texto, e o index diz de qual deles cada vetor veio — não confie na ordem do array, confie no index:
textos = [
"Para trocar a senha, abra Configurações › Segurança.",
"O prazo de entrega padrão é de 3 a 5 dias úteis.",
"Aceitamos cartão de crédito, Pix e boleto bancário.",
]
resposta = requests.post(
"https://api.hinow.ai/v1/embeddings",
headers={"Authorization": f"Bearer {os.environ['HINOW_API_KEY']}"},
json={"model": "hinow/hiembed", "input": textos},
).json()
vetores = [item["embedding"] for item in sorted(resposta["data"], key=lambda i: i["index"])]
print(len(vetores), resposta["usage"]["prompt_tokens"])const textos = [
"Para trocar a senha, abra Configurações › Segurança.",
"O prazo de entrega padrão é de 3 a 5 dias úteis.",
"Aceitamos cartão de crédito, Pix e boleto bancário.",
];
const resposta = await fetch("https://api.hinow.ai/v1/embeddings", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HINOW_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ model: "hinow/hiembed", input: textos }),
});
const { data, usage } = await resposta.json();
const vetores = [...data]
.sort((a, b) => a.index - b.index)
.map((item) => item.embedding as number[]);O ganho é de rede, não de preço: o token custa o mesmo solto ou em lote. Numa medição de 500 textos curtos em uma única chamada, a resposta inteira levou 2,0 s — contra 500 idas e voltas se fossem chamadas separadas.
Um texto tem teto de tamanho
Cada item do input cabe em torno de 8.192 tokens. Um texto de 8.003 tokens passou; acima disso a chamada falha com erro do provedor, e não com um 400 explicando o motivo. Divida o documento em trechos antes de enviar — o que você vai querer fazer de qualquer forma para a busca funcionar bem.
O padrão são 1024 dimensões. O parâmetro dimensions pede um vetor menor, o que reduz memória e tamanho do índice — útil quando são milhões de vetores guardados.
A economia cobra um preço em qualidade, e ele não é linear. Na mesma busca, com a mesma base:
dimensions | Resultado observado |
|---|---|
1024 (padrão) | Primeiro resultado correto, com folga de 0,04 para o segundo |
512 | Primeiro resultado correto, mesma ordem do padrão |
128 | **Primeiro resultado errado** — o trecho certo cai para fora do topo |
Peça a dimensão, mas confira a que voltou
O dimensions nem sempre é respeitado: numa das medições, um pedido de 256 devolveu um vetor de 1024. Vetores de tamanhos diferentes no mesmo índice não podem ser comparados — leia len(embedding) na resposta e recuse o que não bater com o índice.
| Situação | Resposta |
|---|---|
| Modelo de chat neste endpoint | 400 — Model '...' does not support embeddings |
input ausente ou lista vazia | 400 — input is required |
| Modelo que não existe | 404 — Model '...' not found |
encoding_format: "base64" | 502 — não suportado; use o formato padrão, de números |
Texto vazio não é recusado
"input": "" devolve 200, com um vetor válido, e é cobrado. Nada na resposta indica que o texto estava vazio. Filtre strings vazias antes de montar o lote — senão elas entram no índice e passam a aparecer em buscas.
US$ 0,05 por milhão de tokens de entrada. Só entra na conta o que você manda; não há cobrança de saída, porque a saída é o vetor.
Em números de um caso real: indexar 10 mil trechos de mais ou menos 200 tokens cada dá 2 milhões de tokens — US$ 0,10, uma vez. Depois disso, cada busca custa o embedding da pergunta: uma frase de 10 tokens sai por US$ 0,0000005. O custo de uma busca semântica está no armazenamento e no servidor, não na API.
Guarde os vetores
Gerar o embedding de novo custa de novo. Vetor gerado é dado seu: grave junto do texto de origem, com o id do modelo e a dimensão. É o que permite reprocessar só o que mudou — e descobrir, no dia da troca de modelo, o que precisa ser refeito.

