#language-model #nlp #ai #llm #llama #mistral

kalosm-language

一组预训练语言模型

8 个版本

0.3.2 2024 年 8 月 14 日
0.3.0 2024 年 8 月 13 日
0.2.3 2024 年 6 月 30 日
0.2.2 2024 年 2 月 28 日
0.1.1 2023 年 12 月 21 日

#297机器学习 分类中

Download history 4/week @ 2024-04-26 1/week @ 2024-05-17 3/week @ 2024-05-31 3/week @ 2024-06-07 6/week @ 2024-06-14 8/week @ 2024-06-21 230/week @ 2024-06-28 19/week @ 2024-07-05 7/week @ 2024-07-12 3/week @ 2024-07-19 6/week @ 2024-07-26 2/week @ 2024-08-02 162/week @ 2024-08-09

每月 175 次下载
kalosm 中使用

MIT/Apache 许可协议

670KB
15K SLoC

Kalosm 语言

Kalosm 框架的语言处理工具。

Kalosm 的语言部分包含几个核心部分

  • 模型:文本生成和嵌入模型
  • 上下文:文档集合、格式支持、搜索和分块
  • 集成:SurrealDB、Serper 和其他集成

文本生成模型

ModelModelExt 是文本生成模型的核心理念。任何实现了这些理念的模型都可以与 Kalosm 一起使用。

使用模型的最简单方法是创建一个 llama 模型 并在它上面调用 stream_text

use kalosm::language::*;
#[tokio::main]
async fn main() {
    let mut llm = Llama::new().await.unwrap();
    let prompt = "The following is a 300 word essay about why the capital of France is Paris:";
    print!("{prompt}");
    let mut stream = llm
        // Any model that implements the Model trait can be used to stream text
        .stream_text(prompt)
        // You can pass parameters to the model to control the output
        .with_max_length(300)
        // And run .await to start streaming
        .await
        .unwrap();
    // You can then use the stream however you need. to_std_out will print the text to the console as it is generated
    stream.to_std_out().await.unwrap();
}

任务

您可以定义一个带有描述的任务,然后使用输入运行它。任务将缓存描述以加快重复调用。任务与聊天和非聊天模型都兼容,但它们通常与聊天模型表现更好。

use kalosm::language::*;
#[tokio::main]
async fn main() {
    // Create a new model
    let model = Llama::new_chat().await.unwrap();
    // Create a new task that summarizes text
    let task = Task::new("You take a long description and summarize it into a single short sentence");
    let mut output = task.run("You can define a Task with a description then run it with an input. The task will cache the description to repeated calls faster. Tasks work with both chat and non-chat models, but they tend to perform significantly better with chat models.", &model);
    // Then stream the output to the console
    output.to_std_out().await.unwrap();
}

结构化生成

结构化生成允许您更好地控制文本生成的输出。您可以为您的数据推导出一个解析器,以便轻松地从 LLM 获取结构化数据

use kalosm::language::*;
#[derive(Parse, Clone)]
struct Pet {
    name: String,
    age: u32,
    description: String,
}

然后您可以在 Task 中使用解析器生成文本

use kalosm::language::*;
#[derive(Parse, Debug, Clone)]
struct Pet {
    name: String,
    age: u32,
    description: String,
}

#[tokio::main]
async fn main() {
    // First create a model. Chat models tend to work best with structured generation
    let model = Llama::new_chat().await.unwrap();
    // Then create a parser for your data. Any type that implements the `Parse` trait has the `new_parser` method
    let parser = Pet::new_parser();
    // Then create a task with the parser as constraints
    let task = Task::builder("You generate realistic JSON placeholders")
        .with_constraints(parser)
        .build();
    // Finally, run the task
    let pet: Pet = task.run("Generate a pet in the form {\"name\": \"Pet name\", \"age\": 0, \"description\": \"Pet description\"}", &model).await.unwrap();
    println!("{pet:?}");
}

嵌入模型

EmbedderEmbedderExt 是文本嵌入模型的核心理念。任何实现了这些理念的模型都可以与 Kalosm 一起使用。

使用嵌入模型的最简单方法是创建一个 BERT 模型 并对其调用 embed。返回的 Embedding 以数值形式表示文本的含义。

use kalosm::language::*;
#[tokio::main]
async fn main() {
    // First create a model. Bert::new() is a good default embedding model for general tasks
    let model = Bert::new().await.unwrap();
    // Then embed some text into the vector space
    let embedding = model.embed("Kalosm is a library for building AI applications").await.unwrap();
    // And some more text
    let embedding = model.embed(prompt_input("Text: ").unwrap()).await.unwrap();
    // You can compare the cosine similarity of the two embeddings to see how similar they are
    println!("cosine similarity: {}", embedding.cosine_similarity(&embedding));
}

上下文

收集上下文是构建大型语言模型 (LLM) 应用程序的关键部分。向模型提供正确的上下文可以使输出更加相关和有用。它还可以帮助防止幻觉。

Kalosm 提供了从各种来源生成、收集和处理上下文的工具。

收集上下文

Kalosm 提供了从各种来源收集上下文的实用工具

  • 本地文件 (.txt, .md, .html, .docx, .pdf)
  • RSS 流
  • 网站
  • 搜索引擎
  • 通过 Whisper 转写 的麦克风输入和音频输入

这些来源中的每一个都实现了 IntoDocumentIntoDocuments,以将数据转换为包含文档内容和元数据的 Document

use kalosm::language::*;
use std::convert::TryFrom;
use std::path::PathBuf;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Try to extract an article from a URL
    let page = Url::parse("https://www.nytimes.com/live/2023/09/21/world/zelensky-russia-ukraine-news")?;
    let document = page.into_document().await?;
    println!("Title: {}", document.title());
    println!("Body: {}", document.body());

    Ok(())
}

上下文分块

收集上下文后,通常将其分成更小的部分以进行搜索很有用。Kalosm 提供了将上下文分块为文档、句子、段落或语义块的工具。Kalosm 在分割文档为更小部分时会嵌入每个块。最强大的分块器之一是语义分块器,它允许您将文档分块为语义上相似的块,而无需显式设置块的大小。

use kalosm::language::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // First, create an embedding model for semantic chunking
    let model = Bert::new().await?;
    // Then create a document folder with some documents
    let documents = DocumentFolder::new("./documents")?.into_documents().await?;
    // Then chunk the documents into sentences
    let chunked = SemanticChunker::new().chunk_batch(&documents, &model).await?;
    println!("{:?}", chunked);
    Ok(())
}

将上下文分块后,您可以使用嵌入进行搜索或检索增强生成。基于嵌入的搜索允许您找到与特定单词或短语语义上相似的文档,即使没有任何单词完全匹配。

use kalosm::language::*;
use surrealdb::{engine::local::RocksDb, Surreal};

#[tokio::main]
async fn main() {
    // Create database connection
    let db = Surreal::new::<RocksDb>(std::env::temp_dir().join("temp.db")).await.unwrap();

    // Select a specific namespace / database
    db.use_ns("search").use_db("documents").await.unwrap();

    // Create a table in the surreal database to store the embeddings
    let document_table = db
        .document_table_builder("documents")
        .build::<Document>()
        .await
        .unwrap();

    // Add documents to the database
    document_table.add_context(DocumentFolder::new("./documents").unwrap()).await.unwrap();

    loop {
        // Get the user's question
        let user_question = prompt_input("Query: ").unwrap();

        let nearest_5 = document_table
            .select_nearest(user_question, 5)
            .await
            .unwrap();

        println!("{:?}", nearest_5);
    }
}

依赖关系

~50–73MB
~1.5M SLoC