☰
使用 vLLM、LMCache 和 Ceph 进行 KV 缓存:TaoToken 统一 Key 接入配置与验证
2026/9/29 5:28:29 网站建设 项目流程

1. 为什么要在 vLLM 里把 KV 缓存落到 Ceph

如果你正在跑 vLLM 推理服务,大概率遇到过这种场景:同一个长文档、同一段代码库上下文,被不同请求反复送进模型,每次都要重新做一遍 prefill。prefill 是计算密集型的,GPU 算力被大量消耗在重复劳动上,TTFT(首 token 延迟)居高不下。KV 缓存的价值就在这里——把已经算好的 key/value 权重存下来,下次遇到相同前缀直接复用,跳过重复计算。

单机场景下,vLLM 自己就能在 GPU 显存和 CPU 内存里做分层缓存。但一旦进入多节点部署,问题就来了:A 节点算过的 KV 缓存,B 节点用不上;服务重启后缓存全丢;显存和内存容量有限,长上下文根本放不下。这时候就需要一个跨节点、可持久化的共享存储层。

LMCache 是 vLLM 生态里专门解决这个问题的组件,它通过 vLLM 的 KV Connector 接口对接,把缓存块写到远端存储。而 Ceph 作为成熟的分布式对象存储,天然适合做这个远端层——S3 兼容接口、弹性扩容、多节点共享,还能用生命周期策略做缓存过期。三者组合起来,就是一套跨节点可复用的 KV 缓存落盘链路。

这篇内容面向需要跨节点复用 KV 缓存的部署场景,给出 TaoToken 统一 Key/API 通道的配置骨架、CC Switch 切换步骤,以及缓存命中与回落的可复现验证动作。目标是一次性跑通接入,并确认缓存真的生效了。

2. TaoToken 前置:统一 Key 与 API 通道准备

在动手配 vLLM 和 LMCache 之前,先把模型调用的通道理顺。TaoToken 在这里的角色是统一 Key 和 API 入口,让你不用在多个平台之间来回切换 Key,也方便后续做模型对话验证和 Coding Plan 管理。

你需要先拿到一个可用的 API Key。访问控制台创建:

https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=console

创建完成后,在 API Keys 页面复制你的 Key:

https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api-keys

API 基础地址统一用:

https://taotoken.net/api

注意这个地址不加 UTM 参数,直接作为 base_url 使用。如果你后续要用 Claude Code 或 Anthropic 风格的接口,对应的接入文档在这里:

https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc

Claude Code 专用接入页:

https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=ClaudeCodeAnthropic

长期做编码或 Agent 任务的话,Coding Plan 页面可以看套餐:

https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding-plan

想直接在网页里验证模型是否通,用模型对话页:

https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=chat

拿到 Key 之后,先别急着配 vLLM。建议先用一个最小请求确认通道是通的,避免后面把网络问题和缓存问题混在一起排查。

curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 8 }'

返回里有choices字段就说明 Key 和通道没问题。这一步花不了一分钟,但能省掉后面大量「到底是缓存没生效还是 Key 配错了」的纠结。

3. 可复制配置:config.toml 与 settings.json 骨架

TaoToken 的接入配置分两块:一块是config.toml,用于 CLI 或服务端的统一配置;一块是settings.json,用于编辑器或 Agent 类工具的接入。下面给出可直接复制的骨架。

3.1 config.toml 骨架

# ~/.taotoken/config.toml [api] base_url = "https://taotoken.net/api" api_key = "sk-your-taotoken-key" timeout_secs = 120 max_retries = 3 [models] default = "gpt-4o-mini" coding = "claude-sonnet-4-20250514" reasoning = "o3-mini" [proxy] enabled = false # 如需自定义出口,填本地已配置好的地址 # http_proxy = "http://127.0.0.1:7890" [logging] level = "info" file = "~/.taotoken/logs/taotoken.log"

把api_key换成你在控制台创建的那串。base_url保持https://taotoken.net/api,不要在后面加斜杠或路径。

3.2 settings.json 骨架

{ "taotoken": { "baseUrl": "https://taotoken.net/api", "apiKey": "sk-your-taotoken-key", "defaultModel": "gpt-4o-mini", "codingModel": "claude-sonnet-4-20250514", "timeout": 120000, "retries": 3 }, "editor": { "inlineCompletion": true, "chatModel": "gpt-4o-mini" } }

这个settings.json可以放在项目根目录的.taotoken/下,也可以放在用户目录。编辑器插件或 Agent 工具读取时优先找项目级配置,找不到再回落到用户级。

3.3 CC Switch 切换步骤

CC Switch 是用来在多个配置之间快速切换的工具。假设你已经有两套配置:一套指向 TaoToken,一套指向其他通道。操作步骤如下。

第一步,把上面的config.toml保存为~/.taotoken/profiles/taotoken.toml。

第二步,创建切换入口:

mkdir -p ~/.taotoken/profiles cp config.toml ~/.taotoken/profiles/taotoken.toml

第三步,用 CC Switch 注册并激活:

cc-switch add taotoken --config ~/.taotoken/profiles/taotoken.toml cc-switch use taotoken cc-switch status

status会输出当前激活的 profile 和 base_url。确认显示的是https://taotoken.net/api就对了。

第四步,验证切换后的通道:

cc-switch test

这个命令会发一个最小请求,返回 200 且 body 里有模型响应,说明切换成功。

4. vLLM + LMCache + Ceph 落盘链路配置

通道理顺之后,进入核心部分:让 vLLM 通过 LMCache 把 KV 缓存写到 Ceph 的 S3 端点。

4.1 LMCache 配置文件

LMCache 的配置用 YAML,核心参数是chunk_size、remote_url和extra_config里的 S3 并发参数。下面这份配置以 Ceph RGW 的 S3 端点为目标:

# lmcache-ceph.yaml chunk_size: 256 local_cpu: false max_local_cpu_size: 100 remote_url: "s3://lmcache.s3.cephlab.com" save_unfull_chunk: false enable_async_loading: true remote_serde: "naive" blocking_timeout_secs: 100 extra_config: s3_max_io_concurrency: 1024 s3_max_inflight_reqs: 1024 s3_prefer_http2: false s3_region: "default" s3_enable_s3express: false save_chunk_meta: false s3_file_prefix: "test"

几个关键点说明。chunk_size: 256是 LMCache 默认的块大小,对应 256 个 token。local_cpu: false表示不走本地 CPU 内存缓存,直接落远端,适合跨节点共享场景。remote_url指向你的 Ceph RGW bucket。s3_max_io_concurrency和s3_max_inflight_reqs调大是为了充分利用 Ceph 的并发能力,实测下来 1024 在万兆网络下比较合适。

4.2 AWS 凭证配置

LMCache 的 S3 连接器走 AWS SDK,需要凭证文件:

# ~/.aws/credentials [lmcache] region = default endpoint_url = http://s3.cephlab.com:80 aws_access_key_id = your-access-key aws_secret_access_key = your-secret-key response_checksum_validation = when_required preferred_transfer_client = crt

endpoint_url换成你自己的 Ceph RGW 地址。preferred_transfer_client = crt启用 AWS 通用运行时库,能提升并发传输效率。

4.3 启动 vLLM 并挂载 LMCache

启动命令需要设置几个环境变量,并通过--kv-transfer-config把 LMCache 挂上去:

export LMCACHE_CONFIG_FILE="/root/lmcache-ceph.yaml" export LMCACHE_USE_EXPERIMENTAL=True export PYTHONHASHSEED=67 export AWS_PROFILE='lmcache' vllm serve Qwen/Qwen3-32B \ --gpu-memory-utilization 0.55 \ --max-model-len 131072 \ --kv-transfer-config '{"kv_connector":"LMCacheConnectorV1","kv_role":"kv_both","kv_parallel_size":"16"}' \ --tensor-parallel-size 2

kv_connector指定用 LMCacheConnectorV1,kv_role设为kv_both表示既读又写。kv_parallel_size控制并发传输的并行度,根据你的网络和 Ceph 集群能力调整。

如果你用的是 Gaudi3 加速器,额外加这几个环境变量:

export PT_HPU_GPU_MIGRATION=1 export VLLM_USE_V1=1 export VLLM_SKIP_WARMUP=True export VLLM_EXPONENTIAL_BUCKETING=False

4.4 Ceph 侧的准备

Ceph 这边需要提前建好 RGW 的 bucket,并确保 S3 端点可达。存储池建议预创建,避免 RGW 自动创建时参数不理想:

ceph osd pool create default.rgw.buckets.data 2048 2048 replicated ceph osd pool create default.rgw.buckets.index 64 64 replicated ceph osd pool set default.rgw.buckets.data size 2 ceph osd pool set default.rgw.buckets.data min_size 1 ceph osd pool application enable default.rgw.buckets.data rgw

RGW 服务用 cephadm 部署时,可以配置多实例加集中器:

service_type: rgw service_id: standard service_name: rgw.standard placement: count_per_host: 4 label: rgw networks: - 10.67.67.0/24 spec: rgw_frontend_port: 8080 concentrator: haproxy concentrator_frontend_port: 80

这样每个主机跑 4 个 RGW 实例,前面用 haproxy 做集中入口,LMCache 只需要连一个端点。

5. 验证请求与缓存命中确认

配置跑通之后,最关键的一步是确认缓存真的生效了。不能只看服务起来了就认为缓存在工作。

5.1 基线测试:冷缓存下的 TTFT

先在不带缓存的情况下跑一次,记录 TTFT 作为基线。用 LMCache 自带的long_doc_qa.py脚本:

python3 ~/LMCache/benchmarks/long_doc_qa/long_doc_qa.py \ --model Qwen/Qwen3-32B \ --port 8000 \ --num-documents 1 \ --document-length 16384 \ --output-len 100 \ --repeat-count 1 \ --repeat-mode interleave \ --max-inflight-requests 1 \ --output results/ttft_cold.out

第一次跑,缓存是冷的,TTFT 反映的是纯计算 prefill 的耗时。

5.2 热缓存测试:重启后命中远端

关键动作来了。重启 vLLM 服务,确保 GPU 显存和 CPU 内存里的缓存全部清空,然后再次运行同样的请求:

# 重启 vLLM pkill -f "vllm serve" # 等待几秒后重新启动,命令同上 # 再次运行相同请求 python3 ~/LMCache/benchmarks/long_doc_qa/long_doc_qa.py \ --model Qwen/Qwen3-32B \ --port 8000 \ --num-documents 1 \ --document-length 16384 \ --output-len 100 \ --repeat-count 1 \ --repeat-mode interleave \ --max-inflight-requests 1 \ --output results/ttft_warm.out

如果配置正确,第二次的 TTFT 应该显著低于第一次。因为这次 prefill 阶段直接从 Ceph 拉取 KV 缓存块,跳过了重复计算。

5.3 确认缓存块真的写到了 Ceph

除了看 TTFT 数字,还可以直接查 Ceph 的 bucket:

aws s3 ls s3://lmcache.s3.cephlab.com/test/ \ --endpoint-url http://s3.cephlab.com:80 \ --profile lmcache

如果能看到一堆以哈希值命名的对象,说明缓存块确实落盘了。每个对象对应一个 256 token 的 KV 缓存块。

5.4 缓存回落验证

再做一个反向验证:把 Ceph 里的缓存块删掉,重启 vLLM,再跑一次请求。这时候 TTFT 应该回到基线水平,说明缓存未命中时正确回落到计算 prefill。

aws s3 rm s3://lmcache.s3.cephlab.com/test/ --recursive \ --endpoint-url http://s3.cephlab.com:80 \ --profile lmcache

这个「冷→热→冷」的循环跑通,才能确认整条链路是可控的。

6. 本篇常见错排查

配置过程中容易踩的坑集中在几个地方,按出现频率排一下。

6.1 LMCache 连不上 Ceph S3

报错通常是Connection refused或EndpointConnectionError。先确认endpoint_url写对了,注意协议是http还是https,端口是不是 RGW 实际监听的端口。然后用curl直接测端点:

curl -v http://s3.cephlab.com:80

如果 curl 通但 LMCache 不通,检查~/.aws/credentials里的 profile 名和AWS_PROFILE环境变量是否一致。

6.2 缓存写了但读不回来

TTFT 没有下降,但 Ceph 里确实有对象。这种情况多半是chunk_size不一致导致的。vLLM 默认块大小是 16 token,LMCache 默认 256 token,如果配置里chunk_size和实际请求的 token 序列对不齐,哈希值就对不上,自然读不回来。确认lmcache-ceph.yaml里的chunk_size和启动参数没有冲突。

6.3 vLLM 启动时报 KV Connector 不识别

--kv-transfer-config里的kv_connector值必须是 vLLM 和 LMCache 版本匹配的。老版本用LMCacheConnector,新版本用LMCacheConnectorV1。如果你装的 LMCache 是开发版,确认 vLLM 也是对应版本。版本不匹配时,vLLM 会直接报 connector 找不到。

6.4 缓存命中率低

如果 TTFT 有下降但幅度不大,可能是请求的前缀重复度不够。KV 缓存是按 token 序列的哈希值匹配的,前缀只要有一个 token 不同,后面的块就全部失效。测试时确保long_doc_qa.py用的是同一份文档,document-length参数一致。

6.5 TaoToken 通道返回 401

先检查config.toml里的api_key有没有多余空格,base_url是不是https://taotoken.net/api。然后用cc-switch test单独测通道。如果通道测试通过但 vLLM 侧报错,那问题在 vLLM 和 LMCache 的配置,不在 TaoToken。

7. 接入与排障的下一步

整条链路跑通之后,日常使用中如果遇到接入问题,优先查 API Keys 和接入文档:

https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api-keys https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc

需要验证模型响应是否正常,用模型对话页快速测:

https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=chat

如果你长期跑编码任务或 Agent 工作流,Coding Plan 页面有对应的套餐说明:

https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding-plan

我自己的习惯是,每次改完 LMCache 配置后,先跑一遍「冷→热→冷」循环,确认 TTFT 曲线符合预期,再去看 Ceph bucket 里的对象数量。这两个信号对上了,基本就不会有暗坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询