LLM Apps in Production (RAG + Vector DB + Caching) · 课时

集成向量数据库

学习将 RAG 应用连接到 Pinecone、Weaviate 或 Chroma 等向量数据库,并执行索引和查询。

第 3 / 4 课12 个步骤

集成向量数据库 是 CoddyKit 上的免费 LLM Apps in Production (RAG + Vector DB + Caching) 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 LLM Apps in Production (RAG + Vector DB + Caching) 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 LLM Apps in Production (RAG + Vector DB + Caching) 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Connect RAG & Vector DBs

Welcome to the final lesson in our 'Deep Dive into Vector Databases' course! You've learned why vector databases are essential for RAG systems and what vector embeddings are.

Now, let's bring it all together. This lesson focuses on the practical steps of integrating a vector database into your RAG application.

We'll cover:

  • Connecting to a vector database client.
  • Preparing your data for storage.
  • Indexing (adding) your data.
  • Querying (searching) for relevant information.

Vector DBs in RAG: A Quick Recap

Before we dive into integration, let's quickly recall the role of vector databases in RAG.

They are specialized databases designed to store and efficiently search vector embeddings. These embeddings are numerical representations of text, images, or other data, capturing their semantic meaning.

When a user asks a question, we convert it into an embedding, search the vector database for similar document embeddings, and retrieve the most relevant chunks of information. This context is then fed to the LLM.

Choosing a Client Library

To interact with a vector database, you'll use its official client library. These libraries provide methods to connect, add data, query, and manage your index.

Popular choices include:

  • Pinecone Client: For Pinecone's cloud-native vector database.
  • ChromaDB Client: For Chroma, an open-source vector database often used locally or self-hosted.
  • Weaviate Client: For Weaviate, another popular open-source, cloud-native vector database.

Each client has a similar pattern for connecting and performing operations.

Setting Up a Connection

The first step is always to establish a connection to your vector database. This usually involves initializing a client object with your API key, environment details, or host address.

For demonstration, we'll use a simplified SimpleVectorDB class that mimics real vector database operations. Try running this example to see how a client might be initialized.

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

class SimpleVectorDB {
    private String apiKey;
    private String environment;

    public SimpleVectorDB(String apiKey, String environment) {
        this.apiKey = apiKey;
        this.environment = environment;
        System.out.println("SimpleVectorDB client initialized!");
        System.out.println("API Key (masked): ****" + apiKey.substring(apiKey.length() - 4));
        System.out.println("Environment: " + environment);
    }

    // Placeholder for other methods like upsert, query
}

public class Main {
    public static void main(String[] args) {
        String myApiKey = "sk_your_actual_api_key";
        String myEnvironment = "gcp-starter";

        // Initialize the vector database client
        SimpleVectorDB dbClient = new SimpleVectorDB(myApiKey, myEnvironment);
    }
}

Understanding Data Structure

When you add data to a vector database, it typically expects three main components for each item:

  • ID: A unique identifier for your document chunk (e.g., "doc123-chunk4").
  • Vector: The numerical embedding (a list of floating-point numbers) of your text chunk.
  • Metadata: Optional, but highly useful, key-value pairs (e.g., source document, page number, author) that provide additional context and allow for filtering during queries.

This structure helps the database manage and retrieve your information efficiently.

Preparing Data for Indexing

Before you can index data, you need to prepare it. This involves:

  1. Loading Data: Getting your raw text from various sources (PDFs, web pages, databases).
  2. Chunking: Breaking down long documents into smaller, semantically meaningful chunks.
  3. Embedding: Converting each text chunk into its corresponding vector embedding using an embedding model.

For this lesson, we'll assume you already have your text chunks and their embeddings ready to be indexed. The focus here is on the interaction with the vector database itself.

Indexing Documents (Upsert)

The process of adding or updating vectors and their associated metadata in a vector database is often called upserting. It's like inserting if the ID is new, or updating if the ID already exists.

Let's extend our SimpleVectorDB to include an upsert method and add some sample data. Notice how each item has an ID, a vector, and metadata.

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

class SimpleVectorDB {
    private String apiKey;
    private String environment;
    // In-memory store for demonstration
    private Map<String, Map<String, Object>> index = new HashMap<>();

    public SimpleVectorDB(String apiKey, String environment) {
        this.apiKey = apiKey;
        this.environment = environment;
        System.out.println("SimpleVectorDB client initialized!");
    }

    public void upsert(List<Map<String, Object>> vectorsToUpsert) {
        System.out.println("Upserting " + vectorsToUpsert.size() + " vectors...");
        for (Map<String, Object> item : vectorsToUpsert) {
            String id = (String) item.get("id");
            index.put(id, item);
            System.out.println("  Upserted ID: " + id + ", Metadata: " + item.get("metadata"));
        }
        System.out.println("Upsert complete. Total indexed items: " + index.size());
    }
}

public class Main {
    public static void main(String[] args) {
        String myApiKey = "sk_your_actual_api_key";
        String myEnvironment = "gcp-starter";
        SimpleVectorDB dbClient = new SimpleVectorDB(myApiKey, myEnvironment);

        // Sample data for indexing
        List<Map<String, Object>> data = new ArrayList<>();
        data.add(new HashMap<String, Object>() {{
            put("id", "doc1-chunk1");
            put("vector", Arrays.asList(0.1f, 0.2f, 0.3f, 0.4f));
            put("metadata", new HashMap<String, String>() {{ put("source", "report.pdf"); put("page", "1"); }});
        }});
        data.add(new HashMap<String, Object>() {{
            put("id", "doc1-chunk2");
            put("vector", Arrays.asList(0.5f, 0.6f, 0.7f, 0.8f));
            put("metadata", new HashMap<String, String>() {{ put("source", "report.pdf"); put("page", "2"); }});
        }});

        dbClient.upsert(data);
    }
}

Performing a Similarity Search

Once your data is indexed, you can perform queries. A query typically involves:

  1. Converting the user's question into a query embedding.
  2. Sending this query embedding to the vector database.
  3. The database finds the 'k' most similar vectors (document chunks) based on their embeddings.
  4. It returns these document chunks along with their associated metadata.

This is the core of how RAG retrieves relevant context!

Querying Code Example

Let's add a query method to our SimpleVectorDB and simulate a search. For simplicity, our mock query will just return the most 'similar' item based on a very basic matching logic (in a real DB, this is a complex similarity algorithm).

Imagine a user asks a question, and its embedding is our queryVector.

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

class SimpleVectorDB {
    private String apiKey;
    private String environment;
    private Map<String, Map<String, Object>> index = new HashMap<>();

    public SimpleVectorDB(String apiKey, String environment) {
        this.apiKey = apiKey;
        this.environment = environment;
    }

    public void upsert(List<Map<String, Object>> vectorsToUpsert) {
        for (Map<String, Object> item : vectorsToUpsert) {
            index.put((String) item.get("id"), item);
        }
        System.out.println("Upsert complete. Total indexed items: " + index.size());
    }

    // Simple similarity (Euclidean distance for demo)
    private double calculateSimilarity(List<Float> vec1, List<Float> vec2) {
        double sumSqDiff = 0;
        for (int i = 0; i < vec1.size(); i++) {
            sumSqDiff += Math.pow(vec1.get(i) - vec2.get(i), 2);
        }
        return -Math.sqrt(sumSqDiff); // Smaller distance = higher similarity
    }

    public List<Map<String, Object>> query(List<Float> queryVector, int topK) {
        System.out.println("Querying for top " + topK + " similar vectors...");
        List<Map<String, Object>> results = new ArrayList<>();
        List<Map.Entry<String, Map<String, Object>>> sortedEntries = new ArrayList<>(index.entrySet());

        sortedEntries.sort(new Comparator<Map.Entry<String, Map<String, Object>>>() {
            @Override
            public int compare(Map.Entry<String, Map<String, Object>> e1, Map.Entry<String, Map<String, Object>> e2) {
                List<Float> vec1 = (List<Float>) e1.getValue().get("vector");
                List<Float> vec2 = (List<Float>) e2.getValue().get("vector");
                return Double.compare(calculateSimilarity(queryVector, vec2), calculateSimilarity(queryVector, vec1));
            }
        });

        for (int i = 0; i < Math.min(topK, sortedEntries.size()); i++) {
            results.add(sortedEntries.get(i).getValue());
        }
        return results;
    }
}

public class Main {
    public static void main(String[] args) {
        String myApiKey = "sk_your_actual_api_key";
        String myEnvironment = "gcp-starter";
        SimpleVectorDB dbClient = new SimpleVectorDB(myApiKey, myEnvironment);

        List<Map<String, Object>> data = new ArrayList<>();
        data.add(new HashMap<String, Object>() {{
            put("id", "doc1-chunk1");
            put("vector", Arrays.asList(0.1f, 0.2f, 0.3f, 0.4f));
            put("metadata", new HashMap<String, String>() {{ put("source", "report.pdf"); put("page", "1"); }});
        }});
        data.add(new HashMap<String, Object>() {{
            put("id", "doc1-chunk2");
            put("vector", Arrays.asList(0.5f, 0.6f, 0.7f, 0.8f));
            put("metadata", new HashMap<String, String>() {{ put("source", "report.pdf"); put("page", "2"); }});
        }});
        data.add(new HashMap<String, Object>() {{
            put("id", "doc2-chunk1");
            put("vector", Arrays.asList(0.15f, 0.25f, 0.35f, 0.45f)); // Similar to chunk1
            put("metadata", new HashMap<String, String>() {{ put("source", "article.txt"); put("topic", "AI"); }});
        }});

        dbClient.upsert(data);

        // Simulate a query vector (from a user's question)
        List<Float> queryVector = Arrays.asList(0.12f, 0.22f, 0.32f, 0.42f);
        List<Map<String, Object>> queryResults = dbClient.query(queryVector, 2);

        System.out.println("\nQuery Results:");
        for (Map<String, Object> result : queryResults) {
            System.out.println("  ID: " + result.get("id") + ", Metadata: " + result.get("metadata"));
        }
    }
}

Handling Query Results

The results from a vector database query are typically a list of document chunks, ranked by similarity to the query. Each result usually includes:

  • The original ID of the chunk.
  • The text content (if stored in metadata or retrieved separately using the ID).
  • The metadata associated with that chunk.
  • A similarity score or distance metric.

Your RAG application then takes these top-k retrieved chunks, formats them, and passes them as context to the Large Language Model to generate an informed response.

Quick Check: Vector DB Integration

You've learned the key steps to integrate a vector database. Which of the following is the correct order of operations when adding new text data to a RAG system's vector database?

Recap: Integrating Vector DBs

Great job! In this lesson, we demystified the process of integrating a vector database into your RAG application. You learned:

  • How to initialize a vector database client.
  • The essential data structure (ID, vector, metadata) required for indexing.
  • The steps to prepare and upsert your document chunks and their embeddings.
  • How to perform a similarity search (query) to retrieve relevant context.

With this knowledge, you're ready to connect your RAG application to powerful vector databases like Pinecone, Chroma, or Weaviate!

免费开始

用 AI 导师学习 LLM Apps in Production (RAG + Vector DB + Caching) — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
12
课程
48

常见问题解答

「集成向量数据库」课时是免费的吗?

是的 — 「集成向量数据库」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 LLM Apps in Production (RAG + Vector DB + Caching) 课程的其余内容,请升级到 CoddyKit PRO。 LLM Apps in Production (RAG + Vector DB + Caching) 课程共包含 4 节课。

「集成向量数据库」这节课中我会学到什么?

学习将 RAG 应用连接到 Pinecone、Weaviate 或 Chroma 等向量数据库,并执行索引和查询。 你通过在浏览器中直接运行的动手代码来练习 LLM Apps in Production (RAG + Vector DB + Caching),全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 LLM Apps in Production (RAG + Vector DB + Caching) 需要有经验吗?

无需任何先前经验。CoddyKit 上的 LLM Apps in Production (RAG + Vector DB + Caching) 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「集成向量数据库」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 LLM Apps in Production (RAG + Vector DB + Caching) 课中编写并运行代码吗?

能。每节 LLM Apps in Production (RAG + Vector DB + Caching) 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 向量数据库的必要性
  2. 向量嵌入与相似度搜索
  3. 集成向量数据库
  4. 索引、过滤与混合搜索
← 返回 LLM Apps in Production (RAG + Vector DB + Caching)