Tối ưu chi phí token khi gọi API LLM: 12 kỹ thuật giảm 50–80% hoá đơn

Mười hai kỹ thuật thực chiến để giảm chi phí API LLM: đo token theo tính năng, định tuyến theo tầng, đặt max_tokens, cắt ngữ cảnh, prompt caching, RAG, gộp lô, cache kết quả và kiểm soát vòng lặp thử lại.

Tối ưu chi phí token khi gọi API LLM: 12 kỹ thuật giảm 50–80% hoá đơn

Hoá đơn API tăng gấp mười trong một tháng hiếm khi do lượng người dùng tăng gấp mười. Gần như luôn có vài chỗ rò rỉ âm thầm: ngữ cảnh gửi lại quá nhiều, model chọn quá mạnh cho việc quá nhẹ, hoặc một vòng lặp thử lại không ai kiểm soát. Bài này liệt kê mười hai kỹ thuật cụ thể, xếp theo mức độ hiệu quả, kèm cách đo để biết kỹ thuật nào thực sự có tác dụng với hệ thống của bạn.

1. Trước hết: hiểu token thực sự là gì

Model không đọc ký tự, nó đọc token — những mảnh văn bản dài khoảng ba đến bốn ký tự với tiếng Anh. Tiếng Việt có dấu tốn token hơn đáng kể, thường gấp rưỡi đến gấp đôi so với cùng nội dung tiếng Anh, vì bộ mã hoá phải tách dấu thanh thành đơn vị riêng.

Điều quan trọng hơn: token đầu ra đắt hơn token đầu vào nhiều lần, thường là ba đến năm lần tuỳ model. Hệ quả thực tế rất trái trực giác — một prompt dài 2.000 token kèm câu trả lời 100 token thường rẻ hơn một prompt 200 token kèm câu trả lời 1.000 token.

Muốn giảm hoá đơn, hãy nhìn vào độ dài câu trả lời trước khi cắt gọt prompt.

2. Đo trước khi tối ưu

Mọi phản hồi từ API đều kèm khối usage với số token đầu vào và đầu ra. Hãy ghi lại nó cùng với tên tính năng trong sản phẩm của bạn:

r = client.chat.completions.create(...)
u = r.usage
log.info("feature=%s model=%s in=%d out=%d",
         "tom_tat_email", r.model, u.prompt_tokens, u.completion_tokens)

Sau một tuần, bạn sẽ có bảng chi phí theo tính năng. Kinh nghiệm chung: thường có một hoặc hai tính năng chiếm trên 70% hoá đơn, và chúng hiếm khi là tính năng bạn đoán. Bảng điều khiển của TaiKhoanGiaRe cũng hiển thị chi phí từng lượt gọi kèm model, nên bạn đối chiếu được hai nguồn.

3. Chọn model theo độ khó thật của tác vụ

Đây là đòn bẩy lớn nhất, bỏ xa mọi kỹ thuật còn lại. Chênh lệch giá giữa model cao cấp và model flash có thể lên tới vài chục lần.

Tác vụModel nên dùngGhi chú
Phân loại, gắn nhãn, phát hiện ngôn ngữFlash / miniĐầu ra vài token, không cần suy luận sâu
Trích xuất trường từ văn bản có cấu trúcFlash / miniKèm JSON schema để giữ độ chính xác
Viết nội dung marketing, emailTầm trungChất lượng câu chữ mới là thứ khách hàng thấy
Trả lời hỗ trợ kỹ thuậtTầm trung + RAGTri thức đến từ tài liệu, không từ model
Viết và sửa code nhiều fileCao cấpSai một dòng tốn nhiều giờ của người

Cách làm an toàn: xây dựng bằng model mạnh cho tới khi kết quả đúng, sau đó hạ dần và so sánh trên cùng một bộ ví dụ. Rất thường xuyên, 70–80% lượt gọi có thể chuyển sang model rẻ mà không ai nhận ra.

4. Định tuyến theo tầng

Không cần chọn một model cho toàn hệ thống. Hãy để model rẻ xử lý trước, chỉ chuyển lên model đắt khi cần:

def tra_loi(cau_hoi):
    nhan = phan_loai(cau_hoi, model="flash")      # rẻ, vài token
    if nhan in ("chao_hoi", "cau_hoi_thuong_gap"):
        return tra_loi_co_san(nhan)               # không gọi model
    if nhan == "don_gian":
        return goi(cau_hoi, model="flash")
    return goi(cau_hoi, model="sonnet")           # chỉ khi thật cần

Trong một chatbot hỗ trợ thực tế, lớp phân loại và câu trả lời soạn sẵn thường bắt được 30–50% lưu lượng mà không tốn một token sinh nào.

5. Luôn đặt max_tokens

Nếu không giới hạn, model tự quyết định độ dài, và nó thường viết dài hơn bạn cần. Đặt trần theo đúng nhu cầu thực tế của từng tính năng:

r = client.chat.completions.create(
    model="...", messages=[...],
    max_tokens=200,        # tiêu đề, tóm tắt ngắn
)

Kết hợp với chỉ dẫn rõ ràng trong prompt: "Trả lời trong tối đa ba câu, không mở bài, không kết luận." Chỉ riêng việc cấm phần mở bài và kết luận xã giao đã cắt được 20–30% token đầu ra trong nhiều trường hợp.

6. Đừng gửi lại toàn bộ lịch sử hội thoại

Hội thoại là chi phí tăng theo bình phương: mỗi lượt mới gửi lại tất cả các lượt cũ. Sau ba mươi lượt, phần lớn hoá đơn là tiền trả cho việc đọc lại chính mình.

Ba cách xử lý, từ đơn giản đến tinh vi:

7. Tận dụng prompt caching

Nhiều model hỗ trợ lưu tạm phần đầu prompt. Nếu prompt hệ thống, tài liệu tham chiếu hoặc định nghĩa công cụ của bạn không đổi giữa các lượt gọi, phần đó có thể được tính giá thấp hơn nhiều khi trúng cache.

Điều kiện để tận dụng: phần bất biến phải nằm ở đầu và phải giống hệt nhau đến từng ký tự. Chỉ cần chèn dấu thời gian hay tên người dùng vào đầu prompt là toàn bộ lợi ích biến mất. Hãy xếp thứ tự: prompt hệ thống → tài liệu cố định → công cụ → phần thay đổi theo người dùng.

8. RAG thay vì nhồi tài liệu

Dán trọn một tài liệu 50 trang vào mỗi prompt là cách tốn kém nhất để trả lời một câu hỏi chỉ liên quan đến hai đoạn văn.

Quy trình RAG cơ bản: chia tài liệu thành đoạn, tạo embedding, lưu vào cơ sở dữ liệu vector, và mỗi câu hỏi chỉ lấy ba đến năm đoạn liên quan nhất. Chi phí giảm thường theo bậc độ lớn, và chất lượng câu trả lời tăng vì model không bị nhiễu bởi phần không liên quan.

9. Gộp nhiều mục vào một lượt gọi

Khi cần phân loại một nghìn bình luận, gọi một nghìn lần nghĩa là trả tiền cho prompt hệ thống một nghìn lần. Hãy gộp:

prompt = "Phân loại từng bình luận thành tích cực / trung tính / tiêu cực.\n"
prompt += "Trả về JSON: [{\"id\":1,\"nhan\":\"...\"}]\n\n"
for i, c in enumerate(lo_20_binh_luan, 1):
    prompt += f"{i}. {c}\n"

Gộp hai mươi mục một lượt thường tiết kiệm 60–80% so với gọi lẻ. Đừng gộp quá lớn: lô càng dài, model càng dễ bỏ sót mục ở giữa. Hai mươi đến năm mươi mục là khoảng an toàn.

10. Streaming để không trả tiền cho phần bị bỏ

Với giao diện chat, streaming cho phép người dùng dừng khi đã thấy đủ. Nếu bạn ngắt kết nối sớm, phần token chưa sinh sẽ không bị tính. Ngoài lợi ích chi phí, nó còn cải thiện cảm nhận về tốc độ rõ rệt.

11. Ép định dạng đầu ra ngắn gọn

Khi bạn cần dữ liệu chứ không cần văn xuôi, hãy yêu cầu đúng dữ liệu. So sánh hai cách:

# Tốn kém: "Hãy phân tích và giải thích cảm xúc của bình luận này"
# → 150 token văn xuôi

# Tiết kiệm: "Trả về đúng một từ: tich_cuc, trung_tinh hoặc tieu_cuc"
# → 3 token

Nếu model hỗ trợ JSON schema hoặc chế độ structured output, dùng nó: vừa ngắn, vừa loại bỏ phần hậu xử lý dễ vỡ bằng biểu thức chính quy.

12. Kiểm soát vòng lặp thử lại

Một tác nhân tự động gặp lỗi rồi thử lại không giới hạn là cách nhanh nhất để tiêu hết số dư trong một đêm. Ba rào chắn tối thiểu:

13. Lưu lại kết quả đã tính

Rất nhiều câu hỏi lặp lại y hệt nhau. Một bộ nhớ đệm đơn giản với khoá là hàm băm của prompt cộng tên model có thể loại bỏ phần lớn lượt gọi trùng:

key = hashlib.sha256((model + prompt).encode()).hexdigest()
if (v := cache.get(key)):
    return v
v = goi_api(model, prompt)
cache.set(key, v, ttl=86400)

Kỹ thuật này đặc biệt hiệu quả với dịch thuật, tóm tắt tài liệu tĩnh và các câu hỏi thường gặp.

14. Thứ tự nên làm

  1. Ghi log token theo tính năng trong một tuần. Không có dữ liệu thì mọi tối ưu chỉ là phỏng đoán.
  2. Hạ model cho tính năng tốn nhất. Đây thường là 80% mức tiết kiệm với 20% công sức.
  3. Đặt max_tokens và cấm phần mở bài, kết luận thừa.
  4. Cắt ngữ cảnh hội thoại bằng cửa sổ trượt hoặc tóm tắt có cấu trúc.
  5. Thêm bộ nhớ đệm cho các lượt gọi lặp.
  6. Chuyển sang RAG nếu bạn đang nhồi tài liệu dài vào prompt.
  7. Rà lại toàn bộ vòng lặp thử lại và đặt trần chi tiêu.

Làm hết bảy bước trên, mức giảm 50–80% là hoàn toàn khả thi mà chất lượng đầu ra không đổi. Cộng thêm việc dùng một cổng API tính riêng giá cache và tự giữ cache ấm giữa các lượt, khoảng cách giữa chi phí ban đầu và chi phí sau tối ưu có thể là vài lần.

Dùng thử API TaiKhoanGiaRe

Tạo tài khoản, nhận 50 credit miễn phí và lấy API key dùng được ngay cho Claude, GPT, Gemini, tạo ảnh, video và giọng nói.

Lấy API key miễn phí Xem bảng giá

← Về trang Blog