Kotlinv2.4.0

嵌入

embeddings 模块提供了生成和比较文本及代码嵌入的功能。嵌入是捕捉语义含义的向量表示,允许进行高效的相似性比较。

概览

该模块由两个主要组件组成:

  1. embeddings-base:嵌入的核心接口和数据结构。
  2. embeddings-llm:使用 Ollama 进行本地嵌入生成的实现。

入门指南

以下章节包含了如何通过以下方式使用嵌入的基本示例:

  • 通过 Ollama 使用本地嵌入模型
  • 使用 OpenAI 嵌入模型

本地嵌入

要将嵌入功能与本地模型配合使用,您需要在系统上安装并运行 Ollama。 有关安装和运行说明,请参阅 Ollama 官方 GitHub 仓库

kotlin
fun main() {
    runBlocking {
        // 创建 OllamaClient 实例
        val client = OllamaClient()
        // 创建 embedder
        val embedder = LLMEmbedder(client, OllamaModels.Embeddings.NOMIC_EMBED_TEXT)
        // 创建嵌入
        val embedding = embedder.embed("This is the text to embed")
        // 将嵌入打印到输出
        println(embedding)
    }
}

要使用 Ollama 嵌入模型,请确保具备以下前提条件:

  • 已安装并运行 Ollama

  • 使用以下命令将嵌入模型下载到本地计算机:

    bash
    ollama pull <ollama-model-id>

    <ollama-model-id> 替换为特定模型的 Ollama 标识符。有关可用嵌入模型及其标识符的更多信息,请参阅 Ollama 模型概览

Ollama 模型概览

下表提供了可用 Ollama 嵌入模型的概览。

模型 IDOllama ID参数维度上下文长度性能权衡
NOMIC_EMBED_TEXTnomic-embed-text137M7688192用于语义搜索和文本相似性任务的高质量嵌入在质量和效率之间取得了平衡
ALL_MINILMall-minilm33M384512推理速度快,且通用文本嵌入质量良好模型较小且上下文长度较短,但非常高效
MULTILINGUAL_E5zylonai/multilingual-e5-large300M768512在 100 多种语言中表现强劲模型较大,但提供了出色的多语言能力
BGE_LARGEbge-large335M1024512非常适合英语文本检索和语义搜索模型较大,但提供了高质量的嵌入
MXBAI_EMBED_LARGEmxbai-embed-large---文本数据的高维嵌入专为创建高维嵌入而设计

有关这些模型的更多信息,请参阅 Ollama 的 嵌入模型 博客文章。

选择模型

以下是一些根据您的需求选择 Ollama 嵌入模型的通用提示:

  • 对于通用文本嵌入,使用 NOMIC_EMBED_TEXT
  • 对于多语言支持,使用 MULTILINGUAL_E5
  • 为了获得最高质量(以性能为代价),使用 BGE_LARGE
  • 为了获得最高效率(以牺牲部分质量为代价),使用 ALL_MINILM
  • 对于高维嵌入,使用 MXBAI_EMBED_LARGE

OpenAI 嵌入

要使用 OpenAI 嵌入模型创建嵌入,请使用 OpenAILLMClient 实例的 embed 方法,如下面的示例所示。

kotlin
suspend fun openAIEmbed(text: String) {
    // 从 OPENAI_KEY 环境变量获取 OpenAI API 令牌
    val token = System.getenv("OPENAI_KEY") ?: error("Environment variable OPENAI_KEY is not set")
    // 创建 OpenAILLMClient 实例
    val client = OpenAILLMClient(token)
    // 创建 embedder
    val embedder = LLMEmbedder(client, OpenAIModels.Embeddings.TextEmbeddingAda002)
    // 创建嵌入
    val embedding = embedder.embed(text)
    // 将嵌入打印到输出
    println(embedding)
}

AWS Bedrock 嵌入

要使用 AWS Bedrock 嵌入模型创建嵌入,请使用 BedrockLLMClient 实例的 embed 方法及您选择的模型。示例:

kotlin
suspend fun bedrockEmbed(text: String) {
    // 从环境/配置中获取 AWS 凭据
    val awsAccessKeyId = System.getenv("AWS_ACCESS_KEY_ID") ?: error("AWS_ACCESS_KEY_ID not set")
    val awsSecretAccessKey = System.getenv("AWS_SECRET_ACCESS_KEY") ?: error("AWS_SECRET_ACCESS_KEY not set")
    // (可选)用于临时凭据的 AWS_SESSION_TOKEN
    val awsSessionToken = System.getenv("AWS_SESSION_TOKEN")
    // 创建 BedrockLLMClient 实例
    val client = BedrockLLMClient(
        identityProvider = StaticCredentialsProvider {
            this.accessKeyId = awsAccessKeyId
            this.secretAccessKey = awsSecretAccessKey
            awsSessionToken?.let { this.sessionToken = it }
        },
        settings = BedrockClientSettings()
    )
    // 创建 embedder
    val embedder = LLMEmbedder(client, BedrockModels.Embeddings.AmazonTitanEmbedText)
    // 创建嵌入
    val embedding = embedder.embed(text)
    // 将嵌入打印到输出
    println(embedding)
}

支持的 AWS Bedrock 嵌入模型

提供商模型名称模型 ID输入输出维度上下文长度备注
AmazonTitan Embeddings G1 - Textamazon.titan-embed-text-v1文本嵌入1,5368192支持 25 种以上语言,针对检索、语义相似性、聚类进行了优化;为搜索对长文档进行分段。
AmazonTitan Text Embeddings V2amazon.titan-embed-text-v2:0文本嵌入1,0248192高精度、灵活的维度、多语言(100 多种);较小的维度可节省存储空间,输出经过归一化。
CohereCohere Embed English v3cohere.embed-english-v3文本嵌入1,0248192用于搜索、检索和理解文本细微差别的 SOTA 英语文本嵌入。
CohereCohere Embed Multilingual v3cohere.embed-multilingual-v3文本嵌入1,0248192多语言嵌入,在跨语言搜索和语义理解方面处于 SOTA 水平。

有关最新的模型支持情况,请参阅 AWS Bedrock 支持的模型文档

示例

以下示例展示了如何使用嵌入来将代码与文本或其他代码片段进行比较。

代码与文本比较

将代码片段与自然语言描述进行比较以找到语义匹配:

kotlin
suspend fun compareCodeToText(embedder: Embedder) { // Embedder 类型
    // 代码片段
    val code = """
        fun factorial(n: Int): Int {
            return if (n <= 1) 1 else n * factorial(n - 1)
        }
    """.trimIndent()

    // 文本描述
    val description1 = "A recursive function that calculates the factorial of a number"
    val description2 = "A function that sorts an array of integers"

    // 生成嵌入
    val codeEmbedding = embedder.embed(code)
    val desc1Embedding = embedder.embed(description1)
    val desc2Embedding = embedder.embed(description2)

    // 计算差异(值越低表示越相似)
    val diff1 = embedder.diff(codeEmbedding, desc1Embedding)
    val diff2 = embedder.diff(codeEmbedding, desc2Embedding)

    println("Difference between code and description 1: $diff1")
    println("Difference between code and description 2: $diff2")

    // 该代码应与 description1 比 description2 更相似
    if (diff1 < diff2) {
        println("The code is more similar to: '$description1'")
    } else {
        println("The code is more similar to: '$description2'")
    }
}

代码与代码比较

比较代码片段以找到语义相似性,无论语法是否存在差异:

kotlin
suspend fun compareCodeToCode(embedder: Embedder) { // Embedder 类型
    // 同一个算法在不同语言下的两种实现
    val kotlinCode = """
        fun fibonacci(n: Int): Int {
            return if (n <= 1) n else fibonacci(n - 1) + fibonacci(n - 2)
        }
    """.trimIndent()

    val pythonCode = """
        def fibonacci(n):
            if n <= 1:
                return n
            else:
                return fibonacci(n-1) + fibonacci(n-2)
    """.trimIndent()

    val javaCode = """
        public static int bubbleSort(int[] arr) {
            int n = arr.length;
            for (int i = 0; i < n-1; i++) {
                for (int j = 0; j < n-i-1; j++) {
                    if (arr[j] > arr[j+1]) {
                        int temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
            return arr;
        }
    """.trimIndent()

    // 生成嵌入
    val kotlinEmbedding = embedder.embed(kotlinCode)
    val pythonEmbedding = embedder.embed(pythonCode)
    val javaEmbedding = embedder.embed(javaCode)

    // 计算差异
    val diffKotlinPython = embedder.diff(kotlinEmbedding, pythonEmbedding)
    val diffKotlinJava = embedder.diff(kotlinEmbedding, javaEmbedding)

    println("Difference between Kotlin and Python implementations: $diffKotlinPython")
    println("Difference between Kotlin and Java implementations: $diffKotlinJava")

    // Kotlin 和 Python 的实现应该更相似
    if (diffKotlinPython < diffKotlinJava) {
        println("The Kotlin code is more similar to the Python code")
    } else {
        println("The Kotlin code is more similar to the Java code")
    }
}

API 文档

有关嵌入相关的完整 API 参考,请参阅以下模块的参考文档:

  • embeddings-base:提供用于表示和比较文本及代码嵌入的核心接口和数据结构。
  • embeddings-llm:包含用于处理本地嵌入模型的实现。