A partir da versão 0.35, Ollama suporta modelos de decisão construídos na API Jev do TypeSafe. Estes não são modelos de chat no sentido usual: eles não escrevem texto, mas respondem a um conjunto de perguntas digitadas sobre o estado transferido. Para classificação, roteamento, moderação e triagem, isso acaba sendo mais rápido e confiável do que pedir a um LLM normal que retorne JSON e depois analise sua resposta.
Nesta postagem, veremos o que são modelos de decisão, como funcionam no nível HTTP, quais modelos já estão disponíveis e como construí-los no código existente para que os modelos generativos regulares continuem a funcionar.
Como os modelos de decisão diferem dos modelos normais
Um LLM regular recebe um prompt e gera texto token por token. Mesmo que você peça que ela responda em uma palavra, a geração ainda ocorre internamente, e o formato da resposta deve ser controlado por diagrama, instruções e posterior verificação. O modelo de Decisão funciona de maneira diferente: você passa estados e questões com tipos, e o modelo retorna probabilidades e opções selecionadas. Sem texto livre, sem análise de JSON da resposta.
O novo endpoint é chamado /v1/systemone. Em uma solicitação, você pode fazer várias perguntas ao mesmo tempo, e o modelo responderá a todas elas. Isso é conveniente para tarefas em que você precisa tomar diversas decisões relacionadas: por exemplo, determinar a equipe, a necessidade de retorno e a urgência do ticket.
Quais modelos estão disponíveis
Agora você pode executar três modelos de decisão por meio do Ollama:
- nimble é um modelo aberto com 9 bilhões de parâmetros do Bespoke Labs. É o maior e mais preciso disponível.
- tev1 é um modelo experimental com 4 bilhões de parâmetros da Together AI.
- tev1:0.8b é um modelo experimental com 0,8 bilhão de parâmetros do Together AI. O mais rápido e fácil.
Todos trabalham localmente, não exigem pagamento e não enviam dados para serviço externo. Ollama 0.35 e posteriores são suportados.
Instalação
Primeiro verifique a versão do Ollama:
ollama --version
Em seguida, baixe o modelo desejado. Para o mais fácil:
ollama pull tev1:0.8b
Para a versão completa do tev1:
ollama pull tev1
Para ágil:
ollama pull nimble
O modelo ágil ocupa cerca de 9,5 GB de espaço em disco, por isso é uma boa ideia liberar espaço antes de fazer o download. tev1:0.8b ocupa menos de um gigabyte.
Primeira solicitação via curl
O exemplo mais simples é determinar se um texto é um anúncio de emprego:
curl http://localhost:11434/v1/systemone -d '{
"model": "tev1:0.8b",
"state": {
"message": "Senior Swift developer, Berlin, remote friendly"
},
"questions": {
"isJob": {
"type": "noul",
"instructions": "Does the message advertise a job posting that someone can apply to?"
}
}
}'
A resposta é assim:
{
"model": "tev1:0.8b",
"answers": {
"isJob": {
"type": "noul",
"noul": 0.921
}
},
"usage": {
"input_tokens": 42,
"output_tokens": 0
}
}
O campo noul é uma probabilidade de 0 a 1. A decisão é tomada por comparação com um limite, geralmente 0,5. Ao contrário do modelo generativo, não há necessidade de solicitar uma resposta no formato JSON e depois verificar se o modelo não a quebrou.
Tipos de perguntas
Os modelos de decisão suportam três tipos de perguntas.
noul é uma questão binária. Retorna a probabilidade de uma afirmação ser verdadeira:
{
"questions": {
"refund": {
"type": "noul",
"instructions": "Does the customer explicitly ask for a refund?"
}
}
}
escolha – selecionar uma opção de um determinado conjunto. Retorna a opção selecionada, as probabilidades de todas as opções e a confiança:
{
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should handle this ticket?",
"criteria": {
"billing": "Payments and refunds",
"technical": "Bugs and integrations",
"other": "None of the above"
}
}
}
}
pontuação – classificação em uma escala. Retorna o número, a legenda e as probabilidades de cada ponto da escala:
{
"questions": {
"urgency": {
"type": "score",
"instructions": "How urgent is this ticket?",
"criteria": ["Routine", "Soon", "Urgent"]
}
}
}
Uma solicitação pode conter várias perguntas de diferentes tipos ao mesmo tempo. É isto que torna os modelos de decisão convenientes para a triagem: uma operação, um estado, várias decisões independentes.
Python sem bibliotecas adicionais
Para solicitações, o urllib padrão é suficiente; um SDK separado não é necessário:
import json
from urllib.request import Request, urlopen
OLLAMA_DECISION_URL = "http://localhost:11434/v1/systemone"
def ask_decision(state, questions, model="tev1:0.8b"):
payload = {
"model": model,
"state": state,
"questions": questions,
}
request = Request(
OLLAMA_DECISION_URL,
data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"},
method="POST",
)
with urlopen(request, timeout=3600) as response:
return json.loads(response.read().decode())["answers"]
Uso:
answers = ask_decision(
{"message": "Senior Swift developer, Berlin, remote friendly"},
{
"isJob": {
"type": "noul",
"instructions": "Does the message advertise a job posting that someone can apply to?"
}
},
)
probability = answers["isJob"]["noul"]
is_job = probability >= 0.5
Se você precisar de um SDK oficial do Python, ele será chamado typesafe-sdk. Para localhost, pode ser direcionado para Ollama com as variáveis de ambiente TYPESAFE_BASE_URL, TYPESAFE_API_KEY e TYPESAFE_DEFAULT_MODEL. Mas para tarefas simples, uma solicitação HTTP direta é suficiente.
Como entender que um modelo apoia a decisão
Os modelos de decisão não podem responder via /api/generate ou /api/chat. Se você enviar tal solicitação, Ollama retornará um erro 400 com um texto como:
"tev1:0.8b" does not support generate
Isso é importante se você já possui código que funciona com modelos regulares via /api/generate: se você alterar o modelo para um modelo de decisão, ele irá parar de funcionar. É melhor descobrir antecipadamente os recursos do modelo via /api/show e escolher o método de chamada apropriado:
import json
from urllib.request import Request, urlopen
OLLAMA_SHOW_URL = "http://localhost:11434/api/show"
def supports_decision(model):
request = Request(
OLLAMA_SHOW_URL,
data=json.dumps({"model": model}).encode(),
headers={"Content-Type": "application/json"},
method="POST",
)
try:
with urlopen(request, timeout=30) as response:
capabilities = json.loads(response.read().decode()).get("capabilities", [])
except (OSError, TypeError, ValueError):
return False
return "decision" in capabilities
Os modelos de decisão terão apenas decisão em suas capacidades. Os modelos regulares terão acabamento, ferramentas ou outros recursos. Se Ollama não estiver disponível, é razoável considerar o modelo normal e utilizar o caminho generativo.
Como incorporar em código existente
A maneira mais simples não é reescrever o classificador, mas sim dividi-lo em duas estratégias. A estratégia generativa funciona como antes: ela coleta o prompt, envia-o para /api/generate e analisa o JSON. A estratégia de decisão envia o estado e a pergunta digitada para /v1/systemone e compara a probabilidade com um limite.
A escolha da estratégia ocorre em um só lugar, ao criar um classificador:
def create_classifier(model):
if supports_decision(model):
return DecisionClassifier(model)
return GenerativeClassifier(model)
Esta abordagem tem várias vantagens. Os modelos generativos continuam a funcionar inalterados. O modelo de decisão pode ser ativado alterando uma variável de ambiente. E toda a diferença entre os dois métodos está concentrada em duas pequenas classes, e não está espalhada por toda a aplicação.
Para uma classificação binária, a estratégia de decisão é mais ou menos assim:
async def classify(text):
answers = await ask_decision(
{"message": text},
{
"isJob": {
"type": "noul",
"instructions": instructions,
}
},
model,
)
probability = answers["isJob"]["noul"]
return probability >= 0.5, probability
Observe que o modelo de decisão não retorna uma explicação. Se o seu formato de resultado tiver um campo de razão, você poderá construí-lo a partir da probabilidade: por exemplo, armazene a própria probabilidade ou uma string como “o modelo classificou a mensagem em 0,935 como uma vaga”. Isto é mais honesto do que inventar uma razão que o modelo não deu.
As instruções devem ser uma pergunta
Esta é a conclusão prática mais importante. Os modelos de decisão não entendem prompts longos no estilo “você classifica as mensagens, responda verdadeiro se…, falso caso contrário”. Eles querem uma pergunta curta e direta.
Na mesma mensagem sobre uma vaga, recebi as seguintes probabilidades:
- Pergunta direta “Esta mensagem é um anúncio de emprego?” — 0,921.
- Instruções longas explicando o que é considerado uma vaga – 0,026.
- Instruções longas com uma pergunta no final – 0,391.
A diferença é de quase trinta vezes. O modelo não se engana na classificação, simplesmente não entende o que querem dele quando a questão está escondida dentro de um parágrafo. Portanto, para modelos de decisão vale a pena manter instruções curtas separadas e deixar prompts longos para modelos generativos.
É conveniente criar uma variável de ambiente separada:
OLLAMA_JOB_CLASSIFIER_DECISION_INSTRUCTIONS=Does the message advertise a job posting that someone can apply to?
E use um prompt regular apenas para o caminho gerador.
Limite e probabilidades
O limite de 0,5 é adequado como valor padrão, mas é útil incluí-lo na configuração. Para tarefas diferentes, o custo de uma resposta falso positiva e falsa negativa é diferente. Para moderação, é mais seguro aumentar o limite; para a busca de vagas é mais seguro baixá-la, para não perder mensagens úteis.
Também é útil registrar a probabilidade em si, e não apenas o booleano resultante. Quando o classificador comete um erro, o log mostra se foi uma resposta segura ou uma decisão na fronteira. Para questões de escolha, vale guardar as probabilidades e a confiança: elas mostram o quanto o modelo oscila entre as opções.
Desempenho e memória
A velocidade depende muito do tamanho do modelo e do hardware. Na CPU em meus testes obtive os seguintes números:
- tev1:0.8b – fração de segundos para resolver, cabe facilmente na memória.
- tev1 – 4B, visivelmente mais lento, mas ainda adequado para tarefas interativas.
- ágil – 9B em Q8_0, cerca de 10 GB de memória. A primeira solicitação, incluindo o carregamento do modelo, levou cerca de 137 segundos, as soluções subsequentes levaram de 12 a 32 segundos na CPU.
Nimble requer muita RAM. Em uma máquina com 16 GB e Docker/WSL com limite de cerca de 8 GB, o modelo não cabe: o sistema começa a trocar e os containers param de responder. Aumentar o limite WSL para 12 GB por meio do arquivo .wslconfig ajudou:
[wsl2]
memory=12GB
swap=8GB
Após a alteração, você precisa de wsl –shutdown e reinicie o Docker Desktop. Mas mesmo com 12 GB, a reserva continua pequena: o modelo ocupa cerca de 10 GB e não sobra muito para o sistema.
Por padrão, o Ollama descarrega o modelo após cinco minutos de inatividade, liberando memória. Isso é conveniente: o ágil não mantém 10 GB ocupados o tempo todo, mas cada novo lançamento após uma pausa começa a carregar o modelo novamente.
Quando usar modelos de decisão
Os modelos de decisão são adequados para tarefas em que você precisa de uma resposta rápida e barata para uma pergunta claramente formulada:
- Classificação de mensagens, tickets e solicitações.
- Roteamento por comandos ou executores.
- Moderação de conteúdo e verificações de segurança.
- Soluções binárias e multivariadas rápidas em jogos ou aplicativos interativos.
Eles são pouco adequados para tarefas onde é necessário texto detalhado: explicação, extração de campos, resumo, geração de respostas. Para este efeito, permanecem os modelos generativos habituais. O melhor resultado é obtido quando combinados: um modelo de decisão toma uma decisão e um modelo generativo a explica ou extrai dados.
Total
Os modelos de decisão no Ollama são uma ferramenta separada e mais restrita do que os LLMs regulares. Eles não substituem os modelos generativos, mas eliminam a parte rotineira do trabalho: respostas digitadas, probabilidades em vez de análise de texto e um formato previsível. Se você já possui um pipeline de classificação, a transição se resume à verificação dos recursos do modelo, uma estratégia de chamada separada e perguntas instrucionais curtas.
Fontes
https://ollama.com/blog/ollama-now-supports-jev-style-decision-models
https://ollama.com/library/nimble
https://ollama.com/library/tev1
https://typesafe.ai
Leave a Reply