Skip to main content
A minimal guide to running the full remember → recall round trip with no LLM API key anywhere: the GLiNER demo extractor — cognee’s open-source local extraction, a demo of its enterprise GLiNER extraction — builds the graph and writes the chunk summaries, and fastembed embeds them on CPU. Use it when you have no key to spend, when the data cannot leave the machine, or when you want a smoke test that proves the pipeline itself does not depend on an LLM.

Before You Start

  • Complete Quickstart to understand basic operations
  • Recommended (not required): install the GLiNER extra, which provides the local extractor’s runtime up front:
    Without it, the first keyless cognify() installs that runtime itself — CPU-only PyTorch plus gliner2, about 200 MB to download and 800 MB on disk — before the pipeline starts. See Installing the runtime
  • Nothing to install for the embedder: fastembed is a core cognee dependency
  • Allow for the first-run downloads: the GLiNER model is about 750 MB and the bge-small-en-v1.5 embedding model about 67 MB, both cached after the first run — cognee logs a WARNING naming the model, its size and the cache directory on a first-use download, and an INFO line on a cached load. See Keyless local defaults for where each cache lives and how to move it
  • No LLM API key is needed, and none is used — the script removes LLM_API_KEY and OPENAI_API_KEY from the environment before importing cognee
  • Start from an unconfigured provider setup: cognee only reaches for the local pair when nothing else is set, so check that no GRAPH_EXTRACTOR or EMBEDDING_* value is exported in your shell or sitting in a .env file, which cognee reads as well
  • Read Local Setup (No API Key) for the .env form of local provider configuration, and Embedding Providers to swap in a different fastembed model with its matching dimensions

Code in Action

What Just Happened

Step 1: Clear Any Inherited API Key

Cognee reads its LLM key from the environment, so a key exported in your shell or picked up from a .env file would quietly make this run an ordinary LLM run. Popping both variables first is what makes the result meaningful: everything after this line has no LLM to call.

Step 2: Turn Off Per-Turn Feedback (Optional)

AUTO_FEEDBACK is the one setting this script touches, and it is an optimization rather than a requirement: per-turn feedback analysis is an LLM call of its own, but it checks for a usable LLM key before it builds a client and returns an empty analysis with a single debug line when there is none. Leaving it on would not break a keyless run; turning it off keeps the call out of the run entirely. For the two search types this script uses it is belt-and-braces either way — CHUNKS and SUMMARIES opt out of the turn analysis whatever AUTO_FEEDBACK is set to — but the setting still matters the moment you add a completion search to the script. It goes in before import cognee because cognee reads its configuration at import time, hence the # noqa: E402 markers on the imports. Neither the extractor nor the embedder is configured, because cognee picks the local pair itself when nothing else is set. GRAPH_EXTRACTOR defaults to auto, which resolves to the GLiNER demo extractor when no usable LLM key is found, and embeddings resolve the same way to fastembed’s BAAI/bge-small-en-v1.5 on CPU. Cognee reads that model’s vector size from the fastembed registry, so no dimension setting is needed either. Both halves resolve on what is configured, not only on the missing key, and this script forces neither:
  • The embedding fallback applies only when no embedding setting is configured. Any EMBEDDING_PROVIDER, EMBEDDING_MODEL, EMBEDDING_API_KEY or EMBEDDING_ENDPOINT that differs from the OpenAI default is honoured instead — including one read from a .env file. A leftover setting that carries its own EMBEDDING_API_KEY therefore keeps sending embedding requests off the machine with LLM_API_KEY popped; one without a key fails on authentication rather than falling back.
  • Extraction behaves the same way: a GRAPH_EXTRACTOR=llm setting pins the LLM path, and the run then fails for want of a key.
  • COGNEE_SKIP_PREFLIGHT, COGNEE_SKIP_CONNECTION_TEST and MOCK_EMBEDDING switch both fallbacks off, on the grounds that a partial or mocked provider config is deliberate and should be honoured rather than replaced.
Every process that resolves to the demo extractor logs one notice naming it and the enterprise GLiNER extraction behind it — informational, not a failure. If the gliner2 package is missing, the run does not stop: cognee installs the runtime first, logging a WARNING with the environment, the download size and the index it uses, and starts the pipeline once torch and gliner2 import. Only with GLINER_AUTO_INSTALL=false does it stop up front, with KeylessExtractorNotInstalledError and the install command from above; an install that fails raises GlinerInstallError with the same fix.

Step 3: Remember the Text Locally

Pruning first clears any vector collections left over from a previous embedding model — their dimensions would not match the 384 that bge-small-en-v1.5 produces. remember() then ingests the text, builds the graph with GLiNER, and embeds the results with fastembed. Because no LLM task is in the pipeline, cognee also skips the first-run LLM connection probe, so the missing key never becomes an error. If this first call takes minutes, it is the model downloads rather than a hang — the two warnings described above name what is being fetched and where it is going. Later runs load both models from those caches and log at INFO.

Step 4: Recall With the Default Search Type

With no query_type, recall() normally answers with an LLM-written completion. When no usable LLM key is configured it falls back to SearchType.CHUNKS instead — a pure vector search that returns the matching text chunks — which is why the call works here at all. The printed search_type on each result reports which type actually ran.

Step 5: Search the GLiNER Summaries

SearchType.SUMMARIES searches the per-chunk summaries rather than the raw chunks. On this run those summaries were written by GLiNER from the extracted entities and relationships, not by an LLM, and they are indexed and retrievable like any other summary. Both CHUNKS and SUMMARIES are retrieval-only search types, so requesting one explicitly stays LLM-free.

What Still Needs an LLM

The graph, the summaries, and the two searches above run entirely on local models. Three things still do not:
  • Image, audio, and video files. The keyless path covers text, document, and code files; media files are the one ingestion input that still needs a usable LLM, because transcription and vision descriptions have no LLM-free equivalent. ImageLoader, AudioLoader, and VideoLoader raise LLMAPIKeyNotSetError before reading the file — see Loaders.
  • Completion search types. Anything ending in _COMPLETION — GRAPH_COMPLETION, RAG_COMPLETION, HYBRID_COMPLETION — retrieves context and then asks an LLM to write the answer. Requesting one without a key fails; see Search Basics for the full list of types and what each returns.
  • The parts that write text with an LLM. Per-turn feedback analysis, the session-context lessons behind “Extract session context”, the distilled session_learnings from “Distill sessions”, and the optional global context index all need a key to produce anything. Without one they decline rather than fail: the per-turn analysis returns an empty result, and improve() reports those stages as skipped — no_llm_configured for distillation and the global context index, and auto_feedback_disabled for session-context extraction while AUTO_FEEDBACK is off, since that gate is checked first.
Sessions themselves do not need a key. This script keeps remember() sessionless for simplicity, but remember(session_id=...) and an explicit improve(session_ids=[...]) complete on a keyless install: feedback weights, session Q&A, and agent traces all run and reach the permanent graph. The default triplet and vector enrichment needs no LLM either, but it only runs when triplet embeddings are enabled — off by default, in which case that stage is skipped with triplet_embedding_disabled whether or not a key is present.

Local Setup (No API Key)

The .env form of local provider configuration, plus local-run troubleshooting.

Custom GLiNER Extraction

Pass your own entity and relation labels, and measure what extraction dropped.

Embedding Providers

Pick a different fastembed model and its matching dimensions.

Search Basics

Every search type, and which ones need an LLM to answer.