2026年4月

准备购买日区 apple one 家庭组。
之前听说国内的 jcb 可以订阅,最近搜了下,好像被封了。

现在只能买点卡了吗?有大佬知道,买点卡的话,怎么购买最划算呢,我有朋友在日本,可以买线下的点卡,线上的话 amazon 国内的 jcb 会被挡吗?

GitHub 中国区前100名,哪些是真开发者?哪些是Markdown工程师?

大家好,我是彪哥,

本次分析的数据来源于开源项目《中国区 GitHub 用户排行榜》,

仓库数据及分析来自开源工具《悟空 GitHub 数据分析工具》,

该项目也是我自己开发的,支持在线体验。

我们将把GitHub 用户分为两个类型来分析:开发者 和 Markdown 工程师。

image-20260420073129363

开发者第一名

image-20260420072911534

稚晖君。

image-20260420073314941

先看基础信息:

他的公开项目数量其实不算多,这说明他不是那种“到处 fork、到处点 star”的用户,而是亲自做项目输出的人。

粉丝数约 8 万左右,在 GitHub 上已经属于非常高的影响力。

对比他在 B 站的影响力,这个 GitHub 粉丝体量是匹配的。

注册时间是 2015 年,到 2026 年已经 11 年了。

image-20260420073325845

从语言分布来看,他主要使用:

C 语言(占比最高),

C++,

Java,

属于典型的硬件 / 系统 / 工程型开发者路线。

image-20260420073337460

他的项目整体质量非常高,

多个项目 star 数都在 1000+,

其中个别项目甚至达到 1w+ star,

属于典型“少而精”的风格,

说明他的产出不是数量驱动,而是质量驱动。

image-20260420073347573

image-20260420073400258

可以明显看到,他在 2021–2022 年是开发最活跃的阶段,这与他爆火时间基本一致。

之后整体更新频率下降,很多项目趋于停更状态。

本质原因也很现实:进入公司和工程化研发后,个人开源时间减少。

image-20260420073412066

他的大部分项目采用 GNU 系列协议(以及部分强开源约束协议),说明他对开源理念是比较坚定的,属于“强开源倾向”的开发者。

image-20260420074612848

他的项目大多是中文描述,也有少量英文项目。

整体来看的话,

中文社区贡献占主导,

项目在国内传播更强,

英文项目影响力相对有限。

开发者第二名

image-20260420074804889

廖雪峰。

image-20260420075054432

注册时间:2010 年,

到 2026 年:16 年 GitHub 资历,

仓库数:约 100 个,

总 star:约 2 万,

粉丝:约 3.8 万,

近半年仍保持活跃更新,

整体属于长期稳定输出型用户。

image-20260420075155949

主要技术:

Java,

Python,

属于典型的“教学 + 工程结合型开发者”。

image-20260420075224712

他的高 star 项目基本都是:

入门教程,

编程指南,

面向初学者的课程类内容,可以说明技术深度不是重点,教育价值更强一点。

image-20260420075457092

整体趋势是“长期增长 + 偶尔爆发”。

在某些月份会集中更新多个仓库,但整体节奏比较均衡。

image-20260420075617326

他也很喜欢用GNU,MIT和这个Apache这种比较宽松的协议占比是比较低的。

开发者第三名

image-20260420080120010

代码家。

看他博客的介绍,他是掘金的创始人,后来转型做投资。

image-20260420080356178

仓库数只有30,star量46000,平均每个也过千了。

12年注册,到26年的话,已经是14年了。

180天内更新的仓库只有两个,看来这些年是不太活跃了,不怎么写代码了。

image-20260420080447618

主要技术栈:

Java,

Python,

Android / 移动开发相关,

image-20260420080507436

他的高 star 项目主要集中在:

Android 开发工具,

移动端相关框架,

但近年来基本不再高频更新,安卓开发已经过时了。真是时代造英雄。

image-20260420080604561

开发高峰出现在 Android 黄金时期(约 2013 年)。说明他的成长路径和行业周期高度绑定。image-20260420080632932

约一半项目使用 MIT 协议,整体偏宽松开源。

第四名是程序员鱼皮,这两年比较火的程序员。

image-20260420080738490

第五名是云风,这个是真大佬。

image-20260420080754888

篇幅有限,榜单后面的就不一一列举了。

md工程师第一名

image-20260420081214439

阮一峰。

经常能搜到他的博客,seo做的真好。

image-20260420081323415

从基础信息来看,一共65个仓库,20万颗星。11年创立,到26年也已经有15年了。

180天内还更新了7个仓库,很有毅力。

image-20260420081407567

技术站主要以javascript为主,典型前端路线。

image-20260420081427071

核心影响力来源:

《科技爱好者周刊》,

技术博客,

教程类内容,

GitHub变成了技术内容分发平台。

image-20260420081515979

可以看到一直保持着一个非常平均的更新频率。峰值是18年。

image-20260420081540395

从 GitHub 结构来看:

代码比例较低,

文档 / 教程比例极高,

因此被归类为 Markdown 工程师是合理的。

md第二名404

不讲

md第三名

image-20260420081715026

李笑来。

有点意外,难道李笑来也做过程序员?

image-20260420081811718

09年就注册了,到26年已经是17年了,比前面提到的所有开发者注册时间都久。

image-20260420081923083

image-20260420082049271

他的 GitHub 更像:

出版平台,

知识仓库,

内容分发系统,

覆盖范围包括:投资,英语,成长类内容,编程内容。

本质是也是把GitHub变成了免费出版社。

技术只是工具,而不是核心目标。

md工程师第四名是halfrost,他的核心产出是《LeetCode Cookbook》,把算法题解做到了极致。

他是典型的“强代码能力 + 强文档输出”的结合体。

image-20260420082407380

第五名是迷渡,资深前端大牛,Deno 中文社区发起人。他不仅写文章,对开源协议、社区规范非常有研究。

image-20260420082500042

总结

整体来看,这个榜单可以总结为三类人:

① 真开发者

特点:

写代码为主,

项目驱动,

star 来自技术价值,

代表:稚晖君、代码家


② 教学型开发者

特点:

教程 / 面向初学者,

内容传播力强,

技术深度中等,

代表:廖雪峰


③ Markdown 工程师

特点:

写文章 > 写代码,

GitHub = 内容平台,

SEO + 传播能力强,

代表:阮一峰、李笑来

GitHub 前100名,其实不是“技术排名”,而是“影响力排名”。

最后,大家觉得 GitHub 榜单是应该看 Star 数,还是看 Contribution数?

欢迎在评论区交流。

另外,如果你也想看看自己的 GitHub 账户到底属于‘开发者’还是‘Markdown 工程师’,

欢迎去体验一下我开发的《悟空 GitHub 数据分析工具》。

抱拳了

感谢各位朋友捧场!要是觉得内容有有点意思,别客气,点赞、在看、转发,直接安排上!

想以后第一时间看着咱的文章,别忘了点个星标⭐,别到时候找不着了。

行了,今儿就到这儿。

image-20260420090729757

论成败,人生豪迈,我们下期再见!

视频生成流程

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构概览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排除指南
  9. 结论
  10. 附录

简介

本项目提供了一个完整的云端视频生成解决方案,基于剪映专业版的自动化控制实现。系统支持草稿创建、素材添加、视频生成、状态查询和结果下载等全流程功能。通过异步任务队列管理和剪映自动化控制,实现了稳定的云端渲染服务。

新增对非Windows平台的兼容性处理,当Windows依赖不可用时提供优雅降级机制。系统现在支持跨平台部署,包括Windows、Linux和macOS环境。

项目结构

项目采用典型的三层架构设计,包含API层、服务层和工具层:

graph TB
subgraph "API层"
Router[路由层]
Middleware[中间件层]
end
subgraph "服务层"
Service[业务服务层]
Schema[数据模型层]
end
subgraph "工具层"
TaskManager[任务管理器]
Downloader[草稿下载器]
MediaUtils[媒体工具]
Points[积分系统]
Controller[剪映控制器]
end
subgraph "配置层"
Config[配置管理]
Exceptions[异常处理]
end
Router --> Service
Middleware --> Router
Service --> TaskManager
Service --> Downloader
TaskManager --> Controller
TaskManager --> MediaUtils
TaskManager --> Points
Downloader --> Config
MediaUtils --> Config
Points --> Config

核心组件

系统的核心组件包括视频生成服务、任务管理器、草稿下载器和剪映控制器等关键模块。

视频生成服务

负责处理视频生成请求,验证参数并提交到任务队列:

  • 参数验证和草稿URL解析
  • API密钥验证和积分检查
  • 任务提交和状态跟踪
  • 错误处理和异常管理

任务管理器

实现异步任务队列管理,支持并发控制和状态跟踪:

  • 任务队列管理和调度
  • 并发执行控制和锁机制
  • 进度跟踪和状态更新
  • 资源清理和错误恢复
  • 平台兼容性检查:检测非Windows平台并提供降级处理
  • 跨平台支持:在Linux系统上使用UIAutomation占位符类

草稿下载器

处理剪映草稿文件的下载和管理:

  • 草稿文件列表获取
  • 多文件并行下载
  • 路径解析和文件写入
  • 目录扫描和缓存管理

剪映控制器

提供剪映应用程序的自动化控制:

  • 窗口状态检测和切换
  • 导出流程自动化
  • 分辨率和帧率设置
  • 错误处理和超时管理
  • 平台检测机制:在非Windows系统上抛出明确的导入错误
  • 依赖保护:在Linux系统上创建UIAutomation占位符类避免导入错误

架构概览

系统采用异步架构设计,通过任务队列实现高并发处理能力。新增平台兼容性检查机制:

sequenceDiagram
participant Client as 客户端
participant API as API网关
participant Service as 服务层
participant Manager as 任务管理器
participant PlatformCheck as 平台检查
participant Queue as 任务队列
participant Worker as 工作线程
participant Controller as 剪映控制器
participant Storage as 存储系统
Client->>API : 提交视频生成请求
API->>Service : 验证参数和权限
Service->>Manager : 提交任务到队列
Manager->>PlatformCheck : 检查平台兼容性
alt Windows平台
PlatformCheck-->>Manager : 平台可用
Manager->>Queue : 添加到任务队列
Worker->>Queue : 从队列获取任务
Worker->>Service : 处理任务
Service->>Controller : 导出视频
Controller->>Storage : 上传视频文件
else 非Windows平台
PlatformCheck-->>Manager : 返回错误信息
Manager-->>Service : 降级处理
Service-->>API : 返回平台不支持错误
end
API-->>Client : 返回处理结果
Note over Client,Storage : 异步处理流程

详细组件分析

视频生成API接口

提供完整的视频生成服务接口,支持异步处理和状态查询:

接口规范
  • 提交生成任务: POST /openapi/capcut-mate/v1/gen_video
  • 查询任务状态: POST /openapi/capcut-mate/v1/gen_video_status
  • 获取草稿列表: GET /openapi/capcut-mate/v1/get_draft
数据模型
classDiagram
class GenVideoRequest {
+string draft_url
+string apiKey
+validate_api_key()
}
class GenVideoResponse {
+string message
}
class TaskStatus {
<<enumeration>>
PENDING
PROCESSING
COMPLETED
FAILED
}
class VideoGenTask {
+string draft_url
+string draft_id
+TaskStatus status
+datetime created_at
+datetime started_at
+datetime completed_at
+string video_url
+string error_message
+int progress
+string api_key
}
GenVideoRequest --> GenVideoResponse
VideoGenTask --> TaskStatus
状态管理机制

任务状态采用四状态机设计,支持完整的生命周期管理:

stateDiagram-v2
[*] --> 等待中
等待中 --> 处理中 : 任务开始
处理中 --> 完成 : 成功导出
处理中 --> 失败 : 导出失败
完成 --> [*]
失败 --> [*]
note right of 等待中
任务已提交
进度 : 0%
end note
note right of 处理中
正在导出视频
进度 : 10-95%
end note
note right of 完成
导出成功
进度 : 100%
返回视频URL
end note
note right of 失败
导出失败
进度 : 0%
返回错误信息
end note

任务队列管理系统

实现高效的异步任务处理机制,支持并发控制和资源优化:

平台兼容性检查
  • 系统检测:使用 sys.platform.startswith('win') 检测Windows平台
  • 降级处理:非Windows平台直接返回"视频生成功能仅在Windows系统上可用"错误
  • 依赖保护:在Linux系统上创建UIAutomation占位符类避免导入错误
并发控制策略
  • 单实例模式: 确保任务管理器的唯一性
  • 处理锁机制: 防止同时导出多个视频
  • 导出锁机制: 保护剪映导出操作的互斥性
  • 工作线程管理: 自动启动和停止工作线程
任务调度算法
flowchart TD
Start([任务提交]) --> Validate[验证草稿URL]
Validate --> ExtractDraftId[提取草稿ID]
ExtractDraftId --> CheckExisting{检查现有任务}
CheckExisting --> |存在进行中| Skip[跳过重复任务]
CheckExisting --> |不存在| CreateTask[创建新任务]
CreateTask --> AddQueue[添加到队列]
AddQueue --> EnsureWorker[确保工作线程运行]
EnsureWorker --> WaitProcess[等待处理]
WaitProcess --> PlatformCheck[平台兼容性检查]
PlatformCheck --> |Windows| ProcessTask[处理任务]
PlatformCheck --> |非Windows| PlatformError[返回平台错误]
ProcessTask --> ExportVideo[导出视频]
ExportVideo --> UploadVideo[上传视频]
UploadVideo --> Cleanup[清理临时文件]
Cleanup --> Complete[任务完成]
Skip --> End([结束])
PlatformError --> End
Complete --> End

草稿下载和处理

提供完整的草稿文件下载和处理机制:

下载流程
sequenceDiagram
participant Client as 客户端
participant Downloader as 草稿下载器
participant API as 草稿API
participant Storage as 本地存储
Client->>Downloader : 请求下载草稿
Downloader->>Downloader : 提取草稿ID
Downloader->>API : 获取文件列表
API-->>Downloader : 返回文件URL列表
Downloader->>API : 下载文件
API-->>Downloader : 返回文件内容
Downloader->>Downloader : 更新JSON路径
Downloader->>Storage : 写入文件
Storage-->>Downloader : 确认写入完成
Downloader-->>Client : 返回下载结果
文件处理策略
  • 原子写入: 使用O_EXCL标志确保文件写入的原子性
  • 路径解析: 自动更新JSON文件中的路径引用
  • 目录扫描: 使用robocopy触发剪映目录扫描
  • 错误重试: 支持最多3次的网络请求重试

剪映自动化控制

实现剪映应用程序的完整自动化控制:

平台检测机制
  • 导入保护:非Windows平台直接抛出ImportError异常
  • 依赖检查:检查uiautomation库的可用性
  • 错误指导:提供明确的安装指令和替代方案
导出流程控制
flowchart TD
Start([开始导出]) --> PlatformCheck[平台兼容性检查]
PlatformCheck --> |Windows| EnsureWindow[确保剪映窗口]
PlatformCheck --> |非Windows| PlatformError[返回平台错误]
EnsureWindow --> SwitchHome[切换到主页]
SwitchHome --> FindDraft[查找草稿]
FindDraft --> ClickEdit[点击编辑]
ClickEdit --> ClickExport[点击导出]
ClickExport --> SetResolution[设置分辨率]
SetResolution --> SetFramerate[设置帧率]
SetFramerate --> ClickFinal[点击最终导出]
ClickFinal --> WaitComplete[等待完成]
WaitComplete --> MoveFile[移动文件]
MoveFile --> End([导出完成])
PlatformError --> End
WaitComplete --> |超时| Error[导出超时]
Error --> End
窗口状态管理
  • 状态检测:自动检测剪映窗口的不同状态
  • 状态切换:支持主页、编辑页和导出页之间的切换
  • 超时处理:导出超时检测和错误处理
  • 错误恢复:自动错误恢复和状态重置

跨平台兼容性机制

系统现在支持跨平台部署,通过多层次的平台检测和降级机制确保在各种环境下都能正常运行:

平台检测策略
  • 系统级别检测:使用 sys.platform == 'win32' 进行精确的Windows平台识别
  • 模块级检测:在 src/pyJianYingDraft/__init__.py 中统一管理平台兼容性
  • 运行时检测:在任务执行过程中动态检查平台支持状态
优雅降级机制
  • 功能级降级:当Windows依赖缺失时,系统会优雅地降级到纯下载模式
  • 错误处理:提供清晰的错误信息和解决方案指导
  • 占位符实现:在非Windows平台提供功能等价的占位符实现
测试验证机制
  • 跨平台测试:通过 tests/test_cross_platform.py 验证多平台兼容性
  • CI/CD集成:通过 tests/test_ci_dependencies.py 在持续集成环境中测试依赖安装
  • 手动测试:通过 test_fix.py 进行手动平台兼容性验证

依赖关系分析

核心依赖关系

系统采用模块化设计,各组件之间通过清晰的接口进行交互:

graph TB
subgraph "外部依赖"
FastAPI[FastAPI框架]
Requests[HTTP客户端]
UIAutomation[UI自动化]
FFprobe[媒体分析工具]
end
subgraph "内部模块"
Router[路由模块]
Service[服务模块]
Utils[工具模块]
PyJianYing[剪映模块]
end
subgraph "配置管理"
Config[配置模块]
Exceptions[异常模块]
end
FastAPI --> Router
Router --> Service
Service --> Utils
Utils --> PyJianYing
Utils --> Config
Service --> Exceptions
PyJianYing --> UIAutomation
Utils --> FFprobe
Requests --> Utils

数据流分析

系统的数据流遵循标准化的处理流程:

flowchart LR
subgraph "输入层"
Request[HTTP请求]
DraftURL[草稿URL]
APIKey[API密钥]
end
subgraph "处理层"
Validation[参数验证]
Authentication[身份验证]
TaskSubmission[任务提交]
QueueManagement[队列管理]
PlatformCheck[平台检查]
Processing[视频处理]
end
subgraph "输出层"
StatusResponse[状态响应]
VideoURL[视频URL]
ErrorResponse[错误响应]
end
Request --> Validation
DraftURL --> Validation
APIKey --> Authentication
Validation --> TaskSubmission
Authentication --> TaskSubmission
TaskSubmission --> QueueManagement
QueueManagement --> PlatformCheck
PlatformCheck --> Processing
Processing --> StatusResponse
Processing --> VideoURL
Validation --> ErrorResponse
Authentication --> ErrorResponse

性能考虑

系统在设计时充分考虑了性能优化和资源管理:

并发控制策略

  • 单线程导出保护: 通过导出锁确保同一时间只有一个视频导出
  • 异步任务处理: 使用asyncio实现非阻塞的任务处理
  • 连接池管理: HTTP请求使用连接池提高效率
  • 内存管理: 及时清理临时文件和释放资源

资源优化措施

  • 文件原子写入: 避免文件损坏和数据竞争
  • 路径缓存: 减少重复的文件系统操作
  • 批量处理: 支持批量草稿下载和处理
  • 超时控制: 合理的超时设置避免资源占用

性能监控

  • 进度跟踪:实时更新任务进度和状态
  • 错误统计:记录和分析错误类型和频率
  • 资源使用:监控CPU、内存和磁盘使用情况
  • 响应时间:测量API响应时间和处理延迟

故障排除指南

平台兼容性问题

系统现在支持非Windows平台的优雅降级:

Windows依赖缺失
  • 错误表现: 导入uiautomation库时抛出ImportError
  • 解决方法:

    • 在Windows系统上安装依赖:pip install capcut-mate[windows]
    • 或者使用Docker容器运行服务
    • 考虑使用其他视频渲染服务替代方案
非Windows平台限制
  • 错误表现: 直接返回"视频生成功能仅在Windows系统上可用"
  • 解决方法:

    • 在Windows虚拟机或远程Windows服务器上部署
    • 使用云渲染服务提供商
    • 考虑使用跨平台的视频处理工具链
API密钥相关问题
  • 无效API密钥: 检查API密钥格式和有效性
  • 余额不足: 确保账户积分大于1
  • 权限验证: 验证API密钥的使用权限
草稿处理问题
  • 草稿URL无效: 验证草稿URL格式和有效性
  • 草稿文件缺失: 检查草稿文件的完整性和可访问性
  • 草稿内容为空: 确保草稿包含有效的视频、音频或图片素材
剪映导出问题
  • 导出超时: 检查剪映版本和系统资源
  • 文件未生成: 验证磁盘空间和剪映安装完整性
  • 窗口状态异常: 确保剪映应用程序正常运行
网络和存储问题
  • 下载失败: 检查网络连接和文件URL有效性
  • 上传失败: 验证COS配置和网络连接
  • 磁盘空间不足: 清理临时文件和存储空间
跨平台部署问题
  • 导入错误: 检查Python版本和依赖包完整性
  • 功能不可用: 验证平台检测逻辑和降级机制
  • 测试失败: 运行跨平台测试脚本验证兼容性

错误码对照表

错误码中文描述英文描述解决方案
2001无效的草稿URLInvalid draft URL检查URL格式是否正确
2005下载文件失败Download file failed检查网络连接和文件URL
2030视频生成任务提交失败Video generation task submit failed检查系统资源和权限
2031视频生成任务未找到Video generation task not found确认任务是否已提交
2035账户余额不足Insufficient account balance充值后重试
2036无效的apiKeyInvalid apiKey检查API密钥格式
平台不支持Platform not supported在 Windows 上运行或使用不依赖 UI 自动化的流程
Windows 依赖缺失Windows dependencies missing安装 Windows 可选依赖(如 pip install capcut-mate[windows]
跨平台测试失败Cross-platform test failed核对 Python 版本与依赖是否按 CI 脚本安装

结论

本视频生成系统提供了完整的云端渲染解决方案,具有以下特点:

技术优势

  • 异步处理: 支持高并发任务处理和资源优化
  • 自动化控制: 完整的剪映应用程序自动化
  • 状态管理: 完善的任务状态跟踪和错误处理
  • 扩展性: 模块化设计支持功能扩展和维护
  • 平台兼容性: 支持非Windows平台的优雅降级机制
  • 跨平台部署: 完整的Windows、Linux和macOS支持

应用价值

  • 降低门槛: 无需本地剪映安装即可使用云端渲染
  • 提高效率: 自动化处理大幅提高视频生成效率
  • 保证质量: 专业的剪映渲染确保视频质量
  • 降低成本: 云端资源优化使用成本
  • 适应性强: 支持多种部署环境和平台
  • 稳定性高: 完善的错误处理和降级机制

发展方向

  • 性能优化: 进一步提升并发处理能力和响应速度
  • 功能扩展: 支持更多视频格式和渲染参数
  • 监控增强: 完善的性能监控和告警机制
  • 用户体验: 简化的API接口和更好的错误提示
  • 平台完善: 进一步优化非Windows平台的兼容性
  • 测试覆盖: 增加更多的自动化测试和验证

附录

API使用示例

系统提供了完整的API文档和使用示例,支持多种编程语言和平台。

配置说明

详细的配置文件说明和环境变量设置指南。

最佳实践

  • 任务管理: 合理设置并发数量和超时时间
  • 资源规划: 根据硬件配置调整渲染参数
  • 监控告警: 建立完善的监控和告警机制
  • 备份策略: 定期备份重要数据和配置
  • 平台选择: 根据部署环境选择合适的平台配置
  • 跨平台测试: 定期运行跨平台测试确保兼容性
  • 依赖管理: 及时更新和维护平台特定的依赖包

部署指南

  • Windows部署: 安装完整的Windows依赖包
  • Linux部署: 使用Docker容器或虚拟机环境
  • macOS部署: 通过wine或虚拟机运行Windows版本
  • CI/CD集成: 使用提供的测试脚本进行自动化验证

之前一直用第三方支付,但是被薅的很严重,于是打算重构直接接 官方支付,想着随着接入渠道变多,还是要统一一下接入 api ;方便各个 app 维护。于是 做了这个聚合支付产品。

基本上是参考易支付去做。我没有用易支付是因为一看部署还要安装 php ,要 docker ,就头大。 于是拿几个易支付截图扔给 ai ;让他给我做一个容易部署的支付网关; ai 就用 go 给我实现了这个没有任何依赖的独立二进制 就可以在 linux 和 mac ,windows 上运行的 支付网关。数据库也没有那些传统支付网关的 mysql ,redis 依赖,一个 sqlite 就搞定,一个站长小站能有多大的支付浏览压力呢? sqlite 足够你用了;

https://github.com/mageg-x/gopay

这玩意没有什么技术含量,AI 也很快完成,但是考虑这是个 支付产品,安全第一,所以这个项目,我大部分时间都是 加强安全这块, 办法就是 3 大 AI 齐上阵,claude ,codex ,glm5 ; 轮流检查安全问题,提出安全 bug 。

这个产品我现在自己也在用,会一直维护优化下去,有需要的站长也可以拿去食用。和其他聚合支付相比,优点就是部署超简单,支付费率自己控制;不用担心被各种理由扣押资金; 不过也有麻烦;就是要自己去申请支付宝和微信支付;不得不说,微信支付真是一坨屎,申请流程一坨屎,接口一坨屎; tmd ,再骂一句,全是一坨屎。相对来说支付宝友好轻松几百倍。

因为老婆是内分泌科的护士,所以对于血糖和糖尿病的预防有点敏感
我自认为身体是很好的,体重也不超标,但是去医院一查,就是已经胰岛素抵抗了,而且常规体检也不会检查这一项这就是糖尿病的前期,如果不注意防治,很有可能就会发展成糖尿病。
所以建议各位朋友吃完饭有口渴严重的症状,或者主食面食米食吃的多的,最好去医院查一下。

SSL 证书的详细作用(完整版)

SSL 证书是部署在网站服务器上的数字安全证书,核心是通过SSL/TLS 加密协议,实现浏览器 / 客户端与服务器之间的安全通信,完整作用主要体现在数据安全、身份可信、用户体验、业务合规、搜索引擎优化五大方面,具体如下:

1. 传输数据加密,防止信息泄露与窃取

这是 SSL 证书最基础也最核心的功能。未安装证书的网站使用 HTTP 协议,数据以明文形式传输,极易被黑客通过抓包、监听、中间人攻击等方式窃取。安装 SSL 证书后,通信会切换为 HTTPS 协议,对账号密码、手机号、身份证号、银行卡信息、聊天内容、表单提交数据等进行高强度加密,即使数据被截获,也无法破解读取,有效保护用户隐私与敏感信息安全。

2. 验证网站真实身份,防范钓鱼网站

SSL 证书由受信任的第三方权威机构(CA 机构)颁发,颁发前会严格审核网站所有者的真实身份:

  • 个人网站验证域名归属;
  • 企业网站需验证营业执照、组织机构、域名所有权等资质;
  • 金融、电商等高安全场景还会进行更严格的人工核验。

通过浏览器地址栏的小锁图标、企业名称展示,用户可直观确认网站是官方正规平台,而非仿冒的钓鱼、诈骗网站,从源头降低用户被骗风险。

SSL证书https://www.joyssl.com/certificate/select/free.html?nid=7

3. 避免浏览器 “不安全” 警告,提升用户信任度

目前 Chrome、Edge、Firefox、Safari 等主流浏览器,对未部署 SSL 证书的 HTTP 网站,会直接标记 “不安全”,部分浏览器还会弹出风险提示,阻止用户继续访问。这种警告会让用户认为网站存在安全隐患,进而直接关闭页面,导致流量流失。安装 SSL 证书后,网站显示安全锁标识,访问流程顺畅,能显著提升用户对网站的信任感与停留意愿。

4. 保障业务合规,满足平台与行业强制要求

很多场景下,SSL 证书已不是可选配置,而是强制合规条件

  • 小程序、公众号、APP 接口开发,必须使用 HTTPS 加密通信,否则无法上线或正常调用接口;
  • 电商支付、在线交易、金融证券、医疗健康等行业,需满足等保测评、支付卡行业安全标准(PCI DSS)、个人信息保护相关法规,HTTPS 加密是必备要求;
  • 政府、事业单位官网,也需通过 HTTPS 保障政务信息传输安全。

5. 有利于搜索引擎排名,提升网站流量

主流搜索引擎(如百度、谷歌)均明确将HTTPS作为排名权重因素之一,同等条件下,启用 SSL 证书的网站会获得更优的排名。同时,部分搜索引擎会对 HTTP 网站降低收录优先级,甚至减少展示,部署 HTTPS 能帮助网站获得更多自然流量,提升曝光度。

6. 防止数据被篡改,保证内容完整性

除了加密,SSL 证书还能校验数据完整性。黑客可能在数据传输过程中篡改内容(如插入恶意广告、替换下载文件、修改网页文字),而 HTTPS 通信会为传输数据添加校验值,一旦数据被篡改,客户端会立即识别并中断连接,确保用户看到的内容与服务器发出的完全一致。

简单概括:SSL 证书既是网站的安全防护盾,也是身份通行证,同时还是保障业务正常运营、提升用户与平台信任的基础配置。

如今,视频会议早已脱离早年简单“可视电话”的定位,已经发展为一套整合高清音视频传输、人工智能能力、实时协作工具的综合技术系统。它不仅重塑了企业办公、在线教育、远程医疗等多个领域的运作模式,更是成为各行各业推进数字化转型必不可少的核心基础设施。本文将从技术原理、系统架构、核心技术组件以及未来发展方向四个维度,全面梳理视频会议技术的发展现状与演进方向。

视频会议核心技术原理:数据如何实现跨空间实时传输

视频会议的本质,是依托互联网完成音视频数据流的实时跨端传输,完整工作流程可以拆解为“采集-编码-传输-解码-渲染”五个核心环节,每个环节的技术水平直接决定最终的会议体验:

采集环节:摄像头捕捉连续的视频画面帧,麦克风拾取环境声音,最终转化为可处理的原始音视频数字信号。
编码环节:原始未压缩的音视频数据体积极其庞大,1080P分辨率的视频每秒就能产生近1GB的数据,完全无法直接通过网络传输,因此必须通过专业编码器压缩。目前行业主流编码标准分为三类:H.264/AVC兼容性最强,适配绝大多数网络和设备场景;H.265/HEVC压缩效率比前者提升50%,更适合4K超高清视频会议场景;AV1作为开源免专利的新标准,在低带宽环境下表现突出,甚至可在1Mbps带宽下稳定传输1080P画质的视频。
传输环节:压缩完成的数据一般通过RTP/RTCP协议实现实时传输,配合WebRTC技术可直接在浏览器端实现无插件参会,大幅降低接入门槛。要保障流畅的视频会议体验,网络需要满足三个基础要求:高清画质需要3-5Mbps的稳定带宽,4K画质需要10Mbps以上带宽;端到端延迟需要控制在200ms以内,才能保证对话自然不卡顿;同时通过FEC前向纠错技术实现抗丢包,可在30%丢包率的网络环境下仍然维持画面连续流畅。
解码与同步环节:接收端收到压缩数据后完成解码,再通过数据包自带的时间戳同步音视频流,避免常见的声画不同步问题。
渲染环节:最后将处理好的视频画面输出到显示器,声音通过扬声器或耳机播放,完成整个传输流程。
现代视频会议系统架构:从终端到云端的三层分层设计

目前主流的视频会议系统都采用“终端-网络-云端”三层架构设计,不同层级分工明确,共同保障会议稳定运行:

终端层:音视频采集输出的入口:主要负责原始音信号采集和最终内容渲染输出,分为硬件终端和软件客户端两类:硬件终端以专业会议室设备为主,比如华为IdeaHub、Polycom会议室一体机,大多集成4K摄像头、线性麦克风阵列,适配大中型会议室使用需求;软件客户端就是大家常用的Zoom、腾讯会议等应用,支持PC、手机、浏览器多端接入,随时随地都能加入会议。
网络层:数据传输的核心通路:主要通过Wi-Fi、5G、以太网等IP网络完成数据传输,核心要求是带宽稳定。很多企业部署专属视频会议系统时,会采用SD-WAN技术优化传输路径,进一步降低延迟提升稳定性。
云端层:多端交互的处理核心:核心功能是完成多会场数据的处理转发,目前主流架构分为两类:传统MCU多点控制单元架构,会把所有终端上传的数据混合后再分发给各个参会方,更适合小型会议使用;现代主流的SFU选择性转发单元架构,只负责转发各个终端的原始数据流,不需要额外混合处理,大幅降低了服务器运算压力,可以支持千人级的大型研讨会会议。
视频会议核心组件的技术突破:软硬结合驱动体验升级
硬件层面:从“能看见”到“看得清听得清”

近年来视频会议硬件创新速度飞快,核心围绕提升音视频体验推进:摄像头已经普及4K超高清分辨率,还加入AI智能取景功能,部分专业摄像机可自动识别发言人,让发言人始终保持在画面居中位置;麦克风普遍采用线性阵列设计搭配AI降噪算法,通过智能音幕技术可以屏蔽会议室外的无关噪音,走廊脚步声、隔壁的键盘声都能有效过滤;显示设备方面,智能会议平板整合了电子白板、无线投屏、视频会议三大核心功能,书写延迟最低可做到16ms,书写体验接近真实纸笔。

软件层面:AI赋能让视频会议更高效

AI技术的落地给视频会议带来了大量智能化功能,大幅提升了会议效率:首先是实时字幕翻译功能,依托自然语言处理技术可支持30种以上语言的实时互译,准确率可达95%以上,解决了跨国会议的语言障碍;其次是大家熟悉的虚拟背景和美颜功能,依托U-Net人像分割模型可实现毫秒级背景替换,满足隐私需求和场景美化需求;还有新兴的AI会议助手,可以自动完成会议纪要生成、待办任务分配,部分高端产品甚至可以通过识别参会者微表情,分析会议讨论热度和参会者情绪倾向。

视频会议未来发展趋势:三大方向引领行业变革

随着AR/VR、5G、量子计算等新技术的发展,视频会议行业还将迎来新的变革,目前行业公认的三大发展方向为:

沉浸式元宇宙会议:未来将结合AR/VR技术和全息投影,搭建3D虚拟会议室,参会者可以用数字分身进入会场,支持手势交互和空间音频,模拟真实会议室的交流体验,比如讲师在虚拟会场走动时,声音方位会跟着位置变化,更接近线下交流的感受。
边缘计算+5G赋能远端专业场景:把音视频处理单元部署在网络边缘节点,结合5G网络1ms级的低延迟,可以实现8K超高清视频会议,还能支持AR远程协作等高需求场景,比如远程指导工厂设备检修、远程手术指导等。
安全合规能力进一步升级:针对金融、政务等对信息安全要求极高的领域,端到端加密加区块链存证已经逐步落地,可满足审计溯源的需求,而量子加密技术预计会在2030年之前进入试点应用阶段,进一步提升视频会议的信息安全等级。

从简单的可视电话到如今支撑千万人远程办公的核心基础设施,视频会议技术的发展,本质上是数字化转型过程中,企业对高效跨空间沟通需求不断升级的结果,未来随着新技术的不断落地,视频会议还会给更多行业带来全新的变革。

一提到数据分析,很多人都会有同一种感觉:词太多,指标太杂,看着都眼熟,真要解释又容易乱。

尤其是刚入门的时候,最头疼的不是不会做图,也不是不会写SQL,而是开会时总能听到一堆缩写扑面而来。UV、PV、DAU、ARPU、LTV、同比、环比、A/B测试,单个看似乎都懂,放到业务里又常常分不清。

所以这次我干脆花了一周,把工作里最常见、最容易遇到的 120 个数据分析指标与术语重新梳理了一遍。

这篇文章不打算展开讲理论,也不会把每个词都写成长段定义,而是尽量用更适合收藏的方式,把它们分门别类整理出来。你可以把它当成一份数据分析速查表

一、整体框架框架

这 120 个词,表面上很杂,实际可以分成几类来看。

第一类是用户指标,核心是看有多少人来了,是新用户还是老用户,活跃情况怎么样。

第二类是行为指标,重点看用户来了以后做了什么,有没有浏览、停留、转化、留存、互动。

第三类是业务指标,更偏向投放、收入和增长结果。

第四类是分析术语,比如用户画像、AARRR、RFM、埋点这些。

第五类是统计和报告常用词,主要是做分析和写复盘时经常会碰到的表达。

如果先按这个框架去记,后面看这些术语就不会乱。

二、用户指标

做数据分析,最先接触到的往往就是用户指标。

因为很多分析问题,归根到底都绕不开一句话:到底有多少人来了,这些人是新是老,活跃不活跃,有没有留下来。

所以这一类指标,主要就是围绕用户规模和用户状态展开的。

指标含义
IP独立IP数
UV独立访客数
PV页面浏览量
VV访问次数,也常指播放次数
DAU日活跃用户数
MAU月活跃用户数
DNU日新增用户数
活跃留存率新增用户在后续某天仍然活跃的比例
TGI目标群体在某特征上的偏好强弱

这里面最容易混的,其实就是 IP、UV、PV、VV 这几个词。

你可以先这么记:

  • IP 更偏网络地址
  • UV 看的是来了多少个独立的人
  • PV 看的是页面总共被看了多少次
  • VV 看的是访问或播放发生了多少次

而像 DAU、MAU、DNU、留存率这些词,基本就是你以后做增长、运营、产品分析时天天会碰到的核心指标。

先把这一组搞明白,后面很多报表都会顺很多。

三、行为指标

行为指标是最杂也最常用的一类。用户来了以后,到底看了什么、待了多久、有没有继续往下走,基本都要靠这部分指标来判断。

为了看起来更清楚,我把它拆成四块。

访问类

先看访问类。这部分主要是判断用户进来以后看了多少、待了多久、从哪儿来的,属于最基础的一层行为数据。

指标含义
DV访客访问相关统计
用户访问时长用户使用产品的时长
人均页面访问量平均每个用户访问的页面数
人均浏览页数平均浏览页数
平均访问页面每次访问平均看多少页面
访问来源用户从哪里进入产品
平均停留时间用户平均停留时长
跳出率进入后很快离开的比例
搜索访问次数占比通过搜索产生的访问占比
获客成本获取一个用户的平均成本

这组指标最常见的用法,就是用来判断流量质量。

比如访问量看起来不低,但停留时间短、跳出率高,那往往说明流量并没有真正被承接住。

转化类

接下来是转化类。这一部分看的就不是用户来没来,而是来了之后有没有往下走,有没有买,有没有完成关键动作。

指标含义
最近购买间隔距离上次购买过去多久
购买频率一定周期内购买次数
购买商品种类买过多少类商品
平均每次消费额客单价水平
单次最高消费额单笔最高消费金额
日应用下载量每天下载量
一次会话用户数单次会话中的用户数
用户会话次数发起访问的次数
漏斗第一步进入次数漏斗起点进入量
漏斗中间步进入次数漏斗中间各环节进入量
漏斗进入率某一步进入下一步的比例
漏斗退出次数在某一步退出的人数
漏斗退出率在某一步流失的比例

这部分里最实用的通常是漏斗分析。

因为很多业务问题,不是没有用户,而是用户在某个环节掉得特别厉害。把每一步的进入率和退出率拆出来,问题往往就清楚了。

留存类

再往后,就到了留存类。很多产品不是拉新难,而是留人难。用户今天来了,明天不来,活动结束就走,那前面的增长投入就很容易白费。

指标含义
用户留存率一段时间后仍在使用的比例
渠道留存率不同渠道用户的留存情况
次日留存率新增用户第二天还在的比例
退出率用户退出的比例
活跃度用户使用活跃程度
活动参与率参与活动的用户占比
活跃交易用户数活跃且发生交易的用户数
用户回访率老用户再次访问的比例
用户流失率流失用户占比
功能使用率某功能被使用的比例
GMV成交总额
复购率再次购买的比例
退货率退货订单占比

留存类指标有个特点,就是特别能反映用户质量。

新增看的是规模,留存看的是质量。很多时候,增长看起来很热闹,但留存一拆,问题就全出来了。

社交类

如果产品本身有社区、内容或互动属性,那还会经常看到社交类指标。

这类指标看的是用户有没有参与互动,而不只是单纯浏览。

指标含义
好友数量用户好友数
帖子数量发帖数
看帖数量浏览帖子数
回复数量回复数
分享数量分享数
点赞数量点赞数
转发数量转发数
评论数量评论数

这组数据特别适合用来看社区活跃度。

因为一个平台真正热不热闹,不只是看有多少人来,还要看有没有人愿意发、愿意聊、愿意互动。

四、业务指标

如果说前面的指标更偏过程,那业务指标就更偏结果。

尤其在投放、运营、增长、销售这些场景里,最后大家真正关心的,往往还是效果怎么样,花的钱值不值,带来了多少收入。

这类指标不算多,但都非常常见。

指标含义
曝光量被展示的次数
CPM每千次展示成本
CPC每次点击成本
CPA每次转化成本
ROI投入产出比
ARPU每用户平均收入
ARRPU每付费用户平均收入
CTR点击率
CVR转化率
CAC获客成本
CPR每回应成本
ADPV广告页面浏览量
ADimp单个广告展示次数

这一类指标最容易在投放复盘里扎堆出现。

你可以这么记:

  • 曝光、点击、转化是一条线
  • CPM、CPC、CPA 是这条线上的成本指标
  • CTR、CVR 是效果指标
  • ARPU、ARRPU、ROI 更偏收入结果

如果只是看点击高不高,往往不够。最后还是要回到转化和投入产出上。

五、常用术语

除了指标本身,数据分析里还有很多高频术语。

这些词不一定直接对应某个数字,但在做分析、搭框架、写复盘时特别常见。如果这些词不熟,很多报告看起来就会有点吃力。

分析术语

先看分析工作里最常出现的一批词。

术语含义
用户画像给用户打标签,描出典型特征
AARRR获取、激活、留存、收入、传播
RARRA更强调留存的一种增长模型
OSM目标、策略、衡量指标
UJM用户旅程地图
RFM最近消费、消费频率、消费金额
A/B测试多版本对比,选更优方案
数据埋点记录用户行为的数据采集方式
LTV用户生命周期价值
归因分析判断转化结果应归功于哪个渠道

这一组其实很像分析工作的工具箱。

比如你要做用户分层,常会碰到 RFM;要做实验优化,会用 A/B测试;要看渠道效果,离不开归因分析。

统计术语

再看统计学里常见的一批词。这部分乍一看有点基础,但真的做分析时又绕不开。尤其是做数据清洗、结果解释和报告表达的时候,这些词都会反复出现。

术语含义
绝对数总量、总规模
相对数两个指标的对比结果
百分比占比大小
百分点百分比之间的差值
频数出现次数
频率出现占比
比例部分占整体
比率不同类别之间的比较
变量会变化的数据项
连续变量可连续取值
离散变量只能按整数计数
定性变量类别型变量
均值平均数
中位数排序后居中的值
缺失值数据缺漏
异常值明显偏离整体的数据
方差数据离散程度
标准差波动大小
皮尔森相关系数两变量线性相关程度

这部分最容易混的,往往是百分比和百分点、比例和比率、均值和中位数。

平时如果这些概念没分清,写分析结论时就特别容易表述不准。

报告术语

最后这一组,是很多人在看分析报告时最常遇到的表达。

单独拎出来都不难,但一放到复盘PPT和周报月报里,数量一多就容易晕。

术语含义
倍数一个数是另一个数的几倍
翻番变成原来的 2 的 n 次方
同比和去年同期比
环比和上一个周期比
增量增长的绝对值
增速增长速度
增长率增量除以基期
增幅增长幅度
基期作为参照的时期
现期当前统计时期
YTD今年截至目前
LY去年
YoY同比
MAT滚动年总值
Q1第一季度
Q4第四季度
GDP国内生产总值
GNH国民幸福指数
GNP国民生产总值

如果你平时经常要看经营分析、业务复盘、财务类报告,那这一组词真的很值得熟悉。

因为很多时候,不是分析难,而是报告里的表达本身就很密。

其实整理这些指标的时候,我也一直在想一件事:

很多人不是不懂指标,而是工作里真的很难把这些指标高效地用起来。数据分散在不同系统里,口径对不齐,临时做个分析还得来回取数。

六、最后说几句

这120个指标,基本上涵盖了我们日常工作中的各项业务,我建议大家先理解、吃透与自己业务相关的指标,做好重点监测与分析。至于其它的,直接收藏这篇文章,工作中遇到那个,就翻出来再看看,长此以往,你对数据的运用一定会越来越自如。

一直会有一些电话打过来说是移动的,要送手机,我问有没有条件,说是 3 年保持我当前的套餐不能换。

主要是这些电话都不是来自于 10086 ,都是私人电话,我信不过。直接说我不要了。即便是 3 年我也未必就一直用这个套餐。

然后现在感觉刚才这个电话,态度真的差,我都想投诉了。打 10086 投诉?

大家有没有碰到这种。

解锁 Even 老师的黄油汉堡胚 ➕️黄油恰巴塔!

汉堡胚:软 fufu,黄油香绝了(我自行减了糖,加了波兰种)
恰巴塔:脆皮+大气孔,越嚼越香(家里没有橄榄油了,我用黄油代替的,一样很好吃。虽然是家用小烤箱,但口感真的不输外面卖的,自己做的更放心)

跟着视频一步步来,真的不翻车。自己做的面包,比买的还上头。Even 老师的教程视频真的很赞,推荐所有面包脑袋去试试!laugh

音频生成技术正在经历一场全新的范式迁移——从传统级联架构,逐步向端到端生成范式演进。长期以来,主流的做法是"曲线救国":合成系统先将音频压缩成梅尔频谱图等中间表征,再依赖神经声码器"翻译"回波形。每一次转换都带来信息损失与误差累积,最终丢失了最需要保留的细腻音色与个性化细节。

能不能让 AI 直接学会声音本身的规律,跳过中间环节?

为破解这一技术瓶颈,美团 LongCat 团队正式发布 LongCat-AudioDiT。在该模型中,我们彻底抛弃梅尔谱等中间表示,直接在波形潜空间进行基于扩散模型的文本转语音(Text-to-Speech, TTS),从根源阻断数据转换的级联误差

另外,我们做了两个关键改进:首先,我们识别并纠正了一个长期存在的"训练-推理不匹配"问题;其次,我们用自适应投影引导(APG)取代了传统的无分类器引导(CFG),从而大幅提升了最终的语音生成质量。

结果表明,LongCat-AudioDiT 在 Seed 基准测试中取得当前最优(SOTA)的零样本语音克隆性能,同时保持了具有竞争力的可懂度。 其中 LongCat-AudioDiT-3.5B 模型,在 Seed-ZH 测试集的说话人相似度(SIM)指标提升至 0.818,Seed-Hard 测试集达到 0.797,超过了 Seed-TTS、CosyVoice3.5、MiniMax-Speech 等知名模型,验证了波形空间直接生成范式的有效性。

今天,我们将 LongCat-AudioDiT(1B/3.5B)完整开源:

接下来,我们将为您拆解 LongCat-AudioDiT 的核心技术创新。

一、波形潜在空间直接生成架构:规避中间表征的信息衰减瓶颈

业界主流 TTS 系统长期受困于"多阶段"的复杂流程:先预测中间声学特征(如梅尔频谱),再依赖一个独立的神经声码器将特征"翻译"成最终波形。这种"预测+翻译"的范式,本质上是在两个不同空间里"传话",必然会累积误差,导致最终合成的声音丢失了高保真、个性化的细节——而这恰恰是零样本语音克隆最需要保留的部分。

为此,我们构建了全新的 LongCat-AudioDiT 架构。其核心逻辑非常简单:

只用一个波形变分自编码器(Wav-VAE)和一个扩散 Transformer(DiT),在波形隐空间里完成声音的压缩、建模与重建。

1.1 Wav-VAE:为波形量身定制的压缩器

Wav-VAE 作为一个全卷积音频自编码器,它将原始波形压缩为紧凑的连续隐向量。其设计蕴含了多项关键创新:

  • 高效的下采样与多尺度建模:编码器通过多级 Oobleck 块实现层级下采样,每个块内堆叠了带空洞卷积的残差单元,能够捕获从局部到全局的时序依赖。最终将 24kHz 的波形压缩到约 11.7Hz 的帧率,压缩比超过 2000 倍。
  • 非参数捷径稳定训练:为了在激进下采样时保持训练稳定,每个编码器/解码器块都引入了非参数的"空间到通道"或"通道到空间"捷径分支,为梯度提供了直接的线性通路,大幅提升了收敛稳定性。
  • 对抗式多目标训练:Wav-VAE 的优化目标融合了多分辨率 STFT 损失、多尺度梅尔损失、时域 L1 损失、KL 散度正则,以及多尺度 STFT 判别器的对抗损失和特征匹配损失。这套组合拳确保了重建波形既保持精确的时频结构,又具备自然听感。

1.2 扩散 Transformer:在隐空间中学习从文本到声音的映射

有了高质量的隐空间,我们的 DiT 模型便在这个空间里学习条件流匹配(CFM)。

文本编码方面,我们选择了支持 107 种语言的 UMT5 作为文本编码器。一个关键的发现是:仅使用最后一层隐藏状态模型无法生成可懂的语音。我们推测这是因为高层语义抽象丢失了关键的词法、音素线索。因此,我们创新性地将原始词嵌入(第一层)与最后一层隐藏状态相加,经过 LayerNorm 平衡 scale 后送入后续模块。这种"高低结合"的策略大幅提升了生成语音的可懂度。此外,我们还引入了轻量的 ConvNeXt V2 序列模块对文本表征进行细化处理,加速了文本-语音对齐的收敛。

DiT 的骨干网络基于 Transformer,并集成了多项结构优化:

  • 全局自适应层归一化(Global AdaLN) 注入时间步信息,并通过全局共享的 AdaLN 块有效减少参数量。
  • QK-Norm + RoPE 稳定注意力训练,同时利用旋转位置编码捕捉相对位置关系。
  • 长跳跃连接 将输入直接加到输出,在实验中带来了一致的质量提升。
  • 表征对齐(REPA) 借助 mHuBERT 的自监督特征引导 DiT 中间层,虽不提升最终质量,但显著加速了收敛。

二、推理机制的双重关键突破:从精准对齐到生成净化

如果说波形潜在空间架构解决了声学建模的"空间选择"问题,那么我们对推理过程的两项关键改进,则从根本上优化了生成过程的"路径精度"与"质量纯度"。

2.1 修复流匹配 TTS 的「训练-推理」不匹配问题

我们首次发现并解决了流匹配 TTS 中长期存在的训练-推理不匹配问题。在标准 CFM 训练框架中,模型仅在掩码区域计算损失,而音频提示区域(prompt)并不参与优化;然而在推理阶段,这些同样提供音色条件的提示区域却会不受约束地通过扩散 ODE 自由演化,导致其分布轨迹偏离训练时的约束条件,最终造成生成语音的说话人音色漂移与稳定性下降。

为此,我们提出双重约束机制:

  1. 提示区域隐变量强制重置:在每一步推理迭代中,严格将提示区域的隐变量重置为其理论真值(即训练时的 ground truth),确保提示区域的演化轨迹与训练分布完全对齐,为生成部分提供稳定且纯净的声学条件;
  2. 无条件预测净化:在计算无条件速度场时,移除提示区域的隐变量输入,从而计算出完全正确的无条件速度,避免信息泄漏。

2.2 自适应投影引导(APG):缓解 CFG「过饱和」问题

传统的扩散模型普遍使用无分类器引导(CFG),通过放大条件预测与无条件预测的差异来提升生成质量。但这种方法有一个副作用:引导强度越大,越容易导致频谱"过饱和",从而使得音质劣化、语音听起来不够自然。

我们提出的自适应投影引导(APG)则换了一个思路:引导信号中真正有益的部分,和引发劣化的部分,在几何上是正交的。APG 将引导信号分解为平行与正交两个分量,保留正交分量(有益部分),同时抑制平行分量(劣化部分),从而在提升自然度的同时避免音质损失。

简单来说,CFG 是"无差别放大",APG 是"精准筛选"。两项推理优化协同作用,在保持高说话人相似度的同时,显著提升了生成语音的自然度与声学质量。

三、核心洞察:VAE 重建越好,TTS 生成反而越差?

在 Wav-VAE 的实验中,我们观察到了一个非常有意思的现象:VAE 重建质量越好 ≠ 语音生成效果越好

单纯追求高重建分数,会导致潜空间维度膨胀。这使得下游的扩散模型难以学习,导致综合表现下降。

为了深入探究这个问题,我们系统性地对比了不同潜空间维度与帧率配置下的建模表现,最终确定了最优配置:64 维潜在维度 + 11.7Hz 帧率。这一配置既为生成模型留出足够的学习空间,又保留了足够的声学细节,实现了重建保真度与生成质量的最佳平衡。

四、模型性能:定义「零样本」下的声音复刻极限

我们在 Seed 基准上测试了 LongCat-AudioDiT 的表现,并与业界知名模型,比如 SeedTTS、CosyVoice3.5、MiniMax-Speech 等进行对比。

结果表明,LongCat-AudioDiT 在说话人相似度(SIM)方面取得了 SOTA 的表现,同时具有极具竞争力的可懂度。

说话人相似度(SIM)

  • 中文测试集(Seed-ZH):LongCat-AudioDiT-3.5B 取得了 0.818 的相似度分数,大于之前 SOTA Seed-DiT 的分数 0.809。
  • 中文难句测试集(Seed-Hard):LongCat-AudioDiT-3.5B 取得了 0.797 的 SOTA 分数。

文本准确率(WER/CER)

  • 中文 CER:LongCat-AudioDiT-1.1B 为 1.18%,LongCat-AudioDiT-3.5B 为 1.09%。在 NAR(非自回归)模型中表现非常出色。
  • 英文 WER:两个版本分别为 1.78% 和 1.50%。其中 LongCat-AudioDiT-3.5B 的 1.50% 达到所有参评模型中的第二最低的错误率,展现了极强的英文文本转语音准确性。
  • 中文难句 CER:LongCat-AudioDiT-3.5B 取得了 6.04% 的成绩,相比于同样基于扩散模型的 F5 TTS(8.67%)错误率大幅降低,表现稳健。

模型在准确率指标上保持了第一梯队的水平,没有为了追求相似度而牺牲可懂度。

值得一提的是,LongCat-AudioDiT 并没有使用高质量人工标注数据和多阶段的训练,仅仅通过 ASR 转写的预训练数据和单阶段预训练就取得了比多阶段训练的模型,如 Seed-TTS、CosyVoice3.5、MiniMax-Speech 等知名模型更好的表现。

总结来说,LongCat-AudioDiT 模型凭借其优秀的说话人相似度(SIM)和稳定的准确率(WER/CER),在零样本语音克隆任务中展现出强大的竞争力。

开源开放

LongCat-AudioDiT 以极简的架构、纯粹的波形潜空间建模,证明了绕开中间表征的扩散 TTS 路线不仅能走通,更能达到业界最佳水平。我们相信,这套"波形隐空间直通"的设计范式将为高保真语音合成与多模态音频生成提供新的思路。

今天,我们将 LongCat-AudioDiT 模型(1B / 3.5B)全部开源,期待与社区同仁共同推动语音生成技术的边界。

🚀 开源平台链接

我们也期待,这套技术能帮助更多开发者和研究者,构建出更自然、更富表现力的语音交互体验。

| 关注「美团技术团队」微信公众号(meituantech),阅读更多技术干货!

| 本文系美团技术团队出品,著作权归属美团。欢迎出于分享和交流等非商业目的转载或使用本文内容,敬请注明“内容转载自美团技术团队”。本文未经许可,不得进行商业性转载或者使用。任何商用行为,请发送邮件至 tech@meituan.com 申请授权。

到 s11, 智能体已经能自主认领和完成任务。但所有任务共享一个目录。两个智能体同时重构不同模块 -- A 改 config.py, B 也改 config.py, 未提交的改动互相污染, 谁也没法干净回滚。

任务板管 "做什么" 但不管 "在哪做"。解法: 给每个任务一个独立的 git worktree 目录, 用任务 ID 把两边关联起来。"各干各的目录, 互不干扰",任务管目标,,worktree 管目录,按 ID 绑定。

Java实现代码

public class WorktreeTaskIsolationSystem {
    
    // --- 新增配置 ---
    private static final Path REPO_ROOT = detectRepoRoot(WORKDIR);  // Git仓库根目录
    private static final Path TASKS_DIR = REPO_ROOT.resolve(".tasks");
    private static final Path WORKTREES_DIR = REPO_ROOT.resolve(".worktrees");
    private static final Path EVENTS_LOG_PATH = WORKTREES_DIR.resolve("events.jsonl");
    
    // --- 新增:Git 仓库检测 ---
    private static Path detectRepoRoot(Path cwd) {
        try {
            ProcessBuilder pb = new ProcessBuilder("git", "rev-parse", "--show-toplevel");
            pb.directory(cwd.toFile());
            Process process = pb.start();
            
            boolean finished = process.waitFor(10, TimeUnit.SECONDS);
            if (!finished) {
                return cwd;
            }
            
            String output = new String(process.getInputStream().readAllBytes()).trim();
            Path root = Paths.get(output);
            return Files.exists(root) ? root : cwd;
            // 自动检测:自动发现Git仓库根目录
            // 向后兼容:如果不是Git仓库,使用当前目录
        } catch (Exception e) {
            return cwd;
        }
    }
    
    // --- 新增:事件总线(EventBus)---
    static class EventBus {
        private final Path eventLogPath;
        
        public EventBus(Path eventLogPath) {
            this.eventLogPath = eventLogPath;
            try {
                Files.createDirectories(eventLogPath.getParent());
                if (!Files.exists(eventLogPath)) {
                    Files.writeString(eventLogPath, "");
                }
            } catch (IOException e) {
                throw new RuntimeException("Failed to create event bus", e);
            }
        }
        
        /**
         * 发出事件
         */
        public void emit(String event, Map<String, Object> task, 
                        Map<String, Object> worktree, String error) {
            Map<String, Object> payload = new LinkedHashMap<>();
            payload.put("event", event);
            payload.put("ts", System.currentTimeMillis() / 1000.0);
            payload.put("task", task != null ? task : Map.of());
            payload.put("worktree", worktree != null ? worktree : Map.of());
            
            if (error != null) {
                payload.put("error", error);
            }
            // 结构化事件:事件类型、时间戳、关联数据
            // 错误跟踪:支持记录操作失败信息
            
            try {
                String jsonLine = gson.toJson(payload) + "\n";
                Files.writeString(eventLogPath, jsonLine, 
                    StandardOpenOption.CREATE, StandardOpenOption.APPEND);
                // JSONL格式:每行一个事件,便于流式处理
                // 追加写入:支持长时间运行的事件记录
            } catch (IOException e) {
                System.err.println("Failed to emit event: " + e.getMessage());
            }
        }
        
        /**
         * 列出最近事件
         */
        public String listRecent(int limit) {
            int n = Math.max(1, Math.min(limit, 200));
            
            try {
                List<String> lines = Files.readAllLines(eventLogPath);
                List<Map<String, Object>> events = new ArrayList<>();
                
                int start = Math.max(0, lines.size() - n);
                for (int i = start; i < lines.size(); i++) {
                    try {
                        Type type = new TypeToken<Map<String, Object>>(){}.getType();
                        Map<String, Object> event = gson.fromJson(lines.get(i), type);
                        events.add(event);
                    } catch (Exception e) {
                        Map<String, Object> errorEvent = new HashMap<>();
                        errorEvent.put("event", "parse_error");
                        errorEvent.put("raw", lines.get(i));
                        events.add(errorEvent);
                        // 容错处理:即使解析失败也记录原始数据
                    }
                }
                
                return gson.toJson(events);
            } catch (IOException e) {
                return "[]";
            }
        }
    }
    
    // 初始化事件总线
    private static final EventBus EVENTS = new EventBus(EVENTS_LOG_PATH);
    
    // --- 新增:任务管理器(支持工作树绑定)---
    static class TaskManager {
        private final Path tasksDir;
        private int nextId = 1;
        
        public TaskManager(Path tasksDir) {
            this.tasksDir = tasksDir;
            try {
                Files.createDirectories(tasksDir);
                this.nextId = getMaxId() + 1;
            } catch (IOException e) {
                throw new RuntimeException("Failed to initialize task manager", e);
            }
        }
        
        /**
         * 绑定任务到工作树
         */
        public String bindWorktree(int taskId, String worktree, String owner) throws IOException {
            Map<String, Object> task = loadTask(taskId);
            task.put("worktree", worktree);
            // 任务-工作树关联:建立任务和工作树的双向链接
            
            if (owner != null && !owner.isEmpty()) {
                task.put("owner", owner);
            }
            
            if ("pending".equals(task.get("status"))) {
                task.put("status", "in_progress");
                // 状态自动转换:绑定工作树时自动开始任务
            }
            
            task.put("updated_at", System.currentTimeMillis() / 1000.0);
            saveTask(task);
            return gson.toJson(task);
        }
        
        /**
         * 解绑工作树
         */
        public String unbindWorktree(int taskId) throws IOException {
            Map<String, Object> task = loadTask(taskId);
            task.put("worktree", "");
            task.put("updated_at", System.currentTimeMillis() / 1000.0);
            saveTask(task);
            return gson.toJson(task);
            // 解绑机制:支持任务和工作树的解耦
        }
        
        /**
         * 列出所有任务
         */
        public String listAllTasks() throws IOException {
            // ... 列出任务逻辑,包含工作树绑定信息
            sb.append(String.format("%s #%d: %s%s%s\n", 
                marker, id, subject, ownerStr, worktreeStr));
            // 可视化展示:显示任务状态、所有者、工作树绑定
        }
    }
    
    // 初始化任务管理器
    private static final TaskManager TASKS = new TaskManager(TASKS_DIR);
    
    // --- 新增:工作树管理器(WorktreeManager)---
    static class WorktreeManager {
        private final Path repoRoot;
        private final TaskManager taskManager;
        private final EventBus eventBus;
        private final Path worktreesDir;
        private final Path indexPath;
        private final boolean gitAvailable;
        
        public WorktreeManager(Path repoRoot, TaskManager taskManager, EventBus eventBus) {
            this.repoRoot = repoRoot;
            this.taskManager = taskManager;
            this.eventBus = eventBus;
            this.worktreesDir = repoRoot.resolve(".worktrees");
            this.indexPath = worktreesDir.resolve("index.json");
            // 集成架构:工作树管理器与任务管理器、事件总线集成
            
            try {
                Files.createDirectories(worktreesDir);
                if (!Files.exists(indexPath)) {
                    Map<String, Object> index = new HashMap<>();
                    index.put("worktrees", new ArrayList<Map<String, Object>>());
                    Files.writeString(indexPath, gson.toJson(index));
                }
            } catch (IOException e) {
                throw new RuntimeException("Failed to initialize worktree manager", e);
            }
            
            this.gitAvailable = isGitRepo();
        }
        
        /**
         * 检查是否是Git仓库
         */
        private boolean isGitRepo() {
            try {
                ProcessBuilder pb = new ProcessBuilder("git", "rev-parse", "--is-inside-work-tree");
                pb.directory(repoRoot.toFile());
                Process process = pb.start();
                return process.exitValue() == 0;
            } catch (Exception e) {
                return false;
            }
        }
        
        /**
         * 执行Git命令
         */
        private String runGit(List<String> args) throws Exception {
            if (!gitAvailable) {
                throw new RuntimeException("Not in a git repository. worktree tools require git.");
            }
            
            ProcessBuilder pb = new ProcessBuilder("git");
            pb.command().addAll(args);
            pb.directory(repoRoot.toFile());
            
            Process process = pb.start();
            boolean finished = process.waitFor(120, TimeUnit.SECONDS);
            
            if (!finished) {
                process.destroy();
                throw new RuntimeException("git command timeout");
            }
            
            int exitCode = process.exitValue();
            if (exitCode != 0) {
                String error = new String(process.getErrorStream().readAllBytes()).trim();
                String output = new String(process.getInputStream().readAllBytes()).trim();
                String message = error.isEmpty() ? output : error;
                if (message.isEmpty()) {
                    message = "git " + String.join(" ", args) + " failed";
                }
                throw new RuntimeException(message);
            }
            
            String output = new String(process.getInputStream().readAllBytes()).trim();
            String error = new String(process.getErrorStream().readAllBytes()).trim();
            String result = output + (error.isEmpty() ? "" : "\n" + error);
            return result.isEmpty() ? "(no output)" : result;
        }
        
        /**
         * 加载索引文件
         */
        @SuppressWarnings("unchecked")
        private Map<String, Object> loadIndex() throws IOException {
            String content = Files.readString(indexPath);
            Type type = new TypeToken<Map<String, Object>>(){}.getType();
            return gson.fromJson(content, type);
        }
        
        /**
         * 保存索引文件
         */
        private void saveIndex(Map<String, Object> index) throws IOException {
            Files.writeString(indexPath, gson.toJson(index));
        }
        
        /**
         * 验证工作树名称
         */
        private void validateName(String name) {
            if (name == null || name.isEmpty() || name.length() > 40) {
                throw new IllegalArgumentException("Worktree name must be 1-40 characters");
            }
            
            if (!name.matches("[A-Za-z0-9._-]+")) {
                throw new IllegalArgumentException(
                    "Invalid worktree name. Use letters, numbers, ., _, - only"
                );
            }
            // 名称规范:确保工作树名称安全且规范
        }
        
        /**
         * 创建工作树
         */
        public String createWorktree(String name, Integer taskId, String baseRef) throws Exception {
            validateName(name);
            
            Map<String, Object> existing = findWorktree(name);
            if (existing != null) {
                throw new IllegalArgumentException("Worktree '" + name + "' already exists");
            }
            
            if (taskId != null && !taskManager.taskExists(taskId)) {
                throw new IllegalArgumentException("Task " + taskId + " not found");
            }
            
            // 发出创建前事件
            Map<String, Object> taskInfo = taskId != null ? 
                Map.of("id", taskId) : Map.of();
            Map<String, Object> worktreeInfo = Map.of("name", name, "base_ref", baseRef);
            eventBus.emit("worktree.create.before", taskInfo, worktreeInfo, null);
            
            try {
                Path worktreePath = worktreesDir.resolve(name);
                String branch = "wt/" + name;  // 自动生成分支名
                
                // Git工作树创建
                runGit(Arrays.asList("worktree", "add", "-b", branch, 
                    worktreePath.toString(), baseRef));
                // Git工作树:独立的代码工作目录
                // 自动分支:为每个工作树创建独立分支
                
                // 创建索引条目
                Map<String, Object> entry = new LinkedHashMap<>();
                entry.put("name", name);
                entry.put("path", worktreePath.toString());
                entry.put("branch", branch);
                entry.put("task_id", taskId);
                entry.put("status", "active");
                entry.put("created_at", System.currentTimeMillis() / 1000.0);
                
                // 保存到索引
                Map<String, Object> index = loadIndex();
                @SuppressWarnings("unchecked")
                List<Map<String, Object>> worktrees = (List<Map<String, Object>>) index.get("worktrees");
                worktrees.add(entry);
                saveIndex(index);
                
                // 绑定任务
                if (taskId != null) {
                    taskManager.bindWorktree(taskId, name, "");
                }
                
                // 发出创建后事件
                Map<String, Object> worktreeAfter = new LinkedHashMap<>();
                worktreeAfter.put("name", name);
                worktreeAfter.put("path", worktreePath.toString());
                worktreeAfter.put("branch", branch);
                worktreeAfter.put("status", "active");
                
                eventBus.emit("worktree.create.after", taskInfo, worktreeAfter, null);
                
                return gson.toJson(entry);
                
            } catch (Exception e) {
                eventBus.emit("worktree.create.failed", taskInfo, 
                    Map.of("name", name, "base_ref", baseRef), e.getMessage());
                throw e;
            }
        }
        
        /**
         * 获取工作树状态
         */
        public String getWorktreeStatus(String name) throws IOException {
            Map<String, Object> worktree = findWorktree(name);
            if (worktree == null) {
                return "Error: Unknown worktree '" + name + "'";
            }
            
            Path worktreePath = Paths.get((String) worktree.get("path"));
            if (!Files.exists(worktreePath)) {
                return "Error: Worktree path missing: " + worktreePath;
            }
            
            try {
                ProcessBuilder pb = new ProcessBuilder("git", "status", "--short", "--branch");
                pb.directory(worktreePath.toFile());
                
                Process process = pb.start();
                boolean finished = process.waitFor(60, TimeUnit.SECONDS);
                
                if (!finished) {
                    process.destroy();
                    return "Error: Git status timeout";
                }
                
                String output = new String(process.getInputStream().readAllBytes()).trim();
                String error = new String(process.getErrorStream().readAllBytes()).trim();
                String result = output + (error.isEmpty() ? "" : "\n" + error);
                
                return result.isEmpty() ? "Clean worktree" : result;
                // Git状态检查:提供详细的工作树状态信息
                
            } catch (Exception e) {
                return "Error: " + e.getMessage();
            }
        }
        
        /**
         * 在工作树中运行命令
         */
        public String runInWorktree(String name, String command) throws Exception {
            // 安全检查
            String[] dangerous = {"rm -rf /", "sudo", "shutdown", "reboot", "> /dev/"};
            for (String d : dangerous) {
                if (command.contains(d)) {
                    return "Error: Dangerous command blocked";
                }
            }
            
            Map<String, Object> worktree = findWorktree(name);
            if (worktree == null) {
                return "Error: Unknown worktree '" + name + "'";
            }
            
            Path worktreePath = Paths.get((String) worktree.get("path"));
            if (!Files.exists(worktreePath)) {
                return "Error: Worktree path missing: " + worktreePath;
            }
            
            try {
                ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
                pb.directory(worktreePath.toFile());
                // 目录隔离:命令在工作树的独立目录中执行
                
                Process process = pb.start();
                boolean finished = process.waitFor(300, TimeUnit.SECONDS);
                
                if (!finished) {
                    process.destroy();
                    return "Error: Timeout (300s)";
                }
                
                String output = new String(process.getInputStream().readAllBytes()).trim();
                String error = new String(process.getErrorStream().readAllBytes()).trim();
                String result = output + (error.isEmpty() ? "" : "\n" + error);
                
                return result.isEmpty() ? "(no output)" : 
                    result.substring(0, Math.min(result.length(), 50000));
                
            } catch (Exception e) {
                return "Error: " + e.getMessage();
            }
        }
        
        /**
         * 删除工作树
         */
        public String removeWorktree(String name, boolean force, boolean completeTask) throws Exception {
            Map<String, Object> worktree = findWorktree(name);
            if (worktree == null) {
                return "Error: Unknown worktree '" + name + "'";
            }
            
            // 发出删除前事件
            Integer taskId = (Integer) worktree.get("task_id");
            Map<String, Object> taskInfo = taskId != null ? 
                Map.of("id", taskId) : Map.of();
            Map<String, Object> worktreeInfo = Map.of(
                "name", name, 
                "path", worktree.get("path")
            );
            
            eventBus.emit("worktree.remove.before", taskInfo, worktreeInfo, null);
            
            try {
                List<String> args = new ArrayList<>();
                args.addAll(Arrays.asList("worktree", "remove"));
                if (force) {
                    args.add("--force");
                }
                args.add((String) worktree.get("path"));
                
                runGit(args);
                // Git工作树删除:清理Git工作树
                
                // 完成任务
                if (completeTask && taskId != null) {
                    Map<String, Object> task = gson.fromJson(taskManager.getTask(taskId), 
                        new TypeToken<Map<String, Object>>(){}.getType());
                    
                    taskManager.updateTask(taskId, "completed", null);
                    taskManager.unbindWorktree(taskId);
                    // 任务-工作树生命周期协同:删除工作树时自动完成任务
                    
                    Map<String, Object> taskEvent = new HashMap<>();
                    taskEvent.put("id", taskId);
                    taskEvent.put("subject", task.get("subject"));
                    taskEvent.put("status", "completed");
                    
                    eventBus.emit("task.completed", taskEvent, 
                        Map.of("name", name), null);
                }
                
                // 更新索引
                Map<String, Object> index = loadIndex();
                @SuppressWarnings("unchecked")
                List<Map<String, Object>> worktrees = (List<Map<String, Object>>) index.get("worktrees");
                
                for (Map<String, Object> wt : worktrees) {
                    if (name.equals(wt.get("name"))) {
                        wt.put("status", "removed");
                        wt.put("removed_at", System.currentTimeMillis() / 1000.0);
                        break;
                    }
                }
                saveIndex(index);
                // 索引更新:标记工作树为已删除状态
                
                // 发出删除后事件
                Map<String, Object> worktreeAfter = new HashMap<>();
                worktreeAfter.put("name", name);
                worktreeAfter.put("path", worktree.get("path"));
                worktreeAfter.put("status", "removed");
                
                eventBus.emit("worktree.remove.after", taskInfo, worktreeAfter, null);
                
                return "Removed worktree '" + name + "'";
                
            } catch (Exception e) {
                eventBus.emit("worktree.remove.failed", taskInfo, worktreeInfo, e.getMessage());
                throw e;
            }
        }
        
        /**
         * 保留工作树(标记为保留状态)
         */
        public String keepWorktree(String name) throws IOException {
            Map<String, Object> worktree = findWorktree(name);
            if (worktree == null) {
                return "Error: Unknown worktree '" + name + "'";
            }
            
            Map<String, Object> index = loadIndex();
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> worktrees = (List<Map<String, Object>>) index.get("worktrees");
            
            Map<String, Object> keptWorktree = null;
            
            for (Map<String, Object> wt : worktrees) {
                if (name.equals(wt.get("name"))) {
                    wt.put("status", "kept");
                    wt.put("kept_at", System.currentTimeMillis() / 1000.0);
                    keptWorktree = wt;
                    break;
                }
            }
            
            saveIndex(index);
            // 保留状态:标记工作树为需要保留,不自动清理
            
            // 发出保留事件
            Integer taskId = (Integer) worktree.get("task_id");
            Map<String, Object> taskInfo = taskId != null ? 
                Map.of("id", taskId) : Map.of();
            
            Map<String, Object> worktreeInfo = new HashMap<>();
            worktreeInfo.put("name", name);
            worktreeInfo.put("path", worktree.get("path"));
            worktreeInfo.put("status", "kept");
            
            eventBus.emit("worktree.keep", taskInfo, worktreeInfo, null);
            
            return keptWorktree != null ? gson.toJson(keptWorktree) : 
                "Error: Unknown worktree '" + name + "'";
        }
    }
    
    // 初始化工作树管理器
    private static final WorktreeManager WORKTREES = new WorktreeManager(REPO_ROOT, TASKS, EVENTS);
    
    // --- 新增:工具处理器 ---
    static {
        // 新增任务工具
        TOOL_HANDLERS.put("task_create", args -> {
            String subject = (String) args.get("subject");
            String description = (String) args.get("description");
            return TASKS.createTask(subject, description);
        });
        
        TOOL_HANDLERS.put("task_list", args -> TASKS.listAllTasks());
        
        TOOL_HANDLERS.put("task_get", args -> {
            int taskId = ((Number) args.get("task_id")).intValue();
            return TASKS.getTask(taskId);
        });
        
        TOOL_HANDLERS.put("task_update", args -> {
            int taskId = ((Number) args.get("task_id")).intValue();
            String status = (String) args.get("status");
            String owner = (String) args.get("owner");
            return TASKS.updateTask(taskId, status, owner);
        });
        
        TOOL_HANDLERS.put("task_bind_worktree", args -> {
            int taskId = ((Number) args.get("task_id")).intValue();
            String worktree = (String) args.get("worktree");
            String owner = (String) args.get("owner");
            return TASKS.bindWorktree(taskId, worktree, owner);
        });
        
        // 新增工作树工具
        TOOL_HANDLERS.put("worktree_create", args -> {
            String name = (String) args.get("name");
            Integer taskId = args.get("task_id") != null ? 
                ((Number) args.get("task_id")).intValue() : null;
            String baseRef = (String) args.get("base_ref");
            if (baseRef == null) baseRef = "HEAD";
            return WORKTREES.createWorktree(name, taskId, baseRef);
        });
        
        TOOL_HANDLERS.put("worktree_list", args -> WORKTREES.listWorktrees());
        
        TOOL_HANDLERS.put("worktree_status", args -> {
            String name = (String) args.get("name");
            return WORKTREES.getWorktreeStatus(name);
        });
        
        TOOL_HANDLERS.put("worktree_run", args -> {
            String name = (String) args.get("name");
            String command = (String) args.get("command");
            return WORKTREES.runInWorktree(name, command);
        });
        
        TOOL_HANDLERS.put("worktree_keep", args -> {
            String name = (String) args.get("name");
            return WORKTREES.keepWorktree(name);
        });
        
        TOOL_HANDLERS.put("worktree_remove", args -> {
            String name = (String) args.get("name");
            boolean force = args.get("force") != null && (Boolean) args.get("force");
            boolean completeTask = args.get("complete_task") != null && (Boolean) args.get("complete_task");
            return WORKTREES.removeWorktree(name, force, completeTask);
        });
        
        TOOL_HANDLERS.put("worktree_events", args -> {
            int limit = args.get("limit") != null ? ((Number) args.get("limit")).intValue() : 20;
            return EVENTS.listRecent(limit);
        });
    }
    
    // --- 新增:工具定义 ---
    private static List<Map<String, Object>> getToolSpecs() {
        List<Map<String, Object>> tools = new ArrayList<>();
        
        // 任务工具定义...
        
        // 工作树工具定义...
        
        return tools;
    }
}

这段代码引入了工作树任务隔离系统,实现了:

  1. 目录级隔离:每个任务在自己的工作树中执行
  2. 控制平面与执行平面分离

    • 控制平面:任务管理(.tasks/)
    • 执行平面:工作树管理(.worktrees/)
  3. 事件总线:记录完整生命周期事件
  4. Git 工作树集成:利用 git worktree 实现隔离

关键洞察:通过目录隔离并行任务,通过任务ID进行协调。

Git工作树隔离架构

核心思想:从文件系统隔离升级为Git仓库级别的代码隔离,通过Git工作树实现完全隔离的并行开发环境,为每个任务提供独立的代码工作空间,避免冲突,支持真正的并行开发。

// 核心路径配置
private static final Path REPO_ROOT = detectRepoRoot(WORKDIR);  // Git仓库根目录
private static final Path WORKTREES_DIR = REPO_ROOT.resolve(".worktrees");  // 工作树目录
// Git仓库感知:自动检测Git仓库根目录
// 工作树管理:专门的工作树存储目录
// 版本控制集成:与Git深度集成
// Git仓库检测
private static Path detectRepoRoot(Path cwd) {
    try {
        ProcessBuilder pb = new ProcessBuilder("git", "rev-parse", "--show-toplevel");
        pb.directory(cwd.toFile());
        Process process = pb.start();
        
        String output = new String(process.getInputStream().readAllBytes()).trim();
        Path root = Paths.get(output);
        return Files.exists(root) ? root : cwd;
        // 自动发现:自动定位Git仓库根目录
        // 兼容处理:非Git仓库时回退到当前目录
    } catch (Exception e) {
        return cwd;
    }
}
  • Git原生集成:深度集成Git版本控制系统
  • 仓库感知:自动识别和适应Git仓库结构
  • 向后兼容:非Git环境也能工作
  • 专业级隔离:为专业软件开发设计

工作树管理系统

// 工作树管理器核心
static class WorktreeManager {
    private final Path repoRoot;
    private final TaskManager taskManager;
    private final EventBus eventBus;
    private final Path worktreesDir;
    private final Path indexPath;
    private final boolean gitAvailable;
    // 三组件集成:仓库、任务、事件总线
    // 索引管理:工作树元数据索引
    // 可用性检查:检测Git环境
}
  • 集成架构:与任务管理和事件系统深度集成
  • 元数据管理:工作树元数据集中管理
  • 环境感知:自动检测和适应Git环境
  • 专业级管理:企业级的工作树生命周期管理

Git工作树创建机制

// 创建工作树
public String createWorktree(String name, Integer taskId, String baseRef) throws Exception {
    validateName(name);
    
    Path worktreePath = worktreesDir.resolve(name);
    String branch = "wt/" + name;  // 自动生成分支名
    
    // Git工作树创建
    runGit(Arrays.asList("worktree", "add", "-b", branch, 
        worktreePath.toString(), baseRef));
    // Git工作树:独立的工作目录
    // 自动分支:为每个工作树创建独立分支
    
    // 创建索引条目
    Map<String, Object> entry = new LinkedHashMap<>();
    entry.put("name", name);
    entry.put("path", worktreePath.toString());
    entry.put("branch", branch);
    entry.put("task_id", taskId);
    entry.put("status", "active");
    entry.put("created_at", System.currentTimeMillis() / 1000.0);
    // 完整元数据:名称、路径、分支、关联任务
    // 状态管理:明确的工作树生命周期状态
    
    // 保存到索引
    Map<String, Object> index = loadIndex();
    @SuppressWarnings("unchecked")
    List<Map<String, Object>> worktrees = (List<Map<String, Object>>) index.get("worktrees");
    worktrees.add(entry);
    saveIndex(index);
    // 索引管理:集中式工作树元数据管理
    // 持久化:工作树信息持久化存储
}
  • Git原生:使用Git工作树实现真正的代码隔离
  • 自动分支:为每个工作树自动创建分支
  • 元数据完整:完整的工作树元数据记录
  • 持久化索引:工作树信息持久化存储
  • 状态管理:明确的工作树生命周期状态

任务-工作树双向绑定

// 任务管理器中的工作树绑定
public String bindWorktree(int taskId, String worktree, String owner) throws IOException {
    Map<String, Object> task = loadTask(taskId);
    task.put("worktree", worktree);
    // 双向绑定:任务记录工作树,工作树记录任务
    // 关联管理:建立任务和工作树的一对一关系
    
    if (owner != null && !owner.isEmpty()) {
        task.put("owner", owner);
    }
    
    if ("pending".equals(task.get("status"))) {
        task.put("status", "in_progress");
        // 状态自动转换:绑定工作树时自动开始任务
        // 工作流优化:简化任务启动流程
    }
    
    task.put("updated_at", System.currentTimeMillis() / 1000.0);
    saveTask(task);
    return gson.toJson(task);
}
// 工作树管理器中的任务绑定
if (taskId != null) {
    taskManager.bindWorktree(taskId, name, "");
    // 协同绑定:创建工作树时自动绑定任务
    // 双向同步:确保任务和工作树状态一致
}
  • 双向关联:任务和工作树相互引用
  • 状态协同:任务和工作树状态自动同步
  • 工作流简化:自动的状态转换和绑定
  • 数据一致性:确保关联数据的一致性

工作树操作隔离

// 在工作树中运行命令
public String runInWorktree(String name, String command) throws Exception {
    Map<String, Object> worktree = findWorktree(name);
    Path worktreePath = Paths.get((String) worktree.get("path"));
    
    try {
        ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
        pb.directory(worktreePath.toFile());
        // 目录隔离:命令在工作树的独立目录中执行
        // 环境隔离:每个工作树有自己的Git环境
        
        Process process = pb.start();
        boolean finished = process.waitFor(300, TimeUnit.SECONDS);
        
        String output = new String(process.getInputStream().readAllBytes()).trim();
        String error = new String(process.getErrorStream().readAllBytes()).trim();
        String result = output + (error.isEmpty() ? "" : "\n" + error);
        
        return result.isEmpty() ? "(no output)" : 
            result.substring(0, Math.min(result.length(), 50000));
        
    } catch (Exception e) {
        return "Error: " + e.getMessage();
    }
}
  • 完全隔离:每个工作树是独立的文件系统目录
  • Git环境隔离:每个工作树有自己的Git配置和历史
  • 安全执行:命令在隔离环境中执行
  • 结果返回:返回完整的命令执行结果

Git状态检查

// 获取工作树状态
public String getWorktreeStatus(String name) throws IOException {
    Path worktreePath = Paths.get((String) worktree.get("path"));
    
    try {
        ProcessBuilder pb = new ProcessBuilder("git", "status", "--short", "--branch");
        pb.directory(worktreePath.toFile());
        // Git状态:获取详细的工作树Git状态
        // 信息丰富:包括分支信息、变更状态等
        
        Process process = pb.start();
        boolean finished = process.waitFor(60, TimeUnit.SECONDS);
        
        String output = new String(process.getInputStream().readAllBytes()).trim();
        String error = new String(process.getErrorStream().readAllBytes()).trim();
        String result = output + (error.isEmpty() ? "" : "\n" + error);
        
        return result.isEmpty() ? "Clean worktree" : result;
        
    } catch (Exception e) {
        return "Error: " + e.getMessage();
    }
}
  • Git专业:提供专业的Git状态信息
  • 实时状态:实时检查工作树的Git状态
  • 变更追踪:跟踪代码变更情况
  • 问题诊断:便于诊断Git相关问题

工作树生命周期管理

// 删除工作树
public String removeWorktree(String name, boolean force, boolean completeTask) throws Exception {
    // Git工作树删除
    List<String> args = new ArrayList<>();
    args.addAll(Arrays.asList("worktree", "remove"));
    if (force) {
        args.add("--force");
    }
    args.add((String) worktree.get("path"));
    
    runGit(args);
    // Git清理:使用Git命令清理工作树
    // 选项支持:支持强制删除等选项
    
    // 完成任务
    if (completeTask && taskId != null) {
        taskManager.updateTask(taskId, "completed", null);
        taskManager.unbindWorktree(taskId);
        // 生命周期协同:删除工作树时自动完成任务
        // 状态清理:清理任务和工作树的关联
        
        Map<String, Object> taskEvent = new HashMap<>();
        taskEvent.put("id", taskId);
        taskEvent.put("subject", task.get("subject"));
        taskEvent.put("status", "completed");
        
        eventBus.emit("task.completed", taskEvent, 
            Map.of("name", name), null);
    }
    
    // 更新索引
    for (Map<String, Object> wt : worktrees) {
        if (name.equals(wt.get("name"))) {
            wt.put("status", "removed");
            wt.put("removed_at", System.currentTimeMillis() / 1000.0);
            break;
        }
    }
    saveIndex(index);
    // 状态更新:标记工作树为已删除状态
    // 历史保留:保留工作树的删除记录
}
  • 完整生命周期:创建、使用、保留、删除的完整生命周期
  • Git原生:使用Git命令管理工作树
  • 任务协同:工作树删除时自动处理关联任务
  • 状态管理:明确的工作树状态管理
  • 历史追踪:保留工作树的历史记录

工作树保留机制

// 保留工作树
public String keepWorktree(String name) throws IOException {
    for (Map<String, Object> wt : worktrees) {
        if (name.equals(wt.get("name"))) {
            wt.put("status", "kept");
            wt.put("kept_at", System.currentTimeMillis() / 1000.0);
            keptWorktree = wt;
            break;
        }
    }
    saveIndex(index);
    // 保留状态:标记工作树为需要保留
    // 不自动清理:保留的工作树不会被自动清理
    // 时间戳记录:记录保留时间
}
  • 选择性保留:可以保留有价值的工作树
  • 长期存储:保留的工作树可以长期存在
  • 状态明确:明确的保留状态标记
  • 时间追踪:记录保留时间

事件总线集成

// 事件总线
static class EventBus {
    public void emit(String event, Map<String, Object> task, 
                    Map<String, Object> worktree, String error) {
        Map<String, Object> payload = new LinkedHashMap<>();
        payload.put("event", event);
        payload.put("ts", System.currentTimeMillis() / 1000.0);
        payload.put("task", task != null ? task : Map.of());
        payload.put("worktree", worktree != null ? worktree : Map.of());
        
        if (error != null) {
            payload.put("error", error);
        }
        // 结构化事件:标准的事件格式
        // 时间戳:精确的事件时间
        // 关联数据:关联的任务和工作树信息
        // 错误信息:支持错误事件记录
        
        String jsonLine = gson.toJson(payload) + "\n";
        Files.writeString(eventLogPath, jsonLine, 
            StandardOpenOption.CREATE, StandardOpenOption.APPEND);
        // JSONL格式:便于流式处理和分析
        // 追加写入:支持长时间运行的事件记录
    }
}
  • 全面审计:所有工作树操作都有完整的事件记录
  • 结构化日志:标准化的JSON事件格式
  • 时间序列:精确的时间戳序列
  • 错误追踪:完整的错误事件追踪
  • 可分析性:便于后续的数据分析

架构演进与价值

从 AutonomousAgentsSystem 到 WorktreeTaskIsolationSystem 的升级

维度AutonomousAgentsSystemWorktreeTaskIsolationSystem
代码隔离文件系统级Git仓库级
并行开发有限并行完全并行
版本控制外部集成原生集成
冲突避免手动管理自动隔离
专业程度通用系统专业开发系统

总结

完结撒花。。。

总体来说,这个开源网站系统性地拆解了一个高级AI编程智能体的构建过程,展现了一条清晰的能力演进路径:从具备基础感知和执行能力的单一智能体(工具与执行),发展到能够进行内部规划、分解任务、调用外部知识的协调者(规划与协调),再升级为可以管理资源、并行处理、支撑长时对话的高效执行者(内存管理与并发),最终演化为一个角色分明、通信顺畅、协同作战的智能体团队(协作)。

这条路径揭示了一个核心范式:强大的AI Agent系统并非一蹴而就,可以说是通过不断叠加精心设计的、模块化的机制(如状态管理、上下文隔离、知识外挂、异步处理、消息传递)逐步构建而成。

每个阶段都解决了前一阶段遇到的关键瓶颈,最终将这些模块像积木一样组合,形成一个既可应对复杂项目开发,又能高效管理自身资源与协作的成熟智能体系统。这为我们构建自己的生产级AI Agent提供了宝贵的蓝图和实战指南。

我前几天在本站逛的时候了解到 GitHub 不允许一个人拥有多个 GitHub 免费账号。但是好像只有滥用或者看起来滥用的时候才会被封号?所以有没有规避的方法?实在不行我就只能把现在常用的号注销了,反正也没有太多重要的东西,转移到其他网站上就行了。就是不知道哪个网站合适。国内的我不想用,虽然没有违法的东西但是国内那个审核误伤太坑了。我那个常用号只有一个介绍我的点子的项目我比较在意,其他的我感觉价值都不大。

我的现在的常用 GitHub 号在其他网站上相同的 ID 相关的黑历史比较多,我怕那些黑历史干扰我做自媒体,所以我就弄了个新 GitHub 号。我做的自媒体有点特殊,需要 GitHub 。两个号都在同一台电脑上登录了,比较慌。不过新号还没做什么。

我感觉知乎的保存效果可能不比 GitHub 差。我看了一下我知乎主页置顶的那篇介绍我的点子的文章的数据,最近还有一些零星的阅读。就是不知道那些阅读是不是我的活动带来的,不知道我挂了之后还能不能有一些零星的阅读。也许我可以期待一下将来能出现从整个互联网获取点子的 AI ?

ai 生成爽是很爽,但是数量太多了,每次阅读起来真的太累了
今天加了两个函数,回来一看,又多了 300 行,也不能说它错,因为字段检验,格式又是自己写的要求
本来立项的时候,规定一个文件最长就 400 行,现在都多余,无非是拆分一堆小文件,还不如一个文件两千行,省得点了
整个项目搞下来都几万行了
读是肯定要读的,不然后面报错,只能跟 ai 一起赌运气了,好累啊,难道要用 AI 控制 AI?

每周一个工程师值得拥有的精选好物,本期山姆零食大礼包~,精选山姆 TOP 组合,送女朋友也不错~

老规矩,回复即可参与!


免五低佣低两融开户,找老倔驴,靠谱! 开户选择多还靠谱,聚合几十家券商优惠,连接 100+家营业部,已帮助 2000 人+。

  • 只玩 ETF 的聪明钱、银河 ETF 万 0.5 ,1 毛起收非常合适。适合大多数散户,宽指 ETF+逆回购+打新。
  • 低门槛有申万5 万放几天完成调佣保持 1.5 万两个月,或者国泰入 11 万放几天完成调佣保持 2.5 万
  • 量化选手 miniqmt 免五申万可选,不免五低门槛江海东莞国金可选,ptrade 10 万有山西,学习入门不错的,也是吃 AI 红利一种方式。
  • 50W 免五国泰国信可选,两融利率选西南广发银河平安等,最低可以万 0.7 免五。

另外,渣打远程开港卡(存刀年化 3.7%,还能远程开港卡),港美 FX 可选;

开户点这里: https://jue.lv/kh/V2/202604c (10+券商可选,开户有礼!)

友情提醒:不因奖品而参与股市,得不偿失!

OpenJDK

JEP 532——模式、instanceof 和 switch 中的基本类型(第五个预览版)——已从JEP 草案 8379318升级候选状态。继在 JDK 23 至 JDK 26 中进行过四轮预览之后,该 JEP 提出了第五个预览版本,内容保持不变。该功能允许在所有模式上下文中使用基本类型,并扩展 instanceof 和 switch 结构以支持所有基本类型,从而增强了模式匹配功能。

JDK 27

JDK 27 的早期访问构建Build 17于上周发布,它是 Build 16 的升级,修复了各种问题。要了解关于这个构建的更多细节,请查阅发布说明

 

Oracle 公司 Java 平台组首席架构师Mark Reinhold已经正式提出了 JDK 27 的发布计划,具体如下:

  • Rampdown Phase One( 从主干分叉):2026 年 6 月 4 日

  • Rampdown Phase Two:2026 年 7 月 16 日

  • 初始发布候选:2026 年 8 月 6 日

  • 最终发布候选:2026 年 8 月 20 日

  • 正式发布:2026 年 9 月 14 日

 

这个拟议时间表的审议期已于 2026 年 4 月 13 日(星期一)结束。

 

对于JDK 27,欢迎开发者通过Java Bug 数据库报告缺陷。

Jakarta EE

在每周的Hashtag Jakarta EE 博客中,Eclipse 基金会 Jakarta EE 开发大使Ivar Grimstad介绍了 Jakarta EE 12 的最新进展,他在文中写道:

在上周的 Jakarta EE 平台电话会议上,我们讨论了将 Jakarta NoSQL 纳入 Jakarta EE 12 规范所需的条件。目前有部分成员对将其纳入规范仍持保留态度,因此,如果你希望看到 Jakarta NoSQL 被纳入 Jakarta EE 12,请积极发表意见。如果你有空闲时间,也可以参与进来,协助项目解决平台项目提出的问题,以增强其作为候选规范的竞争力。

目前,Jakarta EE 12 的第 2 个里程碑版本有多个规范正在制定当中,其中包括:Jakarta Connectors 3.0Jakarta Faces 5.0Jakarta Transactions 2.1以及Jakarta JSON Processing 2.2

Spring Framework

Spring Cloud Gateway团队披露了 CVE-2026-22750 漏洞,即“Spring Cloud Gateway 中 SSL Bundle 配置被静默绕过”。该漏洞存在于 4.2.0 版本中,具体表现为:系统会忽略spring.ssl.bundle属性设置,而且不会进行记录或发出警告,并默认采用 SSL 配置。这可能会使管理员产生一种虚假的安全感。

Hibernate

Hibernate ORM7.3.0.Final 版本发布,带来了 Bug 修复和一些新功能,包括:新增KeyType枚举,允许使用 Jakarta PersistenceEntityManager接口中定义的重载方法find(),以及Session接口中定义的方法findMultiple(),让开发人员除了使用实体标识符之外,还可以基于自然 ID 进行实体加载; 此外,新增@NaturalIdClass注解,用于对非聚合的复合自然 ID 进行建模,方便加载操作,其实现与 Jakarta Persistence 中用于非聚合标识符建模的 @IdClass 注解一致。要了解有关该版本的更多详细信息,请参阅发布说明

Open Liberty

Open Liberty26.0.0.4Beta 测试版包含以下内容:支持 JDK 26; Open Liberty 新特性:jakartaee-11.0(Jakarta EE 11 平台)、webProfile-11.0(Jakarta EE 11 Web Profile)、appAuthentication-3.1(Jakarta Authentication 3.1)、appAuthorization-3.0(Jakarta Authorization 3.0)以及appSecurity-6.0(Jakarta Security 4.0); 更新 mcpServer-1.0 ,支持工具动态注册。

LangChain4j

LangChain4j1.13.0 正式(连同第 23 个 Beta 测试版)发布,提供了 Bug 修复和一些值得注意的变更:新增RecoverabilityITPendingResponse类,用于智能体系统执行状态的持久化与恢复; 新增lassPathSkillLoader类,该类使用类路径而非文件系统来解析skills目录;新增HibernateContentRetriever类,用于通过Hibernate 查询语言(HQL)检索数据。要了解有关该版本的更多详细信息,请参阅发布说明

Keycloak

Keycloak26.6.0 版本发布,带来了 Bug 修复、依赖项升级以及以下新功能:全面支持 RFC 7523,即用于 OAuth 2.0 客户端身份验证和授权的 JSON Web Token (JWT) 配置文件,该规范允许使用外部签名的 JWT 断言来请求 OAuth 2.0 访问令牌; 实验性支持OAuth 客户端 ID 元数据文档(CIMD) ,使 Keycloak 能够作为最新版本模型上下文协议(MCP) 规范的授权服务器;全面支持基于 JUnit 6 的Keycloak 测试框架。要了解有关该版本的更多详细信息,请参阅发布说明

Helidon

Helidon 4.4.1 版本发布,带来 Bug 修复和一些重要的变更,包括:实现Smile 数据格式;支持通过 JavaSSLContext类配置 LangChain4jMcpClient接口的实现,以支持传输层安全(TLS)协议;恢复对嵌套配置键的环境变量遍历进行懒加载的机制。要了解有关该版本的更多详细信息,请参阅发布说明

谷歌智能体开发工具包

谷歌发布Agent Development Kit (ADK) for Java1.1.0,带来了 Bug 修复以及以下新功能:新增ChatCompletionsRequestChatCompletionsResponse类,作为聊天自动补全功能的数据传输对象;在LlmRegistry类中添加对Gemma模型的支持;新增用于跟踪管理的抽象类EventData。要了解有关该版本的更多详细信息,请参阅发布说明

JetBrains

JetBrains宣布,他们在 2025 年 1 月推出Junie CLI现在已经能够检测并自动连接安装在开发者工作站上的任何 JetBrains IDE。该功能带来的好处包括:理解项目上下文;在单存储库或测试配置较为复杂的项目中自动运行测试;提供精准重构;构建和调试复杂项目;使用语义代码导航。这项新功能目前还处于测试阶段,并计划支持 Android Studio。请注意,Junie CLI 是一项订阅服务。

 

原文链接:

https://www.infoq.com/news/2026/04/java-news-roundup-apr06-2026/

低空司回应无人机「起飞难」

据《财新》报道,在 4 月 17 日举行的国新办发布会上,国家发展改革委低空经济发展司司长郑剑回应称,针对无人机飞行活动审批难问题,该司正在与有关部门研究推广部分地方「扫码飞」等好经验、好做法,提高飞行计划审批效率。这是无人机监管收紧以来,官方首次回应用户抱怨的热点话题。

按照现行规定,无人机须在民航局「民用无人驾驶航空器综合管理平台」(UOM)或「无人驾驶航空器公安管理平台」完成实名登记,此后每次起飞都要提前申报,获准后方可飞行,否则用户将面临公安部门的罚款或者拘留。在具体执行中,上述规定让不少无人机用户难以适应。

低空司此次回应提及的「扫码飞」,是四川省为纾解飞行需求,在无人机管理领域开展的探索。当地用户通过小程序完成线上报备后,即可在适飞空域飞行,无需再亲自前往属地派出所办理手续。除四川省外,2 月初,上海在政务服务 App「随申办」也上线了类似「扫码飞」的无人机管理服务模块,并在中心城区管制空域内划出三处无人机飞行体验区。

业内人士表示,国内低空空域主要由军用航空部门和民用航空部门分区进行管理,军航拥有最终裁判权,空域的使用权最终都要获得属地空军的批准,地方政府参与度仍然不足。国内某无人机企业负责人指出,当前飞行申请数量庞杂,但军民航审批能力相对有限,应对之道是将适飞空域和部分管制空域管理权限交给地方政府,同时提高审批的自动化水平。

此前在 2023 年 11 月 8 日,民航局发布了《空域管理条例(征求意见稿)》,提出国家分级设立空中交通管理联合运行机构,负责本责任区空域管理有关事项。行业人士表示,该条例的立法程序有望于 2026 年完成。


7 家电商平台因幽灵外卖被罚没 35.97 亿元

据《财新》报道,4 月 17 日,市场监管总局发布公告称,依法对拼多多、美团、京东、饿了么(现淘宝闪购)、抖音、淘宝、天猫等 7 家电商平台「幽灵外卖」系列案作出行政处罚决定,责令 7 家电商平台改正违法行为,暂停新增蛋糕店铺 3 至 9 个月不等,并处以罚没款共计 35.97 亿元。同时,对 7 家平台企业法定代表人和食品安全总监合计处以罚款 1968.74 万元。拼多多的罚没金额最高,为 15.22 亿元;三家外卖平台美团、京东、饿了么分别为 7.46 亿、6.35 亿、5.58 亿元;抖音、淘宝、天猫分别为 5689 万、4697 万、3174 万元。

「幽灵外卖」指的是没有堂食场地,或已经关门停业,却依旧上线于各类外卖平台的商家。而转单平台为平台商家提供转单服务,即允许转单店铺将消费者订单转交其他食品经营者加工制作。

根据市场监管总局公告,上述 7 家电商平台对入网食品经营者许可证审核把关不严,未依法履行资质审查义务;与转单平台签订合作协议,明知或应知转单行为侵害消费者合法权益,但未采取必要措施;7 家电商平台法定代表人和食品安全总监,负有食品安全管理责任,但未全面履行有关岗位职责。

另外,根据市场监管总局对拼多多经营主体上海寻梦信息技术有限公司的行政处罚决定书,但在案件调查过程中,当事人多次出现无正当理由拒绝提供有关材料、信息,或提供虚假材料、信息等行为,甚至采用暴力、软对抗等手段阻碍监管执法。据此前报道,12 月 3 日,在案件调查过程中,拼多多数名员工与市场监管局工作人员产生冲突,后拼多多的政府关系部门多名员工被辞退,并引发员工维权舆情。

此前在 2025 年 11 月,市场监管总局指导京东、美团、拼多多、抖音电商、小红书、淘宝、微信小店、快手电商 8 家网络食品交易第三方平台企业共同发起并签署《网络食品交易第三方平台食品安全管理自律公约》。2026 年 2 月 26 日,市场监管总局宣布,《网络餐饮服务经营者落实食品安全主体责任监督管理规定》将于 6 月 1 日正式实施,其中要求外卖平台应当对外卖商家进行实名登记,并通过实地核查等方式,保证外卖商家经营资质证书载明的信息与实际情况相符。


Kindle for PC 将停止运行,去 DRM 途径再减

Good e-Reader 报道,亚马逊近日通过弹窗通知用户,将于 6 月 30 日正式停用现有的 Kindle for PC 桌面客户端。届时,该软件将完全不能使用。亚马逊方面确认,目前正在开发一款全新的 PC 端 Kindle 应用程序,仅兼容 Windows 11 操作系统,并且只允许通过微软应用商店下载安装。

原版 Kindle for PC 客户端发布于 2009 年。长期以来,该软件常被用于将电子书下载至本地,进而剥离 DRM(数字版权管理)加密保护。为修补漏洞与打击盗版,亚马逊近年来已多次提示要求用户升级客户端,并限制旧版本访问或下载电子书的功能。此前在 2023 年,亚马逊已经停用了旧版 Kindle for Mac,将其替换为仅限在苹果 Mac App Store 下载的新版。

与独立安装版相比,基于应用商店分发的版本一般在技术上更难破解。亚马逊此次将 PC 客户端整体转向微软应用商店,意在进一步收紧对 Kindle 的管控,以满足出版商对于防范电子书盗版的要求。


Claude Opus 4.7 token 消耗量显著提高

根据 Claude Opus 4.7 的官方迁移指南,Opus 4.7 改用了新的 token 分词器(tokenizer),将导致 token 用量相比之前版本最多升高 35%。

但根据用户自行测试情况,这只是一个保守的估计。一项测试中,TypeScript 代码的 token 数增是原来的 1.36 倍,英文技术文档为 1.47 倍,一次包含 80 轮对话的 debugging 过程成本从约 6.65 美元涨至近 8.80 美元。另一项汇集了五百多条数据的统计显示,token 用量平均提高 38.6%。不过,中日韩(CJK)等非拉丁语系文本的 token 消耗基本保持不变。

新版分词器将英文和代码切分成了更小的片段,单个 token 包含的字符数显著下降。Anthropic 声称,这一调整能让任务执行更准确。但许多用户已经在抱怨本来就消耗过快的使用额度更加容易用完。


谷歌 IPv6 流量占比首次过半

谷歌公布的数据显示,在 2026 年 3 月 28 日这一天,通过 IPv6 访问其服务的全球用户流量占比达到 50.1%,高于去年同期的 46.33%,也是该统计数据首次突破半数大关。

不过,其他互联网基础设施机构的数据表明,IPv6 尚未全面占优。Cloudflare 的监测服务指出,目前 IPv6 仅占全球 HTTP 请求来源的 40.1%;亚太互联网络信息中心(APNIC)的数据也显示,具备 IPv6 能力的网络比例约为 43.13%。

IPv6 的诞生旨在解决上一代协议 IPv4 地址枯竭的问题。IPv4 仅能提供约 43 亿个 IP 地址,而采用 128 位地址长度的 IPv6 能够提供几乎无限的地址空间。然而,由于新协议并未带来太多颠覆性的新功能,加之网络地址转换技术(NAT)的广泛应用允许海量设备共享同一个公网 IPv4 地址,许多机构选择通过 NAT 技术来缓解地址短缺,导致 IPv6 的全球普及速度长期滞后于预期。

在 IPv6 的普及进程中,不同国家和地区的推进速度存在显著差异。由于互联网发展早期的分配机制相对宽松,欧美国家抢先获取了大量 IPv4 资源。相比之下,中国、印度等人口大国分配到的 IPv4 地址严重不足,促使这些国家更早、更大力度地推进 IPv6 部署。APNIC 的数据显示,包括中国在内的亚太地区 29 个国家,已于 2025 年率先跨越了 IPv6 普及率 50% 的门槛。


数码和智能产品成消费品以旧换新热点

据新华社报道,根据商务部全国家电以旧换新、数码和智能产品购新信息系统数据,截至 4 月 16 日,数码和智能产品购新 4243.3 万件,同比增长 31.7%;销售额 1261.53 亿元,同比增长 36.4%。其中,手机销售占比超八成。

今年以来,手机等数码产品购新补贴提质扩容为数码和智能产品购新补贴,首次将智能眼镜纳入补贴范围,带动通讯器材类商品零售额保持较快增长。截至 4 月中旬,16 个智能眼镜国产品牌参与购新补贴政策,带动重点企业销售量、销售额同比分别增长 42.4%、46.8%。

据了解,在家电以旧换新、数码和智能产品购新补贴政策带动下,1 至 3 月,限额以上单位通讯器材类商品零售额 2840 亿元,同比增长 20.8%,高于同期社会消费品零售总额增速 18.4 个百分点,在 16 类商品中位居第一。


不妨一看的简讯

  • 据日经新闻报道,目前,三星电子、SK 海力士和美光科技三大 DRAM 供应商仅能满足约 60% 的市场总体需求。到 2026 年中期,内存占低端智能手机制造成本的比例预计将从 20% 翻倍至近 40%。
  • 近日,英伟达 CEO 黄仁勋在播客节目 Dwarkesh Podcast表示,反对美国强化对中国芯片设备出口管制,因为中国拥有庞大的能源资源和充足的传统制造能力,完全可以通过堆叠来获取所需的庞大算力。他警告说,严格的出口管制会在无意中迫使中国建立一个强大且独立的独立技术栈,最终导致美国把世界第二大市场拱手让人,并危及美国技术标准在推向全球时的统治地位。
  • 根据微软发布的更新日志,在 Windows 11 Insider Preview Build 26300.8170 中,FAT32 分区容量限制从 32GB 增加到 2TB,但只能通过命令行操作。FAT32 的 32GB 容量是微软的人为限制,几十年来一直没有松动。
  • MacWorld 声称,今年 iPhone 18 Pro 的主打标志性配色将是深樱桃色(Dark Cherry);折叠屏 iPhone 展开状态下的机身厚度仅为 4.7 毫米,目前测试的仅有银白色以及靛蓝色。


少数派的近期动态


你可能错过的好文章


    真的上瘾,停不下来。酒也不喝了,有空就坐在电脑前面。最近吭哧吭哧做了个 SEO 评测工具,auditedge.app,全部 ai 制作,自己看着还行,发出来让大家拍砖。砸醒我吧,太上瘾了。