
openjev-sglang là gì?
openjev-sglang là một máy chủ triển khai HTTP API của TypeSafe/Jev bằng Qwen3.6-35B-A3B trên SGLang. Nó chuyển các câu hỏi phân loại thành kết quả xác suất token đầu tiên hiệu quả, thay vì tạo ra các phản hồi dài.
Triển khai mặc định chạy một container SGLang trên mỗi GPU NVIDIA B200. SGLang 0.5.19 cung cấp frontend Rust, bộ nhớ đệm radix và các CUDA graph prefill có thể ngắt. Một tiến trình Python riêng xử lý API công khai bằng FastAPI, uvloop, tokenizer Hugging Face chạy trên Rust và các kết nối bất đồng bộ được gom nhóm tới SGLang trên localhost.
Không có yêu cầu nào được gửi tới TypeSafe. Endpoint công khai cung cấp evaluation API, trong khi các route tạo sinh và quản trị của SGLang vẫn ở chế độ riêng tư trên localhost.
Tính năng chính
- Ba loại đánh giá: Noul cho xác suất có/không, Choice cho lựa chọn phân loại và Score cho các mức theo thứ tự.
- Suy luận một token: mỗi câu hỏi được đánh giá từ log probability của các nhãn câu trả lời mà không tạo chuỗi suy luận.
- Bộ nhớ đệm tiền tố dùng chung: một tiền tố prompt chung được làm nóng trước khi các nhánh câu hỏi chạy đồng thời.
- Tối đa 64 câu hỏi: theo mặc định, câu hỏi Choice và Score hỗ trợ từ 2 đến 64 câu trả lời.
- Trạng thái có cấu trúc: state và instructions có thể là chuỗi, đối tượng JSON hoặc mảng.
- Endpoint vận hành: health, liveness, danh mục model, giới hạn, lược đồ OpenAPI, Swagger UI và tài liệu tham chiếu Scalar tương tác được tích hợp sẵn.
- Triển khai Modal: ứng dụng được cung cấp hỗ trợ tự động mở rộng, bộ nhớ đệm model bền vững, khôi phục khi khởi động và scale-to-zero.
- Bảo vệ có thể cấu hình: hỗ trợ giới hạn yêu cầu, kiểm soát số lượng kết nối đồng thời, timeout và xác thực Bearer tùy chọn.
Điều kiện tiên quyết
Cài đặt uv và tạo tài khoản Modal nếu bạn định sử dụng triển khai đám mây được cung cấp. Lần build đầu tiên sẽ import một image SGLang lớn, còn lần khởi động GPU đầu tiên sẽ tải trọng số model và biên dịch hoặc ghi lại các kernel.
Các dependency CUDA vẫn nằm trong container SGLang. Chạy uv sync trên máy trạm chỉ cài đặt API, các tiện ích triển khai và các bài kiểm thử.
Cài đặt dự án
Clone repository, truy cập thư mục của repository rồi đồng bộ môi trường Python:
uv sync
Nếu Modal chưa được xác thực trên máy hiện tại, hãy hoàn tất thiết lập:
uv run modal setup
Chạy triển khai Modal tạm thời
Để kiểm thử đầu cuối, hãy khởi động một máy chủ tạm thời, chạy các kiểm tra suy luận đi kèm rồi tắt máy chủ sau đó:
uv run modal run modal_app.py
Lệnh này lưu báo cáo smoke test dưới dạng smoke-result.json. Báo cáo bao gồm thời gian chờ khởi động, độ trễ suy luận và thông tin khả dụng về việc sử dụng bộ nhớ đệm.
Triển khai endpoint ổn định
Triển khai ứng dụng dưới dạng dịch vụ Modal liên tục:
uv run modal deploy modal_app.py
Bản triển khai sẽ in ra một URL tương tự https://YOUR-SERVER.us-west.modal.direct. Lưu URL này vào biến môi trường để tiện sử dụng:
export OPENJEV_URL="https://YOUR-SERVER.us-west.modal.direct"
Endpoint Modal mặc định cố ý không yêu cầu xác thực. Endpoint sử dụng vùng định tuyến US West và có thể lập lịch tính toán tại các vùng US đã cấu hình. Không có giới hạn container cụ thể, các instance sẽ scale về zero sau năm phút không hoạt động.
Máy chủ đã scale về zero sẽ trả về HTTP 503 trong khi khởi động. Lệnh smoke đi kèm tự động thử lại các phản hồi khởi động này.
Chạy smoke test với URL đã triển khai:
uv run openjev smoke "$OPENJEV_URL"
Smoke test kiểm tra cả ba loại câu trả lời, kiểm tra một câu hỏi có 64 câu trả lời, thực hiện các kiểm tra ngữ nghĩa cơ bản và xác minh rằng 65 câu trả lời bị từ chối.
Gửi đánh giá đầu tiên
Route chính là POST /v1/systemone. Yêu cầu sau phân loại tin nhắn của khách hàng bằng các câu hỏi Noul, Choice và Score:
curl "$OPENJEV_URL/v1/systemone" \
-H 'Content-Type: application/json' \
-d '{
"model": "jev-latest",
"state": [
{"role": "system", "content": "You are a support assistant."},
{"role": "user", "content": "I was charged twice. Please refund the duplicate."}
],
"questions": {
"refund": {
"type": "noul",
"instructions": "Does the user request a refund?"
},
"department": {
"type": "choice",
"instructions": "Which department should handle this?",
"criteria": {
"billing": "Payments and refunds",
"technical": "Software bugs"
}
},
"urgency": {
"type": "score",
"instructions": "How urgent is the request?",
"criteria": ["Routine", "Urgent", "Emergency"]
}
}
}'
Bạn cũng có thể lưu JSON vào một file và gửi mà không cần escape shell:
curl "$OPENJEV_URL/v1/systemone" \
-H 'Content-Type: application/json' \
--data-binary @examples/request.json
Tìm hiểu các loại câu hỏi
- Noul: trả về xác suất chuẩn hóa của
yes. - Choice: trả về tùy chọn có xác suất cao nhất cùng toàn bộ phân phối xác suất. Tên tùy chọn ban đầu được giữ nguyên trong phản hồi.
- Score: trả về mức kỳ vọng bắt đầu từ 0, được tính từ chỉ số của từng mức và xác suất tương ứng, cùng với chú giải.
Các tùy chọn được trình bày cho mô hình dưới dạng nhãn chữ cái kèm phần mô tả. Các khóa phản hồi thường được ẩn khỏi mô hình. Nếu phần mô tả của một tùy chọn là null, khóa của tùy chọn đó sẽ cung cấp ý nghĩa thay thế.
Cung cấp trạng thái và chỉ dẫn
Cả state và instructions đều chấp nhận chuỗi, đối tượng JSON hoặc mảng. Danh sách tin nhắn trò chuyện hoặc một đối tượng chứa chính xác {"messages": [...]} sẽ được dựng bằng mẫu trò chuyện gốc của mô hình.
Các vai trò và đối tượng tin nhắn ban đầu được giữ nguyên, đồng thời mỗi câu hỏi phân loại được thêm vào như một lượt người dùng khác. Các giá trị có cấu trúc khác được tuần tự hóa nguyên vẹn vào một tin nhắn người dùng. Một đối tượng chứa messages cùng các trường khác cũng được giữ nguyên để siêu dữ liệu không bị loại bỏ âm thầm.
Trạng thái trò chuyện chỉ hỗ trợ nội dung văn bản. Không hỗ trợ nội dung hình ảnh, âm thanh và video.
Khám phá các endpoint của dịch vụ
POST /v1/systemonethực hiện đánh giá Noul, Choice và Score.GET /v1/modelstrả về danh mục mô hình với các trường theo kiểu TypeSafe và OpenAI.GET /v1/limitsbáo cáo các giới hạn tiếp nhận.GET /healthbáo cáo trạng thái sẵn sàng, tình trạng SGLang và thời gian khởi động.GET /health/livekiểm tra API có đang hoạt động hay không.GET /mở tài liệu tham chiếu API Scalar với một ví dụ yêu cầu có thể chỉnh sửa.GET /docsmở giao diện Swagger UI tích hợp sẵn.GET /openapi.jsontrả về lược đồ OpenAPI được tạo tự động.
Tên mô hình yêu cầu jev-latest là bí danh tương thích. ID mô hình công khai mặc định là Qwen/Qwen3.6-35B-A3B, trong khi kho lưu trữ của NVIDIA được sử dụng nội bộ làm nguồn trọng số.
Cách hoạt động của suy luận
- API xác thực lược đồ, số lượng câu trả lời, kích thước nội dung, độ dài ngữ cảnh và ngân sách token tổng hợp.
- API dựng mẫu trò chuyện gốc một lần với chế độ suy nghĩ bị tắt, sau đó tách tiền tố dùng chung khỏi các hậu tố câu hỏi được mã hóa token độc lập.
- API gửi tiền tố chung đến SGLang với
max_new_tokens=1. Token được lấy mẫu sẽ bị loại bỏ, để lại tiền tố cho việc tái sử dụng radix cache khi phù hợp. - API gửi đồng thời một nhánh cho mỗi câu hỏi. Mỗi nhánh chứa tiền tố, hậu tố câu hỏi, phần đầu trợ lý và dấu đánh dấu
Answer:. - API chỉ yêu cầu xác suất log cho các nhãn câu trả lời hợp lệ và chuẩn hóa lại chúng bằng softmax ổn định.
Với N câu hỏi, máy chủ thực hiện N + 1 lần gọi một token: một lần gọi làm nóng cache và một lần gọi cho mỗi câu hỏi. Token được tạo ra bị bỏ qua, vì vậy không có quá trình tiếp diễn tự hồi quy hoặc chuỗi suy nghĩ được tạo ra. Giải mã suy đoán không được bật.
Các nhãn chạy từ A đến Z, sau đó sử dụng các tổ hợp một token đã được xác minh như AA và AB. Tất cả 64 nhãn đều được kiểm tra bằng tokenizer đang hoạt động trong quá trình khởi động. Điều này tránh việc sử dụng các nhãn số nhiều token như 10 hoặc 64.
Tìm hiểu mức sử dụng và chỉ số cache
Header phản hồi x-openjev-prefix-tokens báo cáo kích thước tiền tố chung được yêu cầu. Khi SGLang cung cấp số lượng cache, x-openjev-cached-tokens chứa tổng số lần cache trúng của các nhánh.
Frontend Rust của SGLang 0.5.19 không cung cấp các số lượng cache này. Trong cấu hình đó, header sẽ không xuất hiện và báo cáo smoke ghi nhận null, không phải số 0. Nhật ký bộ lập lịch vẫn có thể hiển thị các lần cache trúng thực tế. Header Server-Timing phân tách thời gian chuẩn bị prompt, prefill dùng chung và suy luận nhánh.
usage.input_tokens là tổng số lượng prompt hoàn chỉnh được báo cáo qua các lần gọi khởi động và gọi nhánh, bao gồm cả các token đã được cache. usage.output_tokens là N + 1. Các số liệu này mô tả hoạt động của backend thay vì số token được tính toán duy nhất hoặc các ước tính thanh toán của TypeSafe.
Cấu hình giới hạn và xác thực
Các giới hạn tiếp nhận mặc định bao gồm 64 câu hỏi, từ 2 đến 64 câu trả lời cho mỗi câu hỏi Choice hoặc Score, nội dung JSON 2 MiB, 32.768 token cho mỗi nhánh bao gồm đầu ra, tổng cộng 262.144 token đầu vào được gửi, 16 lượt đánh giá đồng thời và 64 lệnh gọi backend đồng thời.
Yêu cầu không hợp lệ trả về HTTP 422 trước khi suy luận. Nội dung vượt quá giới hạn kích thước trả về 413, tình trạng quá tải trả về 529 cùng Retry-After, còn thời gian chờ backend trả về 504. Các lượt đánh giá thất bại hoặc bị hủy sẽ hủy các nhánh cùng nhóm và cố gắng dừng chúng trong SGLang.
Có thể cấu hình thông qua các biến môi trường OPENJEV_*. Các cài đặt phổ biến gồm:
OPENJEV_MODEL: mặc định lànvidia/Qwen3.6-35B-A3B-NVFP4.OPENJEV_SERVED_MODEL_NAME: ghi đè ID mô hình công khai và được truyền cho SGLang.OPENJEV_REVISION: chọn bản sửa đổi checkpoint cố định.OPENJEV_FRONTEND: mặc định làrust;pythonlà phương án dự phòng được chỉ định rõ.OPENJEV_MAX_INPUT_TOKENS: mặc định là32768.OPENJEV_MAX_TOTAL_INPUT_TOKENS: mặc định là262144.OPENJEV_MAX_CONCURRENT_REQUESTS: mặc định là16.OPENJEV_MAX_CONCURRENT_BRANCHES: mặc định là64.OPENJEV_REQUEST_TIMEOUT: mặc định là120giây.OPENJEV_TEMPERATURE: mặc định là1.0và ảnh hưởng đến việc chuẩn hóa nhãn.OPENJEV_API_KEY: bật xác thực Bearer tùy chọn cho API công khai.OPENJEV_BACKEND_API_KEY: cấu hình khóa Bearer tùy chọn riêng cho SGLang.
Trình khởi chạy Modal tự động chuyển tiếp OPENJEV_PROFILE, OPENJEV_FRONTEND và OPENJEV_SERVED_MODEL_NAME từ môi trường cục bộ. Thêm các cài đặt từ xa khác vào image.env(...) hoặc sử dụng Modal Secret cho thông tin xác thực.
Chạy cục bộ với backend SGLang hiện có
Để sử dụng backend đang chạy, trỏ API đến URL cục bộ của backend:
uv run openjev serve --connect http://127.0.0.1:30000
Backend phải sử dụng phiên bản model và tokenizer tương ứng. Backend cũng phải hỗ trợ log probability của các token được chọn, bộ nhớ đệm radix và độ dài ngữ cảnh đủ lớn.
Trên máy chủ hoặc container B200 đã cài SGLang 0.5.19 trong một môi trường Python riêng, hãy chỉ định rõ trình thông dịch:
uv run openjev serve --sglang-python /path/to/sglang/bin/python
Phát triển và xác thực
Sử dụng các lệnh đi kèm để chạy kiểm thử ngoại tuyến, kiểm tra tích hợp tokenizer, lint và tạo schema:
uv run pytest
uv run pytest -m integration
uv run ruff check .
uv run openjev schema
Các bài kiểm thử thông thường bao quát hành vi của unit và API ở chế độ ngoại tuyến. Kiểm thử tích hợp sử dụng tokenizer thực và tải xuống một mô hình nhỏ từ Hugging Face, nhưng không yêu cầu GPU. Việc tạo schema cũng không yêu cầu GPU hay tải xuống mô hình.
Mẹo triển khai nâng cao
Giữ container GPU luôn sẵn sàng
Modal thu nhỏ dịch vụ về 0 sau năm phút không hoạt động. Đặt min_containers=1 trong modal_app.py khi độ trễ khởi động luôn thấp quan trọng hơn việc tránh sử dụng GPU nhàn rỗi.
Dự kiến quá trình khởi tạo ở lần chạy đầu
Lần khởi động GPU đầu tiên sẽ tải xuống trọng số và biên dịch hoặc chụp kernel. Trọng số mô hình, dữ liệu tinh chỉnh SGLang và dữ liệu biên dịch Triton được lưu trong Modal Volume openjev-huggingface. Các lần khởi động sau sử dụng lại những tệp này, dù việc chụp đồ thị CUDA vẫn diễn ra khi khởi động.
Coi việc tái sử dụng bộ nhớ đệm là cơ hội, không phải bảo đảm
Việc tái sử dụng radix không phải là một phiên KV được ghim riêng cho từng yêu cầu. Trạng thái lặp lại trong mô hình Qwen lai, ranh giới trang bộ nhớ đệm, áp lực bộ nhớ đệm và lưu lượng đồng thời có thể làm giảm số lần truy cập trúng bộ nhớ đệm. Backend sử dụng --mamba-radix-cache-strategy extra_buffer.
Diễn giải độ tin cậy cẩn thận
OpenJev định nghĩa độ tin cậy là 1 - H(probabilities) / log(number_of_options), được giới hạn trong khoảng từ 0 đến 1. Phân phối xác suất đồng đều cho độ tin cậy bằng 0, còn phân phối tập trung hoàn toàn cho độ tin cậy bằng 1.
Các xác suất này được điều kiện hóa theo các tùy chọn đã cung cấp và có thể phụ thuộc vào cách diễn đạt prompt cũng như thứ tự nhãn. Đây không phải là các ước lượng độ chính xác đã được hiệu chuẩn.
Lập kế hoạch cho sự cố backend
Nếu SGLang thoát bất ngờ, API cũng sẽ thoát. Sau đó, trình khởi chạy Modal sẽ chấm dứt container để Modal có thể thay thế container, thay vì để một tiến trình HTTP công khai kết nối với backend suy luận đã chết. Khi tắt bình thường, cả hai watcher đều được vô hiệu hóa một cách gọn gàng.
Kết luận
openjev-sglang cung cấp một cách chuyên biệt để chạy phân loại tương thích với Jev trên Qwen3.6, với khả năng đọc xác suất một token hiệu quả. Cấu hình Modal hỗ trợ triển khai B200 có khả năng mở rộng, trong khi các lệnh cục bộ hỗ trợ kiểm thử và kết nối với dịch vụ SGLang hiện có. Hãy bắt đầu bằng smoke test, xác thực các giới hạn và cài đặt xác thực của bạn, đồng thời theo dõi thời gian phản hồi và các header bộ nhớ đệm khi lưu lượng tăng.
