SurrealDB Vector Database
Use SurrealDB as a vector database for your Knowledge Base.
Setup
uv pip install -U surrealdb pypdf openai agnoThe example uses OpenAI for embeddings and the agent model, so set your API key:
export OPENAI_API_KEY=xxxdocker run -d \
--rm \
--pull always \
-p 8000:8000 \
surrealdb/surrealdb:latest \
start \
--user root \
--pass rootor
./cookbook/scripts/run_surrealdb.shExample
from agno.agent import Agent
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.knowledge.knowledge import Knowledge
from agno.vectordb.surrealdb import SurrealDb
from surrealdb import Surreal
# SurrealDB connection parameters
SURREALDB_URL = "ws://localhost:8000"
SURREALDB_USER = "root"
SURREALDB_PASSWORD = "root"
SURREALDB_NAMESPACE = "test"
SURREALDB_DATABASE = "test"
# Create a client
client = Surreal(url=SURREALDB_URL)
client.signin({"username": SURREALDB_USER, "password": SURREALDB_PASSWORD})
client.use(namespace=SURREALDB_NAMESPACE, database=SURREALDB_DATABASE)
surrealdb = SurrealDb(
client=client,
collection="recipes", # Collection name for storing documents
search_ef=40, # HNSW search time/accuracy trade-off
embedder=OpenAIEmbedder(),
)
def sync_demo():
"""Demonstrate synchronous usage of SurrealDb"""
knowledge_base = Knowledge(
vector_db=surrealdb,
)
# Load data synchronously
knowledge_base.insert(
url="https://agno-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"
)
# Create agent and query synchronously
agent = Agent(knowledge=knowledge_base)
agent.print_response(
"What are the 3 categories of Thai SELECT is given to restaurants overseas?",
markdown=True,
)
if __name__ == "__main__":
# Run synchronous demo
print("Running synchronous demo...")
sync_demo()The async example supplies both authenticated clients to the same namespace and database: Knowledge currently checks the schema synchronously during construction. Context managers close both connections when the example finishes.
Async Support ⚡
SurrealDB awaits async client I/O. Knowledge initialization, PDF extraction, and query embeddings still use synchronous operations; async methods alone do not guarantee nonblocking execution.
import asyncio
from agno.agent import Agent
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.knowledge.knowledge import Knowledge
from agno.vectordb.surrealdb import SurrealDb
from surrealdb import AsyncSurreal, Surreal
SURREALDB_URL = "ws://localhost:8000"
SURREALDB_NAMESPACE = "test"
SURREALDB_DATABASE = "test"
CREDENTIALS = {"username": "root", "password": "root"}
async def main():
# Knowledge checks/creates the schema through the synchronous client.
with Surreal(SURREALDB_URL) as sync_client:
sync_client.signin(CREDENTIALS)
sync_client.use(namespace=SURREALDB_NAMESPACE, database=SURREALDB_DATABASE)
async with AsyncSurreal(SURREALDB_URL) as async_client:
await async_client.signin(CREDENTIALS)
await async_client.use(namespace=SURREALDB_NAMESPACE, database=SURREALDB_DATABASE)
vector_db = SurrealDb(
client=sync_client,
async_client=async_client,
collection="recipes",
search_ef=40,
embedder=OpenAIEmbedder(),
)
knowledge = Knowledge(vector_db=vector_db)
await knowledge.ainsert(
url="https://agno-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf",
)
agent = Agent(knowledge=knowledge)
await agent.aprint_response("How do I make pad thai?", markdown=True)
if __name__ == "__main__":
asyncio.run(main())Use ainsert() and aprint_response() with the async client for awaited database I/O. Measure or offload the remaining synchronous work when needed.
SurrealDB Params
| Parameter | Type | Default | Description |
|---|---|---|---|
client | Optional[Union[BlockingWsSurrealConnection, BlockingHttpSurrealConnection]] | None | A blocking connection, either HTTP or WS |
async_client | Optional[Union[AsyncWsSurrealConnection, AsyncHttpSurrealConnection]] | None | An async connection, either HTTP or WS |
collection | str | "documents" | Collection name to store documents |
distance | Distance | Distance.cosine | Distance metric to use (cosine, l2, or max_inner_product) |
efc | int | 150 | Accepted but currently not applied to the generated index |
m | int | 12 | Accepted but currently not applied to the generated index |
search_ef | int | 40 | HNSW search time/accuracy trade-off |
embedder | Optional[Embedder] | OpenAIEmbedder() | Embedder instance for creating embeddings |