我們如何利用 distilabel 建立 Argilla 2.0 聊天機器人

釋出於 2024 年 7 月 16 日
在 GitHub 上更新

太長不看 (TL;DR)

瞭解如何為您選擇的工具(本例中為 Argilla 2.0)構建一個聊天機器人,使其能夠理解技術文件並與使用者就此進行交流。

在本文中,我們將向您展示如何利用 distilabel 並微調一個領域特定的嵌入模型,以建立一個既準確又具吸引力的對話模型。

本文概述了為 Argilla 2.0 建立聊天機器人的過程。我們將:

  • 從技術文件中建立一個合成數據集,用於微調特定領域的嵌入模型,
  • 建立一個向量資料庫來儲存和檢索文件,以及
  • 將最終的聊天機器人部署到 Hugging Face Space,允許使用者與其互動,並將互動資料儲存在 Argilla 中以進行持續評估和改進。

點選此處跳轉至應用程式。

argilla-sdk-chatbot

目錄

為微調自定義嵌入模型生成合成資料

需要快速回顧一下 RAG 嗎?可以透過這個方便的入門筆記本來複習基礎知識。我們會等你跟上進度!

下載和分塊資料

分塊資料意味著將您的文字資料分割成每個約 256 個 token 的可管理塊(後續 RAG 中使用的塊大小)。

讓我們進入第一步:處理目標倉庫的文件。為了簡化此任務,您可以利用像 llama-index 這樣的庫來讀取倉庫內容並解析 Markdown 檔案。具體來說,langchain 提供了有用的工具,如 MarkdownTextSplitter,而 llama-index 提供了 MarkdownNodeParser 來幫助您提取必要的資訊。如果您更喜歡一種更簡化的方法,可以考慮使用 davanstriencorpus-creator 應用。

為了使事情更簡單高效,我們開發了一個自定義的 Python 指令碼來為您完成繁重的工作。您可以在我們的倉庫中找到它,地址是 這裡

該指令碼自動化了從 GitHub 倉庫中檢索文件並將其作為資料集儲存在 Hugging Face Hub 上的過程。最棒的是,它使用起來非常簡單!讓我們看看如何執行它。

python docs_dataset.py \
    "argilla-io/argilla-python" \
    --dataset-name "plaguss/argilla_sdk_docs_raw_unstructured"

雖然該指令碼易於使用,但您可以透過使用額外的引數來進一步根據您的需求進行定製。然而,有兩個必要的輸入您需要提供:

  • 存放文件的 GitHub 倉庫路徑。

  • Hugging Face Hub 的資料集 ID,您的資料集將儲存在這裡。

一旦您提供了這些必需的引數,指令碼將負責其餘的工作。以下是幕後發生的事情:

  • 該指令碼會從指定的 GitHub 倉庫下載文件到您的本地目錄。預設情況下,它會在 /docs 目錄中查詢文件,但您可以透過指定不同的路徑來更改此設定。

  • 它從下載的文件中提取所有 Markdown 檔案。

  • 將提取的 Markdown 檔案分塊成可管理的小塊。

  • 最後,它將準備好的資料集推送到 Hugging Face Hub,使其準備就緒。

為了讓您更好地瞭解該指令碼的內部工作原理,這裡有一段程式碼片段總結了其核心邏輯:

# The function definitions are omitted for brevity, visit the script for more info!
from github import Github

gh = Github()
repo = gh.get_repo("repo_name")

# Download the folder
download_folder(repo, "/folder/with/docs", "dir/to/download/docs") 

# Extract the markdown files from the downloaded folder with the documentation from the GitHub repository
md_files = list(docs_path.glob("**/*.md"))

# Loop to iterate over the files and generate chunks from the text pieces
data = create_chunks(md_files)

# Create a dataset to push it to the hub
create_dataset(data, repo_name="name/of/the/dataset")

該指令碼包含用於下載文件、從 Markdown 檔案建立塊以及建立資料集的簡短函式。包含更多功能或實現更復雜的分塊策略應該會很簡單。

您可以檢視可用的引數

點選檢視 docs_dataset.py 幫助資訊
$ python docs_dataset.py -h
usage: docs_dataset.py [-h] [--dataset-name DATASET_NAME] [--docs_folder DOCS_FOLDER] [--output_dir OUTPUT_DIR] [--private | --no-private] repo [repo ...]

Download the docs from a github repository and generate a dataset from the markdown files. The dataset will be pushed to the hub.

positional arguments:
  repo                  Name of the repository in the hub. For example 'argilla-io/argilla-python'.

options:
  -h, --help            show this help message and exit
  --dataset-name DATASET_NAME
                        Name to give to the new dataset. For example 'my-name/argilla_sdk_docs_raw'.
  --docs_folder DOCS_FOLDER
                        Name of the docs folder in the repo, defaults to 'docs'.
  --output_dir OUTPUT_DIR
                        Path to save the downloaded files from the repo (optional)
  --private, --no-private
                        Whether to keep the repository private or not. Defaults to False.

使用 distilabel 為我們的嵌入模型生成合成資料

我們將從我們的文件中生成合成問題,這些問題可以由每個文件塊來回答。我們還將透過生成易於區分的不相關問題來生成困難負例。我們可以使用這些問題、困難負例和文件來構建用於微調資料集的三元組。

完整的管道指令碼可以在參考倉庫的 pipeline_docs_queries.py 中看到,但讓我們回顧一下不同的步驟

  1. load_data:

我們旅程的第一步是獲取包含有價值的文件塊的資料集。仔細觀察後,我們注意到包含這些塊的列被恰當地命名為 `chunks`。然而,為了讓我們的模型無縫執行,我們需要給這個列賦予一個新的身份。具體來說,我們想將它重新命名為 `anchor`,因為這是我們後續步驟所期望的輸入。我們將使用 `output_mappings` 來為我們完成這個列的轉換

load_data = LoadDataFromHub(
    name="load_data",
    repo_id="plaguss/argilla_sdk_docs_raw_unstructured",
    output_mappings={"chunks": "anchor"},
    batch_size=10,
)
  1. generate_sentence_pair

現在,我們來到了我們過程中最有趣的部分,將文件片段轉化為合成查詢。這就是 GenerateSentencePair 任務大顯身手的地方。這個強大的任務為生成高質量的句子對提供了廣泛的可能性。我們鼓勵您探索其文件以解鎖其全部潛力。

在我們的特定用例中,我們將利用 GenerateSentencePair 的能力來製作合成查詢,最終提升我們模型的效能。讓我們更深入地瞭解如何配置此任務以實現我們的目標。

llm = InferenceEndpointsLLM(
    model_id="meta-llama/Meta-Llama-3-70B-Instruct",
    tokenizer_id="meta-llama/Meta-Llama-3-70B-Instruct",
)

generate_sentence_pair = GenerateSentencePair(
    name="generate_sentence_pair",
    triplet=True,  # Generate positive and negative
    action="query",
    context="The generated sentence has to be related with Argilla, a data annotation tool for AI engineers and domain experts.",
    llm=llm,
    input_batch_size=10,
    output_mappings={"model_name": "model_name_query"},
)

讓我們來分解一下上面的程式碼片段。

透過設定 `triplet=True`,我們指示任務生成一系列三元組,包括一個錨點、一個正向句子和一個負向句子。正如 Sentence Transformers 庫的訓練概述中所解釋的,這種格式非常適合微調。

action="query" 引數是此任務的一個關鍵方面,因為它指導 LLM 為正向句子生成查詢。這就是魔法發生的地方,我們的文件塊被轉化為有意義的查詢。

為了進一步幫助模型,我們加入了 `context` 引數。當錨定句子缺乏足夠的上下文時(這在簡短的文件塊中經常出現),這會向 LLM 提供額外資訊。

最後,我們選擇利用 `meta-llama/Meta-Llama-3-70B-Instruct` 模型的力量,透過 InferenceEndpointsLLM 元件。這個選擇使我們能夠利用該模型的能力,生成高質量的合成查詢,最終提高我們模型的效能。

  1. multiply_queries

透過使用 `GenerateSentencePair` 步驟,我們獲得了與分塊數量相同的訓練樣本,本例中為 251 個。然而,我們認識到這可能不足以微調一個能夠準確捕捉我們特定用例細微差別的自定義模型。

為了克服這個限制,我們將使用另一個 LLM 來生成額外的查詢。這將允許我們增加訓練資料集的大小,為我們的模型提供更豐富的學習基礎。

這讓我們進入了流程的下一步:`MultipleQueries`,一個我們為了進一步擴充資料集而精心製作的自定義 `Task`。

multiply_queries = MultipleQueries(
    name="multiply_queries",
    num_queries=3,
    system_prompt=(
        "You are an AI assistant helping to generate diverse examples. Ensure the "
        "generated queries are all in separated lines and preceded by a dash. "
        "Do not generate anything else or introduce the task."
    ),
    llm=llm,
    input_batch_size=10,
    input_mappings={"query": "positive"},
    output_mappings={"model_name": "model_name_query_multiplied"},
)

現在,讓我們深入瞭解我們自定義 `Task` 的配置,該任務旨在擴充我們的訓練資料集。此任務的關鍵是 `num_queries` 引數,本例中設定為 3。這意味著我們將為每個示例生成三個額外的“正向”查詢,從而有效地將我們的資料集大小增加四倍(假設某些示例可能不會成功)。

為了確保大型語言模型 (LLM) 保持正軌,我們精心設計了一個 `system_prompt`,為我們的指令提供清晰的指導。考慮到所選模型的強大功能和我們示例的簡單性,我們不需要使用結構化生成技術。然而,在更復雜的場景中,這可能是一種有價值的方法。

對我們自定義 `Task` 的內部工作原理感到好奇嗎?點選下面的下拉選單探索完整的定義

MultipleQueries 定義
multiply_queries_template = (
    "Given the following query:\n{original}\nGenerate {num_queries} similar queries by varying "
    "the tone and the phrases slightly. "
    "Ensure the generated queries are coherent with the original reference and relevant to the context of data annotation "
    "and AI dataset development."
)

class MultipleQueries(Task):
    system_prompt: Optional[str] = None
    num_queries: int = 1

    @property
    def inputs(self) -> List[str]:
        return ["query"]

    def format_input(self, input: Dict[str, Any]) -> ChatType:
        prompt = [
            {
                "role": "user",
                "content": multiply_queries_template.format(
                    original=input["query"],
                    num_queries=self.num_queries
                ),
            },
        ]
        if self.system_prompt:
            prompt.insert(0, {"role": "system", "content": self.system_prompt})
        return prompt

    @property
    def outputs(self) -> List[str]:
        return ["queries", "model_name"]

    def format_output(
        self, output: Union[str, None], input: Dict[str, Any]
    ) -> Dict[str, Any]:
        queries = output.split("- ")
        if len(queries) > self.num_queries:
            queries = queries[1:]
        queries = [q.strip() for q in queries]
        return {"queries": queries}

  1. merge_columns

當我們接近流程的最後階段時,我們的重點轉向了資料處理。我們的最終目標是建立一個精煉的資料集,由適合微調的三元組行組成。然而,在生成多個查詢後,我們的資料集現在包含兩個不同的列:`positive` 和 `queries`。`positive` 列包含原始查詢作為單個字串,而 `queries` 列儲存一個字串列表,表示為同一實體生成的額外查詢。

為了將這兩列合併成一個單一、連貫的列表,我們將使用 MergeColumns 步驟。這將使我們能夠將原始查詢與生成的查詢結合起來,建立一個統一的列表。

merge_columns = MergeColumns(
    name="merge_columns",
    columns=["positive", "queries"],
    output_column="positive"
)
  1. expand_columns

最後,我們使用 ExpandColumns 將之前的正向列移動到不同的行。因此,每個 `positive` 查詢將佔據一個單獨的行,而 `anchor` 和 `negative` 列將被複制以匹配擴充套件後的正向查詢。這種資料操作將產生一個具有理想微調結構的資料集。

expand_columns = ExpandColumns(columns=["positive"])

點選下拉選單檢視完整的流水線定義

Distilabel 管道
from pathlib import Path
from typing import Any, Dict, List, Union, Optional

from distilabel.pipeline import Pipeline
from distilabel.steps import LoadDataFromHub
from distilabel.llms import InferenceEndpointsLLM
from distilabel.steps.tasks import GenerateSentencePair
from distilabel.steps.tasks.base import Task
from distilabel.steps.tasks.typing import ChatType
from distilabel.steps import ExpandColumns, CombineKeys


multiply_queries_template = (
    "Given the following query:\n{original}\nGenerate {num_queries} similar queries by varying "
    "the tone and the phrases slightly. "
    "Ensure the generated queries are coherent with the original reference and relevant to the context of data annotation "
    "and AI dataset development."
)

class MultipleQueries(Task):
    system_prompt: Optional[str] = None
    num_queries: int = 1

    @property
    def inputs(self) -> List[str]:
        return ["query"]

    def format_input(self, input: Dict[str, Any]) -> ChatType:
        prompt = [
            {
                "role": "user",
                "content": multiply_queries_template.format(
                    original=input["query"],
                    num_queries=self.num_queries
                ),
            },
        ]
        if self.system_prompt:
            prompt.insert(0, {"role": "system", "content": self.system_prompt})
        return prompt

    @property
    def outputs(self) -> List[str]:
        return ["queries", "model_name"]

    def format_output(
        self, output: Union[str, None], input: Dict[str, Any]
    ) -> Dict[str, Any]:
        queries = output.split("- ")
        if len(queries) > self.num_queries:
            queries = queries[1:]
        queries = [q.strip() for q in queries]
        return {"queries": queries}


with Pipeline(
    name="embedding-queries",
    description="Generate queries to train a sentence embedding model."
) as pipeline:
    load_data = LoadDataFromHub(
        name="load_data",
        repo_id="plaguss/argilla_sdk_docs_raw_unstructured",
        output_mappings={"chunks": "anchor"},
        batch_size=10,
    )

    llm = InferenceEndpointsLLM(
        model_id="meta-llama/Meta-Llama-3-70B-Instruct",
        tokenizer_id="meta-llama/Meta-Llama-3-70B-Instruct",
    )

    generate_sentence_pair = GenerateSentencePair(
        name="generate_sentence_pair",
        triplet=True,  # Generate positive and negative
        action="query",
        context="The generated sentence has to be related with Argilla, a data annotation tool for AI engineers and domain experts.",
        llm=llm,
        input_batch_size=10,
        output_mappings={"model_name": "model_name_query"},
    )

    multiply_queries = MultipleQueries(
        name="multiply_queries",
        num_queries=3,
        system_prompt=(
            "You are an AI assistant helping to generate diverse examples. Ensure the "
            "generated queries are all in separated lines and preceded by a dash. "
            "Do not generate anything else or introduce the task."
        ),
        llm=llm,
        input_batch_size=10,
        input_mappings={"query": "positive"},
        output_mappings={"model_name": "model_name_query_multiplied"},
    )

    merge_columns = MergeColumns(
        name="merge_columns",
        columns=["positive", "queries"],
        output_column="positive"
    )

    expand_columns = ExpandColumns(
        columns=["positive"],
    )

    (
        load_data
        >> generate_sentence_pair
        >> multiply_queries
        >> merge_columns
        >> expand_columns
    )


if __name__ == "__main__":

    pipeline_parameters = {
        "generate_sentence_pair": {
            "llm": {
                "generation_kwargs": {
                    "temperature": 0.7,
                    "max_new_tokens": 512,
                }
            }
        },
        "multiply_queries": {
            "llm": {
                "generation_kwargs": {
                    "temperature": 0.7,
                    "max_new_tokens": 512,
                }
            }
        }
    }

    distiset = pipeline.run(
        parameters=pipeline_parameters
    )
    distiset.push_to_hub("plaguss/argilla_sdk_docs_queries")

在 Argilla 中探索資料集

現在我們已經生成了資料集,是時候使用 Argilla 深入研究並根據需要進行優化了。要開始,請檢視我們的 argilla_datasets.ipynb 筆記本,它提供瞭如何將資料集上傳到 Argilla 的分步指南。

如果您還沒有設定 Argilla 例項,別擔心!請遵循我們文件中易於理解的指南,在 Hugging Face Space 上建立一個 Argilla 例項。一旦您的 Space 啟動並執行,只需透過更新 `api_url` 指向您的 Space 即可連線到它

import argilla as rg

client = rg.Argilla(
    api_url="https://plaguss-argilla-sdk-chatbot.hf.space",
    api_key="YOUR_API_KEY"
)

一個包含技術文件塊的 Argilla 資料集

在您的 Argilla 例項啟動並執行後,讓我們進入下一步:為您的資料集配置 `Settings`。好訊息是,我們將建立的預設 `Settings` 應該可以無縫地適用於您的特定用例,無需進一步調整

settings = rg.Settings(
    guidelines="Review the chunks of docs.",
    fields=[
        rg.TextField(
            name="filename",
            title="Filename where this chunk was extracted from",
            use_markdown=False,
        ),
        rg.TextField(
            name="chunk",
            title="Chunk from the documentation",
            use_markdown=False,
        ),
    ],
    questions=[
        rg.LabelQuestion(
            name="good_chunk",
            title="Does this chunk contain relevant information?",
            labels=["yes", "no"],
        )
    ],
)

讓我們仔細看看我們建立的資料集結構。我們將檢查 `filename` 和 `chunk` 欄位,它們分別包含解析的檔名和生成的塊。為了進一步增強我們的資料集,我們可以定義一個簡單的標籤問題 `good_chunk`,這允許我們手動標記每個塊是否有用。這種人在迴路的方法使我們能夠改進我們的自動化生成過程。有了這些基本要素,我們現在準備好建立我們的資料集了

dataset = rg.Dataset(
    name="argilla_sdk_docs_raw_unstructured",
    settings=settings,
    client=client,
)
dataset.create()

現在,讓我們檢索我們之前在 Hugging Face Hub 上建立的資料集。還記得我們在資料分塊部分生成的資料集嗎?我們將下載該資料集並提取我們需要的核心列以便繼續

from datasets import load_dataset

data = (
    load_dataset("plaguss/argilla_sdk_docs_raw_unstructured", split="train")
    .select_columns(["filename", "chunks"])
    .to_list()
)

我們已經到達了最後的里程碑!為了將所有東西整合在一起,讓我們將記錄日誌到 Argilla。這將允許我們在 Argilla 介面中視覺化我們的資料集,提供一種清晰直觀的方式來探索和與我們的資料互動

dataset.records.log(records=data, mapping={"filename": "filename", "chunks": "chunk"})

這些是您可能期望看到的示例型別

argilla-img-1

一個包含三元組的 Argilla 資料集,用於微調嵌入模型

現在,我們可以使用我們在上一節中生成的準備好進行微調的資料集重複此過程。幸運的是,過程很簡單:只需下載相關的資料集並使用其指定的名稱上傳到 Argilla 即可。有關詳細的演練,請參閱 Jupyter 筆記本,其中包含所有必要的說明

settings = rg.Settings(
    guidelines="Review the chunks of docs.",
    fields=[
        rg.TextField(
            name="anchor",
            title="Anchor (Chunk from the documentation).",
            use_markdown=False,
        ),
        rg.TextField(
            name="positive",
            title="Positive sentence that queries the anchor.",
            use_markdown=False,
        ),
        rg.TextField(
            name="negative",
            title="Negative sentence that may use similar words but has content unrelated to the anchor.",
            use_markdown=False,
        ),
    ],
    questions=[
        rg.LabelQuestion(
            name="is_positive_relevant",
            title="Is the positive query relevant?",
            labels=["yes", "no"],
        ),
        rg.LabelQuestion(
            name="is_negative_irrelevant",
            title="Is the negative query irrelevant?",
            labels=["yes", "no"],
        )
    ],
)

讓我們仔細看看我們資料集的結構,它由三個基本的 TextFields 組成:`anchor`、`positive` 和 `negative`。`anchor` 欄位表示文字塊本身,而 `positive` 欄位包含一個可以使用錨文字作為參考來回答的查詢。相比之下,`negative` 欄位包含一個不相關的查詢,作為三元組中的負面示例。正面和負面問題在幫助我們的模型區分這些示例並學習有效的嵌入方面起著至關重要的作用。

下圖展示了一個例子

argilla-img-2

到目前為止我們建立的資料集設定主要用於探索我們的資料集,但我們可以更進一步。透過自定義這些設定,我們可以識別和糾正錯誤的示例,提高生成問題的質量,並迭代改進我們的資料集,使其更適合我們的需求。

一個用於跟蹤聊天機器人對話的 Argilla 資料集

現在,讓我們建立我們的最終資料集,它將專門用於跟蹤使用者與我們聊天機器人的互動。*注意*:您可能希望在完成 Gradio 應用後再重新訪問此部分,因為它將提供對上下文更全面的理解。現在,讓我們看看這個資料集的 `Settings`

settings_chatbot_interactions = rg.Settings(
    guidelines="Review the user interactions with the chatbot.",
    fields=[
        rg.TextField(
            name="instruction",
            title="User instruction",
            use_markdown=True,
        ),
        rg.TextField(
            name="response",
            title="Bot response",
            use_markdown=True,
        ),
    ],
    questions=[
        rg.LabelQuestion(
            name="is_response_correct",
            title="Is the response correct?",
            labels=["yes", "no"],
        ),
        rg.LabelQuestion(
            name="out_of_guardrails",
            title="Did the model answered something out of the ordinary?",
            description="If the model answered something unrelated to Argilla SDK",
            labels=["yes", "no"],
        ),
        rg.TextQuestion(
            name="feedback",
            title="Let any feedback here",
            description="This field should be used to report any feedback that can be useful",
            required=False
        ),
    ],
    metadata=[
        rg.TermsMetadataProperty(
            name="conv_id",
            title="Conversation ID",
        ),
        rg.IntegerMetadataProperty(
            name="turn",
            min=0,
            max=100,
            title="Conversation Turn",
        )
    ]
)

在這個資料集中,我們將定義兩個基本欄位:`instruction` 和 `response`。`instruction` 欄位將儲存初始查詢,如果對話被擴充套件,它將包含到那時為止的整個對話歷史。另一方面,`response` 欄位將儲存聊天機器人的最新響應。為了便於評估和反饋,我們將包括三個問題:一個評估響應的正確性,另一個確定模型是否偏離主題,以及一個可選欄位供使用者提供對響應的反饋。此外,我們將包括兩個元資料屬性,以便對對話進行篩選和分析:一個唯一的對話 ID 和對話中的輪次編號。

下圖展示了一個例子

argilla-img-3

一旦我們的聊天機器人獲得了大量的使用者參與,這個資料集就可以作為寶貴的資源來改進和增強我們的模型,使我們能夠根據真實世界的互動迭代和提高其效能。

微調嵌入模型

現在我們的自定義嵌入模型資料集已經準備好了,是時候進入訓練過程了。

為了指導我們完成這一步,我們將參考 train_embedding.ipynb 筆記本,該筆記本的靈感來自 Philipp Schmid 關於為 RAG 微調嵌入模型的部落格文章。雖然該部落格文章對整個過程進行了全面的概述,但我們將重點關注我們用例中特定的關鍵差異和細微之處。

要更深入地瞭解底層決策和詳細的演練,請務必檢視原始部落格文章並審閱筆記本以獲取分步解釋。

準備嵌入資料集

我們將首先下載資料集並選擇核心列,這些列恰好已經與 Sentence Transformers 期望的命名約定保持一致。接下來,我們將為每個樣本新增一個唯一的 id 列,並將資料集分為訓練集和測試集,其中 90% 用於訓練,10% 用於測試。最後,我們將格式化後的資料集轉換為 JSON 檔案,準備好輸入訓練器進行模型微調。

from datasets import load_dataset

# Load dataset from the hub
dataset = (
    load_dataset("plaguss/argilla_sdk_docs_queries", split="train")
    .select_columns(["anchor", "positive", "negative"])  # Select the relevant columns
    .add_column("id", range(len(dataset)))               # Add an id column to the dataset
    .train_test_split(test_size=0.1)                     # split dataset into a 10% test set
)
 
# Save datasets to disk
dataset["train"].to_json("train_dataset.json", orient="records")
dataset["test"].to_json("test_dataset.json", orient="records")

載入基線模型

資料集準備就緒後,我們現在可以載入基線模型,它將作為我們微調過程的基礎。我們將使用參考部落格文章中採用的相同模型,以確保我們的自定義嵌入模型開發有一個一致的起點。

from sentence_transformers import SentenceTransformerModelCardData, SentenceTransformer
 
model = SentenceTransformer(
    "BAAI/bge-base-en-v1.5",
    model_card_data=SentenceTransformerModelCardData(
        language="en",
        license="apache-2.0",
        model_name="BGE base ArgillaSDK Matryoshka",
    ),
)

定義損失函式

考慮到我們資料集的結構,我們將利用 `TripletLoss` 函式,它更適合處理我們的 `(anchor-positive-negative)` 三元組。此外,我們還會將它與 `MatryoshkaLoss` 結合使用,這是一個強大的損失函式,已經顯示出有希望的結果(要深入瞭解 `MatryoshkaLoss`,請檢視這篇文章)。

from sentence_transformers.losses import MatryoshkaLoss, TripletLoss
 
inner_train_loss = TripletLoss(model)
train_loss = MatryoshkaLoss(
    model, inner_train_loss, matryoshka_dims=[768, 512, 256, 128, 64]
)

定義訓練策略

現在我們已經有了基線模型和損失函式,是時候定義將指導微調過程的訓練引數了。由於這項工作是在 Apple M2 Pro 上完成的,我們需要進行一些調整以確保訓練過程順利進行。

為了適應我們機器有限的資源,我們將減少 `per_device_train_batch_size` 和 `per_device_eval_batch_size`,與原始部落格文章相比。此外,我們需要移除 `tf32` 和 `bf16` 精度選項,因為它們在此裝置上不受支援。此外,我們將換掉 `adamw_torch_fused` 最佳化器,該最佳化器可以在 Google Colab 筆記本中使用以加快訓練速度。透過進行這些修改,我們將能夠微調我們的模型。

from sentence_transformers import SentenceTransformerTrainingArguments
  
# Define training arguments
args = SentenceTransformerTrainingArguments(
    output_dir="bge-base-argilla-sdk-matryoshka", # output directory and hugging face model ID
    num_train_epochs=3,                           # number of epochs
    per_device_train_batch_size=8,                # train batch size
    gradient_accumulation_steps=4,                # for a global batch size of 512
    per_device_eval_batch_size=4,                 # evaluation batch size
    warmup_ratio=0.1,                             # warmup ratio
    learning_rate=2e-5,                           # learning rate, 2e-5 is a good value
    lr_scheduler_type="cosine",                   # use constant learning rate scheduler
    eval_strategy="epoch",                        # evaluate after each epoch
    save_strategy="epoch",                        # save after each epoch
    logging_steps=5,                              # log every 10 steps
    save_total_limit=1,                           # save only the last 3 models
    load_best_model_at_end=True,                  # load the best model when training ends
    metric_for_best_model="eval_dim_512_cosine_ndcg@10",  # optimizing for the best ndcg@10 score for the 512 dimension
)

訓練並儲存最終模型

from sentence_transformers import SentenceTransformerTrainer
 
trainer = SentenceTransformerTrainer(
    model=model,    # bg-base-en-v1
    args=args,      # training arguments
    train_dataset=train_dataset.select_columns(
        ["anchor", "positive", "negative"]
    ),  # training dataset
    loss=train_loss,
    evaluator=evaluator,
)

# Start training, the model will be automatically saved to the hub and the output directory
trainer.train()
 
# Save the best model
trainer.save_model()
 
# Push model to hub
trainer.model.push_to_hub("bge-base-argilla-sdk-matryoshka")

就是這樣!我們可以看看這個新模型:plaguss/bge-base-argilla-sdk-matryoshka。請仔細檢視資料集卡片,其中包含了關於我們模型的寶貴見解和資訊。

但這還不是全部!在下一節中,我們將對我們的模型進行測試,看看它的實際效果。

向量資料庫

到目前為止,我們已經取得了顯著的進展,為我們的 RAG 聊天機器人建立了一個數據集並微調了一個模型。現在,是時候構建向量資料庫了,它將使我們的聊天機器人能夠高效地儲存和檢索相關資訊。

在選擇向量資料庫時,有許多可用的替代方案。為了保持簡單明瞭,我們將使用 lancedb,這是一個輕量級的嵌入式資料庫,不需要伺服器,類似於 SQLite。正如我們將看到的,lancedb 允許我們建立一個簡單的檔案來儲存我們的嵌入,使其易於移動和快速檢索資料,這非常適合我們的用例。

要跟上進度,請參考附帶的筆記本:vector_db.ipynb。在這個筆記本中,我們將深入探討構建和使用我們的向量資料庫的細節。

連線到資料庫

安裝完依賴項後,讓我們例項化資料庫

import lancedb

# Create a database locally called `lancedb`
db = lancedb.connect("./lancedb")

當我們執行程式碼時,當前工作目錄中應該會出現一個新資料夾,這標誌著我們的向量資料庫已成功建立。

例項化微調後的模型

現在我們的向量資料庫已經建立,是時候載入我們微調過的模型了。我們將利用 `sentence-transformers` 登錄檔來載入模型,釋放其能力併為行動做好準備。

import torch
from lancedb.embeddings import get_registry

model_name = "plaguss/bge-base-argilla-sdk-matryoshka"
device = "mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu"

model = get_registry().get("sentence-transformers").create(name=model_name, device=device)

建立包含文件塊的表

在我們載入了微調模型之後,我們準備建立將儲存我們嵌入的表格。為了定義這個表格的模式,我們將使用一個 `LanceModel`,類似於 `pydantic.BaseModel`,來為我們的 `Docs` 實體建立一個健壯的表示。

from lancedb.pydantic import LanceModel, Vector

class Docs(LanceModel):
    query: str = model.SourceField()
    text: str = model.SourceField()
    vector: Vector(model.ndims()) = model.VectorField()

table_name = "docs"
table = db.create_table(table_name, schema=Docs)

之前的程式碼片段為建立一個包含三個基本列的表格奠定了基礎

  • query: 專用於儲存合成查詢

  • text: 存放分塊的文件文字

  • vector: 與我們微調模型的維度相關聯,準備儲存嵌入

有了這個表結構,我們現在可以與表進行互動了。

填充表格

在建立了我們的表格結構之後,我們現在準備用資料來填充它。讓我們載入最終的資料集,其中包含查詢,並將它們連同相應的嵌入一起攝取到我們的資料庫中。這個關鍵步驟將使我們的向量資料庫充滿活力,使我們的聊天機器人能夠高效地儲存和檢索相關資訊。

ds = load_dataset("plaguss/argilla_sdk_docs_queries", split="train")

batch_size = 50
for batch in tqdm.tqdm(ds.iter(batch_size), total=len(ds) // batch_size):
    embeddings = model.generate_embeddings(batch["positive"])
    df = pd.DataFrame.from_dict({"query": batch["positive"], "text": batch["anchor"], "vector": embeddings})
    table.add(df)

在之前的程式碼片段中,我們以批處理方式遍歷資料集,使用我們微調的模型為 `positive` 列中的合成查詢生成嵌入。然後,我們建立了一個 Pandas 資料框,以包含 `query`、`text` 和 `vector` 列。這個資料框將 `positive` 和 `anchor` 列與新生成的嵌入分別結合起來。

現在,讓我們來測試一下我們的向量資料庫!對於一個示例查詢,“我如何獲取當前使用者?”(使用 Argilla SDK),我們將使用我們的自定義嵌入模型生成嵌入。然後,我們將利用 `cosine` 度量來衡量相似度,在我們的表格中搜索前 3 個最相似的出現。最後,我們將提取相關的 `text` 列,它對應於最匹配我們查詢的文件塊。

query = "How can I get the current user?"
embedded_query = model.generate_embeddings([query])

retrieved = (
    table
        .search(embedded_query[0])
        .metric("cosine")
        .limit(3)
        .select(["text"])  # Just grab the chunk to use for context
        .to_list()
)
點選檢視結果

這將是結果

>>> retrieved
[{'text': 'python\nuser = client.users("my_username")\n\nThe current user of the rg.Argilla client can be accessed using the me attribute:\n\npython\nclient.me\n\nClass Reference\n\nrg.User\n\n::: argilla_sdk.users.User\n    options:\n        heading_level: 3',
  '_distance': 0.1881886124610901},
 {'text': 'python\nuser = client.users("my_username")\n\nThe current user of the rg.Argilla client can be accessed using the me attribute:\n\npython\nclient.me\n\nClass Reference\n\nrg.User\n\n::: argilla_sdk.users.User\n    options:\n        heading_level: 3',
  '_distance': 0.20238929986953735},
 {'text': 'Retrieve a user\n\nYou can retrieve an existing user from Argilla by accessing the users attribute on the Argilla class and passing the username as an argument.\n\n```python\nimport argilla_sdk as rg\n\nclient = rg.Argilla(api_url="", api_key="")\n\nretrieved_user = client.users("my_username")\n```',
  '_distance': 0.20401990413665771}]

>>> print(retrieved[0]["text"])
python
user = client.users("my_username")

The current user of the rg.Argilla client can be accessed using the me attribute:

python
client.me

Class Reference

rg.User

::: argilla_sdk.users.User
    options:
        heading_level: 3

讓我們深入研究資料集的第一行,看看能發現什麼。乍一看,它似乎包含了與查詢相關的資訊,這正是我們所期望的。要獲取當前使用者,我們可以使用 `client.me` 方法。然而,我們也注意到一些無關的內容,這很可能是由於所採用的分塊策略造成的。這個策略雖然有效,但可以從一些改進中受益。透過在 Argilla 中審查資料集,我們可以更深入地瞭解如何最佳化我們的分塊方法,最終得到一個更精簡的資料集。不過,就目前而言,這似乎是一個很好的起點。

將資料庫儲存在 Hugging Face Hub 上

現在我們有了一個數據庫,我們將把它作為另一個工件儲存在我們的資料集倉庫中。您可以訪問該倉庫以找到可以幫助我們的函式,但它就像執行以下函式一樣簡單

import Path
import os

local_dir = Path.home() / ".cache/argilla_sdk_docs_db"

upload_database(
    local_dir / "lancedb",
    repo_id="plaguss/argilla_sdk_docs_queries",
    token=os.getenv("HF_API_TOKEN")
)

我們資料庫儲存之旅的最後一步僅需一個命令!透過執行該函式,我們將建立一個名為 `lancedb.tar.gz` 的全新檔案,它將整齊地打包我們的向量資料庫。您可以在 Hugging Face Hub 上的 plaguss/argilla_sdk_docs_queries 倉庫中預覽生成的檔案,它與其他重要檔案一起儲存。

db_path = download_database(repo_id)

關鍵時刻到了!我們的資料庫成功下載後,我們現在可以驗證一切是否正常。預設情況下,檔案將儲存在 `Path.home() / ".cache/argilla_sdk_docs_db"`,但可以輕鬆自定義。我們可以再次連線到它並檢查一切是否按預期工作

db = lancedb.connect(str(db_path))
table = db.open_table(table_name)

query = "how can I delete users?"

retrieved = (
    table
        .search(query)
        .metric("cosine")
        .limit(1)
        .to_pydantic(Docs)
)

for d in retrieved:
    print("======\nQUERY\n======")
    print(d.query)
    print("======\nDOC\n======")
    print(d.text)

# ======
# QUERY
# ======
# Is it possible to remove a user from Argilla by utilizing the delete function on the User class?
# ======
# DOC
# ======
# Delete a user

# You can delete an existing user from Argilla by calling the delete method on the User class.

# ```python
# import argilla_sdk as rg

# client = rg.Argilla(api_url="", api_key="")

# user_to_delete = client.users('my_username')

# deleted_user = user_to_delete.delete()
# ```

用於文件檢索的資料庫已經完成,接下來讓我們來做應用程式吧!

建立我們的聊天機器人

我們聊天機器人的所有部件都已準備就緒;我們需要將它們連線起來,並在一個介面中提供。

Gradio 應用

讓我們把 RAG 應用帶入現實!使用 gradio,我們可以毫不費力地建立聊天機器人應用。在這種情況下,我們將設計一個簡單而有效的介面來展示我們聊天機器人的能力。要檢視應用的實際效果,請參閱 GitHub 上 Argilla SDK Chatbot 倉庫中的 app.py 指令碼。

在我們深入探討構建聊天機器人應用的細節之前,讓我們先退一步,欣賞一下最終的成果。僅用幾行程式碼,我們就成功建立了一個使用者友好的介面,讓我們的 RAG 聊天機器人栩栩如生。

chatty

import gradio as gr

gr.ChatInterface(
    chatty,
    chatbot=gr.Chatbot(height=600),
    textbox=gr.Textbox(placeholder="Ask me about the new argilla SDK", container=False, scale=7),
    title="Argilla SDK Chatbot",
    description="Ask a question about Argilla SDK",
    theme="soft",
    examples=[
        "How can I connect to an argilla server?",
        "How can I access a dataset?",
        "How can I get the current user?"
    ],
    cache_examples=True,
    retry_btn=None,
).launch()

就是這樣!如果您渴望瞭解更多關於建立自己的聊天機器人的資訊,請務必檢視 Gradio 的優秀指南使用 Gradio 快速建立聊天機器人。這是一個知識的寶庫,能讓您在短時間內構建出自己的聊天機器人。

現在,讓我們更深入地探討我們的 `app.py` 指令碼的內部工作原理。我們將分解關鍵元件,重點關注讓我們的聊天機器人活起來的基本元素。為了保持簡潔,我們將略過一些更精細的細節。

首先,讓我們檢查 `Database` 類,它是我們聊天機器人知識和功能的支柱。這個元件在儲存和檢索驅動我們聊天機器人對話的資料方面起著至關重要的作用

點選檢視 Database 類
class Database:

    def __init__(self, settings: Settings) -> None:

        self.settings = settings
        self._table: lancedb.table.LanceTable = self.get_table_from_db()

    def get_table_from_db(self) -> lancedb.table.LanceTable:

        lancedb_db_path = self.settings.LOCAL_DIR / self.settings.LANCEDB

        if not lancedb_db_path.exists():
            lancedb_db_path = download_database(
                self.settings.REPO_ID,
                lancedb_file=self.settings.LANCEDB_FILE_TAR,
                local_dir=self.settings.LOCAL_DIR,
                token=self.settings.TOKEN,
            )

        db = lancedb.connect(str(lancedb_db_path))
        table = db.open_table(self.settings.TABLE_NAME)
        return table

    def retrieve_doc_chunks(
        self, query: str, limit: int = 12, hard_limit: int = 4
    ) -> str:

        # Embed the query to use our custom model instead of the default one.
        embedded_query = model.generate_embeddings([query])
        field_to_retrieve = "text"
        retrieved = (
            self._table.search(embedded_query[0])
            .metric("cosine")
            .limit(limit)
            .select([field_to_retrieve])  # Just grab the chunk to use for context
            .to_list()
        )
        return self._prepare_context(retrieved, hard_limit)

    @staticmethod
    def _prepare_context(retrieved: list[dict[str, str]], hard_limit: int) -> str:

        # We have repeated questions (up to 4) for a given chunk, so we may get repeated chunks.
        # Request more than necessary and filter them afterwards
        responses = []
        unique_responses = set()

        for item in retrieved:
            chunk = item["text"]
            if chunk not in unique_responses:
                unique_responses.add(chunk)
                responses.append(chunk)

        context = ""
        for i, item in enumerate(responses[:hard_limit]):
            if i > 0:
                context += "\n\n"
            context += f"---\n{item}"
        return context

隨著我們的 `Database` 類的就位,我們成功地在我們聊天機器人的對話流和儲存在我們資料庫中的知識之間架起了橋樑。現在,讓我們把一切都整合起來!一旦我們下載了我們的嵌入模型(指令碼會自動完成),我們就可以例項化 `Database` 類,從而有效地將我們的資料庫部署到期望的位置——在這種情況下,是我們的 Hugging Face Space。

這標誌著我們聊天機器人開發旅程中的一個重要里程碑。隨著我們的資料庫整合並準備就緒,我們距離釋放聊天機器人的全部潛力僅一步之遙。

database = Database(settings=settings)  # The settings can be seen in the following snippet

context = database.retrieve_doc_chunks("How can I delete a user?", limit=2, hard_limit=1)

>>> print(context)
# ---
# Delete a user

# You can delete an existing user from Argilla by calling the delete method on the User class.

# ```python
# import argilla_sdk as rg

# client = rg.Argilla(api_url="", api_key="")

# user_to_delete = client.users('my_username')

# deleted_user = user_to_delete.delete()
# ```
點選檢視 Settings 類
@dataclass
class Settings:
    LANCEDB: str = "lancedb"
    LANCEDB_FILE_TAR: str = "lancedb.tar.gz"
    TOKEN: str = os.getenv("HF_API_TOKEN")
    LOCAL_DIR: Path = Path.home() / ".cache/argilla_sdk_docs_db"
    REPO_ID: str = "plaguss/argilla_sdk_docs_queries"
    TABLE_NAME: str = "docs"
    MODEL_NAME: str = "plaguss/bge-base-argilla-sdk-matryoshka"
    DEVICE: str = (
        "mps"
        if torch.backends.mps.is_available()
        else "cuda"
        if torch.cuda.is_available()
        else "cpu"
    )
    MODEL_ID: str = "meta-llama/Meta-Llama-3-70B-Instruct"

拼圖的最後一塊現在已經就位——我們的資料庫已經準備好為我們的聊天機器人對話提供動力。接下來,我們需要準備我們的模型來處理湧入的使用者查詢。這就是推理端點發揮作用的地方。這些專用端點提供了一種無縫的方式來部署和管理我們的模型,確保它隨時準備響應使用者輸入。

幸運的是,使用推理端點非常簡單,這要歸功於 `huggingface_hub` 庫中的 inference client

def get_client_and_tokenizer(
    model_id: str = settings.MODEL_ID, tokenizer_id: Optional[str] = None
) -> tuple[InferenceClient, AutoTokenizer]:
    if tokenizer_id is None:
        tokenizer_id = model_id

    client = InferenceClient()
    base_url = client._resolve_url(model=model_id, task="text-generation")
    # Note: We could move to the AsyncClient
    client = InferenceClient(model=base_url, token=os.getenv("HF_API_TOKEN"))

    tokenizer = AutoTokenizer.from_pretrained(tokenizer_id)
    return client, tokenizer

# Load the client and tokenizer
client, tokenizer = get_client_and_tokenizer()

在我們的元件就位後,我們已經到了準備將被饋送到我們客戶端的提示的階段。這個提示將作為激發我們機器學習模型魔力的輸入,引導它生成一個既準確又資訊豐富的響應,同時避免回答不相關的問題。在本節中,我們將深入探討製作一個結構良好的提示的細節,為我們的模型成功做好準備。`prepare_input` 函式將準備對話,應用提示和聊天模板以傳遞給模型。

def prepare_input(message: str, history: list[tuple[str, str]]) -> str:

    # Retrieve the context from the database
    context = database.retrieve_doc_chunks(message)

    # Prepare the conversation for the model.
    conversation = []
    for human, bot in history:
        conversation.append({"role": "user", "content": human})
        conversation.append({"role": "assistant", "content": bot})

    conversation.insert(0, {"role": "system", "content": SYSTEM_PROMPT})
    conversation.append(
        {
            "role": "user",
            "content": ARGILLA_BOT_TEMPLATE.format(message=message, context=context),
        }
    )

    return tokenizer.apply_chat_template(
        [conversation],
        tokenize=False,
        add_generation_prompt=True,
    )[0]

此函式將接受兩個引數:`message` 和 `history`,這得益於 gradio 的 ChatInterface。它將從資料庫中獲取文件片段以幫助 LLM 生成響應,並準備好要傳遞給我們 `LLM` 模型的提示。

點選檢視系統提示和機器人模板

這些是使用的 `system_prompt` 和提示模板。它們深受 Weights and Biases 的 `wandbot` 的啟發。

SYSTEM_PROMPT = """\
You are a support expert in Argilla SDK, whose goal is help users with their questions.
As a trustworthy expert, you must provide truthful answers to questions using only the provided documentation snippets, not prior knowledge.
Here are guidelines you must follow when responding to user questions:

##Purpose and Functionality**
- Answer questions related to the Argilla SDK.
- Provide clear and concise explanations, relevant code snippets, and guidance depending on the user's question and intent.
- Ensure users succeed in effectively understanding and using Argilla's features.
- Provide accurate responses to the user's questions.

**Specificity**
- Be specific and provide details only when required.
- Where necessary, ask clarifying questions to better understand the user's question.
- Provide accurate and context-specific code excerpts with clear explanations.
- Ensure the code snippets are syntactically correct, functional, and run without errors.
- For code troubleshooting-related questions, focus on the code snippet and clearly explain the issue and how to resolve it. 
- Avoid boilerplate code such as imports, installs, etc.

**Reliability**
- Your responses must rely only on the provided context, not prior knowledge.
- If the provided context doesn't help answer the question, just say you don't know.
- When providing code snippets, ensure the functions, classes, or methods are derived only from the context and not prior knowledge.
- Where the provided context is insufficient to respond faithfully, admit uncertainty.
- Remind the user of your specialization in Argilla SDK support when a question is outside your domain of expertise.
- Redirect the user to the appropriate support channels - Argilla [community](https://join.slack.com/t/rubrixworkspace/shared_invite/zt-whigkyjn-a3IUJLD7gDbTZ0rKlvcJ5g) when the question is outside your capabilities or you do not have enough context to answer the question.

**Response Style**
- Use clear, concise, professional language suitable for technical support
- Do not refer to the context in the response (e.g., "As mentioned in the context...") instead, provide the information directly in the response.

**Example**:

The correct answer to the user's query

 Steps to solve the problem:
 - **Step 1**: ...
 - **Step 2**: ...
 ...

 Here's a code snippet

 ```python
 # Code example
 ...
 ```
 
 **Explanation**:

 - Point 1
 - Point 2
 ...
"""

ARGILLA_BOT_TEMPLATE = """\
Please provide an answer to the following question related to Argilla's new SDK.

You can make use of the chunks of documents in the context to help you generating the response.

## Query:
{message}

## Context:
{context}
"""

我們已經達到了我們對話式人工智慧系統的頂點:`chatty` 函式。這個函式扮演著編排者的角色,將我們到目前為止構建的各種元件整合在一起。它的主要職責是呼叫 `prepare_input` 函式,該函式會精心製作將被傳遞給客戶端的提示。然後,我們會在文字生成時逐段產生文字流,一旦響應完成,對話歷史將被儲存,為我們提供寶貴的資源來審查和改進我們的模型,確保它在每次迭代中持續進步。

def chatty(message: str, history: list[tuple[str, str]]) -> Generator[str, None, None]:
    prompt = prepare_input(message, history)

    partial_response = ""

    for token_stream in client.text_generation(prompt=prompt, **client_kwargs):
        partial_response += token_stream
        yield partial_response

    global conv_id
    new_conversation = len(history) == 0
    if new_conversation:
        conv_id = str(uuid.uuid4())
    else:
        history.append((message, None))

    # Register to argilla dataset
    argilla_dataset.records.log(
        [
            {
                "instruction": create_chat_html(history) if history else message,
                "response": partial_response,
                "conv_id": conv_id,
                "turn": len(history)
            },
        ]
    )

關鍵時刻到了!我們的應用程式現在已經準備好接受測試了。要檢視它的實際效果,只需在您的本地環境中執行 `python app.py`。但在您這樣做之前,請確保您可以訪問部署在推理端點上的模型。在這個例子中,我們使用的是強大的 Llama 3 70B 模型,但您可以隨意嘗試其他適合您需求的模型。透過調整模型和微調應用程式,您可以釋放其全部潛力,探索人工智慧開發的新可能性。

在 Hugging Face Spaces 上部署聊天機器人應用


現在我們的應用程式已經啟動並執行,是時候與世界分享它了!為了部署我們的應用程式並使其可供他人訪問,我們將遵循 Gradio 的指南中概述的步驟來分享您的應用程式。我們選擇的託管平臺是 Hugging Face Spaces,這是一個展示人工智慧驅動專案的絕佳工具。

首先,我們需要在我們的倉庫中新增一個 `requirements.txt` 檔案,其中列出了執行我們的應用程式所需的依賴項。這是確保我們的應用程式可以輕鬆複製和部署的關鍵一步。您可以在 Hugging Face Spaces spaces dependencies 中瞭解有關管理依賴項的更多資訊。

接下來,我們需要將我們的 Hugging Face API 令牌新增為秘密,請遵循本指南中的說明。這將允許我們的應用程式與 Hugging Face 生態系統進行身份驗證。

一旦我們上傳了我們的 `app.py` 檔案,我們的 Space 將被構建,我們將能夠透過以下連結訪問我們的應用程式:

https://huggingface.co/spaces/plaguss/argilla-sdk-chatbot-space

請在此處檢視我們的示例 Space 檔案,瞭解這一切是如何組合在一起的。透過遵循這些步驟,您將能夠與世界分享您自己的人工智慧驅動的應用程式,並與 Hugging Face 社群中的其他人合作。

體驗我們的聊天機器人

我們現在可以對聊天機器人進行測試。我們提供了一些預設查詢供您開始,但您也可以隨意嘗試自己的問題。例如,您可以問:`新 SDK 中的 Settings 是什麼?`

從下面的截圖中您可以看到,我們的聊天機器人已經準備好為您的查詢提供有用的響應

chatbot img

但這還不是全部!您還可以挑戰我們的聊天機器人為特定資料集生成設定,就像我們在本教程前面建立的那個一樣。例如,您可以讓它為旨在微調嵌入模型的資料集建議設定,類似於我們在一個包含三元組以微調嵌入模型的 Argilla 資料集部分中探討的那個。

看看下面的截圖,看看我們的聊天機器人如何回應這類查詢。

chatbot sentence-embedding

來吧,提出您的問題,看看我們的聊天機器人能提供什麼樣的見解!

下一步

在本教程中,我們成功構建了一個聊天機器人,它可以為有關 Argilla SDK 及其應用的問題提供有用的回答。透過利用 Llama 3 70B 和 Gradio 的強大功能,我們建立了一個使用者友好的介面,可以幫助開發人員理解如何處理資料集和微調嵌入模型。

然而,我們的聊天機器人只是一個起點,我們還有很多方法可以改進和擴充套件其功能。以下是一些可以著手的下一步工作:

  • 改進分塊策略:嘗試不同的分塊策略、引數和大小,以最佳化聊天機器人的效能和響應質量。

  • 實現去重和過濾:在訓練資料集中新增去重和過濾機制,以移除重複和無關資訊,確保聊天機器人提供準確簡潔的回答。

  • 為響應包含來源:透過在聊天機器人的響應中包含相關文件和來源的連結,增強其功能,讓使用者可以更深入地探討主題並進一步探索。

透過解決這些領域的問題,我們可以將我們的聊天機器人提升到一個新的水平,使其成為使用 Argilla SDK 的開發人員更有價值的資源。可能性是無窮的,我們很期待看到這個專案未來的發展。敬請期待未來的更新和改進!

社群

註冊登入 以發表評論

© . This site is unofficial and not affiliated with Hugging Face, Inc.