API Reference
agrag
Agentic GraphRAG: graph-based RAG with agentic reasoning.
Modules:
- agents – Agentic layer: planner/researcher/verifier over SearchEngine.
- chunking – Chunking helpers for the ingestion layer.
- cypher – Cypher query builders for graph stores.
- embedding – Text embedding: turn strings into dense vectors.
- graphdb – Graph storage backends and the build shortcut.
- ingestion – The ingestion package.
- observability – OpenTelemetry wiring for the ingestion layer.
- retrieval – Retrieval package: search engine, fusion, reranking, and retrievers.
- vectordb – Vector storage backends and the build shortcut.
agrag.agents
Agentic layer: planner/researcher/verifier over SearchEngine.
Modules:
- build – Build the planner/researcher/verifier agent graph.
- ledger – Citation ledger: assigns and tracks stable keys for one agent run.
- middleware – Agent middleware for composing multiple chat models per strategy.
- model – Translate LLMClientConfig into the matching LangChain chat model.
- prompts – Agent prompt templates for planner, researcher, verifier.
- settings – Env-backed LLM and loop config for the agent layer.
- subagents – Subagent definitions: planner, researcher, verifier.
- tools – Agent tools: thin wrappers calling SearchEngine with fixed Recipes.
agrag.agents.build
Build the planner/researcher/verifier agent graph.
Functions:
- build_agent – Build the planner/researcher/verifier agent graph.
agrag.agents.build.build_agent
build_agent(*, engine:SearchEngine, llm_settings:AgentLLMSettings, agent_settings:AgentSettings | None = None, filters:SearchFilters | None = None) -> Any
Build the planner/researcher/verifier agent graph.
Constructs a LangGraph-based agent with three roles: planner (decomposes the question), researcher (has tools), and verifier (judges evidence sufficiency).
Each call to ainvoke creates a fresh Ledger so
citation numbering, identity mappings, and retrieved evidence
do not leak across runs.
Parameters:
- engine (
SearchEngine) – Retrieval to expose to the researcher subagent's tools. - llm_settings (
AgentLLMSettings) – The model every subagent role calls, via build_chat_model. With several clients, the remaining ones compose per strategy through agent middleware. - agent_settings (
AgentSettings | None) – Loop-level configuration; defaults from environment. The recursion limit is enforced as the LangGraphrecursion_limitin the invoke config. - filters (
SearchFilters | None) – Retrieval scope applied to every tool search, e.g. document or tenant constraints. None searches unfiltered.
Returns:
Any– A compiled agent graph ready for invoke/ainvoke, or aAny– simple single-search fallback when deepagents is notAny– installed.
agrag.agents.ledger
Citation ledger: assigns and tracks stable keys for one agent run.
Classes:
- Ledger – Assigns and tracks stable citation keys for one agent run.
agrag.agents.ledger.Ledger
Ledger() -> None
Assigns and tracks stable citation keys for one agent run.
A key (E1, R1, C1 for entities, relations, and chunks) is assigned the first time this run encounters that item, by SearchResult.identity_key, and never reassigned within the run. The agent is shown rendered evidence carrying these keys, never raw SearchResults.
Functions:
- cite – Return this result's citation key, assigning one if new.
- render – Return the markdown-with-key text the agent sees.
- resolve – Return the SearchResult behind a citation key.
Attributes:
agrag.agents.ledger.Ledger.cite
cite(result:SearchResult) -> str
Return this result's citation key, assigning one if new.
Parameters:
- result (
SearchResult) – The SearchResult to assign a key to.
Returns:
str– The citation key (e.g.E1,C3).
agrag.agents.ledger.Ledger.keys
keys: list[str]
Return all citation keys assigned so far.
agrag.agents.ledger.Ledger.render
render(result:SearchResult) -> str
Return the markdown-with-key text the agent sees.
Parameters:
- result (
SearchResult) – The SearchResult to render.
Returns:
str– Markdown text with the citation key and item summary.
agrag.agents.ledger.Ledger.resolve
resolve(key:str) -> SearchResult | None
Return the SearchResult behind a citation key.
Parameters:
- key (
str) – The citation key to look up.
Returns:
SearchResult | None– The SearchResult, or None if the key is unknown.
agrag.agents.middleware
Agent middleware for composing multiple chat models per strategy.
Classes:
- RoundRobinModelMiddleware – Rotate across the configured chat models, one model per call.
agrag.agents.middleware.RoundRobinModelMiddleware
RoundRobinModelMiddleware(models:list[Any]) -> None
Bases: AgentMiddleware
Rotate across the configured chat models, one model per call.
Overrides the request's model on every model call so requests are distributed across all configured clients in order.
Functions:
- awrap_model_call – Run the call against the next model in rotation.
- wrap_model_call – Run the call against the next model in rotation.
Parameters:
Raises:
ValueError– models is empty.
agrag.agents.middleware.RoundRobinModelMiddleware.awrap_model_call
awrap_model_call(request:ModelRequest, handler:Callable[[ModelRequest], Awaitable[ModelResponse]]) -> Any
Run the call against the next model in rotation.
agrag.agents.middleware.RoundRobinModelMiddleware.wrap_model_call
wrap_model_call(request:ModelRequest, handler:Callable[[ModelRequest], ModelResponse]) -> Any
Run the call against the next model in rotation.
agrag.agents.model
Translate LLMClientConfig into the matching LangChain chat model.
Classes:
- UnsupportedAgentProviderError – Raised when a provider has no agent-side mapping yet.
Functions:
- build_chat_model – Translate one LLMClientConfig into a LangChain chat model.
- build_model_middleware – Build agent middleware composing multiple clients per strategy.
agrag.agents.model.UnsupportedAgentProviderError
Bases: Exception
Raised when a provider has no agent-side mapping yet.
agrag.agents.model.build_chat_model
build_chat_model(config:LLMClientConfig) -> Any
Translate one LLMClientConfig into a LangChain chat model.
Covers anthropic, openai, openai-generic (mapped to ChatOpenAI with base_url set), and google-ai. The remaining LLMProvider values are valid for BAML but have no agent-side mapping yet.
Parameters:
- config (
LLMClientConfig) – The provider, model, api_key, and base_url to use.
Returns:
Any– A constructed, ready-to-call BaseChatModel.
Raises:
UnsupportedAgentProviderError– config.provider has no agent-side mapping.
agrag.agents.model.build_model_middleware
build_model_middleware(clients:list[LLMClientConfig], *, strategy:Literal['single', 'fallback', 'round_robin'] = 'single') -> list[Any]
Build agent middleware composing multiple clients per strategy.
The agent calls clients[0] as its primary model. With more than
one client, the returned middleware teaches the agent loop to use
the rest: "fallback" tries the other clients in order when the
primary model call fails, and "round_robin" rotates across
every client per model call.
Parameters:
- clients (
list[LLMClientConfig]) – The configured clients, in priority order. - strategy (
Literal['single', 'fallback', 'round_robin']) – How to composeclients."single"ignores all but the first client.
Returns:
list[Any]– Middleware for create_deep_agent/create_agent; empty when therelist[Any]– is nothing to compose.
Raises:
UnsupportedAgentProviderError– a client's provider has no agent-side mapping.
agrag.agents.prompts
Agent prompt templates for planner, researcher, verifier.
Attributes:
agrag.agents.prompts.PLANNER_SYSTEM
PLANNER_SYSTEM = 'You are a research planner. Given a user question, decompose it into 2-4 focused sub-questions that a researcher can answer by searching a knowledge graph. Each sub-question should be specific and answerable independently.\n\nReturn your sub-questions as a numbered list.'
agrag.agents.prompts.RESEARCHER_SYSTEM
RESEARCHER_SYSTEM = 'You are a researcher with access to a knowledge graph. Use the available tools to find evidence for each sub-question. Cite every claim with the citation keys (E1, C3, etc.) returned by tools. Base your answer only on evidence found through tools, not on general knowledge.\n\nWhen you have gathered enough evidence, provide a concise answer with citations.'
agrag.agents.prompts.VERIFIER_SYSTEM
VERIFIER_SYSTEM = "You are an evidence verifier. Given a question, a set of sub-questions, and the researcher's evidence, check:\n1. Every sub-question has at least one citation.\n2. Every citation key resolves to real evidence.\n3. The answer directly addresses the original question.\n\nIf evidence is sufficient, say PASS. If not, list what is missing."
agrag.agents.settings
Env-backed LLM and loop config for the agent layer.
Classes:
- AgentLLMSettings – LLM client config for the agent's own reasoning turns.
- AgentSettings – Configuration for the agent loop itself.
agrag.agents.settings.AgentLLMSettings
Bases: BaseSettings
LLM client config for the agent's own reasoning turns.
Mirrors ExtractionLLMSettings for the agent role: same shape, same from_openai_compatible_env() convention, because the agent's model and the extraction model are configured the same way even though the agent calls its model through LangChain, not BAML.
Attributes:
- clients (
list[LLMClientConfig]) – The LLM client(s) to use. One element for a single provider; more than one composed per strategy through agent middleware. - strategy (
Literal['single', 'fallback', 'round_robin']) – How to compose multiple clients."fallback"tries the other clients in order when a model call fails;"round_robin"rotates across all clients per call. Ignored with one client.
Env prefix: AGENT_LLM_.
Functions:
- from_openai_compatible_env – Build settings from OpenAI-compatible env vars.
agrag.agents.settings.AgentLLMSettings.clients
clients: list[LLMClientConfig]
agrag.agents.settings.AgentLLMSettings.from_openai_compatible_env
from_openai_compatible_env() -> AgentLLMSettings
Build settings from OpenAI-compatible env vars.
Loads .env first, then reads AGENT_LLM_BASE_URL,
AGENT_LLM_API_KEY, and AGENT_LLM_MODEL_ID. When the
agent-specific variables are unset, the shared LLM_*
convenience variables used by the extraction role stand in, so
one .env can configure every LLM-backed role. The model
name defaults to gpt-4o-mini when neither variable names
one.
Returns:
AgentLLMSettings– AgentLLMSettings with one openai-generic client.
agrag.agents.settings.AgentLLMSettings.model_config
model_config = SettingsConfigDict(env_prefix='AGENT_LLM_', env_file='.env', extra='ignore')
agrag.agents.settings.AgentLLMSettings.strategy
strategy: Literal['single', 'fallback', 'round_robin'] = 'single'
agrag.agents.settings.AgentSettings
Bases: BaseSettings
Configuration for the agent loop itself.
Attributes:
- recursion_limit (
int) – The maximum LangGraph step count before the loop stops and reports incomplete progress.
Env prefix: AGENT_.
agrag.agents.settings.AgentSettings.model_config
model_config = SettingsConfigDict(env_prefix='AGENT_', env_file='.env', extra='ignore')
agrag.agents.settings.AgentSettings.recursion_limit
recursion_limit: int = 50
agrag.agents.subagents
Subagent definitions: planner, researcher, verifier.
Functions:
- make_planner_prompt – Return the planner subagent config.
- make_researcher_prompt – Return the researcher subagent config.
- make_verifier_prompt – Return the verifier subagent config.
agrag.agents.subagents.make_planner_prompt
make_planner_prompt() -> dict[str, Any]
Return the planner subagent config.
Returns:
agrag.agents.subagents.make_researcher_prompt
make_researcher_prompt() -> dict[str, Any]
Return the researcher subagent config.
Returns:
agrag.agents.subagents.make_verifier_prompt
make_verifier_prompt() -> dict[str, Any]
Return the verifier subagent config.
Returns:
agrag.agents.tools
Agent tools: thin wrappers calling SearchEngine with fixed Recipes.
Each tool is a LangChain-compatible callable that deepagents can register. Tools are named for what the agent is trying to find out, not for the retrieval method they use.
Functions:
- make_tools – Build the agent's tool set over one SearchEngine and Ledger.
agrag.agents.tools.make_tools
make_tools(engine:'SearchEngine', ledger:'Ledger', *, filters:'SearchFilters | None' = None) -> list[Any]
Build the agent's tool set over one SearchEngine and Ledger.
Parameters:
- engine (
'SearchEngine') – The SearchEngine every tool calls. - ledger (
'Ledger') – The citation ledger for one run. - filters (
'SearchFilters | None') – Retrieval scope applied to every tool's search. Pass document or tenant constraints here so the agent cannot surface graph data outside them; the LLM never sees or chooses the scope.
Returns:
list[Any]– A list of LangChain tool instances: search_source_text,list[Any]– look_up_entity, find_connection, explore_related, andlist[Any]– answer_from_graph_structure.
agrag.chunking
Chunking helpers for the ingestion layer.
This module isolates the chonkie dependency to one import site, so the rest of the codebase (and tests) can build a chunker without importing chonkie directly.
Modules:
- text – Splits a text Document into Chunks with the chonkie chunker.
Classes:
- RecursiveChunker – Chunker that recursively splits text into smaller chunks, based on the provided RecursiveRules.
Functions:
- default_chunker – Build the default text chunker.
agrag.chunking.RecursiveChunker
RecursiveChunker(tokenizer:Union[str, TokenizerProtocol] = 'character', chunk_size:int = 2048, rules:RecursiveRules = RecursiveRules(), min_characters_per_chunk:int = 24) -> None
Bases: BaseChunker
Chunker that recursively splits text into smaller chunks, based on the provided RecursiveRules.
Parameters:
- tokenizer (
Union[str, TokenizerProtocol]) – Tokenizer to use - chunk_size (
int) – Maximum size of each chunk. - rules (
RecursiveRules) – Recursive rules to use for chunking. - min_characters_per_chunk (
int) – Minimum number of characters per chunk.
Functions:
- achunk – Chunk the given text asynchronously.
- achunk_batch – Chunk a batch of texts asynchronously.
- achunk_document – Chunk a document asynchronously.
- chunk – Recursively chunk text.
- chunk_batch – Chunk a batch of texts.
- chunk_document – Chunk a document.
- from_recipe – Create a RecursiveChunker object from a recipe.
Attributes:
- chunk_size –
- min_characters_per_chunk –
- rules –
- sep –
- tokenizer (
AutoTokenizer) – Get the tokenizer instance.
Parameters:
- tokenizer (
Union[str, TokenizerProtocol]) – Tokenizer to use - chunk_size (
int) – Maximum size of each chunk. - rules (
RecursiveRules) – Recursive rules to use for chunking. - min_characters_per_chunk (
int) – Minimum number of characters per chunk.
Raises:
ValueError– If chunk_size <=0ValueError– If min_characters_per_chunk < 1ValueError– If rules is not a RecursiveRules object.
agrag.chunking.RecursiveChunker.achunk
achunk(text:str) -> list[Chunk]
Chunk the given text asynchronously.
Parameters:
- text (
str) – The text to chunk.
Returns:
agrag.chunking.RecursiveChunker.achunk_batch
achunk_batch(texts:Sequence[str], show_progress:bool = True) -> list[list[Chunk]]
Chunk a batch of texts asynchronously.
Parameters:
Returns:
agrag.chunking.RecursiveChunker.achunk_document
achunk_document(document:Document) -> Document
Chunk a document asynchronously.
Parameters:
- document (
Document) – The document to chunk.
Returns:
Document– The document with chunks populated.
agrag.chunking.RecursiveChunker.chunk
chunk(text:str) -> list[Chunk]
Recursively chunk text.
Parameters:
- text (
str) – Text to chunk.
agrag.chunking.RecursiveChunker.chunk_batch
chunk_batch(texts:Sequence[str], show_progress:bool = True) -> list[list[Chunk]]
Chunk a batch of texts.
Parameters:
Returns:
agrag.chunking.RecursiveChunker.chunk_document
chunk_document(document:Document) -> Document
Chunk a document.
After chunking, non-empty document.metadata is shallow-merged into each
chunk's :attr:~chonkie.types.Chunk.metadata (chunk keys override on conflict).
Parameters:
- document (
Document) – The document to chunk.
Returns:
Document– The document with chunks populated.
agrag.chunking.RecursiveChunker.chunk_size
chunk_size = chunk_size
agrag.chunking.RecursiveChunker.from_recipe
from_recipe(name:Optional[str] = 'default', lang:Optional[str] = 'en', path:str | PathLike | None = None, tokenizer:Union[str, TokenizerProtocol] = 'character', chunk_size:int = 2048, min_characters_per_chunk:int = 24) -> RecursiveChunker
Create a RecursiveChunker object from a recipe.
The recipes are registered in the Chonkie Recipe Store. If the recipe is not there, you can create your own recipe and share it with the community!
Parameters:
- name (
Optional[str]) – The name of the recipe. - lang (
Optional[str]) – The language that the recursive chunker should support. - path (
Optional[str]) – The path to the recipe. - tokenizer (
Union[str, TokenizerProtocol]) – The tokenizer to use. - chunk_size (
int) – The chunk size. - min_characters_per_chunk (
int) – The minimum number of characters per chunk.
Returns:
- RecursiveChunker (
RecursiveChunker) – The RecursiveChunker object.
Raises:
ValueError– If the recipe is not found.
agrag.chunking.RecursiveChunker.min_characters_per_chunk
min_characters_per_chunk = min_characters_per_chunk
agrag.chunking.RecursiveChunker.rules
rules = rules
agrag.chunking.RecursiveChunker.sep
sep = '✄'
agrag.chunking.RecursiveChunker.tokenizer
tokenizer: AutoTokenizer
Get the tokenizer instance.
agrag.chunking.default_chunker
default_chunker(chunk_size:int = 1024) -> RecursiveChunker
Build the default text chunker.
Parameters:
- chunk_size (
int) – The maximum number of characters per chunk.
Returns:
RecursiveChunker– A character-based recursive chunker.
agrag.chunking.text
Splits a text Document into Chunks with the chonkie chunker.
Functions:
- chunk_document – Split a document's text into chunks.
- iter_chunk_documents – Chunk a stream of documents into a flat stream of chunks.
agrag.chunking.text.chunk_document
chunk_document(document:Document, chunker:RecursiveChunker) -> list[Chunk]
Split a document's text into chunks.
This function computes line_start and line_end from each chunk's character
span,
because the chunker does not report line numbers. It also sets heading_path from
the
document's heading outline.
Parameters:
- document (
Document) – The document to split. This function reads only itstextandheading_outlinefields. - chunker (
RecursiveChunker) – The chunker to run.
Returns:
agrag.chunking.text.iter_chunk_documents
iter_chunk_documents(documents:Iterator[Document], chunker:RecursiveChunker) -> Iterator[Chunk]
Chunk a stream of documents into a flat stream of chunks.
Parameters:
- documents (
Iterator[Document]) – The documents to chunk, in order. - chunker (
RecursiveChunker) – The chunker to run on each document.
Yields:
Chunk– Each chunk, in document then chunk order.
agrag.cypher
Cypher query builders for graph stores.
Leaf modules only: nothing here imports agrag.graphdb, so the dependency
points one way (store -> cypher).
Modules:
- entities – Cypher builders for node writes and filters.
- merge – Cypher for the tombstone/transfer/dedup merge path.
- relations – Cypher builders for relationship writes and graph traversal.
- safety – Safety gate for generated Cypher queries.
- schema – Cypher builders for constraints and native vector indexes.
agrag.cypher.entities
Cypher builders for node writes and filters.
Leaf module: imports nothing from agrag.graphdb or other store packages, so
the dependency points one way (store -> cypher).
Functions:
- clear_chunk_embedding_query – Build Cypher removing a vector property from Chunk nodes.
- clear_property_query – Build Cypher removing one property from a batch of nodes, guarded by text.
- fetch_all_by_label_query – Build Cypher paginating every node with label, for consolidate().
- fetch_by_merge_keys_query – Build Cypher for a batched exact-match lookup by merge key.
- fetch_relations_between_query – Build Cypher for batched lookup of existing relations by endpoints.
- filter_clause – Build a Cypher WHERE clause and parameters from a flat-dict filter.
- hydrate_chunks_by_id_query – Build Cypher fetching chunks by id.
- hydrate_entities_by_id_query – Build Cypher fetching entities by id, excluding tombstones.
- is_safe_identifier – Report whether a label or relationship type is a safe Cypher identifier.
- merge_key_index_query – Build a CREATE INDEX query on the node merge_key property.
- resolve_merged_into_query – Return a node and the id of the node it was merged into.
- set_chunk_embedding_query – Build Cypher setting a vector property on Chunk nodes.
- set_embedding_query – Build Cypher setting one vector property per node, guarded by its text.
- upsert_merge_alias_query – Build Cypher recording every accepted merge_key's owning entity id.
- upsert_node_query – Build the Cypher for an UNWIND-batched node upsert.
- upsert_survivor_query – Build Cypher upserting a merge survivor with atomic accumulation.
- validate_identifier – Check that a label or relationship type is a safe Cypher identifier.
Attributes:
agrag.cypher.entities.MERGE_ALIAS_LABEL
MERGE_ALIAS_LABEL = '_AgragMergeAlias'
agrag.cypher.entities.NODE_IDENTITY_LABEL
NODE_IDENTITY_LABEL = '_AgragNode'
agrag.cypher.entities.clear_chunk_embedding_query
clear_chunk_embedding_query(vector_property:str) -> str
Build Cypher removing a vector property from Chunk nodes.
Guards on text the same way set_chunk_embedding_query does,
so a concurrent update that changed a chunk's text between this
call's embed and its clear does not accidentally wipe a newer
vector.
Parameters:
- vector_property (
str) – The property to remove. Must already be validated.
Returns:
str– Parameterized Cypher expecting $records, a list of dicts withstr– the keys id and expected_text.
agrag.cypher.entities.clear_property_query
clear_property_query(property_name:str) -> str
Build Cypher removing one property from a batch of nodes, guarded by text.
Used to drop a stale value rather than leave it readable after a write
that was supposed to replace it fails partway through, such as an
embedding vector left over from before an entity's text changed. The
same name/description guard as set_embedding_query applies:
a record only clears the property if the node's text still matches what
this call started with, so it cannot wipe a vector a newer, still-in-
flight call has already written for different text.
Parameters:
- property_name (
str) – The property to remove. Must already be validated.
Returns:
str– Parameterized Cypher expecting $records, a list of dicts with the keysstr– id, expected_name, and expected_description.
agrag.cypher.entities.fetch_all_by_label_query
fetch_all_by_label_query(label:str) -> str
Build Cypher paginating every node with label, for consolidate().
Parameters:
- label (
str) – The node label. Must already be validated.
Returns:
str– Parameterized Cypher expecting $skip and $limit.
agrag.cypher.entities.fetch_by_merge_keys_query
fetch_by_merge_keys_query() -> str
Build Cypher for a batched exact-match lookup by merge key.
Resolves through the merge-key alias table (MERGE_ALIAS_LABEL)
rather than matching each node's own merge_key property directly:
that property is cleared when a node is tombstoned (see
clear_tombstone_merge_keys_query), so a name it once held would
otherwise become unreachable. The alias always points at the entity id
that first held the key, which may itself now be a tombstone; the caller
follows its merged_into chain to the live survivor.
merge_key is returned alongside n so the caller can map a row
back to the mention(s) that queried it without re-deriving a key from
the resolved entity's current name: an accepted alias (see
upsert_merge_alias_query) can name an entity by something other
than its current canonical name, so re-deriving would silently fail to
map those mentions back.
Returns:
str– Parameterized Cypher expecting $merge_keys (list of strings).
agrag.cypher.entities.fetch_relations_between_query
fetch_relations_between_query(rel_type:str) -> str
Build Cypher for batched lookup of existing relations by endpoints.
Parameters:
- rel_type (
str) – The relationship type. Must already be validated.
Returns:
str– Parameterized Cypher expecting $pairs (list ofstr–{source_id, target_id}). Returns each match's id andstr– source_chunk_ids alongside the pair it matched.
agrag.cypher.entities.filter_clause
filter_clause(filters:dict[str, Any], node_var:str = 'node') -> tuple[str, dict[str, Any]]
Build a Cypher WHERE clause and parameters from a flat-dict filter.
Parameters:
- filters (
dict[str, Any]) – A flat-dict filter: a scalar value means exact match, a list value means any of, and all keys are AND-ed together. - node_var (
str) – The Cypher variable bound to the node in the surrounding query.
Returns:
str– TheWHEREclause text (beginning withWHEREwhenfiltersisdict[str, Any]– non-empty, otherwise an empty string) and the parameter dict to passtuple[str, dict[str, Any]]– with it.
agrag.cypher.entities.hydrate_chunks_by_id_query
hydrate_chunks_by_id_query() -> str
Build Cypher fetching chunks by id.
Chunks are never tombstoned, so no merged_into guard is needed. The query filters on the Chunk label for type safety.
Returns:
str– Parameterized Cypher expecting $ids (list of string ids).
agrag.cypher.entities.hydrate_entities_by_id_query
hydrate_entities_by_id_query() -> str
Build Cypher fetching entities by id, excluding tombstones.
A tombstoned node is never deleted (ADR 0033) so a naive
MATCH (n) WHERE n.id IN $ids would surface one. This query
filters on merged_into IS NULL to return only live nodes.
Returns:
str– Parameterized Cypher expecting $ids (list of string ids).
agrag.cypher.entities.is_safe_identifier
is_safe_identifier(value:str) -> bool
Report whether a label or relationship type is a safe Cypher identifier.
A non-raising counterpart to validate_identifier, for filtering a
batch of names (for example ones read back from the database) rather
than validating one name a caller must supply correctly.
Parameters:
- value (
str) – The label or relationship type to check.
Returns:
bool–Trueifvalueis a safe identifier.
agrag.cypher.entities.merge_key_index_query
merge_key_index_query(label:str) -> str
Build a CREATE INDEX query on the node merge_key property.
Backs the global exact-match lookup.
Parameters:
- label (
str) – The node label. Must already be validated.
Returns:
str– A Cypher query creating the range index if absent.
agrag.cypher.entities.resolve_merged_into_query
resolve_merged_into_query() -> str
Return a node and the id of the node it was merged into.
A tombstoned node is never deleted; it only gains a merged_into
property pointing at its survivor (ADR 0033). The pointer is a
property, not a relationship, so a chain is followed one hop per
call: merged_into is null on a live node and holds the next id
on a tombstone.
Returns:
str– A parameterized query expecting an $id parameter, returning thestr– node asnodeand its survivor id asmerged_into.
agrag.cypher.entities.set_chunk_embedding_query
set_chunk_embedding_query(vector_property:str) -> str
Build Cypher setting a vector property on Chunk nodes.
Similar to set_embedding_query but guards on text instead of
name/description, since chunks have no name field. The text
guard prevents a stale write from overwriting a newer vector.
Parameters:
- vector_property (
str) – The property to set. Must already be validated.
Returns:
str– Parameterized Cypher expecting $records, a list of dicts with thestr– keys id, vector, and expected_text.
agrag.cypher.entities.set_embedding_query
set_embedding_query(vector_property:str) -> str
Build Cypher setting one vector property per node, guarded by its text.
Touches only vector_property, unlike a full node upsert: another
write can update an entity's provenance or properties while its new
embedding is being computed, and overwriting the whole node from a
snapshot taken before that update would discard it along with
delivering the vector. The name/description match is an
optimistic-concurrency guard: a record only applies if the node's text
still matches what its vector was computed from, so a slower write from
an older call cannot overwrite a newer one's vector with a stale one.
Also requires merged_into IS NULL: a concurrent merge can tombstone
the node -- clearing this same property -- after this call already read
its text and started embedding, but before this write lands. Without
this guard, the write would restore a vector on an absorbed entity
purely because its name/description happened not to change, putting it
back in native vector search. tombstone_query sets merged_into
and removes the embedding in the same write, so this guard racing that
one always sees them change together.
Parameters:
- vector_property (
str) – The property to set. Must already be validated.
Returns:
str– Parameterized Cypher expecting $records, a list of dicts with the keysstr– id, vector, expected_name, and expected_description.
agrag.cypher.entities.upsert_merge_alias_query
upsert_merge_alias_query() -> str
Build Cypher recording every accepted merge_key's owning entity id.
Every apply_merge call writes one of these for each merge_key the
merge accepted -- the survivor's own current name, but also every other
name (mention text or absorbed entity's name) resolution folded into
it -- so a later mention of any of those names resolves back to this
entity instead of creating a duplicate. ON CREATE SET only claims a
merge_key that has no alias yet: if resolution in some other merge
already accepted this same key for a different entity, that entity
keeps it. Without this, a resolution decision in one add() call
could silently steal a name an unrelated entity already owns.
Once created, an alias is never rewritten to point elsewhere: if the
entity it names is later itself absorbed, fetch_by_merge_keys_query's
caller follows that entity's merged_into chain from here instead of
this table being kept in sync with every later merge.
The returned rows are what let a caller detect the case ON CREATE SET alone cannot: an accepted merge_key already owned by some other
live entity, not one this same merge is writing or absorbing. Neither
entity's own node merge_key collides in that case, so nothing at the
database level rejects the write; the caller must compare each row's
entity_id against its own survivor and tombstone ids itself.
Returns:
str– Parameterized Cypher expecting $merge_keys (list of strings) andstr– $entity_id. Returns each merge_key alongside the entity_id that nowstr– owns it -- $entity_id when this call claimed or already owned it,str– another entity's id when a different one claimed it first.
agrag.cypher.entities.upsert_node_query
upsert_node_query(labels:Sequence[str]) -> str
Build the Cypher for an UNWIND-batched node upsert.
MERGE identity is anchored to NODE_IDENTITY_LABEL, not to labels
itself, so a node keeps resolving to the same id regardless of what
labels it currently carries. labels is then applied additively with
SET, which is idempotent (a label the node already has is a no-op)
and never removes a label a previous upsert of the same id set but this
one omits: labels only ever accumulate. Every node in one call gets the
same additive label set, since Cypher requires labels to be literal in
the query text rather than a runtime parameter; nodes whose
NodeRecord.labels differ need separate calls, one per distinct label
set (see Neo4jGraphStore.upsert_nodes for how a mixed batch is
grouped and split before reaching this builder).
Identity is reasserted after applying properties, so a caller-supplied
properties["id"] cannot overwrite the id used to MERGE and
orphan the node from later upserts of the same record.
Parameters:
- labels (
Sequence[str]) – The node's labels to add, in addition to the identity anchor. Must already be validated, and non-empty.
Returns:
str– A parameterized Cypher query expecting a$recordslist parameter.
Raises:
ValueError–labelsis empty, or any label is not a safe identifier.
agrag.cypher.entities.upsert_survivor_query
upsert_survivor_query(label:str) -> str
Build Cypher upserting a merge survivor with atomic accumulation.
Unlike upsert_node_query's plain SET n += record.properties
overwrite, source_chunk_ids and merged_from are unioned against
whatever the node currently has, and merge_count is incremented by a
delta, all read and written inside this one query. Two concurrent
callers merging into the same entity each read the node's current
accumulator values fresh here, so neither's contribution is lost to
whichever write lands second -- unlike overwriting from a full snapshot
taken before either write landed. Every other property is still applied
as-is (last write wins); resolving a conflict there needs the candidate
values, which only a Python-side read can gather, so making that
atomic too is out of scope here.
Parameters:
- label (
str) – The node label. Must already be validated.
Returns:
str– A parameterized Cypher query expecting a$recordsliststr– parameter whose items carryid,properties(every survivorstr– field exceptsource_chunk_ids,merged_from, andstr–merge_count),new_source_chunk_ids,new_merged_from, andstr–merge_count_delta.
agrag.cypher.entities.validate_identifier
validate_identifier(value:str) -> str
Check that a label or relationship type is a safe Cypher identifier.
Parameters:
- value (
str) – The label or relationship type to check.
Returns:
str–valueunchanged, once validated.
Raises:
ValueError–valueis not a safe identifier.
agrag.cypher.merge
Cypher for the tombstone/transfer/dedup merge path.
Functions:
- apply_relationship_dedup_delete_query – Build Cypher deleting relationships a dedup pass superseded.
- apply_relationship_dedup_update_query – Build Cypher applying a kept relationship's merged properties.
- clear_tombstone_merge_keys_query – Build Cypher removing merge_key from nodes about to be absorbed.
- delete_internal_relationships_query – Build Cypher deleting edges that would become meaningless self-links.
- fetch_node_relationships_query – Build Cypher fetching one direction of a node's own relationships.
- tombstone_query – Build Cypher marking one or more nodes as merged, never deleting them.
- transfer_relationships_query – Build Cypher moving one direction of a tombstoned node's relationships.
agrag.cypher.merge.apply_relationship_dedup_delete_query
apply_relationship_dedup_delete_query() -> str
Build Cypher deleting relationships a dedup pass superseded.
Returns:
agrag.cypher.merge.apply_relationship_dedup_update_query
apply_relationship_dedup_update_query() -> str
Build Cypher applying a kept relationship's merged properties.
Returns:
str– Parameterized Cypher expecting $updates (list ofstr–{id, rel_type, properties}), where properties is the full mergedstr– property map -- not just source_chunk_ids -- so a duplicate's otherstr– fields are not silently dropped when its edge is deleted.
agrag.cypher.merge.clear_tombstone_merge_keys_query
clear_tombstone_merge_keys_query(label:str) -> str
Build Cypher removing merge_key from nodes about to be absorbed.
Must run before upsert_survivor_query writes the survivor, not after
tombstone_query: canonical selection can choose a different node as
survivor than the one a property rule (e.g. KEEP_FIRST) resolves the
name from, so the survivor's resolved merge_key can equal a still-live
tombstone's own merge_key. Writing the survivor first would then collide
with the per-label merge_key uniqueness constraint, since both nodes
would briefly hold the same value.
Parameters:
- label (
str) – The node label. Must already be validated.
Returns:
str– Parameterized Cypher expecting $tombstone_ids.
agrag.cypher.merge.delete_internal_relationships_query
delete_internal_relationships_query() -> str
Build Cypher deleting edges that would become meaningless self-links.
Covers two cases, both before any transfer runs, inside the same transaction as the merge:
- An edge between two absorbed nodes: left untransferred, it would
become a stale
survivor->tombstoneedge after the first transfer. - An edge directly between an absorbed node and its own survivor:
transfer_relationships_queryexcludes these (other.id <> $survivor_id), since transferring one would create asurvivor->survivorself-loop that no relation type's semantics call for. Deleting them here, in both directions, is what keeps them from being silently orphaned on the tombstone instead.
Returns:
agrag.cypher.merge.fetch_node_relationships_query
fetch_node_relationships_query(*, outgoing:bool) -> str
Build Cypher fetching one direction of a node's own relationships.
Run against the survivor after every transfer completes, so the dedup pass that follows sees the survivor's whole neighbourhood in that direction -- both freshly transferred edges and ones it already had -- rather than only what one transfer call happened to move.
Parameters:
- outgoing (
bool) – True fetches (node)-[r]->(other) edges. False fetches (other)-[r]->(node) edges.
Returns:
str– Parameterized Cypher expecting $node_id.
agrag.cypher.merge.tombstone_query
tombstone_query(label:str, *, vector_property:str) -> str
Build Cypher marking one or more nodes as merged, never deleting them.
Also removes vector_property: a native Neo4j vector index only covers
nodes that currently carry the indexed property, so dropping it takes the
tombstone out of vector search immediately, with no query-time filter and
no dependency on a later re-embed ever running against it.
Parameters:
- label (
str) – The node label. Must already be validated. - vector_property (
str) – The embedding property to remove. Must already be validated.
Returns:
str– Parameterized Cypher expecting $tombstone_ids and $survivor_id.
agrag.cypher.merge.transfer_relationships_query
transfer_relationships_query(*, outgoing:bool) -> str
Build Cypher moving one direction of a tombstoned node's relationships.
Parameters:
- outgoing (
bool) – True moves (tombstone)-[r]->(other) edges. False moves (other)-[r]->(tombstone) edges.
Returns:
str– Parameterized Cypher expecting $tombstone_id and $survivor_id.
agrag.cypher.relations
Cypher builders for relationship writes and graph traversal.
Leaf module: imports nothing from agrag.graphdb. See entities.py for the
identifier-validation contract shared by every Cypher builder.
Functions:
- bfs_expand_query – Build Cypher for BFS expansion from seed entity ids.
- chunks_mentioning_entities_query – Build Cypher finding chunks that mention given entities.
- entities_mentioned_in_chunks_query – Build Cypher finding entities mentioned by given chunks.
- upsert_relation_query – Build the Cypher for an UNWIND-batched relationship upsert.
agrag.cypher.relations.bfs_expand_query
bfs_expand_query(*, depth:int = 2, limit:int = 50, filters:dict[str, Any] | None = None, relation_types:Sequence[str] | None = None) -> tuple[str, dict[str, Any]]
Build Cypher for BFS expansion from seed entity ids.
Traverses outgoing relationships from a set of seed entities, bounded
by depth hops and limit total result nodes. The depth is
formatted into the query text (not a parameter) because Neo4j does
not accept a parameter for a variable-length relationship bound. It
must come from RetrievalSettings, never from user input.
relation_types restricts which relationships a traversal may
cross. Neo4j does not accept a parameter for relationship types
either, so each type is validated and formatted into the pattern.
depth is clamped to [1, 10] and limit to [1, 1000] so
misconfigured or malicious settings cannot produce unbounded
traversals. The clamp is applied here, closest to the Cypher
interpolation, so every caller benefits.
Result nodes are restricted to _AgragNode entities that are
not Chunk nodes: chunks are intermediate path nodes only,
never returned as BFS results.
Parameters:
- depth (
int) – The maximum BFS hops. Clamped to [1, 10]. - limit (
int) – The maximum number of result nodes. Clamped to [1, 1000]. - filters (
dict[str, Any] | None) – Optional flat-dict filter applied to neighbor nodes. A scalar value means exact match, a list means any of. - relation_types (
Sequence[str] | None) – Optional relationship types the traversal may cross. None or empty crosses every type.
Returns:
str– A(query, params)tuple. The query expects$seed_idsdict[str, Any]– (list of string ids) plus any filter parameters.
Raises:
ValueError– A relation type is not a safe Cypher identifier.
agrag.cypher.relations.chunks_mentioning_entities_query
chunks_mentioning_entities_query() -> str
Build Cypher finding chunks that mention given entities.
Walks the MENTIONED_IN edge from Chunk to Entity. Returns chunks that reference any of the given entity ids.
Returns:
str– Parameterized Cypher expecting $entity_ids (list of string ids).
agrag.cypher.relations.entities_mentioned_in_chunks_query
entities_mentioned_in_chunks_query() -> str
Build Cypher finding entities mentioned by given chunks.
Walks the MENTIONED_IN edge from Chunk to Entity in reverse. Returns entities referenced by any of the given chunk ids.
Returns:
str– Parameterized Cypher expecting $chunk_ids (list of string ids).
agrag.cypher.relations.upsert_relation_query
upsert_relation_query(rel_type:str) -> str
Build the Cypher for an UNWIND-batched relationship upsert.
Relationship identity is record.id, not the (start, end, type)
triple: two relationships of this type between the same nodes keep
separate identities when their ids differ, so parallel relationships do
not collapse into one. When a record's endpoints move, the relationship
keeps its id: the stale copy at the old endpoints is deleted before the
new one is written, backed by the per-type uniqueness constraint from
relation_id_constraint_query. A relationship's type is immutable once
written; retyping one requires deleting it under its old type first, since
a single upsert call only ever targets one type. Identity is reasserted
after applying properties, so a caller-supplied properties["id"]
cannot overwrite the id used to MERGE and orphan the relationship
from later upserts of the same record.
source_chunk_ids is unioned against whatever is already on the
relationship at write time, inside this same query, rather than blindly
overwritten: two concurrent callers upserting the same relationship each
compute their own union from a read taken before either write lands, so
without this, whichever caller's write commits second would silently
discard the chunk ids the other one contributed. Reading the current
value here, inside the same MERGE, keeps the union correct regardless of
which caller's read was stale.
Parameters:
- rel_type (
str) – The relationship type. Must already be validated.
Returns:
str– A parameterized Cypher query expecting a$recordslist parameter whosestr– items carryid,start_id,end_id, andpropertieskeys.str–propertiesmay includesource_chunk_ids; other keys arestr– applied as-is.
agrag.cypher.safety
Safety gate for generated Cypher queries.
Classes:
- UnsafeCypherError – Raised when a generated Cypher query contains a write clause.
Functions:
- reject_write_cypher – Raise fast on an obvious write clause, ahead of EXPLAIN.
- strip_cypher_syntax – Blank string literals, comments, and backtick identifiers.
agrag.cypher.safety.UnsafeCypherError
Bases: Exception
Raised when a generated Cypher query contains a write clause.
agrag.cypher.safety.reject_write_cypher
reject_write_cypher(query:str) -> None
Raise fast on an obvious write clause, ahead of EXPLAIN.
This is a cheap pre-filter, not the safety boundary: execute_read's read transaction is what actually prevents a write from running, since Neo4j itself rejects one there. This check exists so a write-shaped generated query fails immediately instead of spending an EXPLAIN round trip first.
Keywords are matched case-insensitively, and only outside string
literals, comments, and backtick identifiers, so a lowercase
delete or a quote inside a comment cannot desync the scan.
The check is conservative: a write keyword used as a property
name (e.g. RETURN n.set) is also rejected, acceptable for a
pre-filter that guards model-generated text.
Parameters:
- query (
str) – The Cypher text a BAML call produced.
Raises:
UnsafeCypherError– The query contains a write keyword outside a string literal, comment, or backtick identifier.
agrag.cypher.safety.strip_cypher_syntax
strip_cypher_syntax(query:str) -> str
Blank string literals, comments, and backtick identifiers.
Replaces the contents of string literals, // and /* */
comments, and backtick-quoted identifiers with spaces, keeping every
other character intact so token boundaries survive. Scans char by
char and honors backslash and doubled-quote escapes, so an escaped
quote inside a literal cannot close the scan early and let a real
keyword after it hide inside a bogus "string".
Parameters:
- query (
str) – The Cypher text to scrub.
Returns:
str– The query with literal, comment, and identifier content blanked,str– layout otherwise unchanged.
agrag.cypher.schema
Cypher builders for constraints and native vector indexes.
Leaf module: imports nothing from agrag.graphdb. See entities.py for the
identifier-validation contract shared by every Cypher builder.
Functions:
- merge_alias_constraint_query – Build a CREATE CONSTRAINT query making the merge-key alias table unique.
- merge_key_constraint_query – Build a CREATE CONSTRAINT query making
merge_keyunique per label. - node_id_constraint_query – Build a CREATE CONSTRAINT query making
idunique per node. - plain_index_query – Build a CREATE INDEX query on the node
idproperty. - relation_id_constraint_query – Build a CREATE CONSTRAINT query making
idunique per relationship type. - vector_index_name – Derive the deterministic name a vector index is created under.
- vector_index_query – Build a CREATE VECTOR INDEX query for native vector search.
- vector_search_query – Build a native vector search query and its filter parameters.
agrag.cypher.schema.merge_alias_constraint_query
merge_alias_constraint_query() -> str
Build a CREATE CONSTRAINT query making the merge-key alias table unique.
One global constraint, not per label: MERGE_ALIAS_LABEL is shared
across every entity type, and merge_key already embeds the label
(see Entity.merge_key), so a single uniqueness constraint on it is
sufficient.
Returns:
str– A Cypher query creating the uniqueness constraint if absent.
agrag.cypher.schema.merge_key_constraint_query
merge_key_constraint_query(label:str) -> str
Build a CREATE CONSTRAINT query making merge_key unique per label.
Backs the concurrent-ingestion safety tier: two concurrent add() calls
for the same (label, normalized name) cannot both create a canonical
node; the second fails the constraint and is resolved to the canonical via
the merge path. A node absorbed by a merge has its merge_key cleared
before it is marked merged_into, so the constraint permits one live
survivor per key plus any number of tombstones.
Parameters:
- label (
str) – The node label. Must already be validated.
Returns:
str– A Cypher query creating the uniqueness constraint if absent.
agrag.cypher.schema.node_id_constraint_query
node_id_constraint_query(label:str) -> str
Build a CREATE CONSTRAINT query making id unique per node.
Neo4j constraint names share one flat, global namespace regardless of
whether they apply to a node label or a relationship type, so this name
is kind-prefixed and length-prefixed the same way vector_index_name
is: label "X_rel" and relationship type "X" would otherwise both
produce X_rel_id_unique, and IF NOT EXISTS would then silently
leave the second one never created.
Parameters:
- label (
str) – The node label. Must already be validated.
Returns:
str– A Cypher query creating the uniqueness constraint if absent.
agrag.cypher.schema.plain_index_query
plain_index_query(label:str) -> str
Build a CREATE INDEX query on the node id property.
Parameters:
- label (
str) – The node label. Must already be validated.
Returns:
str– A Cypher query creating the range index if absent.
agrag.cypher.schema.relation_id_constraint_query
relation_id_constraint_query(rel_type:str) -> str
Build a CREATE CONSTRAINT query making id unique per relationship type.
This backs the stale-relationship lookup in upsert_relation_query with
an index and guarantees at most one relationship of rel_type carries a
given id. See node_id_constraint_query for why the name is
kind-prefixed and length-prefixed rather than a plain concatenation.
Parameters:
- rel_type (
str) – The relationship type. Must already be validated.
Returns:
str– A Cypher query creating the uniqueness constraint if absent.
agrag.cypher.schema.vector_index_name
vector_index_name(label:str, vector_property:str) -> str
Derive the deterministic name a vector index is created under.
Each component is length-prefixed so the encoding is unambiguous: a plain
join like f"{label}_{vector_property}_vector" would let a label and
property containing underscores collide, for example ("A_B", "C") and
("A", "B_C") both joining to "A_B_C_vector". A collision would
make ensure_vector_index reuse one index for two different label and
property pairs, and vector_search would then search the wrong nodes.
ensure_vector_index and vector_search both call this function, so
they always agree on the name.
Parameters:
- label (
str) – The node label. Must already be validated. - vector_property (
str) – The vector property name. Must already be validated.
Returns:
str– The index nameensure_vector_indexandvector_searchshare.
agrag.cypher.schema.vector_index_query
vector_index_query(label:str, vector_property:str, dimensions:int, distance:Distance) -> str
Build a CREATE VECTOR INDEX query for native vector search.
Parameters:
- label (
str) – The node label. Must already be validated. - vector_property (
str) – The vector property name. Must already be validated. - dimensions (
int) – The embedding dimension. - distance (
Distance) – The distance metric, mapped to Neo4j's similarity function.
Returns:
str– A Cypher query creating the vector index if absent.
Raises:
ValueError–distanceis not a metric Neo4j vector indexes support.
agrag.cypher.schema.vector_search_query
vector_search_query(index_name:str, filters:dict[str, Any] | None = None) -> tuple[str, dict[str, Any]]
Build a native vector search query and its filter parameters.
Parameters:
- index_name (
str) – The vector index name fromvector_index_name. - filters (
dict[str, Any] | None) – An optional flat-dict filter applied withWHERE.
Returns:
str– The Cypher query yieldingnodeandscore, and a parameter dictdict[str, Any]– holding only the filter parameters (the caller addsindex,k,tuple[str, dict[str, Any]]– andvector).
agrag.embedding
Text embedding: turn strings into dense vectors.
Modules:
- base – The Embedder and EmbeddingCache protocols.
- errors – Errors that the embedding layer raises.
- fastembed_bm25 – BM25 sparse embedder backed by FastEmbed.
- sentence_transformers – Sentence-transformers embedder implementation.
- settings – Settings for the sentence-transformers embedder.
- sparse_base – Sparse lexical vectors and the sparse embedder protocol.
Classes:
- Embedder – A component that turns text into dense embedding vectors.
- EmbeddingSettings – Sentence-transformers embedder configuration.
- FastEmbedBM25Embedder – A sparse BM25 embedder built on FastEmbed.
- SentenceTransformerEmbedder – An embedder backed by sentence-transformers.
- SparseEmbedder – A component that turns text into sparse lexical vectors, for hybrid search.
- SparseVector – A sparse vector: nonzero indices and their values.
Functions:
- build_embedder – Build an embedder from a model name, or return an embedder unchanged.
agrag.embedding.Embedder
Bases: ABC
A component that turns text into dense embedding vectors.
Functions:
- dimensions – Return the dimension of the vectors this embedder produces.
- embed – Embed a batch of texts.
- embed_one – Embed a single text.
Attributes:
- distance (
Distance) – Return the distance metric for vector indexes created for this embedder. - model (
str) –
agrag.embedding.Embedder.dimensions
dimensions() -> int
Return the dimension of the vectors this embedder produces.
Async because a lazily-loaded embedder may need to load its model to
answer, and that load must go through the same worker-thread/lock
path embed uses rather than blocking the event loop.
agrag.embedding.Embedder.distance
distance: Distance
Return the distance metric for vector indexes created for this embedder.
Defaults to cosine, which matches normalized sentence-transformer models. Concrete embedders may override when their vectors use a different metric.
agrag.embedding.Embedder.embed
embed(texts:Sequence[str]) -> list[list[float]]
Embed a batch of texts.
Parameters:
Returns:
agrag.embedding.Embedder.embed_one
embed_one(text:str) -> list[float]
Embed a single text.
Parameters:
- text (
str) – The text to embed.
Returns:
agrag.embedding.Embedder.model
model: str
agrag.embedding.EmbeddingSettings
Bases: BaseSettings
Sentence-transformers embedder configuration.
All fields are overridable via environment variables with the
EMBEDDING_ prefix.
Attributes:
- model (
str) – The sentence-transformers model name or path. Env:EMBEDDING_MODEL. - device (
str | None) – The device to load the model on, such as"cpu"or"cuda".Noneuses sentence-transformers' own default detection. Env:EMBEDDING_DEVICE. - normalize (
bool) – Whether to L2-normalize output vectors. Env:EMBEDDING_NORMALIZE. - batch_size (
int) – The number of texts encoded permodel.encodecall. Env:EMBEDDING_BATCH_SIZE. - cache_folder (
str | None) – Where sentence-transformers caches downloaded models.Noneuses the library default. Env:EMBEDDING_CACHE_FOLDER.
agrag.embedding.EmbeddingSettings.batch_size
batch_size: int = 32
agrag.embedding.EmbeddingSettings.cache_folder
cache_folder: str | None = None
agrag.embedding.EmbeddingSettings.device
device: str | None = None
agrag.embedding.EmbeddingSettings.model
model: str = 'ibm-granite/granite-embedding-small-english-r2'
agrag.embedding.EmbeddingSettings.model_config
model_config = SettingsConfigDict(env_prefix='EMBEDDING_', env_file='.env', extra='ignore')
agrag.embedding.EmbeddingSettings.normalize
normalize: bool = True
agrag.embedding.FastEmbedBM25Embedder
FastEmbedBM25Embedder(*, model:str | None = None) -> None
Bases: SparseEmbedder
A sparse BM25 embedder built on FastEmbed.
The model loads lazily on first embed, so constructing the embedder
does not download weights. Each blocking call into FastEmbed runs in a
worker thread, keeping the event loop free. FastEmbed ships with the
qdrant extra, so a clean install without that extra raises
EmbeddingMissingExtraError rather than ImportError.
Functions:
- embed – Embed a batch of documents into BM25 sparse vectors.
- query_embed – Embed a batch of search queries into BM25 sparse vectors.
Attributes:
Parameters:
- model (
str | None) – The FastEmbed BM25 model name. Defaults to FastEmbed's built-in BM25 model.
agrag.embedding.FastEmbedBM25Embedder.embed
embed(texts:Sequence[str]) -> list[SparseVector]
Embed a batch of documents into BM25 sparse vectors.
Applies FastEmbed's document-side term-frequency and length
normalization weighting. Use query_embed for search queries.
Parameters:
Returns:
list[SparseVector]– One sparse vector per input text, in the same order.
agrag.embedding.FastEmbedBM25Embedder.model
model: str
The configured model name, or the FastEmbed default when unset.
agrag.embedding.FastEmbedBM25Embedder.query_embed
query_embed(texts:Sequence[str]) -> list[SparseVector]
Embed a batch of search queries into BM25 sparse vectors.
Uses FastEmbed's query_embed, which assigns each unique query
term a uniform weight of 1.0 rather than the document-side
term-frequency and length-normalization weighting embed applies;
IDF weighting is applied separately by the sparse index's
Modifier.IDF at query time.
Parameters:
Returns:
list[SparseVector]– One sparse vector per input text, in the same order.
agrag.embedding.SentenceTransformerEmbedder
SentenceTransformerEmbedder(*, settings:EmbeddingSettings | None = None, cache:EmbeddingCache | None = None, model:object | None = None) -> None
Bases: Embedder
An embedder backed by sentence-transformers.
The model loads lazily on first embed, so constructing the embedder
does not touch the GPU or download weights. Every blocking call into the
model runs in a worker thread (asyncio.to_thread), so the event loop
stays free for other work while a large batch encodes.
Functions:
- dimensions – Return the dimension the loaded model produces.
- embed – Embed a batch of texts, using the cache where possible.
- embed_one – Embed a single text.
Attributes:
- distance (
Distance) – Return the distance metric for vector indexes created for this embedder. - model (
str) – The configured model name.
Parameters:
- settings (
EmbeddingSettings | None) – Embedder configuration. Defaults toEmbeddingSettings(). - cache (
EmbeddingCache | None) – An optional content-addressed cache. Defaults to a no-op cache. - model (
object | None) – A pre-built sentence-transformers model, for tests. When set,__init__imports nothing andembedcalls this object directly instead of building one.
agrag.embedding.SentenceTransformerEmbedder.dimensions
dimensions() -> int
Return the dimension the loaded model produces.
Calling this loads the model the first time, the same
lock-protected, worker-thread path embed uses, so it is safe to
call concurrently with embed without stalling the event loop or
loading a second copy of the model.
Raises:
EmbeddingMissingExtraError– sentence-transformers is not installed.
agrag.embedding.SentenceTransformerEmbedder.distance
distance: Distance
Return the distance metric for vector indexes created for this embedder.
Defaults to cosine, which matches normalized sentence-transformer models. Concrete embedders may override when their vectors use a different metric.
agrag.embedding.SentenceTransformerEmbedder.embed
embed(texts:Sequence[str]) -> list[list[float]]
Embed a batch of texts, using the cache where possible.
Parameters:
Returns:
agrag.embedding.SentenceTransformerEmbedder.embed_one
embed_one(text:str) -> list[float]
Embed a single text.
Parameters:
- text (
str) – The text to embed.
Returns:
agrag.embedding.SentenceTransformerEmbedder.model
model: str
The configured model name.
agrag.embedding.SparseEmbedder
Bases: ABC
A component that turns text into sparse lexical vectors, for hybrid search.
Functions:
- embed – Embed a batch of documents into sparse vectors.
- query_embed – Embed a batch of search queries into sparse vectors.
Attributes:
agrag.embedding.SparseEmbedder.embed
embed(texts:Sequence[str]) -> list[SparseVector]
Embed a batch of documents into sparse vectors.
Parameters:
Returns:
list[SparseVector]– One sparse vector per input text, in the same order.
agrag.embedding.SparseEmbedder.model
model: str
agrag.embedding.SparseEmbedder.query_embed
query_embed(texts:Sequence[str]) -> list[SparseVector]
Embed a batch of search queries into sparse vectors.
Query-side sparse embedding is not always the same computation as
document-side embedding: BM25, for example, applies term-frequency
and document-length normalization on the document side but only a
uniform per-term weight on the query side, since IDF weighting is
applied by the sparse index at query time instead. Implementations
with no such asymmetry may implement this identically to embed.
Parameters:
Returns:
list[SparseVector]– One sparse vector per input text, in the same order.
agrag.embedding.SparseVector
Bases: BaseModel
A sparse vector: nonzero indices and their values.
Attributes:
- indices (
list[int]) – The positions of nonzero entries. - values (
list[float]) – The weight at each index, aligned withindices.
agrag.embedding.SparseVector.indices
indices: list[int]
agrag.embedding.SparseVector.values
values: list[float]
agrag.embedding.base
The Embedder and EmbeddingCache protocols.
Classes:
- Embedder – A component that turns text into dense embedding vectors.
- EmbeddingCache – A content-addressed cache for embedding vectors.
- NullEmbeddingCache – A cache that never stores anything. The default when none is injected.
agrag.embedding.base.Embedder
Bases: ABC
A component that turns text into dense embedding vectors.
Functions:
- dimensions – Return the dimension of the vectors this embedder produces.
- embed – Embed a batch of texts.
- embed_one – Embed a single text.
Attributes:
- distance (
Distance) – Return the distance metric for vector indexes created for this embedder. - model (
str) –
agrag.embedding.base.Embedder.dimensions
dimensions() -> int
Return the dimension of the vectors this embedder produces.
Async because a lazily-loaded embedder may need to load its model to
answer, and that load must go through the same worker-thread/lock
path embed uses rather than blocking the event loop.
agrag.embedding.base.Embedder.distance
distance: Distance
Return the distance metric for vector indexes created for this embedder.
Defaults to cosine, which matches normalized sentence-transformer models. Concrete embedders may override when their vectors use a different metric.
agrag.embedding.base.Embedder.embed
embed(texts:Sequence[str]) -> list[list[float]]
Embed a batch of texts.
Parameters:
Returns:
agrag.embedding.base.Embedder.embed_one
embed_one(text:str) -> list[float]
Embed a single text.
Parameters:
- text (
str) – The text to embed.
Returns:
agrag.embedding.base.Embedder.model
model: str
agrag.embedding.base.EmbeddingCache
Bases: ABC
A content-addressed cache for embedding vectors.
normalize is part of the cache key alongside text and model
because it changes the vector an embedder produces for the same text and
model: without it, embedders sharing one cache but configured with
opposite EmbeddingSettings.normalize values would read back the wrong
output mode. Any future embedder setting that changes output values must
join this key the same way.
Functions:
- get – Return the cached vector for
(text, model, normalize). - set – Store
vectorunder(text, model, normalize).
agrag.embedding.base.EmbeddingCache.get
get(*, text:str, model:str, normalize:bool) -> list[float] | None
Return the cached vector for (text, model, normalize).
Returns:
agrag.embedding.base.EmbeddingCache.set
set(*, text:str, model:str, normalize:bool, vector:list[float]) -> None
Store vector under (text, model, normalize).
agrag.embedding.base.NullEmbeddingCache
Bases: EmbeddingCache
A cache that never stores anything. The default when none is injected.
Functions:
agrag.embedding.base.NullEmbeddingCache.get
get(*, text:str, model:str, normalize:bool) -> list[float] | None
Always miss.
agrag.embedding.base.NullEmbeddingCache.set
set(*, text:str, model:str, normalize:bool, vector:list[float]) -> None
Do nothing.
agrag.embedding.build_embedder
build_embedder(value:str | Embedder) -> Embedder
Build an embedder from a model name, or return an embedder unchanged.
Parameters:
- value (
str | Embedder) – A sentence-transformers model name, such as"ibm-granite/granite-embedding-small-english-r2"(the default model), or an already-constructedEmbedderfor full control over device, batching, or caching.
Returns:
Embedder– A ready-to-use embedder.
agrag.embedding.errors
Errors that the embedding layer raises.
Classes:
- EmbeddingDimensionMismatchError – A stored collection or index expects a different embedding dimension.
- EmbeddingError – The base class for every embedding error.
- EmbeddingMissingExtraError – An embedder exists, but its package extra is not installed.
agrag.embedding.errors.EmbeddingDimensionMismatchError
EmbeddingDimensionMismatchError(*, expected:int, actual:int) -> None
Bases: EmbeddingError
A stored collection or index expects a different embedding dimension.
Attributes:
- expected – The dimension the collection or index was created with.
- actual – The dimension the embedder actually produces.
agrag.embedding.errors.EmbeddingDimensionMismatchError.actual
actual = actual
agrag.embedding.errors.EmbeddingDimensionMismatchError.expected
expected = expected
agrag.embedding.errors.EmbeddingError
Bases: Exception
The base class for every embedding error.
agrag.embedding.errors.EmbeddingMissingExtraError
EmbeddingMissingExtraError(extra:str) -> None
Bases: EmbeddingError
An embedder exists, but its package extra is not installed.
Attributes:
- extra – The name of the package extra to install.
agrag.embedding.errors.EmbeddingMissingExtraError.extra
extra = extra
agrag.embedding.fastembed_bm25
BM25 sparse embedder backed by FastEmbed.
Classes:
- FastEmbedBM25Embedder – A sparse BM25 embedder built on FastEmbed.
Attributes:
agrag.embedding.fastembed_bm25.DEFAULT_BM25_MODEL
DEFAULT_BM25_MODEL = 'Qdrant/bm25'
agrag.embedding.fastembed_bm25.FastEmbedBM25Embedder
FastEmbedBM25Embedder(*, model:str | None = None) -> None
Bases: SparseEmbedder
A sparse BM25 embedder built on FastEmbed.
The model loads lazily on first embed, so constructing the embedder
does not download weights. Each blocking call into FastEmbed runs in a
worker thread, keeping the event loop free. FastEmbed ships with the
qdrant extra, so a clean install without that extra raises
EmbeddingMissingExtraError rather than ImportError.
Functions:
- embed – Embed a batch of documents into BM25 sparse vectors.
- query_embed – Embed a batch of search queries into BM25 sparse vectors.
Attributes:
Parameters:
- model (
str | None) – The FastEmbed BM25 model name. Defaults to FastEmbed's built-in BM25 model.
agrag.embedding.fastembed_bm25.FastEmbedBM25Embedder.embed
embed(texts:Sequence[str]) -> list[SparseVector]
Embed a batch of documents into BM25 sparse vectors.
Applies FastEmbed's document-side term-frequency and length
normalization weighting. Use query_embed for search queries.
Parameters:
Returns:
list[SparseVector]– One sparse vector per input text, in the same order.
agrag.embedding.fastembed_bm25.FastEmbedBM25Embedder.model
model: str
The configured model name, or the FastEmbed default when unset.
agrag.embedding.fastembed_bm25.FastEmbedBM25Embedder.query_embed
query_embed(texts:Sequence[str]) -> list[SparseVector]
Embed a batch of search queries into BM25 sparse vectors.
Uses FastEmbed's query_embed, which assigns each unique query
term a uniform weight of 1.0 rather than the document-side
term-frequency and length-normalization weighting embed applies;
IDF weighting is applied separately by the sparse index's
Modifier.IDF at query time.
Parameters:
Returns:
list[SparseVector]– One sparse vector per input text, in the same order.
agrag.embedding.sentence_transformers
Sentence-transformers embedder implementation.
Classes:
- SentenceTransformerEmbedder – An embedder backed by sentence-transformers.
agrag.embedding.sentence_transformers.SentenceTransformerEmbedder
SentenceTransformerEmbedder(*, settings:EmbeddingSettings | None = None, cache:EmbeddingCache | None = None, model:object | None = None) -> None
Bases: Embedder
An embedder backed by sentence-transformers.
The model loads lazily on first embed, so constructing the embedder
does not touch the GPU or download weights. Every blocking call into the
model runs in a worker thread (asyncio.to_thread), so the event loop
stays free for other work while a large batch encodes.
Functions:
- dimensions – Return the dimension the loaded model produces.
- embed – Embed a batch of texts, using the cache where possible.
- embed_one – Embed a single text.
Attributes:
- distance (
Distance) – Return the distance metric for vector indexes created for this embedder. - model (
str) – The configured model name.
Parameters:
- settings (
EmbeddingSettings | None) – Embedder configuration. Defaults toEmbeddingSettings(). - cache (
EmbeddingCache | None) – An optional content-addressed cache. Defaults to a no-op cache. - model (
object | None) – A pre-built sentence-transformers model, for tests. When set,__init__imports nothing andembedcalls this object directly instead of building one.
agrag.embedding.sentence_transformers.SentenceTransformerEmbedder.dimensions
dimensions() -> int
Return the dimension the loaded model produces.
Calling this loads the model the first time, the same
lock-protected, worker-thread path embed uses, so it is safe to
call concurrently with embed without stalling the event loop or
loading a second copy of the model.
Raises:
EmbeddingMissingExtraError– sentence-transformers is not installed.
agrag.embedding.sentence_transformers.SentenceTransformerEmbedder.distance
distance: Distance
Return the distance metric for vector indexes created for this embedder.
Defaults to cosine, which matches normalized sentence-transformer models. Concrete embedders may override when their vectors use a different metric.
agrag.embedding.sentence_transformers.SentenceTransformerEmbedder.embed
embed(texts:Sequence[str]) -> list[list[float]]
Embed a batch of texts, using the cache where possible.
Parameters:
Returns:
agrag.embedding.sentence_transformers.SentenceTransformerEmbedder.embed_one
embed_one(text:str) -> list[float]
Embed a single text.
Parameters:
- text (
str) – The text to embed.
Returns:
agrag.embedding.sentence_transformers.SentenceTransformerEmbedder.model
model: str
The configured model name.
agrag.embedding.settings
Settings for the sentence-transformers embedder.
Classes:
- EmbeddingSettings – Sentence-transformers embedder configuration.
agrag.embedding.settings.EmbeddingSettings
Bases: BaseSettings
Sentence-transformers embedder configuration.
All fields are overridable via environment variables with the
EMBEDDING_ prefix.
Attributes:
- model (
str) – The sentence-transformers model name or path. Env:EMBEDDING_MODEL. - device (
str | None) – The device to load the model on, such as"cpu"or"cuda".Noneuses sentence-transformers' own default detection. Env:EMBEDDING_DEVICE. - normalize (
bool) – Whether to L2-normalize output vectors. Env:EMBEDDING_NORMALIZE. - batch_size (
int) – The number of texts encoded permodel.encodecall. Env:EMBEDDING_BATCH_SIZE. - cache_folder (
str | None) – Where sentence-transformers caches downloaded models.Noneuses the library default. Env:EMBEDDING_CACHE_FOLDER.
agrag.embedding.settings.EmbeddingSettings.batch_size
batch_size: int = 32
agrag.embedding.settings.EmbeddingSettings.cache_folder
cache_folder: str | None = None
agrag.embedding.settings.EmbeddingSettings.device
device: str | None = None
agrag.embedding.settings.EmbeddingSettings.model
model: str = 'ibm-granite/granite-embedding-small-english-r2'
agrag.embedding.settings.EmbeddingSettings.model_config
model_config = SettingsConfigDict(env_prefix='EMBEDDING_', env_file='.env', extra='ignore')
agrag.embedding.settings.EmbeddingSettings.normalize
normalize: bool = True
agrag.embedding.sparse_base
Sparse lexical vectors and the sparse embedder protocol.
Classes:
- SparseEmbedder – A component that turns text into sparse lexical vectors, for hybrid search.
- SparseVector – A sparse vector: nonzero indices and their values.
agrag.embedding.sparse_base.SparseEmbedder
Bases: ABC
A component that turns text into sparse lexical vectors, for hybrid search.
Functions:
- embed – Embed a batch of documents into sparse vectors.
- query_embed – Embed a batch of search queries into sparse vectors.
Attributes:
agrag.embedding.sparse_base.SparseEmbedder.embed
embed(texts:Sequence[str]) -> list[SparseVector]
Embed a batch of documents into sparse vectors.
Parameters:
Returns:
list[SparseVector]– One sparse vector per input text, in the same order.
agrag.embedding.sparse_base.SparseEmbedder.model
model: str
agrag.embedding.sparse_base.SparseEmbedder.query_embed
query_embed(texts:Sequence[str]) -> list[SparseVector]
Embed a batch of search queries into sparse vectors.
Query-side sparse embedding is not always the same computation as
document-side embedding: BM25, for example, applies term-frequency
and document-length normalization on the document side but only a
uniform per-term weight on the query side, since IDF weighting is
applied by the sparse index at query time instead. Implementations
with no such asymmetry may implement this identically to embed.
Parameters:
Returns:
list[SparseVector]– One sparse vector per input text, in the same order.
agrag.embedding.sparse_base.SparseVector
Bases: BaseModel
A sparse vector: nonzero indices and their values.
Attributes:
- indices (
list[int]) – The positions of nonzero entries. - values (
list[float]) – The weight at each index, aligned withindices.
agrag.embedding.sparse_base.SparseVector.indices
indices: list[int]
agrag.embedding.sparse_base.SparseVector.values
values: list[float]
agrag.graphdb
Graph storage backends and the build shortcut.
Modules:
- base – The GraphStore abstraction and its build shortcut helpers.
- errors – Errors that the graph-store layer raises.
- neo4j – Neo4j graph-store backend.
- serialize – Convert graph records into Neo4j-driver-friendly parameters.
- settings – Settings for the Neo4j graph-store backend.
Classes:
- GraphStore – A graph database backend: schema, writes, and native vector search.
- GraphStoreError – The base class for every graph-store error.
- GraphStoreMissingExtraError – A graph store exists, but its package extra is not installed.
- Neo4jGraphStore – A
GraphStorebacked by Neo4j, using native vector indexes. - Neo4jSettings – Neo4j connection configuration.
Functions:
- build_graph_store – Build a graph store from a backend name, or return one unchanged.
Attributes:
agrag.graphdb.GraphStore
Bases: ABC
A graph database backend: schema, writes, and native vector search.
Functions:
- close – Release the backend connection.
- connect – Open the backend connection and verify connectivity.
- ensure_vector_index – Create a native vector index if it does not exist.
- execute_read – Run a read transaction.
- execute_write – Run a write transaction.
- register_labels – Mark labels as known, without writing anything.
- register_relation_types – Mark relationship types as known, without writing anything.
- session – Open a session as an async context manager.
- setup_constraints – Create per-label and per-relation-type uniqueness constraints.
- setup_indexes – Create per-label property indexes.
- transaction – Start an explicit transaction spanning multiple writes.
- upsert_nodes – Write or merge nodes, honoring each record's full label set.
- upsert_relations – Write or merge relationships between existing nodes.
- vector_search – Search nodes by dense vector.
agrag.graphdb.GraphStore.close
close() -> None
Release the backend connection.
agrag.graphdb.GraphStore.connect
connect() -> None
Open the backend connection and verify connectivity.
agrag.graphdb.GraphStore.ensure_vector_index
ensure_vector_index(*, label:str, vector_property:str, dimensions:int, distance:Distance) -> None
Create a native vector index if it does not exist.
Parameters:
- label (
str) – The node label to index. - vector_property (
str) – The embedding property name. - dimensions (
int) – The embedding dimension. - distance (
Distance) – The distance metric.
agrag.graphdb.GraphStore.execute_read
execute_read(query:str, parameters:Mapping[str, Any] | None = None, *, timeout:float | None = None) -> list[dict[str, Any]]
Run a read transaction.
Parameters:
- query (
str) – The Cypher query to run. - parameters (
Mapping[str, Any] | None) – The query parameters. - timeout (
float | None) – Server-side transaction timeout in seconds. The database terminates the transaction when it runs longer. None uses the server's default timeout. Backends that cannot enforce a timeout ignore it.
Returns:
agrag.graphdb.GraphStore.execute_write
execute_write(query:str, parameters:Mapping[str, Any] | None = None) -> list[dict[str, Any]]
Run a write transaction.
Parameters:
- query (
str) – The Cypher query to run. - parameters (
Mapping[str, Any] | None) – The query parameters.
Returns:
agrag.graphdb.GraphStore.register_labels
register_labels(labels:Sequence[str]) -> None
Mark labels as known, without writing anything.
setup_constraints()/setup_indexes() only cover labels this instance has already written (or that already exist live in the database) — both empty on a brand-new database. register_labels lets a caller holding a GraphSchema (Graph.open()) provision a fresh database fully before its first write.
Parameters:
Raises:
ValueError– Any label is not a safe identifier.
agrag.graphdb.GraphStore.register_relation_types
register_relation_types(types:Sequence[str]) -> None
Mark relationship types as known, without writing anything.
The relationship-type counterpart to register_labels — see its docstring for why this exists.
Parameters:
Raises:
ValueError– Any type is not a safe identifier.
agrag.graphdb.GraphStore.session
session() -> AbstractAsyncContextManager[Any]
Open a session as an async context manager.
Returns:
AbstractAsyncContextManager[Any]– A context manager yielding a backend session.
agrag.graphdb.GraphStore.setup_constraints
setup_constraints() -> None
Create per-label and per-relation-type uniqueness constraints.
Constraints cover every node label and relationship type written through this instance or already present in the database, so a fresh instance can set up an existing database without first rewriting every record.
agrag.graphdb.GraphStore.setup_indexes
setup_indexes() -> None
Create per-label property indexes.
Covers every node label written through this instance or already present in the database, so a fresh instance can set up an existing database without first rewriting every record.
agrag.graphdb.GraphStore.transaction
transaction() -> AsyncIterator[GraphStoreTransaction]
Start an explicit transaction spanning multiple writes.
Every call through the yielded handle should join one backend
transaction, committing as a whole on clean exit from the
async with block and rolling back as a whole if the block raises.
The default here simply yields self and gives no atomicity beyond
what each individual call already provides; a backend that can offer
real atomicity, such as Neo4jGraphStore, overrides this with a
driver transaction.
Use this when a caller must guarantee several writes either all apply
or none do, such as apply_merge's tombstone, relationship
transfer, and dedup steps.
Returns:
AsyncIterator[GraphStoreTransaction]– An async context manager yielding the transactional handle.
agrag.graphdb.GraphStore.upsert_nodes
upsert_nodes(label:str, nodes:Sequence[NodeRecord], *, batch_size:int = 256) -> None
Write or merge nodes, honoring each record's full label set.
Parameters:
- label (
str) – The label this batch is tracked under for constraint and index bookkeeping. - nodes (
Sequence[NodeRecord]) – The node records to upsert. Each node'sNodeRecord.labelsnames the full label set actually written to it, which may include labels beyondlabel. - batch_size (
int) – Records per backend write call, applied within each distinct label set whennodesmixes more than one. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.graphdb.GraphStore.upsert_relations
upsert_relations(relations:Sequence[RelationRecord], *, batch_size:int = 256) -> None
Write or merge relationships between existing nodes.
Parameters:
- relations (
Sequence[RelationRecord]) – The relation records to upsert. - batch_size (
int) – Records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.graphdb.GraphStore.vector_search
vector_search(*, label:str, vector_property:str, query_vector:Sequence[float], limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search nodes by dense vector.
Parameters:
- label (
str) – The node label to search. - vector_property (
str) – The embedding property name. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – Maximum number of hits. - filters (
dict[str, Any] | None) – An optional flat-dict filter on node properties.
Returns:
agrag.graphdb.GraphStoreError
Bases: Exception
The base class for every graph-store error.
agrag.graphdb.GraphStoreMissingExtraError
GraphStoreMissingExtraError(extra:str) -> None
Bases: GraphStoreError
A graph store exists, but its package extra is not installed.
Attributes:
- extra – The name of the package extra to install.
agrag.graphdb.GraphStoreMissingExtraError.extra
extra = extra
agrag.graphdb.GraphStoreName
GraphStoreName = Literal['neo4j']
agrag.graphdb.Neo4jGraphStore
Neo4jGraphStore(*, settings:Neo4jSettings | None = None, driver:AsyncDriver | None = None) -> None
Bases: GraphStore
A GraphStore backed by Neo4j, using native vector indexes.
The driver connects lazily on first use, so constructing the store does not
open a network connection. execute_read/execute_write wrap the
driver's managed transactions with no added retry loop, per ADR 0027.
Functions:
- close – Close the driver, releasing its connection pool.
- connect – Open the driver and verify connectivity.
- ensure_vector_index – Create a native vector index if it does not exist.
- execute_read – Run a read transaction and return its rows.
- execute_write – Run a write transaction and return its rows.
- register_labels – Add labels to this instance's known-label set.
- register_relation_types – Add types to this instance's known-relation-type set.
- session – Open a session to the configured database.
- setup_constraints – Create a uniqueness constraint on
idfor every known label. - setup_indexes – Create a range index on
idfor every known label. - transaction – Open one Neo4j explicit transaction spanning multiple writes.
- upsert_nodes – Write or merge nodes, honoring each record's full label set.
- upsert_relations – Write or merge relationships between existing nodes.
- vector_search – Search nodes by dense vector using the native vector index.
Parameters:
- settings (
Neo4jSettings | None) – Neo4j connection settings. Defaults toNeo4jSettings(). - driver (
AsyncDriver | None) – A pre-builtAsyncDriver, for tests. When set,__init__imports nothing and the store calls this object directly instead of building one.
agrag.graphdb.Neo4jGraphStore.close
close() -> None
Close the driver, releasing its connection pool.
agrag.graphdb.Neo4jGraphStore.connect
connect() -> None
Open the driver and verify connectivity.
agrag.graphdb.Neo4jGraphStore.ensure_vector_index
ensure_vector_index(*, label:str, vector_property:str, dimensions:int, distance:Distance) -> None
Create a native vector index if it does not exist.
agrag.graphdb.Neo4jGraphStore.execute_read
execute_read(query:str, parameters:Mapping[str, Any] | None = None, *, timeout:float | None = None) -> list[dict[str, Any]]
Run a read transaction and return its rows.
Parameters:
- query (
str) – The Cypher query to run. - parameters (
Mapping[str, Any] | None) – The query parameters. - timeout (
float | None) – Server-side transaction timeout in seconds, applied through the driver'sunit_of_workso the database terminates the transaction when it runs longer. None uses the server's default timeout.
Returns:
agrag.graphdb.Neo4jGraphStore.execute_write
execute_write(query:str, parameters:Mapping[str, Any] | None = None) -> list[dict[str, Any]]
Run a write transaction and return its rows.
Raises:
GraphStoreConstraintViolationError– The write violated a uniqueness constraint, translated from the driver's own exception so callers do not need a hard dependency on it.
agrag.graphdb.Neo4jGraphStore.register_labels
register_labels(labels:Sequence[str]) -> None
Add labels to this instance's known-label set.
Parameters:
Raises:
ValueError– Any label is not a safe identifier.
agrag.graphdb.Neo4jGraphStore.register_relation_types
register_relation_types(types:Sequence[str]) -> None
Add types to this instance's known-relation-type set.
Parameters:
Raises:
ValueError– Any type is not a safe identifier.
agrag.graphdb.Neo4jGraphStore.session
session() -> AbstractAsyncContextManager[Any]
Open a session to the configured database.
agrag.graphdb.Neo4jGraphStore.setup_constraints
setup_constraints() -> None
Create a uniqueness constraint on id for every known label.
"Known" means written by this instance or already present in the
database, so a fresh store can set up constraints for an existing
database without first rewriting every record. Also creates the
global uniqueness constraint on NODE_IDENTITY_LABEL that
upsert_node_query's MERGE relies on to resolve a node by id
regardless of its other, mutable labels, and a per-type uniqueness
constraint on id for every known relationship type, which backs
the stale-relationship cleanup upsert_relation_query performs on
endpoint changes.
agrag.graphdb.Neo4jGraphStore.setup_indexes
setup_indexes() -> None
Create a range index on id for every known label.
"Known" means written by this instance or already present in the database, so a fresh store can set up indexes for an existing database without first rewriting every record.
agrag.graphdb.Neo4jGraphStore.transaction
transaction() -> AsyncIterator[GraphStoreTransaction]
Open one Neo4j explicit transaction spanning multiple writes.
Commits when the async with block exits cleanly; rolls back and
re-raises when it raises. The identity constraint is ensured before
opening the transaction, the same way upsert_nodes ensures it
before writing, since _Neo4jTransaction.upsert_nodes skips that
check to avoid a nested write racing the transaction it belongs to.
Raises:
GraphStoreConstraintViolationError– A write inside the block, or the commit itself, violated a uniqueness constraint -- Neo4j validates some constraints only at commit time for an explicit transaction, so this can surface here even when every individual write appeared to succeed.
agrag.graphdb.Neo4jGraphStore.upsert_nodes
upsert_nodes(label:str, nodes:Sequence[NodeRecord], *, batch_size:int = 256) -> None
Write or merge nodes, honoring each record's full label set.
label names the batch for constraint/index bookkeeping, matching
every other tracked label; the labels actually written to a node come
from NodeRecord.labels, which may name more than one label (for
example a node that is both Chunk and Entity). Records with
different label sets are grouped and written with separate MERGE
queries, since Cypher requires labels to be literal in the query text
rather than a runtime parameter, so batch_size chunks apply within
each group rather than across the whole call.
Raises:
ValueError–batch_sizeis not positive.
agrag.graphdb.Neo4jGraphStore.upsert_relations
upsert_relations(relations:Sequence[RelationRecord], *, batch_size:int = 256) -> None
Write or merge relationships between existing nodes.
Relationship identity is each record's id, not its endpoints: see
upsert_relation_query for how endpoint changes and same-id
parallel relationships are handled.
Raises:
ValueError–batch_sizeis not positive.
agrag.graphdb.Neo4jGraphStore.vector_search
vector_search(*, label:str, vector_property:str, query_vector:Sequence[float], limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search nodes by dense vector using the native vector index.
A label with no provisioned vector index has nothing to search, so an absent index returns an empty result list rather than a driver error.
When filters is set, Neo4j's vector procedure applies the filter
only after selecting its top k candidates, so a plain k=limit
call can return fewer matches than actually exist. This escalates
k and retries until limit filtered hits come back or the
escalation reaches _VECTOR_SEARCH_MAX_K.
Raises:
ValueError–limitis not positive. A non-positive value is not a meaningful request and would send that same non-positivekto Neo4j's native vector procedure, which requires a positive top-k.
agrag.graphdb.Neo4jSettings
Bases: BaseSettings
Neo4j connection configuration.
Attributes:
- uri (
str) – The Bolt connection URI, including scheme (neo4j+s://for Aura). Env:NEO4J_URI. - username (
str) – The database username. Env:NEO4J_USERNAME. - password (
SecretStr) – The database password. Env:NEO4J_PASSWORD. - database (
str) – The target database name. Env:NEO4J_DATABASE. - max_connection_lifetime (
int) – The maximum seconds a pooled connection lives, kept well below Aura's roughly five-minute idle timeout. Env:NEO4J_MAX_CONNECTION_LIFETIME.
Raises:
ValueError–uriis plaintext (bolt://orneo4j://) and points at a non-local host. Neo4j always authenticates with a password, so a plaintext scheme always sends it in the clear; useneo4j+s://(orbolt+s://) for a remote instance.
agrag.graphdb.Neo4jSettings.database
database: str = 'neo4j'
agrag.graphdb.Neo4jSettings.max_connection_lifetime
max_connection_lifetime: int = 240
agrag.graphdb.Neo4jSettings.model_config
model_config = SettingsConfigDict(env_prefix='NEO4J_', env_file='.env', extra='ignore')
agrag.graphdb.Neo4jSettings.password
password: SecretStr = SecretStr('neo4j')
agrag.graphdb.Neo4jSettings.uri
uri: str = 'bolt://localhost:7687'
agrag.graphdb.Neo4jSettings.username
username: str = 'neo4j'
agrag.graphdb.base
The GraphStore abstraction and its build shortcut helpers.
Classes:
- GraphStore – A graph database backend: schema, writes, and native vector search.
- GraphStoreTransaction – The read/write/upsert surface available inside a
transaction()block.
agrag.graphdb.base.GraphStore
Bases: ABC
A graph database backend: schema, writes, and native vector search.
Functions:
- close – Release the backend connection.
- connect – Open the backend connection and verify connectivity.
- ensure_vector_index – Create a native vector index if it does not exist.
- execute_read – Run a read transaction.
- execute_write – Run a write transaction.
- register_labels – Mark labels as known, without writing anything.
- register_relation_types – Mark relationship types as known, without writing anything.
- session – Open a session as an async context manager.
- setup_constraints – Create per-label and per-relation-type uniqueness constraints.
- setup_indexes – Create per-label property indexes.
- transaction – Start an explicit transaction spanning multiple writes.
- upsert_nodes – Write or merge nodes, honoring each record's full label set.
- upsert_relations – Write or merge relationships between existing nodes.
- vector_search – Search nodes by dense vector.
agrag.graphdb.base.GraphStore.close
close() -> None
Release the backend connection.
agrag.graphdb.base.GraphStore.connect
connect() -> None
Open the backend connection and verify connectivity.
agrag.graphdb.base.GraphStore.ensure_vector_index
ensure_vector_index(*, label:str, vector_property:str, dimensions:int, distance:Distance) -> None
Create a native vector index if it does not exist.
Parameters:
- label (
str) – The node label to index. - vector_property (
str) – The embedding property name. - dimensions (
int) – The embedding dimension. - distance (
Distance) – The distance metric.
agrag.graphdb.base.GraphStore.execute_read
execute_read(query:str, parameters:Mapping[str, Any] | None = None, *, timeout:float | None = None) -> list[dict[str, Any]]
Run a read transaction.
Parameters:
- query (
str) – The Cypher query to run. - parameters (
Mapping[str, Any] | None) – The query parameters. - timeout (
float | None) – Server-side transaction timeout in seconds. The database terminates the transaction when it runs longer. None uses the server's default timeout. Backends that cannot enforce a timeout ignore it.
Returns:
agrag.graphdb.base.GraphStore.execute_write
execute_write(query:str, parameters:Mapping[str, Any] | None = None) -> list[dict[str, Any]]
Run a write transaction.
Parameters:
- query (
str) – The Cypher query to run. - parameters (
Mapping[str, Any] | None) – The query parameters.
Returns:
agrag.graphdb.base.GraphStore.register_labels
register_labels(labels:Sequence[str]) -> None
Mark labels as known, without writing anything.
setup_constraints()/setup_indexes() only cover labels this instance has already written (or that already exist live in the database) — both empty on a brand-new database. register_labels lets a caller holding a GraphSchema (Graph.open()) provision a fresh database fully before its first write.
Parameters:
Raises:
ValueError– Any label is not a safe identifier.
agrag.graphdb.base.GraphStore.register_relation_types
register_relation_types(types:Sequence[str]) -> None
Mark relationship types as known, without writing anything.
The relationship-type counterpart to register_labels — see its docstring for why this exists.
Parameters:
Raises:
ValueError– Any type is not a safe identifier.
agrag.graphdb.base.GraphStore.session
session() -> AbstractAsyncContextManager[Any]
Open a session as an async context manager.
Returns:
AbstractAsyncContextManager[Any]– A context manager yielding a backend session.
agrag.graphdb.base.GraphStore.setup_constraints
setup_constraints() -> None
Create per-label and per-relation-type uniqueness constraints.
Constraints cover every node label and relationship type written through this instance or already present in the database, so a fresh instance can set up an existing database without first rewriting every record.
agrag.graphdb.base.GraphStore.setup_indexes
setup_indexes() -> None
Create per-label property indexes.
Covers every node label written through this instance or already present in the database, so a fresh instance can set up an existing database without first rewriting every record.
agrag.graphdb.base.GraphStore.transaction
transaction() -> AsyncIterator[GraphStoreTransaction]
Start an explicit transaction spanning multiple writes.
Every call through the yielded handle should join one backend
transaction, committing as a whole on clean exit from the
async with block and rolling back as a whole if the block raises.
The default here simply yields self and gives no atomicity beyond
what each individual call already provides; a backend that can offer
real atomicity, such as Neo4jGraphStore, overrides this with a
driver transaction.
Use this when a caller must guarantee several writes either all apply
or none do, such as apply_merge's tombstone, relationship
transfer, and dedup steps.
Returns:
AsyncIterator[GraphStoreTransaction]– An async context manager yielding the transactional handle.
agrag.graphdb.base.GraphStore.upsert_nodes
upsert_nodes(label:str, nodes:Sequence[NodeRecord], *, batch_size:int = 256) -> None
Write or merge nodes, honoring each record's full label set.
Parameters:
- label (
str) – The label this batch is tracked under for constraint and index bookkeeping. - nodes (
Sequence[NodeRecord]) – The node records to upsert. Each node'sNodeRecord.labelsnames the full label set actually written to it, which may include labels beyondlabel. - batch_size (
int) – Records per backend write call, applied within each distinct label set whennodesmixes more than one. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.graphdb.base.GraphStore.upsert_relations
upsert_relations(relations:Sequence[RelationRecord], *, batch_size:int = 256) -> None
Write or merge relationships between existing nodes.
Parameters:
- relations (
Sequence[RelationRecord]) – The relation records to upsert. - batch_size (
int) – Records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.graphdb.base.GraphStore.vector_search
vector_search(*, label:str, vector_property:str, query_vector:Sequence[float], limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search nodes by dense vector.
Parameters:
- label (
str) – The node label to search. - vector_property (
str) – The embedding property name. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – Maximum number of hits. - filters (
dict[str, Any] | None) – An optional flat-dict filter on node properties.
Returns:
agrag.graphdb.base.GraphStoreTransaction
Bases: Protocol
The read/write/upsert surface available inside a transaction() block.
A structural type, not a base class: GraphStore itself satisfies it
(the default transaction() yields self), and a backend's own
transaction handle, such as Neo4j's, satisfies it without inheriting from
anything here.
Functions:
- execute_read – Run a read inside the surrounding transaction.
- execute_write – Run a write inside the surrounding transaction.
- upsert_nodes – Write or merge nodes inside the surrounding transaction.
agrag.graphdb.base.GraphStoreTransaction.execute_read
execute_read(query:str, parameters:Mapping[str, Any] | None = None) -> list[dict[str, Any]]
Run a read inside the surrounding transaction.
agrag.graphdb.base.GraphStoreTransaction.execute_write
execute_write(query:str, parameters:Mapping[str, Any] | None = None) -> list[dict[str, Any]]
Run a write inside the surrounding transaction.
agrag.graphdb.base.GraphStoreTransaction.upsert_nodes
upsert_nodes(label:str, nodes:Sequence[NodeRecord], *, batch_size:int = 256) -> None
Write or merge nodes inside the surrounding transaction.
agrag.graphdb.build_graph_store
build_graph_store(value:GraphStoreName | GraphStore) -> GraphStore
Build a graph store from a backend name, or return one unchanged.
Parameters:
- value (
GraphStoreName | GraphStore) –"neo4j", or an already-constructedGraphStore.
Returns:
GraphStore– A ready-to-use graph store.
agrag.graphdb.errors
Errors that the graph-store layer raises.
Classes:
- GraphStoreAliasConflictError – A merge-key alias a merge tried to claim already names another entity.
- GraphStoreConstraintViolationError – A write violated a uniqueness constraint the backend enforces.
- GraphStoreDataIntegrityError – A read found the graph store in a state its own invariants forbid.
- GraphStoreError – The base class for every graph-store error.
- GraphStoreMissingExtraError – A graph store exists, but its package extra is not installed.
agrag.graphdb.errors.GraphStoreAliasConflictError
GraphStoreAliasConflictError(conflicts:dict[str, str]) -> None
Bases: GraphStoreConstraintViolationError
A merge-key alias a merge tried to claim already names another entity.
Unlike the base class, this is not surfaced by the backend's own
uniqueness constraint -- claiming an already-owned alias is a silent
no-op at the database level (see upsert_merge_alias_query) -- so
apply_merge detects it itself from the claim's own return rows and
raises this instead. For example, one writer creates a canonical entity
named "Bob" while a concurrent writer separately resolves "Bob" as an
accepted alias of a different canonical entity named "Robert": neither
writer's own node merge_key collides, so recovery must come from here,
not from a constraint violation.
Attributes:
- conflicts – Every accepted merge_key this claim found already owned, mapped to the entity id that owns it.
agrag.graphdb.errors.GraphStoreAliasConflictError.conflicts
conflicts = conflicts
agrag.graphdb.errors.GraphStoreConstraintViolationError
Bases: GraphStoreError
A write violated a uniqueness constraint the backend enforces.
Raised instead of letting the backend's own driver exception propagate,
so callers can recognize this specific case -- for example, two
concurrent writers both missing an exact-match lookup and racing to
create the same merge_key -- and recover by re-resolving to
whichever write landed first, rather than treating it as a fatal error.
agrag.graphdb.errors.GraphStoreDataIntegrityError
Bases: GraphStoreError
A read found the graph store in a state its own invariants forbid.
Raised when persisted data cannot be trusted at face value -- for
example a merged_into tombstone chain that cycles, points at a
missing node, or runs past its expected bound without reaching a live
node. Returning the last-seen data in these cases would let a caller
silently act on a tombstone instead of the entity it was absorbed into.
agrag.graphdb.errors.GraphStoreError
Bases: Exception
The base class for every graph-store error.
agrag.graphdb.errors.GraphStoreMissingExtraError
GraphStoreMissingExtraError(extra:str) -> None
Bases: GraphStoreError
A graph store exists, but its package extra is not installed.
Attributes:
- extra – The name of the package extra to install.
agrag.graphdb.errors.GraphStoreMissingExtraError.extra
extra = extra
agrag.graphdb.neo4j
Neo4j graph-store backend.
Classes:
- Neo4jGraphStore – A
GraphStorebacked by Neo4j, using native vector indexes.
agrag.graphdb.neo4j.Neo4jGraphStore
Neo4jGraphStore(*, settings:Neo4jSettings | None = None, driver:AsyncDriver | None = None) -> None
Bases: GraphStore
A GraphStore backed by Neo4j, using native vector indexes.
The driver connects lazily on first use, so constructing the store does not
open a network connection. execute_read/execute_write wrap the
driver's managed transactions with no added retry loop, per ADR 0027.
Functions:
- close – Close the driver, releasing its connection pool.
- connect – Open the driver and verify connectivity.
- ensure_vector_index – Create a native vector index if it does not exist.
- execute_read – Run a read transaction and return its rows.
- execute_write – Run a write transaction and return its rows.
- register_labels – Add labels to this instance's known-label set.
- register_relation_types – Add types to this instance's known-relation-type set.
- session – Open a session to the configured database.
- setup_constraints – Create a uniqueness constraint on
idfor every known label. - setup_indexes – Create a range index on
idfor every known label. - transaction – Open one Neo4j explicit transaction spanning multiple writes.
- upsert_nodes – Write or merge nodes, honoring each record's full label set.
- upsert_relations – Write or merge relationships between existing nodes.
- vector_search – Search nodes by dense vector using the native vector index.
Parameters:
- settings (
Neo4jSettings | None) – Neo4j connection settings. Defaults toNeo4jSettings(). - driver (
AsyncDriver | None) – A pre-builtAsyncDriver, for tests. When set,__init__imports nothing and the store calls this object directly instead of building one.
agrag.graphdb.neo4j.Neo4jGraphStore.close
close() -> None
Close the driver, releasing its connection pool.
agrag.graphdb.neo4j.Neo4jGraphStore.connect
connect() -> None
Open the driver and verify connectivity.
agrag.graphdb.neo4j.Neo4jGraphStore.ensure_vector_index
ensure_vector_index(*, label:str, vector_property:str, dimensions:int, distance:Distance) -> None
Create a native vector index if it does not exist.
agrag.graphdb.neo4j.Neo4jGraphStore.execute_read
execute_read(query:str, parameters:Mapping[str, Any] | None = None, *, timeout:float | None = None) -> list[dict[str, Any]]
Run a read transaction and return its rows.
Parameters:
- query (
str) – The Cypher query to run. - parameters (
Mapping[str, Any] | None) – The query parameters. - timeout (
float | None) – Server-side transaction timeout in seconds, applied through the driver'sunit_of_workso the database terminates the transaction when it runs longer. None uses the server's default timeout.
Returns:
agrag.graphdb.neo4j.Neo4jGraphStore.execute_write
execute_write(query:str, parameters:Mapping[str, Any] | None = None) -> list[dict[str, Any]]
Run a write transaction and return its rows.
Raises:
GraphStoreConstraintViolationError– The write violated a uniqueness constraint, translated from the driver's own exception so callers do not need a hard dependency on it.
agrag.graphdb.neo4j.Neo4jGraphStore.register_labels
register_labels(labels:Sequence[str]) -> None
Add labels to this instance's known-label set.
Parameters:
Raises:
ValueError– Any label is not a safe identifier.
agrag.graphdb.neo4j.Neo4jGraphStore.register_relation_types
register_relation_types(types:Sequence[str]) -> None
Add types to this instance's known-relation-type set.
Parameters:
Raises:
ValueError– Any type is not a safe identifier.
agrag.graphdb.neo4j.Neo4jGraphStore.session
session() -> AbstractAsyncContextManager[Any]
Open a session to the configured database.
agrag.graphdb.neo4j.Neo4jGraphStore.setup_constraints
setup_constraints() -> None
Create a uniqueness constraint on id for every known label.
"Known" means written by this instance or already present in the
database, so a fresh store can set up constraints for an existing
database without first rewriting every record. Also creates the
global uniqueness constraint on NODE_IDENTITY_LABEL that
upsert_node_query's MERGE relies on to resolve a node by id
regardless of its other, mutable labels, and a per-type uniqueness
constraint on id for every known relationship type, which backs
the stale-relationship cleanup upsert_relation_query performs on
endpoint changes.
agrag.graphdb.neo4j.Neo4jGraphStore.setup_indexes
setup_indexes() -> None
Create a range index on id for every known label.
"Known" means written by this instance or already present in the database, so a fresh store can set up indexes for an existing database without first rewriting every record.
agrag.graphdb.neo4j.Neo4jGraphStore.transaction
transaction() -> AsyncIterator[GraphStoreTransaction]
Open one Neo4j explicit transaction spanning multiple writes.
Commits when the async with block exits cleanly; rolls back and
re-raises when it raises. The identity constraint is ensured before
opening the transaction, the same way upsert_nodes ensures it
before writing, since _Neo4jTransaction.upsert_nodes skips that
check to avoid a nested write racing the transaction it belongs to.
Raises:
GraphStoreConstraintViolationError– A write inside the block, or the commit itself, violated a uniqueness constraint -- Neo4j validates some constraints only at commit time for an explicit transaction, so this can surface here even when every individual write appeared to succeed.
agrag.graphdb.neo4j.Neo4jGraphStore.upsert_nodes
upsert_nodes(label:str, nodes:Sequence[NodeRecord], *, batch_size:int = 256) -> None
Write or merge nodes, honoring each record's full label set.
label names the batch for constraint/index bookkeeping, matching
every other tracked label; the labels actually written to a node come
from NodeRecord.labels, which may name more than one label (for
example a node that is both Chunk and Entity). Records with
different label sets are grouped and written with separate MERGE
queries, since Cypher requires labels to be literal in the query text
rather than a runtime parameter, so batch_size chunks apply within
each group rather than across the whole call.
Raises:
ValueError–batch_sizeis not positive.
agrag.graphdb.neo4j.Neo4jGraphStore.upsert_relations
upsert_relations(relations:Sequence[RelationRecord], *, batch_size:int = 256) -> None
Write or merge relationships between existing nodes.
Relationship identity is each record's id, not its endpoints: see
upsert_relation_query for how endpoint changes and same-id
parallel relationships are handled.
Raises:
ValueError–batch_sizeis not positive.
agrag.graphdb.neo4j.Neo4jGraphStore.vector_search
vector_search(*, label:str, vector_property:str, query_vector:Sequence[float], limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search nodes by dense vector using the native vector index.
A label with no provisioned vector index has nothing to search, so an absent index returns an empty result list rather than a driver error.
When filters is set, Neo4j's vector procedure applies the filter
only after selecting its top k candidates, so a plain k=limit
call can return fewer matches than actually exist. This escalates
k and retries until limit filtered hits come back or the
escalation reaches _VECTOR_SEARCH_MAX_K.
Raises:
ValueError–limitis not positive. A non-positive value is not a meaningful request and would send that same non-positivekto Neo4j's native vector procedure, which requires a positive top-k.
agrag.graphdb.serialize
Convert graph records into Neo4j-driver-friendly parameters.
Functions:
- node_params – Build the
$recordsentry for a node upsert. - relation_params – Build the
$recordsentry for a relationship upsert.
agrag.graphdb.serialize.node_params
node_params(record:NodeRecord) -> dict[str, Any]
Build the $records entry for a node upsert.
Parameters:
- record (
NodeRecord) – The node record to serialize.
Returns:
agrag.graphdb.serialize.relation_params
relation_params(record:RelationRecord) -> dict[str, Any]
Build the $records entry for a relationship upsert.
Parameters:
- record (
RelationRecord) – The relation record to serialize.
Returns:
agrag.graphdb.settings
Settings for the Neo4j graph-store backend.
Classes:
- Neo4jSettings – Neo4j connection configuration.
agrag.graphdb.settings.Neo4jSettings
Bases: BaseSettings
Neo4j connection configuration.
Attributes:
- uri (
str) – The Bolt connection URI, including scheme (neo4j+s://for Aura). Env:NEO4J_URI. - username (
str) – The database username. Env:NEO4J_USERNAME. - password (
SecretStr) – The database password. Env:NEO4J_PASSWORD. - database (
str) – The target database name. Env:NEO4J_DATABASE. - max_connection_lifetime (
int) – The maximum seconds a pooled connection lives, kept well below Aura's roughly five-minute idle timeout. Env:NEO4J_MAX_CONNECTION_LIFETIME.
Raises:
ValueError–uriis plaintext (bolt://orneo4j://) and points at a non-local host. Neo4j always authenticates with a password, so a plaintext scheme always sends it in the clear; useneo4j+s://(orbolt+s://) for a remote instance.
agrag.graphdb.settings.Neo4jSettings.database
database: str = 'neo4j'
agrag.graphdb.settings.Neo4jSettings.max_connection_lifetime
max_connection_lifetime: int = 240
agrag.graphdb.settings.Neo4jSettings.model_config
model_config = SettingsConfigDict(env_prefix='NEO4J_', env_file='.env', extra='ignore')
agrag.graphdb.settings.Neo4jSettings.password
password: SecretStr = SecretStr('neo4j')
agrag.graphdb.settings.Neo4jSettings.uri
uri: str = 'bolt://localhost:7687'
agrag.graphdb.settings.Neo4jSettings.username
username: str = 'neo4j'
agrag.ingestion
The ingestion package.
Modules:
- extract – The Extractor interface: reads one Chunk and produces an ExtractionResult.
- graph – The public Graph API for ingestion.
- merge – Merge mechanics: computing how a resolved group of mentions and entities combine.
- resolve – Entity resolution: deciding which ExtractedEntity mentions are the same thing.
- types – Graph.add()'s result and per-stage observability types.
Classes:
- Graph – A knowledge graph that a caller can open and add content to.
agrag.ingestion.Graph
Graph(*, schema:GraphSchema, graph_store:GraphStore, embedder:Embedder, extractor:Extractor, tracer:Tracer | None = None) -> None
A knowledge graph that a caller can open and add content to.
Functions:
- add – Add content to the graph.
- consolidate – Run full tiered resolution against everything persisted.
- open – Open a graph, connecting and fully provisioning graph_store.
Parameters:
- schema (
GraphSchema) – The entity/relation types this graph validates every extraction against. - graph_store (
GraphStore) – Where entities, relations, chunks, and MENTIONED_IN edges are written. - embedder (
Embedder) – Populates entity embeddings for native vector search. - extractor (
Extractor) – Runs against each chunk. - tracer (
Tracer | None) – A tracer to record spans for every step. Pass None for none.
agrag.ingestion.Graph.add
add(source:SourcesType | None = None, *, text:str | None = None, documents:Sequence[Document] | None = None, loader:Loader | None = None, error_policy:ErrorPolicy = ErrorPolicy.RAISE, on_progress:Callable[[AddResult], None] | None = None, return_chunks:bool = False) -> AddResult
Add content to the graph.
Give exactly one of source, text, and documents.
Parameters:
- source (
SourcesType | None) – A file path, a directory, a glob, or a list of these. - text (
str | None) – Raw text to add as one document. - documents (
Sequence[Document] | None) – Already-built documents to add directly. - loader (
Loader | None) – A loader to use instead of the registry default. Requires a single-filesource; a directory, glob, or list of sources raises an error. - error_policy (
ErrorPolicy) – The action to take on a per-source error. - on_progress (
Callable[[AddResult], None] | None) – A callback the call runs after each batch and once more at the end with the fully-populated result. - return_chunks (
bool) – Whether to include the produced chunks in the returned AddResult. False by default to avoid holding full text for a large corpus when not needed.
Returns:
AddResult– A summary of what was added per pipeline stage.
Raises:
ValueError– The call got zero, or more than one, ofsource,text, anddocuments. Also raised whenloaderis set withoutsource, or with a source that can match more than one file.UnsupportedFormatError– No loader is registered for a source's format.MissingExtraError– A loader is registered for a source's format, but its package extra is not installed. This error followserror_policyinstead of always stopping the call.
agrag.ingestion.Graph.consolidate
consolidate(*, apply:bool = False) -> ConsolidationReport
Run full tiered resolution against everything persisted.
Dry-run by default: produces a report of what would merge before any node is touched. Pass apply=True to write the merges.
For each EntityType label in self._schema, fetches every persisted entity with that label and runs the same comparator sequence add() uses in-batch (ExactMatch, FuzzyMatch, LLMVerify) pairwise across all of them — O(n^2) within each label's population. Confirmed matches become MergePlans via compute_merge.
Parameters:
- apply (
bool) – Write the computed merges. False produces a report only.
Returns:
ConsolidationReport– A report of every group consolidate() found, applied or not.
agrag.ingestion.Graph.open
open(*, schema:GraphSchema, graph_store:GraphStore, embedder:Embedder, extractor:Extractor, tracer:Tracer | None = None) -> Graph
Open a graph, connecting and fully provisioning graph_store.
Provisioning order: connect, then register every label/relation type this graph will ever write (schema's own labels/types plus the fixed system names CHUNK_LABEL/SYSTEM_RELATION_TYPES), then setup_constraints(), then setup_indexes(), then vector indexes for every schema entity label — so a brand-new database is fully ready, including the merge_key index the global exact-match tier needs and the embedding vector indexes native search needs, before this call returns.
Parameters:
- schema (
GraphSchema) – The entity/relation types this graph validates every extraction against. - graph_store (
GraphStore) – Where entities, relations, chunks, and MENTIONED_IN edges are written. - embedder (
Embedder) – Populates entity embeddings for native vector search. - extractor (
Extractor) – Runs against each chunk. - tracer (
Tracer | None) – A tracer to record spans for every step. Pass None for none.
Returns:
Graph– A graph connected to graph_store and ready to accept add() calls.
Raises:
Exception– Whatever connect(), registration, constraint/index setup, or vector-index provisioning raises. graph_store is closed first, so a failed open() never leaks a connection.
agrag.ingestion.extract
The Extractor interface: reads one Chunk and produces an ExtractionResult.
Classes:
- BAMLExtractor – Extracts with an LLM, via a BAML function and a runtime ClientRegistry.
- EscalatingExtractor – Runs a cheap primary extractor first, escalating per chunk when it's weak.
- ExtractionLLMSettings – Env-backed LLM client config for the extraction role.
- Extractor – Reads one Chunk and produces the entities and relations it contains.
- ExtractorMissingExtraError – An Extractor needs a package extra that is not installed.
- GlinerExtractor – Extracts locally with a GLiNER2.5 model. No network call.
agrag.ingestion.extract.BAMLExtractor
BAMLExtractor(*, settings:ExtractionLLMSettings | None = None, client:object | None = None) -> None
Bases: Extractor
Extracts with an LLM, via a BAML function and a runtime ClientRegistry.
Functions:
- extract – Extract with an LLM call through the configured ClientRegistry.
Attributes:
- settings –
Parameters:
- settings (
ExtractionLLMSettings | None) – LLM client config. Defaults toExtractionLLMSettings(), loaded from the environment/.env. Ignored whenclientis given: an injected client also disablessettings.retry, since a caller building its own client is assumed to own its own retry behavior too. - client (
object | None) – An already-built BAML client object exposingExtractEntitiesAndRelations. Tests inject a fake here.
agrag.ingestion.extract.BAMLExtractor.extract
extract(chunk:Chunk, schema:GraphSchema) -> ExtractionResult
Extract with an LLM call through the configured ClientRegistry.
Raises:
ExtractorMissingExtraError– Thellmpackage extra is not installed.ValueError–chunk.idisNone.
agrag.ingestion.extract.BAMLExtractor.settings
settings = settings
agrag.ingestion.extract.EscalatingExtractor
EscalatingExtractor(primary:Extractor, escalate_to:Extractor, *, min_confidence:float = 0.5, min_chunk_words:int = 8) -> None
Bases: Extractor
Runs a cheap primary extractor first, escalating per chunk when it's weak.
Functions:
- extract – Extract with the primary extractor, escalating when it's weak.
Attributes:
Parameters:
- primary (
Extractor) – Runs first, for every chunk. - escalate_to (
Extractor) – Runs instead of, never in addition to, the primary's result, when escalation triggers. Merging both extractors' output would mean reconciling overlapping spans between them, which is what entity resolution is for, not extraction. - min_confidence (
float) – Escalate when the primary's mean entity confidence falls below this, among entities that report a confidence. - min_chunk_words (
int) – Below this word count, a zero-entity result from the primary is treated as plausibly correct, not a miss.
agrag.ingestion.extract.EscalatingExtractor.escalate_to
escalate_to = escalate_to
agrag.ingestion.extract.EscalatingExtractor.extract
extract(chunk:Chunk, schema:GraphSchema) -> ExtractionResult
Extract with the primary extractor, escalating when it's weak.
Returns escalate_to's result outright when escalation triggers, never a combination of both extractors' results.
agrag.ingestion.extract.EscalatingExtractor.min_chunk_words
min_chunk_words = min_chunk_words
agrag.ingestion.extract.EscalatingExtractor.min_confidence
min_confidence = min_confidence
agrag.ingestion.extract.EscalatingExtractor.primary
primary = primary
agrag.ingestion.extract.ExtractionLLMSettings
Bases: BaseSettings
Env-backed LLM client config for the extraction role.
Attributes:
- clients (
list[LLMClientConfig]) – The LLM client(s) to use. One element for a single provider; more than one composed perstrategy. - strategy (
Literal['single', 'fallback', 'round_robin']) – How to compose multiple clients. Ignored with one client. - retry (
RetryConfig) – Retry settings applied to the extraction LLM call.
Env prefix: EXTRACTION_LLM_.
Functions:
- from_openai_compatible_env – Build settings from a generic OpenAI-compatible endpoint.
agrag.ingestion.extract.ExtractionLLMSettings.clients
clients: list[LLMClientConfig]
agrag.ingestion.extract.ExtractionLLMSettings.from_openai_compatible_env
from_openai_compatible_env() -> ExtractionLLMSettings
Build settings from a generic OpenAI-compatible endpoint.
Reads LLM_BASE_URL, LLM_API_KEY, and LLM_MODEL_ID from the
environment or .env, so the model name is never hardcoded. Raises
RuntimeError when the required variables are not all set.
Returns:
ExtractionLLMSettings– Settings pointing at oneopenai-genericclient.
agrag.ingestion.extract.ExtractionLLMSettings.model_config
model_config = SettingsConfigDict(env_prefix='EXTRACTION_LLM_', env_file='.env', extra='ignore')
agrag.ingestion.extract.ExtractionLLMSettings.retry
retry: RetryConfig = Field(default_factory=RetryConfig)
agrag.ingestion.extract.ExtractionLLMSettings.strategy
strategy: Literal['single', 'fallback', 'round_robin'] = 'single'
agrag.ingestion.extract.Extractor
Bases: ABC
Reads one Chunk and produces the entities and relations it contains.
Functions:
- extract – Extract entities and relations from one chunk.
agrag.ingestion.extract.Extractor.extract
extract(chunk:Chunk, schema:GraphSchema) -> ExtractionResult
Extract entities and relations from one chunk.
Parameters:
- chunk (
Chunk) – The chunk to read. Onlychunk.textandchunk.idare used. - schema (
GraphSchema) – The entity/relation types to extract. Every returned entity'slabeland relation'slabelmust be declared in this schema.
Returns:
ExtractionResult– The entities and relations this call found, in extraction order.
agrag.ingestion.extract.ExtractorMissingExtraError
ExtractorMissingExtraError(component:str, extra:str) -> None
Bases: IngestionError
An Extractor needs a package extra that is not installed.
Attributes:
agrag.ingestion.extract.ExtractorMissingExtraError.component
component = component
agrag.ingestion.extract.ExtractorMissingExtraError.extra
extra = extra
agrag.ingestion.extract.GlinerExtractor
GlinerExtractor(*, model_name:str = 'fastino/gliner2.5-small-v1', model:object | None = None) -> None
Bases: Extractor
Extracts locally with a GLiNER2.5 model. No network call.
Functions:
- extract – Extract with the local GLiNER2.5 model.
Attributes:
Parameters:
- model_name (
str) – The checkpoint to load ifmodelis not given. - model (
object | None) – An already-built GLiNER2.5 model. Tests inject a fake here to avoid a real model download.
agrag.ingestion.extract.GlinerExtractor.extract
extract(chunk:Chunk, schema:GraphSchema) -> ExtractionResult
Extract with the local GLiNER2.5 model.
Raises:
ExtractorMissingExtraError– Theextractpackage extra is not installed.ValueError–chunk.idisNone.
agrag.ingestion.extract.GlinerExtractor.model_name
model_name = model_name
agrag.ingestion.graph
The public Graph API for ingestion.
Classes:
- Graph – A knowledge graph that a caller can open and add content to.
Attributes:
agrag.ingestion.graph.Graph
Graph(*, schema:GraphSchema, graph_store:GraphStore, embedder:Embedder, extractor:Extractor, tracer:Tracer | None = None) -> None
A knowledge graph that a caller can open and add content to.
Functions:
- add – Add content to the graph.
- consolidate – Run full tiered resolution against everything persisted.
- open – Open a graph, connecting and fully provisioning graph_store.
Parameters:
- schema (
GraphSchema) – The entity/relation types this graph validates every extraction against. - graph_store (
GraphStore) – Where entities, relations, chunks, and MENTIONED_IN edges are written. - embedder (
Embedder) – Populates entity embeddings for native vector search. - extractor (
Extractor) – Runs against each chunk. - tracer (
Tracer | None) – A tracer to record spans for every step. Pass None for none.
agrag.ingestion.graph.Graph.add
add(source:SourcesType | None = None, *, text:str | None = None, documents:Sequence[Document] | None = None, loader:Loader | None = None, error_policy:ErrorPolicy = ErrorPolicy.RAISE, on_progress:Callable[[AddResult], None] | None = None, return_chunks:bool = False) -> AddResult
Add content to the graph.
Give exactly one of source, text, and documents.
Parameters:
- source (
SourcesType | None) – A file path, a directory, a glob, or a list of these. - text (
str | None) – Raw text to add as one document. - documents (
Sequence[Document] | None) – Already-built documents to add directly. - loader (
Loader | None) – A loader to use instead of the registry default. Requires a single-filesource; a directory, glob, or list of sources raises an error. - error_policy (
ErrorPolicy) – The action to take on a per-source error. - on_progress (
Callable[[AddResult], None] | None) – A callback the call runs after each batch and once more at the end with the fully-populated result. - return_chunks (
bool) – Whether to include the produced chunks in the returned AddResult. False by default to avoid holding full text for a large corpus when not needed.
Returns:
AddResult– A summary of what was added per pipeline stage.
Raises:
ValueError– The call got zero, or more than one, ofsource,text, anddocuments. Also raised whenloaderis set withoutsource, or with a source that can match more than one file.UnsupportedFormatError– No loader is registered for a source's format.MissingExtraError– A loader is registered for a source's format, but its package extra is not installed. This error followserror_policyinstead of always stopping the call.
agrag.ingestion.graph.Graph.consolidate
consolidate(*, apply:bool = False) -> ConsolidationReport
Run full tiered resolution against everything persisted.
Dry-run by default: produces a report of what would merge before any node is touched. Pass apply=True to write the merges.
For each EntityType label in self._schema, fetches every persisted entity with that label and runs the same comparator sequence add() uses in-batch (ExactMatch, FuzzyMatch, LLMVerify) pairwise across all of them — O(n^2) within each label's population. Confirmed matches become MergePlans via compute_merge.
Parameters:
- apply (
bool) – Write the computed merges. False produces a report only.
Returns:
ConsolidationReport– A report of every group consolidate() found, applied or not.
agrag.ingestion.graph.Graph.open
open(*, schema:GraphSchema, graph_store:GraphStore, embedder:Embedder, extractor:Extractor, tracer:Tracer | None = None) -> Graph
Open a graph, connecting and fully provisioning graph_store.
Provisioning order: connect, then register every label/relation type this graph will ever write (schema's own labels/types plus the fixed system names CHUNK_LABEL/SYSTEM_RELATION_TYPES), then setup_constraints(), then setup_indexes(), then vector indexes for every schema entity label — so a brand-new database is fully ready, including the merge_key index the global exact-match tier needs and the embedding vector indexes native search needs, before this call returns.
Parameters:
- schema (
GraphSchema) – The entity/relation types this graph validates every extraction against. - graph_store (
GraphStore) – Where entities, relations, chunks, and MENTIONED_IN edges are written. - embedder (
Embedder) – Populates entity embeddings for native vector search. - extractor (
Extractor) – Runs against each chunk. - tracer (
Tracer | None) – A tracer to record spans for every step. Pass None for none.
Returns:
Graph– A graph connected to graph_store and ready to accept add() calls.
Raises:
Exception– Whatever connect(), registration, constraint/index setup, or vector-index provisioning raises. graph_store is closed first, so a failed open() never leaks a connection.
agrag.ingestion.graph.SYSTEM_RELATION_TYPES
SYSTEM_RELATION_TYPES = ['MENTIONED_IN']
agrag.ingestion.graph.SourceType
SourceType = Union[str, Path]
agrag.ingestion.graph.SourcesType
SourcesType = Union[SourceType, Sequence[SourceType]]
agrag.ingestion.merge
Merge mechanics: computing how a resolved group of mentions and entities combine.
This module is storage-agnostic: it decides what a merge should look like, but never touches GraphStore itself. Applying a computed MergePlan is a separate step.
Classes:
- ConflictRecord – One property that had more than one candidate value.
- MergePlan – Computed result of merging zero or more entities and mentions.
- PropertyRules – Per-property conflict resolution, with a default for unlisted properties.
- PropertyStrategy – Fallback rule for a property with no entry in PropertyRules.
Functions:
- apply_merge – Write a computed MergePlan to storage.
- compute_merge – Compute how existing_entities and mentions combine into one Entity.
- mentioned_in_id – Return the deterministic id for a new Chunk -[:MENTIONED_IN]-> Entity edge.
- relation_id – Return the deterministic id for a domain relationship triple.
Attributes:
- PropertyRule – Per-property conflict resolver.
agrag.ingestion.merge.ConflictRecord
Bases: BaseModel
One property that had more than one candidate value.
Attributes:
- field (
str) – The property name. - candidates (
list[object]) – Every distinct candidate value seen, in encounter order. - resolved (
object) – The value compute_merge chose.
agrag.ingestion.merge.ConflictRecord.candidates
candidates: list[object]
agrag.ingestion.merge.ConflictRecord.field
field: str
agrag.ingestion.merge.ConflictRecord.resolved
resolved: object
agrag.ingestion.merge.MergePlan
Bases: BaseModel
Computed result of merging zero or more entities and mentions.
Attributes:
- survivor (
Entity) – The resulting Entity. Its merge_count, source_chunk_ids, and merged_from are this call's best local computation, for reporting; apply_merge writes new_source_chunk_ids and merge_count_delta atomically instead, so a concurrent writer's own contribution to the same node is never overwritten. - tombstone_ids (
list[UUID]) – Ids of entities absorbed into survivor. Also this call's new contribution to the survivor's merged_from, applied atomically. - conflicts (
list[ConflictRecord]) – Every field that had more than one candidate value. - accepted_merge_keys (
list[str]) – Every normalized merge_key this merge accepted -- from existing_entities and mentions alike, not only the survivor's own chosen name -- so a later mention of any accepted name resolves back to this entity instead of creating a duplicate. - new_source_chunk_ids (
list[UUID]) – The chunk ids this call's mentions and absorbed entities contribute, applied as an atomic union against whatever the survivor's node currently has. - merge_count_delta (
int) – The amount to atomically add to whatever merge_count the survivor's node currently has.
agrag.ingestion.merge.MergePlan.accepted_merge_keys
accepted_merge_keys: list[str] = []
agrag.ingestion.merge.MergePlan.conflicts
conflicts: list[ConflictRecord] = []
agrag.ingestion.merge.MergePlan.merge_count_delta
merge_count_delta: int = 0
agrag.ingestion.merge.MergePlan.new_source_chunk_ids
new_source_chunk_ids: list[UUID] = []
agrag.ingestion.merge.MergePlan.survivor
survivor: Entity
agrag.ingestion.merge.MergePlan.tombstone_ids
tombstone_ids: list[UUID] = []
agrag.ingestion.merge.PropertyRule
PropertyRule = Callable[[list[object]], object]
Per-property conflict resolver.
Takes every candidate value for one property, in encounter order, already filtered to exclude None, and returns the resolved value.
agrag.ingestion.merge.PropertyRules
PropertyRules(rules:dict[str, PropertyRule] = dict(), default:PropertyStrategy = PropertyStrategy.KEEP_FIRST) -> None
Per-property conflict resolution, with a default for unlisted properties.
Attributes:
- rules (
dict[str, PropertyRule]) – Property name to resolver, for properties needing a specific rule. - default (
PropertyStrategy) – Strategy applied to a property with no entry in rules.
agrag.ingestion.merge.PropertyRules.default
default: PropertyStrategy = PropertyStrategy.KEEP_FIRST
agrag.ingestion.merge.PropertyRules.rules
rules: dict[str, PropertyRule] = field(default_factory=dict)
agrag.ingestion.merge.PropertyStrategy
Bases: StrEnum
Fallback rule for a property with no entry in PropertyRules.
Attributes:
- KEEP_FIRST –
- KEEP_LAST –
- MERGE_ALL –
agrag.ingestion.merge.PropertyStrategy.KEEP_FIRST
KEEP_FIRST = 'keep_first'
agrag.ingestion.merge.PropertyStrategy.KEEP_LAST
KEEP_LAST = 'keep_last'
agrag.ingestion.merge.PropertyStrategy.MERGE_ALL
MERGE_ALL = 'merge_all'
agrag.ingestion.merge.apply_merge
apply_merge(plan:MergePlan, *, graph_store:GraphStore, schema:GraphSchema) -> None
Write a computed MergePlan to storage.
Every call runs inside one GraphStore transaction: when tombstone_ids is non-empty, it first clears merge_key from every entity about to be absorbed, since canonical selection can pick a different node as survivor than the one a property rule (e.g. KEEP_FIRST) resolves the name from, so the survivor's resolved merge_key can equal a still-live tombstone's own merge_key -- writing the survivor before clearing that would collide with the per-label merge_key uniqueness constraint. It then always upserts the survivor and records a merge-key alias for its current name, and, when tombstone_ids is non-empty, also tombstones, deletes edges that would become meaningless self-links, transfers what remains, and dedupes the survivor's resulting neighbourhood. A failure partway through leaves no half-written state: no survivor without its alias, no tombstone without its edges transferred, no transferred edge without its duplicate cleaned up.
Parameters:
- plan (
MergePlan) – The merge to write. - graph_store (
GraphStore) – Where the merge is written. - schema (
GraphSchema) – The schema the survivor's label belongs to.
Raises:
GraphStoreAliasConflictError– An accepted merge_key is already owned by a live entity outside this merge's own survivor and tombstone ids -- a concurrent writer accepted that name as an alias of, or created it as the canonical name of, a different entity.GraphStoreDataIntegrityError– A candidate conflicting alias owner's merged_into chain cycles, points at a missing node, or does not reach a live node within the hop limit.
agrag.ingestion.merge.compute_merge
compute_merge(*, existing_entities:list[Entity], mentions:list[ExtractedEntity], schema:GraphSchema, rules:PropertyRules | None = None, description_settings:Any | None = None, description_client:Any | None = None) -> tuple[MergePlan, list[Any]]
Compute how existing_entities and mentions combine into one Entity.
No storage is touched. Zero existing entities produces a brand-new Entity. One produces an updated copy folding in the mentions. Two or more picks a canonical survivor and marks the rest for tombstoning.
Parameters:
- existing_entities (
list[Entity]) – Already-persisted entities this call reconciles. - mentions (
list[ExtractedEntity]) – Fresh ExtractedEntity mentions to fold in. - schema (
GraphSchema) – Used to look up the entity type's declared properties for the canonical-id schema-completeness check. - rules (
PropertyRules | None) – Per-property conflict resolution. Defaults to keep_first. - description_settings (
Any | None) – LLM settings for description summarization. - description_client (
Any | None) – Injected LLM client for tests.
Returns:
Raises:
ValueError– existing_entities and mentions are both empty, or their labels disagree.
agrag.ingestion.merge.mentioned_in_id
mentioned_in_id(chunk_id:UUID, entity_id:UUID) -> UUID
Return the deterministic id for a new Chunk -[:MENTIONED_IN]-> Entity edge.
Only a fresh id for a pair with no persisted edge yet is guaranteed to equal
this. An entity merge can transfer an existing edge onto a new entity id
while keeping its old id (see transfer_relationships_query), so a
caller writing to an already-persisted pair should look up the edge by
its endpoints first and fall back to this id only when none is found.
Parameters:
Returns:
UUID– The edge id. Deterministic: same pair always returns same id.
agrag.ingestion.merge.relation_id
relation_id(source_id:UUID, target_id:UUID, rel_type:str) -> UUID
Return the deterministic id for a domain relationship triple.
Two concurrent add() calls resolving the same (source_id, target_id, rel_type) triple can both miss the existing-relation lookup
and each try to create it; since this id depends only on the triple, both
writers compute the same one, so upsert_relation_query's MERGE
converges to a single edge instead of two parallel ones with unrelated
random ids. Mirrors mentioned_in_id.
Parameters:
- source_id (
UUID) – The relationship's source Entity id. - target_id (
UUID) – The relationship's target Entity id. - rel_type (
str) – The relationship's type.
Returns:
UUID– The relationship id. Same triple always returns the same id.
agrag.ingestion.resolve
Entity resolution: deciding which ExtractedEntity mentions are the same thing.
Classes:
- CandidateSource – Narrows which entity pairs resolution compares — the blocking step.
- Comparator – One matching strategy a Resolver runs against a candidate pair.
- ComparisonVerdict – A Comparator's verdict on one entity pair.
- ExactMatch – Matches when normalized text is identical. Never returns NO_MATCH.
- FuzzyMatch – Matches by string similarity, within a confident-match/distinct band.
- InBatchCandidateSource – Blocks by label: only entities sharing a label are ever compared.
- LLMVerify – Asks an LLM to verify an ambiguous pair. Last resort; never UNCERTAIN.
- ResolutionGroup – One set of ExtractedEntity indices resolution decided are the same entity.
- Resolver – Runs an ordered comparator sequence over blocked candidate pairs.
agrag.ingestion.resolve.CandidateSource
Bases: ABC
Narrows which entity pairs resolution compares — the blocking step.
Functions:
- candidates_for – Return indices worth comparing against entities[index].
agrag.ingestion.resolve.CandidateSource.candidates_for
candidates_for(index:int, entities:list[ExtractedEntity]) -> list[int]
Return indices worth comparing against entities[index].
Parameters:
- index (
int) – The entity to find candidates for. - entities (
list[ExtractedEntity]) – The full entity list this call is scoped to.
Returns:
list[int]– Indices intoentities, excludingindexitself. Order doeslist[int]– not matter; duplicates are harmless but wasteful.
agrag.ingestion.resolve.Comparator
Bases: ABC
One matching strategy a Resolver runs against a candidate pair.
Functions:
- compare – Compare two entities.
agrag.ingestion.resolve.Comparator.compare
compare(a:ExtractedEntity, b:ExtractedEntity) -> ComparisonVerdict
Compare two entities.
Parameters:
- a (
ExtractedEntity) – The first entity. - b (
ExtractedEntity) – The second entity.
Returns:
ComparisonVerdict– This comparator's verdict. UNCERTAIN defers to the next comparator.
agrag.ingestion.resolve.ComparisonVerdict
Bases: StrEnum
A Comparator's verdict on one entity pair.
Attributes:
- MATCH – The comparator is confident these are the same entity.
- NO_MATCH – The comparator is confident these are different entities.
- UNCERTAIN – This comparator can't decide; the next one gets a turn.
agrag.ingestion.resolve.ComparisonVerdict.MATCH
MATCH = 'match'
agrag.ingestion.resolve.ComparisonVerdict.NO_MATCH
NO_MATCH = 'no_match'
agrag.ingestion.resolve.ComparisonVerdict.UNCERTAIN
UNCERTAIN = 'uncertain'
agrag.ingestion.resolve.ExactMatch
Bases: Comparator
Matches when normalized text is identical. Never returns NO_MATCH.
Functions:
- compare – Return MATCH on identical normalized text, else UNCERTAIN.
agrag.ingestion.resolve.ExactMatch.compare
compare(a:ExtractedEntity, b:ExtractedEntity) -> ComparisonVerdict
Return MATCH on identical normalized text, else UNCERTAIN.
agrag.ingestion.resolve.FuzzyMatch
FuzzyMatch(*, match_above:float = 0.92, no_match_below:float = 0.7) -> None
Bases: Comparator
Matches by string similarity, within a confident-match/distinct band.
Attributes:
- match_above – A similarity score at or above this is a confident match.
- no_match_below – A similarity score below this is a confident non-match. A score in between is UNCERTAIN and defers to the next comparator.
Functions:
- compare – Return a verdict from token-sort-ratio similarity.
agrag.ingestion.resolve.FuzzyMatch.compare
compare(a:ExtractedEntity, b:ExtractedEntity) -> ComparisonVerdict
Return a verdict from token-sort-ratio similarity.
agrag.ingestion.resolve.FuzzyMatch.match_above
match_above = match_above
agrag.ingestion.resolve.FuzzyMatch.no_match_below
no_match_below = no_match_below
agrag.ingestion.resolve.InBatchCandidateSource
Bases: CandidateSource
Blocks by label: only entities sharing a label are ever compared.
Scoped to whatever entity list a caller passes to candidates_for — today, always the current extraction batch. A future graph-backed candidate source can replace this without changing any Comparator, since comparators only ever see the pairs a CandidateSource proposes.
Functions:
- candidates_for – Return every other entity sharing entities[index]'s label.
agrag.ingestion.resolve.InBatchCandidateSource.candidates_for
candidates_for(index:int, entities:list[ExtractedEntity]) -> list[int]
Return every other entity sharing entities[index]'s label.
agrag.ingestion.resolve.LLMVerify
LLMVerify(*, chunks_by_id:dict[UUID, Chunk], settings:ExtractionLLMSettings | None = None, client:object | None = None) -> None
Bases: Comparator
Asks an LLM to verify an ambiguous pair. Last resort; never UNCERTAIN.
Never raises from an LLM-call failure: it resolves to NO_MATCH instead, by the same fail-safe design as every comparator a Resolver runs — an ambiguous or failed comparison never merges two entities. A missing package extra is a configuration error, not an ambiguous judgment call, and is raised outright instead (see compare's Raises section).
Functions:
- compare – Return the LLM's verdict, or NO_MATCH if the call itself fails.
Attributes:
- chunks_by_id –
- settings –
Parameters:
- chunks_by_id (
dict[UUID, Chunk]) – Maps a Chunk id to the Chunk, for prompt context. - settings (
ExtractionLLMSettings | None) – LLM client config. Defaults toExtractionLLMSettings(). Ignored whenclientis given: an injected client also disablessettings.retry, since a caller building its own client is assumed to own its own retry behavior too. - client (
object | None) – An already-built BAML client. Tests inject a fake here.
agrag.ingestion.resolve.LLMVerify.chunks_by_id
chunks_by_id = chunks_by_id
agrag.ingestion.resolve.LLMVerify.compare
compare(a:ExtractedEntity, b:ExtractedEntity) -> ComparisonVerdict
Return the LLM's verdict, or NO_MATCH if the call itself fails.
Raises:
ExtractorMissingExtraError– Thellmpackage extra is not installed.
agrag.ingestion.resolve.LLMVerify.settings
settings = settings
agrag.ingestion.resolve.ResolutionGroup
Bases: BaseModel
One set of ExtractedEntity indices resolution decided are the same entity.
Attributes:
- entity_indices (
list[int]) – Indices into the entity list passed to Resolver.resolve. A group of one means resolution found no match for that entity.
agrag.ingestion.resolve.ResolutionGroup.entity_indices
entity_indices: list[int]
agrag.ingestion.resolve.Resolver
Resolver(*, comparators:list[Comparator], candidate_source:CandidateSource) -> None
Runs an ordered comparator sequence over blocked candidate pairs.
Groups every pair a comparator confirms as a match into a ResolutionGroup.
Functions:
- resolve – Group entities that resolution decided are the same thing.
Attributes:
Parameters:
- comparators (
list[Comparator]) – Tried in order per candidate pair. The first non-UNCERTAIN verdict wins; if every comparator is UNCERTAIN, the pair does not merge. - candidate_source (
CandidateSource) – Narrows which pairs get compared at all.
agrag.ingestion.resolve.Resolver.candidate_source
candidate_source = candidate_source
agrag.ingestion.resolve.Resolver.comparators
comparators = comparators
agrag.ingestion.resolve.Resolver.resolve
resolve(entities:list[ExtractedEntity]) -> list[ResolutionGroup]
Group entities that resolution decided are the same thing.
Parameters:
- entities (
list[ExtractedEntity]) – The entities to resolve. Only entities passed in the same call are ever compared against each other — resolving against previously-resolved entities from an earlier call is not supported by this Resolver.
Returns:
list[ResolutionGroup]– One ResolutionGroup per distinct entity found. Every input indexlist[ResolutionGroup]– appears in exactly one group.
agrag.ingestion.types
Graph.add()'s result and per-stage observability types.
Classes:
- AddResult – Graph.add()'s return type — one summary per pipeline stage.
- ConsolidationReport – Report from Graph.consolidate().
- ExtractionStats – Extraction-stage results.
- IngestStats – Ingestion-stage results. Renamed from IngestResult (ADR 0031).
- MergeStats – Merge-stage results.
- ResolutionStats – Resolution-stage results.
- StageFailure – One item's failure within a pipeline stage.
- StorageStats – Storage-write-stage results.
agrag.ingestion.types.AddResult
Bases: BaseModel
Graph.add()'s return type — one summary per pipeline stage.
Attributes:
- ingestion (
IngestStats) – What today's IngestResult covered. - extraction (
ExtractionStats) – Extractor output across every chunk this call processed. - resolution (
ResolutionStats) – Resolution's tier-by-tier match counts. - merge (
MergeStats) – What merge mechanics did with resolution's groups. - storage (
StorageStats) – What made it to GraphStore, and what didn't. - chunks (
list[Chunk]) – Every Chunk this call produced. Empty unless return_chunks=True — holding full chunk text for a large corpus is a real memory cost most callers don't need paid for.
agrag.ingestion.types.AddResult.chunks
chunks: list[Chunk] = Field(default_factory=list)
agrag.ingestion.types.AddResult.documents
documents: int
Proxy to ingestion.documents for backward compatibility.
agrag.ingestion.types.AddResult.extraction
extraction: ExtractionStats = Field(default_factory=ExtractionStats)
agrag.ingestion.types.AddResult.ingestion
ingestion: IngestStats = Field(default_factory=IngestStats)
agrag.ingestion.types.AddResult.merge
merge: MergeStats = Field(default_factory=MergeStats)
agrag.ingestion.types.AddResult.quarantined
quarantined: int
Proxy to ingestion.quarantined for backward compatibility.
agrag.ingestion.types.AddResult.quarantined_items
quarantined_items: list[StageFailure]
Proxy to ingestion.quarantined_items for backward compatibility.
agrag.ingestion.types.AddResult.resolution
resolution: ResolutionStats = Field(default_factory=ResolutionStats)
agrag.ingestion.types.AddResult.skipped
skipped: int
Proxy to ingestion.skipped for backward compatibility.
agrag.ingestion.types.AddResult.sources
sources: int
Proxy to ingestion.sources for backward compatibility.
agrag.ingestion.types.AddResult.storage
storage: StorageStats = Field(default_factory=StorageStats)
agrag.ingestion.types.ConsolidationReport
Bases: BaseModel
Report from Graph.consolidate().
Attributes:
- would_merge (
list[MergePlan]) – The merge plans found, whether applied or not. - applied (
bool) – Whether the plans were applied. - failures (
list[StageFailure]) – Failures re-embedding an applied survivor's final text. Always empty when apply is False.
agrag.ingestion.types.ConsolidationReport.applied
applied: bool = False
agrag.ingestion.types.ConsolidationReport.failures
failures: list[StageFailure] = Field(default_factory=list)
agrag.ingestion.types.ConsolidationReport.would_merge
would_merge: list[MergePlan] = Field(default_factory=list)
agrag.ingestion.types.ExtractionStats
Bases: BaseModel
Extraction-stage results.
Attributes:
- chunks_processed (
int) – - entities_extracted (
int) – - failures (
list[StageFailure]) – - relations_extracted (
int) –
agrag.ingestion.types.ExtractionStats.chunks_processed
chunks_processed: int = 0
agrag.ingestion.types.ExtractionStats.entities_extracted
entities_extracted: int = 0
agrag.ingestion.types.ExtractionStats.failures
failures: list[StageFailure] = Field(default_factory=list)
agrag.ingestion.types.ExtractionStats.relations_extracted
relations_extracted: int = 0
agrag.ingestion.types.IngestStats
Bases: BaseModel
Ingestion-stage results. Renamed from IngestResult (ADR 0031).
Attributes:
- documents (
int) – - quarantined (
int) – - quarantined_items (
list[StageFailure]) – - skipped (
int) – - sources (
int) –
agrag.ingestion.types.IngestStats.documents
documents: int = 0
agrag.ingestion.types.IngestStats.quarantined
quarantined: int = 0
agrag.ingestion.types.IngestStats.quarantined_items
quarantined_items: list[StageFailure] = Field(default_factory=list)
agrag.ingestion.types.IngestStats.skipped
skipped: int = 0
agrag.ingestion.types.IngestStats.sources
sources: int = 0
agrag.ingestion.types.MergeStats
Bases: BaseModel
Merge-stage results.
Attributes:
- nodes_created (
int) – Brand-new entities materialized this call. - nodes_updated (
int) – Existing entities that absorbed new mention data without tombstoning anything. - nodes_merged (
int) – Entities tombstoned into a survivor this call. - conflicts_resolved (
int) – Total property/description conflicts resolved across every merge this call performed. - failures (
list[StageFailure]) – Includes an LLM failure during description summarization (ADR 0033's fallback-to-concatenation path still records one here, even though it didn't block the merge).
agrag.ingestion.types.MergeStats.conflicts_resolved
conflicts_resolved: int = 0
agrag.ingestion.types.MergeStats.failures
failures: list[StageFailure] = Field(default_factory=list)
agrag.ingestion.types.MergeStats.nodes_created
nodes_created: int = 0
agrag.ingestion.types.MergeStats.nodes_merged
nodes_merged: int = 0
agrag.ingestion.types.MergeStats.nodes_updated
nodes_updated: int = 0
agrag.ingestion.types.ResolutionStats
Bases: BaseModel
Resolution-stage results.
Attributes:
- exact_match_hits (
int) – Mentions that matched an already-persisted entity via the global exact-match tier. - in_batch_groups (
int) – Resolution groups the in-batch fuzzy/LLM tier found. - ambiguous_count (
int) – Comparisons no comparator could confidently decide (ADR 0013's fail-safe: never merged).
agrag.ingestion.types.ResolutionStats.ambiguous_count
ambiguous_count: int = 0
agrag.ingestion.types.ResolutionStats.exact_match_hits
exact_match_hits: int = 0
agrag.ingestion.types.ResolutionStats.in_batch_groups
in_batch_groups: int = 0
agrag.ingestion.types.StageFailure
Bases: BaseModel
One item's failure within a pipeline stage.
Attributes:
- item_id (
str) – The chunk id, mention id, or batch id — whichever unit the stage failed on. - error_type (
str) – The exception's class name. - error_message (
str) – The exception's message. - trace_id (
str | None) – The OTel trace id correlating to the full span detail, when tracing is configured. - span_id (
str | None) – The OTel span id within that trace.
agrag.ingestion.types.StageFailure.error_message
error_message: str
agrag.ingestion.types.StageFailure.error_type
error_type: str
agrag.ingestion.types.StageFailure.item_id
item_id: str
agrag.ingestion.types.StageFailure.span_id
span_id: str | None = None
agrag.ingestion.types.StageFailure.trace_id
trace_id: str | None = None
agrag.ingestion.types.StorageStats
Bases: BaseModel
Storage-write-stage results.
Attributes:
- nodes_written (
int) – Chunk and Entity nodes together, one aggregate count rather than a sub-count per kind — both are written in the same final phase, so there is one natural accounting point. - relationships_written (
int) – Domain Relation and MENTIONED_IN edges together, for the same reason. - failures (
list[StageFailure]) – One record per batch write that failed, capped per call. A GraphStore write is a single managed transaction, so a failure here means the whole batch did not land, not a partial subset of it.
agrag.ingestion.types.StorageStats.failures
failures: list[StageFailure] = Field(default_factory=list)
agrag.ingestion.types.StorageStats.nodes_written
nodes_written: int = 0
agrag.ingestion.types.StorageStats.relationships_written
relationships_written: int = 0
agrag.observability
OpenTelemetry wiring for the ingestion layer.
This module imports only opentelemetry-api. The SDK and exporters stay in
the optional observability extra and are never imported here; a caller
wires them before opening a graph. The tracer is constructor-injected, never
ambient.
Functions:
- get_tracer – Return a usable tracer.
- traced – Wrap a call in a span on the given tracer.
agrag.observability.get_tracer
get_tracer(tracer:Tracer | None) -> Tracer
Return a usable tracer.
Parameters:
- tracer (
Tracer | None) – A caller-supplied tracer, orNoneto use OpenTelemetry's global no-op tracer.
Returns:
Tracer– The supplied tracer, or the global no-op tracer when the caller passedNone.
agrag.observability.traced
traced(tracer:Tracer | None) -> Callable[[Callable], Callable]
Wrap a call in a span on the given tracer.
Use this at each pipeline call site (loader, chunker). It works on both sync and async functions; the span name is the wrapped callable's qualified name.
Parameters:
- tracer (
Tracer | None) – The tracer to record on, orNonefor a no-op span.
Returns:
agrag.retrieval
Retrieval package: search engine, fusion, reranking, and retrievers.
Modules:
- errors – Errors that the retrieval layer raises.
- filters – Constraints applied across every retrieval method in one call.
- fusion – Reciprocal Rank Fusion: combine ranked results from multiple methods.
- identity – Shared identity resolution for merged_into chains.
- methods – Low-level search method helpers shared by retrievers.
- recipes – Named, data-only configurations of what SearchEngine runs.
- rerank – Rerankers that reorder fused search results.
- retrievers – Retriever implementations for entity, chunk, BFS, and text2cypher search.
- search_engine – Retrieval's public entry point, independent of Graph (ADR 0035).
- settings – Env-backed configuration for retrieval methods and fusion.
agrag.retrieval.errors
Errors that the retrieval layer raises.
Classes:
- AllRetrievalMethodsFailedError – Every retrieval method a Recipe named failed.
- RetrievalError – The base class for every retrieval error.
- UnknownRecipeMethodError – A Recipe named a method SearchEngine does not know how to run.
agrag.retrieval.errors.AllRetrievalMethodsFailedError
AllRetrievalMethodsFailedError(failures:dict[str, BaseException]) -> None
Bases: RetrievalError
Every retrieval method a Recipe named failed.
Raised instead of returning an empty result list so a total retrieval outage is not mistaken for a query with no matches.
Attributes:
- failures – Each failed method name mapped to the exception it raised.
agrag.retrieval.errors.AllRetrievalMethodsFailedError.failures
failures = failures
agrag.retrieval.errors.RetrievalError
Bases: Exception
The base class for every retrieval error.
agrag.retrieval.errors.UnknownRecipeMethodError
UnknownRecipeMethodError(unknown:list[str], known:list[str]) -> None
Bases: RetrievalError
A Recipe named a method SearchEngine does not know how to run.
A misspelled method name is a configuration error and must be raised at search time so an empty successful search cannot silently hide a typo.
Attributes:
- unknown – The method names the recipe listed that are not in the retriever registry.
- known – The method names this SearchEngine can run.
agrag.retrieval.errors.UnknownRecipeMethodError.known
known = list(known)
agrag.retrieval.errors.UnknownRecipeMethodError.unknown
unknown = list(unknown)
agrag.retrieval.filters
Constraints applied across every retrieval method in one call.
Classes:
- SearchFilters – Constraints applied across every retrieval method in one call.
agrag.retrieval.filters.SearchFilters
Bases: BaseModel
Constraints applied across every retrieval method in one call.
Attributes:
- labels (
list[str]) – Entity labels a result must have, when searching entities. - relation_types (
list[str]) – Relation types a traversal may cross. - document_ids (
list[str]) – Restrict chunk results to these source documents. - properties (
dict[str, Any]) – Exact-match property filters, applied identically to vector-store payload filters and Cypher WHERE clauses.
Functions:
- to_cypher_where – Return a parameterized WHERE clause fragment.
- to_payload_filter – Return a flat-dict filter for VectorStore search calls.
- to_property_filter – Return a flat-dict filter over node properties only.
agrag.retrieval.filters.SearchFilters.document_ids
document_ids: list[str] = Field(default_factory=list)
agrag.retrieval.filters.SearchFilters.labels
labels: list[str] = Field(default_factory=list)
agrag.retrieval.filters.SearchFilters.properties
properties: dict[str, Any] = Field(default_factory=dict)
agrag.retrieval.filters.SearchFilters.relation_types
relation_types: list[str] = Field(default_factory=list)
agrag.retrieval.filters.SearchFilters.to_cypher_where
to_cypher_where(node_var:str = 'node') -> tuple[str, dict[str, Any]]
Return a parameterized WHERE clause fragment.
Labels are emitted as native Cypher node labels (node:Label)
rather than property filters, since Neo4j represents entity types
as labels on nodes. Document-id and property filters go through
filter_clause as before.
Parameters:
- node_var (
str) – The Cypher variable bound to the node.
Returns:
agrag.retrieval.filters.SearchFilters.to_payload_filter
to_payload_filter() -> dict[str, Any]
Return a flat-dict filter for VectorStore search calls.
Labels become a label payload key, which is how a
VectorStore records the graph label a record came from. A
GraphStore holds labels on the node itself, not as a property,
so the native path uses to_property_filter instead and
selects labels by the index it searches.
Returns:
dict[str, Any]– A dict suitable for VectorStore.search/hybrid_searchdict[str, Any]– filters parameter.
agrag.retrieval.filters.SearchFilters.to_property_filter
to_property_filter() -> dict[str, Any]
Return a flat-dict filter over node properties only.
Excludes labels, which are node labels rather than
properties on every graph backend this project supports.
Returns:
dict[str, Any]– A dict of property name to expected value, where a listdict[str, Any]– value means any of.
agrag.retrieval.fusion
Reciprocal Rank Fusion: combine ranked results from multiple methods.
Functions:
- fuse – Combine every method's ranked results into one deduplicated list.
agrag.retrieval.fusion.fuse
fuse(results_by_method:dict[str, list[SearchResult]], *, rrf_k:int = 60) -> list[SearchResult]
Combine every method's ranked results into one deduplicated list.
Runs unconditionally, even for a single method, so a Rerank pass never sees duplicates. Uses Reciprocal Rank Fusion: an item's fused score is the sum of 1 / (rrf_k + rank) across every method that returned it.
Each method contributes at most one vote per item, scored at the
item's best (lowest) rank within that method. A multi-label
entity that surfaces in two positions of one method's output, or
a pre-fusion merged_into collapse, only adds one vote from
that method, so duplicate hits from a single retriever cannot
unfairly promote an item over a single best hit from another
method.
Deduplication uses SearchResult.identity_key, which is (type, id) after hydration has already resolved any merged_into chain to the live survivor. Fusion does not re-resolve identity; it trusts that every SearchResult it receives already carries a live id.
Parameters:
- results_by_method (
dict[str, list[SearchResult]]) – Each method's own ranked output, keyed by method name. - rrf_k (
int) – The RRF constant; higher values flatten the influence of rank position.
Returns:
list[SearchResult]– One list, ranked by fused score descending, one entry perlist[SearchResult]– distinct identity_key.
agrag.retrieval.identity
Shared identity resolution for merged_into chains.
Functions:
- resolve_entity – Return the live Entity behind an id, following merged_into.
Attributes:
agrag.retrieval.identity.MAX_MERGE_HOPS
MAX_MERGE_HOPS = 32
agrag.retrieval.identity.resolve_entity
resolve_entity(graph_store:GraphStore, entity_id:UUID) -> Entity
Return the live Entity behind an id, following merged_into.
Every retrieval path that can produce an entity id must call this before wrapping the id in a SearchResult. This is the single place the merged_into invariant is enforced.
A merge writes a merged_into property on the tombstone rather
than a relationship, so the chain is walked one hop per query.
Parameters:
- graph_store (
GraphStore) – Where the entity and its possible tombstone chain live. - entity_id (
UUID) – The id a retrieval method found, which may or may not still be live.
Returns:
Entity– The live Entity, after resolving zero or more hops.
Raises:
ValueError– The id does not exist, its node cannot be parsed, the chain points at a missing node, the chain cycles, or it is longer thanMAX_MERGE_HOPS.
agrag.retrieval.methods
Low-level search method helpers shared by retrievers.
Modules:
- vector – Shared vector search helper for GraphStore and VectorStore.
agrag.retrieval.methods.vector
Shared vector search helper for GraphStore and VectorStore.
Functions:
- vector_search – Embed query and search on whichever store is configured.
agrag.retrieval.methods.vector.vector_search
vector_search(query:str, *, embedder:Embedder, graph_store:GraphStore, vector_store:VectorStore | None, collection:str, labels:Sequence[str], limit:int, filters:SearchFilters | None, settings:RetrievalSettings) -> list[VectorHit]
Embed query and search on whichever store is configured.
When vector_store is set, runs hybrid_search there (dense plus
BM25, blended by settings.hybrid_alpha) against collection.
When it is None, runs GraphStore's native vector_search once per
label in labels and merges the hits, ignoring hybrid_alpha
since that path is dense-only. One native vector index exists per
label, so a search over several labels is several searches.
Parameters:
- query (
str) – The natural-language query text to embed. - embedder (
Embedder) – Produces the query's dense vector. - graph_store (
GraphStore) – The GraphStore-native fallback target. - vector_store (
VectorStore | None) – The optional VectorStore target; None selects the GraphStore-native path. - collection (
str) – The VectorStore collection name. - labels (
Sequence[str]) – The node labels to search on the GraphStore-native path, each backed by its own vector index. - limit (
int) – Maximum hits to return. - filters (
SearchFilters | None) – Constraints translated to whichever store is searched. Labels are a payload key on the VectorStore path and choose the searched indexes on the native path, so they are not sent as node property filters. - settings (
RetrievalSettings) – Supplies hybrid_alpha for the VectorStore path.
Returns:
Raises:
ValueError– The native path was selected with no labels to search.
agrag.retrieval.recipes
Named, data-only configurations of what SearchEngine runs.
Classes:
- Recipe – A named configuration of what SearchEngine runs for a query.
Attributes:
- CHUNK –
- ENTITY –
- GRAPH_EXPAND –
- HYBRID –
- HYBRID_RERANKED –
agrag.retrieval.recipes.CHUNK
CHUNK = Recipe(methods=['chunk'], limit=10)
agrag.retrieval.recipes.ENTITY
ENTITY = Recipe(methods=['entity'], limit=10)
agrag.retrieval.recipes.GRAPH_EXPAND
GRAPH_EXPAND = Recipe(methods=['entity'], bfs=True, limit=20)
agrag.retrieval.recipes.HYBRID
HYBRID = Recipe(methods=['entity', 'chunk'], limit=10)
agrag.retrieval.recipes.HYBRID_RERANKED
HYBRID_RERANKED = Recipe(methods=['entity', 'chunk'], reranker='cross_encoder', limit=10)
agrag.retrieval.recipes.Recipe
Bases: BaseModel
A named configuration of what SearchEngine runs for a query.
Attributes:
- methods (
list[str]) – Which retrieval methods to fan out to concurrently, by name. - bfs (
bool) – Whether to run a BFS expansion after methods complete, seeded from their entity results. BFS needs seed ids methods produce, so it cannot run concurrently with them. - bfs_depth (
int | None) – Traversal depth when bfs is true. None uses RetrievalSettings.traversal_depth. - reranker (
Literal['cross_encoder', 'node_distance'] | None) – The optional Rerank pass to run after Fusion. None skips reranking. - limit (
int) – The maximum number of results SearchEngine returns.
agrag.retrieval.recipes.Recipe.bfs
bfs: bool = False
agrag.retrieval.recipes.Recipe.bfs_depth
bfs_depth: int | None = None
agrag.retrieval.recipes.Recipe.limit
limit: int = 10
agrag.retrieval.recipes.Recipe.methods
methods: list[str]
agrag.retrieval.recipes.Recipe.reranker
reranker: Literal['cross_encoder', 'node_distance'] | None = None
agrag.retrieval.rerank
Rerankers that reorder fused search results.
Modules:
- cross_encoder – Cross-encoder reranker using sentence-transformers.
- node_distance – Node distance reranker: reorder by graph proximity to seeds.
agrag.retrieval.rerank.cross_encoder
Cross-encoder reranker using sentence-transformers.
Functions:
- cross_encoder_rerank – Rerank results using a cross-encoder model.
agrag.retrieval.rerank.cross_encoder.cross_encoder_rerank
cross_encoder_rerank(query:str, results:list[SearchResult], *, min_score:float | None = None) -> list[SearchResult]
Rerank results using a cross-encoder model.
Requires the embed-local extra (sentence-transformers).
Scores (query, text) pairs and reorders by relevance. Drops
results scoring below min_score when set.
Parameters:
- query (
str) – The natural-language query text. - results (
list[SearchResult]) – The fused results to rerank. - min_score (
float | None) – Optional minimum score threshold. Results below this are dropped.
Returns:
list[SearchResult]– Results reranked by cross-encoder score, descending.
agrag.retrieval.rerank.node_distance
Node distance reranker: reorder by graph proximity to seeds.
Functions:
- node_distance_rerank – Rerank results by graph proximity to seed entity ids.
agrag.retrieval.rerank.node_distance.node_distance_rerank
node_distance_rerank(results:list[SearchResult], *, graph_store:GraphStore, seed_ids:list[UUID]) -> list[SearchResult]
Rerank results by graph proximity to seed entity ids.
Uses shortest-path distance from each result entity to the closest seed entity. Entities closer to seeds rank higher. Results without an entity item (chunks, relations) are placed at the end with a high distance penalty.
Parameters:
- results (
list[SearchResult]) – The fused results to rerank. - graph_store (
GraphStore) – The graph store for shortest-path queries. - seed_ids (
list[UUID]) – The seed entity ids to measure distance from. Seeds are the query's direct hits, not the whole candidate list: a candidate that is its own seed measures distance zero, so seeding with every candidate leaves the order unchanged.
Returns:
list[SearchResult]– Results reranked by proximity, closest first.
agrag.retrieval.retrievers
Retriever implementations for entity, chunk, BFS, and text2cypher search.
Modules:
- base – Abstract base class for retrieval methods.
- bfs – BFS retriever: graph traversal from seed entity ids.
- chunk – Chunk retriever: dense vector search over chunks.
- entity – Entity retriever: dense vector search over entities.
- text2cypher – Text2Cypher retriever: generate Cypher from natural language.
agrag.retrieval.retrievers.base
Abstract base class for retrieval methods.
Classes:
- Retriever – One retrieval method: given a query, return SearchResults.
agrag.retrieval.retrievers.base.Retriever
Bases: ABC
One retrieval method: given a query, return SearchResults.
Subclasses own exactly one strategy (dense entity search, chunk search, BFS expansion). SearchEngine fans a query out to every Retriever a Recipe names and hands the combined output to Fusion.
Functions:
- retrieve – Run this retrieval method and return hydrated results.
Attributes:
####### agrag.retrieval.retrievers.base.Retriever.name
name: str
####### agrag.retrieval.retrievers.base.Retriever.retrieve
retrieve(query:str, *, filters:SearchFilters | None = None, limit:int = 10) -> list[SearchResult]
Run this retrieval method and return hydrated results.
agrag.retrieval.retrievers.bfs
BFS retriever: graph traversal from seed entity ids.
Classes:
- BFSRetriever – Graph traversal from seed entity ids.
agrag.retrieval.retrievers.bfs.BFSRetriever
BFSRetriever(*, graph_store:GraphStore, settings:RetrievalSettings | None = None) -> None
Bases: Retriever
Graph traversal from seed entity ids.
Takes seed entity ids (from a prior EntityRetriever call, or supplied directly), runs bfs_expand_query, and hydrates the returned entities through resolve_entity and relations directly. Degree-capped by RetrievalSettings.traversal_limit.
Functions:
- retrieve – Run BFS expansion from seed entity ids.
Attributes:
- name –
Parameters:
- graph_store (
GraphStore) – The graph store to traverse. - settings (
RetrievalSettings | None) – Retrieval configuration; defaults from environment.
####### agrag.retrieval.retrievers.bfs.BFSRetriever.name
name = 'bfs'
####### agrag.retrieval.retrievers.bfs.BFSRetriever.retrieve
retrieve(query:str, *, filters:SearchFilters | None = None, limit:int | None = None, seed_ids:list[UUID] | None = None, depth:int | None = None) -> list[SearchResult]
Run BFS expansion from seed entity ids.
Parameters:
- query (
str) – The natural-language query text (unused for BFS, kept for interface consistency). - filters (
SearchFilters | None) – Constraints applied to traversal. relation_types restrict which relationships the traversal crosses; property filters apply to neighbor nodes. - limit (
int | None) – Maximum results. None uses traversal_limit. - seed_ids (
list[UUID] | None) – The entity ids to expand from. If None, BFS returns empty. - depth (
int | None) – BFS hops. None uses RetrievalSettings.traversal_depth.
Returns:
list[SearchResult]– SearchResults with entities and relations found via BFS.
agrag.retrieval.retrievers.chunk
Chunk retriever: dense vector search over chunks.
Classes:
- ChunkRetriever – Dense chunk search via vector similarity.
agrag.retrieval.retrievers.chunk.ChunkRetriever
ChunkRetriever(*, graph_store:GraphStore, embedder:Embedder, vector_store:VectorStore | None = None, settings:RetrievalSettings | None = None) -> None
Bases: Retriever
Dense chunk search via vector similarity.
Chunks are never tombstoned, so no merged_into resolution is
needed. Embeds the query, searches via the GraphStore-native or
VectorStore path, then hydrates each hit into a Chunk. The native
path searches the Chunk vector index ingestion provisions; the
VectorStore path searches chunk_collection.
Functions:
- retrieve – Run chunk search and return hydrated results.
Attributes:
- name –
Parameters:
- graph_store (
GraphStore) – Backs chunk search when vector_store is absent. - embedder (
Embedder) – Produces query vectors. - vector_store (
VectorStore | None) – Optional VectorStore for hybrid search. - settings (
RetrievalSettings | None) – Retrieval configuration; defaults from environment.
####### agrag.retrieval.retrievers.chunk.ChunkRetriever.name
name = 'chunk'
####### agrag.retrieval.retrievers.chunk.ChunkRetriever.retrieve
retrieve(query:str, *, filters:SearchFilters | None = None, limit:int | None = None) -> list[SearchResult]
Run chunk search and return hydrated results.
Parameters:
- query (
str) – The natural-language query text. - filters (
SearchFilters | None) – Constraints applied to the search. - limit (
int | None) – Maximum results. None uses settings.chunk_top_k.
Returns:
list[SearchResult]– Ranked SearchResults with hydrated Chunk items.
agrag.retrieval.retrievers.entity
Entity retriever: dense vector search over entities.
Classes:
- EntityRetriever – Dense entity search via vector similarity.
agrag.retrieval.retrievers.entity.EntityRetriever
EntityRetriever(*, graph_store:GraphStore, embedder:Embedder, vector_store:VectorStore | None = None, settings:RetrievalSettings | None = None, entity_labels:Sequence[str] | None = None) -> None
Bases: Retriever
Dense entity search via vector similarity.
Embeds the query, searches via the GraphStore-native or
VectorStore path, then resolves every hit through
resolve_entity so the caller can trust item.id is live.
The native path searches one vector index per entity label, so it
needs the labels ingestion provisioned indexes for: the label
filter when the caller sets one, otherwise entity_labels.
Functions:
- retrieve – Run entity search and return hydrated results.
Attributes:
- name –
Parameters:
- graph_store (
GraphStore) – Backs entity search when vector_store is absent. - embedder (
Embedder) – Produces query vectors. - vector_store (
VectorStore | None) – Optional VectorStore for hybrid search. - settings (
RetrievalSettings | None) – Retrieval configuration; defaults from environment. - entity_labels (
Sequence[str] | None) – The schema entity labels native search runs against. None uses settings.entity_labels.
####### agrag.retrieval.retrievers.entity.EntityRetriever.name
name = 'entity'
####### agrag.retrieval.retrievers.entity.EntityRetriever.retrieve
retrieve(query:str, *, filters:SearchFilters | None = None, limit:int | None = None) -> list[SearchResult]
Run entity search and return hydrated results.
Parameters:
- query (
str) – The natural-language query text. - filters (
SearchFilters | None) – Constraints applied to the search. - limit (
int | None) – Maximum results. None uses settings.entity_top_k.
Returns:
list[SearchResult]– Ranked SearchResults with resolved entity ids.
Raises:
ValueError– Native search was selected and neither the filter nor the configuration names an entity label.
agrag.retrieval.retrievers.text2cypher
Text2Cypher retriever: generate Cypher from natural language.
Classes:
- Text2CypherRetriever – Let the agent ask structured questions via generated Cypher.
Attributes:
- logger –
agrag.retrieval.retrievers.text2cypher.Text2CypherRetriever
Text2CypherRetriever(*, graph_store:GraphStore, settings:RetrievalSettings | None = None) -> None
Bases: Retriever
Let the agent ask structured questions via generated Cypher.
Calls a BAML function to generate a read-only Cypher query, runs reject_write_cypher as a safety pre-filter, then bounds the query with a row limit and a server-side transaction timeout before EXPLAIN and execution. Rows that carry an entity id are resolved through resolve_entity before becoming a SearchResult; relationship and chunk rows are parsed directly. Scalar rows (for example counts or property values) cannot become a SearchResult and are logged instead of being silently dropped.
Functions:
- retrieve – Generate and execute a Cypher query for the question.
Attributes:
- name –
Parameters:
- graph_store (
GraphStore) – Where the generated query runs. - settings (
RetrievalSettings | None) – Retrieval configuration; defaults from environment.
####### agrag.retrieval.retrievers.text2cypher.Text2CypherRetriever.name
name = 'text2cypher'
####### agrag.retrieval.retrievers.text2cypher.Text2CypherRetriever.retrieve
retrieve(query:str, *, filters:SearchFilters | None = None, limit:int = 10) -> list[SearchResult]
Generate and execute a Cypher query for the question.
Parameters:
- query (
str) – The natural-language question. - filters (
SearchFilters | None) – Ignored; text2cypher applies its own filters. - limit (
int) – Maximum results to return.
Returns:
list[SearchResult]– SearchResults from the generated query: entity results resolved throughresolve_entity; relation and chunk rows parsed directly. Rows with no entity, relation, or chunk item are logged and skipped.
agrag.retrieval.retrievers.text2cypher.logger
logger = logging.getLogger(__name__)
agrag.retrieval.search_engine
Retrieval's public entry point, independent of Graph (ADR 0035).
Classes:
- SearchEngine – Retrieval's public entry point, independent of Graph.
Attributes:
- logger –
agrag.retrieval.search_engine.SearchEngine
SearchEngine(*, graph_store:GraphStore, embedder:Embedder, vector_store:VectorStore | None = None, settings:RetrievalSettings | None = None, entity_labels:Sequence[str] | None = None) -> None
Retrieval's public entry point, independent of Graph.
Fans a query out to every method a Recipe names, fuses the results, and optionally reranks them. Constructed from its own stores; does not depend on a Graph instance existing.
Functions:
- search – Run recipe's methods, fuse, expand, and optionally rerank.
Parameters:
- graph_store (
GraphStore) – Always required; backs entity/chunk search when vector_store is absent, and always backs BFS. - embedder (
Embedder) – Produces query vectors for dense and hybrid search. - vector_store (
VectorStore | None) – Optional. When set, entity and chunk search run hybrid_search there instead of GraphStore's native search. Configuring one without a dual-write ingestion change gets an empty result set, not an error. - settings (
RetrievalSettings | None) – Retrieval configuration; defaults from environment. - entity_labels (
Sequence[str] | None) – The schema entity labels native entity search runs against, one vector index each, as provisioned byGraph.open. Pass[entity.label for entity in schema.entities]. None uses settings.entity_labels. Ignored when a vector_store is configured.
agrag.retrieval.search_engine.SearchEngine.search
search(query:str, recipe:Recipe, *, filters:SearchFilters | None = None) -> list[SearchResult]
Run recipe's methods, fuse, expand, and optionally rerank.
Runs recipe.methods concurrently and fuses their output first. When recipe.bfs is set, BFS runs as a second, sequential step seeded from the fused entity results. BFS results are fused into the same list a second time before reranking.
Parameters:
- query (
str) – The natural-language query text. - recipe (
Recipe) – Which methods to run, whether to expand via BFS afterward, and which reranker, if any, follows. - filters (
SearchFilters | None) – Constraints applied identically to every method.
Returns:
list[SearchResult]– Up to recipe.limit results, ranked highest-relevancelist[SearchResult]– first.
Raises:
AllRetrievalMethodsFailedError– Every method the recipe names failed. A method failing while others succeed is logged and its results are simply absent.UnknownRecipeMethodError– The recipe names one or more methods that are not in the retriever registry. A misspelled method name is a configuration error and is reported instead of silently returning no results.
agrag.retrieval.search_engine.logger
logger = logging.getLogger(__name__)
agrag.retrieval.settings
Env-backed configuration for retrieval methods and fusion.
Classes:
- RetrievalSettings – Configuration for retrieval methods and fusion.
agrag.retrieval.settings.RetrievalSettings
Bases: BaseSettings
Configuration for retrieval methods and fusion.
Attributes:
- entity_collection (
str) – The VectorStore collection name for entity search. Only read when a VectorStore is configured on SearchEngine; ignored on the GraphStore-native path. - chunk_collection (
str) – The VectorStore collection name for chunk search. Same condition as entity_collection. - entity_labels (
list[str]) – The graph labels native entity search runs against, one vector index each. These are the schema's entity labels, never a VectorStore collection name. Only read when no VectorStore is configured and the caller passes no label filter. - node_distance_seed_top_k (
int) – How many of the highest-ranked entity hits seed the node-distance reranker. Candidates are ordered by graph distance to those seeds. - entity_top_k (
int) – Results requested per entity search call. - chunk_top_k (
int) – Results requested per chunk search call. - hybrid_alpha (
float) – Dense-versus-keyword blend for hybrid search, 0 to 1. Only meaningful on the VectorStore path; GraphStore-native search is dense-only and ignores this. - traversal_depth (
int) – Maximum BFS hops from a seed entity. - traversal_limit (
int) – Maximum nodes a BFS expansion can return. - rrf_k (
int) – The RRF constant controlling how much rank position matters. - reranker_min_score (
float | None) – Results scoring below this after rerank are dropped. None disables the threshold. - text2cypher_max_retries (
int) – Maximum retry attempts for a text2cypher generation that produces invalid Cypher. - text2cypher_timeout_seconds (
float | None) – Server-side transaction timeout applied to generated read queries. The database terminates a generated query that runs longer, so a pathological query cannot hold server resources indefinitely. None uses the server's default timeout. - text2cypher_max_rows (
int) – Maximum rows a generated read query may return. Appended as a LIMIT clause when the generated query declares none of its own.
Env prefix: RETRIEVAL_.
agrag.retrieval.settings.RetrievalSettings.chunk_collection
chunk_collection: str = 'agrag_chunks'
agrag.retrieval.settings.RetrievalSettings.chunk_top_k
chunk_top_k: int = 10
agrag.retrieval.settings.RetrievalSettings.entity_collection
entity_collection: str = 'agrag_entities'
agrag.retrieval.settings.RetrievalSettings.entity_labels
entity_labels: list[str] = []
agrag.retrieval.settings.RetrievalSettings.entity_top_k
entity_top_k: int = 10
agrag.retrieval.settings.RetrievalSettings.hybrid_alpha
hybrid_alpha: float = 0.5
agrag.retrieval.settings.RetrievalSettings.model_config
model_config = SettingsConfigDict(env_prefix='RETRIEVAL_', env_file='.env', extra='ignore')
agrag.retrieval.settings.RetrievalSettings.node_distance_seed_top_k
node_distance_seed_top_k: int = 3
agrag.retrieval.settings.RetrievalSettings.reranker_min_score
reranker_min_score: float | None = None
agrag.retrieval.settings.RetrievalSettings.rrf_k
rrf_k: int = 60
agrag.retrieval.settings.RetrievalSettings.text2cypher_max_retries
text2cypher_max_retries: int = 3
agrag.retrieval.settings.RetrievalSettings.text2cypher_max_rows
text2cypher_max_rows: int = 1000
agrag.retrieval.settings.RetrievalSettings.text2cypher_timeout_seconds
text2cypher_timeout_seconds: float | None = 10.0
agrag.retrieval.settings.RetrievalSettings.traversal_depth
traversal_depth: int = 2
agrag.retrieval.settings.RetrievalSettings.traversal_limit
traversal_limit: int = 50
agrag.vectordb
Vector storage backends and the build shortcut.
Modules:
- base – The VectorStore abstraction and its build shortcut.
- errors – Errors that the vector-store layer raises.
- milvus – Milvus vector-store backend.
- qdrant – Qdrant vector-store backend.
- settings – Settings for vector-store backends.
- weaviate – Weaviate vector-store backend.
Classes:
- CollectionDimensionMismatchError – A collection already exists with a different embedding dimension.
- MilvusSettings – Milvus connection configuration.
- MilvusVectorStore – A
VectorStorebacked by Milvus, including native hybrid search. - QdrantSettings – Qdrant connection configuration.
- QdrantVectorStore – A
VectorStorebacked by Qdrant, including native hybrid search. - VectorStore – A vector database backend: collection lifecycle, writes, and search.
- VectorStoreError – The base class for every vector-store error.
- VectorStoreMissingExtraError – A vector store exists, but its package extra is not installed.
- WeaviateSettings – Weaviate connection configuration.
- WeaviateVectorStore – A
VectorStorebacked by Weaviate, including native hybrid search.
Functions:
- build_vector_store – Build a vector store from a backend name, or return one unchanged.
agrag.vectordb.CollectionDimensionMismatchError
CollectionDimensionMismatchError(*, expected:int, actual:int) -> None
Bases: VectorStoreError
A collection already exists with a different embedding dimension.
Attributes:
- expected – The dimension the collection was created with.
- actual – The dimension the caller requested.
agrag.vectordb.CollectionDimensionMismatchError.actual
actual = actual
agrag.vectordb.CollectionDimensionMismatchError.expected
expected = expected
agrag.vectordb.MilvusSettings
Bases: BaseSettings
Milvus connection configuration.
Attributes:
- uri (
str) – The Milvus endpoint URI. Env:MILVUS_URI. - token (
str) – The Milvus auth token. Empty string for an unauthenticated instance. Env:MILVUS_TOKEN. - require_tls (
bool) – WhenTrue, reject a plaintexturito a non-local host even with notokenconfigured. Off by default since many deployments run an unauthenticated Milvus on a private network and rely on network segmentation rather than transport encryption. Env:MILVUS_REQUIRE_TLS.
Raises:
ValueError–uriis plaintext (http), points at a non-local host, and eithertokenis set orrequire_tlsisTrue. Usehttpsfor a remote Milvus instance.
agrag.vectordb.MilvusSettings.model_config
model_config = SettingsConfigDict(env_prefix='MILVUS_', env_file='.env', extra='ignore')
agrag.vectordb.MilvusSettings.require_tls
require_tls: bool = False
agrag.vectordb.MilvusSettings.token
token: str = ''
agrag.vectordb.MilvusSettings.uri
uri: str = 'http://localhost:19530'
agrag.vectordb.MilvusVectorStore
MilvusVectorStore(*, settings:MilvusSettings | None = None, client:Any | None = None) -> None
Bases: VectorStore
A VectorStore backed by Milvus, including native hybrid search.
The client connects lazily on first use, so constructing the store does not
open a network connection. Milvus performs BM25 server-side, so hybrid
search needs no client-side sparse embedder; the sparse vector is computed
by a Milvus Function from the text field on write and at query time.
Functions:
- close – Release the backend connection.
- collection_exists – Report whether a collection exists.
- count – Count records in a collection.
- delete – Delete records by id.
- delete_collection – Delete a collection and all its entities.
- ensure_collection – Create the collection if it does not exist.
- hybrid_search – Search by dense vector and keyword text in one fused call.
- initialize – Check connectivity and authentication.
- invalidate_collection – Drop cached distance-metric knowledge of a collection.
- retrieve – Fetch records by id.
- scroll – Iterate records in a collection, in batches.
- search – Search by dense vector only.
- upsert – Write or overwrite records in a collection.
Parameters:
- settings (
MilvusSettings | None) – Milvus connection settings. Defaults toMilvusSettings(). - client (
Any | None) – A pre-builtAsyncMilvusClient, for tests. When set,__init__imports nothing and the store calls this object directly instead of building one.
agrag.vectordb.MilvusVectorStore.close
close() -> None
Release the backend connection.
agrag.vectordb.MilvusVectorStore.collection_exists
collection_exists(name:str) -> bool
Report whether a collection exists.
Parameters:
- name (
str) – The collection name.
Returns:
bool–Trueif the collection exists.
agrag.vectordb.MilvusVectorStore.count
count(collection:str, *, filters:dict[str, Any] | None = None) -> int
Count records in a collection.
Parameters:
- collection (
str) – The collection to count. - filters (
dict[str, Any] | None) – A flat-dict filter on scalar fields.
Returns:
int– The number of matching records.
agrag.vectordb.MilvusVectorStore.delete
delete(collection:str, ids:Sequence[UUID]) -> None
Delete records by id.
Parameters:
agrag.vectordb.MilvusVectorStore.delete_collection
delete_collection(name:str) -> None
Delete a collection and all its entities.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.MilvusVectorStore.ensure_collection
ensure_collection(name:str, *, dimensions:int, distance:Distance, hybrid:bool = False) -> None
Create the collection if it does not exist.
Milvus performs BM25 server-side, so the sparse field and its Function
are always provisioned; the hybrid flag is accepted for interface
parity but is a no-op here. An existing collection must already carry
this same fixed schema, since upsert and hybrid_search always
read and write every field regardless of hybrid.
Parameters:
- name (
str) – The collection name. - dimensions (
int) – The embedding dimension. - distance (
Distance) – The distance metric new collections use. - hybrid (
bool) – Accepted for interface parity; ignored by Milvus.
Raises:
CollectionDimensionMismatchError– The collection exists with a different dimension thandimensions.VectorStoreError– The collection exists but is missing a field or index this adapter requires.
agrag.vectordb.MilvusVectorStore.hybrid_search
hybrid_search(collection:str, query_vector:Sequence[float], query_text:str, *, limit:int = 10, filters:dict[str, Any] | None = None, alpha:float = 0.5) -> list[VectorHit]
Search by dense vector and keyword text in one fused call.
Fusion uses Milvus's native weighted reranker, which normalizes each
request's scores before applying alpha.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - query_text (
str) – The query text, matched by BM25. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on scalar fields. - alpha (
float) – The dense/keyword balance.1.0is pure dense,0.0is pure keyword.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT, oralphais outside[0.0, 1.0].
agrag.vectordb.MilvusVectorStore.initialize
initialize() -> None
Check connectivity and authentication.
agrag.vectordb.MilvusVectorStore.invalidate_collection
invalidate_collection(name:str) -> None
Drop cached distance-metric knowledge of a collection.
This store caches a collection's distance metric after the first
call that resolves it, on the assumption that it alone (via
ensure_collection/delete_collection) owns the collection's
lifecycle for as long as this instance is in use. If something
outside this instance deletes and recreates a collection under the
same name with a different metric, call this first so the next call
re-resolves that collection's metric from the backend instead of
trusting the stale cache.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.MilvusVectorStore.retrieve
retrieve(collection:str, ids:Sequence[UUID]) -> list[VectorRecord]
Fetch records by id.
Requests at most MAX_RESPONSE_LIMIT ids per call, so a large
ids list cannot exceed Milvus's response-size ceiling in one
request the way sending every id at once would.
Parameters:
Returns:
list[VectorRecord]– The records that exist, in the requested order, omitting missinglist[VectorRecord]– ids.
agrag.vectordb.MilvusVectorStore.scroll
scroll(collection:str, *, limit:int = 100, page_offset:str | None = None, filters:dict[str, Any] | None = None, with_vectors:bool = False) -> tuple[list[VectorRecord], str | None]
Iterate records in a collection, in batches.
Milvus rejects a query whose offset + limit exceeds
MAX_RESPONSE_LIMIT, so a numeric offset cannot page past that
many total records. Pages instead cursor on the id primary key:
each page filters on id > page_offset and orders by id
ascending, which needs no offset at all and so never hits that
window regardless of collection size. The explicit order is load
bearing: without it, an unordered query result could omit rows at or
below the next cursor, permanently skipping them on the next page.
Parameters:
- collection (
str) – The collection to read. - limit (
int) – The maximum number of records per page. - page_offset (
str | None) – The id cursor from a previousscrollcall. - filters (
dict[str, Any] | None) – A flat-dict filter on scalar fields. - with_vectors (
bool) – Whether to return each record's vector.
Returns:
list[VectorRecord]– The page of records and the next page cursor, orNoneat thestr | None– end.
agrag.vectordb.MilvusVectorStore.search
search(collection:str, query_vector:Sequence[float], *, limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search by dense vector only.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on scalar fields.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT.
agrag.vectordb.MilvusVectorStore.upsert
upsert(collection:str, records:Sequence[VectorRecord], *, batch_size:int = 256) -> None
Write or overwrite records in a collection.
Parameters:
- collection (
str) – The collection to write to. - records (
Sequence[VectorRecord]) – The records to upsert, in order. - batch_size (
int) – The number of records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.vectordb.QdrantSettings
Bases: BaseSettings
Qdrant connection configuration.
Attributes:
- url (
str) – The Qdrant endpoint URL. Env:QDRANT_URL. - api_key (
str) – The Qdrant API key. Env:QDRANT_API_KEY. - require_tls (
bool) – WhenTrue, reject a plaintexturlto a non-local host even with noapi_keyconfigured. Off by default since many deployments run an unauthenticated Qdrant on a private network and rely on network segmentation rather than transport encryption. Env:QDRANT_REQUIRE_TLS.
Raises:
ValueError–urlis plaintext (http), points at a non-local host, and eitherapi_keyis set orrequire_tlsisTrue. Usehttpsfor a remote Qdrant instance.
agrag.vectordb.QdrantSettings.api_key
api_key: str = ''
agrag.vectordb.QdrantSettings.model_config
model_config = SettingsConfigDict(env_prefix='QDRANT_', env_file='.env', extra='ignore')
agrag.vectordb.QdrantSettings.require_tls
require_tls: bool = False
agrag.vectordb.QdrantSettings.url
url: str = 'http://localhost:6333'
agrag.vectordb.QdrantVectorStore
QdrantVectorStore(*, settings:QdrantSettings | None = None, sparse_embedder:SparseEmbedder | None = None, client:Any | None = None, models:Any | None = None) -> None
Bases: VectorStore
A VectorStore backed by Qdrant, including native hybrid search.
The client connects lazily on first use, so constructing the store does not
open a network connection. Hybrid search builds its sparse query with a
SparseEmbedder that defaults to FastEmbed BM25 and loads only when a
hybrid call first runs, not at construction.
Functions:
- close – Release the backend connection.
- collection_exists – Report whether a collection exists.
- count – Count records in a collection.
- delete – Delete records by id.
- delete_collection – Delete a collection and all its points.
- ensure_collection – Create the collection if it does not exist.
- hybrid_search – Search by dense vector and keyword text, fused by a weighted blend.
- initialize – Check connectivity and authentication.
- invalidate_collection – Drop cached hybrid-state and distance-metric knowledge of a collection.
- retrieve – Fetch records by id.
- scroll – Iterate records in a collection, in batches.
- search – Search by dense vector only.
- upsert – Write or overwrite records in a collection.
Parameters:
- settings (
QdrantSettings | None) – Qdrant connection settings. Defaults toQdrantSettings(). - sparse_embedder (
SparseEmbedder | None) – The sparse embedder hybrid search uses. Defaults to a lazily-builtFastEmbedBM25Embedder. - client (
Any | None) – A pre-builtAsyncQdrantClient, for tests. When set,__init__imports nothing and the store calls this object directly instead of building one. - models (
Any | None) – Theqdrant_client.modelsmodule, for tests. Pair withclientso filter/payload helpers work without needing the realqdrant_clientpackage installed at all.
agrag.vectordb.QdrantVectorStore.close
close() -> None
Release the backend connection.
agrag.vectordb.QdrantVectorStore.collection_exists
collection_exists(name:str) -> bool
Report whether a collection exists.
Parameters:
- name (
str) – The collection name.
Returns:
bool–Trueif the collection exists.
agrag.vectordb.QdrantVectorStore.count
count(collection:str, *, filters:dict[str, Any] | None = None) -> int
Count records in a collection.
Parameters:
- collection (
str) – The collection to count. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields.
Returns:
int– The number of matching records.
agrag.vectordb.QdrantVectorStore.delete
delete(collection:str, ids:Sequence[UUID]) -> None
Delete records by id.
Parameters:
agrag.vectordb.QdrantVectorStore.delete_collection
delete_collection(name:str) -> None
Delete a collection and all its points.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.QdrantVectorStore.ensure_collection
ensure_collection(name:str, *, dimensions:int, distance:Distance, hybrid:bool = False) -> None
Create the collection if it does not exist.
Parameters:
- name (
str) – The collection name. - dimensions (
int) – The embedding dimension. - distance (
Distance) – The distance metric new collections use. - hybrid (
bool) – Whether to provision the named sparse vector hybrid search needs.
Raises:
CollectionDimensionMismatchError– The collection exists with a different dimension thandimensions.VectorStoreError– The collection exists without hybrid search support andhybrid=Truewas requested.
agrag.vectordb.QdrantVectorStore.hybrid_search
hybrid_search(collection:str, query_vector:Sequence[float], query_text:str, *, limit:int = 10, filters:dict[str, Any] | None = None, alpha:float = 0.5) -> list[VectorHit]
Search by dense vector and keyword text, fused by a weighted blend.
Qdrant's native fusion methods (RRF, DBSF) have no continuous
dense/keyword weight, so this runs the dense and sparse (BM25)
searches independently, min-max normalizes each result set's scores
to [0, 1], then combines them per id as
alpha * dense + (1 - alpha) * sparse. Each side fetches a wider
candidate pool than limit so a document strong on only one signal
still has a chance to reach the blended top results.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - query_text (
str) – The query text, matched by BM25. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields. - alpha (
float) – The dense/keyword balance.1.0is pure dense,0.0is pure keyword.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT, oralphais outside[0.0, 1.0].
agrag.vectordb.QdrantVectorStore.initialize
initialize() -> None
Check connectivity and authentication.
agrag.vectordb.QdrantVectorStore.invalidate_collection
invalidate_collection(name:str) -> None
Drop cached hybrid-state and distance-metric knowledge of a collection.
This store caches a collection's hybrid support and distance metric
after the first call that resolves them, on the assumption that it
alone (via ensure_collection/delete_collection) owns the
collection's lifecycle for as long as this instance is in use. If
something outside this instance deletes and recreates a collection
under the same name with different config, call this first so the
next call re-resolves that collection's state from the backend
instead of trusting the stale cache.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.QdrantVectorStore.retrieve
retrieve(collection:str, ids:Sequence[UUID]) -> list[VectorRecord]
Fetch records by id.
Parameters:
Returns:
list[VectorRecord]– The records that exist, in the requested order, omitting missinglist[VectorRecord]– ids.
agrag.vectordb.QdrantVectorStore.scroll
scroll(collection:str, *, limit:int = 100, page_offset:str | None = None, filters:dict[str, Any] | None = None, with_vectors:bool = False) -> tuple[list[VectorRecord], str | None]
Iterate records in a collection, in batches.
Parameters:
- collection (
str) – The collection to read. - limit (
int) – The maximum number of records per page. - page_offset (
str | None) – The offset from a previousscrollcall. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields. - with_vectors (
bool) – Whether to return each record's vector.
Returns:
list[VectorRecord]– The page of records and the next page offset, orNoneat thestr | None– end.
agrag.vectordb.QdrantVectorStore.search
search(collection:str, query_vector:Sequence[float], *, limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search by dense vector only.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT.
agrag.vectordb.QdrantVectorStore.upsert
upsert(collection:str, records:Sequence[VectorRecord], *, batch_size:int = 256) -> None
Write or overwrite records in a collection.
When collection has sparse-vector support (created or previously
seen with ensure_collection(..., hybrid=True)), each record's
payload["text"] is also sparse-embedded and stored under the named
sparse vector, so hybrid_search's keyword arm has real vectors to
match. A record with no text payload key gets an empty sparse
vector and only ever surfaces through the dense side of a hybrid
search.
Parameters:
- collection (
str) – The collection to write to. - records (
Sequence[VectorRecord]) – The records to upsert, in order. - batch_size (
int) – The number of records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.vectordb.VectorStore
Bases: ABC
A vector database backend: collection lifecycle, writes, and search.
Functions:
- close – Release the backend connection.
- collection_exists – Report whether a collection exists.
- count – Count records in a collection.
- delete – Delete records by id.
- delete_collection – Delete a collection and all its points.
- ensure_collection – Create the collection if it does not exist.
- hybrid_search – Search by dense vector and keyword text in one fused call.
- initialize – Check connectivity and authentication.
- retrieve – Fetch records by id.
- scroll – Iterate records in a collection, in batches.
- search – Search by dense vector only.
- upsert – Write or overwrite records in a collection.
agrag.vectordb.VectorStore.close
close() -> None
Release the backend connection.
agrag.vectordb.VectorStore.collection_exists
collection_exists(name:str) -> bool
Report whether a collection exists.
Parameters:
- name (
str) – The collection name.
Returns:
bool–Trueif the collection exists.
agrag.vectordb.VectorStore.count
count(collection:str, *, filters:dict[str, Any] | None = None) -> int
Count records in a collection.
Parameters:
- collection (
str) – The collection to count. - filters (
dict[str, Any] | None) – A flat-dict filter: a scalar value means exact match, a list value means any of, and all keys are AND-ed together. Keys must be valid identifiers (letters, digits, underscore, not starting with a digit) to stay portable: Milvus compiles them into a filter expression and Neo4j'sGraphStorecounterpart compiles them into Cypher, so both reject other characters, while Qdrant and Weaviate accept arbitrary payload keys.
Returns:
int– The number of matching records.
agrag.vectordb.VectorStore.delete
delete(collection:str, ids:Sequence[UUID]) -> None
Delete records by id.
Parameters:
agrag.vectordb.VectorStore.delete_collection
delete_collection(name:str) -> None
Delete a collection and all its points.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.VectorStore.ensure_collection
ensure_collection(name:str, *, dimensions:int, distance:Distance, hybrid:bool = False) -> None
Create the collection if it does not exist.
Parameters:
- name (
str) – The collection name. - dimensions (
int) – The embedding dimension. If the collection already exists with a different dimension, this raises. - distance (
Distance) – The distance metric new collections use. - hybrid (
bool) – Whether to additionally provision the sparse-vector configuration hybrid search needs. Ignored by backends that need no such provisioning.
Raises:
CollectionDimensionMismatchError– The collection exists with a different dimension thandimensions.
agrag.vectordb.VectorStore.hybrid_search
hybrid_search(collection:str, query_vector:Sequence[float], query_text:str, *, limit:int = 10, filters:dict[str, Any] | None = None, alpha:float = 0.5) -> list[VectorHit]
Search by dense vector and keyword text in one fused call.
Parameters:
- collection (
str) – The collection to search. Must have been created withensure_collection(..., hybrid=True). - query_vector (
Sequence[float]) – The dense query embedding. - query_text (
str) – The query text, matched by keyword/BM25. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter: a scalar value means exact match, a list value means any of, and all keys are AND-ed together. Keys must be valid identifiers (letters, digits, underscore, not starting with a digit) to stay portable: Milvus compiles them into a filter expression and Neo4j'sGraphStorecounterpart compiles them into Cypher, so both reject other characters, while Qdrant and Weaviate accept arbitrary payload keys. - alpha (
float) – The dense/keyword balance.1.0is pure dense,0.0is pure keyword. Weaviate and Milvus apply this weight natively. Qdrant's native fusion (Reciprocal Rank Fusion) has no continuous weight, so it appliesalphaby blending two independently-scored, min-max normalized result sets instead of a single native fused call.
Returns:
Raises:
ValueError–limitis not positive, or exceedsagrag.common.validation.MAX_SEARCH_LIMIT, oralphais outside[0.0, 1.0]. Enforced uniformly across backends since they otherwise fail differently outside that range.
agrag.vectordb.VectorStore.initialize
initialize() -> None
Check connectivity and authentication.
Raises:
VectorStoreError– The backend is unreachable, or the credentials are rejected.
agrag.vectordb.VectorStore.retrieve
retrieve(collection:str, ids:Sequence[UUID]) -> list[VectorRecord]
Fetch records by id.
Parameters:
Returns:
list[VectorRecord]– The records that exist, in the requested order, omitting missinglist[VectorRecord]– ids.
agrag.vectordb.VectorStore.scroll
scroll(collection:str, *, limit:int = 100, page_offset:str | None = None, filters:dict[str, Any] | None = None, with_vectors:bool = False) -> tuple[list[VectorRecord], str | None]
Iterate records in a collection, in batches.
Parameters:
- collection (
str) – The collection to read. - limit (
int) – The maximum number of records per page. - page_offset (
str | None) – The offset from a previousscrollcall, orNoneto start at the beginning. - filters (
dict[str, Any] | None) – A flat-dict filter: a scalar value means exact match, a list value means any of, and all keys are AND-ed together. Keys must be valid identifiers (letters, digits, underscore, not starting with a digit) to stay portable: Milvus compiles them into a filter expression and Neo4j'sGraphStorecounterpart compiles them into Cypher, so both reject other characters, while Qdrant and Weaviate accept arbitrary payload keys. - with_vectors (
bool) – Whether to return each record's vector.
Returns:
list[VectorRecord]– The page of records and the next page offset, orNoneat thestr | None– end.
agrag.vectordb.VectorStore.search
search(collection:str, query_vector:Sequence[float], *, limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search by dense vector only.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter: a scalar value means exact match, a list value means any of, and all keys are AND-ed together. Keys must be valid identifiers (letters, digits, underscore, not starting with a digit) to stay portable: Milvus compiles them into a filter expression and Neo4j'sGraphStorecounterpart compiles them into Cypher, so both reject other characters, while Qdrant and Weaviate accept arbitrary payload keys.
Returns:
Raises:
ValueError–limitis not positive, or exceedsagrag.common.validation.MAX_SEARCH_LIMIT. Enforced uniformly across backends since they otherwise fail differently outside that range.
agrag.vectordb.VectorStore.upsert
upsert(collection:str, records:Sequence[VectorRecord], *, batch_size:int = 256) -> None
Write or overwrite records in a collection.
Parameters:
- collection (
str) – The collection to write to. - records (
Sequence[VectorRecord]) – The records to upsert, in order. - batch_size (
int) – The number of records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.vectordb.VectorStoreError
Bases: Exception
The base class for every vector-store error.
agrag.vectordb.VectorStoreMissingExtraError
VectorStoreMissingExtraError(extra:str) -> None
Bases: VectorStoreError
A vector store exists, but its package extra is not installed.
Attributes:
- extra – The name of the package extra to install.
agrag.vectordb.VectorStoreMissingExtraError.extra
extra = extra
agrag.vectordb.WeaviateSettings
Bases: BaseSettings
Weaviate connection configuration.
Attributes:
- mode (
Literal['cloud', 'custom']) –"cloud"connects to Weaviate Cloud."custom"connects to a self-hosted instance (used by integration tests against the local Docker Compose instance) — an explicit field, not inferred from the URL, since inference caused real connection bugs in surveyed reference implementations. Env:WEAVIATE_MODE. - url (
str) – The Weaviate endpoint URL. For"cloud", the cluster URL. For"custom", the full host URL. Env:WEAVIATE_URL. - api_key (
str) – The Weaviate API key. Env:WEAVIATE_API_KEY. - grpc_port (
int) – The gRPC port, used by"custom"mode only ("cloud"mode infers it). Env:WEAVIATE_GRPC_PORT. - require_tls (
bool) – WhenTrue, reject a plaintexturlto a non-local host even with noapi_keyconfigured. Off by default since many deployments run an unauthenticated Weaviate on a private network and rely on network segmentation rather than transport encryption. Env:WEAVIATE_REQUIRE_TLS.
Raises:
ValueError–urlis plaintext (http), points at a non-local host, and eitherapi_keyis set orrequire_tlsisTrue. Usehttpsfor a remote Weaviate instance.
agrag.vectordb.WeaviateSettings.api_key
api_key: str = ''
agrag.vectordb.WeaviateSettings.grpc_port
grpc_port: int = 50051
agrag.vectordb.WeaviateSettings.mode
mode: Literal['cloud', 'custom'] = 'custom'
agrag.vectordb.WeaviateSettings.model_config
model_config = SettingsConfigDict(env_prefix='WEAVIATE_', env_file='.env', extra='ignore')
agrag.vectordb.WeaviateSettings.require_tls
require_tls: bool = False
agrag.vectordb.WeaviateSettings.url
url: str = 'http://localhost:8080'
agrag.vectordb.WeaviateVectorStore
WeaviateVectorStore(*, settings:WeaviateSettings | None = None, client:Any | None = None) -> None
Bases: VectorStore
A VectorStore backed by Weaviate, including native hybrid search.
The client connects lazily on first use, so constructing the store does not open a network connection. Weaviate does its own server-side BM25, so hybrid search needs no client-side sparse embedder.
Functions:
- close – Release the backend connection.
- collection_exists – Report whether a collection exists.
- count – Count records in a collection.
- delete – Delete records by id.
- delete_collection – Delete a collection and all its objects.
- ensure_collection – Create the collection if it does not exist.
- hybrid_search – Search by dense vector and keyword text in one fused call.
- initialize – Open the connection and check authentication.
- retrieve – Fetch records by id.
- scroll – Iterate records in a collection, in batches.
- search – Search by dense vector only.
- upsert – Write or overwrite records in a collection.
Parameters:
- settings (
WeaviateSettings | None) – Weaviate connection settings. Defaults toWeaviateSettings(). - client (
Any | None) – A pre-built Weaviate async client, for tests. When set,__init__imports nothing and the store calls this object directly instead of building one.
agrag.vectordb.WeaviateVectorStore.close
close() -> None
Release the backend connection.
agrag.vectordb.WeaviateVectorStore.collection_exists
collection_exists(name:str) -> bool
Report whether a collection exists.
Parameters:
- name (
str) – The collection name.
Returns:
bool–Trueif the collection exists.
agrag.vectordb.WeaviateVectorStore.count
count(collection:str, *, filters:dict[str, Any] | None = None) -> int
Count records in a collection.
Parameters:
- collection (
str) – The collection to count. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields.
Returns:
int– The number of matching records.
agrag.vectordb.WeaviateVectorStore.delete
delete(collection:str, ids:Sequence[UUID]) -> None
Delete records by id.
Parameters:
agrag.vectordb.WeaviateVectorStore.delete_collection
delete_collection(name:str) -> None
Delete a collection and all its objects.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.WeaviateVectorStore.ensure_collection
ensure_collection(name:str, *, dimensions:int, distance:Distance, hybrid:bool = False) -> None
Create the collection if it does not exist.
Parameters:
- name (
str) – The collection name. - dimensions (
int) – The embedding dimension. - distance (
Distance) – The distance metric new collections use. - hybrid (
bool) – No-op for Weaviate, which needs no sparse provisioning.
Raises:
CollectionDimensionMismatchError– An existing object in the collection carries a vector of a different dimension. Weaviate keeps no schema-level dimension for self-provided vectors, so an existing collection with no vector-bearing object cannot be checked this way.
agrag.vectordb.WeaviateVectorStore.hybrid_search
hybrid_search(collection:str, query_vector:Sequence[float], query_text:str, *, limit:int = 10, filters:dict[str, Any] | None = None, alpha:float = 0.5) -> list[VectorHit]
Search by dense vector and keyword text in one fused call.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - query_text (
str) – The query text, matched by keyword/BM25. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields. - alpha (
float) – The dense/keyword balance.1.0is pure dense,0.0is pure keyword.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT, oralphais outside[0.0, 1.0].
agrag.vectordb.WeaviateVectorStore.initialize
initialize() -> None
Open the connection and check authentication.
agrag.vectordb.WeaviateVectorStore.retrieve
retrieve(collection:str, ids:Sequence[UUID]) -> list[VectorRecord]
Fetch records by id.
Parameters:
Returns:
list[VectorRecord]– The records that exist, in the requested order, omitting missinglist[VectorRecord]– ids.
agrag.vectordb.WeaviateVectorStore.scroll
scroll(collection:str, *, limit:int = 100, page_offset:str | None = None, filters:dict[str, Any] | None = None, with_vectors:bool = False) -> tuple[list[VectorRecord], str | None]
Iterate records in a collection, in batches.
Parameters:
- collection (
str) – The collection to read. - limit (
int) – The maximum number of records per page. - page_offset (
str | None) – The cursor id from a previousscrollcall. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields. - with_vectors (
bool) – Whether to return each record's vector.
Returns:
list[VectorRecord]– The page of records and the next page cursor, orNoneat thestr | None– end.
agrag.vectordb.WeaviateVectorStore.search
search(collection:str, query_vector:Sequence[float], *, limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search by dense vector only.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT.
agrag.vectordb.WeaviateVectorStore.upsert
upsert(collection:str, records:Sequence[VectorRecord], *, batch_size:int = 256) -> None
Write or overwrite records in a collection.
Uses Weaviate's batch import, which replaces an existing object sharing a written id instead of rejecting it, giving real insert-or-replace semantics and per-call batching in one request.
Parameters:
- collection (
str) – The collection to write to. - records (
Sequence[VectorRecord]) – The records to upsert, in order. - batch_size (
int) – The number of records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.VectorStoreError– At least one record in a batch failed to write.
agrag.vectordb.base
The VectorStore abstraction and its build shortcut.
Classes:
- VectorStore – A vector database backend: collection lifecycle, writes, and search.
agrag.vectordb.base.VectorStore
Bases: ABC
A vector database backend: collection lifecycle, writes, and search.
Functions:
- close – Release the backend connection.
- collection_exists – Report whether a collection exists.
- count – Count records in a collection.
- delete – Delete records by id.
- delete_collection – Delete a collection and all its points.
- ensure_collection – Create the collection if it does not exist.
- hybrid_search – Search by dense vector and keyword text in one fused call.
- initialize – Check connectivity and authentication.
- retrieve – Fetch records by id.
- scroll – Iterate records in a collection, in batches.
- search – Search by dense vector only.
- upsert – Write or overwrite records in a collection.
agrag.vectordb.base.VectorStore.close
close() -> None
Release the backend connection.
agrag.vectordb.base.VectorStore.collection_exists
collection_exists(name:str) -> bool
Report whether a collection exists.
Parameters:
- name (
str) – The collection name.
Returns:
bool–Trueif the collection exists.
agrag.vectordb.base.VectorStore.count
count(collection:str, *, filters:dict[str, Any] | None = None) -> int
Count records in a collection.
Parameters:
- collection (
str) – The collection to count. - filters (
dict[str, Any] | None) – A flat-dict filter: a scalar value means exact match, a list value means any of, and all keys are AND-ed together. Keys must be valid identifiers (letters, digits, underscore, not starting with a digit) to stay portable: Milvus compiles them into a filter expression and Neo4j'sGraphStorecounterpart compiles them into Cypher, so both reject other characters, while Qdrant and Weaviate accept arbitrary payload keys.
Returns:
int– The number of matching records.
agrag.vectordb.base.VectorStore.delete
delete(collection:str, ids:Sequence[UUID]) -> None
Delete records by id.
Parameters:
agrag.vectordb.base.VectorStore.delete_collection
delete_collection(name:str) -> None
Delete a collection and all its points.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.base.VectorStore.ensure_collection
ensure_collection(name:str, *, dimensions:int, distance:Distance, hybrid:bool = False) -> None
Create the collection if it does not exist.
Parameters:
- name (
str) – The collection name. - dimensions (
int) – The embedding dimension. If the collection already exists with a different dimension, this raises. - distance (
Distance) – The distance metric new collections use. - hybrid (
bool) – Whether to additionally provision the sparse-vector configuration hybrid search needs. Ignored by backends that need no such provisioning.
Raises:
CollectionDimensionMismatchError– The collection exists with a different dimension thandimensions.
agrag.vectordb.base.VectorStore.hybrid_search
hybrid_search(collection:str, query_vector:Sequence[float], query_text:str, *, limit:int = 10, filters:dict[str, Any] | None = None, alpha:float = 0.5) -> list[VectorHit]
Search by dense vector and keyword text in one fused call.
Parameters:
- collection (
str) – The collection to search. Must have been created withensure_collection(..., hybrid=True). - query_vector (
Sequence[float]) – The dense query embedding. - query_text (
str) – The query text, matched by keyword/BM25. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter: a scalar value means exact match, a list value means any of, and all keys are AND-ed together. Keys must be valid identifiers (letters, digits, underscore, not starting with a digit) to stay portable: Milvus compiles them into a filter expression and Neo4j'sGraphStorecounterpart compiles them into Cypher, so both reject other characters, while Qdrant and Weaviate accept arbitrary payload keys. - alpha (
float) – The dense/keyword balance.1.0is pure dense,0.0is pure keyword. Weaviate and Milvus apply this weight natively. Qdrant's native fusion (Reciprocal Rank Fusion) has no continuous weight, so it appliesalphaby blending two independently-scored, min-max normalized result sets instead of a single native fused call.
Returns:
Raises:
ValueError–limitis not positive, or exceedsagrag.common.validation.MAX_SEARCH_LIMIT, oralphais outside[0.0, 1.0]. Enforced uniformly across backends since they otherwise fail differently outside that range.
agrag.vectordb.base.VectorStore.initialize
initialize() -> None
Check connectivity and authentication.
Raises:
VectorStoreError– The backend is unreachable, or the credentials are rejected.
agrag.vectordb.base.VectorStore.retrieve
retrieve(collection:str, ids:Sequence[UUID]) -> list[VectorRecord]
Fetch records by id.
Parameters:
Returns:
list[VectorRecord]– The records that exist, in the requested order, omitting missinglist[VectorRecord]– ids.
agrag.vectordb.base.VectorStore.scroll
scroll(collection:str, *, limit:int = 100, page_offset:str | None = None, filters:dict[str, Any] | None = None, with_vectors:bool = False) -> tuple[list[VectorRecord], str | None]
Iterate records in a collection, in batches.
Parameters:
- collection (
str) – The collection to read. - limit (
int) – The maximum number of records per page. - page_offset (
str | None) – The offset from a previousscrollcall, orNoneto start at the beginning. - filters (
dict[str, Any] | None) – A flat-dict filter: a scalar value means exact match, a list value means any of, and all keys are AND-ed together. Keys must be valid identifiers (letters, digits, underscore, not starting with a digit) to stay portable: Milvus compiles them into a filter expression and Neo4j'sGraphStorecounterpart compiles them into Cypher, so both reject other characters, while Qdrant and Weaviate accept arbitrary payload keys. - with_vectors (
bool) – Whether to return each record's vector.
Returns:
list[VectorRecord]– The page of records and the next page offset, orNoneat thestr | None– end.
agrag.vectordb.base.VectorStore.search
search(collection:str, query_vector:Sequence[float], *, limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search by dense vector only.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter: a scalar value means exact match, a list value means any of, and all keys are AND-ed together. Keys must be valid identifiers (letters, digits, underscore, not starting with a digit) to stay portable: Milvus compiles them into a filter expression and Neo4j'sGraphStorecounterpart compiles them into Cypher, so both reject other characters, while Qdrant and Weaviate accept arbitrary payload keys.
Returns:
Raises:
ValueError–limitis not positive, or exceedsagrag.common.validation.MAX_SEARCH_LIMIT. Enforced uniformly across backends since they otherwise fail differently outside that range.
agrag.vectordb.base.VectorStore.upsert
upsert(collection:str, records:Sequence[VectorRecord], *, batch_size:int = 256) -> None
Write or overwrite records in a collection.
Parameters:
- collection (
str) – The collection to write to. - records (
Sequence[VectorRecord]) – The records to upsert, in order. - batch_size (
int) – The number of records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.vectordb.build_vector_store
build_vector_store(value:VectorStoreName | VectorStore) -> VectorStore
Build a vector store from a backend name, or return one unchanged.
Parameters:
- value (
VectorStoreName | VectorStore) –"qdrant"or"weaviate", or an already-constructedVectorStorefor full control over settings.
Returns:
VectorStore– A ready-to-use vector store.
agrag.vectordb.errors
Errors that the vector-store layer raises.
Classes:
- CollectionDimensionMismatchError – A collection already exists with a different embedding dimension.
- VectorStoreError – The base class for every vector-store error.
- VectorStoreMissingExtraError – A vector store exists, but its package extra is not installed.
agrag.vectordb.errors.CollectionDimensionMismatchError
CollectionDimensionMismatchError(*, expected:int, actual:int) -> None
Bases: VectorStoreError
A collection already exists with a different embedding dimension.
Attributes:
- expected – The dimension the collection was created with.
- actual – The dimension the caller requested.
agrag.vectordb.errors.CollectionDimensionMismatchError.actual
actual = actual
agrag.vectordb.errors.CollectionDimensionMismatchError.expected
expected = expected
agrag.vectordb.errors.VectorStoreError
Bases: Exception
The base class for every vector-store error.
agrag.vectordb.errors.VectorStoreMissingExtraError
VectorStoreMissingExtraError(extra:str) -> None
Bases: VectorStoreError
A vector store exists, but its package extra is not installed.
Attributes:
- extra – The name of the package extra to install.
agrag.vectordb.errors.VectorStoreMissingExtraError.extra
extra = extra
agrag.vectordb.milvus
Milvus vector-store backend.
Classes:
- MilvusVectorStore – A
VectorStorebacked by Milvus, including native hybrid search.
Attributes:
agrag.vectordb.milvus.MAX_RESPONSE_LIMIT
MAX_RESPONSE_LIMIT = 16384
agrag.vectordb.milvus.MilvusVectorStore
MilvusVectorStore(*, settings:MilvusSettings | None = None, client:Any | None = None) -> None
Bases: VectorStore
A VectorStore backed by Milvus, including native hybrid search.
The client connects lazily on first use, so constructing the store does not
open a network connection. Milvus performs BM25 server-side, so hybrid
search needs no client-side sparse embedder; the sparse vector is computed
by a Milvus Function from the text field on write and at query time.
Functions:
- close – Release the backend connection.
- collection_exists – Report whether a collection exists.
- count – Count records in a collection.
- delete – Delete records by id.
- delete_collection – Delete a collection and all its entities.
- ensure_collection – Create the collection if it does not exist.
- hybrid_search – Search by dense vector and keyword text in one fused call.
- initialize – Check connectivity and authentication.
- invalidate_collection – Drop cached distance-metric knowledge of a collection.
- retrieve – Fetch records by id.
- scroll – Iterate records in a collection, in batches.
- search – Search by dense vector only.
- upsert – Write or overwrite records in a collection.
Parameters:
- settings (
MilvusSettings | None) – Milvus connection settings. Defaults toMilvusSettings(). - client (
Any | None) – A pre-builtAsyncMilvusClient, for tests. When set,__init__imports nothing and the store calls this object directly instead of building one.
agrag.vectordb.milvus.MilvusVectorStore.close
close() -> None
Release the backend connection.
agrag.vectordb.milvus.MilvusVectorStore.collection_exists
collection_exists(name:str) -> bool
Report whether a collection exists.
Parameters:
- name (
str) – The collection name.
Returns:
bool–Trueif the collection exists.
agrag.vectordb.milvus.MilvusVectorStore.count
count(collection:str, *, filters:dict[str, Any] | None = None) -> int
Count records in a collection.
Parameters:
- collection (
str) – The collection to count. - filters (
dict[str, Any] | None) – A flat-dict filter on scalar fields.
Returns:
int– The number of matching records.
agrag.vectordb.milvus.MilvusVectorStore.delete
delete(collection:str, ids:Sequence[UUID]) -> None
Delete records by id.
Parameters:
agrag.vectordb.milvus.MilvusVectorStore.delete_collection
delete_collection(name:str) -> None
Delete a collection and all its entities.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.milvus.MilvusVectorStore.ensure_collection
ensure_collection(name:str, *, dimensions:int, distance:Distance, hybrid:bool = False) -> None
Create the collection if it does not exist.
Milvus performs BM25 server-side, so the sparse field and its Function
are always provisioned; the hybrid flag is accepted for interface
parity but is a no-op here. An existing collection must already carry
this same fixed schema, since upsert and hybrid_search always
read and write every field regardless of hybrid.
Parameters:
- name (
str) – The collection name. - dimensions (
int) – The embedding dimension. - distance (
Distance) – The distance metric new collections use. - hybrid (
bool) – Accepted for interface parity; ignored by Milvus.
Raises:
CollectionDimensionMismatchError– The collection exists with a different dimension thandimensions.VectorStoreError– The collection exists but is missing a field or index this adapter requires.
agrag.vectordb.milvus.MilvusVectorStore.hybrid_search
hybrid_search(collection:str, query_vector:Sequence[float], query_text:str, *, limit:int = 10, filters:dict[str, Any] | None = None, alpha:float = 0.5) -> list[VectorHit]
Search by dense vector and keyword text in one fused call.
Fusion uses Milvus's native weighted reranker, which normalizes each
request's scores before applying alpha.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - query_text (
str) – The query text, matched by BM25. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on scalar fields. - alpha (
float) – The dense/keyword balance.1.0is pure dense,0.0is pure keyword.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT, oralphais outside[0.0, 1.0].
agrag.vectordb.milvus.MilvusVectorStore.initialize
initialize() -> None
Check connectivity and authentication.
agrag.vectordb.milvus.MilvusVectorStore.invalidate_collection
invalidate_collection(name:str) -> None
Drop cached distance-metric knowledge of a collection.
This store caches a collection's distance metric after the first
call that resolves it, on the assumption that it alone (via
ensure_collection/delete_collection) owns the collection's
lifecycle for as long as this instance is in use. If something
outside this instance deletes and recreates a collection under the
same name with a different metric, call this first so the next call
re-resolves that collection's metric from the backend instead of
trusting the stale cache.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.milvus.MilvusVectorStore.retrieve
retrieve(collection:str, ids:Sequence[UUID]) -> list[VectorRecord]
Fetch records by id.
Requests at most MAX_RESPONSE_LIMIT ids per call, so a large
ids list cannot exceed Milvus's response-size ceiling in one
request the way sending every id at once would.
Parameters:
Returns:
list[VectorRecord]– The records that exist, in the requested order, omitting missinglist[VectorRecord]– ids.
agrag.vectordb.milvus.MilvusVectorStore.scroll
scroll(collection:str, *, limit:int = 100, page_offset:str | None = None, filters:dict[str, Any] | None = None, with_vectors:bool = False) -> tuple[list[VectorRecord], str | None]
Iterate records in a collection, in batches.
Milvus rejects a query whose offset + limit exceeds
MAX_RESPONSE_LIMIT, so a numeric offset cannot page past that
many total records. Pages instead cursor on the id primary key:
each page filters on id > page_offset and orders by id
ascending, which needs no offset at all and so never hits that
window regardless of collection size. The explicit order is load
bearing: without it, an unordered query result could omit rows at or
below the next cursor, permanently skipping them on the next page.
Parameters:
- collection (
str) – The collection to read. - limit (
int) – The maximum number of records per page. - page_offset (
str | None) – The id cursor from a previousscrollcall. - filters (
dict[str, Any] | None) – A flat-dict filter on scalar fields. - with_vectors (
bool) – Whether to return each record's vector.
Returns:
list[VectorRecord]– The page of records and the next page cursor, orNoneat thestr | None– end.
agrag.vectordb.milvus.MilvusVectorStore.search
search(collection:str, query_vector:Sequence[float], *, limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search by dense vector only.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on scalar fields.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT.
agrag.vectordb.milvus.MilvusVectorStore.upsert
upsert(collection:str, records:Sequence[VectorRecord], *, batch_size:int = 256) -> None
Write or overwrite records in a collection.
Parameters:
- collection (
str) – The collection to write to. - records (
Sequence[VectorRecord]) – The records to upsert, in order. - batch_size (
int) – The number of records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.vectordb.qdrant
Qdrant vector-store backend.
Classes:
- QdrantVectorStore – A
VectorStorebacked by Qdrant, including native hybrid search.
agrag.vectordb.qdrant.QdrantVectorStore
QdrantVectorStore(*, settings:QdrantSettings | None = None, sparse_embedder:SparseEmbedder | None = None, client:Any | None = None, models:Any | None = None) -> None
Bases: VectorStore
A VectorStore backed by Qdrant, including native hybrid search.
The client connects lazily on first use, so constructing the store does not
open a network connection. Hybrid search builds its sparse query with a
SparseEmbedder that defaults to FastEmbed BM25 and loads only when a
hybrid call first runs, not at construction.
Functions:
- close – Release the backend connection.
- collection_exists – Report whether a collection exists.
- count – Count records in a collection.
- delete – Delete records by id.
- delete_collection – Delete a collection and all its points.
- ensure_collection – Create the collection if it does not exist.
- hybrid_search – Search by dense vector and keyword text, fused by a weighted blend.
- initialize – Check connectivity and authentication.
- invalidate_collection – Drop cached hybrid-state and distance-metric knowledge of a collection.
- retrieve – Fetch records by id.
- scroll – Iterate records in a collection, in batches.
- search – Search by dense vector only.
- upsert – Write or overwrite records in a collection.
Parameters:
- settings (
QdrantSettings | None) – Qdrant connection settings. Defaults toQdrantSettings(). - sparse_embedder (
SparseEmbedder | None) – The sparse embedder hybrid search uses. Defaults to a lazily-builtFastEmbedBM25Embedder. - client (
Any | None) – A pre-builtAsyncQdrantClient, for tests. When set,__init__imports nothing and the store calls this object directly instead of building one. - models (
Any | None) – Theqdrant_client.modelsmodule, for tests. Pair withclientso filter/payload helpers work without needing the realqdrant_clientpackage installed at all.
agrag.vectordb.qdrant.QdrantVectorStore.close
close() -> None
Release the backend connection.
agrag.vectordb.qdrant.QdrantVectorStore.collection_exists
collection_exists(name:str) -> bool
Report whether a collection exists.
Parameters:
- name (
str) – The collection name.
Returns:
bool–Trueif the collection exists.
agrag.vectordb.qdrant.QdrantVectorStore.count
count(collection:str, *, filters:dict[str, Any] | None = None) -> int
Count records in a collection.
Parameters:
- collection (
str) – The collection to count. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields.
Returns:
int– The number of matching records.
agrag.vectordb.qdrant.QdrantVectorStore.delete
delete(collection:str, ids:Sequence[UUID]) -> None
Delete records by id.
Parameters:
agrag.vectordb.qdrant.QdrantVectorStore.delete_collection
delete_collection(name:str) -> None
Delete a collection and all its points.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.qdrant.QdrantVectorStore.ensure_collection
ensure_collection(name:str, *, dimensions:int, distance:Distance, hybrid:bool = False) -> None
Create the collection if it does not exist.
Parameters:
- name (
str) – The collection name. - dimensions (
int) – The embedding dimension. - distance (
Distance) – The distance metric new collections use. - hybrid (
bool) – Whether to provision the named sparse vector hybrid search needs.
Raises:
CollectionDimensionMismatchError– The collection exists with a different dimension thandimensions.VectorStoreError– The collection exists without hybrid search support andhybrid=Truewas requested.
agrag.vectordb.qdrant.QdrantVectorStore.hybrid_search
hybrid_search(collection:str, query_vector:Sequence[float], query_text:str, *, limit:int = 10, filters:dict[str, Any] | None = None, alpha:float = 0.5) -> list[VectorHit]
Search by dense vector and keyword text, fused by a weighted blend.
Qdrant's native fusion methods (RRF, DBSF) have no continuous
dense/keyword weight, so this runs the dense and sparse (BM25)
searches independently, min-max normalizes each result set's scores
to [0, 1], then combines them per id as
alpha * dense + (1 - alpha) * sparse. Each side fetches a wider
candidate pool than limit so a document strong on only one signal
still has a chance to reach the blended top results.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - query_text (
str) – The query text, matched by BM25. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields. - alpha (
float) – The dense/keyword balance.1.0is pure dense,0.0is pure keyword.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT, oralphais outside[0.0, 1.0].
agrag.vectordb.qdrant.QdrantVectorStore.initialize
initialize() -> None
Check connectivity and authentication.
agrag.vectordb.qdrant.QdrantVectorStore.invalidate_collection
invalidate_collection(name:str) -> None
Drop cached hybrid-state and distance-metric knowledge of a collection.
This store caches a collection's hybrid support and distance metric
after the first call that resolves them, on the assumption that it
alone (via ensure_collection/delete_collection) owns the
collection's lifecycle for as long as this instance is in use. If
something outside this instance deletes and recreates a collection
under the same name with different config, call this first so the
next call re-resolves that collection's state from the backend
instead of trusting the stale cache.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.qdrant.QdrantVectorStore.retrieve
retrieve(collection:str, ids:Sequence[UUID]) -> list[VectorRecord]
Fetch records by id.
Parameters:
Returns:
list[VectorRecord]– The records that exist, in the requested order, omitting missinglist[VectorRecord]– ids.
agrag.vectordb.qdrant.QdrantVectorStore.scroll
scroll(collection:str, *, limit:int = 100, page_offset:str | None = None, filters:dict[str, Any] | None = None, with_vectors:bool = False) -> tuple[list[VectorRecord], str | None]
Iterate records in a collection, in batches.
Parameters:
- collection (
str) – The collection to read. - limit (
int) – The maximum number of records per page. - page_offset (
str | None) – The offset from a previousscrollcall. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields. - with_vectors (
bool) – Whether to return each record's vector.
Returns:
list[VectorRecord]– The page of records and the next page offset, orNoneat thestr | None– end.
agrag.vectordb.qdrant.QdrantVectorStore.search
search(collection:str, query_vector:Sequence[float], *, limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search by dense vector only.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT.
agrag.vectordb.qdrant.QdrantVectorStore.upsert
upsert(collection:str, records:Sequence[VectorRecord], *, batch_size:int = 256) -> None
Write or overwrite records in a collection.
When collection has sparse-vector support (created or previously
seen with ensure_collection(..., hybrid=True)), each record's
payload["text"] is also sparse-embedded and stored under the named
sparse vector, so hybrid_search's keyword arm has real vectors to
match. A record with no text payload key gets an empty sparse
vector and only ever surfaces through the dense side of a hybrid
search.
Parameters:
- collection (
str) – The collection to write to. - records (
Sequence[VectorRecord]) – The records to upsert, in order. - batch_size (
int) – The number of records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.
agrag.vectordb.settings
Settings for vector-store backends.
Classes:
- MilvusSettings – Milvus connection configuration.
- QdrantSettings – Qdrant connection configuration.
- WeaviateSettings – Weaviate connection configuration.
agrag.vectordb.settings.MilvusSettings
Bases: BaseSettings
Milvus connection configuration.
Attributes:
- uri (
str) – The Milvus endpoint URI. Env:MILVUS_URI. - token (
str) – The Milvus auth token. Empty string for an unauthenticated instance. Env:MILVUS_TOKEN. - require_tls (
bool) – WhenTrue, reject a plaintexturito a non-local host even with notokenconfigured. Off by default since many deployments run an unauthenticated Milvus on a private network and rely on network segmentation rather than transport encryption. Env:MILVUS_REQUIRE_TLS.
Raises:
ValueError–uriis plaintext (http), points at a non-local host, and eithertokenis set orrequire_tlsisTrue. Usehttpsfor a remote Milvus instance.
agrag.vectordb.settings.MilvusSettings.model_config
model_config = SettingsConfigDict(env_prefix='MILVUS_', env_file='.env', extra='ignore')
agrag.vectordb.settings.MilvusSettings.require_tls
require_tls: bool = False
agrag.vectordb.settings.MilvusSettings.token
token: str = ''
agrag.vectordb.settings.MilvusSettings.uri
uri: str = 'http://localhost:19530'
agrag.vectordb.settings.QdrantSettings
Bases: BaseSettings
Qdrant connection configuration.
Attributes:
- url (
str) – The Qdrant endpoint URL. Env:QDRANT_URL. - api_key (
str) – The Qdrant API key. Env:QDRANT_API_KEY. - require_tls (
bool) – WhenTrue, reject a plaintexturlto a non-local host even with noapi_keyconfigured. Off by default since many deployments run an unauthenticated Qdrant on a private network and rely on network segmentation rather than transport encryption. Env:QDRANT_REQUIRE_TLS.
Raises:
ValueError–urlis plaintext (http), points at a non-local host, and eitherapi_keyis set orrequire_tlsisTrue. Usehttpsfor a remote Qdrant instance.
agrag.vectordb.settings.QdrantSettings.api_key
api_key: str = ''
agrag.vectordb.settings.QdrantSettings.model_config
model_config = SettingsConfigDict(env_prefix='QDRANT_', env_file='.env', extra='ignore')
agrag.vectordb.settings.QdrantSettings.require_tls
require_tls: bool = False
agrag.vectordb.settings.QdrantSettings.url
url: str = 'http://localhost:6333'
agrag.vectordb.settings.WeaviateSettings
Bases: BaseSettings
Weaviate connection configuration.
Attributes:
- mode (
Literal['cloud', 'custom']) –"cloud"connects to Weaviate Cloud."custom"connects to a self-hosted instance (used by integration tests against the local Docker Compose instance) — an explicit field, not inferred from the URL, since inference caused real connection bugs in surveyed reference implementations. Env:WEAVIATE_MODE. - url (
str) – The Weaviate endpoint URL. For"cloud", the cluster URL. For"custom", the full host URL. Env:WEAVIATE_URL. - api_key (
str) – The Weaviate API key. Env:WEAVIATE_API_KEY. - grpc_port (
int) – The gRPC port, used by"custom"mode only ("cloud"mode infers it). Env:WEAVIATE_GRPC_PORT. - require_tls (
bool) – WhenTrue, reject a plaintexturlto a non-local host even with noapi_keyconfigured. Off by default since many deployments run an unauthenticated Weaviate on a private network and rely on network segmentation rather than transport encryption. Env:WEAVIATE_REQUIRE_TLS.
Raises:
ValueError–urlis plaintext (http), points at a non-local host, and eitherapi_keyis set orrequire_tlsisTrue. Usehttpsfor a remote Weaviate instance.
agrag.vectordb.settings.WeaviateSettings.api_key
api_key: str = ''
agrag.vectordb.settings.WeaviateSettings.grpc_port
grpc_port: int = 50051
agrag.vectordb.settings.WeaviateSettings.mode
mode: Literal['cloud', 'custom'] = 'custom'
agrag.vectordb.settings.WeaviateSettings.model_config
model_config = SettingsConfigDict(env_prefix='WEAVIATE_', env_file='.env', extra='ignore')
agrag.vectordb.settings.WeaviateSettings.require_tls
require_tls: bool = False
agrag.vectordb.settings.WeaviateSettings.url
url: str = 'http://localhost:8080'
agrag.vectordb.weaviate
Weaviate vector-store backend.
Classes:
- WeaviateVectorStore – A
VectorStorebacked by Weaviate, including native hybrid search.
agrag.vectordb.weaviate.WeaviateVectorStore
WeaviateVectorStore(*, settings:WeaviateSettings | None = None, client:Any | None = None) -> None
Bases: VectorStore
A VectorStore backed by Weaviate, including native hybrid search.
The client connects lazily on first use, so constructing the store does not open a network connection. Weaviate does its own server-side BM25, so hybrid search needs no client-side sparse embedder.
Functions:
- close – Release the backend connection.
- collection_exists – Report whether a collection exists.
- count – Count records in a collection.
- delete – Delete records by id.
- delete_collection – Delete a collection and all its objects.
- ensure_collection – Create the collection if it does not exist.
- hybrid_search – Search by dense vector and keyword text in one fused call.
- initialize – Open the connection and check authentication.
- retrieve – Fetch records by id.
- scroll – Iterate records in a collection, in batches.
- search – Search by dense vector only.
- upsert – Write or overwrite records in a collection.
Parameters:
- settings (
WeaviateSettings | None) – Weaviate connection settings. Defaults toWeaviateSettings(). - client (
Any | None) – A pre-built Weaviate async client, for tests. When set,__init__imports nothing and the store calls this object directly instead of building one.
agrag.vectordb.weaviate.WeaviateVectorStore.close
close() -> None
Release the backend connection.
agrag.vectordb.weaviate.WeaviateVectorStore.collection_exists
collection_exists(name:str) -> bool
Report whether a collection exists.
Parameters:
- name (
str) – The collection name.
Returns:
bool–Trueif the collection exists.
agrag.vectordb.weaviate.WeaviateVectorStore.count
count(collection:str, *, filters:dict[str, Any] | None = None) -> int
Count records in a collection.
Parameters:
- collection (
str) – The collection to count. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields.
Returns:
int– The number of matching records.
agrag.vectordb.weaviate.WeaviateVectorStore.delete
delete(collection:str, ids:Sequence[UUID]) -> None
Delete records by id.
Parameters:
agrag.vectordb.weaviate.WeaviateVectorStore.delete_collection
delete_collection(name:str) -> None
Delete a collection and all its objects.
Parameters:
- name (
str) – The collection name.
agrag.vectordb.weaviate.WeaviateVectorStore.ensure_collection
ensure_collection(name:str, *, dimensions:int, distance:Distance, hybrid:bool = False) -> None
Create the collection if it does not exist.
Parameters:
- name (
str) – The collection name. - dimensions (
int) – The embedding dimension. - distance (
Distance) – The distance metric new collections use. - hybrid (
bool) – No-op for Weaviate, which needs no sparse provisioning.
Raises:
CollectionDimensionMismatchError– An existing object in the collection carries a vector of a different dimension. Weaviate keeps no schema-level dimension for self-provided vectors, so an existing collection with no vector-bearing object cannot be checked this way.
agrag.vectordb.weaviate.WeaviateVectorStore.hybrid_search
hybrid_search(collection:str, query_vector:Sequence[float], query_text:str, *, limit:int = 10, filters:dict[str, Any] | None = None, alpha:float = 0.5) -> list[VectorHit]
Search by dense vector and keyword text in one fused call.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - query_text (
str) – The query text, matched by keyword/BM25. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields. - alpha (
float) – The dense/keyword balance.1.0is pure dense,0.0is pure keyword.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT, oralphais outside[0.0, 1.0].
agrag.vectordb.weaviate.WeaviateVectorStore.initialize
initialize() -> None
Open the connection and check authentication.
agrag.vectordb.weaviate.WeaviateVectorStore.retrieve
retrieve(collection:str, ids:Sequence[UUID]) -> list[VectorRecord]
Fetch records by id.
Parameters:
Returns:
list[VectorRecord]– The records that exist, in the requested order, omitting missinglist[VectorRecord]– ids.
agrag.vectordb.weaviate.WeaviateVectorStore.scroll
scroll(collection:str, *, limit:int = 100, page_offset:str | None = None, filters:dict[str, Any] | None = None, with_vectors:bool = False) -> tuple[list[VectorRecord], str | None]
Iterate records in a collection, in batches.
Parameters:
- collection (
str) – The collection to read. - limit (
int) – The maximum number of records per page. - page_offset (
str | None) – The cursor id from a previousscrollcall. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields. - with_vectors (
bool) – Whether to return each record's vector.
Returns:
list[VectorRecord]– The page of records and the next page cursor, orNoneat thestr | None– end.
agrag.vectordb.weaviate.WeaviateVectorStore.search
search(collection:str, query_vector:Sequence[float], *, limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search by dense vector only.
Parameters:
- collection (
str) – The collection to search. - query_vector (
Sequence[float]) – The dense query embedding. - limit (
int) – The maximum number of hits to return. - filters (
dict[str, Any] | None) – A flat-dict filter on payload fields.
Returns:
Raises:
ValueError–limitis not positive, or exceedsMAX_SEARCH_LIMIT.
agrag.vectordb.weaviate.WeaviateVectorStore.upsert
upsert(collection:str, records:Sequence[VectorRecord], *, batch_size:int = 256) -> None
Write or overwrite records in a collection.
Uses Weaviate's batch import, which replaces an existing object sharing a written id instead of rejecting it, giving real insert-or-replace semantics and per-call batching in one request.
Parameters:
- collection (
str) – The collection to write to. - records (
Sequence[VectorRecord]) – The records to upsert, in order. - batch_size (
int) – The number of records per backend write call. Must be positive.
Raises:
ValueError–batch_sizeis not positive.VectorStoreError– At least one record in a batch failed to write.