Skip to content

Commit c57f62f

Browse files
committed
Merge ChatReadRetrieveReadApproach into Approach class
Since the Ask tab was removed, there is now only one approach implementation. This refactor merges ChatReadRetrieveReadApproach into the base Approach class, simplifying the codebase by removing the unnecessary inheritance hierarchy. Changes: - Merge all ChatReadRetrieveReadApproach code into approach.py - Remove ABC base class since there's only one implementation - Delete chatreadretrieveread.py - Update app.py to use Approach directly - Update tests to use new import paths - Update documentation to reflect simplified architecture
1 parent 0c21ae3 commit c57f62f

File tree

9 files changed

+496
-583
lines changed

9 files changed

+496
-583
lines changed

AGENTS.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ If necessary, edit this file to ensure it accurately reflects the current state
1010
* app: Contains the main application code, including frontend and backend.
1111
* app/backend: Contains the Python backend code, written with Quart framework.
1212
* app/backend/approaches: Contains the different approaches
13-
* app/backend/approaches/approach.py: Base class for all approaches
14-
* app/backend/approaches/chatreadretrieveread.py: Chat approach, includes query rewriting step first
13+
* app/backend/approaches/approach.py: Main RAG approach class with query rewriting and retrieval
1514
* app/backend/approaches/prompts/chat_query_rewrite.prompty: Prompt used to rewrite the query based off search history into a better search query
1615
* app/backend/approaches/prompts/chat_query_rewrite_tools.json: Tools used by the query rewriting prompt
1716
* app/backend/approaches/prompts/chat_answer_question.prompty: Prompt used by the Chat approach to actually answer the question based off sources
@@ -86,7 +85,7 @@ When adding a new developer setting, update:
8685
* app/frontend/src/pages/chat/Chat.tsx: Add the setting to the component, pass it to Settings
8786

8887
* backend:
89-
* app/backend/approaches/chatreadretrieveread.py : Retrieve from overrides parameter
88+
* app/backend/approaches/approach.py : Retrieve from overrides parameter
9089
* app/backend/app.py: Some settings may need to be sent down in the /config route.
9190

9291
## When adding tests for a new feature

app/backend/app.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
from quart_cors import cors
4646

4747
from approaches.approach import Approach, DataPoints
48-
from approaches.chatreadretrieveread import ChatReadRetrieveReadApproach
4948
from approaches.promptmanager import PromptyManager
5049
from chat_history.cosmosdb import chat_history_cosmosdb_bp
5150
from config import (
@@ -702,8 +701,8 @@ async def setup_clients():
702701

703702
prompt_manager = PromptyManager()
704703

705-
# ChatReadRetrieveReadApproach is used by /chat for multi-turn conversation
706-
current_app.config[CONFIG_CHAT_APPROACH] = ChatReadRetrieveReadApproach(
704+
# Approach is used by /chat for multi-turn conversation
705+
current_app.config[CONFIG_CHAT_APPROACH] = Approach(
707706
search_client=search_client,
708707
search_index_name=AZURE_SEARCH_INDEX,
709708
knowledgebase_model=AZURE_OPENAI_KNOWLEDGEBASE_MODEL,

app/backend/approaches/approach.py

Lines changed: 461 additions & 16 deletions
Large diffs are not rendered by default.

app/backend/approaches/chatreadretrieveread.py

Lines changed: 0 additions & 525 deletions
This file was deleted.

docs/architecture.md

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# RAG Chat: Application Architecture
1+
# RAG Chat: Application architecture
22

3-
This document provides a detailed architectural overview of this application, a Retrieval Augmented Generation (RAG) application that creates a ChatGPT-like experience over your own documents. It combines Azure OpenAI Service for AI capabilities with Azure AI Search for document indexing and retrieval.
3+
This document provides a detailed architectural overview of this application, a Retrieval Augmented Generation (RAG) application that creates a ChatGPT-like experience over your own documents. It combines Azure OpenAI Service for LLM calls with Azure AI Search for document indexing and retrieval.
44

55
For getting started with the application, see the main [README](../README.md).
66

@@ -21,20 +21,16 @@ graph TB
2121
end
2222
2323
subgraph "Backend"
24-
API[🐍 Python API<br/>Flask/Quart<br/>Chat Endpoints<br/>Document Upload<br/>Authentication]
25-
26-
subgraph "Approaches"
27-
CRR[ChatReadRetrieveRead<br/>Approach]
28-
end
24+
API[🐍 Python API<br/>Quart<br/>Chat Endpoints<br/>Document Upload<br/>Authentication<br/>RAG Approach]
2925
end
3026
end
3127
3228
subgraph "Azure Services"
3329
subgraph "AI Services"
34-
OpenAI[🤖 Azure OpenAI<br/>GPT-4 Mini<br/>Text Embeddings<br/>GPT-4 Vision]
30+
OpenAI[🤖 Azure OpenAI<br/>GPT-4.1 Mini<br/>Text Embeddings]
3531
Search[🔍 Azure AI Search<br/>Vector Search<br/>Semantic Ranking<br/>Full-text Search]
3632
DocIntel[📄 Azure Document<br/>Intelligence<br/>Text Extraction<br/>Layout Analysis]
37-
Vision2[👁️ Azure AI Vision<br/>optional]
33+
Vision[👁️ Azure AI Vision<br/>optional]
3834
Speech[🎤 Azure Speech<br/>Services optional]
3935
end
4036
@@ -46,7 +42,6 @@ graph TB
4642
subgraph "Platform Services"
4743
ContainerApps[📦 Azure Container Apps<br/>or App Service<br/>Application Hosting]
4844
AppInsights[📊 Application Insights<br/>Monitoring<br/>Telemetry]
49-
KeyVault[🔐 Azure Key Vault<br/>Secrets Management]
5045
end
5146
end
5247
@@ -59,9 +54,6 @@ graph TB
5954
Browser <--> React
6055
React <--> API
6156
62-
%% Backend Processing
63-
API --> CRR
64-
6557
%% Azure Service Connections
6658
API <--> OpenAI
6759
API <--> Search
@@ -78,7 +70,6 @@ graph TB
7870
%% Platform Integration
7971
ContainerApps --> API
8072
API --> AppInsights
81-
API --> KeyVault
8273
8374
%% Styling
8475
classDef userLayer fill:#e1f5fe
@@ -89,10 +80,10 @@ graph TB
8980
classDef processing fill:#f1f8e9
9081
9182
class User,Browser userLayer
92-
class React,API,CRR appLayer
93-
class OpenAI,Search,DocIntel,Vision2,Speech azureAI
83+
class React,API appLayer
84+
class OpenAI,Search,DocIntel,Vision,Speech azureAI
9485
class Blob,Cosmos azureStorage
95-
class ContainerApps,AppInsights,KeyVault azurePlatform
86+
class ContainerApps,AppInsights azurePlatform
9687
class PrepDocs processing
9788
```
9889

@@ -148,16 +139,15 @@ sequenceDiagram
148139

149140
### Frontend (React/TypeScript)
150141

151-
- **Chat Interface**: Main conversational UI
152-
- **Settings Panel**: Configuration options for AI behavior
153-
- **Citation Display**: Shows sources and references
142+
- **Chat interface**: Main conversational UI
143+
- **Settings panel**: Configuration options for AI behavior
144+
- **Citation display**: Shows sources and references
154145
- **Authentication**: Optional user login integration
155146

156147
### Backend (Python)
157148

158149
- **API Layer**: RESTful endpoints for chat, search, and configuration. See [HTTP Protocol](http_protocol.md) for detailed API documentation.
159-
- **Approach Patterns**: Different strategies for processing queries
160-
- `ChatReadRetrieveRead`: Multi-turn conversation with retrieval
150+
- **RAG approach**: Multi-turn conversation with retrieval
161151
- **Authentication**: Optional integration with Azure Active Directory
162152

163153
### Azure Services Integration
@@ -171,11 +161,14 @@ sequenceDiagram
171161

172162
The architecture supports several optional features that can be enabled. For detailed configuration instructions, see the [optional features guide](deploy_features.md):
173163

174-
- **GPT-4 with Vision**: Process image-heavy documents
175-
- **Speech Services**: Voice input/output capabilities
176-
- **Chat History**: Persistent conversation storage in Cosmos DB
177-
- **Authentication**: User login and access control
178-
- **Private Endpoints**: Network isolation for enhanced security
164+
- **Multimodal embeddings and answering**: Use image embeddings for searching and images when answering
165+
- **Reasoning models**: Use reasoning models like o3/o4-mini for more thoughtful responses
166+
- **Agentic retrieval**: Use agentic retrieval in place of the Search API
167+
- **Speech input/output**: Voice input via browser API, voice output via Azure Speech Services
168+
- **Chat history**: Browser-based (IndexedDB) or persistent storage in Cosmos DB
169+
- **Authentication**: User login and document-level access control
170+
- **User document upload**: Allow users to upload and chat with their own documents
171+
- **Private endpoints**: Network isolation for enhanced security
179172

180173
## Deployment Options
181174

docs/customization.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The backend is built using [Quart](https://quart.palletsprojects.com/), a Python
3232

3333
Typically, the primary backend code you'll want to customize is the `app/backend/approaches` folder, which contains the code and prompts powering the RAG flow.
3434

35-
The RAG flow is implemented in [chatreadretrieveread.py](https://github.com/Azure-Samples/azure-search-openai-demo/blob/main/app/backend/approaches/chatreadretrieveread.py).
35+
The RAG flow is implemented in [approach.py](https://github.com/Azure-Samples/azure-search-openai-demo/blob/main/app/backend/approaches/approach.py).
3636

3737
1. **Query rewriting**: It calls the OpenAI ChatCompletion API to turn the user question into a good search query, using the prompt and tools from [chat_query_rewrite.prompty](https://github.com/Azure-Samples/azure-search-openai-demo/blob/main/app/backend/approaches/prompts/chat_query_rewrite.prompty).
3838
2. **Search**: It queries Azure AI Search for search results for that query (optionally using the vector embeddings for that query).

tests/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
import app
3333
import core
34-
from approaches.chatreadretrieveread import ChatReadRetrieveReadApproach
34+
from approaches.approach import Approach
3535
from approaches.promptmanager import PromptyManager
3636
from core.authentication import AuthenticationHelper
3737
from prepdocslib.blobmanager import AdlsBlobManager, BlobManager
@@ -1125,7 +1125,7 @@ def mock_user_directory_client(monkeypatch):
11251125

11261126
@pytest.fixture
11271127
def chat_approach():
1128-
return ChatReadRetrieveReadApproach(
1128+
return Approach(
11291129
search_client=SearchClient(endpoint="", index_name="", credential=AzureKeyCredential("")),
11301130
search_index_name=None,
11311131
knowledgebase_model=None,

tests/test_app.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ async def test_auth_setup_returns_payload(client):
205205
@pytest.mark.asyncio
206206
async def test_chat_handle_exception(client, monkeypatch, snapshot, caplog):
207207
monkeypatch.setattr(
208-
"approaches.chatreadretrieveread.ChatReadRetrieveReadApproach.run",
208+
"approaches.approach.Approach.run",
209209
mock.Mock(side_effect=ZeroDivisionError("something bad happened")),
210210
)
211211

@@ -222,7 +222,7 @@ async def test_chat_handle_exception(client, monkeypatch, snapshot, caplog):
222222
@pytest.mark.asyncio
223223
async def test_chat_stream_handle_exception(client, monkeypatch, snapshot, caplog):
224224
monkeypatch.setattr(
225-
"approaches.chatreadretrieveread.ChatReadRetrieveReadApproach.run_stream",
225+
"approaches.approach.Approach.run_stream",
226226
mock.Mock(side_effect=ZeroDivisionError("something bad happened")),
227227
)
228228

@@ -239,7 +239,7 @@ async def test_chat_stream_handle_exception(client, monkeypatch, snapshot, caplo
239239
@pytest.mark.asyncio
240240
async def test_chat_handle_exception_contentsafety(client, monkeypatch, snapshot, caplog):
241241
monkeypatch.setattr(
242-
"approaches.chatreadretrieveread.ChatReadRetrieveReadApproach.run",
242+
"approaches.approach.Approach.run",
243243
mock.Mock(side_effect=filtered_response),
244244
)
245245

tests/test_chatapproach.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88

99
from approaches.approach import (
1010
ActivityDetail,
11+
Approach,
1112
DataPoints,
1213
Document,
1314
ExtraInfo,
1415
SharePointResult,
1516
ThoughtStep,
1617
WebResult,
1718
)
18-
from approaches.chatreadretrieveread import ChatReadRetrieveReadApproach
1919
from approaches.promptmanager import PromptyManager
2020
from prepdocslib.embeddings import ImageEmbeddings
2121

@@ -149,7 +149,9 @@ def test_extract_rewritten_query_invalid_json(chat_approach):
149149
}
150150
completion = ChatCompletion.model_validate(payload, strict=False)
151151

152-
result = chat_approach.extract_rewritten_query(completion, "original", no_response_token=chat_approach.NO_RESPONSE)
152+
result = chat_approach.extract_rewritten_query(
153+
completion, "original", no_response_token=chat_approach.QUERY_REWRITE_NO_RESPONSE
154+
)
153155

154156
assert result == "fallback query"
155157

@@ -281,7 +283,7 @@ async def mock_create_embedding_for_text(self, q: str):
281283
async def test_compute_multimodal_embedding_no_client():
282284
"""Test that compute_multimodal_embedding raises ValueError when image_embeddings_client is not set."""
283285
# Create a chat approach without an image_embeddings_client
284-
chat_approach = ChatReadRetrieveReadApproach(
286+
chat_approach = Approach(
285287
search_client=SearchClient(endpoint="", index_name="", credential=AzureKeyCredential("")),
286288
search_index_name=None,
287289
knowledgebase_model=None,

0 commit comments

Comments
 (0)