Ir para o conteúdo

SDK Python

Instale o SDK oficial em Python e use chat, busca na web, agentes e busca semântica no HiNow.

Atualizado em 09 de ago. de 2026

O SDK oficial em Python para a API do HiNow. Requer Python 3.8 ou mais novo e usa httpx por baixo, com cliente síncrono e assíncrono.

A API fala o protocolo da OpenAI, e o SDK segue o mesmo formato. Se você já integrou com a OpenAI, o desenho das chamadas é o que você conhece.

Instalação

terminalbash
pip install hinow-ai

Guarde a chave em HINOW_API_KEY e o SDK a encontra sozinho. Passar apiKey no construtor também funciona, mas evite deixar o valor no código.

terminalbash
export HINOW_API_KEY="hi_sua_chave_aqui"

A primeira chamada

primeira-chamada.pypython
import os
from hinow_ai import Hinow

# The key comes from HINOW_API_KEY when you pass nothing.
client = Hinow(api_key=os.environ["HINOW_API_KEY"])

response = client.chat.completions.create(
    model="hinow/higenesis",
    messages=[{"role": "user", "content": "Explain what an embedding is in one sentence."}],
    max_tokens=120,
    temperature=0,
)

print(response.choices[0].message.content)
print("tokens:", response.usage.total_tokens)

O prefixo hinow/ faz parte do nome do modelo

Mandar himax em vez de hinow/himax devolve 404 model_not_found, e a mensagem não deixa claro que faltou o prefixo. Vale para todos: hinow/himax, hinow/hinova, hinow/higenesis.

Mostrando a resposta enquanto ela chega

Com stream=True o retorno vira um gerador. Cada pedaço chega em chunk.choices[0].delta.content, tipado igual à resposta não-stream.

streaming.pypython
from hinow_ai import Hinow

client = Hinow()

for chunk in client.chat.completions.create(
    model="hinow/hinova",
    messages=[{"role": "user", "content": "List three uses of an LLM, one per line."}],
    stream=True,
):
    print(chunk.choices[0].delta.content or "", end="", flush=True)
print()

Busca na web

Responde na hora, sem job para acompanhar, a US$ 0,005 por chamada. O tipo do retorno acompanha o type, então o compilador só deixa você acessar os campos que aquele tipo realmente devolve.

busca-web.pypython
from hinow_ai import Hinow

client = Hinow()

# The shape of the answer follows `type`: news carries date and source,
# places carries phone and coordinates, autocomplete carries suggestions.
web = client.tools.search("plataforma de IA brasileira", country="br", lang="pt-br")

print(f"{web['total_results']} results · US$ {web['cost']}")
for r in web["results"][:3]:
    print(f"{r['position']}. {r['title']}")
    print(f"   {r['url']}")

news = client.tools.search("artificial intelligence", type="news", country="br")
print(f"\n{news['results'][0]['source']}{news['results'][0]['date']}")
typeO que vem em cada resultado
search, scholar, patentsposition, title, url, snippet
newsos acima mais source, date, image_url
imageslink, image_url, thumbnail_url, width, height
videoschannel, duration, date, thumbnail_url
placesaddress, category, phone, website, rating, coordenadas
shoppingprice, delivery, rating, source
autocompletesuggestions, um array de strings — não tem results

Contatos de um site

Varre um ou mais sites atrás de e-mails, telefones e perfis sociais, devolvendo a página onde cada contato apareceu. Esta roda como job, porque a varredura leva tempo.

contatos-site.pypython
from hinow_ai import Hinow

client = Hinow()

# The crawl runs as a job. This method waits and raises if it fails,
# so "result" always exists when it returns.
job = client.tools.website_contacts_and_wait(
    ["https://teclia.com"],
    max_depth=1,
    max_links_per_page=5,
    on_poll=lambda j: print("…", j["status"]),
)

print(f"cost US$ {job['cost']} · cached: {job['cached']}")
for contact in job["result"]["items"]:
    print(f"{contact['type']}: {contact['value']}  ({contact['sourceUrl']})")

Repetir uma execução idêntica não cobra de novo

O job volta com cached: true quando o resultado veio do cache. Se quiser controlar o ciclo você mesmo, use tools.website_contacts() e acompanhe com tools.jobs.retrieve(job['job_id']) — repare que o campo é job_id, não id.

Agentes

Assistentes, threads e runs no mesmo formato da API da OpenAI. O modelo decide quando chamar as suas funções; o run para, você executa e devolve o resultado.

agente.pypython
import json
from hinow_ai import Hinow

client = Hinow()

assistant = client.beta.assistants.create(
    model="hinow/hinova",
    name="Order support",
    instructions="You look up order status. Always use the tool. Answer in one sentence.",
    tools=[{
        "type": "function",
        "function": {
            "name": "get_order",
            "description": "Lookup um order pelo identificador.",
            "parameters": {
                "type": "object",
                "properties": {"order_id": {"type": "string", "description": 'ex.: "A-1001"'}},
                "required": ["order_id"],
            },
        },
    }],
)

thread = client.beta.threads.create()
client.beta.threads.messages.create(thread["id"], content="What is the status of order A-1001?")

run = client.beta.threads.runs.create_and_poll(thread["id"], assistant_id=assistant["id"])

# "requires_action" is not an error: it is the run handing control back to you.
if run["status"] == "requires_action":
    chamadas = run["required_action"]["submit_tool_outputs"]["tool_calls"]

    run = client.beta.threads.runs.submit_tool_outputs(
        thread["id"], run["id"],
        tool_outputs=[
            {"tool_call_id": c["id"], "output": json.dumps({"id": "A-1001", "status": "delivered"})}
            for c in chamadas
        ],
    )
    run = client.beta.threads.runs.poll(thread["id"], run["id"])

messages = client.beta.threads.messages.list(thread["id"], order="desc", limit=1)
print(messages["data"][0]["content"][0]["text"]["value"])

client.beta.assistants.delete(assistant["id"])
client.beta.threads.delete(thread["id"])

requires_action não é erro

É o run devolvendo o controle para você executar uma função. Por isso o poll retorna nesse estado em vez de continuar girando: leia o required_action, chame submit_tool_outputs e volte a acompanhar.

Documentos e busca semântica

Suba arquivos, junte num vector store e busque por significado. A indexação é assíncrona — buscar antes de terminar devolve zero resultado, sem erro.

conhecimento.pypython
import time
from hinow_ai import Hinow

client = Hinow()

text = b"Free shipping on orders over $200. Standard delivery takes 5 business days."
file = client.files.create(text, filename="shipping-policy.txt", purpose="assistants")

base = client.vector_stores.create(name="Politicas")
anexo = client.vector_stores.files.create(base["id"], file_id=file["id"])

# Indexing is asynchronous. Searching before it finishes returns nothing,
# with no error to say why.
while anexo["status"] == "in_progress":
    time.sleep(1)
    anexo = client.vector_stores.files.retrieve(base["id"], file["id"])

# The per-store filter is called rag_id. Passing vector_store_id raises no error:
# the search sweeps every document on the account.
hits = client.rag.search("qual o prazo de entrega?", rag_id=base["id"], top_k=2)

for a in hits["results"]:
    print(f"{a['score']:.2f}  {a['source']}: {a['text'][:60]}")

client.vector_stores.delete(base["id"])
client.files.delete(file["id"])

O filtro por base chama-se rag_id

Passar vector_store_id não gera erro: a busca simplesmente varre todos os documentos da conta em vez da base que você queria. É o tipo de detalhe que faz parecer que o RAG está devolvendo lixo.

Erros

Cada falha vira uma classe própria, então dá para tratar por tipo em vez de comparar string de mensagem.

erros.pypython
from hinow_ai import Hinow, AuthenticationError, RateLimitError, InsufficientBalanceError

client = Hinow(api_key="hi_invalid_key")

try:
    client.get_balance()
except AuthenticationError as e:
    print("invalid or revoked key:", e)
except RateLimitError:
    print("rate limited; wait and try again")
except InsufficientBalanceError:
    print("out of credit")

Tudo que o cliente expõe

RecursoPara quê
client.chat.completionsConversa, streaming, chamada de funções, modo JSON
embeddingsVetores para busca semântica
images · audio · videoGeração
modelsCatálogo, preço e recursos de cada modelo
toolsBusca na web e contatos de site
filesUpload de documentos
vector_storesBases de conhecimento pesquisáveis
ragBusca semântica nos seus documentos
beta.assistants · beta.threadsAgentes executados no servidor
get_balance()Saldo da conta

Configuração

cliente.pytypescript
const client = new Hinow({
  apiKey: process.env.HINOW_API_KEY,  // ou deixe em branco e use a variável
  baseURL: 'https://api.hinow.ai',    // ou HINOW_BASE_URL
  timeout: 120_000,                   // milissegundos
  maxRetries: 3,
});

Vindo da versão 1.x

Até a 1.0.7, o SDK empacotava temperature, max_tokens, top_p e response_format dentro de um objeto parameters antes de enviar. A API aceita esse formato e ignora, então essas opções nunca surtiam efeito: pedir max_tokens: 10 devolvia a resposta inteira.

A partir da 2.0 tudo vai no nível raiz, como a API espera. Seu código não muda — mas chamadas que silenciosamente ignoravam um limite passam a respeitá-lo, então revise prompts que dependiam do comportamento antigo.

Duas outras correções da mesma versão: o upload de arquivo não funcionava, porque o cliente fixava Content-Type: application/json e isso quebrava o multipart; e os pedaços do streaming agora são tipados, então é chunk.choices[0].delta.content em vez de acesso por dicionário.

Escolhendo entre HiMax, HiNova e HiGenesis

O que cada modelo faz bem, quanto custa e como escrever o prompt para cada um.

Esta página foi útil?