Custom PartialContextQuestionProcessor
This article explains how to create a custom PartialContextQuestionProcessor configuration by supplying your own IContextRetriever and related interface implementations. You can tailor every step: splitting text, producing embeddings, ranking relevance, enforcing token limits, formatting context, and retrieving it efficiently to optimize performance, cost, accuracy, or compliance.
When you need full control over fragmentation, embedding, similarity ranking, and retrieval, use the constructor that accepts an IContextRetriever:
PartialContextQuestionProcessor(
IChatClient chatClient,
IContextRetriever contextRetriever,
IEmbeddingSettings settings,
SimpleTextDocument document)
This constructor gives you end‑to‑end control over how document text is fragmented, embedded, stored, and later selected (ranked) as context for a question, forming your custom PartialContextQuestionProcessor pipeline.
Interfaces
All extension points live in Telerik.Documents.AI.Core (as abstractions) with their default implementations in Telerik.Documents.AI.RAG:
| Interface | Responsibility | Used By |
|---|---|---|
| IContextFragmentsManager | Splits raw document text into token-bounded semantic fragments (pages, sections, paragraphs) | Fragmentation stage |
| IEmbedder | Converts fragments into embeddings/vectors for similarity comparison | Embedding stage |
| ISimilarityCalculator | Scores fragment relevance against a question/prompt | Ranking stage |
| ITokensCounter | Counts tokens for limits enforcement (fragment size, total context) | Throughout pipeline |
| IEmbeddingSettings | Provides token & size limits + formatting hints | Configuration source |
| IContextRetriever | Orchestrates loading text, preparing embeddings, and returning best context | Retrieval stage |
| ISupportJsonEmbeddings / ISupportPlainTextEmbeddings | Control how context is formatted for the model (JSON vs plain text) | Formatting stage |
| IFragments / IFragment | Data structures representing chunk collections and individual chunks | Shared across stages |
Life Cycle
- SetContextAsync(text, embeddingTokenSize) - Text is fragmented (IContextFragmentsManager), tokens checked (ITokensCounter), embeddings generated (IEmbedder), and stored.
- Question time (GetContextAsync(question)) - Similarity scores computed (ISimilarityCalculator), top fragments selected within limits, context formatted (plain or JSON).
- Processor sends formatted context + question via IChatClient and returns model answer.
Custom Implementation
The example below constructs a custom PartialContextQuestionProcessor by supplying a DefaultContextRetriever that mixes user implementations (custom IContextFragmentsManager and IEmbedder) with default components (DefaultSimilarityCalculator, DefaultTokensCounter, and the retriever's own orchestration). This hybrid approach lets you optimize the most impactful stages (fragmentation + embedding) without rewriting the entire retrieval pipeline.
DefaultEmbedder is only available on net8-windows and higher. On other target frameworks you must supply your own IEmbedder (as shown below with CustomOpenAIEmbedder).
// Load the PDF document
string filePath = @"path\to\your\document.pdf";
PdfFormatProvider formatProvider = new PdfFormatProvider();
RadFixedDocument fixedDocument;
using (FileStream fs = File.OpenRead(filePath))
{
fixedDocument = formatProvider.Import(fs, TimeSpan.FromSeconds(10));
}
// Convert the document to a simple text representation
SimpleTextDocument plainDoc = fixedDocument.ToSimpleTextDocument(TimeSpan.FromSeconds(10));
// Set up the AI client (Azure OpenAI in this example)
string key = "AZUREOPENAI_KEY";
string endpoint = "AZUREOPENAI_ENDPOINT";
string model = "gpt-4o-mini";
Azure.AI.OpenAI.AzureOpenAIClient azureClient = new AzureOpenAIClient(
new Uri(endpoint),
new Azure.AzureKeyCredential(key),
new Azure.AI.OpenAI.AzureOpenAIClientOptions());
ChatClient chatClient = azureClient.GetChatClient(model);
IChatClient iChatClient = new OpenAIChatClient(chatClient);
int maxTokenCount = 128000;
int maxNumberOfEmbeddingsSent = 20;
int embeddingTokenSize = 500;
IEmbeddingSettings settings = EmbeddingSettingsFactory.CreateSettingsForSpreadDocuments(maxTokenCount, produceJsonFormattedContext: false);
IContextFragmentsManager customContextFragmentsManager = new CustomOpenAIContextFragmentsManager(new DefaultTokensCounter(settings)); // Implemented by the user
IEmbedder customEmbedder = new CustomOpenAIEmbedder();
DefaultContextRetriever defaultContextRetriever = new DefaultContextRetriever(
customContextFragmentsManager,
customEmbedder,
new DefaultSimilarityCalculator(customEmbedder),
new DefaultTokensCounter(settings),
settings);
using (PartialContextQuestionProcessor partialContextQuestionProcessor =
new PartialContextQuestionProcessor(
iChatClient,
defaultContextRetriever,
settings,
plainDoc))
{
string question = "What is the main topic of the document?";
string answer = await partialContextQuestionProcessor.AnswerQuestion(question);
Console.WriteLine("Answer: " + answer);
}