How ContextGraph Combines Vector Stores for Hybrid Retrieval in Semantica
ContextGraph orchestrates parallel semantic vector searches and knowledge-graph structural queries, blending the results through a configurable hybrid_alpha weight to deliver unified, ranked relevance scores for precedent decisions.
The semantica-agi/semantica repository implements a sophisticated hybrid retrieval system that unifies dense vector embeddings with graph-based relationships. Instead of merging storage backends permanently, ContextGraph coordinates real-time searches across both semantic and structural domains, enabling AI agents to retrieve precedents based on meaning and relational context simultaneously.
The Hybrid Retrieval Architecture of ContextGraph
ContextGraph implements hybrid retrieval through four tightly-coupled layers that handle distinct aspects of the query pipeline.
Decision Query Facade
The find_precedents_hybrid method in semantica/context/decision_query.py (lines 74-112) serves as the primary entry point. This facade exposes a single public API that callers use to request precedent decisions. The implementation first attempts a vector-store hybrid search, then falls back to an enhanced graph search if vector results are insufficient.
Vector-Store Hybrid Engine
Located in semantica/vector_store/hybrid_search.py (lines 250-320), the HybridSearch.search method executes semantic similarity lookups on embedded decision vectors while simultaneously applying optional metadata filters. This enables filtering by categories or other node attributes during the initial vector retrieval phase, reducing the candidate set before similarity calculation.
Hybrid Similarity Calculation
The HybridSimilarityCalculator class in semantica/vector_store/hybrid_similarity.py (lines 45-78) merges the semantic score from vector similarity with a structural score derived from knowledge-graph algorithms like Node2Vec embeddings or centrality metrics. The hybrid_alpha parameter controls the blend: 0 yields pure vector search, 1 yields pure graph search, and the default 0.5 provides equal weighting.
Context Retriever Orchestration
The ContextRetriever class in semantica/context/context_retriever.py (lines 30-36) manages the final integration. It pulls results from both sources, normalizes per-source scores, applies the hybrid_alpha weighting, deduplicates overlapping results by decision ID, and returns a ranked list of RetrievedContext objects.
End-to-End Hybrid Retrieval Flow
The complete retrieval pipeline follows six distinct stages:
-
Decision Embedding Generation: When
ContextGraph.record_decisionstores a decision, theDecisionEmbeddingPipelineautomatically generates semantic embeddings and persists them to the vector store alongside the decision node. -
Query Initiation:
AgentContext(orContextRetriever) receives a query string and delegates toDecisionQuery.find_precedents_hybrid. -
Vector-Store Execution: The system invokes
HybridSearch.searchto retrieve candidates using vector similarity plus metadata filters. Returned hits are converted toDecisionobjects and receive preliminary similarity scores. -
Graph Fallback and Enrichment: If vector results are insufficient, the system executes
_find_precedents_enhanced_graph, leveraging KG algorithms (Node2Vec, centrality calculations) to compute structural similarity scores. -
Score Blending:
HybridSimilarityCalculatormerges semantic and structural components according to the configuredhybrid_alphaweight, producing a unified relevance score for each candidate. -
Deduplication and Ranking: Results from both sources are deduplicated by decision ID and sorted by final hybrid score before being returned to the caller.
Implementing Hybrid Search in Semantica
The following examples demonstrate practical usage patterns for hybrid retrieval.
Basic Hybrid Precedent Lookup
from semantica.context import ContextGraph, AgentContext
# Initialize graph with advanced analytics for structural similarity
graph = ContextGraph(advanced_analytics=True)
# Configure in-memory vector store (FAISS backend) with 384-dimension embeddings
vector_store = ContextGraph.vector_store_class(backend="inmemory", dimension=384)
agent = AgentContext(vector_store=vector_store, knowledge_graph=graph)
# Record a decision (embedding is automatically stored via DecisionEmbeddingPipeline)
graph.record_decision(
category="loan_approval",
scenario="First-time homebuyer",
reasoning="Good credit score",
outcome="approved",
confidence=0.95,
entities=["customer_123", "property_456"],
)
# Hybrid search with 60% graph weight, 40% vector weight
precedents = agent.context.find_precedents_hybrid(
scenario="First-time homebuyer",
category="loan_approval",
limit=5,
similarity_weights={
"semantic": 0.4,
"structural": 0.6,
"text": 0.0,
"category": 0.0
},
)
for d in precedents:
print(f"{d.scenario} → {d.outcome} (score={d.metadata['similarity_score']:.3f})")
This example utilizes ContextGraph.record_decision for storage and AgentContext.find_precedents_hybrid for retrieval, which delegates to the vector-store search before applying structural weighting.
Adjusting the Hybrid Weighting
from semantica.context import ContextRetriever
# Configure retriever to favor graph similarity (80% structural, 20% vector)
retriever = ContextRetriever(
memory_store=None,
knowledge_graph=graph,
vector_store=vector_store,
hybrid_alpha=0.8, # 0=vector-only, 1=graph-only
)
results = retriever.retrieve(
query="What factors led to loan approvals in 2023?",
max_results=3,
)
for r in results:
print(r.content, r.score)
The ContextRetriever initializes a HybridSimilarityCalculator internally and applies hybrid_alpha during the normalization phase defined in semantica/context/context_retriever.py (lines 30-36).
Direct Vector-Store Hybrid Search
from semantica.vector_store import HybridSearch, MetadataFilter
# Assume vector_store is a configured FAISSStore instance
hybrid = HybridSearch(vector_store=vector_store)
# Search with metadata filtering (e.g., only "mortgage" category)
results = hybrid.search(
query="Refinance a mortgage",
filters={"category": "mortgage"},
limit=10,
)
for hit in results:
print(hit.id, hit.score) # Returns semantic similarity score
As implemented in semantica/vector_store/hybrid_search.py (lines 250-320), the HybridSearch.search method combines vector similarity lookups with MetadataFilter constraints before returning candidate matches.
Key Source Files and Components
The hybrid retrieval implementation spans several critical modules:
semantica/context/context_graph.py: Core graph data model that links decision nodes to vector embeddings.semantica/context/decision_query.py: Containsfind_precedents_hybrid, the public API orchestrating vector and graph searches (lines 74-112).semantica/vector_store/hybrid_search.py: ImplementsHybridSearch.searchfor vector similarity plus metadata filtering (lines 250-320).semantica/vector_store/hybrid_similarity.py: DefinesHybridSimilarityCalculator.calculatefor blending semantic and structural scores (lines 45-78).semantica/context/context_retriever.py: Orchestrates final score normalization, weighting, and deduplication (lines 30-36).semantica/vector_store/decision_embedding_pipeline.py: Generates and stores decision embeddings enabling vector search capabilities.semantica/kg/(e.g.,node_embedder.py,centrality_calculator.py): Provides structural similarity signals via graph algorithms.
Summary
- ContextGraph does not merge vector and graph stores permanently; it coordinates parallel searches at query time.
- The hybrid_alpha parameter (0.0 to 1.0) controls the balance between semantic vector similarity and structural graph relationships.
HybridSearch.searchexecutes vector similarity with metadata filtering, whileHybridSimilarityCalculatorblends scores using configurable weights.- The architecture falls back to enhanced graph search (
_find_precedents_enhanced_graph) when vector results are insufficient. - Results are deduplicated by decision ID and ranked by unified hybrid scores before returning to the caller.
Frequently Asked Questions
What is the default hybrid_alpha value in ContextGraph?
The default hybrid_alpha is 0.5, providing equal weighting between semantic vector similarity and structural graph similarity. Setting this parameter to 0 yields pure vector search, while 1 uses only graph-based signals.
How does Semantica handle cases where vector search returns no results?
If the vector store yields insufficient hits, the system automatically falls back to _find_precedents_enhanced_graph, which uses knowledge-graph algorithms like Node2Vec embeddings and centrality calculations to compute structural similarity scores and retrieve relevant precedents.
Can I filter hybrid search results by metadata attributes?
Yes. The HybridSearch.search method in semantica/vector_store/hybrid_search.py accepts a filters dictionary (e.g., {"category": "mortgage"}) that applies metadata constraints during the initial vector similarity lookup, reducing the candidate set before similarity calculation.
Which files control the embedding generation for hybrid retrieval?
The DecisionEmbeddingPipeline in semantica/vector_store/decision_embedding_pipeline.py generates semantic embeddings when decisions are recorded via ContextGraph.record_decision. These embeddings are stored in the vector store and retrieved during hybrid search operations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →