Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

AUXStar/RWKV-Server

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RWKV-Server

RWKV 线性注意力批量推理服务器 —— 用户无感自入队

提交请求,即刻享受 RWKV 线性注意力批量推理的高效与便利。

Python cu130 FastAPI Torch License


📊 性能表现

配置 峰值吞吐 全程平均 显存
2.9B · RTX 4090 11,081 tok/s 4,126 tok/s 9.0 GB
2.9B · 5070 Ti Laptop 5,169 tok/s 1,973 tok/s 9.0 GB
7.2B · RTX 4090 6,373 tok/s 2,483 tok/s 17.1 GB
展开查看详细测试数据

RWKV7 2.9B · RTX 4090(24GB)

批量压力测试:256 个长 prompt 任务并发,max_tokens=2000,temperature=1.0,buffer_size=32。

指标 数值
峰值吞吐 11,081 tok/s(256 并发满载)
全程平均吞吐 4,126 tok/s
单任务速度(256 并发) ~43 tok/s
单任务速度(低并发) ~80 tok/s
总耗时 137.75s(254 任务 × 平均 ~2,158 token 输出)
显存占用 9.0 GB(模型 6.5GB + 256 任务 state ~2.5GB)
 RWKV 推 理 压 力 测 试
 模型: 2.9B · 显卡: RTX 4090 · 任务数: 256 · 显存: 23.5 GB
────────────────────────────────────────────────
 输入 tokens:  20,140       输出 tokens:  548,180
 总吞吐量:     4,126 tok/s  输出吞吐:     3,980 tok/s
 平均每任务输出: 2,158 tokens
────────────────────────────────────────────────
 峰值: Iter 11 cap=256 active=256 speed=11081.09 tok/s per_task=43.29 tok/s

RWKV7 2.9B · RTX 5070 Ti Laptop(12GB)

批量压力测试:256 个长 prompt 任务并发,max_tokens=2000,temperature=1.0,buffer_size=32。

指标 数值
峰值吞吐 5,169 tok/s(256 并发满载)
全程平均吞吐 1,973 tok/s
单任务速度(256 并发) ~20 tok/s
单任务速度(低并发) ~55-80 tok/s
总耗时 286s(256 任务 × 平均 ~2,147 token 输出)
显存占用 9.0 GB(模型 6.5GB + 256 任务 state ~2.5GB)
 RWKV 推 理 压 力 测 试
 模型: 2.9B · 显卡: RTX 5070 Ti Laptop GPU · 任务数: 256 · 显存: 9.0 GB
────────────────────────────────────────────────
 输入 tokens:  20,140       输出 tokens:  545,440
 总吞吐量:     1,973 tok/s  输出吞吐:     1,903 tok/s
 平均每任务输出: 2,147 tokens
────────────────────────────────────────────────
 峰值: Iter 2 cap=256 active=256 speed=5168.75 tok/s per_task=20.19 tok/s

RWKV7 7.2B · RTX 4090(24GB)

批量压力测试:256 个长 prompt 任务并发,max_tokens=2000,temperature=1.0,buffer_size=32。

指标 数值
峰值吞吐 6,373 tok/s(256 并发满载)
全程平均吞吐 2,483 tok/s
单任务速度(256 并发) ~24.5 tok/s
单任务速度(低并发) ~59 tok/s
总耗时 251.43s(254 任务 × 平均 ~2,378 token 输出)
显存占用 17.1 GB(模型 ~13.5GB + 256 任务 state ~3.6GB)
 RWKV 推 理 压 力 测 试
 模型: 7.2B · 显卡: RTX 4090 · 任务数: 256 · 显存: 23.5 GB
────────────────────────────────────────────────
 输入 tokens:  20,140       输出 tokens:  604,139
 总吞吐量:     2,483 tok/s  输出吞吐:     2,403 tok/s
 平均每任务输出: 2,378 tokens
────────────────────────────────────────────────
 峰值: Iter 2 cap=256 active=256 speed=6373.59 tok/s per_task=25.51 tok/s

7.2B 模型比 2.9B 峰值吞吐高 23%,得益于 4090 的算力余量(82.6 TFLOPS FP16)。动态缩容过程:256→128→64→32→16→8→4→2→1,每次紧凑迁移 < 15ms。


项目提供了 Locust 压力测试脚本,默认使用 /v1/tasks/tmp 接口(临时任务自动清理),支持 Web UI 和无头模式:

# Web UI 模式(浏览器动态调整并发)
locust -f test/locustfile.py --host=http://localhost:8000

# 无头模式:256 并发,每秒 +10,持续 10 分钟
locust -f test/locustfile.py --host=http://localhost:8000 --headless \
  -u 256 -r 10 --run-time 10m --csv=perf_report

脚本会自动记录首包延迟 TTFT、流式总耗时等关键指标。


📖 目录


✨ 核心特性

🚀 自入队批量推理 提交即走,调度器自动攒批,无需手动管理 batch
📐 2的幂次动态缩容 任务少时释放显存,多时自动扩容,最大化 GPU 利用率
CUDA Stream 异步零阻塞 state 拷回不阻塞推理流水线
🔌 OpenAI 兼容 API 无缝接入 Chatbox、LobeChat、Open WebUI 等生态
🎯 Per-sample 向量化采样 批次内每个样本独立 temperature / top_k / top_p
📋 提示词模板持久化 好用的提示词 prefill 一次,之后 fork 即用,零重复开销
🌊 流式输出 SSE 实时推送生成内容,首 token 延迟极低
📊 统一日志格式 uvicorn / starlette 日志自动转发,格式一致

🧠 什么是 RWKV-Server?

RWKV(Receptance Weighted Key Value) 是一种结合线性注意力与 Transformer 优势的架构。与 Transformer 的 O(n²) 注意力不同,RWKV 推理复杂度为 O(1)——只需维护一个固定大小的隐藏状态(state),每个 token 的计算量恒定。

这一特性让 批量推理 成为 RWKV 的强项:多个请求的 state 可在 GPU 上天然并行。batch 越大,GPU 利用率越高,吞吐量近乎线性增长。

RWKV-Server 围绕三个原则构建:

  1. 零感知 — 你不需要关心 batch 何时攒满、state 如何管理。提交 prompt,服务端自动完成一切。
  2. 高吞吐 — 利用线性注意力特点,动态攒批 + 脉冲式生成,逼近 GPU 算力上限。
  3. 弹性伸缩 — 根据负载自动调整 batch 容量(1→2→4→8→...→256),空闲时释放显存。
传统 LLM 服务 RWKV-Server
推理复杂度 O(n²) 注意力 O(1) 线性注意力
批量机制 Continuous Batching 状态复用 + 脉冲并行
用户感知 需管理 batch / queue 完全无感,提交即走
显存 KV Cache 随上下文线性增长 固定 state 大小,可预测
容量管理 静态 batch size 2的幂次动态缩容

🏗️ 架构概览

graph TB
    subgraph "客户端"
        A1[OpenAI SDK]
        A2[Chatbox / LobeChat]
        A3[Open WebUI]
    end

    subgraph "API 层"
        B[FastAPI :8000]
        B1["/v1/chat/completions"]
        B2["/v1/completions"]
        B3["/v1/tasks/*"]
    end

    subgraph "业务层"
        D[TaskManager<br/>SQLite + CPU Cache]
    end

    subgraph "调度层"
        E[DynamicScheduler<br/>2的幂次动态缩容]
        F[SimpleScheduler<br/>可继承自定义]
    end

    subgraph "引擎层"
        G[InferEngine<br/>脉冲式批量生成]
        H[BatchSampler<br/>向量化采样]
    end

    subgraph "模型层"
        I[RWKV7<br/>Albatross]
        J[Rapid-Sampling<br/>向量化改造版]
    end

    A1 & A2 & A3 --> B
    B --> B1 & B2 & B3
    B1 & B2 & B3 --> D
    D --> E & F
    E --> G
    G --> H
    G --> I
    H --> J
Loading
模块 核心职责
模型加载器 loader.py 加载 RWKV7 模型、tokenize、向量化 EOS 检测
调度器基类 scheduler_base.py Worker 槽位管理、声明式参数映射、批量收集
动态调度器 scheduler_dynamic.py 2的幂次动态扩缩容、紧凑迁移
简化调度器 scheduler_simple.py 最小实现,供继承自定义
推理引擎 batch_engine.py 脉冲式批量生成、CUDA Stream 异步拷回
批量采样器 batch_sampler.py 向量化采样,per-sample 独立参数
OpenAI API routes/v1/openai/ /v1/chat/completions + /v1/completions
任务管理 task/task.py + task/manager.py Task 生命周期、上下文管理器、SQLite 持久化、LRU 缓存
私有任务 API routes/v1/rwkv/ 9 个任务 CRUD 端点

📡 使用方法

OpenAI 兼容 API

RWKV-Server 兼容 OpenAI Chat Completion 和 Completion 接口:

Chat Completion:

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "rwkv-7",
    "messages": [
      {"role": "system", "content": "你是一个友好的AI助手。"},
      {"role": "user", "content": "什么是光合作用?"}
    ],
    "temperature": 0.7,
    "top_p": 0.9,
    "top_k": 50,
    "max_tokens": 500,
    "presence_penalty": 2.0,
    "stream": false
  }'

流式输出(SSE):

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "rwkv-7",
    "messages": [{"role": "user", "content": "讲个笑话"}],
    "stream": true
  }'

Python 客户端:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="sk-local",
)

# 非流式
response = client.chat.completions.create(
    model="rwkv-7",
    messages=[{"role": "user", "content": "你好!"}],
    temperature=0.7,
    max_tokens=500,
)
print(response.choices[0].message.content)

# 流式
stream = client.chat.completions.create(
    model="rwkv-7",
    messages=[{"role": "user", "content": "讲个笑话"}],
    stream=True,
)
for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

RWKV 原生支持 System: 角色,OpenAI API 中的 system 消息会被转换为 System: {content} 前缀:

response = client.chat.completions.create(
    model="rwkv-7",
    messages=[
        {"role": "system", "content": "你是一个专业的技术翻译,请将英文翻译为中文。"},
        {"role": "user", "content": "LLMs use multi-head self-attention to process tokens in parallel."},
    ],
)
# 实际 prompt:
# System: 你是一个专业的技术翻译...
#
# User: LLMs use multi-head self-attention...
#
# Assistant:  thinking
#  response

与直接拼文本不同,System: 标签让模型明确区分系统指令和用户对话,对角色扮演 / 风格约束 / 安全护栏等场景尤其有效。

🎭 Few-Shot 对话模板

few_shot.txt 提供了 30+ 个对话示例,覆盖知识问答、编程、翻译、数学、创意写作等场景。每个示例都包含推理过程:

User: 什么是光合作用?

Assistant:  <think>用户问了一个基础生物学概念。我需要给出清晰、准确的定义,并解释其重要性。</think>
光合作用是植物、藻类和一些细菌利用光能,将二氧化碳和水转化为有机物(如葡萄糖)并释放氧气的过程。简单说,
就是植物"吃饭"和"呼吸"的方式,为生态系统提供能量和氧气。
<|endoftext|>

few_shot.txtprompt 适合加入 prefill 实现提示词工程调优:纯概念问答题要求先给定义再补充功能,编程题要求选择最标准的方法并附完整代码,翻译题要求直接给出最准确的对应表达,数学题要求展示每一步计算过程。所有这些引导都写在 think 标签里,让模型在回答前进行隐式链式思考(Implicit CoT),显著提升回答质量。

你可以按此格式自由扩展 few-shot.txt,添加你自己的场景模板。

📋 模板任务(Template Tasks)—— 提示词工程

如果你有一个特别好用的提示词,每次请求都要用它,常规做法是每次带在 prompt 里——这意味着每次都从头 prefill,浪费算力。

RWKV-Server 的做法是:把提示词做成模板,prefill 一次,永久复用。

核心技巧:max_tokens=0。设为 0 时,调度器只做 prefill(构建 state),不生成任何内容。prefill 完成后,这个模板的 state 就绪,后续 fork 出的实例直接从这个 state 开始推理,省去重复 prefill。

from server import RWKV070ModelLoader, DynamicScheduler
from server.task.manager import get_task_manager

pipeline = RWKV070ModelLoader("model.pth")
scheduler = DynamicScheduler(pipeline)
scheduler.start_daemon()
task_manager = get_task_manager()

# 创建翻译模板:max_tokens=0,只 prefill 不生成
template_task = scheduler.new_task(
    prompt="User: 你是一个专业的中英技术翻译,请翻译以下内容。\n\n",
    max_tokens=0,  # 关键:只 prefill
    temperature=0.3,
)
scheduler.run()  # prefill 完成,state 已就绪
task_manager.put_task("_tech_translator", template_task)

# 每次使用时 fork,state 自动继承,零 prefill 开销
new_id = task_manager.fork_template("_tech_translator")
task = task_manager.get_task(new_id)
task.continue_gen(
    "请翻译:The transformer architecture revolutionized NLP.",
    max_tokens=500,
)
scheduler.add_task(task)

_ 开头的任务 ID 被视为只读模板,不受容量限制淘汰,不会被覆盖。模板存储在 SQLite 中,重启服务后依然可用。

预设多个角色:

实际场景肯定不止这一点点提示词,fork可节省大量重复的prefill,甚至于让agent在某个环节分支然后并行。

roles = {
    "_coder":       "User: 你是一个资深的 Python 后端工程师。\n\nAssistant: 好的。\n\n",
    "_translator":  "User: 你是一个专业的中英技术翻译。\n\nAssistant: 明白。\n\n",
    "_writer":      "User: 你是一个创意故事作家。\n\nAssistant: 好的,让我们开始。\n\n",
}

for role_id, prompt in roles.items():
    task = scheduler.new_task(prompt=prompt, max_tokens=0)
    scheduler.run()
    task_manager.put_task(role_id, task)

# 随时 fork 使用
coding_task_id = task_manager.fork_template("_coder")

🔌 LLM 门户接入

RWKV-Server 兼容 OpenAI API 标准,可接入主流 LLM 客户端:

Chatbox / LobeChat / Open WebUI:

  • API 地址:http://localhost:8000/v1
  • API Key:任意值(如 sk-local
  • 模型名称:rwkv-7

🔧 私有 API(任务管理)

除了 OpenAI 兼容接口,RWKV-Server 还提供了一套更底层的任务管理 API,适合需要精细控制的场景。

端点 方法 说明
/v1/tasks/tmp POST 临时任务:提交 prompt,可选 stream,结果不持久化
/v1/tasks/create POST 创建持久化任务,支持 stream 参数
/v1/tasks/{task_id}/get_result GET 轮询获取任务结果
/v1/tasks/{task_id}/fork POST Fork 模板并继续生成
/v1/tasks/{task_id}/continue POST 对已有任务追加 prompt 并继续生成
/v1/tasks/{task_id}/stop POST 停止正在生成的任务
/v1/tasks/{task_id}/as_template POST 将一个已完成的任务转为持久化模板
/v1/tasks/{task_id}/delete POST 删除任务(模板需 force=true
/v1/tasks/fim POST Fill In Middle:给定 prefix/suffix,生成中间内容
/v1/tasks/list GET 列出所有活跃任务

临时任务

临时任务与持久化任务共用同一套参数,区别是 task_id 以 TMP_ 开头,便于识别和管理。同样支持 stream 参数:

# 流式模式:SSE 实时推送
curl -X POST http://localhost:8000/v1/tasks/tmp \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "User: 用一句话介绍线性注意力。\n\nAssistant:",
    "max_tokens": 100,
    "temperature": 0.7,
    "stream": true
  }'

# 非流式模式:仅创建任务,返回 task_id,后续轮询获取结果
curl -X POST http://localhost:8000/v1/tasks/tmp \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "User: 用一句话介绍线性注意力。\n\nAssistant:",
    "max_tokens": 100,
    "temperature": 0.7,
    "top_p": 0.3,
    "top_k": 50,
    "stream": false
  }'

非流式模式返回(仅确认创建,结果需轮询):

{
  "task_id": "TMP_abc123def456",
  "result": "",
  "prefill_time": 0.012,
  "gen_time": 0,
  "speed": 0,
  "finished": false
}

创建持久化任务

任务会被存入 SQLite,支持后续轮询、继续生成、转为模板。

# 非流式:返回 task_id,稍后轮询获取结果
curl -X POST http://localhost:8000/v1/tasks/create \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "User: 写一个 Python 二分查找。\n\nAssistant:",
    "max_tokens": 500,
    "temperature": 0.3,
    "stream": false
  }'

# 流式:SSE 实时推送 token
curl -X POST http://localhost:8000/v1/tasks/create \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "User: 讲一个关于程序员的笑话。\n\nAssistant:",
    "max_tokens": 200,
    "temperature": 0.8,
    "stream": true
  }'

轮询结果

curl http://localhost:8000/v1/tasks/TASK_abc123/get_result

返回已生成的内容片段。当 finished: true 时表示生成完成。

Fork + Continue

配合模板任务使用——Fork 出一个副本,追加新 prompt 继续生成:

# Fork 模板并继续:从模板 state 出发,prefill 追加内容后继续生成
curl -X POST http://localhost:8000/v1/tasks/_my_template/fork \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "User: 请翻译:Hello World\n\nAssistant:",
    "max_tokens": 200,
    "temperature": 0.3,
    "stream": true
  }'

对已有任务追加 prompt 继续生成:

curl -X POST http://localhost:8000/v1/tasks/TASK_abc123/continue \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "再补充一个递归版本的实现。\n\n",
    "max_tokens": 500,
    "stream": true
  }'

任务管理

# 将完成的任务转为模板
curl -X POST http://localhost:8000/v1/tasks/TASK_abc123/as_template

# 停止正在生成的任务
curl -X POST http://localhost:8000/v1/tasks/TASK_abc123/stop

# 删除任务
curl -X POST http://localhost:8000/v1/tasks/TASK_abc123/delete

# 查看所有活跃任务
curl http://localhost:8000/v1/tasks/list

Fill In Middle(FIM)

FIM(Fill In Middle)适用于代码补全、文本填充等场景——给定光标前后的文本,模型生成中间缺失的部分。与 rwkv_lightning 使用相同的 prompt 构造格式。

# 代码补全示例
curl -X POST http://localhost:8000/v1/tasks/fim   -H "Content-Type: application/json"   -d '{
    "prefix": "def hello_world():\n    print(",
    "suffix": ")\n    return True",
    "max_tokens": 50,
    "temperature": 0.8,
    "stream": false
  }'

参数说明:

参数 类型 必填 说明
prefix string 光标前的文本
suffix string 光标后的文本,默认空
max_tokens int 最大生成 token 数,默认 2000
temperature float 采样温度
stream bool 是否流式输出

FIM 支持流式和非流式两种模式,行为与普通任务 API 一致。非流式返回 task_id,通过轮询获取结果;流式通过 SSE 实时推送。


🧩 直接调用调度器(Python SDK)

如果你不想走 HTTP API,可以直接 import 调度器嵌入到自己的 Python 应用中。这也是 test.py 压力测试脚本使用的方式——零网络开销,直接操作 state

适合:批量离线推理、自定义 pipeline、嵌入上游 agent 框架、不想起 HTTP 服务的场景。

最简示例

from server import RWKV070ModelLoader, DynamicScheduler
from server.config import settings

# 1. 加载模型
loader = RWKV070ModelLoader(settings.model_path, settings.vocab_path)

# 2. 创建调度器
scheduler = DynamicScheduler(
    loader,
    max_batch_size=256,   # 最大并发
    buffer_size=32,       # 每个 pulse 生成的 token 数
)

# 3. 提交任务
tasks = [
    scheduler.new_task(
        f"User: {prompt}\n\nAssistant:",
        max_tokens=200,
        temperature=0.7,
        top_p=0.3,
        top_k=50,
    )
    for prompt in ["你好,介绍一下你自己", "用 Python 写一个快速排序", "1+1等于几?"]
]

# 4. 运行(阻塞,直到所有任务完成)
scheduler.run()

# 5. 获取结果
for task in tasks:
    print(f"[{task.task_id}] {task.decode(task.pop_tokens())[:200]}...")

run() 是阻塞调用,内部循环直到所有任务状态变为 FINISHED,返回后即可取结果。最简单的用法就是上面 5 步。

关键类与参数

RWKV070ModelLoader(model_path, vocab_path=None)

加载模型和词表:

loader = RWKV070ModelLoader("models/rwkv7-2.9b.pth", "eof_v20230424.txt")

# 常用方法
loader.encode("你好")                # str → list[int]
loader.decode([123, 456])            # list[int] → str
loader.gen_state(batch_size=1)       # 生成初始 state(用于 fork 多个 task)

DynamicScheduler(loader, max_batch_size, buffer_size)

动态调度器,支持 2 的幂次自动扩缩容。另有 SimpleScheduler 继承基类不加任何逻辑,供自定义调度策略。

scheduler.new_task(prompt, ...)Task

创建一个新的推理任务。完整参数:

参数 类型 默认 说明
prompt str | list[int] 必填 输入文本(字符串)或已编码的 token 列表
max_tokens int 50 最大生成 token 数。设为 0 则只 prefill 不生成(模板模式)
temperature float 0.3 采样温度,越高越随机
top_p float 0.1 Nucleus 采样阈值
top_k int 20 Top-K 采样
presence_penalty float 0.0 存在惩罚,鼓励生成新 token
repetition_penalty float 0.0 重复惩罚
penalty_decay float 0.0 惩罚衰减系数
seed int 42 随机种子(确定性输出)
collect_callback callable None 每次 pulse 生成后回调,参数为 tokens: list[int]
finish_callback callable None 任务完成时回调,参数为 all_tokens: list[int]

注意:请勿在回调中添加过于耗时的操作!最佳实践为回调收集后在另外线程处理。

scheduler.add_task(prompt, ...)None

外部添加任务(已创建好的 Task 对象)

Task 对象

创建后自动完成 prefill(CPU 上),state 保持在 CPU 等待调度:

属性 / 方法 说明
task_id 默认 "TMP"
status PREFILLREADYRUNNINGFINISHED
current_token 当前输入 token(prefill 后为 prompt 最后一个 token)
pop_tokens() 取出并清空已收集的生成 token
get_all_tokens() 取出已收集的生成 token,不清空
decode(tokens) 将 token 列表解码为文本
stop() 停止推理(外部中断)
continue_gen() 将已完成任务重置为 READY,继续生成

回调模式

适合流式输出或增量处理场景——不等 run() 全部完成就能拿到中间结果:

def on_tokens(tokens):
    """每次 pulse 生成 buffer_size 个 token 后回调"""
    text = loader.decode(tokens)
    print(text, end="", flush=True)

def on_finish(all_tokens):
    """任务完成回调"""
    print(f"\n--- 完成,共 {len(all_tokens)} tokens ---")

task = scheduler.new_task(
    "User: 写一首关于春天的诗\n\nAssistant:",
    max_tokens=300,
    temperature=0.8,
    collect_callback=on_tokens,   # 每个 pulse 回调
    finish_callback=on_finish,    # 完成时回调
)
scheduler.run()

模板任务(max_tokens=0 + TaskManager)

回调模式适合在线场景,但更高效的用法是利用 max_tokens=0 做模板持久化,配合 TaskManager 管理 state 生命周期:

from server import RWKV070ModelLoader, DynamicScheduler
from server.task.manager import get_task_manager
from server.config import settings

loader = RWKV070ModelLoader(settings.model_path, settings.vocab_path)
scheduler = DynamicScheduler(loader, 256, 32)
task_manager = get_task_manager()
task_manager.set_dependencies(loader, scheduler.sampler)

# Step 1: 创建模板 —— max_tokens=0,只 prefill 不生成
tpl = scheduler.new_task(
    "User: 你是一个资深 Python 后端工程师,请遵循 PEP8 规范。\n\nAssistant: 好的。\n\n",
    max_tokens=0,
    temperature=0.3,
)
scheduler.run()  # prefill 完成,state 在 CPU

# Step 2: 存入 TaskManager(SQLite 持久化)
task_manager.put_task("_coder", tpl)

# Step 3: 使用时 fork —— state 自动继承,零 prefill 开销
for question in ["写一个线程安全的单例", "如何优化数据库连接池?", "解释 GIL 及其影响"]:
    new_id = task_manager.fork_template("_coder")
    task = task_manager.get_task(new_id)
    task.continue_gen()  # 重置状态为 READY
    task.prefill(f"User: {question}\n\nAssistant:")  # 追加新 prompt
    task.max_tokens = 500
    scheduler.add_task(task)

scheduler.run()  # 3 个任务并行推理,共享同一份系统提示词 prefill

TaskManager 常用方法:

方法 说明
put_task(task_id, obj) 存入缓存(以 _ 开头的 ID 视为只读模板)
get_task(task_id) → Task 从缓存或 SQLite 取出
fork_template(template_id) → new_id Fork 模板,state 自动拷贝
close_task(task_id) 关闭并写入 DB
delete_task_from_any_level(task_id, force=False) 删除任务

模板 ID 以 _ 开头被视为只读,不受 LRU 淘汰、不会被覆盖,重启后仍在 SQLite 中。

后台常驻模式

如果需要持续接收任务而不阻塞当前线程:

# 启动后台线程
scheduler.start_daemon()  # 内部循环:有任务就 run(),空闲 sleep 0.5s

# 随时提交新任务
task = scheduler.new_task("User: 你好\n\nAssistant:", max_tokens=100)
# 调度器自动发现 READY 任务并开始推理

# 优雅关闭
scheduler.shutdown()

FIM 示例:代码补全

# FIM 本质是 prompt 构造,两行即可
prompt = f"✿prefix✿✿suffix✿{suffix}✿middle✿{prefix}"
task = scheduler.new_task(prompt, max_tokens=100, temperature=0.8)
scheduler.run()
print(loader.decode(task.pop_tokens()))

完整示例:翻译服务

from server import RWKV070ModelLoader, DynamicScheduler
from server.config import settings

loader = RWKV070ModelLoader(settings.model_path, settings.vocab_path)
scheduler = DynamicScheduler(loader, max_batch_size=64, buffer_size=32)

def translate(texts: list[str], source_lang="中文", target_lang="英文"):
    tasks = [
        scheduler.new_task(
            f"User: 将以下{source_lang}翻译为{target_lang}{t}\n\nAssistant:",
            max_tokens=300,
            temperature=0.3,
            top_p=0.3,
        )
        for t in texts
    ]
    scheduler.run()
    return [loader.decode(t.pop_tokens()) for t in tasks]

# 使用
results = translate(["你好世界", "机器学习很有趣", "今天天气真好"])
for r in results:
    print(r)

关于更详细的sdk,请详见代码实现,大部分函数有较详细文档。


🚀 快速开始

Python SDK —— 优雅调用 RWKV 推理

推荐使用官方 SDK,无需关心批量调度、状态管理、GPU 显存分配——只需创建一个 Task,RWKV-Server 会在后台自动完成一切。

pip install rwkv-api
from rwkv_api import Client

client = Client("http://localhost:8000")

# 创建任务并等待结果 —— 服务端自动批量调度
task = client.create("Hello world", max_tokens=50)
result = task.wait()
print(result.result)

# 实时流式输出
for chunk in client.create_stream("Tell me a story", max_tokens=200):
    print(chunk, end="", flush=True)

SDK 提供同步/异步双客户端、Task 对象生命周期管理、FIM 代码补全、异常处理等完整功能。详见 RWKV-API SDK 文档

对已创建任务订阅流式输出

from rwkv_api import Client

client = Client("http://localhost:8000")

# 先创建任务(非流式)
task = client.create("Hello", max_tokens=200)

# 订阅实时流式输出,重连时传 pos 避免重复
for chunk in task.stream():
    print(chunk, end="", flush=True)

轮询读取 _generated_tokens,不修改 task callback,支持多消费者独立读取。

环境要求

  • Python >= 3.13
  • PyTorch >= cu130(RTX 50 系列 Blackwell GPU / CUDA 12.x 工具链)
  • 操作系统:Linux / Windows

不同模型的显存需求与建议并发数(以 RTX 4090 24GB 为例):

模型 模型权重 剩余可用 建议 MAX_BATCH_SIZE
RWKV7 2.9B ~6 GB ~16 GB 256
RWKV7 7.2B ~14.4 GB ~8 GB 256(每个任务约 11MB state)

7.2B 模型加载后剩余约 8GB,理论支持 700+ 并发,但实际场景几乎不可能同时来那么多请求——256 足够日常使用。

Step 1:下载模型

从 HuggingFace 下载 RWKV7 模型,放到 server/model/ 目录下:

# 例如
mkdir -p server/model
# 将下载的 .pth 文件放入 server/model/

Step 2:克隆仓库

git clone --recurse-submodules https://github.com/AUXStar/RWKV-Server.git
cd RWKV-Server

Step 3:安装依赖

项目使用 uv 管理依赖:

uv sync

Step 4:启动服务

# Windows PowerShell
$env:RWKV_MODEL_PATH = "server/model/rwkv7-g1g-7.2b-20260523-ctx8192.pth"
python run.py

# Linux / macOS
export RWKV_MODEL_PATH="server/model/rwkv7-g1g-7.2b-20260523-ctx8192.pth"
python run.py

不想设环境变量?所有默认值在 server/config.py 里,改完直接 python run.py

服务启动后终端会输出类似日志:

12:01:23.45 | INFO    | scheduler.dynamic  | Init capacity = 1 (max=256)
12:01:23.56 | INFO    | api                | Uvicorn running on http://0.0.0.0:8000

Step 5:发送第一个请求

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "rwkv-7",
    "messages": [
      {"role": "user", "content": "用 Python 写一个快速排序"}
    ],
    "temperature": 0.7,
    "max_tokens": 500
  }'

返回:

{
  "id": "chatcmpl-xxx",
  "object": "chat.completion",
  "model": "rwkv-7",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "以下是 Python 快速排序的实现:\n\n```python\ndef quicksort(arr):\n    ..."
    },
    "finish_reason": "stop"
  }]
}

🔬 架构深度解析

请求-推理完整数据流

sequenceDiagram
    participant C as 客户端
    participant F as FastAPI
    participant TM as TaskManager
    participant DS as DynamicScheduler
    participant IE as InferEngine
    participant M as RWKV7 Model
    participant S as BatchSampler

    C->>F: POST /v1/chat/completions
    F->>TM: put_task()
    TM-->>F: task_id (异步确认)
    F-->>C: 200 + task_id

    loop 后台调度循环
        DS->>DS: background() 检测 pending tasks
        DS->>DS: update_batch() 声明式映射注入 worker 槽位
        DS->>IE: generate(worker, mask, stop_flags)
        loop 每个 pulse (buffer_size 步)
            IE->>M: forward(last_tokens, state)
            M-->>IE: logits
            IE->>S: sample(logits, per-sample params)
            S-->>IE: tokens (B,)
            IE->>IE: batch_is_eos() 向量化检测
            IE->>IE: CUDA Stream 异步拷回完成任务的 state
        end
        DS->>DS: _collect() 收集生成结果
        DS->>DS: _adjust_capacity() 2的幂次缩容
    end

    C->>F: GET /v1/tasks/{task_id}/get_result
    F->>TM: get_task_result()
    TM-->>F: result
    F-->>C: 轮询结果
Loading

调度器 Worker 槽位状态机

stateDiagram-v2
    [*] --> FREE: 槽位初始化
    FREE --> RUNNING: update_batch() 注入 Task
    RUNNING --> FINISHED: EOS 或 max_tokens
    FINISHED --> FREE: _collect() 回收槽位

    note right of FREE
        mask=True
        task=None
    end note
    note right of RUNNING
        mask=False
        task assigned
    end note
    note right of FINISHED
        结果已收集
        等待回收
    end note
Loading

Task 生命周期

stateDiagram-v2
    [*] --> PREFILL: new_task()
    PREFILL --> READY: CPU prefill 完成
    READY --> RUNNING: 被调度器 pick up
    RUNNING --> FINISHED: EOS 或 max_tokens
    FINISHED --> READY: continue_gen()
    FINISHED --> [*]: 结果已收集

    note right of READY
        state 在 CPU 上
        等待被调度
    end note
    note right of RUNNING
        state 在 GPU 上
        with task 上下文
    end note
    note right of FINISHED
        state 已拷回 CPU
        结果已收集
    end note
Loading

2的幂次动态缩容决策流程

flowchart TD
    A["_adjust_capacity()"] --> B["计算 total_needed<br/>= active + ready"]
    B --> C["target = next_power_of_two(total_needed)"]
    C --> D{target == current_capacity?}
    D -->|是| E[不操作]
    D -->|否| F["_compact_and_resize(target)"]
    F --> G[获取活跃槽位索引列表]
    G --> H["紧凑复制所有张量<br/>shift_state, wkv_state, penalties..."]
    H --> I[紧凑复制 rand_state]
    I --> J[重建 tasks 列表]
    J --> K[重置 mask 向量]
    K --> L[清零新增空闲槽位]
    L --> M["gc.collect()<br/>torch.cuda.empty_cache()"]
    M --> N["完成: capacity N → M"]

    subgraph 数值示例
        O["active=5, ready=6<br/>total_needed=11<br/>target=16 (16=2⁴)"]
    end
Loading

为什么是 2 的幂次?

  1. GPU 显存对齐:许多 CUDA 操作在 2 的幂次对齐时性能最优
  2. 状态向量效率shift_state 的 shape 为 (B, 2, L, D),B 为 2 的幂次时内存布局更优
  3. 减少碎片化:频繁小幅度扩缩容会导致 GPU 显存碎片,幂次跳跃减少了扩容频率
  4. 弹性范围大:从 1 到 256,只需 9 个容量级别,管理简洁

⚙️ 配置说明

所有配置通过环境变量 RWKV_ 前缀设置,遵循 12-Factor App 原则。不想设环境变量的话,也可以直接改 server/config.py 里的默认值,改完直接 python run.py

环境变量 默认值 说明
RWKV_MODEL_PATH server/model/rwkv7-g1g-2.9b-20260526-ctx8192.pth 模型文件路径
RWKV_MAX_BATCH_SIZE 256 最大批量推理数(2的幂次上限)
RWKV_BUFFER_SIZE 32 脉冲步数(每个 pulse 生成的 token 数)
RWKV_DEFAULT_MAX_TOKENS 2000 默认最大生成 token 数
RWKV_DEFAULT_TEMPERATURE 1.0 默认采样温度
RWKV_DEFAULT_TOP_P 0.3 默认 top-p 值
RWKV_DEFAULT_TOP_K 50 默认 top-k 值
RWKV_DEFAULT_PRESENCE_PENALTY 2.0 默认存在惩罚(鼓励多样性)
RWKV_DEFAULT_REPETITION_PENALTY 0 默认重复惩罚
RWKV_DEFAULT_PENALTY_DECAY 1.0 默认惩罚衰减系数
RWKV_VERBOSE true 是否启用 INFO 级别日志
RWKV_VOCAB_PATH server/eof_v20230424.txt 词表文件路径
RWKV_TASK_DEFAULT_CPU_CAPACITY 300 CPU 缓存最大任务数
RWKV_TASK_DB_MAX_SIZE 10000 SQLite 最大非模板任务数
RWKV_TASK_ASYNC_QUEUE_SIZE 200 异步写 DB 队列大小
RWKV_TASK_DB_PATH rwkv_tasks.db SQLite 数据库路径

调优建议

  • BUFFER_SIZE:越大单次 pulse 生成 token 越多,但高负载下 GPU 显存压力更大。建议范围 16-64
  • MAX_BATCH_SIZE:根据显存调整。2.9B 模型建议 256,7.2B 模型建议 256
  • PRESENCE_PENALTY:值越高越鼓励多样性,创意写作建议 2.0+,代码生成建议 0.5-1.0

📁 项目结构

RWKV-Server/
├── run.py                           # 启动入口:create_app → uvicorn.run
├── test.py                          # 压力测试(直接调用调度器 API)
├── pyproject.toml                   # uv 项目配置
├── uv.lock                          # uv 依赖锁定文件
├── few_shot.txt                     # 30+ Few-shot 对话示例
├── eof_v20230424.txt                # 词表文件
├── server/
│   ├── __init__.py                  # 公共导出(RWKV070ModelLoader, *Scheduler)
│   ├── config.py                    # Pydantic Settings,环境变量 RWKV_ 前缀
│   ├── logger.py                    # Loguru 日志劫持 uvicorn / starlette
│   ├── utils.py                     # NullLock, stream_callback, finish_callback
│   ├── task/
│   │   ├── task.py                  # Task 类 + Status 枚举 + 上下文管理器
│   │   └── manager.py               # TaskManager(SQLite 持久化 + LRU CPU 缓存)
│   ├── scheduler/
│   │   ├── __init__.py              # CUDA 预热设置(cudnn benchmark, tf32)
│   │   ├── loader.py                # 模型加载 + 向量化 EOS 检测
│   │   ├── scheduler_base.py        # 基类调度器(field_mappings 映射表)
│   │   ├── scheduler_simple.py      # 简化版(可继承自定义)
│   │   ├── scheduler_dynamic.py     # 2的幂次动态扩缩容
│   │   ├── batch_engine.py          # 脉冲批量推理引擎(CUDA Stream 异步拷回)
│   │   └── batch_sampler.py         # 向量化批量采样器
│   ├── api/
│   │   ├── __init__.py
│   │   ├── app.py                   # FastAPI 应用 + lifespan → create_app()
│   │   ├── dependencies.py          # 依赖注入
│   │   └── routes/
│   │       └── v1/
│   │           ├── __init__.py      # 聚合 openai + rwkv 路由
│   │           ├── openai/
│   │           │   ├── __init__.py
│   │           │   ├── routers.py   # OpenAI 兼容 API 端点
│   │           │   ├── schemas.py   # 请求/响应 Pydantic 模型
│   │           │   └── utils.py     # 辅助函数
│   │           └── rwkv/
│   │               ├── __init__.py
│   │               ├── routers.py   # 私有任务 CRUD API 端点
│   │               └── schemas.py   # 请求/响应 Pydantic 模型
│   └── reference/
│       ├── __init__.py
│       ├── model_wrapper.py         # 模型包装器
│       ├── rwkv/                    # Git 子模块:Albatross RWKV7
│       └── sampler/                 # Git 子模块:Rapid-Sampling(向量化改造版)
├── test/
│   ├── locustfile.py                # Locust HTTP 压力测试脚本
│   ├── batch_async.py               # 异步批量测试
│   ├── batch_sync.py                # 同步批量测试
│   └── result/
│       └── log.txt                  # 测试结果日志
└── .gitmodules                      # Git 子模块配置

🙏 参考与致谢

本项目站在巨人的肩膀上,感谢以下优秀项目:

项目 说明
BlinkDL/Albatross RWKV7 官方模型实现,批量推理核心代码来源
RWKV-Vibe/rwkv_lightning State Pool 设计借鉴,高效的线性注意力状态管理
AUXStar/Rapid-Sampling 批量采样器(向量化改造版),支持 per-sample 不同参数
Triang-jyed-driung/Rapid-Sampling 原始 Rapid Sampling 算法

🤝 贡献指南

欢迎提交 Issue 和 Pull Request。在提交 PR 前,请确保:

  1. 代码通过格式化检查
  2. 新增功能包含测试用例
  3. 更新相关文档

⭐ Star History

Star History Chart

About

RWKV7 推理服务 | 高并发批量推理,动态扩缩容,兼容OpenAI API,CUDA优化,低显存部署大模型推理 RWKV linear attention batch inference server — auto-queue, dynamic capacity, OpenAI compatible.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.