Chat with Your Own Data
- 7 minutes to read
When integrating the AI Chat Control with an AI Assistant API (for example, the OpenAI Responses API or Azure AI Projects), you can configure the control to work with external data sources (for example, text files or PDF documents).
By providing a supplementary document as a context source, the assistant is augmented with relevant background information. The AI service parses the document, extracts semantic information, and uses it to generate accurate responses.

OpenAI Responses API
The OpenAI Responses API supplies a unified way to build stateful AI agents that can use tools and external data sources. In this example, it is used to create an assistant that analyzes a user-supplied PDF file.
Install NuGet Packages
Install the following packages:
- Azure.AI.OpenAI (version 2.9.0-beta.1)
- Microsoft.Agents.AI.OpenAI
DevExpress.AIIntegration.AgentsDevExpress.AIIntegration.WinForms.ChatDevExpress.Win
Create an Assistant
OpenAIResponsesCreator creates an AI agent that can process and analyze a document (the agent is exposed as an IChatResponseProvider).
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using DevExpress.AIIntegration.Agents;
using DevExpress.AIIntegration.Chat;
using Microsoft.Extensions.AI;
using OpenAI;
using OpenAI.Files;
using OpenAI.Responses;
using OpenAI.VectorStores;
#pragma warning disable OPENAI001
namespace AIChatAssistantDemo {
public class OpenAIResponsesCreator {
readonly ResponsesClient responsesClient;
readonly OpenAIFileClient fileClient;
readonly VectorStoreClient vectorStoreClient;
readonly string deployment;
public OpenAIResponsesCreator(OpenAIClient client, string deployment) {
responsesClient = client.GetResponsesClient();
fileClient = client.GetOpenAIFileClient();
vectorStoreClient = client.GetVectorStoreClient();
this.deployment = deployment;
}
public IChatResponseProvider Build(
string instructions,
OpenAIResponsesFileInfo fileInfo,
bool useFileSearchTool = true,
CancellationToken ct = default) {
fileInfo.Data.Position = 0;
OpenAIFile file = null;
VectorStore vectorStore = null;
try {
try {
ClientResult<OpenAIFile> fileResponse = fileClient.UploadFile(
fileInfo.Data,
fileInfo.FileName,
FileUploadPurpose.Assistants,
ct);
file = fileResponse.Value;
}
finally {
fileInfo.Data.Dispose();
}
// Create a vector store for file search.
if (useFileSearchTool) {
var vectorStoreOptions = new VectorStoreCreationOptions() {
ExpirationPolicy = new VectorStoreExpirationPolicy(
VectorStoreExpirationAnchor.LastActiveAt,
1)
};
vectorStore = vectorStoreClient.CreateVectorStore(vectorStoreOptions, ct).Value;
vectorStoreClient.AddFileToVectorStore(vectorStore.Id, file.Id, ct);
}
// Create a tools list.
var tools = new List<AITool>();
if (useFileSearchTool && vectorStore != null) {
var fileSearchTool = new HostedFileSearchTool {
Inputs = [new HostedVectorStoreContent(vectorStore.Id)]
};
tools.Add(fileSearchTool);
}
var codeInterpreterTool = new HostedCodeInterpreterTool {
Inputs = [new HostedFileContent(file.Id)]
};
tools.Add(codeInterpreterTool);
// Create an AI agent.
var aiAgent = responsesClient.AsAIAgent(
instructions: instructions,
tools: tools,
name: $"Responses Agent {Guid.NewGuid()}",
model: deployment
);
var session = aiAgent.CreateSessionAsync(ct);
return aiAgent.AsIChatResponseProvider(session.Result);
}
catch {
if (vectorStore != null) {
TryDeleteVectorStore(vectorStore.Id, ct);
}
if (file != null) {
TryDeleteFile(file.Id, ct);
}
throw;
}
}
void TryDeleteVectorStore(string vectorStoreId, CancellationToken ct) {
try {
vectorStoreClient.DeleteVectorStore(vectorStoreId, ct);
}
catch {
// Best-effort cleanup only; preserve the original exception.
}
}
void TryDeleteFile(string fileId, CancellationToken ct) {
try {
fileClient.DeleteFile(fileId, ct);
}
catch {
// Best-effort cleanup only; preserve the original exception.
}
}
}
public record OpenAIResponsesFileInfo(string FileName, Stream Data);
}
#pragma warning restore OPENAI001
Warning
The OpenAI.Responses API is for evaluation purposes only and is subject to change or removal in a future update. The following code snippet suppresses the OPENAI001 diagnostic.
Configure the AI Chat
Connect the AI Chat Control to the registered response provider and define assistant behavior.
using System;
using System.IO;
using DevExpress.XtraBars.Ribbon;
namespace AIChatAssistantDemo {
public partial class AIAssistantForm : RibbonForm {
public Form1() {
InitializeComponent();
// Assign the service key used by the AI Chat Control to resolve
// the registered IChatResponseProvider.
aiChatControl1.ChatResponseProviderServiceKey = Program.ResponsesAPIChatResponseProviderServiceKey;
}
public static string GetInstructions() {
// Return system-level instructions that define the assistant's role and behavior.
return "You are an analytics assistant that specializes in analyzing PDF files. Your role is to assist users by...";
}
public static OpenAIResponsesFileInfo GetFile() {
const string fileName = "RestaurantMenu.pdf";
// Open a file stream that will be sent to the AI service for processing.
Stream data = new FileStream(fileName, FileMode.Open);
return new OpenAIResponsesFileInfo(fileName, data);
}
}
}
Register AI Services and an IChatResponseProvider
using Azure.AI.OpenAI;
using DevExpress.AIIntegration;
using DevExpress.AIIntegration.Chat;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.ClientModel;
using System.Windows.Forms;
namespace AIChatAssistantDemo {
internal static class Program {
internal const string ResponsesAPIChatResponseProviderServiceKey = "ChatResponseProvider-ResponsesApi";
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Create an Azure OpenAI chat client.
var azureChatClient = new AzureOpenAIClient(AzureOpenAIEndpoint, AzureOpenAIKey);
// Create a service collection to register AI chat clients.
var collection = new ServiceCollection();
// Register a keyed IChatResponseProvider for Azure OpenAI.
collection.AddKeyedSingleton<IChatResponseProvider>(ResponsesAPIChatResponseProviderServiceKey, (_, _) => {
return new OpenAIResponsesCreator(azureChatClient, AzureOpenAIModel).Build(AIAssistantForm.GetInstructions(), AIAssistantForm.GetFile());
});
// Register a default (non-keyed) IChatResponseProvider.
// This provider is used when no ChatResponseProviderServiceKey is specified.
collection.AddScoped<IChatResponseProvider>(
(serviceProvider) => azureChatClient.GetChatClient(AzureOpenAIModel).AsIChatClient().AsIChatResponseProvider()
);
// Add DevExpress AI services (required for AIChatControl).
collection.AddDevExpressAIDesktop();
Application.Run(new Form1());
}
static Uri AzureOpenAIEndpoint = new Uri("YOUR_AZURE_ENDPOINT");
static ApiKeyCredential AzureOpenAIKey = new ApiKeyCredential("YOUR_AZURE_API_KEY");
static string AzureOpenAIModel = "gpt-5.2";
}
}
Azure AI Projects
The following example uses the Azure AI Projects API to analyze a user-supplied PDF file.
Install NuGet Packages
Install the following packages:
- Azure.AI.Projects (version 2.0.0)
- Microsoft.Agents.AI.OpenAI
DevExpress.AIIntegration.AgentsDevExpress.AIIntegration.WinForms.ChatDevExpress.Win
Create an Azure AI Projects Agent
using System;
using System.IO;
using System.Linq;
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using DevExpress.AIIntegration.Chat;
using Microsoft.Extensions.AI;
using OpenAI.Files;
using OpenAI.Responses;
using OpenAI.VectorStores;
namespace AIChatAzureAiProjectsDemo {
internal static class AzureAIProjectsAgentCreator {
const string AgentName = "AssistantTestAgent";
const string VectorStoreName = "RestaurantMenuVectorStore";
const string Model = "gpt-5.4-mini";
// Replace "YOUR_ENDPOINT" with the actual endpoint URL of your Azure AI Project.
const string FoundryProjectEndpointSampleValue = "YOUR_ENDPOINT";
#region Instructions
const string Instructions = "You are an analytics assistant that specializes in analyzing PDF files. Your role is to assist users by...";
#endregion
#pragma warning disable OPENAI001
internal static IChatResponseProvider Create() {
AIProjectClient projectClient = new(new Uri(FoundryProjectEndpointSampleValue), new VisualStudioCredential());
var agents = projectClient.AgentAdministrationClient.GetAgents();
CreateOrUpdateAgent(projectClient);
var responseClient = projectClient.ProjectOpenAIClient.GetProjectResponsesClient();
IChatClient chatClient = responseClient.AsIChatClient();
var chatOptions = new ChatOptions {
RawRepresentationFactory = _ => {
CreateResponseOptions options = new() {
Agent = new AgentReference(AgentName)
};
return options;
}
};
return chatClient.AsIChatResponseProvider(chatOptions);
}
static void CreateOrUpdateAgent(AIProjectClient projectClient) {
var agents = projectClient.AgentAdministrationClient.GetAgents();
var existingAgent = agents.FirstOrDefault(a => a.Name == AgentName);
if(existingAgent != null) {
projectClient.AgentAdministrationClient.DeleteAgent(existingAgent.Id);
}
string vectorStoreId = CreateVectorStore(projectClient);
var agentDefinition = new DeclarativeAgentDefinition(Model) {
Instructions = Instructions,
Tools = {
ResponseTool.CreateFileSearchTool([vectorStoreId])
}
};
var options = new ProjectsAgentVersionCreationOptions(agentDefinition);
projectClient.AgentAdministrationClient.CreateAgentVersion(AgentName, options);
}
static string CreateVectorStore(AIProjectClient projectClient) {
var fileClient = projectClient.ProjectOpenAIClient.GetOpenAIFileClient();
var vectorStoreClient = projectClient.ProjectOpenAIClient.GetVectorStoreClient();
using Stream pdfStream = GetEmbeddedResourceStream();
var uploadedFile = fileClient.UploadFile(pdfStream, "RestaurantMenu.pdf", FileUploadPurpose.Assistants);
var creationOptions = new VectorStoreCreationOptions {
Name = VectorStoreName
};
var vectorStore = vectorStoreClient.CreateVectorStore(creationOptions);
vectorStoreClient.AddFileToVectorStore(vectorStore.Value.Id, uploadedFile.Value.Id);
return vectorStore.Value.Id;
}
static Stream GetEmbeddedResourceStream() {
const string fileName = "RestaurantMenu.pdf";
Stream stream = new FileStream(fileName, FileMode.Open);
if(stream is null) {
throw new InvalidOperationException($"'{fileName}' doesn't exist.");
}
return stream;
}
#pragma warning restore OPENAI001
}
}
Register AI Services
// Program.cs
using DevExpress.AIIntegration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Windows.Forms;
namespace AIChat {
internal static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var collection = new ServiceCollection();
collection.AddSingleton(AzureAIProjectsAgentCreator.Create());
// Add DevExpress AI services (required for AIChatControl).
collection.AddDevExpressAIDesktop();
Application.Run(new Form1());
}
}
}
DevExpress AI Chat (RAG) App Template
The AI Chat (RAG) Application template creates a desktop WinForms application with the AI Chat Control and built-in Retrieval-Augmented Generation (RAG) for document-grounded conversations.
This template does the following:
- Uses local document data for context-aware answers.
- Scans the user’s Documents folder and indexes PDF, DOCX, TXT, RTF, and HTML files.
- Extracts, embeds, and semantically searches document text.
- Stores vectors in In-Memory data source (rebuilt on each run) or SQLite (a persistent database).
- Combines the user’s prompt with retrieved content to improve accuracy.
- Optionally integrates the DevExpress MCP Server for DevExpress-specific guidance.
Refer to the following help topic for additional information: Artificial Intelligence — DevExpress Template Kit.