This tutorial deploys the Llama3.1-8B model with Flash Attention on Ray Serve using RBLN NPUs.
The workflow covers:
Verifying the environment and compiled model.
Defining a Ray Serve deployment that targets RBLN hardware.
Launching the application with the Serve CLI.
Sending an inference request to validate the endpoint.
If you need help configuring Ray Serve itself, review the Ray Serve overview first. For a complete script-based example (from compilation to deployment), see the model zoo reference.
The following sections assume you already understand how to compile and execute models with the RBLN SDK. Revisit the RBLN Optimum and the vLLM guide if you need a refresher.
Compile the Llama3.1-8B model using optimum-rbln. This code is based on the Rebellions Model Zoo.
The following parameters are used to compile the Llama3.1-8B model:
export: Must be True to compile the model.
rbln_batch_size: Defines the batch size to use for compilation.
rbln_max_seq_len: Specifies the maximum sequence length.
rbln_num_devices: Sets the number of NPUs to use for inference.
rbln_kvcache_partition_len: Defines the length of KV cache partitions for flash attention. rbln_max_seq_len must be a multiple of rbln_kvcache_partition_len and greater than rbln_kvcache_partition_len.
Note
You need to select an appropriate batch size. In this case, it is set to 1.
importosfromoptimum.rblnimportRBLNLlamaForCausalLMmodel_id="meta-llama/Llama-3.1-8B-Instruct"# Compile and exportmodel=RBLNLlamaForCausalLM.from_pretrained(model_id=model_id,export=True,rbln_batch_size=1,rbln_max_seq_len=131_072,rbln_num_devices=1,rbln_kvcache_partition_len=8_192,)# Save compiled results to diskmodel.save_pretrained(os.path.basename(model_id))
importosfromoptimum.rblnimportRBLNLlamaForCausalLMmodel_id="meta-llama/Llama-3.1-8B-Instruct"# Compile and exportmodel=RBLNLlamaForCausalLM.from_pretrained(model_id=model_id,export=True,rbln_batch_size=1,rbln_max_seq_len=131_072,rbln_num_devices=8,rbln_kvcache_partition_len=16_384,)# Save compiled results to diskmodel.save_pretrained(os.path.basename(model_id))
Ray exposes custom accelerators through the resources argument, so each task or deployment can request exactly the hardware it needs.
The Actor below shows how to request RBLN resources with @ray.remote(resources={"RBLN": <NUM_NPUS>}), where <NUM_NPUS> matches the rbln_num_devices value used at compile time. The companion RBLNActor helper retrieves the assigned device ID and passes it to the Serve deployment. See RBLN NPUs with Ray for additional background.
Ray Serve deployments are defined by annotating a class or function with @serve.deployment. This decorator registers the class as a Ray Serve service endpoint, allowing Ray Serve to manage the lifecycle (deployment, scaling, updates).
importjsonimportosfromunittest.mockimportMagicMockimportrayfromfastapiimportFastAPI,HTTPExceptionfromrayimportservefromstarlette.requestsimportRequestfromstarlette.responsesimportStreamingResponsefromvllmimportAsyncEngineArgs,AsyncLLMEnginefromvllm.entrypoints.openai.chat_completion.protocolimport(ChatCompletionRequest,ChatCompletionResponse,)fromvllm.entrypoints.openai.chat_completion.servingimportOpenAIServingChatfromvllm.entrypoints.openai.completion.protocolimportCompletionRequestfromvllm.entrypoints.openai.completion.servingimportOpenAIServingCompletionfromvllm.entrypoints.openai.models.protocolimportBaseModelPathfromvllm.entrypoints.openai.models.servingimportOpenAIServingModelsfromvllm.entrypoints.serve.engine.protocolimportErrorResponsefromvllm.renderers.online_rendererimportOnlineRendererapp=FastAPI()ray.init(resources={"RBLN":1})@ray.remote(resources={"RBLN":1})classRBLNActor:defgetDeviceId(self):returnray.get_runtime_context().get_accelerator_ids()["RBLN"]@serve.deployment(num_replicas=1,ray_actor_options={"num_cpus":16})@serve.ingress(app)classLlama3_1__8B:def__init__(self,rbln_actor:RBLNActor):""" Initialize actor. :return: """self.engine=Noneself.rbln_actor=rbln_actorself.model_name="Llama-3.1-8B-Instruct"self.raw_request=Noneself.vllm_engine=Noneself.openai_serving_models=Noneself.completion_service=Noneself.chat_completion_service=Noneself.ids=ray.get(rbln_actor.getDeviceId.remote())self.os_environment_vars()self.initialize()defos_environment_vars(self):""" Redefine the environment variables to be passed to the RBLN runtime and vLLM :return: """ifself.idsisNoneorlen(self.ids)<=0:os.environ.pop("RBLN_DEVICES")os.environ["RBLN_DEVICES"]=",".join(self.ids)os.environ["VLLM_WORKER_MULTIPROC_METHOD"]="spawn"definitialize(self):""" Initialize model. This will be called during model loading time :return: """vllm_engine_args=AsyncEngineArgs(model=self.model_name)self.vllm_engine=AsyncLLMEngine.from_engine_args(vllm_engine_args)self.openai_serving_models=OpenAIServingModels(engine_client=self.vllm_engine,base_model_paths=[BaseModelPath(name=self.model_name,model_path=os.getcwd())],)openai_serving_render=OnlineRenderer(model_config=self.vllm_engine.model_config,renderer=self.vllm_engine.renderer,request_logger=None,chat_template=None,chat_template_content_format="auto",)self.completion_service=OpenAIServingCompletion(self.vllm_engine,self.openai_serving_models,online_renderer=openai_serving_render,request_logger=None,)self.chat_completion_service=OpenAIServingChat(self.vllm_engine,self.openai_serving_models,"assistant",online_renderer=openai_serving_render,request_logger=None,chat_template_content_format="auto",chat_template=None,)asyncdefisd():returnFalseself.raw_request=MagicMock()self.raw_request.headers={}self.raw_request.is_disconnected=isd@app.post("/v1/chat/completions")asyncdefchat_completion(self,http_request:Request):""" Handle chat completion request. :param http_request: The HTTP request object :return: The chat completion response """try:json_string:dict=awaithttp_request.json()exceptjson.JSONDecodeError:raiseHTTPException(status_code=400,detail="Invalid JSON format request")request:ChatCompletionRequest=ChatCompletionRequest.model_validate(json_string)g=awaitself.chat_completion_service.create_chat_completion(request,self.raw_request)ifisinstance(g,ErrorResponse):return[g.model_dump()]ifrequest.stream:asyncdefstream_generator():asyncforresponseing:yieldresponsereturnStreamingResponse(stream_generator(),media_type="text/event-stream")else:return[g.model_dump()]@app.post("/v1/completions")asyncdefcompletion(self,http_request:Request):""" Handle completion request. :param http_request: The HTTP request object :return: The completion response """try:json_string:dict=awaithttp_request.json()exceptjson.JSONDecodeError:raiseHTTPException(status_code=400,detail="Invalid JSON format request")request:CompletionRequest=CompletionRequest.model_validate(json_string)g=awaitself.completion_service.create_completion(request,self.raw_request)ifisinstance(g,ErrorResponse):return[g.model_dump()]ifrequest.stream:asyncdefstream_generator():asyncforresponseing:yieldresponsereturnStreamingResponse(stream_generator(),media_type="text/event-stream")else:return[g.model_dump()]rbln_actor=RBLNActor.remote()app=Llama3_1__8B.bind(rbln_actor)
importjsonimportosfromunittest.mockimportMagicMockimportrayfromfastapiimportFastAPI,HTTPExceptionfromrayimportservefromstarlette.requestsimportRequestfromstarlette.responsesimportStreamingResponsefromvllmimportAsyncEngineArgs,AsyncLLMEnginefromvllm.entrypoints.openai.chat_completion.protocolimport(ChatCompletionRequest,ChatCompletionResponse,)fromvllm.entrypoints.openai.chat_completion.servingimportOpenAIServingChatfromvllm.entrypoints.openai.completion.protocolimportCompletionRequestfromvllm.entrypoints.openai.completion.servingimportOpenAIServingCompletionfromvllm.entrypoints.openai.models.protocolimportBaseModelPathfromvllm.entrypoints.openai.models.servingimportOpenAIServingModelsfromvllm.entrypoints.serve.engine.protocolimportErrorResponsefromvllm.renderers.online_rendererimportOnlineRendererapp=FastAPI()ray.init(resources={"RBLN":8})@ray.remote(resources={"RBLN":8})classRBLNActor:defgetDeviceId(self):returnray.get_runtime_context().get_accelerator_ids()["RBLN"]@serve.deployment(num_replicas=1,ray_actor_options={"num_cpus":16})@serve.ingress(app)classLlama3_1__8B:def__init__(self,rbln_actor:RBLNActor):""" Initialize actor. :return: """self.engine=Noneself.rbln_actor=rbln_actorself.model_name="Llama-3.1-8B-Instruct"self.raw_request=Noneself.vllm_engine=Noneself.openai_serving_models=Noneself.completion_service=Noneself.chat_completion_service=Noneself.ids=ray.get(rbln_actor.getDeviceId.remote())self.os_environment_vars()self.initialize()defos_environment_vars(self):""" Redefine the environment variables to be passed to the RBLN runtime and vLLM :return: """ifself.idsisNoneorlen(self.ids)<=0:os.environ.pop("RBLN_DEVICES")os.environ["RBLN_DEVICES"]=",".join(self.ids)os.environ["VLLM_WORKER_MULTIPROC_METHOD"]="spawn"definitialize(self):""" Initialize model. This will be called during model loading time :return: """vllm_engine_args=AsyncEngineArgs(model=self.model_name)self.vllm_engine=AsyncLLMEngine.from_engine_args(vllm_engine_args)self.openai_serving_models=OpenAIServingModels(engine_client=self.vllm_engine,base_model_paths=[BaseModelPath(name=self.model_name,model_path=os.getcwd())],)openai_serving_render=OnlineRenderer(model_config=self.vllm_engine.model_config,renderer=self.vllm_engine.renderer,request_logger=None,chat_template=None,chat_template_content_format="auto",)self.completion_service=OpenAIServingCompletion(self.vllm_engine,self.openai_serving_models,online_renderer=openai_serving_render,request_logger=None,)self.chat_completion_service=OpenAIServingChat(self.vllm_engine,self.openai_serving_models,"assistant",online_renderer=openai_serving_render,request_logger=None,chat_template_content_format="auto",chat_template=None,)asyncdefisd():returnFalseself.raw_request=MagicMock()self.raw_request.headers={}self.raw_request.is_disconnected=isd@app.post("/v1/chat/completions")asyncdefchat_completion(self,http_request:Request):""" Handle chat completion request. :param http_request: The HTTP request object :return: The chat completion response """try:json_string:dict=awaithttp_request.json()exceptjson.JSONDecodeError:raiseHTTPException(status_code=400,detail="Invalid JSON format request")request:ChatCompletionRequest=ChatCompletionRequest.model_validate(json_string)g=awaitself.chat_completion_service.create_chat_completion(request,self.raw_request)ifisinstance(g,ErrorResponse):return[g.model_dump()]ifrequest.stream:asyncdefstream_generator():asyncforresponseing:yieldresponsereturnStreamingResponse(stream_generator(),media_type="text/event-stream")else:return[g.model_dump()]@app.post("/v1/completions")asyncdefcompletion(self,http_request:Request):""" Handle completion request. :param http_request: The HTTP request object :return: The completion response """try:json_string:dict=awaithttp_request.json()exceptjson.JSONDecodeError:raiseHTTPException(status_code=400,detail="Invalid JSON format request")request:CompletionRequest=CompletionRequest.model_validate(json_string)g=awaitself.completion_service.create_completion(request,self.raw_request)ifisinstance(g,ErrorResponse):return[g.model_dump()]ifrequest.stream:asyncdefstream_generator():asyncforresponseing:yieldresponsereturnStreamingResponse(stream_generator(),media_type="text/event-stream")else:return[g.model_dump()]rbln_actor=RBLNActor.remote()app=Llama3_1__8B.bind(rbln_actor)
Use the Ray Serve CLI (serve run) to launch the application. The argument uses the module:application format, where module is the Python filename (without .py) and application is the exported Serve entry point.
In this sample, llama3_1-8b.py defines app, so the following command starts the deployment. Add extra options when connecting to a remote Ray cluster or when pinning RBLN_DEVICES to specific cards.
echo'{"model": "Llama-3.1-8B-Instruct","prompt": "A robot may not injure a human being","stream": false}'|curl-sN-H"Content-Type: application/json"-XPOST--data-binary@-\http://localhost:8000/v1/completions|jq.
[{"id":"cmpl-790b3169a1c1428a8912140848b42753","object":"text_completion","created":1762993969,"model":"Llama-3.1-8B-Instruct","choices":[{"index":0,"text":" or, through inaction, allow a human being to come to harm.\nA","logprobs":null,"finish_reason":"length","stop_reason":null,"token_ids":null,"prompt_logprobs":null,"prompt_token_ids":null}],"service_tier":null,"system_fingerprint":null,"usage":{"prompt_tokens":10,"total_tokens":26,"completion_tokens":16,"prompt_tokens_details":null},"kv_transfer_params":null}]
echo'{"model": "Llama-3.1-8B-Instruct","messages": [ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Who won the world series in 2020?"}, {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."}, {"role": "user", "content": "Where was it played?"}],"temperature": 0.0,"max_tokens": 50,"stream": false}'|curl-sN-H"Content-Type: application/json"-XPOST--data-binary@-\http://localhost:8000/v1/chat/completions|jq.
[{"id":"chatcmpl-bad227512c58497eb40dcc1287f29b50","object":"chat.completion","created":1762994293,"model":"Llama-3.1-8B-Instruct","choices":[{"index":0,"message":{"role":"assistant","content":"The 2020 World Series was played at Globe Life Field in Arlington, Texas. It was a neutral site due to the COVID-19 pandemic, and the Dodgers played the Tampa Bay Rays in the series.","refusal":null,"annotations":null,"audio":null,"function_call":null,"tool_calls":[],"reasoning_content":null},"logprobs":null,"finish_reason":"stop","stop_reason":null,"token_ids":null}],"service_tier":null,"system_fingerprint":null,"usage":{"prompt_tokens":79,"total_tokens":122,"completion_tokens":43,"prompt_tokens_details":null},"prompt_logprobs":null,"prompt_token_ids":null,"kv_transfer_params":null}]