news 2026/10/3 2:28:55

Sunshine ABR 提示词模板深度解析:LLM 驱动的游戏流媒体自适应码率决策引擎

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Sunshine ABR 提示词模板深度解析:LLM 驱动的游戏流媒体自适应码率决策引擎
  • 音视频

【免费下载链接】foundation-sunshine

Sunshine fork: an enhanced sunshine, a self-hosted game streaming host for Moonlight with HDR10/HDR Vivid, virtual displays, advanced audio, optimized encoders, and a modern control panel.

项目地址:https://gitcode.com/gh_mirrors/sunshine5/foundation-sunshine
点击查看免费下载

本文围绕 Sunshine(一个基于 Moonlight 协议的自托管游戏流媒体主机)中自适应码率(Adaptive Bitrate,ABR)决策引擎的 LLM 提示词模板展开,讲解src/assets/abr_prompt.md这份模板如何将网络指标与前台应用识别转化为最优编码码率决策,并结合 src/abr.cpp、src/nvhttp/abr_api.cpp 等源码揭示其完整工作链路。读完本文,你将掌握 ABR 模板的占位符机制、按应用类型分类的码率目标设定方法、视觉复杂度修正规则、网络调整规则,以及该模板在 Sunshine 服务端如何被加载、填充、提交给 LLM 并解析回码率动作。

一、ABR 提示词模板的定位:LLM 决策层的"大脑"

在 Sunshine 的 ABR 架构中,码率控制被设计为两层结构(见 src/abr.h 的文件头注释):

  1. 实时回退层(Fallback):基于丢包等网络阈值做即时反应,始终生效,每 3 秒限频一次;
  2. 事件驱动 LLM 层:在应用切换、网络恢复等事件发生时,异步调用配置好的 LLM API,为当前游戏/应用推荐一个最优目标码率。

src/assets/abr_prompt.md正是第二层 LLM 决策所依赖的提示词模板。它通过{{PLACEHOLDER}}占位符接收会话运行时状态,指导 LLM 完成"识别应用 → 按交互类型定基码率 → 按视觉复杂度修正 → 结合网络反馈微调 → 输出 JSON 动作"的完整推理链。

模板的加载逻辑位于 src/abr.cpp 的load_prompt_template():搜索顺序为配置目录(用户覆盖)→ assets 目录(捆绑默认),首次成功加载后缓存。具体而言,它会先尝试读取config::sunshine.config_file所在目录下的abr_prompt.md(即用户可通过放置同名文件覆盖默认提示词),若不存在则回退到编译期常量SUNSHINE_ASSETS_DIR下的捆绑版本。两份都不存在时,日志会输出警告 "ABR: prompt template not found, LLM decisions will be unavailable",LLM 层将静默失效而回退层继续工作。

二、模板占位符:会话状态如何注入提示词

build_llm_prompt()(src/abr.cpp)负责用运行时状态替换模板中的所有{{key}}占位符,替换逻辑由replace_placeholders()实现(循环查找{{key}}并替换)。模板中的占位符与填充来源对应如下:

占位符填充内容填充来源
{{FOREGROUND_TITLE}}前台窗口标题运行时detect_foreground_app();缺省回退到配置的 app_name,再回退到 "Unknown"
{{FOREGROUND_EXE}}前台进程可执行文件名同上
{{MODE}}ABR 运行模式balanced/quality/lowLatency字符串
{{CURRENT_BITRATE}}当前码率(Kbps)会话状态current_bitrate_kbps
{{MIN_BITRATE}}/{{MAX_BITRATE}}允许码率范围(Kbps)会话配置min_bitrate_kbps/max_bitrate_kbps
{{RECENT_FEEDBACK}}最近网络反馈列表(最新在前)滚动窗口内最近 10 条反馈,每条格式为- [Ns ago] loss=..%, rtt=..ms, fps=.., dropped=.., bitrate=..Kbps
{{FPS_RANGE}}FPS/赛车类目标区间int(max*0.8)-max
{{ACTION_RANGE}}动作/冒险类目标区间int(max*0.6)-int(max*0.8)
{{STRATEGY_RANGE}}策略/回合制目标区间int(max*0.4)-int(max*0.6)
{{DESKTOP_RANGE}}桌面/生产力目标区间int(max*0.2)-int(max*0.3)

注意:范围类占位符并非模板中的静态文本,而是依据会话的max_bitrate_kbps动态计算后填入,因此模板中的-> {{FPS_RANGE}}等描述在实际请求中会变成具体的数值区间(如-> 40000-50000)。

前台应用识别是"应用感知码率"的关键前提。detect_foreground_app()(src/abr.cpp)在 Windows 平台通过GetForegroundWindow()获取前台窗口,再经GetWindowThreadProcessId与QueryFullProcessImageNameW取得进程名,并统一转为 UTF-8。其设计动机(源码注释明确说明):当用户通过 Steam/Epic 等启动器进入游戏时,配置中的app_name往往只是 "Steam Big Picture",而该函数能拿到真正活跃的游戏窗口标题与进程名。该检测以 10 秒为间隔限频(FG_DETECT_INTERVAL_SECONDS),仅在 PID 变化时才更新标题/进程并置app_changed标志,从而驱动 LLM 重新评估。

三、Step 1:按交互类型确定基础码率目标

模板首先要求 LLM 根据 Active Window 与 Process 名称识别正在运行的应用,并在允许范围内按交互类型确定基础目标(基码率)。这是模板中最核心的应用感知规则:

交互类型目标区间(占最大码率比例)示例应用(模板原文)
快节奏 FPS / 竞速(Fast-paced FPS/Racing)80%–100%CS2、Forza、Apex
动作 / 冒险(Action/Adventure)60%–80%Elden Ring、GTA V
策略 / 回合制(Strategy/Turn-based)40%–60%Civilization、XCOM
桌面 / 生产力(Desktop/Productivity)20%–30%explorer.exe、chrome、浏览器

其设计逻辑是:第一人称射击与竞速游戏画面快速运动、信息量大,对码率敏感,应尽量贴近上限;动作冒险居中;策略与回合制画面相对静态;桌面场景对画质要求最低,应把带宽让给网络余量。模板同时强调"IMPORTANT: If current bitrate differs significantly from the adjusted target, you MUST adjust toward it",即当前码率与修正后目标差异显著时,LLM 必须朝目标方向调整。

四、Step 2:按视觉复杂度修正基础区间

在基础区间之上,模板要求 LLM 结合渲染风格做二次修正,这是"画质-码率"权衡的精细化规则:

  • 动漫 / cel-shaded 风格(Genshin Impact、Honkai、Persona):降低 10%–20%——大面积平涂色与重复纹理压缩效率高,无需高码率;
  • 像素艺术 / 2D(Terraria、Stardew Valley、复古游戏):降低 20%–30%——极端可压缩;
  • 写实 / 高细节(RDR2、Flight Simulator、Forza):保持区间上沿——复杂纹理压缩率低;
  • 黑暗 / 恐怖场景(Resident Evil、Dead Space):保持中等——暗部渐变在低码率下易出现色带伪影;
  • 未知应用:使用未修正的基础目标。

该规则本质是让 LLM 综合"运动复杂度 + 纹理复杂度"两维信息,避免对可压缩性强的画面浪费码率、对难压缩的画面过度压缩。

五、调整规则:稳定性与网络适应约束

模板为 LLM 的最终决策设定了硬性约束,防止码率剧烈抖动或在网络恶化时决策失当:

  1. 单次决策最大变化量:当前码率的 15%(稳定性考虑);
  2. 网络丢包 > 5%:覆盖最大变化量限制,强制降低 25%–35%;
  3. 网络丢包持续 2%–5%:降低 10%–20%;
  4. 网络稳定且当前码率 ≠ 目标:每步最多向目标调整 10%;
  5. 任何情况下不得超出[{{MIN_BITRATE}}, {{MAX_BITRATE}}]允许范围。

最后一条在服务端有双重保障:parse_llm_response()在解析出码率后会执行std::clamp(bitrate, state.config.min_bitrate_kbps, state.config.max_bitrate_kbps)强制收敛到会话允许范围(src/abr.cpp);同时,即便 LLM 决策为 0(模板语义"仅当当前码率处于类型目标 5% 以内且网络稳定时才输出 0"),服务端也只把结果当作"不立即动作"处理。

六、响应格式与容错解析

模板严格要求 LLM 只输出 JSON:{"bitrate": <integer_kbps>, "reason": "<reason>"},并明令禁止<think>标签、markdown 代码块、注释及 JSON 前后的任何文本。bitrate置 0 仅在"当前码率处于类型适切目标 5% 以内且网络稳定"时允许。

现实中的 LLM(尤其是 DeepSeek-R1、QwQ 等推理模型)常不遵守此约束,因此服务端实现了多级容错解析(parse_llm_response(),src/abr.cpp):

  1. 先直接尝试json::accept()校验原始 content;
  2. 失败则调用strip_reasoning_blocks()大小写不敏感地剥除<think>...</think>块(未闭合的<think>起始标签也会被清除);
  3. 仍失败则用extract_first_json_object()手动扫描字符串,正确处理字符串转义与花括号嵌套,提取第一个完整 JSON 对象;
  4. 全部失败时给出诊断原因:llm_parse_error: no JSON object in content。

针对真实场景的回归问题——推理模型在max_tokens耗尽(finish_reason == "length")时<think>块被截断、JSON 尚未产出——代码会返回llm_truncated: reasoning exceeded max_tokens,并在日志中提示增大ai_config.json的max_tokens(默认 1024,已预留约 600–800 推理 token 余量)。

解析成功后,若新码率与会话当前码率差异 ≥ 2%(current_bitrate_kbps / 50)才产生立即动作;差异过小则 reason 记为no_change: delta too small。LLM 的推荐值始终被记录为target_bitrate_kbps,作为回退层探测性升码(probe-up)的天花板。

这些容错行为均有单元测试覆盖(位于 src/abr.cpp 的SUNSHINE_TESTS段):ExtractsJsonAfterThinkBlock、ExtractsFirstJsonObjectFromMixedContent、ReportsMissingJsonWhenContentHasOnlyReasoning、DetectsTruncatedReasoningWhenFinishReasonLength、PreservesExplicitMaxBitrateWhenMinIsOmitted。

七、LLM 层的触发与执行链路

LLM 调用是事件驱动的,而非周期性轮询。process_feedback()(src/abr.cpp)每个反馈周期按以下阶段执行:

  • Phase 1 前台检测(限频 10s):PID 变化 → 更新前台应用并置app_changed = true;
  • Phase 2 回退决策(限频 3s):丢包 > 5% 时不受限频立即紧急降码率(emergency_drop,降至当前 70%);丢包 2%–5% 时moderate_drop(降至 90%);丢包 < 0.5% 且连续 5 个稳定周期时probe_up(升至 105%)。探测升码一旦存在 LLM 目标,则取min(probe_bitrate, llm_target_bitrate_kbps),已到或超过目标则停止探测;
  • Phase 3 LLM 触发:仅当(app_changed || network_recovered) && !llm_in_flight && confighttp::isAiEnabled() && 提示词模板非空时,且距上次调用 ≥ 10 秒(LLM_MIN_INTERVAL_SECONDS),才构建提示词并派发后台线程执行。

后台llm_worker()(src/abr.cpp)通过confighttp::processAiChat()以 OpenAI 兼容格式调用 LLM:请求体包含 system 提示(默认 "You are a streaming bitrate optimizer. Respond with a single valid JSON object only...",可从ai_config.json覆盖)、用户消息(即本模板填充后的完整提示词)、temperature(ABR 层默认 0.1)与max_tokens(默认 1024)。worker 使用generation计数器防陈旧结果:会话被清理或重建后,旧 worker 的结果直接丢弃。

network_recovered的判定采用边沿触发——stable_ticks首次达到 5 且无持续高丢包时置位一次,配合app_changed共同决定是否重新咨询 LLM。

八、AI 能力开关:ai_config.json 与相关 REST 端点

模板要真正生效,还需要 AI 代理处于启用状态。confighttp::isAiEnabled()(src/confighttp.cpp)要求ai_config.json中enabled为真、apiBase非空,且(若提供商要求 key)apiKey已配置。该文件与sunshine.conf同目录,默认值为{"enabled": false, "provider": "openai", "apiBase": "https://api.openai.com/v1", "model": "gpt-4.1-mini", "compatibility": "openai-chat", "temperature": 0.3, "max_tokens": 2048}。API key 不落盘于明文 JSON——首次读取到遗留明文 key 时会自动迁移到安全凭据存储ai_llm_credential.bin(见 src/confighttp.cpp)。

ABR 的对外能力通过三条 HTTPS 路由暴露(注册于 src/nvhttp.cpp),客户端(Moonlight)通过源 IP 关联活动会话:

  • GET /api/abr/capabilities:返回supported、version、features(含llm_ai、game_aware、fallback_threshold、bitrate_cap)、llmEnabled(即isAiEnabled())与hostMaxBitrate;
  • POST /api/abr(configure):接收enabled、mode(balanced/quality/lowLatency)、minBitrate、maxBitrate,校验非负且 min ≤ max,再用apply_host_bitrate_cap()以主机配置video.max_bitrate封顶;随后调用abr::enable()启动会话级 ABR;
  • POST /api/abr/feedback:接收packetLoss、rttMs、decodeFps、droppedFrames、currentBitrate,调用abr::process_feedback(),若有新码率则通过stream::session::change_dynamic_param_for_client()以动态 BITRATE 参数实时作用于活动流,并把newBitrate、bitrateApplied、reason返回给客户端。

abr::enable()中的模式预设(src/abr.cpp)值得一提:仅对未显式配置的边界套用预设值,从而保留客户端或主机设定的 maxBitrate 上限——quality模式为max(5000, initial/2)至min(150000, initial*1.5),lowLatency为2000至initial*1.2,balanced为max(3000, initial*0.3)至min(150000, initial*2),并处理初始码率极低时的区间反转。

九、自定义模板与调优建议

由于load_prompt_template()优先加载配置目录下的abr_prompt.md,用户可以:

  1. 在sunshine.conf同目录放置自定义abr_prompt.md,覆盖仓库内 src/assets/abr_prompt.md 的默认模板——例如新增应用分类、调整各区间比例或收紧单步变化量;
  2. 若使用 DeepSeek-R1、QwQ 等"长思维链"推理模型,请在ai_config.json中调大max_tokens,避免<think>块截断导致解析失败(日志会给出llm_truncated: reasoning exceeded max_tokens提示);
  3. 保持temperature较低(ABR 层默认 0.1),使决策更稳定可复现;
  4. 会话键是客户端的设备显示名(device display name),源码注释明确提醒:同名设备的多会话并发会共享同一 ABR 状态而产生交叉污染——正常配对设备名称各异,单会话部署不受影响。

综上,src/assets/abr_prompt.md虽只是数百行提示词文本,却是 Sunshine 将 LLM 能力与游戏流媒体码率控制结合的关键接口:它把"应用识别 + 画质分类 + 网络容忍度"编码为结构化决策规则,再经由 src/abr.cpp 的加载、填充、触发、解析链路落到实时的编码器码率调节上,与始终在线的阈值回退层互补,构成一套完整、可观测、可自定义的自适应码率闭环。

  • 音视频

【免费下载链接】foundation-sunshine

Sunshine fork: an enhanced sunshine, a self-hosted game streaming host for Moonlight with HDR10/HDR Vivid, virtual displays, advanced audio, optimized encoders, and a modern control panel.

项目地址:https://gitcode.com/gh_mirrors/sunshine5/foundation-sunshine
点击查看免费下载

相关推荐

上一篇:使用 kubeadm 部署 Cilium:从集群初始化到连通性验证的完整指南
下一篇:lo 迭代器工具集:it.Last 详解——从 iter.Seq 序列中安全获取最后一个元素

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 2:27:26

数据库模式设计实战:在线考试系统建模与DB2实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/3 2:26:10

telegram - advanced-features

高级功能 - Telegram 机器人 目录 内联模式支付&#xff08;Telegram Stars&#xff09;迷你应用&#xff08;WebApps&#xff09;对话处理器&#xff08;FSM&#xff09;贴纸游戏Passport企业机器人&#xff08;Business Bots&#xff09;消息草稿&#xff08;流式输出&…

作者头像 李华
网站建设 2026/10/3 2:25:03

Web 前端工程化积累:深入理解 Vue 组件中 scoped 样式的作用域与原理

文档教程前端 【免费下载链接】Web 千古前端图文教程&#xff0c;超详细的前端入门到进阶知识库。从零开始学前端&#xff0c;做一名精致优雅的前端工程师。 项目地址&#xff1a; https://gitcode.com/gh_mirrors/we/Web 点击查看 免费下载 本文是「Web 前端工程化」系列中针…

作者头像 李华
网站建设 2026/10/3 2:25:01

TCP 与 UDP:从可靠字节流到无连接数据报,怎么选、怎么测

TCP 与 UDP&#xff1a;从可靠字节流到无连接数据报&#xff0c;怎么选、怎么测 ℹ️ 读者定位 适合你&#xff0c;如果&#xff1a; 会调用 API、配置端口、写 Socket 服务&#xff0c;或者正在学习计算机网络&#xff0c;但还分不清 TCP 的可靠性、UDP 的消息边界和 QUIC 的…

作者头像 李华
网站建设 2026/10/3 2:23:55

好问题从哪里来:一场关于“发现“本身的深度追问

有一类人,总能在一个领域里问出让所有内行都愣住的问题。他们不一定比别人聪明,不一定读书比别人多,甚至不一定是那个领域里技术最扎实的人。但他们总能在别人司空见惯、习以为常的地方,精准地指出一个裂缝——一个此前没有人意识到需要被解释的东西。 这种能力常被简单归结为…

作者头像 李华