Vector Search Implementation for Semantic Queries Using Embeddings in Open Notebook
Open Notebook implements vector search by converting query text into dense embeddings via the Esperanto AI provider, then executing nearest-neighbor lookups through SurrealDB's built-in fn::vector_search function.
The open-notebook repository by lfnovo delivers a semantic search architecture that bridges modern embedding models with SurrealDB's native vector capabilities. This implementation enables users to query content by meaning rather than exact keyword matches, leveraging high-dimensional vector representations stored directly in the database.
Embedding Generation Pipeline
The semantic search workflow begins in open_notebook/utils/embedding.py, which provides a robust wrapper around the embedding model interface. The file exposes three core functions: generate_embedding for single text inputs, generate_embeddings for batch processing, and mean_pool_embeddings for aggregating multiple vectors.
The embedding generation leverages the Esperanto AI-provider wrapper (open_notebook.ai.models.model_manager) to handle model selection and API communication. This layer implements automatic batching, retry logic with exponential backoff, and vector normalization to ensure consistent 768-dimensional output vectors. When a user submits a semantic query, the system transforms the raw text into a dense list of floats that captures the semantic meaning of the input.
SurrealDB Vector Search Execution
Once generated, embeddings flow to open_notebook/domain/notebook.py, where the vector_search coroutine manages database interaction. This function constructs a parameterized SurrealQL query that invokes the database's native vector comparison engine:
SELECT * FROM fn::vector_search(
$embed, -- the embedding list
$results, -- max number of hits
$source, -- optional source filter
$note, -- optional note filter
$minimum_score -- score threshold (0-1)
);
SurrealDB evaluates this function by computing similarity scores between the query vector and stored embeddings for each Source and Note record. The function returns matches ordered by relevance, filtering out results below the specified minimum_score threshold. This approach delegates the computationally expensive nearest-neighbor search to the database layer, optimizing performance for large document collections.
API Implementation and Usage
The search functionality exposes a RESTful interface through api/routers/search.py. The /search endpoint accepts JSON payloads that specify the search strategy via the type field.
FastAPI Search Endpoint
When processing requests with "type": "vector", the endpoint verifies that an embedding model is configured in the environment, then invokes the domain layer's vector_search coroutine. The implementation supports filtering by content type (sources vs. notes) and configurable result limits:
curl -X POST http://localhost:5055/search \
-H "Content-Type: application/json" \
-d '{
"keyword": "machine learning pipelines",
"type": "vector",
"results": 5,
"source": true,
"note": false,
"minimum_score": 0.7
}'
Direct Programmatic Access
Developers can bypass the HTTP layer and call the search logic directly from Python:
from open_notebook.domain.notebook import vector_search
async def semantic_query(query: str):
# 10 results, filter both sources and notes, require at least 0.6 similarity
results = await vector_search(
keyword=query,
results=10,
source=True,
note=True,
minimum_score=0.6,
)
return results
The test suite in tests/test_search_api.py validates both the vector search integration and the fallback mechanisms, ensuring the system behaves correctly under various configuration scenarios.
Fallback Behavior and Error Handling
The implementation includes defensive logic at lines 713-720 in open_notebook/domain/notebook.py that automatically falls back to vector_search when text-based search operations encounter highlight position overflows. This ensures that users receive meaningful semantic results even when traditional text search fails or exceeds buffer limits, creating a resilient search experience that prioritizes result delivery over strict protocol adherence.
Summary
- Embedding generation occurs in
open_notebook/utils/embedding.pyusing the Esperanto AI provider, handling batching, retries, and normalization of 768-dimensional vectors. - Vector comparison executes inside SurrealDB via the
fn::vector_searchfunction called fromopen_notebook/domain/notebook.py, supporting filtering by source, note, and minimum similarity threshold. - API exposure happens through
api/routers/search.py, which validates model configuration and translates HTTP requests into coroutine calls. - Automatic fallback from text search to vector search ensures robust query handling when text search operations exceed positional limits.
Frequently Asked Questions
What embedding model does Open Notebook use for semantic search?
Open Notebook utilizes the Esperanto AI-provider wrapper (open_notebook.ai.models.model_manager) to interface with embedding models. The system generates 768-dimensional dense vectors through the helper functions in open_notebook/utils/embedding.py, though the specific underlying model (such as OpenAI's text-embedding-ada-002 or similar) depends on the provider configuration set in the environment.
How does SurrealDB compare vectors for semantic similarity?
SurrealDB executes the comparison through its built-in fn::vector_search function, which performs a nearest-neighbor search between the query embedding and stored vectors in the database. This function calculates similarity scores (typically cosine similarity) and returns records ordered by relevance, filtering results below the configurable minimum_score parameter ranging from 0 to 1.
Can I filter vector search results by specific content types?
Yes, the vector_search coroutine in open_notebook/domain/notebook.py accepts boolean parameters for source and note that filter the search space accordingly. When calling the API endpoint, you can set "source": true and "note": false to restrict results to only Source records, or enable both to search across all content types simultaneously.
What happens if text search fails in Open Notebook?
The system implements automatic fallback behavior at lines 713-720 of open_notebook/domain/notebook.py. When text search encounters highlight position overflows or similar errors, the code automatically redirects the query to the vector_search pathway, ensuring users always receive semantically relevant results even when traditional text matching fails.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →