LIMEN-AI (Łukasiewicz Interpretable Markov Engine for Neuralized AI)
LIMEN-AI is a neurosymbolic library for building transparent, auditable AI applications. It combines Large Language Models (LLMs) with Łukasiewicz fuzzy logic and Energy-Based Models (EBM) to create systems that:
- Extract structured knowledge from unstructured text
- Perform probabilistic logical reasoning with fuzzy truth degrees
- Learn new rules inductively from examples
- Generate natural language explanations traceable to logical inference
- Support EU AI Act compliance requirements (Articles 13, 14, 15)
- Compatible with Ollama, OpenAI, Gemini, Claude, and DeepSeek
Core Use Case: Transform legal documents, policies, or domain texts into queryable knowledge bases with built-in explainability.
📦 Installation
pip install limen-ai
# Recommended for LLM features:
pip install requests python-dotenv
🚀 Quick Start (5 Lines)
from limen import LimenClient
# Initialize with local Ollama
client = LimenClient(model_name="ollama/gpt-oss:20b")
# Extract and query
proposal = client.extract("TechCorp is provider. Client is GlobalRetail.")
client.add_knowledge(proposal)
answer = client.ask("Who is provider?")
print(answer.natural_language) # "TechCorp is provider."
🛠️ Step-by-Step Guide: Build Your First Application
1. Set Up Environment Variables
Create a .env file in your project directory:
# Choose ONE provider (uncomment relevant section)
# Option A: Local Ollama (Free, good for development)
OLLAMA_BASE_URL=http://localhost:11434/v1
# Option B: OpenAI (Production - best quality)
OPENAI_API_KEY=sk-your-openai-key-here
# Option C: Anthropic Claude (Production - best reasoning)
ANTHROPIC_API_KEY=your-anthropic-key-here
# Option D: Google Gemini (Production - good for long docs)
GEMINI_API_KEY=your-gemini-key-here
# Option E: DeepSeek (Budget-friendly)
DEEPSEEK_API_KEY=your-deepseek-key-here
2. Install and Configure Ollama (Local LLM)
For development without API costs, use Ollama:
# 1. Install Ollama
curl -fsSL https://ollama.com/install.sh | sh
# 2. Pull recommended model (fits in 16GB VRAM)
ollama pull gpt-oss:20b
# 3. Start Ollama server
ollama run gpt-oss:20b
Recommended Ollama Models:
gpt-oss:20b- Best reasoning, JSON output (14-16GB VRAM)qwen2.5:32b- Best for reasoning (16GB VRAM)qwen2.5:14b- Good balance (8GB VRAM)
3. Initialize LIMEN-AI Client
import os
from pathlib import Path
from dotenv import load_dotenv
from limen import LimenClient
load_dotenv()
# Initialize client (choose your provider)
client = LimenClient(
model_name="ollama/gpt-oss:20b", # Local Ollama
# model_name="openai/gpt-4o-mini", # OpenAI
# model_name="claude/claude-3-5-sonnet-20241022", # Anthropic
# model_name="gemini/gemini-1.5-pro", # Google
# model_name="deepseek/deepseek-chat", # DeepSeek
base_url=os.getenv("OLLAMA_BASE_URL"), # For Ollama only
enable_auto_induction=True, # Enable rule learning
use_neurosymbolic_ilp=True # Use LLM-guided ILP
)
4. Extract Knowledge from Document
# Load your document
contract_path = Path("your_contract.txt")
contract_text = contract_path.read_text(encoding="utf-8")
# Extract structured knowledge
proposal = client.extract(contract_text)
# Review what was extracted
print(proposal.to_markdown())
Expected Output:
## 1. Schema Extensions (New Predicates)
- **legalParty**(entity, role): Links entity to its legal role
- **effectiveDate**(date): Specifies effective date of agreement
- **paymentAmount**(amount, currency): Payment details
## 2. Fact Grounding (Extracted from Context)
| Predicate | Arguments | Confidence | Source |
| :--- | :--- | :--- | :--- |
| legalParty | TechCorp, Provider | 0.99 | Sentence 1 |
| legalParty | GlobalRetail, Client | 0.99 | Sentence 2 |
5. Commit Knowledge to Knowledge Base
# After human verification of proposal, commit to KB
result = client.add_knowledge(proposal)
print(f"Added {len(result.facts_added)} facts to KB")
6. Query Your Knowledge Base
# Natural language query
answer = client.ask("Who is the service provider?")
# Get results
print(f"Answer: {answer.natural_language}")
# Access structured inference results
for result in answer.answers:
predicate = result['predicate']
args = result['args']
truth_degree = result['value'] # Fuzzy truth [0, 1]
print(f"{predicate}({args}) = {truth_degree:.4f}")
# View logical trace (reasoning steps)
for step in answer.logical_trace:
print(step)
7. Save and Restore Knowledge Base
# Save complete state (schema, facts, formulas, rules)
client.save_state("my_knowledge_base.json")
# Later, restore without re-extracting
client2 = LimenClient(model_name="ollama/gpt-oss:20b")
client2.load_state("my_knowledge_base.json")
# Now query
answer = client2.ask("What is the monthly fee?")
🔧 Advanced Usage
Direct Predicate Queries (For Local Models)
If using Ollama where natural language queries sometimes fail, query the KB directly:
# After extraction and add_knowledge()
# Method 1: Iterate over all high-confidence facts
for atom, confidence in client.pipeline.assignment.values.items():
if confidence > 0.8 and atom.predicate.name == "legalParty":
entity = atom.arguments[0].name
role = atom.arguments[1].name
print(f"{entity} is {role} (confidence: {confidence:.2f})")
# Method 2: Query specific predicate
from limen.core import Atom
pred = client.pipeline.kb.get_predicate("legalParty")
provider = client.pipeline.kb.get_constant("TechCorp")
client_role = client.pipeline.kb.get_constant("Provider")
atom = Atom(pred, (provider, client_role))
truth_degree = client.pipeline.assignment.get(atom)
print(f"TechCorp is Provider: {truth_degree:.2f}")
Benefits:
- ✅ Deterministic results (no LLM query translation)
- ✅ Lower latency (no additional LLM calls)
- ✅ Reliable (works with any model quality)
Manual Fact Addition (Fill LLM Gaps)
# If LLM missed critical facts, add them manually
client.set_fact("terminationNotice", ["30 days"], 1.0)
client.set_fact("governingLaw", ["California"], 1.0)
client.set_fact("monthlyFee", [15000, "USD"], 1.0)
Inductive Rule Learning
# Provide labeled examples to teach the system rules
labels = {
"legalParty": {
"pos": [("TechCorp", "Provider"), ("GlobalRetail", "Client")],
"neg": [("TechCorp", "Client"), ("GlobalRetail", "Provider")]
}
}
# Trigger inductive learning
client.feedback(labels)
# Check learned rules
if client.pipeline.kb.induced_clauses:
print("Learned rules:")
for clause in client.pipeline.kb.induced_clauses:
print(f" IF {', '.join(clause.body)} THEN {clause.head} (weight: {clause.weight:.2f})")
Human Oversight (Veto Power)
# Override incorrect LLM extraction (Article 14(4) compliance)
client.veto("incorrectPredicate", ["arg1", "arg2"])
# This sets truth degree to 0.0 and adds a high-weight NOT formula
# Future inference will respect this override
🤖 LLM Provider Configuration
Recommended Models by Use Case
| Provider | Model | Extraction | Query Translation | Best For | Cost |
|---|---|---|---|---|---|
| Ollama | gpt-oss:20b |
⭐⭐⭐⭐ | ⭐⭐ | Development | Free |
| Ollama | qwen2.5:32b |
⭐⭐⭐⭐⭐ | ⭐⭐⭐ | Best local | Free |
| OpenAI | gpt-4o-mini |
⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | Production | $$$ |
| OpenAI | gpt-4o |
⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐⭐ | Production | $$$$ |
| Anthropic | claude-3.5-sonnet |
⭐⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐⭐ | Complex | $$$ |
gemini-1.5-pro |
⭐⭐⭐⭐ | ⭐⭐⭐ | Long docs | $$ | |
| DeepSeek | deepseek-chat |
⭐⭐⭐ | ⭐⭐⭐ | Budget | $ |
Key Observations:
- Ollama: Good for development, but query translation varies between runs
- GPT-4/Claude: Recommended for production - high quality extraction and querying
- Workaround for Ollama: Use direct predicate queries instead of natural language
Ollama Configuration
client = LimenClient(
model_name="ollama/gpt-oss:20b",
base_url=os.getenv("OLLAMA_BASE_URL", "http://localhost:11434/v1")
)
Installation:
ollama pull gpt-oss:20b # 14-16GB VRAM
ollama run gpt-oss:20b
OpenAI Configuration
client = LimenClient(
model_name="openai/gpt-4o-mini",
api_key=os.getenv("OPENAI_API_KEY")
)
Anthropic Claude Configuration
client = LimenClient(
model_name="claude/claude-3-5-sonnet-20241022",
api_key=os.getenv("ANTHROPIC_API_KEY")
)
Google Gemini Configuration
client = LimenClient(
model_name="gemini/gemini-1.5-pro",
api_key=os.getenv("GEMINI_API_KEY")
)
DeepSeek Configuration
client = LimenClient(
model_name="deepseek/deepseek-chat",
api_key=os.getenv("DEEPSEEK_API_KEY")
)
📊 Understanding Results
LIMEN-AI returns a StructuredAnswer with multiple components:
answer = client.ask("Who is the provider?")
# Natural language response (LLM-generated)
print(answer.natural_language) # "TechCorp is the provider."
# Structured inference results (from sampling)
for result in answer.answers:
predicate = result['predicate']
args = result['args']
truth_degree = result['value'] # Fuzzy truth [0, 1]
print(f"{predicate}({args}) = {truth_degree:.4f}")
# Logical trace (reasoning steps)
for step in answer.logical_trace:
print(step)
Key Insight: LIMEN-AI performs probabilistic inference using importance sampling. Truth degrees represent expected value under induced distribution, not simple lookup values.
📈 Domain-Specific Usage Patterns
Legal Domain (Contracts, Regulations)
# Extract legal entities, obligations, terms
client.extract(contract_text)
# Query for compliance, obligations, parties
answer = client.ask("What are the termination conditions?")
answer = client.ask("Who is liable for breach?")
answer = client.ask("What is the governing law?")
Cybersecurity Domain (Incidents, Controls)
# Extract security concepts, threats, controls
client.extract(security_policy_text)
# Query for incident response, controls, risks
answer = client.ask("What is the incident response time?")
answer = client.ask("What encryption is required?")
answer = client.ask("Which controls mitigate this threat?")
Financial Domain (Risk, Compliance)
# Extract risk factors, controls, metrics
client.extract(risk_framework_text)
# Query for compliance status, risk ratings, controls
answer = client.ask("What is the overall risk rating?")
answer = client.ask("Which controls are in place for AML?")
answer = client.ask("Is PCI-DSS compliance met?")
Key: LIMEN-AI works across any domain. Just provide domain-specific text and ask questions in that domain.
❓ Troubleshooting & FAQ
Q: I get a ConnectionError when using Ollama.
A: Ensure Ollama is running: ollama run <model>. Check base_url is correct (usually http://localhost:11434/v1).
Q: Queries return "The fact is not supported" even though I see data in extraction. A: This is a query translation issue. The LLM failed to map your natural language question to the correct predicates.
- Solution 1: Use a better model (GPT-4, Claude) - recommended for production
- Solution 2: Query predicates directly instead of natural language (see "Direct Predicate Queries" section)
Q: The extraction is missing some facts. A: Small local models have extraction limitations.
- Solution 1: Use GPT-4, Claude, or Gemini for complete extraction
- Solution 2: Manually add missing facts with
client.set_fact("predicate", ["arg1", "arg2"], 1.0)
Q: How do I save my Knowledge Base?
A: Use client.save_state("my_kb.json") to save complete pipeline state:
- Schema (predicates with descriptions)
- Facts (ground truth assignments)
- Formulas (weighted rules)
- Induced clauses (learned rules)
Later, restore with client.load_state("my_kb.json").
Q: What's the difference between save_state() and save_knowledge_base()?
A: save_state() (JSON) saves everything including facts and learned rules.
save_knowledge_base() (SQLite) only saves KB structure (predicates/formulas) without facts.
Recommendation: Always use save_state() for complete persistence.
🧪 Scientific Validation
LIMEN-AI is built on rigorous mathematical foundations:
Łukasiewicz Logic
- T-norm:
min(a ⊕ b, 1 - a ⊖ b) - Implication:
a → b = 1 - a + b - Conjunction:
a ⊙ b = min(a, b)
Energy-Based Models
- Probability distribution:
P(X) = (1/Z) * exp(E(X)) - Inference via sampling (Importance Sampling, Langevin MCMC)
- Learning via gradient-based optimization
Neurosymbolic Integration
- LLM extracts schema and facts from natural language
- Probabilistic logic engine performs reasoning
- Inductive Logic Programming learns rules from examples
No Experimental Data: All examples in documentation use either:
- Hand-calculable pedagogical examples (clearly labeled as such)
- Real document processing (showing extraction and inference on actual texts)
📝 Changelog
0.3.5
- LLM client robustness:
OpenAIClientnow enforces a configurable per-request timeout (timeout=argument or theLIMEN_LLM_TIMEOUTenvironment variable, default 180 s). A single stuck generation can no longer block a batch indefinitely, which previously caused long extraction/evaluation runs to hang.
0.3.4
- Negation-aware fact extraction and deterministic fact verification in the ingestion pipeline; human-readable rule rendering.
📄 License
LIMEN-AI is licensed under the AGPL-3.0. See LICENSE file for details.
🤝 Contributing
We welcome contributions! Please see our GitHub repository.
Built with 🤖 for building trustworthy AI.
Metadata
Release files for limen-ai 0.3.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| limen_ai-0.3.5.tar.gz | 80.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| limen_ai-0.3.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 166.7 kB
Release files / limen_ai-0.3.5.tar.gz
| Download URL | limen_ai-0.3.5.tar.gz |
|---|---|
| Size | 80.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c35bb5956de0a53f866b42a0464ade28e8db22dc8c5ba11d2c3a74807262fa96
|
|
BLAKE2b-256 checksum How to use checksums |
1ad17e1d75dbc37b58204c63fc67550f96d873bd5dfd0c5112861b0fd0951533
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / limen_ai-0.3.5-py3-none-any.whl
| Download URL | limen_ai-0.3.5-py3-none-any.whl |
|---|---|
| Size | 86.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1d6cc4d7adc692177cddb67ca6de210c56c9138bda94c2226424eb47fae90bd2
|
|
BLAKE2b-256 checksum How to use checksums |
c4653e647facb3b9f3af2d1359a87b0531c82be9ef7192ec76926cf2031cbe1e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Security for limen-ai 0.3.5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.