Open the project:
Open the terminal and run:
cd deploy/aca
azd auth login
azd upFor detailed instructions, see Getting Started below.
You can run this repo virtually by using GitHub Codespaces or VS Code Dev Containers. Click on one of the buttons below to open this repo in one of those options.
All prerequisites are already installed in the container. You can skip to the Starting from scratch section.
- Java 17
- Maven 3.8.x
- Azure Developer CLI
- Node.js
- Git
- Python 3.9, 3.10, or 3.11 - Required for RAG evaluation and to automatically configure login and document filtering with EntraID
- Powershell 7+ (pwsh) - For Windows users only.
- Important: Ensure you can run
pwsh.exefrom a PowerShell command. If this fails, you likely need to upgrade PowerShell.
- Important: Ensure you can run
[!WARNING] Your Azure Account must have
Microsoft.Authorization/roleAssignments/writepermissions, such as User Access Administrator or Owner.
You can clone this repo and change directory to the root of the repo. Or you can run azd init -t Azure-Samples/azure-search-openai-demo-java.
Once you have the project available locally, run the following commands if you don't have any pre-existing Azure services and want to start from a fresh deployment.
Important
All the commands below must be run from the deploy/aca folder
-
Run
azd auth login
-
Run
azd up
- This will provision Azure resources and deploy this sample to those resources, including building the search index based on the files found in the
./datafolder. - For the target location check up-to-date list of regions and models availables here
- This will provision Azure resources and deploy this sample to those resources, including building the search index based on the files found in the
-
After the application has been successfully deployed you will see a web app URL printed to the console. Click that URL to interact with the application in your browser.
It will look like the following:
NOTE: It may take few minutes for the indexer app to consume the ingestion request messages from service bus. You can monitor the ingestion process by checking the log stream of the indexer app in the Azure Portal
If you already have existing Azure resources, you can re-use those by setting azd environment values.
- Run
azd env set AZURE_RESOURCE_GROUP {Name of existing resource group} - Run
azd env set AZURE_LOCATION {Location of existing resource group (i.e eastus2)}
- Run
azd env set AZURE_OPENAI_SERVICE {Name of existing OpenAI service} - Run
azd env set AZURE_OPENAI_RESOURCE_GROUP {Name of existing resource group that OpenAI service is provisioned to} - Run
azd env set AZURE_OPENAI_SERVICE_LOCATION {Location of existing resource (i.e eastus2)}. Only needed if your OpenAI resource is in a different location than the one you'll pick for theazd upstep. - Run
azd env set AZURE_OPENAI_CHATGPT_DEPLOYMENT {Name of existing ChatGPT deployment}. Only needed if your ChatGPT deployment is not the default 'chat'. - Run
azd env set AZURE_OPENAI_EMB_DEPLOYMENT {Name of existing GPT embedding deployment}. Only needed if your embeddings deployment is not the default 'embedding'.
- Run
azd env set AZURE_SEARCH_SERVICE {Name of existing Azure AI Search service} - Run
azd env set AZURE_SEARCH_SERVICE_RESOURCE_GROUP {Name of existing resource group with ACS service} - If that resource group is in a different location than the one you'll pick for the
azd upstep, then runazd env set AZURE_SEARCH_SERVICE_LOCATION {Location of existing service} - If the search service's SKU is not standard, then run
azd env set AZURE_SEARCH_SERVICE_SKU {Name of SKU}. The free tier won't work as it doesn't support managed identity. (See other possible values)
You can also use existing Document Intelligence and Storage Accounts. See ./infra/main.parameters.json for list of environment variables to pass to azd env set to configure those existing resources.
Now you can run azd up, following the steps in Deploying from scratch above.
That will both provision resources and deploy the code.
If you've only changed the backend/frontend code in the app folder, then you don't need to re-provision the Azure resources. You can just run:
azd deployIf you've changed the infrastructure files (infra folder or azure.yaml), then you'll need to re-provision the Azure resources. You can do that by running:
azd provisionWarning
When you run azd up or azd provision multiple times to redeploy infrastructure, make sure to set the following parameters in infra/main.parameters.json to true to avoid container apps images from being overridden with default "mcr.microsoft.com/azuredocs/containerapps-helloworld" image:
"apiAppExists": {
"value": true
},
"webAppExists": {
"value": true
},
"indexerAppExists": {
"value": true
}azd auth login
azd env set AZURE_OPENAI_CHATGPT_MODEL "gpt-4" # Change the chatgpt model to gpt-4
azd upNOTE: This sample has been tested with gpt-4o-mini.Using other models or different versions might result in unexpected behavior.
azd auth login
azd init -t Azure-Samples/azure-search-openai-demo-java.
azd env set AZURE_RESOURCE_GROUP "openai-test-resource-group" # Target resource group for the new resources
azd env set AZURE_LOCATION "eastus" # Target region for the new resources
azd env set AZURE_OPENAI_SERVICE "my-openai-test-service" # Name of the OpenAI service
azd env set AZURE_OPENAI_RESOURCE_GROUP "my-openai-test-resource-group" # Resource group where the OpenAI service is deployed
azd env set AZURE_OPENAI_SERVICE_LOCATION "eastus2" # Region of the OpenAI service
azd env set AZURE_OPENAI_CHATGPT_DEPLOYMENT "gpt-35-turbo" # The "Deployment name" of the deployed model, deployed in the Azure OpenAI studio
azd env set AZURE_OPENAI_EMB_DEPLOYMENT "text-embedding-ada-002" # The "Deployment name" of the deployed model, deployed in the Azure OpenAI studio
azd env set AZURE_SEARCH_SERVICE "my-acs-test-service" # Name of the ACS service
azd env set AZURE_SEARCH_SERVICE_RESOURCE_GROUP "my-acs-test-resource-group" # Resource group where the ACS service is deployed
azd env set AZURE_SEARCH_SERVICE_LOCATION "eastus2" # Region of the ACS service
azd up- In Azure: navigate to the Web App deployed by azd. The URL is printed out when azd completes (as "Endpoint"), or you can find it in the Azure portal.
- Running locally: navigate to localhost:8080
Once in the web app:
- Try different topics in chat or Q&A context. For chat, try follow-up questions, clarifications, ask to simplify or elaborate on answer, etc.
- Explore citations and sources
- Click on "settings" to try different options, tweak prompts, etc.
- Use "Manage File Uploads" to load your documents and start QA session on related topics
See Local Development with IntelliJ for detailed guidance on how to run the backend and frontend applications locally.
Applications Insights is enabled by default. It allows to investigate each request tracing along with the logging of errors.
If you want to disable it set the AZURE_USE_APPLICATION_INSIGHTS variable to false before running azd up
- Run
azd env set AZURE_USE_APPLICATION_INSIGHTS false - Run
azd up
To see the performance data, go to the Application Insights resource in your resource group, click on the "Investigate -> Performance" blade and navigate to any HTTP request to see the timing data. To inspect the performance of chat requests, use the "Drill into Samples" button to see end-to-end traces of all the API calls made for any chat request. Under "Trace & Events" panel you can review custom Java informational logs to better understand content of OpenAI requests and responses.
To see any exceptions and server errors, navigate to the "Investigate -> Failures" blade and use the filtering tools to locate a specific exception. You can see Java stack traces on the right-hand side.
See here for detailed guidance.
This feature allows users to view the chat history of their conversation, stored in the browser using IndexedDB. That means the chat history will be available only on the device where the chat was initiated. To enable browser-stored chat history, run:
azd env set USE_CHAT_HISTORY_BROWSER trueThis is useful especially for unauthenticated users. For authenticated ones see below.
This feature allows authenticated users to view the chat history of their conversations, stored in the server-side storage using Azure Cosmos DB.This option requires that authentication be enabled. The chat history will be persistent and accessible from any device where the user logs in with the same account. To enable server-stored chat history, run:
azd env set USE_CHAT_HISTORY_COSMOS trueWhen both the browser-stored and Cosmos DB options are enabled, Cosmos DB will take precedence over browser-stored chat history.
See Evaluation for detailed guidance on how to evaluate the RAG application using the provided python scripts.
For safety evaluation, see Safety Evaluation.
☀️ ☁️ 👷♂️ WIP
This sample is designed to be a starting point for your own production application, but you should do a thorough review of the security and performance before deploying to production. Here are some things to consider:
- OpenAI Capacity: The default TPM (tokens per minute) is set to 60K for gpt and 80k for embeddings. That is equivalent
to approximately 60 conversations per minute (assuming 1K per user message/response).
You can increase the capacity by changing the
chatGptDeploymentCapacityandembeddingDeploymentCapacityparameters ininfra/main.bicepto your account's maximum capacity. You can also view the Quotas tab in Azure OpenAI studio to understand how much capacity you have. - Azure Storage: The default storage account uses the
Standard_LRSSKU. To improve your resiliency, we recommend usingStandard_ZRSfor production deployments, which you can specify using theskuproperty under thestoragemodule ininfra/main.bicep. - Azure AI Search: The default search service uses the
StandardSKU with the free semantic search option, which gives you 1000 free queries a month. Assuming your app will experience more than 1000 questions, you should either changesemanticSearchto "standard" or disable semantic search entirely in the/app/backend/approachesfiles. If you see errors about search service capacity being exceeded, you may find it helpful to increase the number of replicas by changingreplicaCountininfra/core/search/search-services.bicepor manually scaling it from the Azure Portal. - Azure Containers App: Consumption workload profile is used with 4 CPU core and 8 GB RAM to host all the 3 apps. We recommend to use Dedicated profile and select one from the available types based on your capacity needs. You can use auto-scaling rules or scheduled scaling rules, and scale up the maximum/minimum based on load.
- Service Bus: Standard SKU is used. Consider to use Premium SKU to enable redundancy and predictable performance with high throughput.
- Event Grid: Event Grid basic is used. Consider to use Event Grid Standard tier if the ingestion requests rates are high (> 5MB/s). Only BlobId are sent in the event grid events. The blob content is not sent. Authentication: By default, the deployed app is publicly accessible. We recommend restricting access to authenticated users.
- Networking: We recommend deploying inside a Virtual Network. If the app is only for internal enterprise use, use a private DNS zone. Also consider using Azure API Management (APIM) for firewalls and other forms of protection. For more details, read Azure OpenAI Landing Zone reference architecture.
- Loadtesting: We recommend running a loadtest for your expected number of users. You can use Azure Load Test with Apache Jmeter
Pricing varies per region and usage, so it isn't possible to predict exact costs for your usage. However, you can try the Azure pricing calculator for the resources below.
- Azure Containers App: Consumption workload profile with 4 CPU core and 8 GB RAM. Pricing per vCPU and Memory. Pricing
- Azure OpenAI: Standard tier, ChatGPT and Ada models. Pricing per 1K tokens used, and at least 1K tokens are used per question. Pricing
- Form Recognizer: SO (Standard) tier using pre-built layout. Pricing per document page, sample documents have 261 pages total. Pricing
- Azure AI Search: Standard tier, 1 replica, free level of semantic search. Pricing per hour.Pricing
- Azure Blob Storage: Standard tier with ZRS (Zone-redundant storage). Pricing per storage and read operations. Pricing
- Azure Monitor: Pay-as-you-go tier. Costs based on data ingested. Pricing
- Azure Event Grid: Basic tier. Pricing per operation. Pricing
- Azure Service Bus: Standard tier. Pricing per hour and operations. Pricing
- Azure Cosmos DB: Only provisioned if you enabled chat history with Cosmos DB. Serverless tier. Pricing per request unit and storage. Pricing
The first 180,000 vCPU-seconds, 360,000 GiB-seconds, and 2 million requests each month are free for ACA. To reduce costs, you can switch to free SKUs Document Intelligence by changing the parameters file under the infra folder. There are some limits to consider; for example, the free Document Intelligence resource only analyzes the first 2 pages of each document.
azd down --purge.
Note: The PDF documents used in this demo contain information generated using a language model (Azure OpenAI Service). The information contained in these documents is only for demonstration purposes and does not reflect the opinions or beliefs of Microsoft. Microsoft makes no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the information contained in this document. All rights reserved to Microsoft.
Why do we need to break up the PDFs into chunks when Azure AI Search supports searching large documents?
Chunking allows us to limit the amount of information we send to OpenAI due to token limits. By breaking up the content, it allows us to easily find potential chunks of text that we can inject into OpenAI. The method of chunking we use leverages a sliding window of text such that sentences that end one chunk will start the next. This allows us to reduce the chance of losing the context of the text.
Details
How can we upload additional PDFs without redeploying everything?
To upload more PDFs, put them in the data/ folder and run ./scripts/prepdocs.sh or ./scripts/prepdocs.ps1. To avoid reuploading existing docs, move them out of the data folder. You could also implement checks to see whats been uploaded before; our code doesn't yet have such checks.
Details
What does the `azd up` command do?
The azd up command comes from the Azure Developer CLI, and takes care of both provisioning the Azure resources and deploying code to the selected Azure hosts.
The azd up command uses the azure.yaml file combined with the infrastructure-as-code .bicep files in the infra/ folder. The azure.yaml file for this project declares several "hooks" for the prepackage step and postprovision steps. The up command first runs the prepackage hook which installs Node dependencies and builds the React.JS-based JavaScript files. It then packages all the code (both frontend and backend) into a zip file which it will deploy later.
Next, it provisions the resources based on main.bicep and main.parameters.json. At that point, since there is no default value for the OpenAI resource location, it asks you to pick a location from a short list of available regions. Then it will send requests to Azure to provision all the required resources. With everything provisioned, it runs the postprovision hook to process the local data and add it to an Azure AI Search index.
Finally, it looks at azure.yaml to determine the Azure host (appservice, in this case) and uploads the zip to Azure App Service. The azd up command is now complete, but it may take another 5-10 minutes for the App Service app to be fully available and working, especially for the initial deploy.
Related commands are azd provision for just provisioning (if infra files change) and azd deploy for just deploying updated app code.
Here are the most common failure scenarios and solutions:
-
The subscription (
AZURE_SUBSCRIPTION_ID) doesn't have access to the Azure OpenAI Service. Please ensureAZURE_SUBSCRIPTION_IDmatches the ID specified in the OpenAI access request process. -
You're attempting to create resources in regions not enabled for Azure OpenAI (e.g. East US 2 instead of East US), or where the model you're trying to use isn't enabled. See this matrix of model availability.
-
You've exceeded a quota, most often number of resources per region. See this article on quotas and limits.
-
You're getting "same resource name not allowed" conflicts. That's likely because you've run the sample multiple times and deleted the resources you've been creating each time, but are forgetting to purge them. Azure keeps resources for 48 hours unless you purge from soft delete. See this article on purging resources.
-
You see
CERTIFICATE_VERIFY_FAILEDwhen theprepdocs.pyscript runs. That's typically due to incorrect SSL certificates setup on your machine. Try the suggestions in this StackOverflow answer. -
After running
./app/start.ps1on Windows PowerShell you getThe file C:\path\to\azure-search-openai-demo-java\app\start.ps1 is not digitally signed. You cannot run this script on the current system. Try to runSet-ExecutionPolicy -Scope Process -ExecutionPolicy Bypassand try to re-run./app/start.ps1 -
After running
./app/start.ps1or./app/start.shyou get"Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:compile (default-compile) on project myproject: Fatal error compiling: invalid target release: 17". It means you are not using JDK 17 but a previous version. Be sure to set theJAVA_HOMEenv variable to your Java 17 installation directory and update yourPATHenv variable to have the Java 17 bin folder as the first occurrence amongst the listed directories. More info here -
While running
azd upin VS Code Dev Containers you got this error".. Maven: failed finding mvnw in repository path: exec: /azure-search-openai-demo-java/app/backend/mvnw: permission denied ". Runchmod +x ./azure-search-openai-demo-javaapp/backend/mvnwto fix it and rerunazd up.


