你有没有过这种感觉:这道题明明做过,怎么换个数字又错了?
为什么当初看答案觉得“懂了”,一合上书脑子又一片空白?
我们常挂在嘴边的“粗心”,真的只是因为手抖或者眼花吗?

如果这些问题击中了你的膝盖,那么请承认一个残酷的事实:你从未真正解决过错题,你只是在掩盖错误。

大多数人的错题处理方式是“修正主义”:把红叉改成红勾,把正确答案抄写三遍。这就像是给化脓的伤口贴创可贴——表面上好了,里面还在烂。

错题不是用来“改”的,是用来“诊”的。 每一道错题,都是你知识体系中一个隐蔽的“病灶”。如果你听不懂它的“求救信号”,它就会变着法子反复折磨你。

今天,我们要介绍的这套 AI错题深度分析指令,就是要让 AI 化身福尔摩斯,帮你透过错误的表象,挖出思维深处的“元凶”。

🚨 错觉:你以为的“懂了”只是“记住了”

在传统的学习模式下,我们很难进行深度的错因分析。原因很简单:认知遮蔽

当你看到正确答案时,大脑会自动脑补出一条“合理路径”,让你产生一种“我本来也能做对”的错觉。这种错觉掩盖了你逻辑链条上的真实断点。

比如,一道数学题做错了,老师会说“公式用错了”。但为什么会用错?是因为概念混淆?还是适用条件没记牢?亦或是题目中的陷阱诱导了你的直觉?

没有深度复盘,这些问题永远是黑箱。

而 AI 的介入,打破了这个黑箱。它不给你留面子,不给你找借口,它只做一件事:像外科医生一样,层层解剖你的思维过程。

🛠️ 核心指令:给错题做一次“CT扫描”

这套指令的设计哲学,不再是简单的“给出正确答案”,而是强制进行“归因溯源”。

它要求 AI 扮演一位拥有20年经验的学习诊断专家。它不会轻易放过任何一个“粗心”,而是会追问:

  • 是知识性漏洞?(根本没掌握)
  • 还是理解性偏差?(以为掌握了但理解歪了)
  • 甚至是方法论缺失?(有力气没处使)

它生成的不仅是答案,更是一份思维病理报告

🧬 错题分析 AI 提示词

# 角色定义
你是一位资深的学习诊断专家和教育分析师,拥有20年教学经验,精通认知心理学和教育测量学。你擅长通过错题分析精准定位学生的知识薄弱点,能够从错误中挖掘深层原因,并制定个性化的补缺策略。

你的核心能力包括:
- 🔍 精准识别错误类型(知识性错误、理解性错误、应用性错误、粗心错误)
- 🧠 深度分析错误根因(知识盲区、概念混淆、方法缺失、思维定式)
- 📊 系统梳理知识关联(前置知识、关联知识点、拓展知识)
- 📝 制定针对性补缺方案(补什么、怎么补、练什么)

# 任务描述
请对以下错题进行全面、深入的分析,帮助学习者:
1. 理解错误的本质原因
2. 掌握正确的解题思路
3. 建立系统的知识补缺计划
4. 防止同类错误再次发生

**输入信息**:
- **学科**: [如:数学/物理/英语/化学等]
- **年级/阶段**: [如:高二/大一/考研等]
- **题目内容**: [完整题目描述]
- **学生答案**: [学生给出的错误答案或解题过程]
- **正确答案**: [标准答案,可选]
- **错误频次**: [首次/多次/高频,可选]

# 输出要求

## 1. 错题诊断报告

### 📋 基础信息
- 题目类型
- 涉及知识点
- 难度评估(⭐~⭐⭐⭐⭐⭐)

### 🔍 错误分析
#### 错误类型判定
- [ ] 知识性错误:基础知识掌握不牢
- [ ] 理解性错误:概念理解有偏差
- [ ] 应用性错误:知识迁移能力不足
- [ ] 方法性错误:解题方法/技巧欠缺
- [ ] 粗心性错误:审题/计算/书写疏忽

#### 根因深度剖析
[详细分析错误的深层原因,包括但不限于:]
- 具体哪个知识点存在漏洞
- 哪个概念理解有误
- 哪个解题步骤出现偏差
- 思维过程中的逻辑断点

### ✅ 正确解法详解
[提供完整的正确解题过程]
1. 审题要点
2. 解题思路
3. 详细步骤
4. 答案呈现
5. 解题反思

## 2. 知识补缺地图

### 🗺️ 知识点定位
```
前置知识 → 当前知识点 → 关联知识 → 拓展应用
    ↓           ↓           ↓           ↓
  [列出]      [核心]      [列出]      [列出]
```

### 📚 必补知识清单
| 优先级 | 知识点 | 掌握程度 | 补习建议 |
|--------|--------|----------|----------|
| 🔴高 | [知识点1] | 未掌握 | [具体建议] |
| 🟡中 | [知识点2] | 部分掌握 | [具体建议] |
| 🟢低 | [知识点3] | 需巩固 | [具体建议] |

## 3. 个性化补缺方案

### 📖 学习任务
- **今日任务**(15-30分钟):[具体内容]
- **本周任务**:[系统补习计划]
- **巩固任务**:[长期复习策略]

### 📝 配套练习建议
- **基础练习**:[2-3道巩固基础的题目描述或类型]
- **变式训练**:[2-3道变式题目类型]
- **综合应用**:[1-2道综合题目类型]

### ⚠️ 易错提醒
[总结此类题目的常见陷阱和注意事项]

## 4. 防错策略

### 🛡️ 同类题型解题口诀/方法
[提炼简洁易记的解题口诀或检查方法]

### ✍️ 错题本记录建议
建议以下格式记录本题:
```
【错题摘要】一句话概括题目
【错因标签】#知识漏洞 #概念混淆 #方法缺失 #粗心
【关键提醒】解这类题时必须注意的1-2个点
【复习周期】1天后/3天后/7天后
```

# 质量检查清单

在完成输出后,请自我检查:
- [ ] 错误类型判定准确,有理有据
- [ ] 根因分析深入到具体知识点层面
- [ ] 正确解法步骤完整,逻辑清晰
- [ ] 知识补缺清单具有可操作性
- [ ] 练习建议与错误类型匹配
- [ ] 语言表达适合目标学习者理解

# 注意事项
- 分析要基于学生实际错误,避免泛泛而谈
- 正确解法要分步骤详解,不跳步
- 补缺建议要具体可执行,避免空洞
- 语言风格要鼓励式,避免批评式
- 如果信息不足,可以询问澄清而非猜测

# 输出格式
请按照上述结构,以清晰的Markdown格式输出完整的错题分析报告。使用适当的emoji和表格增强可读性。

⚡️ 现场实测:一道“简单”英语题的翻车现场

为了看看这位“AI专家”到底有几把刷子,我们找来了一道经典的高中英语易错题进行测试。

题目:The book __ on the desk belongs to Tom.
选项:A. lying B. lied C. lay D. lies
学生错选:D (lies)

如果你也选了D,或者在B和C之间犹豫,那么请看AI的诊断(节选):

🔍 错误分析

错误类型判定:✅ 理解性错误(句子结构理解有偏差)

根因深度剖析
你的错误本质是误把定语当作了谓语

  • 你选D(lies),说明你认为这是句子的谓语动词。
  • 但请注意:句子已有谓语动词"belongs"。
  • "____on the desk"是后置定语,修饰"The book"。
  • 定语位置需要用非谓语动词,不能用谓语形式。

看到没?它没有简单地告诉你“A是正确答案”,而是一针见血地指出了你思维模型中的漏洞——你没看出来句子已经有谓语了。这才是你下次遇到类似题目不再选错的关键。

接着,它还会给你一个防错口诀

"一个句子一个谓,多余动词变非谓,主动进行用-ing,被动完成用-ed"

是不是瞬间就通透了?

💡 给你的错题本升个级

错题本不应该是一个“垃圾回收站”,而应该是一个“战略资源库”。

以前,我们整理错题是靠手抄,费时费力效果差。现在,你可以试着这样用这套指令:

  1. 拍照/语音输入:把题目和你的错误答案丢给AI。
  2. 生成报告:获取深度诊断和补习清单。
  3. 定向爆破:根据AI建议的“变式训练”,找几道同类题马上练习。
  4. 标签管理:把AI总结的“错因标签”记下来,考前只看这些标签对应的知识点。

这不再是简单的“订正”,这是一次精准的知识迭代

不要让你的错题白白牺牲。从今天起,用这套指令,榨干每一道错题的剩余价值。记住,比做对一道题更重要的,是彻底消灭一类错误。

AI 驱动招聘变革:从流程电子化到决策智能化的跨越
在数字化浪潮席卷各行各业的今天,人力资源领域的数字化转型早已不是新鲜话题。ERP系统的普及、自动化流程的搭建,让企业招聘摆脱了纯粹的纸质化办公,迈入了“流程电子化”的新阶段。然而,这种看似便捷的数字化,实则暗藏诸多局限——简历筛选仍停留在关键词匹配的浅层阶段,面试评价难逃主观偏见的桎梏,企业往往在海量信息中耗费大量精力,却仍难避免错失核心人才的遗憾,“伪数字化”的标签始终难以摘除。
生成式 AI 的崛起,为招聘行业带来了真正的颠覆性力量,它打破了传统工具的被动属性,以主动洞察、智能交互的姿态,重构了人才甄选的全流程。这一变革的核心,在于将招聘从“事务性操作”升级为“战略性决策”,精准破解了长期困扰行业的低效、主观、高成本三大痛点。
在效率与精准度的双重突破上,AI 面试智能体成为无可替代的核心引擎。通过严格的心理学效度与信度检验,其评估结果与资深面试官形成高度契合,为招聘决策提供了可量化的科学依据。不同于传统简历筛选的片面化,AI 能够深度解析候选人履历,精准定位核心成就与信息疑点,构建层层递进的提问逻辑,既实现了信息核实的严谨性,又能深度挖掘候选人的潜在能力。更值得关注的是,单一智能问题即可同步测评多项核心胜任力,无缝衔接初筛与复试环节,使整体评估效率提升超五成,不仅解放了 HR 从海量简历中“淘金”的时间,更让业务面试官摆脱了初试阶段的重复劳动,将精力聚焦于核心人才的深度沟通。同时,针对编程、财务、工程等不同专业领域,AI 可实现精准化测评,确保人才筛选与岗位需求的高度匹配。
而在候选人体验与雇主品牌传递上,AI 招聘系统也实现了质的飞跃。告别了传统 AI 面试的生硬机械,新一代系统具备了敏锐的情绪感知能力,能够捕捉候选人的语速、语调变化,以专业的引导方式帮助候选人放松心态,充分展现真实水平,避免因紧张导致的评价失真。音画同步技术的应用,让虚拟面试官的表情、口型与语音节奏完美契合,赋予交互满满的温度,彻底摆脱“纸片人”式的疏离感。全程无需手动操作启停,语音自动识别功能让问答流转如真人交谈般自然流畅,极大提升了面试的沉浸感。此外,候选人可随时就职位详情、团队文化、发展路径等问题发起咨询,AI 基于企业知识库提供即时、一致的专业解答,在完成人才评估的同时,实现了雇主价值的高效传递,让每一次面试都成为雇主品牌的加分项。
AI 驱动的招聘变革,绝非对传统招聘逻辑的否定与取代,而是以技术赋能的方式,实现了流程优化与价值升级。它让招聘摆脱了“伪数字化”的束缚,从“流程电子化”真正迈向“决策智能化”,为企业在日趋激烈的人才竞争中搭建起核心优势。未来,随着 AI 技术的持续迭代,招聘行业将进一步突破时空限制,实现更精准的人才匹配、更高效的流程运转、更优质的双向体验,成为企业吸引并留住核心人才的战略支撑,为企业的长远发展注入源源不断的人才活力。

前言:一场技术与激情的双向奔赴

当 2025 年秋季的第一片梧桐叶飘落在交大校园时,一场关于人工智能未来的探索正在悄然展开。这不仅是技术的传授,更是认知的革新——从被动使用AI工具到主动创造智能体,从理论认知到工程实践。上海交通大学“AI赋能智汇高校实训营”正是这样一座桥梁,连接着学术前沿与产业实践,也连接着青年学子与AI的未来。

实训营概况速览

  • 时间: 2025年秋季学期
  • 地点: 上海交通大学(闵行校区)
  • 参与规模: 超过300名交大学子
  • 核心目标: 从零掌握大模型本地部署与微调全流程
  • 特色亮点: 国内首个全面基于NPU生态的大模型实训课程

能力提升三维度评估

同学们的“高光时刻”数据

  1. 参与度爆表

    • 课程满意度评分:4.8/5.0
    • 课后代码提交率:92%
    • 平均每人完成3.2个微调实验
    • 累计GPU/NPU计算时长:超过5,000小时
  2. 成果展示墙

    • 37个创意微调项目诞生
    • 12个项目进入 AI 社区“优秀案例库”
    • 最受欢迎应用方向:科研助手、创意写作、代码生成

技术实践全记录:从环境搭建到模型部署

环境配置篇:跨越“第一道门槛”

挑战场景还原:

“老师,torch_npu导入报错了!”
“镜像选择哪一个是正确的?”
——这是开课时最频繁的问题

我们的解决方案:

# 标准化环境配置流程(最终优化版)
# 1. 镜像选择黄金法则
PyTorch (openeuler-python3.10-pytorch2.1.0-openmind0.9.0) 
# 理由:Python3.10兼容性最佳,torch2.1.0与NPU适配最稳定

# 2. 依赖安装“避坑指南”
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
pip install torch==2.5.1 torch_npu numpy==1.26.4 transformers==4.52.4
# 关键发现:transformers 4.52.4对中文多模态支持最优

# 3. 环境校验“三连击”
python -c "import torch; import torch_npu; import vllm_ascend"
# 绿色√出现时,教室里响起的掌声至今难忘

教学反思:

  • 提前准备的“常见错误对照表”将问题解决时间缩短70%
  • “三人小组互助制”让基础较弱的同学也能跟上进度
  • 最受欢迎的教学创新:环境配置“闯关游戏”式教程

模型部署实战:见证“Hello World”时刻

技术路线演进:

Week 1: 基础文本模型 (Qwen2.5-3B)
Week 2: 视觉语言模型 (Qwen2.5-VL-3B)
Week 3: 国产多模态 (InternVL3.5-1B)

代码实践精华:

# 从“复杂难懂”到“一键部署”的蜕变

# 初版(学生普遍反映配置复杂)
# vllm serve /path/to/model --port 8000 --max-model-len 16384 ...

# 优化版(封装为simple_deploy.py)
from deployment_kit import ModelDeployer
deployer = ModelDeployer(model_name="Qwen2.5-VL-3B")
deployer.launch(port=8000, api_type="openai")

# 效果:部署时间从平均30分钟缩短至5分钟

互动环节亮点:

  • “模型对话接龙”:每组微调一个特色模型,串联成创意故事
  • “Bug排查大赛”:最快解决部署问题的组获得算力奖励
  • 最惊艳的学生作品:《红楼梦》风格的多模态对话模型

微调实操:让模型拥有“交大基因”

LoRA微调实战案例:

# 交大校史知识注入配置(student_project_01)
model_name: Qwen2.5-7B
dataset: sjtu_history_qa.json  # 学生自建的校史问答对
lora_config:
  r: 16
  alpha: 32
  target_modules: ["q_proj", "v_proj"]
training_args:
  num_epochs: 3
  per_device_train_batch_size: 4
  learning_rate: 2e-4

训练成果展示:

微调前:
问:上海交通大学何时成立?
答:交通大学是一所历史悠久的高校...

微调后:
问:上海交通大学何时成立?
答:上海交通大学前身为1896年创立的南洋公学,1921年定名为交通大学...
问:钱学森图书馆在哪里?
答:位于上海交通大学闵行校区,是为纪念校友钱学森而建...

技术突破点:

  1. 显存优化:QLoRA+梯度检查点,7B模型在24G NPU上可训练
  2. 数据质量:学生创新的“三阶段数据清洗法”
  3. 评估体系:自动化的ROUGE-L+BERTScore双指标评估

社区生态共建:AI 平台深度合作

AI 特色功能实践

功能模块使用频次学生评价亮点
模型库一键下载287次“比HuggingFace快5倍”
在线Notebook156次“随时随地继续实验”
模型市场分享42次“看到自己的模型被别人使用很有成就感”

优秀学生项目孵化

项目1:SJTU-CodePal

  • 团队:计算机系3名学生
  • 技术:基于DeepSeek-Coder微调
  • 特色:理解交大课程代码规范(如CS1101实验要求)
  • 成果:被《程序设计基础》课程组采纳为辅助工具

项目2:医工交叉文献助手

  • 团队:医学院+电院跨学科团队
  • 技术:Qwen2.5-VL微调
  • 特色:解析医学影像+文献摘要
  • 成果:在生物医学工程实验室实际部署

总结

当钱学森图书馆的灯光照亮同学们调试代码的身影,当东下院的键盘声敲响AI时代的序曲,我们深切感受到:教育最美的模样,就是点燃学生眼中的光。那些为环境配置而紧锁的眉头,那些看到模型成功响应时绽放的笑容,那些跨学科碰撞出的思想火花——这些瞬间汇聚成了2025年秋天最温暖的记忆。

感谢每一位参与其中的交大学子,你们的热情与创造力是这趟旅程最宝贵的风景。感谢所有支持单位提供的资源保障。人工智能的未来属于青年,而你们,正站在创造未来的起点上。

路虽远,行则将至;事虽难,做则必成。

LLM幻觉问题至今没有根治方案。RAG能缓解一部分,但成本高、架构复杂,而且只适用于有外部知识源的场景。而对于模型"应该知道但经常搞错"的那类问题,比如历史事件的时间线、人物履历的细节,RAG帮不上什么忙。

Chain-of-Verification(CoVe)的思路是既然模型会在生成时犯错,那就让它生成完之后再检查一遍自己的输出,把能发现的错误纠正掉,然后再给用户看。

听起来像是废话?关键在于"怎么检查"。

直接让模型审视自己刚写的东西,它大概率会坚持原有立场,这是确认偏差在作祟。CoVe的核心贡献是发现了一个绕过这个陷阱的方法:验证时必须把原始输出藏起来,让模型在"失忆"状态下重新回答事实性问题,然后用这些独立验证的答案去校对初稿。

某种意义上,这是给LLM装上了"系统2"思维:快思考先出初稿,慢思考再做验证。

工作流程:起草、规划、验证、修复

CoVe不是什么新的模型架构,它是一种提示编排模式,它把生成过程拆成四步:先让模型写初稿(这时候幻觉随便来),然后让它针对自己的初稿生成一组事实核查问题,接着独立回答这些问题,最后用验证过的事实重写原文。

Factored:真正的关键

前面说的四步里,第一、二、四步都是常规提示工程,用思维链就能搞定,而第三步才是核心。

让LLM一边看着自己写的东西一边验证,会有一个问题,这个在学术上管这叫"sycophancy",也就是说模型会顺着自己的话往下说。草稿就在上下文窗口里摆着,概率分布会被带偏,模型倾向于认同自己刚编出来的东西。

所以最简单的解决办法是把上下文剥掉。

CoVe论文里发现,回答验证问题时必须把原始草稿藏起来。举个例子:如果你问"根据这个草稿,X是不是在1998年发生的?"模型八成会点头同意自己。但如果你只问"X是什么时候发生的?"它就得老老实实从训练权重里检索答案,没有偏差可言。

隔离验证问题就是逼模型去查自己的知识库,而不是复读自己刚说过的话。

代码实现

下面是CoVe流程的Python实现,封装成一个类。注意第三步里的CRITICAL注释,那就是Factored验证的精髓。

 classChainOfVerification:  
    def__init__(self, llm):  
        self.llm=llm  

    defrun(self, query):  
        # Step 1: Baseline Generation
        # Let the model hallucinate freely here.
        draft_prompt=f"Question: {query}\nAnswer:"  
        draft=self.llm.generate(draft_prompt)  
        print(f"--- DRAFT ---\n{draft}\n")  

        # Step 2: Plan Verifications
        # Ask the model to identify what needs checking.
        plan_prompt=f"""  
        Context: {query}  
        Draft: {draft}  
        Task: Create a list of 3-5 verification questions to check the facts   
        in the draft. Output ONLY the questions.  
        """  
        plan_text=self.llm.generate(plan_prompt)  
        questions=self.parse_questions(plan_text)
        print(f"--- QUESTIONS ---\n{questions}\n")  

        # Step 3: Factored Verification (The Key Step)
        verification_results= []  
        forqinquestions:  
            # CRITICAL: Do NOT include 'draft' in this prompt context.
            # We want the raw model weights to answer this, uninfluenced by the previous lie.
            verify_prompt=f"Question: {q}\nAnswer:"  
              
            # Low temperature is crucial here for factual retrieval
            answer=self.llm.generate(verify_prompt, temperature=0)  
            verification_results.append((q, answer))  

        # Step 4: Final Synthesis
        # Now we bring it all together.
        verification_context=self.format_pairs(verification_results)  
        synthesis_prompt=f"""  
        Original Query: {query}  
        Draft Response: {draft}  
          
        Verification Data:  
        {verification_context}  
          
        Task: Rewrite the Draft Response to be fully accurate.   
        Remove any details contradicted by the Verification Data.  
        """  
        final_response=self.llm.generate(synthesis_prompt)  
          
        returnfinal_response  

    defparse_questions(self, text):  
        return [line.strip() forlineintext.split('\n') if'?'inline]  

    defformat_pairs(self, pairs):  
         return"\n".join([f"Q: {q}\nA: {a}"forq, ainpairs])

CoVe和RAG该怎么选?

每次聊到CoVe,总有人问:为什么不直接用RAG?

两者解决的是不同问题。

RAG适用于模型根本不可能知道答案的场景,比如你公司Q3的销售数据。CoVe适用于模型理论上应该知道、但可能搞混或偷懒的场景,比如按时间顺序列出纽约市历任市长。

而且研究表明两者可以混用:先用CoVe验证RAG检索回来的文档是否真的相关,再决定要不要用。代价是成本翻倍,但在医疗、法律这种高风险场景下,还是可行的。

从Vibe Coding到系统2代理

关注2026年初Agentic爆发的人,大概都听过"Ralph Wiggum"技术这个梗。

名字来自《辛普森一家》里那个喊着"我在帮忙!"却啥也没干成的角色。这技术的核心就是把LLM塞进一个while循环,让它反复尝试直到单元测试通过。暴力验证,Token消耗会爆表但最后确实能撞出正确答案。虽然听起来很好笑,实际上还挺管用。

工具增强版CoVe

opencode、OpenDevin、Windsurf这些现代自主代理已经在用"工具增强"版本的CoVe了。

它们不再只是问自己"这代码对不对",而是直接动手:先写代码,然后在沙盒里跑npm test或linter,读stderr输出,根据真实报错来修。

这就把CoVe的验证环节从概率猜测变成了确定性判断。

2026年的新拓扑:分支验证

最前沿的做法已经不是简单的线性循环了。是分支。

分支拓扑下,代理不是失败了就重试一次。它会同时提出三个修复方案,在三个隔离容器里并行跑,哪个能让构建变绿就提交哪个。

验证的消耗

这是2026年工程实践必须面对问题

Vibe Coding走系统1路线:快、便宜、但有20%左右的幻觉率,做原型够用。系统2代理反过来:慢、Token成本翻10倍、但可靠性过硬,生产环境离不开。

也就是说是拿计算资源换安心,当业务从聊天机器人升级到自主工程师,这笔成本不是能不能接受的问题,而是必须付的保险费——除非你想承担"Ralph Wiggum式"的风险,比如AI自己把数据库删了。

总结

CoVe的代价很明确:延迟。

生成初稿、生成问题、并行验证、综合重写,整套流程跑下来,Token消耗和响应时间基本翻四倍。对于实时聊天场景,这个延迟可能难以接受。但换个角度看,异步报告生成、代码审查、自动邮件起草这类任务,多等几秒换来输出可信度的大幅提升,这笔账怎么算都划算。

更值得关注的是CoVe带来的转变:过去几年,行业把大量精力投入到"如何让模型生成得更好"上——更大的参数、更多的数据、更精细的对齐。CoVe指向了另一个方向:与其追求一次生成就完美,不如承认模型会犯错,然后在架构层面把纠错机制build进去。

这和软件工程的演进路径很像。早期写代码追求一次写对,后来发现测试驱动开发、持续集成、灰度发布这些"验证优先"的实践才是规模化的正确姿势。

CoVe不会是终点,我们未来大概率会看到更多CoVe与RAG、外部工具、多模型交叉验证的组合方案。

https://avoid.overfit.cn/post/1f3da2d8396d44c6bab8bfea80405cb6

作者:Digvijay Mahapatra

在这里插入图片描述

摘要

这两年,跨屏协作在鸿蒙生态里出现得越来越频繁。
从最早的文件互传、多屏办公,到现在的教育课堂、车机联动,设备之间已经不再是“各干各的”。

在游戏领域,这个变化更明显:

  • 一块屏幕已经不够玩
  • 玩家希望多设备一起参与
  • 大屏负责画面,小屏负责操作

但很多开发者一提“跨屏游戏”,第一反应还是投屏、远程控制、镜像显示。
实际上,鸿蒙给的不是投屏方案,而是一整套分布式游戏协作能力

这篇文章就从游戏开发者的真实视角,讲清楚鸿蒙是如何把多设备变成“一个游戏系统”的。

引言

在传统系统里,如果你想做多设备协作游戏,通常意味着:

  • 自己写网络协议
  • 自己做设备发现
  • 自己处理数据一致性
  • 自己兜底各种异常情况

而在 HarmonyOS 里,这些事情被系统层直接兜住了:

  • 设备发现靠软总线
  • 状态同步靠分布式数据
  • UI 跨屏靠 Ability 调度

你要做的事情更偏向游戏逻辑设计本身,而不是重复造轮子。

接下来我们一步一步拆。

什么是鸿蒙里的跨屏游戏协作

跨屏不是投屏

先说一个很重要的点:

鸿蒙的跨屏游戏 ≠ 投屏

投屏的特点是:

  • 一端渲染
  • 另一端只是显示
  • 没有真正的协作逻辑

而鸿蒙的跨屏游戏,更像是:

  • 多设备同时运行
  • 各自承担不同功能
  • 通过系统级分布式能力协同

比如:

  • 手机只负责操作和技能
  • 平板或智慧屏负责主战场渲染
  • 游戏状态在多设备之间自动同步

一个最常见的跨屏游戏形态

手机(控制器)
  │
  │ 操作指令
  ▼
平板 / 智慧屏(主画面)
  │
  │ 游戏状态同步
  ▼
分布式数据中心

支撑跨屏游戏的三大核心能力

分布式软总线:设备能“找到彼此”

在游戏里,你最关心的不是网络协议,而是:

  • 能不能快速发现附近设备
  • 延迟够不够低
  • 掉线能不能感知

鸿蒙的分布式软总线解决的正是这些问题。

你不需要关心设备是:

  • Wi-Fi
  • 蓝牙
  • 局域网
  • 点对点

系统会自动选最优链路。

分布式数据管理:状态天然同步

跨屏游戏最怕的几个问题:

  • 状态不一致
  • 数据打架
  • 玩家看到的画面不同步

鸿蒙提供的分布式 KV 数据,天生适合游戏里的:

  • 玩家位置
  • 血量
  • 技能状态
  • 回合阶段

而且是系统级同步,不是你自己发包。

分布式 UI:屏幕不是绑死的

在鸿蒙里:

  • Ability 可以被拉起到其他设备
  • 游戏不用重新启动
  • 状态不需要你手动迁移

这对游戏来说很重要,因为你可以自由设计:

  • 哪个屏幕显示什么
  • 玩家如何参与
  • 随时切换设备角色

跨屏游戏的整体架构设计

一个可落地的结构示例

┌────────────┐
│ 手机端     │
│ 操作输入   │
│ 技能按钮   │
└─────┬──────┘
      │
      │ 分布式 KV 数据
      ▼
┌────────────┐
│ 平板端     │
│ 游戏主画面 │
│ 渲染逻辑   │
└────────────┘

手机不负责画面,平板不负责输入,各司其职。

实战核心:跨屏游戏状态同步 Demo

创建分布式 KV Store

import distributedData from '@ohos.data.distributedData';

const kvManager = distributedData.createKVManager({
  bundleName: 'com.example.crossgame',
  context: getContext()
});

const store = await kvManager.getKVStore('gameStore', {
  kvStoreType: distributedData.KVStoreType.SINGLE_VERSION,
  securityLevel: distributedData.SecurityLevel.S1
});

这个 store 在多设备之间是共享的。

手机端发送操作指令

// 模拟摇杆方向
async function sendMove(x: number, y: number) {
  await store.put('player_move', JSON.stringify({
    x,
    y,
    time: Date.now()
  }));
}

这里同步的是“操作”,而不是最终坐标。

平板端监听并更新角色

store.on('dataChange', (data) => {
  data.insertedEntries.forEach(entry => {
    if (entry.key === 'player_move') {
      const move = JSON.parse(entry.value as string);
      updatePlayer(move.x, move.y);
    }
  });
});

跨屏 UI:把主画面拉到大屏

从手机拉起平板的游戏界面

import featureAbility from '@ohos.ability.featureAbility';

featureAbility.startAbility({
  want: {
    bundleName: 'com.example.crossgame',
    abilityName: 'GameMainAbility',
    deviceId: 'remoteDeviceId'
  }
});

前提是:

  • 游戏状态已经存在分布式数据中
  • 新设备启动后直接读取即可

为什么这个能力对游戏很重要

你不需要:

  • 手动传进度
  • 重新初始化状态
  • 处理复杂的恢复逻辑

系统已经帮你兜底。

真实应用场景拆解

场景一:手机当手柄,大屏玩游戏

适合类型

  • 派对游戏
  • 本地多人
  • 家庭娱乐

逻辑示例

// 手机端:技能释放
await store.put('skill_cast', {
  skillId: 2,
  playerId: 'p1'
});
// 大屏端:技能响应
store.on('dataChange', (data) => {
  data.insertedEntries.forEach(e => {
    if (e.key === 'skill_cast') {
      castSkill(e.value);
    }
  });
});

场景二:非对称协作游戏

比如:

  • 一个人当指挥
  • 一个人实际操作
// 指挥端下达命令
await store.put('command', {
  type: 'attack',
  target: 'boss'
});

操作端只负责执行,不做决策。

场景三:教育 + 游戏化互动

老师平板控制节奏,学生手机参与。

// 教师端切换关卡
await store.put('game_stage', 'level_2');

学生端监听并同步切换界面。

常见问题 QA

Q1:分布式 KV 会不会太慢?

不会。
它适合的是:

  • 低频状态
  • 操作指令
  • 游戏阶段

高频帧同步需要更底层方案。

Q2:能不能用在竞技类游戏?

可以,但不建议直接用 KV 同步帧数据。
更适合:

  • 操作同步
  • 客户端预测
  • 状态校正

Q3:设备掉线怎么办?

KV 会自动触发变更事件,你可以监听:

  • 玩家退出
  • 状态回收
  • AI 接管

总结

从游戏开发角度看,鸿蒙的跨屏协作并不是噱头,而是一套真正能落地的系统能力

核心就一句话:

多设备在鸿蒙里,不是多个客户端,而是一个分布式游戏系统。

  • 软总线解决连接
  • 分布式数据解决同步
  • Ability 解决跨屏 UI
  • ArkTS 足够把 Demo 跑起来

在这里插入图片描述

摘要

随着智能终端越来越多,应用早就不再只运行在一台设备上。手机、平板、智慧屏、手表之间的协作,已经成了很常见的需求。在这种背景下,多设备任务该怎么分、分到哪台设备执行,就成了开发中绕不开的问题。

在鸿蒙系统中,这个问题并不是靠开发者“手动指定设备”来解决的,而是通过 设备能力感知 + 分布式调度机制 来完成。开发者更多关心的是:
这个任务适合干什么,而不是非要在哪台设备干。

本文会结合鸿蒙系统的分布式能力,介绍多设备任务分配的整体思路,并通过可运行的 Demo 代码,把这个过程完整跑一遍,最后再结合几个真实场景,聊聊它在实际项目中该怎么用。

引言

如果放在以前,一个应用基本只跑在一台手机上,最多考虑前后台切换。但现在不一样了:

  • 手机在你手里
  • 平板在桌子上
  • 智慧屏在客厅
  • 手表戴在手上

用户希望的是:
设备不同,但体验是连着的。

鸿蒙系统的分布式能力,正是为这种场景设计的。它不是简单的“跨设备通信”,而是把 任务、数据、能力 都变成可以在多设备之间流动的资源。

而多设备任务分配,本质上就是一句话:

把合适的任务,交给合适的设备去做。

鸿蒙多设备任务分配的整体思路

先发现设备,再谈分配

在鸿蒙系统中,只要设备在同一个分布式网络里,系统就能自动发现它们。
开发者不需要自己维护“设备表”,也不用关心设备什么时候上线、下线。

系统会帮你感知这些信息:

  • 设备类型(手机、平板、智慧屏)
  • 基本性能情况
  • 是否可信
  • 当前是否可用

你只需要在合适的时机拿到设备列表即可。

任务一定要能拆

多设备任务分配的前提是:
你的业务本身是能拆开的。

比如:

  • 页面展示是一块
  • 数据采集是一块
  • 计算处理是一块

如果一个任务从头到尾全写死在一个 Ability 里,那基本就没法分配了。

系统负责“怎么选设备”

在鸿蒙里,真正“选哪台设备执行”的逻辑,大部分是系统完成的:

  • 当前设备忙不忙
  • 网络情况好不好
  • 设备能力是否匹配
  • 是否更适合本地执行

开发者更多是通过 Ability 启动方式、Service 类型、数据同步方式 来间接影响分配结果。

核心实现方式一:跨设备启动 Ability

适合什么场景

这种方式最常见,适合:

  • 页面展示
  • 功能模块整体迁移
  • 用户可感知的交互任务

比如:
手机负责控制,平板负责显示大屏内容。

Demo:在平板上启动远程 Ability

import distributedDeviceManager from '@ohos.distributedDeviceManager';
import featureAbility from '@ohos.ability.featureAbility';

const BUNDLE_NAME = 'com.example.distributeddemo';

let deviceManager = distributedDeviceManager.createDeviceManager(BUNDLE_NAME);

function startRemotePage() {
  let devices = deviceManager.getTrustedDeviceListSync();

  devices.forEach(device => {
    if (device.deviceType === 2) { // 假设 2 表示平板
      let want = {
        bundleName: BUNDLE_NAME,
        abilityName: 'RemotePageAbility',
        deviceId: device.deviceId
      };
      featureAbility.startAbility(want);
    }
  });
}

代码说明

  • createDeviceManager:创建设备管理器
  • getTrustedDeviceListSync:获取可信设备列表
  • deviceType:用于简单区分设备类型
  • startAbility:指定 deviceId 后,Ability 会在远端设备启动

整个过程不需要你关心远端设备的进程、生命周期,系统会处理。

核心实现方式二:分布式 Service 执行任务

适合什么场景

这种方式更适合:

  • 计算密集型任务
  • 后台处理
  • 不需要 UI 的逻辑

比如:
手机采集数据,交给性能更强的设备做分析。

Demo:连接远端计算 Service

import featureAbility from '@ohos.ability.featureAbility';

function connectRemoteService(remoteDeviceId: string) {
  let want = {
    bundleName: 'com.example.distributeddemo',
    abilityName: 'ComputeServiceAbility',
    deviceId: remoteDeviceId
  };

  featureAbility.connectAbility(want, {
    onConnect(elementName, remote) {
      console.log('远程 Service 已连接');
      remote.sendMessage({
        command: 'startCompute',
        data: [1, 2, 3, 4]
      });
    },
    onDisconnect() {
      console.log('远程 Service 已断开');
    }
  });
}

代码说明

  • Service 在远端设备运行
  • 本地通过 IPC 的方式和远端通信
  • 计算逻辑完全在远端执行
  • 本地只负责发请求、收结果

这种方式非常适合“重计算、轻交互”的任务。

典型应用场景分析与示例

场景一:手机 + 平板的学习展示系统

场景说明

  • 手机负责控制、翻页
  • 平板负责展示课件内容

实现思路

  • 手机发现平板
  • 在平板启动展示 Ability
  • 通过分布式数据同步当前页码
import distributedData from '@ohos.data.distributedData';

async function syncPage(page: number) {
  let kvManager = distributedData.createKVManager();
  let store = await kvManager.getKVStore('pageStore');
  await store.put('current_page', page);
}

平板端监听数据变化,自动刷新页面。

场景二:多设备健康数据分析

场景说明

  • 手表采集心率
  • 手机做基础处理
  • 平板做数据可视化

实现思路

  • 手表同步原始数据
  • 手机过滤、预处理
  • 平板负责展示图表

核心在于:
任务不是“复制”,而是“分工”。

场景三:家庭智慧屏协同控制

场景说明

  • 手机是遥控器
  • 智慧屏负责 UI 展示
  • 计算逻辑放在智慧屏

实现思路

  • 手机只负责发指令
  • 智慧屏 Service 处理业务逻辑
  • 结果同步回手机

这种模式下,手机压力很小,体验反而更流畅。

常见问题 QA

Q1:我能不能指定“一定要某台设备执行”?

不推荐。
鸿蒙的设计思想是 声明需求,而不是指定设备
你可以通过能力需求去“引导”,但不建议写死。

Q2:设备突然下线怎么办?

系统会通知连接断开,
你需要做的只有一件事:
支持本地降级执行或重试。

Q3:分布式任务一定比本地慢吗?

不一定。
当任务本身就不适合本地执行时,
分布式反而更快、更省电。

总结

在鸿蒙系统中,多设备任务分配并不是一套复杂、难以理解的机制,它的核心思想其实很简单:

  • 把任务拆清楚
  • 描述好任务需求
  • 把调度交给系统

只要你在设计阶段考虑好“哪些任务适合分出去”,鸿蒙的分布式能力就能自然地帮你把事情做好。

一句话总结就是:

多设备任务分配,不是设备协作有多复杂,而是你有没有把任务设计清楚。

在这里插入图片描述

摘要

随着 HarmonyOS / OpenHarmony 在手机、平板、智慧屏、车机等多设备上的落地,应用的复杂度正在明显提升。页面不再只是简单展示,而是伴随着网络请求、数据计算、设备协同等大量逻辑。如果这些逻辑处理不当,很容易出现页面卡顿、点击无响应,甚至 Ability 被系统回收的问题。

线程阻塞,已经成为鸿蒙应用开发中最容易踩坑、也最影响体验的问题之一。本文将结合实际开发场景,用尽量口语化的方式,聊一聊在鸿蒙系统中如何系统性地避免线程阻塞,并给出可以直接运行的 Demo 代码。

引言

在早期的应用开发中,很多开发者习惯把逻辑直接写在点击事件里,或者在页面加载时同步读取数据。这种写法在简单页面中问题不大,但在 HarmonyOS 这种强调流畅体验和多设备协同的系统中,很容易暴露问题。

鸿蒙的 UI 是声明式的,系统对主线程(UI 线程)非常敏感。一旦主线程被占用,页面掉帧、动画卡住、操作延迟都会立刻出现。因此,理解哪些操作会阻塞线程,以及如何把这些操作合理地“挪走”,是每个鸿蒙开发者绕不开的一课。

下面我们从原理、工具、代码和真实场景几个角度,完整地拆解这个问题。

为什么线程阻塞在鸿蒙中这么致命

UI 线程到底在忙什么

在 HarmonyOS 中,UI 线程主要负责三件事:

  • ArkUI 页面渲染
  • 用户事件分发(点击、滑动等)
  • Ability 生命周期回调

简单理解就是:只要和“看得见、点得动”有关的事情,几乎都在 UI 线程上完成

一旦你在这里做了耗时操作,比如计算、IO、网络等待,页面就会立刻表现出“卡”的感觉。

常见的阻塞来源

在实际项目中,最容易导致阻塞的操作通常包括:

  • 同步网络请求
  • 文件读写
  • 数据库查询
  • 大量 for 循环计算
  • 人为 sleep 或死循环

这些操作本身不一定是错的,问题在于它们被放在了不该放的线程上

鸿蒙中避免线程阻塞的核心思路

一个总原则

可以把鸿蒙里的线程使用总结成一句话:

UI 线程只处理 UI,其他事情交给异步、线程池或 Worker。

围绕这个原则,系统也提供了多种工具,帮助开发者把任务“分流”。

异步编程是第一道防线

使用 async / await 处理耗时逻辑

在 ArkTS 中,官方推荐优先使用 Promise 和 async / await。它的好处是代码结构清晰,而且不会阻塞 UI 线程。

示例:页面加载网络数据

@Entry
@Component
struct AsyncDemo {
  @State message: string = '加载中...'

  build() {
    Column() {
      Text(this.message)
        .fontSize(20)
        .margin(20)

      Button('重新加载')
        .onClick(() => {
          this.loadData()
        })
    }
  }

  async loadData() {
    this.message = '请求中...'
    let response = await fetch('https://example.com/data')
    let result = await response.text()
    this.message = result
  }
}

代码说明

  • loadData 使用 async 声明,不会阻塞 UI
  • await 只是暂停当前函数执行,不会卡住页面
  • UI 更新完全由状态变化驱动

这是最基础、也是最常用的一种防阻塞方式。

TaskPool:处理计算和 IO 的利器

什么时候该用 TaskPool

当你遇到下面这些情况时,TaskPool 几乎是必选项:

  • 大量计算
  • 批量数据处理
  • 文件压缩、解析

可运行 Demo 示例

import taskpool from '@ohos.taskpool'

@Concurrent
function calculateSum(count: number): number {
  let sum = 0
  for (let i = 0; i < count; i++) {
    sum += i
  }
  return sum
}

@Entry
@Component
struct TaskPoolDemo {
  @State result: string = '等待计算'

  build() {
    Column() {
      Text(this.result)
        .fontSize(18)
        .margin(20)

      Button('开始计算')
        .onClick(() => {
          this.startTask()
        })
    }
  }

  startTask() {
    this.result = '计算中...'
    taskpool.execute(calculateSum, 1000000).then(res => {
      this.result = `结果是:${res}`
    })
  }
}

代码说明

  • @Concurrent 表示该函数可以并发执行
  • TaskPool 自动管理线程,不需要开发者手动创建线程
  • UI 线程只负责接收结果和更新状态

在真实项目中,使用 TaskPool 往往能立刻解决页面卡顿问题。

Worker:长期后台任务的选择

Worker 的使用场景

如果任务具有下面这些特点,就更适合使用 Worker:

  • 长时间运行
  • 需要持续处理数据
  • 与 UI 强隔离

比如日志分析、音视频处理、复杂解析等。

示例:使用 Worker 处理数据

主线程代码

let worker = new Worker('workers/data_worker.ts')

worker.postMessage({ action: 'start' })

worker.onmessage = (e) => {
  console.log('收到结果:', e.data)
}

Worker 线程代码

onmessage = function (e) {
  if (e.data.action === 'start') {
    let result = 0
    for (let i = 0; i < 500000; i++) {
      result += i
    }
    postMessage(result)
  }
}

代码说明

  • Worker 与 UI 线程完全独立
  • 即使计算时间较长,也不会影响页面交互
  • 通过消息机制进行通信

结合实际场景的应用示例

场景一:列表页面加载大量数据

问题:

  • 首次进入页面时一次性处理全部数据
  • 页面明显卡顿

解决思路:

  • 网络请求使用 async
  • 数据整理放入 TaskPool
async loadList() {
  let data = await fetchData()
  taskpool.execute(processData, data).then(list => {
    this.list = list
  })
}

场景二:文件导入与解析

问题:

  • 文件较大
  • 解析过程耗时

解决思路:

  • Worker 负责解析
  • UI 只显示进度
worker.postMessage({ filePath })

场景三:复杂计算驱动 UI 更新

问题:

  • 计算逻辑和 UI 耦合

解决思路:

  • 计算完全放到 TaskPool
  • UI 只订阅结果

QA 环节

Q:async / await 会不会阻塞线程?
A:不会,它只是让出执行权,不会卡住 UI 线程。

Q:TaskPool 和 Worker 怎么选?
A:短期、一次性的任务优先 TaskPool,长期或持续任务用 Worker。

Q:能不能在生命周期里做耗时操作?
A:不建议,生命周期函数应尽量轻量。

总结

线程阻塞并不是某一个 API 的问题,而是设计问题。在 HarmonyOS 中,系统已经为我们准备好了异步模型、TaskPool 和 Worker,只要遵循“UI 线程只做 UI”的原则,大多数卡顿问题都可以提前避免。

在真实项目中,提前做好任务拆分、线程规划,比后期排查卡顿要省心得多。这也是鸿蒙开发从“能跑”到“跑得顺”的一个重要分水岭。

本文引用了45岁老架构师尼恩的技术分享,有修订和重新排版。

1、引言

分布式IM聊天系统中,IM消息怎么做到不丢、不重、还按顺序到达?这个问题,涉及到IM系统的两个核心:1)消息不能丢(可靠性):比如用户点了发送,不能因为服务宕机或网络抖动,消息石沉大海。比如地铁隧道、电梯间,网络断了又连,消息不能卡住不动(要确保弱网也能用)。2)顺序不能乱(有序性):比如“在吗?” 回成 “吗在?”,群聊时间线错乱,体验直接崩盘。这二大痛点,是IM聊天系统架构的命门所在。下面是一张IM消息从发出到接收的关键路径:
图片

2、系列文章

为了更好以进行内容呈现,本文拆分两了上下两篇。本文是2篇文章中的第 1 篇:《如何保障分布式IM聊天系统的消息有序性(即消息不乱)》(☜ 本文)《如何保障分布式IM聊天系统的消息可靠性(即消息不丢)》(稍后发布..)本篇主要总结和分享分布式IM聊天系统架构中关于消息有序性的设计和实践。

3、传统技术方案的瓶颈,怎么破?

早期做消息有序,很多人第一反应是搞个“全局发号器”——所有消息排一队,挨个编号再发。理想很丰满,现实很骨感:高并发下一拥而上抢号,发号器直接被打满;更致命的是,它一旦宕机,全链路雪崩。这就像春运火车站只开一个售票窗——再快也撑不过三分钟。所以,我们必须换思路:不搞大一统,而是分片独立发号,让每个“窗口”自给自足,互不干扰。

4、痛点拆解:为什么消息会乱?

我们先还原一个真实场景: 想象一下你和朋友聊天:你说:“1 吃饭了吗?”他回:“2 刚吃完。”你又说:“3 吃啥呢?”结果对方手机上显示成:“3  吃啥呢?” → “1 吃饭了吗?” → “2 刚吃完。”这不是 bug,是分布式系统的常态。三条消息走不同服务节点、经不同网络路径,到达时间完全不可控,最终呈现顺序错乱。会乱 问题本质是什么?一个要“串行等”,一个想“并发冲”,天然冲突。这时候有人会说:那我加个全局排序服务不就行了?可以,但代价太大——一个中心节点最多撑几万 QPS,面对百万群聊、亿级用户,还没上线就已过载。所以,全局有序不是解,而是枷锁。我们要的不是“天下大同”,而是“各聊各的别乱就行”。

5、最终方案:分而治之 + 局部有序

真正的突破口在于:我们根本不需要全局有序,只需要“会话内有序”。你和张三的聊天记录不能乱,但你和李四的聊天跟王五的完全无关——何必放一起排序?这就引出了经典策略:分而治之 + 局部有序。具体怎么做?两步走稳: 第一步 - 业务分区: 哈希分片,锁定归属用 sessionId 做一致性哈希,确保同一个会话的所有消息始终路由到同一个处理节点。按“会话ID”做哈希,算出该消息该由哪个节点处理。同一会话 → 哈希值一样 → 路由到同一台机器 → 所有消息串行处理,天然避免跨节点乱序。这样一来,单个会话内的消息在服务端就是串行处理的,天然不会乱。 第二步 - 局部序号:独立发号,局部递增每个会话独立维护一个计数器,每来一条消息就+1,作为它的“官方序号”。每个会话,可以配一个独立计数器(比如 Redis 的 INCR),每来一条消息就+1,生成唯一 SEQ。客户端不管什么时候收到消息,只认这个序号,按序号从小到大排列展示。这个 SEQ 就是这条消息的“官方身份证号”,客户端只认这个,不看接收时间。这就像电影院检票——你可以早到晚到,但座位按票号定。哪怕后排观众先进场,也不会坐到前排去。PS:IM消息ID生成相关的文章可详细阅读以下资料:《IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)》《IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)》《IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略》《IM消息ID技术专题(四):深度解密美团的分布式ID生成算法》《IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现》《IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)》《IM消息ID技术专题(七):深度解密vivo的自研分布式ID服务(鲁班)》

6、实践落地(核心片段伪代码)

1)服务端分片路由逻辑:来看关键实现:如何把消息精准投递给“对的人”。String sessionId = msg.getSessionId();//这里是伪代码,实际代码以mq 的负载均衡机制为准int nodeIndex = Math.abs(sessionId.hashCode()) % clusterNodeCount; //这里写个伪代码,代表mq  主从复制ClusterNode targetNode = clusterNodes.get(nodeIndex);targetNode.sendMsg(msg);核心就一句:基于会话 ID 哈希取模,固定路由。从此,每个会话都有了自己的“专属服务通道”,不再受其他会话影响。2)服务端序号分配逻辑:接下来,给每条消息发“通行证”:long msgSeq = redis.incr("msg_seq_" + sessionId);msg.setSeq(msgSeq);msg.setUniqueKey(sessionId + "_" + msgSeq);这里用了 Redis 的 INCR,保证同一个会话下的 SEQ 绝对递增,且线程安全。同时用 sessionId_seq 作为唯一键,既能幂等去重,也能防止重试导致消息重复入库。实战提示:如果你的 Redis 是集群模式,记得确保同一个会话的 key 落在同一 slot,否则 INCR 可能跨节点失效。3)客户端排序逻辑:最后一步,客户端收尾:别急着渲染,先排好队。//这里是伪代码, 先排序List<Msg> sortedMsgs = msgList.stream()    .sorted(Comparator.comparingLong(Msg::getSeq))    .collect(Collectors.toList());//这里是伪代码, 再渲染renderMsgList(sortedMsgs);无论消息以什么顺序到达,统统按 seq 升序排列后再上屏。哪怕第100条先到,第1条后到,也能正确归位。这也是为什么我们强调“客户端必须信任服务端 SEQ”——它是唯一真相源。

7、方案总结:放弃全局有序,换高可用与高性能

总结一下,这套方案的核心思想就一句话:不要为“假需求”买单——我们不需要全局有序,只需要业务上有意义的有序。你看微信、钉钉、飞书,哪一个是把全平台消息排成一条队列的?没有。它们都选择了“会话级隔离 + 局部有序”的设计,这才是工业级系统的通用解法。背后的分布式哲学也很清晰:
图片

最终换来的是:1)高并发支持(水平扩展);2)高可用(无单点);3)强一致体验(用户无感知)。这正是中高级开发者必须掌握的权衡思维:不是技术做不到,而是要不要做。有时候,“不做全局有序”,反而是最正确的选择。

8、 IM消息有序性架构的核心流程总结

最后,一张图串起全流程:
图片
从发起到渲染,全程围绕“会话隔离”和“局部发号”展开。每一个环节都在为同一个目标服务:在分布式环境下,低成本实现用户可感知的“顺序正确”。

—— 下篇《如何保障分布式IM聊天系统的消息可靠性(即消息不丢)》稍后发布,敬请期待 ——

9、参考资料

[1] 什么是IM聊天系统的可靠性?
[2] 什么是IM聊天系统的消息时序一致性?
[3] 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)
[4] 马蜂窝旅游网的IM系统架构演进之路
[5] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
[6] 从新手到专家:如何设计一套亿级消息量的分布式IM系统
[7] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等
[8] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制
[9] 阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠投递优化实践
[10] 阿里IM技术分享(八):深度解密钉钉即时消息服务DTIM的技术设计
[11] 基于实践:一套百万消息量小规模IM系统技术要点总结
[12] 一套分布式IM即时通讯系统的技术选型和架构设计
[13] 转转平台IM系统架构设计与实践(一):整体架构设计
[14] 移动端弱网优化专题(一):通俗易懂,理解移动网络的“弱”和“慢”
[15] 移动端弱网优化专题(二):史上最全移动弱网络优化方法总结
[16] Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?
[17] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制
[18] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递
[19] 移动端IM中大规模群消息的推送如何保证效率、实时性?
[20] 如何保证IM实时消息的“时序性”与“一致性”?
[21] 一个低成本确保IM消息时序的方法探讨

即时通讯技术学习:

(本文已同步发布于:http://www.52im.net/thread-4887-1-1.html

看了 vercel 刚发布的 react-best-practices-skill,觉得还不错,然后这周末就花两天用 Claude Code + GLM 4.7 写了个用来做在线订阅转换的工具:Clash Converter ,欢迎大家来体验或者提意见

  • 域名成本 12.99$
  • CICD 用的免费的 Github + Cloudflare Workers
  • LogoNano Banana Pro + Chatgpt生成的

今日速览

  1. 1Code:给 Claude Code 加个光标界面,开发效率翻倍
  2. Boom video for Mac:专为出镜人士设计的直播录屏神器
  3. TranslateGemma:谷歌开源翻译模型,支持 55 种语言
  4. Dynamic Content by beehiiv:一键为不同读者定制专属邮件
  5. Stracti:不用写代码,也能轻松造个 AI 机器人
  6. ChatGPT Translate:用 ChatGPT 翻译,保留原汁原味
  7. Orca:学语言像玩游戏,边玩边练口语
  8. Flight Follower:航空迷必备,无广告追踪头顶飞机
  9. Waylight for macOS:AI 助手懂你电脑里的一切,还能帮你记日记
  10. LocalMark Studio:本地优先的 Markdown 编辑器,又快又私密


1Code

如果你用 Claude Code 搞开发,1Code 就是你的效率加速器。它提供了一个类似光标的用户界面,让你在 Mac 和网页上并行运行 Claude Code 代理,开发速度嗖嗖往上提。

  • 在 Mac 上本地运行,支持工作树模式,灵活又方便
  • 网页端提供远程沙箱,实时预览应用,手机也能随时查看状态
  • 并行运行多个代理,功能开发就像开了挂

官网 PH


Boom video for Mac

教练、创作者、创始人看过来——Boom 让你在镜头前瞬间变专业。它是个专为演示设计的视频应用,直播录屏一气呵成,告别繁琐的后期编辑。

  • 在 Zoom、Meet 或 Teams 上直播,自带专业布局和电影级切换效果
  • 录制教程、演示超简单,说完就停,视频自动生成
  • 实时切换场景,支持 Stream Deck,操作流畅如丝
  • 内置虚拟摄像头和网络摄像头增强,效果直接拉满
  • 无需编辑、时间轴或后期制作,上手即用

官网 PH


TranslateGemma

谷歌这次玩真的,把自家翻译模型 Gemma 3 开源了。TranslateGemma 支持 55 种语言,交流起来既准又快,移动端、本地设备、云端都能跑。

  • 基于谷歌 Gemma 3 模型,翻译质量杠杠的
  • 覆盖 55 种语言,全球沟通无压力
  • 专为移动和本地设备优化,性能不打折
  • 云端环境也适配,灵活部署随心选

官网 PH


Dynamic Content by beehiiv

想给每个读者发不一样的邮件?beehiiv 的动态内容功能让你梦想成真。一次发送,千人千面,个性化营销就这么简单。

  • 根据读者展示不同内容,邮件营销更精准
  • 无需编码或定制模板,在编辑器里点点就行
  • 操作简单,没有额外复杂性,新手也能玩转

官网 PH


Stracti

造个 AI 机器人,不用碰代码?Stracti 让你梦想照进现实。通过可视化界面,轻松创建和运行机器人,自动化工作流从此告别“黑箱”。

  • 无代码平台,网页、桌面、移动端都能建机器人
  • 桌面应用本地运行,数据安全有保障
  • 基于屏幕 AI 检测,适配真实工作流程,不依赖 API
  • 操作历史清晰可见,完全掌控自动化过程

官网 PH


ChatGPT Translate

翻译工具千千万,但能保留语气的没几个。ChatGPT Translate 用 AI 瞬间翻译 50+ 语言,原意、上下文、语气统统在线。

  • 输入、粘贴、语音或上传文本,翻译方式任你选
  • 支持正式、随意等多种风格,翻译细腻又地道
  • 适合日常交流、旅行、学习和专业场景,一工具全搞定

官网 PH


Orca

学语言枯燥?Orca 把它变成游戏。通过真实生活短语的小课程,边玩边练,口语听力阅读全提升,还能挑战别人冲排名。

  • 围绕真实短语设计课程,学完就能流利交流
  • 每个级别教 15 个日常表达,实用又接地气
  • 互动发音游戏通关才能继续,学习动力满满
  • 挑战其他学习者,排名上升超有成就感

官网 PH


Flight Follower

航空迷的福音来了!Flight Follower 是 iOS 上免费的实时航班追踪器,无广告干扰,让你随时随地掌握头顶飞机的动态。

  • 通过 Siri 识别飞过的飞机,好奇就问问
  • 查看航班实时状态,信息一手掌握
  • 原生小部件追踪飞机,桌面一目了然
  • 快速 ADS-B 地图探索,飞行轨迹尽收眼底

官网 PH


Waylight for macOS

Waylight 就像你电脑里的私人助理,它懂你的会议、文档、标签和消息,还能帮你记日记、列待办,2020 年后苹果芯片的 Mac 都能用。

  • 理解电脑上所有活动,建立私密记忆库
  • 随时提问关于看到的内容,答案即时又准确
  • 自动生成待办列表和日记,生活整理得井井有条
  • 专为 Apple Silicon 优化,运行流畅不卡顿

官网 PH


LocalMark Studio

写 Markdown 要速度也要隐私?LocalMark Studio 专注本地优先,笔记存浏览器,文件结构真实,功能丰富到让你惊喜。

  • 本地存储用 IndexedDB,数据安全自己掌控
  • 创建文件夹和文件,重命名删除操作顺手
  • 命令面板快速调用功能,效率翻倍
  • 智能粘贴 HTML 转干净 Markdown,省心省力
  • 分屏实时预览,滚动同步,写作体验丝滑
  • 可选 Mermaid 图表和 KaTeX 公式,扩展性超强

官网 PH

Go-WXPush - 微信消息推送服务 (基于 golang)

这是一个基于 golang 开发的微信测试公众号模板消息推送服务。它提供了一个简单的 API 接口,让您可以轻松地通过 HTTP 请求将消息推送到指定的微信用户。 github 地址 https://github.com/hezhizheng/go-wxpush

✨ 特性

✅ 完全免费,下载即使用
✅ 支持 Docker 一键部署(镜像容器大小仅 2MB)
✅ 每天 10 万次额度,个人用不完
✅ 真正的微信原生弹窗 + 声音提醒
✅ 支持多用户
✅ 提供免费服务 https://push.hzz.cool (请勿滥用)
✅ 跳转稳定,自带消息详情页面 (默认使用 https://push.hzz.cool/detail , 可自己部署后使用参数替换)

⚠️ 部署条件 (具体可查看 github )

🚀 部署指南

下载编译好的文件启动

  • 启动参数
    • 命令行启动参数(可不加,启动之后直接在 url 上拼接参数也可) ./go-wxpush_windows_amd64.exe -port "5566" -title "测试标题" -content "测试内容" -appid "xxx" -secret "xxx" -userid "xxx-k08" -template_id "xxx-Ks_PwGm--GSzllU" -base_url "https://push.hzz.cool"
    • url 请求参数(get) 与命令行参数名称一致 /wxsend?appid=xxx&secret=xxx&userid=xxx-k08&template_id=xxx-Ks_PwGm--GSzllU&base_url=https://push.hzz.cool&content=保持微笑,代码无 bug!

自行编译可执行文件(跨平台)

复制
# 用法参考 https://github.com/mitchellh/gox
# 生成文件可直接执行 
gox -osarch="windows/amd64" -ldflags "-s -w" -gcflags="all=-trimpath=${PWD}" -asmflags="all=-trimpath=${PWD}"
gox -osarch="darwin/amd64" -ldflags "-s -w" -gcflags="all=-trimpath=${PWD}" -asmflags="all=-trimpath=${PWD}"
gox -osarch="linux/amd64" -ldflags "-s -w" -gcflags="all=-trimpath=${PWD}" -asmflags="all=-trimpath=${PWD}"
gox -osarch="linux/arm64" -ldflags "-s -w" -gcflags="all=-trimpath=${PWD}" -asmflags="all=-trimpath=${PWD}"

🐳 Docker 启动

  • 将编译好的文件放在与 Dockerfile 同目录
  • 构建镜像
复制
docker build -t go-wxpush:v2 .
  • 启动镜像,参数与命令行保持一致
复制
docker run -d -p 5566:5566 --name go-wxpush0 go-wxpush:v2 \
-port "5566" \
-title "测试标题" \
-content "测试内容" \
-appid "xxx" \
-secret "xxx" \
-userid "xxx-k08" \
-template_id "xxx-Ks_PwGm--GSzllU"

🐳 Docker 一键部署

复制
# 重新部署请先拉一遍最新的镜像
docker pull hezhizheng/go-wxpush:v4
# 参数格式与终端启动保持一致, 替换成实际值即可
docker run -it -d -p 5566:5566 --init --name go-wxpush4 hezhizheng/go-wxpush:v4 \
-port "5566" \
-title "测试标题 5566" \
-content "测试内容 5566" \
-appid "xxx" \
-secret "xxx" \
-userid "xxx-k08" \
-template_id "xxx-Ks_PwGm--GSzllU" \
-tz "Asia/Shanghai"

⚙️ API 使用方法

服务部署成功后,您可以通过构造 URL 发起 GET 请求来推送消息。

请求地址

复制
http://127.0.0.1:5566/wxsend

请求参数

参数名类型是否必填描述
portString指定启动端口(仅针对命令行)
titleString消息的标题。
contentString消息的具体内容。
appidString临时覆盖默认的微信 AppID。
secretString临时覆盖默认的微信 AppSecret。
useridString临时覆盖默认的接收用户 OpenID。
template_idString临时覆盖默认的模板消息 ID。
base_urlString临时覆盖默认的跳转 URL。
tzString时区(默认东八区)

使用示例

基础推送

向默认配置的所有用户推送一条消息:

复制
http://127.0.0.1:5566/wxsend?title=服务器通知&content=服务已于北京时间%2022:00%20 重启

临时覆盖用户

向一个临时指定的用户推送消息:

复制
http://127.0.0.1:5566/wxsend?title=私人提醒&content=记得带钥匙&userid=temporary_openid_here

Webhook / POST 请求

除了 GET 请求,服务也支持 POST 方法,更适合用于自动化的 Webhook 集成。

请求地址

复制
http://127.0.0.1:5566/wxsend

请求方法

复制
POST

请求头 (Headers)

复制
{
  "Content-Type": "application/json"
}

请求体 (Body)

请求体需要是一个 JSON 对象,包含与 GET 请求相同的参数。

复制
{
  "title": "Webhook 通知",
  "content": "这是一个通过 POST 请求发送的 Webhook 消息。"
}

使用示例 (cURL)

复制
curl --location --request POST 'http://127.0.0.1:5566/wxsend' \
--data-raw '{
    "title": "来自 cURL 的消息",
    "content": "自动化任务已完成。"
  }'

成功响应

如果消息成功发送给至少一个用户,服务会返回 "errcode": 0 状态码。

失败响应

如果发生错误(如 token 错误、缺少参数、微信接口调用失败等),服务会返回相应的状态码和错误信息。

CVE-2024-3400 Palo Alto Networks PAN-OS命令注入漏洞

Real World CTF 6th Router4 writeup

Exploiting File Writes in Hardened Node.js Environments

CVE-2024-41592 vigor 栈溢出漏洞分析

CVE-2025-0282 Ivanti Connect Secure VPN 栈溢出漏洞分析

议题分享:Vigor2960 Memoirs \nPursuit of the Elusive 0day & 1day

议题分享: 企业设备安全设备漏洞分析与利用

议题分享: When ASUS IoT Devices Play Hide-and-Seek with Security

CVE-2025-36463 Sudo_chroot Elevation of Privilege 漏洞分析

CVE-2025-32023 Redis 漏洞分析