Duas formas de integrar um LLM gratuito a um script Python
Quando as pessoas pesquisam por LLMs gratuitos para Python, elas geralmente querem dizer uma das duas coisas. A primeira é um modelo de pesos abertos que você baixa e executa localmente, usando algo como Ollama, llama.cpp ou a biblioteca transformers do Hugging Face. A segunda é um endpoint hospedado que custa tão pouco, ou vem com crédito de teste suficiente, que parece gratuito para um protótipo. Ambas são legítimas e adequadas para diferentes tarefas.
Executar localmente significa não ter cobrança por token e nenhum dado sair da sua máquina. Também significa que você precisa de RAM ou memória GPU suficientes para o modelo escolhido, espera pelos downloads e modelos pequenos que cabem em um laptop têm desempenho inferior ao de modelos grandes. Uma API hospedada elimina a questão do hardware, mas você paga por token após o fim do teste. Esta página cobre ambos honestamente e mostra o código Python para a opção hospedada neste site, compatível com OpenAI e funciona com o pacote openai padrão.
Modelos locais e API hospedada lado a lado
| Pergunta | Execute você mesmo | API hospedada pré-paga |
|---|---|---|
| Custo por token | Nenhum, mas você paga pelo hardware e energia | $0,15 por 1M de entrada, $0,50 por 1M de saída |
| Tempo de configuração | Instale o runtime, baixe os pesos e ajuste as configurações | Instale um pacote e cole uma chave |
| Comprimento do contexto | Limitado pela sua memória | 100.000 tokens, prompt mais conclusão |
| Concorrência | O que sua máquina conseguir lidar | 8 requisições simultâneas em uma chave completa, 2 em uma chave de teste |
| Recusas | Depende dos pesos que você escolher | Ajustado para responder sem recusas de conteúdo para uso adulto legal |
| Uso offline | Sim | Não |
Se você tiver uma GPU capaz e seu trabalho for privado ou offline, o local é uma boa opção e você pode parar de ler aqui. Se você quer um modelo maior sem possuir o hardware, ou quer que seu script se comporte da mesma forma em um laptop, um servidor e um runner de CI, a rota hospedada é mais simples. Muitos projetos usam ambos: um modelo local pequeno durante o desenvolvimento e o hospedado em produção, alternando-os alterando apenas uma URL base.
Configure o endpoint hospedado em cinco minutos
Você precisa de uma chave primeiro. Entre com Google ou com e-mail e senha, depois resgate o crédito de teste de $0,50 com um clique na página da chave de API. O teste é válido por 7 dias, um por pessoa e não precisa de pagamento. Depois, instale o SDK e mantenha a chave fora do seu código-fonte.
pip install openai
export NOTRACK_API_KEY="sk-your-key-here"
O cliente precisa de duas alterações em relação à configuração padrão do OpenAI: a URL base e a chave. O ID do modelo é uncensored, e apenas um modelo é oferecido.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.nsfwvideogenerator.cc/v1",
api_key=os.environ["NOTRACK_API_KEY"],
)
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "You are a concise writing assistant."},
{"role": "user", "content": "Give me three title ideas for a noir short story."},
],
temperature=0.8,
)
print(resp.choices[0].message.content)
print(resp.usage)
A autenticação é um cabeçalho Authorization: Bearer padrão, que o SDK adiciona para você. Existem dois métodos: POST /v1/chat/completions e GET /v1/models. Você pode confirmar a conexão com client.models.list(), que retorna o ID do modelo disponível. A lista completa de parâmetros está na página de documentação.
Respostas em streaming
Para qualquer coisa que uma pessoa assiste, use streaming. Defina stream=True e itere sobre os blocos conforme os eventos enviados pelo servidor chegam. O uso é relatado no final do streaming, então você ainda pode registrar as contagens de tokens.
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Write a four-line poem about rain on a tin roof."}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
usage = getattr(chunk, "usage", None)
if usage:
print("\n", usage)
Um detalhe pega muitos no susto: uma requisição em streaming ocupa seu slot de concorrência até o fim do streaming. Com uma chave de teste com 2 slots, dois streams abertos fazem uma terceira chamada receber 429 com o código concurrency. Sempre consuma ou feche o stream.
Chamada de ferramentas e modo JSON
O endpoint suporta tools, tool_choice, streaming de tool_calls e resultados enviados de volta como role: "tool". Aqui está uma solicitação completa com uma função.
import json
tools = [{
"type": "function",
"function": {
"name": "word_count",
"description": "Count the words in a piece of text.",
"parameters": {
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
},
}]
messages = [{"role": "user", "content": "How many words are in: the quick brown fox jumps"}]
first = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = first.choices[0].message
if msg.tool_calls:
messages.append(msg)
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = len(args["text"].split())
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": str(result),
})
final = client.chat.completions.create(model="uncensored", messages=messages, tools=tools)
print(final.choices[0].message.content)
Sempre analise arguments de forma defensiva; o modelo o retorna como uma string JSON e qualquer modelo pode ocasionalmente produzir um formato incorreto. Para saída estruturada sem ferramentas, use o modo JSON.
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "Reply with a JSON object with keys title and tags (list of strings)."},
{"role": "user", "content": "Describe a lighthouse keeper's diary."},
],
response_format={"type": "json_object"},
temperature=0.2,
)
data = json.loads(resp.choices[0].message.content)
print(data["title"], data["tags"])
Diga a palavra JSON e nomeie as chaves no seu prompt, e mantenha a temperatura baixa. Envolva json.loads em um bloco try para código de produção.
Limites de taxa, erros e tentativas
Uma chave completa permite 8 requisições simultâneas e 300 requisições por minuto. Uma chave de teste permite 2 e 60. Ultrapasse e você receberá HTTP 429 com o código rate_limited (muitas por minuto) ou concurrency (muitas de uma vez). Em sobrecarga temporária, a API também retorna 429, com o cabeçalho Retry-After: 5. O SDK tenta novamente alguns erros automaticamente; para um script que distribui tarefas, um wrapper explícito pequeno é mais claro.
import time
from concurrent.futures import ThreadPoolExecutor
from openai import RateLimitError
def ask(prompt, tries=4):
for attempt in range(tries):
try:
r = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": prompt}],
max_tokens=300,
)
return r.choices[0].message.content
except RateLimitError:
time.sleep(5 * (attempt + 1))
raise RuntimeError("still rate limited")
prompts = [f"Summarize idea number {i} in one sentence." for i in range(20)]
with ThreadPoolExecutor(max_workers=2) as pool: # 8 on a full key
results = list(pool.map(ask, prompts))
Corresponder max_workers ao limite de concorrência da sua chave evita a maioria dos 429s antes que aconteçam. Cada resposta também carrega X-Request-Id, X-Balance-USD e dois cabeçalhos de limite de taxa, que você pode ler através de client.chat.completions.with_raw_response.create(...) quando precisar deles para depuração ou suporte.
Como escolher entre local e hospedado
Pule a ideologia e responda a quatro perguntas sobre o seu projeto.
- Os dados precisam ficar na sua máquina? Se um contrato ou hábito disser sim, execute localmente. Os prompts hospedados não são usados para treinamento aqui, mas eles viajam pela rede.
- Quanta memória você tem? O tamanho do modelo determina a qualidade. Um laptop sem GPU dedicada limita você a modelos pequenos, e as respostas mostrarão isso. Um modelo hospedado oferece um grande com uma janela de contexto de 100.000 tokens, o que é difícil de igualar em casa.
- Quantas requisições você enviará? Algumas centenas por semana são triviais em ambos os lados. Centenas de milhares por mês transformam a conta hospedada em um número real, e uma máquina local começa a parecer atraente se ficar ociosa. Calcule a soma: 100.000 requisições de 1.000 tokens de entrada e 500 de saída custam 100.000 x $0,0004 = $40.
- Você precisa que recusas sejam tratadas de uma certa maneira? Muitos modelos de pesos abertos vêm com comportamento de recusa embutido, e outros são ajustados para removê-lo. O modelo hospedado aqui é ajustado para responder sem recusas de conteúdo para uso adulto lícito, então você não precisa procurar os pesos certos.
Se suas respostas apontarem para ambos os lados, comece com o hospedado na primeira semana. O teste não custa nada, e você aprenderá o que seus prompts precisam antes de comprar hardware ou baixar outro arquivo de vários gigabytes.
Erros comuns em scripts Python
A maioria dos problemas que as pessoas enfrentam são pequenos e solucionáveis.
- URL base errada. Ela deve terminar em
/v1. Um sufixo ausente resulta em 404, não em uma mensagem útil. Imprimaclient.base_urlse tiver dúvidas. - Chave no código. Leia-a de uma variável de ambiente, como acima, e adicione seu arquivo
.envao.gitignore. - Nome do modelo errado. O único ID do modelo é
uncensored. Nomes de outros provedores não funcionarão, então altere-os ao portar código. - Loops sem fim. Um loop de chamada de funções que não termina é um bug caro. Limite-o para, digamos, cinco rodadas.
- Ignorar o orçamento de contexto. Prompt e conclusão compartilham os 100.000 tokens. Se você anexar cada turno para sempre, eventualmente atingirá o limite. Reduza ou resuma mensagens antigas.
- Assumindo que JSON é sempre válido. Mesmo no modo JSON, verifique as chaves que você precisa antes de usá-las.
Quando algo parece errado do lado do servidor, cite o valor X-Request-Id da resposta ao escrever para suporte. Isso permite que os operadores encontrem sua chamada exata.
Quanto a opção hospedada custa para trabalho Python
Uma chamada de script típica com 1.000 tokens de entrada e 500 de saída custa $0,00015 mais $0,00025, totalizando $0,0004. Os $0,50 do teste cobrem cerca de 1.250 deles. Uma recarga de $20, o mínimo, cobre 50.000. O crédito nunca expira, requisições falhas ou recusadas não são cobradas e os prompts não são usados para treinamento. Recargas vão até $500 com um bônus a partir de $50, e o pagamento é em cripto, USDT na TRC20 ou USDC na Base. Veja a página de preços para os detalhes.
É apenas texto: sem imagens, áudio, vídeo, embeddings ou fine-tuning. E a única regra rígida é sem conteúdo sexual envolvendo menores de idade. Para um projeto Python que precisa de geração de texto com menos recusas, essa é toda a superfície.
