Chuyển sang Claude Sonnet 5.5: ba chỗ sẽ gãy
Sonnet 5.5 nhanh hơn Sonnet 5 tới 30 %, cùng giá mỗi token. Đổi tên model thì dễ; sửa ba thói quen trong code mới là việc chính.
Lần nâng cấp model nào cũng bắt đầu bằng một lời tự trấn an quen thuộc: chỉ là đổi một chuỗi thôi mà. Mở file cấu hình, thay tên model cũ bằng tên mới, deploy, rồi đi pha cà phê. Với Claude Sonnet 5.5, lời trấn an ấy chỉ đứng vững được chừng mười phút, đủ để request đầu tiên trả về một dạng mà code không ngờ tới, hoặc không trả về gì cả.
Dù vậy, nâng cấp vẫn rất đáng. Theo Anthropic, Sonnet 5.5 thông minh hơn, hiệu quả hơn Sonnet 5 và nhanh hơn 30 %, trong khi giá mỗi token giữ nguyên. Vì thường cần ít token hơn cho cùng một việc, bài công bố cho biết chi phí có thể giảm tới 30 % với phần lớn công việc. Vậy câu hỏi không phải là có nên chuyển hay không, mà là cần sửa gì trên đường chuyển. Mình đã viết một phiếu ngắn về chủ đề này trên Consonance; đây là bản đầy đủ, kèm code.
Ý chính trong một câu
Đổi tên model, rồi sửa ba chỗ mà Sonnet 5.5 không còn chấp nhận thói quen cũ: đọc khối đầu tiên, tắt suy nghĩ, và ép dùng công cụ.
model="claude-sonnet-5-5"
1. Code của bạn đọc content[0].text
Đây là cái bẫy âm thầm nhất, vì API không báo lỗi gì cả. Sonnet 5.5 suy nghĩ theo mặc định: một request không có trường thinking sẽ chạy với adaptive thinking. Nghĩa là câu trả lời có thể mở đầu bằng một khối thinking, và dòng code lấy text của khối đầu tiên sẽ hoặc crash, hoặc trả về thứ bạn không mong đợi.
Cách sửa là thôi giả định vị trí, và đọc từng khối theo loại của nó. Đây là request mà Anthropic đưa ra, chạy được nguyên văn trên Sonnet 5.5:
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=4096,
messages=[
{
"role": "user",
"content": "Analyze the trade-offs between microservices and monolithic architectures",
}
],
output_config={"effort": "medium"},
)
for block in response.content:
if block.type == "text":
print(block.text)
Toàn bộ bài học nằm ở vòng lặp cuối, gói gọn trong đúng một dòng:
if block.type == "text":
Hướng dẫn chuyển đổi còn nhắc thêm hai thói quen nên tập luôn. Trong vòng lặp gọi công cụ, hãy gửi lại các khối thinking nguyên vẹn, kể cả khối rỗng. Và xem lại max_tokens: giá trị này bao gồm cả phần suy nghĩ lẫn phần text, và token suy nghĩ được tính tiền như token đầu ra.
2. Bạn từng gửi thinking={"type": "disabled"}
Nếu bạn chạy Sonnet 5 với chế độ tắt suy nghĩ, thì chính thiết lập đó giờ trả về lỗi 400 invalid_request_error. Thay vào đó là một giá trị mới: between_tools. Với giá trị này, model không suy nghĩ trước khi trả lời; nó chỉ suy nghĩ giữa các lần gọi công cụ, và theo Anthropic, tổng thời gian phản hồi bằng hoặc nhanh hơn trước. Đây là đoạn trước và sau, lấy từ bài công bố:
# Before: Claude Sonnet 5
client.messages.create(
model="claude-sonnet-5",
max_tokens=16000,
thinking={"type": "disabled"},
output_config={"effort": "xhigh"},
messages=[{"role": "user", "content": "..."}],
)
# After: Claude Sonnet 5.5
client.messages.create(
model="claude-sonnet-5-5",
max_tokens=16000,
thinking={"type": "between_tools"},
output_config={"effort": "high"},
messages=[{"role": "user", "content": "..."}],
)
Để ý kỹ: mức effort cũng hạ từ xhigh xuống high. Đó không phải chi tiết thừa, vì between_tools có vài quy tắc riêng:
- Nó chạy ở mức effort
low,mediumvàhigh. Ởxhighhoặcmax, nó trả về lỗi 400; muốn chạy ở các mức đó, hãy dùng adaptive thinking. - Nó không nhận thêm trường nào khác. Gửi kèm
display,budget_tokenshoặcblock_bindingsẽ nhận lỗi 400. - Effort không đổi được giữa chừng cuộc hội thoại. Muốn mỗi lượt một mức khác nhau, hãy dùng adaptive thinking.
- Những dòng cập nhật ngắn mà model viết giữa các lần gọi công cụ vẫn trả về dưới dạng khối
thinking. Tức là quay lại ngay phần 1. - Không cần header beta, nhưng nếu phiên bản SDK của bạn chưa có
between_tools, hãy cập nhật.
Một lưu ý cuối: với request không dùng công cụ nhưng vẫn cần vài bước suy luận, bài công bố khuyên dùng adaptive thinking thay vì between_tools.
3. Bạn ép dùng một công cụ bằng tool_choice
tool_choice loại any hoặc tool bị từ chối với lỗi 400, kể cả trên endpoint đếm token. Thông báo lỗi nói rất rõ:
tool_choice: type "tool" and "any" are not supported for this model.
Cách thay gồm ba bước. Gửi tool_choice={"type": "auto"}. Đánh dấu công cụ là "strict": True để input khớp với schema. Và vì auto cho phép model trả lời mà không cần gọi công cụ, hãy nói rõ trong prompt khi nào cần dùng nó:
weather_tool = {
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {"location": {"type": "string"}},
"required": ["location"],
"additionalProperties": False,
},
"strict": True,
}
client.messages.create(
model="claude-sonnet-5-5",
max_tokens=1024,
tools=[weather_tool],
tool_choice={"type": "auto"}, # was {"type": "tool", "name": "get_weather"}
messages=[
{"role": "user", "content": "What's the weather in Paris? Use the get_weather tool."}
],
)
Chế độ strict đòi hỏi additionalProperties: false trên mọi object trong schema, không chỉ ở cấp ngoài cùng. Đây là chi tiết hay làm vấp khi input có object lồng nhau.
Để Claude Code lo phần việc nhàm chán
Trong một dự án thật, những đoạn code này nằm rải rác ở rất nhiều file. Claude Code có thể chuyển đổi giúp bạn thông qua skill Claude API đi kèm, áp dụng việc đổi model ID và các tham số gây lỗi trên toàn bộ codebase:
/claude-api migrate this project to claude-sonnet-5-5
Dù vậy, vẫn có vài điểm cần cân nhắc chứ không chỉ tìm và thay:
- Các mức effort đã được hiệu chỉnh lại. Cùng một mức không còn cho ra lượng suy nghĩ như trên Sonnet 5, nên thiết lập cũ không áp dụng được nữa. Hãy test lại các mức effort. Mặc định là
hightrên Claude API vàmediumtrong Claude Code. - Ảnh lớn tốn hơn. Một ảnh 2000×1500 tốn khoảng 2,5 lần token so với Sonnet 4.6. Nếu không cần chi tiết, hãy thu nhỏ trước khi gửi.
- Danh sách đầy đủ dài hơn. Hướng dẫn liệt kê năm thay đổi gây lỗi và một thay đổi về cấu trúc câu trả lời. Ngoài những gì đã nói ở đây, hãy kiểm tra thêm hội thoại chỉ-nối-thêm, computer use và advisor tool nếu bạn có dùng.
Kết lại
Tên model là phần dễ nhất. Việc chuyển đổi thật sự chỉ gồm ba thay đổi nhỏ trong cách code nói chuyện với model: đọc khối theo loại, thay disabled bằng between_tools, và đổi công cụ bị ép thành auto cùng một schema strict và một prompt rõ ràng. Làm xong ba việc đó, test lại các mức effort, và bạn có một model nhanh hơn với cùng giá mỗi token, không còn lỗi 400 bất ngờ trên production.