Khắc phục sự cốHướng dẫn
Câu trả lời AI bị cắt? Sửa finish_reason "length" và max_tokens
Câu trả lời API của bạn dừng giữa câu hoặc trả về JSON hỏng? Kiểm tra finish_reason, tăng max_tokens trong giới hạn và thêm bước tiếp tục.

Trên trang này
Script của bạn đã chạy, model đã trả lời, và hàm kết thúc giữa một dòng. Hoặc trình phân tích JSON ném lỗi trên một phản hồi trông hoàn toàn bình thường. Thường thì model không hề lỗi: nó đã chạm giới hạn max_tokens bạn đặt (hoặc một giá trị mặc định bạn không hề thấy) và API đã dừng nó giữa từ.
Cách sửa nhanh: đọc finish_reason trong phản hồi. Nếu nó là "length" (API tương thích OpenAI) hoặc stop_reason là "max_tokens" (Anthropic Messages), câu trả lời đã bị cắt. Hãy tăng max_tokens lên tới giới hạn đầu ra của model, hoặc yêu cầu model tiếp tục. Phần còn lại của trang này trình bày cả hai bằng mã bạn có thể dán vào.
Nếu bạn muốn phiên bản dễ hiểu về lý do điều này xảy ra, hãy bắt đầu với vì sao câu trả lời của AI dừng giữa câu. Trang này là phiên bản gỡ lỗi.
Câu trả lời bị cắt trông thế nào trên màn hình#
Triệu chứng khác nhau tùy theo thứ bạn yêu cầu, nhưng nguyên nhân thì giống nhau. Hãy thử đối chiếu những điều sau với những gì bạn đã thấy:
Ghép cặp
Đối chiếu triệu chứng với nguyên nhân khả dĩ
Nhấn vào một mục bên trái, rồi đến cặp của nó
- Một hàm kết thúc bằng
return resuCâu trả lời mã đã chạm max_tokens giữa dòng json.loadslỗi với "Unterminated string" hoặc "Expecting ',' delimiter"JSON bị cắt giữa chừng- Một bản dịch dừng sau nửa đầu của văn bảnGiới hạn đầu ra nhỏ hơn bản dịch
- Phản hồi hoàn chỉnh và trường ghi
stopModel đã tự kết thúc; hãy tìm nguyên nhân ở chỗ khác
Dòng cuối cùng đó quan trọng. Nếu finish_reason là stop, giới hạn không phải vấn đề của bạn, và tăng max_tokens sẽ không thay đổi gì.
Bước 1: đọc trường cho bạn biết#
Mọi phản hồi đều cho biết vì sao quá trình sinh kết thúc. Trong phản hồi tương thích OpenAI đó là choices[0].: "stop" khi model hoàn tất, "length" khi nó hết token. Trong Anthropic Messages API trường này là stop_reason, và giá trị bị cắt là "max_tokens". Hướng dẫn stop-reason của Anthropic (kiểm tra ngày 28 tháng 10 năm 2026) khuyến nghị đúng hai cách sửa bên dưới: tăng max_tokens hoặc tiếp tục phản hồi.
Đây là cùng một phép kiểm tra ở ba dạng. Base URL là https:/ cho OpenAI SDK và https:/ (không có /v1) cho Anthropic SDK. max_tokens=200 được cố ý đặt nhỏ, để bạn tự thấy việc bị cắt.
Một phép kiểm tra, ba cách
Python (OpenAI SDK)
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.cheaptokens.dev/v1",
api_key=os.environ["CHEAPTOKENS_API_KEY"],
)
resp = client.chat.completions.create(
model="deepseek-ai/DeepSeek-V4-Flash-0731",
max_tokens=200,
messages=[{"role": "user", "content": "Write a Python class for a todo list with tests."}],
)
choice = resp.choices[0]
if choice.finish_reason == "length":
print("Cut off at the token limit")
print(choice.message.content)
print(resp.usage.completion_tokens)Python (Anthropic SDK)
import os
import anthropic
client = anthropic.Anthropic(
base_url="https://api.cheaptokens.dev",
api_key=os.environ["CHEAPTOKENS_API_KEY"],
)
msg = client.messages.create(
model="deepseek-ai/DeepSeek-V4-Flash-0731",
max_tokens=200,
messages=[{"role": "user", "content": "Write a Python class for a todo list with tests."}],
)
if msg.stop_reason == "max_tokens":
print("Cut off at the token limit")
print(msg.content[0].text)curl
curl https://api.cheaptokens.dev/v1/chat/completions \
-H "Authorization: Bearer $CHEAPTOKENS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-ai/DeepSeek-V4-Flash-0731",
"max_tokens": 200,
"messages": [{"role": "user", "content": "Write a Python class for a todo list with tests."}]
}'Hãy tìm "finish_ trong JSON trả về.
Khi nó hoạt động như một phép chẩn đoán, bạn sẽ thấy cặp này: giới hạn thấp cho length, giới hạn rộng rãi cho stop.

Bước 2: tăng max_tokens, nhưng không vượt trần#
Cách sửa hiển nhiên là một con số lớn hơn. Vấn đề: mỗi model có mức trần riêng cho câu trả lời. Đừng đặt giá trị vượt quá nó: giới hạn là theo từng model, nên hãy xem bảng bên dưới trước. Đây là các giới hạn theo từng câu trả lời trên CheapTokens (số liệu kiểm tra ngày 28 tháng 10 năm 2026):
Cuộn bảng sang phải →
| Model | Đầu ra tối đa mỗi câu trả lời | Ngữ cảnh |
|---|---|---|
| DeepSeek-V4-Flash | 32.768 token | 380K |
| GLM-5.3-Flash | 8.192 token | 390K |
| MiniMax-M2.7 | 8.192 token | 180K |
Một bản dịch 9.000 token cần một model có giới hạn mỗi câu trả lời lớn hơn — DeepSeek-V4-Flash nhận tới 32.768 token mỗi câu trả lời. Với mã dài, JSON dài hoặc cả một tài liệu, deepseek- có nhiều chỗ nhất: tới 32.768 token mỗi câu trả lời, một mức giá vào mọi giờ trong ngày. Hãy lấy id model chính xác từ tài liệu CheapTokens và trang models, vì các nhà cung cấp đặt tên khác nhau.
Một quy tắc thực tế: đặt max_tokens bằng câu trả lời dài nhất bạn sẽ chấp nhận, không phải bằng mức tối đa. Bạn trả tiền cho các token model thực sự viết ra, nên một trần cao không tốn gì khi câu trả lời ngắn.
Bước 3: JSON dừng giữa chừng#
Một phản hồi JSON bị cắt là trường hợp khó chịu nhất, vì văn bản trông đúng cho tới khi trình phân tích chạm tới cuối. Giả sử bạn trích xuất các trường từ 40 hóa đơn trong một lần gọi và yêu cầu một mảng. Model viết 31 đối tượng, chạm giới hạn, và mảng không bao giờ đóng lại.

Đừng cố sửa chuỗi bằng cách thêm ]}. Bạn sẽ nhận được JSON hợp lệ nhưng thiếu bản ghi, điều này còn tệ hơn một lỗi. Hãy kiểm tra finish_reason trước; nếu nó là length, hãy tăng giới hạn và chạy lại lần gọi, hoặc chia đầu vào thành các lô nhỏ hơn. Để ép buộc chính định dạng, xem JSON hợp lệ từ một LLM API.
Bước 4: để model tiếp tục#
Đôi khi câu trả lời thực sự dài hơn mọi giới hạn: một chương sách, một lần tái cấu trúc lớn. Khi đó hãy đưa những gì bạn đã có trở lại và yêu cầu model đi tiếp. Vòng lặp bên dưới giữ phần văn bản đã có, yêu cầu phần còn lại, và bỏ cuộc sau vài vòng để một lỗi không thể quay vô hạn.
def complete(base_messages, model, max_tokens=4096, rounds=4):
text = ""
for _ in range(rounds):
messages = list(base_messages)
if text:
messages += [
{"role": "assistant", "content": text},
{"role": "user", "content": "Continue exactly where you stopped. Do not repeat anything."},
]
r = client.chat.completions.create(model=model, max_tokens=max_tokens, messages=messages)
choice = r.choices[0]
text += choice.message.content or ""
if choice.finish_reason != "length":
return text, True # finished on its own
return text, False # still cut after all roundsHai thói quen giữ cho việc này trung thực. Trả về cờ True/False và hiển thị cho người dùng một cảnh báo khi False, thay vì trình bày nửa tài liệu như đã xong. Và hãy nhớ rằng mỗi vòng gửi lại văn bản trước đó làm đầu vào, nên một câu trả lời được tiếp tục tốn kém hơn một câu trả lời lớn. Với dữ liệu có cấu trúc, hãy ưu tiên giới hạn lớn hơn hoặc lô nhỏ hơn thay vì tiếp tục.
Một câu trả lời dài tốn bao nhiêu#
Giả sử một câu trả lời dài là 2.000 token vào và 8.000 token ra. Trên DeepSeek-V4-Flash, yêu cầu đó tốn $0.00083 theo giá hôm nay, và tổng cộng, khi tính cả đầu vào và đầu ra, nó rẻ hơn OpenRouter. Hãy thay các con số bằng tải của riêng bạn:
Máy tính chi phí
Một ngày với 50 câu trả lời dài
Token đầu vào mỗi yêu cầu: 2.000 · Token đầu ra mỗi yêu cầu: 8.000 · Số yêu cầu mỗi ngày: 50
| Mô hình | Mỗi ngày | Mỗi tháng |
|---|---|---|
| GLM-5.3-Flash$0.02$0.04 | $0.018 | $0.54 |
| DeepSeek-V4-Flash$0.015$0.10 | $0.0415 | $1.25 |
| MiniMax-M2.7$0.05$0.15 | $0.065 | $1.95 |
Điều rút ra: phía đầu ra chiếm ưu thế trong tình huống này, nên dư địa trong max_tokens là bảo hiểm rẻ để tránh phải chạy lại. Một câu trả lời bị cắt mà bạn phải tạo lại thì bị trả tiền hai lần. Thông tin nền về hai phía của hóa đơn có trong token đầu vào so với đầu ra, và danh sách model đầy đủ kèm giá nằm trên trang giá.
Trước khi phát hành: một danh sách kiểm tra ngắn#
Danh sách kiểm tra
Danh sách kiểm tra cắt cụt cho mã của bạn



