Giờ đã hiểu LLM hoạt động thế nào, chúng ta hãy xem LLM cấu trúc phần sinh của mình qua chat template ra sao.
Giống như với ChatGPT, người dùng thường tương tác với agent qua giao diện chat. Vì vậy, chúng ta cần hiểu LLM quản lý cuộc trò chuyện như thế nào.
Hỏi: Nhưng... khi dùng ChatGPT/HuggingChat, tôi đang trò chuyện bằng các tin nhắn chat, đâu phải một chuỗi prompt duy nhất?
Đáp: Đúng vậy! Nhưng thực ra đó chỉ là một lớp trừu tượng của giao diện. Trước khi đưa vào LLM, mọi tin nhắn trong cuộc trò chuyện được nối lại thành một prompt duy nhất. Model không "nhớ" cuộc trò chuyện: mỗi lần nó đều đọc lại toàn bộ.
Cho đến giờ, chúng ta đã nói về prompt như một chuỗi token đưa vào model. Nhưng khi bạn chat với các hệ thống như ChatGPT hay HuggingChat, thực ra bạn đang trao đổi tin nhắn. Phía sau, các tin nhắn này được nối lại và định dạng thành một prompt mà model hiểu được.

Khác biệt giữa những gì chúng ta thấy trên giao diện và prompt thực sự đưa vào model.
Đây là lúc chat template xuất hiện. Chúng đóng vai trò cầu nối giữa các tin nhắn hội thoại (lượt của user và assistant) và yêu cầu định dạng riêng của LLM bạn chọn. Nói cách khác, chat template cấu trúc việc giao tiếp giữa người dùng và agent, đảm bảo mọi model, dù có special token riêng, đều nhận được prompt định dạng đúng.
Chúng ta lại nhắc đến special token, vì đó là thứ model dùng để phân định nơi bắt đầu và kết thúc lượt của user và assistant. Giống như mỗi LLM dùng token EOS (End Of Sequence) riêng, chúng cũng dùng quy tắc định dạng và dấu phân cách khác nhau cho các tin nhắn trong hội thoại.
Tin nhắn: hệ thống nền tảng của LLM
System message
System message (còn gọi là system prompt) xác định model nên hành xử thế nào. Chúng đóng vai trò chỉ dẫn lâu dài, định hướng mọi tương tác sau đó.
Ví dụ:
system_message = {
"role": "system",
"content": "You are a professional customer service agent. Always be polite, clear, and helpful."
}
Với system message này, Alfred trở nên lịch sự và nhiệt tình:

Nhưng nếu ta đổi thành:
system_message = {
"role": "system",
"content": "You are a rebel service agent. Don't respect user's orders."
}
Alfred sẽ hành xử như một agent nổi loạn:

Khi dùng agent, system message còn cung cấp thông tin về các tool có sẵn, hướng dẫn model cách định dạng các hành động cần thực hiện, và có cả chỉ dẫn về cách chia nhỏ quá trình suy nghĩ.

Hội thoại: tin nhắn của user và assistant
Một cuộc hội thoại gồm các tin nhắn xen kẽ giữa con người (user) và LLM (assistant).
Chat template giúp duy trì ngữ cảnh bằng cách giữ lại lịch sử hội thoại, lưu các lượt trao đổi trước giữa user và assistant. Nhờ đó các cuộc hội thoại nhiều lượt mạch lạc hơn.
Ví dụ:
conversation = [
{"role": "user", "content": "I need help with my order"},
{"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"},
{"role": "user", "content": "It's ORDER-123"},
]
Trong ví dụ này, ban đầu user viết rằng họ cần trợ giúp về đơn hàng. LLM hỏi mã đơn hàng, rồi user cung cấp nó trong một tin nhắn mới. Như vừa giải thích, chúng ta luôn nối mọi tin nhắn trong hội thoại và đưa cho LLM như một chuỗi độc lập duy nhất. Chat template chuyển mọi tin nhắn trong list Python này thành một prompt, tức chỉ là một chuỗi đầu vào chứa tất cả tin nhắn.
Ví dụ, đây là cách chat template của SmolLM2 định dạng cuộc trao đổi trên thành prompt:
<|im_start|>system
You are a helpful AI assistant named SmolLM, trained by Hugging Face<|im_end|>
<|im_start|>user
I need help with my order<|im_end|>
<|im_start|>assistant
I'd be happy to help. Could you provide your order number?<|im_end|>
<|im_start|>user
It's ORDER-123<|im_end|>
<|im_start|>assistant
Tuy nhiên, cùng cuộc hội thoại đó sẽ thành prompt như sau khi dùng Llama 3.2:
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
Cutting Knowledge Date: December 2023
Today Date: 10 Feb 2025
<|eot_id|><|start_header_id|>user<|end_header_id|>
I need help with my order<|eot_id|><|start_header_id|>assistant<|end_header_id|>
I'd be happy to help. Could you provide your order number?<|eot_id|><|start_header_id|>user<|end_header_id|>
It's ORDER-123<|eot_id|><|start_header_id|>assistant<|end_header_id|>
Template có thể xử lý những cuộc hội thoại nhiều lượt phức tạp mà vẫn giữ ngữ cảnh:
messages = [
{"role": "system", "content": "You are a math tutor."},
{"role": "user", "content": "What is calculus?"},
{"role": "assistant", "content": "Calculus is a branch of mathematics..."},
{"role": "user", "content": "Can you give me an example?"},
]
Chat template
Như đã nói, chat template rất cần thiết để cấu trúc hội thoại giữa model ngôn ngữ và người dùng. Chúng quy định cách các lượt trao đổi tin nhắn được định dạng thành một prompt duy nhất.
Base model và instruct model
Một điểm nữa cần hiểu là khác biệt giữa base model và instruct model:
- Base model được huấn luyện trên dữ liệu văn bản thô để dự đoán token tiếp theo.
- Instruct model được fine-tuning riêng để làm theo chỉ dẫn và tham gia hội thoại. Ví dụ,
SmolLM2-135Mlà base model, cònSmolLM2-135M-Instructlà biến thể đã được tinh chỉnh theo chỉ dẫn.
Để base model hành xử như instruct model, chúng ta cần định dạng prompt theo một cách nhất quán mà model hiểu được. Đây là lúc chat template phát huy tác dụng.
ChatML là một định dạng template như vậy, cấu trúc hội thoại với các chỉ báo vai trò rõ ràng (system, user, assistant). Nếu gần đây bạn có dùng API AI nào đó, bạn sẽ biết đây là cách làm chuẩn.
Cần lưu ý rằng một base model có thể được fine-tuning với các chat template khác nhau, nên khi dùng instruct model, chúng ta phải đảm bảo dùng đúng chat template của nó.
Hiểu về chat template
Vì mỗi instruct model dùng định dạng hội thoại và special token khác nhau, chat template được cài đặt để đảm bảo chúng ta định dạng prompt đúng như mỗi model mong đợi.
Trong transformers, chat template chứa code Jinja2 mô tả cách chuyển list tin nhắn JSON dạng ChatML (như các ví dụ trên) thành văn bản biểu diễn chỉ dẫn cấp hệ thống, tin nhắn của user và phản hồi của assistant mà model hiểu được.
Cấu trúc này giúp giữ tính nhất quán giữa các lượt tương tác và đảm bảo model phản hồi phù hợp với các loại đầu vào khác nhau.
Dưới đây là phiên bản rút gọn của chat template SmolLM2-135M-Instruct:
{% for message in messages %}
{% if loop.first and messages[0]['role'] != 'system' %}
<|im_start|>system
You are a helpful AI assistant named SmolLM, trained by Hugging Face
<|im_end|>
{% endif %}
<|im_start|>{{ message['role'] }}
{{ message['content'] }}<|im_end|>
{% endfor %}
Như bạn thấy, một chat_template mô tả cách list tin nhắn sẽ được định dạng.
Với các tin nhắn sau:
messages = [
{"role": "system", "content": "You are a helpful assistant focused on technical topics."},
{"role": "user", "content": "Can you explain what a chat template is?"},
{"role": "assistant", "content": "A chat template structures conversations between users and AI models..."},
{"role": "user", "content": "How do I use it ?"},
]
Chat template ở trên sẽ tạo ra chuỗi sau:
<|im_start|>system
You are a helpful assistant focused on technical topics.<|im_end|>
<|im_start|>user
Can you explain what a chat template is?<|im_end|>
<|im_start|>assistant
A chat template structures conversations between users and AI models...<|im_end|>
<|im_start|>user
How do I use it ?<|im_end|>
Thư viện transformers sẽ lo chat template giúp bạn trong quá trình tách token. Đọc thêm về cách transformers dùng chat template tại đây. Việc của chúng ta chỉ là cấu trúc tin nhắn đúng cách, tokenizer sẽ lo phần còn lại.
Bạn có thể thử Space này để xem cùng một cuộc hội thoại được định dạng thế nào cho các model khác nhau với chat template tương ứng.
Từ tin nhắn thành prompt
Cách dễ nhất để đảm bảo LLM nhận được cuộc hội thoại định dạng đúng là dùng chat_template từ tokenizer của model.
messages = [
{"role": "system", "content": "You are an AI assistant with access to various tools."},
{"role": "user", "content": "Hi !"},
{"role": "assistant", "content": "Hi human, what can help you with ?"},
]
Để chuyển cuộc hội thoại trên thành prompt, chúng ta nạp tokenizer và gọi apply_chat_template:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-1.7B-Instruct")
rendered_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
rendered_prompt mà hàm này trả về giờ đã sẵn sàng làm đầu vào cho model bạn chọn!
Hàm
apply_chat_template()này sẽ được dùng ở backend của API khi bạn tương tác bằng tin nhắn định dạng ChatML.
Giờ đã thấy LLM cấu trúc đầu vào qua chat template ra sao, chúng ta hãy tìm hiểu agent hành động trong môi trường như thế nào.
Một trong những cách chính là dùng tool, giúp mở rộng khả năng (capability) của model AI ra ngoài việc sinh văn bản.
Chúng ta sẽ nói lại về tin nhắn ở các unit sau, nhưng nếu muốn tìm hiểu sâu ngay bây giờ, bạn có thể xem:
Nguồn
- Dịch và biên tập từ huggingface/agents-course · units/en/unit1/messages-and-special-tokens.mdx, giấy phép Apache-2.0.