Views
No views yet

2025.08.28 🌟 We are excited to introduce Kwai Keye-VL-1.5, a more powerful version! By incorporating innovative Slow-Fast Video Encoding strategy, new LongCoT Cold-Start data pipeline, and advanced RL training strategies, Keye-VL-1.5 reaches new heights in video understanding, image comprehension, and reasoning capabilities. Plus, it now supports an extended context length of up to 128k tokens for handling longer conversations and complex tasks. Stay tuned for more groundbreaking innovations!2025.07.08 🌟 Keye-VL is supported by swift and vLLM. Feel free to use it without hesitation!2025.07.03 🌟 We are excited to announce the release of our comprehensive technical report! You can read it now at arxiv.2025.06.26 🌟 We are very proud to launch Kwai Keye-VL, a cutting-edge multimodal large language model meticulously crafted by the Kwai Keye Team at Kuaishou. As a cornerstone AI product within Kuaishou's advanced technology ecosystem, Keye excels in video understanding, visual perception, and reasoning tasks, setting new benchmarks in performance. Our team is working tirelessly to push the boundaries of what's possible, so stay tuned for more exciting updates!
Keye-vl-utils contains a set of helper functions for processing and integrating visual language information with Keye Series Model.pip install --upgrade keye-vl-utils==1.5.2 -i https://pypi.org/simple1from transformers import AutoModel, AutoTokenizer, AutoProcessor
2from keye_vl_utils import process_vision_info
3
4# default: Load the model on the available device(s)
5model_path = "Kwai-Keye/Keye-VL-1_5-8B"
6
7model = AutoModel.from_pretrained(
8 model_path,
9 torch_dtype="auto",
10 trust_remote_code=True,
11 # flash_attention_2 is recommended for better performance
12 attn_implementation="flash_attention_2",
13).eval()
14
15model.to("cuda")
16
17processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True)
18
19# Image Inputs
20## Non-Thinking Mode
21messages = [
22 {
23 "role": "user",
24 "content": [
25 {
26 "type": "image",
27 "image": "https://s1-11508.kwimgs.com/kos/nlav11508/mllm_all/ziran_jiafeimao_11.jpg",
28 },
29 {"type": "text", "text": "Describe this image./no_think"},
30 ],
31 }
32]
33
34## Auto-Thinking Mode
35messages = [
36 {
37 "role": "user",
38 "content": [
39 {
40 "type": "image",
41 "image": "https://s1-11508.kwimgs.com/kos/nlav11508/mllm_all/ziran_jiafeimao_11.jpg",
42 },
43 {"type": "text", "text": "Describe this image."},
44 ],
45 }
46]
47
48## Thinking mode
49messages = [
50 {
51 "role": "user",
52 "content": [
53 {
54 "type": "image",
55 "image": "https://s1-11508.kwimgs.com/kos/nlav11508/mllm_all/ziran_jiafeimao_11.jpg",
56 },
57 {"type": "text", "text": "Describe this image./think"},
58 ],
59 }
60]
61
62# The default range for the number of visual tokens per image in the model is 4-20480.
63# You can set min_pixels and max_pixels according to your needs, such as a token range of 32-1280, to balance performance and cost.
64# min_pixels = 32 * 28 * 28
65# max_pixels = 1280 * 28 * 28
66# e.g.,
67messages = [
68 {
69 "role": "user",
70 "content": [
71 {
72 "type": "image",
73 "image": "https://s1-11508.kwimgs.com/kos/nlav11508/mllm_all/ziran_jiafeimao_11.jpg",
74 "min_pixels": 32 * 28 * 28,
75 "max_pixels": 1280 * 28 * 28
76 },
77 {"type": "text", "text": "Describe this image./think"},
78 ],
79 }
80]
81
82# Video inputs
83messages = [
84 {
85 "role": "user",
86 "content": [
87 {
88 "type": "video",
89 "video": "http://s2-11508.kwimgs.com/kos/nlav11508/MLLM/videos_caption/98312843263.mp4",
90 },
91 {"type": "text", "text": "Describe this video."},
92 ],
93 }
94]
95
96# You can also set fps and max_frames to restrict total frames send to model.
97# e.g.,
98
99messages = [
100 {
101 "role": "user",
102 "content": [
103 {
104 "type": "video",
105 "video": "http://s2-11508.kwimgs.com/kos/nlav11508/MLLM/videos_caption/98312843263.mp4",
106 "fps": 2.0,
107 "max_frames": 1024
108 },
109 {"type": "text", "text": "Describe this video."},
110 ],
111 }
112]
113
114# Text inputs
115messages = [
116 {
117 "role": "user",
118 "content": "Hello, Keye",
119 }
120]
121
122# Preparation for inference
123text = processor.apply_chat_template(
124 messages, tokenize=False, add_generation_prompt=True
125)
126image_inputs, video_inputs, mm_processor_kwargs = process_vision_info(messages)
127inputs = processor(
128 text=[text],
129 images=image_inputs,
130 videos=video_inputs,
131 padding=True,
132 return_tensors="pt",
133 **mm_processor_kwargs
134)
135inputs = inputs.to("cuda")
136
137# Inference: Generation of the output
138generated_ids = model.generate(**inputs, max_new_tokens=1024)
139generated_ids_trimmed = [
140 out_ids[len(in_ids) :] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
141]
142output_text = processor.batch_decode(
143 generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False
144)
145print(output_text)pip install keye-vl-utils==1.5.2 "vllm>=0.9.2"1# refer to https://github.com/QwenLM/Qwen2.5-VL?tab=readme-ov-file#inference-locally
2
3from transformers import AutoProcessor
4from vllm import LLM, SamplingParams
5from keye_vl_utils import process_vision_info
6
7model_path = "/home/keye/Keye-VL-1_5-8B"
8
9llm = LLM(
10 model=model_path,
11 limit_mm_per_prompt={"image": 10, "video": 10},
12 trust_remote_code=True,
13)
14
15sampling_params = SamplingParams(
16 temperature=0.3,
17 max_tokens=256,
18)
19
20# image
21image_messages = [
22 {
23 "role": "user",
24 "content": [
25 {
26 "type": "image",
27 "image": "https://s1-11508.kwimgs.com/kos/nlav11508/mllm_all/ziran_jiafeimao_11.jpg",
28 },
29 {"type": "text", "text": "Describe this image./think"},
30 ],
31 },
32]
33
34# video
35video_messages = [
36 {
37 "role": "user",
38 "content": [
39 {
40 "type": "video",
41 "video": "http://s2-11508.kwimgs.com/kos/nlav11508/MLLM/videos_caption/98312843263.mp4",
42 },
43 {"type": "text", "text": "Describe this video./think"},
44 ],
45 },
46]
47
48# Here we use video messages as a demonstration
49messages = video_messages
50
51processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True)
52prompt = processor.apply_chat_template(
53 messages,
54 tokenize=False,
55 add_generation_prompt=True,
56)
57image_inputs, video_inputs, video_kwargs = process_vision_info(
58 messages, return_video_kwargs=True
59)
60
61mm_data = {}
62if image_inputs is not None:
63 mm_data["image"] = image_inputs
64if video_inputs is not None:
65 mm_data["video"] = video_inputs
66
67llm_inputs = {
68 "prompt": prompt,
69 "multi_modal_data": mm_data,
70 # FPS will be returned in video_kwargs
71 "mm_processor_kwargs": video_kwargs,
72}
73
74outputs = llm.generate([llm_inputs], sampling_params=sampling_params)
75generated_text = outputs[0].outputs[0].text
76
77print(generated_text)1vllm serve \
2 Kwai-Keye/Keye-VL-1_5-8B \
3 --tensor-parallel-size 8 \
4 --enable-prefix-caching \
5 --gpu-memory-utilization 0.8 \
6 --host 0.0.0.0 \
7 --port 8000 \
8 --trust-remote-code1import base64
2import numpy as np
3from PIL import Image
4from io import BytesIO
5from openai import OpenAI
6from keye_vl_utils import process_vision_info
7import requests
8
9
10# Set OpenAI's API key and API base to use vLLM's API server.
11openai_api_key = "EMPTY"
12openai_api_base = "http://localhost:8000/v1"
13
14client = OpenAI(
15 api_key=openai_api_key,
16 base_url=openai_api_base,
17)
18
19# image url
20image_messages = [
21 {
22 "role": "user",
23 "content": [
24 {
25 "type": "image_url",
26 "image_url": {
27 "url": "https://s1-11508.kwimgs.com/kos/nlav11508/mllm_all/ziran_jiafeimao_11.jpg"
28 },
29 },
30 {"type": "text", "text": "Describe this image./think"},
31 ],
32 },
33]
34
35chat_response = client.chat.completions.create(
36 model="Kwai-Keye/Keye-VL-1_5-8B",
37 messages=image_messages,
38)
39print("Chat response:", chat_response)
40
41# image base64-encoded
42
43import base64
44
45image_path = "/path/to/local/image.png"
46with open(image_path, "rb") as f:
47 encoded_image = base64.b64encode(f.read())
48encoded_image_text = encoded_image.decode("utf-8")
49image_messages = [
50 {
51 "role": "user",
52 "content": [
53 {
54 "type": "image_url",
55 "image_url": {
56 "url": f"data:image;base64,{encoded_image_text}"
57 },
58 },
59 {"type": "text", "text": "Describe this image./think"},
60 ],
61 },
62]
63
64chat_response = client.chat.completions.create(
65 model="Kwai-Keye/Keye-VL-1_5-8B",
66 messages=image_messages,
67)
68print("Chat response:", chat_response)
69
70# video, refer to https://github.com/QwenLM/Qwen2.5-VL?tab=readme-ov-file#start-an-openai-api-service
71video_messages = [
72 {"role": "user", "content": [
73 {"type": "video", "video": "http://s2-11508.kwimgs.com/kos/nlav11508/MLLM/videos_caption/98312843263.mp4"},
74 {"type": "text", "text": "Describe this video./think"}]
75 },
76]
77
78def prepare_message_for_vllm(content_messages):
79 vllm_messages, fps_list = [], []
80 for message in content_messages:
81 message_content_list = message["content"]
82 if not isinstance(message_content_list, list):
83 vllm_messages.append(message)
84 continue
85
86 new_content_list = []
87 for part_message in message_content_list:
88 if 'video' in part_message:
89 video_message = [{'content': [part_message]}]\
90 image_inputs, video_inputs, video_kwargs = process_vision_info(video_message, return_video_kwargs=True)
91 assert video_inputs is not None, "video_inputs should not be None"
92 video_input = (video_inputs.pop()).permute(0, 2, 3, 1).numpy().astype(np.uint8)
93 fps_list.extend(video_kwargs.get('fps', []))
94
95 # encode image with base64
96 base64_frames = []
97 for frame in video_input:
98 img = Image.fromarray(frame)
99 output_buffer = BytesIO()
100 img.save(output_buffer, format="jpeg")
101 byte_data = output_buffer.getvalue()
102 base64_str = base64.b64encode(byte_data).decode("utf-8")
103 base64_frames.append(base64_str)
104
105 part_message = {
106 "type": "video_url",
107 "video_url": {"url": f"data:video/jpeg;base64,{','.join(base64_frames)}"}
108 }
109 new_content_list.append(part_message)
110 message["content"] = new_content_list
111 vllm_messages.append(message)
112 return vllm_messages, {'fps': fps_list}
113
114
115video_messages, video_kwargs = prepare_message_for_vllm(video_messages)
116
117
118chat_response = client.chat.completions.create(
119 model="Kwai-Keye/Keye-VL-1_5-8B",
120 messages=video_messages,
121 max_tokens=128,
122 extra_body={
123 "mm_processor_kwargs": video_kwargs
124 }
125)
126
127print("Chat response:", chat_response)

1@misc{Keye-VL-1.5,
2 title={Kwai Keye-VL-1.5 Technical Report},
3 author={Kwai Keye Team},
4 year={2025},
5 eprint={TBD},
6}
7@misc{kwaikeyeteam2025kwaikeyevltechnicalreport,
8 title={Kwai Keye-VL Technical Report},
9 author={Kwai Keye Team},
10 year={2025},
11 eprint={2507.01949},
12 archivePrefix={arXiv},
13 primaryClass={cs.CV},
14 url={https://arxiv.org/abs/2507.01949},
15}