Skip to main content
A minimal guide to querying Cognee memory. The current top-level flow uses cognee.recall(), while the lower-level cognee.search() API remains available when you need direct retriever control. Before you start:
  • Complete Quickstart to understand basic operations
  • Ensure you have LLM Providers configured for LLM-backed retrieval types
  • Run cognee.remember(...) or otherwise build the graph before querying it
  • Keep at least one dataset with read permission for the user running the search

Code in Action

When you call recall() without an explicit query_type, Cognee uses its default auto-routing behavior to choose the best retrieval strategy for the query. To learn more about that routing behavior and the available lower-level search types, see Recall and Search Types.

Parameters Reference

All examples below assume you are inside an async function. Import helpers when needed:
  • query_text (str, required): The question or phrase to search for.
  • query_type (SearchType, optional): Sets the retrieval mode. With recall(), omitting it enables auto-routing by default; if you pass it explicitly, that strategy is used directly. See Search Types for the full list and Retrievers for how each type maps to a retriever. To pick a type by latency and recall depth, see the speed, cost, and recall depth comparison.
  • top_k (int, optional, default: 15): Maximum number of results to return.
  • system_prompt_path (str, optional, default: "answer_simple_question.txt"): Path to a prompt file packaged with your project.
  • system_prompt (Optional[str]): Inline prompt string. Overrides system_prompt_path when set.
  • only_context (bool, optional, default: False): Skip the LLM completion step and return the retrieved context directly. This avoids the final LLM call and is useful when you want to inspect or reuse the context yourself.
    only_context=True works with any search type. For LLM-completion types (GRAPH_COMPLETION, RAG_COMPLETION, etc.) it returns the text that would have been sent to the LLM. For retrieval-only types (CHUNKS, SUMMARIES) the behavior is effectively unchanged because no final LLM call is made.
  • wide_search_top_k (int, optional, default: 100): Caps initial candidate retrieval for graph-completion retrievers before ranking. Increase for broader recall on large graphs.
  • triplet_distance_penalty (float, optional, default: 6.5): Penalty applied in graph retrieval ranking. Controls how triplet distance influences final result ordering.
  • retriever_specific_config (dict, optional): Per-retriever options. Examples: response_model for typed LLM output; max_iter for GRAPH_COMPLETION_COT; context_extension_rounds for GRAPH_COMPLETION_CONTEXT_EXTENSION. For COT latency tuning, see GRAPH_COMPLETION_COT and the SearchType speed comparison.
    Use include_global_context_index after building the index with cognee.improve(..., build_global_context_index=True). See Global Context Index.
    For lower-level search() calls, a non-string response_model keeps the structured completion in the result payload as a model instance, plain dict, or list of those. Model instances serialize to dictionaries when the payload is dumped. With recall(), graph completions are normalized into ResponseGraphEntry objects: use result.raw for the structured payload and result.text for display text.
  • verbose (bool, optional, default: False): When true, results include text_result, context_result, and objects_result fields alongside the answer.
  • include_references (bool, optional, default: True): When true, completion-style answers (GRAPH_COMPLETION, RAG_COMPLETION, etc.) get a deterministic Evidence: block appended to the answer text, citing the source chunks or graph context. Set to False to restore the exact prior answer text. See Citation and Source Tracking for details.
These options scope retrieval to specific node sets. With recall(), pass node_name and optionally node_name_filter_operator — use the same names you passed to cognee.add(..., node_set=[...]). See NodeSets for background.node_name (Optional[List[str]]): Names of the node sets to include.
node_name_filter_operator (str, optional, default: "OR"): Controls how multiple node-set names are combined. "OR" returns results connected to any of the listed node sets; "AND" returns results connected to all of them.
Node-set filtering applies to graph-completion search types (GRAPH_COMPLETION, GRAPH_COMPLETION_COT, GRAPH_COMPLETION_CONTEXT_EXTENSION, GRAPH_SUMMARY_COMPLETION, TEMPORAL, RAG_COMPLETION, TRIPLET_COMPLETION, CHUNKS). It has no effect on SUMMARIES, CYPHER, or NATURAL_LANGUAGE.
  • session_id (Optional[str]): Links this recall to a conversation session. With recall(), passing session_id by itself makes Cognee search session cache entries first; if nothing matches, it falls through to graph retrieval. When session_id is reused across completion-style recalls, previous Q&A turns can also be included in the prompt context. If omitted while caching is enabled, Cognee writes to the dataset-scoped default session — default_session_<dataset_id> when the dataset is known, falling back to the global default_session when it is not — so recalls against different datasets never share one session. See Default Session ID.
    See Sessions Guide for complete examples. To record feedback on answers, see the Feedback System.
  • datasets (Optional[Union[list[str], str]]): Limit search to specific dataset names.
  • dataset_ids (Optional[Union[list[UUID], UUID]]): Same as datasets, using UUIDs instead of names.
    With backend access control enabled, datasets=["name"] resolves names only within datasets owned by the current user. If Bob is searching Alice’s shared dataset shared_dataset, searching by name can fail even when Bob has read access. Use dataset_ids=[shared_id] for shared datasets the user did not create.
  • user (Optional[User]): The user to run the search as. Required for multi-tenant flows or background jobs.
    When ENABLE_BACKEND_ACCESS_CONTROL=true:
    • Result shape: Searches run only on datasets the user can access. Results are returned as a list of per-dataset objects (dataset_name, dataset_id, search_result). Use verbose=True to include text_result, context_result, and objects_result in each item.
    • Parallel execution: Multiple datasets are searched concurrently using asyncio.gather() — total time is roughly that of the slowest single-dataset search.
    • If no user is given, get_default_user() is used (created if missing); an error is raised only if this user lacks dataset permissions.
    • If datasets is not set, all datasets readable by the user are searched. An error is raised if none are accessible or if a requested dataset is forbidden.
    PermissionDeniedError will be raised unless you search with the same user that added the data or grant access to the default user.
    When ENABLE_BACKEND_ACCESS_CONTROL=false:
    • Dataset filters (datasets, dataset_ids) are ignored — all data is searched.
    • Results are returned as a plain list (e.g. ["answer1", "answer2"]). If only one dataset is searched and the retriever returns a list, Cognee may unwrap one level for backwards compatibility.

Citation and Source Tracking

Provenance is available at two levels:
  1. Dataset level — when ENABLE_BACKEND_ACCESS_CONTROL=true, results are wrapped with dataset_name and dataset_id.
  2. Chunk/summary levelCHUNKS and SUMMARIES results include an id you can use to look up the item in the graph.

Evidence block (include_references)

For completion-style answers (GRAPH_COMPLETION, RAG_COMPLETION, and similar), Cognee appends a short Evidence: block to the answer text by default (include_references=True). It lists the chunks or graph context the answer was grounded in — for example, - chunk 2 of document policy.pdf: "…".
  • Deterministic and in-process: the block is assembled locally from the retrieved payloads or graph context. There is no extra LLM call and no prompt injection — it is appended after completion generation.
  • Response schema unchanged: Evidence is added to the answer text only. Return types and result shapes are the same as before, and non-string response_model paths are unaffected.
  • Graceful degradation: chunk-level evidence is used when the vector payload carries document_name/document_id. Older indexes that predate these fields fall back to entity → chunk → document graph traversal where the backend supports it, or omit the Evidence block silently (no errors) when neither is available.
  • Opting out: set include_references=False to restore the exact previous answer text. This is useful when you compare against stored snapshots or evaluation baselines, which will otherwise diff against the new Evidence block.
Search results do not include raw source file paths. Evidence can show document names when reference metadata is available, but raw_data_location stays on the Document node. To trace a result back to the original stored file path, use dataset provenance or query the graph by id.
SearchType.CHUNKS returns a list of dicts with these fields:
SearchType.SUMMARIES returns a list of dicts with these fields:
For CHUNKS and SUMMARIES, recall() (and the lower-level cognee.search()) use query_text as a retrieval query, not as an identifier lookup. Passing a chunk or summary id as the query searches for semantically similar content and can return unrelated results (or nothing) — not that specific item.For most workflows, keep the id as provenance metadata and use normal recall() queries to retrieve related content. If you need to inspect a specific chunk, summary, or graph node during debugging, query the databases directly:
Use get_node(node_id) / get_nodes(node_ids) for graph lookups and retrieve(collection_name, data_point_ids) for vector-store lookups. Use DocumentChunk_text for CHUNKS IDs and TextSummary_text for SUMMARIES IDs.
get_graph_engine() and get_vector_engine_async() are async (use await for both); the vector engine’s retrieve method is also async. The older synchronous get_vector_engine() still exists as a deprecated backward-compatibility shim — calling it emits a DeprecationWarning, so use get_vector_engine_async() in new code. With ENABLE_BACKEND_ACCESS_CONTROL=true, these getters return the default databases — direct lookups bypass the per-dataset isolation applied by recall().
Each DocumentChunk has an is_part_of relationship to its parent document. The chunk also carries a flat document_id field, so use that field when you already have the chunk object and only need the parent document id.For debugging or graph inspection, get the graph engine directly with get_graph_engine() and traverse from the chunk node.
When ENABLE_BACKEND_ACCESS_CONTROL=true, every result is wrapped with dataset information:
When ENABLE_BACKEND_ACCESS_CONTROL=false, results are a plain list with no dataset_name or dataset_id wrapper.
For modes that return a generated answer (GRAPH_COMPLETION, RAG_COMPLETION, etc.), use verbose=True to receive the raw retrieved objects alongside the answer:

Writing Effective Queries

A good query does two jobs at once: it tells Cognee what you want and, through its wording, hints at how to retrieve it. Follow these practices to get better answers.
  • Ask a full, natural-language question. recall() and the graph-completion retrievers are LLM-backed, so "What discounts did TechSupply offer in 2023?" works better than a bare keyword like "discounts". Reserve short keyword strings for CHUNKS_LEXICAL or CHUNKS.
  • Let phrasing steer auto-routing, or set query_type yourself. When you omit query_type, a rule-based router reads cue words in your query and picks a strategy — summary words (summary, overview, key takeaways) lean toward summary completion, reasoning words (why, explain, step by step) toward chain-of-thought, relationship words (how are X and Y connected, path between) toward context extension, and time words (when, before, after, or a 4-digit year) toward temporal search. If no cue matches, it defaults to GRAPH_COMPLETION. When you know the mode you want, pass query_type explicitly to bypass the router. See Auto-routing behavior and Choosing a Search Type.
  • Phrase positively. A negation (not, no, never, without) within ~20 characters before a cue word suppresses that cue, so "summary without dates" will not route to summary. Rephrase or set query_type when a query needs negated wording.
  • Scope the query to narrow results. Pass datasets to limit which knowledge base is searched and node_name to restrict retrieval to specific node sets. Tighter scope means less noise and faster answers.
  • Tune the call to the task. Lower top_k for concise answers, raise it for broad recall. Use only_context=True when you want the retrieved context without an LLM answer (useful for inspecting retrieval quality or feeding your own prompt). Match the search type to your latency and cost budget using the speed, cost, and recall depth comparison.

Full Example

recall() is the current high-level retrieval entry point. It routes the query to the best available retrieval strategy and can still use graph-backed search under the hood.

Additional Examples

Additional examples are available on our GitHub.

Custom Prompts

Learn about custom prompts for tailored answers

Permission Snippets

Multi-tenant deployment patterns

API Reference

Explore all search types and parameters

Sessions

Enable conversational memory with sessions

Agent Memory Decorator

Attach retrieval to an agent function boundary