Skip to main content

ThinkLess

Stop using an LLM for every decision.

PyPI CI License: Apache 2.0 Python 3.10+ Benchmarks

ThinkLess is an open-source decision plane for AI agents. The routine judgments an agent makes (what the user wants, whether they asked for a person, which order they mean, whether a message is trying to manipulate the system) are answered by rules and small calibrated models in milliseconds. The LLM is kept for the steps that need it: writing, planning, and the decisions the small models are not sure about. Every step is traced with the plane that handled it, its confidence, latency, tokens and cost.

It is model-neutral. Rules, GLiNER 2.5, Laya, TypeSafe's Jev (and any server speaking its System One API, such as Kev and OpenJev), any Hugging Face classifier, and any LLM (local through Transformers, Ollama or vLLM, or hosted through OpenRouter, Anthropic or OpenAI) plug into the same cascade. The whole stack also runs offline on a laptop GPU, with no API key.

The ThinkLess trace viewer comparing three decision planes on the support benchmark, with one ticket's waterfall: six decisions answered by rules, GLiNER and Laya in 126 ms, then a single LLM call for the reply

Why

A typical agent sends every branch of its workflow to one generative model: classify the request, extract the arguments, pick the tool, check the result, check the reply, then write the reply. Most of those are bounded questions with a handful of possible answers. A generative model answers them slowly, at full token cost, and without telling you how sure it is.

ThinkLess treats each of them as a typed question. It asks the cheapest provider first and escalates only when the answer's confidence is below a threshold you set per question and per provider, from data. Your code reads a typed decision and never needs to know which model produced it.

intent = engine.decide(ticket, INTENT)          # rules, then GLiNER, then Laya, then the LLM
if intent.is_("refund_duplicate_charge"):       # only true when the answer is confident
    ...

Results

Same agent, same 53 labeled support tickets, two decision planes: llm sends every decision to the LLM, hybrid asks rules, GLiNER and Laya first. Hosted models ran through OpenRouter, and the dollar figures are what OpenRouter billed (full results):

Fallback LLM Success, llm Success, hybrid Billed per 1k tickets, llm Billed per 1k tickets, hybrid Decision time
Qwen 3.7 Flash 92.5% 98.1% $0.034 $0.019 1.27 s to 0.58 s
Gemini 2.5 Flash Lite 98.1% 98.1% $0.104 $0.059 1.17 s to 0.76 s
GPT-5.6 Luna 98.1% 100% $0.235 $0.141 2.50 s to 1.18 s
Claude Haiku 4.5 98.1% 98.1% $1.338 $0.788 2.21 s to 1.34 s
Qwen3-1.7B, local 86.8% 94.3% free free 1.84 s to 0.43 s
  • Hybrid matched or beat the LLM-only design on every model, at 40 to 44 percent lower billed cost and 35 to 55 percent less time spent on decisions. 87 percent of hybrid decisions never reached the LLM.
  • Small models are the most reliable extractors. Rules and GLiNER found every order number on every run. The larger hosted LLMs did too; Qwen 3.7 Flash and the local 1.7B model missed ones written without the word "order".
  • On Banking77 (77 intents, 500 examples) the cascade matched or beat its LLM at a quarter of the cost. GLiNER alone 71.8 percent; Qwen 3.7 Flash alone 73.8 percent, cascade 74.8 percent; Claude Haiku 4.5 alone 76.2 percent, cascade 76.2 percent. Each time a quarter of the calls reached the LLM.
  • Nothing was tuned on the test tickets. Thresholds and every fix were validated on a separate calibration set first. The baseline is the strongest form of the LLM design: all six triage questions in one prompt.
  • The support set is 53 synthetic tickets: evidence of the mechanism and its failure modes, not a leaderboard. The benchmarks page lists the weak areas found and what was done about each.

Quick start

pip install "thinkless[local]"        # GLiNER, Laya and a local LLM
thinkless doctor                      # check the environment
from thinkless import Choice, Engine, Extract, JSONLSink, Tracer, YesNo
from thinkless.llm import TransformersLLM
from thinkless.providers import GLiNER, Laya, LLMDecider, Rules

rules = Rules()
rules.match("wants_human", r"\b(real person|a human|an agent|operator)\b", True, field="message")
rules.extract("order", field="message", order_id=r"#\s?(\d{4,5})\b")

llm = TransformersLLM("Qwen/Qwen3-1.7B")
engine = Engine(
    [rules, GLiNER(), Laya(), LLMDecider(llm)],     # cheapest first
    llm=llm,
    threshold=0.8,
    tracer=Tracer([JSONLSink(".thinkless/traces")]),
)

with engine.run("ticket") as run:
    decisions = engine.decide_many(
        {"message": "I was charged twice for order #4471. Refund it or I'm cancelling."},
        [
            Choice("What does the customer want?", name="intent",
                   options={"refund": "wants money back", "order_status": "asks where an order is",
                            "cancel": "wants to cancel", "other": "anything else"}),
            YesNo("Is the customer asking for a person?", name="wants_human"),
            Extract(name="order", fields={"order_id": "the order number"}),
        ],
    )

for name, d in decisions.items():
    print(f"{name:12} {d.value!s:24} {d.status.value:9} via {d.provider}")
print(run.summary().decisions_by_plane)      # which plane answered what

Prefer a hosted model? Put OPENROUTER_API_KEY=... in .env and swap one line; OpenRouter reaches Qwen, Gemini, GPT and Claude models with one key:

from thinkless.llm import OpenRouterLLM

llm = OpenRouterLLM("qwen/qwen3.7-flash", reasoning={"enabled": False})

Then open the trace:

thinkless trace view

No GPU? pip install thinkless and run examples/01_rules_only.py: the API, the cascade and the traces with no model downloads.

Try the demo agent

A complete customer support agent ships with the package: a mock store with orders, payments and a help center, 53 labeled tickets, and every hard case we could think of (order numbers written in ways a regex misses, a customer asking about someone else's order, prompt injections, requests for a human, Spanish and German tickets).

thinkless demo --ticket T-016                          # one ticket, printed as a trace tree
thinkless demo --ticket T-051 --mode hybrid --mode llm # compare decision planes
thinkless bench support                                # every ticket in every mode
thinkless bench support --llm openrouter:qwen/qwen3.7-flash --reasoning off
thinkless bench intents --dataset banking77

How it works

Typed questions. Choice, Score, YesNo and Extract declare what you want to know and which answers are allowed. They follow the System One wire format, so the same question works on every provider. Questions

A confidence cascade. Providers are tried cheapest first. Each gets one call with every open question it supports; answers that clear their threshold close, the rest move on. Unresolved questions come back uncertain with the best answer seen, and decision.is_() never matches an uncertain answer. The cascade

One meaning of confidence. Providers disagree about what "confidence" means (Laya and TypeSafe compute it differently), so a threshold of 0.8 would mean different things per backend. ThinkLess derives a single normalized confidence from each provider's probabilities. Confidence

Thresholds from data. thinkless calibrate sweeps thresholds on labeled examples and recommends the lowest one that meets your accuracy target, per question and per provider (thresholds={"intent@gliner": 0.9}). Calibration

Traces for everything. Decisions, provider attempts, generations, tool calls and rule checks are spans with W3C-compatible ids. Write JSONL audit files, export to any OpenTelemetry backend with GenAI semantic conventions, or open the self-contained HTML viewer. Content capture can be switched off without losing structure, timings or confidences. Tracing

Providers and backends

Decision providers Answers Runs
Rules every kind in-process, under 1 ms
GLiNER (GLiNER 2.5) choice, extract local, 16 to 38 ms on a laptop GPU, about 85 ms on CPU
Laya choice, score, yes/no local, about 30 ms per batch on a laptop GPU
SystemOne (Jev, Kev, OpenJev) choice, score, yes/no hosted or self-hosted HTTP
HFClassifier choice, yes/no, for the questions it was trained on any Hugging Face text classifier, local
LLMDecider every kind any LLM backend below
LLM backends Covers
TransformersLLM any Hugging Face chat model, in-process
OpenRouterLLM hundreds of hosted models with one key, billed cost recorded per call
OpenAICompatibleLLM OpenAI, Ollama, vLLM, LM Studio, llama.cpp, Groq
AnthropicLLM Claude, with server-side refusal fallbacks

Writing your own provider is one class. Providers, LLM backends

Documentation

Status

ThinkLess is at 0.1: the core API (questions, the engine, decisions and traces) is meant to stay stable, and providers and benchmarks will grow. Next up are shadow mode, calibration from traces, calibrated LLM confidence from log probabilities, and live Jev runs. See the roadmap.

Contributing

Issues, providers, benchmark runs on other hardware and models, and new demo scenarios are all welcome. Start with CONTRIBUTING.md. The bar for changes that affect accuracy, latency or cost is evidence: a before and after from thinkless bench or thinkless calibrate.

Sponsoring

If ThinkLess saves your team time or money, consider sponsoring its development. Sponsorship funds frontier-model benchmark runs, more providers and more demos.

Citing

See CITATION.cff.

Acknowledgements

ThinkLess builds on the work of the teams behind Jev and the System One API (TypeSafe AI), GLiNER2 (Fastino), Laya (Convai Innovations), Qwen and Banking77 (PolyAI).

ThinkLess is not affiliated with the NeurIPS 2025 paper Thinkless: LLM Learns When to Think, which studies adaptive reasoning inside a single model.

License

Apache License 2.0.

Release files for thinkless 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for thinkless 0.2.0
File Size Uploaded
thinkless-0.2.0.tar.gz 120.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for thinkless 0.2.0
File Interpreter ABI Platform
thinkless-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 249.0 kB

Release files / thinkless-0.2.0.tar.gz

Download URL thinkless-0.2.0.tar.gz
Size 120.5 kB
Tags Source
SHA-256 checksum
How to use checksums
470790666ee7d2346b1a069cced626cf09ffa0193c347f2a9db4fb59e94230ce
BLAKE2b-256 checksum
How to use checksums
e2aecd6d99733541d95033ca105f9b6d0522e584cd7bfaa0b37027dcc2f2c12d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / thinkless-0.2.0-py3-none-any.whl

Download URL thinkless-0.2.0-py3-none-any.whl
Size 128.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cdbdf0fa57b5213ccba247a27838ecce2aa6e67fde001b32bd52d00dd7b911d0
BLAKE2b-256 checksum
How to use checksums
c4b13ae8d1c7a5d9f25de3a92cb951165ccd0a7a22dcb5a8682b468c25e14b61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.0

2 release files

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page