[上海] Kong 招聘多名工程师| Rust / Go / API Gateway / AI Gateway / Infra / 前端 / SDET ( 14 HC )

大家好,我们是 Kong 上海研发团队(核心产品线)

近期团队扩张,一次性开放 10+ 技术 HC 。
如果你对 网关 / 高并发 / 网络 / Rust / Go / 云原生 / AI Infra / 开发者工具 感兴趣,可以聊聊。

不是外包,不是业务 CRUD ,主要做 底层基础设施和高性能系统方向


关于 Kong

Kong 是全球领先的 API Gateway / Cloud Native Infrastructure 公司

核心产品:

  • Kong Gateway (基于 OpenResty / Nginx )
  • Service Mesh
  • AI Gateway (大模型流量治理)
  • Insomnia (开源 API Client ,类似 Postman )

客户多为海外技术型公司。

上海团队是:

  • 核心研发(非 support / 本地化)
  • 直接参与 global 架构设计
  • 英文协作 + 工程文化驱动

团队风格偏:

  • Code Review / Design Doc
  • Async 协作
  • 工程质量优先
  • 相对 WLB (不 996 )


在招岗位


① Gateway Runtime / Infra (核心推荐)

Staff Engineer / Senior / Software Engineer II (多名)

方向:

  • API Gateway Runtime
  • 高性能网络处理
  • 插件系统设计
  • 核心转发链路优化

技术栈:

  • Lua / Rust / Go / C++ / Java / Python
  • OpenResty / Nginx
  • Linux / Networking / 高并发 / 性能优化

希望你有:

  • 系统/中间件/网关/存储/高并发服务经验
  • 熟悉 HTTP/TCP/TLS 等网络协议
  • 做过性能优化/底层架构更佳

👉 适合喜欢「底层 + 性能 + 工程深度」的同学


② AI Gateway (新方向,增长中)

Engineering Manager / Senior Engineer

做什么:

  • 大模型/LLM 请求网关
  • AI 流量治理 & 安全控制
  • Token / Rate Limit / Policy 管理
  • AI Infra 能力建设

技术:

  • Go / Rust / Python / Lua
  • 有 LLM / AI 相关经验加分

👉 属于 AI + Infra 结合赛道,技术挑战比较新


③ 前端(平台型产品)

Config Management UI ( Vue )

  • Vue / TypeScript
  • 偏控制台/配置平台/DevTool
  • ToB/工程化前端经验加分


④ SDET / 自动化测试

Cypress / Playwright / TS/JS

  • 自动化测试框架建设
  • CI/CD 集成
  • 工程质量体系建设

不是纯手工测试,偏工程化能力


⑤ Insomnia Team (开发者工具)

  • Senior Go Engineer
  • Senior SDET

Insomnia 是开源 API Client (类似 Postman ),海外用户很多。

方向偏:

  • 客户端
  • 工具链
  • 开发者生态


为什么可以考虑我们(客观版)

  • 外企文化,节奏相对健康
  • 技术栈硬核( Rust / Go / 网关 / AI Infra )
  • 做真正的基础设施,不是业务系统
  • 团队规模小而强,个人影响力大
  • 和 global 团队直接协作

如果你:

  • 想从业务转 Infra
  • 想做 Rust/Go 底层
  • 或对 AI Infra/网关方向感兴趣

匹配度会比较高。


工作地点

📍 上海


投递方式

内推直达 Hiring Manager:

📮 [email protected]

💬 V2EX 私信我

邮件标题建议:
[岗位 + 年限 + 城市 + 姓名]

我会帮你直接对接,流程相对高效。


有问题欢迎回帖/私信交流。
也可以帮你判断岗位匹配度。

欢迎奔走相告,如感兴趣,非常欢迎直接投递英文简历到 chitty.li@konghq.com

https://jobs.ashbyhq.com/kong?locationId=7bc9ac56-8533-43bc-abe0-919dc8caa459 这是我们 Kong 现在上海在招的所有职位,您可以看看。

老婆的手机前阵子不知道在哪儿把主摄的镜头正当中横着划了一个一公分长很深的划痕

我是没想明白她包里或者口袋里能有什么东西如此坚硬可以把蓝宝石镜头盖划成这样

然后今天吃完饭逛到了国金直营店就顺路进去折旧买新手机

店员走了一遍检测说什么这个划痕没检测出来 当前估值 2930 如果过几天再来说不定就不是这个价了

那只好就折旧了 又加了 8000 多换了个 17pro

这个价格正常吗

内部运维工具的访问路径重构,核心在于以“身份态锚定”为核心构建全链路信任校验体系,彻底摒弃传统架构中基于内网网段的准入逻辑,将每一次运维访问请求都拆解为身份、环境、操作三重态的综合核验。在实际的技术落地中,运维人员对不同层级运维工具的访问,不再依赖固定的内网权限配置,而是需要先完成身份态的动态核验,涵盖人员身份的实时有效性、运维角色的权限匹配度,身份信息会与企业人员管理体系实时同步,确保权限与岗位状态完全绑定,再进行环境态的校验,包括访问终端的运行状态、网络接入的环境合规性,终端的补丁更新、安全配置都会纳入核验范畴,网络接入则不区分内外网,仅以环境合规性为判断标准,最后完成操作态的前置匹配,确认操作行为与运维场景的适配性,操作内容需与对应的运维工单、任务指令关联,无关联的操作请求会直接被拦截。三重态核验通过后,才会生成临时的访问链路,且链路的存续时间与操作范围严格绑定,操作结束后链路即刻失效,超时未完成操作也会自动断开。这种重构方式让访问路径从固定的、静态的内网通道,转变为动态的、按需生成的信任链路,从根源上杜绝了无授权访问、权限越界等问题,同时也让运维访问的每一个环节都处于可追溯、可管控的状态,实现了访问权限的微切片化与访问链路的态化闭环,彻底改变了传统运维访问的粗放模式。

在运维工具访问路径的深层重构中,还需建立“行为态校准”机制,针对批量运维、跨节点操作等复杂场景,构建动态的行为基线与实时校验逻辑。传统架构中,运维人员的批量操作往往缺乏过程校验,一旦出现操作偏差难以及时干预,甚至会引发连锁性的运行问题,而零信任架构下,会基于运维人员的历史操作数据、岗位场景特征,生成专属的行为基线,基线会区分常规运维、应急运维、批量配置等不同场景,动态适配不同的操作特征。在运维操作执行过程中,实时校验操作行为与基线的匹配度,若出现偏离基线的异常操作,比如超出权限范围的批量修改、非工作时段的高频操作,会即刻触发链路的临时冻结与二次核验,同时记录操作的态流数据,形成完整的行为溯源档案,档案会留存操作的全流程细节,为后续的复盘与优化提供依据。这种重构要求让运维操作从“事后追溯”转变为“事中校准”,不仅强化了访问链路的安全性,更优化了运维操作的合规性与精准性。此外,访问路径的重构还需适配多终端、跨地域的运维场景,打破物理位置与终端类型的限制,移动端、桌面端、远程终端的访问都遵循统一的三重态核验逻辑,针对移动终端还会增加设备绑定、生物特征核验等补充维度,确保无论何种访问场景,都能遵循统一的信任校验逻辑,让运维访问路径的重构具备全场景的适配性。

监控系统的数据采集方式重构,核心是建立“数据态溯源”体系,将数据采集的全链路纳入信任校验范畴,彻底改变传统架构中监控节点单向推送数据、采集链路无核验的模式。在实际实践中,监控系统的每一个采集节点,都需要先完成节点身份的锚定核验,采集节点需完成注册备案,绑定唯一的身份标识,核验通过后才能接入采集网络,未备案的节点会被直接拦截,杜绝非法采集节点接入。再对采集的数据进行态化封装,将数据的采集时间、采集节点、数据类型、信任核验结果等核心信息与专属信任标识绑定,形成可溯源的数据单元,每一个数据单元都具备唯一的溯源标识,可反向追踪至采集源头。数据传输过程中,每一个中转节点都需要对数据单元的信任标识进行核验,核验内容包括标识的有效性、数据的完整性,只有核验通过的数据才能进入下一级流转环节,最终汇聚至监控分析平台。这种重构方式让数据采集从无序的、无校验的单向流转,转变为有序的、可溯源的信任传输,从根源上避免了无效数据、篡改数据进入监控体系,同时也让监控数据的来源、流转过程清晰可查,为后续的数据分析与决策提供了可信的数据基础,也让监控采集链路的每一个节点都处于可控的状态,解决了传统监控数据杂乱、溯源困难的核心问题。

监控数据采集的深层重构,还需搭建“数据流转态管控”框架,针对监控数据的跨域汇聚、分级使用等场景,实现数据流转的全态管控与权限绑定。传统架构中,监控数据汇聚后往往采用统一的访问权限,难以实现数据的分级管控与精细化使用,不同岗位的分析人员无差别访问所有监控数据,极易造成数据滥用。而零信任架构下,会根据监控数据的敏感等级、使用场景,将数据划分为基础运行数据、核心节点数据、专项监控数据等不同层级,为不同的分析角色分配差异化的数据使用权限,权限与角色、岗位深度绑定,无法跨层级访问。数据在流转与使用过程中,会实时校验使用者的身份态与权限匹配度,同时记录数据的使用态流,包括数据查看、导出、分析等操作的全流程信息,形成完整的数据使用溯源档案。此外,监控数据的分析过程也会纳入态化管控,分析操作的类型、范围、时长都与权限严格绑定,超出权限范围的分析行为会被及时拦截,分析结果的导出也需经过二次核验。这种重构要求让监控数据从“集中存储、粗放使用”转变为“分级管控、精准使用”,既保障了监控数据的安全流转,又最大化发挥了数据的分析价值,同时也让监控系统的数据采集与使用形成完整的信任闭环,适配零信任架构的核心要求。

零信任架构下内部运维与监控体系的重构,并非一次性的静态实施,而是需要建立“架构态动态校准”机制,实现体系的长效适配与持续优化。在技术落地后,需定期对运维访问的三重态核验规则、监控采集的数据态溯源逻辑进行复盘,复盘周期结合企业技术迭代节奏设定,重点核验规则的适配性、执行效率与风险防控效果。结合运维场景的迭代、监控需求的变化,动态调整核验维度、权限配置与流转规则,比如新增运维工具时,快速补充对应的操作态校验规则,监控范围拓展时,优化数据态封装的维度。同时针对新接入的运维工具、新增的监控采集节点,快速完成信任体系的适配与融合,新节点接入前需完成全流程的信任校验配置,确保无缝融入现有体系。此外,还需建立态流数据的分析机制,通过对运维访问行为态、监控数据流转态的数据分析,识别体系运行中的薄弱环节,比如高频触发的异常核验点、数据流转的卡顿节点,针对性优化重构策略,调整核验规则与流转路径。

传统基于单点服务的观测体系,往往会陷入“局部达标、整体失准”的认知盲区,当业务事务在多服务间流转时,节点间的衔接损耗、状态传导偏差、流程闭环断层等隐性问题,会直接消解单点服务的优质表现,最终导致业务终端的体验劣化却无法溯源,这也使得构建一套锚定业务事务整体态的度量体系,成为分布式技术实践中亟待突破的核心命题。我们需要跳出技术链路的表层拼接视角,以业务语义为核心锚点,搭建覆盖事务全生命周期的全域度量框架,从本质上捕捉跨服务业务事务的真实运行状态,而非被碎片化的指标数据误导判断。在实际的技术落地中,我们常会遇到这样的场景:单个服务的可用率维持在极高水准,但跨十余个服务的业务事务却频繁出现闭环失败,终端反馈体验卡顿,可逐一排查单点服务时,却找不到任何异常指标,这种矛盾的根源就在于传统度量只关注节点本身,忽略了节点间协同流转的核心价值,而全域度量体系的构建,正是要打破这种碎片化观测的局限,让度量视角从“点”延伸至“域”,真正贴合分布式业务事务的运行本质。

定义跨数十服务的业务事务,核心在于完成“语义锚定”与“边界切片”的双重操作,摒弃以技术调用链路为唯一依据的定义方式,转而从业务流转的核心价值闭环出发,提取事务的核心发起节点、价值转化节点、结果闭环节点,以此为基准划分事务的核心域,再将支撑核心域流转的关联服务纳入从属域,剥离与业务价值闭环无直接关联的支撑性服务,避免度量范围的冗余扩张。同时通过“事务态标识”的方式,为每一次完整的业务流转赋予唯一的语义标识,贯穿所有关联服务的运行过程,确保度量数据能够精准归属于对应的业务事务实例。这种定义方式既规避了技术链路的复杂性干扰,又能让度量维度始终贴合业务的核心诉求,为后续的可用性与性能度量奠定精准的基础,也让跨服务的事务度量不再陷入无边界的技术链路追踪困境。在具体的操作实践中,我们会先梳理业务的核心价值流转路径,明确哪些服务是直接参与价值创造的核心节点,哪些是仅提供基础支撑的从属节点,再通过语义关联将核心节点串联成闭合的事务域,从属节点仅作为辅助观测维度纳入体系,这样既保证了度量的精准性,又降低了大规模数据采集的算力消耗,让事务定义既贴合业务逻辑,又具备技术落地的可行性。

度量跨服务业务事务的整体可用性,需构建以“稳态存续度”为核心的多维评估体系,区别于传统的服务在线率指标,该体系聚焦于业务事务从发起至闭环的全流程稳态存续能力,同时纳入“断层自愈率”作为辅助评估维度,稳态存续度通过统计业务事务在全生命周期内未出现流转中断、状态丢失的实例占比,反映事务整体的运行稳定性,而断层自愈率则衡量当某一服务节点出现运行波动时,事务流转的自愈传导效率,即波动节点的状态偏差能否在不影响事务闭环的前提下完成自我修正。我们通过划分事务的发起、流转、转化、闭环四大阶段,分别统计各阶段的稳态存续占比,再结合各阶段的自愈传导效率加权计算,最终得到业务事务的整体可用性分值。这种度量方式突破了单点可用性的局限,真正反映了跨服务事务的整体抗波动能力,也能精准定位导致事务中断的核心环节。在实际观测中,我们发现很多业务事务的可用性问题并非源于节点宕机,而是节点间的状态传导断层,比如某一节点的临时波动导致事务状态丢失,后续节点无法接续流转,而稳态存续度与断层自愈率的结合,能精准捕捉这类隐性故障,让可用性度量从“节点在线”升级为“事务闭环”,更贴合业务层面的真实需求。

对于跨服务业务事务的整体性能度量,我们摒弃了单节点时延求和的传统思路,提出“流转时延熵”与“节点协同滞涩度”两大核心度量指标,流转时延熵用于衡量业务事务在多服务间流转的时延离散程度,时延熵值越低,代表事务各环节的时延分布越均衡,整体流转的流畅性越高,反之则说明存在明显的时延瓶颈节点,节点协同滞涩度则评估相邻服务节点间的衔接效率,反映服务间状态传递、数据交互的滞缓程度。通过采集业务事务全链路的时延数据,分析其离散特征与节点间的衔接损耗,我们能够精准识别出性能瓶颈的核心位置,而非单纯关注单节点的时延高低,这种性能度量逻辑更贴合分布式事务的协同运行本质,能够从整体层面优化业务流转的性能表现,而非陷入单点性能优化的无效内耗。在实践中,我们曾遇到单节点时延极低,但整体事务流转缓慢的情况,通过流转时延熵分析发现,各环节时延差异极大,存在明显的短板节点,而节点协同滞涩度则进一步定位到节点间数据交互的衔接损耗,针对性优化后,整体事务性能提升显著,这也验证了这套性能度量体系的实用价值,让性能优化从单点调试转向全域协同调优。

将分散的度量数据转化为可落地的业务决策依据,核心在于构建“事务态画像”并提取“趋势推演因子”,我们整合稳态存续度、断层自愈率、流转时延熵、节点协同滞涩度等多维度量数据,通过特征聚合形成每类业务事务的专属态画像,直观呈现其可用性与性能的整体状态、薄弱环节与运行特征,同时从历史度量数据中提炼出影响事务运行的核心趋势推演因子,包括服务节点迭代频率、业务流量波动幅度、跨服务数据交互量等,基于这些因子对业务事务的未来运行状态进行推演,提前预判潜在的可用性风险与性能劣化趋势。这种数据应用方式让度量体系不再局限于事后统计,而是实现了事前预判、事中调控、事后优化的全流程支撑,让度量数据真正服务于分布式业务事务的持续优化。在落地过程中,我们会为每类高频业务事务生成动态态画像,实时更新度量数据,同时基于历史数据训练推演模型,当流量波动或服务迭代时,能提前预判事务运行风险,及时调整服务调度策略,避免体验劣化,让度量体系从“观测工具”升级为“决策支撑”,深度融入分布式系统的运维与优化流程。

分布式系统的动态演进特性,决定了业务事务的度量体系必须具备“动态域校准”与“度量弹性适配”能力,随着业务场景的迭代、服务架构的调整,跨服务业务事务的边界、核心流转节点、关联服务都会发生变化,若固守静态的度量体系,必然会导致度量结果的失真,因此我们需要建立定期的度量体系复盘机制,结合业务需求的变化与服务架构的演进,重新校准业务事务的语义锚点与边界切片,调整度量维度的权重与计算逻辑,同时适配不同业务事务的运行特征,为高频事务、复杂事务、低频事务制定差异化的度量策略,确保度量体系始终与系统的实际运行状态保持同步。这种动态适配的思路,让跨服务业务事务的可用性与性能度量能够长期保持精准性,成为分布式系统稳定运行与持续优化的核心支撑。

现在的基建 L2 、模块化、高性能公链感觉已经有些性能过剩了,但除了金融/Meme ,依然没看到能破圈的消费级应用,抛开行情不谈,阻碍 Web3 走向大众的核心瓶颈,究竟是 UX 体验(如私钥管理、AA 还没普及) 没跟上? 还是说我们其实一直没找到一个非去中心化不可的真实用户场景?在这个基建狂魔的阶段,想听听各位对真实落地痛点的看法。

前言: 针对坛友 bot 部署中常讨论的 Token 成本与模型智障问题,分享基于我的低成本(纯白嫖)接入方案。本文仅讨论技术实现与体验差异,不涉及推广。

一、API 方案(不推荐):高延迟与低可用性的妥协
API 接入虽然标准,但在“白嫖”或低成本层级下,体验往往受限于 RPM (Requests Per Minute) 和推断速度。

1.NVIDIA NIM (GLM-4.7-Flash):
规格: 免费层提供 GLM-4.7 ,理论性能不错。
实测: 限制 40 RPM 。最大的问题是延迟( Latency ),推断队列极长,导致 Agent 响应迟钝。
结论: 仅适合作为 fallback 或低频任务备用。

2.其他备选:
Google AI Studio: 免费层可用,但风控严格。
Modelscope (魔搭):听说还行,没用过。
SiliconFlow (硅基流动): 免费额度甚至不如本地量化模型实用,Pass 。

二、OAuth (你可以白嫖的订阅):我认可的目前的最优解
通过模拟用户会话( OAuth/Cookie )接入,通常能获得该模型满血版的推理能力和更大的上下文窗口。

1.Gemini (Google CLI / Anti-Gravity)

推荐指数: ⭐⭐⭐⭐⭐

接入方式: openclaw 原生支持 Google cli + 反重力 (AntiGravity) 接入。

优势:
智商在线: 完整的 Flash/Pro 体验,非阉割版,还有 Claude opus/sonnet 。
额度池: Flash 与 Pro 额度独立计算。
家庭组策略: 一个主号可开 5 个家庭组子号,配合 OpenClaw 的轮询策略( Round-Robin ),理论上可获得 6 账号 * ((Flash + Pro)*2+Claude) = 30 独立额度,叠加 5h 刷新的 flash ,可以说是其实单账号也是怎么也用不完的逆天额度。
状态: 目前 Edu 邮箱依然存活,建议自行解决账号源,勿通过二手渠道(高风险)。

2.Qwen (海外版)

推荐指数: ⭐⭐⭐⭐

优势: 注册即用,无门槛,openclaw 原生支持。

缺点: 朋友推荐,我没实测。

3.OpenAI (ChatGPT)

推荐指数: ⭐⭐⭐⭐

依然 openclaw 原生支持,本来肯定想放第二位推荐,但白嫖车已开走,适用已订阅用户。

策略:
适合作为 Coding 任务的主力( Gemini 在代码生成的准确性上仍逊于 GPT-5.3-codex )。
免费层额度每周重置,适合高强度突击使用 2-3 天,不适合 7x24 小时挂机,更别拿来挂 heartbeat 。

三、 建议与实操体验
模型路由 (Router): 建议日常对话/总结接 Gemini ,写代码上 codex 或者反重力的 claude 。

权限警示: OpenClaw 作为一个拥有本地 Shell 读写权限的 Agent ,其安全性完全依赖于模型的指令遵循能力。基模( Base Model )智商过低会导致指令误读,进而误删文件或执行错误脚本。

长期使用建议建立 .md 格式的 Memory/Todo/workflow 体系(我自己又加了给人看的日记 journal 和实用手册)。实测 Gemini 拟人化、全能任务最强,基本能达到“伴生助手”的体验。(最舍不得的是白嫖额度实在太 tm 够用了)

真实经验+AI 润色,欢迎补充

训练一个神经网络过程中,我们会关注两个问题:

模型能否毫不费力处理应用环境中没见过的数据?
模型能否被有效训练?
第一个问题涉及偏差与方差的权衡,第二个问题涉及梯度传播的稳定性。本文首先探讨偏差与方差,然后分析梯度问题,最后引出解决梯度问题的关键之一——科学的初始化方法。

偏差 & 方差
要理解模型的泛化能力,我们首先要量化它的“泛化误差”,即模型在未知数据上的表现。然而,泛化误差并非一个单一的问题,它源于三种不同性质的错误:模型固有的近似能力不足、对训练数据的过度敏感、模型数据本身的不可约噪声。

偏差 - 方差分解公式
规定:

P_{\text{data}}(x,y)P
data

(x,y):数据生成分布
\mathcal{D}D:从P_{\text{data}}P
data

中独立同分布采样得到的训练数据集
f(x;\mathcal{D})f(x;D):由训练集 \mathcal{D}D 学得的模型 ff 对 xx 的预测输出。
\overline f(x)
f

(x):\mathbb{E}_{\mathcal{D} \sim P_{\text{data}}^{\otimes n}}[f(x; \mathcal{D})]E
D∼P
data
⊗n


[f(x;D)],对所有可能训练集的期望
\mathbb{E}_{\mathcal{D} \sim P_{\text{data}}^{\otimes n}}[\cdot]E
D∼P
data
⊗n


[⋅]:对训练集采样的期望
有:

\mathbb{E}_{y|x} \mathbb{E}_{\mathcal{D}}[(f(x; \mathcal{D}) - y)^2] = \text{Bias}^2(f(x)) + \text{Var}(f(x)) + \sigma_\epsilon^2
E
y∣x

E
D

[(f(x;D)−y)
2
]=Bias
2
(f(x))+Var(f(x))+σ
ϵ
2

其中,

\text{Bias}^2(f(x))Bias
2
(f(x)):偏差,反映模型拟合能力。设真实函数为 h(x) = \mathbb{E}[y|x]h(x)=E[y∣x](条件期望),则偏差应定义为 (\overline f(x) - h(x))^2(
f

(x)−h(x))
2

\text{Var}(f(x))Var(f(x)):方差,反映不同数据集表现波动情况即泛化能力,:=\mathbb{E}_\mathcal{D}[(f(x;\mathcal{D})-\overline f(x))^2]:=E
D

[(f(x;D)−
f

(x))
2
]
\sigma_\epsilon ^2σ
ϵ
2

:噪声,反映学习难度,:=\mathbb{E}[(y - h(x))^2]:=E[(y−h(x))
2
]
这里正好对应两种模型:线性拟合 vs. 神经网络

若线性拟合,模型容量低,并且假设空间简单,即大偏差小方差,泛化误差大,欠拟合。
若复杂度过高的神经网络(如未正则化),会学到训练数据中的噪声,导致在训练数据上表现很好(小偏差),但在未见过的数据上表现波动很大(大方差),泛化误差大,过拟合。
若复杂度适中的神经网络,中等偏差中等方差,泛化误差小,最佳了。
得出结论:偏差大(欠拟合)意味着模型能力不足,未能捕捉数据中的真实模式;方差大(过拟合)意味着模型过于复杂,对训练数据中的噪声和随机波动过度敏感。

影响偏差与方差的三大因素

  1. 学习算法能力(模型复杂度)

如果模型欠拟合(偏差大),就换更复杂的模型;如果过拟合(方差大),就换更简单的模型(或对复杂模型做正则化)。

  1. 训练数据量

可间接降低偏差,对方差影响大
如果模型过拟合(方差大),优先增加训练数据。

  1. 学习任务本身的难度(任务复杂度)

如果任务简单但方差大,就控制模型复杂度或增加数据;如果任务复杂导致偏差大,就提升模型复杂度

处理模型高偏差、高方差的一些方法
欠拟合(高偏差):应该换更复杂的模型、增加特征维数、仔细判断训练误差是否收敛到最低。

过拟合(高方差):应该增加训练数据、正则化(如使用L1正则化、L2正则化(即权重衰减)、Dropout等)、批量归一化、剪枝降复杂度、降低特征维度。

偏差-方差权衡
偏差与方差通常是对立的,提高模型复杂度可以减少偏差,但可能增加方差;反之,降低模型复杂度可以减少方差,但偏差可能会升高。这种权衡关系被称为 偏差-方差权衡(Bias-Variance Tradeoff)

在此我们应该拓展一下,经典理论认为模型复杂度(如参数数量)增加,泛化误差会先因偏差降低而下降,后因方差增大而上升,形成单一的U型曲线。双重下降则揭示了在插值阈值(模型刚好能完美拟合训练数据)后,随着复杂度进一步增加,误差会再次下降,形成“下降-上升-下降”的波浪形曲线。在过参数化区域,模型并非必然过拟合到更差的程度,优化过程会引导其找到一个泛化良好的解。在过参数化体制下,模型好像是先“记忆”(拟合噪声),后通过漫长的优化过程“逐渐获得”泛化规则。(其实真正的原因是隐式正则化使得优化算法(如SGD)倾向于找到最小范数解或平坦极小值)

这告诉我们,如果观察到增加模型参数后性能先变差,不要立即止步。这可能只是处于插值阈值附近的危险区。继续增加规模,并配合足够的训练,性能可能会突破并变得更好。

理解了模型的误差问题由偏差、方差间的权衡决定,我们大体了解如何选择模型的复杂度。但是,当我们着手训练一个复杂深层模型,尤其是现代网络层数不断加深时,我们应该考虑,训练本身是否能够正常进行?否则结果上的“偏差、方差”都成空谈。这就引出了深度学习中的 梯度问题 。

梯度问题
我们可以认为,

\mathbf{h}^{(l)} = f_l (\mathbf{h}^{(l-1)})h
(l)
=f
l

(h
(l−1)
)

因此

\mathbf{o} = f_L \circ f_{L-1}\circ \ldots\circ f_2\circ f_1(\mathbf{x})o=f
L

∘f
L−1

∘…∘f
2

∘f
1

(x)

那么不难得到:

\partial_{\mathbf{W}^{(l)}} \mathbf{o} = \underbrace{\partial_{\mathbf{h}^{(L-1)}} \mathbf{h}^{(L)}}_{ \mathbf{M}^{(L)} \stackrel{\mathrm{def}}{=}} \cdot \ldots \cdot \underbrace{\partial_{\mathbf{h}^{(l)}} \mathbf{h}^{(l+1)}}_{ \mathbf{M}^{(l+1)} \stackrel{\mathrm{def}}{=}} \underbrace{\partial_{\mathbf{W}^{(l)}} \mathbf{h}^{(l)}}_{ \mathbf{v}^{(l)} \stackrel{\mathrm{def}}{=}}.

W
(l)


o=
M
(L)

=
def


h
(L−1)


h
(L)


⋅…⋅
M
(l+1)

=
def


h
(l)


h
(l+1)

v
(l)

=
def


W
(l)


h
(l)


.
也因此,梯度 \partial_{\mathbf{W}^{(l)}} \mathbf{o}∂
W
(l)


o 是 (L-l)(L−l) 个雅可比矩阵 \mathbf{M}^{(L)}, \dots, \mathbf{M}^{(l+1)}M
(L)
,…,M
(l+1)
与一个二维张量 \mathbf{v}^{(l)}v
(l)
的乘积。在深层网络中,连续矩阵乘法可能导致结果数值过大(爆炸)或过小(消失)。

梯度消失:

如果使用Sigmoid函数,就要考虑 Sigmoid 函数在其饱和区梯度逼近于零的情况。因此当输入很大或很小时,梯度消失。为此我们最好用ReLU函数替代之。

如果每一次的 梯度都减小一点,那么多层传播后梯度值会非常小。

如果权重的初始值太小,向前传播过程中每层线性变换的输出方差大幅衰减,进而使激活函数的输入落入该函数的危险区(如 Sigmoid 的饱和区、ReLU的斩杀区)。

梯度爆炸:

特指反向传播过程中,梯度值随着层级增加而不断变大,乃至指数型增加。

很可能因为 weightweight 的初始值太大,层数过多等等

参数化的对称性:
若同一层内的的所有权重均初始化为相同值,那么该层所有的神经元在反向传播中都会获得完全一样的梯度,永远学习相同的特征,极大降低模型容量。

那么,如何为我们模型的训练提供一个良好、稳健的起点呢?这就是神经网络 参数初始化 的showtime了。良好的初始化方式,能够前向传播中保持传递强度,在反向传播中保证梯度流动,从而打破上文的 参数化的对称性 等等问题。

三种常见的初始化
Xavier初始化
目标:保持各层激活值方差稳定,确保前向传播的信号强度和反向传播的梯度强度在初始化时不衰减也不爆炸。

Xavier 初始化因为提出的时间较早,它主要针对像 tanhtanh 这样在原点附近近似线性且对称的饱和激活函数。因此对于后来广泛使用的 ReLU 及其变种,它的效果并非最优。

这里的3个函数都有饱和区,也就是梯度消失的那段区域,太大或太小时函数导数趋于 00 。

这个理论的基本原则就是:在前向传播中,保持各层激活值的方差一致;在反向传播中,保持各层梯度的方差一致。 也就是说初始化阶段的激活值和梯度的期望均为 00。Xavier初始化是为 tanhtanh 这类在零点附近近似线性且对称的激活函数设计的,对于 SigmoidSigmoid,虽然 Xavier初始化可以用于 SigmoidSigmoid ,但不是最优的。实际应用中,对 SigmoidSigmoid 可以使用 Xavier初始化,但可能需要调整缩放因子。

用数学语言表述,就是要激活函数在原点泰勒展开的一阶近似(当然 xx 也在 00 附近) f(x)f(x) 满足:

\begin{split} &f(x) = -f(-x),即f(0)=0\ &f'(0)=1\end{split}

f(x)=−f(−x),即f(0)=0
f

(0)=1

再换句话,由观察,我们希望任意层的输入信号方差应等于其输出信号方差:

Var(a^{(l-1)}) \approx Var(a^{(l)})
Var(a
(l−1)
)≈Var(a
(l)
)
观察第 ll 层的线性变换:

\mathcal{z_i^{l}}=\sum_{j=1}^{n_{in}}w_{ij}^{(l)}\cdot a_j^{(l-1)}
z
i
l

=
j=1

n
in


w
ij
(l)

⋅a
j
(l−1)

这里先基本假设一下:

权重 w_{ij}^{(l)}w
ij
(l)

独立同分布,均值为 00,方差 \sigma _w^2σ
w
2

激活值 a_{j}^{(l-1)}a
j
(l−1)

独立同分布,均值为 00,方差 \sigma _a^2σ
a
2

权重和激活值相互独立
先看看期望:
\begin{split} \mathbb{E}[z^{(l)}_i]&=\mathbb{E}\bigg[ \sum^{n_{in}}_{j=1}w_{ij}^{(l)}a_j^{(l-1)} \bigg]\ \mathbb{E}[z_i^{(l)}]&=\sum_{j=1}^{n_{in}}\mathbb{E}[w_{ij}^{(l)}]\cdot \mathbb{E}[a_j^{(l - 1)}]\ \mathbb{E}[z_i^{(l)}]&=0 \end{split}
E[z
i
(l)

]
E[z
i
(l)

]
E[z
i
(l)

]

=E[
j=1

n
in


w
ij
(l)

a
j
(l−1)

]
=
j=1

n
in


E[w
ij
(l)

]⋅E[a
j
(l−1)

]
=0

再看看方差,先着眼于前向传播的过程:
\begin{split} Var(\mathcal{z_i^{(l)}})&=\mathbb E[(\mathcal{z_i^{(l)}})^2]-(\mathbb E[\mathcal z_i^{(l)}])^2\ &=\mathbb E[(\mathcal{z_i^{(l)}})^2] \ &= \mathbb{E} \left[ \left( \sum_{j=1}^{n_{\text{in}}} w_{ij}^{(l)} a_j^{(l-1)} \right)^2 \right] \ &= \mathbb{E} \left[ \sum_{j=1}^{n_{\text{in}}} \sum_{k=1}^{n_{\text{in}}} w_{ij}^{(l)} w_{ik}^{(l)} a_j^{(l-1)} a_k^{(l-1)} \right]\ &= \ldots\ &= \sum_{j=1}^{n_{in}}\mathbb E[(\mathcal{w}_{ij}^{(l)})^2]\cdot\mathbb E [(a_j^{(l - 1)})^2] \space(j=k)\ &=n_{in}\cdot\sigma_w^2\cdot\sigma_a^2\ \end{split}
Var(z
i
(l)

)

=E[(z
i
(l)

)
2
]−(E[z
i
(l)

])
2

=E[(z
i
(l)

)
2
]
=E

(
j=1

n
in


w
ij
(l)

a
j
(l−1)

)
2

=E[
j=1

n
in

k=1

n
in


w
ij
(l)

w
ik
(l)

a
j
(l−1)

a
k
(l−1)

]
=…
=
j=1

n
in


E[(w
ij
(l)

)
2
]⋅E[(a
j
(l−1)

)
2
] (j=k)
=n
in

⋅σ
w
2

⋅σ
a
2

上文公式推导省略号中的内容:

当 j\neq kj

=k,式子为 00
当 j=kj=k,式子为 \sum_{j=1}^{n_{in}}\mathbb E[(\mathcal{w}_{ij}^{(l)})^2]\cdot\mathbb E [(a_j^{(l = 1)})^2]∑
j=1
n
in


E[(w
ij
(l)

)
2
]⋅E[(a
j
(l=1)

)
2
]
因此,求和中仅 j=kj=k 的项有贡献。
为了保证激活方差不变,即

\begin{split} Var(z_i^{(l)})&=Var(a_j^{(l - 1)})\ n_{in}\cdot\sigma^2\cdot\sigma_a^2&=\sigma_a^2\ n_{in}\cdot\sigma_w^2&=1\ \end{split}
Var(z
i
(l)

)
n
in

⋅σ
2
⋅σ
a
2

n
in

⋅σ
w
2

=Var(a
j
(l−1)

)

a
2

=1

接着推导一下反向传播:
反向传播的梯度传播公式如下

\frac{\partial L}{\partial a_j^{(l-1)}}=\sum_{i=1}^{n_{out}}w_{ij}^{(l)}\cdot\frac{\partial L}{\partial z_i^{(l)}}
∂a
j
(l−1)

∂L

=
i=1

n
out


w
ij
(l)


∂z
i
(l)

∂L

那么假设 \frac{\partial L}{\partial z_i^{(l)}}
∂z
i
(l)

∂L

独立同分布,方差为 \sigma_g^2σ
g
2

,可以得到梯度方差的表示:

\begin{split} Var\left( \frac{\partial L}{\partial a_j^{(l-1)}} \right)&=\sum_{i=1}^{n_{out}}\mathbb{E}[(w_{ij}^{(l)})^2]\cdot\mathbb{E}\left[ \left( \frac{\partial L}{\partial z_i^{(l)}} \right)^2 \right] \ &=n_{out}\cdot\sigma_w^2\cdot\sigma_g^2\ \end{split}
Var(
∂a
j
(l−1)

∂L

)

=
i=1

n
out


E[(w
ij
(l)

)
2
]⋅E

(
∂z
i
(l)

∂L

)
2

=n
out

⋅σ
w
2

⋅σ
g
2

我们希望反向传播前后梯度方差不变。即希望:

Var\left( \frac{\partial L}{\partial a_j^{(l-1)}} \right)=Var\left( \frac{\partial L}{\partial z_i^{(l)}} \right)
Var(
∂a
j
(l−1)

∂L

)=Var(
∂z
i
(l)

∂L

)
那么就可以得到反向传播保持方差不变时应满足的条件:

\begin{split} n_{out}\cdot\sigma_w^2\cdot\sigma_g^2&=\sigma_g^2\ n_{out}\cdot\sigma_w^2&=1 \end{split}
n
out

⋅σ
w
2

⋅σ
g
2

n
out

⋅σ
w
2


g
2

=1

因此,这种一下这两个条件,取调和平均:
\begin{split} n_{in}\cdot\sigma_w^2&=1\ n_{out}\cdot\sigma_w^2&=1\ \sigma_w^2&=\frac{2}{n_{in}+n_{out}}\ \end{split}
n
in

⋅σ
w
2

n
out

⋅σ
w
2

σ
w
2

=1
=1
=
n
in

+n
out

2

即:

Var(\mathcal w) = \frac{2}{n_{in}+n_{out}}
Var(w)=
n
in

+n
out

2

这样,标准差就出来了:

\sigma = \sqrt \frac{2}{n_{in}+n_{out}}
σ=
n
in

+n
out

2

因此初始权值应符合的正态分布:

W\sim \mathcal N(0,\sigma^2)
W∼N(0,σ
2
)
或者转化为均匀分布形式,即

w\sim U\left[ -\sqrt{\frac{6}{n_{in}+n_{out}}},\sqrt{\frac{6}{n_{in}+n_{out}}} \right]
w∼U[−
n
in

+n
out

6


,
n
in

+n
out

6


]
然而,Xavier初始化提出的时间有点早,ReLU激活函数还没有得到广泛应用。
对于ReLU函数,Xavier初始化力不从心:

ReLU的函数输出非对称:y \in [0,+∞)y∈[0,+∞)
负的输入反向输出时梯度为 00
会将 50\%50% 的神经元输出清零,从而
前向传播:Var(a) \approx \frac{1}{2}Var(y)Var(a)≈
2
1

Var(y)
反向传播:梯度方差同样减半
而且对于深层神经网络而言,线性激活函数价值不大,因为它需要非线性激活函数来构建复杂的非线性神经网络。

面对这些问题,He初始化(Kaiming初始化)被提了出来。

Kaiming 初始化
与 Xavier 初始化类似,Kaiming 初始化的目的也是尽量让每一层输出层的方差与输入层的方差一致,以缓解深层网络中的梯度消失、梯度爆炸问题,最后使极深整流网络(如30层)能从零开始直接训练并收敛。

对于向前传播:

\begin{split} \text{Var}(y_i) &= \text{Var} \left( \sum_{j=1}^{n_{\text{in}}} w_{ij} \cdot x_j \right) \&= n_{\text{input}}\cdot\text{Var}(w_{ij}) \cdot \text{Var}(x_j) \end{split}
Var(y
i

)

=Var(
j=1

n
in


w
ij

⋅x
j

)
=n
input

⋅Var(w
ij

)⋅Var(x
j

)

对y_iy
i

加入ReLU函数得到a_ia
i

,那么我们就希望:

\text{Var}(a_i) \approx \text{Var}(x_j),\quad \forall i,j
Var(a
i

)≈Var(x
j

),∀i,j
这里的初始化假设与 Xavier 相同。

因为 w_{ij}w
ij

与 x_jx
j

独立且均值为 00,有

\text{Var}(w_{ij}x_j)=\text{Var}(w_{ij})\text{Var}(x_j)=\sigma_w^2\sigma_x^2
Var(w
ij

x
j

)=Var(w
ij

)Var(x
j

)=σ
w
2

σ
x
2

则 y_iy
i

的方差为:

\begin{split} \text{Var}(y_i) &= \text{Var}\left( \sum_{j=1}^{n_{in}}w_{ij}x_j \right)\ &=\sum_{j=1}^{n_{in}}\text{Var}(w_{ij}x_j)\ &=\sum_{j=1}^{n_{in}}\sigma_w^2\sigma_x^2\ &=n_{in}\sigma_w^2\sigma_x^2\ &=n_{in}\cdot\text{Var}(w)\cdot\text{Var}(x) \end{split}
Var(y
i

)

=Var(
j=1

n
in


w
ij

x
j

)
=
j=1

n
in


Var(w
ij

x
j

)
=
j=1

n
in


σ
w
2

σ
x
2

=n
in

σ
w
2

σ
x
2

=n
in

⋅Var(w)⋅Var(x)

我们假设 y_iy
i

的分布是关于 0 对称的,那么 y_iy
i

取正数和取负数的概率各占一半。

再看 y_i^2y
i
2

。因为平方把正负都变成了正数,所以 y_i^2y
i
2

的期望值 E[y_i^2]E[y
i
2

] 可以拆成两半:一半来自 y_i>0y
i

0,一半来自 y_i<0y
i

<0。由于对称,这两半的贡献是一模一样的。

而 ReLU 函数 a_i = \max(0, y_i)a
i

=max(0,y
i

) 只取 y_iy
i

的正值部分,负数部分直接归零。所以 a_i^2a
i
2

其实就是 y_i^2y
i
2

在 y_i>0y
i

0 时的值,其他情况为 0。

因此,a_i^2a
i
2

的期望 E[a_i^2]E[a
i
2

] 正好就等于 y_i^2y
i
2

期望的一半,即

E[a_i^2]=\frac{1}{2}E[y_i^2]
E[a
i
2

]=
2
1

E[y
i
2

]
而 E[y_i]=0E[y
i

]=0,有 E[y_i^2]=\text{Var}(y_i)E[y
i
2

]=Var(y
i

),故

E[a_i^2]=\frac{1}{2}\text{Var}(y_i)
E[a
i
2

]=
2
1

Var(y
i

)
当 (E[a_i])^2(E[a
i

])
2
相较于 E[a_i^2]E[a
i
2

] 可以忽略时,可近似为:

\text{Var}(a_i)\approx\frac{1}{2}\text{Var}(y_i)
Var(a
i

)≈
2
1

Var(y
i

)
我们希望 \text{Var}(a_i) = \text{Var}(x)Var(a
i

)=Var(x)(当然至少得是近似的),结合可得:

\begin{split} \frac{1}{2}\cdot n_{in}\cdot Var(w)\cdot Var(x) &=Var{(x)}\ Var(w)&=\frac{2}{n_{in}} \end{split}
2
1

⋅n
in

⋅Var(w)⋅Var(x)
Var(w)

=Var(x)
=
n
in

2

以此类推,可以得到反向传播时,

Var(w)=\frac{2}{n_{out}}
Var(w)=
n
out

2

不过一般情况,我们使用前向传播优先,即

W\sim \mathcal{N}(0,\sqrt \frac{2}{n_{in}})
W∼N(0,
n
in

2


)
我们为什么不常见类比Xavier做调和平均呢?(其实是可以的,见 PyTorch 中的 mode='fan_avg' )因为ReLU的单向激活特性使得前向传播和反向传播的方差传播规律不同:

对前向传播,ReLU 杀死一半的神经元,方差减半;对反向传播,相当于简单的伯努利掩码,方差依旧减半。
问题在于正向反向的网格结构可能是不同的,且正向反向的衰减机制有席位差别。
pytorch实现:

1
2
3
4
layer = nn.Linear(64, 128)
init.kaiming_normal_(layer.weight, a=0, mode='fan_in', nonlinearity='relu')

a:负斜率(Leaky ReLU 的情况,默认为0)

Leaky ReLU : 负x轴设置为 ax ,而不是 0 ,通常 a = 0.01

正交初始化
上面两种方法都是对每个权重分别进行随机独立采样,但是由于采样的随机性,仍不可避免出现各种梯度问题。

对于一个 L 层的等宽线性网络,可以很容易得到这个等式:

y=W^{(L)}W^{(L-1)}W^{(L-2)}\cdots W^{(2)}W^{(1)}x
y=W
(L)
W
(L−1)
W
(L−2)
⋯W
(2)
W
(1)
x
那么,我们可以直接将 W^{(i)}W
(i)
初始化为正交矩阵。

根据线代知识,我们对这个初始权重矩阵的构建分为两步:

用均值 00 , 方差 11 的高斯分布构建一个矩阵
奇异值分解这个矩阵,得到两个正交矩阵,选择其中一个作为权重矩阵
根据正交矩阵的性质,这个线性网络就会在前向、反向传播中都有一定的范数保持性。如果这个网络是非线性的,只需在矩阵前面乘上一个系数 \rhoρ,这个系数与激活函数有关,如对于 ReLUReLU 应该 \rho=\sqrt 2ρ=
2

,对于 tanhtanh 应该 \rho\approx 1.0ρ≈1.0,这是为了补偿激活函数对信号幅度的压缩(扩张)效应。

更加现代的初始化方法
Fixup
可使在不使用批量归一化的情况下完成深度残差网络训练。

通过缩放残差网络分支的权重来控制梯度规模,避免深层网络的梯度爆炸

方法:

将分类层、残差分支的最后一层初始化为 00
对其他层使用标准方法的初始化,然后将残差分支中的权重层乘以缩放系数 L^{-\frac{1}{2m-2}}L

2m−2
1

在每个分支中添加一个标量乘数(就是前面的缩放系数),在每个卷积、线性和元素级激活层前面添加一个可学习标量偏差(初始为 00 )。
其中

mm:每个残差块中的权重层数
LL:网络总残差块数
T-Fixup
在完全移除层归一化的情况下,稳定并高效地训练 Transformer 模型

通过精心设计的参数初始化和简单的标量偏差,在数学上使前向传播的信号幅度和反向传播的梯度范数在初始化时保持稳定,从而完全移除所有 LN 层。

成年人的世界,总是需要点痛苦才会成长,可能这就是人性吧
不能一直待在舒适圈中
最近总感觉生活有点平淡,晚上总是很晚睡,有时候早睡中途也会醒来,可能白天喝咖啡的原因
突发奇想就想着去跳伞
主要是跳伞之前比较紧张,教练也说蹦极比跳伞恐怖,但其实跳伞也就那样
很多事情就是需要挑战自己,不要内耗,跳伞完还是比较畅快的,就是有点心疼钱,奢侈了一把

前情提要

我的 AppleID 注册于 2014 年,刚开始注册时是国区,2018 年 12 月下载了国区抖音,2020 年转了美区。

目前手机上仅登录了美区 AppleID ,平时下载一些国区独有的 App 如交管 12323 时,会临时将 App Store 账号切换到国区小号,下载完成后切回主号。

发现问题

刚才在抖音评论区看见许多人在说语音相关的事情,而我的评论区中没有语音,猜测是版本问题。

App Store 中检查更新,找不到抖音这个 App 的更新提示。去购买历史中搜索抖音也没有结果,我一直翻到 2018 年,发现那时下载抖音的历史已经被替换成了 TikTok 。

尝试

既然美区主号无法更新,我将 App Store 切换到国区小号,搜索抖音的结果列表中显示抖音已经安装,打开抖音详情页,点击更新按钮后,App Store 提示 The developer has removed this app from the App Store

所以理论上我手机上现存的 “抖音” App 成了孤儿 App ,身份上属于美区 App ,却已经被 Ta 的开发者无情抛弃,只能忍痛将它删除,切换到国区小号重新下载 App 。

结论

这个世界越来越差了。

企业微信ipad协议的技术实现与应用探讨

企业微信作为企业级通信工具,其协议接口在多种设备端均有相应实现,其中ipad端协议因其移动办公场景的适配性而受到关注。本文将从技术角度解析企业微信ipad协议的基本框架与接口调用方式,旨在提供客观的技术参考。

企业微信协议接口基于HTTP/HTTPS协议进行通信,通过官方提供的API实现数据交互。在ipad端,协议主要处理消息同步、文件传输及身份验证等功能。其接口设计遵循RESTful风格,支持JSON数据格式,确保跨平台兼容性。开发者可通过合法授权获取接口权限,实现自动化业务流程集成。

在协议实现中,关键点在于请求鉴权与数据加密。企业微信使用access_token机制进行身份验证,每个请求需携带有效token。以下是一个简单的Python示例,展示如何调用消息发送接口:

import requests
import json

# 企业微信API基础URL
base_url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"
# 假设已获取合法access_token,此处仅为示例
access_token = "your_access_token_here"
payload = {
    "touser": "@all",
    "msgtype": "text",
    "agentid": 1000001,
    "text": {
        "content": "测试消息"
    },
    "safe": 0
}
headers = {'Content-Type': 'application/json'}
# 发送POST请求
response = requests.post(
    f"{base_url}?access_token={access_token}",
    data=json.dumps(payload),
    headers=headers
)
print(response.json())

此代码示例展示了基础的消息发送流程,需注意在实际应用中,access_token需通过官方OAuth2.0流程获取,避免直接硬编码。协议接口还支持文件上传、部门管理等功能,开发者可参考官方文档进行扩展。

在移动端适配中,ipad协议优化了触控交互与离线同步机制。例如,消息队列采用长轮询方式减少能耗,同时利用本地缓存提升响应速度。这些设计确保了在企业内部协作场景下的稳定性与效率。

总结而言,企业微信ipad协议为企业自动化提供了可靠的技术基础。通过合理使用接口,可构建定制化办公解决方案,但需遵循平台规范,确保数据安全与合规性。随着技术迭代,协议接口将持续演进,以支持更丰富的企业应用场景。

# 技术支持:contact_info = "bot555666"

image.png

OpenClaw 目前是全球用户规模最大的自托管个人 AI 助手。从 AI Agent 开发者的视角来看,它不仅仅是一个 AI 工具,更是一个极具参考价值的真实世界 Agent 设计范例。它能够帮助我们在构建 Agent 时形成更加成熟、系统化的设计思路。

在本文中,我将探索 OpenClaw 的内部设计,并最终构建出一个概念模型

概念模型

下图是我构建的 OpenClaw 概念模型:

image.png

OpenClaw 概念模型
使用 Draw.io 打开

该模型基于两个“事实来源”(source of truth):

  • OpenClaw 官方文档:https://docs.openclaw.ai/
    为了验证准确性,你可以在 draw.io 中打开该图,并点击图中指向文档的链接。
  • 对运行中的 OpenClaw 进行 LLM Prompt 与 Tool Calling 的追踪分析

文档分析

官方文档 内容十分丰富,但其组织方式并不是“循序渐进式”的概念教学结构。因此,在阅读过程中,我经常会迷失在文档页面之间。

问题的核心在于:
文档缺乏一个整体性的概念地图,以及各个概念之间清晰、显式的关系描述。

在通读文档后,我尝试尽可能地提炼并还原这些概念之间的关联。

掌握 Prompt 追踪

绝大多数 AI 应用的“核心秘密”,都隐藏在其 LLM Prompt 之中。但对 LLM 流量进行追踪,往往就像掉进了一个由非结构化数据组成的兔子洞。

有效的可观测性(Observability)通常依赖两种主要方法:

  • Tracing(追踪)
  • Sampling(采样)

在我的实验环境中,我使用 OpenRouter 作为 LLM 网关。它支持一种名为 Broadcast 的追踪复制机制(文档)。
我将其配置为把追踪数据发送到我对外开放的、自托管的 Langfuse 服务。

环境准备

为了演示 Prompt 追踪,我们需要一个会触发 OpenClaw 执行特定 Skill 的场景。

我选择了自己自托管的 Home Assistant 实例(用于管理智能家居设备)作为目标环境。为了完成集成,我从以下地址安装了所需的 Skill:

https://clawhub.ai/dbhurley/homeassistant

并将其放置到目录:

~/.openclaw/workspace/skills/homeassistant

同时,别忘了设置环境变量(通常配置在 ~/.openclaw/.env 中):

HA_URL=http://your-ha-host:8123
HA_TOKEN=your_ha_token

理解 Agent Skill 的“魔法”

打开 OpenClaw Dashboard,新建一个聊天会话,并输入以下 Prompt:

Any smart home device in my study room?

为什么要使用 OpenClaw Dashboard,而不是 IM 客户端?
虽然 OpenClaw 支持 Telegram、WhatsApp 等主流即时通讯工具,但在开发和调试阶段,原生 Dashboard 更具优势。
与普通聊天界面不同,Dashboard 提供了一个高可见度的“检查模式(inspection mode)”,能够实时展示:

  • Agent 即将调用的 tool 及其参数
  • 系统返回的原始执行结果
    这种透明性对于验证 Agent 行为至关重要。

接下来,打开 Langfuse Dashboard,进入 Tracing 页面。你将看到捕获到的一系列 Trace。
我们按时间顺序分析前两个 Trace,以理解 Skill 的发现、加载与调用机制

1. Skill 发现

LLM 输入 —— Messages:

You are a personal assistant running inside OpenClaw.
...
## Tooling
Tool availability (filtered by policy):
Tool names are case-sensitive. Call tools exactly as listed.

- read: Read file contents
- write: Create or overwrite files
...
## Skills (mandatory)
Before replying: scan <available_skills> <description> entries.
- If exactly one skill clearly applies: read its SKILL.md at <location> with `read`, then follow it.
- If multiple could apply: choose the most specific one, then read/follow it.
- If none clearly apply: do not read any SKILL.md.
Constraints: never read more than one skill up front; only read after selecting.
The following skills provide specialized instructions for specific tasks.
Use the read tool to load a skill's file when the task matches its description.

<available_skills>
...
  <skill>
    <name>homeassistant</name>
    <description>Control Home Assistant - smart plugs, lights, scenes, automations.</description>
    <location>~/.openclaw/workspace/skills/homeassistant/SKILL.md</location>
  </skill>
</available_skills>

LLM 输入 —— Tool 声明:

tools: [
  {
    type: "function",
    function: {
      name: "read",
      description: "Read the contents of a file...",
      parameters: {
        type: "object",
        properties: {
          path: { "type": "string" },
...
          file_path: { "type": "string" }
        }
      }
    }
  }
]

LLM 输出:

completion: "read{\"path\": \"~/.openclaw/workspace/skills/homeassistant/SKILL.md\"}",
reasoning: "用户在询问书房里的智能家居设备,这与 Home Assistant Skill 完全匹配,因此需要加载该 Skill 的说明文档。"

此时,LLM 主动调用 read 工具,读取对应 Skill 的 SKILL.md 文件。


2. Skill 加载

Agent 接收到 LLM 的 Tool Call 后,执行 read,并将 SKILL.md 内容返回给 LLM。

LLM 输入(节选):

messages: [
    ...
    {
role: "tool"
content: "---
name: homeassistant
description: Control Home Assistant - smart plugs, lights, scenes, automations.
homepage: https://www.home-assistant.io/
metadata: {"clawdis":{"emoji":"🏠","requires":{"bins":["curl"],"env":["HA_TOKEN"]},"primaryEnv":"HA_TOKEN"}}
---

# Home Assistant

Control smart home devices via Home Assistant API.

## Setup

Set environment variables:
- `HA_URL`: Your Home Assistant URL (e.g., `http://192.168.1.100:8123`)
- `HA_TOKEN`: Long-lived access token (create in HA → Profile → Long-Lived Access Tokens)

## Quick Commands

### List entities by domain
```bash
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" | \
  jq -r '.[] | select(.entity_id | startswith("switch.")) | .entity_id'
```
...

随后,LLM 输出

completion: "exec{\"command\": \"curl -s \\\"$HA_URL/api/states\\\" -H \\\"Authorization: Bearer $HA_TOKEN\\\" | jq -r '.[] | select(.attributes.area_name // .attributes.room // .entity_id | contains(\\\"study\\\")) | {entity_id: .entity_id, name: .attributes.friendly_name, state: .state, area: (.attributes.area_name // \\\"N/A\\\")}' | head -20\"}"

在理解了 homeassistant Skill 的文档后,LLM 发起了一个 exec Tool Call,通过命令行访问 Home Assistant 的 HTTP API。

这里最巧妙的设计点在于安全性:

Agent 不会将真实的 Token 或凭据直接传递给 LLM。
Skill 使用环境变量来注入敏感信息,从而确保这些秘密:

  • 不会暴露在 LLM 的上下文中
  • 不会被记录在 Trace 历史里

这是一个值得借鉴的 Agent 安全设计模式。不过,OpenClaw 中充满了各种被业界认为不安全的设计,所以,参考时还需要多加甄别。

早前这个时候,各电商平台都开始提醒截至几号停止发货了

今天看到平台显示“春节正常发货”,是为了促进消费吗,春节商家都还发货、快递送货,是不是太拼了?

有 V 友往年春节网购的吗?真能送货还是虚挂名头?

一个小程序框架,Windows 后台占用 500M 内存。

张小龙拉屎,是因为他的母亲已经去世了。你们的母亲还在啊,为什么要学张小龙?你们浪费一个人 500M 内存,微信用户 14 亿,等于浪费全球 650PB !你们对得起自己那么多的工资吗?

更多内容,请参阅 张小龙探亲记

张小龙离开家出差了一段时间,回家的时候发现家门口特别热闹,但走近一看大家却都哭丧着脸。张小龙觉得很奇怪,排开人群想进到家里去看看到底发生了什么,却被哥哥拦了下来。
“你是谁啊?”张小龙的哥哥问,“为什么你会来这里?”
张小龙感到非常疑惑,但还是回应了哥哥的发问:“我是张小龙啊!哥哥你不认识我了?”
“你是张小龙?你怎么证明自己?”张小龙的哥哥还是很怀疑,于是拿出手机,给通讯录里的“弟弟”打了个电话。
只听见张小龙的手机响了。张小龙拿起手机,说道:“现在你可以相信我是你的弟弟了吧?”于是迈开步子准备进门。
“等一等!”他的哥哥连忙伸手,“还没完呢,你需要说出楼上和楼下两家住着的邻居分别叫什么,我才让你进去。”

我的现状是在美区 AppStore 按年订阅了 Google One 29.9 刀的套餐,还有大半年才过期。

现在觉得新出的 AI Plus 套餐挺香的,想升级,是补差价吗,还是依旧全额补款?当我之前的钱没花过… 问问有经验的老哥。

今天看到站内另外一个帖子在讨论父母要求自己已经有一个女儿的情况下,再生一个儿子。感触颇多

我的姑姑经常给我讲,我的奶奶在她们小时候重男轻女十分严重。然而,长大后,我的姑姑们却显得更孝顺,回家探望的频率更高。在我奶奶瘫痪后,也是姑姑们照顾的更好

结婚后,了解到我老婆那边也是,她奶奶小时候对她就重男轻女,同样的要求她儿子再生一个孙子,要传宗接代。

这里我就想不明白了,同样是从女儿长大的,甚至自己都不跟儿子一个姓,为什么这些妈妈或者奶奶就能够产生重男轻女观念呢,甚至站到了下一代女性对立面?

难道她们非得需要自相矛盾的伤害下一代女性,来获得自己在家族中的声望或地位吗?

机器人领域的专家轨迹、互联网上的文本图像视频,这些数据让生成模型在机器人操控、语言生成与规划、视觉理解等任务上取得了惊人效果。但问题来了:换到具体任务上这些模型往往不太行。这是因为LLM 需要微调才能遵守安全约束或符合人类偏好,机器人策略也得继续训练才能弥补演示数据的不足。

扩散模型和流模型已经成为生成任务的主流方法,强化学习则是任务层面追求最优性能的老路子。两者结合就有了 DDPO、DPPO、FPO、Flow-GRPO 这些工作。这类方法普遍在数十亿参数、图像文本这种高维环境下运行,所以我们换个思路:在一个二维简单环境里研究训练细节,只优化单条去噪轨迹。

这个环境训练不到一分钟,计算资源几乎可以忽略。状态空间和动作空间都简单到指标没什么意义,不过真正有意思的是不同微调策略下涌现出来的视觉行为。虽然这里聚焦于 DPPO 和扩散策略(把数据当作"动作"),但微调动态完全可以推广到其他基于 RL 的扩散应用场景。

环境

定义一个"环形"高奖励区域,模型要学会把样本去噪到这个环的任意位置。观察点在于:模型会收敛到环上的某个模式,还是把样本均匀分布开?对环宽度的敏感程度如何?下面是一条去噪轨迹的例子:

期望行为:从随机初始化(噪声状态)走向高奖励区域,最后一步就是去噪完成的样本。

不过在开始之前我们先解释 DPPO 和相关术语,再尝试用这个算法优化扩散模型来生成高奖励样本。

DPPO 算法概述

DPPO 是 PPO 的变体,属于 on-policy 方法。核心思路是更新扩散模型参数让生成样本获得更高奖励。它把扩散过程建模成 MDP:每个扩散时间步是一个状态,动作就是"去噪",奖励来自最终的去噪状态。奖励通过蒙特卡洛估计传播回有噪声的时间步——也就是对完整回合的折扣回报求平均来估计期望累积奖励。DPPO 论文里这张图讲得很清楚:

外循环先做回合采样,存下每个扩散时间步的动作对数似然,加上状态、动作、奖励这些标配。内循环跑 K 个 epoch,用 PPO 风格的目标更新扩散模型参数。PPO 的细节网上讲得很多,下面只展开相关部分。内循环结束后,用新策略再采样一批回合。损失包含信任域策略更新、价值函数损失和探索用的熵项。为简化起见,这里只看上图中的"t=0"这一步,对应单条扩散轨迹。

算法 1. DDPO + DDIM 实现的伪代码。第 5 行的"动作"就是去噪一个样本。

步骤 1:回合采样

 state = env.reset()  

# (aside: action variance is learned)  
action_var = nn.Parameter(torch.full((2,), action_std_init * action_std_init))  

current_pos = state[:2]  

# in the rollout...  
with torch.no_grad():  
    # conditional noise prediction  
    pred_noise = policy.actor(current_pos, t)  
    # the "T-1" prediction is the next position in the denoising trajectory  
    action_mean = policy.ddim_step(pred_noise, t, current_pos)  
    dist = Normal(action_mean, action_var.sqrt())  
      
    # sample from distribution with learned noise  
    action = dist.sample()  
    action_log_prob = dist.log_prob(action).sum(dim=-1)  

next_state, reward, done = env.step(action)  

# store in Buffer  
 buffer.states.append(state, action, action_log_prob, reward, done)  

这段代码对应 DPPO 论文公式 4.3。目前微调整个 DDIM 轨迹,后面会比较只微调最后几步的效果:

代码里去噪过程的每一步都被当作动作,这是 DPPO 内部 MDP 的关键。动作方差设为可学习参数,因为 DDIM 本身是确定性的,需要加探索噪声(公式里的 sigma)。

DDIM 步骤方法如下,求解概率流 ODE 得到去噪过程的前一步(参考伪代码里的公式)。这个操作必须可微,梯度才能流过去噪过程:loss → logprobs → dist → action → ddim_step → pred_noise → actor weights。噪声调度参数是预设好的。

 # DPPO differentiates through diffusion steps, so this needs to be differentiable  
def ddim_step(self, model_output, timestep, sample):  
    # Handle t-1 (if t=0, prev=0, but alpha_prev=1.0)  
    prev_timestep = torch.clamp(timestep - 1, min=0)  
    alpha_prod_t_prev = alphas_cumprod[prev_timestep].view(-1, 1)  
    alpha_prod_t = alphas_cumprod[timestep].view(-1, 1)  
    beta_prod_t = 1 - alpha_prod_t  
      
    # DDIM Formula  
    pred_original_sample = (sample - torch.sqrt(beta_prod_t) * model_output) / torch.sqrt(alpha_prod_t)  
    pred_sample_direction = torch.sqrt(1 - alpha_prod_t_prev) * model_output  
    prev_sample = torch.sqrt(alpha_prod_t_prev) * pred_original_sample + pred_sample_direction  
      
     return prev_sample

步骤 2:奖励缩放和 GAE

这部分基本是标准 PPO。跟踪运行统计量来归一化奖励,因为奖励方差太大会让价值函数训练不稳定。然后对缓冲区里所有状态跑一遍价值函数前向(不算梯度),用 GAE 从回报计算优势值,平衡偏差和方差。GAE 做的事情是给去噪过程中的"动作"分配功劳,价值函数则是为带噪声的状态建模这个功劳(注意输入里也带了扩散时间步)。

 # get values from buffer  
old_states = torch.cat(buffer.states, dim=0)  

# scale rewards using running statistics  
rewards_np = np.array(buffer.rewards)  
rewards_norm = (rewards_np - reward_scaler.mean) / (np.sqrt(reward_scaler.var) + 1e-8)  

# compute Values for GAE  
with torch.no_grad():  
    x_t = old_states[:, :2]  
    t_long = old_states[:, 2].long()  
    # Get values from critic  
    values = policy.critic(x_t, t_long)  

advantages = []  
last_gae_lam = 0  

# iterate backwards through the buffer  
# buffer.is_terminals tells us if the episode ended at that step  
for step in reversed(range(len(buffer.rewards))):  
    if step == len(buffer.rewards) - 1:  
        next_non_terminal = 1.0 - float(buffer.is_terminals[step])  
        next_val = next_value  
    else:  
        next_non_terminal = 1.0 - float(buffer.is_terminals[step])  
        next_val = values[step + 1].item()  
          
    # Delta = r + gamma * V(s') * mask - V(s)  
    delta = rewards_norm[step] + gamma * next_val * next_non_terminal - values[step]  
      
    # Advantage = Delta + gamma * lambda * Advantage_next * mask  
    last_gae_lam = delta + gamma * gae_lambda * next_non_terminal * last_gae_lam  
    advantages.insert(0, last_gae_lam)  
   
# Compute Returns: Return = Advantage + Value  
# This is the target for the Value Function  
returns = advantages + values  

# Normalize Advantages (Standard PPO trick)  
 advantages = (advantages - advantages.mean()) / (advantages.std() + 1e-8)

步骤 3:PPO 更新

优化策略,降低低优势动作的概率,提高高优势动作的概率。这个过程跑多个 epoch 以充分利用缓冲区数据,不是更新一次就扔掉。每次迭代策略都在变,所以要在新策略下重新计算旧动作的对数概率,用新旧比率控制策略改进幅度。后面会实验不同的裁剪参数(eps clip)。

 # next state (from previous cell)  
state = next_state  

old_actions = torch.cat(buffer.actions, dim=0)  
old_logprobs = torch.cat(buffer.logprobs, dim=0)  

# K epochs define how   
for _ in range(K_epochs):  
    x_t = old_states[:, :2]  
    t_long = old_states[:, 2].long()  

    pred_noise = policy.actor(x_t, t_long)  
    mean_action = policy.ddim_step(pred_noise, t_long, x_t)  
      
    # learnable action variance (defined during rollout)  
    dist = Normal(mean_action, action_var.sqrt())  
    # recalculate log probs under new policy for policy ratio  
    logprobs = dist.log_prob(old_actions).sum(dim=-1)  
    ratios = torch.exp(logprobs - old_logprobs)  

    surr1 = ratios * advantages  
    surr2 = torch.clamp(ratios, 1-eps_clip, 1+eps_clip) * advantages  
    policy_loss = -torch.min(surr1, surr2)  
       
    # compute V(s) with gradients this time, to train value function  
    state_values = policy.critic(x_t, t_long)  
    value_loss = 0.5 * nn.MSELoss()(state_values, returns)  
      
    # there can also be an entropy term and KL term here, but omit for now  
     loss = policy_loss + value_loss

DPPO 和 DDPO 的区别

网上几乎没有对比这两个名字容易混淆的方法:Denoising Diffusion Policy Optimization(DDPO)和 Diffusion Policy Policy Optimization(DPPO)。DDPO 针对文本生成图像,DPPO 针对扩散策略优化。动机差异之外,DDPO 用按 prompt 的奖励归一化,"类似于价值函数基线";DPPO 用更成熟的 GAE 加上显式学习的价值函数。概念上真的很难分清楚,不过这里的实现因为用了 GAE,技术上算 DPPO。

从头训练 DPPO(失败)

理论上跟 PPO 一样,给够回合数就能最大化奖励。但 RL 和实际训练里,样本效率才是命门。模拟环境确实降低了采样成本,可灵巧操控这种 sim2real 效果差的任务,还是得靠真实演示用尽量少的回合搞定。所以先试试只用 300 个回合从头训练,看看性能曲线。下图和后续图里,蓝点是去噪后的样本,训练过程中定期评估。

300 个回合后 DPPO 完全没收敛,样本压根没往高奖励区域靠。扩散模型本身就需要大量样本,再叠上 RL 臭名昭著的样本低效,失败并不意外。就算加到 5000 个回合,超参不仔细调也收敛不了。

从专家演示微调

现实场景里不可能有无限回合,所以专家演示通常够引导奖励最大化。要模拟"专家演示",需要一个分布:接近高奖励区域的多个模式,大体形状像那么回事,但又留有 RL 优化空间。于是选了一个半径 1.0 的圆形分布,用监督学习训练扩散模型去噪到这个区域——可以类比从演示学习或在互联网数据上预训练。30k epoch 后几百个样本的可视化效果如下:

微调前的预训练动作分布(去噪轨迹未画出)。

加载预训练 checkpoint 再跑 DPPO,性能提升明显行为也符合预期:大约 150 个回合后粒子开始收敛到高奖励区域。不过通常是找到第一个被探索到的高奖励模式,而不是均匀分布在 radius=1.5 的环上。

DPPO 微调把动作从 radius=1 的预训练分布引导到 radius=1.5 的高奖励区域,比从头训效果好太多

添加 KL 约束

Flow-GRPO 等工作在 PPO 目标之外加了 KL 约束。对 LLM 和图像生成模型(Flow-GRPO 的主要场景),偏向有效文本和语义正确的图像是有道理的。机器人领域不太在意行为克隆的真实分布,只是借它引导通常稀疏且初次难以成功的高奖励区域(比如到底拿没拿起咖啡杯)。但如果用的是可能被"利用"的密集奖励,KL 约束就有用了——比如"杯子举多高"这种奖励,很容易被往上抛的动作钻空子。

DPPO 和 Flow-GRPO 目标对比如下:

DPPO 目标

Flow-GRPO 目标

Flow-GRPO 的组大小 G 可以替代 GAE 做优势估计。KL 约束确保新策略不会偏离原策略太多,能防止收敛时的发散行为。策略比率则保证更新幅度不要太大。加上 KL 后损失变成:

带 KL 约束的新 DPPO 目标

观察到的现象是:动作没有像之前那样收敛到一两个模式,而是保留了更多圆形分布的形状,分散在多个奖励模式周围。总奖励偏低,但这在预期之内。Flow-GRPO 论文也有类似发现:

…我们发现省略 KL 会导致视觉多样性崩溃,这是一种奖励利用的形式…(第 5.2 节)

分布在多个高奖励模式上,对应现实中完成任务有多种方式的情况(可以抓杯身也可以抓杯把)。KL 约束还能增加泛化性,防止只收敛到单一高奖励模式。比如普通 DPPO 可能只学会抓杯身,碰到杯子烫得不行的分布外场景就傻了;加了 KL 约束的 DPPO 还知道可以抓杯把。

即便抓杯把本来不在演示分布里,这个好处也可能成立。值得后续研究的问题是:PPO 更新中的 KL 约束到底保持的是预训练分布的形状,还是分布本身?在这个玩具环境里,如果带 KL 的 DPPO 最优策略确实收敛到均匀分布在 radius=1.5 圆上,就可以定性地说形状被保留了,只是低奖励特性被替换。如果 KL 只是把动作值锁在 radius=1.0,那就不成立了。

消融实验

微调跑通之后,就可以看看 PPO 各组件对性能的影响。

只微调最后几个扩散步骤

DPPO 论文建议提高效率的做法是:预训练后复制两份模型,一份冻结用于去噪前面的时间步,另一份微调用于去噪最后几步(附录 C.2 建议 10% 来平衡效率)。但在这个环境里,30% 到 50% 似乎更合适(总共 50 个去噪步骤)。

只微调最后 10%、30%、50% 的步骤(从左到右)。30% 到 50% 之间效果明显更好

这个环境还可以对比不同设置下的扩散轨迹,训练结束后可视化 20 个样本:

只微调最后 10%、30%、50% 步骤的采样轨迹(从左到右)

放大 10% 微调步骤产生的轨迹(最左边),可以看到样本越过预训练流形后有个向高奖励区域的急剧"转向"。转向后面的去噪步骤就是被微调的模型。有意思的是,微调步骤越多,这个转向越平滑,但预期还是会在某个地方出现——最左边轨迹在第 90 百分位步骤能看到,中间轨迹偶尔在第 70 百分位出现,最右边第 50 百分位已经是平滑过渡了。如果转向的急剧程度和微调效果差相关(急剧可能意味着最后几步过度补偿),那可以考虑用轨迹急剧程度作为拟合质量的指标,尤其是高维场景下不容易定位问题的时候。

跟微调整个轨迹的结果对比:

线条颜色更深,说明显著地把样本推向了高奖励区域,初始扩散步骤的重要性可见一斑。

策略比率 eps clip 和学习率的交互

直觉上这两个东西作用类似。策略比率控制策略变化速度,actor 学习率也决定这一点。

低/高 clip 与学习率的对比(clip = 0.1/0.4,lr = 1e-4, 5e-3)。高 clip 意味着允许更大的策略偏移

学习率的影响压过了策略裁剪,这说得通——参数空间偏移太大的话,策略比率会变得巨大。跑了几个实验后结论很清楚:学习率最需要调,策略裁剪挡不住过激更新(哪怕 clip 设到 0.01 配上高学习率也没用)。有意思的是,低学习率似乎有助于保留奖励区域的多个模式。

移除策略比率

完全去掉策略比率,min() 两边都设成优势值乘对数概率(注意如果只用 A 不带 log prob,梯度就断了)。动作收敛到比不加 KL 项更紧密的分布(跟上一节高 clip 结果很像),不过奖励依然挺高。这也暴露了环境复杂度的局限——没有性能掉下去就回不来的区域,而策略比率本来就是为防这个设计的。不过有趣的是,这又是一个能防止奖励模式崩溃的因素。另一个有趣现象是训练久了会在多个奖励模式之间跳——像是高学习率行为的稍微稳定版。

其他超参的一些观察

优化 epoch 数确实和 eps clip 成反比,两个超参都在权衡每次更新的策略改进幅度。

DPPO 更新间隔的时间步数和学习率成反比,两者都在权衡策略改进的速度。

总结

这篇文章解释了如何为单步环境中的扩散模型实现 DPPO,希望能提供一个比典型机器人环境更容易理解训练动态的平台。跑了只微调最后几个去噪步骤、调各种 PPO 超参的实验。大家可以自己从这些结果里得出结论,也可以动手改改环境,看能不能提升样本效率——这仍然是 PPO 的关键瓶颈。

代码在这里:https://avoid.overfit.cn/post/f27f00300f6c4bf79312ed79a23ae9df

作者: Neel

2024 年 10 月 8 日,John Hopfield 和 Geoffrey Hinton 凭借在人工智能领域的奠基性工作获得了诺贝尔物理学奖。这一决定最初让许多人感到困惑:为什么计算机科学的成就被归入了物理学?

诺贝尔委员会的答案揭示了一个深刻的真理:现代 AI 的核心算法并非凭空创造的数学游戏,而是深深植根于描述自然界物质行为的物理定律中。从磁铁的微观结构到统计热力学,再到量子场的宏大理论,AI 正是物理学在数字世界的一种镜像。

以下是这一跨学科奇迹背后的四个核心物理支柱。

1. 从磁铁到记忆:伊辛模型与能量景观

要理解 AI 如何“记忆”,首先需要审视磁铁的物理本质。

在物理学中,伊辛模型 (Ising Model) 被用来解释铁磁性。想象一个微观网格,格子里充满了原子,每个原子都有一个“自旋”方向(向上或向下)。原子倾向于与邻居保持一致(如果邻居向上,我也向上),因为这样系统的总能量最低、状态最稳定。

1982年,John Hopfield 受到这个物理模型的启发,构建了 霍普菲尔德网络 (Hopfield Network)

  • 原子变成了神经元:原本的原子自旋变成了人造神经元的“激活” (1) 或“未激活” (-1) 状态。
  • 磁力变成了权重:原子间的相互作用变成了神经元连接处的“权重” (Synaptic Weight)。

Hopfield 网络最精妙的地方在于它引入了 能量景观 (Energy Landscape) 的概念。可以将网络的所有可能状态想象成一片连绵起伏的山地:

  • 学习即“挖坑”:当教 AI 记住一个图案时,实际上是在调整连接权重,在能量地形上“挖掘”出一个低能量的山谷(势阱)。
  • 回忆即“滚动”:当给 AI 一个残缺的图案(相当于把弹珠放在山坡上),根据物理学趋向最低能量的原理,弹珠会自动滚入最近的山谷。这意味着网络能自动从噪点中“恢复”出最初记忆的完整图像。

2. 从固执到灵活:Hinton 与热力学的魔法

Hopfield 网络虽然天才,但有一个致命缺陷:如果弹珠滚进了一个很浅的坑(局部最优解),它就会卡在里面出不来,无法找到真正的深谷(全局最优)。这就好比 AI 陷入了思维定势。

Geoffrey Hinton 引入了统计物理中的 “温度” (Temperature) 概念,将 Hopfield 网络升级为 玻尔兹曼机 (Boltzmann Machine)

他借用了冶金学中的 “模拟退火” (Simulated Annealing) 原理:

  • 加热:在训练初期,给系统极高的“温度”。这意味着弹珠会剧烈抖动(引入高随机噪声),即使遇到小坑也能轻易跳出来。
  • 降温:随着时间推移,逐渐降低温度,让弹珠慢慢稳定下来,最终有极大概率落入整个地形中最深的山谷。

正是这种受热力学启发的“随机性”,让 AI 摆脱了死记硬背,拥有了举一反三的生成能力。

3. 数学的幽灵双胞胎:神经网络与量子场

如果说磁学解释了 AI 的记忆,热力学解释了 AI 的学习,那么 量子场论 则揭示了 AI 更深层的数学结构。这一联系之紧密,可以通过著名的 模型 (The Phi-Fourth Model) 和一个直观的类比来理解。

场景 A:无限宽网络 = 宇宙真空的涨落

为了理解这一点,我们可以想象一台拥无限多个像素点(神经元)的巨大电视屏幕。

  • 现象:如果你随机初始化这些像素的亮度。虽然每个点是随机的,但如果你统计整个无限屏幕的亮度分布,它会呈现出一个完美的钟形曲线(高斯分布)。
  • 物理对应:这就像量子力学中的“真空”。真空不是空的,而是充满了随机的能量波动。如果没有粒子相互作用(自由场),这些波动的统计规律也正好是完美的钟形曲线。
  • 结论:一个什么都没学的、无限大的 AI 大脑,它的“脑电波”底噪,和宇宙真空的量子涨落是一模一样的。

场景 B:有限宽网络 = 粒子碰撞与 模型

但现实中的 AI 网络是有限的,就像把那台巨大的电视变小了。

  • 现象:因为像素(神经元)变少了,随机性的统计规律开始出现偏差,钟形曲线不再完美。
  • 物理对应:这就像在真空中放入了真实的粒子。粒子不再是孤独的,而是开始相互作用(碰撞、吸引)。物理学家使用 模型 来描述这种粒子成对相互作用的情况。

惊人的同构

最令人震惊的发现在于:为了描述有限宽神经网络的偏差,科学家所使用的数学修正公式,竟然和物理学家用来计算 模型中粒子碰撞的公式是 同构(结构相同) 的。

这也让物理学家找到了解开 AI 黑盒的钥匙——费曼图 (Feynman Diagrams)。这一物理学家算了几十年的、用来描述粒子碰撞的图解工具,现在竟可以用来精确分析神经网络的内部运作。

4. 创造的物理学:扩散模型与墨水实验

这一跨界融合的终极案例,是目前驱动 Midjourney、Sora 等生成式 AI 的核心——扩散模型 (Diffusion Model)

它的灵感直接来源于 非平衡热力学。为了理解它,我们可以把生成一张图片的过程想象成“让时间倒流”

正向过程:熵增与毁灭(Destruction)

想象你有一张清晰的照片,或者一滴滴入清水的浓墨。

  • 物理现象:随着时间推移,墨水分子做布朗运动(无规则运动),图像逐渐模糊,最终变成一盆均匀的、毫无信息的灰水。
  • 数学本质:这是一个不断叠加高斯噪声的过程。在物理学中,这对应着熵增(Entropy Increase),即系统从有序走向无序。这是宇宙最自然的法则,不需要学习。

逆向过程:逆熵与重塑(Creation)

AI 的任务是挑战热力学第二定律:它要学会如何把这盆灰水还原回那滴墨水。

  • 学习机制:科学家训练 AI 观察无数张图片被“加噪”的过程。AI 并不需要一次性复原图片,它只需要学会预测“每一步加了什么噪声”。
  • 生成的艺术:当你要 AI 画画时,你其实是给它一团完全随机的噪点(一块杂乱的大理石)。AI 开始运行“逆向扩散方程”,根据你的提示词,一步步减去噪声

雕刻家的比喻

这就像米开朗基罗雕刻大卫像。以前的 AI(如 GAN)试图一次性堆叠出完美的形状,容易倒塌;而扩散模型则是雕刻
它面对的是一块包含所有可能性的“噪声大理石”,利用物理方程作为凿子,通过成百上千次微小的操作,剔除多余的杂质(噪声),最终让藏在石头里的图像“显形”。

没有流体力学和热力学的方程,就没有今天生成式 AI 的爆发。

结语

2024 年的诺贝尔物理学奖并非一次跨界的勉强,而是一次某种意义上的“归宗”。

物理学研究的是“上帝”构建的神经网络(宇宙),而 AI 研究的是人类构建的宇宙(神经网络)。这两个领域的殊途同归或许暗示着,智能并非碳基生物的特权,而是物质复杂到一定程度后,为了降低系统熵值而产生的一种必然物理现象。

AI 的物理学,才刚刚开始。

本文由mdnice多平台发布