Skip to content

feat(rag): productionize the RAG pipeline (real LLM, real vector stores, async, quantization, eval, facade wiring)#1896

Open
ooples wants to merge 25 commits into
masterfrom
feat/rag-productionization
Open

feat(rag): productionize the RAG pipeline (real LLM, real vector stores, async, quantization, eval, facade wiring)#1896
ooples wants to merge 25 commits into
masterfrom
feat/rag-productionization

Conversation

@ooples

@ooples ooples commented Jul 20, 2026

Copy link
Copy Markdown
Owner

RAG productionization

Turns the RAG subsystem from a broad-but-partly-stubbed surface into a functional, production-oriented stack, and makes all of it reachable through the AiModelBuilder facade (code + YAML). Motivated by a competitive-parity audit (LangChain / LlamaIndex / Haystack / Semantic Kernel; Pinecone / Weaviate / Qdrant / Milvus / Chroma / pgvector / FAISS).

What changed (18 workstreams, one commit each)

  • Real LLM generation — ChatClientGenerator bridges the production IChatClient connectors (OpenAI/Azure/Anthropic/Cohere/Gemini/Mistral/Ollama) with streaming; de-stubbed HyDE, LLM/Cohere rerankers, LLM context compression, LLM query expansion, multi-query, and GraphRAG entity/relation/claim extraction + community reports to actually call it.
  • Real vector stores (7/8) — Qdrant, Pinecone, Weaviate, Milvus, Azure AI Search (HTTP), pgvector (AiDotNet.Storage.Postgres), RedisVL (AiDotNet.Storage.Redis); the in-memory simulations were deleted from core.
  • Performance — scalar/binary/product quantization + ADC, content-hash embedding cache, real ONNX cross-encoder reranker.
  • Quality — RRF hybrid fusion + ensemble/routing/self-query retrievers; RAGAS + IR metrics (nDCG/MRR/MAP/hit-rate); embeddings now fail loudly instead of returning fake vectors; token-aware + real embedding-based semantic chunking.
  • Async — IRetriever/IDocumentStore/IReranker/IContextCompressor/IGenerator are async + cancellation-aware; I/O-bound stores/generators are truly async.
  • Facade — ConfigureVectorStore/ConfigureVectorIndex + chunking/compression wiring (interface AND concrete), the documentStore-dropped-without-a-KG bug fixed, ConfigureRAG, and a YAML composite section wiring every sub-component. Central RagPipeline orchestrator (ingest/query, async, tenant isolation).

Verification

  • Per task: builds green on net471/net8/net10; ~230 new unit tests. Live-service tests are gated ([Trait("Category","Integration")] + env vars) and skip in CI.
  • A full RAG-suite run on the integrated branch is being completed; any failures found will be fixed before merge.

NOT done — gaps vs. "exceed every competitor" (follow-ups, tracked not glossed)

  • Native FAISS (still an in-memory index) and a Neo4j/property-graph backend for GraphRAG.
  • Rich metadata filtering (boolean AND/OR, $in, full ranges) across every external store — current translation is equality + >= range + any-of.
  • RAG-path GPU acceleration.
  • Live integration tests are not exercised in CI (no credentials): the real Qdrant/Pinecone/etc. clients are verified by mocked-HTTP request/response shaping + gated tests, not continuous live runs.

🤖 Generated with Claude Code

franklinic and others added 20 commits July 19, 2026 14:59
…ing)

RAG previously shipped no real LLM generator — only a local-LSTM NeuralGenerator
and a StubGenerator — so every LLM-dependent component (HyDE, LLM/Cohere
rerankers, LLM context compression, LLM query expansion, multi-query retrieval,
GraphRAG summarization, LLM-judge eval) had nothing real to call.

Add ChatClientGenerator<T> : GeneratorBase<T>, IStreamingGenerator<T> that bridges
the RAG IGenerator<T> contract onto the existing production agentic IChatClient<T>
connectors (OpenAI/Azure/Anthropic/Cohere/Gemini/Mistral/Ollama — real HTTP,
retries, timeouts, streaming). Generate() returns the full answer; the new
IStreamingGenerator<T>.GenerateStreamAsync yields token deltas. Reuses the
battle-tested connectors instead of a new HTTP client.

Unit-tested with a fake in-memory IChatClient (no network): role construction,
option propagation, streaming concatenation, and prompt validation. Builds on
net471/net8/net10 (IAsyncEnumerable streaming verified on net471). Unblocks #19,
#25, #34.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
HyDE, LLM query expansion, multi-query retrieval, LLM reranking, and LLM context
compression previously ran lexical templates/heuristics while accepting unused
endpoint/apiKey args — they looked LLM-powered but never called a model.

Add a small non-generic ITextGenerator (string Generate(string)) that IGenerator<T>
now extends, so any real generator (e.g. ChatClientGenerator over a chat connector)
plugs into both the generic and non-generic RAG helpers. Each component gains an
optional generator:
- HyDEQueryExpansion: LLM writes hypothetical answer passages (true HyDE).
- LLMQueryExpansion: LLM produces alternative queries, parsed line-by-line.
- MultiQueryRetriever: reuses the de-stubbed expander (no more "{query} variation N").
- LLMBasedReranker: LLM scores each doc 0-10 for relevance.
- LLMContextCompressor: LLM extracts only query-relevant content.
When no generator is supplied each keeps a clearly-documented offline heuristic
fallback (non-breaking). Verified with a fake ITextGenerator (6 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the in-memory brute-force simulations in QdrantDocumentStore<T>
and PineconeDocumentStore<T> with real HTTP clients that call the
Qdrant and Pinecone REST APIs. Both accept an optional HttpClient /
HttpMessageHandler for testability, support API-key auth + base URL,
translate metadata filters, and bridge the sync IDocumentStore methods
to async internally (matching ElasticsearchDocumentStore). The
IDocumentStore<T> contract is unchanged.

Adds mocked-HttpMessageHandler unit tests (no network) and gated
[Trait("Category","Integration")] tests driven by env vars.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ievers

HybridRetriever summed raw dense (cosine ~0..1) and sparse (BM25, unbounded) scores,
so the larger-scaled list dominated. Switch it to Reciprocal Rank Fusion (rank-based,
scale-free — the default in ES/Weaviate/Qdrant and LangChain/LlamaIndex), keeping the
weights and adding a configurable RRF k (default 60).

Add three retrievers that were absent versus the common frameworks:
- EnsembleRetriever<T>: RRF fusion over any number of weighted retrievers.
- QueryRoutingRetriever<T>: routes a query to the best named data source via an LLM
  (ITextGenerator) with a token-overlap fallback.
- SelfQueryRetriever<T>: uses the generator to split an NL query into a search string
  plus structured metadata filters over declared fields, then delegates (caller filters
  win). Malformed LLM JSON degrades to the raw query.

Verified with fakes (6 tests): RRF ordering, ensemble, routing (LLM + fallback), and
self-query filter extraction/precedence.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the in-memory simulations for WeaviateDocumentStore, MilvusDocumentStore
and AzureSearchDocumentStore with real HTTP clients following the Qdrant/Pinecone
pattern (HttpClient + Newtonsoft, sync *Core overrides bridging to a private async
SendAsync, net471-safe). Adds mocked-HttpMessageHandler unit tests plus one gated
integration SkippableFact per store.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
RAG chunking was character-based only, but LLM context/embedding limits are measured
in tokens. Add TokenBasedChunkingStrategy: ChunkSize/ChunkOverlap are interpreted as
tokens, with an injectable token-counter delegate so callers can plug an exact
tokenizer (tiktoken/HF); the default counts whitespace words as an approximate proxy.
Overlap and start/end positions preserved. (Remaining in #26: real embedding-based
semantic chunking + LLM agentic chunking.)

Verified: 4 tests (budget, overlap, position round-trip, custom counter).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add OnnxCrossEncoderReranker<T> that loads a cross-encoder ONNX model
(e.g. BGE-reranker / ms-marco MiniLM) plus its tokenizer and scores each
(query, document) pair by joint [CLS] q [SEP] d [SEP] inference, sorting
descending and setting RelevanceScore/HasRelevanceScore. Batches pairs,
disposes the session, and throws a clear FileNotFoundException on a
missing model (no silent lexical fallback). Adds a convenience
CrossEncoderReranker<T> ctor that accepts it as the scorer. Ranking logic
is unit-tested via a virtual ScorePairs seam; a gated integration test
loads a real model from an env var and skips when unset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…R/MAP)

Upgrade RAG evaluation beyond lexical overlap:
- FaithfulnessMetric: optional ITextGenerator NLI-style judge (supported claims / total),
  lexical word-overlap fallback when none supplied.
- AnswerSimilarityMetric: optional IEmbeddingModel cosine, Jaccard fallback.
- AnswerCorrectnessMetric: optional ITextGenerator (0-10 judge) + IEmbeddingModel (semantic
  cosine), averaged; Jaccard fallback. Back-compat (endpoint, apiKey) ctor retained.
- ContextRelevanceMetric: optional IEmbeddingModel query-vs-doc cosine, Jaccard fallback.
- New AnswerRelevanceMetric (RAGAS): reverse-generate questions then mean cosine to query.
- New ContextPrecisionMetric (RAGAS AP-style) and ContextRecallMetric (claim attribution),
  each judge/embedding/lexical.
- New RetrievalMetrics static class: pure-math nDCG@k (binary + graded), MRR, MAP, Hit-Rate@k,
  Precision@k, Recall@k over ranked doc ids vs relevant set.
- Shared helpers added to RAGMetricBase (sentence split, list parsing, yes/no verdict, cosine,
  Jaccard). net471-safe (log2 via change-of-base; guards, no ThrowIfNull/IsFinite).

All metrics fall back to documented offline lexical behavior when no model is injected.
Existing IRAGMetric metrics flow through RAGEvaluator unchanged.

Tests (18, net10.0 green): IR metrics with exact numeric assertions; embedding metrics with a
controlled fake IEmbeddingModel; LLM-judge metrics with a scripted fake ITextGenerator; all
offline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SemanticChunkingStrategy was "semantic" in name only — it packed sentences to a size
budget with no embeddings. It now, when given a sentence embedder, places chunk
boundaries at semantic breakpoints (consecutive-sentence cosine distance above a
percentile threshold — Kamradt/LlamaIndex SemanticSplitter), while still capping chunk
size; without an embedder it falls back to the original size-based packing. Sentence
spans are located in the source text so positions round-trip.

Verified: 3 tests (topic-shift split, no-embedder fallback, position round-trip).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…index

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a decorator that caches embeddings by SHA-256 content hash so repeated
texts are not re-embedded, matching LangChain CacheBackedEmbeddings and
LlamaIndex ingestion cache.

- ContentHash: stable, cross-process SHA-256 hex helper (reusable for dedup)
- IEmbeddingCache<T> + thread-safe InMemoryEmbeddingCache<T> (ConcurrentDictionary,
  optional max-size / approximate-LRU eviction)
- CacheBackedEmbeddings<T> : IEmbeddingModel<T> decorator; keys namespaced by
  inner model identity + dimension; batch paths dedup within/across calls,
  invoke inner only for distinct misses, and preserve row ordering
- net471/net8.0-safe; 18 unit tests with a counting fake inner model

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…reports

Add optional ITextGenerator (IGenerator<T>)-driven extraction to KGConstructor
and LLM community reports to CommunitySummarizer, with the existing regex/
extractive behavior retained as a documented offline fallback.

- KGConstructor: new ctor accepting IGenerator<T>; prompts the model for
  structured JSON (entities/relations, optional claims), parses with
  Newtonsoft.Json, and builds the graph. Malformed/empty JSON or generator
  errors transparently degrade to the regex path. Descriptions persisted on
  nodes/edges; claims attached to subject nodes.
- CommunitySummarizer: new ctor accepting IGenerator<T>; generates natural-
  language community reports, falling back to the extractive template when no
  generator is present or the response is empty.
- Options: UseLlmExtraction (default true), ExtractClaims (default false).
- net471-safe (guards, Newtonsoft.Json, no ThrowIfNull/double.IsFinite).
- Tests: 9 CI-runnable tests with a scripted fake generator covering LLM
  population, malformed-JSON fallback, markdown-fenced JSON, claims, and
  LLM-vs-extractive community reports.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the fake in-memory PostgresVectorDocumentStore/RedisVLDocumentStore
in the core library with real IDocumentStore<T> implementations in the opt-in
storage projects, mirroring ElasticsearchDocumentStore.

- AiDotNet.Storage.Postgres: PostgresVectorDocumentStore<T> using Npgsql +
  pgvector (CREATE EXTENSION vector, table with vector(dim) column, ON CONFLICT
  upsert, KNN via <=>/<->/<+> ORDER BY LIMIT, jsonb metadata filters).
- AiDotNet.Storage.Redis: RedisVLDocumentStore<T> using StackExchange.Redis
  RediSearch (FT.CREATE HNSW vector + TAG/NUMERIC fields, HSET, FT.SEARCH KNN
  with server-side filters, FT.DROPINDEX). Honors metadata filters and never
  mutates cached docs.
- Delete the two fake in-memory stores from the core library (breaking change).
- Add unit tests for the SQL/Redis query builders and gated integration tests
  (POSTGRES_VECTOR_CONN / REDIS_CONN).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uilder facade

Make the RAG pipeline wireable through the facade (your "100% wireable" goal):
- ConfigureRetrievalAugmentedGeneration gains chunkingStrategy + contextCompressor
  params/fields, surfaced on AiModelResult and copied in BuildPipeline.
- Fix the documentStore-dropped-without-a-KnowledgeGraph bug: the store is now kept
  in its own field, exposed as AiModelResult.DocumentStore, and a default vector
  retriever is built over it (honoring the configured embedding model + similarity
  metric) so vector-only RAG works.
- New ConfigureVectorStore(IDocumentStore) and ConfigureVectorIndex(VectorIndexKind,
  metric) — one-call paths making all document-store backends and the in-memory
  indexes (Flat/HNSW/IVF/LSH) reachable. These live on both IAiModelBuilder and the
  concrete builder (every Configure* belongs on the interface).
- ConfigureRAG(RAGConfiguration) materializes the previously-orphaned
  RAGConfigurationBuilder into the builder fields.

Verified: 10 facade-wiring tests. YAML/declarative path is the follow-up (#31).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The generated YAML applier previously treated ConfigureRetrievalAugmentedGeneration
as a plain interface section: it kept only the retriever (the method's first
parameter) and silently dropped reranker, generator, query processors, document
store and graph store; ConfigureKnowledgeGraph was emitted as an Action<> TODO.

Rework the YamlConfigSourceGenerator so the RAG section is a COMPOSITE:

- Emit a new YamlRagSection POCO (retriever, reranker, generator,
  queryProcessors[], documentStore, graphStore, embeddingModel,
  similarityMetric, knowledgeGraph) and surface it as the
  RetrievalAugmentedGeneration YAML property.
- Emit a dedicated applier that resolves each named sub-component from its own
  type-registry section and passes them to the facade: ConfigureRetrievalAugmentedGeneration
  (retriever/reranker/generator/queryProcessors/graphStore/documentStore),
  ConfigureEmbeddingModel, ConfigureSimilarityMetric, and ConfigureKnowledgeGraph.
- Wire the standalone KnowledgeGraph section (Action<KnowledgeGraphOptions>) as an
  options params-bag, removing the KG TODO; pipeline-style Action<> sections
  (preprocessing/postprocessing) keep their existing steps shape.
- Mark IQueryProcessor [YamlConfigurable("QueryProcessor")] so the registry exposes
  a QueryProcessor section for the composite applier.
- Add matching JSON-schema/docs handling for the composite and options-bag sections.

Adds RagYamlCompositeTests: a multi-component RAG YAML string loads, applies to a
builder, and every sub-component (reranker/generator/queryProcessors/graphStore/
documentStore/similarityMetric/embeddingModel) plus ConfigureKnowledgeGraph is
verified wired — nothing dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… concrete

Pre-existing failure on this branch: the test asserted ConfigureAutoML(IAutoMLModel<...>)
must NOT be on IAiModelBuilder, but every fluent Configure* method belongs on the
interface (it's declared there at IAiModelBuilder.cs:1507). Flip the assertion to require
the overload on BOTH the interface and the concrete builder, and rename the test to match
(same fix applied on the #1789 branch).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add async, cancellation-aware methods to the RAG interfaces and make the
I/O-bound implementations genuinely non-blocking.

Interfaces (kept sync methods, added async overloads):
- IRetriever<T>.RetrieveAsync(query, topK, filters, ct)
- IDocumentStore<T>: Add/AddBatch/GetSimilar/GetSimilarWithFilters/GetById/
  Remove/Clear/GetAll -> *Async(ct)
- IReranker<T>.RerankAsync (all + topK overloads)
- IContextCompressor<T>.CompressAsync
- IGenerator<T>.GenerateAsync / GenerateGroundedAsync

Base classes implement the async interface methods and expose a protected
virtual *CoreAsync that defaults to Task.FromResult(syncCore), so CPU-bound
subclasses need no changes; I/O-bound subclasses override the core for real
async. All library async uses ConfigureAwait(false); net471-safe (Task-based).

Truly-async (removed sync-over-async on the async path): the external vector
stores Qdrant/Pinecone/Weaviate/Milvus/AzureSearch/ChromaDB and the
Elasticsearch store (token threaded into the HTTP client), the LLM-backed
ChatClientGenerator, and the VectorRetriever/DenseRetriever (await the
embedding model + store). CPU-bound impls (in-memory stores, RRF/MMR/identity
rerankers, extractive compressors, Stub/Neural generators) wrap sync.

Updated all direct interface implementers (VectorIndexDocumentStore,
Stub/NeuralGenerator) and 17 test mock classes. Added focused async +
pre-cancelled-token tests (RagAsyncCancellationTests, 12 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… variations

Seven pre-existing HybridRetrieverTests/MultiQueryRetrieverTests asserted the old
behavior that the RRF-fusion (#27) and real-query-expansion (#19) changes correctly
replaced: exact weighted-sum scores (0.7*d+0.3*s) and the "{query} variation N"
placeholder. RRF is rank-based (scores are small, order is what matters) and MultiQuery
now emits real reformulations. Reassert the meaningful properties: fused doc presence +
ranking, and original-query-first with distinct variations. All 105 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The RAG subsystem had every component but no single class that composed them — callers
wired chunk→embed→store and retrieve→rerank→compress→generate by hand. Add RagPipeline<T>:
- IngestAsync: optional chunk → embed → upsert (returns chunk count).
- QueryAsync: retrieve → optional rerank → optional compress → optional generate, returning
  a RagResult<T> (contexts + grounded answer).
Fully async/cancellation-aware. Optional tenant/namespace: stamped on ingested documents'
metadata and applied as a retrieval filter for cross-tenant isolation. Streaming is already
provided by IStreamingGenerator/ChatClientGenerator.

Verified: 3 tests (chunked ingest into a real InMemoryDocumentStore, query→generate, tenant
stamp + filter). Remaining #33 items — rich boolean/$in/range metadata filters across every
external store, and RAG-path GPU hooks — are larger enhancements tracked as follow-ups.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ooples
ooples force-pushed the feat/rag-productionization branch from c4797ad to 0ec5e8e Compare July 20, 2026 01:23
@github-actions

Copy link
Copy Markdown
Contributor

Commit messages auto-fixed

One or more commit messages did not follow Conventional Commits, so they were rewritten to comply (subject case, header length ≤ 100, valid type). Each commit and its diff were preserved — no squashing.

The branch was force-pushed with the corrected messages. If you have local work on this branch, run git pull --rebase (or reset to the remote) before pushing again.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 156 files, which is 6 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to Pro+ to raise the limit.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 035ee7ba-7b4b-4f69-8d65-4abfc165ff7a

📥 Commits

Reviewing files that changed from the base of the PR and between 4586e2c and 290241a.

📒 Files selected for processing (158)
  • AiDotNet.sln
  • Directory.Packages.props
  • src/AiDotNet.Generators/YamlConfigSourceGenerator.cs
  • src/AiDotNet.Storage.Elasticsearch/RetrievalAugmentedGeneration/DocumentStores/ElasticsearchDocumentStore.cs
  • src/AiDotNet.Storage.Elasticsearch/RetrievalAugmentedGeneration/DocumentStores/ElasticsearchVectorFilterBuilder.cs
  • src/AiDotNet.Storage.Faiss/AiDotNet.Storage.Faiss.csproj
  • src/AiDotNet.Storage.Faiss/GlobalUsings.cs
  • src/AiDotNet.Storage.Faiss/RetrievalAugmentedGeneration/DocumentStores/FaissDocumentStore.cs
  • src/AiDotNet.Storage.Faiss/RetrievalAugmentedGeneration/DocumentStores/FaissSidecar.cs
  • src/AiDotNet.Storage.Neo4j/AiDotNet.Storage.Neo4j.csproj
  • src/AiDotNet.Storage.Neo4j/GlobalUsings.cs
  • src/AiDotNet.Storage.Neo4j/Neo4jCypher.cs
  • src/AiDotNet.Storage.Neo4j/Neo4jGraphStore.cs
  • src/AiDotNet.Storage.Postgres/RetrievalAugmentedGeneration/DocumentStores/PgVectorMetric.cs
  • src/AiDotNet.Storage.Postgres/RetrievalAugmentedGeneration/DocumentStores/PostgresVectorDocumentStore.cs
  • src/AiDotNet.Storage.Postgres/RetrievalAugmentedGeneration/DocumentStores/PostgresVectorFilterBuilder.cs
  • src/AiDotNet.Storage.Redis/RetrievalAugmentedGeneration/DocumentStores/RedisVLDocumentStore.cs
  • src/AiDotNet.Storage.Redis/RetrievalAugmentedGeneration/DocumentStores/RedisVectorField.cs
  • src/AiDotNet.Storage.Redis/RetrievalAugmentedGeneration/DocumentStores/RedisVectorQueryBuilder.cs
  • src/AiDotNet.csproj
  • src/AiModelBuilder.BuildPipeline.cs
  • src/AiModelBuilder.VectorIndexStore.cs
  • src/AiModelBuilder.Workflows.cs
  • src/AiModelBuilder.cs
  • src/Configuration/YamlDocsGenerator.cs
  • src/Configuration/YamlJsonSchema.cs
  • src/Enums/VectorIndexKind.cs
  • src/Interfaces/IAiModelBuilder.cs
  • src/Interfaces/IContextCompressor.cs
  • src/Interfaces/IDocumentStore.cs
  • src/Interfaces/IGenerator.cs
  • src/Interfaces/IQueryProcessor.cs
  • src/Interfaces/IReranker.cs
  • src/Interfaces/IRetriever.cs
  • src/Interfaces/IStreamingGenerator.cs
  • src/Interfaces/ITextGenerator.cs
  • src/Models/Options/AiModelResultOptions.cs
  • src/Models/Results/AiModelResult.cs
  • src/RetrievalAugmentedGeneration/ChunkingStrategies/SemanticChunkingStrategy.cs
  • src/RetrievalAugmentedGeneration/ChunkingStrategies/TokenBasedChunkingStrategy.cs
  • src/RetrievalAugmentedGeneration/ContextCompression/ContextCompressorBase.cs
  • src/RetrievalAugmentedGeneration/ContextCompression/LLMContextCompressor.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/AzureSearchDocumentStore.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/ChromaDBDocumentStore.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/DocumentStoreBase.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/FAISSDocumentStore.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/MilvusDocumentStore.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/PineconeDocumentStore.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/PostgresVectorDocumentStore.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/QdrantDocumentStore.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/RedisVLDocumentStore.cs
  • src/RetrievalAugmentedGeneration/DocumentStores/WeaviateDocumentStore.cs
  • src/RetrievalAugmentedGeneration/Embeddings/CacheBackedEmbeddings.cs
  • src/RetrievalAugmentedGeneration/Embeddings/ContentHash.cs
  • src/RetrievalAugmentedGeneration/Embeddings/EmbeddingModelBase.cs
  • src/RetrievalAugmentedGeneration/Embeddings/GooglePalmEmbeddingModel.cs
  • src/RetrievalAugmentedGeneration/Embeddings/HuggingFaceEmbeddingModel.cs
  • src/RetrievalAugmentedGeneration/Embeddings/IEmbeddingCache.cs
  • src/RetrievalAugmentedGeneration/Embeddings/InMemoryEmbeddingCache.cs
  • src/RetrievalAugmentedGeneration/Embeddings/MultiModalEmbeddingModel.cs
  • src/RetrievalAugmentedGeneration/Embeddings/ONNXSentenceTransformer.cs
  • src/RetrievalAugmentedGeneration/Embeddings/OpenAIEmbeddingModel.cs
  • src/RetrievalAugmentedGeneration/Embeddings/VoyageAIEmbeddingModel.cs
  • src/RetrievalAugmentedGeneration/Evaluation/AnswerCorrectnessMetric.cs
  • src/RetrievalAugmentedGeneration/Evaluation/AnswerRelevanceMetric.cs
  • src/RetrievalAugmentedGeneration/Evaluation/AnswerSimilarityMetric.cs
  • src/RetrievalAugmentedGeneration/Evaluation/ContextPrecisionMetric.cs
  • src/RetrievalAugmentedGeneration/Evaluation/ContextRecallMetric.cs
  • src/RetrievalAugmentedGeneration/Evaluation/ContextRelevanceMetric.cs
  • src/RetrievalAugmentedGeneration/Evaluation/FaithfulnessMetric.cs
  • src/RetrievalAugmentedGeneration/Evaluation/RAGMetricBase.cs
  • src/RetrievalAugmentedGeneration/Evaluation/RetrievalMetrics.cs
  • src/RetrievalAugmentedGeneration/Filtering/MetadataFilter.cs
  • src/RetrievalAugmentedGeneration/Generators/ChatClientGenerator.cs
  • src/RetrievalAugmentedGeneration/Generators/GeneratorBase.cs
  • src/RetrievalAugmentedGeneration/Generators/NeuralGenerator.cs
  • src/RetrievalAugmentedGeneration/Generators/StubGenerator.cs
  • src/RetrievalAugmentedGeneration/Graph/Communities/CommunitySummarizer.cs
  • src/RetrievalAugmentedGeneration/Graph/Construction/ExtractedClaim.cs
  • src/RetrievalAugmentedGeneration/Graph/Construction/ExtractedEntity.cs
  • src/RetrievalAugmentedGeneration/Graph/Construction/ExtractedRelation.cs
  • src/RetrievalAugmentedGeneration/Graph/Construction/KGConstructionOptions.cs
  • src/RetrievalAugmentedGeneration/Graph/Construction/KGConstructor.cs
  • src/RetrievalAugmentedGeneration/QueryExpansion/HyDEQueryExpansion.cs
  • src/RetrievalAugmentedGeneration/QueryExpansion/LLMQueryExpansion.cs
  • src/RetrievalAugmentedGeneration/RagPipeline.cs
  • src/RetrievalAugmentedGeneration/Rerankers/CrossEncoderReranker.cs
  • src/RetrievalAugmentedGeneration/Rerankers/LLMBasedReranker.cs
  • src/RetrievalAugmentedGeneration/Rerankers/OnnxCrossEncoderReranker.cs
  • src/RetrievalAugmentedGeneration/Rerankers/RerankerBase.cs
  • src/RetrievalAugmentedGeneration/Retrievers/DenseRetriever.cs
  • src/RetrievalAugmentedGeneration/Retrievers/EnsembleRetriever.cs
  • src/RetrievalAugmentedGeneration/Retrievers/HybridRetriever.cs
  • src/RetrievalAugmentedGeneration/Retrievers/MultiQueryRetriever.cs
  • src/RetrievalAugmentedGeneration/Retrievers/QueryRoutingRetriever.cs
  • src/RetrievalAugmentedGeneration/Retrievers/RetrieverBase.cs
  • src/RetrievalAugmentedGeneration/Retrievers/SelfQueryRetriever.cs
  • src/RetrievalAugmentedGeneration/Retrievers/VectorRetriever.cs
  • src/RetrievalAugmentedGeneration/VectorSearch/GpuVectorScorer.cs
  • src/RetrievalAugmentedGeneration/VectorSearch/Indexes/GpuFlatIndex.cs
  • src/RetrievalAugmentedGeneration/VectorSearch/Indexes/HNSWIndex.cs
  • src/RetrievalAugmentedGeneration/VectorSearch/Indexes/QuantizedFlatIndex.cs
  • src/RetrievalAugmentedGeneration/VectorSearch/Quantization/BinaryQuantizer.cs
  • src/RetrievalAugmentedGeneration/VectorSearch/Quantization/IVectorQuantizer.cs
  • src/RetrievalAugmentedGeneration/VectorSearch/Quantization/ProductQuantizer.cs
  • src/RetrievalAugmentedGeneration/VectorSearch/Quantization/ScalarQuantizer.cs
  • tests/AiDotNet.Tests/AiDotNetTests.csproj
  • tests/AiDotNet.Tests/IntegrationTests/Configuration/RagYamlCompositeTests.cs
  • tests/AiDotNet.Tests/IntegrationTests/Configuration/SourceGeneratorCoverageTests.cs
  • tests/AiDotNet.Tests/IntegrationTests/KnowledgeGraph/LlmGraphExtractionTests.cs
  • tests/AiDotNet.Tests/IntegrationTests/RetrievalAugmentedGeneration/RAGFacadeWiringTests.cs
  • tests/AiDotNet.Tests/Storage/FaissDocumentStoreTests.cs
  • tests/AiDotNet.Tests/Storage/FaissSidecarTests.cs
  • tests/AiDotNet.Tests/UnitTests/RAG/Embeddings/CacheBackedEmbeddingsTests.cs
  • tests/AiDotNet.Tests/UnitTests/RAG/Embeddings/GooglePalmEmbeddingModelTests.cs
  • tests/AiDotNet.Tests/UnitTests/RAG/Embeddings/HuggingFaceEmbeddingModelTests.cs
  • tests/AiDotNet.Tests/UnitTests/RAG/Embeddings/MultiModalEmbeddingModelTests.cs
  • tests/AiDotNet.Tests/UnitTests/RAG/Embeddings/OpenAIEmbeddingModelTests.cs
  • tests/AiDotNet.Tests/UnitTests/RAG/Embeddings/VoyageAIEmbeddingModelTests.cs
  • tests/AiDotNet.Tests/UnitTests/RAG/Rerankers/OnnxCrossEncoderRerankerTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/BM25RetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/ChunkingStrategies/SemanticChunkingStrategyTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/ChunkingStrategies/TokenBasedChunkingStrategyTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/ColBERTRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DeStubbedLlmComponentsTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DenseRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DocumentStores/AzureSearchDocumentStoreTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DocumentStores/InMemoryDocumentStoreTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DocumentStores/MetadataFilterTranslationTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DocumentStores/MilvusDocumentStoreTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DocumentStores/PineconeDocumentStoreTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DocumentStores/PostgresVectorDocumentStoreTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DocumentStores/QdrantDocumentStoreTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DocumentStores/RedisVLDocumentStoreTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/DocumentStores/WeaviateDocumentStoreTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/Evaluation/RagEvaluationMetricsTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/FLARERetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/Filtering/MetadataFilterTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/Generators/ChatClientGeneratorTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/GraphRAGTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/GraphRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/HybridRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/MultiQueryRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/MultiVectorRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/Neo4jGraphStoreTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/ParentDocumentRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/RagAsyncCancellationTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/RagPipelineTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/Retrievers/RetrieverFusionAndRoutingTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/Retrievers/TestHelpers.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/SelfCorrectingRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/TFIDFRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/VectorRetrieverTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/VectorSearch/Indexes/GpuFlatIndexTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/VectorSearch/Indexes/QuantizedFlatIndexTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/VectorSearch/Quantization/BinaryQuantizerTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/VectorSearch/Quantization/ProductQuantizerTests.cs
  • tests/AiDotNet.Tests/UnitTests/RetrievalAugmentedGeneration/VectorSearch/Quantization/ScalarQuantizerTests.cs

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Review on demand using usage pricing
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rag-productionization

Comment @coderabbitai help to get the list of available commands.

@ooples

ooples commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

Full RAG-suite verification on the integrated branch (net10.0): 2100 passed, 0 failed, 8 skipped (the 8 skips are the gated [Trait("Category","Integration")] live-service tests — Qdrant/Pinecone/Weaviate/Milvus/Azure/pgvector/Redis — which need credentials and do not run in CI). src builds green on net471/net8/net10.

Still-open gaps to actually exceed every competitor (deliberately deferred, not done): native FAISS, Neo4j/property-graph backend, rich boolean/$in/range metadata filters across all external stores, and RAG-path GPU acceleration.

@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
aidotnet_website Ignored Ignored Preview Jul 20, 2026 3:43am
aidotnet-playground-api Ignored Ignored Preview Jul 20, 2026 3:43am

franklinic and others added 2 commits July 19, 2026 21:48
Add AiDotNet.Storage.Neo4j, an opt-in metapackage implementing IGraphStore<T>
over the Neo4j C# driver so GraphRAG can run on a production property graph.
Nodes map to labeled Neo4j nodes, edges to relationships; upserts use MERGE and
traversal uses Cypher MATCH. All per-request data is passed as $parameters; the
only literal identifiers (base node label, relationship type) are validated and
backtick-escaped once at construction, so there is no injection surface. Pure
Cypher/param/mapping logic is factored into Neo4jCypher for unit testing.

net10.0-only (the driver's TFM), matching the Postgres/Redis storage projects;
excluded from the core csproj glob and added to the solution + test project.
Tests: 20 pure-logic unit tests plus gated [Trait(Category,Integration)]
SkippableFact round-trip tests reading NEO4J_URI/NEO4J_USER/NEO4J_PASSWORD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add GPU-accelerated brute-force vector search to the RAG vector-search path,
matching FAISS-GPU / Milvus-GPU flat-search: all stored vectors are packed into
a matrix and scored against the query in a single batched GPU Gemm, then top-k'd.

- GpuVectorScorer: reuses the existing DirectGpuTensorEngine / IDirectGpuBackend
  abstraction (AiDotNetEngine.Current, GetBackend, AllocateBuffer, Gemm,
  DownloadBuffer) - no raw CUDA. Supports dot-product, cosine and Euclidean via
  closed forms over the GPU dot products + precomputed norms.
- GpuFlatIndex<T> : IVectorIndex<T>: batched-GPU flat index with exact CPU
  fallback identical to FlatIndex ordering.
- HNSWIndex.ScoreCandidatesGpu: batched GPU candidate re-scoring for a
  coarse-to-fine pipeline, with CPU fallback.
- Falls back to CPU when no GPU/engine, below threshold, unsupported metric, or
  on any GPU error; gated off under AIDOTNET_DISABLE_GPU like the rest of the
  codebase. Compiles on net10.0/net8.0/net471 (GPU types ship on all TFMs).
- Tests assert GPU-index top-k == CPU FlatIndex top-k across metrics and
  thresholds; deterministic and CI-runnable (GPU disabled -> CPU path).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Commit messages auto-fixed

One or more commit messages did not follow Conventional Commits, so they were rewritten to comply (subject case, header length ≤ 100, valid type). Each commit and its diff were preserved — no squashing.

The branch was force-pushed with the corrected messages. If you have local work on this branch, run git pull --rebase (or reset to the remote) before pushing again.

@ooples
ooples force-pushed the feat/rag-productionization branch from 496b94b to ba72d06 Compare July 20, 2026 01:57
…ll stores

Adds a rich, composable metadata-filter model — Eq/Ne/Gt/Gte/Lt/Lte/In/Exists + And/Or/Not
with fluent factories — and an additive IDocumentStore.GetSimilarWithFilter[Async] that
every real store translates to its native filter language: Qdrant (must/should/must_not),
Pinecone ($and/$or/$in/$gte/…), Weaviate (where operators), Milvus (bool expr), Azure
(OData), pgvector (jsonb, parameterized), Elasticsearch (bool query), Redis (RediSearch);
InMemory/File use the base AST evaluator. Non-breaking: the old Dictionary filters remain,
and DocumentStoreBase provides an in-memory evaluator default so any store gets correct rich
filtering for free.

This matches/exceeds the Pinecone/Qdrant/Weaviate filter expressiveness (previously only
equality + one-sided >= range + any-of). Fixed two issues in the subagent's draft: a
string-vs-number comparison incorrectly ordinal-compared (Gt("name",5) "matched" "abc") — now
only two strings order against each other, otherwise not-comparable; and four sync filter
tests wrongly carried [Fact(Timeout)]. All 78 filter/translation/store tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/franklins-projects-02a0b5a0?upgradeToPro=build-rate-limit

Adds a real FAISS-backed IDocumentStore in a new opt-in storage project so
the core AiDotNet package takes no native dependency (mirrors the
AiDotNet.Storage.Elasticsearch/Sqlite extraction pattern).

- New net10.0-only project src/AiDotNet.Storage.Faiss referencing the FaissNet
  managed wrapper (native Facebook AI Similarity Search). Wired into
  Directory.Packages.props (central versioning), AiDotNet.sln, excluded from the
  core csproj compile glob, and referenced net10-conditionally by the test project.
- FaissDocumentStore<T> supporting Flat / IVFFlat / HNSW / IVFPQ index types and
  Cosine (normalized inner product) / InnerProduct / L2 metrics, selected via ctor.
- FaissSidecar maps FAISS int64 ids -> {docId, content, metadata, embedding};
  drives id round-tripping, metadata filtering, index rebuild on delete for index
  types without in-place removal (HNSW), and JSON persistence alongside the FAISS
  index file (Save/Load).
- Metadata filtering via over-fetch (topK * oversample) + reuse of the base
  DocumentStoreBase.MatchesFilters evaluator (FAISS has no native metadata filter).
- Kept the in-memory FAISSDocumentStore<T> (brute-force simulation) but documented
  it clearly and pointed to the new native FaissDocumentStore<T>; no silent duplication.
- Tests: pure sidecar/id-mapping + over-fetch planner unit tests (no native); gated
  [Trait Integration] tests that build a real Flat/HNSW index + search + persist,
  self-skipping when the native lib can't load. IVF/IVFPQ training tests are opt-in
  (AIDOTNET_FAISS_IVF=1) since FAISS k-means needs a complete Intel MKL runtime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ooples

ooples commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

"Exceed everyone" follow-ups now DONE (4 more commits)

All four gaps from the earlier comment are implemented + pushed:

  • Rich metadata filters — boolean AND/OR/NOT + $in + full ranges via a MetadataFilter AST, translated natively by all 9 stores (base in-memory evaluator default; non-breaking).
  • Neo4j property-graph backend — new AiDotNet.Storage.Neo4j (Neo4jGraphStore : IGraphStore, parameterized Cypher).
  • GPU vector searchGpuFlatIndex + GpuVectorScorer reusing the DirectGpu engine (batched Gemm top-k), CPU fallback, identical ordering.
  • Native FAISSAiDotNet.Storage.Faiss on FaissNet 1.1.0; Flat/HNSW verified end-to-end against the real native lib. (IVF/PQ is coded but gated: the FaissNet package ships an incomplete Intel-MKL redist missing mkl_def.2.dll, so IVF Train aborts — an upstream packaging gap, not our code.)

Final verification (net10.0): 2224 passed, 0 failed, 12 skipped (the 12 skips are the gated [Trait("Category","Integration")] live-service tests — Qdrant/Pinecone/Weaviate/Milvus/Azure/pgvector/Redis/Neo4j + FAISS-IVF). src + all storage projects build green on their target TFMs.

Remaining honest caveats: FAISS IVF/PQ needs a complete MKL runtime to exercise; live vector-DB/Neo4j clients are verified by mocked-HTTP shaping + gated integration tests, not continuous live CI runs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants