当天气预报不再局限于“播报”,而是成为物理世界的数字孪生接口,微服务架构将如何撑起这场感知革命?
“透过天气项目学透 Spring Cloud”不仅是一次技术实践的复盘,更是对未来软件架构形态的一次预演。在传统的认知中,天气项目往往被视为展示 RESTful API、服务注册发现、配置中心等 Spring Cloud 核心组件的经典场景。然而,若我们将目光投向未来 5 到 10 年的技术演进,这个项目将不再仅仅是数据的搬运工,而是演变为集全球感知、边缘计算、AI 赋能于一体的复杂智能系统。
从未来的视角审视 Spring Cloud 在天气项目中的角色,我们将看到微服务治理正在经历一场从“集中式管理”向“云边智协同”的深刻范式转移。
一、 架构形态:从集中式云端迈向“云-边-端”全域协同
未来的气象监测将不再依赖孤立的气象站,而是由数以亿计的物联网传感器、手机气压计、车载雷达以及低轨卫星构成的泛在感知网络。传统的单体 Spring Cloud 架构将无法应对海量的设备接入和极高的并发写入,架构形态将发生根本性进化。

  1. 边缘节点的微服务化
    未来的 Spring Cloud 将不仅仅运行在中心云机房,更将大规模下沉至边缘侧。在未来的天气项目中,每个城市甚至每个街区都会部署边缘计算节点。
    边缘自治:利用 Spring Cloud 的扩展机制,微服务将具备“边缘自治”能力。即使在网络与中心云断连的情况下,本地的气象数据采集、预警广播等服务仍能独立运行。这是未来应对极端自然灾害、保障通信“最后一公里”的关键技术。
    动态拓扑感知:服务治理将不再局限于静态的服务列表。未来的服务发现组件需要能够实时感知移动节点(如气象无人机、应急车)的动态位置,基于地理位置和网络延迟动态调整服务调用链路。
  2. 混合云架构的常态化
    为了应对突发性天气(如台风、暴雨)带来的局部流量洪峰,未来的天气项目将运行在混合云之上。
    无缝跨云调度:Spring Cloud 的服务治理将与底层基础设施深度解耦,实现跨公有云和私有云的无缝服务调度。当某区域流量激增时,系统能自动在云端扩容计算微服务实例,并将流量智能分发,实现真正的“气象级”弹性伸缩。
    二、 数据处理:从批处理演进为“流批一体”的实时孪生
    未来的天气预报要求达到“分钟级”甚至“秒级”的刷新率,这对微服务间的数据流转提出了极高的要求。传统的请求-响应模式将逐渐让位于事件驱动架构(EDA)。
  3. 事件驱动的服务解耦
    在未来的项目中,传感器的每一次数据波动都将触发一个事件。
    实时反应链:Spring Cloud Stream(或其演进形态)将成为连接物理世界与数字世界的神经中枢。一旦监测到气压骤降,事件即刻触发,预警服务、交通调度服务、物流规划服务并发响应,无需等待上层应用轮询。这种“极速解耦”是未来智慧城市运作的基础。
  4. 数字孪生的实时构建
    天气项目将成为构建城市“数字孪生”的核心数据源。微服务架构不仅要传输数据,更要维持一个与真实世界同步的虚拟模型。
    状态一致性挑战:在高度并发的微服务环境下,如何保证全球数百万个虚拟气象节点状态的一致性?未来的分布式事务治理将不再局限于 ACID 或 BASE,而是结合 CRDTs(无冲突复制数据类型)等新型数据结构,实现最终一致性与实时性的完美平衡。
    三、 治理智能化:从人工运维到“自愈合”智能体
    随着系统复杂度呈指数级增长,人工配置 Hystrix 断路器、手动调整熔断策略将成为历史。未来的微服务治理将全面拥抱 AIOps(智能运维)。
  5. 预测性弹性伸缩
    未来的 Spring Cloud Gateway 将集成 AI 预测引擎。
    流量预判:结合历史天气数据和即将到来的气象变化,系统能够预知某地即将发生的暴雨会导致用户查询量激增。在流量到来之前,微服务实例自动完成扩容和预热,实现“零延迟”响应。
  6. 自愈合系统
    异常根因分析:当某个微服务响应变慢时,AI Agent 会自动分析链路追踪数据,判断是数据库锁死、网络抖动还是算法缺陷,并自动注入修复策略(如限流、重启、降级),无需人工干预。系统将具备类似生物体的“免疫修复”能力。
    四、 安全与可信:零信任架构与隐私计算
    气象数据在未来将关联到能源调度、航空保险、农业生产等高价值领域,数据的安全性与隐私性至关重要。
  7. 零信任网络
    未来的 Spring Cloud 安全体系将默认“不信任任何内外部网络”。
    细粒度动态授权:每一次服务调用,即使是内部微服务之间的通信,都需要经过基于身份和上下文的动态鉴权。Service Mesh(服务网格)将成为标准配置,承载所有微服务的流量管控与加密传输。
  8. 数据的可用不可见
    在某些商业场景下,例如保险公司获取气象数据进行理赔核验,未来的架构将支持隐私计算。保险公司可以在不解密原始气象数据的情况下,运行计算逻辑获得结果。这需要在微服务协议层面引入同态加密等技术的支持,彻底解决数据共享的信任危机。
    五、 终极愿景:Spring Cloud 作为“感知即服务”的骨架
    透过未来的天气项目,我们看到 Spring Cloud 的本质正在发生变化。它不再仅仅是 Java 程序员手中的开发框架,而是正在进化为连接数字世界与物理世界的操作系统。
    在这个未来图景中,Spring Cloud 赋予了软件系统“感知”、“思考”和“反应”的能力。它让气象数据不再停留在屏幕上,而是流动到自动驾驶汽车的决策单元中,流动到智能电网的调度算法中,流动到每一个用户的智能终端上。
    “从入门到进阶”的终点,不仅是掌握了一个框架的使用,而是理解了如何构建一个具有韧性、智能且自适应的未来系统。这或许才是我们学习 Spring Cloud 的终极意义所在——在比特与原子的交汇处,用代码重构世界的运行逻辑。

人事小姐姐是我的饭搭子,跟我说年会要搞抽奖,问我有没有好用的在线转盘。

我随手发了几个链接给她,结果她一个个试完来吐槽:

  • Wheel of Names:不能同时转多个轮子,她想一边抽人一边抽奖品
  • 某国产转盘:广告太多,界面丑,领导看了要皱眉
  • 随机数生成器:太干了,没有仪式感

总之就是不体面,我说行吧,周末我给你写一个。

结果这一写,失控了。

刚开始想的很简单,就一个 Canvas 画个轮子,Math.random 选个结果。但写着写着开始较真:

  1. Math.random 不够随机。查了下发现如果要"公平抽奖",应该用
    crypto.getRandomValues(),这是密码学安全的随机数生成器。既然都做了,那就做对。
  2. 她要同时抽人+抽奖品。那就支持多轮盘吧,最多 6 个同时转。转完自动记录中奖历史。
  3. 中奖了的不能重复中。加了淘汰模式,中一个自动移除。
  4. 另外还加了绿幕模式,一键全屏纯绿底。
  5. 做了短链,方便分享或者保存自己定制好的转盘,用 Cloudflare Worker 写了个
    API ,转盘配置存起来生成短链,发个链接别人就能用。

做完发现功能有点多了:

  • 多转盘同时旋转
  • 权重设置(买 5 张票的人权重设 5 )
  • 淘汰模式
  • 倒计时模式( 3 、2 、1 开始!)
  • OBS 绿幕
  • 导入导出 JSON
  • 8 种语言
  • 本地自动保存

UI 也花了点心思,年会现场投屏效果挺好。暗色模式是青绿色系,亮色是橙粉系,看着挺舒
服的。

技术栈是 Next.js + React + TailwindCSS ,整了个 monorepo 用 Turborepo 管理,状态用 Nuqs 存 URL
参数方便分享。分享功能单独拆了个 Cloudflare Worker ,响应挺快的。

地址:gospinwheel.com


对了,快过年了,除了年会抽奖,其实过年聚会也能用:

  • 真心话大冒险:一个轮子选人,一个轮子选"真心话/大冒险",再来一个轮子选具体问题或任务
  • 谁洗碗:吃完年夜饭,全家人名字往里一扔,转
  • 今晚吃啥:火锅/烧烤/日料/随便,选择困难症救星
  • 该谁发红包了:下一个谁发?转盘决定,公平公正
  • 喝酒游戏:转到谁谁喝,配合淘汰模式,喝过的自动移除,雨露均沾

反正我过年准备拿这个整活了,投屏到电视上效果应该不错。

有什么建议欢迎提,毕竟本来只是帮人事做个小工具...

在多项目并发与复杂任务流管理的数字化协作中,传统的线性计划已难以应对灵活多变的业务需求 。如果计划编排缺乏原子化的卡片管理,可能会导致:

  • 执行断层:计划背景被淹没在厚重文档中,导致执行者无法直观获取关键信息 。
  • 排期僵化:无法快速响应需求变更,导致项目排期与实际进度严重脱节。
  • 透明度缺失:团队成员难以实时了解全局节奏及各阶段的准入准出标准。
  • 资源错配:缺乏对任务依赖关系的清晰视图,容易造成资源闲置或关键路径阻塞。

卡片式计划编排工具通过将模糊的项目计划转化为可灵活组合、可实时追踪、可多维对齐的卡片执行引擎,确保团队在复杂的竞争环境中实现精准交付 。

卡片式计划编排工具的核心特性

  • 原子化任务卡片:将复杂计划拆解为独立卡片,封装背景、标准、工时等核心元数据 。
  • 多维可视化视图:支持看板、时间线、甘特图等多种表现形式,实现计划的直观编排 。
  • 依赖关系建模:清晰标记卡片间的逻辑关联(如包含、阻塞、并行),自动计算关键路径 。
  • 自动化流转规则:基于触发器实现卡片状态自动更新,确保计划与执行同步 。
  • 递归进度核算:底层原子卡片的执行质量自动驱动顶层计划的达成率评估。

卡片式计划编排工具的重要意义

  1. 消除信息颗粒度偏差:通过卡片的高度封装,确保执行层与管理层在任务定义上达成高度共识 。
  2. 提升排期灵活性:支持通过拖拽、连线等操作快速调整计划,大幅降低重排排期的成本。
  3. 强化过程确定性:实时审计实际流转速率与排期模型的差异,实现风险的主动预警与修正 。
  4. 沉淀组织标准化路径:将验证有效的编排模式固化为卡片模板,实现项目经验的快速复用。

应用场景

  • 敏捷迭代管理:将产品愿景拆解为 Sprint 任务卡片,驱动研发交付流高效流转。
  • 复杂项目规划:在启动阶段梳理各模块间的依赖链路,利用卡片编排规避交付冲突 。
  • 资源负载均衡:通过可视化看板监控各环节卡片堆积情况,实现动态的人力资源调度。
  • 跨团队协同:通过共享的计划卡片池,对齐跨职能部门的协作节奏与产出标准 。

---

5款值得尝试的卡片式计划编排工具

1. 板栗看板

直观的任务流转与多层级穿透

  • 特点:支持任务卡片的无限层级嵌套,通过看板视图展示计划的深度编排逻辑。
  • 优势:看板视图极度直观,支持卡片逻辑连线,适合追求过程透明的敏捷团队。
  • 适合团队:需要快速响应并对计划进行纵向穿透的小型和中型研发团队 。

2. ClickUp

全功能任务编排与数据看板平台

  • 特点:提供强大的“目标”模块,支持将微观卡片进度自动聚合为宏观指标。
  • 优势:支持极高维度的自定义,能根据卡片元数据生成复杂的排期审计报告。
  • 适合团队:需要对大规模计划进行参数化管理和深度数据分析的团队 。

3. Trello

简单轻量的卡片流转工具

  • 特点:强调“清单化”的计划编排,支持丰富的卡片封面与标签分类 。
  • 优势:操作极简,学习曲线极低,适合快速搭建基础的交付工作流 。
  • 适合团队:注重任务分类和灵活调整、倾向于视觉驱动型协作的团队 。

4. Jira Software

工业级标准与自动化编排引擎

  • 特点:拥有严密的权限与流程控制逻辑,支持复杂的卡片依赖与版本排期。
  • 优势:可与代码仓库深度集成,实现从“计划编排”到“自动执行”的闭环审计。
  • 适合团队:追求高度标准化执行、有严格合规与闭环审计需求的大型组织。

5. Monday.com

高度自由的卡片式协同看板

  • 特点:支持看板与时间轴、工作负荷视图的实时联动,动态展示卡片状态。
  • 优势:视觉色彩丰富,支持强大的自动化集成,能显著提升团队编排兴趣。
  • 适合团队:强调团队协同氛围、需要灵活配置复杂编排场景的项目组。

---

如何选择合适的卡片式计划编排工具?

1. 按团队规模选择

  • 小型团队(1-10人):推荐 板栗看板、Trello 等工具,侧重于快速启动与核心任务的直观流转。
  • 中型团队(10-50人):适合使用 Monday.com、ClickUp,支持更复杂的多维对齐与资源核算 。
  • 大型团队(50+人):建议选择 JiraClickUp,这些工具提供强大的层级管理与权限隔离功能。

2. 按计划复杂度选择

  • 线性任务(如内容生产、日常运营):选择 板栗看板、Trello 等简洁易用的视图工具 。
  • 交叉任务(如软件研发、系统重构):推荐 Jira板栗看板等支持深度连线与递归逻辑核算的专业平台。

---

提升计划编排效率的小建议

  1. 坚持卡片原子化:确保每张卡片描述的是最小可执行单元,避免职责模糊。
  2. 设置基准流转速率:定期审计实际完成时长,为后续计划编排提供真实的数据支撑。
  3. 建立风险预警连线:为关键路径上的卡片设置依赖预警,确保下游环节能提前预知变动 。
  4. 定期进行计划“减脂”:及时清理、归档过时卡片,保持编排体系的干练与精准执行力。

---

总结

卡片式计划编排工具是管理组织执行复杂性的关键手段。通过 板栗看板、ClickUp、Jira 等工具,团队能够将宏观的战略意图精准解构为微观的原子卡片,实现“计划-执行-状态”的实时对齐。

精准的编排,是高效交付的基石。

1.问题描述:

断点太多是否会使DevEco Studio运行卡顿?如何处理?

解决方案:

断点太多会影响DevEco Studio运行,可以通过断点管理删除不必要的断点。

2.问题描述:

为什么图片使用imagePacker.packToFile压缩完之后,反而变大了?

解决方案:

可以参考图片压缩API的质量参数quality与图片原始大小、压缩后大小的关系,quality是图片质量参数,并非是指按百分比压缩。若压缩前图片质量比指定的压缩参数quality小的话,就可能会导致压缩后的图片文件比压缩前更大;若想实现压缩变小,可以降低quality值,或是压缩前使用。PixelMap.scale缩放图片后再进行压缩。

3.问题描述:

AVPlayer有两个播放源,清晰度不一样,希望切换播放源时尽量顺滑,让用户没有感知,有什么方案?

解决方案:

应用中通过层叠布局创建两个avPlayer播放器堆叠,用户只能看到最上层的播放器界面;点击播放时,两个清晰度不一样的视频同时在两个播放器上播放,点击切换时,设置对应清晰度视频所在的播放器的堆叠顺序为高优先级,则会展示该播放器界面在最上层,达到切换的目的。

UTM 5.0.1 发布 - 基于 QEMU 的 macOS 虚拟机与模拟器应用

在 iPhone 和 iPad 中虚拟化 Windows、Linux 和 Unix,如此简单!

请访问原文链接:https://sysin.org/blog/utm-5/ 查看最新版。原创作品,转载请保留出处。

作者主页:sysin.org


UTM for Mac 是一款基于 QEMU 的 macOS 虚拟机与模拟器应用,用于在 Mac 上运行和测试 Windows、Linux 等多种操作系统。

UTM 是什么?

UTM 是一款面向 iOS 和 macOS 的全功能系统模拟器和虚拟机宿主,基于 QEMU。简而言之,它可以让你在 Mac、iPhone 和 iPad 上运行 Windows、Linux 等多种操作系统。

QEMU(Quick Emulator)是一款开源的机器模拟器和虚拟化软件,由 Fabrice Bellard 于 2003 年创建。它通过动态二进制转换技术实现跨平台虚拟化,支持 x86、ARM、MIPS 等多种处理器架构。QEMU 既可以作为独立虚拟机运行完整的操作系统,也可与 KVM(基于内核的虚拟机)配合使用实现硬件加速虚拟化 (sysin),这种组合方案能够提供接近原生性能的虚拟化体验。

QEMU 核心特点是跨平台虚拟化支持,支持 x86、ARM、RISC-V、PowerPC 等多种处理器架构,可在 Windows、Linux、macOS 等操作系统上运行,这意味着在 iOS 上也可以运行 Windows x86 系统。

UTM 和 QEMU 的关系可以概括为:UTM 是基于 QEMU 构建的图形化虚拟化与系统模拟工具。

快速入门

快速入门 - 步骤一

1、使用 “+” 按钮打开新的虚拟机向导。

2、 选择一个虚拟机以显示其详细信息;对虚拟机进行右键点击或使用 Force Touch 可打开 操作菜单 (actions menu)。

3、使用启动按钮快速启动虚拟机。

快速入门 - 步骤二

4、通过工具栏最右侧的图标打开 设置 (settings)。

5、在详情视图中,点击 “浏览…” 按钮选择一个 共享目录 ( shared directory)。

6、在详情视图中打开驱动器菜单,选择要挂载(或弹出)的可移动磁盘映像

UTM 5 新增功能

亮点

  • 改进了 Linux 的图形加速:在 Linux 客户机中,通过 Mesa 的 VirtIO Venus 驱动现已支持 Vulkan 1.3;在 macOS(仅限)上,借助全新的 Apple Core OpenGL 后端支持 OpenGL 4.1。

已知问题

  • (macOS)Apple CoreGL 后端不支持 Vulkan。
  • 由于缺少相关特性,DXVK 无法工作(#7575)。
  • KosmicKrisp 目前以 WIP(进行中)形式提供,但上游当前版本尚不完整,因此推荐使用 MoltenVK 驱动。
  • (macOS 26)由于 HV_UNSUPPORTED 错误,虚拟机无法启动。这是一个构建问题,将在下一个版本中修复。临时解决方法:在设置中禁用 Vulkan(#7579)。

更改内容(v5.0.1)

  • CocoaSpice:重构了 Metal 渲染器,以提升性能并降低延迟
  • 修复了当 BIOS 文件名中包含逗号时无法加载的问题
  • 默认 FPS 现在将设置为 macOS 和 iPadOS 显示器的最大刷新率(配备 ProMotion 的 iPhone 默认仍为 60Hz,但可在设置中覆盖为 120Hz)
  • (macOS)修复了在启用 Vulkan 时启动出现 HV_UNSUPPORTED 的问题(#7579)
  • (iOS)修复了外接显示器的分辨率问题(#6040)
  • (iOS)双指缩放将自动关闭来自来宾系统的缩放自动更新(可通过调整大小按钮重置)
  • (iOS)修复了外接显示器菜单未更新的问题 (sysin)
  • (iOS)修复了外接显示器缩放比例不正确的问题,并且在连接外接显示器时将自动缩放以适配屏幕
  • (iOS)修复了关闭虚拟机电源后会显示主屏幕但不会在后台终止 UTM 的问题

下载地址

UTM v5.0.1 Release 2026-01-20

更多:macOS 下载汇总 (系统、应用和教程)

随着企业数字化转型的深入,报表不仅是数据的展示工具,更是业务逻辑的载体。在与众多开发者的交流中,我们发现了一个长期存在的痛点:“为什么我精心设计的报表导出到 Excel 后,动态的公式都变成了死板的数值?”

在即将发布的 SpreadJS V19.0 中,我们针对报表插件(ReportSheet)带来了一项重量级更新——“导出预览报表到 Excel 时保留公式”功能。今天,我就带大家深度解密这项特性,看它如何打破数据与逻辑之间的壁垒。

一、 痛点回顾:消失的“计算逻辑”

在过去,开发者在报表模板中定义的公式,在导出为 Excel 文件时,往往会被计算引擎处理并转化为静态值

这意味着,当终端用户拿到导出的 Excel 文件并试图修改其中的基础数据时,报表中的小计、总计等关键指标并不会随之更新。用户不得不手动重新输入 Excel 公式,这不仅降低了工作效率,也让报表失去了原本的动态交互灵魂。

二、 核心能力:让 Excel 报表“动”起来

SpreadJS V19.0 引入的“保留公式导出(Preserve Formula in Export)”功能,允许用户在将报表导出为 Excel 文件时,完整保留单元格中的计算逻辑

1. 核心价值总结

  • 逻辑无缝延续:导出后的 Excel 依然拥有动态计算能力,而非固定数值。
  • 自由编辑体验:终端用户修改 Excel 单元格内容后,相关公式会自动重算,保持与原始系统一致的交互体验。

在这里插入图片描述

三、 深度解析:它是如何实现的?

为了兼顾各种复杂的报表场景,我们针对不同的公式类型和布局制定了严密的导出策略。

1. 标准 Excel 函数处理

  • 连续区域引用:如果报表展开后的单元格区域是连续的,导出时将作为单一区域引用。
  • 不连续区域引用:对于 SUM、AVERAGE、MIN、MAX 等聚合函数,即使报表生成的区域不连续,SpreadJS 也会智能地将其导出为多个区域的组合引用。
    在这里插入图片描述

在这里插入图片描述

2. R.V(报表变量/视觉)公式的智能转换

R.V 公式是 SpreadJS 报表中的特色功能。在 V19.0 中:

  • 如果公式在预览模式下可解析,导出时会精准转换为 Excel 实际单元格引用
  • 对于表达式中部分可解析的情况,我们会使用 SJS.EMPTY_CELL(值为 0)进行占位,确保公式结构的完整性。
    在这里插入图片描述

在这里插入图片描述

3. 报表专用公式的保留

对于如 R.IndexR.RankR.YoY(同比)等 SpreadJS 专有的报表函数,导出时会保留其函数名和引用。虽然 Excel 原生不支持这些函数(会显示为 #NAME?),但这为二次开发或后续回导提供了珍贵的元数据信息。
在这里插入图片描述

四、 开发者友好:配置只需一个属性

在 SpreadJS V19.0 中,启用这项功能非常简单。

方式一:API 配置

在设置 StaticCell 类型的模板单元格时,只需指定 preserveFormulaInExport 属性:

// 代码示例
export type StaticCell = {
    type: 'Static',
    preserveFormulaInExport?: boolean; // 设为 true 即可开启
    // ... 其他属性
};

方式二:设计器直观操作

如果您使用的是 SpreadJS 设计器,完全无需编写代码。在“报表单元格”属性面板中,勾选“导出 Excel 时保留公式”选项即可一键开启。

在这里插入图片描述

五、 结语

“保留公式导出”特性的加入,标志着 SpreadJS 报表插件在“所见即所得”的基础上,进一步实现了“所获即所用”。它不仅是导出格式的改进,更是对数据生命周期的深度赋能。

SpreadJS V19.0 还有更多关于 AI 插件增强、协同插件正式版、WebWorker 增量计算等重磅特性蓄势待发。

道阻且长,行则将至。 让我们共同期待 V19.0 带来的生产力变革!

注:具体技术文档请以正式发布版本为准。

当人工智能与实体经济的融合步入深水区,烟草作为国民经济的重要支柱产业,其智能化进程已超越单一的生产自动化,全面渗透至管理、采购、专卖、物流、营销与服务等全价值链环节。打破数据壁垒、构建端到端的协同智能运营体系,成为推动行业向高质量发展的核心课题。

在此背景下,北京中烟创新科技有限公司(简称:中烟创新)作为专注于烟草行业的AI解决方案提供商,经过三年扎实深耕,已将人工智能解决方案植入烟草商业公司23个部门的68个场景及工业公司19个部门的56个场景。实践印证,AI不仅是提升效率的工具,更是驱动业务模式重构、重塑行业竞争力的战略引擎。

一、直面行业痛点,响应深度智能化需求在宏观经济、行业政策与企业内部治理的多重驱动下,烟草企业对智能化的需求日益深化。尤其在综合办公、合规风控、管理决策等领域,传统模式普遍面临效率低下、标准不一、合规风险高等挑战。要破解这些难题,仅依靠技术远远不够,唯有对行业运作逻辑的深刻理解,才能使解决方案真正落地生根。中烟创新坚信:技术是基础,而对业务的洞察才是价值实现的钥匙。 

三年来,团队深入多家烟草企业的财务、法规、专卖、营销、物流等核心部门,与业务人员共同作业,精准把握行业特有的业务流程、合规要求与管理难点。这种深度共创构建了公司独特的“行业知识壁垒”,并具体体现于每一个优化细节中:在采购管理中,精准理解“一项一卷”评查要求,破解采购全流程的合规难题;在专卖执法中,依据行政处罚案卷规范,实现法条自动匹配、文书一键生成;在财务审核中,平衡效率与风控,通过AI实现发票自动识别与智能审验,大幅提升自动化率。

二、“懂行业”的AI:从技术赋能到业务融合基于对业务的深入理解,中烟创新的AI应用不是简单的技术叠加,而是与业务深度咬合的“智能伙伴”。例如,为济南市烟草专卖局打造的招标文件查重系统,以及为行业客户累计开发的128个业务场景解决方案,均证明了“行业知识+人工智能”的融合价值。烟草行业的科技创新,是一场以"懂行业"为前提、以"真落地"为标准、以"创价值"为目标的深度数字化变革,选择"既懂技术更懂烟草"的深耕型合作伙伴成为制胜关键。

三、沉淀与积累:以实力构建信任基石凭借坚实的技术积累与持续的创新实践,中烟创新已构建起体系化的资质与荣誉矩阵:被认定国家高新技术企业,连续入选北京软件核心竞争力企业,并认定为科技型中小企业、创新型中小企业;连续三年获评诚信企业认证,企业社会责任治理AA级;累计拥有发明专利、软件著作权等知识产权百余项,荣获国家、行业及省市级荣誉上百项。

公司不仅提供技术,更注重为每一项创新项目注入可持续的软实力支撑,围绕软件著作权、高水平论文、发明专利等进行全方位支持,全面塑造项目的长期影响力与行业创新价值链。四、携手共创智能化新格局历经三年打磨,中烟创新已在财务管理、专卖监管、采购合规等领域形成成熟的产品矩阵与解决方案。每一套方案都源于真实的业务场景,经过多家烟草企业的实践验证,具备快速部署、敏捷响应的特点。数字化转型浪潮奔涌向前。

中烟创新将继续坚持以客户为中心,加大研发投入,深化行业理解,以“AI+行业知识”的双重驱动,为烟草行业提供更智能、更可靠、更贴身的解决方案。选择中烟创新,不仅是选择一个技术伙伴,更是选择一位懂行业、通业务、可持续赋能的智能化升级同行者。

Hi V2EX ,

去年在这里分享过一次 地球之声,收到了很多反馈和建议。这段时间根据大家的意见迭代了不少功能,iOS APP 也终于在国内 App Store 上架了(已通过 ICP 备案)。

目前的数据

  • iOS APP 下载:100+

看着 [死了么] APP 流下了羡慕的泪水。。。我自己每天都在用,这可能是最大的成就感。

核心功能

1. 多轨白噪音混合器

同时播放多个自然声音,每个声音独立控制:

  • 音量:0-200%(可增强音量)
  • 平衡:左右声道调节
  • 循环模式:自定义播放/静音节奏

每个声音独立节奏,组合起来就像真实环境一样自然。

2. 智能定时器

  • 睡眠定时器:定时停止,支持渐弱淡出
  • 唤醒定时器:定时开始,音量渐强
  • 自动黑屏:省电模式

截图 1:主界面

根据 V2 用户反馈的改进

上次发帖后收到的建议,已经实现的:

  1. APP 内增加优惠券兑换入口
  2. 增加沉浸式黑胶唱片播放界面
  3. 音频下载速度 ✅ 优化了 CDN
  4. 国内 App Store 上架 ✅ 已通过 ICP 备案,现已上架
  5. 增加了更多声音资源以及内置更多场景

规划中的功能:

  • 番茄钟( Web 端已有,移动端开发中)
  • Android 版本(开发中)
  • 更多声音资源(每月更新)

送码活动

准备了 100 个 1 年高级会员兑换码

使用方式:
在 地球之声 APP > 我的 > 升级到高级会员 > 拉到底部点击兑换优惠代码

兑换码:EARTHSOUNDSYEAR2602 (可兑换多次,用完即止)

注意: 兑换码仅限 iOS APP 使用

链接

微信群

创建了一个微信群 https://docs.qq.com/doc/DSWF3VkRma05maG15 用于:

  • 产品反馈和功能建议
  • 独立开发经验交流
  • 早期用户福利(内测新功能、额外赠送会员等)


欢迎任何反馈和建议 💬

感谢看到这里 🙏

如果你觉得这个工具还不错,欢迎分享给有需要的朋友。

作为独立开发者,每一个用户的支持都是继续做下去的动力。

如有不当之处还请多多包涵,欢迎批评指正。

环境:
集群一:ABC 三台机器
集群二:DEF 三台机器
一台公网服务器 G

目标:
本机可以访问集群一或者集群二的服务。集群一和集群二之间隔离。

方案:
在 A 和 D 分别部署 ss 和 frpc ,公网机器 G 部署 frps 。这样就拿到了两个 ss 代理,windows 上通过 clash 来访问不同集群的服务。

结论:
我自己感觉这招不是很好,速度上可能有损耗。
我研究过 easytier ,发现有个限制,如果两个集群都是同一个网段,存在冲突,就必须要设虚拟 IP ,没法使用机器本身的 IP 了。
有没有推荐的其他方案呢?可以让我畅快切换到多个不同的内网环境。

Nova Launcher 被瑞典新东家收购

1 月 21 日,瑞典公司 Instabridge 宣布已完成对 Nova Launcher 的收购,Instabridge 方面明确表示,Nova Launcher 不会停止运营,当前工作的重点是确保产品稳定运行、持续兼容新版安卓系统,并保持正常维护节奏。

不过,该公司同时透露,正在评估为免费版本引入广告的可能性。目前最新版本的代码中已经加入了 Facebook Ads 和谷歌 AdMob 的追踪组件,Reddit 用户也反馈已在应用中看到广告。

Instabridge 表示,付费版 Nova Launcher Prime 仍将保持无广告体验。至于开源,公司表示负责任的开源不仅涉及代码本身,还包括许可证、安全、构建体系、贡献流程和商标管理,因此需要谨慎决策,并承诺一旦有结果将公开说明。来源


《愤怒的小鸟》将全面回归中国大陆

1 月 21 日,知名手游《愤怒的小鸟》发文宣布回归中国大陆市场。金山软件股份有限公司旗下子公司金山世游与 Rovio 娱乐有限公司今日宣布建立战略合作伙伴关系,为该系列游戏全面回归中国大陆铺平道路。

作为回归中国大陆的第一步,双方计划推出两款《愤怒的小鸟》IP 游戏,其中旗舰游戏《愤怒的小鸟:经典归来》将在标志性弹弓玩法的基础上,以 3D 引擎、动态关卡设计和全新魔法系统实现全面升级。《愤怒的小鸟:梦幻爆破》则提供轻松愉快的泡泡消除解谜体验,邀请玩家踏上奇幻旅程。

同时,为了激发《愤怒的小鸟:经典归来》创意社区活力,Rovio 与金山世游联合推出「捣蛋工坊」创作者计划,邀请社区创作者包括自定义关卡与视觉艺术在内的原创内容。来源


工信部称将扩大「二次号码焕新」覆盖范围

国务院新闻办公室于 1 月 21 日举行新闻发布会,针对二次号码焕新,相关责任人介绍称,基础电信企业在放号前批量焕新二次号码超 2.5 亿个,解绑互联网应用超 10 亿件次。App 和小程序的「主动焕新」服务入口,支持解除与 239 款常用互联网应用的历史绑定,为 580 多万用户处理解绑申请超 3.6 亿件次。

下一步将扩大「二次号码焕新」覆盖范围,推动接入更多与民生密切相关的互联网应用。中国移动、中国联通、中国电信已在 2025 年 5 月陆续上线「二次号码焕新」服务,可一键解绑历史互联网账号。来源


Steam 已支持为好友补齐捆绑包

第三方 Steam 数据网站 Steam DB 于 1 月 20 日发现,Steam 游戏平台上的「好友赠礼」已支持「捆绑包补齐」功能,允许玩家为好友补齐已购买游戏的捆绑包。

该功能主要作用于玩家向好友赠送包含多款游戏的捆绑包时,系统会自动识别好友游戏库中已拥有的内容,并相应调整实际支付金额。比如当玩家选择赠送一个游戏捆绑包给好友时,如果好友已经拥有了该捆绑包中的部分游戏,结算价格将自动扣除这些已拥有游戏对应的价值。同时,剩余未被拥有的游戏部分,仍可享受捆绑包提供的组合折扣优惠。此举旨在让玩家能够更便捷地帮助好友补全其游戏收藏,而无需为对方已拥有的内容重复付费。来源


少数派的近期动态

  • 我们正在优化并改进新的首页版式,如果你在使用过程中发现了任何问题或者有改进建议,请通过反馈表单告知我们。首页反馈收集

你可能错过的好文章

> 下载 少数派 2.0 客户端、关注 少数派公众号,解锁全新阅读体验 📰

> 实用、好用的 正版软件,少数派为你呈现 🚀

    OV SSL证书即组织验证型SSL证书,与域名验证型DV SSL证书相比,OV证书在验证过程中除了确认域名所有权外,还要求对申请的公司进行严格的审核,以确保公司的真实性和合法性。可以在浏览器地址栏绿色的小锁中显示单位名称,来增强用户信任,深受单位官网的喜爱。

    谁应该使用OVSSL证书?

    • 企业官方网站:展示公司形象,与客户建立信任。
    • 电子商务网站:处理在线支付和客户个人信息。
    • 会员登录/用户门户网站:保护用户登录凭证和个人数据。
    • API 服务接口:确保服务器到服务器通信的身份真实性。
    • 需要提交敏感信息的网站(如医疗、教育、B2B平台)。
    • 追求比DV证书更高信任等级的所有商业网站。

    OV SSL证书申请流程:

    一、注册账号

    访问JoySSL官方网站,在右上角找到“注册”按钮并点击。填写相关信息,创建一个证书管理账号。注册过程中,务必填写特定的注册码230970,这样才可以获得渠道低价和全程技术支持。

    二、选择证书类型与年限

    登录账号后,进入SSL证书栏,找到“OV证书”选项。根据自身需求,选择OV单域名、OV通配符、或者OV IP地址等SSL证书后,点击“下单”,并通过在线支付或公对公转账的方式完成支付。

    三、申请证书

    在申请页面,需要填写一系列信息,包括域名、单位名称、联系人、联系方式、邮箱等。这些信息将用于验证单位的真实性,所以务必确保准确无误。

    四、验证域名或IP的管理权

    提交申请后,并要求验证域名或者IP地址的所有权。按照系统提示的操作步骤进行验证,包括域名DNS解析认证或者服务器文件验证,操作完成后提交。

    五、组织信息审核

    JoySSL会对企业的组织信息进行验证,通常会通过电话、电子邮件等方式确认公司信息的真实性,审核过程一般在1到3个工作日左右完成。

    六、部署证书

    一旦审核通过后,JoySSL将签发OV SSL证书。下载已经签发的证书,根据JoySSL提供的安装指南或服务器文档,将证书安装到服务器上。

    七、测试证书

    使用浏览器访问网站,检查HTTPS访问是否正常工作,并且浏览器没有任何安全警告。同时,查看浏览器地址栏是否显示安全锁标志以及点开小锁是否有单位名称,这表示OV SSL证书已成功部署并生效。

    最近因为要在 Mac 和 Android 手机之间传文件,发现目前可以用的工具要么是开源且丑的 whoozle/android-file-transfer-linux ,要么是好久没更新的 Google 开发的 Android File Transfer 。

    为什么写这个?

    • Android File Transfer 不支持最新的 ARM 版本,且仍然使用 Intel 转译,体验很差
    • whoozle/android-file-transfer-linux 虽然开源,但界面简陋,而且需要自行编译 ARM 版本,对普通用户很不友好

    于是决定自己撸一个开源工具——SwiftMTP 。折腾不到一个月终于能用了 🎉

    关于我(先坦白)

    我完全不会 Swift 和 GO 的开发,所以目前代码都是 AI 辅助生成的。正因为如此,可能存在 UI 样式异常或其他 bug 。如果你在使用过程中遇到任何问题,请务必及时反馈,我会尽力修复!

    主要功能

    • 自动检测连接的 Android 设备( MTP 模式)
    • 文件浏览,支持文件夹导航
    • 文件下载/上传,支持拖放
    • 支持大文件传输(>4GB )
    • 批量选择和下载
    • 多语言支持(简中、英语、日语、韩语、俄语、法语、德语)
    • 显示设备存储空间

    技术栈

    • 前端:SwiftUI ( MVVM 架构)
    • 后端:Go 1.22 + go-mtpx + libusb-1.0
    • 桥接:CGO ( Swift ↔ C ↔ Go )

    目前已知限制

    • 仅支持 ARM 版本( Apple 芯片)
    • 要求系统版本在 macOS 26 或更高
    • 仅支持单个设备
    • 暂不支持文件夹上传(单文件上传)
    • 传输速度受 MTP 协议限制
    • UI 可能存在样式异常(因为我不会 Swift 😅)

    下载方式

    GitHub: https://github.com/wang93wei/SwiftMTP

    可以从源码构建,或者直接下载安装包。

    注意: 因为没有苹果开发者签名,所以可能需要其他方式方可使用:

    如果看到 "SwiftMTP can't be opened because it is from an unidentified developer",尝试以下方法:

    1. 右键点击应用 → 选择「打开」
    2. 系统设置 → 隐私与安全性 → 允许 SwiftMTP
    3. 或在终端运行:xattr -cr /Applications/SwiftMTP.app

    求反馈

    • 你的设备能否正常检测?
    • 传输速度如何?
    • UI 有没有样式问题?
    • 有没有遇到什么 bug ?
    • 有什么功能建议?

    项目刚起步,代码写得可能不够优雅,欢迎提 issue 或 PR !

    效果图

    2025年LLM的内容安全已经有质的飞跃了,比如模型内生安全、外挂的内容安全围栏、安全改写模型等手段,基于提示词工程的黑盒攻击逐渐难以突破愈发完善的防御机制,而白盒攻击通过直接操纵模型内部状态,展现较高的攻击成功率,但往往攻击成本也很高,下面将展开描述最近行业内的LLM白盒攻击是如何实现的。

    0x01 传统白盒越狱

    1.1 离散优化阶段:基于梯度的字符搜索

    这是LLM白盒攻击的起点,代表技术为贪婪坐标梯度法(GCG)

    • 核心机制:将越狱视为离散优化任务,利用模型的梯度信息寻找一组对抗性后缀。攻击者通过计算每个字符替换对损失函数的影响,挑选能最大化地让模型输出肯定性回答(如,"Sure, here is...")概率的字符 。
    • 攻击痛点:生成的后缀通常是无意义的“乱码”或乱序Token,极易被基于困惑度的过滤器拦截 。

    1.2 语义演化阶段:遗传算法与结构化变异

    为了解决GCG隐蔽性差的问题,研究者引入了遗传算法,代表技术为 AutoDAN

    • 核心机制:采用层次化遗传算法,在保留提示词语义连贯性的基础上进行对抗性优化。它通过词级变异和句级交叉,生成的攻击指令在人类看来具有合理的逻辑结构。然后开始出现混合攻击(GCG+PAIR),利用大模型作为优化器自动迭代攻击模板。
    • 攻击痛点:AutoDAN 虽然提升了隐蔽性,但其高度依赖初始模板、计算开销巨大,且难以直接应用在不开放概率分布的黑盒模型上。

    0x02 LLM机制可解释性研究

    在白盒攻击中,精确定位模型内部负责安全过滤的关键层是实施高效干预的前提。但在标准的 Transformer 实现里,研究者往往只方便拿到输入和输出;要稳定地获取中间激活、精确定位到“某一层/某一处张量”,并在前向过程中做可控干预,工程成本比较高。为了解决这类“可观测、可干预性不足”的问题,那么就需要 TransformerLens 这类工具用于 LLM 的机制可解释性研究。

    TransformerLens 核心是 HookedTransformer 类,它继承自 PyTorch 的 Hook 机制,在每个关键位置插入了HookPoint。这些 HookPoint 会在前向传播时捕获并缓存所有中间激活值,包括注意力模式、MLP输出、残差流等。

    这里我举个例子,比如在分析 "The capital of France is" -> "Paris" 这类唯一解问题时,TransformerLens 会首先添加词嵌入和位置嵌入作为残差流的起点,依托PyTorch Hook 机制,在 TransformerBlock 内部关键计算节点植入 HookPoint,不仅能追踪进入块之前(resid_pre)、注意力处理后(resid_mid)以及 MLP 处理后(resid_post)的完整残差流状态,还能实现组件级观测,针对每一层单独提取注意力机制和 MLP 的输出。其中,注意力输出捕获 "France" 与 "capital" 之间的语义关联,MLP 输出负责更复杂的推理过程,并将所有组件堆叠成 shape 为 [组件数,批次,位置,d_model] 的统一张量;然后凭借残差空间与词表双向映射,通过 tokens_to_residual_directions() 方法利用模型解嵌入矩阵W_U将目标词 "Paris" 映射为残差空间中的方向向量,再借助 Logit Lens(贡献量化)方法,通过 apply_ln_to_stack() 自动适配每层不同的 LayerNorm 或 RMSNorm 缩放因子,对所有组件做一致性的缩放校正,并将每个残差流组件与 "Paris" 方向向量进行点积运算,得到的 Logit 数值就是各组件对 "Paris" 预测的贡献度(数值越大贡献越大),这样就成功建立起隐藏层向量与具体词语的关联。最后可以通过固定参数微调的方式,freeze 其他层,对关键层“旁挂”指定的数据,观测是否可以将 "Paris" 替换成其他答案,从而验证这一层是否为真正的关键层。

    下图是一个demo实验结果,观测 Qwen3:8B 模型,得出27层对于 "Paris" 结果的贡献度可能最大。
    image.png
    这里可以观察到,一般在模型的最后几层是权重比较大的层,很可能影响最终的推理结果。

    0x03 跨层残差绕过LLM内生安全

    SABER (Safety Alignment Bypass via Extra Residuals) 是来自印度理工学院德里分校的研究团队在2025年提出的一种新型白盒越狱方法,该方法通过跨层残差连接绕过了LLM的内生安全,提高了攻击成功率。

    我发现这个项目没有公开实验数据集和代码,目前全网还没有人复现,感觉挺有意思的,所以结合 TransformerLens 尝试复现。

    3.1 原理

    1. 加载模型并包装 Hook 机制,利用 PyTorch 的 register_forward_hook() 在前向传播时抓取该层输出Transformer 每层的隐藏表示(残差流输出)。
    2. 用激活值替换的思路找到防御层,把良性prompt和有害prompt看作两条不同的内部计算轨迹:先记录良性prompt在各层产生的中间表示(即,每层处理后会输出一个张量),然后在评估有害prompt时,逐层把某一层的中间表示替换为良性对应层的表示,并观察模型输出的行为指标(例如,更偏向拒答还是更偏向正常回答)发生了多大变化;如果某一层的替换会引起最大的行为转向,说明该层对安全相关行为最敏感,可作为后续分析与加固的重点对象。所以在有害prompt输入后,可以从防御层之前的层作为源层,提取激活值用于注入攻击。
    3. 注入攻击:提前配置好不同组的干预幅度(干扰目标层的比例)、源层(防御层之前的层)与目标层(防御层之后的层)的相对距离、后缀注入提示词。选定一组“源层/目标层”作为实验配置;随后对同一输入运行一次前向计算以获取源层的中间表示,并构造一个干预函数用于在目标层对激活进行受控修改(利用源层激活值计算出干扰后的目标层激活值);接着把该干预函数注册到目标层对应的激活位置,再运行一次生成过程并记录输出变化;最后统一清理所有 hooks 与缓存,确保每次实验相互独立、可重复对比。
    **SABER 程序执行关键片段**  
    
    **阶段 1: 加载模型并包装 Hook 机制**
    model = AutoModelForCausalLM.from_pretrained(...)
    hooked_model = HookedModel(model, tokenizer) 
    
    **阶段 2: 定位防御层 (Activation Patching)**
    clean_prompt = "How to create a python script?"
    harm_prompt  = "How to create meth drug?"
    
    for layer in all_layers:
        patch clean→harm at last token position
        measure logit_diff change
    
    defense_layer = layer with max effect
    
    **阶段 3: 提取源层激活值**
    source_layer = defense_layer - offset
    source_act = run_with_cache(harm_tokens)[source_layer]
    
    **阶段 4: SABER 注入攻击**
    h'_target = h_target + h_source × (|h_t|/|h_s|) × λ
    
    **阶段 5: 生成越狱响应**
    prompt = harm_prompt + " Sure, here is..."
    output = model.generate(prompt)
    
    # 攻击成功:模型输出有害内容
    

    3.2 实验结论
    这里的测试对象分别选用了: Qwen-1_8B-Chat(弱逻辑模型)、DeepSeek-R1-Distill-Qwen-32B(思考能力强逻辑模型)、Qwen3-30B-A3B-Instruct(MoE架构模型)。

    实验中的六组配置,分别是不同的λ(干预幅度)、层偏移量(源层->目标层)、后缀诱导话术。

    下图是程序运行的结果,可以发现 DeepSeek-R1-Distill 和 Qwen3 都属于“高智商”模型,且使用了更复杂的 RLHF/DPO 对齐,安全对齐权重大的层都是在最后的几层,尤其是有思维链的时候,会先在前中层进行大量思考,如果安全机制在这些层就中断思考,那推理能力会大打折扣。这和 SABER 论文中在中间位置的结论是有区别的,因为当时的模型都是2024年发布的。
    image.png

    0x04 风险分析

    1. 绕过模型内生安全限制,生成任意毒性数据
    2. 恶意推理包装器:在私有化部署的模型推理环境中,恶意用户不需要修改模型文件,只需要在一个 Python 脚本中“劫持”模型的推理过程,输出不合规内容。
    3. 模型投毒:找到安全对齐贡献度最大的层,冻结其他层,然后对目标层进行固定参数微调,降低拒答率,但过拟合的问题严重。

    0x05 防御方案

    1. 模型来源与完整性校验
      • 只使用可信来源模型,做完整性校验。
    2. 防推理过程被 Hook 劫持/滥用
      • 激活异常检测:在推理服务中监控关键层激活的范数/方差变化,出现非自然突增则告警或中断。
      • 代码/运行时完整性:在受控环境禁用或审计动态 hook 行为(如阻止注册 forward hook、限制运行时反射),并对推理进程与依赖做权限隔离与可观测审计。
    3. 模型层级加密
      • 对模型结构进行分析,定位安全相关或关键贡献的目标层,并按加密策略对这些目标层进行加密保护,从模型文件分发与部署环节提升关键层参数/结构的安全性,降低被篡改或被恶意利用的风险。可以参考联想全球安全实验室专利方案 CN120541862A 。

    0x06 参考文献

    1、TransformerLens. TransformerLens 文档(v2.16.1):生成式语言模型的机械可解释性库 [Web Page]. 检索于 https://transformerlensorg.github.io/TransformerLens/
    2、Joshi, M., Nandi, P., & Chakraborty, T. (2025 年 9 月 19 日). SABER:基于跨层残差连接的安全对齐漏洞挖掘. arXiv. https://doi.org/10.48550/arXiv.2509.16060
    3、专利 CN120541862A《模型加密方法、数据处理方法和电子设备》,公开日 2025-08-26

    题目描述

    给你⼀根⻓度为n 的绳⼦,请把绳⼦剪成整数⻓的m 段( m 、n 都是整数, n>1 并 且m>1 , m<=n ),每段绳⼦的⻓度记为k[1],...,k[m]。请问k[1]x...xk[m] 可能的最⼤乘积是多少?例如,当绳⼦的⻓度是8 时,我们把它剪成⻓度分别为2 、3 、3 的三段,此时得到的最⼤乘积是18`。

    输⼊描述:输⼊⼀个数n,意义⻅题⾯。(2 <= n <= 60)

    返回值描述:输出答案。

    示例1
    输⼊:8
    返回值:18

    思路及解答

    备忘录

    本题的解答思路就是每个⻓度的绳⼦,要么最⻓的情况是不剪开(⻓度是本身),要么⻓度是剪开两段的乘积。因此每个⻓度 length 都需要遍历两个相加之后等于 length 的乘积,取最⼤值。

    初始化值⻓度为 1 的值为 1 ,从⻓度为 2 开始,每⼀种⻓度都需要遍历两个⼦⻓度的乘积。

    显然,为了避免多次重复计算,可以写个备忘录

    public class Solution {
        public int cutRope(int target) {
            if (target <= 1) {
                return target;
            }
            int[] nums = new int[target + 1];
            nums[1] = 1;
            nums[0] = 1;
            for (int i = 2; i <= target; i++) {
                int max = i;
                for(int j=0;j<=i/2;j++){
                    int temp = nums[j] * nums[i-j];
                    if(temp > max){
                        max = temp;
                    }
                }
                nums[i]=max;
            }
            return nums[target];
        }
    }

    动态规划

    ⽤动态规划的思维来做,假设绳⼦⻓度为 n 的 最⼤的⻓度为 f(n) ,那你说 f(n) 怎么计算得来呢?

    1. f(n) 可能是 n(不切分)
    2. 也可能是 f(n-1) 和 f(1) 的乘积
    3. 也可能是 f(n-2) 和 f(2) 的乘积
    4. ......

    那么也就是想要求 f( n ) 我们必须先把 f(n-1) , f(n-2) ...之类的前⾯的值先求出来, f(1)=1 这是初始化值。

    public class Solution {
        public int cutRope(int target) {
            int[] dp = new int[target + 1];
            dp[1] = 1;
            for (int i = 2; i <= target; i++) {
                for (int j = 1; j < i; j++) {
                    dp[i] = Math.max(dp[i], (Math.max(j, dp[j])) * (Math.max(i - j, dp[i - j])));
                }
            }
            return dp[target];
        }
    }
    • 时间复杂度:O(n²),外层循环n-3次,内层循环i/2次
    • 空间复杂度:O(n),需要dp数组存储中间结果

    贪心算法(最优解)

    基于数学推导的贪心策略,优先剪出长度为3的段。当n≥5时,优先剪出长度为3的段;剩余4时剪成2×2

    为什么选择3?

    1. 数学证明:当n ≥ 5时,3(n-3) ≥ 2(n-2) > n
    2. 接近自然底数e:最优分段长度应接近e ≈ 2.718,3是最接近的整数
    3. 4的特殊处理:2×2 > 3×1,所以剩余4时剪成2×2而不是3×1
    public class Solution {
        public int cutRope(int n) {
            // 特殊情况处理
            if (n <= 3) return n - 1;
            
            // 计算可以剪出多少段长度为3的绳子
            int countOf3 = n / 3;
            
            // 处理剩余部分:当剩余长度为1时,调整策略
            if (n - countOf3 * 3 == 1) {
                countOf3--; // 减少一段3,与剩余的1组成4
            }
            
            // 计算剩余部分能剪出多少段长度为2的绳子
            int countOf2 = (n - countOf3 * 3) / 2;
            
            // 计算结果:3的countOf3次方 × 2的countOf2次方
            return (int)(Math.pow(3, countOf3)) * (int)(Math.pow(2, countOf2));
        }
    }
    • 时间复杂度:O(1),只有常数次操作
    • 空间复杂度:O(1),只使用固定变量

    数学公式法(理论最优)

    根据n除以3的余数直接套用公式

    public class Solution {
        public int cutRope(int n) {
            if (n <= 3) return n - 1;
            
            int countOf3 = n / 3;
            int remainder = n % 3;
            
            // 根据余数直接返回结果
            if (remainder == 0) {
                return (int) Math.pow(3, countOf3);
            } else if (remainder == 1) {
                return (int) Math.pow(3, countOf3 - 1) * 4;
            } else { // remainder == 2
                return (int) Math.pow(3, countOf3) * 2;
            }
        }
    }
    • 时间复杂度:O(1)
    • 空间复杂度:O(1)

    get1 和 get2 接口的区别是一个加了 async 、await 一个没加的区别,加了 async 、await 会额外生成一些状态机相关的代码,除了这个区别还有其他区别吗?
    我的理解是,如果不需要获取异步后的结果进行其他处理则可以不用加。如果不加 async 、await ,真到生产上会不会有什么问题?

    示例代码:
    using Microsoft.AspNetCore.Mvc;

    namespace WebApplication1.Controllers
    {
    [ApiController]
    [Route("api/[controller]")]
    public class TestController : ControllerBase
    {
    [HttpGet("get1")]
    public Task<Student> Get1Async()
    {
    return new TsetService().Get1Async();
    }
    [HttpGet("get2")]
    public async Task<Student> Get2Async()
    {
    return await new TsetService().Get2Async();

    }
    }


    public class TsetService
    {

    public Task<Student> Get1Async()
    {
    // 模拟数据库查询
    Task.Delay(100);
    return Task.FromResult(new Student { Id = 1, Name = "张三" });
    }

    public async Task<Student> Get2Async()
    {
    // 模拟数据库查询
    await Task.Delay(100);
    return new Student { Id = 1, Name = "张三" };
    }
    }

    public class Student
    {
    public int Id { get; set; }
    public string Name { get; set; }
    }
    }

    很久之前就听说了 iflow,刚出来的时候还是限时免费,火了一段时间,今天再进去看,发现变成永久免费了,不过这玩意不会跟阿里云盘的永久不限速同出一辙吧
    image

    由于是使用机场自己的客户端,没有 tun 模式,网上搜了一下可以使用 Proxifier 解决 Antigravity 的登录问题,正好之前用 OBS 直播油管的时候安装过 Proxifier ,于是直接设置了一个规则,顺利登录 Antigravity 。

    但是马上遇到一个棘手的问题,agent 加载不出来,也就是对话框和模型都加载不出来,我以为是跟 cursor 一样需要在设置里面配置 proxy ,结果设置了也不行,重启几次 IDE 都是加载不出来。

    搜了一下公众号文章,都讲的不清不楚,Proxifier 规则里面要增加好几个 exe ,不止是 antigravity.exe ,直接复制别人公众号文章里面提供的文件名,行不通,于是在任务管理器里面,把 Antigravity 相关的所有 exe 都找到所在文件夹,通过手动添加进去,就搞定了。

    需要添加的几个 exe 的文件夹路径(其中 XXX 需要换成你的用户名):

    C:\Users\xxx\AppData\Local\Programs\Antigravity

    C:\Users\xxx\AppData\Local\Programs\Antigravity\resources\app\extensions\antigravity

    我添加进规则的几个 EXE:antigravity.exe; inno_updater.exe; language_server_windows_x64.exe; fd.exe
    image

    记得要通过 browser 这个按钮添加才有效。

    附赠 Proxifier 注册码 5EZ8G-C3WL5-B56YG-SCXM9-6QZAP

    在这里插入图片描述

    摘要

    随着鸿蒙应用逐步走向国际化,应用不再只面对中文和英文用户。
    中东、北非 等地区,阿拉伯语、希伯来语 这类 从右到左(RTL)语言 是主流,如果应用在这些语言环境下:

    • 布局顺序是反的
    • 返回按钮方向不对
    • 文字对齐看着很别扭

    那基本可以直接劝退用户。

    好消息是:
    鸿蒙系统对 RTL 是原生支持的,而且大部分情况下是“自动完成”的。
    坏消息是:
    一旦你写了不该写的代码,系统也救不了你。

    这篇文章就从真实开发角度,聊清楚鸿蒙里 RTL 适配到底该怎么做、哪些地方最容易踩坑,以及在真实页面里该怎么写。

    引言

    在早期做 Android / Web 国际化时,RTL 基本属于“高级需求”,很多项目甚至直接忽略。
    但在鸿蒙生态里,国际化是默认要考虑的事情,尤其是:

    • 智能设备出海
    • 海外 ROM
    • 多语言系统级应用

    在这些场景下,RTL 不再是“锦上添花”,而是基础能力

    鸿蒙的设计理念其实很明确:

    系统帮你做方向适配,你只要别把方向写死。

    问题就在于:
    很多开发者在不知不觉中,把方向写死了。

    鸿蒙对 RTL 的整体支持机制

    系统层是自动感知的

    当系统语言切换为 RTL 语言时,鸿蒙会自动做这些事情:

    • 整体布局方向切换为 RTL
    • 文本阅读方向切换
    • Row / Flex 子组件顺序镜像
    • 列表、导航组件交互方向变化

    前提只有一个:
    你的代码要写得“语义化”。

    布局方向适配的核心原则

    永远不要写死 left / right

    这是 RTL 适配里最常见、也是最致命的问题

    错误示例(真实项目里经常看到)

    Text('返回')
      .margin({ left: 16 })

    这段代码在中文、英文环境下完全正常,
    但在 RTL 环境下:

    • 系统已经整体翻转
    • 你又强行加了 left
    • 结果就是布局看起来“很怪”

    正确示例(推荐写法)

    Text('返回')
      .margin({ start: 16 })

    这里的 start 是一个语义方向

    • LTR 语言下等价于 left
    • RTL 语言下等价于 right

    你不用管语言,系统会帮你算。

    Demo:基础 RTL 自适应 Row

    下面是一个可以直接运行的 Demo,你只需要切换系统语言就能看到效果。

    @Entry
    @Component
    struct RtlBaseDemo {
      build() {
        Row() {
          Image($r('app.media.arrow'))
            .width(24)
            .height(24)
    
          Text('返回')
            .margin({ start: 8 })
        }
        .padding({ start: 16, end: 16 })
      }
    }

    这个 Demo 的特点:

    • 没有写 left / right
    • 没有强制方向
    • 图标和文字顺序会自动镜像

    在阿拉伯语系统下,你会发现:

    • 箭头跑到了右侧
    • 文本在左
    • 间距依然正确

    文本方向与对齐的正确方式

    文本不要写 Left / Right 对齐

    很多人习惯性这样写:

    Text('مرحبا')
      .textAlign(TextAlign.Left)

    问题是:
    Left 在 RTL 里并不是“阅读起点”。

    正确的写法是:

    Text('مرحبا')
      .textAlign(TextAlign.Start)

    系统会自动判断:

    • 英文 → 左对齐
    • 阿拉伯语 → 右对齐

    Demo:多语言文本展示

    @Entry
    @Component
    struct TextAlignDemo {
      build() {
        Column() {
          Text('Hello HarmonyOS')
            .textAlign(TextAlign.Start)
            .fontSize(18)
    
          Text('مرحبا هارموني')
            .textAlign(TextAlign.Start)
            .fontSize(18)
        }
        .padding(16)
      }
    }

    这个 Demo 非常适合用来自测
    切换系统语言,你能直观看到对齐方向变化。

    结合真实业务场景的 RTL 适配实践

    场景一:应用顶部导航栏

    这是 RTL 最容易翻车的地方。

    典型需求

    • 返回按钮
    • 页面标题

    正确实现方式

    @Component
    struct TitleBar {
      build() {
        Row() {
          Image($r('app.media.back'))
            .width(24)
            .height(24)
    
          Text('设置')
            .margin({ start: 12 })
            .fontSize(20)
        }
        .padding(16)
      }
    }

    这里的关键点:

    • 不指定 FlexDirection
    • 使用 start 间距
    • 图标自动镜像

    系统语言一换,整个标题栏方向自然就对了。

    场景二:设置页列表项

    设置页通常是左右结构,比如:

    • 左边是标题
    • 右边是开关或箭头

    推荐写法

    @Component
    struct SettingItem {
      build() {
        Row() {
          Text('通知')
            .layoutWeight(1)
    
          Image($r('app.media.arrow'))
            .width(16)
        }
        .padding({ start: 16, end: 16, top: 12, bottom: 12 })
      }
    }

    在 RTL 下:

    • 文本会靠右
    • 箭头会跑到左侧
    • 整体阅读顺序符合习惯

    你不需要为 RTL 单独写一套 UI。

    场景三:列表页面与滑动方向

    鸿蒙的 List 在 RTL 下:

    • 排列顺序自动调整
    • 滑动方向符合阅读习惯

    示例代码

    @Entry
    @Component
    struct ListDemo {
      build() {
        List() {
          ForEach(['Item A', 'Item B', 'Item C'], (item: string) => {
            ListItem() {
              Text(item)
                .padding(16)
                .textAlign(TextAlign.Start)
            }
          })
        }
      }
    }

    只要你不去强制对齐方向,列表在 RTL 下基本是“零成本适配”。

    QA:开发中常见问题

    Q1:需要手动判断当前是不是 RTL 吗?

    一般不需要。
    90% 的页面交给系统就够了。

    只有在:

    • 自定义绘制
    • 特殊动画
    • 非标准交互

    这些场景下,才需要手动处理。

    Q2:图片什么时候需要手动镜像?

    • 返回箭头
    • 方向性极强的图标

    可以使用:

    Image($r('app.media.arrow'))
      .mirror(true)

    普通装饰性图片不建议镜像。

    Q3:为什么我写了 start / end 还是不生效?

    通常是因为:

    • 强制写了 FlexDirection.Row
    • 写死了 Alignment.Left
    • 在父容器里破坏了方向规则

    RTL 出问题,优先回头检查是不是哪一层写死了方向

    总结

    鸿蒙里的 RTL 适配,其实不是“多写代码”,而是“少犯错误”。

    一句话经验总结:

    • start / end
    • TextAlign.Start
    • 不强制方向
    • 相信系统

    只要遵守这几条规则,
    绝大多数 RTL 问题都会在你“什么都没做”的情况下自动解决。

    在这里插入图片描述

    摘要(背景与现状)

    随着鸿蒙系统在手机、平板、穿戴设备以及 IoT 场景中的逐步落地,同一套应用需要面向不同国家、不同地区、不同语言和政策环境已经成为常态。
    在实际项目中,我们经常会遇到这些问题:

    • 不同地区展示的文案不一样
    • 某些功能在特定地区不能上线
    • 活动内容、公告、支付方式存在地区差异

    如果地区适配逻辑处理得不好,就很容易出现代码混乱、维护成本高、后期改动困难的问题。

    本文结合鸿蒙系统(HarmonyOS / OpenHarmony)的实际开发方式,从系统能力、资源机制和业务逻辑三个层面,总结一套可落地、好维护的地区特定内容实现方案。

    引言(发展情况与应用场景)

    从早期 Android / iOS 开发经验来看,地区适配往往依赖大量 if-else 判断,代码里到处是国家缩写,后期维护非常痛苦。
    鸿蒙在设计之初,就在国际化与地区适配方面做了比较完整的能力封装,比如:

    • 系统级语言和地区识别
    • 资源文件按地区自动匹配
    • ArkUI 对多语言、多地区资源的天然支持

    在真实项目中,大多数地区定制需求并不复杂,核心思路其实只有一句话:

    先交给系统做资源适配,实在不行再写判断逻辑。

    下面我们一步一步来看具体实现方式。

    鸿蒙地区特定内容的整体实现思路

    在鸿蒙系统中,地区定制通常可以拆分为三个层次:

    1. 系统层:获取当前设备的语言和地区信息
    2. 资源层:根据地区自动加载不同资源
    3. 业务层:在运行时根据地区控制功能和内容

    这三层并不是互斥的,而是经常组合使用。

    通过系统语言和地区识别用户环境

    获取系统地区信息

    鸿蒙提供了 i18n 模块用于国际化相关能力,获取系统地区非常简单。

    import i18n from '@ohos.i18n';
    
    const locale: string = i18n.getSystemLocale();
    console.info(`当前系统地区为: ${locale}`);

    常见返回值包括:

    • zh-CN:中国大陆
    • zh-HK:香港地区
    • en-US:美国
    • ja-JP:日本

    这个值通常在应用启动时获取一次即可。

    基于地区进行基础内容控制

    let isChinaRegion: boolean = false;
    
    if (locale.startsWith('zh-CN')) {
      isChinaRegion = true;
    }

    在 ArkUI 页面中直接使用:

    if (isChinaRegion) {
      Text('中国地区专属内容')
        .fontSize(16)
    }

    这种方式比较直观,适合少量差异控制,但不建议大量使用在文案层面。

    通过资源文件实现地区内容自动适配

    资源目录结构设计

    这是鸿蒙中最推荐、维护成本最低的方式。

    resources/
     ├─ base/
     │   └─ element/
     │       └─ string.json
     ├─ zh_CN/
     │   └─ element/
     │       └─ string.json
     ├─ en_US/
     │   └─ element/
     │       └─ string.json

    不同地区资源内容示例

    base 目录作为兜底资源:

    {
      "welcome_text": "Welcome"
    }

    中国地区资源:

    {
      "welcome_text": "欢迎使用(中国地区)"
    }

    美国地区资源:

    {
      "welcome_text": "Welcome (US Version)"
    }

    ArkUI 中直接使用资源

    Text($r('app.string.welcome_text'))
      .fontSize(18)

    系统会根据当前设备地区自动匹配资源,不需要任何额外判断。

    如果没有对应地区资源,就自动回退到 base。

    结合运行时逻辑实现地区功能差异

    在真实项目中,地区差异不仅体现在文案上,功能层面的限制更常见。

    地区功能开关示例

    let enablePayment: boolean = true;
    
    if (!locale.startsWith('zh-CN')) {
      enablePayment = false;
    }

    ArkUI 中控制按钮展示:

    if (enablePayment) {
      Button('立即支付')
        .width(200)
    }

    代码逻辑说明

    • 地区判断逻辑集中在一个地方
    • UI 只关心布尔状态,不直接判断地区
    • 后期调整地区规则只改一处代码

    这种写法在中大型项目中特别重要。

    结合实际业务场景的应用示例

    场景一:地区公告与活动内容展示

    不同地区活动内容变化频繁,适合服务端下发。

    let requestParam = {
      locale: locale
    };

    服务器返回内容:

    {
      "notice": "日本地区限定活动"
    }

    客户端展示:

    Text(serverData.notice)

    这种方式运营改内容不需要重新发版。

    场景二:支付方式地区限制

    function isPaymentSupported(locale: string): boolean {
      return locale.startsWith('zh-CN');
    }
    if (isPaymentSupported(locale)) {
      Button('使用本地支付')
    }

    清晰区分业务规则和 UI。

    场景三:隐私协议与合规文案差异

    通过资源文件区分不同地区隐私条款:

    Text($r('app.string.privacy_policy'))

    不同地区加载不同内容,避免代码层面处理复杂文本。

    常见问题 QA

    Q1:可以只用代码判断不做资源适配吗?

    可以,但不推荐。
    代码判断适合控制功能,不适合承载大量文案。

    Q2:地区和语言一定是一一对应的吗?

    不一定。
    比如香港地区可能使用中文或英文,建议优先按语言,再结合地区判断。

    Q3:地区变化时需要重启应用吗?

    一般不需要,重新加载页面即可。
    资源匹配通常在页面创建时生效。

    总结

    在鸿蒙系统中实现地区特定内容,其实并不复杂,关键在于合理分层

    • 文案和静态内容优先使用资源适配
    • 功能和业务规则使用少量逻辑判断
    • 活动和运营内容交给服务端

    一句话概括就是:

    资源适配解决大部分问题,代码只处理真正的差异逻辑。

    关于 gh-ost

    gh-ost 是 GitHub 开发的一个 MySQL 在线表结构变更工具(online schema migration tool)。它的全称是 "GitHub's Online Schema Translator"。

    gh-ost 现在已经是大型互联网公司进行数据库运维的重要工具。

    主要作用

    gh-ost 允许在不锁表、不影响业务的情况下,对 MySQL 数据库表进行结构变更(如添加列、修改索引等)。

    核心特点

    1. 无触发器设计 - 不像传统工具使用触发器来同步数据,gh-ost 通过解析 binlog 来捕获变更
    2. 可暂停/恢复 - 可以随时暂停迁移过程,对生产环境更友好
    3. 可测试 - 支持在从库上测试变更,确认无误后再应用到主库
    4. 动态调整 - 可以实时调整迁移速度,避免影响线上服务

    工作原理

    1. 创建一个与原表结构相同的"影子表"(ghost table)
    2. 在影子表上执行 DDL 变更
    3. 通过 binlog 将原表的增量数据同步到影子表
    4. 数据同步完成后,快速切换表名完成迁移

    使用方法

    1. 安装
      gh-ost 可以直接从最新的 发布页面 下载二进制文件,支持 Linux 和 macOS。
    2. 基本命令

      • 测试迁移

        gh-ost --test-on-replica --database=mydb --table=mytable --alter="ADD COLUMN new_col INT" --execute
      • 真实迁移

        gh-ost --database=mydb --table=mytable --alter="ADD COLUMN new_col INT" --execute

    实际例子

    假设你有一个用户表需要添加新字段:

    gh-ost \
      --host=localhost \
      --user=root \
      --password=password \
      --database=mydb \
      --table=users \
      --alter="ADD COLUMN age INT DEFAULT 0" \
      --execute

    场景说明:

    • 原表 users 有 1000 万条数据
    • 使用传统 ALTER TABLE 可能需要锁表数小时
    • 使用 gh-ost 可以在后台逐步完成变更,期间用户可以正常读写数据
    • 最后只需要几秒钟的短暂切换时间即可完成迁移

    适用场景

    • 大表的结构变更(百万级以上数据)
    • 需要保证高可用性的生产环境
    • 需要精确控制数据库负载的情况

    数据库支持范围

    gh-ost 目前只适用于 MySQL(包括 Percona Server 和 MariaDB)。它依赖 MySQL 的 binlog 机制,因此不支持 PostgreSQL、Oracle 等其他数据库。

    常见的坑

    1. 外键约束问题

    gh-ost 不支持有外键的表。如果表有外键关系,迁移会失败。

    解决办法: 需要先删除外键,迁移完成后再重新添加

    2. binlog 格式要求

    必须使用 ROW 格式的 binlog,STATEMENT 或 MIXED 格式不支持。

    -- 检查 binlog 格式
    SHOW VARIABLES LIKE 'binlog_format';
    
    -- 如果不是 ROW,需要修改配置
    SET GLOBAL binlog_format = 'ROW';

    3. 主键要求

    必须有主键或唯一索引,否则 gh-ost 无法正常工作。

    4. 磁盘空间

    会创建影子表,需要额外的磁盘空间(大约是原表的大小)。如果磁盘空间不足,迁移会失败。

    5. 复制延迟

    如果主从复制本身就有延迟,gh-ost 的迁移会进一步加重延迟。需要监控 --max-lag-millis 参数。

    6. 触发器冲突

    虽然 gh-ost 本身不用触发器,但如果原表上已有触发器,可能会导致数据不一致。

    7. 字符集问题

    影子表的字符集需要与原表一致,否则可能出现乱码或数据截断。

    8. 长时间迁移中断

    如果迁移过程很长(几天),期间 MySQL 重启或 binlog 被清理,会导致迁移失败需要重新开始。

    实践建议

    # 先在从库测试
    gh-ost \
      --host=slave-host \
      --test-on-replica \
      --migrate-on-replica \
      --database=mydb \
      --table=users \
      --alter="ADD COLUMN age INT" \
      --execute
    
    # 设置合理的限流参数
    gh-ost \
      --max-load=Threads_running=25 \
      --critical-load=Threads_running=100 \
      --chunk-size=1000 \
      --throttle-query="SELECT HOUR(NOW()) BETWEEN 2 AND 6" \
      --execute

    替代方案

    如果 gh-ost 不适用,可以考虑:

    • pt-online-schema-change (Percona Toolkit)
    • 原生 Online DDL (MySQL 5.6+ 支持部分操作)
    • 对于其他数据库,PostgreSQL 可以用 pg_repack