prolog-reasoner
Execução SWI-Prolog para LLMs com CLP(FD) e recursão — aumenta a precisão lógica/de restrições de 73% para 90% em um benchmark de 30 problemas.
Documentação
prolog-reasoner
SWI-Prolog como uma "calculadora lógica" para LLMs — disponível como servidor MCP e biblioteca Python. Elimine a caixa-preta do raciocínio lógico de LLMs.
LLMs são excelentes em linguagem natural, mas têm dificuldade com lógica formal. Prolog é excelente em raciocínio lógico, mas não processa linguagem natural. prolog-reasoner preenche essa lacuna expondo a execução de SWI-Prolog para LLMs.
Isso ajuda?
No benchmark de lógica integrado com 30 problemas:
| Pipeline | Precisão |
|---|---|
Somente LLM (claude-sonnet-4-6) | 22/30 (73,3%) |
| LLM + prolog-reasoner | 27/30 (90,0%) |
A lacuna se concentra em satisfação de restrições e raciocínio de múltiplas etapas — o território combinatório em que LLMs são fracos e Prolog é forte. Detalhamento completo abaixo.
Por que funciona
LLMs fazem correspondência de padrões; Prolog realmente busca e resolve. Quando o LLM escreve seu problema em Prolog, duas coisas acontecem ao mesmo tempo:
- Prolog lida com o trabalho combinatório em que LLMs são fracos — satisfação de restrições, inferência de múltiplas etapas, busca exaustiva.
- O raciocínio existe como código que você pode ler, reexecutar e depurar. Quando algo dá errado, você vê exatamente o Prolog que falhou e por quê.
Duas formas de usar
- Servidor MCP — Claude (ou qualquer cliente MCP) o chama como solucionador lógico durante a conversa. Bases de regras permitem que o LLM salve regras de domínio estáveis uma vez e as referencie por nome a cada chamada.
- Biblioteca Python — pipeline completo de NL→Prolog com autocorreção. Requer OpenAI ou Anthropic.
Recursos
- Ferramentas MCP:
execute_prologpara execução arbitrária de SWI-Prolog, além delist_rule_bases/get_rule_base/save_rule_base/delete_rule_basepara bases de regras nomeadas reutilizáveis (v14) - Bases de regras: salve regras Prolog estáveis uma vez (ex.: regras de movimento de xadrez, axiomas legais) e referencie-as por nome a partir de
execute_prologpara que o LLM escreva apenas os fatos específicos da situação a cada chamada - Representação intermediária transparente: o código Prolog é a trilha de auditoria — inspecione, modifique ou verifique antes da execução
- Suporte a CLP(FD): programação com restrições para agendamento e otimização
- Negação por falha, recursão, todos os recursos padrão do SWI-Prolog
- Modo biblioteca: tradução NL→Prolog com loop de autocorreção (OpenAI / Anthropic)
Requisitos
- Python ≥ 3.10
- SWI-Prolog instalado e no PATH (≥ 9.0)
- Chave de API para OpenAI ou Anthropic — apenas para o modo biblioteca, não para o servidor MCP
Instalação
# MCP server only (no LLM dependencies)
pip install prolog-reasoner
# Library with OpenAI
pip install prolog-reasoner[openai]
# Library with Anthropic
pip install prolog-reasoner[anthropic]
# Both providers
pip install prolog-reasoner[all]
Configuração do Servidor MCP
O servidor MCP expõe cinco ferramentas — execute_prolog executa código Prolog escrito pelo LLM conectado, e quatro ferramentas de base de regras gerenciam módulos Prolog nomeados e reutilizáveis. Ele não chama nenhuma API externa de LLM, portanto nenhuma chave de API é necessária.
Claude Desktop / Claude Code
{
"mcpServers": {
"prolog-reasoner": {
"command": "uvx",
"args": ["prolog-reasoner"]
}
}
}
Ou, se prolog-reasoner estiver instalado diretamente:
{
"mcpServers": {
"prolog-reasoner": {
"command": "prolog-reasoner"
}
}
}
Docker (SWI-Prolog incluído)
Use Docker se você não quiser instalar SWI-Prolog localmente:
docker build -f docker/Dockerfile -t prolog-reasoner .
{
"mcpServers": {
"prolog-reasoner": {
"command": "docker",
"args": ["run", "-i", "--rm", "prolog-reasoner"]
}
}
}
Referência de ferramentas
execute_prolog(prolog_code, query, rule_bases=None, max_results=100, trace=False)
prolog_code— fatos e regras Prolog (string)query— consulta Prolog a executar, ex.:"mortal(X)"(string)rule_bases— lista opcional de nomes de bases de regras salvas para antepor aprolog_code(em ordem). Use para reutilizar regras de domínio estáveis entre chamadas sem reenviá-lasmax_results— limita o número de soluções retornadas (padrão 100)trace— quandoTrue, anexa uma árvore de prova estruturada por solução ametadata.proof_trace. Sub-recurso opcional; tem custo de desempenho e não suporta CLP(FD), predicados de ordem superior ou assert/retract.
Retorna um objeto JSON com success, output, query, error e metadata.
Em caso de sucesso, metadata inclui execution_time_ms, result_count, truncated e rule_bases_used. Quando bases de regras foram solicitadas, rule_base_load_ms também é anexado (tempo de I/O de disco). Em caso de falha, metadata também inclui error_category (um de syntax_error, undefined_predicate, unbound_variable, type_error, domain_error, evaluation_error, permission_error, timeout, trace_mechanism_error, unknown) e error_explanation — uma dica em linguagem natural para o LLM conectado (ou humano) decidir como corrigir o código Prolog.
Ferramentas de base de regras — gerenciam módulos Prolog nomeados e reutilizáveis em PROLOG_REASONER_RULES_DIR (padrão: ~/.prolog-reasoner/rules/). Os nomes são restritos a [a-z0-9_-], com 1–64 caracteres.
save_rule_base(name, content)— grava ou sobrescreve uma base de regras. O conteúdo é validado sintaticamente (somente análise) antes da gravação; falhas aparecem comoRULEBASE_003. Retorna{"success": true, "name": ..., "created": bool}, ondecreatedétruena primeira gravação efalseem sobrescrita. Arquivos acima demax_rule_sizesão rejeitados comRULEBASE_005.list_rule_bases()— retorna todas as bases de regras salvas comname,descriptionetags. Os metadados são extraídos dos comentários iniciais% description:/% tags:de cada arquivo.get_rule_base(name)— retorna o código-fonte Prolog bruto de uma base de regras salva.delete_rule_base(name)— remove uma base de regras salva.
Para erros de nome/tamanho/inexistência, as ferramentas retornam {"success": false, "error": "...", "error_code": "RULEBASE_001"|"RULEBASE_002"|"RULEBASE_003"|"RULEBASE_005"} em vez de lançar exceções. Falhas de I/O (RULEBASE_004) são propagadas como erros de infraestrutura.
Convenções de base de regras — inicie cada arquivo de base de regras com comentários iniciais que funcionam como metadados de list_rule_bases:
% description: Chess piece movement rules
% tags: chess, games
piece_move(knight, (X1,Y1), (X2,Y2)) :- ...
Depois referencie a partir de execute_prolog:
{
"rule_bases": ["chess_moves"],
"prolog_code": "position(knight, (4,4)).",
"query": "piece_move(knight, (4,4), Target)"
}
As bases de regras também servem como base para forks especializados por domínio: envie um conjunto curado (axiomas legais, regras de jogos, cenários fiscais, etc.) empacotado via BUNDLED_RULES_DIR como um pacote de raciocínio pronto para uso.
Uso da Biblioteca
A biblioteca expõe PrologExecutor (somente Prolog, sem LLM) e PrologReasoner (pipeline NL→Prolog, precisa de chave de API de LLM).
Executar Prolog diretamente (sem LLM)
import asyncio
from prolog_reasoner.config import Settings
from prolog_reasoner.executor import PrologExecutor
async def main():
settings = Settings() # no API key needed
executor = PrologExecutor(settings)
result = await executor.execute(
prolog_code="human(socrates). mortal(X) :- human(X).",
query="mortal(X)",
)
print(result.output) # mortal(socrates)
asyncio.run(main())
Pipeline completo NL→Prolog (requer chave de API de LLM)
import asyncio
from prolog_reasoner import PrologReasoner, TranslationRequest, ExecutionRequest
from prolog_reasoner.config import Settings
from prolog_reasoner.executor import PrologExecutor
from prolog_reasoner.translator import PrologTranslator
from prolog_reasoner.llm_client import LLMClient
async def main():
settings = Settings(llm_api_key="sk-...") # from env or explicit
llm = LLMClient(
provider=settings.llm_provider,
api_key=settings.llm_api_key,
model=settings.llm_model,
timeout_seconds=settings.llm_timeout_seconds,
)
reasoner = PrologReasoner(
translator=PrologTranslator(llm, settings),
executor=PrologExecutor(settings),
)
translation = await reasoner.translate(
TranslationRequest(query="Socrates is human. All humans are mortal. Is Socrates mortal?")
)
print(translation.prolog_code)
result = await reasoner.execute(
ExecutionRequest(prolog_code=translation.prolog_code, query=translation.suggested_query)
)
print(result.output)
asyncio.run(main())
Configuração
Todas as configurações via variáveis de ambiente (prefixo PROLOG_REASONER_):
| Variável | Padrão | Necessário para |
|---|---|---|
LLM_PROVIDER | openai | biblioteca (openai ou anthropic) |
LLM_API_KEY | "" | somente biblioteca — deixe sem definir para MCP |
LLM_MODEL | gpt-5.4-mini | biblioteca |
LLM_TEMPERATURE | 0.0 | biblioteca |
LLM_TIMEOUT_SECONDS | 30.0 | biblioteca |
SWIPL_PATH | swipl | ambos |
EXECUTION_TIMEOUT_SECONDS | 10.0 | ambos |
RULES_DIR | ~/.prolog-reasoner/rules | ambos (onde ficam as bases de regras salvas pelo usuário) |
BUNDLED_RULES_DIR | não definido | ambos (opcional — sincronizado em RULES_DIR na primeira inicialização para enviar regras padrão com um fork) |
MAX_RULE_SIZE | 1048576 (1 MiB) | ambos (limite de gravação por arquivo; save_rule_base rejeita conteúdo maior com RULEBASE_005) |
MAX_RULE_PROMPT_BYTES | 65536 (64 KiB) | somente biblioteca (orçamento total para a seção de prompt "Bases de regras disponíveis"; truncado com um marcador quando excedido) |
LOG_LEVEL | INFO | ambos |
Benchmark
benchmarks/ contém 30 problemas de lógica em 5 categorias (dedução, transitivo, restrição, contradição, múltiplas etapas) para comparar o raciocínio somente-LLM com o raciocínio LLM+Prolog. O benchmark exercita o caminho da biblioteca (tradutor + executor), pois requer a etapa NL→Prolog.
Resultados
Medido em anthropic/claude-sonnet-4-6, execução única sobre 30 problemas:
| Pipeline | Precisão | Latência média |
|---|---|---|
| Somente LLM | 22/30 (73,3%) | 1,7s |
| LLM + Prolog | 27/30 (90,0%) | 3,8s |
Detalhamento por categoria:
| Categoria | Somente LLM | LLM + Prolog |
|---|---|---|
| dedução | 6/6 | 6/6 |
| transitivo | 6/6 | 5/6 |
| restrição | 3/7 | 6/7 |
| contradição | 4/4 | 3/4 |
| múltiplas etapas | 3/7 | 7/7 |
A lacuna se concentra em restrição (SEND+MORE, 6 rainhas, mochila, coloração K4, Einstein-lite) e múltiplas etapas (teoria de jogos Nim, cavaleiros-e-mentirosos com 3 pessoas, TSP-4, quebra-cabeça do zebra) — exatamente o território combinatório/pesado em busca onde solucionadores simbólicos superam a conclusão de padrões. Em questões puramente dedutivas ou transitivas, o LLM já é forte e Prolog adiciona latência sem ganhos de precisão.
Todas as 3 falhas de LLM+Prolog foram erros de execução Prolog provenientes de código malformado gerado por LLM (definições de predicados ausentes, variáveis CLP(FD) não vinculadas) em vez de erros de raciocínio — resolvíveis via ajuste de prompt. Notavelmente, toda falha é inspecionável: você pode ver exatamente o Prolog que falhou e por quê, em vez de uma resposta errada em linguagem natural sem explicação.
Executando você mesmo
docker run --rm -e PROLOG_REASONER_LLM_API_KEY=sk-... \
prolog-reasoner-dev python benchmarks/run_benchmark.py
Os resultados são salvos em benchmarks/results.json.
Comparação com outros MCPs de Prolog
Vários servidores MCP de Prolog existem, cada um com escolhas de design diferentes. prolog-reasoner é intencionalmente sem estado e de uso pontual — Prolog é uma calculadora que você chama quando a lógica importa, não a espinha dorsal da memória do seu agente.
| prolog-reasoner | MCPs de Prolog com estado | |
|---|---|---|
| Papel do Prolog | Ferramenta de raciocínio por chamada | Base de conhecimento em todo o projeto |
| Estado | Execução sem estado (cada chamada independente); bases de regras nomeadas opcionais para regras estáticas reutilizáveis, sem memória de sessão entre chamadas | Sessões persistentes / KBs em camadas |
| Reprodutibilidade | Mesma entrada (incl. mesmas bases de regras) → mesma saída, sempre | Depende do estado acumulado |
| Esforço de integração | Use onde a lógica importa, pule onde não importa | Compromisso arquitetural |
| Testável A/B vs somente-LLM | Sim (cada chamada é um experimento controlado) | Estruturalmente não comparável |
É também por isso que benchmarks de precisão são publicados aqui e não em outros lugares: a ausência de estado é o que torna possível uma comparação lado a lado.
Se você precisa de memória persistente de agente, armazenamento de fatos protegido contra alucinações ou um substrato neuro-simbólico completo, outros projetos podem se adequar melhor:
- adamrybinski/prolog-mcp — Trealla WASM com sessões de salvar/carregar
- umuro/prolog-mcp — KB em camadas com persistência em arquivo
- vpursuit/model-context-lab — SWI-Prolog com sandbox de segurança
- dr3d/prolog-reasoning — memória neuro-simbólica com segurança no caminho de gravação
Somos a opção de uso pontual.
Desenvolvimento
# Build dev image
docker build -f docker/Dockerfile -t prolog-reasoner-dev .
# Run tests (no API key needed — LLM calls are mocked)
docker run --rm prolog-reasoner-dev
# With coverage
docker run --rm prolog-reasoner-dev pytest tests/ -v --cov=prolog_reasoner
# Or via docker compose
docker compose -f docker/docker-compose.yml run --rm test
Licença
MIT