PitRadio:Gran Turismo 7 的中文赛事工程师
特别声明本文以人工形式完成了原始草稿的撰写,在完稿后使用了 GPT 6.1 Sol 模型进行了多个段落的润色,并认真进行了人工审核确保 AI 润色后的表达没有偏离我个人的本意。同时封面图也由 GPT 6.1 Sol 辅助生成。关于文章内容有任何疑问和意见,欢迎在评论区讨论项目背景我做 PitRadio 的起点,其实是想…
特别声明
本文以人工形式完成了原始草稿的撰写,在完稿后使用了 GPT 6.1 Sol 模型进行了多个段落的润色,并认真进行了人工审核确保 AI 润色后的表达没有偏离我个人的本意。同时封面图也由 GPT 6.1 Sol 辅助生成。
关于文章内容有任何疑问和意见,欢迎在评论区讨论
项目背景
我做 PitRadio 的起点,其实是想让《Gran Turismo 7》(以下简称 GT7)的画面再沉浸一点,特别是对于使用 PSVR2 来游玩 GT7 的玩家来说。
因为我平常是个很在意视听体验的人。家里 NAS 收藏的电影,能下载 4K 全都是 4K,而且最好是高码率;遇到喜欢的电影或剧集,也常常宁愿多等一阵,等到有满意的 4K、杜比版本再看。玩游戏时,这种习惯也没变。尤其戴上 PSVR2 玩 GT7 两三年后,就总想有没有办法可以在关闭 HUD 来获得干净沉浸游戏画面的同时不丢失游戏相关信息,想象一下:眼睛看着赛道,想要知道的消息由耳边的“工程师”告诉我,这种体验应该会很酷,而且最好说的是熟悉的普通话,或者粤语,听起来也自然一些。
找了一圈,没有找到在中文听感上足够让我满意的产品,自己动手的念头就冒出来了。作为一名码农,我也正好想借这个机会试一试:在 AI 编程 Agent 越来越成熟的今天,一个人从产品调研、需求梳理、设计原型,一路走到架构设计、开发和测试,究竟能做到什么程度?
于是就有了 PitRadio 这个项目。它首先服务于我自己游玩 GT7 时的一个小愿望,也逐渐变成了一次完整的 “Vibe” Coding 开发实践。
在座舱里,听到熟悉的中文

电脑和 PS5 接入同一局域网后,PitRadio 会接收 GT7 的遥测数据,也就是游戏持续发出的车辆状态与比赛数据,再把其中值得关注的变化转成语音。
声音可以从电脑的扬声器或耳机播放,也可以经由 Discord 语音频道投送到 PS5。在 PS5 加入对应频道之后,戴着 PSVR2 也能听到播报,体验更加沉浸。
目前支持普通话、粤语和英语。界面语言与播报语言可以分别设置,不过对我来说,普通话和粤语始终是最想做好的部分。
我希望它开口时像一个坐在无线电另一端的人:信息简短,数字清楚,该提醒时提醒,没必要的时候就安静。后面会聊到,为了这个听感,语音模型只是其中一环,文案怎么写、消息什么时候说,同样花了不少功夫。
工程师需要知道,什么时候该开口

最容易做出来的版本,是检测到事件就播报:名次变了就报名次,过线就报圈速,油少了就报油量。可这些事情可能同时发生,这会车手注意力也可能聚焦在重刹、过弯,或者救车。
于是在项目里设置了专门的 VoicePolicy,也就是播报策略。它负责在已经确认的事件里决定:哪些现在说,哪些等一等,哪些可以合成一句,哪些已经没有必要再说。
比如短时间内先掉了一位,紧接着又追回原位。如果前一条消息还没有开始播放,再按顺序念一遍“掉到第五”“回到第四”,只会增加干扰。PitRadio 会检查这一段变化的最终结果,取消已经失去意义的待播消息。
过线时也是一样。完成一圈和刷新个人最佳可以同时成立,但没必要连着播两段。能合并的就合并,一次最多保留两个核心事实;如果同时出现需要进站的燃油风险,普通圈速信息则应该让位。
适合等待的消息,会尽量避开重刹、弯中车手高负荷和车辆失稳的时刻。等车手驾驶负担下降,再播仍然有效的信息。如果错过时机、已经过期的消息就丢弃,不让工程师在半圈之后补报旧信息。比赛开始、过线摘要等有明确时间节点的信息,以及紧急燃油指令,则有各自的及时播报规则,并不是所有消息都要排队等直道。
这些处理各自听起来都是小事,但想要把这个播报策略处理好,需要把所有可能的赛况综合起来考虑。播报策略处理得好不好,直接决定了连续开几圈之后,我会不会想把播报关掉。应用也提供三档播报密度和类别开关:想安静一点,就少听几类;希望收到基础驾驶提醒,则可以选择“频繁”档并开启对应类别。
我对“接近真人工程师”的理解,很大一部分就在这些细节里:说话要跟得上当前的比赛,也要顾及车手此刻有没有余力听。
遥测数据能告诉我们什么,又不能告诉什么


遥测数据中包含了基础的比赛信息和车辆数据,例如当前排名、上一圈圈速、比赛总圈数和当前圈数、轮胎温度、油门开度和制动输入等等数据。
真正让我觉得有意思的,是那些不能直接读取、需要从几组数据里推算的东西,即我们说的派生数据。最初我很希望把燃油、轮胎和天气信息串起来,做出更完整的进站建议。尤其在开启油耗和胎耗的比赛里,这些信息往往比刚才那圈快了几十分之一秒更重要。
实际探索下来,有些问题可以逐步解决,有些则碰到了 GT7 遥测数据范围和主机平台封闭性的限制暂时没办法解决。
剩下的油,还能跑几圈?
“剩余油量 ÷ 每圈油耗”,看起来就是一道简单的除法计算。难点在于,每圈油耗该取哪个值?
如果过分依赖眼前的油门状态,松一下油门、再踩下去,预计圈数就可能跟着变化。对于要安排燃油进站策略的“工程师”来说,我更希望得到一个稳定、又能跟随驾驶方式变化的估算。
目前的做法是先用最近最多三个有效完整圈建立基线,越近的一圈权重越高。只有一圈、两圈时,就先使用已有的有效样本。这样得到一个相对稳定的单圈消耗,再用剩余油量计算预计可跑圈数。
但只看完整圈也有问题:如果我刚调整了燃油 Map,或者开始持续省油,要等跑完一整圈才反映出来,显然有点迟。因此又加了一层“同位置比较”:把参考圈分成二十个区间,比较当前区间与历史相同位置的油耗。连续几个区间都表现出同一个方向的变化后,才逐步修正原来的估算。
这里比较的是同一段路。直道和弯道原本就有不同的油耗,不能把正常的驾驶节奏误当成长期趋势。加油、暂停、数据中断或驶上松散路面等情况,也需要分别处理,不能不加区分地算进历史。
最终得到的,是用于判断燃油风险的预计圈数,而不是逐帧复刻游戏 HUD 中的剩余圈数读数。在条件满足的固定圈数比赛中,它可以进一步给出“这一圈结束时进站”的提醒。可惜的是固定时间赛比如耐力赛目前只提供燃油风险提示,因为现有数据没有可靠的剩余比赛时间,不能据此判断能否撑到终点。
胎耗和天气:有些信息确实算不出来
轮胎这一部分,我也尝试过类似的思路。
GT7 遥测数据提供四轮温度,但没有直接给出胎耗百分比。我曾考虑能否从其它字段找到间接线索,比如轮胎有效半径:如果磨损之后半径发生变化,是否就有机会据此估计消耗?
为了核对这个猜想,项目录制了一组使用中性赛车胎、开启九倍胎耗的比赛数据,覆盖明显磨损和换新胎的过程。结果发现:前后轮的半径字段分别始终保持固定值,换胎前后也没有重置。我感觉这也是为什么说 GT7 是 Sim-Cade,而不是 Sim 的原因吧。不知道 iRacing 那边的情况是怎么样。
这条路走不通了。至少在这组实测里,这个字段并没有反映我所期待的磨损数据变化。
胎温同样不能直接换算成胎耗。轮胎过热,可以提醒我注意持续高温带来的损耗风险,却不能据此说“还剩百分之多少”或者“还能跑三圈”。当前留下的是持续高胎温提醒,胎耗百分比、轮胎剩余寿命和换胎时机都没有被包装成现成功能。
天气雷达的限制更直接。游戏里能看到天气,不等于应用收到的遥测数据里也有对应信息。在目前能获得并验证的遥测数据中,我没有找到足以还原雷达、判断雨区移动或预测何时下雨的依据。仅凭车辆此刻的运动状态,也无法补出赛道远处的天气变化。
这些探索最后没有变成想象中的完整进站策略,确实有些遗憾。平台没有开放的信息,并不会因为多套几个公式就可以计算得出。也因此,在依赖胎耗或天气判断的比赛中,我仍建议保留游戏里必要的信息显示,如下图设置。保留这些游戏内信息,再搭配语音播报,可以兼顾准确信息与沉浸体验。
用车辆的实际运动,判断推头和甩尾
相比胎耗,车辆动态给了我更多可以验证的线索。
转向不足,俗称“推头”,可以粗略理解为:前轮已经转过去了,车却没有按预期转那么多。转向过度则可能表现为车尾向外滑,车辆转得比驾驶者希望的更多。
项目把前轮实际转角、车速和轴距放进一个简化的车辆运动学关系里,估算理论上的转弯响应:
理论横摆角速度 ≈ 车速 ÷ 轴距 × tan(前轮平均转角)
“横摆角速度”就是车身朝向每秒转过多少角度。拿估算结果与车辆实际的转动速度对照,再结合车身朝向和移动方向之间的夹角,就有了判断横向失稳的几条线索。
当然,公式本身不能直接充当结论。实际转动小于理论值,并不一定就是推头;轮胎打滑,也不一定就是甩尾。规则还要检查车速、状态是否持续、有没有反打方向,以及是否离地、越界或经过路肩。
目前的基础驾驶指导只覆盖持续驱动轮打滑、持续推头和明显持续甩尾。例如发现持续推头时,提醒减少转向角、适当降低入弯速度;发现明显车尾横滑时,提醒稳住方向、柔和控制油门。它们在“频繁”播报档中启用,也不是对每一次轻微车身摆动都作出播报。
这部分是我觉得项目里很有意思的一段:遥测数据中的原始数据,经过有依据的组合计算,确实能描述一小部分驾驶感受。但现有计算逻辑仍受标定样本限制,不能把已经跑通的场景直接外推到所有车型和所有工况。至于精确指导刹车点、走线和出弯油门曲线,那是我后面规划的功能。
让声音像无线电,也像一个人在说话
说完“什么时候说”和“说什么”,才轮到“怎么说”。
目前 PitRadio 使用云端 TTS,也就是把文字转换成语音的服务。采用这种大模型语音合成模型,是希望获得比以往常规 TTS 更连贯的发音、停顿和语气效果。不过,比赛判断与播报内容仍由规则引擎和播报内容模板生成,不让语言合成模型临场改写播报文案。
比如“1:32.876”,播出来应该是“一分三十二秒八七六”;这些转换在进入语音合成之前就完成了。圈速、名次、剩余圈数和赛车术语,都需要按口语重新组织。
粤语也有自己的整句模板和数字读法,不能只把普通话文案交给模型,再加一句“请用粤语说”。我想听到的是自然的表达,而不只是换了发音的书面中文。
动态播报采用整句合成,没有把“现在”“第三”“上一圈”之类的片段预先合成好再拼起来。拼接虽然能够节省语音合成的算力需求,但音高、停顿和句尾很容易断开,听久了尤其明显。
语气也需要克制。圈速汇报可以平静一点,燃油告警要清楚坚定,刷新最佳时可以带一点肯定,但不必变成热情的赛事解说。音频处理上再加少量无线电质感,让声音更贴近座舱里的交流。效果不能加得太重,否则发动机一响,最需要听清的数字反而被盖住了。
到底像不像一个人在说话,文字描述终究有限。我把真实游戏中的播报录屏放在了 PitRadio 官网,可以直接听普通话、粤语和英语的播报效果。
Vibe Coding 是真的 Vibe 吗?
做这个项目之前,我对 AI 辅助开发的好奇,主要是它能帮我写多少代码。做下来以后,我更在意的是:怎样让它持续朝着正确的方向工作,以及改完之后,我凭什么相信结果?
Agent 的能力越强,单次能够完成的工作越多,这两个问题反而越重要。
开发过程中,我也尝试落地一些 Harness 工程的理念,例如渐进式披露,把 AGENTS.md 作为目录,产品需求、技术架构和事件规则等各种项目信息进行分别归档,让 Agent 按需阅读,而不是一次塞入全部信息,包括某一次重要功能或者模块的开发也会归档这次的行为,也会对一些可能会反复出现的错误进行经验总结。这些工作做得越好,后续也就受益越多。

这个项目也让我更加认可测试驱动开发(TDD)的理念:先说清楚怎样才算做对,再去实现和验证。为了核对播报是否符合预期,我建立了原始遥测的录制与回放机制,让同一场比赛可以反复用于回归和冒烟测试,并要求回放与实时播报共用同一条处理流程。这样逐渐积累下来的上下文信息、真实样本和测试用例,反而是项目里最珍贵的资产,也让我在每次修改代码之后,有了可用来进行回归测试的用例,以及不同阶段,用来验证产品主流程的冒烟测试用例。同时再做一些主流程的集成测试和端到端测试,基本上能确保代码质量的下限。

架构选型同样需要认真取舍。AI 帮我更快地完成了不少小规模技术方案的验证,但方案能跑起来,不代表适合正式使用。比如我曾经考虑过自托管语音模型,经过延迟、听感和维护成本的比较,最终还是选择了云端服务。因此,开发速度提高之后,提前想清楚各部分的职责、验证关键假设,反而更加重要,否则省下的编码时间,很可能又花在后续返工上。
同样,规则判断、播报策略和语音输出需要保持清楚的边界。换一个语音服务,不应该连排名变化和燃油告警的逻辑都重写。AI 可以很快帮我完成一次修改,但边界如果没有想清楚,后面每一次修改都会更难验证。
所以,Vibe Coding 到底是不是很“Vibe”?至少在这个项目里,我没有体验到把想法丢给 Agent,当一个甩手掌柜,就能放心等成品的轻松。
变化更明显的是我自己的工作内容:手写代码的时间少了,定义问题、整理上下文信息、设计验证方法、核对真实结果的时间多了。有时最值得做的事,甚至是用一次实验确认某条路走不通,然后及时停下来。
不过,能从“我想在 GT7 里听到中文工程师”这样一个个人愿望出发,逐步把它做成可以使用的应用,这个过程还是很有意思的。
如果你也玩 GT7,尤其习惯戴着 PSVR2 游玩游戏,可以到 PitRadio 官网 看看演示、下载应用并申请公测。目前公测期间免费,因为服务器资源有限,所以语音播报需要申请通过后使用。目前应用支持 macOS 和 Windows 平台,后续计划推出 iOS/Android 应用。
原文出处:少数派 Matrix (本文由聚合程序自动采集,版权归原作者所有)