Các mô hình ngôn ngữ lớn (LLM) ở khắp mọi nơi, từ các ứng dụng hàng ngày đến các công cụ tiên tiến. Sử dụng chúng rất dễ dàng. Nhưng nếu bạn cần chạy mô hình của riêng bạn? Cho dù bạn đã điều chỉnh một mô hình hay đang xử lý dữ liệu nhạy cảm với quyền riêng tư, sự phức tạp ngày càng tăng. Trong bài đăng này, chúng tôi sẽ chia sẻ những gì chúng tôi đã học được trong khi xây dựng hệ thống kết luận LLM của riêng mình. Chúng tôi sẽ bao gồm lưu trữ và triển khai các mô hình, thiết kế kiến trúc dịch vụ và giải quyết các vấn đề thực tế như định tuyến, phát trực tuyến và quản lý dịch vụ vi mô. Quá trình liên quan đến những thách thức, nhưng cuối cùng, chúng tôi đã xây dựng một hệ thống đáng tin cậy và thu thập những bài học đáng chia sẻ. Giới thiệu LLMs đang thúc đẩy một loạt các ứng dụng - từ chatbots và các đại lý dòng công việc đến các công cụ tự động hóa thông minh.Trong khi việc thu thập tăng cường sản xuất, công cụ-calling, và giao thức đa đại lý là quan trọng, họ hoạt động ở một mức độ trên động cơ cốt lõi: một LLM cơ bản. Nhiều dự án dựa vào các nhà cung cấp bên ngoài, chẳng hạn như , hoặc , mà là đủ cho hầu hết các trường hợp sử dụng. Nhưng đối với một số ứng dụng, nó nhanh chóng trở thành một vấn đề. Điều gì nếu nhà cung cấp đi xuống? Điều gì nếu bạn cần kiểm soát đầy đủ về độ trễ, giá cả, hoặc thời gian hoạt động? quan trọng nhất - điều gì nếu bạn quan tâm đến quyền riêng tư và không thể đủ khả năng để gửi dữ liệu người dùng cho một bên thứ ba? Mở Giống Gemini Anthropic Mở Giống Gemini Anthropic Đó là nơi tự lưu trữ trở nên cần thiết. Dịch vụ một mô hình được đào tạo trước hoặc điều chỉnh tốt cung cấp kiểm soát, bảo mật và khả năng tùy chỉnh mô hình theo nhu cầu kinh doanh cụ thể. Xây dựng một hệ thống như vậy không đòi hỏi một đội ngũ lớn hoặc các nguồn lực rộng lớn. Chúng tôi đã xây dựng nó với ngân sách khiêm tốn, một nhóm nhỏ và chỉ một vài nút. Hạn chế này ảnh hưởng đến quyết định kiến trúc của chúng tôi, đòi hỏi chúng tôi phải tập trung vào tính thực tế và hiệu quả. Trong các phần tiếp theo, chúng tôi sẽ bao gồm những thách thức phải đối mặt, các giải pháp được thực hiện và những bài học được học trên đường đi. tổng quan Đây là các thành phần cốt lõi tạo thành xương sống của hệ thống. Định dạng và Mã hóa Một ngôn ngữ được chia sẻ trên các dịch vụ là điều cần thiết.Điều đó có nghĩa là các định dạng yêu cầu / phản hồi nhất quán, sơ đồ tham số sản xuất, cấu trúc lịch sử đối thoại và serialization hoạt động ở mọi nơi - từ frontend đến backend đến người chạy mô hình. Streaming và Routing. xử lý nhiều mô hình, loại yêu cầu và ưu tiên máy chủ đòi hỏi các quyết định định định tuyến có chủ ý. Chúng tôi sẽ phác thảo cách các yêu cầu người dùng đến được định tuyến qua hệ thống - từ điểm nhập ban đầu đến nút công nhân thích hợp - và cách phản hồi được truyền trở lại. Mô hình lưu trữ và triển khai. nơi các mô hình sống, và làm thế nào họ được chuẩn bị để sử dụng trong sản xuất? Chúng tôi sẽ thảo luận về các bài kiểm tra chính để thực hiện, bao gồm đảm bảo độ tin cậy của mô hình. Khả năng quan sát.Làm thế nào bạn biết mọi thứ đang hoạt động?Chúng tôi sẽ hiển thị các số liệu mà chúng tôi theo dõi, cách chúng tôi giám sát sự thất bại và các quét mà chúng tôi sử dụng để đảm bảo sức khỏe và độ tin cậy của hệ thống. Schema và Data Encoding Lựa chọn sơ đồ truyền dữ liệu phù hợp là rất quan trọng. Một định dạng được chia sẻ giữa các dịch vụ đơn giản hóa việc tích hợp, giảm lỗi và cải thiện khả năng thích ứng. Chúng tôi nhằm mục đích thiết kế hệ thống để hoạt động liền mạch với cả các mô hình tự lưu trữ và các nhà cung cấp bên ngoài - mà không làm lộ sự khác biệt cho người dùng. Tại sao thiết kế Schema Matters Không có tiêu chuẩn phổ quát cho trao đổi dữ liệu LLM. Nhiều nhà cung cấp theo các chương trình tương tự như Trong khi những người khác - như hoặc Nhiều nhà cung cấp này cung cấp các SDK tương thích với OpenAI giữ lại cùng một sơ đồ, mặc dù thường có giới hạn hoặc bộ tính năng giảm (ví dụ, , 3) Các dự án khác như Mục tiêu là thống nhất các biến thể này bằng cách đóng gói chúng vào một giao diện tương thích OpenAI. Mở cửa Claude Giống Gemini SDK tương thích OpenAI của Anthropic Lớp tương thích OpenAI của Gemini OpenRouter Mở cửa Claude Giống Gemini SDK tương thích OpenAI của Anthropic Lớp tương thích OpenAI của Gemini OpenRouter Tiếp tục với một chương trình nhà cung cấp được xác định trước duy nhất có những lợi thế của nó: Bạn sẽ nhận được một API ổn định, được kiểm tra tốt. Bạn có thể dựa vào các SDK và công cụ hiện có. Nhưng cũng có những nhược điểm thực sự: Nó tạo ra khóa nhà cung cấp, làm cho nó khó khăn hơn để hỗ trợ nhiều nhà cung cấp. Nó giới hạn sự linh hoạt để mở rộng sơ đồ với các tính năng tùy chỉnh cần thiết cho nhu cầu kinh doanh hoặc yêu cầu nhóm khoa học dữ liệu. Bạn tiếp xúc với những thay đổi phá vỡ hoặc giảm giá ngoài tầm kiểm soát của bạn. Những chương trình này thường mang những hạn chế thừa kế hạn chế kiểm soát hạt mịn. To address this, we chose to define our - một sơ đồ được thiết kế xung quanh nhu cầu của chúng tôi, sau đó chúng tôi có thể lập bản đồ thành các định dạng bên ngoài khác nhau khi cần thiết. own internal data model Thiết kế nội bộ Schema Trước khi giải quyết những thách thức, chúng ta hãy xác định vấn đề và phác thảo những kỳ vọng của chúng ta đối với giải pháp: Chuyển đổi dễ dàng sang các định dạng được yêu cầu bởi các nhà cung cấp bên ngoài và ngược lại. Hỗ trợ đầy đủ các tính năng cụ thể cho các nhóm khoa học dữ liệu và kinh doanh của chúng tôi. Đảm bảo rằng chương trình có thể dễ dàng mở rộng để đáp ứng các yêu cầu trong tương lai. Chúng tôi bắt đầu bằng cách xem xét các chương trình LLM chính để hiểu cách các nhà cung cấp cấu trúc thông điệp, tham số và đầu ra. phổ biến trên hầu hết các hệ thống, bao gồm: core domain entities Thông điệp (ví dụ: nhanh, lịch sử) Các thông số tạo ra (ví dụ: nhiệt độ, top_p, beam_search) Chúng tôi xác định một số thông số, chẳng hạn như , , or , như là cụ thể cho cấu hình nội bộ của nhà cung cấp và logic kinh doanh. Những yếu tố này nằm bên ngoài lĩnh vực cốt lõi của LLM và không phải là một phần của chương trình chia sẻ. Thay vào đó, chúng được coi là các phần mở rộng tùy chọn. Bất cứ khi nào một tính năng trở nên được áp dụng rộng rãi hoặc cần thiết cho khả năng tương tác rộng hơn, chúng tôi đánh giá việc tích hợp nó vào chương trình cốt lõi. service_tier usage_metadata reasoning_mode Ở cấp độ cao, sơ đồ đầu vào của chúng tôi được cấu trúc với các thành phần chính này: Mô hình – Được sử dụng như một phím định tuyến, hoạt động như một định danh định tuyến, cho phép hệ thống chuyển yêu cầu đến nút công nhân thích hợp. Parameters Generation – Cài đặt mô hình cốt lõi (ví dụ: nhiệt độ, top_p, max_tokens). Tin nhắn – Lịch sử hội thoại và tải nhanh. Công cụ – Định nghĩa của các công cụ mà mô hình có thể sử dụng. Điều này dẫn chúng ta đến kế hoạch sau, được thể hiện trong một Nó minh họa cấu trúc và mục đích của thiết kế, mặc dù một số chi tiết thực hiện được bỏ qua vì sự đơn giản. Phanxicô Phanxicô class ChatCompletionRequest(BaseModel): model: str # Routing key to select the appropriate model or service messages: list[Message] # Prompt and dialogue history generation_parameters: GenerationParameters # Core generation settings tools: list[Tool] # Optional tool defenitions class GenerationParameters(BaseModel): temperature: float top_p: float max_tokens: int beam_search: BeamSearchParams # Optional, non-core fields specific to certain providers provider_extensions: dict[str, Any] = {} ... # Other parameters Chúng tôi cố ý di chuyển các thông số sản xuất vào một lĩnh vực riêng biệt thay vì đặt chúng ở cấp gốc. các thông số (ví dụ, nhiệt độ, top-p, cài đặt mô hình) và Nhiều nhóm trong hệ sinh thái của chúng tôi lưu trữ các thông số liên tục này trong các hệ thống cấu hình bên ngoài, làm cho sự tách biệt này thực tế và cần thiết. liên tục biến Chúng tôi bao gồm một trường bổ sung được gọi là Trong các Các thông số này khác nhau đáng kể giữa các nhà cung cấp LLM khác nhau, xác nhận và giải thích các lĩnh vực này là - thành phần biết cách giao tiếp với một nhà cung cấp mô hình cụ thể. do đó, chúng tôi tránh sự kết nối vượt qua không cần thiết gây ra bởi việc xác nhận dữ liệu dư thừa trên nhiều dịch vụ. provider_extensions GenerationParameters delegated to the final module that handles model inference Để đảm bảo tương thích ngược, các tính năng sơ đồ đầu ra mới được giới thiệu như: trong biểu đồ yêu cầu. Các trường này hoạt động như các biểu ngữ tính năng – người dùng phải đặt chúng để chọn vào các hành vi cụ thể. Cách tiếp cận này giữ cho biểu đồ cốt lõi ổn định trong khi cho phép tiến hóa gia tăng. Ví dụ, các dấu vết lý luận sẽ chỉ được bao gồm trong đầu ra nếu trường tương ứng được đặt trong yêu cầu. explicit, optional fields Những sơ đồ này được duy trì trong một thư viện Python được chia sẻ và được sử dụng trên các dịch vụ để đảm bảo xử lý yêu cầu và phản hồi nhất quán. Làm việc với các nhà cung cấp bên thứ ba We began by outlining how we built our own platform — so why bother with compatibility across external providers? Despite relying on our internal infrastructure, there are still several scenarios where external models play a role: Tạo dữ liệu tổng hợp để tạo nguyên mẫu và thử nghiệm bởi các nhóm khoa học dữ liệu của chúng tôi. Nhiệm vụ mục đích chung nơi một số mô hình độc quyền thực hiện tốt hơn ra khỏi hộp. Các trường hợp sử dụng không nhạy cảm nơi quyền riêng tư, độ trễ hoặc kiểm soát cơ sở hạ tầng ít quan trọng hơn. Dòng truyền thông tổng thể với các nhà cung cấp bên ngoài có thể được tóm tắt như sau: Quá trình này liên quan đến các bước sau: Dịch vụ đặc biệt LLM-Gateway chịu trách nhiệm giao tiếp với nhà cung cấp nhận được yêu cầu của người dùng trong định dạng sơ đồ của chúng tôi. Yêu cầu được chuyển đổi sang định dạng cụ thể của nhà cung cấp, bao gồm bất kỳ phần mở rộng provide_extensions. Nhà cung cấp bên ngoài xử lý yêu cầu và trả lời. Dịch vụ LLM-Gateway nhận được câu trả lời và lập bản đồ nó trở lại chương trình phản hồi tiêu chuẩn của chúng tôi. Đây là một sơ đồ cấp cao trừu tượng một số microservices riêng lẻ. chi tiết về các thành phần cụ thể và định dạng phản hồi phát trực tuyến sẽ được bao gồm trong các phần sau. Streaming định dạng Trả lời LLM được tạo ra dần dần - token theo token - và sau đó tổng hợp thành Từ quan điểm của người dùng, cho dù thông qua một trình duyệt, ứng dụng di động hoặc thiết bị đầu cuối, trải nghiệm phải được duy trì Điều này đòi hỏi một cơ chế vận chuyển hỗ trợ . chunks fluid and responsive low-latency, real-time streaming Có hai lựa chọn chính để đạt được điều này: WebSockets: Một kênh truyền thông full-duplex cho phép tương tác hai chiều liên tục giữa máy khách và máy chủ. : A unidirectional, HTTP-based streaming protocol that is widely used for real-time updates. Sự kiện Server-Sent (SSE) WebSockets WebSockets Sự kiện Server-Sent (SSE) Sự kiện Server-Sent (SSE) Tại sao SSE trên WebSockets? Trong khi cả hai lựa chọn đều khả thi, — đặc biệt đối với các API tương thích với OpenAI và các hệ thống tương tự. Điều này là do một số lợi thế thực tế: SSE is the more commonly used solution for standard LLM inference : SSE runs over standard HTTP, requiring no special . Simplicity upgrades or negotiation : It works natively in all major browsers without additional libraries. Compatibility Dòng chảy đơn phương: Hầu hết các phản hồi LLM chỉ chảy từ máy chủ đến máy khách, điều này phù hợp với thiết kế của SSE. Proxy-Friendliness: SSE chơi tốt với cơ sở hạ tầng HTTP tiêu chuẩn, bao gồm cả proxy ngược. nâng cấp hoặc đàm phán Do những lợi ích này, . SSE is typically chosen for text-only, prompt-response streaming use cases Tuy nhiên, một số trường hợp sử dụng mới nổi đòi hỏi giao tiếp hai chiều phong phú hơn, chậm trễ thấp - chẳng hạn như chuyển văn thời gian thực hoặc tương tác từ giọng nói sang giọng nói. Giải quyết những nhu cầu này bằng cách sử dụng Các giao thức này thích hợp hơn cho đầu vào và đầu ra đa phương thức liên tục. API thời gian thực của OpenAI WebSockets API thời gian thực của OpenAI Since our system focuses exclusively on Chúng tôi gắn bó với vì sự đơn giản, tương thích và phù hợp với mô hình phát trực tuyến của chúng tôi. text-based interactions SSE Trả lời Stream Content Với được chọn như là lớp vận chuyển, bước tiếp theo là xác định Hiệu quả streaming đòi hỏi nhiều hơn chỉ là văn bản thô - nó cần cung cấp đủ để hỗ trợ người tiêu dùng tiếp theo như giao diện người dùng và các công cụ tự động hóa. Stream phải bao gồm thông tin sau: SSE what structure, metadata, and context Header-Level Metadata: Thông tin nhận dạng cơ bản như yêu cầu ID. Nội dung thực tế Chunks. đầu ra cốt lõi - các token hoặc chuỗi được tạo ra bởi mô hình - được cung cấp dần dần khi các chuỗi (n) được phát trực tiếp trở lại, chunk-by-chunk. Mỗi thế hệ có thể bao gồm nhiều chuỗi (ví dụ, n = 2, n = 4) .Những chuỗi này được tạo ra độc lập và phát trực tiếp song song, mỗi phân chia thành tập hợp của riêng mình của các phần gia tăng. Sử dụng và Token-Level Metadata. Điều này bao gồm số lượng token được tạo ra, dữ liệu thời gian, và chẩn đoán tùy chọn như logprobs hoặc lý luận theo dõi. Sau khi xác định cấu trúc của phản ứng phát trực tuyến, chúng tôi cũng xem xét một số yêu cầu phi chức năng cần thiết cho độ tin cậy và sự tiến hóa trong tương lai. Thiết kế dòng chảy của chúng tôi được thiết kế để: Cấu trúc – phân biệt rõ ràng giữa các loại nội dung và ranh giới sự kiện. Có thể mở rộng – có thể mang theo các siêu dữ liệu tùy chọn mà không phá vỡ các khách hàng hiện có. Độ bền: Khả năng chống lại dữ liệu bị lỗi, bị chậm trễ hoặc một phần. Trong nhiều ứng dụng - như hoặc - Nhiều chuỗi (hoàn thành) được tạo song song như một phần của một yêu cầu thế hệ duy nhất. side-by-side comparison diverse sampling Định dạng toàn diện nhất cho các phản hồi phát trực tuyến được xác định trong Theo thông số kỹ thuật, một chunk thế hệ duy nhất có thể bao gồm nhiều chuỗi trong Array : OpenAI API tham khảo choices OpenAI API tham khảo Lựa chọn Array Một danh sách các tùy chọn hoàn thành trò chuyện. Có thể chứa nhiều hơn một yếu tố nếu n lớn hơn 1. choices array Một danh sách các tùy chọn hoàn thành trò chuyện. Có thể chứa nhiều hơn một yếu tố nếu n lớn hơn 1. Mặc dù, trong thực tế, các mảnh cá nhân thường chỉ chứa một delta duy nhất, định dạng cho phép nhiều bản cập nhật chuỗi mỗi mảnh. Điều quan trọng là phải tính đến điều này, vì các bản cập nhật trong tương lai có thể sử dụng rộng rãi hơn khả năng này. is designed to support this structure. official Python SDK official Python SDK Chúng tôi đã chọn theo cùng một cấu trúc để đảm bảo khả năng tương thích với một loạt các tính năng tiềm năng. Biểu đồ dưới đây minh họa một ví dụ từ việc thực hiện của chúng tôi, nơi một thế hệ duy nhất bao gồm ba chuỗi, được phát trực tuyến trong sáu phần theo thời gian: Chunk 1 — Generation Start. Chunk này đánh dấu sự khởi đầu của toàn bộ thế hệ. Nó không chứa bất kỳ nội dung thực tế nào nhưng bao gồm các siêu dữ liệu được chia sẻ, chẳng hạn như ID thế hệ, timestamp, và vai trò (ví dụ, trợ lý, v.v.). Two sequences begin streaming in parallel. Each is tagged with a unique identifier to distinguish it from others. Chunk 2 — Sequence Start (Green & Purple). Chunk 3 — Sequence Start (Blue) & Sequence Delta. Sequence thứ ba bắt đầu (blue), trong khi hai chuỗi đầu tiên (xanh và tím) dòng nội dung gia tăng thông qua các sự kiện delta. The green and blue sequences continue streaming deltas. The purple sequence finishes — this includes a structured finish_reason (like stop, length, etc.). Chunk 4 — Midstream Updates & Finish (Purple). Chunk 5 – Remaining Sequence Finishes. Cả hai chuỗi màu xanh lá cây và màu xanh lá cây hoàn tất. chu kỳ cuộc sống của mỗi chuỗi bây giờ được đóng hoàn toàn giữa các dấu bắt đầu và kết thúc tương ứng của nó. Chunk 6 – Generation Finish. Chunk này đóng thế hệ và có thể bao gồm thống kê sử dụng toàn cầu, số lượng token cuối cùng, thông tin độ trễ hoặc chẩn đoán khác. Như bạn có thể thấy, để làm cho dòng mạnh mẽ và dễ dàng phân tích, chúng tôi đã chọn , thay vì dựa vào các cơ chế ngụ ý như kiểm tra không, EOFs, hoặc token ma thuật. cách tiếp cận có cấu trúc này đơn giản hóa phân tích xuống, đặc biệt là trong các môi trường nơi nhiều kết thúc được phát trực tuyến song song, và cũng cải thiện khả năng gỡ lỗi và cách ly lỗi trong quá trình phát triển và kiểm tra thời gian chạy. explicitly signal Start and Finish events for both the overall generation and each individual sequence Moreover, we introduce an additional chunk that carries structured information about failures. Some errors — such as malformed requests or authorization issues — can be surfaced directly via standard HTTP response codes. However, if an error occurs , we have two options: either abruptly terminate the HTTP stream or emit a well-formed SSE error event. We chose the latter. Abruptly closing the connection makes it hard for clients to distinguish between network issues and actual model/service failures. By using a dedicated error chunk, we enable more reliable detection and propagation of issues during streaming. Error during the generation process Backend Services and Request Flow At the center of the system is a single entrypoint: . It handles basic concerns like authentication, usage tracking and quota enforcement, request formatting, and routing based on the specified model. While it may look like the Gateway carries a lot of responsibility, each task is intentionally simple and modular. For external providers, it adapts requests to their APIs and maps responses back into a unified format. For self-hosted models, requests are routed directly to internal systems using our own unified schema. This design allows seamless support for both external and internal models through a consistent interface. LLM-Gateway Self-Hosted Models Như đã đề cập trước đó, is well-suited for streaming responses to end users, but it’s not a practical choice for . When a request arrives, it must be routed to a suitable worker node for model inference, and the result streamed back. While some systems handle this using chained HTTP proxies and header-based routing, in our experience, this approach becomes difficult to manage and evolve as the logic grows in complexity. Server-Sent Events (SSE) internal backend communication Our internal infrastructure needs to support: Lập lịch nhận thức ưu tiên - Yêu cầu có thể có mức độ cấp bách khác nhau (ví dụ, tương tác so với hàng loạt), và các nhiệm vụ ưu tiên cao phải được xử lý trước. — Certain nodes run on higher-performance GPUs and should be preferred; others serve as overflow capacity. Hardware-aware routing Phân phối mô hình cụ thể – Mỗi nhân viên được cấu hình để chỉ hỗ trợ một tiểu tập mô hình, dựa trên khả năng tương thích phần cứng và hạn chế tài nguyên. Để đáp ứng các yêu cầu này, chúng tôi sử dụng một to decouple task routing from result delivery. This design provides better flexibility and resilience under varying load and routing conditions. We use cho mục đích này, mặc dù các nhà môi giới khác cũng có thể khả thi tùy thuộc vào độ trễ, thông lượng và sở thích hoạt động của bạn. RabbitMQ là một sự phù hợp tự nhiên do sự trưởng thành và phù hợp với công cụ hiện có của chúng tôi. message broker thỏ RabbitMQ thỏ Bây giờ chúng ta hãy xem xét kỹ hơn cách hệ thống này được thực hiện trong thực tế: We use , cho phép chúng tôi định tuyến các yêu cầu dựa trên khả năng tương thích mô hình và khả năng nút. dedicated queues per model The LLM-Gateway service (represented as the user) initiates an HTTP request to trigger a text generation task. starts a new to manage this request. Client Sends Request. Scheduler service Request Handler Task Routing thông qua dịch vụ Scheduler. yêu cầu được xử lý bởi Scheduler, người chọn hàng đợi thích hợp (được đánh dấu bằng màu xanh lá cây trên hình ảnh) dựa trên mô hình được yêu cầu và đính kèm thông điệp cho nó. An appropriate (only one worker is shown for simplicity, but there are many) subscribed to the queue picks up the task and begins processing. This worker runs the selected model locally. Worker Picks Up Task. Inference Worker Streaming the Response.The worker streams the response chunk-by-chunk into the Response Queue, to which the Scheduler replica handling the request is subscribed.Công nhân streams the response chunk-by-chunk into the Response Queue, to which the Scheduler replica handling the request is subscribed. The Scheduler listens to the reply queue and receives the response chunks as they arrive. Receiving Response Chunks. The chunks are converted to SSE format and streamed to the client. SSE Streaming. To handle , chúng tôi tránh áp đảo các thông điệp môi giới: large payloads Thay vì nhúng dữ liệu đầu vào hoặc đầu ra lớn trực tiếp vào nhiệm vụ, chúng tôi tải nó lên một cửa hàng tương thích S3 bên ngoài. A reference (such as a URL or resource ID) is included in the task metadata, and the worker retrieves the actual content when needed. Applying the Design with RabbitMQ Khi nói đến Mỗi người là một RabbitMQ thường xuyên , dedicated to handling a single model type. We require , which can be achieved using Trong thiết lập này, các thông điệp có giá trị ưu tiên cao hơn được gửi và xử lý trước các giá trị ưu tiên thấp hơn. , nơi tin nhắn nên được chuyển đến các nút có hiệu suất cao nhất trước, can help. Consumers with higher priority receive messages as long as they are active; lower-priority consumers only receive messages when the higher-priority ones are blocked or unavailable. routing and publishing messages Request Queue đuôi priority-aware scheduling Thông điệp ưu tiên hardware-aware routing ưu tiên của người tiêu dùng đuôi Thông điệp ưu tiên ưu tiên của người tiêu dùng If message loss is unacceptable, the following must be in place: Nhà xuất bản xác nhận để đảm bảo rằng nhà môi giới đã nhận và lưu trữ thông điệp. Hàng đợi lâu dài và tin nhắn dai dẳng để dữ liệu tồn tại khởi động lại. for stronger durability through replication. These also support . Quorum queues simplified message and consumer priorities as of RabbitMQ 4.0 Nhà xuất bản xác nhận Nhà xuất bản xác nhận Quorum đuôi Quorum queues Thông điệp đơn giản và ưu tiên của người tiêu dùng từ RabbitMQ 4.0 So far, we’ve covered how tasks are published — but how is the Bước đầu tiên là hiểu làm thế nào work in RabbitMQ. The broker supports a concept called , which are bound to a single connection and automatically deleted when that connection closes. This makes them a natural fit for our setup. streamed response temporary queues exclusive queues exclusive queues Exclusive hàng Chúng tôi tạo , ensuring it’s automatically cleaned up when the replica shuts down. However, this introduces a challenge: while each service replica has a single RabbitMQ queue, it must handle . one exclusive queue per Scheduler service replica many requests in parallel Để giải quyết vấn đề này, chúng tôi xử lý chuỗi RabbitMQ như một , định tuyến các câu trả lời đến bản sao đúng của Scheduler. Mỗi yêu cầu người dùng được gán một , which is included in every response chunk. Inside the Chúng tôi duy trì thêm một với hàng đợi trong bộ nhớ ngắn - một cho mỗi yêu cầu đang hoạt động. hàng đợi đến được khớp với những hàng đợi này dựa trên ID và được chuyển tiếp tương ứng. những hàng đợi trong bộ nhớ này được loại bỏ sau khi yêu cầu hoàn thành, trong khi hàng đợi RabbitMQ vẫn tồn tại trong suốt cuộc đời của bản sao dịch vụ. transport layer unique identifier Scheduler in-memory routing layer Schematically this looks as follows: A central dispatcher within the Scheduler dispatches chunks to the appropriate in-memory queue, each managed by a dedicated handler. Handlers then stream the chunks to users using SSE-protocol. Inference There are several mature frameworks available for efficient LLM inference, such as and . These systems are designed to và tạo token phản hồi trong thời gian thực, thường với các tính năng như loạt liên tục và tối ưu hóa bộ nhớ GPU. như là động cơ kết luận cốt lõi, với một số sửa đổi tùy chỉnh: VLLM Thỏa thuận process multiple sequences in parallel vLLM vLLM VLLM Thỏa thuận Thỏa thuận Thực hiện tìm kiếm chùm tùy chỉnh - để phù hợp hơn với logic thế hệ của chúng tôi và hỗ trợ các hạn chế có cấu trúc. Hỗ trợ cho các sơ đồ đầu ra có cấu trúc – cho phép các mô hình trả về đầu ra phù hợp với các định dạng cụ thể cho doanh nghiệp. Thông qua kinh nghiệm, chúng tôi đã học được rằng ngay cả các bản cập nhật thư viện nhỏ cũng có thể — cho dù trong chất lượng sản xuất, chủ nghĩa xác định, hoặc hành vi đồng thời. Do đó, chúng tôi đã thiết lập một đường ống thử nghiệm mạnh mẽ: significantly alter model behavior Kiểm tra căng thẳng để phát hiện các vấn đề đồng thời, rò rỉ bộ nhớ hoặc hồi quy ổn định. to ensure consistent outputs for fixed seeds and parameter sets. Determinism testing to cover a wide range of generation settings, without going overboard. Parameter grid testing Lưu trữ và triển khai Hầu hết các hệ thống hiện đại chạy trong — trong đám mây hoặc trong Kubernetes (K8s). mặc dù thiết lập này hoạt động tốt cho các dịch vụ backend điển hình, nó giới thiệu những thách thức xung quanh . LLM models can be , và mô hình nướng nặng trực tiếp vào hình ảnh Docker - nhanh chóng trở nên rắc rối: containerized environments model weight storage tens or even hundreds of gigabytes in size Xây dựng chậm - Ngay cả với xây dựng nhiều giai đoạn và bộ nhớ đệm, chuyển các tệp mô hình lớn trong giai đoạn xây dựng có thể làm tăng đáng kể thời gian CI. — Each rollout requires pulling massive images, which can take several minutes and cause downtime or delays. Slow deployments — Neither Docker registries nor Kubernetes nodes are optimized for handling extremely large images, resulting in bloated storage usage and bandwidth strain. Resource inefficiency Để giải quyết vấn đề này, chúng tôi tách từ vòng đời hình ảnh Docker. Mô hình của chúng tôi được lưu trữ trong một , và thu thập ngay trước khi khởi động dịch vụ suy luận. Để cải thiện thời gian khởi động và tránh tải xuống dư thừa, chúng tôi cũng sử dụng để lưu trữ trọng lượng mô hình trên mỗi nút. model storage external S3-compatible object storage Lượng vĩnh viễn địa phương (Public Persistent Volumes - PVCs) Lượng vĩnh viễn địa phương (Public Persistent Volumes - PVCs) Lượng vĩnh viễn địa phương (Public Persistent Volumes - PVCs) quan sát Một hệ thống như thế này - được xây dựng trên - Yêu cầu Để đảm bảo độ tin cậy và hiệu suất trên quy mô. streaming, message queues, and real-time token generation robust observability In addition to standard service-level metrics (CPU, memory, error rates, etc.), we found it essential to monitor the following: Độ sâu hàng đợi, backlog tin nhắn và số lượng người tiêu dùng - theo dõi số lượng tin nhắn đang chờ, kích thước hàng đợi hiện tại và số lượng người tiêu dùng đang hoạt động giúp phát hiện các chướng ngại vật phân phối nhiệm vụ và sự mất cân bằng trong việc sử dụng nhân viên. Token/chunk throughput – theo dõi số lượng token hoặc phần phản hồi được tạo ra mỗi giây giúp xác định độ trễ hoặc sự hồi quy thông qua. — to pinpoint where requests fail or stall across components (gateway, broker, workers, etc.). phân phối tracking Kiểm tra sức khỏe động cơ suy đoán – vì các quy trình suy đoán có thể bị hỏng trong điều kiện hiếm hoi (ví dụ, đầu vào kém hoặc giá trị tham số cực đoan), giám sát chủ động về tính sống động và sự sẵn sàng là rất quan trọng. phân phối tracking phân phối tracking Further Improvements Trong khi hệ thống của chúng tôi đã sẵn sàng sản xuất, vẫn còn những thách thức và cơ hội quan trọng để tối ưu hóa: Using a to boost inference performance. distributed KV-cache Supporting to conserve compute when outputs are no longer needed. request cancellation Tạo một đường ống phân phối mô hình đơn giản cho các nhóm khoa học dữ liệu. Conclusion Trong khi xây dựng một hệ thống phục vụ LLM đáng tin cậy và độc lập với nhà cung cấp có vẻ phức tạp lúc đầu, nó không đòi hỏi phải phát minh lại bánh xe. Mỗi thành phần - phát trực tuyến thông qua SSE, phân phối nhiệm vụ thông qua các nhà môi giới tin nhắn và kết luận được xử lý bởi thời gian chạy như vLLM - phục vụ một mục đích rõ ràng và được dựa trên các công cụ hiện có, được hỗ trợ tốt. In the next post, we’ll explore more advanced topics such as distributed KV-caching, handling multiple models across replicas, and deployment workflows suited to ML-oriented teams. tác giả Tochka , Ông Stanislav Shimovolos Ông Stanislav Shimovolos Ông Stanislav Shimovolos Tochka , Maxim Afanasyev Maxim Afanasyev Tổng thống Maxim Afanasyev Công nhận Công việc làm tại Tochka Ông Dmitry Kryukov Ông Dmitry Kryukov Ông Dmitry Kryukov