Tune cognee's performance
SkillAI & modelsA skill for tuning cognee's speed and cost when ingestion or queries get slow, expensive, or rate limited. It walks through estimating ingestion cost before running, adjusting batching and chunk-size knobs, setting LLM and embedding rate limits, and routing stages to cheaper or local models.
Then ask your AI: use the Tune cognee's performance skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; Ahel provides instructions and does not run this skill.
No other account needed.
Have a working cognee installation and the documents or datasets you plan to ingest.
What your AI can do with it
- Estimate per-stage token counts and approximate cost with remember(dry_run=True)
- Adjust data_per_batch, chunks_per_batch, and chunk_size on remember() and cognify()
- Set LLM rate limits with LLM_RATE_LIMIT_ENABLED, REQUESTS, and INTERVAL
- Route extraction, summarization, and query stages to cheaper or local models
Getting started
- Have a working cognee installation and the documents or datasets you plan to ingest.
- Run a dry-run estimate with cognee.remember(path, dry_run=True) to see per-stage token counts and approximate cost before any LLM calls.
- Set the ingestion knobs you need on remember() or cognify(): data_per_batch, chunks_per_batch, chunk_size, run_in_background, and self_improvement.
- Configure LLM throttling and per-stage models through environment variables such as LLM_RATE_LIMIT_ENABLED, LLM_RATE_LIMIT_REQUESTS, LLM_RATE_LIMIT_INTERVAL, and LLM_EXTRACTION_MODEL.
- Run the ingestion and check the returned status, awaiting the result later if you used run_in_background.
What this skill tells your AI
The instructions your AI receives, as published by topoteretes/cognee in .agents/skills/cognee-performance/SKILL.md and read by Ahel’s review.
The LLM is the bottleneck. Building the graph costs two LLM calls per chunk (graph extraction and summarization), and almost every other tuning question comes down to how many of those calls run, how fast, and on which model. Database and embedding work is small next to that.
Use it
1. Estimate before you ingest
estimate = await cognee.remember("./docs", dry_run=True)
print(estimate) # per-stage token counts and approximate cost; no LLM calls
The estimate covers graph extraction and summarization only, not
improve(), embeddings, or contradiction detection. Not available with
GLiNER or a remote instance.
2. Ingestion knobs
All are remember() arguments (and cognify() ones):
| Knob | Default | What it controls |
|---|---|---|
data_per_batch | 20 | How many documents are processed at the same time (a concurrency limit, not a batch). Lower it to reduce load; raise it for many small files. |
chunks_per_batch | 2000 (env CHUNKS_PER_BATCH) | How many chunks each extraction/storage call receives. Lower it to spread load and fail smaller. The DLT pipeline defaults to 100. |
chunk_size | min(embedding max tokens, LLM max tokens / 2); about 8191 tokens with default OpenAI models | Max tokens per chunk. Fewer, bigger chunks mean fewer LLM calls; smaller chunks mean finer-grained graphs. |
run_in_background | False | Return immediately (status="running"); await result later. |
self_improvement | True | improve() after the graph is built. False (or IMPROVE_AUTO_ENABLED=false) skips that extra work. |
Worst-case concurrent LLM calls are about
data_per_batch × min(chunks per document, chunks_per_batch) × 2, and there
is no separate concurrency cap. The rate limiter below is the brake.
Several datasets in one cognify(datasets=[...]) call run one after
another, not in parallel.
3. LLM throttling and models
| Env var | Default | Notes |
|---|---|---|
LLM_RATE_LIMIT_ENABLED | false | Turn on a requests-per-interval limit |
LLM_RATE_LIMIT_REQUESTS / LLM_RATE_LIMIT_INTERVAL | 60 / 60 s | 10 requests for local providers (Ollama, llama.cpp, LM Studio) |
AUTO_RATE_LIMIT | true | On a 429/503/529 or timeout, switches the limiter on for 15 minutes (extended while errors continue) |
LLM_EXTRACTION_MODEL / _PROVIDER / _ENDPOINT / _API_KEY / _API_VERSION | the main model | Use a cheaper or faster model just for graph extraction |
LLM_SUMMARIZATION_*, LLM_QUERY_* | the main model | Same, for summaries and for answering queries |
LLM_MAX_COMPLETION_TOKENS | 16384 | Also caps the default chunk size (half of it) |
LLM_ARGS | — | Extra litellm arguments merged into every call, e.g. a request timeout |
Structured-output calls retry with exponential backoff for at least two attempts and four minutes before failing; auth, not-found, and quota errors are not retried.
The rate limiter is built from the main model's settings. A stage routed to
a local model does not get the local default of 10 requests; set
LLM_RATE_LIMIT_REQUESTS yourself.
4. Embeddings
| Env var | Default |
|---|---|
EMBEDDING_BATCH_SIZE | 36 texts per request |
EMBEDDING_MAX_CONCURRENT_DATA_POINTS | 150 (so 150 / 36 = 4 concurrent requests) |
EMBEDDING_RATE_LIMIT_ENABLED / _REQUESTS / _INTERVAL | off / 60 / 60 s |
Embedding calls retry transient errors, rate-limit 429s included, with
exponential jitter for up to 128 s (budget-exhaustion errors are terminal,
not retried), but AUTO_RATE_LIMIT does not apply to them; enable
EMBEDDING_RATE_LIMIT_ENABLED yourself for sustained load. Without any
credentials cognee embeds locally with fastembed (BAAI/bge-small-en-v1.5),
which runs on the CPU and blocks while it works.
5. Skip the LLM for extraction
remember(data, extractor="gliner") builds the graph and summaries with a
local GLiNER model: no LLM calls, embeddings still run. The runtime installs
on first use (GLINER_AUTO_INSTALL=false to disable; then pip install "cognee[gliner]"). See the cognee-ingestion skill for its limits.
6. Read latency
AUTO_FEEDBACK=falseis the biggest win for chat-style use: by default every answered turn (the default session is used when nosession_idis passed) makes one extra LLM call to analyze feedback. KeepCACHING=trueso session memory still works.- Pick a type without an LLM when you need passages, not an answer:
CHUNKS,CHUNKS_LEXICAL,SUMMARIES,CODE,SKILLS. Completion types make one LLM call;GRAPH_COMPLETION_COT,_DECOMPOSITION,_CONTEXT_EXTENSION,GRAPH_SUMMARY_COMPLETIONandTEMPORALmake several;NATURAL_LANGUAGEmakes one and retries (up to 3 attempts) only on an empty or failed query;FEELING_LUCKYadds one to pick the type. - Narrow the search: pass
datasets=[...](one search runs per dataset) and a smallertop_k(per dataset, default 15; HYBRID caps each lane at 10, so only values below 10 shrink its context). SESSION_SEARCH_MODE=concurrent(default) overlaps the feedback analysis with the answer;sequentialruns them back to back.
7. Several datasets at once
With access control on (the default), each dataset has its own databases.
DATASET_QUEUE_MAX_CONCURRENT (default 6, from DATABASE_MAX_LRU_CACHE_SIZE)
caps how many datasets are processed at once in one process, and
SUBPROCESS_IDLE_TTL_SECONDS (600) keeps idle database workers warm.
DATASET_QUEUE_ENABLED (default true) enforces that cap, releases
subprocess engines when a dataset's last scope exits (they stay warm for
SUBPROCESS_IDLE_TTL_SECONDS and close at once only when it is 0) and pins
in-use engines against eviction.
Setting it false removes the cap rather than disabling parallelism, and
risks file-lock leaks and engine eviction under parallel load, so keep it
on.
8. Scaling a deployment
Open-source cognee scales vertically, in one process:
- The API server runs one worker (
gunicorn -w 1), and the improve and session locks, caches and semaphores are in-process only. More workers or replicas against the same data are not coordinated (the Helm chart README says to validate before scaling past one replica). - The default embedded databases (SQLite, LanceDB, Ladybug) live on local disk. For production, use Postgres + PGVector and a graph-native backend such as Neo4j.
distributed/deploy/holds one-click deploy templates (Modal, Fly, Railway, Render, Daytona), not a distributed runner.
For production scale: horizontal scaling (distributed ingestion across workers), cognee's enterprise GLiNER extraction, and the production Postgres graph adapter are part of cognee's proprietary offering. Contact social@cognee.ai.
Pitfalls
CHUNK_SIZE,CHUNK_OVERLAP,CHUNK_STRATEGY(in.env.template) andcognee.config.set_chunk_size()etc. have no effect on ingestion. Passchunk_size=toremember()instead.LLM_RATE_LIMIT_TOKENSandEMBEDDING_RATE_LIMIT_TOKENSdo nothing; only request-count limits are enforced.FALLBACK_MODELis used only when the main model rejects content on policy grounds, not when it is slow, down, or rate-limited.data_per_batch=Nonecrashes. Omit the argument to get the default.- A background
cognify()is not tracked bycognee.wait_for_background_tasks()(a backgroundremember()orimprove()is). Await its pipeline status yourself. - Big default chunks with a small local embedder. The default chunk size
follows the configured embedding limit (8191), even for fastembed's
512-token model. Pass a smaller
chunk_sizefor local embedding models. - Benchmark with
CACHING=true: with it off you measure cognee without its memory layer.
How it works
remember() → add() → cognify(): every document of the dataset is
scheduled at once, data_per_batch of them run concurrently, and each runs
the task chain (classify, chunk, extract graph + summarize, store). Tasks
receive their input in batches of chunks_per_batch.
extract_graph_and_summarize runs extraction and summarization together,
each gathering one LLM call per chunk in the batch. Every LLM call passes
through one process-wide rate limiter.
- Cognify task list and defaults:
cognee/api/v1/cognify/cognify.py - Concurrency (
data_per_batchsemaphore):cognee/modules/pipelines/operations/run_tasks.py - Task batching:
cognee/modules/pipelines/tasks/task.py,run_tasks_base.py - LLM calls per chunk:
cognee/tasks/graph/extract_graph_and_summarize.py - Chunk-size default:
cognee/infrastructure/llm/utils.py:get_max_chunk_tokens - LLM config, rate limits, stage routing:
cognee/infrastructure/llm/config.py,cognee/shared/rate_limiting.py,cognee/infrastructure/llm/overload_policy.py,cognee/infrastructure/llm/retry_config.py - Embedding config:
cognee/infrastructure/databases/vector/embeddings/config.py - Dataset queue:
cognee/infrastructure/databases/dataset_queue/queue.py - Cost estimate:
cognee/modules/cognify/estimator.py
Extending it
- Benchmarks:
cognee/tests/performance/(batch_add_cognify_test.py,locust_performance_analysis.py, andstatistics_percentile/for p50–p99 runs with mocked or replayed LLM calls). Measure before and after a change. - Retrieval quality and cost:
cognee/eval_framework/(python -m cognee.eval_framework; Modal runs cost money). - A new pipeline task that calls an LLM should keep
needs_llm=Trueand go throughLLMGateway, so it shares the rate limiter and retry policy.
Signals
- GitHub stars
- 32k
- Forks
- 3k
- Last commit
- Oct 2026
Ahel review
K1binfo
installs-packages
Automated review, not a security audit. Ruleset v1+k2.
Questions
- How do I estimate cost before ingesting?
- Call cognee.remember(path, dry_run=True). It returns per-stage token counts and approximate cost with no LLM calls.
- What controls how many documents are processed at the same time?
- data_per_batch, default 20. It is a concurrency limit, not a batch. Lower it to reduce load; raise it for many small files. Worst-case concurrent LLM calls are about data_per_batch times min(chunks per document, chunks_per_batch) times 2.
Advanced
- Item type
- skill
- Key
cognee-performance- Source
- github.com/topoteretes/cognee
Related picks
Skill · davila7
The pick for C / C++dbos-python
Skill · sickn33
The pick for Pythonpython-design-patterns
Skill · wshobson
The pick for Pythonsupabase-postgres-best-practices
Skill · supabase
The pick for Postgresperforming-sqlite-database-forensics
Skill · mukul975
The pick for SQLitesqlite-ops
Skill · aiskillstore
The pick for SQLite