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—text splitting, embedding production, relevance ranking, token limit enforcement, context formatting, and retrieval—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 the pipeline fragments, embeds, stores, and selects document text as context for a question.
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 and size limits plus formatting hints | Configuration source |
IContextRetriever | Orchestrates loading text, preparing embeddings, and returning best context | Retrieval stage |
ISupportJsonEmbeddings / ISupportPlainTextEmbeddings | Controls how context is formatted for the model (JSON versus plain text) | Formatting stage |
IFragments / IFragment | Data structures representing chunk collections and individual chunks | Shared across stages |
Life Cycle
SetContextAsync(text, embeddingTokenSize)—TheIContextFragmentsManagerfragments the text,ITokensCounterchecks tokens, andIEmbeddergenerates and stores embeddings.GetContextAsync(question)—TheISimilarityCalculatorcomputes similarity scores, selects top fragments within limits, and formats context (plain text or JSON).- The processor sends the formatted context and the question through
IChatClientand returns the model answer.
Custom Implementation
The following example 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 and embedding) without the need to rewrite the entire retrieval pipeline.
The
DefaultEmbedderis only available on net8-windows and higher. On other target frameworks you must supply your ownIEmbedder(as shown with CustomOpenAIEmbedder).
// Load the DOCX document
string filePath = @"path\to\your\document.docx";
DocxFormatProvider formatProvider = new DocxFormatProvider();
RadFlowDocument flowDocument;
using (FileStream fs = File.OpenRead(filePath))
{
flowDocument = formatProvider.Import(fs, TimeSpan.FromSeconds(10));
}
// Convert the document to a simple text representation
SimpleTextDocument plainDoc = flowDocument.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 = (IChatClient)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);
}