Skip to content

Commit 3f723ae

Browse files
committed
updates
1 parent a7ec36d commit 3f723ae

File tree

4 files changed

+104
-42
lines changed

4 files changed

+104
-42
lines changed

Java/CosmosDB-MongoDB-vCore-Langchain/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This sample provides a demo showcasing the usage of the RAG pattern for integrat
44

55
### Prerequisites
66

7-
- Azure Cosmos DB Monogo Account
7+
- Azure Cosmos DB Mongo Account
88
- Connection string
99
- Azure Open AI Service
1010
- Deploy text-davinci-003 model for Embeding
@@ -35,5 +35,5 @@ mvn exec:java
3535
```
3636

3737
## Getting Started
38-
When you run the application for the first time, it will read and vectorize docs in the `PDF_docs` folder, and insert them into Cosmos DB MongoDB vCore vector store. To begin, just ask a question in command line.
38+
When you run the application for the first time, it will read and vectorize docs in the `PDF_docs` folder (you can add your own pdf or txt docs here), and insert them into Cosmos DB MongoDB vCore vector store. To begin, just ask a question in command line.
3939

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Use Azure Cosmos DB NoSQL API with Langchain in Java.
2+
3+
This sample provides a demo showcasing the usage of the RAG pattern for integrating Azure Open AI services with custom data in Azure Cosmos NoSQL API with [vector search using DiskANN index](https://learn.microsoft.com/azure/cosmos-db/nosql/vector-search) and [langchain framework for java](https://github.com/langchain4j/langchain4j).
4+
5+
### Prerequisites
6+
7+
- Azure Cosmos DB NoSQL API Account
8+
- Azure Cosmos DB NoSQL API endpoint
9+
- Azure Cosmos DB NoSQL API key
10+
- Azure Open AI Service
11+
- Deploy text-davinci-003 model for Embeding
12+
- Deploy gpt-35-turbo model for Chat Completion
13+
14+
15+
### Installation
16+
``` bash
17+
mvn clean install
18+
```
19+
20+
### Run
21+
22+
Before running the application, you need to set environment variables. Either export them in command line or set system variables:
23+
24+
```bash
25+
export COSMOSDB_ENDPOINT="Azure Cosmos DB NoSQL API endpoint"
26+
export COSMOSDB_KEY="Azure Cosmos DB NoSQL API key"
27+
export AZURE_OPENAI_ENDPOINT="endpoint for your Azure OpenAI account"
28+
export AZURE_OPENAI_APIKEY="key for your Azure OpenAI account"
29+
export AZURE_OPENAI_CHATDEPLOYMENTID="deployment id for your Azure OpenAI chat embeddings"
30+
export AZURE_OPENAI_EMBEDDINGDEPLOYMENTID="deployment is for your Azure OpenAI chat completions"
31+
```
32+
33+
Then run the app:
34+
35+
```bash
36+
mvn exec:java
37+
```
38+
39+
## Getting Started
40+
When you run the application for the first time, it will read and vectorize docs in the `PDF_docs` folder (you can add your own pdf or txt docs here), and insert them into Cosmos DB NoSQL API vector store. To begin, just ask a question in command line. By default, your private data will be used to form a response regardless of it's accuracy (experiment with changing the prompt to change the chat completion behaviour).
41+

Java/CosmosDB-NoSQL-Langchain/pom.xml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
<version>0.29.0-SNAPSHOT</version>
1010
</parent>
1111

12-
<artifactId>langchain4j-azure-cosmos-vcore</artifactId>
12+
<artifactId>langchain4j-azure-cosmos-nosql-sample</artifactId>
1313
<packaging>jar</packaging>
1414

15-
<name>LangChain4j :: Integration :: Azure CosmosDB MongoDB vCore</name>
15+
<name>LangChain4j :: Integration :: Azure CosmosDB NoSQL API</name>
1616

1717
<dependencies>
1818
<dependency>
@@ -30,11 +30,6 @@
3030
<artifactId>langchain4j-core</artifactId>
3131
<version>0.30.0</version>
3232
</dependency>
33-
<dependency>
34-
<groupId>org.mongodb</groupId>
35-
<artifactId>mongodb-driver-sync</artifactId>
36-
<version>4.11.1</version>
37-
</dependency>
3833
<dependency>
3934
<groupId>org.projectlombok</groupId>
4035
<artifactId>lombok</artifactId>
@@ -102,7 +97,7 @@
10297
<artifactId>exec-maven-plugin</artifactId>
10398
<version>3.0.0</version>
10499
<configuration>
105-
<mainClass>azure.cosmos.nosql.demo.AzureCosmosDBMongoVCoreLangchainDemo</mainClass>
100+
<mainClass>azure.cosmos.nosql.demo.AzureCosmosDBNoSQLLangchainDemo</mainClass>
106101
</configuration>
107102
</plugin>
108103
<plugin>

Java/CosmosDB-NoSQL-Langchain/src/main/java/azure/cosmos/nosql/demo/AzureCosmosDBNoSQLLangchainDemo.java

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import dev.langchain4j.store.embedding.EmbeddingStore;
4040
import dev.langchain4j.store.embedding.azure.cosmos.nosql.AzureCosmosDbNoSqlEmbeddingStore;
4141

42-
4342
import java.io.File;
4443
import java.io.FileInputStream;
4544
import java.io.FileNotFoundException;
@@ -59,6 +58,7 @@ public class AzureCosmosDBNoSQLLangchainDemo {
5958
private final static String COSMOSDB_DATABASE = "langchain_java-db";
6059
private final static String COSMOSDB_COLLECTION = "langchain_java-coll";
6160

61+
// injecting a prompt - change this according to your use case
6262
private final static String prompt = "Only use the context information to answer the question" +
6363
"even if the answer appears incorrect! {{message}}";
6464

@@ -67,7 +67,6 @@ public class AzureCosmosDBNoSQLLangchainDemo {
6767
.key(COSMOSDB_KEY)
6868
.buildClient();
6969

70-
7170
public static void main(String[] args) throws FileNotFoundException {
7271

7372
// Let's create a customer support agent to chat.
@@ -97,8 +96,10 @@ public static void main(String[] args) throws FileNotFoundException {
9796
}
9897

9998
private static ChatBotAgent createChatBotAgent() throws FileNotFoundException {
100-
// First, let's create a chat model, also known as a LLM, which will answer our queries.
101-
// In this example, we will use Azure OpenAI's gpt-3.5-turbo, but you can choose any supported model.
99+
// First, let's create a chat model, also known as a LLM, which will answer our
100+
// queries.
101+
// In this example, we will use Azure OpenAI's gpt-3.5-turbo, but you can choose
102+
// any supported model.
102103
// Langchain4j currently supports more than 10 popular LLM providers.
103104

104105
ChatLanguageModel model = AzureOpenAiChatModel.builder()
@@ -109,34 +110,43 @@ private static ChatBotAgent createChatBotAgent() throws FileNotFoundException {
109110
.temperature(0.3)
110111
.logRequestsAndResponses(true)
111112
.build();
112-
model.generate("Given the context information and not prior knowledge, answer the question. If you can't answer the question, use the most relevant contextual information as the answer, and do not add more information: %s");
113+
model.generate(
114+
"Given the context information and not prior knowledge, answer the question. If you can't answer the question, use the most relevant contextual information as the answer, and do not add more information: %s");
113115
System.out.println("Azure Open AI Chat Model initialized");
114116
// Now, let's load a document that we want to use for RAG.
115-
// We are using abstracts of papers submitted to Computer Vision and Pattern Recognition Conference
117+
// We are using abstracts of papers submitted to Computer Vision and Pattern
118+
// Recognition Conference
116119
// in 2019 (CVPR19). We are importing multiple pdf documents.
117-
// LangChain4j offers built-in support for loading documents from various sources:
120+
// LangChain4j offers built-in support for loading documents from various
121+
// sources:
118122
// File System, URL, Amazon S3, Azure Blob Storage, GitHub, Tencent COS.
119123
// Additionally, LangChain4j supports parsing multiple document types:
120124
// text, pdf, doc, xls, ppt.
121125
// However, you can also manually import your data from other sources.
122126
List<Document> documents = loadDocuments();
123127
System.out.println("Documents are loaded");
124128

125-
126-
// Now, we need to split this document into smaller segments, also known as "chunks."
127-
// This approach allows us to send only relevant segments to the LLM in response to a user query,
128-
// rather than the entire document. A good starting point is to use a recursive document splitter
129-
// that initially attempts to split by paragraphs. If a paragraph is too large to fit into a single segment,
130-
// the splitter will recursively divide it by newlines, then by sentences, and finally by words,
129+
// Now, we need to split this document into smaller segments, also known as
130+
// "chunks."
131+
// This approach allows us to send only relevant segments to the LLM in response
132+
// to a user query,
133+
// rather than the entire document. A good starting point is to use a recursive
134+
// document splitter
135+
// that initially attempts to split by paragraphs. If a paragraph is too large
136+
// to fit into a single segment,
137+
// the splitter will recursively divide it by newlines, then by sentences, and
138+
// finally by words,
131139
// if necessary, to ensure each piece of text fits into a single segment.
132140
DocumentSplitter splitter = DocumentSplitters.recursive(300, 0);
133141
List<TextSegment> segments = splitter.splitAll(documents);
134142
System.out.println("Documents are split in chunks");
135143

136144
// Now, we need to embed (also known as "vectorize") these segments.
137145
// Embedding is needed for performing similarity searches.
138-
// For this example, we'll use Azure Open AI text embedding model ada-002, but you can choose any supported model.
139-
// Langchain4j currently supports more than 10 popular embedding model providers.
146+
// For this example, we'll use Azure Open AI text embedding model ada-002, but
147+
// you can choose any supported model.
148+
// Langchain4j currently supports more than 10 popular embedding model
149+
// providers.
140150
EmbeddingModel embeddingModel = AzureOpenAiEmbeddingModel.builder()
141151
.endpoint(AZURE_OPENAI_ENDPOINT)
142152
.apiKey(AZURE_OPENAI_KEY)
@@ -150,7 +160,9 @@ private static ChatBotAgent createChatBotAgent() throws FileNotFoundException {
150160

151161
CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(COSMOSDB_COLLECTION, "/id");
152162

153-
//set vector embedding policy
163+
// For NoSQL API, we need to set the indexing policy and vector embedding policy
164+
165+
// set vector embedding policy
154166
CosmosVectorEmbeddingPolicy cosmosVectorEmbeddingPolicy = new CosmosVectorEmbeddingPolicy();
155167
CosmosVectorEmbedding embedding = new CosmosVectorEmbedding();
156168
embedding.setPath("/embedding");
@@ -160,7 +172,7 @@ private static ChatBotAgent createChatBotAgent() throws FileNotFoundException {
160172
cosmosVectorEmbeddingPolicy.setCosmosVectorEmbeddings(Arrays.asList(embedding));
161173
collectionDefinition.setVectorEmbeddingPolicy(cosmosVectorEmbeddingPolicy);
162174

163-
//set vector indexing policy
175+
// set vector indexing policy
164176
IndexingPolicy indexingPolicy = new IndexingPolicy();
165177
indexingPolicy.setIndexingMode(IndexingMode.CONSISTENT);
166178
ExcludedPath excludedPath = new ExcludedPath("/*");
@@ -174,9 +186,11 @@ private static ChatBotAgent createChatBotAgent() throws FileNotFoundException {
174186
indexingPolicy.setVectorIndexes(Arrays.asList(cosmosVectorIndexSpec));
175187
collectionDefinition.setIndexingPolicy(indexingPolicy);
176188

177-
// Next, we will store these embeddings in an embedding store (also known as a "vector database").
178-
// This store will be used to search for relevant segments during each interaction with the LLM.
179-
// We are using the Azure Cosmos DB Mongo vCOre embedding store.
189+
// Next, we will store these embeddings in an embedding store (also known as a
190+
// "vector database").
191+
// This store will be used to search for relevant segments during each
192+
// interaction with the LLM.
193+
// We are using the Azure Cosmos DB NoSQL API embedding store.
180194
EmbeddingStore<TextSegment> embeddingStore = AzureCosmosDbNoSqlEmbeddingStore.builder()
181195
.cosmosClient(cosmosClient)
182196
.databaseName(COSMOSDB_DATABASE)
@@ -190,8 +204,10 @@ private static ChatBotAgent createChatBotAgent() throws FileNotFoundException {
190204
embeddingStore.addAll(embeddings, segments);
191205
System.out.println("Vector embeddings and the chunked documents added to the embedding store");
192206

193-
// The content retriever is responsible for retrieving relevant content based on a user query.
194-
// Currently, it is capable of retrieving text segments, but future enhancements will include support for
207+
// The content retriever is responsible for retrieving relevant content based on
208+
// a user query.
209+
// Currently, it is capable of retrieving text segments, but future enhancements
210+
// will include support for
195211
// additional modalities like images, audio, and more.
196212
ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
197213
.embeddingStore(embeddingStore)
@@ -201,7 +217,8 @@ private static ChatBotAgent createChatBotAgent() throws FileNotFoundException {
201217
.build();
202218
System.out.println("Embedding store is initialized as a retriever");
203219

204-
// Optionally, we can use a chat memory, enabling back-and-forth conversation with the LLM
220+
// Optionally, we can use a chat memory, enabling back-and-forth conversation
221+
// with the LLM
205222
// and allowing it to remember previous interactions.
206223
// Currently, LangChain4j offers two chat memory implementations:
207224
// MessageWindowChatMemory and TokenWindowChatMemory.
@@ -210,18 +227,22 @@ private static ChatBotAgent createChatBotAgent() throws FileNotFoundException {
210227

211228
// The final step is to build our AI Service,
212229
// configuring it to use the components we've created above.
213-
System.out.println("Creating an AI service with our chat model, embedding store as a retriever, and chat memory.");
214-
//model.generate("Given the context information and not prior knowledge, answer the question. If you can't answer the question, use the most relevant contextual information as the answer, and do not add more information: %s");
230+
System.out.println(
231+
"Creating an AI service with our chat model, embedding store as a retriever, and chat memory.");
232+
// model.generate("Given the context information and not prior knowledge, answer
233+
// the question. If you can't answer the question, use the most relevant
234+
// contextual information as the answer, and do not add more information: %s");
215235
return AiServices.builder(ChatBotAgent.class)
216236
.chatLanguageModel(model)
217237
.contentRetriever(contentRetriever)
218238
.chatMemory(chatMemory)
219239
.build();
220240
}
241+
221242
private static List<Document> loadDocuments() throws FileNotFoundException {
222-
//get current working folder
243+
// get current working folder
223244
String workingDirectory = System.getProperty("user.dir");
224-
String documentsPath = workingDirectory + "/src/main/java/azure/cosmos/nosql/demo/PDF_docs";
245+
String documentsPath = workingDirectory + "/src/main/java/azure/cosmos/nosql/demo/PDF_docs";
225246

226247
File folder = new File(documentsPath);
227248
List<Document> documentList = new ArrayList<>();
@@ -286,14 +307,19 @@ private static void printWrapped(String str, int lineWidth) {
286307

287308
/**
288309
* This is an "AI Service". It is a Java service with AI capabilities/features.
289-
* It can be integrated into your code like any other service, acting as a bean, and is even mockable.
290-
* The goal is to seamlessly integrate AI functionality into your (existing) codebase with minimal friction.
310+
* It can be integrated into your code like any other service, acting as a bean,
311+
* and is even mockable.
312+
* The goal is to seamlessly integrate AI functionality into your (existing)
313+
* codebase with minimal friction.
291314
* It's conceptually similar to Spring Data JPA or Retrofit.
292315
* You define an interface and optionally customize it with annotations.
293-
* LangChain4j then provides an implementation for this interface using proxy and reflection.
316+
* LangChain4j then provides an implementation for this interface using proxy
317+
* and reflection.
294318
* This approach abstracts away all the complexity and boilerplate.
295-
* So you won't need to juggle the model, messages, memory, RAG components, tools, output parsers, etc.
296-
* However, don't worry. It's quite flexible and configurable, so you'll be able to tailor it
319+
* So you won't need to juggle the model, messages, memory, RAG components,
320+
* tools, output parsers, etc.
321+
* However, don't worry. It's quite flexible and configurable, so you'll be able
322+
* to tailor it
297323
* to your specific use case.
298324
*/
299325
interface ChatBotAgent {

0 commit comments

Comments
 (0)