当前位置: 首页 > article >正文

昇腾CANN cann-recipes-infer Continuous Batching:从静态 Padding 到动态调度,吞吐翻 10 倍

LLM 推理服务线上最大的浪费静态 batching。一个 batch 里 8 个请求序列长度从 12 到 2048——短的 12 个 token 2ms 就算完了然后等长的那条跑完。190ms 算力闲置GPU/NPU 空转。Continuous Batching 的解法不等——哪个请求算完了立刻把它的位置让给新请求。batch 永不满永不空转。静态 batching 的吞吐 avg_seq_len / max_seq_len × peak_throughput。2048 max, 512 avg → 利用率 25%。Continuous Batching → 利用率 85-95%。核心机制Request Slot 的抢占与填充Continuous Batching 把 “batch” 的概念从静态槽位变成动态 slot 池。每个 slot 绑定一个正在运行的请求。请求完成后 slot 释放调度器从等待队列拉下一个请求填入。# cann-recipes-infer/continuous_batching/scheduler.pyfromdataclassesimportdataclassfromtypingimportList,OptionaldataclassclassRequest:id:intprompt:List[int]# 输入的 token 序列max_new_tokens:int# 最大生成 token 数temperature:float1.0generated:List[int]None# 已生成的 tokenstate:strpending# pending/running/donedataclassclassSlot:一个 batch 位置——持续占有的 GPU 资源index:int# 在 batch 中的索引 (0..max_batch-1)request:Optional[Request]Nonekv_cache_offset:int0# KV Cache 分页的起始地址kv_cache_pages:int0# 已占据的 page 数is_running:boolFalseclassContinuousBatchingScheduler:def__init__(self,max_batch_size64,max_seq_len4096,page_size16,kv_cache_total_pages4096):self.max_batchmax_batch_size self.max_seq_lenmax_seq_len self.page_sizepage_size# 每个 page 存 16 个 token 的 KV cacheself.total_pageskv_cache_total_pages self.slots[Slot(i)foriinrange(max_batch_size)]self.free_pageslist(range(kv_cache_total_pages))# 空闲页栈self.waiting_queue[]# 等待队列 [(priority, request)]defschedule(self,new_requests:List[Request])-List[int]:返回需要运行的 slot 索引列表# 步骤 1新请求入队forreqinnew_requests:self.waiting_queue.append((0,req))# priority0FIFO# 步骤 2释放已完成的 slotforslotinself.slots:ifslot.requestandslot.request.statedone:self._free_slot(slot)# 步骤 3填充空闲 slotfree_slots[sforsinself.slotsifnots.is_running]forslotinfree_slots:ifnotself.waiting_queue:break_,reqself.waiting_queue.pop(0)# 分配 KV cache 页needed_pages(len(req.prompt)req.max_new_tokensself.page_size-1)//self.page_sizeiflen(self.free_pages)needed_pages:# 不够 page → 请求继续等待self.waiting_queue.insert(0,(0,req))continueslot.requestreq slot.kv_cache_offsetself.free_pages[0]*self.page_size*self.kv_dim*2slot.kv_cache_pagesneeded_pages slot.is_runningTruereq.staterunning# 分配 pagepagesself.free_pages[:needed_pages]delself.free_pages[:needed_pages]slot.allocated_pagespages# 步骤 4返回活跃 slotreturn[s.indexforsinself.slotsifs.is_running]def_free_slot(self,slot:Slot):释放 slot 的所有资源self.free_pages.extend(slot.allocated_pages)slot.requestNoneslot.is_runningFalseslot.allocated_pages[]KV Cache 的分页管理PagedAttention 的 KV 缓存不是连续分配——是按页分配的物理地址不连续。好处碎片化少一个请求的 2048 个 token KV cache 可以分配在 128 个不连续的 16-page 块中、重用率更高前缀相同的请求共享物理 page。# cann-recipes-infer/continuous_batching/kv_cache.pyclassPagedKVCache:分页管理的 KV Cache每个 page 存储 page_size 个 token 的 K/Vdef__init__(self,num_layers,num_heads,head_dim,total_pages,page_size,dtype):self.num_layersnum_layers self.num_headsnum_heads self.head_dimhead_dim self.page_sizepage_size# 物理存储[num_layers, 2, total_pages, page_size, num_heads, head_dim]# 2 [K_cache, V_cache]self.cachetorch.empty(num_layers,2,total_pages,page_size,num_heads,head_dim,dtypedtype,devicenpu)# Page 表逻辑 page → 物理 page支持不连续映射self.page_table{}# request_id → [physical_page_ids]defwrite_kv(self,layer_id,request_id,token_pos,k,v):写入一个 token 的 K/V 到分页缓存pagesself.page_table[request_id]page_idxtoken_pos//self.page_size# 逻辑 page 号offsettoken_pos%self.page_size# page 内偏移phys_pagepages[page_idx]self.cache[layer_id,0,phys_page,offset]k# Kself.cache[layer_id,1,phys_page,offset]v# Vdefread_kv(self,layer_id,request_id,start,end):读取 [start, end) 范围的 K/V可能跨页pagesself.page_table[request_id]k_chunks,v_chunks[],[]posstartwhileposend:page_idxpos//self.page_size offsetpos%self.page_size chunk_endmin(end,(page_idx1)*self.page_size)phys_pagepages[page_idx]k_chunks.append(self.cache[layer_id,0,phys_page,offset:chunk_end-posoffset])v_chunks.append(self.cache[layer_id,1,phys_page,offset:chunk_end-posoffset])poschunk_endreturntorch.cat(k_chunks,dim0),torch.cat(v_chunks,dim0)defallocate_pages(self,request_id,num_pages):为请求分配页pagesallocator.allocate(num_pages)self.page_table[request_id]pagesreturnpagesdeffree_pages(self,request_id):释放请求占用的页pagesself.page_table.pop(request_id)allocator.free(pages)Attention 计算混合 Prefill 和 DecodeContinuous Batching 的核心难点batch 中混合了 prefill 和 decode 请求。Prefill 请求一次处理所有 prompt token计算量大decode 请求每次只处理 1 个 token很小但频繁。# cann-recipes-infer/attention/mixed_attention.pydefmixed_prefill_decode_attention(Q,K,V,# [total_tokens, num_heads, head_dim]request_sizes,# [num_requests]: 每个请求的 token 数request_states,# [prefill, decode, ...]kv_cache:PagedKVCache,softmax_scale:float): 混合 prefill/decode 的 attention 计算 Q 的形状prefill 请求贡献 seq_len 个 querydecode 请求贡献 1 个 query total_tokens sum(prefill_seq_lens) num_decode_requests # 步骤 1分离 prefill 和 decode 请求prefill_indices[ifori,sinenumerate(request_states)ifsprefill]decode_indices[ifori,sinenumerate(request_states)ifsdecode]# 步骤 2Prefill attention——FlashAttention 处理长序列ifprefill_indices:prefill_Q_sections[]prefill_KV_sections[]token_offset0foriinprefill_indices:n_tokensrequest_sizes[i]# 每个 prefill 请求独立做 attention不能混合不同请求的 KVprefill_QQ[token_offset:token_offsetn_tokens]prefill_KK[token_offset:token_offsetn_tokens]prefill_VV[token_offset:token_offsetn_tokens]# FlashAttentionO(N²×D) 计算O(N×D) 内存outputflash_attention(prefill_Q,prefill_K,prefill_V,softmax_scalesoftmax_scale)prefill_Q_sections.append(output)token_offsetn_tokens prefill_outputstorch.cat(prefill_Q_sections,dim0)else:prefill_outputsNone# 步骤 3Decode attention——PagedAttention 处理单 tokenifdecode_indices:decode_outputs[]token_offsetsum(request_sizes[i]foriinprefill_indices)foriindecode_indices:# 每个 decode 请求只处理一个 queryqQ[token_offset:token_offset1]# [1, num_heads, head_dim]# 从分页 KV cache 读取全部历史 KVk,vkv_cache.read_kv(request_idi,start0,endrequest_sizes[i])# PagedAttentionO(N×D) 计算N历史长度, 只乘一次outputpaged_attention(q,k,v,softmax_scalesoftmax_scale)decode_outputs.append(output)token_offset1decode_outputstorch.cat(decode_outputs,dim0)else:decode_outputsNone# 合并输出ifprefill_outputsisnotNoneanddecode_outputsisnotNone:returntorch.cat([prefill_outputs,decode_outputs],dim0)returnprefill_outputsordecode_outputsPrefill 和 decode 分开处理的原因prefill 用 FlashAttention块内计算吞吐优化decode 用 PagedAttention逐 token 加载历史 KV延迟优化。两个 kernel 不能混用——混合只会拖慢两者。性能对比LLaMA-7B on 8× Ascend 910 NPU请求 Poisson arrival (λ50 req/s)mean seq512 | 策略 | 吞吐 (req/s) | TPOT (ms) | 显存利用率 | 平均 batch 大小 | |------|-------------|----------|-----------|----------------| | 静态 batching, bs8 | 12.3 | 1,420 | 25% | 8.0 | | 静态 batching, bs32 | 38.7 | 3,210 | 48% | 32.0 | | 静态 batching, bs64 | 44.2 | 4,890 | 31% | 64.0 | | Continuous Batching | 482 | 187 | 88% | 53.2 (动态) | 吞吐差异44.2 vs 482 → 10.9× 延迟差异4,890ms vs 187ms → 26×为什么静态 bs64 只有 31% 显存利用率因为转化为实际活跃 token 时只有 ¾ 是 prefill/decoding token剩余是 padding。Continuous Batching 没有 padding。踩坑一Prefix Caching 与 Page Sharing 的竞态两个请求共享相同的 system prompt“You are a helpful assistant…”。PagedAttention 可以让它们共享同一个 KV cache page——前缀一样不需要各自存。# ❌ 两个请求各自分配 KV cache page浪费req1allocate_pages(promptYou are a helpful assistant...Task A)req2allocate_pages(promptYou are a helpful assistant...Task B)# You are a helpful assistant... 7 tokens → 2 pages# 分配了 4 pages → 浪费 2 pages前缀 7 tokens 存了两遍# ✅ Prefix Caching共享前缀的 KV cacheprefix_hashhash(You are a helpful assistant...)ifprefix_hashinprefix_cache:shared_pagesprefix_cache[prefix_hash]# 复用req1_pagesshared_pagesalloc.allocate(needed_for_task_A)req2_pagesshared_pagesalloc.allocate(needed_for_task_B)# 前缀的 2 pages 被两个请求共享 → 省 2 pageselse:shared_pagesalloc.allocate(needed_for_prefix)prefix_cache[prefix_hash]shared_pages# 关键前缀 page 的引用计数# 释放 req1 时不能释放共享 pagereq2 还在用# 必须 refcnt ≥ 1 才能释放踩坑二Prefill 长请求占满 batch → Decode 饥饿Pre-PreFill 阶段一个请求的 prompt 有 4096 个 token → FlashAttention 在 8 张 NPU 上跑 4 秒。4 秒内没有 decode 请求被服务→decode 饥饿。TPOTTime Per Output Token因为这个 4 秒的 prefill 从 187ms 涨到 4,187ms。# ❌ 一个长 prefill 占满所有 slotslot[0]:prefill(4096tokens)→4seconds slot[1..63]:空 → decode 请求无法进入等 prefill 完成分配 KV pages# ✅ Prefill 分块Chunked Prefill长 prompt 切成多段# 每段 512 tokens中间插入 decode 请求的 service windowdefchunked_prefill(request,chunk_size512):promptrequest.prompt total_chunks(len(prompt)chunk_size-1)//chunk_sizeforchunk_idinrange(total_chunks):chunk_startchunk_id*chunk_size chunk_endmin(chunk_startchunk_size,len(prompt))chunkprompt[chunk_start:chunk_end]# 做一部分 prefill0.5msoutputflash_attention_chunk(Q[chunk_start:chunk_end],...)# 让出算力给 decode 请求1ms 的 decode windowifchunk_idtotal_chunks-1:yield_to_decode_requests(timeout_ms1.0)# 积累 KV cache 并继续kv_cache.write(request_id,chunk_start,chunk_end,K,V)实测Chunked Prefill 把 TPOT 从 4,187ms 降回 204msdecode 每 0.5ms prefill 后得到 1ms 的服务窗口。总吞吐从 482 降到 468 req/s-3%但 TPOT 降 20×——用户体验的提升远超 3% 吞吐损失。踩坑三KV Cache 页碎片化导致 OOM64 个请求 × 512 pages/request 32768 pages。分配和释放随机高度碎片化——free_pages 列表是碎片分布的分配 128 个 page 可能找不到连续块即使总空闲 pages 128。# ❌ 碎片化128 个 page 散落在 2000 个空闲位置中# 需要 128 pages → 实际有 2000 free pages → 但连续不足 → OOM# ✅ 碎片压缩定期 compact page 表defcompact_page_table(page_table,active_requests):把所有活跃 page 移到连续区域# 收集所有活跃 pageactive_pagesset()forreq_idinactive_requests:active_pages.update(page_table[req_id])# 构建新的连续映射new_mapping{}new_idx0forold_pageinsorted(active_pages):new_mapping[old_page]new_idx kv_cache[new_idx]kv_cache[old_page]# 搬数据new_idx1# 更新 page 表forreq_idinactive_requests:page_table[req_id][new_mapping[p]forpinpage_table[req_id]]free_pageslist(range(new_idx,total_pages))returnfree_pages,page_tableCompaction 的代价手动搬 32768 个 page → 32768 × (page_size × num_heads × head_dim × 2 × 2 bytes) 对于 LLaMA-7B (d4096, heads32, head_dim128): 32768 × 16 × 32 × 128 × 2 × 2 8.5GB 数据迁移 → 在 NPU 的 HBM 内部拷贝约 10ms。每个 1000 step 做一次 compact → 额外的 0.001% 时间 → 可忽略。Continuous Batching 颠覆了 LLM 推理服务的调度范式——不再让短序列等长序列。核心动态 slot 池 PagedAttention 分页 KV cache Prefix Caching 共享前缀 Chunked Prefill 避免 decode 饥饿。在 8× Ascend 910 NPU 上达到 482 req/svs 静态 batching 44.2 req/s 10.9× 提升TPOT 从 4890ms 降到 187ms26× 改善。三个关键点Prefix Caching 的引用计数管理共享 page 不能单独释放、Chunked Prefill 的长 prompt 分段策略每 512 token 让出 1ms decode 窗口、KV Cache 的碎片压缩定期 compact page 表防 OOM。

相关文章:

昇腾CANN cann-recipes-infer Continuous Batching:从静态 Padding 到动态调度,吞吐翻 10 倍

LLM 推理服务线上最大的浪费:静态 batching。一个 batch 里 8 个请求,序列长度从 12 到 2048——短的 12 个 token 2ms 就算完了,然后等长的那条跑完。190ms 算力闲置,GPU/NPU 空转。Continuous Batching 的解法:不等—…...

昇腾CANN catlass 模板元编程:零成本抽象的算子融合实战

CUTLASS 是 NVIDIA 的矩阵乘模板库,catlass 是昇腾的对应物——用 C 模板元编程在编译期生成算子,运行时零开销。核心思路:把算子拆成可组合的模板参数,编译期决定一切(tile 大小、数据布局、指令选择)&…...

使用TaotokenCLI工具一键配置开发环境与密钥

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 使用Taotoken CLI工具一键配置开发环境与密钥 在接入多个大模型服务时,开发者通常需要为不同的工具和项目手动配置API密…...

昇腾CANN ops-transformer RoPE 旋转位置编码:从复数旋转到 NTK 外推的完整实战

Transformer 的自注意力机制本身对位置不敏感——"猫坐在垫子上"和"垫子坐在猫上"的 attention score 一样,因为点积 QK^T 不区分 token 顺序。位置编码就是给每个 token 打上它在序列中的位置标签。 RoPE(Rotary Position Embeddin…...

Python 开发者五分钟快速上手 Taotoken 调用 OpenAI 兼容大模型

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Python 开发者五分钟快速上手 Taotoken 调用 OpenAI 兼容大模型 对于已经熟悉 Python 和 OpenAI SDK 的开发者来说,接入…...

在Node.js后端服务中集成统一的大模型调用层

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 在Node.js后端服务中集成统一的大模型调用层 在构建现代Web应用时,为不同功能模块引入AI能力已成为提升用户体验和产品…...

从237ms到39ms:DeepSeek-Coder推理首token时延压缩术(含完整torch.compile+Triton内核patch)

更多请点击: https://intelliparadigm.com 第一章:DeepSeek-Coder推理首token时延压缩的工程意义与瓶颈全景 首token时延(Time to First Token, TTFT)是衡量代码大模型在线服务响应能力的关键SLA指标。在IDE插件、实时结对编程、…...

掌握数字病理分析:QuPath开源工具实战全解析

掌握数字病理分析:QuPath开源工具实战全解析 【免费下载链接】qupath QuPath - Open-source bioimage analysis for research 项目地址: https://gitcode.com/gh_mirrors/qu/qupath QuPath是一款专业的开源生物医学图像分析软件,专为数字病理和生…...

使用Python快速接入Taotoken聚合大模型平台完整教程

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 使用Python快速接入Taotoken聚合大模型平台完整教程 对于希望快速体验不同大模型能力的Python开发者而言,通过一个统一…...

使用curl命令直接测试Taotoken聊天补全接口的完整指南

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 使用curl命令直接测试Taotoken聊天补全接口的完整指南 在开发或调试大模型应用时,有时我们希望在无需依赖特定编程语言…...

DeepSeek-VL多模态模型本地部署:仅需8GB显存的量化推理方案(INT4+FlashAttention-2实测FP16精度保留98.6%)

更多请点击: https://codechina.net 第一章:DeepSeek-VL多模态模型本地部署概览 DeepSeek-VL 是由深度求索(DeepSeek)推出的开源多模态大模型,支持图像理解、图文问答、视觉推理等任务。其本地部署需兼顾计算资源约束…...

Taotoken的Token Plan如何帮助我们控制月度AI支出

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken的Token Plan如何帮助我们控制月度AI支出 1. 从按需付费到计划消费的转变 作为自由职业者或小型工作室,我们在…...

ChatGPT翻译质量断崖式下滑的真相:当LLM遇上专业领域术语库缺失,这4种场景下错误率超61%——你的项目还在裸奔吗?

更多请点击: https://codechina.net 第一章:ChatGPT翻译质量怎么样 ChatGPT 在翻译任务中展现出较强的上下文理解能力与语言生成流畅性,但其质量受输入提示(prompt)设计、源语言复杂度、专业领域术语密度及目标语言语…...

DeepSeek多租户资源隔离:5大核心机制+3个避坑指南,立即提升SLA至99.99%

更多请点击: https://codechina.net 第一章:DeepSeek多租户资源隔离的架构演进与核心挑战 DeepSeek在支撑大规模AI模型训练与推理服务的过程中,逐步从单租户单集群模式演进为支持数千租户共享基础设施的多租户平台。这一演进并非简单叠加命名…...

三指拖拽终极指南:在Windows上实现macOS级触控板体验

三指拖拽终极指南:在Windows上实现macOS级触控板体验 【免费下载链接】ThreeFingersDragOnWindows Enables macOS-style three-finger dragging functionality on Windows Precision touchpads. 项目地址: https://gitcode.com/gh_mirrors/th/ThreeFingersDragOnW…...

Scroll Reverser完整指南:macOS多设备滚动方向智能管理工具

Scroll Reverser完整指南:macOS多设备滚动方向智能管理工具 【免费下载链接】Scroll-Reverser Per-device scrolling prefs on macOS. 项目地址: https://gitcode.com/gh_mirrors/sc/Scroll-Reverser Scroll Reverser是一款专为macOS设计的智能滚动方向管理工…...

Adobe Illustrator自动化脚本终极指南:告别重复劳动的设计神器

Adobe Illustrator自动化脚本终极指南:告别重复劳动的设计神器 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 你是否曾经在Adobe Illustrator中为了调整几十个画板而重…...

BabelDOC:如何用结构化中间语言实现PDF格式无损翻译?

BabelDOC:如何用结构化中间语言实现PDF格式无损翻译? 【免费下载链接】BabelDOC Yet Another Document Translator 项目地址: https://gitcode.com/GitHub_Trending/ba/BabelDOC 在学术研究和跨国协作中,PDF文档翻译一直是一个技术难题…...

3步搞定Mac Boot Camp驱动自动化部署:Brigadier完全指南

3步搞定Mac Boot Camp驱动自动化部署:Brigadier完全指南 【免费下载链接】brigadier Fetch and install Boot Camp ESDs with ease. 项目地址: https://gitcode.com/gh_mirrors/bri/brigadier 还在为Mac电脑安装Windows系统后的驱动问题头疼吗?Br…...

2026年Java面试突围指南(附高频场景题+答案)

前言今年的面试比往年要难得多,各个互联网企业对于 Java 岗位的要求越来越多,也越来越高,主要是初级岗位已经趋近饱和,但高级岗位又相对来说缺乏,这类的人才偏少,因此作为 Java 开发人员,我们应…...

微信聊天记录永久保存终极指南:3步实现智能数据管理

微信聊天记录永久保存终极指南:3步实现智能数据管理 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatM…...

自己用 ai 写了个链接 mysql 数据库的 mcp 工具

概要背景是这样的,之前用 ai 帮我生成 entity 都要我自己导出表结构,然后粘贴给它分析生成对应的 entity ,感觉好麻烦,而且还不能实时查看我的表和 entity 字段是否对应了, 问了 ai 建议我写个本地针对性的脚本或者用 …...

鸣潮自动化脚本终极指南:解放双手的完整解决方案

鸣潮自动化脚本终极指南:解放双手的完整解决方案 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸 一键日常 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves 你是否厌倦了在《鸣潮…...

DeepSeek企业版限流策略配置手册(内部泄露版):含6大行业客户真实配置快照、TPS压测曲线图及SLA违约赔偿条款映射表

更多请点击: https://intelliparadigm.com 第一章:DeepSeek企业版限流策略配置概览 DeepSeek企业版提供细粒度、可编程的API限流能力,支持基于用户身份、租户ID、模型类型及请求路径等多维度组合策略。限流配置通过统一的策略中心&#xff0…...

AppImageLauncher:3步解决Linux应用管理的终极难题

AppImageLauncher:3步解决Linux应用管理的终极难题 【免费下载链接】AppImageLauncher Helper application for Linux distributions serving as a kind of "entry point" for running and integrating AppImages 项目地址: https://gitcode.com/gh_mir…...

Informer2020深度解析:基于ProbSparse注意力机制的长序列时间序列预测实战指南

Informer2020深度解析:基于ProbSparse注意力机制的长序列时间序列预测实战指南 【免费下载链接】Informer2020 The GitHub repository for the paper "Informer" accepted by AAAI 2021. 项目地址: https://gitcode.com/gh_mirrors/in/Informer2020 …...

如何用3个步骤建立完全私有的点对点文件同步网络?

如何用3个步骤建立完全私有的点对点文件同步网络? 【免费下载链接】syncthing-android Wrapper of syncthing for Android. 项目地址: https://gitcode.com/gh_mirrors/sy/syncthing-android 你是否曾因云端服务的隐私隐患而犹豫不决?是否厌倦了每…...

BiliDownloader:三分钟掌握B站视频下载的终极指南

BiliDownloader:三分钟掌握B站视频下载的终极指南 【免费下载链接】BiliDownloader BiliDownloader是一款界面精简,操作简单且高速下载的b站下载器 项目地址: https://gitcode.com/gh_mirrors/bi/BiliDownloader BiliDownloader是一款专为Bilibil…...

免费开源播放器MPC-BE:打造你的终极媒体播放解决方案

免费开源播放器MPC-BE:打造你的终极媒体播放解决方案 【免费下载链接】MPC-BE MPC-BE – универсальный проигрыватель аудио и видеофайлов для операционной системы Windows. 项目地址: htt…...

独立开发者如何利用Taotoken的Token Plan套餐有效控制月度预算

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 独立开发者如何利用Taotoken的Token Plan套餐有效控制月度预算 作为一名独立开发者,项目预算通常有限,而AI…...