# Vector Search Implementation for Semantic Queries Using Embeddings in Open Notebook

> Discover how Open Notebook implements vector search for semantic queries using embeddings. Learn how Esperanto AI and SurrealDB power efficient nearest-neighbor lookups for your data.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: deep-dive
- Published: 2026-06-22

---

**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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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:

```sql
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`](https://github.com/lfnovo/open-notebook/blob/main/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:

```bash
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:

```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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/embedding.py) using the Esperanto AI provider, handling batching, retries, and normalization of 768-dimensional vectors.
- **Vector comparison** executes inside SurrealDB via the `fn::vector_search` function called from [`open_notebook/domain/notebook.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/notebook.py), supporting filtering by source, note, and minimum similarity threshold.
- **API exposure** happens through [`api/routers/search.py`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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.