- Có thể giới hạn phản hồi của mô hình cục bộ theo JSON Schema, giúp giảm gánh nặng phân tích cú pháp hậu xử lý và làm cho kết quả trích xuất dữ liệu nhất quán hơn
- Người dùng truyền schema vào tham số
format trong cURL, Python, JavaScript để yêu cầu đầu ra có cấu trúc theo cùng một cách
- Với Python có thể dùng cùng Pydantic, còn JavaScript dùng cùng Zod để dễ liên kết định nghĩa schema và xác thực phản hồi ở cấp mã
- Các ví dụ trả về và xác thực thông tin quốc gia, văn bản về thú cưng, kết quả phân tích hình ảnh bằng
llama3.2-vision dưới dạng các trường JSON đã định
- Nếu cần kết quả ổn định, khuyến nghị thêm “return as JSON” vào prompt và đặt temperature về 0
Giới hạn phản hồi của mô hình bằng JSON Schema
- Ollama hỗ trợ đầu ra có cấu trúc, giới hạn đầu ra của mô hình tuân theo một định dạng JSON Schema cụ thể
- Các thư viện Python và JavaScript của Ollama cũng đã được cập nhật để hỗ trợ đầu ra có cấu trúc
- Tính năng này có thể được dùng cho các tác vụ sau
- Phân tích cú pháp dữ liệu từ tài liệu
- Trích xuất dữ liệu từ hình ảnh
- Cấu trúc hóa phản hồi của mô hình ngôn ngữ
- Đạt độ tin cậy và tính nhất quán cao hơn JSON mode
Cài đặt và cách gọi
- Cần tải phiên bản mới nhất của Ollama
- Cập nhật thư viện Python lên phiên bản mới nhất bằng lệnh sau
pip install -U ollama
- Cài đặt thư viện JavaScript bằng lệnh sau
npm i ollama
- Khi yêu cầu đầu ra có cấu trúc, truyền schema vào tham số
format trong yêu cầu cURL hoặc trong thư viện Python·JavaScript
Truyền JSON Schema bằng cURL
- Ví dụ cURL gửi yêu cầu tới
http://localhost:11434/api/chat, đặt model là llama3.1 và stream là false
- Trong
format, đưa vào schema đối tượng có name, capital, languages
name: chuỗi
capital: chuỗi
languages: mảng chuỗi
- Cả ba trường đều được chỉ định là
required
- Phản hồi được trả về theo định dạng JSON Schema có trong yêu cầu
{
"capital": "Ottawa",
"languages": [
"English",
"French"
],
"name": "Canada"
}
Sử dụng thư viện Python và JavaScript
-
Python
- Ollama Python library truyền schema dưới dạng đối tượng JSON vào tham số
format
- Schema có thể được truyền dưới dạng
dict; cách khuyến nghị là tuần tự hóa bằng model_json_schema() của Pydantic
- Ví dụ định nghĩa các trường
name, capital, languages trong mô hình Country, rồi xác thực phản hồi bằng Country.model_validate_json()
country = Country.model_validate_json(response.message.content)
- Kết quả ví dụ trả về
Canada, Ottawa, English, French khớp với các trường đã định nghĩa
-
JavaScript
- Ollama JavaScript library truyền schema dưới dạng đối tượng JSON vào tham số
format
- Schema có thể được truyền dưới dạng
object; cách khuyến nghị là dùng Zod và zodToJsonSchema()
- Ví dụ định nghĩa schema
Country bằng đối tượng Zod, sau đó JSON.parse() phần thân phản hồi và xác thực bằng Country.parse()
const country = Country.parse(JSON.parse(response.message.content));
Trích xuất dữ liệu từ văn bản và hình ảnh
-
Trích xuất văn bản về thú cưng
- Đầu ra có cấu trúc có thể được dùng để rút ra thông tin cần thiết từ văn bản
- Ví dụ định nghĩa các mô hình Pydantic
Pet và PetList để trả về thông tin thú cưng theo cấu trúc JSON
Pet: name, animal, age, color, favorite_toy
PetList: mảng pets
- Văn bản đầu vào chứa thông tin về hai con mèo
- Luna: 5 tuổi, lông màu xám, thích yarn
- Loki: 2 tuổi, màu đen, thích tennis balls
- Đầu ra được xác thực dưới dạng danh sách đối tượng
Pet theo schema đã định nghĩa
-
Mô tả hình ảnh bằng mô hình thị giác
- Đầu ra có cấu trúc có thể được dùng cùng mô hình thị giác
- Ví dụ phân tích hình ảnh bằng
llama3.2-vision và trả về kết quả theo schema ImageDescription
- Schema bao gồm các trường sau
summary
objects
scene
colors
time_of_day
setting
text_content
- Yêu cầu ví dụ chỉ thị phân tích đối tượng, cảnh, màu sắc và văn bản có thể phát hiện trong hình ảnh
- Trong tùy chọn, đặt
temperature về 0 để dùng đầu ra mang tính quyết định hơn
- Kết quả ví dụ tóm tắt cảnh cây cọ trên bãi biển, đồng thời trả về các đối tượng
tree và beach, màu sắc, thời điểm trong ngày và bối cảnh ngoài trời dưới dạng các trường có cấu trúc
Sử dụng API tương thích OpenAI
- Ví dụ tương thích OpenAI đặt client
OpenAI với base_url="http://localhost:11434/v1" và api_key="ollama"
- Dùng
client.beta.chat.completions.parse() để truyền mô hình Pydantic PetList vào response_format
- Kiểm tra
completion.choices[0].message trong phản hồi; nếu có parsed thì in kết quả đã phân tích cú pháp
- Nếu có
refusal thì in phản hồi từ chối, còn openai.LengthFinishReasonError được xử lý là trường hợp có quá nhiều token
Thiết lập đầu ra ổn định và kế hoạch tương lai
- Khuyến nghị dùng Pydantic của Python hoặc Zod của JavaScript để định nghĩa schema phản hồi
- Nên thêm “return as JSON” vào prompt để mô hình hiểu yêu cầu
- Nếu muốn đầu ra mang tính quyết định hơn, đặt temperature về 0
- Các kế hoạch trong tương lai gồm
- Phơi bày logits cho sinh có kiểm soát
- Cải thiện hiệu năng và độ chính xác của đầu ra có cấu trúc
- Tăng tốc GPU cho lấy mẫu
- Hỗ trợ thêm các định dạng vượt ngoài JSON Schema
1 bình luận
Các ý kiến trên Hacker News
Nếu cần ràng buộc đầu ra mạnh hơn, llama.cpp hỗ trợ GBNF
https://github.com/ggerganov/llama.cpp/blob/master/grammars/...
Nhìn đơn giản thì vì các mô hình đã thấy JSON nhiều hơn hẳn, nên tôi nghĩ chúng có lẽ tạo JSON tốt hơn các định dạng khác
Tin tốt
Tôi từng băn khoăn nên cấu trúc prompt thông thường thế nào khi tạo dữ liệu CSV để không bị kèm những câu thừa như "Here is your data" hay "Please note blah blah" ở đầu/cuối; giờ có thể định nghĩa chính xác định dạng trả về mong muốn và chuyển đầu ra có cấu trúc thẳng sang CSV, thật đáng mừng
Nếu không, đầu ra có thể đúng định dạng CSV về mặt kỹ thuật nhưng vô nghĩa. Có thể mô hình thực ra định viết câu trả lời dạng đoạn văn, nhưng token sampler lại chọn các token xác suất thấp mà mô hình không thật sự muốn nói
\n và cho dừng ởHoạt động được. Tôi đưa câu dưới đây vào gemma2:2b và nhận được JSON mong muốn
You have spent 190 at Fresh Mart. Current balance: 5098Kết quả là
{"amount": 190, "balance": 5098, "category": "Shopping", "place": "Fresh Mart"}Thật sự đáng kinh ngạc. Đây đúng là một trong những tính năng tôi từng muốn
Điểm hay của ollama là nó tạo cảm giác dùng LLM như một chương trình UNIX khác, khiến LLM có vẻ thuộc về UNIX một cách tự nhiên
Nhưng tôi tò mò có ai chạy tốt trên GPU AMD chưa. Nghe nói khó hơn, nhưng năm sau khi mua card tôi muốn ủng hộ đối thủ cạnh tranh
Tôi cấp 16GB bộ nhớ chia sẻ qua BIOS trên một mini PC có 780M và nó chạy khá ổn
Tôi tò mò các ràng buộc kiểu này ảnh hưởng thế nào đến chất lượng đầu ra của LLM
Trong một số trường hợp, nếu chất lượng đầu ra cao hơn thì tôi muốn chọn cách phân tích cú pháp Markdown hoặc văn bản thường
Lượt đầu dùng mô hình nặng và ngôn ngữ tự nhiên để xử lý suy luận trong các phần Markdown, rồi cung cấp câu trả lời cuối cùng bằng ngôn ngữ tự nhiên. Nếu có thể thì gắn nhãn rõ bằng header Markdown
Lượt thứ hai dùng mô hình rẻ hơn và nhanh hơn để chuyển câu trả lời đó sang định dạng đầu ra có cấu trúc, cho phần không phải LLM của pipeline tiêu thụ
Về cơ bản, dùng chế độ JSON schema để tạo ranh giới gọn gàng quanh các phần ngôn ngữ tự nhiên mơ hồ, và để LLM đóng vai trò bộ tiền xử lý nắm bắt chính đầu ra của nó ở một định dạng hữu ích
Ngoài ra phải cho mô hình biết schema. Nếu không, sẽ phát sinh nhiều vấn đề token hóa kỳ lạ hơn
Ví dụ, nếu schema kỳ vọng khóa JSON
"foobarbaz"và token hóa BPE chuẩn là["foobar", "baz"], thì token mask do các thư viện đầu ra ràng buộc hiện nay tạo ra có thể cho phép mô hình chọn giữa"f","foo","foobar". Nếu mô hình chọn"foo", ràng buộc sẽ ép token tiếp theo, chẳng hạn"bar"và"baz". Khi đó mô hình sẽ thấy["foo", "bar", "baz"]thay vì["foobar", "baz"], nên bị rối [0]Nếu trong prompt mô hình biết rằng
"foobarbaz"là một trong các khóa schema, thường nó sẽ ưu tiên"foobar"hơn"foo"[0] Ở các mô hình mới, do chuẩn hóa nên các token này có liên quan với nhau, nhưng không giống nhau
Phụ thuộc nhiều vào việc LLM và prompt vốn có khả năng tạo phản hồi JSON hay không. Càng ép LLM nhiều, khả năng tạo đầu vào bình thường càng thấp
Với các mô hình nhỏ, bạn sẽ chạm đến rìa của không gian còn có năng lực dự đoán có ý nghĩa nhanh hơn, và đầu ra bắt đầu gần giống nhiễu ngẫu nhiên
Đây không phải đo lường nghiêm ngặt, chỉ là cảm nhận sau khi dành nhiều thời gian cho nhiều dự án LLM. Tôi chưa dùng các công cụ cụ thể này, nhưng trước đây ollama cũng đã có thể đảm bảo đầu ra JSON bằng một cách có vẻ tương tự, và tôi từng cùng đối tác làm một thứ giống jsonformer cho oobabooga, một công cụ runtime LLM khác
Hy vọng nếu những thay đổi đó được đưa vào, việc sinh cấu trúc tổng quát không chỉ giới hạn ở JSON cũng có thể khả thi
Chúng dễ đốt nhiều token, nhưng nếu việc cần làm biện minh được cho chi phí đó thì có thể thúc khá mạnh. Dù không phải chất lượng tuyệt đối tốt nhất, một công cụ giúp đạt mức 95% mà không tốn công vẫn đủ đáng để có trong bộ công cụ
Tôi tò mò liệu có dùng được với bất kỳ mô hình nào được hỗ trợ không
Phần cứng của tôi chỉ chạy ổn định được các mô hình 1B~3B, nên tôi hỏi vậy
Với mô hình nhỏ, kết quả có thể thất thường, nhưng yêu cầu “trả về x dưới dạng JSON” thường giúp tăng độ chính xác
PR liên quan đến tính năng này đã mở gần 1 năm
Việc các maintainer quá im lặng thì hơi đáng tiếc
Hy vọng năm sau chúng tôi có thể chăm sóc và merge PR từ cộng đồng tốt hơn
Hiện vẫn đang dùng oobabooga. Nhờ hỗ trợ exlv2, việc suy luận trên dual 3090 hiệu quả hơn nhiều
Theo tôi nhớ thì dù exl2 nhanh hơn, đặc biệt ở độ sâu bit thấp, lượng tử hóa gptq có vẻ tốt hơn về độ chính xác
Tò mò không biết so với
outlinesthì có giá trị gia tăng gìhttps://www.souzatharsis.com/tamingLLMs/notebooks/structured...
Dựa trên các nghiên cứu gần đây liên quan đến outlines/xgrammar, hy vọng có thể cập nhật phần sampling để hỗ trợ nhiều định dạng hơn, tăng độ chính xác và cải thiện hiệu năng
Tò mò liệu có cách tốt nhất nào để cung cấp đầu vào có cấu trúc cho LLM không
Ví dụ như đưa vào 100 câu và yêu cầu phân loại từng câu theo nhiều cách. Nhận dữ liệu có cấu trúc thì dễ, nhưng cách của tôi là thêm số dòng ở đầu mỗi câu nên cảm thấy khá thô
Tuy nhiên trong trường hợp này, tốt nhất là đưa từng câu một để mô hình không bị nhầm lẫn
Nếu cấu trúc prompt theo dạng
"Hãy phân loại câu sau. Quy tắc là ..."+ câu, bạn có thể tận dụng prefix cache, nên hiệu năng cũng có thể tốt hơn so với hỏi tất cả cùng lúcTất nhiên đây là cách khả thi khi có prefix cache và không bị tính phí theo token đầu vào. Ngày nay hầu hết nhà cung cấp cho phép dùng với chi phí thấp hơn nếu bạn cho biết ý định sử dụng prefix cache