BaseRetriever’s interface works, taught by building a tiny, fully offline retriever. No database, network connection, embeddings, or LLM required.
Before You Start
- Have
cogneeinstalled (see Installation) — needed only for theBaseRetrieverimport; no LLM provider or database configuration is required for this example. - No prior OOP knowledge is assumed — the concepts you need (classes, inheritance, abstract methods) are explained at the end of the page.
Code in Action
What Just Happened
The three methods below —get_retrieved_objects, get_context_from_objects, and get_completion_from_context — are called, in order, by get_completion(), each explained one step at a time below. JsonToyRetriever inherits get_completion() from BaseRetriever rather than defining it.
Step 1: Retrieve Objects
get_retrieved_objects is the first of the three methods BaseRetriever requires every subclass to implement (get_retrieved_objects, get_context_from_objects, get_completion_from_context). It turns the raw query into a small dictionary and writes it to a JSON file. A production retriever would query a vector database, a graph database, or another storage backend here instead of building a toy dictionary.
Step 2: Build Context
get_context_from_objects, the second stage, turns retrieved objects into the context that gets handed to the completion step. Here it’s just the same dictionary formatted as JSON text; a real retriever might concatenate document chunks or format graph relationships instead.
Step 3: Produce the Completion
get_completion_from_context, the third stage, would normally call an LLM with the context built in Step 2. This toy version returns a deterministic string instead, so the whole example stays offline and reproducible.
Step 4: Run the Retriever
get_completion() is not implemented by JsonToyRetriever — it’s inherited from BaseRetriever. get_completion() calls the three stages above in order, passing each stage’s return value into the next, and returns the final result: the base class defines the workflow, while the subclass only defines the behavior of each step. Running this prints:
toy_query.json file alongside it.
Step 5: Prove the Orchestration Manually
get_retrieved_objects, then get_context_from_objects, then get_completion_from_context, passing each result into the next — produces the exact same output as get_completion(). The assert above never fails: it’s the same three calls either way, just written out instead of hidden inside the inherited method. Running this prints an extra line:
OOP Concepts You Need
Classes, Inheritance, and Abstract Methods
Classes, Inheritance, and Abstract Methods
A class is a blueprint describing what an object can do; an instance is one actual object created from it.One class can inherit from another, gaining its methods for free, and a subclass can override an inherited method with its own implementation:Sometimes a base class needs to require a method without providing it — an abstract method: declared on the base class, but with no implementation there, forcing every subclass to supply its own. Python’s If a subclass forgets to implement
abc module (Abstract Base Classes) provides this via the @abstractmethod decorator:speak, Python raises an error before the object can even be created. See Python’s abc module docs for the full mechanism.BaseRetriever works the same way: it declares get_retrieved_objects, get_context_from_objects, and get_completion_from_context as abstract methods, so calling BaseRetriever() directly raises a TypeError unless all three methods are implemented.Search
See how built-in retrievers map to search types, and how to register a custom one
Search Basics
Run your first real Cognee search once you’re ready to move past this toy example