Sự xuất hiện của DeepSeek-R1 vào đầu năm 2025 đã làm đảo lộn nhiều quan điểm cũ về phát triển trí tuệ nhân tạo. Thay vì chạy đua nâng cấp số lượng tham số phần cứng thô, DeepSeek đã chứng minh một bước đi mang tính đột phá: Chắt lọc tri thức (Knowledge Distillation) từ các mô hình suy luận siêu lớn (Reasoning Models) có thể truyền lại khả năng lập luận đa bước (Chain of Thought - CoT) cho các mô hình nhỏ (SLMs) như Qwen hoặc Llama.
Nhờ kỹ thuật này, các phiên bản chắt lọc như DeepSeek-R1-Distill-Qwen-14B hay DeepSeek-R1-Distill-Llama-8B đạt điểm số suy luận toán học và lập trình vượt qua các mô hình gốc lớn hơn gấp nhiều lần.
Bài viết này sẽ đi sâu làm rõ cơ chế hoạt động của kỹ thuật chắt lọc tri thức lập luận, các công thức toán học đứng sau và cách thiết lập một pipeline Python để tự chưng cất tri thức từ DeepSeek-R1 sang Qwen Coder.
1. Phân Loại Các Phương Pháp Chắt Lọc Tri Thức (Knowledge Distillation)
Chắt lọc tri thức là kỹ thuật chuyển giao năng lực từ một mô hình lớn, thông minh (Teacher - Giáo viên) sang một mô hình nhỏ hơn, gọn nhẹ hơn (Student - Học sinh). Mục tiêu là làm sao Student có thể mô phỏng lại hành vi hoặc phân phối xác suất đầu ra của Teacher với sai số nhỏ nhất.
┌───────────────────────┐
│ Teacher (Large) │
│ e.g., DeepSeek-R1 │
└───────────┬───────────┘
│
[Tri Thức Chuyển Giao]
│
┌─────────┴─────────┐
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ Logits-Based │ │ Sequence-Level │
│ (Xác suất mềm) │ │ (CoT Reasoning) │
└────────┬─────────┘ └────────┬─────────┘
│ │
└─────────┬─────────┘
│
▼
┌───────────────────────┐
│ Student (Small) │
│ e.g., Qwen-Coder-7B │
└───────────────────────┘
Trong thực tế, có ba hướng tiếp cận chính:
1.1. Chắt lọc dựa trên Logits (Response-Based Distillation)
Student học trực tiếp từ xác suất phân phối của từ tiếp theo (next-token logits) mà Teacher sinh ra. Thay vì chỉ học nhãn cứng (Hard Label - từ đúng nhất), Student học cả nhãn mềm (Soft Label) chứa đựng mối tương quan sâu sắc giữa các từ.
- Công thức hàm mất mát (Loss Function): $$L_{\text{KD}} = (1 - \gamma) \cdot L_{\text{CE}}(y, p_s) + \gamma \cdot T^2 \cdot \text{KL}(p_t^{\tau}, p_s^{\tau})$$ Trong đó:
- $L_{\text{CE}}$ là hàm Cross-Entropy chuẩn giữa nhãn thực tế $y$ và phân phối của Student $p_s$.
- $\text{KL}$ là khoảng cách Kullback-Leibler đo độ lệch giữa phân phối xác suất mềm của Teacher $p_t^{\tau}$ và Student $p_s^{\tau}$.
- $T$ là tham số nhiệt độ (Temperature) dùng để làm phẳng phân phối xác suất (Softening logits).
1.2. Chắt lọc dựa trên Đặc Trưng (Feature-Based Distillation)
Student học cách mô phỏng trực tiếp các lớp ẩn (Hidden States) hoặc ma trận chú ý (Attention Maps) của Teacher. Phương pháp này rất phức tạp vì đòi hỏi cấu trúc chiều ẩn của Student phải được ánh xạ tương đương với Teacher thông qua các lớp chiếu tuyến tính (Projection Layers).
1.3. Chắt lọc mức chuỗi ngữ cảnh (Sequence-Level/CoT Distillation)
Đây là phương pháp tạo ra sự đột phá của DeepSeek-R1. Thay vì truyền các hàm phân phối xác suất phức tạp, chúng ta cho Teacher (DeepSeek-R1) giải hàng vạn bài toán phức tạp và lưu lại toàn bộ chuỗi lập luận suy nghĩ (Chain of Thought - CoT) nằm trong cặp thẻ <think> ... </think>. Sau đó, dùng tập dữ liệu CoT hoàn chỉnh này để thực hiện huấn luyện tinh chỉnh SFT truyền thống cho Student (Qwen/Llama).
- Ưu thế tuyệt đối: Rất dễ triển khai, không yêu cầu can thiệp sâu vào mã nguồn phân bổ GPU hoặc lấy logits từ API. Mô hình nhỏ sẽ tự học cách cấu trúc lập luận: đi từ phân tích bài toán, chia nhỏ bước giải, tự phát hiện lỗi sai, trước khi đưa ra đáp án cuối cùng.
2. Vì Sao Qwen 2.5 Coder Là Đối Tượng Lý Tưởng Cho Distillation?
Qwen 2.5 Coder (đặc biệt là phân khúc 7B và 14B) đã chứng minh năng lực lập trình và đọc hiểu cú pháp tuyệt vời nhờ tập dữ liệu pre-training khổng lồ về mã nguồn. Tuy nhiên, điểm yếu của Qwen Coder gốc là khả năng lập luận các thuật toán logic cấp cao hoặc giải thích thiết kế hệ thống đa chiều. Khi được nhúng tri thức suy luận CoT từ DeepSeek-R1, Qwen Coder sẽ kết hợp được cả hai sức mạnh: Cú pháp code chuẩn xác tuyệt đối và Tư duy thuật toán sâu sắc.
3. Thực Chiến: Xây Dựng Pipeline Tạo Dữ Liệu CoT Từ DeepSeek-R1
Để thực hiện Sequence-Level Distillation, chúng ta cần sinh tập dữ liệu huấn luyện CoT. Dưới đây là mã nguồn Python sử dụng thư viện httpx kết nối tới vLLM (hoặc API của DeepSeek) để sinh dữ liệu chắt lọc tự động từ một danh sách câu hỏi lập trình đầu vào:
import asyncio
import json
import httpx
from pydantic import BaseModel
# Cấu hình API endpoint (Trỏ tới vLLM chạy DeepSeek-R1 hoặc các nhà cung cấp API cloud)
API_URL = "https://api.deepseek.com/v1/chat/completions"
API_KEY = "your-api-key-here"
class CodeTask(BaseModel):
id: int
instruction: str
async def generate_cot_data(task: CodeTask, client: httpx.AsyncClient) -> dict:
prompt = f"""Hãy giải bài toán lập trình sau. Yêu cầu bắt buộc:
1. Viết toàn bộ quá trình phân tích logic, các hướng tiếp cận tiềm năng, phân tích độ phức tạp thời gian/bộ nhớ và các lỗi thường gặp trong quá trình giải.
2. Trình bày lời giải mã nguồn bằng Python ở cuối cùng.
Bài toán:
{task.instruction}"""
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": "deepseek-reasoning", # Chế độ DeepSeek-R1 trả về cả quá trình suy nghĩ
"messages": [
{"role": "user", "content": prompt}
],
"temperature": 0.6,
"max_tokens": 4096
}
try:
response = await client.post(API_URL, json=payload, headers=headers, timeout=120.0)
response_json = response.json()
# DeepSeek-R1 trả về chuỗi suy nghĩ qua trường 'reasoning_content' riêng biệt
choice = response_json["choices"][0]
message = choice["message"]
reasoning = message.get("reasoning_content", "")
content = message.get("content", "")
# Định dạng lại dữ liệu huấn luyện SFT CoT chuẩn
# Đóng gói suy nghĩ vào tag <think> để mô hình Student học đúng cấu trúc sinh tự nhiên
formatted_output = f"<think>\n{reasoning}\n</think>\n\n{content}"
return {
"instruction": task.instruction,
"output": formatted_output,
"id": task.id
}
except Exception as e:
# Lưu ý SEO/Reviewer: Trong môi trường production, hãy sử dụng thư viện `tenacity`
# để tự động retry khi API trả về lỗi 429 (Rate Limit) hoặc 500 thay vì chỉ log lỗi.
print(f"Error processing task {task.id}: {str(e)}")
return {
"instruction": task.instruction,
"output": None,
"id": task.id
}
async def main():
# Danh sách các bài toán lập trình thô cần chắt lọc lời giải
raw_tasks = [
{"id": 1, "instruction": "Viết hàm tìm chu kỳ của một danh sách liên kết đơn (Linked List Cycle)."},
{"id": 2, "instruction": "Thiết kế cấu trúc dữ liệu LRU Cache với độ phức tạp O(1) cho các thao tác get và put."},
{"id": 3, "instruction": "Tìm độ dài chuỗi con không lặp lại dài nhất trong một chuỗi cho trước (Longest Substring Without Repeating Characters)."}
]
tasks = [CodeTask(**t) for t in raw_tasks]
print(f"Starting distillation of {len(tasks)} tasks...")
limits = httpx.Limits(max_keepalive_connections=5, max_connections=10)
async with httpx.AsyncClient(limits=limits) as client:
# Chạy đồng thời các request để tối ưu tốc độ thu thập
jobs = [generate_cot_data(task, client) for task in tasks]
results = await asyncio.gather(*jobs)
# Loại bỏ các mẫu lỗi
cleaned_results = [r for r in results if r["output"] is not None]
# Lưu xuống tệp JSONL làm nguyên liệu cho quá trình huấn luyện SFT ở Phần 3
output_file = "deepseek_r1_distilled_cot.jsonl"
with open(output_file, "w", encoding="utf-8") as f:
for item in cleaned_results:
f.write(json.dumps(item, ensure_ascii=False) + "\n")
print(f"Successfully saved {len(cleaned_results)} distilled samples to {output_file}")
if __name__ == "__main__":
asyncio.run(main())
4. Tầm Quan Trọng Của Định Dạng Thẻ <think> ... </think>
Khi huấn luyện mô hình chắt lọc, việc giữ nguyên định dạng phân tách giữa Quá trình suy nghĩ (Reasoning) và Kết quả cuối cùng (Answer) là yếu tố sống còn:
- Ngăn chặn sự xáo trộn đặc trưng: Giúp mô hình Student phân định rõ ràng thời điểm nào nó đang thực hiện lập luận phân tích bài toán (hoàn toàn tự do, không cần ép khuôn đầu ra) và thời điểm nào nó phải tuân thủ nghiêm ngặt cú pháp định dạng của kết quả (ví dụ định dạng JSON hoặc mã nguồn lập trình sạch).
- Căn chỉnh hành vi thế hệ tiếp theo: Trong bài viết tiếp theo, chúng ta sẽ học cách tối ưu hóa cấu trúc này thông qua học tăng cường (Reinforcement Learning), ép mô hình phải suy nghĩ lâu hơn để tăng độ chính xác của câu trả lời.
Kế Hoạch Cho Bài Viết Tiếp Theo
Sau khi hoàn tất chắt lọc dữ liệu CoT và thực hiện SFT cho mô hình học sinh, chúng ta sẽ nhận thấy một giới hạn mới: Mô hình học sinh có xu hướng “bắt chước” văn phong nhưng chưa thực sự hiểu đúng bản chất thế nào là một lập luận chuẩn xác, dẫn đến việc sinh ra các chuỗi suy nghĩ dài dòng nhưng kết quả cuối cùng vẫn sai.
Để giải quyết triệt để vấn đề này, chúng ta cần bước vào pha tối thượng của tối ưu hóa mô hình: Preference Alignment (Căn chỉnh hành vi).
Trong Phần 5: Căn Chỉnh Hành Vi (Preference Alignment), chúng ta sẽ cùng nghiên cứu các thuật toán căn chỉnh DPO, KTO và đặc biệt là thuật toán đột phá GRPO (Group Relative Policy Optimization) không cần mô hình Critic giúp tối ưu hóa trực tiếp logic toán học của SLM với chi phí tiết kiệm.