Context Builder Mechanism for RAG Conversations in Open-Notebook

The ContextBuilder is an async-aware orchestrator that assembles retrieval-augmented generation (RAG) prompt contexts by fetching sources, notes, and insights from the graph database, deduplicating and prioritizing them by relevance, and truncating results to a configurable token budget before returning a structured JSON payload.

Open-Notebook implements a sophisticated context builder mechanism for RAG conversations through the ContextBuilder utility located in open_notebook/utils/context_builder.py. This system acts as a configurable pipeline that transforms raw graph data into optimized LLM-ready context windows. Understanding this architecture is essential for developers extending the RAG capabilities or integrating custom knowledge sources into the conversation flow.

Core Data Structures

The context builder relies on three primary dataclasses that define how knowledge is packaged and prioritized before reaching the language model.

ContextItem Dataclass

The ContextItem class represents a single atomic unit of context within the RAG pipeline. Defined at lines 21-30 of context_builder.py, this dataclass encapsulates an ID, content type (source, note, or insight), raw content, priority score, and token count. Each item lazily computes its token count via open_notebook/utils/token_utils, ensuring the builder can enforce budget constraints without requiring pre-computed sizes from callers.

ContextConfig Dataclass

ContextConfig (lines 38-48) centralizes the inclusion rules and ranking logic for the context assembly process. This configuration object stores boolean flags for including insights and notes, defines per-type priority weights, and sets the maximum token limit. When instantiated, it translates high-level parameters like include_insights=True into concrete filtering rules that the orchestrator applies during the build phase.

ContextBuilder Orchestrator

The ContextBuilder class (lines 59-65) serves as the main entry point and pipeline controller. Its constructor accepts flexible keyword arguments—including source_id, notebook_id, max_tokens, and custom configuration objects—and stores them in self.params for extensibility. If no explicit ContextConfig is provided, the builder automatically constructs one from the extracted boolean flags and token limits.

The Context Building Pipeline

The ContextBuilder.build() method executes a seven-step pipeline that transforms database records into a formatted response dictionary.

Step 1: Initialization and Reset

The build process begins by clearing the internal self.items list to ensure clean state between invocations. This reset prevents context leakage when the same builder instance processes multiple consecutive RAG queries.

Step 2: Source Context Retrieval

When a source_id is supplied, the _add_source_context method (lines 42-84) fetches the corresponding Source record from the graph database. It extracts either short or long-form context via Source.get_context(), creates a ContextItem, and optionally attaches related insights if include_insights is enabled.

Step 3: Notebook Context Expansion

If processing a notebook_id, the _add_notebook_context method (lines 10-27) loads the Notebook model and iterates over its associated sources and notes. This method delegates to specialized helpers that convert Notebook.get_sources() and Notebook.get_notes() results into individual ContextItem instances, allowing entire research notebooks to be compressed into single context windows.

Step 4: Custom Parameter Processing

The pipeline includes a hook method _process_custom_params (lines 96-104) designed for subclassing. Developers can override this to inject domain-specific filtering logic—such as date-range constraints or semantic similarity thresholds—without modifying the core deduplication and truncation logic.

Step 5: Deduplication and Prioritization

The _remove_duplicates method (lines 51-63) eliminates ContextItem instances with duplicate IDs that may arise when notebooks contain overlapping sources. Subsequently, _prioritize (lines 15-18) sorts the remaining items by their numeric priority score in descending order, ensuring the most relevant content appears first in the final context window.

Step 6: Token Budget Enforcement

The truncate_to_fit method (lines 20-47) enforces the max_tokens constraint by calculating the cumulative token_count of all items and dropping the lowest-priority entries until the total fits within budget. This greedy algorithm preserves high-priority context while gracefully degrading when source material exceeds LLM context limits.

Step 7: Response Formatting

Finally, _format_response (lines 67-107) groups items by type, computes aggregate statistics, and returns a plain dictionary with optional notebook metadata. If any step raises an exception, the builder wraps it in DatabaseOperationError, enabling the API layer in api/context_service.py to translate failures into appropriate 5xx HTTP responses.

Token Counting Strategy

Each ContextItem computes its token footprint lazily through the token_count property, which delegates to utilities in open_notebook/utils/token_utils. This design decouples tokenization from data retrieval, allowing the builder to make truncation decisions based on actual encoder counts rather than heuristic character estimates. The lazy evaluation ensures that tokenization only occurs for items that survive the deduplication and prioritization phases, optimizing performance when processing large notebooks.

Convenience Functions for Common Use Cases

Open-Notebook exposes three async helper functions that wrap the ContextBuilder for typical RAG scenarios:

  • build_notebook_context – Generates comprehensive context for an entire notebook, including all sources, notes, and insights, truncated to the specified token limit.
  • build_source_context – Creates focused context from a single source document with optional insight inclusion, ideal for deep-dive questions on specific materials.
  • build_mixed_context – Assembles arbitrary combinations of source IDs and note IDs, supporting ad-hoc RAG queries that span multiple disconnected resources.

All three functions instantiate ContextBuilder with appropriate arguments and forward to builder.build(), as implemented at lines 119-146 of context_builder.py.

Integration with RAG Workflows

The context builder integrates directly into Open-Notebook's LangGraph workflows through open_notebook/graphs/ask.py, where it serves as a node in the retrieval pipeline. During conversation execution, the graph invokes the builder to assemble historical context before passing the formatted dictionary to the language model. HTTP clients can also trigger context generation via api/context_service.py, which exposes the builder's capabilities through REST endpoints.

Summary

  • The ContextBuilder in open_notebook/utils/context_builder.py orchestrates RAG context assembly through a configurable, async-aware pipeline.
  • ContextItem and ContextConfig dataclasses standardize how knowledge units are packaged, prioritized, and filtered.
  • The build pipeline executes seven distinct phases: initialization, source retrieval, notebook expansion, custom processing, deduplication, prioritization, and token-budget truncation.
  • Token counting occurs lazily via open_notebook/utils/token_utils, ensuring accurate budget enforcement without unnecessary computation.
  • Convenience functions (build_notebook_context, build_source_context, build_mixed_context) provide simplified interfaces for common retrieval patterns.

Frequently Asked Questions

How does the ContextBuilder handle duplicate content across multiple sources?

The builder calls _remove_duplicates during the pipeline execution, which scans the collected ContextItem instances and removes any with duplicate IDs. This prevents the same source document from consuming token budget multiple times when it appears in both a direct source query and a notebook collection.

What happens when the context exceeds the maximum token limit?

The truncate_to_fit method implements a priority-based truncation algorithm. It sorts items by relevance score (highest first), calculates cumulative token counts, and removes the lowest-priority items until the total fits within the max_tokens budget. This ensures the most important context survives while gracefully degrading less relevant material.

Can developers customize which content types are included in the context?

Yes, through the ContextConfig dataclass or constructor flags like include_insights and include_notes. Developers can also subclass ContextBuilder and override _process_custom_params to implement domain-specific filtering logic—such as semantic similarity thresholds or date-range constraints—without modifying the core truncation and formatting logic.

Where is the ContextBuilder invoked during actual chat conversations?

The builder is integrated into the LangGraph workflow defined in open_notebook/graphs/ask.py, where it serves as a retrieval node that assembles historical context before LLM invocation. Additionally, HTTP-based RAG requests are handled by api/context_service.py, which instantiates the builder and returns formatted context through REST endpoints.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →