SSD Nodes Learn 🎉 VPS từ $5.50/tháng
Hướng dẫn Matt ConnorBởi Matt Connor

Multi-model routing cho coding agent: Khi nào nên dùng?

Việc định tuyến coding agent qua nhiều model làm mất prompt cache và tăng chi phí vận hành. Bài viết phân tích toán học đằng sau việc ghim model so với định tuyến linh hoạt.

Multi-model routing ảnh hưởng thế nào đến một coding agent

Multi-model routing gửi mỗi request đến model rẻ nhất có khả năng xử lý nó. Với lưu lượng chat, cách này hoạt động tốt. Với một coding agent, nó thường tốn kém hơn là tiết kiệm, vì hóa đơn của agent chủ yếu đến từ phần prompt prefix được cache theo từng model, và việc chuyển đổi model sẽ làm mất cache đó.

Quy tắc mà bài viết này đề xuất: định tuyến qua các provider để đảm bảo tính sẵn sàng, chỉ định tuyến qua các tier để tối ưu chi phí tại các ranh giới tác vụ, và ghim một model cho mỗi phiên làm việc đối với bất kỳ tác vụ agentic nào. Mọi nội dung dưới đây là lập luận cho quy tắc này.

Bốn thuật ngữ, được định nghĩa một lần. Router chọn một model cho mỗi request. Gateway là proxy mà request đi qua, có thể thực hiện định tuyến hoặc không. Prompt cache là việc provider lưu trữ phần prefix đã xử lý của prompt, giúp các request sau lặp lại prefix đó sẽ chỉ bị tính phí một phần nhỏ so với giá input. KV cache (key value cache) là khái niệm tương tự bên trong một server mà bạn tự vận hành.

Tại sao lưu lượng chat định tuyến tốt còn lưu lượng agent thì không

Một yêu cầu chat chỉ là một lượt hội thoại. Nó đến, được phân loại, chuyển tới model, rồi trả về. Không có dữ liệu nào được lưu lại cho lượt tiếp theo. Router có thể gửi câu hỏi này tới một model nhỏ và câu hỏi sau tới một model lớn, và cả hai yêu cầu đều không biết về sự tồn tại của nhau. Đây là kiểu workload mà hầu hết các benchmark định tuyến đều đo lường, và các router tốt thực sự làm rất tốt việc này.

Một lượt agent không phải là một yêu cầu đơn lẻ. Một chỉ dẫn như "sửa lỗi test đang fail" có thể biến thành từ 20 đến 60 API call. Mỗi call gửi lại toàn bộ hội thoại: system prompt, mọi định nghĩa tool, mọi file mà agent đã đọc, mọi output lệnh mà nó đã thấy. Context chỉ có tăng lên. Đến call thứ 30, phần prefix lặp lại có thể lên tới hàng chục nghìn token, trong khi nội dung thực sự mới trong mỗi call chỉ là vài trăm token.

Hình thái đó làm thay đổi ý nghĩa của từ "đắt đỏ". Trong chat, chi phí xấp xỉ bằng giá của model nhân với số yêu cầu. Trong một vòng lặp agent, chi phí là phần prefix, bị tính phí lại trên mỗi call đơn lẻ. Phần còn lại của bài viết này được suy ra từ chính sự thật đó.

Prompt cache được tính theo từng model và agent nằm bên trong đó

Anthropic tính phí đọc cache bằng 0.1 lần giá input cơ bản, và phí ghi cache trong năm phút là 1.25 lần. Đây là bảng giá niêm yết công khai, tính đến tháng 8 năm 2026.

ChartClaude API published list price per million input tokens, August 2026
The data behind this chart
[
  {
    "label": "Opus 5",
    "uncached_input_usd": "5.00",
    "cache_read_usd": "0.50"
  },
  {
    "label": "Sonnet 5",
    "uncached_input_usd": "2.00",
    "cache_read_usd": "0.20"
  },
  {
    "label": "Haiku 4.5",
    "uncached_input_usd": "1.00",
    "cache_read_usd": "0.10"
  }
]

Hãy so sánh loạt dữ liệu thứ hai với loạt thứ nhất, theo hàng ngang thay vì hàng dọc. Một lần đọc cache trên Opus 5 có giá 0.50 đô la cho mỗi triệu token. Input không dùng cache trên Haiku 4.5, model rẻ nhất trong danh sách, có giá 1.00 đô la. Như vậy, việc đọc lại một prefix đã có sẵn trong cache trên model đắt nhất lại tốn ít chi phí cho mỗi token input hơn so với việc đọc cùng prefix đó lần đầu trên model rẻ nhất.

So sánh đơn giản đó phá vỡ hầu hết các kế hoạch định tuyến (routing). Một router chuyển công việc xuống một tier thấp hơn thường chỉ so sánh giá niêm yết. Nhưng một agent đang trong phiên làm việc không trả giá niêm yết cho model mà nó đang sử dụng. Nó trả phí đọc cache, vốn đã thấp hơn mức giá không dùng cache của model rẻ tiền.

Cache được đánh khóa (key) dựa trên hash của prompt prefix và được tách biệt theo từng model. Một request gửi đến model khác sẽ thực hiện hash đối chiếu với một kho lưu trữ chưa từng ghi nhận dữ liệu đó, vì vậy nó không tìm thấy gì và phải trả giá đầy đủ. Cache cũng là một hệ thống phân cấp: công cụ (tools) trước, sau đó đến system prompt, rồi đến các tin nhắn. Một thay đổi ở bất kỳ cấp độ nào cũng làm mất hiệu lực của cấp độ đó và mọi thứ phía sau nó, nghĩa là việc chỉnh sửa một định nghĩa công cụ sẽ loại bỏ cache của system prompt nằm phía sau nó. Các agent đăng ký công cụ tại thời điểm runtime sẽ gặp vấn đề này mà không cần thông qua router.

Chi phí thực tế của một lần chuyển đổi giữa phiên làm việc

Hãy xét một phiên làm việc với 40,000 token tiền tố (prefix) ổn định, một kích thước thông thường sau khi agent đã đọc qua một vài tệp tin. Dưới đây là chi phí tiền tố của một lượt truy vấn, được tính toán từ bảng giá niêm yết ở trên.

ChartPrefix cost of one 40k-token turn, arithmetic from the list prices above
The data behind this chart
[
  {
    "label": "Opus 5, cache warm",
    "prefix_cost_usd": "0.020"
  },
  {
    "label": "Sonnet 5, turn after switch",
    "prefix_cost_usd": "0.100"
  },
  {
    "label": "Opus 5, cache re-warmed",
    "prefix_cost_usd": "0.250"
  }
]

Việc duy trì trên Opus 5 với cache ấm tốn 0.020 đô la cho phần tiền tố của lượt đó. Lượt đầu tiên sau khi chuyển hướng xuống Sonnet 5 tốn 0.100 đô la, vì Sonnet không lưu trữ tiền tố này và phải thực hiện ghi mới. Việc quay lại Opus 5 tốn 0.250 đô la, vì mục nhập gốc đã hết hạn trong thời gian phiên làm việc chuyển đi nơi khác.

Như vậy, một vòng lặp phải trả phí cho hai lần ghi cache để tránh hai lần đọc cache. Đổi lại, việc chuyển đổi giúp tiết kiệm được một lượt output với giá của Sonnet thay vì giá của Opus. Khối chi tiết dưới đây tính toán toàn bộ hành trình: khoản tiết kiệm chỉ là một phần nhỏ của một xu, trong khi phí phạt cache lên tới hàng chục xu. Phí phạt lớn hơn gấp hơn một bậc độ lớn, và nó tăng dần theo độ dài tiền tố trong khi khoản tiết kiệm thì không.

Cách tính các con số này

Mọi con số ở đây là kết quả tính toán dựa trên bảng giá niêm yết trong biểu đồ đầu tiên. Đây là mô hình chi phí thay vì một bài benchmark, và không có request nào được gửi đi để tạo ra các con số này. Thay đổi kích thước tiền tố thì tỷ lệ này cũng thay đổi theo.

Tiền tố: 40,000 token, giữ nguyên trong suốt lượt truy vấn.

Opus 5, warm read     40,000 x $0.50 / 1e6  = $0.020
Sonnet 5, cache write 40,000 x $2.50 / 1e6  = $0.100   (1.25 x $2 base)
Opus 5, cache write   40,000 x $6.25 / 1e6  = $0.250   (1.25 x $5 base)

Chi phí cho một vòng lặp đi và về: $0.100 + $0.250 = $0.350. Hai lượt Opus ấm mà nó thay thế: $0.040. Chi phí phát sinh cho việc chuyển hướng: $0.310.

Khoản tiết kiệm, trên một lượt với 800 token output, là chênh lệch giá output giữa Opus 5 ở mức $25 mỗi triệu token và Sonnet 5 ở mức $10 mỗi triệu token:

800 x ($25 - $10) / 1e6 = $0.012

Chi $0.310 để tiết kiệm $0.012 là một khoản đầu tư lỗ gấp khoảng hai mươi lăm lần. Khoản tiết kiệm tỉ lệ thuận với số token output, vốn nhỏ và gần như cố định mỗi lượt. Phí phạt tỉ lệ thuận với kích thước tiền tố, vốn tăng dần trong suốt phiên làm việc. Phiên làm việc càng dài thì tình trạng này càng tệ, không bao giờ tốt hơn.

Định dạng gọi tool không đồng nhất giữa các nhà cung cấp

Một agent là một vòng lặp gọi tool, vì vậy định dạng gọi tool quan trọng theo cách mà chat thông thường không bao giờ gặp phải. Messages API của Anthropic trả về một khối nội dung tool_use và yêu cầu trả lại một khối tool_result. Các API tương thích với OpenAI trả về một mảng tool_calls, trong đó function.arguments là một chuỗi được mã hóa JSON thay vì một đối tượng lồng nhau. Một gateway sẽ thực hiện chuyển đổi giữa hai định dạng này, và với các lệnh gọi thông thường, việc chuyển đổi diễn ra suôn sẻ.

Các vấn đề xuất hiện ở những trường hợp biên. Các lệnh gọi tool song song, nơi model đưa ra nhiều lệnh gọi trong một phản hồi, được biểu diễn khác nhau và không được hỗ trợ giống hệt nhau ở mọi nơi. Việc thực thi schema nghiêm ngặt là một tính năng tùy theo nhà cung cấp, vì vậy một model đảm bảo các đối số hợp lệ theo schema trên một endpoint thường chỉ có xu hướng tạo ra các đối số hợp lệ trên endpoint khác. Agent nhìn nhận sự khác biệt này như một kết quả tool chứa lỗi phân tích cú pháp, sau đó nó cố gắng sửa lỗi bằng cách tốn thêm một lượt truy vấn. Các lượt sửa lỗi đó được tính phí theo giá prefix đầy đủ, vì vậy sự không khớp định dạng sẽ xuất hiện trên hóa đơn cũng như trong transcript.

Các endpoint tự host cần được cấu hình rõ ràng cho việc này. Server tương thích với OpenAI của vLLM yêu cầu --enable-auto-tool-choice cùng với một --tool-call-parser khớp với dòng model (hermes, mistral, llama3_json và các loại khác), cộng với một chat template xử lý các tin nhắn có vai trò tool. Tài liệu của vLLM nêu trực tiếp về các giới hạn của hướng đi này: với tool_choice="auto" và không có ràng buộc schema nghiêm ngặt, vLLM trích xuất các lệnh gọi tool từ văn bản thô, vì vậy các đối số đôi khi có thể bị định dạng sai hoặc vi phạm schema tham số của hàm. Việc chọn sai trình phân tích cú pháp cho model của bạn là một lỗi cấu hình khiến agent không thể gọi tool, điều này rất đáng lưu ý trước khi bạn định tuyến lưu lượng truy cập vào đó. Sự khác biệt giữa Ollama và vLLM khi tự phục vụ model là vấn đề quan trọng ở đây, vì hai công cụ này cung cấp khả năng gọi tool theo các điều kiện khác nhau.

Fallback giữa chừng làm thay đổi hành vi mà không báo lỗi

Fallback routing là tính năng dễ bị kích hoạt ngoài ý muốn nhất. Gateway được cấu hình để thử lại trên một model khác khi model đầu tiên trả về lỗi rate limit hoặc 5xx, sau đó đưa model bị lỗi vào trạng thái cooldown trong vài giây. Với lưu lượng chat, đây là cách xử lý đúng. Tuy nhiên, trong một tác vụ agent kéo dài, điều này có nghĩa là nửa sau của tác vụ đã chạy trên một model mà bạn không hề chọn.

Không có gì báo cáo về việc này. Tác vụ không fail, agent không cảnh báo và exit status vẫn là thành công. Kết quả bạn nhận được là một tác vụ mà kế hoạch được viết bởi một model, còn các chỉnh sửa lại được thực hiện bởi model khác, dẫn đến giọng văn và các thói quen thay đổi giữa chừng. Tín hiệu đáng tin cậy duy nhất là trường model trong log request của gateway hoặc metadata của phản hồi. Vì vậy, nếu bạn sử dụng fallback, hãy log trường đó theo từng request và kiểm tra lại khi kết quả không như mong đợi. Việc debug hành vi mà không biết model nào đã tạo ra nó sẽ tốn nhiều thời gian hơn cả thời gian mà fallback tiết kiệm được.

Bẫy tương tự cũng xảy ra với context compression. Nhiều agent tóm tắt lịch sử dài bằng cách gọi một model nhỏ. Nếu lệnh gọi đó sử dụng một model khác hoặc một system prompt khác, nó sẽ tự ghi vào một entry cache riêng và không làm mới cache của phiên làm việc chính. Kết quả là lượt request đầy đủ tiếp theo sẽ phải chịu chi phí cho một cold prefix. Việc nén dữ liệu đã tiết kiệm được token nhưng lại làm mất cache.

Chi phí định tuyến là có thật, nhưng độ trễ không phải là vấn đề chính

Các router thực sự làm tăng khối lượng công việc cho mỗi request, và việc xác định chính xác mức độ ảnh hưởng là điều cần thiết. DigitalOcean báo cáo rằng mô hình Arch-Router của họ giải quyết ý định định tuyến trong khoảng 51 mili giây, với độ chính xác định tuyến đạt 93.17% theo đánh giá của riêng họ. Đó là các số liệu của họ, từ phép đo và benchmark của họ, không phải của chúng tôi và cũng không phải là kết quả phổ quát. Hãy chấp nhận các con số đó và kết luận sẽ rất khả quan: 51 mili giây cho bốn mươi lần gọi agent chỉ cộng thêm khoảng hai giây vào một tác vụ kéo dài vài phút.

Hai giây không phải là thứ làm cho việc định tuyến trở nên đắt đỏ ở đây. Chi phí gây ảnh hưởng thực sự là một router phân loại bằng cách gọi toàn bộ mô hình, vì đó là một lần inference thứ hai trên mỗi request, bị tính phí và xếp hàng như bất kỳ request nào khác. Bên dưới cả hai là các phép tính cache đã nêu ở trên, vốn không phải là chi phí phụ (overhead). Đó là chi phí của chính thứ mà việc định tuyến lẽ ra phải tối ưu hóa.

Trên máy chủ bạn tự vận hành, quy tắc tương tự cũng áp dụng với ít không gian xoay xở hơn. Tương đương cục bộ của prompt cache là prefix caching trong KV cache, nằm trong bộ nhớ GPU. Việc host hai mô hình trên một GPU sẽ chia sẻ bộ nhớ đó giữa chúng, vì vậy mỗi mô hình giữ một KV cache nhỏ hơn và đẩy các prefix ra sớm hơn. Do đó, việc định tuyến giữa hai mô hình cục bộ có thể làm giảm tỷ lệ cache hit cho cả hai cùng lúc. Nếu bạn đang tính toán phần cứng cho việc này, bài viết về bộ nhớ và CPU mà một coding agent thực sự cần trên một VPS là điểm khởi đầu hữu ích hơn là một router.

Quy tắc quyết định

  • Định tuyến qua nhiều nhà cung cấp để đảm bảo tính sẵn sàng. Khi lựa chọn thay thế là một yêu cầu thất bại, mọi chi phí đều là chi phí hợp lý. Hãy ghim fallback vào một model có cùng định dạng tool call để vòng lặp của agent không bị gián đoạn, đồng thời ghi log xem model nào đã xử lý mỗi cuộc gọi.
  • Định tuyến qua các tier để tối ưu chi phí chỉ tại các ranh giới tác vụ. Chọn Haiku cho việc đổi tên và Opus cho việc refactor là một quyết định đúng đắn nếu thực hiện một lần trước khi phiên làm việc bắt đầu. Đó là quyết định tồi nếu thực hiện ở lượt thứ ba mươi của phiên đó.
  • Ghim một model cho mỗi phiên đối với bất kỳ tác vụ agentic nào. Giá trị của một phiên nằm ở warm cache của nó. Hãy coi việc chuyển đổi model giống như việc xóa cache đó, vì đó chính xác là những gì sẽ xảy ra.
  • Định tuyến các subagent một cách linh hoạt. Một subagent bắt đầu với context nhỏ và mới sẽ không có warm cache để mất, vì vậy nó có thể chạy trên bất kỳ model nào phù hợp với công việc. Đây là nơi duy nhất bên trong một agent mà việc định tuyến gần như không tốn phí.

Để xây dựng hệ thống này, gateway sẽ đảm nhận công việc: model alias và danh sách fallback tường minh. Một cấu hình LiteLLM proxy tối thiểu trông như sau.

model_list:
  - model_name: agent-primary
    litellm_params:
      model: anthropic/claude-opus-5
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: agent-standby
    litellm_params:
      model: anthropic/claude-sonnet-5
      api_key: os.environ/ANTHROPIC_API_KEY

router_settings:
  fallbacks: [{"agent-primary": ["agent-standby"]}]
  num_retries: 2
  cooldown_time: 30

Trỏ agent vào agent-primary và nó sẽ giữ nguyên một model cho đến khi model đó không thể truy cập được. Cả hai mục đều nằm trên cùng một nhà cung cấp, vì vậy định dạng tool call không thay đổi khi fallback kích hoạt. Bạn vẫn chấp nhận thay đổi tier tại thời điểm đó, đây là một sự đánh đổi xứng đáng chỉ vì lựa chọn thay thế là một yêu cầu thất bại. Đó là định tuyến tính sẵn sàng mà không kèm theo định tuyến chi phí, đây là sự kết hợp mà hầu hết các coding agent đều mong muốn. Bản dựng đầy đủ, bao gồm các key và ngân sách, đã được đề cập trong chạy LiteLLM gateway tự host trên VPS của bạn, và bài viết này cố tình không lặp lại nội dung đó.

Khi một model được chọn kỹ lưỡng hiệu quả hơn bất kỳ router nào

Routing là giải pháp cho sự chênh lệch về độ khó của các request. Một coding agent có ít sự chênh lệch đó hơn vẻ ngoài của nó, vì phần tốn kém nhất của mỗi lần gọi API đều là phần prefix giống nhau, bất kể yêu cầu là gì. Khi phần prefix chiếm ưu thế, sự khác biệt giữa tier giá rẻ và tier đắt tiền của bạn sẽ thu hẹp dần về mức chênh lệch giá output, mà output lại chỉ chiếm một phần nhỏ trong tổng số token của agent.

Vì vậy, lựa chọn mặc định hợp lý nhất là dùng một model duy nhất, được chọn ngay từ đầu, bật tính năng cache với TTL (time to live) đủ dài để bao phủ các khoảng nghỉ khi bạn dừng lại đọc diff. Anthropic cung cấp tính năng cache write trong một giờ với mức giá gấp 2 lần input cơ bản, vốn sẽ hoàn vốn chỉ sau hai lần đọc, và đây thường là đòn bẩy hiệu quả hơn bất kỳ router nào. Hãy chọn tier một cách có chủ đích thông qua so sánh trực tiếp Opus, Sonnet và Haiku, và nếu hóa đơn vẫn là vấn đề, hãy giảm chi phí bằng cách thiết lập ngân sách và context nhỏ hơn như trong bài kiểm soát chi phí AI agent trên VPS thay vì chuyển đổi model giữa phiên làm việc.

Hãy dùng routing khi các request độc lập và ngắn, hoặc khi các subagent bắt đầu với context mới. Hãy cố định model khi bạn có một phiên làm việc dài để thực hiện một công việc cụ thể. Hầu hết công việc của coding agent thuộc loại thứ hai, đó là lý do tại sao router giúp tiết kiệm tiền trên sản phẩm chat của bạn lại âm thầm gây tốn kém trong trường hợp này. Nếu bạn chưa quyết định chọn agent nào, bài so sánh Claude Code với Cursor, Codex và Copilot sẽ giải thích cách mỗi công cụ xử lý việc chọn model, và một số trong đó sẽ tự đưa ra quyết định này thay cho bạn.

FAQ

Việc chuyển đổi model giữa chừng có thực sự làm mất prompt cache không?

Có. Prompt cache được đánh chỉ mục dựa trên hash của tiền tố prompt và được lưu trữ riêng cho từng model. Do đó, một request gửi đến model khác sẽ so khớp với một kho lưu trữ chưa từng thấy tiền tố đó. Hệ thống sẽ không tìm thấy gì, bạn phải trả phí đầy đủ cho input không được cache, và sau đó trả thêm phí ghi cache nếu tính năng này được bật. Việc chuyển đổi ngược lại cũng không khôi phục được mục nhập ban đầu, vì thời gian tồn tại mặc định là năm phút thường đã hết hạn vào lúc đó. Hãy kiểm tra các trường cache_read_input_tokenscache_creation_input_tokens trong đối tượng usage của phản hồi: một lượt truy vấn đọc được không token nào từ cache trong một phiên làm việc dài là dấu hiệu của vấn đề này.

Việc định tuyến sang một model rẻ hơn có bao giờ tiết kiệm chi phí cho agent không?

Chỉ khi không có cache đang hoạt động (warm cache) để mất. Việc đọc cache trên Anthropic có chi phí bằng 0.1 lần giá input cơ bản, khiến cho việc đọc từ cache trên Opus 5 rẻ hơn so với giá input không cache trên Haiku 4.5. Khi một phiên làm việc đã có một tiền tố được cache lớn, model hiện tại đã là lựa chọn rẻ hơn về mặt input. Việc định tuyến chỉ có lợi khi ngữ cảnh còn mới và nhỏ: ở đầu một tác vụ, hoặc trong một subagent chỉ mang theo ngữ cảnh cần thiết.

Tại sao agent của tôi lại hoạt động khác đi ở giữa tác vụ?

Hãy kiểm tra xem cơ chế gateway fallback có được kích hoạt hay không. Khi gặp giới hạn tốc độ (rate limit) hoặc lỗi 5xx trên model chính, gateway sẽ thử lại trên model dự phòng và đưa model chính vào trạng thái cooldown trong vài giây, khiến phần còn lại của tác vụ chạy ở nơi khác. Quá trình này không tạo ra lỗi hay cảnh báo, và tác vụ vẫn báo thành công. Trường model trong log request của gateway hoặc metadata của phản hồi là bản ghi duy nhất đáng tin cậy, vì vậy hãy log lại trường này cho mỗi request nếu bạn có sử dụng fallback.

Các tool call có hoạt động giống nhau trên mọi nhà cung cấp không?

Không hoàn toàn. Messages API của Anthropic sử dụng các khối nội dung tool_usetool_result, trong khi các API tương thích với OpenAI sử dụng một mảng tool_calls mà trong đó function.arguments là một chuỗi được mã hóa JSON. Một gateway có thể chuyển đổi tốt các trường hợp phổ biến, nhưng việc gọi tool song song và thực thi schema nghiêm ngặt sẽ khác nhau tùy theo nhà cung cấp. Trên vLLM tự host, bạn phải thiết lập --enable-auto-tool-choice--tool-call-parser khớp với dòng model của bạn. Tài liệu của vLLM lưu ý rằng nếu không có ràng buộc schema nghiêm ngặt, server sẽ trích xuất tool call từ văn bản thô, dẫn đến việc các đối số đôi khi có thể bị sai định dạng.

Tôi nên đặt cache TTL bao lâu cho một phiên làm việc lập trình?

Hãy sử dụng thời gian tồn tại mặc định là năm phút cho công việc liên tục, và tùy chọn một giờ khi có người đọc các diff giữa các lượt truy vấn. Anthropic tính phí ghi cho loại năm phút bằng 1.25 lần input cơ bản và loại một giờ bằng 2 lần, so với phí đọc là 0.1 lần. Phí ghi năm phút được hoàn vốn chỉ sau một lần đọc, và phí ghi một giờ được hoàn vốn sau hai lần đọc. Do đó, với bất kỳ phiên làm việc nào mà bạn dự định quay lại và tiếp tục, thời gian tồn tại dài hơn thường tốn ít chi phí hơn so với việc phải trả phí cho một tiền tố lạnh (cold prefix).