Vượt giới hạn max_tokens — Kỹ thuật tiếp nối response dài
Điểm nổi bật
Nhấn để đến mục tương ứng
- 1 Tận dụng Claude hiệu quả: import anthropic client = anthropic.Anthropic response = client.messages.create model="claude-opus-4-5", maxtokens=100, — mẹo quan trọng là cung cấp đủ ngữ cảnh để AI trả về kết quả chính xác hơn 80% so với prompt chung chung.
- 2 Một điều ít người đề cập: Ý tưởng: khi phát hiện maxtokens , append response cũ vào messages và gọi API lại, yêu cầu Claude tiếp tục từ chỗ dở:. Hiểu rõ bối cảnh áp dụng sẽ quyết định 80% thành công khi triển khai.
- 3 Giá trị cốt lõi: Cải thiện: def smartcontinuation messages: list, systemprompt: str = "", maxtokenspercall: int = 4096,. Đầu tư 15-30 phút học phần này sẽ giúp bạn tiết kiệm hàng giờ trong công việc hàng ngày.
- 4 Bước đầu tiên bạn nên làm: def generatelongcodespec: str, language: str = "Python" -> str: """ Generate code dài với continuation, đảm bảo. Áp dụng đúng cách sẽ thấy kết quả rõ rệt từ tuần đầu tiên.
- 5 Thành thật mà nói: Tính chi phí continuation Mỗi lần continuation, bạn phải gửi lại toàn bộ history input tokens tăng dần: def. Phương pháp này hiệu quả trong hầu hết trường hợp, nhưng bạn cần điều chỉnh cho phù hợp ngữ cảnh riêng.
Claude có context window 200k tokens nhưng max_tokens trong mỗi API call bị giới hạn (thường 4.096 đến 8.192). Khi bạn yêu cầu viết một bài viết dài, generate code phức tạp, hay tạo báo cáo chi tiết, response có thể bị cắt giữa chừng. Bài này hướng dẫn kỹ thuật continuation loop để nhận toàn bộ output.
Vấn đề: stop_reason = "max_tokens"
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=100, # Cố ý đặt thấp để demo
messages=[{
"role": "user",
"content": "Viết một bài viết 1000 từ về lịch sử Việt Nam."
}],
)
print(f"stop_reason: {response.stop_reason}")
print(f"Content: {response.content[0].text[:200]}...")
# Output:
# stop_reason: max_tokens ← Response bị cắt!
# Content: Việt Nam là một quốc gia có lịch sử hàng nghìn năm...
Khi stop_reason == "max_tokens", có nghĩa là Claude chưa hoàn thành — response bị cắt cứng tại giới hạn token. Khác với stop_reason == "end_turn" nghĩa là Claude đã hoàn thành tự nhiên.
Giải pháp: Continuation Loop
Ý tưởng: khi phát hiện max_tokens, append response cũ vào messages và gọi API lại, yêu cầu Claude tiếp tục từ chỗ dở:
def generate_with_continuation(
messages: list,
system_prompt: str = "",
max_tokens_per_call: int = 4096,
max_continuations: int = 10,
model: str = "claude-opus-4-5",
) -> dict:
"""
Generate response dài bằng cách tự động tiếp tục khi bị cắt.
Returns:
dict với keys: full_text, total_tokens, continuation_count, completed
"""
full_text = ""
total_input_tokens = 0
total_output_tokens = 0
continuation_count = 0
current_messages = messages.copy()
while continuation_count <= max_continuations:
response = client.messages.create(
model=model,
max_tokens=max_tokens_per_call,
system=system_prompt,
messages=current_messages,
)
# Cộng dồn token usage
total_input_tokens += response.usage.input_tokens
total_output_tokens += response.usage.output_tokens
# Lấy text từ response
chunk = response.content[0].text
full_text += chunk
print(f" Chunk {continuation_count + 1}: {len(chunk)} chars, "
f"stop_reason={response.stop_reason}")
# Kiểm tra điều kiện dừng
if response.stop_reason == "end_turn":
# Claude hoàn thành tự nhiên
print(f" Completed after {continuation_count} continuations!")
return {
"full_text": full_text,
"total_input_tokens": total_input_tokens,
"total_output_tokens": total_output_tokens,
"continuation_count": continuation_count,
"completed": True,
}
elif response.stop_reason == "max_tokens":
# Bị cắt — cần tiếp tục
continuation_count += 1
if continuation_count > max_continuations:
print(f" Reached max continuations ({max_continuations})")
break
# Thêm response vừa nhận vào messages
current_messages.append({
"role": "assistant",
"content": chunk
})
# Thêm lời nhắc tiếp tục
current_messages.append({
"role": "user",
"content": "Tiếp tục."
})
else:
# stop_reason khác (stop_sequence, v.v.)
print(f" Stopped with reason: {response.stop_reason}")
break
return {
"full_text": full_text,
"total_input_tokens": total_input_tokens,
"total_output_tokens": total_output_tokens,
"continuation_count": continuation_count,
"completed": False,
}
# Test
print("Generating long article...")
result = generate_with_continuation(
messages=[{
"role": "user",
"content": "Viết bài viết đầy đủ về lịch sử lập trình từ 1940 đến nay, bao gồm các ngôn ngữ lập trình quan trọng và milestone lớn."
}],
system_prompt="Viết văn tiếng Việt rõ ràng, súc tích. QUAN TRỌNG: Không dùng dấu chấm lửng (...) khi kết thúc câu. Hoàn thành đầy đủ mọi ý tưởng.",
max_tokens_per_call=2048,
max_continuations=5,
)
print(f"
=== KẾT QUẢ ===")
print(f"Hoàn thành: {result['completed']}")
print(f"Số lần tiếp tục: {result['continuation_count']}")
print(f"Tổng output: {len(result['full_text'])} chars")
print(f"Tổng tokens: {result['total_input_tokens']} in + {result['total_output_tokens']} out")
print(f"
Nội dung:
{result['full_text'][:500]}...")
Vấn đề: Seamless Continuation
Kỹ thuật "Tiếp tục." đơn giản đôi khi tạo ra seam (chỗ nối lộ liễu). Claude có thể thêm "Như tôi đã đề cập..." hoặc bắt đầu đoạn mới không tự nhiên. Cải thiện:
def smart_continuation(
messages: list,
system_prompt: str = "",
max_tokens_per_call: int = 4096,
max_continuations: int = 10,
model: str = "claude-opus-4-5",
) -> dict:
"""
Continuation thông minh hơn: prefill với ký tự cuối để seamless.
"""
full_text = ""
total_input_tokens = 0
total_output_tokens = 0
continuation_count = 0
current_messages = messages.copy()
while continuation_count <= max_continuations:
response = client.messages.create(
model=model,
max_tokens=max_tokens_per_call,
system=system_prompt,
messages=current_messages,
)
total_input_tokens += response.usage.input_tokens
total_output_tokens += response.usage.output_tokens
chunk = response.content[0].text
full_text += chunk
if response.stop_reason != "max_tokens":
return {
"full_text": full_text,
"total_input_tokens": total_input_tokens,
"total_output_tokens": total_output_tokens,
"continuation_count": continuation_count,
"completed": response.stop_reason == "end_turn",
}
continuation_count += 1
if continuation_count > max_continuations:
break
# Lấy vài từ cuối để continuity
last_words = chunk[-50:] if len(chunk) > 50 else chunk
# Thêm vào messages và prefill với đoạn cuối
current_messages.append({"role": "assistant", "content": chunk})
current_messages.append({
"role": "user",
"content": "Tiếp tục viết từ chỗ vừa dừng, không cần nhắc lại nội dung trước."
})
print(f" Continuation {continuation_count} (last: '...{last_words.strip()}')")
return {
"full_text": full_text,
"total_input_tokens": total_input_tokens,
"total_output_tokens": total_output_tokens,
"continuation_count": continuation_count,
"completed": False,
}
Streaming với Continuation
def stream_with_continuation(
messages: list,
system_prompt: str = "",
max_tokens_per_call: int = 4096,
max_continuations: int = 10,
) -> str:
"""Stream response với auto-continuation."""
full_text = ""
current_messages = messages.copy()
continuation_count = 0
while continuation_count <= max_continuations:
chunk_text = ""
with client.messages.stream(
model="claude-opus-4-5",
max_tokens=max_tokens_per_call,
system=system_prompt,
messages=current_messages,
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
chunk_text += text
final_message = stream.get_final_message()
stop_reason = final_message.stop_reason
full_text += chunk_text
if stop_reason != "max_tokens":
break
continuation_count += 1
if continuation_count > max_continuations:
break
current_messages.append({"role": "assistant", "content": chunk_text})
current_messages.append({
"role": "user",
"content": "Tiếp tục."
})
print() # Newline giữa các chunks khi streaming
print() # Final newline
return full_text
Xử lý code generation dài
def generate_long_code(spec: str, language: str = "Python") -> str:
"""
Generate code dài với continuation, đảm bảo syntax đúng.
"""
system = f"""Bạn là senior {language} developer.
Viết code đầy đủ, production-ready, có comments.
QUAN TRỌNG: Khi bị interrupt giữa chừng, hãy hoàn thành block code hiện tại trước.
Không để code bị cắt giữa function hay class."""
result = generate_with_continuation(
messages=[{
"role": "user",
"content": f"Viết {language} code đầy đủ cho: {spec}"
}],
system_prompt=system,
max_tokens_per_call=4096,
max_continuations=8,
)
# Validate code đủ không
code = result["full_text"]
# Kiểm tra các dấu hiệu code bị cắt
incomplete_markers = ["...", "# TODO: Continue", "# ..."]
has_incomplete = any(m in code for m in incomplete_markers)
if not result["completed"]:
print("WARNING: Code có thể chưa hoàn chỉnh")
if has_incomplete:
print("WARNING: Phát hiện dấu hiệu code bị cắt")
return code
# Generate REST API
api_code = generate_long_code(
"REST API cho e-commerce với FastAPI: endpoints cho products, orders, users. Bao gồm models, routers, và database operations.",
language="Python"
)
Tips quan trọng
Tính chi phí continuation
Mỗi lần continuation, bạn phải gửi lại toàn bộ history (input tokens tăng dần):
def estimate_continuation_cost(
initial_input_tokens: int,
avg_output_per_call: int,
n_continuations: int,
input_price_per_mtok: float = 3.0,
output_price_per_mtok: float = 15.0,
) -> dict:
"""Ước tính chi phí cho n continuations."""
total_input = 0
total_output = 0
for i in range(n_continuations + 1):
# Input tăng dần vì phải gửi lại history
input_tokens = initial_input_tokens + i * avg_output_per_call
total_input += input_tokens
total_output += avg_output_per_call
cost_input = (total_input / 1_000_000) * input_price_per_mtok
cost_output = (total_output / 1_000_000) * output_price_per_mtok
return {
"total_input_tokens": total_input,
"total_output_tokens": total_output,
"estimated_cost_usd": cost_input + cost_output,
}
# Ví dụ: 5 continuations, mỗi call output 2000 tokens
cost = estimate_continuation_cost(
initial_input_tokens=1000,
avg_output_per_call=2000,
n_continuations=5,
)
print(f"Estimated cost: ${cost['estimated_cost_usd']:.4f}")
print(f"Total tokens: {cost['total_input_tokens'] + cost['total_output_tokens']:,}")
Khi nào không nên dùng continuation?
-
Thay vào đó: Dùng
max_tokenslớn hơn ngay từ đầu (claude-opus-4-5 hỗ trợ 8.192) - Chia task: Thay vì viết "bài 5000 từ", chia thành 5 sections riêng biệt
- Summarize thay vì expand: Đôi khi response ngắn hơn mà vẫn đủ thông tin
Kết hợp với Streaming
Để UX tốt nhất trong production, kết hợp streaming + continuation:
- Stream response trong real-time để user thấy ngay
- Detect
max_tokensở cuối stream - Tự động request continuation (có thể show spinner nhỏ)
- Continue streaming từ continuation response
Kỹ thuật continuation là building block quan trọng cho mọi ứng dụng cần output dài — từ code generators đến report writers. Kết hợp với Prompt Caching để giảm chi phí input tokens tăng dần trong mỗi continuation call.
Bai viet co huu ich khong?
Bản quyền thuộc về tác giả. Vui lòng dẫn nguồn khi chia sẻ.






