2026年2月

为什么大家都在吹 Claude Code,但你却用不上?

大家好,我是你们的编程老友。

最近技术圈里,Anthropic 出品的 Claude Code 口碑炸裂,不少博主都在吹它如何颠覆编程体验。但我知道,很多朋友看完文章后,实际感受是:“看着是好,但我连门都摸不着。”

封号、限区、海外支付、昂贵的API费用、复杂的网络环境……这一套组合拳下来,直接把绝大多数国内开发者的热情浇灭了。看着视频里那个在终端里指哪打哪、帮你重构代码、理解整个项目的 AI 搭子,你只能望洋兴叹:“有没有一种方式,不折腾、不翻车,也能把 Claude Code 跑起来?”

答案是:有,而且不一定非要用 Anthropic 的官方模型。 今天,我就带你换个思路,用国内平台 + 国产代码模型,让 Claude Code 这个强大的工具,真正为你所用。

一、Claude Code 到底强在哪?它和普通AI工具有什么区别?

在动手之前,我们先要搞清楚一件事:Claude Code 到底是什么?

它不是一个网页对话框,也不是 IDE 里的插件,而是一个运行在你终端里的 命令行工具。你可以把它理解为一位 “会干活的编程搭子”

  • 原生 CLI 体验:它深度贴合程序员的工作流。你不需要在聊天窗口和编辑器之间反复粘贴代码,直接在项目根目录下敲 claude 命令,它就能理解你的整个项目上下文。
  • 强项目感知:普通 Chat Bot 只能理解你粘贴的那段代码。而 Claude Code 能扫描你的整个项目结构、文件依赖,理解代码间的逻辑关系。当你问“这个函数在哪里被调用了?”或者“帮我重构这个模块”时,它不是在瞎猜,而是在“看懂”你的项目。
  • 偏 Agent 化:它的核心能力是“执行任务”,而不是“回答问题”。比如,你可以让它“帮我写一个脚本,把项目里所有的 .js 文件批量重命名为 .jsx,并更新所有内部的引用”。它不是一个字一个字地给你建议,而是直接帮你干活

简而言之,如果你是后端、前端、全栈工程师,日常高频在终端和 IDE 里写代码,Claude Code 就是那个能帮你从繁琐重复劳动中解放出来的得力干将。但如果你只是偶尔查个语法,或者完全不想碰命令行,那它可能确实不太适合你。

二、现实困境与破局思路:换个“大脑”,问题迎刃而解

Anthropic 官方方案的门槛是实实在在的:

  1. 网络与地区限制:懂的都懂,这是最让人头疼的一步。
  2. 账号与风控:即使过了网络关,海外手机号、信用卡,以及可能随时触发的人工审核,每一步都像在踩地雷。
  3. 成本问题:Claude Sonnet/Opus 模型的价格,对于个人开发者和中小型项目来说,并不算便宜。

但这里我们需要转变一个关键认知:Claude Code = 工具壳 + 协议。 它本身是一个开源的命令行工具,通过一套标准协议去调用大模型。这意味着,模型是可替换的!

我们完全可以保留 Claude Code 这个强大的“工具形态”,然后给它装上国内平台的“国产大脑”。而这个“突破口”,正是各大国内AI平台推出的 “Code Plan”

三、国内可用方案总览:选择很多,能力不差

目前,国内主流平台基本都推出了类似的服务,打破了过去“唯Anthropic马首是瞻”的局面。这不再是“能不能用”的问题,而是“选哪个更合适”的问题。

为了方便大家对比选择,我整理了一份当前主流平台的 “Coding Plan 订阅套餐”速览表。你可以根据自己的使用习惯、预算和对特定模型的偏好,快速锁定目标。

🎯 字节跳动 · 方舟 Coding Plan

  • 价格:¥40/月(首月¥9.9)
  • 支持模型:Kimi、DeepSeek、GLM、豆包等多厂商模型聚合
  • 一句话点评:模型选择最灵活,想换哪个换哪个

🎯 阿里巴巴 · 百炼 Coding Plan

  • 价格:¥40/月(首月¥10)
  • 支持模型:通义千问系列(qwen3-max、qwen3-coder-plus)
  • 一句话点评:大厂出品,每月最高9万次请求,额度管够

🎯 稀宇科技 · MiniMax Coding Plan

  • 价格¥29/月
  • 支持模型:MiniMax系列(M2、M2.1、M2.5)
  • 一句话点评:极致性价比,预算有限的首选

🎯 智谱 · GLM Coding Plan

  • 价格:¥49/月(包季9折)
  • 支持模型:GLM系列(GLM-4.7、GLM-5等)
  • 一句话点评:国内最早推出,支持20+编程工具,生态最成熟

🎯 月之暗面 · Kimi Code

  • 价格:¥49/月
  • 支持模型:Kimi系列(K2、K2.5、K2 Thinking)
  • 一句话点评:256K超长上下文+100 Tokens/s极速响应,价格仅为Claude的20%

🎯 摩尔线程 · AI Coding Plan

  • 价格:¥120/季度
  • 支持模型:GLM-4.7
  • 一句话点评:季度付费,适合中长期稳定项目

🎯 快手 · KwaiKAT Coding Plan

  • 价格¥29/月
  • 支持模型:快手自研 KAT-Coder-Pro V1
  • 一句话点评:同样¥29,国产自研新势力,值得一试

🎯 百度 · 千帆 Coding Plan

  • 价格:¥40/月(首月¥9.9)
  • 支持模型:DeepSeek、GLM、Kimi、MiniMax多厂商聚合
  • 一句话点评:控制台一键切换模型,无需改本地配置,体验丝滑

🎯 无问芯穹 · Infini Coding Plan

  • 价格¥19.9/月起
  • 支持模型:deepseek、kimi、minimax、glm等多厂商
  • 一句话点评:全场最低价,一站式接入多家顶尖模型

它们的共性优势非常明显:国内可直接访问、支持 Claude Code 接入、模型选择自由

更重要的是,别再迷信“只有 Claude 能打”了。经过实测,像 GLM-4.7、Kimi-K2.5-thinking 等国产模型,在日常编程、代码重构、解释代码、编写脚本等核心场景下,其表现已经非常接近 Claude Sonnet 的水平。对于绝大多数开发者而言,这种体验上的微小差距,完全被“稳定、持续、低成本”的巨大优势所弥补。

四、实操篇:Claude Code 国内快速上手

纸上谈兵千遍,不如动手一遍。接下来,我们就以火山引擎方舟平台的 Code Plan 为例,手把手带你跑通整个流程。

第一步:安装 Claude Code 本体

前提是你已经安装了 Node.js 18 或更高版本。Windows 用户请确保已安装 Git for Windows。

打开你的命令行终端,执行以下命令进行全局安装:

npm install -g @anthropic-ai/claude-code

安装完成后,如果你在项目目录下首次输入 claude 命令,它会进行一些初始化引导,可能会因为无法连接官方API而卡住。没关系,我们直接进行下一步配置。

第二步:配置国内 Code Plan 接入

Claude Code 的配置文件位于你的用户目录下。我们需要修改或创建它,告诉它:“别去找官方了,用这个国内的接口。”

  • 配置文件路径

    • Windows: C:\Users\你的用户名\.claude\settings.json
    • macOS/Linux: ~/.claude/settings.json
  • 关键环境变量解释

    • ANTHROPIC_BASE_URL:这是核心,把请求地址指向国内平台的网关。火山引擎方舟的 Code Plan 地址是 https://ark.cn-beijing.volces.com/api/coding
    • ANTHROPIC_AUTH_TOKEN:你在方舟平台申请的 API Key,用于身份认证。
    • ANTHROPIC_MODEL:你想使用的具体模型名称,比如 glm-4.7
  • 示例配置结构
    打开 settings.json 文件,将内容修改为如下结构(请替换 token 为你自己的):

    {
      "env": {
        "ANTHROPIC_AUTH_TOKEN": "你的火山引擎方舟API Key",
        "ANTHROPIC_BASE_URL": "https://ark.cn-beijing.volces.com/api/coding",
        "ANTHROPIC_MODEL": "glm-4.7"
      }
    }

    为了绕过初次运行的引导检查,你可能还需要在同级目录下创建一个 .claude.json 文件,内容如下:

    {
        "hasCompletedOnboarding": true
    }

第三步:模型选择建议

配置中的 ANTHROPIC_MODEL 可以根据你的任务类型灵活选择,这正是国产方案的优势所在:

  • 逻辑型任务 / 复杂Agent流程:如果你的任务涉及复杂的逻辑推理和多步规划,推荐选择 GLM-4.7kimi-k2.5-thinking。它们在理解复杂指令方面表现突出。
  • 日常业务代码 / 脚本编写:对于常见的增删改查、前端页面调整、工具函数编写,kimi-k2.5Doubao-Seed-Code 就完全足够,且响应速度更快,成本更低。
  • 性价比之选:不必追求理论上的“最强模型”,而应追求“稳定 + 成本可控”。在国产平台上,大多数模型的定价都远低于 Claude 官方,让你可以更放心地把它融入日常工作流。

配置完成后,再次在你项目的根目录下输入 claude 命令。如果一切顺利,你将看到熟悉的欢迎界面,你的 AI 编程搭子,正式上线!

五、真实体验与避坑指南

经过一段时间的深度使用,我发现 Claude Code 在以下几个场景中价值最高:

  • 重构老代码:面对一段难以维护的老代码,直接让它“帮我用现代 ES6 语法重构这个文件,并保持功能不变”。它不仅能改好,还会解释改了哪里,为什么。
  • 快速理解项目:接手一个新项目时,直接问它“这个项目的主要架构是什么?数据流是怎么走的?”它能帮你快速建立起项目地图。
  • 编写脚手架/工具函数:写一些重复性的脚本或工具函数,可以直接交给它,比如“帮我写一个脚本,用 fs-extra 递归复制 src 目录到 dist,但排除所有 test.js 文件”。

当然,过程中也有一些小坑需要注意:

  • 超时/无响应:当项目文件过多或任务过于复杂时,可能会超时。可以尝试先 cd 到项目的子目录,或者将任务拆解得更小一些。
  • 模型不听指令:偶尔模型会“自作聪明”。这时需要检查你的提示词,尽量清晰、结构化地描述任务,遵循“角色+上下文+任务+要求”的格式。
  • 权限问题:确保你在项目目录下有足够的读写权限,Claude Code 才能顺利创建和修改文件。

六、总结与行动建议

核心观点很简单:Claude Code 的真正价值在于它先进的“工具形态”,而国内平台提供的 Code Plan 已经完全可以承载这个形态,并提供稳定、高性价比、能力不俗的国产模型。

我们不必执着于 Anthropic 的官方模型。对于国内开发者而言,这套平替方案才是真正能让 Claude Code 从“概念”走向“生产力”的关键一步。

所以,别再犹豫了。建议你今天就按照文中的步骤配置一次,亲身体验一下这个“会干活的AI编程搭子”能为你带来怎样的效率提升。相信我,一旦用上,你就回不去了。如果你在配置过程中遇到任何问题,欢迎在评论区留言,我们一起交流解决。

为什么要做这个

AI 原生能力越来越强,势必会引入更多的创作者加入创作。在创作成本越来越低的现在,就像是 figma 代替了 sketch ,纯浏览器端的视频编辑工具必然会取代 capcut 这样的端上应用,让用户能够随时开启创作,而无需特别专业的能力

之前 Opencut 的爆火也证明了这一点,但是 opencut 只是一个基础,只能进行基础的框架,没有办法适用于实战场景,所以我做了 Cutia 。

而现在的浏览器能力已经能够支撑一整套的媒体编辑能力。所以为什么不做呢?

Highlight

  • 浏览器端运行,无需安装
  • 隐私优先,所有数据存储在本地
  • 多轨道时间轴编辑(视频、音频、文本、贴纸)
  • AI 对话助手,自然语言控制编辑器
  • AI 图像/视频生成
  • 角色库,多次生成保持视觉一致性
  • 自动字幕生成(浏览器内 Whisper ,不上传音频)
  • 转场效果(淡入淡出、擦除、滑动、缩放)
  • 40+ 文本预设 + 8 种字幕模板
  • Freesound 音效库集成
  • 导出 MP4/WebM ,无水印
  • 完全离线可用
  • 12 种语言支持
  • 开源免费( MIT )

预览

全文链接:https://tecdat.cn/?p=45082
原文出处:拓端数据部落公众号

 

封面

大模型本地化部署与实战应用专题

引言

在当今AI技术快速迭代的背景下,大模型的能力边界不断被突破,但随之而来的隐私安全、推理成本等问题也逐渐凸显。对于许多企业和研究者而言,将大模型部署在本地环境,既能保证数据隐私,又能灵活控制推理流程,成为了迫切需求。我们团队在近期的一个咨询项目中,就帮助客户完成了Qwen3.5大模型的本地化部署,并基于此开发了一款股票筛选工具,整个方案已通过实际业务校验。
本文将从环境准备开始,一步步讲解如何在单GPU上高效运行Qwen3.5,包括llama.cpp的编译、模型下载、服务启动,以及最终的应用开发。希望能为有大模型本地化需求的读者提供一些实用参考。
本文内容改编自过往客户咨询项目的技术沉淀并且已通过实际业务校验,该项目完整代码教程已分享至交流社群。阅读原文进群获取更多最新AI见解和行业洞察,可与900+行业人士交流成长;还提供人工答疑,拆解核心原理、代码逻辑与业务适配思路,帮大家既懂 怎么做,也懂 为什么这么做;遇代码运行问题,更能享24小时调试支持。

全文脉络流程图

进群获取完整内容及更多AI见解、行业洞察,与900+行业人士交流成长。

Qwen3.5模型概述

Qwen3.5是阿里推出的最新大模型系列,在推理、编程和多模态任务上都有出色表现。独立基准测试显示,Qwen3.5-397B-A17B在LiveCodeBench、AIME26等测试中得分很高,不少类别上超过了主流模型,推理吞吐量也比前代提升明显。

硬件与软件要求

要在本地流畅运行Qwen3.5,得先满足硬件和软件要求。我们这次用的是NVIDIA H200 GPU(141GB显存),搭配240GB系统内存,能高效运行MXFP4_MOE版本的Qwen3.5。
作为参考,Unsloth 4-bit动态量化版本UD-Q4_K_XL大约占214GB磁盘空间,能直接放在256GB的设备上,也能在单张24GB GPU加256GB内存的环境中运行,每秒能生成25个以上token。3-bit量化版本能放在192GB内存里,8-bit版本则需要最多512GB的显存和内存总和。
一般来说,显存加内存的总和最好和量化后的模型大小差不多。如果不够,llama.cpp能把部分模型卸载到SSD,但推理速度会变慢。
软件方面,得安装最新的NVIDIA GPU驱动,还有近期的CUDA Toolkit,保证和llama.cpp、CUDA加速推理兼容。

环境搭建

要在本地运行Qwen3.5,得有一台性能强劲的GPU机器。大多数笔记本和台式机没有足够的显存或内存来运行这么大的模型,所以我们用云GPU虚拟机。
这次我们用Hyperbolic来私密运行模型,也可以用AutoDL、恒源云等替代平台。选Hyperbolic是因为它目前的GPU实例性价比很高。
先启动一个单H200 GPU的实例。

机器启动后,能看到公网IP地址和连接所需的SSH命令。

连接前,确保本地设置好了SSH,创建虚拟机时添加了公钥。
实例准备好后,用带端口转发的SSH连接。这很重要,因为我们要通过8080端口在本地访问llama.cpp推理服务:

ssh -L 8080:localhost:8080 root@129.212.191.53

第一次连接时,输入yes确认,然后用SSH密钥认证。

登录后,验证GPU是否正确检测:

nvidia-smi

输出里应该能看到NVIDIA H200。

最后,安装下载、编译和运行llama.cpp所需的Linux软件包:

sudo apt updatesudo apt install pciutils build-essential cmake curl libcurl4-openssl-dev -y

完成这步后,环境就准备好安装llama.cpp和本地运行Qwen3.5了。


相关文章

DeepSeek、LangGraph和Python融合LSTM、RF、XGBoost、LR多模型预测NFLX股票涨跌|附完整代码数据

原文链接:https://tecdat.cn/?p=44060


安装llama.cpp

llama.cpp是开源的C/C++推理引擎,能让你用最少的设置本地运行大语言模型,支持CPU和GPU加速。
先克隆llama.cpp仓库:

接下来,用CMake配置启用CUDA的构建。我们用-DGGML_CUDA=ON启用CUDA,把CUDA架构设为90a,因为我们用的是NVIDIA H200(Hopper架构)。这能让构建生成针对Hopper特性优化的GPU代码。


现在编译服务器二进制文件。llama-server是内置的REST服务器,能把llama.cpp暴露为API端点:


最后,把编译好的二进制文件复制到主文件夹,方便运行:

下载Qwen3.5模型

现在llama.cpp安装好了,下一步是下载GGUF格式的Qwen3.5模型权重。这些文件很大,所以用Hugging Face CLI是最可靠的方法,直接把它们下载到GPU机器上。
我们先安装Python,因为Hugging Face下载工具和认证工具是作为Python包分发的。虽然llama.cpp本身是用C++写的,但Python让管理模型下载和传输容易多了。
先安装pip:

接下来,安装Hugging Face Hub客户端和性能辅助工具。hf_transferhf-xet能大幅加快下载速度,这在下载数百GB的模型文件时很重要:

现在从Hugging Face下载Qwen3.5模型。这次我们只获取MXFP4_MOE变体,它针对高效的MoE推理进行了优化:


下载完成后,模型文件会存储在model_storage/Qwen3.5里,准备加载到llama.cpp进行本地推理。
进群获取完整内容及更多AI见解、行业洞察,与900+行业人士交流成长。

启动推理服务

现在我们能用llama-server启动Qwen3.5了。这会给我们一个OpenAI兼容的API端点,能从本地工具和应用调用。
我们针对单GPU设置优化了服务器,做了三件关键的事。第一,启用--fit on,让llama.cpp自动在GPU显存和系统内存之间平衡模型,而不是在模型不能完全放进显存时失败。
第二,用--ctx-size 16384设置更大的上下文窗口,让服务器能处理更长的提示。第三,启用--jinja并传递--chat-template-kwargs来控制聊天格式,禁用思考模式以获得更快、更直接的响应。
用以下命令运行服务器:

模型加载时,你会注意到它同时使用GPU显存和系统内存,这对于大型MoE模型来说是正常的。

加载完成后,服务器可以在以下地址访问:

  • 虚拟机上的0.0.0.0:8080
  • SSH端口转发后本地机器上的http://127.0.0.1:8080

    让服务器保持运行。在本地电脑上,打开一个新终端,用SSH端口转发重新连接:

然后通过列出可用模型来测试服务器:

如果响应中看到Qwen3.5,说明服务器运行正常,你可以准备从OpenAI SDK和本地应用调用它了。

接口测试

现在Qwen3.5推理服务器运行起来了,下一步是验证它能和真实的客户端应用正常工作。llama.cpp最大的优势之一是llama-server暴露了OpenAI兼容的API,这意味着你可以使用官方OpenAI SDK而不用改变代码结构。
先在本地机器上(或者如果你愿意的话在虚拟机里)安装OpenAI Python包:

现在运行一个简单的测试脚本。这会连接到你本地转发的端点http://127.0.0.1:8080/v1,而不是OpenAI的云服务器。

这里有几个重要的细节需要理解:

  • base_url指向你本地的Qwen3.5服务器,而不是OpenAI的API。
  • SDK仍然需要api_key,但llama.cpp不强制认证,所以任何占位符值都可以。
  • model="Qwen3.5"名称和我们启动服务器时设置的别名匹配。
    如果一切配置正确,你会从模型得到快速、清晰的响应。

    这确认了:
  • Qwen3.5模型加载成功
  • llama.cpp服务器运行正常
  • 你的SSH端口转发正常工作
  • 端点与OpenAI风格的应用完全兼容
    此时,你可以将Qwen3.5集成到任何已经支持OpenAI API格式的本地工具、智能体工作流或应用中。

股票筛选应用开发

llama.cpp包含一个内置的、ChatGPT风格的WebUI,你可以用它直接在浏览器中与模型聊天。这对于快速测试、提示迭代和生成代码很有用,不需要先写任何客户端脚本。
因为我们已经设置了SSH端口转发,你可以在本地机器上打开WebUI,它的行为就像服务器运行在你的笔记本上一样。
默认情况下,WebUI可以在以下地址访问:
http://127.0.0.1:8080
如果这个页面加载,它确认了两件事。你的SSH隧道工作正常,Qwen3.5服务器可以在本地访问,同时仍然在GPU虚拟机上私密运行。

进入WebUI后,粘贴这个提示。目标是让模型同时生成Python代码和简短的使用指南。
构建一个简单的Python TUI(文本用户界面)“股票筛选训练器”,使用rich库运行(没有Web UI),用python stock_app.py启动。它应该让你输入股票代码列表,选择模式(成长/价值/分红)和风险(低/中/高),从免费来源获取每个股票的基本公开指标,显示实时加载状态,然后渲染一个漂亮的表格和“根据我的评分规则的前5名”部分,带有清晰的“仅供教育,不构成财务建议”免责声明,并将完整结果保存到stockults.csv
几秒钟内,Qwen3.5应该会生成一个stop.py文件,通常还有一个关于如何运行它的快速解释。

现在切换到你的本地终端(你的笔记本)。安装生成的应用所需的依赖:

这会安装:

  • rich用于TUI布局、表格、提示和进度指示器
  • yfinance用于获取免费的公开股票指标
    创建一个名为stock_app.py的文件,粘贴模型生成的代码,然后运行:

运行脚本后,你应该会看到TUI在你的终端中正常启动。应用会提示你输入要分析的股票代码,以及你偏好的筛选模式和风险水平。
例如,我们用三只热门股票测试了它。

短暂的加载阶段后,工具返回完整的股票指标表格,根据评分规则突出显示结果,并将所有内容保存到stock_results.csv文件。

这是一个很好的例子,说明Qwen3.5如何仅使用4-bit量化模型端点和简单提示,一次性生成完整的工作应用。
进群获取完整内容及更多AI见解、行业洞察,与900+行业人士交流成长。

总结

本地运行Qwen3.5是一种强大的方式,可以在保持一切私密和完全在你控制之下的同时,访问前沿规模的模型。在本文中,模型托管在单个H200 GPU虚拟机上,使用SSH端口转发从本地机器安全访问,并通过优化的llama.cpp OpenAI兼容端点提供服务。
也就是说,有一些实际限制值得记住。因为一切都依赖于活动的SSH隧道,连接需要保持稳定。如果你的网络中断或会话断开,你会失去对本地端口的访问,通常需要重新连接并重新启动部分工作流。
另一个常见问题是正确构建llama.cpp。如果你没有为你的GPU指定正确的CUDA架构标志,编译可能需要更长时间,并且可能无法完全针对硬件进行优化。提前设置正确的架构会在构建时间和性能上产生明显差异。
最后,虽然4-bit MXFP4_MOE量化对于高效运行大型模型非常好,但它并不总是适合智能体编程工作流。在使用Qwen Code CLI、Kilo Code CLI和OpenCode等工具进行测试时,模型在深度推理方面遇到困难,并且在较长的生成循环中经常失败,有时甚至触发GPU不稳定。
更高精度的量化或更小的专注于推理的模型可能更适合可靠的基于智能体的编程。

封面

不清楚现在 AI 编程是怎么运作的,问问大伙。

一堆有结构的 markdown 组合起来,还有些 markdown 用来描述每个 markdown 干什么的,让 AI 挑着读?

看起来还有 json ,用来结构化描述这堆 markdown 作用,或者 AI 平台会用写好的代码读取这个 json ?

至于 markdown 里,就是没有特定结构的自然语言咯?描述规则、规范等等?

AI 客户端会让我们把这堆东西按一定目录结构放到特定文件夹里?比如一个项目里面的.claude 、.cursor 、.agents 、AGENTS.md 等用于提供给不同 AI 客户端用?

要是需要让 AI 调用外部代码能力的情况,就是 http 请求或者 stdio 通信?比如起个本地后端服务用于获取一言,那 markdown 里就写请求地址、入参出参长啥样? AI 模型判断到自己需要调的时候,就会去发请求?发请求、读写本地文件、执行命令这些基础能力是 AI IDE 等客户端自带的?

所以和各种 AI API 发请求时,除了校验、会话 id 、模型调参之类的,就只是在传这些 markdown 和上下文组成的字符串?不能一股脑都传过去吧,怎么实现按需传的?

我给这组 API 起个更“好记”的名字:ArkUI 参数类型工具箱
原因很简单:你在写 ArkUI 的时候,真正高频碰到的不是某个组件,而是这些“参数类型”——它们决定了你属性方法能不能传、传了有没有效果、资源引用会不会报错/不生效。


1)Resource:资源引用($r / $rawfile),写对了才会生效

Resource 就是“引用资源文件”的类型。它一般用在颜色、字符串、尺寸、媒体资源这些地方。

1.1 两种常见写法

① $r:引用 sys/app 的资源表

$r('belonging.type.name')
  • belonging'sys''app'
  • type'boolean' | 'color' | 'float' | 'intarray' | 'integer' | 'pattern' | 'plural' | 'strarray' | 'string' | 'media'
  • name:资源名(你在资源里定义的)

例子:

Text($r('app.string.app_name'))
Text('hello').fontColor($r('sys.color.font_primary'))

② $rawfile:引用 rawfile 目录文件

$rawfile('filename')

例子:

Image($rawfile('banner.png'))

1.2 Resource 这块最常见的坑

坑 1:类型不匹配
比如某个属性支持 string | Resource,你用 $r 引用的资源必须也能被当成 string 用。
你要是拿个 color 的资源去喂给 string 参数,最后基本就是“看起来没报错,但效果等于没写”。

坑 2:用法不被这个属性支持
有些属性虽然类型签名看着支持 Resource,但具体实现并不一定对所有 Resource 用法都生效。遇到“设置了但没效果”,优先怀疑这个。


2)Length:长度单位(最常用,但也最容易写乱)

Length 你每天都在用:width/height/padding/margin/fontSize/...

它本质就是:数字 + 单位规则

2.1 Length 支持三种输入

① string:可以写单位或百分比

'10px'
'10vp'
'10fp'
'100%'

② number:默认单位是 vp

10   // 等同于 10vp

③ Resource:引用尺寸资源

$r('app.float.page_padding')

2.2 一个特别容易忽略的小规则

string 不写单位时,默认也是 vp。

'10'  // 等同于 10vp(很多人以为是 px)

所以我个人建议:

  • number 就当 vp 用
  • string 就写清单位(特别是 px/fp 这种)

3)ResourceStr:字符串参数“既能传字符串也能传资源”

你会在很多地方看到这种写法:某个属性入参是 string | Resource
那这个参数类型通常就叫 ResourceStr

Text('标题')
Text($r('app.string.title'))

这种类型的核心价值就是:国际化时不改代码结构,只换资源。


4)Padding / Margin:内外边距(四方向版)

这俩就不多废话了,你懂的:

.padding({ top: 12, right: 16, bottom: 12, left: 16 })
.margin({ top: 8 })
  • Padding / Margin 里每个方向都是 Length
  • 不写的方向就当默认 0

4.1 LocalizedPadding / LocalizedMargin(API 12+):支持 RTL 的 start/end

这个是很多人做国际化后才发现的坑:
在 RTL(从右到左)语言模式下,left/right 语义可能不对。

所以 API 12+ 给了:

  • start/end(会跟随 LTR/RTL 自动翻转)
  • top/bottom 不变

你可以理解成:

  • 想写“逻辑上的左边距” → 用 start
  • 想写“逻辑上的右边距” → 用 end

5)边框相关:EdgeWidths / EdgeColors / EdgeStyles / BorderRadiuses

边框这块参数挺多,但其实记住一句话就行:

边框就是:宽度 + 颜色 + 样式 + 圆角

5.1 分方向的写法(EdgeXXX)

比如只想让上边框更粗:

.borderWidth({ top: 2, right: 0, bottom: 0, left: 0 })
  • EdgeWidths:四边宽度(Length)
  • EdgeColors:四边颜色(ResourceColor)
  • EdgeStyles:四边样式(BorderStyle)
  • BorderRadiuses:四角圆角(Length)

5.2 LocalizedEdgeXXX / LocalizedBorderRadiuses(API 12+)

同样是为了 RTL:

  • start/end 会随语言方向翻转
  • top/bottom 不变

6)BorderOptions:边框“合并包”(我自己最爱用这个)

很多组件支持你直接传一个对象,把边框一次性写全:

.border({
  width: 1,
  color: '#e5e5e5',
  radius: 12,
  style: BorderStyle.Solid
})

BorderOptions 里可以写:

  • width:Length 或 EdgeWidths 或 LocalizedEdgeWidths
  • color:ResourceColor 或 EdgeColors 或 LocalizedEdgeColors
  • radius:Length 或 BorderRadiuses 或 LocalizedBorderRadiuses
  • style:BorderStyle 或 EdgeStyles
  • dashGap/dashWidth(虚线专用,API 12+,并且不支持百分比)

小提醒: 虚线那俩只有当你样式是虚线时才会生效,不然写了也等于没写。


7)ResourceColor:颜色入参“万能类型”

ResourceColor = Color | number | string | Resource

你可以随便挑一种习惯:

  • Color.Red(枚举)
  • 0xffff0000(number,rgb/argb)
  • '#ff0000' / 'rgba(...)'(string)
  • $r('sys.color.font_primary')(Resource)

我自己习惯:

  • 写 demo / 临时样式用 string
  • 做统一主题/规范用资源 $r(...)

8)Offset / Position / Area / RectResult:坐标与区域信息

这几个一般出现在相对布局、测量回调、位置信息获取里。

  • Offset:偏移量 { dx, dy }(都是 Length)
  • Position:坐标点 { x, y }(都是 Length)
  • Area:元素区域信息(宽高 + position/globalPosition)
  • RectResult:更偏“测量结果”的 { x, y, width, height }(数字)

简单记法:

  • Position/Offset 更像“你要怎么摆”
  • Area/RectResult 更像“系统告诉你摆完是什么结果”

9)Font:字体配置(别全塞 Text 上,整理成对象更清爽)

Font 是文本样式对象,常见字段:

Text('Hello')
  .font({
    size: 16,
    weight: 400,
    family: 'HarmonyOS Sans',
    style: FontStyle.Normal
  })

注意一个细节:

  • size 如果是 number,单位是 fp(不是 vp)
  • 不支持百分比

10)Dimension / PX / VP / FP / LPX / Percentage / Degree:更“严格”的单位类型

如果你看到某些属性不收普通 Length,而是收 Dimension 或更具体的 PX/VP/FP,可以理解成:

这个属性想让单位表达更明确、更严格。

比如:

  • 10px10vp10fp10lpx10%10deg

你只要按要求写就行,不要想着偷懒传个 '10' 过去。


11)CustomBuilder:给组件塞一段自定义 UI(配合 @Builder)

这个就是“插槽”的感觉:属性里让你传一个函数,内部会调用它来渲染自定义内容。

你会在一些组件的属性方法里看到需要 CustomBuilder 的参数类型。


12)一些“看起来冷门但会突然用上”的类型

我把这几个当成“备用工具”:

  • ColorFilter:4*5 矩阵的颜色滤镜(做颜色处理会用)
  • ModalTransition:全屏模态转场方式(NONE/DEFAULT/ALPHA)
  • OutlineOptions + EdgeOutlineWidths/OutlineRadiuses/EdgeOutlineStyles:外描边(有时做高亮边框很好用)
  • VoidCallback / Callback<T>:回调类型(看签名就知道怎么传)
  • Configuration:颜色模式、字体缩放倍数(做适配时用)
  • Bias:锚点约束下的偏移比例(相对布局更精细控制)
  • ChainWeightOptions:链中组件权重(布局分配)
  • CacheCountInfo:缓存数量信息(更偏性能调参)
  • ResponsiveFillType / ItemFillPolicy:响应式填充(WaterFlow/Grid/List/Swiper)

这些不一定每天用,但你看到类型名时不至于懵。


13)最后给一个“我自己的写法习惯”(省事还不容易踩坑)

  1. 尺寸:能用 number 就用 number(默认 vp)
  2. 需要明确单位的:用 string 写清楚 vp/px/fp/%
  3. 国际化/主题:优先用 $r 走资源
  4. RTL 适配:能用 start/end 就别写 left/right
  5. 边框:优先用 border({...}) 这种对象写法,少写四条边到处散落
  6. 遇到“设置没效果”:先怀疑类型不匹配 or 该属性不支持这种 Resource 用法

一、准备文件

  1. 你得先有俩东西:

    • nmon采集的数据文件(后缀是 .nmon,比如 server01_20260228.nmon,这是服务器性能数据);
    • nmon analyser工具下载链接:https://pan.quark.cn/s/e2c7e4e2b769(就是那个 nmon analyser v33g.xls文件,得是Excel格式)。
  2. 把这两个文件放一块儿,比如都扔到桌面,省得找起来麻烦。

二、打开工具并允许宏运行

  1. 双击打开 nmon analyser v33g.xls(Windows系统直接点就行,Mac可能得用Excel打开)。
  2. 这时候Excel可能会弹提示:“是否启用宏?”——必须点“启用宏” !不然工具没法干活儿(宏是用来解析nmon数据的核心功能)。

三、导入nmon数据文件

  1. 打开xls后,会看到一个叫  “Analyser” ​ 的工作表(一般第一个就是)。
  2. 找到顶部菜单栏里的  “File”(文件) ​ → 点  “Open”(打开)
  3. 在弹出的窗口里,找到你之前准备好的 .nmon文件,选中它,点  “打开”

四、等工具自动分析

导入之后不用管,工具会自动跑一会儿(进度条走完就行)。

跑完后,你会看到一堆新的工作表,比如:

  • CPU_ALL(CPU整体使用情况)、
  • MEM(内存)、
  • DISK(磁盘)、
  • NET(网络)……

五、看分析结果

直接点上面的工作表标签就能切换,每个表里都是图表+数据:

  • CPU_ALL里能看到 %usr(用户态占用)、%sys(内核态占用)、%idle(空闲)——如果idle太低,说明CPU忙;
  • MEM里有 memfree(空闲内存)、buffers/cache(缓存)——free太少可能要加内存;
  • DISK看 read/write(读写速率)——要是某块盘一直满负荷,可能IO瓶颈;
  • NET看 recv/send(收发流量)——带宽不够就升级网卡。

六、导出结果(可选)

如果想存成PDF/图片给别人看:

  1. 选中要导出的图表或表格;
  2. 右键→复制,或者直接截图;
  3. 粘到Word/PPT里,再保存成你要的格式就行。

一、布局世界的基石:理解容器本质

在HarmonyOS的UI构建宇宙中,Row和Column就像两位性格迥异的建筑师。Row是位擅长横向铺陈的设计师,总把元素按水平轴线排列得整整齐齐;Column则偏爱纵向延伸,用垂直轴线构建出错落有致的层次感。记得在智能家居控制面板的开发中,我们用Row搭建功能入口栏,用Column组织设备状态卡片,这种组合拳让界面既规整又不失灵动。

这两个基础容器掌握着布局的核心哲学:单一方向原则。就像城市规划中的主干道与高架桥,Row负责横向交通,Column管理纵向流动。但别被它们的名字局限——通过巧妙的主轴交叉轴配置,完全可以实现复杂的九宫格布局。


二、核心差异看一波

2.1 布局方向对比

维度Row(水平大师)Column(垂直专家)
主轴方向从左到右的水平高速公路从上到下的垂直电梯井
交叉轴垂直方向的次干道水平方向的辅路
典型应用顶部导航/按钮组/图片画廊表单/列表/卡片内容
空间分配justifyContent控制水平间隙alignItems管理垂直对齐

2.2 鸿蒙版本演进

鸿蒙6带来的layoutWeight动态权重系统,彻底改变了传统固定尺寸的布局思维。就像给元素装上了弹性骨架,让它们能根据屏幕尺寸自由伸缩。而鸿蒙5开发者需要注意,旧版中layout_weight需要配合width/height: 0%才能生效的特殊写法。

2.3具体来康康啥是啥

1、Row 组件

Row 是水平布局容器,用于将子组件沿水平方向排列。其核心属性包括间距控制、主轴对齐、交叉轴对齐。

  1. 核心属性
    (1)space:子组件水平间距
    作用:设置子组件在主轴(水平方向)上的间距,单位默认为 vp(虚拟像素);
    示例:Row({ space: 16 })表示子组件之间间隔 16vp。
    (2)justifyContent:主轴(水平)对齐方式
    作用:控制子组件在主轴(水平方向)上的排列方式,取值为 FlexAlign枚举;
    常用值:
    FlexAlign.Start(默认):子组件靠左对齐;
    FlexAlign.Center:子组件水平居中;
    FlexAlign.End:子组件靠右对齐;
    FlexAlign.SpaceBetween:子组件均匀分布,首尾与父容器边缘对齐;
    FlexAlign.SpaceEvenly:子组件及首尾间距均等。
    (3)alignItems:交叉轴(垂直)对齐方式
    作用:控制子组件在交叉轴(垂直方向)上的对齐方式,取值为 VerticalAlign枚举;
    常用值:
    VerticalAlign.Center(默认):子组件垂直居中;
    VerticalAlign.Top:子组件靠顶部对齐;
    VerticalAlign.Bottom:子组件靠底部对齐。
  2. 举个例子:水平功能按钮组
    咱们用 Row 组件实现的水平按钮组案例,包含三个按钮(首页、分类、购物车),并设置了间距、居中对齐和阴影效果:

    @Component
    export struct ButtonGroupExample {
     build() {
         Row({ space: 16 }) // 子组件水平间距16vp
             {
             Button('首页')
                 .width(80)
                 .height(40)
                 .fontSize(14)
                 .fontColor(0xFFFFFF)
                 .backgroundColor(0x007DFF)
                 .borderRadius(24);
    
             Button('分类')
                 .width(80)
                 .height(40)
                 .fontSize(14)
                 .fontColor(0xFFFFFF)
                 .backgroundColor(0x007DFF)
                 .borderRadius(24);
    
             Button('购物车')
                 .width(80)
                 .height(40)
                 .fontSize(14)
                 .fontColor(0xFFFFFF)
                 .backgroundColor(0x007DFF)
                 .borderRadius(24);
         }
         .width('100%') // 容器宽度占父容器100%
         .height(80) // 容器高度80vp
         .backgroundColor(0xFFFFFF) // 背景色白色
         .justifyContent(FlexAlign.Center) // 子组件水平居中
         .shadow({ radius: 4, color: 0x05000000 }); // 阴影效果
     }
    }
    2、Column 组件详解

    Column 是垂直布局容器,用于将子组件沿垂直方向排列。其核心属性与 Row 类似,但主轴方向为垂直方向,因此 justifyContent控制垂直对齐,alignItems控制水平对齐。

    1. 核心属性

    (1)space:子组件垂直间距
    作用:设置子组件在主轴(垂直方向)上的间距,单位默认为 vp;
    示例:Column({ space: 20 })表示子组件之间间隔 20vp。
    (2)justifyContent:主轴(垂直)对齐方式
    作用:控制子组件在主轴(垂直方向)上的排列方式,取值为 FlexAlign枚举;
    常用值:
    FlexAlign.Start(默认):子组件靠顶部对齐;
    FlexAlign.Center:子组件垂直居中;
    FlexAlign.End:子组件靠底部对齐;
    FlexAlign.SpaceBetween:子组件均匀分布,首尾与父容器边缘对齐。
    (3)alignItems:交叉轴(水平)对齐方式
    作用:控制子组件在交叉轴(水平方向)上的对齐方式,取值为 HorizontalAlign枚举;
    常用值:
    HorizontalAlign.Center(默认):子组件水平居中;
    HorizontalAlign.Start:子组件靠左对齐;
    HorizontalAlign.End:子组件靠右对齐。

    1. 举个例子:垂直表单布局

    咱们用 Column 组件实现的登录表单案例,包含标题、输入框、按钮等子组件,并设置了垂直间距和水平居中:

    @Entry
    @Component
    export struct LoginFormExample {
     build() {
         Column({ space: 24 }) // 子组件垂直间距24vp
             {
             Text('用户登录')
                 .fontSize(24)
                 .fontWeight(FontWeight.Bold)
                 .alignItems(HorizontalAlign.Center); // 标题水平居中
    
             TextInput({ placeholder: '请输入用户名' })
                 .width('80%')
                 .height(48)
                 .padding(12)
                 .border({ width: 1, color: 0xE0E0E0 })
                 .alignItems(HorizontalAlign.Center); // 输入框水平居中
    
             TextInput({ placeholder: '请输入密码' })
                 .width('80%')
                 .height(48)
                 .padding(12)
                 .border({ width: 1, color: 0xE0E0E0 })
                 .alignItems(HorizontalAlign.Center); // 输入框水平居中
    
             Button('登录')
                 .width('80%')
                 .height(48)
                 .fontSize(16)
                 .fontColor(0xFFFFFF)
                 .backgroundColor(0x007DFF)
                 .borderRadius(24)
                 .alignItems(HorizontalAlign.Center); // 按钮水平居中
         }
         .width('100%')
         .height('100%')
         .backgroundColor(0xF5F5F5);
     }
    }

三、小例子来康康

3.1 电商商品卡片(鸿蒙6+)

// 使用Flex布局实现响应式商品项
@Entry
@Component
struct ProductCard {
  @Prop product: Product;

  build() {
    Row() {
      Image(this.product.imageUrl)
        .width(100)
        .objectFit(ImageFit.Cover)
        .borderRadius(8)
      
      Column({ space: 8 }) {
        Text(this.product.name)
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
        
        Text(`¥${this.product.price}`)
          .fontSize(14)
          .fontColor(Color.Red)
          .maxLines(2)
        
        Row() {
          Text('立即购买')
            .fontSize(16)
            .fontColor(Color.White)
            .backgroundColor(Color.Blue)
            .padding({ left: 12, right: 12 })
        }
      }
      .layoutWeight(1)
    }
    .padding(16)
    .backgroundColor(Color.White)
  }
}

这个案例完美展现了Row与Column的嵌套艺术:外层Row构建商品主图与信息区的水平布局,内层Column处理文本信息的垂直堆叠,最后的Row实现价格与按钮的水平对齐。

3.2 鸿蒙5兼容方案

// 旧版布局实现(需注意权重语法)
Column() {
  @Link isExpanded = false
  
  Row() {
    Text('展开详情')
      .onClick(() => isExpanded = !isExpanded)
  }
  .height(40)
  
  if(isExpanded) {
    Column() {
      // 详细内容
    }
  }
}

在鸿蒙5中,动态布局需要借助状态变量和条件渲染,代码量明显增加。建议使用@ohos.animator实现平滑过渡效果。


四、性能优化小技巧

4.1 布局嵌套瘦身术

在聊天消息列表开发中,我们曾遇到嵌套8层Column导致的性能问题。通过以下改造,帧率从45FPS提升至60FPS:

// 优化前(深层嵌套)
Column() {
  ForEach(messages, (msg) => {
    Column() {
      Row() {
        Image(msg.avatar)
        Text(msg.sender)
      }
      Text(msg.content)
    }
  })
}

// 优化后(扁平化结构)
Column() {
  ForEach(messages, (msg) => {
    MessageItem(msg) // 独立组件
  })
}

组件拆分配合buildCache启用,内存占用减少37%。

4.2 空间魔法:Blank组件妙用

在底部导航栏实现中,Blank组件让按钮自动对齐变得优雅:

Row() {
  TabButton('首页')
  Blank() // 自动填充剩余空间
  TabButton('我的')
}
.justifyContent(FlexAlign.SpaceBetween)

相比手动计算margin,这种声明式写法维护成本降低60%。


五、跨版本适配一波

5.1 条件编译方案

// 版本特性检测
const layoutProps = isHarmonyOS6() 
  ? { layoutWeight: 1 } 
  : { width: '100%' }

Column(layoutProps) {
  // 内容
}

5.2 渐进式迁移

  1. 样式迁移:将固定尺寸替换为百分比/dp单位
  2. 事件迁移onClick改为@ohos.gesture
  3. 动画迁移animateTo替代旧版动画API

六、大家伙记得避坑

6.1 常见陷阱

  • 尺寸坍缩:未设置minWidth/minHeight导致内容溢出
  • 层级错乱:深层嵌套破坏视觉层次
  • 性能黑洞:滚动容器内滥用复杂布局

6.2 调试三板斧

  1. 布局边界可视化:启用showLayoutBoundary
  2. 层级分析器:查看组件树深度
  3. 性能监控:使用@ohos.performance

总结一下下

Row和Column这对黄金搭档,既是UI构建的脚手架,也是性能优化的关键。记住三个黄金法则:

  1. 单一职责:每个容器只做一件事
  2. 空间留白:给内容呼吸的空间
  3. 版本兼容:用条件编译筑起防护墙

当你在深夜调试布局时,不妨想象自己是个城市规划师——Row是笔直的林荫道,Column是层叠的立体车库,而你,正是这个数字世界的造物主。参考华为官方文档:Row组件参考Column组件参考

flowchart TD
    Start[开始:明确布局需求] --> ChooseContainer{Row or Column?};
    %% 选择容器类型
    ChooseContainer -->|水平排列(如导航栏、按钮组)| UseRow[Row组件];
    ChooseContainer -->|垂直排列(如表单、列表)| UseColumn[Column组件];
    
    %% Row组件设计流程
    UseRow --> SetRowProps[设置Row属性];
    SetRowProps --> SpaceRow[设置子组件水平间距(space)];
    SetRowProps --> JustifyRow[设置主轴(水平)对齐方式(justifyContent)];
    SetRowProps --> AlignRow[设置交叉轴(垂直)对齐方式(alignItems)];
    SetRowProps --> AddRowChildren[添加子组件(如Button、Image)];
    
    %% Column组件设计流程
    UseColumn --> SetColumnProps[设置Column属性];
    SetColumnProps --> SpaceColumn[设置子组件垂直间距(space)];
    SetColumnProps --> JustifyColumn[设置主轴(垂直)对齐方式(justifyContent)];
    SetColumnProps --> AlignColumn[设置交叉轴(水平)对齐方式(alignItems)];
    SetColumnProps --> AddColumnChildren[添加子组件(如Text、TextInput)];
    
    %% 通用逻辑:嵌套与响应式
    AddRowChildren --> NestComponents[嵌套其他容器(如Column/Row)];
    AddColumnChildren --> NestComponents;
    NestComponents --> ResponsiveDesign[响应式适配(如媒体查询、layoutWeight)];
    
    %% 结束:渲染与验证
    ResponsiveDesign --> Render[渲染UI];
    Render --> Validate[验证布局效果(如DevEco Studio预览)];
    Validate --> End[结束];

引言

随着鸿蒙系统在穿戴设备领域的生态拓展,Wear Engine Kit 作为鸿蒙为智能手表提供的核心开发套件,整合了硬件协同、分布式通信、数据管理等能力,为开发者构建高体验的穿戴应用提供了底层支撑。本文以「健身动态」智能手表应用为例,结合真实健身场景,基于 Wear Engine Kit 的开放能力,从业务需求到代码实现完整拆解应用开发流程,为鸿蒙穿戴应用开发提供可落地的实践参考。

一、业务需求分析

「健身动态」应用面向日常健身人群,需满足以下核心需求:

  1. 多模态运动数据采集:支持跑步、骑行、健身操等场景的心率、步数、动作姿态等数据实时采集,精度需满足运动分析标准。
  2. 运动状态智能识别:自动识别当前运动类型,无需用户手动切换模式。
  3. 实时数据可视化:在手表小屏上以轻量化方式展示关键数据(心率、距离、卡路里),运动后生成多维度分析报告。
  4. 跨设备数据同步:支持将运动数据同步至鸿蒙手机,实现多端数据互通。
  5. 数据安全存储:用户的健康数据需本地加密存储,避免隐私泄露。

二、业务场景详述

场景1:户外晨跑

用户戴上智能手表,点击「健身动态」应用启动跑步模式。Wear Engine Kit 驱动加速度计、心率传感器高频采集数据:

  • 跑步过程中,手表实时显示心率(如「140次/分」)、已跑距离(「3.2公里」)、消耗卡路里(「210千卡」);
  • 当心率超过用户预设的安全阈值(如160次/分),手表振动提醒并降低数据采集频率以节省功耗;
  • 跑步结束后,应用自动生成「心率波动折线图」「步频分布柱状图」,并同步至用户的鸿蒙手机。

场景2:室内健身操

用户打开健身操课程视频,「健身动态」通过 Wear Engine Kit 整合的陀螺仪+加速度计数据:

  • 识别用户的动作幅度(如深蹲深度、手臂伸展角度),实时反馈动作标准度;
  • 课程结束后,统计「动作完成率」「平均运动强度」,并将数据存入本地历史库。

三、需求开发逻辑

基于 Wear Engine Kit 的能力,对应需求的开发逻辑如下:

  1. 数据采集层:通过 Wear Engine 的传感器管理接口,调用心率、加速度计、陀螺仪硬件,根据运动类型动态调整采样频率(跑步场景:加速度计100Hz/次,心率1Hz/次;健身操场景:陀螺仪50Hz/次)。
  2. 数据处理层:利用 Wear Engine 的数据预处理能力,对传感器原始数据进行滤波降噪,再通过特征提取算法识别运动类型。
  3. 展示层:基于 Wear Engine 优化的 ArkTS UI 框架,适配手表小屏布局,实现数据实时刷新与图表渲染。
  4. 同步层:通过 Wear Engine 的分布式软总线接口,建立手表与手机的 P2P 连接,完成数据跨设备同步。
  5. 存储层:使用 Wear Engine 提供的加密存储接口,对健康数据进行本地加密存储。

四、实现方案

架构设计

应用采用「分层架构」,基于 Wear Engine Kit 能力拆解为4个核心模块:

健身动态应用
├─ 传感器采集模块(依赖 Wear Engine 硬件接口)
├─ 数据处理模块(依赖 Wear Engine 数据算法能力)
├─ UI展示模块(依赖 Wear Engine ArkTS UI 框架)
└─ 数据管理模块(依赖 Wear Engine 存储/分布式接口)

代码实现

以下基于 ArkTS 语言,结合 Wear Engine Kit 的关键 API 实现核心功能:

1. 传感器数据采集(依赖 Wear Engine 传感器接口)

import sensor from '@ohos.sensor'; // Wear Engine 传感器管理API

// 初始化传感器管理器
const sensorManager = sensor.getDefaultSensorManager();

// 心率传感器采集
export function startHeartRateCollect(callback: (rate: number) => void) {
  const heartRateSensor = sensorManager.getDefaultSensor(sensor.SensorType.TYPE_HEART_RATE);
  if (!heartRateSensor) throw new Error("心率传感器不可用");
  
  // 注册传感器监听(Wear Engine 提供的高频采集能力)
  sensorManager.registerSensorListener(heartRateSensor, (data) => {
    const rate = data.values[0];
    callback(rate);
  }, { samplingRate: 1000 }); // 采样频率:1次/秒
}

// 加速度计+陀螺仪联合采集(用于动作识别)
export function startMotionCollect(callback: (acc: number[], gyro: number[]) => void) {
  const accSensor = sensorManager.getDefaultSensor(sensor.SensorType.TYPE_ACCELEROMETER);
  const gyroSensor = sensorManager.getDefaultSensor(sensor.SensorType.TYPE_GYROSCOPE);
  
  // 多传感器同步采集(Wear Engine 硬件协同能力)
  sensorManager.registerSensorListener(accSensor, (accData) => {
    sensorManager.registerSensorListener(gyroSensor, (gyroData) => {
      callback(accData.values, gyroData.values);
    }, { samplingRate: 50000 }); // 50次/秒(适配健身操动作识别)
  }, { samplingRate: 50000 });
}

2. 运动状态识别(依赖 Wear Engine 数据处理能力)

// 基于传感器数据特征识别运动类型
export function recognizeMotionType(acc: number[], gyro: number[]): string {
  // 计算加速度幅值(Wear Engine 提供的基础数据处理能力)
  const accMagnitude = Math.sqrt(acc[0]**2 + acc[1]**2 + acc[2]**2);
  // 计算陀螺仪角速度均值
  const gyroMean = (Math.abs(gyro[0]) + Math.abs(gyro[1]) + Math.abs(gyro[2])) / 3;
  
  if (accMagnitude > 12 && gyroMean < 0.5) return "Running"; // 跑步特征
  if (accMagnitude > 8 && gyroMean > 1) return "FitnessDance"; // 健身操特征
  if (accMagnitude > 5 && gyroMean < 0.3) return "Cycling"; // 骑行特征
  return "Stationary";
}

3. 实时数据展示(依赖 Wear Engine ArkTS UI 框架)

@Entry
@Component
struct MotionDataDisplay {
  @State heartRate: number = 0;
  @State distance: number = 0;
  @State motionType: string = "Stationary";

  build() {
    Column({ space: 10, justifyContent: FlexAlign.Center })
     .width('100%')
     .height('100%') {
      // 运动类型展示
      Text(`当前模式:${this.motionType}`)
       .fontSize(18)
       .fontWeight(FontWeight.Bold);
      
      // 心率展示(Wear Engine 适配手表的UI组件)
      Text(`心率:${this.heartRate} 次/分`)
       .fontSize(22)
       .backgroundColor('#FF4081')
       .color('white')
       .padding({ left: 15, right: 15, top: 5, bottom: 5 })
       .borderRadius(20);
      
      // 距离展示
      Text(`距离:${this.distance.toFixed(1)} 公里`)
       .fontSize(20);
    }
  }

  // 页面加载时启动数据采集
  aboutToAppear() {
    startHeartRateCollect((rate) => {
      this.heartRate = rate;
    });
    startMotionCollect((acc, gyro) => {
      this.motionType = recognizeMotionType(acc, gyro);
      // 计算距离(简化逻辑)
      this.distance += 0.01;
    });
  }
}

4. 分布式数据同步(依赖 Wear Engine 分布式软总线)

import distributedData from '@ohos.data.distributedData'; // Wear Engine 分布式数据API

// 同步运动数据至鸿蒙手机
export async function syncMotionData(data: MotionData) {
  // 初始化分布式数据存储
  const kvManager = distributedData.createKvManager({ context: getContext() });
  const kvStore = await kvManager.getKVStore('motion_data_store');
  
  // 写入分布式存储(Wear Engine 自动同步至同账号设备)
  await kvStore.put(`motion_${Date.now()}`, JSON.stringify(data));
}

安全机制

基于 Wear Engine Kit 的安全能力,实现以下隐私保护措施:

  1. 数据加密存储:使用 @ohos.security.crypto API(Wear Engine 安全子模块)对用户健康数据进行 AES 加密后存储;
  2. 权限管控:在应用配置文件中声明 ohos.permission.READ_HEALTH_DATA 权限,运行时通过 @ohos.permissionManager 向用户申请授权;
  3. 分布式数据权限:同步至手机的数据仅对同华为账号的设备可见,避免跨账号泄露。

总结

本文基于 Wear Engine Kit 开发的「健身动态」应用,通过整合其传感器管理、分布式通信、数据安全等能力,实现了真实健身场景下的核心需求。Wear Engine Kit 不仅降低了穿戴设备的硬件适配成本,还通过鸿蒙的分布式特性拓展了应用的跨设备能力。开发者在实际开发中,可进一步结合 Wear Engine 的 AI 动作识别、低功耗优化等高级能力,提升应用的体验与性能。

一、浮层功能的本质与价值

在移动端开发领域,浮层设计就像给应用界面添加"便利贴"——既能突出关键信息,又不破坏原有布局结构。ArkUI的overlay机制正是这种设计哲学的完美体现,它允许开发者在不改变组件树结构的前提下,通过叠加文本、组件或动态内容实现丰富的交互效果。

记得去年参与智能家居项目时,我们需要在设备控制面板上添加实时状态提示。正是通过overlay属性,我们在不修改原有布局的情况下,实现了温度数值的动态悬浮显示。这种非侵入式的开发方式,极大提升了代码的可维护性。


二、API演进与核心差异解析

2.1 基础实现方式对比

版本特性鸿蒙5实现方案鸿蒙6+优化方案
文本浮层字符串直接赋值支持富文本格式与动态样式注入
组件浮层需手动管理生命周期新增ComponentContent自动生命周期管理
定位系统基础对齐方式引入九宫格定位+像素级偏移
性能表现频繁刷新时出现闪烁增量更新机制减少重绘区域

代码对比一下下

// 鸿蒙5传统写法
Image($r('app.media.logo'))
  .overlay("Beta版", {
    align: Alignment.Bottom,
    offset: {x: 0, y: -15}
  })

// 鸿蒙6+增强方案
Text.create("Beta版")
  .fontSize(14)
  .fontColor(Color.Warn)
  .position({x: 10, y: -20})
  .applyTo(Image.$r('app.media.logo'))

2.2 隐藏的彩蛋功能

在鸿蒙6的OverlayOptions中,新增了zIndex属性和pointerEvents控制选项。这在实现弹窗遮挡关系时特别有用:

.overlay(dialogContent, {
  align: Alignment.Center,
  zIndex: 999,         // 确保弹窗在最上层
  pointerEvents: true  // 允许点击穿透
})

三、实战举个例子

3.1 动态加载场景

在电商详情页的商品评价模块,我们实现了根据用户滑动动态加载历史评价的浮层提示:

// 动态加载组件浮层
@Builder dynamicReviewLoader(index: number) {
  if(index % 3 === 0) {
    ReviewCard(this.reviews[index])
      .width('90%')
      .margin({bottom: 15})
  }
}

// 浮层配置
Image($r('app.media.product'))
  .overlay(
    ComponentContent(this.uiContext, 
      wrapBuilder(dynamicReviewLoader), 
      { startIndex: 0 }
    ),
    { align: Alignment.Bottom, offset: {y: -50} }
  )

3.2 复杂交互实现

针对客服系统的快捷回复面板,我们采用分层浮层方案:

sequenceDiagram
    participant User
    participant MainView
    participant OverlayMgr
    
    User->>+MainView: 点击快捷回复按钮
    MainView->>+OverlayMgr: 获取浮层管理器
    OverlayMgr->>+OverlayMgr: 创建回复面板组件
    OverlayMgr-->>-MainView: 返回浮层句柄
    MainView->>+OverlayMgr: 设置定位参数
    OverlayMgr-->>-User: 显示带动画的浮层

四、跨版本适配实战技巧

4.1 版本特性检测方案

// 动态选择实现方式
const setupTooltip = () => {
  if(isHarmonyOS6()) {
    return new TooltipV2({
      content: "长按保存图片",
      trigger: "hover"
    })
  } else {
    return new TooltipV1({
      text: "长按保存图片",
      position: "top"
    })
  }
}

4.2 性能优化实录

在聊天应用的表情包浮层场景中,通过这个小优化使FPS从45提升至60:

  1. 对象池技术:复用已销毁的浮层实例
  2. 脏区域标记:仅更新变化部分
  3. 硬件加速:启用GPU渲染

    class EmojiOverlay {
      private pool: ComponentContent[] = []
      
      getComponent() {
     return this.pool.pop() ?? new ComponentContent(...)
      }
      
      recycle(component: ComponentContent) {
     this.pool.push(component)
      }
    }

五、进阶开发一波

5.1 状态管理方案

采用@Link实现父子组件浮层联动:

// 父组件
@State isEditing = false

Button("编辑")
  .onClick(() => this.isEditing = true)

// 子组件
@Link isEditing: boolean

build() {
  if(this.isEditing) {
    OverlayText("正在编辑...")
      .position({x: 100, y: 200})
  }
}

5.2 动画系统整合

结合Animator实现平滑过渡:

const slideIn = animateTo(
  { transform: translate(0, -100) },
  { duration: 300, curve: Curve.EaseOut }
)

overlayElement.animate(slideIn)

六、 小问题避坑

6.1 常见陷阱

  • 定位偏移:未考虑安全区域(需使用safeAreaInsets
  • 内存泄漏:未正确回收ComponentContent实例
  • 事件穿透:忘记设置pointerEvents属性

6.2 调试工具链

  1. ArkUI Inspector:实时查看浮层层级
  2. Performance面板:分析渲染耗时
  3. 内存快照:检测未释放的浮层对象

七、猜想一波

根据HarmonyOS 6.1的路线图,浮层功能将迎来三大升级:

  1. 3D变换支持:实现立体旋转效果
  2. 物理引擎集成:模拟真实触感反馈
  3. AI辅助定位:智能计算最佳显示位置

小小总结

浮层开发看似简单,实则暗藏玄机。掌握好版本差异、生命周期管理和性能优化技巧,能让你的应用界面既美观又高效。记住,最好的浮层应该像呼吸般自然——存在时不可或缺,消失时浑然不觉。下次开发的时候,不妨试试本文的实战技巧,让你的UI焕发新生哦。

Yann LeCun 反复强调过一个观点:当前LLM基于概率、逐 Token 预测的设计路线,很可能走不到人类水平的AI。他的团队更看好另一条路,基于能量的模型(EBM)。

上图来自他十多年前的一篇论文,LLM对候选答案返回"概率",EBM返回的则是"能量",能量最低的选项胜出。举个例子:输入 X = "汽车有4个轮子吗?",LLM可能给出 p("是") = 0.9、p("否") = 0.1;EBM则可能给出 E("是", X) = -3.1、E("否", X) = 0.4。谁的能量低谁就是答案。

两类模型的差异大吗?对EBM的输出做某种"归一化"就应该得到LLM输出的概率,但是差异恰恰就在归一化这一步。LLM用 Softmax 保证概率之和为1,EBM则松开了这条约束。训练时不需要归一化、不需要计算概率,在高维连续空间中反而获得了更多的灵活性和可训练性。对连续数据(比如图像)的全部可能输出做归一化本身就极其困难,能绕开就绕开。

构建EBM模型

给每个(可能的)数据点分配一个能量值,这个值是某个函数 E(x) 对输入数据点返回的标量。数据点出现的概率与该标量成反比——能量低则概率高,反过来也成立。回忆高中物理里各种"能量"(势能、动能等),势能越低的系统通常越稳定,道理一样。

假设已经拿到了 E(x),能否把它转换成概率?有时候确实需要,因为两个分别训练的系统各自输出的能量没有共同的校准基准,不能直接比较与合并;做密度估计时也需要概率。

密度估计是整个概率AI的核心主题,假定存在一个随机过程持续产生可观测的数据点,密度估计的任务是根据已观测的数据"猜"出该过程的概率密度函数(PDF)。一旦掌握了PDF数据的分布规律就清楚了:不仅能做预测,还能做生成。

理解数据生成过程的PDF,远超常规AI中"给定 X 预测 Y"的范畴。后者只是在估计某个过程的结果,不尝试理解或建模整个过程,生成完全是另一码事。

寻找能量函数 E(x)

训练EBM的核心目标:找到一个能量函数,能够为给定的 X 识别出最佳的 Y。换言之,在一系列可能的 Y 值中,哪一个和当前 X 最兼容?

合理的做法是训练一个深度神经网络,接收数据点(X 和 Y 的组合)作为输入,输出一个标量。X 和 Y 兼容性低时输出高值,兼容性好时输出低值。为了符号简洁,将能量函数的输入统一记作 x,即 E(x),x 代表 X 和 Y 的组合。

训练方式是常规套路:取大量数据样本,学习能量函数 E(x) 的参数 θ,让已观测到的、合理的数据点能量低,不太可能出现的数据点能量高。损失函数需要同时做两件事:(1) 压低正确答案的能量;(2) 抬高错误答案的能量。

一般性理论到这里就够了,但是接下来才进入更棘手的部分:寻找密度函数。

寻找概率密度函数(PDF)

目标是找到由 θ 参数化的概率密度函数 q(x):

能量函数 E(x) 的值域是 -∞ 到 +∞,取指数后输出自动变为正值,概率必须为正。至于为什么不直接约束 E(x) 本身为正?因为放开限制能让设计更自由,只要用 exp(E(x)) 保证输出为正即可。接下来做归一化:所有状态的概率之和(或积分)应该等于1,分母中的 Z 干的就是这件事。这样PDF就搞定了。

Z 大概是学概率模型的人最怕遇到的东西。名字有好几个——配分函数、归一化常数——出了名地难算。

指数前面那个负号呢?坦白讲没有功能性意义,纯粹是惯例所以去掉也不影响。

能量函数和密度函数的概念到此为止。

来自物理学的一点启发

上面的内容大量借鉴自物理学。把墨水滴入水中,它怎样扩散?过程本身是随机的,但宏观上系统总是从高能量状态向低能量状态演化。如果一个随机过程有10种可能的状态,每种状态各有其能量值,系统最终大概率停留在能量最低的那个状态。能量是一种粗粒度度量,它把一个状态内部所有微观过程的贡献浓缩成一个数。

远在AI出现之前,Boltzmann就发明了一种概率分布来描述热平衡中气体的统计力学行为。Gibbs后来做了进一步改进,这个分布被称为 Boltzmann分布(也叫Gibbs分布)。它给出系统处于某个状态的概率,是该状态能量和系统温度的函数。

p_i 是系统处于状态 i 的概率,ε_i 是该状态的能量,常数 k*T 不重要。Boltzmann分布说的一件事很简单:能量低的状态被占据的概率更高。要得到精确的概率值,除以归一化常数 Z 即可。而这个方程和EBM的密度估计 q(x) 几乎一模一样——物理学的直觉和EBM的数学走到了同一条路上。

训练EBM

LeCun讨论了多种损失函数。这类任务天然适合对比训练方法:拿一对样本喂给模型,训练目标是让其中一个的能量高于另一个。这种对比性质适合自监督训练。要绕开 Z可以构造只关心能量相对差异、不需要计算绝对概率的训练场景——比如取两个能量的比值,让 Z 在分子分母间自行消掉。

最终目标是学到一个能量景观:高概率的数据点能量低,低概率的能量高,全程不碰 Z。可选的算法有 Score Matching 族以及其他几类方法,但如果要建模密度函数 q(x) 呢?

这意味着要计算精确概率而非相对概率。分母里的 Z 注定让事情变困难。精确计算需要遍历所有可能的数据配置,计算量是"不可解的"。绕过精确 Z 的办法是用 MCMC 等采样过程产生大量样本,对训练所需的对数似然梯度做近似估计。对数似然展开后有两个关键项:

第一项的梯度把已观测数据点的能量往下压让它们更可能出现。第二项对数配分函数 Z 的梯度,则把其余所有位置的能量往上抬,防止模型给什么数据都打低能量。这一项实际上就是能量在模型当前分布上的平均梯度。

操作上可以这么理解:从模型中"生成"样本,和已观测的数据点混在一起训练,目的是让已观测数据点获得低能量、模型生成的样本获得高能量。用LeCun讲课时的比喻来说,损失函数应该在能量景观中"雕刻"出地形——训练样本附近挖坑(能量低),其他地方填高。模型要学会在观测数据所在位置"挖洞",在其余位置"堆土"。详细推导见附录。

回头再看LeCun论文中训练EBM的原始图示:

Y_i 是正确答案,Y_i 上方带hash标记的则是"最具迷惑性的错误答案",所有错误答案中能量最低的那个。在连续情况下定义正误很直观:Y_i 一定距离内的答案算正确,超出该距离的算错误。设计良好的损失函数在学习过程中会压低 E(Y_i, X_i),同时抬高错误答案的能量,尤其是 E(Y¯_i, X_i)。

不过生成样本非常慢,因为马尔可夫链必须跑到平衡态才能采样步数往往很大。为此 Hinton 提出了对比散度(CD)方法:只运行极短的马尔可夫链,采样速度大幅提升。设 p_0 为数据分布、p_∞ 为模型分布,梯度按以下公式计算:

右侧第一项是数据分布与模型分布之间的"散度",即 p_0 和 p∞ 之差(至于它们为什么不直接叫 P_data 和 P_model,LeCun也没解释)。第二项是短程MCMC链——从 p_0 出发跑 n 步得到 p_n——与模型分布 p∞ 之间的散度。直觉解释见附录。

上面这个差分关注的是"模型经过 n 步后偏离数据的程度",由此产生的梯度引导模型让训练数据更可能出现,同时让 n 步重建的结果更不可能出现。令人意外的是即使 n = 1,训练出来的EBM质量也相当好。

配合一些工程技巧——比如训练过程中维护并复用样本缓冲区——速度还能进一步提升。

使用训练好的EBM做推理

假设手上已有一个训练好的EBM,推理过程是什么样的?

和常规模型不同EBM的推理不是直接"给定 X 输出 Y"。这里需要遍历 Y 的所有可能取值,找出哪个 X 与 Y 的组合能量最低,那就是最终预测。本质上这是一个优化问题,模型预测的是输入 X 和输出 Y 之间的兼容程度。由此可以衍生出几类任务:分类——"哪个 Y 与 X 最兼容?"取能量最低的组合,应用场景如机器人导航;排序——"Y1 和 Y2 哪个与 X 更兼容?"按能量排序即可,应用场景如数据挖掘;检测——"这个 Y 与 X 兼容吗?"看能量升降趋势,如人脸检测中图像越不像人脸能量越高。

推理可以概括为:固定已观测变量的值,搜索剩余变量的配置使能量最小化。这个过程代价可能很高,需要选择合适的优化算法。参考LeCun的论文,按照 Y 的形式不同,推理策略也不同:

如果 Y 是连续变量且能量曲面 E(X,Y) 光滑,直接套用基于梯度的优化算法找最优 Y 就行。与训练阶段更新网络权重不同,这里是对 Y 本身做优化——从某个初始 Y 出发,沿 E(X,Y) 对 Y 的梯度方向迭代,直到落入极小值。思路和训练神经网络并无本质区别。如果 Y 是一组离散变量,能量函数可以表达为因子图——即若干依赖于不同变量子集的能量函数(因子)之和——那么可以用 min-sum 等算法。图、团和EBM的关系后面会进一步讨论。如果输出 Y 的每个元素可以表示为加权有向无环图(DAG)中的一条路径,特定 Y 的能量就是沿路径的边和节点值之和;因为图无环且能量是简单求和,最优路径可以用动态规划(如Viterbi算法)高效求解,在生物序列分析(如基因查找)中很实用。还有一些情况下,能量函数依赖于一组隐变量 Z——比如训练人脸检测系统时尺度和姿态信息未知。很多时候精确优化不切实际,必须诉诸近似方法,包括替代能量函数。

EBM的优势

EBM属于指数族,在AI领域有大量成熟的技术和工具可供复用。做最大似然估计取对数似然时"对数"和"指数"相互抵消,让数学处理变得简洁得多。统计物理中配分函数、自由能、变分近似等概念同样可以直接搬过来用。

在架构设计和训练准则方面,EBM比概率方法有更大的回旋余地。关键优势在于:概率方法不可解的场景下,EBM是可解的。概率模型必须做归一化,往往需要在所有可能的变量配置空间上计算积分,而很多时候这个积分根本算不出来。EBM不要求归一化,这个问题被天然绕过了。

EBM还有一个有意思的性质:总能量可以是多个能量函数之和——即专家乘积(Product of Experts)。图模型其实是EBM的一个特例,能量函数分解为各个能量项的和。为每个团(clique)分别设计能量函数然后简单相加就得到总能量,已有成熟的推理算法可以对这些项之和关于目标变量求最小值。听起来有些抽象,值得展开解释。

EBM作为因子图

从专家乘积(PoE)说起。PoE模型将多个专家各自输出的概率密度相乘得到总概率,每个"专家"对应一个未归一化能量函数。什么是未归一化能量函数?之前定义过归一化版本的能量函数:

未归一化能量函数就是分子部分,即 Exp(-E(x))。

假设整体能量函数复杂到无法直接处理——高维、变量众多。如果能把这个复杂系统拆分成若干子系统,每个子系统只依赖一小部分变量,每个子系统就是一个"专家"。这些专家的乘积给出总概率。因为子系统规模小得多,可以更透彻地分析和设计各自的能量函数。

做乘积时,把各专家的指数函数相乘即可。根据 Exp(a) * Exp(b) = Exp(a+b),乘法变成了各能量的简单加法,整体(未归一化)能量就是各子能量之和。

和试图为整个复杂系统找一个巨大的能量函数相比,把多个小而专的能量函数直接相加明显更可行——一个专家负责某方面,另一个负责另一方面。EBM的能量函数就这样被"因式分解"为各个函数(因子)之和,等价于因子图表示的图模型。

任何传统图模型都可以表示为因子图,EBM在这类场景下有天然的适配性。为每个团分别定义能量函数,求和即得总能量。团就是变量的一个子集。循环置信传播等高效算法可以用来计算最低能量配置。

从Hopfield网络到Transformer注意力机制

能量模型并非新事物1982年 John Hopfield 就提出了一种循环人工神经网络,功能类似"联想记忆系统"。

就像一丝微弱的气味能唤起完整的记忆一样,Hopfield网络接收不完整的数据,尝试还原完整的原始模式。它的机制正是EBM:将"模式"存储为能量景观中稳定的局部最小值。面对损坏或缺失的输入,网络迭代更新神经元状态,沿能量景观不断下降,直至落入最近的稳定"记忆",输出完整的重建结果。具体过程如下:

  • 将损坏或不完整的图像输入网络。
  • 网络中的神经元彼此相连,迭代更新自身状态,持续降低系统总能量。
  • 网络达到稳定的最低能量状态时停止更新——得到对原始未损坏模式的最佳重建。

去噪只是一个方面。这类网络也能用于求解优化问题(如旅行商问题),收敛到低能量状态就对应着优化问题的解。

Hopfield网络的能量函数由 Lyapunov函数 控制返回一个将神经元状态映射到实数值的标量,Hopfield网络是确定性的总会收敛到最近的局部能量最小值。另一种架构——玻尔兹曼机——则引入了随机性(概率性),使网络有能力跳出局部最小值去寻找全局最优。

玻尔兹曼机通常包含隐含单元,因而能建模更复杂的数据结构、学习内部表示。从物理意义上说,隐含节点在可见节点之间引入了有效的高阶交互,产生了针对可见节点的新能量函数。当隐含节点与可见节点之间的交互设为零时,玻尔兹曼机退化为Hopfield网络。

模拟和训练玻尔兹曼机不容易。一种简化方案是移除所有层内连接、只保留层间连接——所有可见节点都连到所有隐含节点,同层内无连接。由此得到的受限玻尔兹曼机参数更少、表达能力有所下降,但训练更方便且泛化性能更好。训练依然适用前面讨论过的那些技术。

2024年诺贝尔物理学奖颁给了Geoffrey Hinton和John Hopfield。Hopfield网络启发了现代机器学习方法。AI领域没有独立的诺贝尔奖类别,不过Hinton和LeCun拿到了地位相当的图灵奖——话题又回到了LeCun和他的团队。

LeCun的世界模型

LeCun离开Meta后创立了AMI Labs。他的核心论点是:当前LLM一次生成一个 Token 的固有设计,决定了它无法达到人类水平的智能,EBM可能是另一条出路。

EBM能同时预测整个输出序列的能量,而LLM每次只输出单个 Token 的概率。给整个句子算一个能量,再和其他候选句子比较,这在LLM框架下做不到。推而广之,规划在中途就能评估进展时效果最好——如果只在最后才拿到反馈,那和猜没什么区别。一个可以施加到中间状态的评分,能告诉你当前是否正确、哪里需要修复。EBM正好提供了这种能力:能量可以在部分轨迹上计算,而非仅限于最终答案。

从认知科学角度看,EBM可以(大致)对应Daniel Kahneman《思考,快与慢》中那种缓慢而审慎的类型2思维:在推理时运行优化过程以最小化能量,模仿深思熟虑的过程。LLM则按顺序逐 Token 生成、从不回头检查,本质上是"快"而直觉式的类型1思考。EBM可以在输出之前对完整答案反复斟酌,正如人类在面对复杂问题时所做的那样。LeCun的原话是:"真正的推理应该被表述为一个优化问题。"

Softmax 在这方面有结构性缺陷。它本质上是"赢者通吃"——两个输出值只要稍有差距,Softmax就会把这个差距放大为概率上的巨大悬殊。生成模型在理想状态下应当能考虑多种可能的下一步,而不是每次都锁定得分最高的那个选项。基于 Softmax 的模型天生具有单峰偏差:擅长表示分布中单一的宽峰,难以处理落在输入空间不相邻区域的数据。EBM不存在这个问题,它可以同时给多个不相交的数据区域赋予低能量(多峰分布中多个不同的峰)。Softmax还带来过度自信的问题——膨胀大的输出、压制小的输出,程度远超合理范围。虽然有各种变通方案,但这是一个结构层面的硬伤。

LLM还有一个根本局限:它困在文本的离散世界里,缺乏人类意义上的"世界模型",无法预判行动的后果。试图构建一个预测未来每个细节的生成模型注定行不通。在世界建模的框架下,做法是在输入空间中预测未来状态,再通过EBM衡量这些预测状态与当前上下文之间的"兼容性"。

人脑对世界的感知方式也不是直接的。大脑通过感官观察世界,从中构建出外部世界的表征,这个过程发生在一个独立的潜空间中。潜空间的结构与真实世界有关联,但针对实用性而非精确性做了优化。世界模型也应当具备类似特性。

JEPA(联合嵌入预测架构)是世界模型方向上的一次尝试。它学习世界的抽象表征(团队用视频做了实验),在抽象空间中做预测。I-JEPA 面向图像,V-JEPA 面向视频,都跳过了像素级重建,直接在潜空间中预测更高层次的特征。JEPA及类似模型在不同程度上借鉴了EBM的思想。严格说它们不是完整的EBM——推理时不做能量优化,仍然走常规前向传播——但确实把能量或相关替代指标用作了模型架构的关键组件。Logical Intelligence 发布的Kona是一个更激进的例子。

Kona是面向关键系统的"基于能量"的AI模型,核心机制是物理驱动的优化而非逐 Token 预测。它能同时生成完整的推理轨迹,并直接对问题和约束做条件化。推理在连续潜空间中进行,输出密集向量 Token 而非离散 Token,因而可以利用学到的能量对推理轨迹做受控的局部编辑,通过近似梯度信息改善连贯性和约束满足度。在困难数独上Kona的解题率达到96.2%,超出当时所有前沿LLM。

附录

每当在概率AI方面有疑问,翻开Goodfellow等人的《深度学习》总能找到答案。这本书封底有三位在AI领域可能无人能及的学者的推荐语,不是没有原因的。直接跳到第18章,标题恰如其分——"面对配分函数"。先从之前讨论过的对数似然入手。

它来源于一个简单的关系:

PDF p 等于未归一化的 PDF(p 上方带hash标记)除以归一化常数 Z。θ 是要通过梯度下降求解的参数集。上式对数似然的梯度展开后变成:

到这里并没有做什么复杂的操作。倒三角是梯度符号。幸运的是,这在机器学习中是常见的模式——学习的正阶段(第一项)和负阶段(第二项)。第一项从数据集中采样就能轻松求出,真正麻烦的是第二项。注意 Z 本身只是 p(带hash标记)的求和或积分,因而是 θ 的函数,求梯度就必须对它做计算。

第二项可以通过几步简单变换改写为期望值的形式。

有了期望值的形式,就可以用采样来近似:从模型 p(x) 中抽取若干 x 的样本,做蒙特卡罗估计得到训练所需的梯度。最终的对数似然梯度变为:

方程中两项各有分工。第一项对应从数据集中均匀抽样计算梯度;第二项对应从正在训练的模型 p(x) 中用MCMC抽样、取平均后计算梯度。这就是机器学习文献中的正阶段与负阶段。正阶段中,对从数据集抽取的 x 增大 log p˜(x);负阶段中,对从模型分布抽取的 x 减小 log p˜(x),以此降低配分函数。全程只需要处理未归一化的 p˜,不涉及 Z 的精确计算,操作上完全可行。

能量函数去哪了?Goodfellow给出了连接:深度学习文献中通常用能量函数来参数化 log p˜。正阶段于是对应压低数据集中训练样本的能量,负阶段对应抬高从模型中抽取的样本的能量。

再看Goodfellow版本的能量升降图示,和LeCun的版本略有不同:

绿色的点表示数据集的PDF。从数据集中均匀采样时,取到的 x 更多地集中在绿色峰值附近。正阶段是对数似然梯度的第一项,它让模型的 PDF p(x) 在这些数据点周围有更高的密度(对应的能量应被压低,但这里暂不引入能量概念以保持简洁),从而让模型逐渐逼近数据分布。

但正阶段有一个副作用:它盲目地在所有位置增加未归一化概率——绿色峰值处加得多一些,其他地方也加了。只做这一步是不够的。要加速收敛,必须同步降低其他位置的未归一化概率。这正是负阶段做的事情。(虽然叫"阶段",两者实际上同步发生。)

负阶段从模型分布中采样点,压低它们的未归一化概率。通过MCMC从 p(x) 中采到的点可能来自任何位置——好的数据点也好,坏的数据点也好,一律压低。把好数据点的概率推回去是正阶段的职责。

两项协同工作。第二项抵消了正阶段到处加常数的倾向,训练过程中模型与数据集的分布逐渐趋同。当二者完全相等时,正阶段在任何一点推高的力与负阶段推低的力大小相等,梯度的期望降为零,训练收敛。

负阶段降低了从模型中采样的点的概率,因此这些点通常被解读为模型对世界的"错误信念"。一个引人遐想的推论:负阶段被提议用于解释人类的做梦——大脑维护着一个关于世界的概率模型,清醒时经历真实事件并沿 log p˜ 的梯度更新模型,睡眠时经历从当前模型中采样出的事件并沿 log p˜ 的负梯度走,以最小化 log Z。

如何简化MCMC采样

MCMC的主要成本在于每步都要从随机初始化开始"预热"马尔可夫链(详见前面分享的MCMC链接)。自然的优化思路是从一个接近模型分布的分布出发来初始化链。用什么初始化?可以直接用数据集。

对比散度(CD)算法在每步用数据分布的样本初始化马尔可夫链。训练初期,数据分布和模型分布差距较大,负阶段精度不高;与此同时正阶段默默发挥作用。等正阶段把模型分布拉近了数据分布,负阶段的精度也跟着上来。

CD算法的梯度计算方式前面已经展示过:

可以这样理解:当输入来自数据时,如果模型的马尔可夫链对输入做了剧烈改动,就予以惩罚。这个估计有偏差——MCMC中 n 步之后的项被忽略了——但偏差很小。研究表明,CD丢掉的恰恰是正确MCMC更新梯度中最小的那些项。

https://avoid.overfit.cn/post/45846459329949159b3817dade6a84e7

作者:Allohvk

PixPin1.9.11是 PixPin 截图贴图工具​ 的安装包,这玩意儿能截屏、贴图、取色、加标注,写文档、做笔记、写代码时特别好用,比系统自带截图功能强不少。

一、准备工作

  1. 下载安装包

  2. 确认系统版本

    • 支持 Win7/Win10/Win11,32 位和 64 位系统都能用,老电脑装也没问题。
  3. 用管理员身份运行(推荐)

    • 右键 PixPin1.9.11.exe→ 选“以管理员身份运行”,防止权限不足装不上。

二、安装步骤

  1. 双击 PixPin1.9.11.exe运行(如果右键过了就直接双击)。
  2. 第一次打开会弹出“用户账户控制”提示 → 点  “是”
  3. 进入安装向导,选语言(默认中文)→ 点  “下一步”
  4. 阅读许可协议 → 选“我接受协议” → 点  “下一步”
  5. 选安装位置:

    • 默认是 C:\Program Files\PixPin,可点“浏览”改到其他盘(比如 D 盘)。
  6. 附加任务:

    • 建议勾“创建桌面快捷方式”和“开机自动启动”(开机就能用,不用每次手动开)。
  7. 点  “安装” ​ 开始安装,等进度条走完(几十秒)。
  8. 安装完会问是否立即启动 → 可先取消,等会儿再开。

三、首次使用与基本操作

  1. 在桌面或开始菜单找到 PixPin​ → 点开。
  2. 第一次打开是主界面,默认快捷键是 F1 截屏F3 贴图,可以直接用。
  3. 截屏:按 F1,框选要截的区域,松手就截好,自动进剪贴板。
  4. 贴图:截完按 F3,截图会“贴”在屏幕上,能拖动、缩放,不怕被其他窗口盖住。
  5. 取色:截屏时鼠标移到颜色上,底部会显示颜色值,点一下就复制,做设计、写代码很方便。
  6. 标注:贴图后右键,可以加箭头、文字、马赛克,改完直接保存。

👉 彗星来的那一夜 ,豆瓣评分 8.6 分,67 万人评。

这是一部 2013 年的电影,很久了,再次分享是最近重新看了一遍,搭配 B 站解说看完后觉得很震撼很有意思。以前看过一次,由于当时没看懂,所以现在看的时候都已经把剧情几乎全部忘记了。

电影制作成本仅 5 万美元,而且貌似是导演自己家里拍摄。

其实看完第二遍也没看懂多少,看了 B 站解说后就觉得这片真不错。喜欢物理设定/科幻的朋友们可以试试看,另外内容基本有很多对话,所以如果觉得枯燥可能就不适合了。

另外推荐看完后看的解说:

自己的一点儿想法

  • 1, 打伊朗肯定不是短时间能解决的, 老美的肯定会陷进去

  • 2, 台湾是可以短时间搞定的

另外的一些疑问

  • 1, 趁机在台海军演, 美国会是什么反应?

  • 2, 伊朗到底可以坚持多久?

  • 3, 伊朗如果被打败了, 中东局势会怎么走?

只是发表个人意见, 可以互相聊聊~~~

到账速度确实是秒到账的,但是为什么要出这样一个功能呢,方便大家的资金出境么,想着这样是不是更好的能监控到你转账的每个账号?
但是香港账号也不是什么隐私了,都能 crs 交换回来,而且以前没有跨境支付通时候很多人直接用中银转中银香港那种不也是能被记录下,所以考虑这个跨境通被监控记录是不是多虑呢,就算人肉背过去存进去,那账户信息和余额不也会是被 crs 交换回来吗