開源 AI 食譜文件
使用 Meta 合成數據工具包構建文件聊天機器人
並獲得增強的文件體驗
開始使用
使用 Meta 合成數據工具包構建文件聊天機器人
本筆記本演示了一種構建特定領域問答(Q&A)聊天機器人的實用方法。我們將專注於建立一個能夠回答有關特定文件問題的聊天機器人——在本例中,是關於 LangChain 的聊天模型(Chat Models)文件。
目標: 微調一個小型高效的語言模型(LLM),使其能夠理解並回答有關 LangChain 聊天模型文件的問題。
方法
- 資料獲取: 從目標 LangChain 文件頁面獲取文字內容。
- 合成數據生成: 使用 Meta 的
synthetic-data-kit
從該文件自動生成問答對。 - 高效微調: 利用 Unsloth 和
Hugging Face 的 TRL SFTTrainer
,在生成的合成數據上高效微調 Llama-3.2-3B 模型。 - 評估: 用關於文件的特定問題測試微調後的模型。
這種方法使我們能夠將 LLM 調整到特定領域,而無需大量手動整理的資料集。
使用的硬體
本筆記本在 Google Colab(免費版)上使用 NVIDIA T4 GPU 執行
1. 設定與安裝
首先,我們需要安裝必要的庫。我們將使用 unsloth
來高效地處理和訓練模型,使用 synthetic-data-kit
來生成我們的訓練資料。
%%capture
# In Colab, we skip dependency installation to avoid conflicts with preinstalled packages.
# On local machines, we include dependencies for completeness.
import os
if "COLAB_" not in "".join(os.environ.keys()):
!pip install unsloth vllm==0.8.2
else:
!pip install --no-deps unsloth vllm==0.8.2
# Get https://github.com/meta-llama/synthetic-data-kit
!pip install synthetic-data-kit
%%capture
import os
if "COLAB_" in "".join(os.environ.keys()):
import sys, re, requests; modules = list(sys.modules.keys())
for x in modules: sys.modules.pop(x) if "PIL" in x or "google" in x else None
!pip install --no-deps bitsandbytes accelerate xformers==0.0.29.post3 peft "trl==0.15.2" triton cut_cross_entropy unsloth_zoo
!pip install sentencepiece protobuf datasets huggingface_hub[hf_xet] hf_transfer
# vLLM requirements - vLLM breaks Colab due to reinstalling numpy
f = requests.get("https://raw.githubusercontent.com/vllm-project/vllm/refs/heads/main/requirements/common.txt").content
with open("vllm_requirements.txt", "wb") as file:
file.write(re.sub(rb"(transformers|numpy|xformers|importlib_metadata)[^\n]{0,}\n", b"", f))
!pip install -r vllm_requirements.txt
2. 合成數據生成
我們將使用 Unsloth 的 SyntheticDataKit
(它封裝了 Meta 的 synthetic-data-kit
)從我們選擇的文件中建立問答對。
>>> from unsloth.dataprep import SyntheticDataKit
>>> generator = SyntheticDataKit.from_pretrained(
... model_name="unsloth/Llama-3.2-3B-Instruct",
... max_seq_length=2048,
... )
🦥 Unsloth: Will patch your computer to enable 2x faster free finetuning. 🦥 Unsloth Zoo will now patch everything to make training faster! INFO 05-05 15:14:48 [__init__.py:239] Automatically detected platform cuda.
generator.prepare_qa_generation(
output_folder="data", # Output location of synthetic data
temperature=0.7, # Higher temp makes more diverse data
top_p=0.95,
overlap=64, # Overlap portion during chunking
max_generation_tokens=512, # Can increase for longer QA pairs
)
>>> !synthetic-data-kit system-check
[?25l[32m VLLM server is running at [0m[4;94mhttps://:8000/v1[0m [32m⠋[0m[32m Checking VLLM server at https://:8000/v1...[0m [2KAvailable models: [1m{[0m[32m'object'[0m: [32m'list'[0m, [32m'data'[0m: [1m[[0m[1m{[0m[32m'id'[0m: [32m'unsloth/Llama-3.2-3B-Instruct'[0m, [32m'object'[0m: [32m'model'[0m, [32m'created'[0m: [1;36m1746459182[0m, [32m'owned_by'[0m: [32m'vllm'[0m, [32m'root'[0m: [32m'unsloth/Llama-3.2-3B-Instruct'[0m, [32m'parent'[0m: [3;35mNone[0m, [32m'max_model_len'[0m: [1;36m2048[0m, [32m'permission'[0m: [1m[[0m[1m{[0m[32m'id'[0m: [32m'modelperm-5296f16bbd3c425a82af4d2f84f0cbfe'[0m, [32m'object'[0m: [32m'model_permission'[0m, [32m'created'[0m: [1;36m1746459182[0m, [32m'allow_create_engine'[0m: [3;91mFalse[0m, [32m'allow_sampling'[0m: [3;92mTrue[0m, [32m'allow_logprobs'[0m: [3;92mTrue[0m, [32m'allow_search_indices'[0m: [3;91mFalse[0m, [32m'allow_view'[0m: [3;92mTrue[0m, [32m'allow_fine_tuning'[0m: [3;91mFalse[0m, [32m'organization'[0m: [32m'*'[0m, [32m'group'[0m: [3;35mNone[0m, [32m'is_blocking'[0m: [3;91mFalse[0m[1m}[0m[1m][0m[1m}[0m[1m][0m[1m}[0m [32m⠋[0m Checking VLLM server at https://:8000/v1... [2K[32m⠋[0m Checking VLLM server at https://:8000/v1... [?25h [1A[2K
2.1. 獲取並匯入文件
在本例中,我們將使用關於聊天模型的 LangChain 文件頁面。
要獲取文字
- 轉到 MDX 檔案的原始版本(例如,在 GitHub 上點選“Raw”)。
- 複製全部文字內容。
- 將其在本地儲存為
.txt
檔案。在本筆記本中,我們假設您已將其儲存為/content/langchain-ai-langchain.txt
。您可以使用像gitingest
這樣的工具或手動複製貼上。
注意: 如果您在 Colab 中執行此筆記本,請確保將文字檔案上傳到您的 Colab 環境中的 /content/langchain-ai-langchain.txt
。
>>> # Make sure synthetic_data_kit_config.yaml points to the 'data_docs' folder
>>> !synthetic-data-kit -c synthetic_data_kit_config.yaml ingest /content/langchain-ai-langchain.txt
[?25l[32m⠋[0m Processing /content/langchain-ai-langchain.txt... [?25h [1A[2K[32m Text successfully extracted to [0m[1;32mdata/output/langchain-ai-langchain.txt[0m
2.2. 資料分塊並生成問答對
匯入的文件將被分割成更小的塊,然後為每個塊生成問答對。
>>> filenames = generator.chunk_data("data/output/langchain-ai-langchain.txt")
>>> print(f"Created {len(filenames)} chunks.")
Created 3 chunks.
import time
# Process 2 chunks for now -> can increase but slower!
for filename in filenames[:2]:
!synthetic-data-kit \
-c synthetic_data_kit_config.yaml \
create {filename} \
--num-pairs 25 \
--type "qa"
time.sleep(2) # Sleep some time to leave some room for processing
2.3. 格式化並儲存問答對
生成的問答對隨後被轉換為適合微調的格式。
>>> qa_pairs_filenames = [
... f"data/generated/langchain-ai-langchain_{i}_qa_pairs.json"
... for i in range(len(filenames[:2]))
... ]
>>> for filename in qa_pairs_filenames:
... !synthetic-data-kit \
... -c synthetic_data_kit_config.yaml \
... save-as {filename} -f ft
[?25l[32m⠋[0m Converting data/generated/langchain-ai-langchain_0_qa_pairs.json to ft format with json storage... [?25h [1A[2K[1A[2K[32m Converted to ft format and saved to [0m [1;32mdata/final/langchain-ai-langchain_0_qa_pairs_ft.json[0m [?25l[32m⠋[0m Converting data/generated/langchain-ai-langchain_1_qa_pairs.json to ft format with json storage... [1A[2K[1A[2K[32m Converted to ft format and saved to [0m [1;32mdata/final/langchain-ai-langchain_1_qa_pairs_ft.json[0m
>>> generator.cleanup()
Attempting to terminate the VLLM server gracefully... Server did not terminate gracefully after 10 seconds. Forcing kill... Server killed forcefully.
2.4. 載入格式化後的資料集
現在,讓我們載入生成並格式化後的資料。
from datasets import Dataset
import pandas as pd
final_filenames = [f"data/final/langchain-ai-langchain_{i}_qa_pairs_ft.json" for i in range(len(filenames[:2]))]
conversations = pd.concat([pd.read_json(name) for name in final_filenames]).reset_index(drop=True)
dataset = Dataset.from_pandas(conversations)
dataset[0]
dataset[-1]
記憶體管理說明(對資源受限環境至關重要)
如果在接下來的步驟中載入 Llama 模型進行微調時遇到 CUDA 記憶體不足(OOM)錯誤(即使在執行 `generator.cleanup()` 之後),這意味著 GPU 記憶體沒有完全釋放。這在像 Google Colab 免費版這樣的環境中很常見。
解決方案策略
- 歸檔生成的資料: 在 `generator.cleanup()` 單元格之後,將整個 `/content/data` 資料夾壓縮並下載到本地。
- 重啟 Colab 執行時: 前往“執行時”->“重新啟動執行時...”。這將完全清除 GPU 記憶體。
- 重新執行安裝和匯入: 再次執行初始的安裝單元格和必要的匯入單元格。
- 恢復資料: 上傳壓縮的資料資料夾並解壓資料。
- 從恢復的檔案中載入資料集: 使用指令碼從解壓後的 `/content/data/final/` 目錄載入資料。
- 繼續進行模型載入和微調。
下面的單元格包含壓縮命令。如果您重新啟動,您需要手動執行“可選:重啟並重新載入資料”部分中的解壓和資料載入程式碼。
# !zip -r data.zip /content/
# !unzip data.zip
# import os
# import pandas as pd
# from datasets import Dataset
# # Path to your folder containing JSON files
# folder_path = 'content/data/final/'
# # List all .json files in the folder
# final_filenames = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if f.endswith('.json')]
# # Read and combine the JSON files
# conversations = pd.concat([
# pd.read_json(name) for name in final_filenames
# ]).reset_index(drop=True)
# # Convert to Hugging Face Dataset
# dataset = Dataset.from_pandas(conversations)
3. 使用 Unsloth 微調 LLM
現在,我們將使用 Unsloth 載入基礎模型進行 4 位量化,然後在我們合成生成的資料集上對其進行微調。
3.1. 載入基礎模型和分詞器
我們將使用 4 位精度的 Llama-3.2-3B-Instruct
。Unsloth 使這一過程非常節省記憶體。
>>> from unsloth import FastLanguageModel
>>> import torch
>>> model, tokenizer = FastLanguageModel.from_pretrained(
... model_name="unsloth/Llama-3.2-3B-Instruct",
... max_seq_length=1024, # Choose any for long context!
... load_in_4bit=True, # 4 bit quantization to reduce memory
... load_in_8bit=False, # [NEW!] A bit more accurate, uses 2x memory
... full_finetuning=False, # [NEW!] We have full finetuning now!
... )
🦥 Unsloth: Will patch your computer to enable 2x faster free finetuning. 🦥 Unsloth Zoo will now patch everything to make training faster! INFO 05-05 15:54:31 [__init__.py:239] Automatically detected platform cuda. ==((====))== Unsloth 2025.4.7: Fast Llama patching. Transformers: 4.51.3. vLLM: 0.8.2. \\ /| Tesla T4. Num GPUs = 1. Max memory: 14.741 GB. Platform: Linux. O^O/ \_/ \ Torch: 2.6.0+cu124. CUDA: 7.5. CUDA Toolkit: 12.4. Triton: 3.2.0 \ / Bfloat16 = FALSE. FA [Xformers = 0.0.29.post3. FA2 = False] "-____-" Free license: http://github.com/unslothai/unsloth Unsloth: Fast downloading is enabled - ignore downloading bars which are red colored!
3.2. 新增 LoRA 介面卡
我們使用 LoRA(低秩適配)進行引數高效微調。
model = FastLanguageModel.get_peft_model(
model,
r=16, # Choose any number > 0 ! Suggested 8, 16, 32, 64, 128
target_modules=[
"q_proj",
"k_proj",
"v_proj",
"o_proj",
"gate_proj",
"up_proj",
"down_proj",
],
lora_alpha=16,
lora_dropout=0, # Supports any, but = 0 is optimized
bias="none", # Supports any, but = "none" is optimized
# [NEW] "unsloth" uses 30% less VRAM, fits 2x larger batch sizes!
use_gradient_checkpointing="unsloth", # True or "unsloth" for very long context
random_state=3407,
use_rslora=False, # We support rank stabilized LoRA
loftq_config=None, # And LoftQ
)
3.3. 為聊天格式準備資料
我們需要將我們的資料集格式化為 Llama-3.2 模型期望的聊天模板。
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
Cutting Knowledge Date: December 2023
Today Date: 01 May 2025
You are a helpful assistant.<|eot_id|><|start_header_id|>user<|end_header_id|>
What is 1+1?<|eot_id|><|start_header_id|>assistant<|end_header_id|>
2<|eot_id|>
def formatting_prompts_func(examples):
convos = examples["messages"]
texts = [tokenizer.apply_chat_template(convo, tokenize=False, add_generation_prompt=False) for convo in convos]
return {
"text": texts,
}
pass
# Get our previous dataset and format it:
dataset = dataset.map(
formatting_prompts_func,
batched=True,
)
dataset[0]
3.4. 訓練模型
我們將使用 Hugging Face TRL 的 `SFTTrainer` 來微調模型,該類專門為監督式微調(SFT)設計。我們使用 SFTConfig 配置訓練引數,指定資料集、模型、訓練步驟和最佳化設定。這種設定使我們能夠在有限的硬體環境下,利用梯度累積和像 adamw_8bit 這樣的混合精度最佳化器來高效地微調模型。
from trl import SFTTrainer, SFTConfig
trainer = SFTTrainer(
model=model,
processing_class=tokenizer,
train_dataset=dataset,
eval_dataset=None, # Can set up evaluation!
args=SFTConfig(
dataset_text_field="text",
per_device_train_batch_size=2,
gradient_accumulation_steps=4, # Use GA to mimic batch size!
warmup_steps=5,
max_steps=60,
learning_rate=2e-4,
logging_steps=1,
optim="adamw_8bit",
weight_decay=0.01,
lr_scheduler_type="linear",
seed=3407,
report_to="none", # Use this for WandB etc
),
)
trainer_stats = trainer.train()
4. 推理與測試
讓我們用一些與 LangChain 聊天模型文件相關的問題來測試我們微調後的模型。
>>> messages = [
... {"role": "user", "content": "What is the standard interface for binding tools to models?"},
... ]
>>> inputs = tokenizer.apply_chat_template(
... messages,
... tokenize=True,
... add_generation_prompt=True, # Must add for generation
... return_tensors="pt",
... ).to("cuda")
>>> from transformers import TextStreamer
>>> text_streamer = TextStreamer(tokenizer, skip_prompt=True)
>>> _ = model.generate(input_ids=inputs, streamer=text_streamer, max_new_tokens=256, temperature=0.1)
Standard [tool calling API](/docs/concepts/tool_calling): standard interface for binding tools to models.<|eot_id|>
5. 結論
我們已成功
- 獲取了 LangChain 聊天模型 的文件文字。
- 使用
synthetic-data-kit
生成了合成的問答對。 - 使用 Unsloth 和 Hugging Face 的 TRL SFTTrainer 高效地微調了 Llama-3.2-3B 模型。
- 測試了模型回答特定於文件問題的能力。
本筆記本為建立針對各種文件或特定領域文字的專業聊天機器人提供了模板。合成數據生成和高效微調技術的使用使得這種方法即使在資源有限的情況下也易於實現。
進一步的改進可以包括
- 使用更大一部分的文件或多個相關頁面。
- 更精細地篩選合成的問答對。
- 嘗試不同的基礎模型或進行超引數調優。
- 實施更強大的評估框架(例如,與一個保留的測試問題集進行比較,或使用 ROUGE、BLEU 等指標,如果適用,或使用 LLM-as-a-judge)。