迅步科技

关于

迅步科技专注Shopify独立站,Shopify应用及无头网站开发,为您的品牌提供快速、灵活、个性化的电商体验,提升用户转化率与运营效率。欢迎咨询合作。

微信联系二维码
分类

XunbuOS Podcast 2026-08-26

Shopify 工程博客精选:LLM 压缩、移动端测试稳定性与 Checkout 性能优化

今日 XunbuOS Podcast 汇总 Shopify 工程团队的十篇技术文章,覆盖 LLM 推理优化、移动端 E2E 测试重建、AI 代理安全扫描框架、Checkout Extensibility 迁移、Catalog API 聚类等热点话题。


Gisting:将 LLM Agent 系统提示词压缩 4 倍

压缩机制

Shopify 实现 gisting 技术,将 Sidekick GraphQL agent 的系统提示词从约 6,000 token 压缩到约 1,500 个 gist token(4:1 压缩比),且不损失预测质量。特殊 token 的嵌入通过知识蒸馏学习,推理时将完整提示词替换为 gist token。

关键实现:teacher pass 中模型看到完整提示词,student pass 中用 gist token 替换,通过 KL 散度损失函数训练 gist 嵌入。部署时直接将嵌入写入模型的嵌入矩阵,推理无需自定义注意力掩码。

性能数据

在 350 RPM 负载下:

  • 中位首 token 延迟(TTFT):438ms 降至 354ms(-19%)
  • 中位端到端请求延迟:6.8s 降至 4.2s(-38%)
  • 吞吐量:20.2 QPS 提升至 23.4 QPS(+16%)
  • GPU 需求减少 14%

与前缀缓存的叠加效应

前缀缓存无法消除解码成本——每个生成的 token 需关注序列中所有 key,且 KV 缓存读取量随序列长度线性增长。Gisting 降低注意力计算和 KV 缓存读取成本,两种技术可叠加使用。

训练优化

Autoresearch loop 发现三项关键优化:均值初始化嵌入将初始 loss 降低 7 倍;4:1 是最优压缩比;大规模多样化数据集消除质量差距。预计算 teacher logits 和预 tokenize 数据将训练时间从 30 小时缩短至 6 小时。


移动端 E2E 测试稳定性提升至 98%

旧框架问题

Shopify 最大应用的 E2E 测试套件用 WebdriverIO + Appium + React Native Test ID,稳定性仅 50%。开发者用 pause(1000) 等临时手段掩盖等待问题,断言检查的是组件树节点存在性而非用户体验。

重建方案:严格 API + 计算机视觉

新框架由两部分组成:构建器风格 API(强制良好模式)和计算机视觉查找元素(像用户一样扫描屏幕)。底层仍由 Appium 驱动设备,但开发者无法绕过包装器。

  • 每一步操作必须携带断言
  • 逃生舱以 UNSAFE_ 前缀命名,提示开发者避免使用
  • PaddleOCR 处理文本识别,OpenCV 将截图与 Polaris SVG 匹配
  • 每次运行生成带注释的视频,显示每一步查找内容与结果

迁移效果

新 API 推广到阻塞式 CI 几周后,测试稳定性从 50% 提升至 98%。其余失败主要来自偶发网络问题和模拟器启动失败。预推广不稳定门槛要求新测试多次运行证明稳定后才允许进入阻塞套件。


Sidekick 持续学习循环:成本降低 96%

学习闭环架构

Shopify GraphQL agent 的持续学习循环包含五个阶段:

  1. 定义质量:评估标准(rubric)将产品需求转化为评分维度,用 Cohen's kappa 验证标注者一致性
  2. 校准评判器:用 DSPy + GEPA/ACE 优化器,回测 A/B 测试结果,执行定向降级测试
  3. 自动研究改进编排:agent 提出修改,评判器评估,保留高分支方案
  4. 从离散工件到参数更新:挖掘困难负样本,前沿模型批判分析失败,强化学习折叠回模型权重
  5. Gisting 压缩服务提示词:减少延迟与 GPU 成本

效果数据

  • 微调后模型在评判器质量上超越前沿模型基线
  • 服务成本:前沿模型估算年成本约 2,700 万美元,微调模型接近 100 万美元(-96%)
  • 延迟:TTFT 下降约 19%,端到端延迟下降约 38%
  • 吞吐量:每秒请求数增加约 16%,GPU 减少约 14%

自愈管道

生产失败对话自动进入管道:前沿推理模型批判分析 → 仲裁器合并修复指令 → 重播对话 → 评判器评分 → SFT + GRPO 训练。Toloka 处理评判模型无法修复的案例。


构建智能体安全扫描框架

多智能体编排

Dispatch 框架用 Ruby 编写,包含九个有序阶段:测试引导、架构文档、文件编目、分区、猎手、验证、后处理、报告、修复。验证者使用与猎手不同的模型,对抗性审查减少噪音。

成果

  • 超过 80 个应用完成完整扫描(含 Shopify Core 单体仓库)
  • 六周内产生 300+ 发现,两个被评为"严重"
  • 保守估计价值超过 40 万美元漏洞赏金
  • 完整应用扫描成本:50-300 美元;增量差异扫描:5-50 美元

关键经验

  • 分区策略:目标 token 数量约为模型上下文窗口的 20-30%,按相关领域分组文件,提高准确性和召回率
  • 多个模型交叉验证:一个模型捕获另一个模型的错误,减少误报
  • 确定性脚本:结构化输入输出用编程方式强制执行,减少格式错误
  • 测试预言机:Web 漏洞候选用前端单元测试、多租户固件测试验证,无法证实则降级严重性

Checkout Blocks 升级到 Polaris Web Components

迁移范围

五个高流量 UI 扩展从 React + Remote UI 迁移到 Preact + Polaris Web Components + remote-dom,API 版本从 2025-07 升级到 2026-01,代码库重写为 TypeScript。

性能提升

传输体积缩减 40.5% 至 84.4%:

扩展传输体积缩减
payment-icons-84.4%
static-content-54.1%
custom-field-44.6%

加载性能(ELT,按结账量加权):P50 -8%,P90 -7%。

64KB 包体积限制下的工程决策

  • 去掉 react-reconciler(约 89KB):Preact 免费收益
  • 自研 Liquid 解析器 "droplet"(约 73KB → 13KB,gzip 后):42,000 行生产环境 fixture 对等性验证
  • 替换 dayjs(约 12KB):用小型内部日期工具
  • 保留 markdown-to-jsx(约 15KB):通过别名映射到 Preact,避免改变渲染行为

沿途修复的 Bug

  • ID 冲突(唯一一次生产回滚):useId() 生成确定性 ID 导致同一扩展两个实例冲突,改用 useStableId hook 生成随机实例唯一 ID
  • 文本对齐:Polaris Web Components 的 Paragraph/Heading 移除 textAlign,重新暴露 textAlignment 属性
  • s-checkbox label 插槽:重构为接受 HTMLElement,支持"接受[条款和条件]"模式

ShopifyQL Code Editor 构建实践

架构方案

ShopifyQL Notebooks 用 CodeMirror 作为编辑器框架,语言功能封装在 TypeScript 语言服务器中(ANTLR 语法 + LSP 协议)。由于 Lezer(CodeMirror 的解析引擎)不遵循 LSP,构建自定义适配器连接两者。

关键技术:令牌偏移量转换

ShopifyQL 语言服务器的令牌格式为 5 个整数:行号、起始字符、长度、类型、修饰符。其中行号和起始字符是相对前一个令牌的增量值,而非绝对位置。CodeMirror 则要求所有偏移相对于文档顶部。

解决方案是自定义 TokenIterator 类:

  • 计算每一行长度(含换行符)
  • 内部跟踪当前行和字符位置
  • 将 ANTLR 相对偏移转换为 CodeMirror 绝对偏移

语言功能对接

  • 语言服务器 doValidate → CodeMirror linting 插件
  • doCompleteautocomplete 插件
  • doHoverrequestHoverTooltips 插件

Catalog API:聚类数十亿产品

聚类策略

Shopify 采用精度优先策略——展示错误结果比结果不完整更糟。先解决店内聚类(intra-store clustering),将单一全局任务分解为数百万个店铺级任务。

LLM 参与方式

"核心价值主张"框架作为提示核心:如果属性不改变买家购买的根本原因,则是变体;否则构成产品身份。两阶段管道:

  1. 预分块:ANN 检索 + 稀疏平均链接,构建最多 200 个产品的语义相关块
  2. 提取与聚类:提取品牌和型号分配 UPI,异常值检测默认保持合并

成本控制

单例检测器分析商店主题代码,Liquid 模板商家的确定性链接模式直接解决,LLM 仅处理模糊情况。动态结构化输出模式使字段顺序控制推理,清理非 ASCII 标记提升召回率 8%。


Ruvy:Ruby 到 WebAssembly 工具链

与 ruby.wasm 的差异

  • 预初始化:Ruvy 在构建时预初始化 Ruby VM,运行时性能提升约 20%
  • 编译耗时:Wasmtime 上比 ruby.wasm 快约 70%(446ms vs 1.66s)
  • 无需运行时参数:不要求提供 WASI 参数,兼容边缘计算环境

使用方式

Ruvy 读取 Ruby 文件生成 index.wasm 模块,调用 _start 函数即执行代码。--prelude 标志预加载额外 Ruby 文件目录。

适用场景:Shopify Functions 中复用 Shopify Scripts 的 Ruby 逻辑。


Sidekick 拒绝能力:LLM 法官共识自动策展

问题根源

生产日志只记录成功案例,模型从未学过拒绝无法完成的请求。手动合并 600 条标注数据时,同一查询在生产和 Toloka 数据集标签相反,导致模型矛盾信号。

解决方案

四个前沿 LLM 法官(A/B/C/D)独立评估每条查询,仅当四者在判断结论和推理逻辑上完全一致时才采纳标签变更。分类体系必须互斥:可解决但需更多上下文、缺失能力、错误技能、歧义。

效果数据

  • 分群技能评估分数:0.619 → 0.798(+28.9%)
  • 拒绝准确率 86.3%,误报率 4.6%
  • 法官与真实标签一致性接近 90%,Cohen's kappa 超过 0.75

Shopify Hack Days 39:音乐播放页面原型

平台级原型

13 人团队在三天内探索音乐产品页面。Jamie Guerrero 用 5 个 PR 构建了跨平台的 Audio 媒体类型:新数据库表、Merchandising::Audio 模型、Audio GraphQL 类型、Liquid drops、音频可视化器 web 组件。{{ product.media | media_tag }} 渲染播放器的方式与 3D 模型相同。

应用原型:Shop Sounds

  • 完整 Shopify 应用:发布管理、产品变体同步、metafield 配置
  • 音轨列表播放器:全局音频单例解决跨页面播放问题
  • 六个 GLSL 着色器 × 七种配色方案 = 42 种视觉身份
  • 巡演日期块:Haversine 公式计算到场距离,显示"23 英里外"
  • 数据层全部用 metaobjects 和 metafields

分类:今日要点速览

类别关键数据
LLM 推理优化提示词压缩 4:1,GPU 减少 14%
移动端测试稳定性 50% → 98%
Checkout 迁移包体积缩减最多 84.4%
安全扫描300+ 发现,成本 50-300 美元/次
AI 成本控制服务成本降低 96%

播客全文

女:Hello 大家好,欢迎收听 XunbuOS Podcast,我是小雅。

男:大家好,我是老冯。

女:今天这期内容特别丰富,我们攒了好几篇 Shopify 工程团队的技术分享,从 AI 到移动端测试到前端架构都有。老冯,咱们从哪个聊起?

男:我觉得可以先聊那篇 gisting 的文章,就是怎么把 LLM 的系统提示词压缩掉。这个跟我们之前聊的 Sidekick 持续学习那篇是同一个体系里的。

女:对,那篇我看标题就挺感兴趣。简单说就是把六千个 token 的 system prompt 压缩到一千五?这压缩比可以啊,4:1 对吧?

男:对,4:1。核心思路挺优雅的:训练一组特殊的 gist token,推理的时候用这组 token 替换掉完整的提示词。模型权重不动,只训练这些 token 的 embedding。本质上是知识蒸馏,让模型看到简短的 gist token 时,行为表现得跟看到完整提示词一样。

女:这个对商家意味着什么?就是一串 token 的事儿,能有多大影响?

男:影响还真不小。他们在 350 RPM 的负载下做了测试,TTFT 中位数从 438 毫秒降到 354 毫秒,端到端延迟从 6.8 秒降到 4.2 秒,吞吐量从 20.2 QPS 提升到 23.4 QPS。最关键的是,省下来的 GPU 是实打实的——他们最终减少了 14% 的 GPU 配额。

女:14% 的 GPU,这在现在的成本环境下不是小数目。那既然 gist token 这么好用,为什么之前没人这么做?

男:其实这个想法有论文基础,Wingate 他们在 2022 年就提出过。但真正落地的时候有不少细节坑。比如 embedding 的初始化方式,他们试过随机初始化,损失高得离谱。后来发现把提示词切成片段、取均值初始化,初始 loss 直接降了 7 倍。

女:这细节够细的。还有个问题,现在很多系统不是都有 prefix caching 吗?缓存了 KV cache,提示词的 prefill 成本基本可以忽略啊。为什么还需要 gisting?

男:这是个好问题。前缀缓存解决的是 prefill 的重复计算问题,但 decode 阶段每个 token 都要关注整个序列的 KV cache。序列越长,每次 decode 要流式读取的 KV 就越多,这是内存带宽瓶颈。batch 越大,这个成本越明显。Gisting 是把序列本身变短了,所以 KV cache 也变小了,decode 成本线性下降。两者是叠加的,不是互斥的。

女:明白了,所以 gisting 是治本,缓存是治标。那这篇文章后来提到,gisting 跟持续学习也打通了?

男:对,这个设计很聪明。蒸馏出来的 gist embedding 可以作为后训练的起点,梯度同时更新模型权重和 gist embedding。这样就不用每轮都重新蒸馏了,持续学习的成本也降下来了。

女:这个飞轮转起来确实是核心竞争力。说到持续学习,下一篇文章讲的就是 Sidekick 的持续学习循环,从生产失败里面学东西。

男:这篇我觉得是今天最值得聊的。核心思路是把生产环境里的失败——用户纠正、被拒绝的输出、反复出现的失败——转化为训练信号,让模型权重持续更新。而不是像传统做法那样,把知识堆在提示词、检索示例、路由规则这些离散工件里。

女:听起来很理想,但你怎么定义什么是"好"?这个定义应该是整个飞轮的地基吧?

男:对,他们花了很多篇幅讲这个。关键是先写一份 rubric,把产品质量拆成几个维度,每个维度有具体的锚点。然后让两位产品专家盲审 25 个随机样本,计算标注者间一致性。如果 Cohen's kappa 只有 0.2 左右,说明 rubric 太模糊,得回去改。目标不高,就希望 LLM 评判器和人类专家之间的匹配度,能跟两个人类专家之间的匹配度相当就可以。

女:所以评判器的能力上限其实就是人类标注者的一致性?

男:就是这个意思。人类专家对某些歧义案例都没法 100% 一致,没必要追求完美,跟人差不多就行。

女:那校准完评判器之后呢?怎么用它来改进模型?

男:分两个阶段。第一个阶段是在不碰权重的前提下,优化编排层——提示词、工具定义、控制流。他们把这当成一个自动研究问题,类似 Karpathy 最近做的事:一个 agent 提出修改,评判器评估,分数提升就保留,否则回滚。

女:这是离散的,第二阶段就该动权重了对吧?

男:对。等编排优化到平台期,开始从生产流量里挖掘困难负样本,就是评判器打分很低、暴露模型弱点的对话。用一个自愈管道,几个前沿推理模型分析每次失败,仲裁器合并成修复指令,重放对话,评判器再评分。通过之后,这些修好的轨迹就成了强化学习的训练数据。

女:具体训练方式呢?

男:两阶段。先 SFT,把修好的轨迹蒸馏到小模型,注意是训练完整的轨迹包括推理过程,不只是答案。然后 GRPO,用评判器当奖励信号,对每个提示采样一组响应,强化表现最好的。

女:这跟之前提的"从生产失败压缩为模型权重"这句话就完全对上了。那效果呢?

男:他们拿 GraphQL agent 举例,每分钟最多服务 2000 个请求。用前沿模型服务这些流量每年估计要 2700 万美元,微调后的模型接近 100 万,降了 96%。而且质量还超过了前沿基线。

女:96% 的成本下降,这个数字太夸张了。难怪 Shopify 这么重视基建。

男:对,这篇文章最后有个总结我印象很深:前沿模型帮你启动,最初的改进存在于它周围的工件里,但持续学习把这些经验转化到连续参数空间。每个周期都始于一个更强的模型,这才是护城河。

女:好,那咱们转到另外一篇。移动端 E2E 测试的重建,把稳定性从 50% 提到了 98%。这个我特别想听,因为测试不稳定真的太常见了。

男:这篇的痛点描写很真实。他们之前用 WebdriverIO 加 Appium,用 Test ID 定位元素。灵活性太大反而成了负担——没有任何机制强制好的测试模式。开发者图省事就加个 pause(1000),本地看着没问题,CI 上偶尔就挂。久而久之,测试套件不可靠到从 PR 检查里被移除了。

女:测试套件烂到被移除,这确实说明问题很严重。那他们重建的核心思路是什么?

男:从底层换思路。第一,构建一个严格的 builder 风格 API,让写出不稳定测试变得困难。每一步都带断言,你没法点击一个元素而不声明屏幕应该显示什么。第二,用计算机视觉代替 Test ID 查找元素,像真人一样看屏幕点"保存"按钮。

女:每一步都带断言这个设计,能详细说说吗?

男:就是每个操作之前必须有断言说明前一个操作的结果,操作之后要验证状态。如果应用偏离预期,测试就在偏离的步骤立即失败,而不是等到后续操作时报"元素未找到"。另外逃生舱口都有 UNSAFE_ 前缀,测试代码里出现 UNSAFE_timeoutInSeconds 就是审查信号。

女:有趣的命名方式。那计算机视觉这块怎么实现?

男:底层还是 Appium 驱动设备,但定位方式换成截屏扫描。PaddleOCR 做文本识别,OpenCV 匹配 Polaris 设计系统里的 SVG 图标。Test ID 还在,但得通过 UNSAFE_testID 主动选择,等于是默认不用。真正的优势在编写速度——你不用打开检查器去翻组件树,直接看模拟器写 touch({ text: 'Save' }) 就行。

女:这个对 AI 代理也友好,因为语法跟屏幕显示一一对应。

男:对,文章里提到 AI 能一次写出正确测试,不需要任何代码库知识。每次运行还生成带注释的视频,失败时能看到 OCR 在搜什么、找到了什么、点了哪里。

女:这个体验差距太大了。那迁移之后稳定性数据呢?

男:他们推广到阻塞 CI 几周后,稳定性到 98%,之前是 50%。剩余失败主要是偶发网络问题和模拟器启动。另外他们建了个预推广门槛,新测试进阻塞套件之前,专用管道先跑多次,失败率超阈值就拒绝。

女:这个门槛很重要,不然好测试会被坏测试连累。那最后一个问题,这套方案有没有推广到其他应用?

男:已经在最大的应用上验证了,正在探索推广。文章结尾有个观点我很认同:原来我们以为 E2E 测试本质上就是不稳定的,最好的办法是管理这种不稳定性。但事实证明,很多问题在 API 本身,不在测试代码。换掉 API,用正确的原则之后,稳定 98% 是自然结果。

女:说到换 API,下面这篇也跟"换"有关,不过换的是 UI 扩展的底层架构。Checkout Blocks 升级到 Polaris Web Components,这个跟第三方开发者直接相关。

男:对,这篇实操性很强。背景是 Shopify 在把整个 UI 扩展体系从 Remote UI 迁到 remote-dom 加 Polaris Web Components,旧 API 2025-07 版本要下线了。2026 年 10 月 1 号之后,部署包含早于 2026-01 的扩展会被阻止。

女:这个时间点得提醒一下听众。那他们迁移完有什么收益?

男:每个扩展的传输体积都大幅下降,从 40% 到 85% 不等。加载性能也有提升,ELT P50 普遍降了 6% 到 12%。

女:那迁移过程中最难的挑战是什么?

男:64KB gzip 的硬性限制。他们的扩展原来 gzip 后 100 到 112KB,是限制的两倍多。不砍到 64KB 以下没法发布。所以整个工程工作基本就是围着这个预算转。

女:怎么砍的?

男:最大的一笔是去掉 react-reconciler,约 89KB。旧架构用 React 加 React reconciler 把组件树翻译成 remote-ui 的协议,remote-dom 不需要这个,直接渲染 DOM,所以换成 Preact 是自然选择。然后是替换 liquidjs,约 73KB。他们自研了一个最小化 Liquid 解析器,内部叫 "droplet",gzip 后 13KB,比 liquidjs 小约 40%。

女:自研解析器,这不简单。他们怎么保证行为一致?

男:方法很严谨。拿官方 Liquid 规范当真理来源,然后建了一个对等性测试套件——从数据仓库里抽样几万个真实商家 Liquid 配置,每个配置都有 liquidjs 的确切输出。光 fixture 文件就超过 42,000 行。迭代到 droplet 在这个语料库上跟 liquidjs 完全匹配,只保留几个有意的差异。

女:这也是用生产数据验证,不是合成用例。那这种自研的价值有多大?毕竟 liquidjs 就 22KB,节省 9KB,值得吗?

男:在 64KB 预算下,9KB 是九分之一的差距。而且他们现在有个更甘心的投入——省下来的钱让其他更重要的功能活下来了。另外还有 dayjs,约 12KB,换成了内部日期工具,只覆盖实际用到的功能。

女:那有没有什么东西他们本来想换但没换的?

男:有,markdown-to-jsx。他们考虑过换成一个 2KB 的解析器加自定义转换,但原型做完之后放弃了——风险太高,会改变 markdown 对商家的实际渲染方式。最后通过 pnpm workspace 里把 React 别名映射到 Preact,markdown-to-jsx 直接跑在 Preact 上,行为完全不变。

女:这个决策很理智。那迁移过程中有没有踩坑?我猜对这么大规模的升级肯定有。

男:有一个挺典型的 Bug,也是他们唯一一次生产回滚。custom-field 扩展上线后,结账页面上有多个弹层的情况下,点击第二个字段的链接打开的是第一个字段的模态框。原因是 ID 冲突——他们用 Preact 的 useId() 生成 ID,但 useId() 生成的是限定在单棵渲染树范围内的确定性 ID,同一扩展的两个实例生成了相同 ID。Polaris Web Components 重度依赖 ID 做 commandFor 连接,所以出问题了。

女:修复方式?

男:写了个 useStableId hook,用 Math.random() 生成实例唯一的 ID,而不是确定性的。

女:这类问题听起来就是那种你不真的上线跑一跑根本发现不了的问题。那文章里还有提到 AI 辅助迁移?

男:对,他们大量使用内部代理技能做机械性工作——React 到 Preact 的转换、Polaris React 组件换成对应的 s-* 组件、hooks 迁移到新 API。工程师把精力集中在需要判断力的决策上。

女:好,那咱们聊聊那篇 AI 代码审查的框架文章。这个感觉是把 LLM 用在安全上,挺有意思的角度。

男:对,这篇文章讲的是怎么用多智能体框架做代码审查和漏洞发现。他们做了一个叫 Dispatch 的编排器,能把大规模扫描的复杂度隐藏掉,让扫描作者专注写漏洞猎手智能体。

女:那这套工作流出过什么真实成果?

男:六个月扫描了 80 多个应用,包括 Shopify Core(全球最大的 Rails 单体仓库之一),产生 300 多个发现,其中两个被评为"严重"。他们保守估计这些发现的价值超过 40 万美元的等效漏洞赏金。而且全量应用扫描成本只要 50 到 300 美元,增量差异扫描只要 5 到 50 美元。

女:这个投资回报率相当惊人。那工作流具体是啥样?

男:分成几个有序阶段。先是测试引导,找正确的测试命令并验证套件能跑。然后生成架构文档,记录数据模型、API、授权模式。接着文件编目、分区——把相关文件分成有界的块,保证每个猎手智能体的上下文窗口不被塞爆。然后并行跑猎手智能体,每个分区一个。关键是验证阶段——用另一个模型写真实测试来验证候选发现。

女:所以是有两个不同的模型,一个找问题,一个验证?

男:对,而且用不同模型是故意的。验证者对抗性审查猎手的发现,可以减少噪音和盲点。如果验证者没法用真实约束下写出的测试证明可利用性,发现就被降级或拒绝。比如 IDOR 验证者,要求从公开调用点往后追踪,创建不同租户的测试固件,测试必须提取有影响力的跨租户数据——布尔值、原始 ID 这些会被降为"低"严重性。

女:这个标准很实用。那文章里说"框架比模型更持久",这个观点我觉得特别重要。你怎么理解?

男:新模型不断出,每个都发现更多候选漏洞,但更优秀的猎手也产生更多听起来自信的噪音。发噪音给开发者比没有更糟糕,浪费时间和信任。

女:那真正持久的是什么?

男:是针对你软件生态特性调优的框架:用真实集成测试证明可利用性的测试预言机、保持成本与召回率平衡的分区、跨模型验证、有凭证和 Git 所有权的确定性代码。这样新模型来了能快速迁移,但框架本身一直在积累。

女:说到积累,咱们前面聊了 gisting、持续学习、代码审查、移动测试,还有几篇没聊。剩下的时间咱们挑一两篇快速过一下?那篇 Catalog API 的聚类,还有那篇 ShopifyQL Notebooks 的编辑器的,都还挺有意思的。

男:Catalog API 那篇讲的是怎么把数百万商家的产品数据标准化,核心是产品聚类——把所有相关变体归到一个通用产品标识符下。挑战在于精度和召回率的权衡。他们选择精度优先,因为展示错误结果比结果不完整更糟。

女:他们用 LLM 来解决这个问题的思路是什么?

男:核心是"核心价值主张"框架:如果某个属性不改变买家购买产品的根本原因,它是变体;如果改变了,就构成产品身份的一部分,需要拆分。比如颜色是变体,但"内存大小"可能改变购买理由。不过不是所有产品都需要 LLM——很多商家的 Liquid 模板已经有确定性的分组机制,这些用确定性方法解决就行,LLM 只处理真正模糊的情况。

女:那 ShopifyQL Notebooks 那篇呢?我记得是讲怎么把 ShopifyQL 语言服务器接进 CodeMirror 的。

男:这个技术细节比较多,但核心难点很有意思。ShopifyQL 的语法定义在 ANTLR 里,语言服务器也基于 ANTLR,但 CodeMirror 用的是自己的 Lezer 解析引擎。本来可以不讲兼容,把语法重写,但他们选了个更聪明的路——写一个适配器,遵循 LSP 协议,并把 ANTLR 的令牌流转成 Lezer 能用的缓冲区。

女:最难的地方在哪?

男:令牌偏移量的表示方式。ANTLR 的令牌偏移是相对的——行号和字符位置都是相对于前一个令牌的。CodeMirror 则是绝对偏移,整个文档是一长串文本。最坑的是注释,它们在 ANTLR 的默认通道里不被解析,主通道全部解析完之后才处理,所以注释令牌的行号会出现负数。他们写了一个 TokenIterator 类来解决这个问题,遍历文档、跟随偏移量方向、沿途转换。

女:说到这种技术细节,我突然想到一个跟这个完全不在一个领域、但精神相通的故事——Hack Days 那篇。13 个人三天做出来一个音乐播放器应用原型,还带可视化器和巡演日期。这种黑客松文化在 Shopify 看来是真的落地了。

男:对,那篇读起来很放松,但里面有个重要的技术点我发现没——Sammy 提到的"全局音频单例"。当顾客浏览店铺时播放音乐,切页面音乐不打断。这个是通过应用嵌入块注入单个 audio 元素实现的。这跟咱们之前聊的结账扩展的渲染模型其实是一个思路——保持共享状态在页面间延续。

女:从平台工程到边角文化,今天聊得真不少。最后收个尾吧,你觉得今天这几篇串起来,有什么共同的主题?

男:我觉得最明显的是"从生产数据中学习"这个主线。Gisting 用蒸馏学习优化提示词;持续学习飞轮从生产失败学权重;代码审查框架用真实测试验证漏洞;移动测试从真实用户行为学怎么定位元素。就连 Hack Days 那个音乐播放器,也是从商家数据出发——音乐周边商品 GMV 超过 10 亿美元但是体验不行。这些都是把生产环境当作数据的来源,而不是假设解决方案在真空中成立。

女:听你这么一说确实,每个案例都有这个特征。那

参考链接


迅步科技专注Shopify独立站,Shopify应用及无头网站开发,为您的品牌提供快速、灵活、个性化的电商体验,提升用户转化率与运营效率。欢迎咨询合作。

0:00
0:00
0:00
XunbuOS Podcast 2026-08-26 · XunbuOS Podcast