-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathget-started.js
More file actions
145 lines (127 loc) · 4.78 KB
/
Copy pathget-started.js
File metadata and controls
145 lines (127 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import "dotenv/config";
import { AzureCosmosDBNoSQLVectorStore, AzureCosmosDBNoSQLSearchType } from "@langchain/azure-cosmosdb";
import { AzureChatOpenAI, AzureOpenAIEmbeddings } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
import { RunnableSequence } from "@langchain/core/runnables";
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
import { Document } from "@langchain/core/documents";
import { readFileSync } from "node:fs";
// Azure OpenAI configuration from environment variables
const azureOpenAIConfig = {
azureOpenAIApiKey: process.env.AZURE_OPENAI_API_KEY,
azureOpenAIBasePath: process.env.AZURE_OPENAI_ENDPOINT,
azureOpenAIApiVersion: process.env.AZURE_OPENAI_API_VERSION,
};
// Cosmos DB connection string is read automatically by the SDK from env
process.env.AZURE_COSMOSDB_NOSQL_CONNECTION_STRING ??=
process.env.AZURE_COSMOSDB_NOSQL_CONNECTION_STRING;
async function run() {
// Validate required environment variables
const required = [
"AZURE_OPENAI_API_KEY",
"AZURE_OPENAI_ENDPOINT",
"AZURE_COSMOSDB_NOSQL_CONNECTION_STRING",
];
const missing = required.filter((key) => !process.env[key]);
if (missing.length > 0) {
console.error(`Missing required environment variables: ${missing.join(", ")}`);
console.error("Copy .env.example to .env and fill in your values.");
process.exit(1);
}
const databaseName = process.env.AZURE_COSMOSDB_DATABASE_NAME || "langchain";
const containerName = process.env.AZURE_COSMOSDB_CONTAINER_NAME || "documents";
// Load and split documents
const text = readFileSync("./sample-data.txt", "utf-8");
const rawDocuments = [new Document({ pageContent: text })];
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 1000,
chunkOverlap: 100,
});
const documents = await splitter.splitDocuments(rawDocuments);
console.log(`Split into ${documents.length} document chunks.`);
// Create the Azure Cosmos DB vector store
const store = await AzureCosmosDBNoSQLVectorStore.fromDocuments(
documents,
new AzureOpenAIEmbeddings({
...azureOpenAIConfig,
azureOpenAIApiDeploymentName:
process.env.AZURE_OPENAI_EMBEDDING_DEPLOYMENT || "text-embedding-3-small",
}),
{ databaseName, containerName }
);
console.log("Documents stored in Azure Cosmos DB.");
// 1. Semantic similarity search
const searchResults = await store.similaritySearch(
"What are the key features?",
4
);
console.log("\n--- Semantic Search Results ---");
for (const doc of searchResults) {
console.log(`- ${doc.pageContent.substring(0, 100)}...`);
}
// 2. Vector search with score threshold
const scoredResults = await store.similaritySearchWithScore(
"What are the key features?",
10,
{
searchType: AzureCosmosDBNoSQLSearchType.VectorScoreThreshold,
threshold: 0.8,
}
);
console.log("\n--- Results with Scores ---");
for (const [doc, score] of scoredResults) {
console.log(` Score: ${score.toFixed(4)}, Content: ${doc.pageContent.substring(0, 80)}...`);
}
// 3. MMR search for diverse results
const mmrResults = await store.maxMarginalRelevanceSearch(
"What are the key features?",
{ k: 5, fetchK: 20, lambda: 0.5 }
);
console.log("\n--- MMR Search Results ---");
for (const doc of mmrResults) {
console.log(`- ${doc.pageContent.substring(0, 100)}...`);
}
// 4. RAG: Answer questions using retrieved documents
const model = new AzureChatOpenAI({
...azureOpenAIConfig,
azureOpenAIApiDeploymentName:
process.env.AZURE_OPENAI_CHAT_DEPLOYMENT || "gpt-4.1",
temperature: 0,
});
const retriever = store.asRetriever();
const formatDocs = (docs) => docs.map((d) => d.pageContent).join("\n\n");
const prompt = ChatPromptTemplate.fromMessages([
[
"system",
"Answer the user's questions based on the below context:\n\n{context}",
],
["human", "{question}"],
]);
const chain = RunnableSequence.from([
{
context: async (input) => {
const docs = await retriever.invoke(input.question);
return formatDocs(docs);
},
question: (input) => input.question,
},
prompt,
model,
new StringOutputParser(),
]);
const question = "What are the main benefits described in the document?";
const answer = await chain.invoke({ question });
console.log(`\n--- RAG Response ---`);
console.log(`Question: ${question}`);
console.log(`Answer: ${answer}`);
const sourceDocs = await retriever.invoke(question);
console.log("\nSource documents:");
for (const doc of sourceDocs) {
console.log(`- ${doc.pageContent.substring(0, 100)}...`);
}
}
run().catch((error) => {
console.error("Error:", error.message);
process.exit(1);
});