包含关键字 typecho 的文章

使用Docker安装Temporal, 使用外部MySQL数据库

1. 初始化MySQL数据库

# 创建用户 temporal
CREATE USER 'temporal'@'%' IDENTIFIED BY 'temporal';

# 创建数据库 temporal
CREATE DATABASE `temporal` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
grant all privileges on `temporal`.* TO 'temporal'@'%';

# 创建数据库 temporal_visibility
CREATE DATABASE `temporal_visibility` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
grant all privileges on `temporal_visibility`.* TO 'temporal'@'%';

2. 配置文件

docker-compose.yml

services:
  temporal-init:
    image: temporalio/auto-setup:1.29.3
    container_name: temporal_init
    environment:
      DB: mysql8
      # 改为正确MySQL配置
      MYSQL_SEEDS: "192.168.2.215"
      DB_PORT: 3306
      MYSQL_USER: "temporal"
      MYSQL_PWD: "temporal"
      MYSQL_DB: "temporal"
      DEFAULT_NAMESPACE: "default"
    command: ["temporal-sql-tool", "create-schema", "-k", "default", "-v", "1.19"]
    restart: "no"
    
  temporal:
    image: temporalio/auto-setup:1.29.3
    container_name: temporal_server
    environment:
      # 使用外部 MySQL
      DB: mysql8
      MYSQL_SEEDS: "192.168.2.215"    # 你的 MySQL 地址
      DB_PORT: 3306
      MYSQL_USER: "temporal"
      MYSQL_PWD: "temporal"
      MYSQL_DB: "temporal"                 # Temporal 数据库
      DEFAULT_NAMESPACE: "default"
      # 这里填127.0.0.1会报错, 需要在ports将7233端口映射到宿主机, 填写宿主机的IP
      TEMPORAL_BROADCAST_ADDRESS: "192.168.2.215"
    ports:
      - "7233:7233"   # gRPC frontend
      - "7234:7234"   # history
      - "7235:7235"   # matching
      - "7239:7239"   # worker
      - "8088:8088"   # Temporal Web API (可选)
    depends_on:
      - temporal-init
    restart: always

  temporal-ui:
    image: temporalio/ui:2.45.0
    container_name: temporal_ui
    environment:
      TEMPORAL_ADDRESS: "temporal:7233"  # 指向 Temporal Server 容器名
      TEMPORAL_UI_PORT: "8080"
    ports:
      - "8080:8080"   # 浏览器访问
    depends_on:
      - temporal
    restart: always

temporal-init: 用于自动初始化数据
temporal: 启动核心进程
temporal-ui: 启动UI管理界面
访问 http://192.168.2.215:8080/ 查看管理后台
image.png

3. 启动

# 启动
docker compose up -d
# 查看日志
docker logs --tail=100 -f temporal_server

销毁命令:

docker compose down
docker container list

导言

周一早晨,你打开笔记本电脑,心中萦绕着一个问题:两年后,我的工作是否还有意义?

上周,你花了三小时撰写一份活动方案。而一位同事使用AI智能体,仅用四分钟就生成了质量接近80%的版本——如果诚实地说,可能接近90%。

不是担心是否会失业,而是担心你所做的工作是否还能体现价值。你依然保住了工作,但你能感觉到它在不断缩水。问题不在于“机器人来了”,而在于你不再清楚自己该擅长什么。花了五年积累的Excel技能?自动化了。分析竞争对手并整合信息的能力?已有AI代劳。清晰撰写项目进展的技巧?不复存在。

你的职业身份正在以你无法追赶的速度消失,却无人告诉你下一步该何去何从。


案例分享

Sarah是资深研究分析师,十年经验,时薪250美元。公司引入AI研究助手后:

  • 初期:AI用90分钟完成她需2-3周的基础研究,她转而负责“高阶分析”。
  • 六个月后:公司质疑她工作的附加价值,将她的角色转为“质量审核员”,时薪降至150美元。
  • 最终:公司用AI搭配两名初级员工(年薪6.5万美元)替代了她85%的工作。
  • 核心问题:无人能明确定义“更高价值的工作”具体是什么,企业最终只能选择成本更低的方案。

职场困境

这一现象并非个人失败所致,而是经济激励结构的必然结果:

  • 企业通过AI降低成本,经理只需比较AI订阅费与员工薪资便可做出决策。
  • 但企业缺乏动力为员工设计未来角色,因为“重新定义工作”无法在财报中体现短期回报。
  • 速度错配:AI能力以6-12个月为周期迭代,而人通过教育或企业培训的适应周期长达2-5年。
  • 工业时代的制度无法解决指数级变化的问题,导致个人陷入系统性困境。

常见的应对策略

当感到自身价值被侵蚀时,人们通常会采取看似合理的应对方式:

  1. 更熟练地使用AI工具

    • 学习提示工程,掌握ChatGPT、Claude等平台,成为团队中的“AI专家”。
    • 致命伤:仍在比拼执行速度,而执行本身正被标准化,一旦工具被大幅优化,“提示技巧”便会失效。
  2. 深耕现有专业领域

    • 会计师钻研更复杂的税法,设计师学习更多软件,分析师构建更精细的模型。
    • 致命伤:在逐渐被自动化的领域深入,如同在洪区筑堡垒,AI已能逼近专家水平,专长反而成为包袱。
  3. 强调“软技能”

    • 试图通过创造力、同理心或人际关系凸显“不可替代的人性”。
    • 致命伤:这些概念过于模糊,难以度量,当AI能10秒生成100个创意时,“保持人性”无法转化为具体价值。

根本问题:上述策略都是被动适应,而非主动重塑,真正有效的是构建一个前所未有的新角色。


有效策略:成为协同指挥者

不要只执着于优化现有工作,要充分利用AI完成此前不可能的任务,持续发现约束消失后的新可能性

  • 案例:市场营销者Marcus用AI同时运行50个活动变体,他的角色转变为设计测试框架、解读数据模式、制定战略决策。
  • 关键:找到因人力限制而无法规模化的环节,用AI突破瓶颈,并专注于决策层。
  • 行动指南

    • 第一周:找出一个因耗时过长而无法大量进行的工作。
    • 第二周:用AI将其规模扩大10倍,容忍质量暂时下降。
    • 第三周:分析规模化带来的新洞察。
    • 第四周:向老板展示“新增能力”而不仅仅是“效率提升”。

结语

AI正揭示一个残酷的真相:许多人所谓的“战略思维”,其实只是严谨的执行力。当AI以惊人速度接管基础工作,那些曾被经验掩盖的、真正战略洞察力的缺失,便暴露无遗。企业曾习惯将“资深”等同于“有战略判断力”,而AI的到来,迫使所有人直面这一认知误区。经验堆积成的护城河,正在技术的冲击下迅速瓦解。

别再执着于捍卫那个正在缩水的旧角色。真正的出路,是主动构建一个——甚至六个月前都还不存在的——新角色。成为那个率先洞察新可能性,并围绕它构建价值的人。不要指望企业为你规划未来,也别等待教育系统赶上变革。在这个快速迭代的时代,唯一可靠的,是自我重塑的能力。

周一的清晨依旧会来,不同的是:当别人仍在焦虑中追问“我的价值何在”时,你是否已经走在了构建答案的路上。

越来越多企业开始用SRM软件,把原本依赖Excel、邮件、微信群的采购协作过程,升级为更标准、更可追溯、更可分析的数字化流程。

以华为云云商店上架的SRM软件产品介绍为例,成熟的SRM软件方案通常会围绕四大模块搭建能力框架:供应商管理中心、价格管理中心、采购执行协同中心、采购商城中心

对于中小企业来说,选对SRM系统往往意味着:采购团队终于能从“处理琐碎流程”转向“做供应商管理与成本优化”。今天我将从以下三点展开去讲,希望能对中小企业有所帮助。

1、中企业企业为什么要SRM软件?

2、几款主流的SRM软件介绍

3、如何选择适合的SRM软件?

一、为什么中小企业特别需要SRM系统?

不少中小企业的采购管理,仍停留在“Excel+纸质单据+人工沟通”的阶段。短期内能跑,但一旦企业规模上来,问题会集中爆发:

1、流程繁琐、效率偏低
从需求提出、询价比价、下单审批到对账结算,环节多且高度依赖人工操作,容易出错,也很难标准化。

2、供应商管理分散,信息更新滞后
供应商档案、资质文件、合同、历史交易记录散落在多个表格或文件夹里,更新不及时,关键风险(比如资质过期、交付异常)很难提前发现。

3、价格与成本不可控,采购“靠经验”
缺少统一的价格库、历史报价追溯困难,比价辑不透明,降本更多靠采购员个人能力,难以沉淀为组织能力。

4.绩效评估缺机制,无法科学分级管理
交付准时率、质量问题、服务响应等数据无法形成体系,导致供应商管理长期停留在“印象打分”,优胜劣汰难执行。

二、正远SRM:全景化协同采购管理方案

https://www.zhengyuantech.cn/

在华为云云商店上架的正远SRM数字化采购管理平台,定位是“采购全过程数字化与供应商协同网络构建”。其产品介绍明确强调:通过电子化流程与多种寻源方式,帮助企业提升采购效率、提高透明度并降低采购成本。

正远SRM的一大特点是采购方式覆盖较广,支持询比价采购、招标采购、竞价采购等,同时也提供多种采购组织模式的适配能力。

它的核心能力围绕四大模块展开:

1、供应商管理中心
支持供应商全生命周期管理,包括准入、资质、供货能力与产能评估等,强调把好准入关,形成科学供应商管理体系。

2、价格管理中心
提供采购预询价、比价采购、招标、竞价等多方式寻源策略,用于建立更体系化的价格管理与成本优化机制。

3、采购执行协同中心
通过供应商门户/协同网络实现订单协同:订单下发、交付反馈、异常处理等流程在线化,提高执行透明度与协同效率。

4、采购商城中心
面向标准物资采购提供内部采购商城能力,覆盖商品发布、价格审批、上架下架、购物车、订单中心等功能,实现自助式集中采购。

总体而言,正远SRM强调“轻灵活、低耦合”,对于需求变化快、流程迭代频繁的中小企业更友好。

三、金蝶AI星辰:轻量化云SRM选择

预算相对谨慎、希望快速上线的中小企业,通常会优先考虑云端SaaS类产品。金蝶面向小微企业推出的金蝶云·星辰定位是“小微企业SaaS管理云”,主打免安装、免维护、快速开通使用,并支持开放API接口连接生态。

在采购数字化方向,金蝶也有对应的采购云能力:例如金蝶云星空采购云强调供采双方协同的数智化采购平台思路。

对中小企业来说,星辰类产品的优势通常体现在:

1、SaaS订阅模式降低门槛
无需部署硬件与维护服务器,初期投入相对可控。

2、易上手更利于推进供应商协同
供应商侧操作越轻量,落地成功率越高。

3、与财务、进销存等体系形成联动
中小企业往往更关注“业务财务一体化”,避免数据割裂。

四、其他主流SRM系统盘点

除正远、金蝶外,中小型企业在SRM选型中还会常见以下几类方案:

1、8Manage SRM
覆盖寻源、招标、采购订单、合同管理等全流程,支持SaaS与本地部署,适合流程相对复杂、希望强化报表分析与权限控制的企业。

2、携客云SRM
偏“性价比与易用性”的云端采购管理工具,适合预算更有限、希望快速上线、优先解决协同与流程电子化的小型企业。

3、用友BIP采购云
用友采购云强调从寻源到签约的数字化,并提供电子招投标能力,覆盖从立项到定标的全过程,同时也包含采购商城能力。
整体更偏平台化、体系化,适合有一定规模、对合规与流程控制要求更高的企业。

4、简道云(零代码)
如果企业采购场景差异大,或者希望低成本快速搭建个性化流程,零代码方案也是现实选择。优点是灵活与低门槛,但复杂SRM场景往往需要较多自定义设计。

五、如何选择适合的SRM系统?

面对众多选择,中小企业建议抓住几个“选型硬指标”,避免被演示效果带偏:

1、先明确企业核心需求,不要一开始就追求“大而全”
中小企业优先把“供应商档案统一、寻源比价、订单协同、对账效率”这些刚需做扎实。

2、优先考虑部署与成本模式:云优先,本地谨慎
SaaS订阅模式更适合中小企业,避免前期投入过大、上线周期过长。

3、考察集成能力,避免数据孤岛
优先选择与现有ERP/财务体系同生态产品,或开放API较完整的平台。

4、易用性决定落地率,尤其是供应商侧
供应商端如果操作复杂、培训成本高,协同很难推起来。

5、服务保障要写进合同,别只听口头承诺
关注实施周期、培训方式、响应SLA、驻场与远程支持能力。

一家机械制造企业引入SRM系统后,供应商准入审核周期从7天缩短到2天,优质供应商占比提升40%。采购人员的时间分配也发生明显变化:从处理琐碎事务转向做谈判与供应商管理。

当一家电子元器件经销商上线SRM系统三个月后,供应商引入周期从14天缩短至3天,采购成本下降8%,库存周转率提升22%。

这些变化背后,是采购协作方式的改变——流程更透明、数据能沉淀、风险可预警,供应链也因此更敏捷、更抗风险。

(名字改的太快,暂定名 DroidCenter 把,原来想的是开热点,但后面加了虚机,等后面把其他做了可能就又想改了)

去年开的坑,今年终于填上了,适配一加,但是小米 888 之类的( K40Pro+)之类的也测试了可用。

https://imgur.com/OLxH4tj.png

实测支持双频并发热点

2.4GHz+5GHz 、2.4GHz+6GHz

https://imgur.com/ludMq0R.png

可以双发(测试了 Ace5Pro 和小米 K40Pro+),但是双发实测性能有衰减,不如单发,并且 2.4G 会检测 Overlapping ( 99%的情况下会落到 20MHz ),所以只能说是有,非必要不开。

5Ghz 可以开满血热点

( 160MHz ,OpenSpeedtest 测试>2.2Gbps )

https://imgur.com/nwuje6a.png

6Ghz 可以开满血热点

( 320MHz ,OpenSpeedtest 测试>3.6Gbps ,可能还可以更高)

https://imgur.com/XIDpPiK.png

书接上文: https://www.v2ex.com/t/1108368

反正是完全不走 Android 热点服务,直接去启动 hostapd 的,如果设备原先开热点不满血的(比如开出来热点只有 40 、80MHz 什么的),也可以试试,多半能开到设备满血性能。

现在手机热点也基本搞明白了,实际是可以优化的很快,驱动调整空间也很大( WCNSS 配置比较开放),可能秒了目前绝大多数 MiFi 和 CPE ,毕竟手机 x80/x85 基带遥遥领先。感觉是半个新思路了。。群友也有 dalao ,测试了中兴 F50 也可以起 OpenWRT 虚机啥的。

另外增加了亿些功能,包括常用路由,网桥,组网,路由管理,都有实现基本,

https://imgur.com/FIw9SX1.png

对于无法满足的需求,现已支持虚拟机!(也许 v 友对 Android 开虚机习以为常了 :)

https://imgur.com/Igxr7yi.png

基本的配置都做了支持,包括 VNC 等等

https://imgur.com/aI4NKeH.png

实测过了 Debian ,

https://imgur.com/bZNDrOC.png

RouterOS ,

https://imgur.com/eKIAAUj.png

https://imgur.com/ECKcarI.png

飞牛 OS ( arm 版),

https://imgur.com/tlV7V23.png

都能跑

支持 user (端口转发,适合简单不过流量的虚机,比如飞牛),

https://imgur.com/u0D2915.png

也支持挂载到网桥,可以将热点接口挂载在软路由下面。

(要是不在乎翻译效率,其实 x86 的也。。。)

如果手机支持 KVM 可调用 KVM ,不支持就是 TCG ,性能以实测为准(目前测试 NAS 性能还不错,从手机里开的飞牛,走 5GHz 热点下载有个 200MB/s 左右)。

https://imgur.com/Xmu6NMw.png

AT 命令,Web 终端也等等也做了支持的。

https://imgur.com/eJkR2ml.png

目前还有很多饼正在内测开发中,欢迎各位 dalao 品鉴吐槽,提提意见。当然 bug 可能也有的,有些功能没有加到细节(比如 iptables ,考虑到小白,就先 permit from lan 了),各种功能每天都在加 ing 。bug 的话早上提,晚上修,也可以来当裙友免费体验一下提需求当甲方的感觉(

还有很大优化空间,后面计划包括 USB 外挂网卡,RNDIS ,也会纳入管理,可以做真有线路由。

可能也适合那些无头 Android 5G 盒子,前提是能正常解 BL ,如果有合适的型号也可以推荐,这边看 ok 的话也适配一下

Make Android Great Again, Together

(开发消耗几个馒头 + 一撮头发 + 20B token ,Cursor + Claude + ChatGPT + Z.AI GLM Max + Kimi 2.5 Allegretto ,一堆订阅领衔主演)

淘宝买的,椅背调节角度是 3 档,113-125-135
但是到手安装后,现在后躺的角度,其实只有 2 个角度,就是下图 图 2,感觉上躺到底之后角度也不够,

因为前几天还买了 网易的 S9 pro + ,它也是介绍为 3 档,最大 135°,对比现在买的西昊,明显刚觉躺到底的角度更大
而且后躺是确实有 3 个角度锁定,也就是 图 1 所示

由于网易的椅子已经退回,所以没有很直接的比对,但是感觉上确实后仰角度差异较大

  • 问西昊淘宝的客服,说他们就是 图 2 情况,
  • 问京东呢,说是 图 1 的情况

想问下各位有没有买 西昊 B300 这个型号椅子的朋友,你们的后仰调节角度正常吗

670X296/image.png

  • 一个可以每天领取$V2EX 空投的网站, 但是在做的过程中发现缺少很多前置工具, 所以目前只是完成了一部分界面的逻辑


  • 为了完成一些前置工具, 我又开始了这个 chrome 插件的开发, 但是刚好赶上 livid 发布自定义节点, 所以也是暂时搁置了, 大概完成了 30%的工作, 这个项目的目标是在做的过程中, 能把一些用到的工具抽象成库文件供其他开发者使用.


  • 因为现在自定义节点的管理操作需要来回切换上下文, 所以我暂停了其他项目, 开始了这个项目, 目前完成了 90%左右, 但是前天突然心血来潮, 想做一个让 V 友写小说的节点, 所以我暂时暂停了这个项目.




  • 为了识别 V 友们在有故事的人节点中发布的小说能够合并成一本, 还有一个正在做的爬虫服务正在开发, 书籍仓库已经建好了V2EX-INFO/VBooks, 后面所有 V 友写的小说还有 AI 生成的小说都会放在这个仓库中, 开源使用了 MIT 协议, 所以转换小说到这个仓库的时候需要让 V 友确认一下他们写的小说允不允许被开源, 细节还没想好, 走一步看一步.


还有一些其他正在做的服务, 大部分处于知识积累阶段, 不知道什么时候能够开始. 比如一个去中心化的广告与流量平台

以及一些没有界面的纯 solana 链上的 dapp

附一张我使用 Planet 管理 todo 的截图:

ps: 以上应该是我最近会做的事情, 给自己的时间大概是 6 个月左右, 有些项目可能在做的过程中发现了更好的竞品, 如果能够直接使用的话, 这个项目就非常有可能会被我放弃掉, 哈哈哈哈.

摘要引言

摩尔线程正式发布了 AI Coding Plan 智能编程服务,开启 国产 AI Coding 全栈解决方案 的新篇章,同时推出30 天免费体验,这是国产算力与代码智能深度融合的首次规模级落地。


🧠 核心突破:为什么这次不同?

在大模型生成内容革命中,AI Coding 一直被视为未来效率飞跃的关键应用方向。摩尔线程这次发布的 AI Coding Plan 之所以值得所有开发者关注,有几大显著特点:

✅ 01. 从底层架构开始的中国力量

这套服务不是“云端 API + 调用额度”的简单组合,而是从国产全功能 GPU 到智能编码模型一体化构建的全栈方案
核心硬件采用的是 摩尔线程 MTT S5000 全精度算力底座,结合软硬协同的模型执行引擎,使得 AI 编程在本地高效、流畅运行成为可能。


💡 02. 顶级代码模型:GLM-4.7

AI Coding Plan采用了 GLM-4.7 模型 作为底层代码智能核心。该模型在全球专业评测平台(Code Arena)中,在开源与国产模型中表现名列前茅,尤其在:

  • ⚙️ 函数补全
  • 🐛 漏洞检测
  • 📌 结构重构建议

等实战场景中均表现优异,甚至在一些任务中超越 GPT-5.2。


🔗 03. 即插即用跨平台编码生态

不仅如此,AI Coding Plan 与主流智能编程工具实现了无缝对接:

  • 🤖 Claude Code
  • 🧑‍💻 Cursor
  • 🛠️ OpenCode

开发者可以在熟悉的 IDE 中直接启用国产 AI Coding 能力,无须额外迁移训练环境或学习复杂新工具。


📊 三档套餐覆盖全场景需求

为了满足从轻量级开发到企业级研发周期的不同需求,AI Coding Plan 提供了四种套餐:

套餐类型说明适用场景
🆓 Free Trial30 天免费试用入门试水、个人项目
⚡ Lite Plan中频使用额度小型团队、Side Project
🚀 Pro Plan大调用额度复杂系统开发
🏢 Max Plan峰值优先保障企业级高频开发

作为开发者,你现在可以,抢先进入官网申请 30 天免费体验

免费体验入口👇
👉 https://code.mthreads.com

image

数据库性能优化这事儿,很多人条件反射就三板斧:改 SQL、加索引、再加索引。一通操作下来,查询快了,磁盘炸了;延迟降了,维护成本上天;更扎心的是——你还以为自己“优化得很专业”。😅

这篇文章的思路很“叛逆”:与其在常规套路里打转,不如换个角度,利用 PostgreSQL 本身的一些机制做“非常规优化”。下面挑 3 个最容易落地、同时最容易被忽略的点,讲透它们为什么能省钱又提速。


1)别再全表扫了

先看一个特别真实的场景:用户表只有两种 plan:freepro,并且写了约束,保证不会出现别的值。

CREATE TABLE users (
    id INT PRIMARY KEY,
    username TEXT NOT NULL,
    plan TEXT NOT NULL,
    CONSTRAINT plan_check CHECK (plan IN ('free', 'pro'))
);

然后某位大佬在报表工具里一顿操作猛如虎,写了个:

SELECT * FROM users WHERE plan = 'Pro';

注意大小写:Propro。结果当然是 0 行。问题是——它为了得到“0 行”,居然可能 把全表扫了一遍,这就很离谱:明明约束告诉你“根本不可能有 Pro”,你还扫什么扫?扫得我 CPU 风扇都快起飞了。

这时可以打开一个“看起来冷门但对报表场景很香”的开关:constraint_exclusion

SET constraint_exclusion to 'on';

开启后,PostgreSQL 会在生成执行计划时参考约束信息,发现条件永远为假,就直接变成“秒回 0 行”,彻底避免无意义的 Seq Scan。

为什么它默认不是 on?因为它会增加规划阶段开销:对“系统自动生成的简单查询”,大概率用不上;但对 BI/报表这种人肉手写 SQL的场景,写错值、写错条件太常见了。
结论很直白:如果你的数据库经常被报表工具/分析师/临时查询折腾,考虑在报表环境把它打开,能省不少冤枉资源。


2)只要“按天统计”,就别用“精确到秒”的索引

函数索引省 3 倍空间还更快

第二个场景更像日常优化现场:10M 的销售表 sale,分析师要做按天汇总:

SELECT date_trunc('day', sold_at AT TIME ZONE 'UTC'), SUM(charged)
FROM sale
WHERE '2025-01-01 UTC' <= sold_at AND sold_at < '2025-02-01 UTC'
GROUP BY 1;

大家的第一反应:给 sold_at 上 B-Tree 索引!

CREATE INDEX sale_sold_at_ix ON sale(sold_at);

查询确实快了,但你一看索引体积——214MB,心里也跟着“咯噔”一下:为了按天统计,建了个精确到毫秒级的索引,这属于用大炮打蚊子

更聪明的做法是:只索引“天”,别索引“秒”。直接上表达式索引(函数索引):

CREATE INDEX sale_sold_at_date_ix ON sale((date_trunc('day', sold_at AT TIME ZONE 'UTC'))::date);

然后把查询写成同样表达式:

SELECT date_trunc('day', sold_at AT TIME ZONE 'UTC'), SUM(charged)
FROM sale
WHERE date_trunc('day', sold_at AT TIME ZONE 'UTC')::date BETWEEN '2025-01-01' AND '2025-01-31'
GROUP BY 1;

结果:索引体积从 214MB 变成 66MB,直接小了 3 倍多,还更快。原因不只是 datetimestamptz 小,而是离散值更少,B-Tree 可以做去重优化(deduplication),索引变得更紧凑。

但函数索引有个“脾气”:表达式得一模一样,稍微换个写法就可能用不上索引,比如把 date_trunc 换成 ::date,就直接退化回 Seq Scan。现实里让全团队“严格写同一表达式”,基本等同于要求大家每天不犯错(这事比上班准点还难🙂)。

解决方案有两种:

方案 A:View,把表达式固化成列

CREATE VIEW v_sale AS
SELECT *, date_trunc('day', sold_at AT TIME ZONE 'UTC')::date AS sold_at_date
FROM sale;

方案 B:Generated Column(更像“官方自带的 view 列”)

从 PostgreSQL 14 起支持生成列;文章里提到 PostgreSQL 18 还支持虚拟生成列:看起来是列,实际上是每次访问时计算的表达式,既保证表达式一致,又不额外存储(主打一个“既要又要”)。

ALTER TABLE sale ADD sold_at_date DATE
GENERATED ALWAYS AS (date_trunc('day', sold_at AT TIME ZONE 'UTC'));

然后查询就统一写:

SELECT sold_at_date, SUM(charged)
FROM sale
WHERE sold_at_date BETWEEN '2025-01-01' AND '2025-01-31'
GROUP BY 1;

这类优化特别适合那种“指标按天/按周/按月统计”的系统:别让索引为你用不到的精度买单


3)长 URL 唯一约束把索引撑爆?

用排他约束 + Hash 索引,5 倍缩容(但有坑)

当你要对一个超长字段(比如 URL)做唯一约束时,B-Tree 索引可能接近表本体大小,因为 B-Tree 叶子节点会存储被索引值本身。URL 又长又几乎不重复,索引很容易“胖成球”。

那能不能用 Hash 索引?Hash 索引存的是 hash 值,通常小很多。问题来了:PostgreSQL 的 Hash 索引 不支持 unique index

CREATE UNIQUE INDEX urls_url_unique_hash ON urls USING HASH(url);
-- ERROR: access method "hash" does not support unique indexes

但 PostgreSQL 还有个很少人用、名字很霸气的约束:Exclusion Constraint(排他约束)。它能配合 Hash 索引做“等值排他”,效果等同唯一约束:

ALTER TABLE urls ADD CONSTRAINT urls_url_unique_hash EXCLUDE USING HASH (url WITH =);

于是你得到了一个“用 Hash 索引实现的唯一性”。索引体积可能从 154MB 掉到 32MB,约 5 倍缩水,而且等值查询同样能用索引:

SELECT * FROM urls WHERE url = 'https://hakibenita.com';

不过它不是银弹,有几个硬坑必须知道:

  • 不能被外键引用:外键要求引用“唯一约束”,而排他约束不算传统意义的 unique constraint,所以引用会失败。
  • INSERT ... ON CONFLICT 有限制
    ON CONFLICT (url) 可能不认;需要写 ON CONFLICT ON CONSTRAINT ...;更糟的是 DO UPDATE 不支持排他约束。
  • 更通用的替代写法是用 MERGE(如果你的版本支持):
MERGE INTO urls t
USING (VALUES (1000004, 'https://hakibenita.com')) AS s(id, url)
ON t.url = s.url
WHEN MATCHED THEN UPDATE SET id = s.id
WHEN NOT MATCHED THEN INSERT (id, url) VALUES (s.id, s.url);

适用场景一句话总结:超长字符串字段需要唯一性,但不需要被外键引用,且写入冲突处理可以接受用 MERGE/业务层逻辑替代


结语

真正的优化,不是“更快”,而是“更合适”✅

这 3 个技巧的共同点很朴素:
不是让数据库“更努力”,而是让数据库别做无意义的事

  • 报表查错值?让约束帮你秒判 false,别全表扫
  • 只按天统计?索引就按天建,别为秒级精度付账
  • 长字段唯一性撑爆索引?换思路,用排他约束把 Hash 索引用起来

下次你准备“再加一个索引”之前,不妨先问一句:
需求到底需要多精?这条查询真的值得我为它养一个 200MB 的索引吗?
能把性能、成本、维护复杂度一起优化的,才是最爽的优化😉


喜欢就奖励一个“👍”和“在看”呗~

image

自己开发了一个 openwrt IOS 端客户端

已经上架了 APP store,直接搜索 wrthub 即可。

支持各种信息查看、WIFI 管理、连接设备管理、openclash 等各类插件管理,欢迎下载。




图片

GMI Cloud Inference Engine 是全球 AI 模型统一接入与在线使用的“高性能推理引擎平台”,底层搭载 H100/H200 芯片,集成全球近百个最前沿的大语言模型和视频生成模型,如 Minimax、DeepSeek、GPT OSS、Qwen、Kling 等,为 AI 开发者与企业提供速度更快、质量更高的模型服务。

欢迎来到!🎉🎉🎉

GMI Cloud Inference Engine AI 场景实践案例集【语言工具篇】之二。

**本期任务目标:**在 IOS 端的【Para翻译】app 中接入 Inference Engine 的 API。

Para 翻译是一个 IOS 多平台翻译聚合工具,其具有截屏翻译、浮窗划词翻译、自定义翻译风格等功能,其会员用户支持自定义接入第三方 API,灵活满足用户的个性化需求。

本文将以接入 Inference Engine 中的 MiniMax-M2.1 API 为例,详细讲解在 Para 翻译中接入 API 的过程。Token福利文末自行领取!!

MiniMax-M2.1 界面:

https://console.gmicloud.ai/playground/llm/minimax-m2/bbfb2cb...

01

准备工作:下载 APP

Get ready?

在 app store 里搜索并下载 Para 翻译。接入自定义 API 服务需要开通会员哦~

图片

02

接入步骤

API Connection Guide

第一步,按照如下图所示步骤点击按钮,找到自定义 API 窗口。

图片

图片

图片

图片

第二步,填写 API 信息。

自定义翻译服务名称可以随意命名,建议包含“GMI Cloud”或“Inference Engine”,以及模型名称登关键词,方便查找。

自定义 API 接口地址可直接复制:https://api.gmi-serving.com/v1/chat/completions

APIKEY 和模型名称则填写从 GMI Cloud 官网上获得的信息。API KEY、对应的模型设置,需要到 GMI Cloud 官网获取。

模型名称可在模型对应页面找到,比如我这里用的 MiniMax-M2.1,对应界面为:

https://console.gmicloud.ai/playground/llm/minimax-m2-1/1ed90...

点击页面下方的“验证”,确认接通后就可以开始使用啦~

图片

最后,我们再找一个英文界面尝试一下!

首先在 app 里选择好我们刚刚设置的 【GMI 翻译 API】。

图片

打开悬浮窗,进入任意英文界面。

图片

稍等片刻,翻译成功!

图片

很多人在本地开发时可能都会遇到这样的情况。数据少的时候,页面秒开,SQL 怎么写都感觉不到卡顿。可一上线,面对百万级流量,查询直接超时,数据库 CPU 飙升。

要避免这种开发时候猛如虎,上线操作二百五的尴尬,最好的办法就是在本地造点数据出来测。只有数据量上去了,那些平时隐藏的性能坑才会原形毕露。

image.png

先造它一亿条数据

如果表里只有几千行数据,全表扫描和走索引几乎没区别,甚至全表扫描更快。要验证索引策略,必须上强度。

别傻乎乎地写脚本在应用层循环插入,网络开销会慢到怀疑人生。PostgreSQL 自带的 generate_series 是个神器,下面这个函数能在几分钟内帮你造出一亿条模拟的用户操作日志,足够把坑找出来。

-- 创建一个能快速生成大量模拟数据的函数
CREATE OR REPLACE FUNCTION populate_large_table(target_rows BIGINT)
RETURNS VOID AS $$
BEGIN
  -- 批量插入,避免逐行提交的开销
  INSERT INTO user_events (user_id, event_type, created_at)
  SELECT
    (random() * 1000000)::INTEGER, -- 模拟 100万个不同的用户
    CASE (random() * 3)::INTEGER    -- 随机生成操作类型
      WHEN 0 THEN 'login'
      WHEN 1 THEN 'logout'
      WHEN 2 THEN 'purchase'
      ELSE 'view'
    END,
    NOW() - (random() * INTERVAL '365 days') -- 分布在过去一年
  FROM generate_series(1, target_rows);
END;
$$ LANGUAGE plpgsql;

-- 执行生成(注意:这会占用不少磁盘空间,执行时间取决于机器性能)
-- SELECT populate_large_table(100000000);

当这一亿条数据落盘后,随便跑一个 SELECT * FROM user_events WHERE user_id = 12345,就会发现耗时从毫秒级变成了几秒甚至十几秒。这时候,索引的价值就体现出来了。

索引不是越多越好

新手最容易犯的错就是给每个字段都加索引。要知道,索引本质上是空间换时间,而且是有代价的。

读取变快,写入变慢

每次 INSERTUPDATEDELETE,数据库不仅要改数据文件,还得同步更新相关的索引树。如果你表上有 5 个索引,插入一行数据就得维护 5 棵树。对于日志、IoT 传感器上报这类写多读少的业务,索引加多了简直灾难

策略建议:

  • 高频查询列:加索引(如外键、时间戳)。
  • 高频更新列:慎加索引。
  • 低区分度列:别加索引。比如“性别”或“状态(0/1)”,数据库扫索引发现要回表一半的数据,通常会直接放弃索引走全表扫描,这索引建了也是白建。

    *

拒绝盲猜,看执行计划

别觉得写了 WHERE user_id = ... 数据库就一定走索引。优化器有时候比我们想象的懒。

一定要用 EXPLAIN(PostgreSQL/MySQL 通用)来看看数据库到底在干什么:

EXPLAIN ANALYZE SELECT * FROM user_events WHERE user_id = 42;
  • 如果看到 Index Scan:恭喜,索引生效了。
  • 如果看到 Seq Scan(Sequential Scan):说明在全表扫描。这时候就要检查是不是数据分布不均,或者查询条件没对上索引。

    *

几种常用的索引避坑姿势

1. 复合索引:顺序是关键

当查询条件包含多个字段时,比如要查“某用户在某天的记录”,单列索引往往不够快。这时候要建复合索引:

CREATE INDEX idx_user_date ON user_events(user_id, created_at);

注意顺序(最左前缀原则)

这个索引对 WHERE user_id = ? 有效,对 WHERE user_id = ? AND created_at = ? 也有效。

但如果查询只有 WHERE created_at = ?,这个索引就废了。把最常用的筛选列放在最左边。

2. 唯一索引:既是约束也是加速

如果业务逻辑要求邮箱或手机号不能重复,直接上唯一索引。它不仅能提升查询速度,还能在数据库层面兜底,防止代码逻辑漏洞导致脏数据写入。

CREATE UNIQUE INDEX idx_unique_email ON users(email);

3. 针对性索引类型

  • 全文索引 (Full-Text) :不要用 LIKE '%关键词%' 去搜大段文本,慢得要死。MySQL 和 PG 都有专门的全文索引,支持分词。
  • GIN 索引:PG 特有,专门处理 JSONB 或数组数据。
  • 位图索引 (Bitmap) :适合数据仓库场景下,针对“状态”、“标签”这类低基数字段的组合查询(PG 默认常用 B-Tree,特定场景可用 BRIN 或扩展)。

    *

对于新手来说,安装数据库需要很繁琐的步骤。有了 ServBay 就不同了。ServBay能一键安装数据库。而且它支持多实例并发运行。就是说你可以同时启动 MySQL 8.0 和 MariaDB,或者同时跑一个 PostgreSQL 12 和 16。

这就很方便做数据迁移测试或者性能对比,看看同一条复杂 SQL 在不同版本数据库下的表现差异。

image.png

  • 一键部署:囊括了 MySQL, PostgreSQL, MongoDB, Redis, MariaDB 等主流数据库,不用到处找安装包或配置 Brew。
  • 开箱即用:安装完自动配好环境变量,直接在终端敲 psqlmysql 就能连,省去了改配置文件的麻烦。
  • 不污染系统:所有服务独立运行,不想用的时候一键停止或卸载,不会在系统里留下垃圾文件。

其实数据库优化从来就没有什么标准答案,只有取舍。

是牺牲写入速度换读取速度?还是牺牲磁盘空间换查询时间?这些都得看具体的业务场景,甚至要看你能不能接受数据会有几秒钟的延迟。

总之,实践是检验真理的唯一标准。自己试试就知道了。

2025年LLM领域有个有意思的趋势:与其继续卷模型训练,不如在推理阶段多花点功夫。这就是所谓的推理时计算(Test-Time / Inference-Time Compute):在推理阶段投入更多计算资源,包括更多Token、更多尝试、更深入的搜索,但不会改动模型权重。

ARC-AGI基准测试就是个典型案例。通过推理时技术可以达到87.5%的准确率,但代价是每个任务超过1000美元的推理成本。没用这些技术的LLM通常只能拿到不到25%。

本文要讲四种主流的推理时计算技术:深度方向的Chain-of-Thought,宽度方向的Self-Consistency,搜索方向的Tree-of-Thoughts,以及迭代方向的Reflexion/Self-Refine。

预备知识:LLM调用封装

先把基础设施搭好。下面是通用的LLM调用接口和辅助函数:

 fromcollectionsimportCounter, deque
importre

# ---- LLM调用封装 ----
defllm(prompt: str, temperature: float=0.7, max_tokens: int=800) ->str:
    """
    LLM调用的占位函数。
    在实际使用中,可以替换为OpenAI、Claude或本地模型的API调用。
    
    参数:
        prompt: 输入提示词
        temperature: 采样温度,控制输出多样性
        max_tokens: 最大生成token数
        
    返回:
        模型生成的文本
    """
    # 示例:使用OpenAI API
    # from openai import OpenAI
    # client = OpenAI()
    # response = client.chat.completions.create(
    #     model="gpt-4",
    #     messages=[{"role": "user", "content": prompt}],
    #     temperature=temperature,
    #     max_tokens=max_tokens
    # )
    # return response.choices[0].message.content
    
    raiseNotImplementedError("请实现你的LLM调用逻辑")

# ---- 辅助函数:提取最终答案 ----
defextract_final_answer(text: str) ->str:
    """
    从模型输出中提取最终答案。
    
    寻找格式为 "FINAL: <答案>" 或 "Final: <答案>" 的模式。
    在实际应用中,建议:
    - 让模型输出JSON格式,如 {"final": "..."}
    - 或使用针对具体任务的解析逻辑
    
    参数:
        text: 模型的完整输出文本
        
    返回:
        提取的最终答案(最多200字符)
    """
    m=re.search(r"(FINAL|Final)\s*[:\-]\s*(.*)", text)
     return (m.group(2).strip() ifmelsetext.strip())[:200]

深度(Depth):链式思维推理

Chain-of-Thought(CoT)是最基础也用得最多的推理时技术。核心思想很直白:让模型「思考」久一点。

传统调用方式期望模型直接给答案,但复杂问题不是这么解决的。CoT让模型生成详细的中间推理步骤,在数学、逻辑推理、编程这些任务上效果很明显。

为什么管用?首先是分解作用,大问题拆成小步骤,每一步更容易做对。其次是中间步骤充当了一种「外部记忆」,帮模型追踪推理过程。第三是强制模型展示推理,减少直接「猜」答案的情况。最后,模型推理过程中可以自查前面步骤对不对。

触发CoT有几种常见办法:零样本提示就是加一句「Let's think step by step」;少样本提示是给2-3个带推理步骤的例子;指令微调是用带CoT标注的数据集训练;系统提示则是在system message里定义推理风格。

 defsolve_with_cot(question: str) ->str:
    """
    使用链式思维(Chain-of-Thought)解决问题。
    
    通过精心设计的提示词,引导模型:
    1. 进行逐步推理
    2. 展示中间计算过程
    3. 最后给出明确的最终答案
    
    参数:
        question: 需要解答的问题
        
    返回:
        包含推理过程和最终答案的完整响应
    """
    prompt=f"""You are a careful reasoner. Your task is to solve the following problem.

Instructions:
1. Break down the problem into smaller steps
2. Show your reasoning for each step
3. Double-check your calculations
4. End with a clear final answer

Format your response as:
Step 1: [your first step]
Step 2: [your second step]
...
FINAL: <your final answer>

Question: {question}
"""
    # 使用较低的temperature以获得更确定性的输出
    returnllm(prompt, temperature=0.2, max_tokens=900)

# 使用示例
if__name__=="__main__":
    question="一个农场有鸡和兔,共35个头和94只脚。请问有多少只鸡和多少只兔?"
    result=solve_with_cot(question)
    print(result)
     print("\n提取的最终答案:", extract_final_answer(result))

CoT适合数学应用题、逻辑推理、代码调试、规划任务这类需要多步计算的问题。简单事实问答用CoT有点浪费,创意写作也不太合适——过度结构化会限制发挥。

局限性也很明显。Token消耗会上升,输出越长成本越高。模型可能在推理链中犯错,错误还会传播。输出格式也不总是稳定,需要后处理。

宽度(Width):自洽性采样

Self-Consistency的想法很简单:与其相信单次输出,不如生成多个答案,选最一致的那个。

有点像集体决策——单条推理链可能出错,但如果多条独立路径都指向同一答案,那答案八成是对的。

这方法管用的原因:单次采样可能因为随机性出错,多次采样能平均掉这些错误。正确答案往往能通过多条不同路径得到。不同路径可能捕捉问题的不同侧面。答案的一致性程度还顺便反映了模型的「信心」。

做Self-Consistency有几个关键决策要做。

第一是采样多样性。这点至关重要。如果所有采样都走同一条推理路径,自洽性就没意义了。高多样性设置是temperature 0.7-0.9、top_p 0.9-0.95,加上多样的提示词变体。temperature太低或提示词太固定都不行。

第二是采样数量。3-5个边际收益最高,适合成本敏感场景;10-20个是常规配置;40个以上适合对准确率要求极高的场景,但边际收益已经很低了。

第三是聚合策略。最常用的是多数投票,选出现次数最多的答案。也可以加权投票,根据置信度加权。还可以把相似答案聚类后再投票。

 defsolve_with_self_consistency(
    question: str, 
    n: int=10,
    temperature: float=0.8
) ->dict:
    """
    使用自洽性(Self-Consistency)方法解决问题。
    
    通过高温度采样生成多个多样化的答案,
    然后通过多数投票选择最一致的答案。
    
    参数:
        question: 需要解答的问题
        n: 采样数量,建议10-20
        temperature: 采样温度,建议0.7-0.9以确保多样性
        
    返回:
        包含以下键的字典:
        - final: 最终答案(得票最多的)
        - votes: 该答案的得票数
        - confidence: 置信度(得票数/总数)
        - all_finals: 所有提取的答案列表
        - vote_distribution: 完整的投票分布
        - samples: 所有原始输出(用于调试)
    """
    prompt_template="""Solve this problem step by step. 
Show your reasoning, then end with 'FINAL: ...'

Question: {question}"""
    
    samples= []
    foriinrange(n):
        out=llm(
            prompt_template.format(question=question),
            temperature=temperature,  # 高温度确保多样性
            max_tokens=900
        )
        samples.append(out)
    
    # 提取所有最终答案
    finals= [extract_final_answer(s) forsinsamples]
    
    # 统计投票
    vote_counter=Counter(finals)
    most_common=vote_counter.most_common()
    winner=most_common[0]
    
    return {
        "final": winner[0],
        "votes": winner[1],
        "confidence": winner[1] /n,
        "all_finals": finals,
        "vote_distribution": dict(vote_counter),
        "samples": samples
    }

defsolve_with_weighted_consistency(
    question: str,
    n: int=10,
    score_fn=None
) ->dict:
    """
    带权重的自洽性方法。
    
    除了多数投票外,还可以根据每个答案的质量分数加权。
    
    参数:
        question: 需要解答的问题
        n: 采样数量
        score_fn: 评分函数,接受(question, answer)返回0-1的分数
        
    返回:
        包含加权投票结果的字典
    """
    samples= []
    for_inrange(n):
        out=llm(
            f"Solve step by step. End with 'FINAL: ...'\n\nQ: {question}",
            temperature=0.8,
            max_tokens=900
        )
        samples.append(out)
    
    finals= [extract_final_answer(s) forsinsamples]
    
    # 加权投票
    weighted_votes= {}
    forfinal, sampleinzip(finals, samples):
        weight=score_fn(question, sample) ifscore_fnelse1.0
        weighted_votes[final] =weighted_votes.get(final, 0) +weight
    
    winner=max(weighted_votes.items(), key=lambdax: x[1])
    
    return {
        "final": winner[0],
        "weighted_score": winner[1],
        "weighted_distribution": weighted_votes,
        "all_finals": finals
    }

# 使用示例
if__name__=="__main__":
    question="如果今天是星期三,那么100天后是星期几?"
    result=solve_with_self_consistency(question, n=10)
    
    print(f"最终答案: {result['final']}")
    print(f"得票数: {result['votes']}/{len(result['all_finals'])}")
    print(f"置信度: {result['confidence']:.1%}")
     print(f"投票分布: {result['vote_distribution']}")

Self-Consistency适合有确定答案的问题(数学、编程、事实问答)、答案空间有限的问题(选择题、是/否问题)、以及生产环境中需要高可靠性的场景。开放式问题答案空间太大,每次答案都不同,投票没意义。创意任务没有「正确」答案可投票,也不适用。

局限性:成本线性增长,N次采样就是N倍成本。如果模型系统性地偏向某个错误答案,投票也救不了。同一答案的不同表述可能被当作不同答案,答案标准化是个麻烦事。

搜索(Search):思维树探索

Tree-of-Thoughts(ToT)把推理过程当成搜索问题来做。每个节点是一个「思维状态」,也就是部分推理结果;每条边是一个「思维步骤」,即推理动作;目标是找到通向正确答案的路径。

跟线性的CoT不同,ToT允许分支(从一个状态探索多个可能的下一步)、回溯(放弃没希望的分支,回到之前的状态)、评估(判断当前状态离目标有多近)。

为什么有效?线性推理一旦犯错就没法恢复,ToT可以回溯。某些问题天然是树形结构,比如博弈、规划。通过评估函数引导搜索,避免盲目探索。只深入探索有希望的分支,Token利用率更高。

搜索策略有几种选择。BFS广度优先,逐层探索,不会错过浅层解但内存消耗大。DFS深度优先,一条路走到底,内存效率高但可能陷入死胡同。Beam Search每层保留top-k状态,平衡效率和覆盖,但可能丢失最优解。A*用启发式函数引导,最优且高效,但需要好的启发函数。MCTS蒙特卡洛树搜索能处理大搜索空间,但需要大量模拟。

 deftot_bfs(
    question: str, 
    max_depth: int=4, 
    beam: int=3, 
    branch: int=4,
    external_evaluator=None
) ->dict:
    """
    使用BFS策略的思维树(Tree-of-Thoughts)方法。
    
    工作流程:
    1. 从空状态开始
    2. 对当前frontier中的每个状态,生成多个可能的下一步
    3. 评估所有新状态
    4. 保留得分最高的beam个状态作为新frontier
    5. 重复直到达到最大深度
    6. 从最佳状态生成最终答案
    
    参数:
        question: 需要解答的问题
        max_depth: 最大搜索深度
        beam: 每层保留的状态数(beam width)
        branch: 每个状态扩展的分支数
        external_evaluator: 外部评估函数(可选),
                           接受(question, state)返回分数
        
    返回:
        包含以下键的字典:
        - final_text: 最终答案
        - best_state: 最佳推理状态
        - best_score: 最佳状态的分数
        - search_tree: 搜索过程的记录(用于可视化)
    """
    
    defpropose_next_steps(state: str) ->list:
        """
        给定当前推理状态,生成多个可能的下一步。
        """
        prompt=f"""You are exploring different ways to solve a problem.

Question: {question}

Current reasoning state:
{stateifstateelse"(Starting from scratch)"}

Propose {branch} different possible next steps to continue the reasoning.
Each step should be a distinct approach or calculation.
Return as a numbered list:
1. [first possible step]
2. [second possible step]
...
"""
        raw=llm(prompt, temperature=0.9, max_tokens=400)
        
        # 解析编号列表
        steps= []
        forlineinraw.splitlines():
            line=line.strip()
            iflineandline[0].isdigit():
                # 移除编号前缀
                step=line.split(".", 1)[-1].strip()
                ifstep:
                    steps.append(step)
        
        returnsteps[:branch] ifstepselse [raw.strip()]
    
    defllm_score_state(state: str) ->float:
        """
        使用LLM评估一个推理状态的promising程度。
        
        注意:在实际应用中,使用外部评估器(如单元测试、规则检查)
        通常比LLM自我评估更可靠。
        """
        ifexternal_evaluator:
            returnexternal_evaluator(question, state)
        
        prompt=f"""Evaluate how promising this partial solution is.

Question: {question}

Current reasoning state:
{state}

Consider:
1. Is the reasoning logical and correct so far?
2. Is it making progress toward a solution?
3. Are there obvious errors or dead ends?

Rate from 0 to 10 (10 = very promising, likely to lead to correct answer).
Output only a number.
"""
        s=llm(prompt, temperature=0.0, max_tokens=10).strip()
        try:
            returnfloat(re.findall(r"\d+(\.\d+)?", s)[0])
        except:
            return5.0  # 默认中等分数
    
    # 初始化
    frontier= [""]  # 初始状态为空
    best_state=""
    best_score=-1.0
    search_tree= []  # 记录搜索过程
    
    fordepthinrange(max_depth):
        candidates= []
        depth_record= {"depth": depth, "states": []}
        
        forstateinfrontier:
            next_steps=propose_next_steps(state)
            
            forstepinnext_steps:
                # 构建新状态
                new_state= (state+"\n"+step).strip()
                
                # 评估新状态
                score=llm_score_state(new_state)
                candidates.append((score, new_state))
                
                depth_record["states"].append({
                    "state": new_state[:200] +"..."iflen(new_state) >200elsenew_state,
                    "score": score
                })
        
        search_tree.append(depth_record)
        
        # 排序并保留top-k
        candidates.sort(reverse=True, key=lambdax: x[0])
        frontier= [sfor_, sincandidates[:beam]]
        
        # 更新最佳状态
        ifcandidatesandcandidates[0][0] >best_score:
            best_score, best_state=candidates[0]
    
    # 从最佳状态生成最终答案
    final_prompt=f"""Based on the reasoning below, produce the final answer.

Question: {question}

Reasoning:
{best_state}

Provide a clear, concise final answer.
End with: FINAL: <your answer>
"""
    final=llm(final_prompt, temperature=0.2, max_tokens=400)
    
    return {
        "final_text": final,
        "final_answer": extract_final_answer(final),
        "best_state": best_state,
        "best_score": best_score,
        "search_tree": search_tree
    }

deftot_dfs(
    question: str,
    max_depth: int=5,
    branch: int=3,
    threshold: float=3.0
) ->dict:
    """
    使用DFS策略的思维树方法。
    
    通过深度优先搜索探索解决方案空间,
    当某个分支的分数低于阈值时进行剪枝。
    
    参数:
        question: 需要解答的问题
        max_depth: 最大搜索深度
        branch: 每个状态扩展的分支数
        threshold: 剪枝阈值,分数低于此值的分支被放弃
        
    返回:
        包含最终答案和搜索路径的字典
    """
    best_result= {"state": "", "score": -1.0}
    visited_count= [0]  # 使用列表以便在嵌套函数中修改
    
    defpropose_steps(state: str) ->list:
        prompt=f"""Propose {branch} next reasoning steps.

Question: {question}
Current state:
{stateifstateelse"(empty)"}

Return as numbered list."""
        raw=llm(prompt, temperature=0.9, max_tokens=300)
        steps= [l.split(".", 1)[-1].strip() 
                 forlinraw.splitlines() 
                 ifl.strip()[:1].isdigit()]
        returnsteps[:branch] ifstepselse [raw.strip()]
    
    defscore_state(state: str) ->float:
        prompt=f"""Rate this partial solution 0-10.
Question: {question}
State: {state}
Output only a number."""
        s=llm(prompt, temperature=0.0, max_tokens=10).strip()
        try:
            returnfloat(re.findall(r"\d+(\.\d+)?", s)[0])
        except:
            return5.0
    
    defdfs(state: str, depth: int):
        visited_count[0] +=1
        
        ifdepth>=max_depth:
            score=score_state(state)
            ifscore>best_result["score"]:
                best_result["state"] =state
                best_result["score"] =score
            return
        
        forstepinpropose_steps(state):
            new_state= (state+"\n"+step).strip()
            score=score_state(new_state)
            
            # 剪枝:跳过低分分支
            ifscore<threshold:
                continue
            
            ifscore>best_result["score"]:
                best_result["state"] =new_state
                best_result["score"] =score
            
            dfs(new_state, depth+1)
    
    dfs("", 0)
    
    # 生成最终答案
    final=llm(
        f"""Produce final answer based on:
Question: {question}
Reasoning: {best_result['state']}
End with FINAL: ...""",
        temperature=0.2
    )
    
    return {
        "final_text": final,
        "final_answer": extract_final_answer(final),
        "best_state": best_result["state"],
        "best_score": best_result["score"],
        "states_visited": visited_count[0]
    }

# 使用示例
if__name__=="__main__":
    question="使用数字1, 5, 6, 7(每个只能用一次),通过加减乘除得到24。"
    
    result=tot_bfs(question, max_depth=3, beam=2, branch=3)
    
    print("=== BFS Tree-of-Thoughts ===")
    print(f"最佳推理路径:\n{result['best_state']}")
    print(f"\n最佳分数: {result['best_score']}")
     print(f"\n最终答案: {result['final_answer']}")

ToT适合组合问题(24点游戏、数独)、规划任务、博弈问题(象棋、围棋)、头脑风暴这类需要探索不同方向的场景。答案空间极大时可能需要配合启发式剪枝。简单问题用不着——直接CoT就够了。

局限性:计算成本高昂,需要大量LLM调用来评估和扩展节点。LLM自评估不太可靠,评估函数质量直接决定效果。实现复杂度比其他几种方法高不少。还有些问题压根没有明显的树形结构,ToT就不太适用。

迭代(Iteration):反思与自我改进

Reflexion和Self-Refine用的是经典的「生成-评估-改进」循环:模型先产生初始答案,拿到反馈后修正答案,如此反复直到满意或达到最大轮数。

人类学习不也是这样吗?很少有事情一次就做对,总是通过反馈不断改进。

但有个重要的坑要注意:没有可靠外部反馈的「自我纠正」可能适得其反。

研究表明,模型仅靠自己判断来「自我纠正」时,可能把正确答案改成错误答案,可能对错误判断过度自信,可能在无效修改上浪费Token。

所以最佳实践是尽量用外部反馈源。代码执行(单元测试、错误信息)和规则检查(格式验证、约束检查)最可靠。工具调用(计算器、搜索引擎)和人类反馈也不错。另一个LLM做交叉验证勉强能用。同一个LLM自评效果最差,缺乏外部参照。

 defself_refine(
    question: str, 
    score_fn, 
    rounds: int=3,
    improvement_threshold: float=0.1
) ->dict:
    """
    使用自我改进(Self-Refine)方法迭代优化答案。
    
    核心流程:生成 -> 评估 -> 根据反馈改进 -> 重复
    
    参数:
        question: 需要解答的问题
        score_fn: 评估函数,签名为:
                  score_fn(answer_text) -> (score: float, feedback: str)
                  - score: 0.0-1.0之间的分数
                  - feedback: 具体的改进建议
                  强烈建议使用外部评估器!
        rounds: 最大改进轮数
        improvement_threshold: 最小改进阈值,低于此值则提前停止
        
    返回:
        包含以下键的字典:
        - final: 最终答案
        - final_score: 最终分数
        - history: 完整的改进历史
        - rounds_used: 实际使用的轮数
    """
    # 生成初始答案
    initial_prompt=f"""Provide a thoughtful answer to this question.
Show your reasoning and end with FINAL: ...

Question: {question}
"""
    answer=llm(initial_prompt, temperature=0.4)
    history= []
    prev_score=-float('inf')
    
    forround_numinrange(rounds):
        # 评估当前答案
        score, feedback=score_fn(answer)
        
        history.append({
            "round": round_num+1,
            "answer": answer,
            "score": score,
            "feedback": feedback
        })
        
        # 检查是否有足够的改进
        ifround_num>0and (score-prev_score) <improvement_threshold:
            # 如果改进不明显,考虑提前停止
            ifscore>=prev_score:
                pass  # 继续,至少没有退步
            else:
                # 退步了,恢复上一个答案
                answer=history[-2]["answer"]
                score=history[-2]["score"]
                break
        
        # 如果分数已经很高,提前停止
        ifscore>=0.95:
            break
        
        prev_score=score
        
        # 根据反馈改进答案
        refine_prompt=f"""Improve your answer based on the feedback below.

Question: {question}

Your current answer:
{answer}

Feedback (score: {score:.2f}/1.00):
{feedback}

Instructions:
1. Keep what is correct in your current answer
2. Fix the issues mentioned in the feedback
3. Make sure not to introduce new errors
4. End with FINAL: ...

Improved answer:
"""
        answer=llm(refine_prompt, temperature=0.3)
    
    # 最终评估
    final_score, final_feedback=score_fn(answer)
    
    return {
        "final": answer,
        "final_answer": extract_final_answer(answer),
        "final_score": final_score,
        "history": history,
        "rounds_used": len(history)
    }

# ---- 示例评估函数 ----

defmake_code_evaluator(test_cases: list):
    """
    创建一个代码评估函数。
    
    参数:
        test_cases: 测试用例列表,每个元素是(input, expected_output)
        
    返回:
        评估函数
    """
    defevaluator(code_answer: str) ->tuple:
        # 提取代码块
        code_match=re.search(r"```python\n(.*?)```", code_answer, re.DOTALL)
        ifnotcode_match:
            return0.0, "No Python code block found. Please wrap your code in ```python ... ```"
        
        code=code_match.group(1)
        
        passed=0
        failed_cases= []
        
        forinp, expectedintest_cases:
            try:
                # 危险:实际应用中应使用沙箱!
                local_vars= {}
                exec(code, {"__builtins__": {}}, local_vars)
                
                # 假设代码定义了solve函数
                if'solve'inlocal_vars:
                    result=local_vars['solve'](inp)
                    ifresult==expected:
                        passed+=1
                    else:
                        failed_cases.append(f"Input: {inp}, Expected: {expected}, Got: {result}")
                else:
                    return0.0, "No 'solve' function found in your code."
                    
            exceptExceptionase:
                failed_cases.append(f"Input: {inp}, Error: {str(e)}")
        
        score=passed/len(test_cases)
        
        iffailed_cases:
            feedback="Failed test cases:\n"+"\n".join(failed_cases[:3])  # 最多显示3个
            iflen(failed_cases) >3:
                feedback+=f"\n... and {len(failed_cases) -3} more failures"
        else:
            feedback="All test cases passed!"
        
        returnscore, feedback
    
    returnevaluator

defmake_math_evaluator(correct_answer):
    """
    创建一个数学答案评估函数。
    
    参数:
        correct_answer: 正确答案
        
    返回:
        评估函数
    """
    defevaluator(answer_text: str) ->tuple:
        extracted=extract_final_answer(answer_text)
        
        # 尝试数值比较
        try:
            extracted_num=float(re.findall(r"-?\d+\.?\d*", extracted)[0])
            correct_num=float(correct_answer)
            
            ifabs(extracted_num-correct_num) <0.01:
                return1.0, "Correct!"
            else:
                return0.0, f"Incorrect. Your answer: {extracted_num}, Expected: {correct_num}"
        except:
            pass
        
        # 字符串比较
        ifextracted.lower().strip() ==str(correct_answer).lower().strip():
            return1.0, "Correct!"
        else:
            return0.0, f"Incorrect. Your answer: {extracted}, Expected: {correct_answer}"
    
    returnevaluator

defmake_llm_evaluator(criteria: str):
    """
    创建一个基于LLM的评估函数(不推荐作为唯一评估源)。
    
    参数:
        criteria: 评估标准描述
        
    返回:
        评估函数
    """
    defevaluator(answer_text: str) ->tuple:
        prompt=f"""Evaluate this answer based on the following criteria:

Criteria: {criteria}

Answer to evaluate:
{answer_text}

Provide:
1. A score from 0.0 to 1.0
2. Specific feedback on what's wrong and how to improve

Format:
SCORE: [number]
FEEDBACK: [your feedback]
"""
        response=llm(prompt, temperature=0.0)
        
        try:
            score=float(re.search(r"SCORE:\s*([\d.]+)", response).group(1))
            score=min(1.0, max(0.0, score))
        except:
            score=0.5
        
        try:
            feedback=re.search(r"FEEDBACK:\s*(.+)", response, re.DOTALL).group(1).strip()
        except:
            feedback=response
        
        returnscore, feedback
    
    returnevaluator

# 使用示例
if__name__=="__main__":
    # 示例1:代码任务
    question="编写一个函数solve(n),返回n的阶乘。"
    test_cases= [
        (0, 1),
        (1, 1),
        (5, 120),
        (10, 3628800)
    ]
    
    result=self_refine(
        question=question,
        score_fn=make_code_evaluator(test_cases),
        rounds=3
    )
    
    print("=== Self-Refine for Code ===")
    print(f"最终分数: {result['final_score']:.2%}")
    print(f"使用轮数: {result['rounds_used']}")
    print(f"\n改进历史:")
    forhinresult['history']:
        print(f"  Round {h['round']}: score={h['score']:.2f}")
    
    # 示例2:数学任务
    question="计算 17 * 23 + 45 - 12"
    correct=17*23+45-12
    
    result=self_refine(
        question=question,
        score_fn=make_math_evaluator(correct),
        rounds=2
    )
    
    print("\n=== Self-Refine for Math ===")
    print(f"最终答案: {result['final_answer']}")
    print(f"正确答案: {correct}")
     print(f"最终分数: {result['final_score']:.2%}")

Self-Refine适合代码生成(有单元测试作为外部反馈)、格式化任务(有明确规范可检查)、约束满足问题(可验证约束是否满足)、事实核查(可通过检索验证)。主观任务需要人类反馈或多模型交叉验证。没有反馈来源时别用——纯LLM自评不靠谱。

局限性:反馈质量决定上限,垃圾反馈只会导致垃圾改进。模型有时候会在不同版本之间来回「改」,出现震荡。每轮迭代都消耗Token,成本会累积。也无法保证收敛——模型可能根本没法利用反馈真正改进。


技术对比与选择指南

四种技术各有特点。CoT思考更深,Token消耗低,LLM只调用一次,实现简单,不需要外部反馈,适合推理链问题。Self-Consistency采样更广,Token消耗中等,LLM调用N次,实现也简单,不需要外部反馈,适合有确定答案的问题。ToT探索更多,Token消耗高,LLM调用次数是分支数乘以深度,实现复杂,外部反馈可选但推荐,适合组合和规划问题。Self-Refine改进更好,Token消耗中等,LLM调用次数是轮数乘以2,实现复杂度中等,强烈推荐外部反馈,适合可迭代改进的问题。

选择思路如下,需要分步推理就先试CoT,不稳定的话加上Self-Consistency。有确定答案且需要可靠性,直接用Self-Consistency。组合或搜索问题用ToT。有外部反馈源就用Self-Refine。不确定用什么就先用CoT,看效果再定。

这些技术可以组合使用。CoT加SC是每次采样都用CoT然后多数投票。ToT加SC是ToT生成多个最终答案用SC选择。ToT加SR是用SR迭代改进ToT的最佳结果。复杂任务可能需要把多种技术串成流水线。

 defcombined_approach(question: str, score_fn) ->str:
    """
    组合使用多种推理时技术。
    
    流程:
    1. 用ToT探索解决方案空间
    2. 用Self-Consistency从多个ToT结果中选择
    3. 用Self-Refine迭代改进最终答案
    """
    # 第一阶段:ToT探索(运行3次)
    tot_results= []
    for_inrange(3):
        result=tot_bfs(question, max_depth=3, beam=2, branch=3)
        tot_results.append(result['final_answer'])
    
    # 第二阶段:Self-Consistency选择
    vote=Counter(tot_results).most_common(1)[0][0]
    
    # 第三阶段:Self-Refine改进
    final_result=self_refine(
        question=question,
        score_fn=score_fn,
        rounds=2
    )
    
     returnfinal_result['final_answer']

实践建议

别一上来就用最复杂的技术。推荐的顺序是:先直接提问作为baseline,然后加CoT提示,再加Self-Consistency,最后才考虑ToT或Self-Refine。

对于Self-Refine和ToT,评估器质量直接决定效果。花时间构建好的评估器比调参更重要。

推理时技术能大幅提升性能,但成本也会大幅增加。建议设置Token预算上限,记录每个任务的实际消耗,根据任务重要性调整投入。

部署到生产环境前做A/B测试,找到最佳的性能/成本权衡点。

总结

推理时计算技术代表了LLM能力释放的新范式。在推理阶段多投入一些计算,同一个模型不重新训练就能有明显提升。本文介绍的四种技术——CoT、Self-Consistency、Tree-of-Thoughts、Self-Refine——各有特点和适用场景。理解原理和局限性,选择合适的技术或组合,是LLM应用开发的关键技能。

随着这一领域的发展,会有更多创新的推理时技术出现。但核心原则不会变:给模型更多「思考」的空间,让它展示真正的推理能力。

https://avoid.overfit.cn/post/2bb5bb4e569a4687a272dc6e9fe6809a

就这么几个文字,给折叠了,聊天窗口无法复制,并且双击放大后仍然无法选中,无法复制!网友说收藏之后可以复制。我测试单独转发这条消息之后可以复制,多条消息合并转发之后显示“[文字]”,笑到无语。

今天上午还好好的,下午就这样了,求求 zxl 做个人吧

微信千问口令缩的更小并且禁用了复制.jpg

1.前言

本文旨在提供 征程 6B 计算平台的部署指南,将会从硬件、软件两部分进行介绍,本文整理了我们推荐的使用流程,和大家可能会用到的一些工具特性,以便于您更好地理解工具链。某个工具具体详细的使用说明,还请参考用户手册。

2.征程 6B 硬件配置

image.png

image.png

BPU 内部器件:

TAE:BPU 内部的张量加速引擎,主要用于 Conv、MatMul、Linear 等 Gemm 类算子加速,征程 6B 新增浮点输出支持(模型中间层支持 ​fp16​ 输出,模型输出层支持 fp32 输出)

AAE:Pooling、Resizer、Warping 等偏专用单元的集合,其中 Warping 可用于加速 Gridsample 等算子

DTE:BPU 内部的数据排布变换引擎,支持各种维度的高效变换

VAE:BPU 内部的 SIMD 向量加速引擎,可用于加速 Add、Mul、查表等 Vector 计算,征程 6B 新增浮点支持

VPU:BPU 内部的 SIMT 向量加速单元,征程 6EM 可用于实现 Quantize、Dequantize 等算子,征程 6B 没有该硬件

SPU:BPU 内部的 RISC-V 标量加速单元,征程 6EM 可用于实现 TopK 等算子,征程 6B 没有该硬件,仅有 APM

APM:BPU 内部另一块 RISC-V 标量加速单元,主要用于 BPU 任务调度等功能

3.征程 6 工具链简介

3.1 模块架构图

image.png

PTQ:征程 6 工具链基于 horizon_tc_ui 包封装的 hb_compile 命令行工具,提供 ONNX 模型 PTQ 全流程转换能力,其内部会先调用 hmct 包实现模型解析、图优化、校准功能,再调用 hbdk4_compiler 包实现模型的定点化和编译功能;

QAT:征程 6 工具链基于 horizon_plugin_pytorch 包提供量化感知训练能力;

HBDK:征程 6 工具链编译器,基于 hbdk4_compiler 包提供模型定点化、图修改、模型编译、静态 perf 等功能;

高效模型算法包:征程 6 工具链基于 horizon-torch-samples 包,以源码开放形式提供了多场景参考算法,这些模型基于开源数据集训练,模型结构贴合地平线芯片进行了高效且用户友好的设计,并基于 QAT 链路实现了模型的量化转换;

UCP:征程 6 工具链统一计算平台,通过一套统一的异构编程接口实现了对 征程 6 计算平台相关计算资源的调用,提供视觉处理、模型推理、高性能计算库、自定义算子插件开发等功能;

AI-Benchmark:征程 6 工具链基于预编译好模型提供的嵌入式工程示例,可实现模型的性能评测和精度评测。

3.2 两套模型转换链路

image.png

征程 6 工具链支持 PTQ(训练后量化)、QAT(量化感知训练)两套模型转换链路,其特性和优缺点如下:

PTQ:基于 hb_compile 命令行工具转换模型,配置好 yaml、校准数据集后,可一步实现模型的图优化、校准、量化、编译全流程。​该量化方式快捷易用,但仅基于数学统计方式的离线量化不利于模型迭代,且可能会触发难以解决的 corner case​,因此在量产项目中通常用于早期评测和简单模型的量化。

QAT:在 PyTorch 开源框架上,基于 plugin 插件的形式提供模型量化能力,并调用 hbdk 编译器的 API 实现模型的定点化和编译。该链路支持模型校准后进一步的 finetune 训练,虽然上手难度和训练成本都较高,​但精度上限也更高,更利于模型迭代优化​,是量产项目中的更优选择。

3.3 工具链推荐使用流程

鉴于两条量化链路的特性,我们建议的工具链使用流程如下:
image.png

Step1:先导出浮点 ONNX 模型(opset10~19),并基于 PTQ 链路进行快速的模型结构验证,全 int8 性能上限验证;若该性能符合预期,则可以精调 PTQ,若最终精度/精度都可同时满足预期,则可进行板端部署。

Step2:如果遇到 PTQ 无法解决的精度 corner case,则需要转到 QAT 链路进行量化。依然建议先进行模型结构验证和全 int8 性能上限验证;若该性能符合预期,则优先在全 int16 配置下将精度训练至符合预期,然后再降低 int16 比例,实现 int8/int16/fp16 混合精度下的性能/精度调优,最后进行板端部署。

在以上推荐链路中:

PTQ 链路的模型结构验证和标准量化,可在 X86 端参考本文 4.2 节使用 hb_compile 命令行工具;

模型性能分析和验证,可在 X86 端参考本文 6.4 节《静态 perf》使用 hbm_perf 接口生成 html 分析文件,可在板端参考本文 8.2.1 节使用 hrt_model_exec 工具;

模型推理,可在 X86 端参考用户手册《<u>训练后量化-PTQ 转换工具-HBRuntime 推理库</u>》,可在板端参考本文第 8 章《模型板端部署》使用 UCP 推理接口;

模型性能/精度调优,请见后续文章的详细介绍。

4.PTQ 链路

4.1 模型转换流程

image.png

4.2 hb\_compile 工具

hb_compile 为 PTQ 模型转换的命令行工具,支持以下 3 种使用方式:

image.png

4.3 PTQ 模型产出物

original\_float.onnx浮点对 Caffe1.0 模型进行解析,转成 ONNX
optimized\_float.onnx浮点图优化,例如 BN 融合到 Conv
calibrated.onnx伪量化插入校准节点,并基于校准数据计算统计到每个节点的量化参数
ptq.onnx查表算子定点 + 其他算子伪量化将查表算子定点化
quantized.bc定点整个模型定点化,并转换为地平线 hbir 中间表达
hbm指令集经过编译后的最终部署模型

4.4 PTQ 精度配置方法

在 config.yaml 中,支持通过 json 的方式配置 ​全局​、​某类算子​、​某个子图​、某个节点 ​的计算精度,可根据 BPU 算子支持约束进行配置。

# 校准参数组
calibration_parameters:
  quant_config: './quant_config.json'

4.5 PTQ 精度调优流程

请参考用户手册《<u>训练后量化-PTQ 转换步骤-模型精度调优</u>》和《训练后量化-PTQ 转换步骤-精度调优实战》章节。

5.QAT 链路

5.1 模型转换流程

image.png

浮点模型改造​:在模型前插入 QuantStub、在模型后插入 DequantStub,用于识别模型首尾部,剥离前后处理

模型校准:通过在模型中插入 Observer 的方式,在 forward 过程中统计各处的数据分布,以计算出量化参数

部分模型仅通过 Calibration 便可满足精度要求,则无需进行 QAT,可直接编译模型用于部署

即使 Calibration 无法满足精度要求,也可降低后续 QAT 难度,缩短训练时间,提升最终训练精度

量化感知训练:进一步通过训练的方式微调模型参数,如果 Calibration 精度较好,则推荐固定激活 scale

JIT-STRIP:使用 hook 和 subclass tensor 的方式感知图结构,在原有 forward 上做算子替换/算子融合等操作,并且会根据模型中 QuantStub 和 DequantStub 的位置识别并跳过前后处理

优点:全自动,代码修改少,屏蔽了很多细节问题,便于 debug

缺点:动态代码块仍需要特殊处理

5.2 QAT 精度配置方法

请见:<u>【地平线 J6 工具链入门教程】QAT 新版 qconfig 量化模板使用教程</u>。

5.3 QAT 精度调优流程

整体调优流程:

征程 6B 区别于征程 6E/M 来说浮点算子(fp16)的支持能力更多,但是由于没有 vpu,因此不高优推荐 fp16 调优,仍建议沿用。
image.png

fp16 配置方式:

QAT 新版 qconfig 量化模板使用教程见:https://developer.horizon.auto/blog/13112

my_qconfig_setter=QconfigSetter(
    reference_qconfig=get_qconfig(observer=MSEObserver),
    templates=[
        ModuleNameTemplate({ "":qint16,}),
        ModuleNameTemplate({"quant":torch.float16}),
        ...        
        ],
        save_dir="./work_dir",
    )

需要注意,由于征程 6B 没有 vpu,fp16 算子的使用可能会引入 cpu 的 quant、dequant 算子。建议尽量少的配 FP 16,避免性能损失。

6.模型导出/定点化/编译

6.1 PTQ 链路

该流程封装在 hb_compile 中,相关参数通过 yaml 进行配置。若自行调用编译器接口执行,参考代码如下:

import onnx
from hbdk4.compiler.onnx import export
from hbdk4.compiler import convert, save, compile

# 经过PTQ校准得到的伪量化onnx模型,非线性的查表算子已定点
ptq_model = onnx.load("xxx_ptq_model.onnx")    

# 导出查表算子定点+其他算子伪量化的hbir模型
qat_bc = export(ptq_model)
save(qat_bc, "qat.bc")

# 导出全定点hbir模型
quantized_bc = convert(qat_bc, "nash-b")
save(quantized_bc, "quantized.bc")

# 编译生成hbm模型
compile(
    m=quantized_bc, 
    path="model.hbm", 
    opt=2, 
    march="nash-b", 
    progress_bar=True,
    input_no_padding=True,
    output_no_padding=True
)

6.1.1 输入/输出去 padding

模型在 BPU 上推理时,其输入和输出节点的内存大小和数据存放规则需满足硬件对齐要求。

内存对齐:申请的内存大小需满足某个字节数的整数倍,

跨距对齐:跨距(Stride)是指数据存储在内存中时,每一行所占空间的实际大小,当对齐到某个字节数的整数倍后,硬件即可高效处理。该对齐的操作又叫 Padding,实际的对齐规则取决于具体的软硬件系统。假设一份 NHWC 为 1x20x30x1 的 int8 数据,若硬件要求跨距 W32 对齐,那么每一行 W 都将 Padding 2 个字节。

征程 6 工具链支持在 compile 接口中传入 input_no_paddingoutput_no_padding 参数来控制是否使用 BPU 自动完成 padding 对齐操作。开启后用户即可不关心 BPU 跨距对齐要求,无需手动 Padding,数据可连续存储在内存中。该特性可优化模型输入/输出的 IO 负载,但也有微小概率会引入性能的小幅下降,所以是否开启该功能请在您的模型上实际验证,并请在模型编译和板端部署环节统一跨距对齐的处理策略。

6.2 QAT 链路

QAT 链路的模型定点化和编译直接调用如上的编译器接口,模型导出额外封装了一层,参考代码如下:

from horizon_plugin_pytorch.quantization.hbdk4 import export

def export(
    model: nn.Module,
    example_inputs: Any,
    name: str = "forward",
    input_names: Optional[Any] = None,    # 建议在模型导出时就配置好输入输出节点名称
    output_names: Optional[Any] = None,
    input_descs: Optional[Any] = None,
    output_descs: Optional[Any] = None,
    native_pytree: bool = True,
) -> Module

6.3 模型修改

编译器支持在 hbir 上进行多 batch 拆分、插入数据前处理、算子删除、调整输入输出 layout 等修改操作,其主要应用场景如下:

多 batch 拆分:典型场景是 BEV 模型在部署时,多 V 输入来源于不同的摄像头,其数据在内存中独立存储,因此模型可将其多 V 输入沿 batch 维度做拆分;

数据前处理:征程 6 工具链支持在模型前端插入一个前处理节点,以实现颜色空间转换(如 NV12—> BGR)、数据归一化((data-mean)/std),和 Resizer 功能(从大图上抠图 + Resize),并可由 BPU 进行加速;

算子删除:征程 6 工具链支持将模型首尾部的 Quantize、Dequantize、Cast、Reshape、Transpose 等算子删除,以适配更加灵活的部署方案;

调整输入输出 layout:模型首尾部除了支持删除 Reshape、Transpose 节点外,还支持插入 Transpose 节点,用户可灵活调整其 layout 排布。

以下参考代码对一个多输入模型实现了多 batch 输入拆分、图像输入的色彩空间转换、数据归一化、Resizer 功能:

from hbdk4.compiler import load, convert

qat_bc = load("qat.bc")  
func = qat_bc[0]
batch_input = ["input_name1"]   # 需要使用独立地址方式部署的输入节点名称列表
resizer_input = ["resize"]      # 部署时数据来源于resizer的输入节点名称列表
pyramid_input = ["pym"]         # 部署时数据来源于pyramid的输入节点名称列表

def channge_source(input, source):
    node = input.insert_transpose(permutes=[0, 3, 1, 2])
    node = node.insert_image_preprocess(mode="yuvbt601full2bgr", divisor=1, mean=[128, 128, 128], std=[128, 128, 128])
    if source == "pyramid":
        node.insert_image_convert("nv12")          
    elif source == "resizer":
        node.insert_roi_resize("nv12")

for input in func.inputs[::-1]:
    if input.name in batch_input:
        origin_name = input.name
        split_inputs = input.insert_split(dim=0)
        for split_input in reversed(split_inputs):
            if origin_name in pyramid_input:
                channge_source(split_input, "pyramid")
            elif origin_name in resizer_input:
                channge_source(split_input, "resizer")

6.4 静态 perf

对于编译好的 hbm,编译器支持在 X86 端对其 BPU 部分进行静态性能预估,执行以下命令即可生成一个 html 文件,包含模型预估性能、带宽、内存占用、BPU 内部单帧执行时序图等信息。

from hbdk4.compiler import hbm_perf
hbm_perf(model="xxx.hbm", output_dir="./")

7.浮点能力使用

7.1 TAE 张量输出,VAE 向量计算支持浮点

征程 6B BPU 的 TAE 张量计算单元支持 FP16/FP32 输出,VAE 向量计算单元支持 FP16 计算。但在实际部署中仍需综合评估后再使用,具体原因如下:

精度:FP16 并非在所有情况下都优于 INT16,通常情况下数值范围小时 FP16 更优,数值范围大时 INT16 更优,但也需要考虑数值较小或较大部分的误差对模型输出的影响程度。所以量化精度是否使用 FP16,更建议基于精度 Debug 的分析结果来确定;

性能:除 Reduce 性能为 INT16 的 1/2 外,其他算子的 FP16 性能和 INT16 性能持平

额外开销:虽然 FP16 算子本身无需量化,但上下游算子如果涉及 FP16 <—> INT16 的数据转换,则会引入量化/反量化:

虽然该节点可以由 VAE 硬件直接支持,但相比于全 INT16 直接串接仍会有额外的性能、带宽开销;

新引入的量化或反量化节点的 Scale 需要重新校准/QAT 训练得到。

7.2 无 VPU 加速量化/反量化

相比于 征程 6EM 计算平台,征程 6B 无 VPU 硬件加速模型首尾部的量化/反量化节点,但支持 Gemm 类算子直接 FP32 输出,其他 INT8/INT16 输出节点的反量化,则更建议使用编译器接口将其从 quantized.bc 上移除,并参考该篇文章(<u>反量化节点的融合实现</u>)将其融合进前后处理代码中,以减少一次数据遍历的冗余开销。

from hbdk4.compiler import load

quantized_bc = load("quantized.bc")
quantized_bc[0].remove_io_op(op_types=["Quantize", "Dequantize"])

7.3 无 SPU,标量计算能力有限

相比于 征程 6 其他计算平台,征程 6B 的标量计算单元算力减少,因此 TopK 等标量算子的部署性能需要综合评估后选择合适方案。

8.模型板端部署

8.1 UCP 简介

UCP(Unify Compute Platform,统一计算平台)定义了一套统一的异构编程接口, 将 SOC 上的功能硬件抽象出来并进行封装,对外提供基于功能的 API 进行调用。UCP 提供的具体功能包括:​视觉处理​(Vision Process)、​神经网络模型推理​(Neural Network)、​高性能计算库​(High Performance Library)、​自定义算子插件开发​。

image.png

UCP 支持的 Backend 如下:
image.png

8.2 快速上手

使用 UCP 推理模型的基本代码参考如下,详细信息可参考用户手册《<u>统一计算平台-模型推理开发</u>》、《<u>模型部署实践指导-模型部署实践指导实例</u>》、《<u>UCP 通用 API 介绍</u>》等相关章节。

// 1. 加载模型并获取模型名称列表以及Handle
{
    hbDNNInitializeFromFiles(&packed_dnn_handle, &modelFileName, 1);
    hbDNNGetModelNameList(&model_name_list, &model_count, packed_dnn_handle);
    hbDNNGetModelHandle(&dnn_handle, packed_dnn_handle, model_name_list[0]);
}

// 2. 根据模型的输入输出信息准备张量
std::vector<hbDNNTensor> input_tensors;
std::vector<hbDNNTensor> output_tensors;
int input_count = 0;
int output_count = 0;
{
    hbDNNGetInputCount(&input_count, dnn_handle);
    hbDNNGetOutputCount(&output_count, dnn_handle);
    input_tensors.resize(input_count);
    output_tensors.resize(output_count);
    prepare_tensor(input_tensors.data(), output_tensors.data(), dnn_handle);
}

// 3. 准备输入数据并填入对应的张量中
{
    read_data_2_tensor(input_data, input_tensors);
    // 确保更新输入后进行Flush操作以确保BPU使用正确的数据
    for (int i = 0; i < input_count; i++) {
      hbUCPMemFlush(&input_tensors[i].sysMem, HB_SYS_MEM_CACHE_CLEAN);
    }
}

// 4. 创建任务并进行推理
{
    // 创建任务
    hbDNNInferV2(&task_handle, output_tensors.data(), input_tensors.data(), dnn_handle)
    
    // 提交任务
    hbUCPSchedParam sched_param;
    HB_UCP_INITIALIZE_SCHED_PARAM(&sched_param);
    sched_param.backend = HB_UCP_BPU_CORE_ANY;
    hbUCPSubmitTask(task_handle, &sched_param);
    
    // 等待任务完成
    hbUCPWaitTaskDone(task_handle, 0);
}

// 5. 处理输出数据
{
    // 确保处理输出前进行Flush操作以确保读取的不是缓存中的脏数据
    for (int i = 0; i < output_count; i++) {
      hbUCPMemFlush(&output_tensors[i].sysMem, HB_SYS_MEM_CACHE_INVALIDATE);
    }
    // 对输出进行后处理操作
}

// 6. 释放资源
{
    // 释放任务
    hbUCPReleaseTask(task_handle);
    // 释放输入内存
    for (int i = 0; i < input_count; i++) {
      hbUCPFree(&(input_tensors[i].sysMem));
    }
    // 释放输出内存
    for (int i = 0; i < output_count; i++) {
      hbUCPFree(&(output_tensors[i].sysMem));
    }
    // 释放模型
    hbDNNRelease(packed_dnn_handle);
}

8.2.1 hrt\_model\_exec 工具

为了方便用户快速查看 hbm 和 quantized.bc 的模型信息、进行模型单帧推理和性能评测,征程 6 工具链 UCP 提供了 hrt_model_exec 工具,并支持编译 X86、aarch64(aarch64 仅支持 hbm 推理)两个架构下的可执行程序。

hrt\_model\_exec 的三种使用方法如下:

# 设置环境变量
# arch代表架构类型,aarch64或x86
arch=aarch64
bin=../$arch/bin/hrt_model_exec
lib=../$arch/lib/
export LD_LIBRARY_PATH=${lib}:${LD_LIBRARY_PATH}

# 获取模型信息
${bin} model_info --model_file=xxx.hbm

# 模型单帧推理
${bin} infer --model_file=xxx.hbm --input_file=xxx.bin

# 模型性能评测-Latency(单线程)
${bin} perf --model_file=xxx.hbm --thread_num 1 --frame_count=1000

# 模型性能评测-FPS(多线程)
${bin} perf --model_file=xxx.hbm --thread_num 8 --frame_count=1000

8.3 图像输入动态 shape/stride

在 征程 6 芯片的视频通路上,有一块叫 Pyramid 的金字塔硬件处理模块,可提供 Camera 输入图像的缩放及 ROI 抠图能力,其输出为 nv12 类型的图像数据,并可基于共享内存机制直接给到 BPU 进行模型推理。因此在 征程 6 工具链中:

  1. Pyramid 模型指的是具有 nv12 图像输入的模型;
  2. Resizer 模型指的是具有 nv12 图像输入和 ROI 输入的模型,编译器支持通过 JIT 动态指令的方式,从 nv12 图像上完成 ROI 抠图 + Resize 的功能。

在 征程 6 工具链中,Pyramid 的输入 stride 为动态,Resizer 模型的 stride 和 shape 都是动态。如下为 mobilenetv1 编译后的模型信息:
image.png
hrt_model_exec model_info 板端可执行程序工具

image.png

其中,-1 为占位符,表示为动态,Pyramid 输入的 stride 为动态;Resizer 输入的 H、W、stride 均为动态。

8.4 非图像 tensor 内存对齐

对于非图像 tensor,征程 6B 要求 128 对齐,征程 6EM 要求内存 64 对齐,征程 6PH 要求 256 对齐。如上图所示,模型输出节点虽然 stride[0] 为 4000,但需要申请的 BPU 内存大小(aligned byte size)为 4096,即为 128 对齐的结果。

在模型实际部署中,非图像输入/输出节点所需申请的内存大小( aligned byte size)均可从模型节点属性的结构体中读取到(hbDNNTensorProperties),因此无需特别关注。

8.5 图像 tensor 跨距对齐

征程 6EMB 对于 Pyramid/Resizer 模型的图像输入,要求 W32 对齐,征程 6PH 要求 W64 对齐。若您有 征程 6 不同架构平台迁移的场景,请注意跨距对齐要求的差异。

部署代码建议您避免 hard code,推荐基于模型节点属性中的 validShape(张量有效内容尺寸)和 stride(张量各维度步长)进行解析和使用。

8.5.1 Pyramid 输入

Pyramid 输入 tensor 准备的参考代码如下:

hbDNNTensor *input = input_tensor;
for (int i = 0; i < input_count; i++) {
HB_CHECK_SUCCESS(
    hbDNNGetInputTensorProperties(&input[i].properties, dnn_handle, i),
    "hbDNNGetInputTensorProperties failed");
    
    auto dim_len = input[i].properties.validShape.numDimensions;    // 获取维度信息
    for (int32_t dim_i = dim_len - 1; dim_i >= 0; --dim_i) {
      if (input[i].properties.stride[dim_i] == -1) {                // stride=-1即为动态
        auto cur_stride =                                           // 计算当前维度stride
            input[i].properties.stride[dim_i + 1] *
            input[i].properties.validShape.dimensionSize[dim_i + 1];
        input[i].properties.stride[dim_i] = ALIGN_32(cur_stride);   // 32对齐
      }
    }

    int input_memSize = input[i].properties.stride[0] *             // 计算内存大小
                        input[i].properties.validShape.dimensionSize[0];
    HB_CHECK_SUCCESS(hbUCPMallocCached(&input[i].sysMem[0], input_memSize, 0),
                     "hbUCPMallocCached failed");
    
    const char *input_name;
    HB_CHECK_SUCCESS(hbDNNGetInputName(&input_name, dnn_handle, i),    // 获取节点名称
                     "hbDNNGetInputName failed");
}

示例:

ucp_tutorial/dnn/basic_samples/code/00_quick_start/resnet_nv12/src/main.cc

注意​:

视频通路上的金字塔硬件,其输出层支持配置 y、uv 的 stride,但仅要求 W16 对齐,若数据需要喂给 BPU 推理模型,建议直接按 BPU 的跨距对齐要求来配置。金字塔硬件的更多信息请参考系统软件用户手册。

8.5.2 Resizer 输入

Resizer 输入的 H、W 也是动态的,因此需要设置为原图尺寸,并计算好 W32 对齐的 Stride;ROI 作为模型输入节点,也需要对其进行赋值。以下为参考代码:

#define ALIGN(value, alignment) (((value) + ((alignment)-1)) & ~((alignment)-1))
#define ALIGN_32(value) ALIGN(value, 32)

int prepare_image_tensor(const std::vector<hbUCPSysMem> &image_mem, int input_h,
                         int input_w, hbDNNHandle_t dnn_handle,
                         std::vector<hbDNNTensor> &input_tensor) {
  // 准备Y、UV输入tensor
  for (int i = 0; i < 2; i++) {
    HB_CHECK_SUCCESS(hbDNNGetInputTensorProperties(&input_tensor[i].properties,
                                                   dnn_handle, i),
                     "hbDNNGetInputTensorProperties failed");
    // auto w_stride = ALIGN_32(input_w);
    // int32_t y_mem_size = input_h * w_stride;
    input_tensor[i].sysMem[0] = image_mem[i];

    // 配置原图大小,NHWC
    input_tensor[i].properties.validShape.dimensionSize[1] = input_h;
    input_tensor[i].properties.validShape.dimensionSize[2] = input_w;
    if (i == 1) {
      // UV输入大小为Y的1/2
      input_tensor[i].properties.validShape.dimensionSize[1] /= 2;
      input_tensor[i].properties.validShape.dimensionSize[2] /= 2;
    }

    // stride满足32对齐
    input_tensor[i].properties.stride[1] =
        ALIGN_32(input_tensor[i].properties.stride[2] *
                 input_tensor[i].properties.validShape.dimensionSize[2]);
    input_tensor[i].properties.stride[0] =
        input_tensor[i].properties.stride[1] *
        input_tensor[i].properties.validShape.dimensionSize[1];
  }
  return 0;
}

// 准备roi输入tensor
int prepare_roi_tensor(const hbUCPSysMem *roi_mem, hbDNNHandle_t dnn_handle,
                       int32_t roi_tensor_id, hbDNNTensor *roi_tensor) {
  HB_CHECK_SUCCESS(hbDNNGetInputTensorProperties(&roi_tensor->properties,
                                                 dnn_handle, roi_tensor_id),
                   "hbDNNGetInputTensorProperties failed");
  roi_tensor->sysMem[0] = *roi_mem;
  return 0;
}

int prepare_roi_mem(const std::vector<hbDNNRoi> &rois,
                    std::vector<hbUCPSysMem> &roi_mem) {
  auto roi_size = rois.size();
  roi_mem.resize(roi_size);
  for (auto i = 0; i < roi_size; ++i) {
    int32_t mem_size = 4 * sizeof(int32_t);
    HB_CHECK_SUCCESS(hbUCPMallocCached(&roi_mem[i], mem_size, 0),
                     "hbUCPMallocCached failed");
    int32_t *roi_data = reinterpret_cast<int32_t *>(roi_mem[i].virAddr);
    roi_data[0] = rois[i].left;
    roi_data[1] = rois[i].top;
    roi_data[2] = rois[i].right;
    roi_data[3] = rois[i].bottom;
    hbUCPMemFlush(&roi_mem[i], HB_SYS_MEM_CACHE_CLEAN);
  }
  return 0;
}

示例:

ucp_tutorial/dnn/basic_samples/code/02_advanced_samples/roi_infer/src/roi_infer.cc

8.6 小模型批量处理功能

由于 BPU 是资源独占式硬件,所以对于 Latency 很小的模型而言,其框架调度开销占比会相对较大。在 征程 6 平台,UCP 支持通过复用 task\_handle 的方式,将多个小模型任务一次性下发,全部执行完成后再一次性返回,从而可将 N 次框架调度开销合并为 1 次,以下为参考代码:

// 获取模型指针并存储
std::vector<hbDNNHandle_t> model_handles;

// 准备各个模型的输入输出,准备过程省略
std::vector<std::vector<hbDNNTensor>> inputs;
std::vector<std::vector<hbDNNTensor>> outputs;

// 创建任务并进行推理
{
    // 创建并添加任务,复用task_handle
    hbUCPTaskHandle_t task_handle{nullptr};
    for(size_t task_id{0U}; task_id < inputs.size(); task_id++){
        hbDNNInferV2(&task_handle, outputs[task_id].data(), inputs[task_id].data(), model_handles[i]);
    }
    
    // 提交任务
    hbUCPSchedParam sche_param;
    HB_UCP_INITIALIZE_SCHED_PARAM(&sche_param);
    sche_param.backend = HB_UCP_BPU_CORE_ANY;
    hbUCPSubmitTask(task_handle, &sche_param);
    
    // 等待任务完成
    hbUCPWaitTaskDone(task_handle, 0);
}

8.7 优先级调度/抢占

UCP 支持任务优先级调度和抢占,可通过 hbUCPSchedParam 结构体进行配置,其中:

  • priority > customId > submit\_time(任务提交时间)
  • priority 支持 [0, 255],对于模型任务而言:

[0, 253] 为普通优先级,不可抢占其他任务,但在未执行时支持按优先级进行排队

254 为 high 抢占任务,可支持抢占普通任务

255 为 urgent 抢占任务,可抢占普通任务和 high 抢占任务

可被中断抢占的低优任务,需要在模型编译阶段配置 max_time_per_fc 参数拆分模型指令

  • 其他 backend 任务,priority 支持 [0, 255],但不支持抢占,可以认为都是普通优先级

8.8 X86 仿真

征程 6 工具链在 X86 端支持 hbm 指令仿真,但效率非常低,所以更推荐使用 quantized.bc 模型进行推理,其定点部分和 hbm 数值二进制一致,浮点部分可能存在架构本身差异,但通常对精度影响可忽略不计。

征程 6B 平台 X86 仿真需要配置如下环境变量,默认架构为"nash-m":

export HB\_UCP\_SIM\_PLATFORM\_TYPE=nash-b

8.8.1 推理 quantized.bc

Python 推理:

quantized.bc 在 X86 端的推理,可以使用 horizon_tc_ui 包封装的 HBRuntime 接口,具体可见用户手册《<u>训练后量化-PTQ 转换工具-HBRuntime 推理库</u>》,参考代码如下:

import numpy as np
from horizon_tc_ui.hb_runtime import HBRuntime

sess = HBRuntime("quantized.bc")
input_names = sess.input_names
output_names = sess.output_names

data1 = np.load("input1.npy")
data2 = np.load("input2.npy")
input_feed = {input_names[0]: data1, input_names[1]: data2}

output = sess.run(output_names, input_feed)

quantized.bc 也可以直接调用其 func 的 feed 接口进行推理,其输入格式也为 dict,value 支持 torch.tensor 和 np.array 两种类型,输出格式与输入格式保持一致。参考代码如下:

import numpy as np
from hbdk4.compiler import load

hbir = load("quantized.bc")
func = hbir[0]

data1 = np.load("input1.npy")
data2 = np.load("input2.npy") 
input_feed = {inputs[0].name: data1, inputs[1].name: data2}
hbir_outputs = func.feed(input_feed)

C++ 推理:

quantized.bc 的 C++ 推理接口复用 hbm UCP 推理接口,仅 so 动态库需要替换成 X86 版本即可。 您也可以在 X86 端使用 hrt_model_exec 工具对 quantized.bc 进行模型信息查看和单帧推理。

8.8.2 推理 hbm

由于 X86 端 hbm 推理为指令仿真,运行速度非常慢,因此工具链提供了 hbm_infer 工具以便用户在服务器端给直连的开发板下发推理任务。本文只介绍最简单的单进程使用方式,多进程、多阶段模型输入输出的传输优化,以及统计模型推理、网络传输耗时等功能请参考用户手册《<u>hbm\_infer 工具介绍</u>》。

# hbm也可传入一个list,推理时通过指定model_name来选择推理哪个模型,推理所用的.so即可只传输一次
hbm_model = HbmRpcSession(
    host="xx.xx.xx.xx",
    local_hbm_path="xx.hbm", 
)

# 打印模型输入输出信息
hbm_model.show_input_output_info()

# 准备输入数据
input_data = {
    'img': torch.ones((1, 3, 224, 224), dtype=torch.int8)
}

# 执行推理并返回结果
# 若传入的是list,需要正确指定model_name
# output_data = hbm_model(input_data, model_name=model_name)
output_data = hbm_model(input_data) 

print([output_data[k].shape for k in output_data])

# 关闭server
hbm_model.close_server()

9.UCP 视觉处理/高性能算子

除模型推理外,UCP 还提供了视觉处理和高性能算子两大方向的多种算子接口,可支持诸如 Remap、Jpeg、H264/265、FFT/IFF 等功能,这些算子底层是基于地平线 SOC 上不同硬件 IP 进行的封装,并提供统一的调用接口。

更多信息可参考用户手册《<u>统一计算平台</u>》的相关章节。

注意:

  1. 板端实际部署时,ISP 到 Pyramid 的视频通路不建议使用 UCP,无法实现数据 Online,建议直接调用底软接口进行功能实现。
  2. 基于 DSP Backend 实现的 HPL 算子,在 征程 6B 平台仅会提供 征程 6EM 上 Q8 实现的源码,如需在 征程 6B 上使用 HPL 算子,需要您自行适配 V130 并编译镜像。VP 算子和 SLAM 等 征程 6EM 上已有的 Q8 DSP sample,将在 征程 6B 后续正式版本中提供 V130 版本。

10.UCP 自定义算子(DSP)

为了简化用户开发,UCP 封装了一套基于 RPC 的开发框架,来实现 CPU 对 DSP 的功能调用,但具体 DSP 算子实现仍是调用 Cadence 接口去做开发。总体来说可分为三个步骤:

使用 Cadence 提供的工具及资料完成算子开发;

int test_custom_op(void *input, void *output, void *tm) {
  // custom impl
  return 0;
}

DSP 侧通过 UCP 提供的 API 注册算子,编译带自定义算子的镜像;

// dsp镜像中注册自定义算子
hb_dsp_register_fn(cmd, test_custom_op, latency)

ARM 侧通过 UCP 提供的算子调用接口,完成开发板上的部署使用。

// 将输入输出的hbUCPSysMem映射为DSP可访问的内存地址
hbUCPSysMem in;
hbUCPMalloc(&in, in_size, 0)
hbDSPAddrMap(&in, &in)

hbUCPSysMem out;
hbUCPMalloc(&out, out_size, 0)
hbDSPAddrMap(&out, &out)

// 创建并提交DSP任务
hbUCPTaskHandle_t taskHandle{nullptr};
hbDSPRpcV2(&taskHandle, &in, &out, cmd)

hbUCPSchedParam ctrl_param;
HB_UCP_INITIALIZE_SCHED_PARAM(&ctrl_param);
ctrl_param.backend = HB_UCP_DSP_CORE_ANY;
hbUCPSubmitTask(task_handle, &ctrl_param);

// 等待任务完成
hbUCPWaitTaskDone(task_handle, 0);

更多信息可见用户手册《<u>统一计算平台-自定义算子-DSP 算子开发</u>》。

11.性能监测工具

征程 6 平台 BPU、DSP 都是独占的硬件资源,任务一旦提交就会独占推理,UCP 侧仅能通过 hrt_ucp_monitor 工具去监测其硬件占用率(采样频率支持配置 [10, 1000],默认 500),并且能查看到 DDR 内存占用情况。

image.png

12.QNX 带来的功能裁剪

  1. UCP Service (中继模式)
    UCP 框架支持两种主要工作模式:直连模式、中继模式。系统默认运行在直连模式下,在中继模式下,UCP 将支持跨进程任务优先级的统一调度。但 QNX 上跨进程调度的模型性能较差,不满足使用需求,故功能移除。
  2. UCP Trace: UCP trace 通过在 UCP 执行的关键路径上嵌入 trace 记录,提供深入分析 UCP 应用程序调度逻辑的能力。在出现性能异常时,可以通过分析 UCP trace,快速找到异常发生的时间点。但 QNX 底软不支持 Trace 功能,故移除。
  3. DEB 部署包: 用于简化板端部署,可通过自动安装所需的二进制文件和相关依赖库,快速设置并运行 UCP 相关的应用程序,具体包括:ucp_servicehrt_ucp_monitor。但鉴于 ucp_service 不支持,该功能也移除。

▌导读

在AI时代,数据工程师和AI工程师的协作变得前所未有的重要。阿里云DLF产品负责人李鲁兵在本次分享中,详细介绍了全模态湖仓DLF 3.0的完整能力体系。这个平台不仅支持传统的结构化数据处理,更在业界首次实现了结构化、半结构化、非结构化数据的统一管理和处理,为Data+AI一体化提供了端到端的解决方案。

▌全模态平台的核心理念:数据统一、计算按需、工作流驱动

全模态湖仓管理平台的设计理念可以概括为四个关键词:数据统一、计算按需、工作流驱动、多方协作。在AI时代,数据工程师负责数据准备和预处理,AI工程师专注于模型训练、推理和召回,两个角色需要在统一的平台上无缝协作,这对平台能力提出了更高的要求。

数据统一是基础。传统的数据平台往往将结构化数据、半结构化数据、非结构化数据分别存储在不同系统中,造成数据孤岛和管理复杂度的急剧上升。DLF 3.0通过统一的Omni Catalog,实现了对Paimon、Iceberg、Lance、Format Table、Object Table等多种格式的统一管理。无论是传统的数据库表,还是文本、音频、图片、视频等多模态数据,都可以在同一套元数据目录中进行管理,Data工程师和AI工程师可以基于同一份数据进行协作。

计算按需是核心。不同的应用场景需要不同的计算引擎。实时分析需要Flink和Hologres,离线分析依赖Spark和MaxCompute,全模态检索要用到Milvus和Elasticsearch/OpenSearch,模型训练则需要PAI和Ray。DLF 3.0支持所有这些计算引擎在统一的湖仓之上按需调用,一份数据,多个引擎共享,避免了数据的重复存储和迁移。

工作流驱动是保障。数据处理和AI应用往往涉及多个步骤:数据摄取、预处理、特征工程、模型训练、推理、召回等。DLF 3.0提供了完整的工作流编排能力,数据工程师和AI工程师可以通过工作流将各个环节串联起来,实现端到端的自动化流程。

多方协作是目标。通过统一的IDE/Notebook开发环境、Copilot代码辅助、自然语言分析、Agent智能助手等能力,DLF 3.0降低了开发门槛,提升了协作效率。数据工程师和AI工程师可以在同一个平台上使用各自熟悉的工具,同时又能无缝共享数据和成果。

▌产品方案大图:从结构化到全模态的能力升级

DLF 3.0的产品方案大图清晰地展示了从结构化数据处理到全模态处理的能力演进。在传统的数据处理链路上,我们有CDC/Batch Ingestion(数据摄取)、Stream/Batch ETL(数据加工)、OLAP Analytic(分析查询)三个主要环节,对应的计算引擎包括Flink、Spark、Hologres、StarRocks、MaxCompute等。

在全模态处理链路上,新增了四个关键环节:数据集管理、数据预处理、数据训练、数据推理、数据检索召回。这些环节分别对应不同的计算引擎:数据预处理可以使用MaxFrame和PySpark,模型训练依赖PAI和Ray,数据检索召回则需要Milvus和Elasticsearch/OpenSearch等搜索引擎。

两条链路并非孤立存在,而是通过统一的Omni Catalog和DLF元数据服务实现了深度融合。底层的Lakehouse Managed Storage Service提供了统一的存储层,支持Virtual File System、生命周期管理、冷热分层、存储优化等能力。数据缓存加速服务CPFS进一步提升了GPU/CPU的数据读取效率,为AI训练和推理提供了高性能保障。

DLF作为统一的湖仓管理平台,提供了Rest Catalog Service、Lakehouse SDK(Paimon、Iceberg)、File SDK、权限管理、血缘追踪、监控日志等完整的企业级能力。这种架构设计使得同一份数据可以同时服务于传统的数据分析场景和新兴的AI应用场景,真正实现了Data+AI一体化。

▌Omni Catalog:全模态管理的统一目录

在全模态时代,元数据管理面临前所未有的挑战。传统的Catalog只需要管理Tables、Views、Functions等结构化对象,而在AI场景下,还需要管理各种文件(Files)、向量索引、Blob数据等非结构化对象。如果不同类型的数据使用不同的Catalog或System进行管理,就会产生新的数据孤岛,计算引擎需要跨不同的Catalog进行处理,大幅增加了复杂度。

DLF 3.0推出的Omni Catalog正是为了解决这一问题。它通过一套统一的元数据目录,同时管理Tables和Files,支持Paimon、Iceberg、Lance、Format Table(Parquet、ORC、Avro)、Object Table(Files)等多种格式。计算引擎无论是传统的大数据引擎(Flink、Spark、Hologres)还是新型的AI框架(Ray、PyTorch),都可以通过统一的Rest API、Open API、Paimon SDK、Iceberg SDK、VFS SDK进行数据访问。

Omni Catalog的核心优势在于降低了数据孤岛的风险。通过统一的目录,数据治理、权限控制、血缘追踪等能力可以覆盖所有类型的数据,而不需要在不同系统间切换。这对于企业级应用尤为重要,因为数据合规、安全审计等需求必须覆盖全域数据,而不能有盲区。

▌DLF提供商业化Paimon全模态存储:统一管理异构数据

Paimon作为DLF 3.0的核心表格式,在全模态存储方面进行了深度创新。全模态存储面临三大核心需求:统一管理异构数据的能力、支持结构化和多模态数据的顺序访问(用于大规模批式推理)、提供高性能的标签和向量检索(支持随机访问)。

Paimon通过Row ID机制实现了对不同列、不同格式数据的统一管理。每一行数据都有一个全局唯一的Row ID,通过Row ID可以关联该行在不同文件格式中的存储位置。对于结构化数据,Paimon使用Parquet Files存储,对于向量数据,可以使用Lance Files或Faiss Vector索引,对于大型Blob数据(图片、音频、视频),则使用Paimon Blob格式。

在索引构建方面,Paimon提供了多种索引类型。Btree和Bitmap索引用于快速的标量查询,Invert倒排索引支持全文检索,Vector Index则提供高效的向量相似度搜索。这些索引通过Index Manifests进行统一管理,建立了字段与Row ID之间的映射关系。

在数据访问方面,Paimon通过Data Manifests管理文件组,支持Row Ranges范围扫描。对于顺序访问场景(如模型训练),Paimon可以将多条数据打包成Virtual File Group,提供高吞吐的批量读取。对于随机访问场景(如实时检索),Paimon通过全局索引实现了毫秒级的点查性能。

通过这种灵活的File Formats组合和统一的Table Format封装,Paimon实现了在一张宽表上承载结构化、半结构化、非结构化所有类型数据的目标,为全模态应用提供了坚实的存储基础。

▌DLF湖表管理与优化:智能化提升性能降低成本

DLF 3.0提供了完整的湖表管理和优化能力,通过智能化的方式提升读写性能、降低存储成本。整个优化体系包括四大核心能力:自适应分桶、智能Compaction、快照管理清理、存储服务与冷热分层。

自适应分桶是一项创新性功能。传统的分桶策略需要用户在建表时指定分桶数,但随着数据量的变化,固定的分桶数可能导致性能问题。DLF 3.0支持根据数据量自适应地调整分桶数(Rescale),用户只需指定分桶Key,平台会自动维护最优的分桶配置,大幅降低了管理负担。

智能Compaction是性能优化的关键。随着数据的不断写入,湖表会产生大量小文件,影响读取性能。DLF 3.0提供了多种Compaction策略:动态资源模式支持延时优先、资源优先、均衡模式三种策略,平台会根据当前资源状况自动调整Compaction节奏;固定资源模式则允许用户自定义资源配置和参数,实现精细化控制。对于全模态数据,DLF 3.0还支持针对不同文件类型(结构化、半结构化、非结构化)采用不同的Compaction策略,保证整体效率。

快照管理和清理功能帮助用户有效管理数据生命周期。用户可以基于分区或快照设置自动清理策略,平台还会自动扫描Orphan Files(孤儿文件)并清理,避免存储空间的浪费。同时支持手动触发管理操作,满足特殊场景需求。

整个优化流程由DLF元数据服务、Event Store事件存储、Paimon存储优化服务协同完成。作业生成引擎、规则优化引擎、智能优化引擎共同组成了智能决策层,作业调度管理则负责在多个计算资源池上高效执行Compaction任务。这种架构设计实现了从元数据到数据文件的全链路优化,用户无需关心底层细节,即可享受高性能和低成本的双重优势。

▌智能冷热分层:大幅降低存储成本

存储成本是企业在构建数据湖时的重要考量因素。DLF 3.0提供了智能的冷热分层能力,可以根据数据访问模式自动将数据在不同存储类型间迁移,在保证性能的同时大幅降低成本。

DLF 3.0支持四种存储类型:标准存储、低频存储、归档存储、冷归档存储。平台会根据数据的最近访问时间和最近更新时间,自动决定数据应该存储在哪个层级。对于频繁访问的热数据,保持在标准存储以保证高性能;对于访问频率降低的温数据,迁移到低频存储节省成本;对于长期不访问的冷数据,则可以归档到成本更低的归档存储或冷归档存储。

智能加热是冷热分层的重要补充功能。当归档的数据再次被访问时,平台会自动将其加热到更高性能的存储层级。加热策略支持Partition(分区)和File(文件)两层管理,可以针对分区级别或文件级别的访问进行精细化控制。这种设计既保证了数据访问的性能,又最大化地利用了低成本存储,实现了性能与成本的最佳平衡。

通过智能冷热分层,企业可以在不牺牲数据可用性的前提下,将长期存储成本降低数倍。对于PB级甚至EB级的数据湖,这种成本优化能力可以为企业节省大量资金,使得海量数据的长期保存成为可能。

▌细粒度权限控制:企业级安全保障

企业级数据平台必须具备完善的权限控制和安全审计能力。DLF 3.0提供了从用户管理、权限控制到审计治理的全链路安全保障体系。

在用户管理方面,DLF 3.0原生支持阿里云RAM用户体系,基于用户和角色进行权限管理。用户可以通过Open API和REST API进行编程式的权限配置,也可以通过控制台进行可视化管理。

权限控制方面,DLF 3.0支持对湖表设置ACL细粒度权限,可以精确到Catalog、Database、Table、Column(列)甚至Row(行)级别。列级权限允许用户只访问特定的列,行级权限则通过WHERE条件和AND、OR等逻辑运算符,实现对特定行范围的访问控制。列Masking功能可以对敏感字段进行脱敏处理,保护数据隐私。

Data Sharing能力支持跨主账号的数据协作。企业可以将特定的数据集授权给合作伙伴或其他部门,实现安全可控的数据共享。权限检索功能帮助管理员快速了解数据的授权情况,权限委托和授权管理则提供了灵活的权限分级体系。

审计和治理方面,DLF 3.0全面记录所有操作日志,满足生产环境的合规要求。审计管理功能支持漏洞发现和安全治理,帮助企业及时发现和修复安全隐患。这套完整的安全体系,使得DLF 3.0可以满足金融、医疗、政务等高安全要求行业的需求。

▌实时湖仓与全模态处理:AI时代的两大刚需

实时化和全模态化是AI时代数据平台的两大刚需。DLF 3.0在这两个方向上都实现了业界领先的能力。

在实时湖仓方面,DLF 3.0基于Paimon实现了三大核心能力:流式更新、流式订阅、实时查询。数据可以通过Flink等流计算引擎不断流式更新到湖仓中,支持大规模的增量更新和部分列更新。下游系统可以通过流式订阅的方式实时消费变更日志(Changelog),构建实时数据链路。查询层面,Paimon的数据可以被StarRocks、Hologres等OLAP引擎实时查询,延迟可以达到秒级甚至亚秒级。

与业界的Iceberg和Delta相比,Paimon在流式更新场景下具有明显优势。Iceberg和Delta主要面向日志场景,Compaction代价高、速度慢,难以支撑大规模流式增量更新。而中国市场的实时需求走在世界前列,Paimon正是为此而生,通过排序和文件组织优化,大幅降低了Compaction成本,实现了ODS、DWD、DWS全链路的实时更新。

在全模态处理方面,DLF 3.0提供了完整的多模态宽表能力。一张Paimon表可以同时存储id、url、vectors(向量)、labels(标签)、summary(文本摘要)、blobs(大型二进制对象)、meta(元数据)、json(半结构化数据)等多种类型的字段,避免了多表查询和治理负担。统一的存储底层使得数据工程师和AI工程师可以基于同一张表协作,通过高效的索引机制支持向量检索、全文检索、分析查询、模型推理、训练等多种应用场景。


DLF 3.0还对接了主流的大数据处理和AI预处理框架,包括Spark、Flink、Ray、PyTorch等,提供了PyPaimon等Python原生接口,使得AI工程师可以像操作本地文件一样便捷地访问湖上数据。相比业界的LanceDB等方案,DLF 3.0具有生态丰富、统一性强、工业级验证等优势,已经在阿里巴巴集团和众多外部客户中大规模落地。

▌典型场景与客户案例:从理论到实践

DLF 3.0已经在多个典型场景中得到了验证。在离线实时一体化湖仓场景中,通过Flink CDC实现数据库的实时摄取,支持Schema Evolution和整库同步,分钟级实时可查询。Flink在Paimon上进行流读流写,实现全链路实时湖仓,支持低成本的去重和部分列更新。Spark提供数仓级别的批处理性能,支持Filter/Min/Max/TopN/Limit等算子下推和Native计算加速。StarRocks和Hologres则通过Manifests缓存、删除向量、文件过滤等优化技术,实现了对Paimon湖表的极速查询,性能可以对标内表。

在全模态数据管理和处理场景中,音频、文本、图片、视频等多模态数据通过统一的采集入湖,经过Spark或Ray进行预处理(如文本Chunking、Embedding等),将结构化标签、向量、Blob数据统一存储在一张Paimon表中。AI工程师可以通过Milvus或StarRocks进行向量检索和标量过滤,实现样本圈选和预览。PyPaimon直接对接Ray和PyTorch,支持数据加载和模型训练,整个流程端到端打通,数据无需跨系统迁移。

在客户案例方面,智能汽车向量湖是一个典型应用。自动驾驶场景产生海量的车载数据、地理信息、雷达数据、视频图片等多模态数据。通过DLF 3.0,这些数据统一采集并通过人工或机器打标生成Labels,经过预处理将图片、视频拆解为目标对象,再通过Embedding生成向量。Labels和向量数据构建成统一的向量湖,支持标量+向量混合检索召回,可以快速找到符合特定条件的数据样本,用于AI模型的迭代训练。整个方案实现了从数据采集到推理到检索的完整Pipeline,百亿级数据规模的混合检索性能表现优异。

阿里巴巴集团内部的全模态湖也是重要实践。基于Paimon Blob字段,集团构建了EB级的多模态混合存储,支持视频、音频、图片等大型文件的高效管理。通过顺序读高吞吐的数据加载能力,GPU的数据利用率提升了10%,这对于大规模AI训练具有巨大的成本节省价值。这些真实案例充分验证了DLF 3.0全模态湖仓方案的技术先进性和商业价值。

▌产品商业化与生态建设

DLF产品已于2025年正式商业化,现在提供免费试用机会。阿里云还建立了DLF钉钉交流群(群号:106575000021),欢迎用户加入进行技术交流和问题反馈。

全模态湖仓代表了大数据和AI结合发展的下一阶段重要方向。随着多模态AI应用的普及,企业对统一管理和处理异构数据的需求将越来越强烈。DLF 3.0通过开放的架构、强大的性能、完善的企业级能力,为客户提供了一个面向未来的数据平台选择。无论是传统的大数据分析场景,还是新兴的AI训练推理场景,DLF 3.0都可以提供端到端的支持,帮助企业在AI时代保持竞争力。

▌导读

在AI时代,数据工程师和AI工程师的协作变得前所未有的重要。阿里云DLF产品负责人李鲁兵在本次分享中,详细介绍了全模态湖仓DLF 3.0的完整能力体系。这个平台不仅支持传统的结构化数据处理,更在业界首次实现了结构化、半结构化、非结构化数据的统一管理和处理,为Data+AI一体化提供了端到端的解决方案。

▌全模态平台的核心理念:数据统一、计算按需、工作流驱动

全模态湖仓管理平台的设计理念可以概括为四个关键词:数据统一、计算按需、工作流驱动、多方协作。在AI时代,数据工程师负责数据准备和预处理,AI工程师专注于模型训练、推理和召回,两个角色需要在统一的平台上无缝协作,这对平台能力提出了更高的要求。

数据统一是基础。传统的数据平台往往将结构化数据、半结构化数据、非结构化数据分别存储在不同系统中,造成数据孤岛和管理复杂度的急剧上升。DLF 3.0通过统一的Omni Catalog,实现了对Paimon、Iceberg、Lance、Format Table、Object Table等多种格式的统一管理。无论是传统的数据库表,还是文本、音频、图片、视频等多模态数据,都可以在同一套元数据目录中进行管理,Data工程师和AI工程师可以基于同一份数据进行协作。

计算按需是核心。不同的应用场景需要不同的计算引擎。实时分析需要Flink和Hologres,离线分析依赖Spark和MaxCompute,全模态检索要用到Milvus和Elasticsearch/OpenSearch,模型训练则需要PAI和Ray。DLF 3.0支持所有这些计算引擎在统一的湖仓之上按需调用,一份数据,多个引擎共享,避免了数据的重复存储和迁移。

工作流驱动是保障。数据处理和AI应用往往涉及多个步骤:数据摄取、预处理、特征工程、模型训练、推理、召回等。DLF 3.0提供了完整的工作流编排能力,数据工程师和AI工程师可以通过工作流将各个环节串联起来,实现端到端的自动化流程。

多方协作是目标。通过统一的IDE/Notebook开发环境、Copilot代码辅助、自然语言分析、Agent智能助手等能力,DLF 3.0降低了开发门槛,提升了协作效率。数据工程师和AI工程师可以在同一个平台上使用各自熟悉的工具,同时又能无缝共享数据和成果。

▌产品方案大图:从结构化到全模态的能力升级

DLF 3.0的产品方案大图清晰地展示了从结构化数据处理到全模态处理的能力演进。在传统的数据处理链路上,我们有CDC/Batch Ingestion(数据摄取)、Stream/Batch ETL(数据加工)、OLAP Analytic(分析查询)三个主要环节,对应的计算引擎包括Flink、Spark、Hologres、StarRocks、MaxCompute等。

在全模态处理链路上,新增了四个关键环节:数据集管理、数据预处理、数据训练、数据推理、数据检索召回。这些环节分别对应不同的计算引擎:数据预处理可以使用MaxFrame和PySpark,模型训练依赖PAI和Ray,数据检索召回则需要Milvus和Elasticsearch/OpenSearch等搜索引擎。

两条链路并非孤立存在,而是通过统一的Omni Catalog和DLF元数据服务实现了深度融合。底层的Lakehouse Managed Storage Service提供了统一的存储层,支持Virtual File System、生命周期管理、冷热分层、存储优化等能力。数据缓存加速服务CPFS进一步提升了GPU/CPU的数据读取效率,为AI训练和推理提供了高性能保障。

DLF作为统一的湖仓管理平台,提供了Rest Catalog Service、Lakehouse SDK(Paimon、Iceberg)、File SDK、权限管理、血缘追踪、监控日志等完整的企业级能力。这种架构设计使得同一份数据可以同时服务于传统的数据分析场景和新兴的AI应用场景,真正实现了Data+AI一体化。

▌Omni Catalog:全模态管理的统一目录

在全模态时代,元数据管理面临前所未有的挑战。传统的Catalog只需要管理Tables、Views、Functions等结构化对象,而在AI场景下,还需要管理各种文件(Files)、向量索引、Blob数据等非结构化对象。如果不同类型的数据使用不同的Catalog或System进行管理,就会产生新的数据孤岛,计算引擎需要跨不同的Catalog进行处理,大幅增加了复杂度。

DLF 3.0推出的Omni Catalog正是为了解决这一问题。它通过一套统一的元数据目录,同时管理Tables和Files,支持Paimon、Iceberg、Lance、Format Table(Parquet、ORC、Avro)、Object Table(Files)等多种格式。计算引擎无论是传统的大数据引擎(Flink、Spark、Hologres)还是新型的AI框架(Ray、PyTorch),都可以通过统一的Rest API、Open API、Paimon SDK、Iceberg SDK、VFS SDK进行数据访问。

Omni Catalog的核心优势在于降低了数据孤岛的风险。通过统一的目录,数据治理、权限控制、血缘追踪等能力可以覆盖所有类型的数据,而不需要在不同系统间切换。这对于企业级应用尤为重要,因为数据合规、安全审计等需求必须覆盖全域数据,而不能有盲区。

▌DLF提供商业化Paimon全模态存储:统一管理异构数据

Paimon作为DLF 3.0的核心表格式,在全模态存储方面进行了深度创新。全模态存储面临三大核心需求:统一管理异构数据的能力、支持结构化和多模态数据的顺序访问(用于大规模批式推理)、提供高性能的标签和向量检索(支持随机访问)。

Paimon通过Row ID机制实现了对不同列、不同格式数据的统一管理。每一行数据都有一个全局唯一的Row ID,通过Row ID可以关联该行在不同文件格式中的存储位置。对于结构化数据,Paimon使用Parquet Files存储,对于向量数据,可以使用Lance Files或Faiss Vector索引,对于大型Blob数据(图片、音频、视频),则使用Paimon Blob格式。

在索引构建方面,Paimon提供了多种索引类型。Btree和Bitmap索引用于快速的标量查询,Invert倒排索引支持全文检索,Vector Index则提供高效的向量相似度搜索。这些索引通过Index Manifests进行统一管理,建立了字段与Row ID之间的映射关系。

在数据访问方面,Paimon通过Data Manifests管理文件组,支持Row Ranges范围扫描。对于顺序访问场景(如模型训练),Paimon可以将多条数据打包成Virtual File Group,提供高吞吐的批量读取。对于随机访问场景(如实时检索),Paimon通过全局索引实现了毫秒级的点查性能。

通过这种灵活的File Formats组合和统一的Table Format封装,Paimon实现了在一张宽表上承载结构化、半结构化、非结构化所有类型数据的目标,为全模态应用提供了坚实的存储基础。

▌DLF湖表管理与优化:智能化提升性能降低成本

DLF 3.0提供了完整的湖表管理和优化能力,通过智能化的方式提升读写性能、降低存储成本。整个优化体系包括四大核心能力:自适应分桶、智能Compaction、快照管理清理、存储服务与冷热分层。

自适应分桶是一项创新性功能。传统的分桶策略需要用户在建表时指定分桶数,但随着数据量的变化,固定的分桶数可能导致性能问题。DLF 3.0支持根据数据量自适应地调整分桶数(Rescale),用户只需指定分桶Key,平台会自动维护最优的分桶配置,大幅降低了管理负担。

智能Compaction是性能优化的关键。随着数据的不断写入,湖表会产生大量小文件,影响读取性能。DLF 3.0提供了多种Compaction策略:动态资源模式支持延时优先、资源优先、均衡模式三种策略,平台会根据当前资源状况自动调整Compaction节奏;固定资源模式则允许用户自定义资源配置和参数,实现精细化控制。对于全模态数据,DLF 3.0还支持针对不同文件类型(结构化、半结构化、非结构化)采用不同的Compaction策略,保证整体效率。

快照管理和清理功能帮助用户有效管理数据生命周期。用户可以基于分区或快照设置自动清理策略,平台还会自动扫描Orphan Files(孤儿文件)并清理,避免存储空间的浪费。同时支持手动触发管理操作,满足特殊场景需求。

整个优化流程由DLF元数据服务、Event Store事件存储、Paimon存储优化服务协同完成。作业生成引擎、规则优化引擎、智能优化引擎共同组成了智能决策层,作业调度管理则负责在多个计算资源池上高效执行Compaction任务。这种架构设计实现了从元数据到数据文件的全链路优化,用户无需关心底层细节,即可享受高性能和低成本的双重优势。

▌智能冷热分层:大幅降低存储成本

存储成本是企业在构建数据湖时的重要考量因素。DLF 3.0提供了智能的冷热分层能力,可以根据数据访问模式自动将数据在不同存储类型间迁移,在保证性能的同时大幅降低成本。

DLF 3.0支持四种存储类型:标准存储、低频存储、归档存储、冷归档存储。平台会根据数据的最近访问时间和最近更新时间,自动决定数据应该存储在哪个层级。对于频繁访问的热数据,保持在标准存储以保证高性能;对于访问频率降低的温数据,迁移到低频存储节省成本;对于长期不访问的冷数据,则可以归档到成本更低的归档存储或冷归档存储。

智能加热是冷热分层的重要补充功能。当归档的数据再次被访问时,平台会自动将其加热到更高性能的存储层级。加热策略支持Partition(分区)和File(文件)两层管理,可以针对分区级别或文件级别的访问进行精细化控制。这种设计既保证了数据访问的性能,又最大化地利用了低成本存储,实现了性能与成本的最佳平衡。

通过智能冷热分层,企业可以在不牺牲数据可用性的前提下,将长期存储成本降低数倍。对于PB级甚至EB级的数据湖,这种成本优化能力可以为企业节省大量资金,使得海量数据的长期保存成为可能。

▌细粒度权限控制:企业级安全保障

企业级数据平台必须具备完善的权限控制和安全审计能力。DLF 3.0提供了从用户管理、权限控制到审计治理的全链路安全保障体系。

在用户管理方面,DLF 3.0原生支持阿里云RAM用户体系,基于用户和角色进行权限管理。用户可以通过Open API和REST API进行编程式的权限配置,也可以通过控制台进行可视化管理。

权限控制方面,DLF 3.0支持对湖表设置ACL细粒度权限,可以精确到Catalog、Database、Table、Column(列)甚至Row(行)级别。列级权限允许用户只访问特定的列,行级权限则通过WHERE条件和AND、OR等逻辑运算符,实现对特定行范围的访问控制。列Masking功能可以对敏感字段进行脱敏处理,保护数据隐私。

Data Sharing能力支持跨主账号的数据协作。企业可以将特定的数据集授权给合作伙伴或其他部门,实现安全可控的数据共享。权限检索功能帮助管理员快速了解数据的授权情况,权限委托和授权管理则提供了灵活的权限分级体系。

审计和治理方面,DLF 3.0全面记录所有操作日志,满足生产环境的合规要求。审计管理功能支持漏洞发现和安全治理,帮助企业及时发现和修复安全隐患。这套完整的安全体系,使得DLF 3.0可以满足金融、医疗、政务等高安全要求行业的需求。

▌实时湖仓与全模态处理:AI时代的两大刚需

实时化和全模态化是AI时代数据平台的两大刚需。DLF 3.0在这两个方向上都实现了业界领先的能力。

在实时湖仓方面,DLF 3.0基于Paimon实现了三大核心能力:流式更新、流式订阅、实时查询。数据可以通过Flink等流计算引擎不断流式更新到湖仓中,支持大规模的增量更新和部分列更新。下游系统可以通过流式订阅的方式实时消费变更日志(Changelog),构建实时数据链路。查询层面,Paimon的数据可以被StarRocks、Hologres等OLAP引擎实时查询,延迟可以达到秒级甚至亚秒级。

与业界的Iceberg和Delta相比,Paimon在流式更新场景下具有明显优势。Iceberg和Delta主要面向日志场景,Compaction代价高、速度慢,难以支撑大规模流式增量更新。而中国市场的实时需求走在世界前列,Paimon正是为此而生,通过排序和文件组织优化,大幅降低了Compaction成本,实现了ODS、DWD、DWS全链路的实时更新。

在全模态处理方面,DLF 3.0提供了完整的多模态宽表能力。一张Paimon表可以同时存储id、url、vectors(向量)、labels(标签)、summary(文本摘要)、blobs(大型二进制对象)、meta(元数据)、json(半结构化数据)等多种类型的字段,避免了多表查询和治理负担。统一的存储底层使得数据工程师和AI工程师可以基于同一张表协作,通过高效的索引机制支持向量检索、全文检索、分析查询、模型推理、训练等多种应用场景。


DLF 3.0还对接了主流的大数据处理和AI预处理框架,包括Spark、Flink、Ray、PyTorch等,提供了PyPaimon等Python原生接口,使得AI工程师可以像操作本地文件一样便捷地访问湖上数据。相比业界的LanceDB等方案,DLF 3.0具有生态丰富、统一性强、工业级验证等优势,已经在阿里巴巴集团和众多外部客户中大规模落地。

▌典型场景与客户案例:从理论到实践

DLF 3.0已经在多个典型场景中得到了验证。在离线实时一体化湖仓场景中,通过Flink CDC实现数据库的实时摄取,支持Schema Evolution和整库同步,分钟级实时可查询。Flink在Paimon上进行流读流写,实现全链路实时湖仓,支持低成本的去重和部分列更新。Spark提供数仓级别的批处理性能,支持Filter/Min/Max/TopN/Limit等算子下推和Native计算加速。StarRocks和Hologres则通过Manifests缓存、删除向量、文件过滤等优化技术,实现了对Paimon湖表的极速查询,性能可以对标内表。

在全模态数据管理和处理场景中,音频、文本、图片、视频等多模态数据通过统一的采集入湖,经过Spark或Ray进行预处理(如文本Chunking、Embedding等),将结构化标签、向量、Blob数据统一存储在一张Paimon表中。AI工程师可以通过Milvus或StarRocks进行向量检索和标量过滤,实现样本圈选和预览。PyPaimon直接对接Ray和PyTorch,支持数据加载和模型训练,整个流程端到端打通,数据无需跨系统迁移。

在客户案例方面,智能汽车向量湖是一个典型应用。自动驾驶场景产生海量的车载数据、地理信息、雷达数据、视频图片等多模态数据。通过DLF 3.0,这些数据统一采集并通过人工或机器打标生成Labels,经过预处理将图片、视频拆解为目标对象,再通过Embedding生成向量。Labels和向量数据构建成统一的向量湖,支持标量+向量混合检索召回,可以快速找到符合特定条件的数据样本,用于AI模型的迭代训练。整个方案实现了从数据采集到推理到检索的完整Pipeline,百亿级数据规模的混合检索性能表现优异。

阿里巴巴集团内部的全模态湖也是重要实践。基于Paimon Blob字段,集团构建了EB级的多模态混合存储,支持视频、音频、图片等大型文件的高效管理。通过顺序读高吞吐的数据加载能力,GPU的数据利用率提升了10%,这对于大规模AI训练具有巨大的成本节省价值。这些真实案例充分验证了DLF 3.0全模态湖仓方案的技术先进性和商业价值。

▌产品商业化与生态建设

DLF产品已于2025年正式商业化,现在提供免费试用机会。阿里云还建立了DLF钉钉交流群(群号:106575000021),欢迎用户加入进行技术交流和问题反馈。

全模态湖仓代表了大数据和AI结合发展的下一阶段重要方向。随着多模态AI应用的普及,企业对统一管理和处理异构数据的需求将越来越强烈。DLF 3.0通过开放的架构、强大的性能、完善的企业级能力,为客户提供了一个面向未来的数据平台选择。无论是传统的大数据分析场景,还是新兴的AI训练推理场景,DLF 3.0都可以提供端到端的支持,帮助企业在AI时代保持竞争力。

如何形容现在市面上普遍的 OCR 呢?可能你已经习惯了它的「固执」——无论文档布局多复杂,它总是老老实实从左到右、从上到下扫一遍。遇到双栏论文还好,碰上跨页表格或者公式脚注混排,输出结果往往乱得让人头疼。这不是识别不准,而是理解方式出了问题。

今年 1 月 DeepSeek 团队推出的 DeepSeek-OCR 2 换了个思路,它不再把文档当成一张平面图,而是尝试理解这篇文章应该先读什么。新设计的 DeepEncoder V2 架构引入了因果流机制:视觉编码器看完整个页面后,由专门的查询模块决定阅读顺序——标题优先于正文,表格注释紧跟数据,公式按逻辑展开而非按位置罗列。

结果很直接。OmniDocBench 最新测试中,这套方案把整体准确率推到了 91% 以上,公式识别的提升尤为明显。更实用的是,它输出的 Markdown 已经带着层级结构,省去了大量后期整理的功夫。

参数规模控制在单卡能跑的级别,token 上限可调,重复生成的情况也比上一代少了近三分之一。对于需要批量处理文档的场景,这意味着可用性的大幅提升。

当一个模型能够同时看懂版式、识别文字并直接输出结构化结果,文档数字化的目标就不再只是「能认字」,而是「能理解」。DeepSeek-OCR 2 正是在这一方向上的一次重要尝试。

教程链接: https://go.openbayes.com/NOdm2

使用云平台: OpenBayes

http://openbayes.com/console/signup?r=sony_0m6v

首先点击「公共教程」,找到「DeepSeek-OCR 2:视觉因果流」,单击打开。

页面跳转后,点击右上角「克隆」,将该教程克隆至自己的容器中。

在当前页面中看到的算力资源均可以在平台一键选择使用。平台会默认选配好原教程所使用的算力资源、镜像版本,不需要再进行手动选择。点击「继续执行」,等待分配资源。

若显示「Bad Gateway」,这表示模型正在加载中,请等待约 2-3 分钟后刷新页面即可。


使用步骤如下:

  1. 页面跳转后,点击左侧 README 页面,进入后点击上方「运行」。

  1. 点击运行后等待加载模型与初始化

  1. 待运行完成,即可点击右侧 API 地址跳转至 demo 页面。

  1. 上传所需要的 JPG/PNG 格式的图片或 PDF 文档。

  1. 上传完成后点击运行,稍等片刻右侧结果框生成纯文本结果。


教程链接:

https://go.openbayes.com/NOdm2

本文测评 12 款常见产品管理系统/平台:ONES、Tower、Jira Product Discovery、Jira Software、Productboard、Aha! Roadmaps、Craft.io、airfocus、ProductPlan、Tempo Strategic Roadmaps(原 Roadmunk)、Azure Boards、monday.com。我会用“能力模型+1–5星评分”对比战略规划、需求管理、研发协同、用户反馈、数据指标、知识沉淀、组织治理与集成扩展等方面,帮你更快做出适配团队的选型判断。

测评结论速览

结论速选

  • 想要“需求—研发协同—测试/交付”尽量在一套体系里跑:优先看 ONES 这类端到端研发管理平台路线。
  • 最痛是“想法太多、证据分散、优先级吵不清”:优先看 Productboard / Aha! Roadmaps 这种上游产品发现与路线图工具。
  • 更看重工程交付节奏(看板、Backlog、冲刺、报表):ONES / Jira Software / Azure Boards 更像执行中枢。
  • 更看重“排期、依赖联动、跨部门推进”:Tower 更像协作与排期底座,甘特依赖与自动调整对“变更引发的连锁延期”很有帮助。
  • 更看重“路线图呈现与组合视图(Portfolio)对齐管理层”:优先看 ProductPlan。

对比表(编辑评分|1–5星)

说明:这是“可核验信息基础上的编辑评分”,用于快速对比,不是第三方认证/行业榜单。

评分尺度:

  • 5星:公开资料显示能力成熟、链路完整、适用面广
  • 3星:能力明确但偏单点/偏分层,需要搭配其他工具/方法
  • 1–2星:该维度公开能力弱或依赖外部实现,不建议作为主承载

证据来源:

  • 官方产品页/功能页/帮助中心/支持文档(最高优先级);
  • 官方博客/官方集成文档(用于补充“如何实现”的细节);
  • 若某项能力在公开资料里找不到,我也会标注出来。

产品管理系统深度测评

1) ONES

一句话定位:ONES 是国产企业级研发管理平台,公开定位强调“端到端软件研发管理”,并明确覆盖从需求管理、迭代跟进到测试的链路,更像把产品管理系统与研发协同放在同一底座上。适合中大型产品研发组织,以及痛点是“规划在A、开发在B、测试在C”的断链,且愿意把评审规则、状态机、验收标准沉淀为组织资产的团队。
产品管理能力拆解(战略规划/需求管理/研发协同/反馈/指标/知识/治理/运营)
战略规划:强调“场景方案与流程落地”,战略层表达(如 OKR/产品战略树)能否做深,取决于你们是否把“口径与规则”写进系统。
需求管理:优势在“需求进入交付链路后可追踪”,适合把需求、迭代、测试串联起来做闭环。
研发协同:端到端链路是它作为产品管理系统底座的关键——当状态、职责、验收统一后,跨团队沟通会更省。
用户反馈/产品运营:公开信息里可看到“工单/服务台”等场景,适合作为主反馈中枢还需要结合你们渠道与流程
数据指标/治理:拥有效能改进与可视化分析能力,适合效能管理者用同一套口径看多项目/多团队表现。
优势亮点(为什么重要 + 场景)
闭环追溯:需求到测试贯通,让复盘能回答“做了什么、为何做、交付成了什么”。
流程可落地:把协作规则写进系统,减少“靠人盯”的成本,适合人员流动较大的组织。
统一口径:对效能管理者来说,统一口径比“功能堆满”更关键。

2) Tower

一句话定位:Tower 是 ONES 旗下团队协作工具,官方定位是“安排任务、管理进度、沉淀团队知识”,并提供列表/日历/看板/甘特等多视图,把它放进产品管理系统版图里更像“协作与排期底座”。适合中小到中型跨部门团队,以及项目排期、依赖关系复杂;需要把“计划—推进—提醒—复盘”放进同一工作空间的团队。
产品管理能力拆解
战略规划:Tower 更擅长把目标落到“阶段、里程碑与责任人”,而非提供完整 OKR 体系;它适合作为战略落地的执行层。
需求管理:软件研发支持迭代计划、需求管理、Bug 管理等,偏“承接已明确需求并推进”。
研发协同:甘特图用于进度管控,,适合应对“需求变更→排期连锁反应”。
用户反馈:若你们在飞书协作,Tower 协作可以把聊天消息/图片快速转为任务,并与群聊/云文档空间等深度整合,这类“就地采集反馈→进入任务流”的路径很务实。
优势亮点
依赖+排期可视化:项目经理能更快定位延期风险,把精力从“搬日期”转回“管风险”。
多视图对齐:同一份数据给不同角色用不同视图看,减少“你说不清、我看不懂”。
飞书侧入口自然:对“反馈从聊天里来”的团队,消息转任务能显著降低漏记与重复沟通。

3) Jira Product Discovery

一句话定位:Jira Product Discovery(Atlassian)定位在“产品发现与优先级”,支持用字段与表达式公式把想法/洞察变成可排序的优先级,并用视图做路线图沟通。适合产品决策争议大、跨部门拉扯多、需要建立优先级共识的团队。
产品管理能力拆解
战略规划:更像战略输入的承接层——把战略拆成可讨论的机会/想法并持续评估。
需求管理:它管理的是“上游需求”(机会/想法/洞察),核心价值是把争论从“谁嗓门大”转为“按口径排序”。
研发协同:交付闭环通常需要 Jira 的执行体系承接(把被选中的需求稳定流入研发 Backlog)。
组织治理:优势在“决策可复盘”——字段与公式让你解释得清楚“为什么做A不做B”。
优势亮点
公式化优先级:把 RICE 等模型落到系统,减少拍脑袋与反复扯皮。
视图沟通:同一份数据给不同受众不同视角,降低对齐成本。
与Jira衔接自然:对已在 Atlassian 生态内的团队,落地成本更低。

4) Jira Software

一句话定位:Jira Software 是典型工程执行型产品管理系统组件,官方明确支持 scrum/kanban 等方法,并覆盖敏捷板、Backlog、路线图、报表与集成生态。适合工程交付为中心的组织,产品经理需要在产品管理系统里紧跟开发进度、风险与发布。
产品管理能力拆解
战略规划:战略表达往往在外部形成(文档/OKR),再映射到史诗/故事与路线图。
需求管理:更擅长“已确认需求”的拆解与流转(Backlog、用户故事管理),而不是大规模反馈聚类。
研发协同:强项在节奏与透明——冲刺、看板、报告能帮助团队建立稳定交付节拍。
数据指标:报表丰富,但建议把指标用于改进而非考核(否则团队会“为指标而工作”)。
优势亮点
方法适配广:scrum、kanban 或混合都能落地。
Backlog 纪律强:用户故事管理与可见性提升,有助于减少“需求说了但没人做”。
生态成熟:当你们需要和CI/CD、知识库、客服等系统连接时,生态价值会逐年放大。

5) Productboard

一句话定位:Productboard 公开定位是“帮助产品经理理解客户需求、确定优先级,并让组织围绕路线图对齐”,在产品管理系统里更偏“反馈→优先级→路线图”的主线。适合客户声音很多、需求入口分散、需要用路线图统一叙事并降低跨部门沟通成本的团队。
产品管理能力拆解
战略规划:强在“把战略讲清楚并持续对齐”,通过路线图让不同部门理解取舍逻辑。
需求管理/用户反馈:定位直接强调理解客户需求,适合把分散的客户声音收拢为主题与需求,再进入优先级与路线图。
研发协同:通常通过与工程工具联动完成交付闭环(公开定位强调“下一步要构建什么并对齐”,具体联动深度建议试用验证,本文不做超出公开信息的断言)。
组织治理/产品运营:当路线图成为单一真相源,销售/CS/市场的预期管理会更稳定(这是产品运营层面的真实价值)。
优势亮点
围绕路线图对齐:减少重复解释与版本不一致。
以用户需求驱动优先级:把“感觉”变成“可回溯的证据链”(至少在信息结构上)。
更贴近产品语言:讨论焦点更偏用户问题与价值,而不是工程任务颗粒度。

6) Aha! Roadmaps

一句话定位:Aha! Roadmaps 公开强调通过品牌化 Ideas Portal 收集反馈、对想法排序,并将最佳想法Promote到路线图对象(features/epics等),属于偏治理的产品管理系统路线。适合产品线多、反馈来源复杂、需要强治理与推进机制的组织(尤其规模化阶段)。
产品管理能力拆解
战略规划:更适合做“路线图中枢”——把战略拆成可管理层级并持续推进。
需求管理/用户反馈:Ideas Portal 统一入口,“Promote”机制让想法有明确去处并能跟踪状态。
研发协同:常通过与工程工具衔接完成交付闭环(公开资料强调从想法到路线图再到交付状态追踪)。
组织治理:强在“可追溯”——你能清楚回溯某个 feature 从哪条反馈/想法来、为何被选中。
优势亮点
Ideas → Roadmap 的推进链路:减少“想法堆在墙上没人管”。
入口统一带来数据结构化:有利于沉淀分类、主题与决策依据。
状态可追溯:对 PMO/效能角色很友好,复盘成本更低。

7) Craft.io

一句话定位:Craft.io 公开定位为端到端产品管理平台,并在 OKR 页面明确提出“连接 objectives 到 initiatives/projects/epics”,走的是“OKR/战略→规划→执行”的产品管理系统路线。适合目标管理清晰、管理层需要强对齐,或希望把 OKR 与产品规划强绑定的中大型产品组织。
产品管理能力拆解
战略规划/OKR:OKR 是显性定位,强调从目标到执行对象的连接,减少“目标只在PPT里”。
需求管理:更偏把需求纳入战略框架(initiative/epic/feature),适合做结构化规划。
研发协同:官网强调从反馈收集到执行覆盖整个生命周期(具体研发侧细节以试用为准,本文不做超出公开信息的断言)。
指标/治理/运营:OKR 关联关系天然服务治理:当目标—投入—产出关系清晰,运营沟通也更“讲得通”。
优势亮点
目标到执行可追溯:能回答“为什么做这件事”,并在复盘时检查假设是否成立。
端到端生命周期叙事:对“从反馈到执行”的团队更顺手。
减少战略漂移:当目标与路线图对象有关联,改方向就会更谨慎、更可控。

8) airfocus

一句话定位:airfocus 公开定位为产品管理工具,并在优先级模块明确提供“评分框架、Priority Poker”等机制,把优先级讨论做成可协作流程,属于模块化产品管理系统路线。适合中型以上产品团队,对优先级质量、路线图沟通和跨团队参与度要求高的组织。
产品管理能力拆解
战略规划:其定位强调围绕清晰产品战略来优先级排序与路线图对齐。
需求管理/优先级:强项就是“把取舍标准落地”——评分框架与协作式 Priority Poker 让不同角色参与排序。
用户反馈/指标/运营:官网模块展示包含反馈与洞察、OKR等(深度以试用为准,本文不做超出公开信息的断言)。
组织治理:模块化意味着可以按成熟度逐步启用,避免“一口气把系统做成怪物”。
优势亮点
评分框架让争论回到标准:把“口水战”转成“口径讨论”,适合争议多的团队。
Priority Poker 促进共识:让多角色参与排序,减少单点拍板的偏差。
模块化上手:先从优先级/路线图开始,再扩到OKR/洞察,节奏更可控。

9) ProductPlan

一句话定位:ProductPlan 公开强调“从发现到发布”用路线图与 portfolio 视图形成单一真相源,并在支持文档中明确 Portfolio View 可把多条路线图合并为一个整体视图用于分享给高层与干系人。适合产品线多、路线图需要统一口径;高频跨部门沟通导致成本高的组织。
产品管理能力拆解
战略规划:强在“战略可视化”——把战略倡议与里程碑放到可分享的路线图上,减少信息偏差。
需求管理:更偏承接“已确认的规划项”,上游洞察/反馈体系通常要配套。
研发协同:常作为“路线图层”,下游对接 Jira/Azure 等执行系统(公开强调从发现到发布,但具体执行承接需试用验证)。
组织治理/产品运营:Portfolio View 对管理层对齐很友好——把多个产品/团队的路线图放在一张图里谈取舍。
优势亮点
Portfolio View“把全局拉齐”:适合 VP/负责人快速看到全局节奏与冲突。
单一真相源:减少“每个人都有一张路线图”的版本地狱。
面向受众分享:路线图不仅是内部用,还是对外预期管理工具。

10) Tempo Strategic Roadmaps(原 Roadmunk)

一句话定位:Tempo 的 Strategic Roadmaps 公开介绍里强调 Idea Manager:记录团队想法、在路线图中进出以便快速转向,并提供内置优先级模板或自定义评分框架,更偏“想法管理+路线图呈现”的产品管理系统层。适合对路线图沟通要求很高,需要把“想法收拢→优先级→路线图表达”做得顺的团队。
产品管理能力拆解
战略规划/路线图:核心在“把方向讲清楚”,并让路线图可随项目变化快速调整。
需求管理:偏“想法/主题→路线图条目”,适合对齐与沟通,不是重规格的需求工程工具。
用户反馈:公开资料聚焦 idea management 与 prioritization framework;更深入的反馈采集形态建议以官方资料与试用验证为准(本文不做超出公开信息的断言)。
研发协同:更像路线图层,需要下游执行系统承接。
优势亮点
Idea Manager 支持快速转向:变化来了能把想法/条目快速进出路线图,减少大改带来的混乱。
内置模板/自定义评分:让优先级讨论回到标准,提高决策一致性。
更像“路线图表达工具”:对管理层沟通友好,适合把复杂工作讲成清晰节奏。

11) Azure Boards

一句话定位:Azure Boards(Azure DevOps)公开强调提供 Kanban boards、backlogs、dashboards、scrum boards 等敏捷工具,并支持自定义工作流与“1,000+ extensions”,属于工程交付承接型产品管理系统组件。适合微软生态与 DevOps 体系成熟的研发组织。
产品管理能力拆解
战略规划:更偏执行层,战略通常在外部形成后映射到工作项/积压。
需求管理:适合管理“已确认需求”的交付推进(用户故事、bug、工作项等)。
研发协同:看板/冲刺/容量等机制对效率管理者很关键,利于建立节奏与透明度。
治理/集成:扩展与自定义能力适合大组织长期演进,也更容易融入 Teams/Slack 等协作。
优势亮点
敏捷执行能力完整:Kanban、Backlog、Dashboard、Scrum boards 一应俱全。
可定制与扩展:适合把组织方法固化为流程与权限体系。
与常用协作工具结合:有利于把执行信息带回团队日常协作场域。

12) monday

一句话定位:monday 在“Product Management Software”页面明确写到可在一处管理 roadmaps、plans、challenges、KPIs,并强调高度可定制,属于“可配置工作系统”型产品管理系统。适合协作对象广(产品/市场/运营/支持/交付),流程变化快、需要快速调整系统结构的团队。
产品管理能力拆解
战略规划/产品运营:KPI 与计划集中管理对运营节奏有帮助,但战略严密性取决于你怎么设计板、字段与评审机制。
需求管理:更像可配置工作流承接需求与任务,而非专注产品发现的证据链体系。
研发协同:跨部门协作友好;工程深度(如代码/PR强关联)需要看集成与组织实践(本文不做超出公开资料的断言)。
组织治理:优势是“可定制”,风险也是“过度可定制导致口径漂移”,需要制度化维护。
优势亮点
路线图+计划+KPI同处:管理层看全局、团队看分工,沟通链路更短。
可配置适配管理模式:更像“搭积木”,适合非标准流程。
可视化带来透明:很多扯皮来自看不见彼此的工作,透明度能直接降低摩擦。

选产品管理系统,最怕的是“拿工具替代思考”。我更建议你先把三个问题问清楚:你们的瓶颈在哪一段?是上游“优先级吵不清”,还是中游“排期依赖失控”,还是下游“交付追溯断链”?瓶颈不同,主系统就不同。你们要“一体化闭环”还是“分层组合”?一体化适合追求口径统一、链路完整;分层组合适合成熟团队按强项拼装(路线图层 + 执行层 + 协作/知识层)。你们愿不愿意为“口径一致”付出维护成本?系统越灵活,越需要字段字典、状态机、评审模板与复盘节奏。否则工具越强,混乱也会更快被放大。

工具能做的,是把共识“写下来、追踪起来”;做不到的,是替你们完成那些本该由团队共同承担的取舍。把方法立住,你选哪一款产品管理系统,都会更顺。

如果你正在挑一款需求管理软件,大概率会在“需求入口分散、评审难落地、变更失控、交付对不齐”之间反复踩坑。本文以可核验公开资料为依据,按统一评分模型测评 ONES、Tower、Jira Product Discovery、Aha! Roadmaps、Productboard、YouTrack、Azure DevOps Boards、GitLab Requirements、Jama Connect、IBM DOORS、Polarion、ReqView,给你一张可直接对照的选型清单:谁适合产品团队、谁更偏工程合规、谁适合研发执行闭环。

一、测评方法论:5大一级指标 + 14项细分维度

评分口径:本文“综合得分/星级”是编辑评分,依据各工具的公开产品页/帮助中心/官方文档中可核验功能信息;不使用“不可验证的第三方满分/认证/客户数”。

5大一级指标(建议权重):

  • 需求全生命周期能力(30%):从需求入口到验收闭环是否完整
  • 优先级与路线图(20%):能否把“想做”变成“先做什么”
  • 评审与变更治理(20%):需求管理软件的分水岭在“变更可控”
  • 追溯与影响分析(20%):需求—设计—任务—测试的链路是否可追问
  • 集成与协作体验(10%):跨部门/跨工具链协作成本

14项细分维度:

  • 需求入口:多渠道收集 / 表单化 / 统一归口
  • 需求池:去重归类 / 状态流转 / 负责人机制
  • 需求表达:模板 / 验收标准 / 附件与上下文
  • 优先级:自定义字段 / 评分模型 / 价值-成本权衡
  • 路线图:多视图 / 干系人沟通 / 与交付同步
  • 评审:评审流程 / 评论与决议 / 结论可追溯
  • 变更:版本化 / 变更记录 / 影响范围提示
  • 依赖:需求依赖/前后置 / 冲突提示
  • 追溯:需求↔任务 / 需求↔测试 / 历史审计
  • 影响分析:变更触发的下游影响识别
  • 交付对齐:迭代/版本关联 / 发布说明
  • 协作:通知 / 权限 / 外部协作
  • 集成:API/Webhook / 与代码/CI/客服系统对接
  • 报表:周期、吞吐、积压、变更等基础度量

二、2026年需求管理软件总榜(选型参考,非绝对优劣)

关键提醒:工具排名是“选型参考”;真正的优劣取决于你团队的协作方式与治理成熟度。品牌推荐官文章也会强调“排序非绝对优劣”,但常用更强断言表达。

三、2026年需求管理软件深度测评

NO.1|ONES(从需求到交付验证的闭环流水线)

推荐指数:★★★★★
综合得分:92/100(编辑评分)
关键优势:产品能力(93)/集成协作(90)/场景适配(92)/治理追溯(91)/交付对齐(94)

核心定位:ONES 是面向企业的一站式研发管理平台品牌,覆盖从需求到交付协作与效能提升的核心场景。在需求管理方面是更偏“产研一体”的需求管理软件,把需求池、迭代规划、测试关联放在同一条链路里。其“需求池”思路强调:统一入口、梳理评审、优先级排期、再分配落地。

需求管理能力拆解

  • 需求入口与需求池:需求池作为统一归口,覆盖收集、梳理、评审、分配等环节,适合把分散需求“先收住”。
  • 优先级与评审闭环:需求评审的关键不是“开会”,而是把优先级决策、依赖关系、验收标准写进需求对象里,减少“会后口头共识”。(公开资料侧强调优先级、关系与跟踪机制)
  • 交付对齐与追溯:当需求进入测试阶段,可将测试计划与需求关联,形成“需求跟踪视图/矩阵”,让交付质量回到需求本身;测试用例也支持与需求、任务关联,利于问责与复盘。

适用场景:中大型产品团队、需要“需求—迭代—测试”联动的组织;以及希望把需求管理软件作为研发管理底座的团队。

使用与避坑建议:

  • 别一上来就追求复杂流程:先把“需求入口—需求池—优先级—迭代对齐”跑顺,再补审批/变更规则。
  • 度量先从可解释指标开始:周期、积压、变更次数这类“能解释”的指标先做起来,别一开始追求花哨看板。

参考来源:ONES 需求池管理实践文章、需求池管理流程文章、ONES TestCase 产品页。

NO.2|Jira Product Discovery(需求发现/优先级)

推荐指数:★★★★☆
综合得分:88/100
关键优势:产品能力(90)/集成协作(88)/场景适配(86)/治理追溯(80)/交付对齐(86)
核心定位:Jira Product Discovery 是 Atlassian 面向产品团队推出的需求发现与优先级/路线图工具,强调把想法与洞察集中管理并用字段与公式做排序。
需求管理能力拆解
需求入口与需求池:更像“机会/想法池”,适合把用户反馈、销售线索、访谈结论先结构化沉淀。
优先级与路线图:支持自定义字段与公式,帮助团队把“价值/影响/成本”量化成排序依据;并能用不同视图对不同干系人沟通。
评审闭环:优势在于“基于证据的对齐”,而不是审批流;适合减少拍脑袋,但需要你们先统一评分口径。
变更与追溯:对“需求—交付”闭环依赖 Jira 生态(这不是缺点,只是边界)。
适用场景:产品团队需要提升“优先级共识质量”;尤其是多干系人拉扯严重、需要用证据做取舍的团队。
局限与避坑建议:
别把它当完整交付系统:它强在“上游”,下游需要配套交付工具链。
评分模型要小而美:字段越多越像形式主义,建议从 3-5 个关键维度起步。
参考来源:Atlassian 官方产品页与功能页。

NO.3|Productboard(把需求讲成路线图)

推荐指数:★★★★☆
综合得分:87/100
关键优势:产品能力(89)/集成协作(85)/场景适配(88)/治理追溯(78)/交付对齐(84)
核心定位:Productboard 是产品管理软件平台,核心价值是帮助团队理解客户需求、做特性优先级,并让组织围绕路线图对齐。
需求管理能力拆解
需求入口与需求池:强在“把多渠道声音汇总成可行动的需求主题”,适合产品在信息噪音中做归类。
优先级与路线图:强调“围绕路线图对齐组织”,并支持把路线图以链接形式对外共享(适用于对齐销售/客户)。
评审与变更:适合“产品评审”,但工程变更控制需要与交付工具联动(否则会变成“路线图很好看,落地很难追”)。
适用场景:产品驱动型组织;需要经常向外部/内部解释“为什么先做这个”的团队。
局限与避坑建议:
别把路线图当承诺清单:路线图输出越容易共享,越要把“可变更边界”讲清楚。
落地追溯要预先设计:至少保证需求与交付任务有稳定映射关系,否则复盘时很难说清“这条需求到底交付了什么”。
参考来源:Productboard 官方产品页与路线图共享帮助文档。

NO.4|Aha! Roadmaps(Idea 门户 + 推进到路线图)

推荐指数:★★★★☆
综合得分:86/100
关键优势:产品能力(88)/集成协作(83)/场景适配(86)/治理追溯(80)/交付对齐(82)
核心定位:Aha! Roadmaps 是以产品路线图与创意管理见长的平台,支持把 Ideas 直接“Promote”到路线图记录并建立关联追踪。
需求管理能力拆解
需求入口:Ideas Portal 让“外部/一线声音”有标准入口。
需求推进机制:支持把 idea “Promote”到路线图中的不同记录类型,并可新建或链接到既有记录,适合把多个反馈收敛到同一需求主题。
评审与变更:优势在“推进机制清晰”;但你仍需要定义“什么时候可以Promote、谁批准、如何记录决议”。
适用场景:产品线多、反馈来源杂、需要强治理与对齐的组织。
局限与避坑建议:
不要用工具替代决策:Aha 能让流程更可追溯,但“取舍标准”仍要团队自己建立。
避免门户变成许愿池:设置最小提交模板与反馈分类规则,否则会被低质量输入淹没。
参考来源:Aha 官方产品页与支持文档。

NO.5|Azure DevOps Boards(把需求分层成 Epic/Feature)

推荐指数:★★★★☆
综合得分:84/100
关键优势:产品能力(80)/集成协作(88)/场景适配(85)/治理追溯(82)/交付对齐(88)
核心定位:Azure Boards 是 Microsoft Azure DevOps 体系中的工作项与 Backlog 管理能力,支持用 Epics/Features 组织需求并分层推进到执行。
需求管理能力拆解:
需求池与分层:通过 features/epics backlogs 把需求按层级归类,利于“从愿景到迭代”的结构化分解。
优先级与排期:优势在“与开发执行紧耦合”,但产品侧的“需求质量(验收标准/证据)”需要你们自己用模板/规范补齐。
追溯:在工程侧可追溯较强,但跨到测试/发布/客户反馈时,仍需要流程设计与集成。
适用场景:研发组织成熟、执行体系以 ADO 为核心;需要把需求管理软件与交付过程合一。
局限与避坑建议
别只堆层级:Epic/Feature 不是越多越好,关键是每一层都能回答“这层做完意味着什么”。
验收标准务必前置:否则会变成“做了很多条目,但没人敢说交付完成”。
参考来源:Microsoft Learn 官方文档。

NO.6|YouTrack(看板与 Backlog 一体)

推荐指数:★★★★☆
综合得分:83/100
关键优势:产品能力(80)/集成协作(80)/场景适配(86)/治理追溯(78)/交付对齐(82)
核心定位:YouTrack 是 JetBrains 的项目/Issue 跟踪平台,强调用 Backlog 与敏捷看板把团队工作保持聚焦并可随优先级变化回收至 Backlog。
需求管理能力拆解:
需求池/Backlog:支持围绕查询与Backlog协作,但如果你们希望“产品侧更强的需求表达/评审”,要自己补流程。
流转与协作:看板卡片拖动会同步更新字段值,协作反馈更即时。
变更治理:更偏“执行流转”,而非“治理控制”;适合敏捷团队,但对强合规场景不够。
适用场景:研发团队主导的敏捷协作;不想为复杂RM系统付出高实施成本的组织。
局限与避坑建议
别把“能拖动”当“治理”:需求评审结论、验收标准、变更边界仍要写清楚。
Backlog规则要一致:否则会出现“需求在板上/在Backlog里”争议,影响透明度。
参考来源:JetBrains YouTrack 官方文档。

NO.7|Tower(更擅长排期与依赖)

推荐指数:★★★★☆
综合得分:80/100
关键优势:产品能力(75)/集成协作(82)/场景适配(86)/治理追溯(70)/交付对齐(84)
核心定位:Tower 是国内团队协作与项目管理产品,突出以时间线(甘特图)等视图提升任务排期与依赖协作效率。在需求管理方面更像“把需求落到任务与排期”的协作工具——当你需求评审完,最怕的不是“没人做”,而是“做着做着依赖乱了、排期失真”。Tower 的时间线/甘特与依赖联动,能把交付风险提前暴露。
需求管理能力拆解:
需求到任务拆解:适合作为“需求落地承接层”,把需求拆成任务、设置负责人/日期/依赖,保证交付透明。
依赖与变更联动:支持“自动调整后置任务时间”“防止任务依赖冲突”,这对频繁变更的需求落地很实用——变更不是问题,变更不联动才是问题。
可视化排期:支持按天/周/月/季/年粒度看时间线,便于和干系人对齐节奏。
适用场景:需要强排期、强依赖管理的项目型团队;或把专业需求管理软件与协作排期工具组合使用的团队。
局限与避坑建议:
需求治理要在上游完成:Tower 适合执行与排期,不适合承载复杂的需求评审与合规追溯。
依赖不是越多越好:建议只给关键路径建依赖,否则维护成本反噬。
参考来源:Tower 官方博客(甘特/时间线/依赖联动说明)。

NO.8|GitLab Requirements(把需求放进工程体系)

推荐指数:★★★☆☆
综合得分:79/100
关键优势:产品能力(75)/集成协作(86)/场景适配(78)/治理追溯(80)/交付对齐(82)
核心定位:GitLab Requirements 是 GitLab 平台中的“需求工件”能力,把需求作为长期存在的 artifact 来管理,用于描述产品行为与验收标准。
需求管理能力拆解
需求对象化:在项目中可创建/查看需求列表,需求不再只是 issue 描述。
合规协作:导出需求到 CSV 并通过邮件附件发送的能力,对“需要对外共享/审计留档”的场景有现实价值。
追溯与交付对齐:工程侧链路天然更紧密,但产品侧需求池、路线图治理能力相对有限。
适用场景:DevOps 一体化团队;希望需求管理软件尽量贴近代码与工程资产的组织。
局限与避坑建议
别把导出当治理完成:导出只是能力,治理要靠流程与责任边界。
需求表达要标准化:否则需求会退化成“另一个Issue字段”。
参考来源:GitLab Requirements 官方文档。

NO.9|Jama Connect(需求变更影响分析)

推荐指数:★★★★☆
综合得分:85/100
关键优势:产品能力(88)/集成协作(78)/场景适配(84)/治理追溯(92)/交付对齐(83)
核心定位:Jama Connect 是 Jama Software 的需求管理与追溯平台,主打 Live Traceability 与实时风险识别能力(如 Live Trace Explorer)。
需求管理能力拆解
变更影响分析:当需求变化时,识别对下游需求与测试的“涟漪效应”,这是合规与质量团队真正关心的地方。
追溯到测试:把需求与测试活动的关系建立起来,帮助你回答“这个需求验证了吗、覆盖了吗”。
评审与协作:更适合正式评审与证据沉淀,而非轻量敏捷日常。
适用场景:汽车、医疗、航天等对追溯与验证要求高的行业;或系统工程团队。
局限与避坑建议
实施成本要前置评估:Jama 的价值在体系化使用,零散使用反而浪费。
先定义追溯模型再上工具:否则你会得到“很多链接”,但解释不清为什么要链接。
参考来源:Jama 官方帮助文档与能力介绍页。

NO.10|IBM DOORS(传统工程 RM)

推荐指数:★★★★☆
综合得分:82/100
关键优势:产品能力(80)/集成协作(70)/场景适配(82)/治理追溯(94)/交付对齐(78)
核心定位:IBM Engineering Requirements Management DOORS 系列(DOORS 与 DOORS Next)是 IBM 的规模化需求管理解决方案,强调协作评审、变更管理与可追溯性。
需求管理能力拆解
基线与签署:支持对基线进行电子签署,并记录签署人、时间等信息,满足审计与责任追溯需要。
多级追溯:强调多层级追溯视图与可定制视图,适合复杂需求分解与验证链路。
变更治理:优势在“控制与证据链”,但对产品团队而言会显得偏重、偏工程。
适用场景:强监管行业、系统工程/硬件软件协同项目、对审计链要求极高的组织。
局限与避坑建议
不要把它当轻量需求池:它更适合“规格与基线管理”,不是日常想法收集。
角色分工要清晰:否则会出现“工程团队用得很好,产品团队完全进不来”。
参考来源:IBM 产品页与官方文档(电子签名/基线)。

NO.11|Polarion(自动变更控制 + 审计链)

推荐指数:★★★★☆
综合得分:84/100
关键优势:产品能力(83)/集成协作(76)/场景适配(84)/治理追溯(92)/交付对齐(80)
核心定位:Polarion 是 Siemens 的网页版 ALM 平台,用于统一管理需求、开发、测试与发布,并强调端到端可追溯与可见性。
需求管理能力拆解:
自动变更控制:对每条需求的变更进行控制与记录,目标是让审计/合规检查更容易通过。
工作流与审计链:用工作流规则约束需求状态流转,“什么时候能进入下一状态”变成可配置规则,而不是口头约定。
电子签署:支持让干系人对规格文档电子签署(公开资料中明确提及)。
适用场景:大型组织、流程治理成熟或必须提升合规证据链的团队。
局限与避坑建议:
别用它解决“沟通不愿写清楚”:工具能强约束流程,但写清楚仍要靠团队习惯。
先梳理关键工作流再落工具:否则配置会变成一场无止境的“流程之战”。
参考来源:Siemens Polarion 官方介绍页。

NO.12|ReqView(轻量工程 RM)

推荐指数:★★★☆☆
综合得分:78/100
关键优势:产品能力(76)/集成协作(70)/场景适配(78)/治理追溯(85)/交付对齐(72)
核心定位:ReqView 是面向软硬件开发的需求管理工具,强调在 Git 中建立基线,并支持覆盖/风险/变更影响分析与多格式报告输出(Word/Excel/PDF/HTML)。
需求管理能力拆解
文档化需求与基线:对需要交付规格文档、并希望版本可控的团队,Git 基线的概念很贴近工程实践。
追溯与影响分析:强调分析覆盖、风险与变更影响,适合“改一条需求会影响哪里”的场景。
报告输出:可生成 Word/Excel/PDF/HTML 等报告格式,这对交付与审计沟通很友好。
适用场景:硬件/软件协同、系统工程、需要规格文档交付但不想上重型RM套件的团队。
局限与避坑建议
对“产品型需求池”支持较弱:更适合工程规格与追溯,不适合做海量想法收集。
需要团队具备版本管理习惯:否则“基线在Git”会变成少数人才能维护的资产。
参考来源:ReqView 官方产品页。

挑需求管理软件这件事,表面看是功能对比,实际是在选择一种“治理方式”。如果你们最痛的是需求入口分散,先选能把需求池立住的;如果你们最痛的是优先级共识,选能把证据、字段、公式沉淀下来的;如果你们最痛的是变更失控与追责困难,那就把“追溯与影响分析”当作硬指标;如果你们在强合规行业,别怕工具偏重——怕的是你们没有一条可审计的证据链。工具不会替你做决策,但工具会逼你把决策写清楚。当你们愿意把“为什么做、先做什么、变更影响什么、怎么验收”落在系统里,需求管理软件才会从“记录器”变成“协作的共同语言”。

图片
年味愈发醇厚,服务业的 “春运时间” 已正式拉开帷幕。当汹涌人潮涌向全国万千连锁门店,品牌管理者们正面临一场全方位的运营大考:人手告急:客流峰值期店员忙到分身乏术,服务 SOP 执行变形,谁来及时纠偏?安全红线:后厨用火用电需求激增、地面水渍易引发滑倒风险,如何防患于未然?缺货焦虑:年货爆款上架即售罄,人工补货速度追不上顾客扫货节奏,如何破解?百度一见,将多模态视觉技术深度融入春节服务全场景,为连锁门店派驻 “全天候在岗的 AI 店长”,让门店在旺季忙而有序,稳稳斩获新年第一桶金!
图片

管服务:协同无差错,服务有标准

越是人手紧缺,越需要AI来充当“数字化店长”。百度一见可直接复用门店原有摄像头,实时捕捉前端服务全场景,自动识别员工仪容仪表、服务流程规范、出餐时效等关键指标,发现问题即刻推送至店长后台,确保即便在客流峰值,服务标准也始终在线。

人员行为智能提醒:口罩、工帽、围裙等细节,是春节食安管理的关键一环。一见赋予现场摄像头智能查纠能力,自动识别店员穿戴违规行为,及时预警整改。

服务流程量化管理:针对服务合规 “无法量化管理” 痛点,一见将 “菜品按时上桌”“顾客离座及时收台”“员工着装规范” 等环节转化为可量化指标,总部可实时管理全国门店执行情况,实现千家门店服务标准统一管控。

场景适配灵活高效:临时新增 “餐具摆放检查” 或 “新春口罩佩戴识别” 需求?一见支持一句话生成专业级视觉AI应用,完美适配餐饮、零售、茶饮等各类业态门店。 

管安全:风险无死角,运营更安心

门店场景的合规与安全,是春节旺季运营的底线。无论是餐饮门店的后厨卫生、虫害防治,还是零售门店的消防安全、环境整洁,一旦出现问题,不仅会面临监管处罚,还会严重影响品牌口碑,甚至错失旺季客流。一见打破传统人工巡检的局限,打造全天候、无死角的安全监测,让门店守住安全合规底线,安心过年。

守住舌尖上的安全:在食品安全领域,一见能精准识别后厨虫害、生熟食交叉污染、操作台不洁等风险,大幅降低人工巡检的漏判概率,守住顾客“舌尖上的安全”,筑牢品牌信任壁垒。

护航门店平稳运营:在门店环境与安全方面,一见可实时监测消防通道是否畅通、消防设备是否齐全、外部人员是否闯入,及时预警潜在风险,全方位规避安全隐患与合规问题,保障门店春节期间安全、平稳运营。

管物料:库存精准控,损耗降到底

春节期间,连锁门店商品 / 物料需求量暴增,库存周转速度加快,传统人工盘点耗时费力且易出错。百度一见依托多模态大模型技术,打造全自动化 “AI 盘库” 解决方案,革新传统库存管理模式。

智能盘库高效省心自动完成物料消耗盘点,实时同步库存数据,无需员工闭店后熬夜加班,大幅降低人工成本,盘点效率提升 60% 以上。同时结合春节消费趋势,精准预判物料需求,辅助门店提前规划备货,有效避免缺货或库存积压问题。

安全与损耗双重管控:针对零售门店货架管理核心痛点,一见可精准识别商品缺货断档、商品破损、摆放错位、价签不匹配等问题,实现从商品上架陈列、货架实时监测到库存补给的全程可视化管理,让旺季货架管理更精准、库存周转更高效。目前,百度一见已携手餐饮、茶饮、零售等多个行业的头部连锁品牌,实现后厨违规操作降低80%、服务合规率提升40%、库存盘点效率提升60%的显著成效。
立即联系一见,定制专属连锁门店春节运营方案,稳稳拿下全年开门红!
👉https://cloud.baidu.com/survey/yijian-intelligentchainstores....

图片