Nonobench
Um benchmark de código aberto sobre o quão bem LLMs resolvem quebra-cabeças nonogram, de 5x5 a 20x20.
Servidor MCP hospedado
npx add-mcp 'https://www.nonobench.com/mcp'Instala no Claude Code, Codex, Cursor e outros
Documentação
Nonobench
Uma suíte de benchmarks para avaliar as capacidades de raciocínio de LLMs na resolução de quebra-cabeças Nonogram (Picross) em diferentes tamanhos de grade. Os resultados são publicados em nonobench.com.
Criado por Maurice Kleine.
O que é um Nonogram?
Nonograms (também conhecidos como Picross, Griddlers ou Paint by Numbers) são quebra-cabeças de lógica onde você preenche células em uma grade com base em pistas numéricas para cada linha e coluna. As pistas indicam grupos consecutivos de células preenchidas, separados por pelo menos uma célula vazia. Resolver esses quebra-cabeças requer dedução lógica e satisfação de restrições - tornando-os um excelente teste das capacidades de raciocínio de LLMs.
Estrutura do Projeto
nonobench/
├── bench/ # Benchmark runner, results database and exporter
└── visualizer/ # TanStack Start dashboard on Cloudflare Workers (nonobench.com), also home of the puzzle set
Pré-requisitos
- Runtime Bun (v1.4+)
- Node.js v24+ (para o visualizador)
- Chave de API OpenRouter
Início Rápido
1. Clonar o Repositório
git clone https://github.com/mauricekleine/nonobench.git
cd nonobench
2. Configurar Variáveis de Ambiente
Crie um arquivo .env no diretório bench/ (veja bench/.env.example):
OPENROUTER_API_KEY=your_openrouter_api_key_here
Esta é a única variável necessária. O visualizador é construído sem nenhuma.
3. Executando Benchmarks
cd bench
bun install
bun run bench # prints the plan and exits, no API calls
bun run bench --model <name> # run one model (repeat --model for more)
bun run bench --all-missing # run every configured model with missing work
bun run bench --model <name> --sizes 20x20 # opt in to the extended tier
As execuções são incrementais e somente de acréscimo: um par modelo/quebra-cabeça que já possui um resultado bem-sucedido nunca é executado novamente, e o banco de dados se recusa a sobrescrevê-lo. Execuções com falha são tentadas novamente na próxima invocação. Os resultados são armazenados em bench/results.db (SQLite).
Flags úteis:
--max-cost <usd>interrompe o lançamento de novos quebra-cabeças quando o gasto desta sessão atingir o valor. Requisições já em andamento ainda terminam, então uma sessão pode ultrapassar em até--parallelrequisições por modelo selecionado. Use o limite da própria chave OpenRouter como teto máximo.--parallel <n>define requisições concorrentes por modelo (padrão 10); reduza para provedores com limite de taxa.--limit <n>executa apenas os primeiros n quebra-cabeças de cada tamanho, para pilotos contra um banco de dados de teste (NONOBENCH_DB=/tmp/copy.db).
Modos de saída
Novas execuções pedem a resposta como saída estruturada estrita (um esquema JSON, roteado apenas para endpoints que o impõem), então os modelos não podem envolver a grade em prosa. Para alguns modelos, os endpoints que impõem esquema prejudicam mensuravelmente as respostas; esses executam em modo texto (outputMode: "text" em bench/constants.ts, escolhido por um teste A/B 5x5 com o prompt de benchmark). Cada execução registra seu modo, e a avaliação é idêntica para ambos: a resposta deve satisfazer cada pista. O executor também interrompe um modelo que não resolve nenhum dos quebra-cabeças 5x5 com saída estruturada, e um cujas execuções iniciais relatam principalmente zero tokens de raciocínio, pois ambos apontam para o harness em vez do modelo.
Após o benchmark, exporte os resultados para o visualizador:
bun run export
Isso escreve visualizer/app/results.json (agregados) e visualizer/public/results-raw.json (cada execução, incluindo prompts e saídas).
Outros scripts:
bun test- verificações de parser, avaliador, política de banco de dados e quebra-cabeçasbun run typecheck- verificação TypeScriptbun run regrade- comparação somente leitura das notas armazenadas contra o avaliador atual
Executando Contra um Modelo Local
O executor pode avaliar um modelo que você mesmo serve. Qualquer servidor com um endpoint /v1 compatível com OpenAI funciona: vLLM, SGLang, llama.cpp, LM Studio e Ollama.
Esta configuração usa duas máquinas. O servidor de modelo é a estação de trabalho que serve o modelo. A máquina de benchmark é o laptop que executa o benchmark.
1. Sirva o modelo na estação de trabalho
Vincule o servidor a todas as interfaces. O endereço de vinculação padrão, 127.0.0.1, aceita conexões apenas do próprio servidor de modelo.
vLLM:
vllm serve Qwen/Qwen3-32B --host 0.0.0.0 --port 8000
Ollama:
ollama pull qwen3:32b
OLLAMA_HOST=0.0.0.0:11434 ollama serve
llama.cpp:
llama-server -m ./qwen3-32b-Q4_K_M.gguf --host 0.0.0.0 --port 8080
SGLang:
python -m sglang.launch_server --model-path Qwen/Qwen3-32B --host 0.0.0.0 --port 30000
LM Studio: abra a aba Developer e selecione Start Server. Ative o switch Network Server, para que o servidor escute em todas as interfaces.
CUIDADO: Não exponha a porta à internet. A maioria dos servidores locais não tem autenticação, então qualquer pessoa que alcance a porta pode executar o modelo.
2. Abra a porta no servidor de modelo
Restrinja a regra ao seu próprio sub-rede. Permita tráfego TCP da sua rede local para a porta:
sudo ufw allow from 192.168.1.0/24 to any port 8000 proto tcp
No macOS, permita conexões de entrada para o aplicativo do servidor em Configurações do Sistema.
3. Verifique a conexão a partir do laptop
Encontre o endereço LAN do servidor de modelo. No Linux, execute ip -4 addr show. No macOS, execute ipconfig getifaddr en0.
A partir do laptop, solicite a lista de modelos:
curl http://192.168.1.20:8000/v1/models
Certifique-se de que a resposta liste seu modelo. Copie o valor exato de id. Você precisa desse valor para NONOBENCH_LOCAL_MODEL.
Se a requisição falhar, verifique o endereço de vinculação da etapa 1. Depois verifique a regra de firewall, o endereço e a porta.
Se o servidor de modelo não estiver acessível na sua rede, crie um túnel SSH para ele. Em seguida, use o endereço http://127.0.0.1:8000/v1:
ssh -N -L 8000:127.0.0.1:8000 user@192.168.1.20
4. Execute o benchmark
cd bench
bun install
NONOBENCH_LOCAL_BASE_URL=http://192.168.1.20:8000/v1 \
NONOBENCH_LOCAL_MODEL=Qwen3-32B \
bun run bench:local --model Qwen3-32B
Faça um piloto primeiro. O próximo comando executa dois quebra-cabeças 5x5 em um banco de dados de teste:
NONOBENCH_LOCAL_BASE_URL=http://192.168.1.20:8000/v1 \
NONOBENCH_LOCAL_MODEL=Qwen3-32B \
NONOBENCH_DB=local-pilot.db \
bun run bench --model Qwen3-32B --sizes 5x5 --limit 2
Certifique-se de que o plano liste seu modelo como [local, text].
Variáveis de ambiente para um modelo local
| Variável | Significado |
|---|---|
NONOBENCH_LOCAL_BASE_URL | O endpoint /v1 do servidor. Ollama usa a porta 11434. |
NONOBENCH_LOCAL_MODEL | O id do modelo que o servidor retorna de GET /v1/models. |
NONOBENCH_LOCAL_NAME | O nome de exibição e o valor para --model. Padrão é o id do modelo. Não deve corresponder a um nome de modelo de nuvem. |
NONOBENCH_LOCAL_EFFORT | O esforço de raciocínio com o qual seu servidor está configurado (none, low, xhigh, …). Apenas rótulo — o executor nunca envia configurações de raciocínio para um servidor local. Padrão é none. |
NONOBENCH_LOCAL_API_KEY | O token bearer, quando o servidor exigir um. Padrão é local. |
O executor adiciona o modelo local ao plano somente quando você define ambos NONOBENCH_LOCAL_BASE_URL e NONOBENCH_LOCAL_MODEL.
Notas sobre execuções locais
- Execuções locais custam $0. Mantenha-as fora do conjunto de dados publicado: execute-as com
bun run bench:local, que ébun run benchcomNONOBENCH_DB=local-results.db.bench/results.dbé o conjunto de dados compartilhado, e o teste de contrato de exportação o verifica contra as exportações commitadas. O executor se recusa a escrever um modelo local no banco de dados compartilhado. - Antes de começar, o executor verifica o
iddo modelo contra a listaGET /v1/modelsdo servidor. Um erro de digitação falha com os modelos que o servidor realmente serve, e um servidor inacessível falha antes que qualquer execução seja registrada. - O modo texto é o padrão para um modelo local. Muitos servidores locais aceitam uma requisição de esquema JSON e depois a ignoram. Se seu servidor impõe o esquema, defina
NONOBENCH_OUTPUT_MODE=json_schema. - Comece com
--parallel 1. Uma GPU atende menos requisições ao mesmo tempo do que um provedor de nuvem. - O nível 20x20 pede 128.000 tokens de saída. Se seu servidor tem um contexto menor, execute apenas os tamanhos principais.
- O executor não aplica o disjuntor de tokens de raciocínio a um modelo local. Alguns servidores locais relatam zero tokens de raciocínio para cada execução.
- Defina as mesmas variáveis em
bench/.envpara evitar o prefixo em cada comando. - Uma execução de benchmark registra o modelo local em
bench/local-models.json(nome, id do modelo do servidor, família, URL do servidor), então umbun run exportposterior e o visualizador o detectam sem nenhuma variável de ambiente. Para registrar um modelo que você já avaliou, adicione uma entrada lá:"<name>": { "baseURL": "http://host:port/v1", "modelId": "<server model id>", "family": "<name>" }. OmitamodelIdquando o nome for o id do servidor.
4. Visualizando Resultados
cd visualizer
bun install
bun run dev
Em seguida, abra http://localhost:3000 para ver o painel interativo.
Suas próprias execuções vivem em um banco de dados separado. Sirva-as com:
cd visualizer
bun run dev:local
dev:local exporta bench/local-results.db para os arquivos de dados do painel, inicia o servidor de desenvolvimento e restaura os arquivos commitados quando você o interrompe. Enquanto ele executa, o painel mostra apenas os modelos nesse banco de dados — suas execuções locais, não o ranking publicado. Defina NONOBENCH_LOCAL_DB para servir outro banco de dados.
Enquanto esse servidor executa, bun test em bench falha em um teste: o teste de contrato de exportação compara os arquivos de dados do painel contra bench/results.db, e dev:local colocou suas execuções neles. Interrompa o servidor, deixe o script restaurar os arquivos commitados, e a suíte passa novamente.
5. Implantando
O visualizador é um Cloudflare Worker (visualizer/wrangler.jsonc). As páginas são pré-renderizadas no momento da construção e servidas como ativos estáticos; o Worker serve a API, o servidor MCP e as rotas de agente, lendo o JSON exportado através de sua vinculação de ativos. Mesclar para main implanta produção através do Cloudflare Workers Builds. De visualizer/:
bun run deploy:betaconstrói o checkout e o implanta em beta.nonobench.com, um Worker separado que enviaX-Robots-Tag: noindex.bun run deploy:verify <sha>espera até que o Worker ativo execute uma construção contendo esse commit: produção para commits emmain, beta para commits de branch.
Acesso de Agentes
nonobench.com expõe os dados de benchmark a agentes, sem autenticação:
-
API REST sob
/api/v1(ranking, modelos, quebra-cabeças, um verificador de soluções, execuções individuais). A especificação está em/api/openapi.json, e/.well-known/api-catalog(RFC 9727) aponta para ela. -
Servidor MCP em
/mcp(Streamable HTTP sem estado, MCP 2026-07-28 com compatibilidade de cliente 2025), descrito por/.well-known/mcp/server-card.json. Adicione-o a um cliente comclaude mcp add --transport http nonobench https://www.nonobench.com/mcp. Requisições de navegador podem usar as origens do site ou origens HTTP localhost/127.0.0.1. Está listado no Claude Connectors Directory, no MCP Registry (io.github.mauricekleine/nonobench), Smithery, Glama e mcpservers.org. -
WebMCP ferramentas registradas no navegador via
navigator.modelContext. -
Markdown:
/e/puzzlesretornam markdown quando solicitados comAccept: text/markdown./llms.txtdá uma visão geral. -
Descoberta:
robots.txt(com Content Signals),sitemap.xml,Linkcabeçalhos na página inicial, uma habilidade de agente em/.well-known/agent-skills/index.json, e um manifesto ARD em/.well-known/ai-catalog.json.
Tudo isso é lido dos mesmos arquivos exportados que o painel (visualizer/app/results.json e visualizer/public/results-raw.json), então bun run export também o atualiza.
Avaliação
Cada modelo recebe o mesmo prompt de sistema e as pistas de linha e coluna do quebra-cabeça. Respostas padrão são a grade como uma única string de 1s e 0s. Respostas em modo difícil são uma linha por linha, porque em 400 células a maioria dos modelos conta errado uma única string (veja LEARNINGS.md). Uma resposta está correta quando satisfaz cada pista de linha e coluna.
Dez dos 30 quebra-cabeças (um 5x5, quatro 10x10, cinco 15x15) têm mais de uma solução válida, então as respostas são verificadas contra as pistas em vez de comparadas com a solução armazenada. A correção é derivada das saídas brutas armazenadas no momento da exportação; o banco de dados nunca é reescrito. A suíte de testes de quebra-cabeças fixa quais quebra-cabeças são ambíguos, e qualquer novo quebra-cabeça deve ter uma solução única.
Dados de Quebra-Cabeças
O nível principal tem 30 quebra-cabeças (10 de cada 5x5, 10x10 e 15x15), definidos em visualizer/components/puzzles/ e compartilhados pelo executor e pelo painel. Eles foram originados de nono-dataset. O modo difícil tem 10 quebra-cabeças 20x20 gerados. O ID de um quebra-cabeça é um hash de sua solução, então mudar a solução de um quebra-cabeça cria um novo quebra-cabeça.
Níveis e geração
Execuções de benchmark padrão cobrem os três tamanhos principais (Padrão). Use --sizes 20x20 com uma seleção de modelo para executar o modo Difícil; tamanhos separados por vírgula também funcionam. O plano do executor relata trabalho 20x20 ausente separadamente. A precisão geral principal e a seleção de melhor variante usam apenas execuções Padrão; o modo Difícil tem seus próprios resultados. Requisições em modo Difícil recebem um orçamento de resposta de 128.000 tokens, limitado ao máximo do endpoint (bench/max-output-tokens.json).
A partir de bench/, bun run generate-puzzles recria o conjunto 20x20 com uma semente fixa. Ele preenche grades aleatoriamente (sem imagens, para que um modelo não possa adivinhar a figura), mantém grades com pelo menos três blocos por linha e pouca simetria de espelhamento, e verifica a unicidade com um solucionador exato (NONOGRAM_SOLVER). O conjunto mistura cinco quebra-cabeças que a propagação linha-coluna resolve com cinco onde ela trava com 20–200 células restantes. bun test verifica suas dicas, flags de unicidade e solvabilidade por linha; a lista original de ambiguidades permanece fixada.
Configuração
Edite bench/constants.ts para configurar:
MODELS- Matriz de configurações de modelo (ID do modelo OpenRouter, nome de exibição, configurações de raciocínio)MAX_PARALLEL_RUNS_PER_MODEL- Execuções de quebra-cabeça simultâneas por modelo (padrão: 10)REQUEST_TIMEOUT_MS- Tempo limite por solicitação; uma solicitação com tempo esgotado é armazenada como uma execução falha (padrão: 30 minutos)
NONOBENCH_DB, NONOBENCH_RESULTS_JSON e NONOBENCH_RESULTS_RAW_JSON substituem os caminhos do banco de dados e de exportação, o que é útil para testar contra uma cópia.
Pilha de Tecnologias
Executor de Benchmark
- Bun - Runtime JavaScript e SQLite
- AI SDK - Interface unificada de LLM
- OpenRouter - Gateway de API de LLM
- TypeScript
Visualizador
- TanStack Start - Framework React, páginas pré-renderizadas
- Cloudflare Workers - Hospedagem, com ativos estáticos
- React 19 - Biblioteca de UI
- Tailwind CSS 4 - Estilização
- shadcn/ui - Biblioteca de componentes
- Recharts - Gráficos
- Zustand - Gerenciamento de estado
Contribuindo
Contribuições são bem-vindas! Sinta-se à vontade para:
- Adicionar suporte a novos modelos de LLM
- Melhorar a metodologia do benchmark
- Aprimorar o painel de visualização
Licença
MIT