Integrate LlamaIndex.TS with Astra DB Serverless
LlamaIndex.TS can use Astra DB Serverless to store and retrieve vectors for ML applications.
Prerequisites
This guide requires the following:
-
An active Serverless (vector) database
-
Node.js 16.20.2 or later, and the required dependencies:
npm install llamaindex tsx
Connect to the database
-
In the Astra Portal, click the name of the database that you want to connect to.
-
Generate an application token with the Database Administrator role.
-
In your terminal, assign your token and API endpoint to environment variables:
- Linux or macOS
-
export API_ENDPOINT=API_ENDPOINT export APPLICATION_TOKEN=APPLICATION_TOKEN export OPENAI_API_KEY=API_KEY - Microsoft Windows
-
set API_ENDPOINT=API_ENDPOINTset APPLICATION_TOKEN=APPLICATION_TOKENset OPENAI_API_KEY=API_KEY
Load and split documents
-
Download the text of Edgar Allen Poe’s "The Cask of Amontillado" to be indexed in the vector store.
curl https://raw.githubusercontent.com/CassioML/cassio-website/main/docs/frameworks/langchain/texts/amontillado.txt \ --output amontillado.txt -
Create
load.tsin asrcdirectory. -
Import dependencies:
import fs from "node:fs/promises"; import { AstraDBVectorStore, Document, VectorStoreIndex, storageContextFromDefaults, } from "llamaindex"; -
Create a
mainfunction.This function loads your
.txtfile into aDocumentobject, creates a vector store, and stores the embeddings in aVectorStoreIndex. Wrapping the function inasyncallows the use ofawaitto execute non-blocking calls to the database.import fs from "node:fs/promises"; import { AstraDBVectorStore, Document, VectorStoreIndex, storageContextFromDefaults } from "llamaindex"; const collectionName = "amontillado"; async function main() { try { // Load the text file const path = "./src/sample-data/amontillado.txt"; const essay = await fs.readFile(path, "utf-8"); // Create a Document object from the text file const document = new Document({ text: essay, id_: path }); // Initialize AstraDB Vector Store and connect const astraVS = new AstraDBVectorStore({ params: { token: process.env.APPLICATION_TOKEN, endpoint: process.env.API_ENDPOINT } }); await astraVS.create(collectionName, { vector: { dimension: 1536, metric: "cosine" } }); await astraVS.connect(collectionName); // Create embeddings and store them in VectorStoreIndex const ctx = await storageContextFromDefaults({ vectorStore: astraVS }); const index = await VectorStoreIndex.fromDocuments([document], { storageContext: ctx }); } catch (e) { console.error(e); } } main(); -
Compile and run the code:
npx tsx src/load.ts
Chat with your documents
-
Create
chat.tsin asrcdirectory. -
Import dependencies:
import { AstraDBVectorStore, serviceContextFromDefaults, VectorStoreIndex, ContextChatEngine } from "llamaindex"; -
Create a
mainfunction.This code is separate from
load.tsso that you can tune your query and prompt independently.The majority of this function sets up the chat interaction loop. The code specific to your LlamaIndex.TS integration is:
-
A new
AstraDBVectorStoreinstance called 'astraVS' is created and connects to theamontilladocollection you populated earlier. -
const indexcreates an index over your vector store with the default storage context. For more information, see LlamaIndex Service Context. -
The retriever returns the top 20 results from the index of the vector store.
-
The chat engine uses the retriever to respond to user input.
// ... import { AstraDBVectorStore, serviceContextFromDefaults, VectorStoreIndex, ContextChatEngine } from "llamaindex"; const collectionName = "amontillado"; // Function to check if the input is a quit command function isQuit(question) { return ["q", "quit", "exit"].includes(question.trim().toLowerCase()); } // Function to get user input as a promise function getUserInput(readline) { return new Promise(resolve => { readline.question("What would you like to know?\n> ", userInput => { resolve(userInput); }); }); } async function main() { const readline = require("readline").createInterface({ input: process.stdin, output: process.stdout }); try { // Connect to AstraDB Vector Store const astraVS = new AstraDBVectorStore({ params: { token: process.env.APPLICATION_TOKEN, endpoint: process.env.API_ENDPOINT } }); await astraVS.connect(collectionName); // Setup vector store and chat engine const ctx = serviceContextFromDefaults(); const index = await VectorStoreIndex.fromVectorStore(astraVS, ctx); const retriever = await index.asRetriever({ similarityTopK: 20 }); const chatEngine = new ContextChatEngine({ retriever }); // Query engine for chat interactions const queryEngine = await index.asQueryEngine(); // Chat loop let question = ""; while (!isQuit(question)) { question = await getUserInput(readline); if (isQuit(question)) { readline.close(); process.exit(0); } try { const answer = await queryEngine.query({ query: question }); console.log(answer.response); } catch (error) { console.error("Error:", error); } } } catch (err) { console.error(err); console.log("If your AstraDB initialization failed, make sure to set env vars for your APPLICATION_TOKEN, API_ENDPOINT, and OPENAI_API_KEY as needed."); process.exit(1); } } main().catch(console.error).finally(() => { process.exit(1); }); -
-
Compile and run the code:
npx tsx src/chat.tsIf you get a
TOO_MANY_COLLECTIONSerror, you must delete a collection from your database to allow the script to create a new collection. Or, use a different database that has fewer collections.
Complete code examples
- load.ts
-
import fs from "node:fs/promises"; import { AstraDBVectorStore, Document, VectorStoreIndex, storageContextFromDefaults } from "llamaindex"; const collectionName = "amontillado"; async function main() { try { // Load the text file const path = "./src/sample-data/amontillado.txt"; const essay = await fs.readFile(path, "utf-8"); // Create a Document object from the text file const document = new Document({ text: essay, id_: path }); // Initialize AstraDB Vector Store and connect const astraVS = new AstraDBVectorStore({ params: { token: process.env.APPLICATION_TOKEN, endpoint: process.env.API_ENDPOINT } }); await astraVS.create(collectionName, { vector: { dimension: 1536, metric: "cosine" } }); await astraVS.connect(collectionName); // Create embeddings and store them in VectorStoreIndex const ctx = await storageContextFromDefaults({ vectorStore: astraVS }); const index = await VectorStoreIndex.fromDocuments([document], { storageContext: ctx }); } catch (e) { console.error(e); } } main(); - chat.ts
-
import { AstraDBVectorStore, serviceContextFromDefaults, VectorStoreIndex, ContextChatEngine } from "llamaindex"; const collectionName = "amontillado"; // Function to check if the input is a quit command function isQuit(question) { return ["q", "quit", "exit"].includes(question.trim().toLowerCase()); } // Function to get user input as a promise function getUserInput(readline) { return new Promise(resolve => { readline.question("What would you like to know?\n> ", userInput => { resolve(userInput); }); }); } async function main() { const readline = require("readline").createInterface({ input: process.stdin, output: process.stdout }); try { // Connect to AstraDB Vector Store const astraVS = new AstraDBVectorStore({ params: { token: process.env.APPLICATION_TOKEN, endpoint: process.env.API_ENDPOINT } }); await astraVS.connect(collectionName); // Setup vector store and chat engine const ctx = serviceContextFromDefaults(); const index = await VectorStoreIndex.fromVectorStore(astraVS, ctx); const retriever = await index.asRetriever({ similarityTopK: 20 }); const chatEngine = new ContextChatEngine({ retriever }); // Query engine for chat interactions const queryEngine = await index.asQueryEngine(); // Chat loop let question = ""; while (!isQuit(question)) { question = await getUserInput(readline); if (isQuit(question)) { readline.close(); process.exit(0); } try { const answer = await queryEngine.query({ query: question }); console.log(answer.response); } catch (error) { console.error("Error:", error); } } } catch (err) { console.error(err); console.log("If your AstraDB initialization failed, make sure to set env vars for your APPLICATION_TOKEN, API_ENDPOINT, and OPENAI_API_KEY as needed."); process.exit(1); } } main().catch(console.error).finally(() => { process.exit(1); });