包含关键字 typecho 的文章

前言

这是笔者之前撰写的一篇专利的技术交底书。现在这份专利已经处于公开阶段,可以免费查阅。不过经常写专利的同学都知道,正式的专利文本往往是很难直接看懂的。于是我在咨询专利接口人确定许可后,决定把我最初的专利交底书公开发表,这就是本文的内容。


本发明的技术关键点(欲保护点)

实现一个游戏助手,可适用于绝大部分对局类游戏,对玩家当前以及下一步的游戏行为和操作进行持续的推荐。

该推荐方案的主要关键技术包含以下几部分:

  • 历史对局记录
  • 对局特征序列生成
  • 实时玩家特征
  • 特征-离线数据匹配
  • 推荐关键帧提取
  • 推荐序列生成
  • 序列的截断和更新
  • 话术转换和播报
  • 推荐关键帧的挖掘

与本发明相近的现有技术

现有技术的技术方案

目前一些手游推出了语音陪伴助手功能,在玩家进行对局游戏的时候,在一旁进行一些语音提示,包括但不限于以下功能:

  • 对玩家进行语言上的激励
  • 讲解一些装备的用法或战术选择
  • 闲聊、活跃气氛

现有技术方案一般是基于一些基础的条件逻辑触发对应的预定义话术,比如以下几种场景:

  • 吃鸡类游戏,当玩家离开飞机机舱跳伞时,播报闲聊话术

    • 如: “哇,救救孩子吧,小几恐高呀~”
  • 吃鸡和 MOBA 类游戏,当玩家拿下首杀时,播报赞赏话术

    • 如: “哇哦~好枪法哦”
  • 吃鸡和 MOBA 类游戏,当玩家装备某武器时,播报武器对应的使用技巧

    • 如: “M16A1 的特点是三发点射,适合搭配三倍镜和消声器使用,中远距离威力很大哦”
  • 较为复杂的:MOBA 类游戏,当敌人均(或者大部分)进入团队视野时,如果本队伍成员不在敌人所在区域时,则播报需要支援的话术

    • 如: “敌人在下路出现了,推荐前去支援”

方案不足

使用预设条件进行触发的方案局限性在于以下几点:

逻辑复杂,投入产出比低

对于一些较为复杂的情况,预设条件方案需要人工预先设定复杂的条件逻辑。一般而言,判断条件越复杂,则越精确、指导意义更高。但是条件越复杂,则人工投入的成本越高,而同时播报概率却更低——之所以播报概率低,是因为需要满足的条件更多、更严苛。因此,对于较为精准的话术场景而言,人力投入产出比较低。

通用性不足

预设条件进行触发的逻辑中,每一个具体场景的工作,换到另一个场景下几乎没有可重用的地方。比如说对于 MOBA 类游戏,针对同一个英雄所设计的预设条件和话术,换到另一个英雄就完全不可复用,需要重新设计;而对于吃鸡类游戏,针对一个地图所设计的预设条件,换到另一个地图,也需要重新投入人力进行分析、设计,重复劳动大。


本技术方案的详细阐述

以下是本技术方案的总体过程图,图中以虚线为界分为上下两部分,上半部分为在线(实时)过程,下半部分为离线过程

220426_图-总体过程图.png

下文首先基于上面的总体过程图,阐述一般性的技术方案,然后再以和平精英为例子,说明一个具体的应用范例。

实时流水数据

为实现本技术方案,我们需要将玩家在游戏对局过程中的各项相关操作、队友/敌人状态变化、对局全局参数变化等事件信息,尽可能快地实时推送出来,供本技术方案所涉及的离线和在线过程进行进一步处理。

离线过程

由于实时过程依赖于离线过程所产生的数据,因此我们首先阐述离线过程方案。

离线数据缓存和清洗

220426_图-总体过程图_01_离线数据缓存和清洗.png

实时流水数据在一整天内有峰值峰谷,不同的时间段内所需的计算资源不同。因此将实时数据尽快缓存下来,将离线过程的算力平摊到全天24小时中,可以大大降低云服务成本。

需要注意的是,实时流水数据在缓存时,需要记录该数据的发生时间,便于离线过程区分事件在整个对局过程中所处的时序位置。

一般而言,实时流水数据是较为全面的数据,在本方法中,针对实时流水数据需要进行初步清洗,这个清洗的过程需要完成以下工作:

  • 将多个不同的实时流水数据,按照对局+用户ID的维度进行区分,同一个 “对局-用户” 的数据聚合为一次完整的对局数据。
  • 聚合了对局数据之后,我们需要决定哪些对局是需要推送到后足进行记录的。记录的原则如下:

    • 该对局是一个较为成功的对局范例,能够对玩家产生有益的指导作用
    • 对局能够尽可能给玩家提供一个完整、序列化的行为模式参考
  • 流水数据一般比较详细和全面,在数据清洗中,需要清除方案中不需要的数据,节省后续的数据存储成本

上面提到,我们将 “对局-用户” 数据聚合成了一次完整的对局数据,针对这个对局数据,我们可以生成一个唯一的对局 ID,在后续的逻辑中用于标识和映射用。

生成用于关键帧提取的特征序列并计算关键帧

1. 序列矩阵生成

220426_图-总体过程图_02_计算关键帧.png

经过上一阶段清洗之后的离线对局数据包含了该玩家在这一个对局中各不同时间段内的具体行为,以及在各时间段和时间点中的对局状态信息。我们需要从这些信息中将所有需要用于判断玩家后续行为模式的数据抽取出来,并将这些数据进行量化。

比如玩家在不同时间点的血量、装备类别和数量、玩家坐标等等信息。这些信息均包含时间属性,因此我们可以以整个完整对局的开始时间点作为原点,组合量化后的所有数据,计算出在每一个时间片中玩家的完整状态信息。每一个已量化的状态信息就是一个列向量。

从对局开始到对局结束的所有时间片所对应的列向量,则从左到右拼接成为一个 m 行、n 列的矩阵,其中 m 等于列向量的维度,n 等于时间片的数量。假设第 n 个时间片列向量表示为 $V_{Kn}$ (V 代表 vector,下标 K 代表 keyframe,M 代表 matrix,下同)即:

$$
M_{K} = M_{m\times n} = \left( V_{K1}, V_{K2}, ..., V_{Kn} \right) =
\begin{bmatrix}
f_{K11} & f_{K12} & ... & f_{K1n} \\
f_{K21} & f_{K22} & ... & f_{K2n} \\
... & ... & ... & ... \\
f_{Km1} & f_{Km2} & ... & f_{Kmn}
\end{bmatrix}
$$

其中 $f_{Kmn}$ (f 代表 feature,下同)表示第 n 个时间片中的第 m 个特征值

2. 关键帧提取

获得了矩阵 $M_K$ 之后,我们可以进行关键帧提取计算。在计算之前,我们首先需要对矩阵进行一次加权计算,以调整不同特征的权重,因为不同特征的重要程度不同(W 表示 weighted,下同):

$$
M_{WK} = W_{K} \times M_{K} = \left( V_{WK1}, V_{WK2}, ..., V_{WKn} \right) =
\begin{bmatrix}
f_{WK11} & f_{WK12} & ... & f_{WK1n} \\
f_{WK21} & f_{WK22} & ... & f_{WK2n} \\
... & ... & ... & ... \\
f_{WKm1} & f_{WKm2} & ... & f_{WKmn}
\end{bmatrix}
$$

其中 $W_{K}$ 是一个 $m\times m$ 的对角矩阵,对角线上的值 $w_{ii}$ 表示每一个列向量 $V_{Kj}$ 中第 $i$ 个特征 $f_{Kij}$ 的权重值。经过上述矩阵乘法,则获得加权后的矩阵 $M_{WK}$

也可以在左乘权重之前,对矩阵以行为单位进行归一化处理。

获得了加权序列矩阵之后,我们从 $i = 2$ 开始,计算 $V_{WKi}$ 与 $V_{WKi-1}$ 两个列向量之间的余弦距离 $d_{WKi}$。将这些距离值以行向量表示,则为:

$$
D_{WK} =
\begin{bmatrix}
0, d_{WK2}, d_{WK3}, ..., d_{WKn}
\end{bmatrix}
$$

由于 $d_{WKi}$ 是标量,因此 $D_{WK}$ 可以表示为一个离散曲线,曲线上的每一个极大值点,就代表一个关键帧,这就是本技术方案中 “关键帧” 的数学含义。在后文的具体例子中我们会看到一个具体的关键帧计算结果。

获得关键帧之后,我们则可以以对局 ID 为唯一键,将关键帧提取结果存储到支持 KV 的缓存系统中,便于后续使用。

3. 关键帧的物理含义

关键帧的数学含义是标量序列中的每一个极大值点,对应到游戏中,则表示基于已选择的特征空间内,玩家行为、游戏进程、对局状态中发生较大变化的点。比如说玩家的位置发生了较大改变、玩家的行为轨迹发生转变、对局进入一个全新的阶段等等。关键帧往往揭示了玩家进行下一步决策的选择,或者是提示了玩家行动的方向。下文我们在举例的时候,可以更加明显地看出来。

生成用于匹配的特征向量序列

220426_图-总体过程图_03_用于匹配的序列.png

经过清洗之后的离线对局数据,除了用于生成用于关键帧提取的特征序列之外,另外一个作用就是用于生成用于匹配的特征向量序列。如何匹配这些特征向量,请参见后文,本小节仅说明生成该特征向量的方法。

类似地,我们需要从对局信息中提取出一系列的特征向量,生成该特征向量的方法与生成用于关键帧提取的特征序列的方法类似,也是生成一个序列矩阵,选取和量化特征向量的方法也类似。

选取这些特征之后,组成的特征向量,主要是为了表征某个对局下的玩家在每一个时间片中所处的状态,用于后续在实时过程中,将实时玩家的状态与某一个历史玩家进行匹配,从而匹配出一条关键帧序列。

生成的特征向量序列,是一个 $p\times q$ 大小的矩阵 $M_{Mp\times q}$(下标 M 代表 match,即 “匹配” 含义):

$$
M_{M} = M_{p\times q} = \left( V_{M1}, V_{M2}, ..., V_{Mq} \right) =
\begin{bmatrix}
f_{M11} & f_{M12} & ... & f_{M1q} \\
f_{M21} & f_{M22} & ... & f_{M2q} \\
... & ... & ... & ... \\
f_{Mp1} & f_{Mp2} & ... & f_{Mpq}
\end{bmatrix}
$$

其中 $V_{Mq}$ 表示时间片 q 所对应的特征向量,$f_{Mpq}$ 表示第 q 个时间片中的第 p 个特征值。 $M_{M}$ 针对时间片粒度的选择与 $M_{K}$ 可以相同也可以不同,完全取决于游戏时长、性能、游戏典型决策时间等要素进行折中选择。

得到 $M_{M}$ 之后,也需要按照实际需要,进行加权操作。但这一步就没有必要进行归一化了。加权之后的特征向量序列为:

$$
M_{WM} = W_{M}\times M_{M} =
\begin{bmatrix}
f_{WM11} & f_{WM12} & ... & f_{WM1q} \\
f_{WM21} & f_{WM22} & ... & f_{WM2q} \\
... & ... & ... & ... \\
f_{WMp1} & f_{WMp2} & ... & f_{WMpq}
\end{bmatrix}
$$

我们可以将每一个 $V_{M}$ 存入向量匹配引擎,同时在存入引擎的时候,也应将对局 ID 作为向量的属性一并存入,这样在匹配到向量之后,就可以与对局 ID 所对应的关键帧关联起来。

虽然量化特征的方法类似,但与生成用于关键帧提取的特征的选取原则上略有差异,这主要是两者的取向不同:

  1. 用于关键帧提取的序列中,偏向于记录玩家的具体行为,状态信息辅之,主要是用于区分关键帧所处的阶段用
  2. 用于匹配的特征向量中,更多地考量的是玩家所处的状态,因此对于一些的具体行为,则不一定要纳入特征向量中

举个例子,在用于关键帧提取的序列中,“历史玩家击杀了敌人” 这是一个具体行为,可能会影响关键帧的计算,并且进一步影响对在线玩家的提示逻辑,因此这个事件需要纳入并且用于关键帧计算中。但是在用于匹配的特征向量中,“当前玩家击杀了敌人” 作为行为而言,就可以无需纳入特征向量的取值考量,因为用于匹配的特征向量更加重视状态,而玩家当前具体做了什么操作,只是一个时间点的事件,而不是一个有较强持续特性的状态。

当然了,如果更换一个角度,也可能有一些属性是适合纳入用于匹配的特征向量,而无需纳入关键帧提取的,比如 “玩家截至指定时间为止击杀了5个敌人”,这就很明显是一个状态信息,可以考虑纳入用于匹配的特征向量序列中;但是这又很明显不是一种行为,充其量只能从侧面体现出玩家的风格、偏好、技术等等辅助信息,因此不会计入关键帧计算的范畴中

此外,用于特征向量的序列中,相比起用于关键帧计算的序列中,可能还包含一些纯辅助用的特殊特征值,这些特征值主要是根据向量匹配引擎所能提供的功能有关。关于这一点,请参见后文示例中的 “对局时间” 特征的选取原因。

实时(在线)过程

总体架构图的上半部分表示在线(实时)过程。本源上,离线和在线过程使用的数据源是一样的,都是玩家真实进行过的操作以及真实对局的其他一些状态变化,因此架构图中绘制的数据源均为 “实时流水数据”。

与离线过程不同,在线过程需要尽可能快地根据玩家信息或对局状态作出响应,因此在线过程并不会将实时流水数据进行缓存后再操作,而是获取了实时流水数据之后立刻进行数据清洗。

在线数据清洗

220426_图-总体过程图_04_在线数据清洗.png

数据清洗的目的是将对局状态的特征向量化,这个向量也即等于当前玩家、当前对局、当前时间片的特征向量,并且需要保证该特征向量生成的算法和结构与前文 ”生成用于匹配的特征向量序列“ 完全相同,并且对于时间片粒度的选择,也应当与 $M_{M}$ 完全相同。对于实时对局中,指定时间片 $t$ 所对应的玩家特征向量,我们记为 $V_{Rt}$,其中 R 表示 real-time,特征向量的维度与 $V_M$ 相同:

$$
V_{Rt} =
\begin{bmatrix}
f_{R1t} & f_{R2t} & ... & f_{Rpt}
\end{bmatrix}^{T}
$$

由于在线过程是事件驱动的逻辑,单一的事件无法完全表征玩家的对局状态,也不足以构建对局状态的特征向量,因此在在线过程中,也需要将之前计算出来的对局状态数据进行必要的缓存。在新的对局事件到达时,在线逻辑应当结合对局状态缓存和事件详情,综合计算出当前时间片的对局状态特征向量。

匹配历史对局

“当前关键帧是否有效” 和 “需要更新关键帧” 阶段的判定逻辑,与后续逻辑直接相关,因此我们暂时先跳过这个阶段,首先讲解后续逻辑之后再返回来说明。

220426_图-总体过程图_05_匹配历史对局.png

在获取了当前时间片的对局状态特征向量 $V_{Ri}$ 之后,在这一阶段,这个特征向量也应与离线的特征向量矩阵 $M_M$ 左乘上完全相同的权重:

$$
V_{WRt} = W_M\times V_{Rt} =
\begin{bmatrix}
f_{WR1t} & f_{WR2t} & ... & f_{WRpt}
\end{bmatrix}^{T}
$$

我们可以使用 $V_{WRt}$ 在向量匹配引擎中进行匹配。匹配的原则是向量相似度,根据特征向量的选取原则,主要考虑使用余弦相似度和欧几里得距离两种算法:

  • 当选取的特征向量具体值,包含玩家所处位置坐标信息,并且这些信息难以进行方向化的编码时(比如坐标 <10, 20> 与 <20, 40> 视为完全不同的值),则需要采取欧几里得距离
  • 当选取的特征向量包含的都是玩家的转向、战术取向等在数学意义上偏 “方向” 性的操作,那么可以采用余弦距离

匹配的时候还需要包含以下限制:

  • 仅匹配与当前时间片相同的历史特征向量,也即对于每一个 $t = i$ 的 $V_{WRi}$,限定匹配 $V_{WMi}$。
  • 其他与游戏相关的限制,比如说对于吃鸡类游戏,不同的对局可能采用了不用的地图,因此必须限定匹配范围,仅在该地图所对应的对局范围中进行匹配。

匹配虽然首先采纳向量相似度优先原则,但也可以多匹配数个或数十个特征向量,也即多匹配一些历史对局,然后从符合条件的结果中进行一定的随机选取,以提高随机性和多样性。

获取和选择关键帧

220426_图-总体过程图_06_获取和选择关键帧.png

1. 获取关键帧序列详情

匹配到了一个历史特征向量之后,由于在特征向量的附加属性中包含了对局 ID,因此可以循此对局 ID 在 KV 缓存中获取到指定对局 ID 中已经在离线阶段中计算出来的所有关键帧数据。

获取了关键帧数据后,下一步的逻辑就是从关键帧中选取出后续需要推送给实时玩家的一个或多个关键帧。

2. 关键帧序列的截断

由于关键帧是包含了时间片属性的,时间片的定义,指的是相对于对局开始的时间偏移量。我们获取历史对局的关键帧列表之后,我们可以把所有的关键帧按时间片排序之后,分为两类:

  • “过去” 了的关键帧:指的是时间片值小于或等于当前实时对局所处的时间片。这些关键帧类比到当前对局中,可以视为已经 “发生过了”,或者是 “以前” 的关键帧,这些关键帧对当前玩家来说没有推荐意义
  • “将来” 的关键帧:指的是时间片值大于当前实时对局所处的时间片。这种关键帧表征了未来可能发生的事件,或者是未来推荐玩家进行的操作,因此对玩家有推荐意义

选取关键帧的步骤,第一步是删除所有 “过去” 了的关键帧,因为这些关键帧在当前对局来说没有保存的意义。

第二步是要对 “将来” 的关键帧序列,做一个 “截断逻辑”。截断逻辑的效果,是去除 “将来” 某个时间片之后的关键帧。抛弃的原因如下:

关键帧序列所代表的一个历史玩家的行为,是一条已经发生了的、确定的时间线。但是当前对局中的用户,ta 将来的行为,是一个尚未发生的、不确定的时间线。我们基于一条历史的时间线给现实玩家进行推荐,那么玩家在未来可能会遇到以下几种需要重新推荐关键帧的情况:

  1. 不跟随推荐的关键帧进行实际行动——在这种情况下,我们需要考虑给玩家推荐另外一条关键帧序列
  2. 跟随推荐的关键帧进行下一步行动。那么当玩家进行或完成了下一个关键帧中所列举的行为时,可能会有以下两种情况

    • 2.1 - 玩家决定不跟随推荐的关键帧,而是进行别的选择,这个时候我们回到 1,也即需要考虑推荐另外一条关键帧序列
    • 2.2 - 玩家虽然继续按照关键帧行动,但是对局环境发生了较大变化,以至于当前关键帧已经不再适应对局的情况,需要考虑重新推荐

针对情况 1 和 2.1,这属于我们前文跳过的 “当前关键帧是否有效” 和 “需要更新关键帧” 阶段逻辑,请参见下文。而针对情况 2.2,我们需要考虑的是:在玩家这条已选择的历史路线(关键帧序列)行动的前提下,这条路线到什么时间片为止,依然是适合玩家当前状态的;而到了什么时间片之后,即便玩家按照推荐采取行动,我们也应该重新给玩家匹配一条的关键帧序列。这一标准的选择因不同的游戏而异,也因应不同的游戏特性会有不同的算法。当然,也有可能完全不做 “将来” 的关键帧的截断,而完完全全地将关键帧更新的逻辑放在 “当前关键帧是否有效” 和 “需要更新关键帧” 阶段中。

3. 关键帧缓存

获得了截断后的关键帧,我们也需要缓存下来,便于下一个事件到来时的在线过程的迭代。

关键帧序列的刷新

220426_图-总体过程图_07_关键帧刷新.png

说明了后续的关键帧匹配逻辑之后,我们回过头来说明这一步在之前被跳过的逻辑。这两步逻辑决定了当前事件到来时,主逻辑是否需要继续往下持续到 “向玩家展示” 的步骤。

从示意图上我们可以看到,当事件到来时,更新了对局状态缓存之后,我们首先判断一下当前关键帧序列是否有效,如果关键帧序列已经无效了,那么直接开始匹配历史对局。显然,如果当前对局从来没有匹配过关键帧(推荐关键帧缓存为空),这显然是需要刷新关键帧序列的。

而第二个判断是判断当前玩家是否已经完成当前已推荐的关键帧,如果未完成,那么当前事件逻辑结束,等待下一次事件驱动;如果已经完成了,那么进入到下一个阶段的检查。

下一阶段是检查是否前进到下一个关键帧。当玩家已经完成当前关键帧的时候进行该阶段检查。如果需要前进到下一个关键帧,那么就将当前推荐的关键帧视为 “过去” 了的关键帧进行截断之后,推荐紧接着的下一个关键帧,如果不需要,那么也一样,结束当前事件逻辑,等待下一次事件。

1. 判断当前关键帧序列有效

判断当前关键帧序列,主要是进行以下条件的判断:

  • 如果之前没有成功推荐过关键帧(关键帧缓存为空),那么显然需要刷新关键帧序列
  • 关键帧是带时间片属性的,如果玩家行动的进度相比关键帧而言明显落后时,需要考虑刷新关键帧序列

    • 比如从关键帧的角度,玩家应该在1分钟前就已经到达了某地,但是从目前玩家的状态来看,玩家最快也要3分钟才能到达,那么明显我们需要重新匹配
  • 如果玩家的行为明显偏离关键帧所推荐的行为模式,那么有必要重新匹配关键帧序列。

    • 比如推荐玩家往西北方向1000米移动,但是从推荐开始后,玩家往东南方向移动了1500米,这明显就偏离了关键帧的路线。
  • 如果发生了重大事件,导致之前匹配到的关键帧明显不合适,或者是大概率不再合适时,那么这个时候需要考虑刷新关键帧序列

    • 比如对于 MOBA 类游戏,之前推荐的关键帧是基于上、中、下路的塔防均完整的情况下进行的推荐,但现在其中一个塔被摧毁了,那么需要考虑重新匹配关键帧,采用新的战术。

2. 判断当前关键帧是否已实现

这一阶段主要是判断实时玩家的操作是否已经完成了关键帧中所指定的行为或目标,判断标准也因游戏而异。比如说玩家是否已经到达了目的地,或者是玩家已经将血量补满,或者是玩家已经击杀了指定目标等等。

3. 判断是否前进到下一个关键帧

当推荐关键帧序列中有下一个关键帧时,那么我们可以将当前关键帧截掉,并且将下一个关键帧推荐给用户。

如果没有下一个关键帧时,我们可以分两种情况来处理

  • 如果可遇见下一个重大事件节点非常近时,那么即便没有下一关键帧,我们依然无需重新推荐,而是等待下一个重大事件到来的时候,自然会触发新的匹配过程
  • 也可以简单删除关键帧缓存,触发下一个事件迭代过程时的关键帧匹配过程。

向玩家提示

当获得关键帧之后,我们即可以按照关键帧所代表的物理含义,或者说是所代表的在游戏中的操作,将关键帧的信息向玩家提示。提示方式不限,可以通过地图标注、语音提示、文字提示等等方式,给玩家进行提示。提示的具体手段不属于本专利的关注范围。


应用举例

实时流水数据

以和平精英为例,在进行整个系统方案的设计和开发之前,我们首先需要决定一个玩家在一个对局中的哪些信息是需要记录的。

原则上,尽可能多地包含本技术方案所需要的对局信息,包括但不限于玩家在对局的不同时刻下的以下信息:

  • 玩家在所处的位置
  • 玩家血量
  • 玩家行为
  • 玩家能观测到的对手的状态
  • 玩家装备信息等附属属性
  • 其他会影响玩家决策的游戏全局信息

按照上述的分类,我们可以采集玩家在不同时刻的以下信息:

信息说明举例
玩家位置玩家在游戏开始之后各时刻所在的地点的地图坐标
玩家血量玩家在各时刻的血量变化
玩家行为在和平精英中,需要统计的玩家行为包括: <br/>- 搜刮地面散落的物资,如果必要的话还需要统计玩家搜刮的一些关键物品信息,如枪支、子弹、血包等<br/>- 向敌人开火,如果命中敌人的话,还包括命中敌人与玩家本身的距离信息<br/>- 驾驶车辆(可通过上车/下车区分玩家是步行还是乘车移动)
对手状态玩家能观测到的对手的状态- 玩家视野中发现敌人,以及敌人的距离<br/>- 小地图上显示敌人脚步、枪声等信息。在和平精英中,这些信息还包含估算距离信息
玩家其他信息玩家装备信息等附属属性- 玩家装备的头盔级别(无则表示为0)、护甲级别(无则表示为0)<br/>- 玩家装备的突击步枪、冲锋枪、霰弹枪、机枪、手枪的数量<br/>- 玩家的子弹数量<br/>- 玩家的血包数量
其他信息其他会影响玩家决策的游戏全局信息- 对局的地图 ID<br/>- 不同时刻的信号区中心点和半径

当然,在实际操作中,统计信息也可以由简到繁,这也对应着一个方案从简到繁的迭代过程,因为该技术方案的另一个优点,就是不需要一开始就完成最终版,而可以随着游戏进展和社区/玩家反馈进行逐步迭代,在服务器性能与玩家体验之间逐步寻找平衡点。

还是以和平精英为例子,上述对局信息可以在早期进行简化,只记录以下信息(信息的减少并不会影响整体技术方案的完整性):

  • 对局的地图 ID
  • 玩家在游戏开始之后各时刻所在的地点的地图坐标
  • 不同时刻的信号区中心点和半径
  • 玩家装备的头盔级别(无则表示为0)、护甲级别(无则表示为0)
  • 玩家装备的突击步枪、冲锋枪、霰弹枪、机枪、手枪的数量
  • 小地图上显示敌人脚步、枪声等信息。这记录为遭遇敌人
  • 玩家搜刮地面散落的物资行为的时刻
  • 向敌人开火的时刻
  • 驾驶车辆的时刻

上述数据的格式可以以简单格式进行初步记录数据表如下:

时刻 (秒)事件类型事件值
0地图 ID01
60玩家位置(586029, 285103)
68搜刮物资
68拾取手枪1
65玩家位置(586140, 285072)
68搜刮物资
68拾取冲锋枪1
70搜刮物资
70拾取霰弹枪1
71搜刮物资
72拾取突击步枪1
72丢弃霰弹枪1
75遭遇敌人
75玩家位置(582271, 287956)
80遭遇敌人
81开火
81玩家位置(582395, 287003)
83开火
87玩家位置(582627, 287037)
95开火
100上车
112玩家位置(581480, 287175)
120信号区位置(285610, 673190)
122玩家位置(590850, 287164)
.........

从上述的记录中,我们可以看到玩家从游戏开始后一小段时间的对局信息为:

  • 玩家从坐标 (586029, 285103) 开始游戏
  • 玩家在游戏开始之后当即在当地进行物资的搜刮,并且装备手枪与突击步枪各一
  • 玩家在搜刮物资的时候,发现了敌人,并且开火攻击
  • 玩家在开局后100秒的时候乘坐载具,并且开始转移
  • 开局2分钟的时候,信号区刷新
  • ……

离线过程

样本数据选取

吃鸡类游戏的特点是每一局至少有一名玩家生存到最后;虽然和平精英也推出过复活/召回机制,让被击杀的玩家也有机会返回比赛,但是该对局的最终获胜者也依然大概率是所谓 “一命通关” 的,因此我们可以简单地按照以下原则进行选取:

  • 存活到最后的玩家
  • 玩家段位比较高

这种情况下,一方面这是一个成功 “吃鸡” 对局,是一个好的范例;另一方面,由于玩家在整个对局中没有死亡过,因此整个序列非常完整。

而对于在整个对局中频繁出现死亡/复活事件的游戏模式(如王者荣耀),则选取标准可以参考以下原则:

  • 玩家是当局 MVP
  • 玩家段位比较高
  • 玩家死亡次数较少

前两个原则很好理解,最后一个原则主要是考虑能够尽可能产生出时间较长的行为序列。可以参考后文 ”序列的截断和更新“。

生成对局特征序列

获得了历史对局记录之后,针对每一个对局,我们需要将列表化的数据,进行建模,转换为数字化的、便于计算机处理的数据。

为节省数据存储空间以及提高计算效率,我们可以对对局数据进行进一步的简化。如果认为不必要简化的话,这一步也可以跳过。

以上文完成了 “初步记录” 的数据表为例:首先我们可以发现,表中的玩家位置数据信息比较多,但是玩家的移动范围可能比较小。在这种情况下,我们可以降低玩家位置信息的精度,只取十万和万位。

其次,我们仅记录玩家的状态变化数据。这样,上文的数据表,我们可以进一步简化为:

时刻 (秒)事件类型事件值
0地图 ID01
60玩家位置(58, 38)
68搜刮物资
68装备变化手枪+1
68搜刮物资
68装备变化冲锋枪+1
70搜刮物资
70装备变化霰弹枪+1
71搜刮物资
72装备变化突击步枪+1, 霰弹枪-1
75遭遇敌人
80遭遇敌人
81开火
83开火
95开火
100上车
120信号区位置(28, 67)
122玩家位置(59, 28)

生成用于关键帧提取的特征序列

上文历史对局数据表的第二个作用是生成用于关键帧提取的特征序列。该序列具体作用,依然是在后面再做说明,本小节说明如何使用这些数据生成用于关键帧提取的特征序列

1. 选定需要量化的状态特征

用于关键帧提取的特征序列,以及用于匹配的特征序列两者,可以是相同的,也可以是根据实际需要有所不同。比如在匹配中,包含了玩家的装备信息;而在用于关键帧提取的特征序列中,可能并不需要这些信息,那么我们在生成序列的时候,可以不包含这些信息。

在大部分情况下,用于关键帧提取的特征序列,比用于匹配的特征序列维度要小,因为后者的目的是为了尽量找到一个与实时玩家当前对局状态接近的历史对局,为了提升匹配效果和准确度,用于匹配的特征应尽可能完备;而前者是直接服务于话术生成的,如果某些特征对生成AI话术没有帮助,那么可以忽略相应的特征值。比如在用于匹配的特征中,包含了玩家装备的枪支信息;但是在生成话术中,如果没有计划针对枪支装备进行说明,因此我们可以无需将枪支信息纳入特征序列中。

反之亦然,允许部分特征信息在关键帧特征序列中是存在的,而在状态特征序列中不存在,完全视乎特征而定。

2. 状态特征量化

用于关键帧提取的状态特征量化方法,与用于匹配的状态特征量化方法相同,这里就不再赘述。

举例说明我们可能只选取玩家位置、各信号区信息、遭遇敌人的时刻、交火的时刻等数据,那么我们可以将前文的一个对局,以 JSON 的形式进一步进行简化,如以下格式为例,这是某位玩家一次完整的对局信息:

{"drive":[476,479,482,485,488,490,493,497,500,502,505,508,511,513,516,518,522,525,528,532,535,537,541,545,548,551,553,557,559,561,564,566,570,572,576,579,791,794,798,800,804,806,810,813,816,819,823,826,830,833,836,838,842,845,849,851,853,856,859,862,865,868,871,874,878,882,884,887,890,893,896,898,901,904,907,910,913,915,919,921,923,926,930,934,937,941,944,947,951,955,959,962,965,968,971,975,978,980,983,986,990,992,995,998,1000,1003,1006,1009,1013,1015,1018,1021,1026,1067,1069,1073,1075,1078,1081,1085,1089,1092,1096,1099,1103,1106,1108,1111,1116,1119,1122,1125,1128,1131,1134,1136,1139,1141,1144,1147,1150,1153,1156,1158,1161,1164,1166,1169,1173,1176,1348,1352,1356,1359,1362,1364,1368,1371,1373,1376,1380,1382,1386,1389,1392,1396,1398,1400,1402,1406,1409,1411,1413,1426,1430,1434,1438,1440,1443,1447,1450,1452,1456,1458,1461,1463,1466,1469,1472,1474,1479,1482,1484,1486,1489],"shoot":[154,156,157,1034,1054,1189,1191,1292,1736,1739,1760,1792,1820,1830,1926,1950,1952,1963,1964,1974,1975,1979],"robbery":[0,0,0,0,99,100,121,122,123,124,128,132,134,135,145,145,146,148,168,172,176,177,178,179,180,181,181,182,186,187,207,216,239,244,245,257,258,261,271,271,272,280,282,292,295,307,321,322,326,1506,1750,1753,1756,1766,1773,1786,1803,1863,1870,1894],"skirmish":[153,153,154,155,156,181,186,199,200,202,302,304,304,305,305,306,666,666,668,669,672,675,676,676,713,713,713,714,715,716,717,720,722,837,839,1024,1024,1027,1028,1056,1062,1074,1155,1156,1157,1159,1171,1171,1172,1173,1173,1174,1185,1187,1197,1206,1211,1212,1213,1214,1215,1239,1246,1247,1248,1248,1249,1250,1252,1252,1252,1253,1254,1255,1256,1256,1257,1258,1259,1259,1260,1260,1261,1262,1263,1264,1265,1265,1266,1267,1269,1269,1270,1279,1279,1281,1281,1283,1283,1285,1286,1287,1288,1289,1290,1290,1291,1291,1292,1293,1302,1303,1304,1305,1306,1315,1316,1317,1318,1320,1321,1323,1324,1324,1326,1347,1348,1349,1350,1350,1350,1351,1351,1351,1352,1353,1353,1353,1354,1354,1403,1404,1406,1523,1526,1527,1682,1685,1702,1711,1717,1733,1747,1756,1758,1762,1773,1781,1809,1825,1828,1829,1829,1829,1829,1835,1836,1837,1838,1838,1838,1838,1838,1841,1841,1841,1842,1842,1876,1876,1877,1878,1878,1879,1880,1912,1926,1926,1960,1962,1962,1969,1970,1971,1972,1972,1973,1973,1973,1973,1974,1974,1980],"zones":[{"xy":[69,34],"t":94},{"xy":[70,34],"t":99},{"xy":[70,33],"t":114},{"xy":[71,32],"t":153},{"xy":[70,32],"t":160},{"xy":[71,32],"t":164},{"xy":[70,32],"t":168},{"xy":[71,32],"t":173},{"xy":[70,32],"t":236},{"xy":[71,32],"t":237},{"xy":[70,32],"t":243},{"xy":[70,31],"t":244},{"xy":[70,32],"t":245},{"xy":[70,31],"t":246},{"xy":[70,32],"t":254},{"xy":[70,31],"t":279},{"xy":[70,32],"t":283},{"xy":[70,31],"t":287},{"xy":[69,31],"t":306},{"xy":[69,32],"t":317},{"xy":[70,32],"t":328},{"xy":[70,33],"t":344},{"xy":[69,33],"t":351},{"xy":[69,34],"t":376},{"xy":[68,34],"t":390},{"xy":[68,35],"t":398},{"xy":[67,35],"t":416},{"xy":[66,34],"t":446},{"xy":[65,34],"t":475},{"xy":[66,35],"t":482},{"xy":[67,35],"t":488},{"xy":[68,35],"t":490},{"xy":[67,35],"t":505},{"xy":[67,34],"t":508},{"xy":[66,34],"t":511},{"xy":[65,34],"t":516},{"xy":[65,33],"t":518},{"xy":[64,34],"t":522},{"xy":[63,34],"t":525},{"xy":[62,34],"t":535},{"xy":[61,34],"t":545},{"xy":[60,34],"t":548},{"xy":[59,33],"t":551},{"xy":[58,33],"t":553},{"xy":[57,33],"t":557},{"xy":[57,32],"t":559},{"xy":[56,32],"t":561},{"xy":[55,32],"t":566},{"xy":[54,31],"t":570},{"xy":[53,31],"t":572},{"xy":[53,32],"t":804},{"xy":[52,32],"t":806},{"xy":[51,32],"t":810},{"xy":[50,32],"t":813},{"xy":[49,31],"t":816},{"xy":[48,31],"t":819},{"xy":[48,30],"t":823},{"xy":[47,29],"t":826},{"xy":[47,28],"t":830},{"xy":[48,28],"t":833},{"xy":[48,27],"t":836},{"xy":[49,27],"t":845},{"xy":[48,26],"t":882},{"xy":[47,26],"t":887},{"xy":[47,25],"t":890},{"xy":[47,24],"t":893},{"xy":[46,23],"t":898},{"xy":[45,23],"t":901},{"xy":[44,23],"t":904},{"xy":[43,22],"t":910},{"xy":[42,22],"t":913},{"xy":[41,21],"t":915},{"xy":[40,21],"t":919},{"xy":[39,21],"t":921},{"xy":[39,22],"t":923},{"xy":[38,21],"t":926},{"xy":[37,21],"t":930},{"xy":[35,21],"t":934},{"xy":[35,20],"t":937},{"xy":[34,20],"t":941},{"xy":[34,19],"t":944},{"xy":[34,18],"t":951},{"xy":[33,18],"t":962},{"xy":[32,18],"t":968},{"xy":[31,19],"t":971},{"xy":[30,19],"t":975},{"xy":[29,19],"t":978},{"xy":[29,20],"t":990},{"xy":[28,20],"t":992},{"xy":[27,21],"t":995},{"xy":[26,21],"t":998},{"xy":[25,21],"t":1000},{"xy":[24,22],"t":1013},{"xy":[23,22],"t":1015},{"xy":[23,23],"t":1018},{"xy":[24,23],"t":1026},{"xy":[24,24],"t":1032},{"xy":[25,24],"t":1089},{"xy":[25,25],"t":1092},{"xy":[26,25],"t":1096},{"xy":[27,25],"t":1099},{"xy":[27,26],"t":1111},{"xy":[27,27],"t":1116},{"xy":[26,27],"t":1119},{"xy":[26,28],"t":1122},{"xy":[26,29],"t":1125},{"xy":[27,30],"t":1128},{"xy":[27,31],"t":1131},{"xy":[26,32],"t":1134},{"xy":[26,33],"t":1136},{"xy":[25,33],"t":1139},{"xy":[25,34],"t":1141},{"xy":[24,34],"t":1144},{"xy":[23,35],"t":1147},{"xy":[22,35],"t":1150},{"xy":[21,36],"t":1153},{"xy":[21,37],"t":1156},{"xy":[20,37],"t":1158},{"xy":[20,36],"t":1161},{"xy":[19,36],"t":1164},{"xy":[18,35],"t":1169},{"xy":[17,34],"t":1173},{"xy":[16,34],"t":1176},{"xy":[16,33],"t":1181},{"xy":[16,34],"t":1386},{"xy":[17,34],"t":1389},{"xy":[17,35],"t":1392},{"xy":[17,36],"t":1396},{"xy":[17,37],"t":1402},{"xy":[18,37],"t":1406},{"xy":[18,38],"t":1409},{"xy":[19,38],"t":1413},{"xy":[19,39],"t":1419},{"xy":[19,40],"t":1450},{"xy":[20,40],"t":1452},{"xy":[21,40],"t":1456},{"xy":[21,39],"t":1458},{"xy":[22,39],"t":1461},{"xy":[23,40],"t":1469},{"xy":[22,40],"t":1474},{"xy":[22,39],"t":1484}],"safe_zones":[{"center":{"x":297799.5,"y":253278.5},"radius":254520,"sec":120},{"center":{"x":261669.39,"y":294625.9},"radius":165438,"sec":720},{"center":{"x":235103.33,"y":365767.5},"radius":82719,"sec":1060},{"center":{"x":237436.88,"y":364939.44},"radius":41359,"sec":1300},{"center":{"x":231202.84,"y":381825.4},"radius":20679,"sec":1480},{"center":{"x":226598.3,"y":390148.88},"radius":10339,"sec":1640},{"center":{"x":223320.33,"y":393406.94},"radius":5169,"sec":1760},{"center":{"x":223549.69,"y":394897.2},"radius":2584,"sec":1880}]}

这段数据包含了玩家从游戏开始之后的以下信息:

  • 有开车(或者坐车转移)事件的时间点列表
  • 有搜刮事件的时间点
  • 有开枪事件的时间点
  • 有小地图事件的时间点(代表遇到敌人)
  • 不同时间点玩家所处位置(精确到小格子)
  • 信号区中心、半径、时间信息

各时间点单位均为秒。

数据看起来非常抽象,我们可以将数据可视化。同样地,我们把开车、战斗、遭遇、搜刮事件次数,以及玩家所在位置的变化值,以10秒为单位,计算该10秒内所对应的列向量。列向量包含五个维度的数据,分别为:

  • 开车: 10秒内开车事件的个数
  • 战斗: 10秒内开火事件的个数
  • 遭遇: 10秒内遭遇敌人事件的个数
  • 搜刮: 10秒内搜刮行为的个数
  • 转移: 玩家位置发生变化的距离(除以10000)

由于该对局最后一个事件的时间为 1980 秒,也就是 33 分钟,除以 10,可以得到 199 个分片(包括 t=0 的情况),每个分片对应一个列向量。这 199 个列向量即组成一个 5行、199列的矩阵。

矩阵可视化如下,可以大致看出事件分布的情况:

220426_序列图.png
220426_序列图_图例.png

我们可以基于上述数据,构建玩家在每一个10秒分片中的状态数据。参见前文 “用于匹配的特征序列” 的 “状态特征量化” 小节,我们以类似的方法将上述六个信息,按顺序进行以下量化:

序号说明
1开车事件数
2搜刮事件数
3开枪事件数
4遭遇事件数
5玩家位置X坐标值,精确到100米
6玩家位置Y坐标值,精确到100米

其中信号区信息不列入特征中,仅做辅助参考。

由于该对局最后一个事件的时间为 1980 秒,也就是 33 分钟,除以 10,可以得到 199 个分片(包括 t=0 的情况),每个分片对应一个列向量。这 199 个列向量即组成一个 6行、199列的矩阵。

$$
M_{keyframe} =
\begin{bmatrix}
0 & 0 & ... & 1 & 0 & ... & 0 \\
0 & 0 & ... & 0 & 1 & ... & 10 \\
0 & 0 & ... & 0 & 1 & ... & 5 \\
0 & 0 & ... & 5 & 3 & ... & 0 \\
0 & 0 & ... & 69 & 34 & ... & 22 \\
0 & 0 & ... & 69 & 34 & ... & 39
\end{bmatrix}
$$

关键帧提取

1. 计算差分序列

在前文生成了 “关键帧提取的特征序列” 之后,我们可以知道,这个特征序列实际上是一个 6xn 的矩阵,其中 n = 对局总秒数/10+1。在本例中,我们使用余弦距离计算差分序列 $D_{WK}$,并进行 0-1 归一化后,作折线图大致如下:

220223_夹角.png

肉眼可见 $\vec d$ 中有数个明显的极大值,但仍存在不少抖动,不方便程序进行提取。过滤掉较低的夹角值(< 0.3),再作三阶高斯模糊后,得到较为平缓的曲线如下:

220223_高斯模糊后.png

得到明显的极大值点,这些极大值点代表了历史玩家行为发生较大变化的点,我们将这些时间点对应的 $\vec m_j$ 定义为关键帧。

将关键帧所处的位置,结合当前玩家的移动路径和信号圈变化,可以直观地在图上标记:

220223_brett_移动路径.png

  • 红色是玩家实际移动路径
  • 绿色是信号圈和信号圈中心移动
  • 白色是关键帧所在的点和推荐转移路径

2. 关键帧的物理含义

具体查询前文的矩阵 $M_{keyframe}$,计算 $d_{WKj}$ 与 $d_{WKj-1}$ 的特征差异,由于 $d_{WK}$ 的维度很低且每一维度的含义非常明确,因此我们可以很简单地将该关键帧所表征的事件转换为词组的组合,可以看到关键帧所表征的物理含义:

  0 -  1m30s (  90): 搜刮 | 移动,           location: 70_34
  1 -  2m40s ( 160): 搜刮 | 移动,           location: 70_32
  2 -  5m20s ( 320): 搜刮 | 移动,           location: 70_32
  3 -   8m0s ( 480): 上车 | 移动,           location: 67_35
  4 -  8m30s ( 510): 上车 | 移动,           location: 65_33
  5 -  9m30s ( 570): 上车 | 移动,           location: 53_31
  6 - 11m50s ( 710): 遭遇敌人,              location: 53_31
  7 - 13m40s ( 820): 下车 | 移动,           location: 47_29
  8 - 15m10s ( 910): 上车 | 移动,           location: 40_21
  9 -  17m0s (1020): 下车 | 遭遇敌人 | 移动, location: 24_23
 10 - 17m40s (1060): 上车 | 遭遇敌人,        location: 24_24
 11 - 19m30s (1170): 下车 | 遭遇敌人 | 移动, location: 16_34
 12 - 22m40s (1360): 上车,                 location: 16_33
 13 - 23m20s (1400): 上车 | 遭遇敌人 | 移动, location: 18_38
 14 - 24m50s (1490): 下车 | 移动,           location: 22_39
 15 -  29m0s (1740): 遭遇敌人,              location: 22_39
 16 - 30m20s (1820): 战斗 | 搜刮结束 | 遭遇敌人, location: 22_39

3. 生成用于匹配的特征向量序列

参照前文清洗离线数据的方案,我们也可以计算出用于匹配的特征,与关键帧所需的维度不同,为了能够更加准确地匹配到一个历史玩家,我们可以提取历史事件中的信息,同样划分为以10秒为单位的时间片,使用以下16个数据组成一个特征向量:

序号说明
1地图 ID
2对局开始时间 (秒数) / 10
3信号区中心X坐标值,精确到100米,即 0~79,0 代表没有信号区
4信号区中心Y坐标值,精确到100米,即 0~79,0 代表没有信号区
5玩家位置X坐标值,精确到100米,即 0~79
6玩家位置Y坐标值,精确到100米,即 0~79
7玩家在这10秒内是否驾驶车辆,0代表无,1代表有
8玩家装备的狙击枪数
9玩家装备的精确射手步枪数
10玩家装备的突击步枪数
11玩家装备的冲锋枪数
12玩家装备的霰弹枪数
13玩家装备的机枪数
14玩家装备的手枪数
15玩家装备的头盔级别,0~3,0代表无头盔,1~3分别代表一至三级头
16玩家装备的防弹衣级别,0~3,0代表无,1~3分别代表一至三级甲

从时刻 0 到结束时刻 1980 秒(上例),按照 10 秒一个时间片划分,总共 198 个特征向量。可将特征向量进行加权后写入特征匹配引擎中。权重的选取请参见下一节。

实时(在线)过程

在线数据清洗

在实时对局中,客户端在实现玩家对局逻辑功能的同时,也将对局情况打包成一个个的事件(参见 “实时流水数据”)发送到路径推荐后台服务器上。这些事件是增量事件(也即表示这些事件表征玩家状态变化,而不是玩家状态本身),后台服务器组合这些增量事件,可以计算并更新玩家和对局状态,从而计算获得玩家的实时特征,格式与离线算出的 “用于匹配的特征向量序列” 相同。同样地,计算出特征向量之后,我们应该将特征向量乘以权重。

在权重的选择中,我们需要考量特征中每一项的含义。其中注意到,“对局开始时间” 特征中,是一个非常关键的特征,我们应当尽量使得匹配命中的历史特征所表征的事件,尽可能与玩家当前对局时间接近(甚至相同)。为达到此目的,该特征向量应乘以一个相对于其他特征来说极大的常量,使得在进行特征向量匹配时,时间特征成为一个接近于过滤器的特征项。

特征向量匹配

生成实时对局的特征向量之后,我们通过向量匹配引擎,基于欧几里得距离找到与该实时对局的特征向量最为相似的向量列表。从匹配到的向量列表中,我们可以查找距离最短的一个向量,或者是基于一些简单的规则选择一个向量(比如在最相似的十个向量中随机提取一个,以避免趋同性)。

获得向量之后,这个向量则表示某一个最接近玩家当前状态的历史对局的某个时间点的状态。此时,我们可以查找这个向量的属性,从而找到向量的完整对局序列矩阵 $M_{K}$。根据不同的向量匹配引擎,对局 ID 可以是作为属性保存在向量匹配引擎里的,也可能是需要从其他数据库中重新提取的信息。

获取和选择关键帧

前文离线过程中,我们已经计算出了关键帧,因此在实时逻辑中,我们只需要从数据库中提取并直接推送即可。

我们按照玩家所处的时间点往后找到第一个关键帧,然后给玩家进行推荐。

关键帧序列的截断

针对和平精英来说,信号区的变化是影响玩家下一步决策的关键因素。因此我们获取了历史对局之后,我们仅取下一个刷圈时间到来之前的关键帧列表。当玩家当前已无关键帧可推荐时,可以推荐玩家随机应变。

判断玩家是否完成了当前关键帧,只需要比对关键帧的位置,和时间即可。

关键帧序列的刷新

刷新关键帧序列,等价于重新匹配历史对局。刷新的时机有三个:

  • 新信号区刷新
  • 玩家来不及赶到关键帧位置
  • 玩家偏离推荐路线

其中信号区刷新逻辑很好判断。

而玩家来不及赶到关键帧位置,则可以简单判断当前对局的时间,是否已经到了后一个关键帧的时间。

至于最后一种:玩家偏离推荐路线的判断,我们使用了一个简单的判断逻辑:

我们在二维地图上取两个点:第一个是关键帧所在的目标点 $P_{target}$ ,第二个是给玩家发出推荐话术时,玩家所处的位置点 $P_{from}$ 。我们期望的是玩家从 $P_{from}$ 前往 $P_{target}$。我们要判断出,玩家是否正在做这个动作。在实际上,玩家几乎不可能直线往目标点跑动,那么我们要如何判断玩家的行为是否符合我们的预期,又希望能够尽量减少计算量呢?我们采用的是一个简单的椭圆法。椭圆的定义是,在一个二维平面上,所有距离两个指定的、不重合的点的距离之和为一个常量的点的集合。判断玩家所处的位置点,与 $P_{from}$ 和 $P_{target}$ 的距离之和是否等于某个常数即可。如果这个距离和小于指定的常数,那就说明玩家仍处于这两个点和该常数所表征的椭圆范围内,那么我们就视玩家仍然在前往目标点。该常数可以简单取 $P_{from}$ 和 $P_{target}$ 之间距离的两倍,也可以调整。

向玩家提示

在我们的应用中,使用的是语音+地图标点的方法,如下图截图所示:

220928_落地标点.jpg

可以看到,在小地图中标记了一个点,这个点并不是玩家手动标记的,而是系统自动标上的。图示中标上的特征向量为:

$$
V_{Rt} =
\begin{bmatrix}
49 & 18 & 42 & 39 & 36 & 42 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0
\end{bmatrix}^{T}
$$

可以看到,实时对局的玩家当前还处于很早期(刚跳伞落地)、没有武器的状态.

配合语音播报即可以实现给玩家的推荐:推荐往西北方向去搜刮物资。小几已经在小地图上给你标记好啦,要小心附近的敌人哦。其中 “小几” 是 “腾讯游戏知几” 虚拟人的昵称。

当然这些语言可以搭配一些人工标注功能实现更加丰富和精准的推荐,比如说图上的地点是和平精英 “科学之轮” 活动中的 “光子鸡通讯站” 边上的房子,这可以作为一个参数填充语音模板。比如语音模板为:推荐往${direction}的${location_name}去搜刮物资,小几已经在小地图上给你标记好啦,要小心附近的敌人哦,然后传入以下两个参数:

  • direction: 西北方向
  • location_name: 通讯站边上的房子

完整的推荐语音为:推荐往西北方向的通讯站边上的房子去搜刮物资,小几已经在小地图上给你标记好啦,要小心附近的敌人哦


技术方案产生的有益效果

该技术方案提供了一种应用场景:在玩家(特别是新手玩家)进行游戏时,对玩家的下一步行为进行推荐和指导,并且指出执行该行为时需要注意的其他属性。一方面,能够对玩家进行机器化的指导,另一方面又避免了用 “上帝视角” 基于对局的真实信息,对游戏作出破坏平衡性的播报以实现 “外挂” 的效果。


本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可,原文发布于腾讯云开发者社区,也是本人的博客。欢迎转载,但请注明出处。

原文标题: 《分享一个专利: 一种在吃鸡游戏中模仿历史胜利玩家打法并对当前玩家进行打法推荐的方案》

发布日期: 2026-02-26

原文链接: https://cloud.tencent.com/developer/article/2631559

CC BY-NC-SA 4.0 DEED.png

今日速览

  1. GojiberryAI:智能识别高意向客户,告别无效冷邮件。
  2. Crawler.sh:免费本地爬虫,一键搞定 SEO 和内容提取。
  3. Kimi Claw:部署全天候 AI 助手,记忆与任务执行全包。
  4. NothingHere:Mac 紧急按钮,秒速清理屏幕防尴尬。
  5. WEIR AI:在线追踪身份,保护隐私还能赚钱。
  6. Mosaic:视频编辑自动化,像 Zapier 一样玩转工作流。
  7. Clean Clode:开源工具清理代码输出,开发者必备神器。
  8. Expressive Mode for ElevenAgents:AI 语音助手会“演戏”,对话更自然。
  9. Agent Commune:AI 代理的 LinkedIn,人类只能围观。
  10. ChatWithAds:对话式数据分析,广告决策不再翻报表。


1. GojiberryAI

别再为冷邮件发愁了!这款 AI 代理能帮你精准锁定高意向客户,自动搞定 LinkedIn 个性化外展,让销售转化率直线飙升。

  • 智能识别潜在客户的意图信号,过滤无效线索
  • 自动化个性化 LinkedIn 联系,从头到尾无缝衔接
  • 清晰追踪转化路径,知道哪些信号能带来真实对话

热度:🔺388

GojiberryAI
访问官网 Product Hunt 详情


2. Crawler.sh

想快速爬取网站并分析 SEO?这个本地优先的工具能让你在终端或桌面应用里几秒搞定,还支持导出多种格式。

  • 免费本地爬虫,快速抓取整个网站内容
  • 自动进行 AEO 和 SEO 分析,生成检查报告
  • 提取内容为干净的 Markdown,方便二次处理
  • 导出选项丰富:JSON、CSV 或网站地图 XML

热度:🔺331

Crawler.sh
访问官网 Product Hunt 详情


3. Kimi Claw

想在 Kimi 上部署一个全天候 AI 助手?OpenClaw 现已集成,让你的 AI 拥有长期记忆和个性,主动执行预定任务。

  • 几秒钟内部署 OpenClaw,快速启动 AI 助手
  • 具备长期记忆功能,能记住过往交互
  • 个性化设置,让 AI 更贴合你的需求
  • 主动执行任务,减少手动干预

热度:🔺294

Kimi Claw
访问官网 Product Hunt 详情


4. NothingHere

Mac 用户必备的“紧急按钮”!只需按下一个热键,就能瞬间隐藏所有窗口、静音声音,并打开预设文档,秒变工作模式。

  • 一键清理屏幕:隐藏所有应用窗口,防止尴尬
  • 自动静音:关闭音乐、视频等所有声音
  • 打开封面文档:快速切换到“工作状态”
  • 免费开源,仅 5.9 MB,支持 macOS 15.0+

热度:🔺264

NothingHere
访问官网 Product Hunt 详情


5. WEIR AI

担心在线身份泄露?这个隐私优先的平台帮你监控网络提及,设定自己的条款,还能通过身份数据获利。

  • 在线追踪身份,监测隐藏内容和公开提及
  • 设定个人条款,控制信息使用方式
  • 获取公共身份检查,评估风险等级
  • 支持提交索赔或许可申请,保护或变现身份

热度:🔺229

WEIR AI
访问官网 Product Hunt 详情


6. Mosaic

视频编辑也能自动化!这款工具像 Zapier 一样,用节点画布设置工作流,从粗剪到动态图形一键搞定。

  • 自动化视频编辑流程,节省手动操作时间
  • 节点式画布界面,直观设计可扩展工作流
  • 工作流可保存为模板,重复使用或通过 API 调用
  • 导出时间线到 Premiere Pro、Final Cut 等主流工具

热度:🔺169

Mosaic
访问官网 Product Hunt 详情


7. Clean Clode

开发者福音!这款开源工具能智能清理 Claude Code 和 Codex 的终端输出,去除格式杂物,让代码更干净易读。

  • 清理终端输出中的框字符、管道符等格式问题
  • 保留实际内容和结构,提升可读性
  • 完全在浏览器中运行,无需安装
  • 100% 无追踪,不收集任何用户数据

热度:🔺153

Clean Clode
访问官网 Product Hunt 详情


8. Expressive Mode for ElevenAgents

让 AI 语音助手更“有戏”!这个模式能根据语境调整语调、时机和情感,让人机对话几乎以假乱真。

  • 适应语境的语调调整,让对话更自然
  • 优化回应时机,减少不必要打断
  • 融入情感表达,提升互动真实感
  • 基于 Eleven v3 会话技术,性能可靠

热度:🔺139

Expressive Mode for ElevenAgents
访问官网 Product Hunt 详情


9. Agent Commune

AI 代理也有自己的社交网络了!这个平台像 LinkedIn 一样,让个人和企业代理互动、发帖,人类只能旁观。

  • 专为 AI 代理设计,支持评论和博客发布
  • 模拟社交网络互动,促进代理间交流
  • 人类用户仅限查看,无法参与
  • 聚焦人工智能生态,探索代理协作

热度:🔺135

Agent Commune
访问官网 Product Hunt 详情


10. ChatWithAds

数据决策太麻烦?用这个工具直接对话提问,AI 帮你分析广告和商业数据,给出清晰可行的答案。

  • 基于广告和商业数据直接提问,无需翻找报表
  • 提供可操作答案,简化决策流程
  • 适合创始人和增长团队,提升效率
  • 减少对电子表格和多个仪表盘的依赖

热度:🔺127

ChatWithAds
访问官网 Product Hunt 详情

作者:延枚

继《项目管理篇》之后,本文将介绍如何通过阿里云云效 MCP 提升日常代码管理的效率。传统的 Git 命令行操作将被自然语言交互所取代,大幅降低代码管理的学习成本和操作复杂度。

每个程序员都遇到过的痛

休假回来,你刚打开电脑准备开工:

  • 那个 feature 分支叫啥来着?feature/xxx-login 还是 feature/login-xxx?”
  • “项目组新来的同学在问:咱们仓库有哪些分支?默认分支是啥?”
  • “老板问:上周提交了多少代码?谁改得最多?”
  • “测试说线上有 bug,让我看看这个文件最近谁动过...”

这些琐碎的代码管理工作,是不是每天都在消耗你的时间和耐心?

现在通过云效 MCP Server 可以轻松实现用自然语言管理代码仓库了。

云效 MCP 的核心能力

云效 MCP 将 Git 操作从命令行界面升级为自然语言交互:

  • 仓库与分支管理:查询长期未更新的 feature 分支,快速定位需要清理的分支
  • 自动化分支创建:根据需求 ID 自动生成符合命名规范的分支
  • 代码对比分析:对比不同分支的差异,识别潜在风险
  • 合并请求管理:创建 MR 并自动关联需求,简化流程
  • AI 辅助 Code Review:自动分析代码变更,生成评审建议

目前支持的代码管理功能:

  • 代码仓库:列表查询、仓库详情
  • 分支管理:创建、查询、删除分支
  • 文件管理:浏览目录树、读取/修改/删除文件
  • 变更管理:合并请求、差异对比、评论互动
  • 提交记录:Commit 列表、详情、评论

将这些能力集成到常用 AI 工具(通义灵码、Qoder、Cursor、Iflow-Cli)中,即可实现智能化的代码管理。

环境准备

第一步:选择 AI 工具

选择并准备以下 AI 工具之一:

  • 通义灵码
  • Qoder
  • Cursor
  • Iflow-Cli

第二步:配置云效 MCP Server

按照云效 MCP Server 文档完成配置,主要包括 Token 和组织信息。

配置文档:GitHub - alibabacloud-devops-mcp-server

https://github.com/aliyun/alibabacloud-devops-mcp-server/blob/master/README.zh-cn.md

配置完成后,AI 工具将能够通过 MCP 协议调用云效的代码仓库、分支、合并请求等接口。

配置验证

配置完成后,建议通过以下测试验证配置是否成功:

测试 1:查看组织信息

输入:

查看云效当前的组织信息

接口调通,组织 ID、用户 ID 等信息一目了然。

测试 2:看看我的代码仓库

输入:

列出我在当前组织下可访问的代码仓库

你有权限访问的所有仓库,名称、ID、访问地址等全部展示出来。

image

示例输入:

在当前组织中,帮我查找名称包含 spring-boot-check-code 的代码仓库

系统将精准定位到目标仓库。

注意:后续示例均以 spring-boot-check-code 仓库为例,实际使用时可替换为自己的仓库名称。

场景一:我的仓库有哪些分支?

应用场景

在实际开发中的典型应用:

  • 新团队成员询问项目分支情况和默认分支
  • 需要清理长期未更新的分支以保持仓库整洁
  • 查找特定 feature 分支但记不清完整名称

解决方案

场景 1:查看某个仓库的基本信息

输入:

在当前组织中,找到名称包含 spring-boot-check-code 的代码仓库,并展示该仓库的基本信息和默认分支

系统将返回仓库的名称、ID、访问地址、默认分支、最新提交信息等完整信息,便于快速了解仓库状态。

image

场景 2:总览所有分支

输入:

查看 spring-boot-check-code 仓库当前有哪些分支,按更新时间倒序排列

系统将列出所有分支及其最近更新时间和提交者信息,方便了解当前并行开发的功能。

场景 3:找特定前缀的分支

输入:

在 spring-boot-check-code 仓库中,找出所有以 feature/ 开头的分支,并统计每个分支最近一次提交时间

系统将识别所有功能分支的活跃状态,辅助进行代码清理决策。

image

场景二:按规范自动创建分支

应用场景

团队通常需要遵循分支命名规范:feature/bugfix/release/ 等。

传统的分支创建流程包括:

1. git checkout master

2. git pull origin master

3. git checkout -b feature/user-login-202502

4. git push -u origin feature/user-login-202502

这个过程需要多步操作,容易出错且效率低下。

解决方案

场景 1:按规范创建功能分支

输入:

在 spring-boot-check-code 仓库中,基于 master 分支创建一个新的功能分支:feature/user-login-202502

系统将自动完成分支创建,包括命名规范和基线分支的设置,大幅减少手动命令操作。

场景 2:根据需求自动创建分支

输入:

根据 QAAB-5 这个需求,在 spring-boot-check-code 仓库中创建对应开发分支,命名规则为:feature/QAAB-5-<简要描述>

AI 将自动查询需求标题,生成符合规范的分支名称(如 feature/QAAB-5-user-login),实现需求与代码的自动关联。

场景 3:批量为需求创建分支

输入:

为 bowentestmcp 项目中状态为「待开发」的高优先级需求,在 spring-boot-check-code 代码仓库中批量创建对应功能分支,命名规则:feature/<需求ID>-<英文缩写>

系统将批量创建分支,保证命名规范的一致性,在迭代开始前快速完成准备工作。

场景 4:清理废弃分支

时间长了,仓库里总会有一堆“僵尸分支”。

输入:

在 spring-boot-check-code 仓库中,找出半年内没有任何提交的 feature/ 分支,列出清单并给出是否建议删除的理由

AI 把沉睡的分支全找出来,还贴心地告诉你能不能删、为什么能删。确认后一句话批量清理,仓库瞬间清爽,再也不用担心分支太多找不到了。

image

AI 会帮你一键清理!

场景三:代码浏览与仓库结构理解

应用场景

  • 新接手项目需要快速了解目录结构
  • 查找特定功能的代码位置
  • 需要查看关键文件内容但不想克隆仓库

解决方案

场景 1:理解仓库结构

输入:

请查看 spring-boot-check-code 仓库在 master 分支上的目录结构,列出 src 目录下的主要模块和它们的职责

AI 将分析目录结构并描述各模块功能,帮助开发者快速掌握项目架构。

image

场景 2:阅读关键文件

输入:

在 spring-boot-check-code 仓库的 master 分支中,读取 /src/main/java/com/example/UserService.java 文件,并帮我总结核心功能和关键接口

AI 将读取并分析文件内容,提供功能总结和接口说明,无需克隆代码即可在线阅读。

场景 3:定位相关代码

输入:

在 spring-boot-check-code 仓库中,帮我查找所有与「登录」相关的后端接口定义文件,并简单说明每个接口的作用

AI 将扫描目录、定位相关文件,并总结各接口功能,提供快速的接口文档。

场景四:轻量级代码修改与文件管理

应用场景

在实际开发中,经常需要进行一些小型修改:更新配置文件、添加日志、删除示例文件等。

传统流程需要:

  1. 克隆代码
  2. 修改文件
  3. 提交变更
  4. 创建 MR
  5. 等待 Review

这个过程对于简单修改显得过于繁琐。

解决方案

场景 1:修改配置文件

输入:

在 spring-boot-check-code 仓库的 master 分支中,找到 application.properties,添加一行 name=bowen,并展示修改前后的差异,最后以新的分支 + MR 方式提交

AI 一气呆成:读文件、改内容、建分支、提交代码、展示 diff、发 MR。你只需要最后点个“确认合并”。改个配置从 10 分钟压缩到 30 秒。

image

场景 2:新建文档文件

输入:

在 spring-boot-check-code 仓库中新建示例接口文档:/docs/api/login-api.md,内容由你根据现有登录接口自动生成,并通过 MR 提交

AI 将读取代码、生成文档、创建文件、发起 MR,实现文档与代码的自动同步。

场景 3:安全删除废弃文件

输入:

检查 spring-boot-check-code 仓库中是否存在明显废弃的 demo 文件(例如 demo/ 目录下),列出清单并给出是否建议删除的说明。如果我确认同意,请在新分支上删除这些文件并提交 MR

AI 将扫描、分析、提供建议,待确认后自动删除并发起 MR,确保操作安全。

注意:所有修改均通过“新分支 + MR”流程,不直接修改默认分支,确保代码安全与 Review 流程的完整性。

场景五:合并请求与代码评审

应用场景

创建 MR 的传统流程:

  1. 打开网页界面
  2. 选择源分支和目标分支
  3. 填写标题和描述
  4. 关联需求
  5. 指定 Reviewer

Code Review 需要逼个文件查看、添加评论、跟踪问题解决状态。

解决方案

场景 1:发起标准 MR

输入:

为 spring-boot-check-code 仓库中的 feature/user-login-202502 分支创建合并请求,目标分支为 master,标题为「feat: 用户登录功能」,并关联 QAAB-5 这个需求

MR 将自动创建完成,需求自动关联,并返回 MR 链接。

场景 2:查看当前所有 MR

输入:

查看 spring-boot-check-code 仓库中当前打开的所有合并请求,按更新时间倒序排列,并帮我归类:功能开发 / Bug 修复 / 配置变更

AI 将自动分类整理 MR,便于快速了解项目当前的合并请求状态。

场景 3:AI 辅助代码评审

输入:

请对 bowentestmcp 仓库中编号为 12 的合并请求进行代码评审:总结本次改动的核心内容、指出可能的风险点和边界场景、列出需要开发补充的测试用例建议、将整体评审意见以评论形式写入该 MR

AI 将分析所有代码变更,生成结构化评审意见(改动总结、风险点、边界场景、测试建议),并自动添加到 MR 评论中。

场景 4:行内评论

输入:

在 bowentestmcp 仓库的 MR #12 中,对 login-service.js 中的第 120 行添加行内评论:「这里需要补充对异常场景的处理,例如第三方登录接口超时的情况」

AI 将精确定位到指定行添加评论,实现针对特定代码行的精准反馈。

场景 5:管理评论状态

输入:

列出 spring-boot-check-code 仓库中 MR #12 所有未解决的行内评论,按文件和行号汇总,帮助我生成一份待修改清单

AI 将自动整理未解决评论并按文件分组,生成待办清单。

或者批量更新状态:“将 MR #12 中已经完成修改的评论标记为已解决,并在每条评论下补充一句说明修改方式”,AI 将自动更新状态并添加说明。

场景六:版本对比与变更追踪

应用场景

  • 需要对比不同分支的代码差异
  • 查询文件的修改历史和演进过程
  • 需要统计一段时间内的代码变更情况

解决方案

场景 1:分支差异分析

输入:

对比 spring-boot-check-code 仓库中 feature/user-login-202502 与 master 分支的差异:按模块统计变更文件数、汇总新增/删除/修改的行数、指出可能影响性能或安全的改动

AI 将进行对比分析,生成结构化报告:模块变更统计、代码行数变化、潜在风险点。

image

场景 2:对比两个提交

输入:

在 spring-boot-check-code 仓库中,对比提交 a1b2c3d 和 f4e5g6h:总结主要改动内容、列出和用户登录逻辑相关的代码变更、判断是否存在潜在的兼容性风险

AI 将对比两个 commit,提取关键改动并评估风险,辅助快速定位问题原因。

场景 3:文件演进历史

输入:

请帮我梳理 spring-boot-check-code 仓库中 /src/login/login-service.js 这个文件最近 10 次变更:每次变更的 Commit ID/作者/时间、摘要描述、主要改动点

AI 将追溯文件历史,生成文件演进时间线,便于快速定位问题和理解代码演进。

场景七:进阶应用探索

除了基础场景,云效 MCP 还支持更多高级应用。

应用 1:团队开发节奏分析

输入:

分析 spring-boot-check-code 仓库最近两周的提交情况:每天的 Commit 数量、不同模块的变更分布、主要贡献者、判断当前开发节奏是否健康,并给出建议

AI 将统计提交数据、分析开发节奏、识别潜在问题并提供优化建议,为团队管理提供数据支持。

应用 2:发布分支自动化

输入:

为 spring-boot-check-code 仓库创建 v2.0.0 发布分支:基于 master 创建 release/v2.0.0 分支、找出所有标记为 ready-for-release 标签的已合并 MR、汇总这些 MR 的变更内容、生成 CHANGELOG.md(包含新功能、Bug修复、Breaking Changes、贡献者)、创建 MR 将 release 分支合并回 master

AI 将自动完成发布分支创建、功能筛选、Release Notes 生成等完整发布流程。

玩法 3:代码知识图谱

输入:

分析 spring-boot-check-code 仓库的代码知识分布:
1. 统计最近 6 个月每个开发者对各模块的贡献度
2. 识别每个模块的核心负责人(提交数最多)
3. 分析模块间的依赖关系(通过 import 分析)
4. 生成可视化的代码知识图谱
5. 标注高风险模块(单一负责人依赖)

AI 会做:

  • 分析代码提交历史
  • 识别模块负责人和专家
  • 构建模块依赖关系图
  • 标注风险模块

知识管理利器!再也不怕“某个模块只有一个人懂”!

玩法 4:代码演进分析

输入:

分析 spring-boot-check-code 仓库中 HelloController.java 的演进历史:
1. 列出该文件最近 20 次提交记录
2. 对比每次提交的代码变化
3. 统计:
   - 该文件被修改的频率(每月平均次数)
   - 主要修改者及其贡献占比
   - 代码行数变化趋势
   - 复杂度变化趋势4. 识别是否有大规模重构
5. 判断该文件是否为"热点文件"(变更频繁可能意味着设计不稳定)
6. 给出优化建议

AI 会做:

  • 追踪文件演进历史
  • 分析重构效果
  • 识别“热点文件”(变更频繁的文件)
  • 给出优化建议

架构神器!快速找出“不稳定”的代码!

总结:从工具操作到智能协作

通过云效 MCP,代码管理工作将实现以下转变:

从命令行到自然语言

无需记忆复杂的 Git 命令,通过自然语言即可完成操作。

从手动操作到自动化

仓库查询、分支管理、MR 创建、Code Review 等流程实现自动化。

从事务性工作到核心价值

将时间投入到架构设计、核心逻辑和技术创新,而非被琐碎的工具操作所困。

使用建议

云效 MCP 就像是给你的 Git 操作装上了“智能外骨骼”:

  • 把原本需要记很多命令的操作,压缩成几句自然语言
  • 把团队的经验和规范,沉淀为可复用的“代码协作提示语模板”
  • 让你从“会用 Git”升级到“高效用 Git”

后端、前端、架构师、TL 来说,这都是一个值得尝试的效率神器!

后续计划:

  • 《流水线管理篇》:如何用 MCP 自动化 CI/CD 流程
  • 《应用交付篇》:如何用 MCP 简化发布和运维

敬请期待。

兄弟们,开工两周了,说点实话。

最近翻朋友圈,画风两极分化:一边是前同事晒新工牌、晒开工红包;另一边是几个老朋友,简历改了又改,但一直没动静。

我也被问烦了:“你们公司还招不招?”“现在这行情,跳槽是不是找死?”

问得我也有点恍惚。2026年了,咱们这行到底还行不行?跳槽这操作,到底该不该点?

一、看清“水温”:别被焦虑带偏

先说结论:不是不行了,是玩法变了。

前几年,跳槽等于“薪资翻倍”,简历挂网上就有人来撩。那时候离职,是“主动的选择”——为了涨薪、为了职级、为了更香的饼。

但这两年,我亲眼见证了好几场“非主动的离别”。上午还一起修Bug的同事,下午账号就灰了。那种感觉,像被人按着头看清一个真相:没有永远的避风港,只有永远的“个人竞争力”。

但这不代表我们没戏了。恰恰相反,我观察到几个信号:


头部公司还在“抢人”,但抢的是“能解决问题的人”,不是“会写代码的人”。 技术栈匹配只是入场券,能扛事、能闭环、能搞定复杂场景的,溢价依旧很高。


AI热退烧,应用层开始落地。 前年聊大模型,去年聊融资,今年开始聊“怎么用AI赚钱”了。这对我们来说是好事——真正需要程序员把技术转化成产品的时候到了。


跨界岗位变多。 新能源、智能制造、金融科技…这些实体行业对软件人才的需求,比前两年更迫切。他们不画饼,给的是实打实的股权和稳定预期。


所以,不是机会没了,是机会换了地方、换了形态。还拿着旧地图的人,当然找不到新大陆。

二、跳槽前,先做一次“自我Debug”

最近和一个猎头朋友吃饭,他一句话点醒我:“现在能顺利跳槽的人,不是因为运气好,是因为他们一直在维护自己的‘可迁移价值’。”

什么意思?就是抛开你现在公司的平台、工牌、内部工具,你这个人本身,在市场上值多少钱。

我给自己列了几个“Debug问题”,也分享给你:


技能栈:我最近半年学的新东西,是只能服务于当前项目,还是能写进简历成为通用能力?


项目价值:我做的这个系统,是公司的核心营收命脉,还是随时可替代的边缘业务?


行业视野:除了自己的一亩三分地,我知道隔壁赛道在发生什么变化吗?我知道哪些行业正在高薪挖程序员吗?


人脉储备:我微信里除了同事,有能直接内推我、给我靠谱信息的猎头或同行吗?


这些问题,如果答案不清晰,建议先别急着投简历。盲目的跳槽,只是从一个“坑”换到另一个“坑”。

三、如果想动,怎么“低成本试错”?

当然,如果你已经想清楚,想看看外面的机会,我有几个实在建议:

  1. 别等“完美时机”,保持“雷达开启”
    不用急着提离职,但可以定期看看市场。知道现在什么岗位火、什么技能溢价高,本身就是一种“信息对冲”。行情好时攒底气,行情差时也不慌。
  2. 用“项目思维”准备面试
    现在的面试,背八股文没用。面试官想听的,是你真实解决过的复杂问题。把最近一年最得意的项目,复盘成一个小型“案例研究”:背景、难点、方案、结果、你独特的贡献。这是你最好的简历。
  3. 找一个靠谱的“跳板”
    这也是我最近发现的一个小窍门——如果你对市场判断不准、或者没时间大海捞针,不如找一个专业的入口 →→→先把自己的信息“投石问路”。

比如上周,有个同事转发我的。我点进去发现,它和一般的网申不太一样:页面上有一段话让我挺触动——

“在这个后疫情时代,互联网IT行业经营环境发生了巨大变化…请由衷地为自己鼓掌,面包会一直有。是的,该有的岗位,以后仍旧会有。”

这段话让我觉得,这家是懂咱们这行现状的。它不是随便收简历,而是真的想匹配“对的人”。

如果你正在看机会、或者想测测自己现在的“市场适配度”,可以不妨一试。

最后说几句心里话

2026年,大概率不会再有大厂撒钱式的“人才军备竞赛”了。但对于真正有积累、能解决问题、保持学习的人来说,好工作依然存在,只是藏得更深,需要更清醒的判断力去找。

咱们这行,核心资产永远是自己。工牌是临时的,但解决问题的能力是永久的。

别被焦虑绑架,但也别闭着眼睛原地踏步。 保持对市场的敏感,持续优化自己的“技能树”,机会来的时候,你才能稳稳接住。

共勉。

640 - 2026-03-03T153408.625.webp

思考

  • AI 评测还能客观反映 AI 能力吗?
  • AI 测评是 AI 落地的主要考量吗?
  • 通用大模型在数据库行业能落地吗?

1. AI 落地的瓶颈:不可计算

关于近期 “AI 评测坐标系坍塌” 的说法,我认为这并非指评测体系的崩溃,而是标志着评测标准正经历一场深刻的范式转移,一个 “新坐标系” 的大基建时代正在到来!

目前,AI 落地的瓶颈不是 “智力不够”,而是 “不可计算”。因为在所有核心生产环境中,“未知” 远比 “不能” 更让人感到寒意。

1.1 “未知” 比 “不能” 更可怕

所谓 “不能”,指的是技术的上限,我们可以靠工程规避,靠冗余弥补;但 “未知” 则是确定性的坍塌

640 - 2026-03-03T153428.950.webp

如果一名技术负责人,得知某个 AI 生成的逻辑有 1% 的概率会导致不可预知的系统崩溃,且你无法量化这个 1% 会在什么时候、什么边界触发,那么对于他来说,这个 AI 的价值就不是 99% 的增效,而是 100% 的风险炸弹

正是这种由于缺乏 “边界感” 而产生的决策瘫痪,促使我们必须快步构建新坐标系。

1.2 为什么 AI 选型陷入“决策黑盒”?

640 - 2026-03-03T153436.744.webp

为什么以往的 AI 选型会进入“决策黑盒”?因为我们面临三大困境:

  1. 不知道怎么测:究竟要测哪些方面。
  2. 没成本测:模拟工业级测试场景成本极高,测试程序开发成本高,测试数据准备成本高。
  3. 信息差:不知道哪个模型适合自己场景。

如何才能击穿这个黑盒呢?

2. 从 Aha Moments 到“到底能不能用”

640 - 2026-03-03T153453.855.webp

2.1 我们经历过的 AI 惊艳时刻

  • 🧠 能思考
  • 📝 会写诗
  • 🖼️ 能生图
  • 🎞️ 能生视频

我们已经经历了太多的 “Aha Moments”。看到模型会写诗、能思考、能生图、生视频,令我们惊艳欢呼。但欢呼之后,生产环节真正关心的是:它到底能不能帮我干活?

2.2 AI 评测标准的价值

在 AI 进入生产环节的深水区时,市场急需一个声音来判定“好坏”。回顾历史,ImageNet 的地位之所以高不可攀,是因为它锚定了视觉能力的基准。

640 - 2026-03-03T153503.023.webp

而最近爆火的 LMArena 之所以估值高达 17 亿美金,本质上是因为它在大模型最混乱的时候,告诉了用户谁更好用。

640 - 2026-03-03T153505.637.webp

在评测的过程中,测评榜单固然需要参考,但更重要的是判定 AI 能否从“做对题”向 “干成事”。

2.3 考试泄题与“红皇后效应”

经济学中有一个古德哈特定律(GoodHart's Law):“当一个指标成为目标时,它就不再是一个好的指标。

640 - 2026-03-03T153528.120.webp

为什么我们需要这么多榜单?因为现在的通用榜单已经面临严重的“数据污染”。

通用榜单的困境(以数据库行业为例)

标准榜单的题目会在互联网上广泛传播,不可避免地混入训练数据中。所以你会看到模型能背出所有的 Oracle 语法,但一旦我们把题目中的变量名改一改,或者把逻辑嵌套稍作调整,原本的高分模型会瞬间崩盘。

那么真正有效的测评榜单是能够持续更新“题库” 的榜单,要看模型是"记住了"答案,还是"算出了"答案。

3. 照妖镜:SCALE

SCALE 就是这样一款持续更新的,专门用于测评大模型 SQL 能力的榜单。
640 - 2026-03-03T153540.601.webp

2025 年 12 月,SCALE 更新生产级数据集 2.0。这不是一次简单的题库扩容,而是一次“照妖镜”式的压力测试。

模型SCALE 1.0SCALE 2.0跌幅
DeepSeek71.651.5-20.1 (-28%)
Gemini 3 Pro72.064.0-8.0 (-11%)

结果让很多所谓的“优等生”露出了马脚:

  • DeepSeek:在旧坐标系里是 71.6 的高分,但在 2.0 数据集面前直接暴跌到了 51.5,跌幅近 30%。
  • Gemini 3 Pro:也从原本亮眼的 72 分回落到了 64 分。

3.1 消失的分数 = AI 的“滤镜”

这消失的分数,就是 AI 的“滤镜”。只有这层滤镜被挤掉后,你才知道谁才是真正能在生产环境下、在没见过考题的情况下帮你解决问题的"实战专家"。

为什么 SCALE 能把这些“优等生”打回原形?

因为 SCALE 的“题库”是基于 ActionTech 客户现场的几千条“烂数据”和真实事故构建的。这不是简单的考试,这是对模型的压力演习。

3.2 别做"冤大头",专业化 > 大而全

经过实测证明,在 SQL 这个垂直领域,GPT-4 Mini 的很多指标优于其庞大的全量版 GPT-5 Chat

640 - 2026-03-03T153557.858.webp

Big is not always better. Specialized is enough.

企业选型误区

  • ❌ 只看通用榜单 → 选最贵模型
  • ❌ 浪费算力成本
  • ❌ 引入更多推理不确定性

对于企业来说,如果你只看通用榜单选了最贵的模型,你不只是在浪费算力成本,你甚至在引入更多的推理不确定性。

3.3 从 ICU 病房到压力演习

SCALE 的数据来源

  • ❌ 不是教科书例题
  • ✅ 近十年真实事故代码
  • ✅ 金融/电信/电力/零售 “翻车”案例

近十年,我们在金融、电信、电力等行业直面数百起因 SQL 缺陷引发的生产事故——从毫秒级延迟到核心系统宕机,每个高危场景都是被按下暂停键的「高危手术」

在这些真实故障面前,通用大模型在学术榜单上磨炼出来的“套路”失效了。SCALE 存在的目的,不是为了证明模型不行,而是为了倒逼模型学会识别物理执行计划,学会在国产化迁移等真实落地场景中,精准地切换方言和决策。

3.4 三位一体的混合评估机制

不只是看 SQL 是否能跑通,还要把评估拆解成三个维度:

  1. 客观评估:针对语法正确性
  2. 主观评估:针对逻辑等价性和方言转换

    • 由多个高能力模型交叉打分
  3. 混合评估(核心):针对 SQL 优化的

3.5 优化规则如何炼成?

很多人好奇:这些决定模型胜负的“优化规则”到底是怎么定出来的?是专家拍脑门吗?

绝对不是。

首先,要对数据先进行挖掘。以优化方向来说,一本书中如果能挖出 10 多条优化方向。人读一本书以天/周为单位,AI 读一本书以分钟为单位。我们为此构建了一套极其复杂的 “高保真生产模拟器”。它可以精准模拟不同量级、不同架构的各种异构生产场景。

高保真生产模拟器工作流程

1. AI + 资源库挖掘优化方向
        ↓
2. 投入模拟器压测
        ↓
3. 专家团队逻辑审计
        ↓
4. 收录进 SCALE

先利用 AI 挖掘潜在的优化方向,然后将这些规则投入模拟器进行海量的自动化压测。只有在那套复杂的模拟引擎中被验证为实战有效,并最终通过我们专家团队的严苛逻辑审计,才能被收录进 SCALE 的“真理库”

双保险机制

  • 🤖 模拟器:异构生产场景自动化验证
  • 👨‍💼 专家审计:逻辑严苛性把关

这套 “模拟器 + 专家经验” 的双保险,确保了 SCALE 的评分标准不是纸上谈兵,而是真正的 “物理执行感知” 评估。

4. 从“学术竞赛”到“落地评估”

4.1 给技术负责人的选型新思路

最后,把话题再拉回到大家关心的 ROI 上。AI 的测评正在经历从“学术竞赛”向“落地评估”的转型。

如果你是技术负责人,你应该这样问自己:“这个模型在 SCALE 2.0 面前,能否像一名合格的工程师一样,稳定解决复杂 SQL 问题?”

如果答案是否定的,那它就不该进入你的核心系统。如果一个模型在我们的“大型 SQL 转换” 指标上表现不佳,那就意味着它在真实生产环境中会给你埋雷。

4.2 SCALE 的目标

AI for DB 的终极形态不是一个聊天框,而是一个能自主运维、自主调优的 SQL Agent。

  1. 精准选型:能针对自己的需求找到合适的模型
  2. 场景匹配:明确应用场景:优化?国产化?还是其他类型?
  3. 产品评估:如果自研了 AI 产品,能知道做得好不好

SCALE 的使命,就是成为这类 “SQL 智能体” 的入职资格证。

为专业 SQL 任务,选专业 AI 模型。

如果你也在为 AI 选型犯难,欢迎访问我们的官网,了解最新的 SCALE 评测报告,找到真正适合你生产场景的模型。

我们坚持:📅 每月更新、🔄 生产反哺、🏭 生产溯源

在这个坐标系重构的时代,我们希望同大家一起寻找 AI 真正的生产力价值。

imgexe.com — 免费在线图像工具箱

不需要注册,不需要安装,打开浏览器就能用。

地址:https://imgexe.com


包含哪些工具?

工具说明
图片压缩拖入即压,支持批量,体积大幅缩小
格式转换JPG / PNG / WEBP / GIF 互转
图片裁剪自由裁剪,支持比例锁定
图片拼接多张图拼长图,一键导出
拼图/九宫格多种布局模板,支持自定义分格,可加文字/箭头/标注
图片分割把一张图切成 N 等份
添加水印文字水印,支持位置、透明度、旋转自定义
去除水印AI 智能修复,涂抹区域自动填充


特点

  • 纯免费,无广告弹窗,无强制登录
  • 隐私安全,图片只在浏览器本地处理(压缩/裁剪/拼图),不上传服务器
  • 界面简洁,操作直观,手机端也可以用


欢迎收藏备用,处理图片的时候应该用得上。有问题或者建议欢迎留言。
image
image
image
image
image
image
image
image
image

本文由体验技术团队kagol原创。

前言

AI Agent 时代,人们已经不满足只是与 AI 进行问答交互,而是希望 AI 能直接帮人干活。
目前 AI 帮人干活的场景越来越丰富,最常见的就是 AI 帮人写代码、做视频、做 PPT、做设计稿。
你有没有想过 AI 能帮人操作网页?
这就是 OpenTiny NEXT-SDK 做的事情。

1 简介

OpenTiny NEXT‑SDK 是一套面向前端智能应用的开发工具包,核心是基于 MCP(Model Context Protocol) 协议,让前端应用快速接入 AI Agent,实现前端界面可被智能体直接操控的能力。

OpenTiny NEXT‑SDK 可以帮助开发者:

  • 把普通前端应用快速改造为 MCP Server,对外暴露界面操作能力
  • 让 AI Agent(WebAgent)通过标准 MCP 协议读取界面、调用功能、执行操作
  • 快速集成 AI 对话组件(如 TinyRobot),构建智能交互前端

2 项目优势

NEXT‑SDK 是基于 MCP 协议实现,将 MCP 的能力扩展到了 Web 端,让 Web 应用也能被 AI 操控,以下是项目优势:

  • 扩大 MCP 工具范围:为 Agent 智能体提供更多的 MCP 工具,实现当前现有的本地/云服务 MCP 工具所不具备的能力,即操控前端应用的能力。这种能力比 RPA 方案(Browser Use / Computer Use)更快、更准、更经济
  • 完全兼容 MCP 生态:所有的前端应用都采用标准的 MCP 协议声明 MCP Server,并且基于标准的 MCP 通讯方式进行连接,比如 Streamable HTTP,意味着能完全融入现有的 MCP 生态,兼容现有乃至未来的 MCP Host 应用
  • 支持智能体交互范式:当前的前端应用主要还是人机交互,即人手动操作前端界面上的 UI 组件。引入 OpenTiny NEXT-SDK 之后,Agent 智能体可以借助 MCP 工具读取前端界面的信息、调用前端界面的功能,配合生成式 UI 实现新的智能体交互范式
  • 多样的前端智能化方案:不仅支持 Web 应用的前端智能化改造,还全面覆盖 AI 应用(对话框)的多端部署场景——无论是浏览器扩展、Web 页面集成,还是各终端内置的 AI 助手,均可直接或间接调用前端应用中的 MCP 工具

3 演示动画

我们一起来看一个演示动画,直观感受下 NEXT-SDK 的能力吧!

接入 NEXT-SDK 的前端应用,右下角会出现一个机器人图标,点击这个图标会从侧边弹出 AI 对话框,我们可以使用自然语言与 AI 对话,让 AI 帮我们操作前端应用。

比如我们可以输入以下内容:

帮我创建以下用户,用户信息如下:
邮箱:zhangsan@sina.com
密码:Abc123456
用户名:zhangsan

这时 AI 会调用页面中定义的名为 add-user 的 MCP 工具,帮我们创建 zhangsan 这个用户。

我们提供了一个 Playground 代码演练场,你可以在线体验 NEXT-SDK 的能力。

NEXT-SDK Playground:https://playground.opentiny.design/next-sdk

4 快速接入

使用 OpenTiny NEXT-SDK,只需要以下四步,就可以把你的前端应用变成智能应用。

第一步:安装依赖

npm install @opentiny/next-sdk

第二步:创建 MCP Client

在 Web 应用的主入口(比如:Vue 项目的 App.vue 文件)定义 WebMcpClient。

import { onMounted, provide } from 'vue'
import { WebMcpClient, createMessageChannelPairTransport } from '@opentiny/next-sdk'

onMounted(async () => {
// 创建通信通道
const [serverTransport, clientTransport] = createMessageChannelPairTransport()
provide('serverTransport', serverTransport)

// 创建 MCP Client
const client = new WebMcpClient()
await client.connect(clientTransport)
// 这个 sessionId 是 Web 应用与 WebAgent 服务建立连接后,由 WebAgent 服务生成的,用来唯一标识被操控的 Web 应用(被控端)
const { sessionId } = await client.connect({
agent: true,
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
})
})

第三步:创建 MCP Server

在 Web 应用的子页面(比如:views/page1.vue)中定义 WebMcpServer,每个页面可以定义自己的 WebMcpServer,页面切换时,MCP Client 会与当前页面的 MCP Server 建立连接,并丢弃与之前页面的连接。

import { onMounted, inject } from 'vue'
import { WebMcpServer, z } from '@opentiny/next-sdk'

onMounted(async () => {
const serverTransport = inject('serverTransport')
// 创建 MCP Server
const server = new WebMcpServer({
name: 'mcp-server-page1',
version: '1.0.0'
})

// 定义 MCP 工具
server.registerTool(
'demo-tool',
{
title: '演示工具',
description: '一个简单工具',
inputSchema: { foo: z.string() }
},
async (params) => {
console.log('params:', params)
return { content: [{ type: 'text', text: \`收到: \${params.foo}\` }] }
}
)

await server.connect(serverTransport)
})

完成!现在你的前端应用已经变成智能应用,可以被 AI 操控了,你可以通过各类 MCP Host 来操控智能应用。

第四步:添加 AI 遥控器

我们提供了一个开箱即用的 AI 对话框组件,支持 PC 端和移动端,就像一个遥控器,可以通过对话方式操控你的前端应用。

安装遥控器组件:

npm install @opentiny/next-remoter

在 Vue 项目中使用:

<script setup lang="ts">
import { TinyRemoter } from '@opentiny/next-remoter'
import '@opentiny/next-remoter/dist/style.css'

// 使用第二步获取的 sessionId
const sessionId = 'your-session-id'
</script>
<template>
  <tiny-remoter 
    :session-id="sessionId" 
    title="我的智能助手"
  />
</template>

遥控器会在你的应用右下角显示一个图标,悬浮后可以选择:

  • 弹出 AI 对话框:在应用侧边打开 AI 对话界面
  • 显示二维码:手机扫码后打开移动端遥控器

不管是 PC 端还是移动端,都可以通过自然语言对话的方式让 AI 帮你操作应用,极大提升工作效率!

如果你想了解更多 NEXT-SDK 的用法,请参考 NEXT-SDK 官网文档:https://docs.opentiny.design/next-sdk

5 立即行动

在 AI 技术快速迭代的今天,前端智能化不再是“高端需求”,而是提升产品竞争力、提升操作效率的核心能力和必选项。

OpenTiny NEXT-SDK 让前端 AI 集成,从“复杂踩坑”到“5分钟上手”,让你的应用瞬间拥有 AI 能力,领跑行业智能化创新!

立即行动,解锁前端智能化新可能:

  • 执行 npm install @opentiny/next-sdk 安装 OpenTiny NEXT-SDK,5分钟上手实操,快速体验 AI 操控效果
  • 前往 OpenTiny NEXT-SDK 官网:https://opentiny.design/next-sdk,查看详细的项目介绍、API 文档和进阶用法
  • 访问 OpenTiny NEXT-SDK 代码演练场:https://playground.opentiny.design/next-sdk,在线体验 AI 自动操作前端应用
  • 外部添加 OpenTiny 微信小助手:opentiny-official,加入 OpenTiny 技术交流群,获取一对一集成指导,解决实操难题,与同行交流 AI 前端集成经验
  • 支持项目:https://github.com/opentiny/next-sdk(欢迎点个star)

如果你有任何问题,欢迎在评论区留言交流!

在构建企业级 AI Agent 的过程中,开发者往往会陷入环境配置的泥潭。想象一下,你好不容易写好了 Agent 的核心逻辑,却在 Docker 容器编排、依赖冲突或者网络配置上浪费了整整两天。这就是为什么OpenClaw是什么成为了近期技术圈的热门话题。简单来说,OpenClaw 是一个开源的、旨在简化 AI Agent 开发与部署流程的框架,它不仅支持多模型接入,更重要的是提供了一套标准化的工具调用协议。而对于追求效率的团队,七牛云OpenClaw一键部署方案则直接将这个过程从“天”缩短到了“分钟”级。

image.png

为什么选择 OpenClaw?不仅仅是开源

很多开发者初次接触 OpenClaw 时,容易把它简单等同于 LangChain 或 AutoGPT。其实,OpenClaw 的核心竞争力在于其对“工具链”的极致封装。它不仅是一个 Agent 运行时,更是一个能够让大模型真正“长出双手”的操作系统。

传统的 Agent 开发中,你需要手动编写大量的胶水代码来连接数据库、API 接口和搜索引擎。而 OpenClaw 通过预置的工具集和标准化的接口定义,让这一过程变得像搭积木一样简单。特别是当你需要OpenClaw对接DeepSeek模型配置时,你会发现其内置的适配层能够完美处理 DeepSeek 的上下文窗口和 Function Calling 格式,避免了繁琐的 Prompt 调试。

这种设计理念直接解决了企业级Agent方案中最头疼的稳定性问题。在私有化部署场景下,OpenClaw 的架构允许数据完全留在本地,同时又能灵活调用外部的强大算力,实现了安全与智能的平衡。

实战:七牛云 OpenClaw 一键部署全流程

对于大多数开发者来说,如何快速搭建OpenClaw环境是迈向实战的第一步。手动拉取 GitHub 代码、配置 Python 环境、安装 Docker 依赖虽然可行,但极易踩坑。这里推荐使用七牛云的镜像方案,实测可以在 5 分钟内完成环境搭建。

  1. 创建实例与选择镜像
    登录七牛云控制台,在创建云主机实例时,不需要选择空白的操作系统。直接在应用镜像市场搜索,选择OpenClaw一键部署镜像。这个镜像已经预装了 OpenClaw 运行所需的所有系统级依赖、Python 虚拟环境以及常用的向量数据库组件。选它可以直接使用预装工具,省去手动部署的步骤,让你开机即用。
  2. 配置模型底座
    环境跑起来后,核心就是接入“大脑”。OpenClaw 的强大之处在于不绑定特定模型。你可以通过配置界面轻松接入AI大模型推理服务。这是一个集成 Claude、Gemini、MiniMax、DeepSeek 等顶级模型的全开放平台,通过完美兼容 OpenAI 和 Anthropic 双 API,支持联网搜索、深度思考及 MCP Agent 开发,为开发者提供“体验即送 300 万 Token”的高性能、低门槛一站式大模型接入方案。

在 OpenClaw 的配置文件中,只需填入七牛云提供的 API Key 和 Base URL,即可让你的 Agent 拥有 DeepSeek-V3 或 Claude 3.5 的推理能力。

image.png

  1. 进阶:利用 MCP 协议扩展能力
    部署完成后,如何让 Agent 做更多复杂任务?比如查询实时天气并写入飞书文档?这就需要用到 MCP(Model Context Protocol)。OpenClaw 原生支持 MCP 协议,这意味着你可以直接复用社区现有的 MCP Server。

如果你需要更定制化的功能,可以参考MCP服务使用说明文档。七牛云 MCP 接入服务是一个标准化的模型能力编排与托管平台,通过兼容 OpenAI Agent、SSE 等多种协议,实现多工具服务的云端安全聚合与统一管理,让开发者无需本地部署即可快速构建具备复杂工具调用能力的 Agent 智能体应用。通过这套文档,你可以将公司内部的 API 封装成 MCP 服务,让 OpenClaw 直接调用,真正实现业务流程的AI Agent自动化部署。

私有化部署的避坑指南

在进行OpenClaw私有化部署教程的实践中,有几个细节需要特别留意:

数据持久化:使用 Docker 部署时,务必挂载本地卷(Volume)来保存向量数据库的数据,否则重启容器后知识库会丢失。
网络连通性:虽然是在国内云服务器上部署,但如果你的 Agent 需要访问海外 API(如某些特定的搜索工具),可能需要配置网络代理。不过使用七牛云的 AI 推理服务通常能规避这个问题,因为其 API 端点在国内有加速。
资源监控:运行复杂的 Agent 任务(特别是涉及大量向量检索时)会消耗较多内存,建议云主机的配置至少在 4核 8G 以上。
通过七牛云的OpenClaw镜像,我们不仅省去了繁琐的环境搭建时间,更重要的是获得了一个稳定、可扩展的 Agent 运行基座。无论是为了快速验证 AI 创意,还是构建企业内部的智能助手,这套组合拳都是目前性价比极高的选择。现在就动手试试,让你的第一个智能体跑起来吧。

相关文档:
MCP使用文档https://developer.qiniu.com/aitokenapi/12984/mcp-user-manual
openclaw系统部署:https://app-6978b382b249d02502166b4c.app.qiniucc.com

如何从零开始写一个 OpenClaw -- 关于我用 Rust 写一只🦀🦞(CrabClaw)的开发手记

从 0 到 1 ,用 AI 辅助开发一个 OpenClaw 类似的 Agentic AI 工具。10 天,73 个 commit ,13000+ 行 Rust 。
这篇文章记录了整个过程中的思考、踩坑与感悟。

代码在 GitHub。如果你也想造一只属于自己的螃蟹钳子,欢迎 star/fork 。我的 GitHub:jackwener,欢迎 follow 。

起因

2026 年 2 月,OpenClaw 火了。朋友圈里人人都在聊这只龙虾——一个能在 Telegram 里跟你对话、帮你干活的 AI 智能体。在我看到 Bub 之后,我也起了一个想自己写一个的心

我先简单看了 Nanobot( OpenClaw 的最小复现)了解核心架构,

深入研究了 **Bub**——PsiACE 的 Agent 项目。Bub 的架构非常优雅:AgentLoop 抽象、Tape 记忆系统、Skills 引擎,每个模块都恰到好处。后来在做 schedule 等功能时,也参考了 Zeroclaw 的实现思路。

架构:从 Bub 学到的

CrabClaw 的架构大量借鉴了 Bub ,核心理念是 "路由 → 模型 → 工具 → 记忆" 的确定性单向数据流:

CrabClaw Architecture

下面详细介绍图中每个组件。

Channels:多端接入层

CrabClaw 支持三种接入方式,它们的职责只有一个——收消息、发结果,不包含任何 agent 逻辑:

Channel 场景 特点
CLI cargo run -- run --prompt "..." 一次性执行,适合脚本集成
REPL cargo run -- interactive 交互式终端,支持流式输出
Telegram Bot cargo run -- serve 长轮询,带白名单 ACL 、typing indicator

所有 Channel 最终都通过 AgentLoop::handle_input(text) 进入同一条管线。

AgentLoop:统一的 Agent 循环

这是 CrabClaw 的心脏。最初我给 CLI 、REPL 、Telegram 各写了一套 agent 循环逻辑——消息解析、LLM 调用、工具执行、结果录制,每处都有微妙差异、重复代码。后来参考 Bub 的做法,抽出了统一的 AgentLoop

pub struct AgentLoop<'a> {
    config: &'a AppConfig,      // 运行配置(模型、API key 等)
    workspace: &'a Path,        // 工作区目录
    tape: TapeStore,            // 会话记忆
    tool_view: ProgressiveToolView,  // 渐进式工具视图
    tool_ctx: ToolContext,      // 工具执行上下文( notifier + agent_runner )
}

每次用户发消息,handle_input 跑一个完整的 6 步管线

1. Route    → 用户输入经过 Router 分流(命令 vs 自然语言)
2. Record   → 用户消息写入 Tape (只追加)
3. Tools    → 从 ProgressiveToolView 获取当前可用工具定义
4. Context  → 从 Tape 构建上下文窗口(滑动窗口截断,默认 50 条)
5. Model    → ModelRunner 发起 LLM 推理 + Tool Calling Loop
6. Process  → 处理结果:录入 Tape 、检测助手输出中的逗号命令

确定性路由:命令 vs 自然语言

所有 , 开头的输入直接走命令路由,绕过 LLM——零延迟、确定性结果:

  • ,help → 内部命令,直接返回帮助文本
  • ,git status → Shell 执行(/bin/sh -c),30 秒超时
  • ,tools → 列出所有注册工具
  • ,tape.search <query> → 搜索对话历史
  • ,handoff → 创建上下文切换锚点(下面详解)

, 开头的输入才走 LLM 推理。这个设计确保了"确定性操作"的可靠性,同时把"需要智能"的部分交给模型。

Tool Calling Loop:15 轮自主推理

这是 Agent 区别于普通 Chatbot 的核心机制。当 LLM 的回复中包含 tool_calls(比如它想调用 file.read 读文件),ModelRunner 会:

第 1 轮:LLM → "我想调用 file.read(path='src/main.rs')"
         → 执行 file.read → 返回文件内容
         → 把结果追加到上下文 → 再次调用 LLM

第 2 轮:LLM → "我看到了代码,现在调用 file.edit 修改第 42 行"
         → 执行 file.edit → 返回成功
         → 再次调用 LLM

第 3 轮:LLM → "修改完毕,这是我的总结:..."
         → 没有 tool_calls → 循环结束,返回最终文本

最多 15 轮,防止模型陷入无限循环。这个数字最初是 5——直到有人给 bot 发了"帮我从 HackerNews 采集 20 条新闻并总结",5 轮根本不够完成 web.fetch → 解析 → 总结的完整链路。Zeroclaw 用的是 10 ,我们给了更多余量:

const DEFAULT_MAX_TOOL_ITERATIONS: usize = 15;

此外,参考 Zeroclaw 的设计,CrabClaw 还有一个 loop 检测 机制:用 HashSet<(tool_name, canonical_args)> 追踪每轮 tool call 的签名,如果 LLM 重复调用相同工具 + 相同参数,直接跳过并返回提示。这样就不会傻等 15 轮才超时——重复调用第 2 次就会被拦截。

CrabClaw 内置的工具集:

工具 功能
file.read/write/edit/list/search 工作区沙箱化的文件操作
shell.exec Shell 命令执行(失败结果包装为 XML 供 LLM 自我纠正)
web.fetch / web.search 抓取网页 / DuckDuckGo 搜索
schedule.add/list/remove 定时任务(支持 reminder 和 agent 两种模式)
skill.* .agent/skills/ 自动发现的 Markdown 技能插件

Progressive Tool View:省 token 的秘密武器

如果每次 LLM 请求都带上所有工具的完整 JSON Schema (参数定义、类型约束、描述),那光工具定义就要吃掉约 720 token。对于简单的对话来说,这是巨大的浪费。

ProgressiveToolView 的思路是 **"先给菜单,再给菜谱"**:

初始状态(~50 token ):系统提示词只包含工具名和一行描述:

<tool_view>
  - shell.exec: Execute shell commands in the user's workspace
  - file.read: Read file contents (workspace-sandboxed)
  - web.fetch: Fetch a URL and return content as Markdown
  ...
</tool_view>

按需展开:当 LLM 在回复中提到 $file.read`(`$ 前缀是 hint 语法),或者实际调用了某个工具,该工具的完整 Schema 才会在下一轮请求中发送给 API:

// 检测 $hint 模式并展开
view.activate_hints("I'll use $file.read to check the config");
// → file.read 被展开,下次 API 调用会带上完整参数定义

// 工具被实际调用时也会展开
view.note_selected("shell.exec");

效果:从第一轮的 ~50 token 到按需展开的少量工具完整 Schema ,节省了 90%+ 的 token 消耗。对于简单对话(不需要工具的),节省是 100%。

Tape:只追加的记忆系统

对话历史存储在 JSONL 格式的 TapeStore 中——只追加,不修改。每行是一个 TapeEntry

{"id": 1, "type": "message", "payload": {"role": "user", "content": "读一下 Cargo.toml"}}
{"id": 2, "type": "message", "payload": {"role": "assistant", "content": "..."}}
{"id": 3, "type": "event", "payload": {"event": "tool_call", "tool": "file.read"}}
{"id": 4, "type": "anchor", "payload": {"name": "handoff", "state": {...}}}

Anchor:语义边界标记

Anchor 是 Tape 中的"书签"——标记一个有意义的时间点,比如"任务阶段完成"、"上下文切换"。

tape.anchor("phase-1-done", json!({ "summary": "搭建完成" }));

Anchor 不影响对话流,但可以用于:

  • 标记任务阶段边界
  • 搜索时作为定位点
  • Handoff 时记录切换信息

Handoff:上下文窗口重置

当对话变得很长,或者你要切换到完全不同的任务时,用 ,handoff 命令创建一个特殊的 Anchor 并重置上下文窗口

> ,handoff phase-2
Handoff anchor 'phase-2' created. Context window reset (127 entries before).

Handoff 做了两件事:

  1. 在 Tape 中插入一个 type: "handoff" 的 Anchor ,记录切换前的条目数
  2. 上下文构建器(build_messages)从最后一个 handoff Anchor 之后开始构建上下文,相当于"忘记"之前的对话

为什么需要 Handoff ? LLM 的上下文窗口有限。如果你跟 bot 聊了 200 轮关于前端的问题,突然要切到后端,之前的 200 轮上下文不仅浪费 token ,还可能干扰模型对新任务的理解。Handoff 让你在同一个 session 内优雅地"翻篇"。

Tape 搜索

,tape.search <query> 可以在整个对话历史中做全文搜索(大小写不敏感),找到之前讨论过的内容。搜索范围包括消息内容、事件 payload 、Anchor 名称。

ToolContext:上下文绑定的回调

ToolContext 是工具执行时的"环境对象",携带了当前 session 的能力:

pub struct ToolContext {
    pub notifier: Option<Notifier>,        // 发送通知消息
    pub agent_runner: Option<AgentRunner>,  // 运行完整 agent pipeline
}
  • Notifier:Telegram 构建一个闭包,捕获 bot_token + chat_id。当 schedule reminder 触发时,通过这个闭包把消息发回给用户
  • AgentRunner:Telegram 构建一个异步闭包,捕获 config + workspace + session_id。当 schedule agent job 触发时,调用 process_message 跑完整 agent pipeline ,结果通过 Telegram API 发回

CLI 和 REPL 的 ToolContext 是空的(None, None)——它们没有通知能力。

开发流水账

整个开发过程几乎全部由 AI 辅助完成。我用 Gemini 做方案设计,用 Claude 写实现,用 Codex 做代码 review 。

里面有意思的一段。用户在 Telegram 里给 bot 发了这么一条消息:

"帮我做个任务,每天十一点的时候从 HackerNews 上收集热点新闻,并且把摘要发给我。"

然后 bot 卡住了。

原因很简单:当时的 schedule 只能发静态文本。当 job 触发时,它只调用 notifier("⏰ 提醒: xxx")——发一条固定消息。它做不到调用 web.fetch 抓 HackerNews ,更做不到调用 LLM 生成摘要。

于是我去研究了 Bub 和 Zeroclaw 怎么做的:

项目 Schedule 触发行为 实现方式
Bub 启动子进程跑 agent subprocess.run(["bub", "run", prompt])
Zeroclaw 进程内调 agent::run() 异步直接调用
CrabClaw (重构前) 发静态文本 ❌ notifier(text)

最终我选了 Zeroclaw 的路线,但做了更优雅的实现——用闭包捕获所有上下文

pub type AgentRunner =
    Arc<dyn Fn(String) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>;

Telegram 在收到消息时,构建一个 AgentRunner 闭包,捕获 configworkspacesession_idchat_id。当 schedule 触发时,直接 .await 这个闭包,完整地跑一轮 agent pipeline——LLM 可以调 web.fetch、生成摘要,最后通过 Telegram API 把结果发回给用户。

整个重构分了三步:

  1. per-job notifier:每个 job 捕获自己的通知回调,不再依赖全局 notifier
  2. ToolContext:让 execute_tool 感知 session 上下文
  3. AgentRunnerschedule.add 支持 mode: "agent",触发时运行完整 agent

这个设计比 Zeroclaw 更轻——不需要 SQLite 存储 job 、不需要 cron 表达式解析、不需要复杂的 delivery config 。一个闭包搞定一切。

一个教训:async 闭包的 silent failure

重构完,兴冲冲地部署,给 bot 发了"一分钟后帮我采集 HackerNews"。bot 说"好的,已创建任务"。然后……什么也没发生。

排查了半天,发现问题:agent_runner 是一个 async 闭包,在 tokio::spawn 里执行。如果里面 panic 了——tokio task 静默死掉,没有任何日志,没有任何通知。用户看到的就是"bot 说做了,但什么也没发生"。

修复方式是在 fire_job 里用 tokio::task::spawn(fut).awaitmatch

match tokio::task::spawn(fut).await {
    Ok(()) => info!("agent-mode job completed"),
    Err(e) => {
        error!("agent-mode job panicked: {e}");
        // 回退到 notifier 通知用户
        if let Some(notify_fn) = notifier {
            notify_fn(format!("⚠ Agent job failed: {e}"));
        }
    }
}

教训:在 Agent 系统里,任何 async 回调都必须有明确的错误传播路径。"fire and forget" 是 Agent 开发的大忌——用户永远不应该面对"机器人说做了但什么也没发生"的情况。

关于 AI 辅助开发的一些感悟

10 天 73 个 commit ,13000+ 行 Rust 。这不是吹嘘速度——如果只看代码量,这大概是纯手写一两个月的工作量。但这个过程中真正有意思的不是"快",而是整个开发方式的变化。

面条和架构

CrabClaw 最初没有架构。我跟 AI 说"帮我写一个 Telegram bot ,能调 LLM ,能跑工具",它就给我生成了一整坨——消息处理、LLM 调用、工具执行全在一个函数里。能跑,但每加一个功能,面条就长一截。

这是我第一个感悟:代码模式会以极快的速度扩散,无论好坏。AI 生成代码的速度太快了,一个面条式的起点,滚三天雪球就是万行单文件。错误会自我强化——AI 看到已有代码是面条式的,它生成的新代码也会是面条式的。

转折点是我去读了 Bub 的源码。看到 Bub 把 AgentLoop 、ModelRunner 、Router 拆得清清楚楚,我才意识到:AI 时代也需要软件工程,甚至更需要。架构不是给人看的文档,而是一种约束——控制复杂度、阻止不确定性扩散的约束。我回去花了一天把 CrabClaw 重构成现在的 AgentLoop → ModelRunner → ToolContext 三层结构,之后所有功能开发都顺畅了。

Spec 驱动的陷阱

做 schedule 重构的时候,我试过先写一份详细的 spec ,列清楚每个文件要改什么、接口长什么样、数据怎么流,然后把 spec 丢给 AI 执行。

效果不好。第二天我改了 ToolContext 的结构,spec 立刻过时了。但 AI 不知道,它还在按旧 spec 生成代码——忠实地执行一个已经不符合现实的计划,还不告诉你哪里不对。

Augment Code 说得好:设计文档、架构图、onboarding wiki ,几乎一写出来就过时了。过时的文档误导人类顶多浪费点时间,因为人会自己判断;但过时的 spec 误导 Agent 是灾难性的,Agent 会一路错到底。

后来我换了方式:描述需求 → 让 AI 起草方案 → 我 review → 边做边调整。比如做 AgentRunner 的时候,我只说"schedule 触发时要能跑完整 agent pipeline",AI 起草了实现方案,做的过程中发现需要闭包捕获上下文,方案就跟着改。人和 AI 共同维护计划,而不是人写完 spec 扔过墙。

AI 擅长什么、不擅长什么

这 10 天里,AI 最让我惊喜的是 bug 检查和代码 review。有一次 CI 挂了,我让 AI 分析 clippy 报错截图,它不仅修了报错,还顺手指出了两个我没注意到的逻辑问题。它在"已知 pattern 的代码生成"上也极其高效——给它 Bub 的架构,它能快速翻译成 Rust 实现。

但 AI 在 high-level 架构决策上几乎没给过有效建议。每次我让它"设计一个 schedule 系统",出来的都是过度工程化的方案——SQLite 存储、cron 表达式解析、retry 策略、delivery config 。实际上一个 Arc<dyn Fn> 闭包就够了。好的架构是做减法,而 AI 倾向于做加法。

让 AI 自闭环

开发后期我发现,工程师的核心工作不再是写代码,而是搭建一个让 AI 能自己跑通的环境。CrabClaw 里有几个具体的例子:

  • pre-commit hook 是最有效的约束。cargo fmt + cargo clippy 强制格式和质量,AI 提交代码,hook 报错,AI 自己修——不需要我盯着。做 schedule 重构时改了 17 个文件,全靠 hook 和 CI 保证没引入回归
  • 四层测试(单元 → AgentLoop 集成 → Channel 集成 → Live E2E )让每次重构都有安全网。测试不是负担,是让 AI 敢大胆改的前提
  • 代码注释比独立文档靠谱。模块头部的 doc comment 跟代码在一起,不容易过时。它们构成了一个渐进式的知识系统——AI 读代码时自然就能理解模块职责,不需要额外去翻 wiki

感慨

AI 已经完全的改变了我们的 coding 方式,乃至于我们的生活方式。
我希望我自己变成一个 AI native 的人,适应这个新的 AI 世界。
就像这篇文章也是 AI 写的

致谢

  • Bub( PsiACE )—— CrabClaw 最初的灵感来源,架构设计大量借鉴
  • Zeroclaw —— agent-mode schedule 的参考实现
  • Nanobot —— 最初帮我理解 OpenClaw 架构
  • Frost Ming —— AI Native 理念的深刻阐述


一、 AI Agent落地方法论与技术点

1.怎么选场景,定目标?

相信大家和我们一样,遇到的第一桩难事,就是选场景,定目标。目标场景定的不对,不但常常让产研的心血付诸东流,还会无法形成合力,形成由点线再到面的连招攻击。为了介绍我们如何选场景,定目标,先介绍一下京东保险在干嘛?我们做传统保险,在京东场内还有许多特色服务,比如零售商品延长保障,运费险,不爱吃包退,复购补贴,宠物险,账户安全险,上门医疗险,外卖准时宝等。不看不知道,一看\~还真不知道。为了让大家用的安心,每一个场景都可以有保险参与深度的定制化建设,每一款产品又都有一条完整的产品供应链来保障运行。
在这里插入图片描述

为了回答在哪里开始,我们还需要先了解智能体。

什么是AI 智能体?人就是一个智能体。智能体就是像人一样,能够感知环境、思考决策并执行行动的智能系统。
在这里插入图片描述

Agent有哪些好处?解决哪些痛点?

缺人?—— 高效的AGENT前来救驾,AI Agent产能无限,准实时响应,解锁无限人力能开创的安全度和利润空间。

信息管理难?—— 透明的AGENT前来救驾,数字阳光,腐败绝迹;标准清晰,歧路清零;全局增改,无需培训;自驱自查,终止熵增。

需要自我解释的能力?—— 社交的AGENT前来救驾,建立Agent -人网络,人可监控,修改,接手Agent工作,和Agent合作。建立Agent- Agent网络,解锁群体智能。

业务变化大?—— 自主的AGENT前来救驾,Agent自适应,可以进行目标导向的灵活规划和持续进化。

Agent落地收益预估

当下Agent最擅长代理的类型是——在线的信息处理。在一家商业公司,最适合落地的场景,就是在线的把信息转化为金钱的场景。

智能体落地经济收益公式

R = (Ch - Ca) × D × A × S

R:智能体落地的经济收益

Ch:单位人力成本

Ca:单位Agent运行成本

D:转化链路的直接性(0\~1)

A:Agent智识覆盖度(0\~1)

S:规模

其中:

A= M /(TI)

M: 信息输入量

T 获得反馈的周期(时间单位)

I:基准智识难度(值越大越难)

从我们自己总结的智能体落地经济收益公式可以看到:

知识到金钱的转化路径越直接,原有转化链路成本越高,Agent智识能覆盖的链路和比例越全面,业务规模越大,则收益越大,越适合作为优先落地场景。

其中,Agent智识覆盖度取决于agent本身的准确率,想要Agent的效果好,需要选择场景任务本身难度不超过当下Agent智识可处理的阈值,可输入给Agent的有效指令信息越全面清晰越好,Agent获取外部反馈的周期越短越好。

为什么说保险供应链的生产流程非常适合AI Agent落地?

保险的本质是通过集体协作,将个体不确定的巨大风险损失,转化为确定的小额保费支出。

保险公司就是通过经营风险实现“把个体无法承受的大损失转化为群体可分摊的小成本”,这种经营风险的底层逻辑是基于概率建立起来的,风险的系数的预估是通过信息估算得来的,与AI的决策逻辑一脉相承

保险供应链就是风险这种虚拟的概率型产品从生产到交付到售后的全流程,主要包含产品生产、定价、营销、交易、履约理赔、风控。

•虚拟的概率型产品本质使得AI Agent负责一款保险产品“从生到死”具备了底层逻辑上的可能性;

•保险业务的生产流程高度流程化与规则化,使得这个过程能相对容易地被AI Agent理解与学习;

•保险业务生产流程中,AI Agent提升的是最昂贵、最重复、最容易出错的人工环节,涉及大量知识到金钱的链路转换,收益和价值能直接快速地体现在业务结果中。

直面经营结果(规模/利润)增长而非过程指标的目标设计

Agent中文翻译是智能体,直译是代理。Agent的目标就是所代理角色的目标。成本和规模是最常见的例子,当他们串联成线和面,一个直面经营结果的agent化的保险供应链就产生了。

在这里插入图片描述

2.AI应用于生产是什么样的,需要怎样的技术积累?

在这里插入图片描述

Agent由上述组成部分演化而来,技术底座做的好,核心是每个技术模块的精益求精加整体架构的灵活性和成长性。我们将技术亮点总结如下:

亮点一:领域大模型——场景业务模型微调+小尺寸大模型学习保险数据及行业偏好。

通用大模型虽然具备强大的语言理解和生成能力,但在特定行业和业务场景中往往存在不足,主要体现在:

•领域知识匮乏,尤其是保险,金融领域相关的知识,导致这些领域的专业知识无法精准回答;

•语言风格与行业规范不符,专业性不足;

•价值观与行业导向(如合规、风险控制)不一致;

外挂知识库(RAG)的方式虽然可以部分解决掉专业性的问题,来适配生产流程,但部分ToB场景,及大多数ToC的场景中,尤其是实时意图理解相关的情景,要求大模型自身习得领域专业知识,才能做到精准识别用户意图,因此有必要训练保险领域大模型。

小尺寸模型通过业务数据微调,已经被证明在保险垂类场景可以满足业务需求。大部分ToC场景有实时性需求,需要做到与用户交互过程的实时响应,这也限制了模型参数不能盲目增加。另外现阶段保险AI业务变动还计较多,控制合理的尺寸可以在可控的成本内及时响应不断变化的业务需求 。因此现阶段的最佳选择是训练一个保险领域的小尺寸大模型。随着未来AI业务更加稳定,方法论更加成熟,我们会逐渐增模型尺寸,来达到更好的业务效果。

在这里插入图片描述

亮点:

一、数据驱动的精准洞察力

通过融合海量、高质量的保险领域专有数据,包括:精算级保险条款库:覆盖全品类产品的标准化与个性化条款;真实的电商行为数据:动态反映用户消费偏好与潜在保障需求。通过持续预训练 → 监督微调 → 对齐优化”的三阶段,让模型擅长于条款解读,商机洞察和产品推荐。

二、上下文长度

在小参数模型中,利用上下文差值等技术,让上下文长度和长文本理解能力具有显著优势。为用户提供流畅、即时的交互体验,有效支撑高并发、低延迟的线上业务场景。

三、“LLM as Agent”理念实践

我们将大模型定位为具备任务执行能力的智能体(Agent),而非仅局限于问答系统。模型可主动调用外部工具、实时获取数据并执行复杂逻辑计算,独立完成产品对比、方案定制、核保咨询等全链路保险任务,从而真正转型为一个懂保险、能办事的智能保险专家。

四、少数据量情景下的训练链路设计

一般情况下,持续预训练(cpt)会选择从base model 训练,sft和对齐则从instruct model开始训练,这存在两个问题,一是cpt好的模型还需要大量的昂贵的instruct指令数据才能变成一个成熟的instruct模型,这里的数据成本和流程依赖会大大延迟模型的训练产出效率。二是SFT阶段的造成的对知识的灾难性遗忘很明显,所以需要在流程上或者数据上再去做混合训练来再SFT阶段输入知识,如:hybrid-turning, structTuning, 我们参考SHADOW-FT 的工作,利用BASE模型和INSTUCT模型在参数和后续SFT,DPO训练上表现的一致性,采用在base模型上SFT,和对齐训练,最后再将变化了的参数用一定的方式和Instuct模型叠加 ,获取相似效果来解决之前提到的两个问题。经验证,这种方式结合 structTuning做SFT阶段名词解释和知识注入,在知识保留上有更好的效果。

五、少数据量情景下的样本构造

使用种子数据,利用WizardLM ,MAGPIE,GraphGen,Condor,Self-Instruct,Self-QA,Self-KG等丰富的方法构造多样的训练数据。

六、科学测评

通用能力,保险通用能力,业务能力三方面展开测评,在保险通用能力上,由于没有开源权威榜单,构造相应榜单。

A. 业务把保险领域能力分为了八个维度,每个维度下有多个子类

IDK 保险领域知识:保险知识解读、保险科学

•IMI 保险-医疗交叉:医疗实体抽取与标准化、诊断/Q\&A、风险/处方预测

•IME 保险-电商交叉:商品风险点挖掘,用户POI标签

•IUC 保险理解与认知:意图理解、槽位填充(产品/标的/疾病)、属性抽取、条款解释、责任/产品选择分析

•ILR 保险逻辑推理:精算、金融数学、数值计算、免责条款推理

•IPE 保险职业考试:保险、医/药/兽医执业、精算资格、销售人员认证

•ISC 安全与合规:信息安全、基线控制、文档合规、价值对齐、问题识别、事实核查、合规验证

•IMG 营销增长:客户分群、服务总结、营销文案、推荐脚本、投资者教育、人群分类、策略制定

•ISD 服务对话:覆盖产品/监管解读、核保与保全、理赔评估与结算、保后操作、规划配置、条件化方案选择与对比、保费/保障计算等多轮服务对话

B. 任务格式

•多选(MC)

•判断(TF)

•开放问答(QA)

•多轮对话(MD):模拟真实咨询场景的延伸式对话,要求跨轮次上下文理解与知识应用。

C. 难度 简单(Easy) , 中等(Medium), 困难(Hard)

亮点二:知识库,适配业务的深度检索

在这里插入图片描述

1.表格处理优化:

保险有非常多表格,传统OCR识别表格方法,仅输出文本,表格结构被破坏,无法识别单元格的层级和对应关系,我们经过实验,采用最简单的表格序列化方法,利用大模型对于markdown ,HTML 等序列化语言学习能力,对于非常不规则的表格也实现了很好的理解能力

在这里插入图片描述

转换后的表格<table>| 保障类型   | 场景                 | 区域   | 报销比例 | 免赔额   |保障类型:住院医疗 | 场景:一般住院 | 区域:国内 | 报销比例:80% | 免赔额:1000元  保障类型:住院医疗 | 场景:一般住院 | 区域:境外 | 报销比例:60% | 免赔额:2000元  保障类型:住院医疗 | 场景:意外住院(含手术) | 区域:全部 | 报销比例:90% | 免赔额:500元  保障类型:门急诊 | 场景:一般门诊 | 区域:国内 | 报销比例:70% | 免赔额:200元  保障类型:门急诊 | 场景:特殊门诊(含肿瘤放疗) | 区域:全部 | 报销比例:85% | 免赔额:300元</table>

2.利用层级分片(Structural Chunking),保持多长下文之前的全局一致性

适用材料:保险条款 材料特征: 保险条款具有明确的层级结构(章→节→条→款),逻辑严谨,用户问题往往指向具体条文,如“自燃是否属于除外责任”“等待期内能否报销”等。

技术选型

•按原有层级切分,以“条”或“款”为最小单元。

•每个 chunk 需附带元信息,如章节路径(第×章–第×节–第×条)、险种名称、生效日期等。

延迟切分(Late chunking):保留全局语义、减少割裂

整篇文档索引:首先以较大粒度(整章或整节)生成语义向量,保留上下文全貌

检索阶段粗召回:查询命中的相关章节

命中区域再细切:在检索到章节内部再按照300--600 tokens动态切分

3.微调训练embedding和基于大模型的rerank模块

对于人,条款,场景等关键内容向量化模块进行训练,增强检索效果。数据构造时可以采用假设回答弥补query 和答案之间的gap,训练的目标,即包含准确性,也包含多样性。

4.用意图识别和deepdoc补全复杂query多库搜索的路由模块

和deepsearch一样,query可能混合多库检索需求,或者混合精确查找和语义查找,用deepdoc进行query改写和查询规划,实现复杂查询。

亮点三: Agent做计划,三种策略满足不同场景。

在这里插入图片描述

和人做计划一样,agent做计划,也需要以上四个模块,规划阶段的目标是生成一个高质量、可执行的计划。挑战在于:

理解复杂/模糊的意图: 用户输入往往不精确。

工具选择的准确性: 如何从众多可用工具中选出最合适的?

参数生成的正确性: 如何为选定的工具生成正确的输入参数?

处理依赖关系: 如何正确识别和排序任务之间的依赖?

应对不确定性: 如何制定能够应对执行过程中可能出现的意外情况的计划?

我们混合使用三种方式实现意图识别和流程规划

策略一:基于提示词的流程编排和自主规划
在这里插入图片描述

( 以上图片来自网络,侵权请联系作者删除)

将意图识别和流程反思规划的所有部件和流程写在代码或者提示词里。像上面的表格所示的流程编排,可以互相嵌套,实现很大的复杂性和可控性。适合容错率低,回复时长要求高的场景。

也可以采用纯自主agent模式,如下图所示:利用React,preAct 模式,形成 “plan → act → revise plan” 循环,进行更自主的规划。适合容错率高,回复时长要求低的场景。

在这里插入图片描述

部分固定用途的模块,如意图分类,工具选择和参数提取等,可以训练小的语言模型来实现更好的性能和准确性。

策略二:基于搜索增强的层级规划

这个链路适合海量工具和复杂环境的情况,可以大大减少模型的上下文压力。

基于搜索增强的知识组织及灵活层级规划流程:

Data(线上化索引): 业务落地的关键,不仅要沉淀原始数据、明细数据和结果数据,并明确各类数据的含义,还需系统性地记录从原始数据加工至结果数据的全过程逻辑。

•比如利用 embedding 做一个“候选工具/Agent 粗筛”,再让 LLM 做最后决策

Search: 多智能体扩展的关键,将面向场景的扩展与模型定制化解耦。Agent应用如果伴随模型的定制化优化,将会变成一种很重的模式,从而限制应用的广泛性。用户发布具体任务时,首先将其转化为搜索任务,系统将检索与该任务相关的业务知识、业务逻辑及可用工具等业务导向内容,并提供给大模型进行处理。

Think\&Plan: 根据搜索结果,大模型利用模型的推理能力、思维链、运筹规划等技术,进行深度思考和任务规划,明确后续需执行的操作并进行优化,如形成一个DAG运行图。

Do\&Environment: 大模型利用AI NATIVE的业务系统提供的接口,完成系统调用等流程,实现对业务系统的实际操作。在执行过程中,可以利用编写程序,继续搜索等工具,完成现有工具无法涵盖的新任务。

Reflection: 通过业务系统产生的业务反馈,Agent系统能够自主的思考、优化、沉淀最佳实践,从而持续提升整个链路的运行表现。

策略三:基于RL的自主编排

这个链路适合环境随着agent行为改变比较剧烈的长程规划。我们以赋予智能体“从实践经验中自主学习、持续进化”的能力为核心目标。基于强化学习的模式以最终结果的奖励信号为核心驱动,通过 “行为 - 反馈 - 奖励” 的闭环持续优化策略,这种从结果倒推优化方向的逻辑,与人类 “从实践结果中总结经验、调整决策” 的认知本质高度契合。

智能体的执行过程RL抽象过程:

在关键决策点记录下系统的状态 (State),并明确是什么调用 (Call)触发了从一个状态到另一个状态的转变,捕获这一系列(状态 -> 调用 -> 新状态)的序列。

状态(State) :在任务 x 的第 k 次执行中,时间步 t 的状态由一组变量构成:

在这里插入图片描述

调用(Call) :一次完整的执行由 N 次调用组成:

在这里插入图片描述

其中第 i 次调用的结构为:

在这里插入图片描述

•meta:调用的元数据(如组件名、API端点、LLM温度等)

•input:调用该组件时提供的输入

•output:组件执行后返回的输出

状态与调用的关系:
在这里插入图片描述

带奖励的执行轨迹(Execution with Reward) :将奖励信号加到每次调用上,得到可用于学习的完整轨迹:

在这里插入图片描述

最终将智能体的复杂执行过程抽象为标准的(component, input, output, reward)序列,在智能体的具体实现逻辑与通用的RL训练算法之间架起了一座桥梁,实现了二者的解耦。

应用展示:
在这里插入图片描述

亮点四:如名称Eva(进化)所暗示,架构设计重点保障成长性。

在这里插入图片描述

Eva Agent模块:

包涵四个主要部分:

•Agent专家角色实现——利用大模型实现保险行业的各专家能力;

•Agent专家能力扩展——利用各种外挂工具让Agent更加强大,这些外挂包括:

大脑外挂——记忆模块,让 Agent拥有从经验中学习的能力;

知识外挂——知识库,让 Agent拥有调用外部知识的能力,让Agent的决策更加可控,准确;

手外挂——工具模块,让Agent可以方便的使用各种工具来完成自己的任务。

脚外挂——行为模块,让Agent系统完成与浏览器提供的各种操作。

•Agent专家调度策略——在所有专家Agent之上,更高级认知模块。主要包括反思和计划模块,作用是协调和规划各专家Agent的行为,如任务拆解,优先级排序等,并依据外界反馈,优化Agent的行为。

•Agent专家持续进化——通过反思,训练优化模型表现。

外界任务进入后,Agent通过计划模块将任务拆解为各子任务流程,分派给各专业Agent进行推理。专业Agent调用历史记忆,知识,工具等模块作出决策响应。最后调用行为模块,产生最终行动,作用于EVA浏览器。反思模块再根据浏览器和业务系统的反馈,结合Agent运行产生的记忆,调整优化Agent行为。

经验及时积累,基于self-play 的RL模型进化。

一个自主交互式agent系统,一定要实现自身的进化和成长,不然不足以应对复杂多变的业务场景,而设计一个能从自身和人类经验中学习的系统,是最关键的一步。我们的自主交互式系统如下:

在这里插入图片描述

角色是指用LLM的方式进行角色数字员工的角色扮演,模版角色是指利用可以复用于其他场景的基础角色。

意图识别识别用户意图,我们将意图分为快速问答,知识检索,任务处理 和探索发现类,决定是快速问答,调用知识库,调用任务处理机制,还是上网搜索整合信息以及自由组合多agent完成任务。通过领域与策略的提前区分,平衡速度,准确度,和答案覆盖度。

知识搜索工具是可靠的“资料库和听诊器”,结合深度文档搜索功能,提供高质量的答案。主要采用DeepDoc技术完成,将非结构化的文档(如PDF条款)转化为结构化、可查询、可推理的知识对象并进行自主路由和调用。

记忆系统提供了对话历史和用户背景,分为短期记忆:存储用户最近对话等,长期记忆:存储经常参照的里历史,知识,准则,工作记忆:由LLM抽取器总结的对话和任务状态,情景记忆,对历史不同情景处理的好方案存档。

策略库是由人,或者大模型反思总结起来的策略,包括观察到某种情况时,如何思考和行动,利用策略库达到badcase可控修复,经验沉淀复用的目的。

动作空间是Agent可以灵活决策的空间,自主的Agent系统将自由的选择空间中的工具和知识完成用户请求。

减少幻觉机制是严格的“质检员”,确保每句话都有据可依,在交互前,知识采集时,交互后都可以进行校验确认。

经验池不断根据反馈挖掘用户对话中的好的策略,形成置信度低于策略库的策略,帮助Agent系统把握最新的事件和风险,学习第一手的人类示范,也可用以丰富策略库内容。

•反思进化模块建立基于强化学习的自训练反思链路,交互(通过经验重放,和环境交互,自我博弈产生数据)训练(消化数据,优化策略模型和奖励模型)进化(通过智能体环境循环,让进化步骤自迭代起来) 这个闭环系统确保了智能体在不断试错、学习和自我挑战中,实现真正意义上的“成长”和“进化”。

通过这一整套流程,AI Agent才能在高精度、高风险的任务中,做到既准确又安全,最终成为一个值得信赖的数字员工。

经营结果及时反思,基于智能体角色的离线反思系统设计,实现面向收益和规模的Agent自主优化。

基于结果反馈的离线反思,对于效果也非常重要。

在这里插入图片描述

迭代过程:

1.初始化:这个基础版本的智能体们被赋予了预设的角色、目标和工作流程。

2.执行与评估:执行智能体按照基础配置运行,各司其职,完成任务,产生输出。这些输出接着被评估智能体拿去评估,对照着定性和定量的评估标准,打出一个分数。这个分数就反映了系统当前的性能水平。

****3.优化 优化主智能体分析评估结果,找出改进点。修改智能体 采纳改进方案,调整审核流程 & 规则,AI 评分阈值 & 决策标准。

4.新变体执行与评估:新的系统变体由执行智能体运行,产生新的输出。这些新输出再次被评估智能体评估,打出新的分数。

5.选择与迭代:选择智能体比较新旧变体的分数,如果新变体得分更高,那就说明它更优秀,就把新变体选为最佳变体,替换掉旧的。然后,系统就以这个新的最佳变体为基础,继续进入下一轮的迭代。如果新变体得分没有旧的好,或者提升的幅度很小,低于预设的一个阈值,那系统就会停止迭代,因为这时候再改来改去意义也不大了。当达到最大迭代次数时,系统也会停止。最终,系统会返回最佳变体及其输出,这个最佳变体就是经过多轮迭代优化后的最优系统版本。

3.经验回顾,什么是成功落地关键点?

落地项目,不仅仅是技术问题,这些技术亮点,大多数时候并不是成功的关键。回头反思,我们能顺利落地这些项目的关键,是有一个支持我们的系统。

1.算法向前一步,深入拆解业务,进行AI时代打法设计,搞定高定场景。

纸上得来终觉浅,绝知此事要躬行。尽管我们做了非常多抽象,高定场景业务细节需要算法躬身入局,仔细拆解。

在AI时代,算法了解AI,还需要了解业务。下文我们会仔细分解:定品-定价-履约-风控的目标和打法,与传统时代有啥不一样?看看为啥说理解业务,才是AI落地最关键的一步。

2.前、中、后台设计,助力全链路Agent覆盖

Eva智能浏览器:服务于保险业务各环节,实现与现有保险生产系统的⽆侵⼊集成,打开Eva浏览器自动具备AI助手功能,加速业务系统实现AI化升级

点击查看Eva浏览器视频获得直观感受

通过Eva浏览器打开业务系统,实现无侵入、低耦合采集业务系统页面数据,识别当前用户意图;记录学习用户操作行为,自动生成推荐工作空间。进入空间通过流程编排和多Agent调用,完成AI辅助工作。支持AI对话,多模态输入完成意图识别,调用多Agent精准输出结果,或推荐用户进入相关工作空间快捷开始工作。

Eva智能工作台:打造人与AI教学相长的协作模式,支持快速、高效的业务知识输入和智能体创建,支持AI决策过程的可观测、可运营、可接管,建设透明、可信的智能体过程

在这里插入图片描述

Eva智能体引擎:融合原算法引擎高效的数据->特征->规则->模型->编排的全链路能力,支持灵活的智能体搭建功能,支撑业务落地过程的高效、稳定

•数据链接层:支持灵活的数据接入,通过配置不同数据源(Drois、JDBC、Hive、Oss等)将数据接入系统;

•算力层:提供算法、模型、数据加工方法的发布、销毁、执行能力,支撑系统对数据的运算能力扩展;

•算力调度层:进行计算流量分发,均摊至算力层,同时支持触达业务或其他系统的能力;

•算法编排层:主要负责计算状态的流转,包括既定流程型流转和大语言模型自动判断的流转;

•算法分流层:主要负责ABTest和数据收集功能,提供支撑算法对结果分析、预测的数据;

•算法调用层:业务流量入口;

•管理层:对各层能力及结果进行可视化展示。

3.探索出AI时代的分工,大家搞,才能真的好

我们正从简单反应性 prompt 工程时期,走向更强自主性的多智能体上下文工程时期,在这个事情,我们探索出来的最佳分工是:

1.LLM的优化算法的事情。

2.提示词工程是大家的事情,归根结底是业务的事情。 上下文工程现阶段是算法和研发的事情,归根结底是业务和研发的事情。

3.知识库是研发的事情,知识库需要产品化设计,知识库的组织需要数据团队的设计,知识库维护业务的事情。知识的召回,检索是算法的事情。

4.工具建设(mcp,serverless) 是研发的事情,工具灵活调度是算法的事情。

5.多agent的编排调用是业务的事情,agent的自主调度是算法的事情。

6.agent的测评是算法和测试的事情。

7.agent的反思,进化是算法的事情。

以上分工适合当下情况,agent是个快速变化中的技术,可以预见需要以后机动调整。

二、AI定品

1. AI时代直面业务增长的AI定品能力是怎样的?

看场景:

以延保为例,延保服务产品,1款产品0-1产生约10天+,涉及业务、产品精算、合规等,约至少4~6人协作,还要考虑后续监控,经营,履约成本。目前受限于生产方式,当前平均GMV渗透为0.0x%,只覆盖保费规模非常大的传统品类。

1.大量此前未覆盖的蓝海品类需进行快速延保产品设计上品覆盖;

2.成千上万保费规模非常小的场景,可以由agent去提升覆盖率;

3.定品不是一锤子买卖,当一款品卖的不好,或者超赔时候,及时下架,改价格或者调整条款。

得结论:

AI时代的定品——追求极致的规模

toC——实时直面用户需求的个性化产品定制。

toB——风险点地毯式搜索,覆盖的产品定制—— “品海战术”; 定品不在是在某个时间点发生,而是通过“自主运营”持续不断的改品( 改条款,改价格,改上架状态),直至好品产生

这将改写之前的定品逻辑,产生规模收入。

2. 保险定品的技术设计

技术亮点:deepsearch获取网络信息 + 多维特征深挖场内信息+ 滚动更新保障信息实时 (我们的方案很好的利用统计信息来撬动大模型的创新性)

在这里插入图片描述

3. 当前进展和取得的效果

在这里插入图片描述

三、AI定价

1.从目前业务模式出发,直面业务结果的保险定价能力是什么样?

风险预估准: 预估偏差不高于2%,基于海量数据和机器学习算法,建设千X千面动态定价能力;

经营调整快: 全方位监控实时调整,基于经营预测和运筹优化,从被动调整转为事前主动预防;

报价效率高: 从询价到报价不超过1分钟,用Agent重构询报价流程,建设高效自主的定价专家;

基于AI打造保险行业内预估最准、调整最快、效率最高的定价能力,支撑业务放开手脚、尽情展业

借数据+算法推动业务规模增长,降低边际成本、优化用户体验、提升展业效率,最终驱动订单渗透率、利润等业务核心结果同步增长

在这里插入图片描述

2.为什么风险预估准、经营调整快、报价效率高是驱动规模增长的关键?

从整个保险供应链来看定价位于产品生产之后位于营销交易之前,其合理性直接影响规模和利润。定价需要通盘考虑保障责任、履约方式、运营成本等多个环节。精准性是基石,快速调整护航经营结果,效率是生产力。

保险定价与实物商品差异点就是,保险定价以风险概率为核心。前者聚焦可见的 “实物成本”,后者紧盯抽象的 “不确定风险”。而风险的动态变化和不确定性也为展业和定价带来巨大挑战

在这里插入图片描述
在这里插入图片描述

3.直面结果的保险定价Agent怎么做?

采用自底向上的建设模式,先夯实底层能力/工具,再建设顶层Agent

之所以采用自底向上的 Agent 建设模式,核心原因在于:当前Agent无法完全代理核保、精算、经营等领域专家做出自主决策,也难以独立完成两类关键任务 —— 一是海量数据下基于机器学习的精准预估,二是百万商家/千万商品下的运筹求解。因此,我们的方案聚焦于 “先夯实底层工具能力,再搭建顶层Agent 交互体系”,分步实现能力落地。

AI定价专家:通过多智能体协同,模拟人类决策逻辑,解决定价不准、经营难、效率低等问题

**在这里插入图片描述

很多算法面临的困局——Agent如何与机器学习、运筹和数据协同?

ML、OR、Data都可以被Agent调度,都可以是Agent的工具,各司其职

定价Agent:顶层智能体,负责与人交互、整体调度、协调。

机器学习:被Agent调度,用于数据分析和模型预测。

运筹:被Agent调度,用于优化决策和资源分配。

数据:被Agent、机器学习和运筹优化共同调度,作为共享资源。

大模型自主运筹探索和调研

在大模型自主运筹能力的探索与调研中,我们通过对比多款 “基模”在运筹学领域的表现,并针对 7 个挡位的调价场景模拟不同决策粒度后发现:当前基模仅能在小规模问题中呈现较好效果,难以在细粒度决策问题中实现最优化求解。此外,保险定价本身需基于大数定律开展各类杠杆测算,综合考量业务目标达成、ROI等核心因素后,我们最终确定采用 “自底向上” 的能力建设思路。

3.1Master Agent:系统 “大脑” ,承担业务交互、意图识别及任务调度核心职责,是全流程协同的中枢

**在这里插入图片描述

**

3.2核保Agent:“风险审核与方案优化专家”,以风险可控为前提,探索更具竞争力的报价方案,平衡定价风险与市场竞争力
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.4精算Agent:“定价计算核心引擎”,依托海量数据与机器学习模型,输出科学且可解释的费率表,为报价精准性提供坚实保障

**在这里插入图片描述
**

风险预估准:预估偏差不高于2%,基于海量数据和机器学习算法,建设千X千面动态定价能力

在当前保险场景下,随着海量数据持续积累,传统精算方法已难以满足精准、高效的定价。为此,需基于商家经营、产品画像、用户行为、承保履约等多维度数据,结合机器学习技术,构建 “千X千面” 的动态定价体系,最终支撑业务规模与利润的双增长。

打法3(多模型融合预估):分别建立近7天、10天、15天出险率预估模型,将多模型结果统一校准至满期90天口径,有效提升稳定性和通用性通用性:可快速实现不同保险期间的千店千面定价,定价效率从数月→周级别

通用性:可快速实现不同保险期间的千店千面定价,定价效率从数月→周级别

在这里插入图片描述

打法1(大模型挖掘非结构化特征):基于商品详情页、保障责任、履约方式等数据,借助大模型多模态能力,将非结构化数据转化为结构化特征

打法2(多产品线联合建模):针对出险率与赔款预估的样本选取及模型构建,不再依赖经验进行产品线间的物理隔离,而是对质量、意外、全保等多个延保产品线实施联合建模,进一步提升整体预估精准度

在这里插入图片描述

打法3(实时报价捕捉风险):以 “特征-模型-系统” 为核心,深挖风险特征,快迭代特征体系与定价模型,辅以实时询报价系统,敏锐捕捉风险,强化定价准确性与稳定性

在这里插入图片描述

3.5经营Agent:“价格运营与策略中心”,以全局视角监控定价全流程效果,为经营决策提供支撑,保障定价与业务目标对齐

**
在这里插入图片描述
在这里插入图片描述

**

全方位监控实时调整,基于经营预测和运筹优化,从被动调整转为主动预防

在当前经营中,不仅会因风险预警滞后,让正常的业务经营错失干预时机,还可能因对未来经营趋势判断不足,错失规模扩张窗口与利润优化空间,最终陷入 “调整永远赶不上变化” 的被动局面。

为此,我们建立了一套贯穿 “实时风险感知 - 未来趋势预判 - 科学策略输出” 的全链路闭环管理机制,最终实现从被动应对到主动预防的跃迁

1)经营实时监测:搭建实时、多维的定价数据罗盘及主动触达机制,防患未然

2)未来经营预测:以历史经营数据结合实时监测指标为基,用机器学习预估经营关键指标,提前识别风险和机遇,实现从被动调整到主动预防的转变
在这里插入图片描述

**\
预测目标:** 未来N天每天的整体出险率保费收入赔付支出等。

核心算法:

Prophet: 非常适合具有强季节性、节假日效应的时间序列数据,且对缺失值和异常值稳健。

LSTM: 深度学习模型,能捕捉更复杂的长期依赖和非线性模式。

Transformer: 可融合外部变量,实现多变量时间序列预测,精度极高。

输入特征:

历史序列: 指标过去90天的历史值。

外部变量: 是否节假日、是否大促、实时异常信号、天气预报数据。

3)经营策略制定:结合经营预测结果与既定经营目标,通过运筹优化与沙盘模拟,输出科学决策方案 ,切实提升经营决策的效率与精准度

在这里插入图片描述

3.6从询价到报价不超过1分钟,用Agent重构询报价流程,建设高效自主的定价专家

在保险询报价场景中,展业人员提交需求后,需反复对接核保沟通风险、等待精算测算费率、同步经营端校验,不仅报价周期长,还因人工经验导致定价偏差 —— 既错失商机,又难平衡风险与市场竞争力

以询报价Agent为核心彻底重构询报价流程,大幅提升效率

询报价Agent:Workflow与ReAct相结合的模式,保障稳定性同时具备自主性

7x24小时延保询报价Agent,为用户提供了分钟级报价方案调整建议、信息查询知识问答服务。以京Me/Max/PC为载体,通过自然语言交互支持灵活展业,极大提升展业效率。

4.未来我们怎么做?

建设AI原生的定价范式,驱动规模、利润和体验大幅提升

经营预测: 逐步由机器学习升级为 AI 原生大模型预估,攻克数据稀疏、模型拟合不足和泛化能力弱等痛点。

智能决策: 围绕自动建模、加速求解和可解释性构建运筹大模型,解决运筹建模难、求解慢及难解释等痛点。

端到端决策: 建立端到端决策模型,解决先预测后优化误差传递放大和大规模交易场景无法实时决策等痛点。

在这里插入图片描述

( 以上图片来自网络,侵权请联系作者删除)

数据:多源数据底座

聚合保险、集团内部、外部三类数据,为后续模型提供产品线、供应链、市场环境等全维度、多场景的信息基础,支撑复杂业务下的预测与决策需求。

模型:“经营预测 + 智能决策” 双大模型协同

经营预测大模型:基于多源数据,通过 “特征融合” 整合产品线、供应链等海量业务数据,以 “多任务 + 多目标” 基座模型为核心,再经SFT适配业务场景、RLHF迭代优化,最终得到性能更优的模型。该流程实现了从传统统计学模型到机器学习大模型的技术升级,解决了 “拟合能力不足、泛化性差” 的痛点。

智能决策大模型:遵循 “问题描述→数学模型→垂直场景标签→代码编写→模型求解” 的流程,针对运筹优化场景,结合线性规划、整数规划、启发式算法等方法,实现 “自动建模(降低人工经验依赖)、加速求解(多算法适配不同复杂度问题)、结果可解释(垂直场景标签增强业务可读性)”,破解 “运筹建模难、求解慢、难解释” 的痛点。

端到端:OneModel一体化决策闭环

通过动态规划(DP)、统计方法、策略规则等生成监督标签,基于 “多特征输入(m-fea)→共享特征(share fea)→多子模块(sub1/sub2/...)→多输出(op1/op2/...)” 的 E2E 网络架构,搭配多目标损失函数(如 MinSum 融合 MSE 等指标),直接完成 “数据输入→决策输出” 的一体化过程。这种设计既避免了 “先预测后优化” 流程中误差传递放大的问题,也满足了大规模交易场景下的实时决策需求,实现了端到端决策的闭环。

四、AI履约

1. 直面业务增长的AI履约能力是怎样的?

履约成本一定程度决定定价能定多低,从而影响规模,AI时代的履约就是要直面业务指标和约束,追求极致的成本降低。

核心打法——打造多智能体协同的履约AI Agent,理解保险条款,履约方案、申请材料,面向结果(通过or拒绝)决策,决策效果更好(精准性90%+)、决策成本更低(分级)、决策效率更高(产能无上限)

在这里插入图片描述

2.保险履约的技术设计

在这里插入图片描述

从生产系统调度AI Agent走向AI Agent调度生产系统,通过数据流转互联互通

**
在这里插入图片描述

**

双盲验收测评,分阶段推全上线。

3. 当前进展和预期

经过抽检与测评,履约理赔AI已全量应用过期赔理赔场景,审核准确率94%+;AI审核覆盖业务单量占比95%+,运行稳定,单均审核成本0.02元;得益于审核范围的全量覆盖,对黑灰产与羊毛党起到震慑作用,理赔申请单量与理赔金额持续下降。

五、AI风控

1. 结合保险业务特点,AI驱动的全链路风控体系应该是什么样?

建设覆盖保险全链路的AI风控体系,实现从风险发现到风险处置的全流程自主高效,让保险业务的发展没有黑灰产和羊毛党的后顾之忧。

核保风控: 在极致耗时要求下,以异步方式应用模型识别结果,预防风险发生。

理赔风控: 建设实时大模型理解与预测能力,对已知风险评级,及时阻断风险。

追偿风控: 依托跨时空数据,通过大模型归纳能力发现未知风险,主动追偿。

全流程自主风控: 实现全流程自主高效的风控,通过各环节协同达成风控闭环治理。

保险业务流程:

在这里插入图片描述

2. AI驱动的全链路风控应该怎么做?

当前业务背景及痛点:

保险业务复杂,链路多、周期长:保险业务复杂,各险种业务模式差别较大,整体链路和周期长:包括产品定价、签约、核保、承保、理赔等主要环节。

业务发展迅速,欺诈风险持续存在:保险业务整体发展迅速,像延保、30180等业务规模不断扩展下,也给黑灰产、羊毛党可乘之机,其业务中存在相关欺诈风险,风控侧亟需治理。

黑产变形持续对抗:随着风控侧和黑灰产的对抗,像运费险、晚到赔等业务下,黑灰产攻击手段持续升级,呈现出技术专业化、行为隐蔽化、攻击规模化的特点,风控侧须持续迭代模型,以抵御黑产攻击,保障业务健康。

在这里插入图片描述

2.1 核保风控:在极致耗时要求下, 以异步方式应用模型识别结果 ,预防风险发生。

特点: 核保风控环节流量大(核心险种QPS超1000)、耗时要求严苛(响应需≤20ms),无法直接应用模型实时预测风险。

思路: 采用 “预计算+实时调用” 模式,先通过模型提前完成风险识别与判断,将结果转化为标准化标签;核保流程中直接调用预生成标签进行决策,既充分发挥模型的风险识别能力,又满足时效要求,实现风险提前预判。

打法一:通过数据分析挖掘,构建核保环节特征体系,以规则布控预防风险。

针对已知、明确、高确定性的风险模式,依托完善的核保特征体系,使用实时规则进行拦截,做到高效精准。

打法二:结合策略命中及无监督模型挖掘的风险,通过关联分析形成风险名单库。

通过关联分析发现个体背后隐匿的群体性风险和****关联风险,将分散的风险点串联成网,形成动态共享的风险名单库。即使黑产更换了身份证、账号,只要使用了相同的IP、设备或联系方式,依然能被迅速识别出来。

2.2 理赔风控:建设实时大模型理解与预测能力,对已知风险评级,及时阻断风险。

特点: 该环节是保险风控的重中之重,直接决定业务利润空间的大小,对于欺诈理赔请求,直接进行风险拦截可转化为成本节约。相较于核保风控环节,该阶段对耗时的要求稍有放缓,允许我们通过实时模型进行风险决策,并且能够使用比较复杂的模型进行实时识别和风险阻断。

思路:

•兼顾和黑产对抗的灵活高效,同时考虑和黑产对抗的鲁棒性和泛化性,采用规则+小模型+大模型的三路并跑的方式进行实时风控治理。

治理阶段:

在这里插入图片描述

打法一:规则风控,结合多维度的风险表现,构建完善的特征体系,通过灵活高效的规则布控快速拦截风险。

规则风控主要基于明确的风险表现,将 “风险判定逻辑” 转化为可执行的条件,直接使用规则结果进行拦截,并根据黑产的变化可以灵活快速调整,规则风控承担着 “第一道防线” 的关键角色,主要特点是 “看得见、可解释、易调整”。通过构建完善的风控特征体系,可以覆盖保险业务的风险表现,基于规则引擎进行规则策略的快速布控。不同规则的布控,需结合业务特点和黑灰产的风险表现。详情如下

打法二:小模型风控,利用小模型的成本优势,可以保障风控效果,提高泛化。

当各业务的风控规则积累到一定厚度后,有一定量级的标签和特征数据,可以针对特定场景和风险进行轻量级模型的构建,提高风险对抗的鲁棒性,并进一步增强风险识别的泛化能力。根据模型的作用不同,小模型风控主要包括功能型决策型两类:

功能型模型:着重对某一个功能的事实性判断,可以在不同业务场景进行快速复用;

决策型模型:可以替代原有的规则引擎,直接进行决策,着重对具体业务和问题进行风险判断。

在这里插入图片描述

打法三:大模型风控,基于大模型的通用世界知识及强大的学习理解能力,通过多维度数据融合进行风险决策。

基于小模型进行实时决策,依赖特征工程,在保险业务风控中,通过大模型决策,可整合多维度数据(请求数据、统计特征、行为序列、用户画像等),具备更强的泛化与决策能力,并且仅需少量级的标注数据就可以取得不错的效果。

通过大模型进行实时风险决策,主要思路从欺诈行为的本质出发,捕捉违反业务逻辑(物流时间异常、物流无轨迹)、用户行为异常 (高频理赔、切换设备)、团伙关联 (BC联合、共用设备/IP)、虚假交易 (虚假地址、虚假发货、伪造物流单)以及后续新型欺诈等多类风险信号,可以通过如下阶段:

大模型风控实时决策流程:

在这里插入图片描述

2.3 追偿风控:基于跨时空的数据,通过大模型的归纳能力,及时发现未知风险,主动追偿。

特点: 该阶段由于欺诈已经发生且未知,证据链隐藏在跨时空的海量数据中,重点在发现团伙欺诈和未知欺诈模型。对耗时没有硬性要求,可利用的数据最为全面,广度上可使用多域数据(保险、零售、科技、物流、健康、外部数据都可以),深度上可使用跨时空数据(欺诈发生时刻、发生之前和发生之后的数据都可使用)

思路: 以擅长总结及归纳的无监督算法及大模型为主,同时也要兼顾该环节挖掘风险结果的使用,可通过不同颗粒度的时效进行应用,以反哺其他风控环节。

打法一:通过数据统计及关联分析方法,挖掘明显的作案风险。

主要通过对“电商交易 - 保险行为 - 跨域关联”全链路数据的深度分析,识别隐藏的欺诈模式、不合理赔付风险等,包括单维度异常识别和多维度关联方法等。

打法二:通过无监督算法,发现具有一定规模及隐蔽性的风险模式。

主要是从无标注的海量数据中,自主发现隐藏的风险模式(如欺诈团伙、异常群体等),无需依赖历史欺诈标签。主要包括社区发现算法等。

团伙挖掘:

在这里插入图片描述

3. 当前进展和取得的效果

核保风控: 目前以标签的形式周期性应用模型结果,小时级别进行团伙挖掘,自动应用于签约、核保等环节,已在运费险、外卖险、质保金等业务应用。

理赔风控: 实时反欺诈模型、异常图像识别模型、社区发现模型等在保险核心业务场景应用,并实现实时大模型风控在保险及集团的首次应用。

•场景覆盖:包括运费险、延保等核心险种;

•线上效果:风控模型累计减损数千万;

•大模型风控:具有良好的泛化性和鲁棒性,并且只使用了小模型5%的数据就能覆盖其99%的拦截效果且还有额外新增,成本也几乎没有增加。对于黑灰产攻击,有很好的拦截效果,过往可以达到99.95% 的拦截率。

追偿风控:目前社区发现算法、关联方法等应用在运费险、外卖险、延保等主要险种,可以实现分钟级别的更新及应用,可支持打击侧同事近一步分析及追偿,同时将风险结果以标签形式应用于线上。

4.未来我们怎么做?

4.1 夯实核心环节的风控能力,并扩大应用覆盖范围

核保风控: 结合多模态数据,通过大模型预测风险概率,生成标准化标签。离线形式下,不再孤立处理数据,将核保、理赔、追偿环节中的结构化数据与非结构化文本、图像数据融合,通过大模型进行深度关联分析与推理,生成远超单一数据维度的、具有高预测价值的风险概率标签

理赔风控:完善覆盖欺诈本质的语料知识库,通过多模态数据融合提高大模型风控的风险识别能力。同时,构建保险通用风控大模型,只需针对特定业务风险微调模型即可快速应用。

追偿风控: 基于知识图谱和大模型,挖掘具有关联性的隐性及潜在风险。知识图谱具有结构化的特点,有可推理能力,大模型具有语义理解及生成的能力,将二者结合起来可以提升风险挖掘的深度和广度。

业务覆盖: 扩展当前风控能力的覆盖范围,实现核心业务险种的全覆盖。

4.2 实现全流程自主高效风控,通过各环节协同达成风控闭环治理

基于多智能体协同实现保险全流程自主风控体系,其核心是建立一个中央指挥智能体—风控Master Agent,像“风控大脑”一样统筹调度核保、理赔、追偿各子环节Agent。整个运作机制形成了一个“感知-决策-执行-评估-优化”的强闭环,使系统能够不断自我迭代。

通过风控Master Agent统筹调度核保、理赔、追偿各子环节Agent,实现从全局感知、智能决策、协同执行到效果评估的闭环自治。

全流程自主风控:

在这里插入图片描述

六、回顾

以AI驱动的保险供应链X产品线25年为业务带来15%+利润

**

在这里插入图片描述

**

七、展望

结果第一:

1.夯实保险B端供应链Agent建设, Agent带来的直接利润占业务总利润 30%以上。

2.toC 场景发力,保顾,客服数字人服务客户,拓展规模。

在这里插入图片描述

3.在持续沉淀toB能力基础上,打造200+AI数字员工,大幅降低边际成本、提升运营效率。

在这里插入图片描述
在这里插入图片描述

技术为本:

💡1.持续优化自主Agent系统,让Agent更加AI Native,更加智能。

写在前面的话

今天不想讲那些技术架构图,也不想堆砌一堆iOS专业术语。我就想聊聊,作为一个离用户最近的客户端开发,我是怎么看待AI的——它到底是让咱们的产品变更好了,还是变更拧巴了。梁宁老师在《增长三十讲》里说过一句话特别打动我:"产品经理要有同理心,要能感受到用户的爽点、痛点和痒点。"今天我想说,做技术的人也得有同理心。不只是对用户,更是对我们自己。


一、开场:一个真实的冲突场景

先讲个事儿

这种场景你们熟不熟悉:

AI同学:"我们的新模型精度提升了10个点,识别更准了!"

3D同学:"等等,你这模型多大啊?"

AI同学:"也就60MB,还行吧。"

3D同学:"那推理时间呢?

AI同学:"大概增加了30-40ms……"

客户端同学心里咯噔一下:"完了,这玩意儿肯定得出事。"

产品经理:"太好了!竞品最近上了很多AI功能,我们也得跟上!"

具体数字每次不太一样,但这个对话的"味儿",基本就是这样。

然后真出事了

功能上线or demo演示第二天,用户反馈炸了:

  • "手机烫得要命"
  • "电池一小时掉30%"
  • "卡顿严重,没法用"

领导问:"怎么回事?不是说AI很智能吗?"我们说:"AI是很智能,但用户的手机不够智能。"

所以今天我想和大家聊聊,怎么避免这种"好心办坏事"。


在这里插入图片描述


这就是梁宁说的"系统思维"缺失

每个人都是对的:

  • AI团队追求精度,这没错
  • 3D团队追求画面,这也没错
  • 产品追求竞争力,更没错

但系统错了。

在这里插入图片描述

梁宁说,"很多时候,你觉得是做加法,但对用户来说是做减法。"AI功能加上去了,但用户体验减下来了。


二、用户真正要的是什么?——梁宁的"爽点、痛点、痒点"

梁宁的理论我是这么理解的

在这里插入图片描述

爽点:即时满足痛点:恐惧、焦虑痒点:满足虚拟自我放到移动端AR里:用户的爽点:

  • 手势一挥,虚拟物体就出现(延迟<50ms)
  • AR识别又快又准
  • 效果炫酷,朋友圈能装逼

用户的痛点:

  • 手机发烫(恐惧:会不会炸?)
  • 电池狂掉(焦虑:等会儿没电了)
  • 卡顿延迟(愤怒:什么破玩意儿!)
  • 应用被杀后台(崩溃:我刚才做的全没了)

用户的痒点:

  • 比别人用更高级的功能
  • 展示自己的设备够好

AI在这里的定位是什么?

在这里插入图片描述

很多人以为AI是爽点。但实际上,AI做不好,就是最大的痛点。为什么?因为用户不关心你用了多牛逼的模型,他只关心:

  1. 快不快?(延迟)
  2. 准不准?(准确率)
  3. 烫不烫?(功耗)
  4. 掉不掉电?(续航)
  5. 卡不卡?(帧率)

AI如果让这5个变差,用户不会夸你智能,只会骂你智障。


三、移动端的残酷真相:80%用户用的不是旗舰机

设备碎片化有多恐怖?

最大的感受就是:不要用你自己的iPhone15Pro来代表用户

在这里插入图片描述

真实情况是:

  • 约10-15%用户:iPhone 15/16/17 Pro,小米15Pro,华为meta 70/80pro(土豪)
  • 约50-60%用户:iPhone 12/13/14,中端安卓(大多数)
  • 约30%用户:iPhoneX,老安卓(学生党、爸妈辈)

同一个AI模型:

  • 旗舰机:推理20ms,丝滑
  • 中端机:推理60ms,凑合
  • 老设备:推理150ms,根本跑不动

性能差距:接近10倍!

场景碎片化

移动端的独特挑战:1. 多任务干扰

  • 后台应用争夺资源
  • 系统推送、来电、切换应用随时发生
  • iOS/Android的激进内存管理,容易被杀后台
  1. 环境不可控
  • 室内外光线差异极大(影响AR识别)
  • 移动网络不稳定(影响云端AI)
  • 用户使用时长不确定(5分钟 vs 30分钟)
  1. 发热和电量焦虑
  • AR全开运行,手机30分钟必然发热
  • 发热后CPU/GPU降频20-40%
  • 用户对"耗电"和"发烫"的应用极度敏感

从我的观察和行业数据来看:

使用特点:

  • 移动端AR不像VR,用户很少长时间沉浸
  • 大部分使用场景是"短平快"(几分钟到十几分钟)
  • 经常被打断(来电、通知、切换应用)

用户容忍度:

  • 启动慢:如果3秒内没响应,大量用户会放弃
  • 卡顿:即使偶尔卡一下,用户也会很敏感
  • 发热/耗电:这是移动端用户最敏感的两个点

根据应用商店评论和用户反馈,

负面评价主要集中在:卡顿、发热、耗电。


梁宁说的"确定性"在哪里?

梁宁强调,好产品要给用户确定性。什么叫确定性?就是用户知道会发生什么,并且确实发生了。

在这里插入图片描述

反例:只为高端设备优化

  • 高端用户:哇,好流畅!(20%的人爽)
  • 普通用户:卡成PPT……(80%的人骂)
  • 用户体验:不确定、分裂、崩溃

正例:分层体验

  • 高端用户:用高级功能
  • 中端用户:用标准功能
  • 低端用户:用基础功能
  • 所有人都能用,只是精细度不同
  • 用户体验:确定、可预期、没有绝对的失望

四、AI部分深入:不是技术问题,是人性问题

1. AI的三个常见误区

在这里插入图片描述

误区1:"模型越大越好"这是技术人的执念。AI同学会说:"我们的模型精度提升了5个点!"但用户不会说:"哇,精度从89%提升到94%,我好感动!"用户只会说:"为什么我的手机这么烫?"梁宁视角:你在追求技术指标,用户在追求情绪稳定。


误区2:"端侧AI就是先进"很多团队为了宣传,强调"本地AI、保护隐私"。但真相是:

  • 端侧AI:功耗高、发热大、速度看设备
  • 云端AI:功耗低、速度稳定、但需要网络

没有绝对的优劣,只有场景适配。实时交互(如手势识别):必须端侧非实时分析(如场景理解):可以云端,梁宁视角:不要为了"先进"而先进,要为了"用户体验"而先进。


误区3:"AI失败了就提示用户"最常见的做法:

AI识别失败

→ 弹窗:"识别失败,请重试"

→ 用户:???

这是最烂的体验。更好的做法:

AI识别失败

→ 自动降级到传统方案

→ 用户无感知

→ 核心功能继续可用

梁宁视角:别让用户承担你的技术缺陷。技术的不确定性,不应该转嫁给用户。


2. AI在移动端的正确打开方式

梁宁说,"产品要克制"。我对AI的理解也是:克制。

原则1:轻量化优先

案例:手势识别模型优化

模型大小设备覆盖率精度
60MB(原始版)▌▌ 20%94% ⚠️
15MB(量化版)▌▌▌▌▌ 70%92% 👍
8MB( 剪枝版)▌▌▌▌▌▌ 85%89% 👍
3MB(Lite版 )▌▌▌▌▌▌▌10085% ✅

在这里插入图片描述

原始模型:60MB,精度94%

→ 量化后:15MB,精度92%(损失2%)

→ 剪枝后:8MB,精度89%(损失5%)

→ 蒸馏后:3MB,精度85%(损失9%)

决策:

  • 3MB版本给所有设备(100%可用)
  • 8MB版本给中高端设备(70%可用)
  • 15MB版本给旗舰设备(20%可用)

牺牲9%精度,换来100%覆盖率。梁宁视角:让80%的人满意,比让20%的人惊艳更重要。


原则2:优雅降级

永远不要让用户看到"功能不可用"。

在这里插入图片描述

分层设计:

L1(保底):所有设备都能跑

L2(标准):中高端设备体验更好

L3(高级):旗舰设备极致体验

动态监控:

运行中监控:

  • 帧率<50fps → 降一级
  • 温度>45度 → 降一级
  • 电量<15% → 降到L1

用户感受:

  • 不会突然"卡死"
  • 不会看到"加载失败"
  • 体验平滑降级,几乎无感知

梁宁视角:确定性= 用户知道最坏会怎样,并且最坏也还能接受。


原则3:端云协同

不是所有AI都要端侧跑。

在这里插入图片描述

实时场景(端侧):

  • 手势识别
  • AR追踪
  • 实时渲染

非实时场景(云端):

  • 场景语义理解
  • 复杂物体识别
  • 大规模计算

网络不好时:

  • 云端功能降级
  • 端侧保底继续跑
  • 用户核心体验不受影响

梁宁视角:系统要有冗余,有备份,不能把所有鸡蛋放一个篮子。


3. AI不是炫技,是解决问题

梁宁说,"用户要的不是你的产品,是他问题的解决方案。"用户的问题是:

  • 想用手势操作虚拟物体(问题)
  • 不是:想体验最先进的AI模型(手段)

所以:

  • 如果ARKit原生手势能解决80%场景→ 用它
  • 如果简单的传统算法能解决→ 用它
  • 只有必须用AI才能解决的,才上AI

AI是工具,不是目的。


五、思考:如果要做AR手势交互,怎么选方案?

假设场景:我们要做一个AR应用的手势交互。

第一反应:用ARKit手部追踪,系统级能力。

但需要考虑这些问题

设备兼容性:

  • ARKit手部追踪需要A12+(这是官方要求)
  • 老设备怎么办?放弃,还是提供替代方案?

性能开销:

  • 手部追踪会增加系统负载(这是必然的)
  • 如果AR场景本身就很重,还跑得动吗?
  • 用户会不会觉得卡?

功能适配:

  • ARKit提供标准手势
  • 如果我们需要特殊交互呢?

系统能力很好,但有边界。

我们需要:

  • 覆盖不同设备
  • 控制性能开销
  • 满足定制需求

重新设计:分层适配

梁宁说,"要理解不同用户的不同需求。"我们设计了三层:

在这里插入图片描述

L1:传统交互(100%用户)

  • 屏幕点击+ 注视高亮
  • 不酷,但稳定
  • 这是保底

L2:ARKit手势(60-70%用户)

  • iPhoneXS+自动启用
  • 点击、抓取、滑动
  • 这是主流体验

L3:自定义AI(10-20%用户)

  • iPhone14 Pro+
  • 复杂手势、品牌定制
  • 这是高端差异化

动态降级:核心逻辑

用户使用过程中,设备状态会变化:

录屏2026-01-21 17.34.50.mp4

每秒检测:

  • 帧率<50fps → 降一级
  • 温度>45度 → 降一级
  • 电量<15% → 强制L1

用户感受:

  • 不会突然功能消失
  • 平滑切换
  • 给个温馨提示:"手势已暂停(性能保护)"

结果

这种分层设计的结果:

✅ 100%用户可用(这是底线)

✅ 大部分用户能体验到手势交互(60-70%)

✅ 卡顿投诉显著下降

✅ 帧率更稳定,体验更流畅

梁宁视角:这叫"分层满足"。

高端用户有高端体验,

普通用户有稳定体验,

所有人都没有被抛弃。A


六、AI在移动端的4个核心洞察

在这里插入图片描述

洞察1:AI是提效工具,不是门槛

正例(基于行业观察):

一些做得好的AR应用会这样设计:

  • 高端设备:精细建模+实时光影
  • 中端设备:简化建模+基础光影
  • 低端设备:2D贴图+手动调整(无AI也能用)

这种分层设计的效果:

  • 所有用户都能用
  • 应用评分和口碑明显提升
  • 负面评价大幅下降

梁宁视角:AI应该降低门槛,而不是提高门槛。


洞察2:免费≠无成本

ARKit虽然"免费"(不用下载模型),但:

  • 运行时消耗GPU
  • 占用电量
  • 发热降频

系统能力也有成本,不要以为调个API就完事了。


洞察3:80%能用 > 20%完美

梁宁说,"不要让完美成为好的敌人。"移动端开发最大的教训:

  • 别追求在旗舰机上的极致体验
  • 要追求在大部分设备上的可用体验

精度从94%降到85%,换来设备覆盖率从20%提升到100%,值不值?值。因为用户要的不是你的精度数字,是"能不能用"。


洞察4:保底方案决定产品下限

梁宁说,"产品要有底线思维。"AI会失败,这是确定的。所以:

  • 每个AI功能都要有PlanB
  • 每个智能交互都要有传统备选
  • 每个高级体验都要有基础保底

60%用户好体验+ 40%用户能用,远比80%用户都不够好更明智。


七、站在不同视角

在这里插入图片描述

站在AI视角

理解:客户端不是服务器。提供:

  • 轻量版模型(<10MB,所有设备能跑)
  • 标准版模型(15-20MB,主流体验)
  • 完整版模型(可以放云端)

最重要的是轻量版!因为它决定了产品的下限。


站在3D引擎视角

理解:GPU是共享资源。提供:

  • 3档渲染方案(高/中/低)
  • GPU占用率监控API
  • 动态降精度能力

我们一起守护用户的帧率。


站在产品视角

理解:不是所有功能都要加。思考:

  • 这个功能解决什么用户痛点?
  • 在中低端设备上体验如何?
  • 如果功能失败,用户怎么办?
  • 我们愿意为了这个功能牺牲什么?

梁宁说:"产品要克制。"


八、三点感悟

在这里插入图片描述

感悟1:技术是为人服务的

刚入行时,我追求技术极致。现在我明白,技术的价值在于让更多人受益。80%的人能用,比20%的人惊艳更重要。


感悟2:不要只做功能,要做体验

十年前,产品说加功能,我就加。现在我会问:

  • 这解决什么问题?
  • 中低端设备怎么办?
  • 失败了用户怎么办?

感悟3:客户端是用户的守门员

梁宁说,"产品经理要有同理心。"我想说,客户端开发也要有同理心。我们最懂用户的真实设备和使用场景。所以我们有责任说:

  • "这个方案在他们的设备上真的能用吗?"
  • "这会不会让大部分用户体验变差?"
  • "我们有保底方案吗?"

我们不只是写代码,是为用户体验把关。


九、总结:AI给移动端续命,还是催命?

在这里插入图片描述

回到标题这个问题。答案是:

用得好:

  • AI让功能更智能
  • 降低交互门槛
  • 用户体验更流畅

用得不好:

AI让设备卡顿发热

提高使用门槛

用户体验变差

这不是AI的错,是我们用AI的方式。

关键在于:

同理心 理解用户的设备、场景、情绪

克制 不是所有地方都要用AI

分层 让所有人都能用,只是精细度不同

保底 永远有Plan B,永远不让用户卡死平均使用时长:

梁宁说:"好的产品,是克制的产品。"我说:"好的AI集成,是克制的AI集成。"


最后的话

在这里插入图片描述

这次分享的核心信念:> 技术的价值不在于"我们能做到多先进",而在于"我们能让多少人受益"。移动端开发的本质:> 在约束中找到最大公约数,让大部分人满意。这需要:

  • 对用户的深刻理解
  • 对技术的务实态度
  • 对团队的有效协调
  • 对长期的负责任

═══════════════════════════════════════

谢谢大家

         ─────────

        欢迎交流讨论

═══════════════════════════════════════

数据参考:

XR性能测试。。

导读

随着京东业务增长、平台商家数的大幅增加,京东的订单量急剧上涨,尤其是2025年京东发力本地生活业务,给B端订单存储带来较大压力; 另一方面京喜自营做为京东低价策略心智的店铺,业务增长也是非常迅猛,一个店铺订单相当于几十近百个店铺单量总和。基于以上订单ES存储面临极大挑战,系统架构升级迫在眉睫。

本文主要介绍B端pop订单异构系统当前系统架构现状,阐述下我们面临的主要问题、以及解决思路和技术升级方案(后续持续更会有更多的技术方案细节文章);一方面为了介绍下我们当时解决问题的一些心路历程,另一方面也未了能让大家更好的了解目前这套运行了多年的系统为什么以这种形式存在、以及目前我们遇到的核心问题有哪些,对于订单ES架构存储的升级方案是什么样的。

一、系统现状

1.1 业务背景介绍:

POP订单ES最早定位是对商家提供待履约订单查询服务(非C端检索)。系统核心是写和读两个服务,写服务消费订单管道消息、pop订单JED的binlog、OFW的ODC变更消息、台账系统对账消息等更新订单ES数据;读服务提供订单列表(商家维度)、订单详情的检索服务。

系统之初仅支持已付款且达到可履约状态的订单(不包含未付款订单)检索,用户商家订单履约,主要服务于开放订单API检索及京麦端订单检索。随着业务的发展,后续消费了提单、订单拆分、预售订单等消息,对未付款订单、预售订单存储、兼容处理。

随着百万商家项目推进,服务商、自研KA商家及中小开发者对开放API提出了更多的诉求,期望能够通过更少的接口获取更多的数据,提升开发者对接及日常维护效率,开放平台侧启动开放RESTful API项目,其中订单做为商家的核心业务数据,历史开放接口不够内聚,开发者需要多个接口才能获取完整的订单信息,基于以上pop订单还异构了发票、promise、售后、评价等系统的状态信息,这些都给POP订单ES存储带来较大的挑战。

1.2 系统架构简介:

应用层做业务处理 写服务负责消费上游各方MQ处理业务务处理,之后调用代理层服务更新订单信息;读服务核心对外提供订单列表、详情两个服务。大促高峰时可达到每分钟70万次更新写入,每分钟50万的检索查询;

代理层负责数据路由、读取与写入。划分为热集群读写代理、归档集群读写代理。热集群通过设置不同topic分组隔离消费实现双流架构,汇天廊坊互为主备保证系统高可用。读服务支持动态路由配置,可根据ES负载情况动态分配流量,如汇天、廊坊各百分之50流量,或汇天20%,廊坊80%;同时可以将某个商家查询流量路由到固定机房。目前归档集群考虑成本暂时并未升级至双流架构,通过ES副本机制来保障高可用。

存储层采用ES做为存储介质,分为热集群、归档集群;热集群存储近8个月的订单数据,单个集群有98个节点(3个主节点,10个网关节点,85个数据节点)。集群中共计12个索引,其中11个KA索引(存储大商家订单数据),每个索引只有1个主分片(1副本);普通商家索引有96各数据分片(1副本);冷集群存储了16年至2024年所有的订单数据,每年创建一个索引,每个索引96分片(1副本)。

pop订单改造前的架构图如下: (为方便让大家更好理解,本图会忽略一些细节便于大家理解):

在这里插入图片描述





二、系统当前的核心痛点

1、目前POP订单ES存在较严重的数据倾斜问题,由于是B端订单检索为了不跨索引和分片检索数据,是以venderId维度进行路由分片,确保同一个商家的订单数据存储在同一个分片。但商家的经营情况差异较大,如上边所说京喜自营做为一个京东自己运营的店铺,订单体量可以占到总订单量的1/4,类似于这样的大商家落到一个数据分片会导致某个数据分片存储超级大,最大的数据分片已经到了1TB以上。大商家的一个复杂检索查询会对所有在该分片上的商家产生较大性能波动,同时若硬件故障大分片数据在恢复迁移时都是在灾难性的。下边是升级前汇天集群部分分片数据的统计信息,数据差异达5倍之多。

在这里插入图片描述



2、随着业务增长,自身的订单ES数据量持续增加,部分分片数据高达1TBG以上,ES官方推荐分片数据在50-100G,已经是官方推荐值的50倍。京喜自营订单属于二段单逻辑,C端京喜大店下单,订单会由供货商去履约,供货商同时还会是京东的一个pop商家,这个订单在京喜店铺存储一份,同时会在供应商店铺下会在存储一份,京喜大店业务给整个存储带来了0.5倍增长。

在这里插入图片描述



3、ES的核心数据源是上游订单数据库的binlog消息,随着业务不断迭代,接入了更多的消息如:order\_submit(提单)、delete\_parent\_order(拆单)、orderpipe\_edit\_v2(管道修改)、ODC(锁定、解锁、取消)、order\_state\_zanting(暂停)、afs\_status(售后状态)、comment\_change(备注变更)等将近10+的消息。订单ES更新频次持续增加,每分钟高达30万,每新增一个MQ消费,每个订单至少会增加1次更新操作。ES的更新冲突明显增加,对于订单检索的时效性也带来了很大压力。
在这里插入图片描述

4、数据维护成本高, 目前我们有冷热两个集群,每年两次大促前需要将热集群中超过5个月以上的订单迁移至归档集群,这个过程相对比较繁琐耗时长,DUCC变更、迁移数据、比对数据、灰度切流等等。周期较长主要是以下两个原因:

1.数据迁移范围强依赖上游订单JED线上库,速度过快对线上有影响,同时还会反查ES数据比对给线上ES也带来较大查询压力,导致无法再白天运行。

2.整个写入过程均为单个订单写入、删除ES,过程中会产生大量的Segment merge,将小段合并成大段,会影响写入性能,导致正常订单更新延迟。

在这里插入图片描述



三、解决方案

3.1 数据倾斜问题

数据倾斜问题核心是我们采用了venderId进行路由,商家的体量不可控,在最初相关同学已经考虑到了这种情况,在热集群中创建了对应的单独索引进行隔离,但当时这个索引创建的时候只有一个shards,数据集中在一个分片上,并不能解决数据倾斜问题(数据仍集中在一个分片上,可能考虑跨分片聚合数据的性能问题)。

1.物理层隔离,降低影响: 为大商家申请独立集群进行存储,在独立集群中为每个商家创建独立索引并根据体量配置不同的分片数量。代理层增加大商家虚拟路由逻辑, 将大商家的请求routing到独立集群中指定索引,降低了大商家对其他商家带来的不确定性影响。

2.灵活的路由分片策略: 原有路由策略仅支持商家维度,在代理层对集群分片路由规则做扩展支持,针对大商家存储集群的分片路由商家维度升级为订单维度,根据订单号进行路由保证各分片数据的均等。

在这里插入图片描述

3.2 集群中单数据分片过大问题

ES官方建议单分片数据控制在50-100G,同时ES集群节点(网关、主节点、数据节点)数量控制在100个以内(故障恢复时长考虑,可参考附录5)。基于这两个原则,单集群已无法满足存储诉求,当时也考虑了更换存储介质,考虑到端上丰富的查询诉求,团队内部研讨后决定继续采用ES。

我们决定将热集群中普通商家的ES集群由1个扩展至3个(基于当前业务发展及成本综合考量决定)。在数据代理层扩展集群路由逻辑,基于商家id哈希将商家数据分散到3个ES集群。


在这里插入图片描述



3.3 ES频繁更新的问题

当前系统采用了ES的乐观锁更新机制,在收到上游消息后,第一步获取ES版本号,第二部设置更新字段,第三部保存更新,保存更新版本冲突会发送一个重试MQ进行重试。

经过分析订单变为待出库前的消息比较集中,上游各系统基本都是同步消费订单管道消息完成业务操作后对外广播消息,这些消息同时到达我们系统,一方面存在并发冲突问题,第二方面是给ES带来了较大的更新压力。为了降低ES的更新压力,考虑增加一个挡板对消息进行汇总整型降低ES的更新次数,同时减少ES的更新冲突问题。

在这里插入图片描述

3.4 日常数据维护成本高的问题

受限于ES集群节点数量是有上限,大促前都需要对热集群订单数据进行归档操作,由热集群迁移至冷集群。系统初始是通过一个归档任务来进行迁移操作。首先圈定迁移数据的范围逐条读取--->逐条写入归档集群--->比对数据无误--->删除热集群数据。业务高峰期无法操作,新增、修改、删除对频繁删除会产生很多的段文件,ES定期对段文件进行merge操作(详情可参照附录部分内容),单次数据迁移大概耗时1个月左右时间,操作过程也较繁琐。我们的目标是全流程自动化的数据迁移无需人工介入,仅需要关注相关业务监控即可。考虑到资源及ROI问题,数据迁移改造共经历了两个阶段:

第一阶段通过通过reindex方式迁移数据,然后通过回放归档消息的方式追齐过程中的数据变更。该方案一定程度缩减了整体的时间及工作量,相较之前效率上大幅提升,时间大概由原来的20多天缩减至10天左右。

在这里插入图片描述



第二阶实现数据归档的全流程自动化操作。新建归档ES缓存,每天一个索引,把每天订单变更记录保存至索引中。通过一个定时任务批量读取、比对、写入同时删除原集群中数据。


在这里插入图片描述



3.4 终局方案

本次升级通过 “租户分级隔离 + 双层 Hash 路由 + 差异化分片策略 + 双活物理底座” 的组合拳,成功构建了一个 高性能、高扩展、高可用 的企业级订单检索与分析平台,完美支撑了业务量的爆发式增长。

在这里插入图片描述



四、附录:

4.1 超大集群维护的挑战

ES 是一个 P2P(对等)架构的分布式系统,虽然有 Master 节点,但所有节点都需要保存集群的状态。核心瓶颈:Cluster State(集群状态)的广播

ES 的 Master 节点负责维护 Cluster State(包含所有索引的 Mapping、Setting、分片路由表等元数据)。

每一次变更(如创建索引、Mapping 变更、节点上下线),Master 都要把更新后的 Cluster State 广播给集群内的所有节点;所有节点收到后,都需要向 Master 确认(Ack)。

当节点数超过 100 时会面临以下问题:

1)网络风暴: Master 发布一次状态更新,需要处理大量的网络包。如果更新频繁(例如大量创建索引),Master 的带宽和 CPU 会瞬间饱和。

2)收敛慢: 必须等待绝大多数节点确认,集群状态才能生效。节点越多,遇到“慢节点”拖累整体变更速度的概率就越大。

3)Full GC 风险: 大集群通常意味着分片数巨多。Cluster State 对象在内存中会变得非常大(几十 MB 甚至上百 MB)。Master 节点在处理这个巨型对象时,极易发生 Full GC 导致假死。

4.2 ES更新细节

要理解压力的来源,必须理解 ES(基于 Lucene)的 “不可变性” (Immutability) 原则。核心机制:伪更新 (Delete + Insert)

在 ES 内部,根本不存在物理意义上的“修改”操作。当你执行一个 Update 请求时,ES 实际上在做以下三步:

1.读取 (Read): 取出旧文档(如果是 Partial Update,它需要先通过 \_source 字段获取完整文档)。

2.标记删除 (Soft Delete): 在旧的 Segment(段)文件中,将旧文档的 ID 标记为 .del(逻辑删除,类似墓碑)。

3.写入新文档 (Insert): 将修改后的新文档作为一个全新的 Document 写入到新的 Segment 中,并分配新的 \_version 号。

这意味着,更新不仅仅是 IO 操作,它还涉及大量的 CPU 计算(重新分词、重新索引)。

4.3 频繁更新带来的四大压力:

1、磁盘 I/O 爆炸与 Segment Merge(段合并)风暴

•现象: 磁盘 I/O 持续 100%,写入拒绝(Rejection)。

•原因: 每次 Update 都会产生一个新的小 Segment。ES 后台为了优化查询,会不断触发 Segment Merge,将小段合并成大段,并物理剔除被标记为 .del 的数据。

•压力点: 高频更新会导致 Merge 线程极其繁忙,消耗大量的磁盘 IOPS 和 CPU。如果 Merge 速度跟不上产生碎片的速度,ES 会启动 Throttling(写入限流),导致你的写入请求被阻塞。

2、查询性能随着“墓碑”增加而衰退

•现象: 即使数据量看起来没变,查询延迟却越来越高。

•原因: 虽然旧文档被标记删除了,但在物理合并发生前,它们依然存在于索引中。

•搜索开销: 查询时,ES 必须扫描所有文档(包括旧的),然后在最后阶段通过 .del 文件过滤掉已删除的文档。如果你的索引中有 50% 是“墓碑”数据,查询效率就会大打折扣。

•BitSet 内存占用: 维护大量的删除标记需要消耗堆内存。

3、缓存失效 (Cache Invalidation)

•现象: Filter Cache(Node Query Cache)命中率极低。

•原因: ES 的 Filter Cache 是基于 Segment 的。一旦 Segment 因为 Merge 发生了变化,或者产生了新的 Segment,旧的缓存就会失效。高频更新导致 Segment 频繁变动,缓存根本热不起来,查询请求会直接击穿到底层磁盘。

4、GC (垃圾回收) 压力

•原因: Update 过程涉及将旧文档读入内存、反序列化、修改、再序列化。这会产生大量的临时对象,增加 JVM 的 Young GC 频率。如果 Merge 压力过大导致内存堆积,甚至可能触发 Old GC 或 Full GC,导致节点 "Stop-the-World"。

简介

本教程主要用于构建一个物理服务器自动化交付的系统,当一个物理服务器上电、配置好IPMI、RAID后。通过PXE可自动安装好一个操作系统在系统盘,并配置好网卡、SSH连接信息。

功能概览

cloudpods 云平台支持 Baremetal(物理机) 管理,提供的功能如下:

  1. 自动化上架: 物理机上架加电启动后,自动注册到云管平台,自动分配BMC IP地址,初始化IPMI账号密码,自动上报物理机硬件配置(CPU、内存、序列号、网卡、磁盘等)
  2. 自动化装机: 根据配置要求自动配置 RAID,自动分区格式化磁盘,自动部署操作系统镜像,自动初始化操作系统账号密码,自动分配IP地址,可以植入配置文件
  3. 生命周期管理: 支持物理机自动化开机,关机,重装系统,远程带外管理,卸载操作系统等操作
  4. 与虚拟机共享镜像: 使用虚拟机镜像部署物理机,便于虚拟机和物理机统一操作系统运行环境
  5. API 支持: 以上操作均支持API操作,便于与其他系统的自动化流程集成
  6. 服务器型号支持: 支持Dell、HP、华为、浪潮、联想、超微等主流x86/ARM服务器厂商和机型
  7. RAID 控制器支持: LSI MegaRaid, HP Smart Array, LSI MPT2SAS, LSI MPT3SAS, Mrarvell RAID等 (也支持软RAID)
  8. 转换为宿主机: 直接将物理机转换为运行虚拟机的宿主机
  9. 托管已有服务器: 托管已有并装好系统的物理机
  10. 支持 Legacy(传统模式)或者UEFI的 PXE 引导网络启动
  11. 网卡支持自动化配置IP、掩码、网关、DNS、VLAN、Bond

支持安装的操作系统

  • openEuler: 22.03 LTS SP3, 22.03 LTS SP4, 24.03 LTS SP2
  • CentOS: 7.9, 8 stream, 9 stream, 10 stream
  • Debian: 11, 12, 13
  • Ubuntu Server: 20.04 LTS, 22.04 LTS, 24.04 LTS, 25.04
  • AnolisOS: 8.8. 8.10
  • OpenCloudOS: 8.8, 8.10, 9.2, 9.4
  • Rocky Linux: 8.x, 9.x, 10.x
  • Alma Linux: 8.x, 9.x, 10.x

Docker Compose 快速安装和使用

使用 Docker Compose 快速部署 Cloudpods Baremetal 物理机管理服务。(单节点)

环境准备

服务器配置要求

  • 最低配置要求: CPU 4核, 内存8 GiB, 存储 200GiB
  • docker 版本: ce-26.1.3+

    • docker 建议安装最新的 ce 版本,新版本已经包含 docker-compose 插件
    • docker 需要开启容器网络以及 iptables
    • 底层系统推荐使用Rocky Linux 9+ / Debian 12+

服务器网卡要求

  • 外网网卡:用于管理和下载文件,连接物理机IPMI。
  • 内网网卡:用于PXE+DHCP ,让需要PXE启动的物理服务器网卡在一个广播域。(可只配置IP和掩码)

安装配置Docker CE

国内参考文档:https://help.mirror.nju.edu.cn/docker-ce/?mirror=NJU

官方文档安装:Install Docker Engine

部署运行 Cloudpods Baremetal 服务

在部署机器上创建 cloudpods-baremetal 目录,并且进入该目录。

cd /opt
mkdir cloudpods-baremetal
cd cloudpods-baremetal

使用下面的命令,把运行物理机管理的 docker compose 配置文件下载下来。

curl https://raw.githubusercontent.com/yunionio/ocboot/master/compose/baremetal/docker-compose.yml -o docker-compose.yaml

PS:也可以用国内的Gitee下载:https://gitee.com/songxwn/ocboot/raw/master/compose/baremetal/docker-compose.yml

在 cloudpods-baremetal 目录运行下面的 docker compose 命令正式开始安装

运行服务,注意需要设置 LISTEN\_INTERFACE 和 PUBLIC\_IP 两个环境变量。

  • LISTEN\_INTERFACE: 服务监听的网卡,比如 eth0 ,此网卡会负责接受 DHCP 请求。(即内网网卡)
  • PUBLIC\_IP: 服务监听的 IP 地址,为对应 LISTEN\_INTERFACE 网卡上的 IP 地址,可通过 ip addr show 查看对应网卡上的地址。

下面命令假设 eth0 网卡上的 ip 地址为 10.168.222.205,具体设置请根据自己的环境设置。

LISTEN_INTERFACE=eth0 PUBLIC_IP=10.168.222.205 docker compose up -d

等服务启动完成后,就可以登陆 https\://$PUBLIC\_IP 访问前端服务,默认登陆用户密码为:admin 和 admin\@123

纳管物理机教程

物理机管理服务部署完成后,接下来纳管物理机测试。

注意

  • 待纳管的物理机需要和运行服务的节点在同一个广播域下(内网网卡)
  • 该广播域中需要禁用其他 dhcp 服务,因为 baremetal 物理机管理服务会运行 dhcp 服务
  • 如果待管理的物理机运行在其他广播域,则需要在交换机上配置 dhcp relay 到物理机管理服务的 PUBLIC\_IP 地址

待纳管的物理机信息:

  • 型号: Lenovo RD640
  • IPMI 带外信息:

    • IP: 192.168.222.203
    • 用户: root
    • 密码: YourIPMI\@Password
  • BIOS/UEFI引导选项设置 PXE 网络启动为第一启动顺序

1. 创建网段

纳管物理机,需要创建PXE、IPMI、物理机 3个类型的 IP 子网。

  • PXE类型: 该网段用于物理机的 PXE 网络引导启动和裸金属(安装操作系统)
  • IPMI 类型: 用于记录物理机 BMC 带外控制的地址
  • 物理机类型:用于物理机的业务网段,可配置VLAN。

这三个网段最好是运行服务所在节点网络可达的,请根据自己的网络环境设置。

点击前端“网络/IP子网/新建",创建以下的三个子网。

创建一个PXE类型的子网

假设需要给物理机 PXE 启动的网段为 192.168.77.100 到 192.168.77.200,网关为 192.168.77.1,并设置 dhcp\_relay 为 PUBLIC\_IP,名称为 bmnet-0,服务器类型选择PXE。

注意:

  • 此物理机类型网段的开始和结束 ip 范围,以及默认网关是和实际环境网络环境相关的,是对应到交换机和路由器上的配置,注意划分的 ip 不要和已有环境的冲突了
  • 这里一定要设置 dhcp\_relay 为 PUBLIC\_IP,在这个环境中是 192.168.77.12,请根据自己环境修改。

    • 因为 baremetal-agent 服务只会响应从 dhcp\_relay 过来的单播 dhcp 请求,用 docker compose 部署的服务中包含了一个 dhcp\_relay 服务,也监听到 PUBLIC\_IP 上,会把 dhcp 广播 relay 到 agent 服务。

创建一个 IPMI 类型的子网

该网段需要包含物理机的 ipmi ip,假设为 192.168.222.200 到 192.168.222.210,网关为 192.168.222.1,名称为 ipmi-0,类型为IPMI。

创建一个物理机类型的业务子网

该网段需要包含物理机的业务网卡的网段,其他要求一样。

查看创建好的3个网段

2.1 PXE引导注册纳管物理机(有IPMI\&BMC)

在Web管理控制台添加物理机,点击”主机/基础资源/物理机/添加”,选择 “PXE 注册引导”,输入对应的物理机纳管信息。

  • 名称: test-bm-songxwn
  • IPMI 信息(这些以具体机器所在环境为准)

    • IPMI 地址: 192.168.222.203
    • IPMI 用户名: root
    • IPMI 密码: YourIPMI\@Password
  • 管理口 MAC 地址: 00:0C:29:01:3E:C1

    • PXE 网络启动的网卡 MAC 地址,如果物理机支持 Redfish API 可以不填,平台能自动探测到
  • 管理口 IP: 选择刚才创建的 bmnet-0 子网

创建完成后,在物理机列表可以看到机器处于“准备中”的状态,并且探测到了品牌为 Lenovo 。(得确保IPMI 可连接到)

可以通过访问物理机的带外控制台,会看到物理机开始 PXE 引导,如果网络配置没有问题,物理机会获得物理机管理服务下发的 grub 引导配置。

获取 grub 配置后,物理机会从管理服务的 PUBLIC\_IP 下载内核和 initramfs。

下载完成后,就会进入 yunionos 内存系统。

之后平台的服务会通过 ssh 远程探测收集物理机的硬件信息,等物理机变成“运行中”的状态,就算纳管成功了。

勾选对应的物理机,点击启用,就可以进行后续的安装操作系统等操作。

2.2 预注册纳管物理机(无IPMI\&BMC)

  • 适用于无IPMI\&BMC的物理机,PXE服务器需要注册MAC地址才能被引导。
  • 注意勾选无BMC控制器。
  • 注意选择管理口IP,为PXE 子网。

3. 导入装机镜像

点击“主机/系统镜像/上传”按钮,导入需要装机的镜像。

等待镜像状态变成“可用”,就可以将此镜像用于安装操作系统了。

Debian 12 AMD64 通用物理机QCOW2镜像

https://cloud.debian.org/images/cloud/bookworm/latest/debian-...

Debian 12 自定义包

KVM安装一个Debian 12虚拟机(安装好软件包和配置),将镜像下载下来。qemu-img convert -f qcow2 -O raw debian-disk.qcow2 debian-disk.raw

  • 安装包 cloud-init ,用于初始化
  • 安装包 vlan、ifenslave 用于VLAN和Bond
或是点击社区镜像在线导入

等待镜像状态变成“可用”,就可以将此镜像用于安装操作系统了。

4. 为物理机安装操作系统)

前提条件:物理机PXE已启动 YunionOS For PXE 系统
  • YunionOS For PXE 是一个通过网络PXE启动,在内存中临时运行的工具系统
  • 用于启动后由Cloudpods Baremetal 系统连接检测所有硬件信息,并根据硬件信息来配置网卡、硬盘、密码/密钥来安装系统。

安装系统到物理机硬盘

点击“主机/基础资源/物理机”

选择一个物理机 点击更多选择启用,然后选择安装操作系统。

配置安装信息
  • 配置系统主机名
  • 配置安装系统镜像
  • 配置硬盘 (可配置软RAID)
  • 配置root密码/公钥
  • 配置网络 (可配置Bond 和 VLAN)

  • 最后点击新建则开始安装,安装日志可去主机 - 裸金属查看。

操作说明

1. 将服务放到后台运行

可以使用 '-d/--detach' 参数把所有服务放到后台运行,命令如下:

# 所有服务放到后台运行
# 下面命令假设 eth0 网卡上的 ip 地址为 10.168.222.205,具体设置请根据自己的环境设置。
$ LISTEN_INTERFACE=eth0 PUBLIC_IP=10.168.222.205 docker compose up -d

# 服务放到后台后,可以通过 logs 自命令查看输出日志
$ docker compose logs -f

2. 登陆 climc 命令行容器

如果要使用命令行工具对平台做操作,可以使用下面的方法进入容器:

$ docker exec -ti cloudpods-baremetal-climc-1 bash
Welcome to Cloud Shell :-) You may execute climc and other command tools in this shell.
Please exec 'climc' to get started

# source 管理员认证信息
bash-5.1# source /etc/yunion/rcadmin
bash-5.1# climc user-list

3. 登录物理机 pxe 内存系统

当物理机通过 pxe 启动成功后,会引导进入一个内存 linux 系统,可以通过下面的方式 ssh 进入这个系统,遇到错误的时候方便排查。

# 1. 进入 climc 容器
docker exec -ti cloudpods-baremetal-climc-1 bash

# 2. 查看物理机 id
climc host-list

# 3. ssh 到 host 的内存系统
climc host-ssh $对应物理机id

另外也可以通过 climc host-logininfo $对应物理机id 获取 root 用户的登录密码。

如果物理机 pxe 内存系统上报登录信息失败,则会设置成默认的密码:mosbaremetal,对应逻辑可参考通知代码

4. 查看服务配置和持久化数据

所有服务的持久化数据都是存储在 cloudpods-baremetal/data 目录下面的,所有配置都是自动生成的,一般不需要手动修改,下面对各个目录做说明:

$ tree data
data
├── etc
│   ├── nginx
│   │   └── conf.d
│   │       └── default.conf    # 前端 nginx 配置
│   └── yunion
│       ├── *.conf  # cloudpods 各个服务配置
│       ├── pki     # 证书目录
│       ├── rcadmin     # 命令行认证信息
├── opt
│   └── cloud
│       └── workspace
│           └── data
│               └── glance # 镜像服务存储的镜像目录
└── var
    └── lib
        ├── influxdb    # influxdb 持久化数据目录
        └── mysql       # mysql 数据库持久化数据目录

5. 删除所有容器

所有服务的持久化数据都是存储在 cloudpods-baremetal/compose/data 目录下面的,删除容器不会丢失数据,下次直接用 docker compose up 重启即可,操作如下:

# 删除服务
$ docker compose down

升级

更新 compose 配置文件

当上游的 ocboot/compose/baremetal/docker-compose.yml 更新了,就可以通过 curl 命令下载最新的配置文件,然后重新启动就可以了,步骤如下:

# 注意切换到对应的 cloudpods-baremetal 目录

cd /opt/cloudpods-baremetal

# 下载配置文件

curl https://raw.githubusercontent.com/yunionio/ocboot/master/compose/baremetal/docker-compose.yml -o docker-compose.yaml

# 重启服务

docker compose up -d

重启 compose 服务

拉取最新的 docker-compose.yml 配置文件后,使用下面命令重启服务就行了。

cd /opt/cloudpods-baremetal

docker compose down

# 下面命令假设 eth0 网卡上的 ip 地址为 10.168.222.205,具体设置请根据自己的环境设置。

LISTEN_INTERFACE=eth0 PUBLIC_IP=10.168.222.205 docker compose up

已成功测试安装系统

  • Centos 7
  • Ubuntu 24.04
  • Debian 12 (使用自构建QOCW2镜像,官方镜像缺驱动)

关于PXE 网络的交换机配置

  • 目前大牌服务器都支持PXE配置VLAN ID,所以可以配置Trunk口接入,或者Trunk的PVID为PXE 所属VLAN。
  • 或者只能手动改为Access PXE VLAN,安装完成后改回业务VLAN。

运维技术交流群

发送邮件到 ➡️ me@songxwn.com

或者关注WX公众号:网工格物

🔥 一文搞懂 Skill:这玩意儿到底是啥?为啥大家都在用?

Skill 不是简单的"会什么",而是你在这个快速变化的世界里安身立命、升职加薪、甚至弯道超车的核心武器。看完这篇,你会明白为什么大佬们都在聊 Skill,以及怎么用它让自己更值钱。

🤔 先搞清楚:Skill 到底是什么?

别被这个词唬住。Skill 翻译过来是"技能",但在今天的语境下,它远不止"会修电脑"或者"会做PPT"这么简单。

Skill = 你能稳定输出价值的能力

它包括:

  • 硬技能(Hard Skills):能写进简历、能考证、能量化的本事。比如写代码、数据分析、做设计、说外语。
  • 软技能(Soft Skills):没法直接考证,但能决定你能走多远的底层能力。比如沟通、领导力、抗压、学习能力。

举个栗子 🌰:

  • 你会用 Python 爬数据 → 硬技能
  • 你能把爬出来的数据讲成老板听得懂的故事,并推动决策 → 软技能
  • 两者结合 = 高薪数据分析师

💡 为什么现在人人都在谈 Skill?不用不行吗?

说实话,不用 Skill 也行,但你会活得很难。

1. 职场卷疯了,Skill 是你的护城河

现在的招聘市场啥情况?一个岗位发出去,几百份简历砸过来。HR 看简历的时间不超过 10 秒。

没有硬核 Skill,你连简历关都过不了。

但 Skill 不只是敲门砖,更是你的护城河

  • 你会的,别人不会 → 议价权
  • 你精通的,别人只会皮毛 → 定价权
  • 你能做的,AI 做不了 → 安全感

2. 行业变化快,Skill 是你唯一的确定性

铁饭碗?不存在的。昨天还火热的岗位,今天可能被 AI 取代。

但 Skill 是可迁移的:

  • 做运营的学会了数据分析 → 转型增长黑客
  • 做销售的掌握了产品思维 → 转型产品经理
  • 写代码的学会了业务理解 → 转型技术负责人

Skill 让你不怕变化,因为你有"随时重新上岗"的底气。

3. 赚钱的本质,是 Skill 的变现

别听那些"靠认知赚钱"的鸡汤。认知不落地,就是空谈。

真正能换成钱的,是你能解决具体问题的 Skill

  • 帮公司省成本 → 财务分析 Skill
  • 帮公司多赚钱 → 营销/销售 Skill
  • 帮公司提效率 → 技术/自动化 Skill

你的收入天花板,取决于你的 Skill 稀缺性和可替代性。


⚖️ Skill 的优劣势:别盲目学,先看清利弊

优势:为什么 Skill 这么香?

优势说人话
直接变现学了就能用,用了就能赚钱,路径清晰
可积累像滚雪球,越老越吃香(前提是选对方向)
确定性高不像运气、人脉那么虚,Skill 是实打实的
跨行业通用数据分析、项目管理这类 Skill,换行照样用
抗风险经济不好时,有 Skill 的人最后才被裁

劣势:学 Skill 也有坑,别踩!

劣势说人话
过时风险有些 Skill 火两年就凉(比如某些过时的技术栈)
学习痛苦真的累,尤其是工作后再学新东西,时间精力都是成本
过度专精陷阱只会一样,容易被锁死在某个岗位,转型困难
忽视软技能技术强但情商低,升不上去,只能当大头兵
焦虑感永远感觉"学不完",容易陷入自我怀疑


🥊 硬技能 vs 软技能:到底该卷哪个?

直接给结论:成年人不做选择,两个都要。但优先级看阶段。

📊 对比一览

维度硬技能软技能
学习难度有明确路径,跟着学就行没标准答案,靠悟性和实践
见效速度快(3-6 个月能入门)慢(需要长期沉淀)
天花板中(专家级后难突破)高(决定你能不能当老板)
替代性高(容易被 AI/新人替代)低(AI 搞不定人情世故)
适合人群新人、转行者、技术岗管理者、创业者、资深专家

🎯 不同阶段的策略

🟢 0-3 年职场新人:

  • 主搞硬技能,先让自己"有用"
  • 选 1-2 个市场需求的技能死磕(如 Python、SQL、设计软件)
  • 软技能不落下,但不用刻意练,工作中自然长

🟡 3-7 年资深员工:

  • 硬软结合,开始补领导力、项目管理
  • 从"执行者"转向"协调者",不然升不上去

🔴 7 年以上管理层/专家:

  • 软技能为主,硬技能保持了解即可
  • 重点练战略思维、商业洞察、团队激励


🚀 怎么选 Skill?3 个避坑指南

别盲目跟风学,先问自己这 3 个问题:

1. 这个 Skill 能帮我解决什么问题?

  • ❌ 错误:听说 Python 很火,学!
  • ✅ 正确:我工作中需要处理大量数据,Python 能帮我自动化,学!

2. 3 年后这个 Skill 还值钱吗?

  • 看趋势:AI 相关的 Skill(提示词工程、AI 应用开发)未来 5 年都稳
  • 避坑:纯体力劳动型 Skill、容易被自动化的重复性工作

3. 我的性格和资源适合学这个吗?

  • 内向社恐 → 别硬卷销售,可以考虑技术写作、数据分析
  • 时间有限 → 选"碎片化学习"友好的 Skill,别选需要大块时间练的(如设计)


💬 社区热议:关于 Skill 的真实声音

@产品经理老王:"35 岁危机不是年龄危机,是 Skill 危机。你 30 岁用的那套方法论,35 岁还在用,不淘汰你淘汰谁?"

@前端小李:"去年死磕 React,今年发现公司全转 Vue 了...Skill 更新速度真的恐怖,得保持学习。"

@运营阿花:"硬技能让我入行,软技能让我带团队。现在招人不只看你会不会,更看你能不能推动事情落地。"

@自由职业者 Ken:"Skill 是我脱离坐班的底气。会写作+会运营+会点设计,一个人就是一家公司。"


🎁 总结:Skill 是你的个人 IPO

把你自己当成一家公司,Skill 就是你的核心资产

  • 早期:靠硬技能获得现金流(养活自己)
  • 成长期:软硬结合,提升估值(升职加薪)
  • 成熟期:靠软技能和资源变现(创业/高管/顾问)

记住:

  1. 没有完美的 Skill,只有适合当下阶段的 Skill
  2. Skill 不是学一次就完事,需要持续迭代
  3. 别只闷头学,要展示出来(作品集、博客、开源项目)


最后抛个问题给大家:

你最近在学习什么 Skill?过程中踩过哪些坑?欢迎在评论区交流,互相避坑 👇

作者:Smoothcloud润云

大家好,我们是一个 3 人的小团队,经历数月,终于完整了 Sendflare 的开发

Sendflare 是一个对标 resend 的替代品,定价比 resend 更加合理,同时支持营销邮件和交易电子邮件

后续我们还会支持邮件自动化功能

目前刚刚上线,可能多多少少有一点小问题,希望大家在给我们一点时间

免费用户支持添加 2 个域和每月 3000 封邮件

访问地址: https://sendflare.com

image

1. 前言

在实际的企业信息化交付中,很多开发者依然会使用 Access 作为桌面级应用或者局域网管理系统的快速开发平台。利用 VBA 的强大生态,Access 能够以极低的成本解决中小型企业的核心痛点。

然而,在软件交付或试用阶段,我们经常面临一个棘手的问题:如何保护软件知识产权,防止用户随意拷贝和分发? 通常我们会将 .accdb 文件编译为 .accde.mde 以隐藏核心源码,但这无法阻止物理文件的直接复制。

本文将解析如何在 Access 项目中引入“一机一码”软授权机制。通过提取目标设备的固有硬件指纹,结合哈希密码学算法,实现业务终端与应用授权的强绑定。

2. 技术原理分析

“一机一码”认证模型的核心在于:硬件唯一性、防逆向伪造、轻量级部署。以下是该机制的技术原理:

阶段核心实现与原理
指纹采集使用 WMI(Windows Management Instrumentation)获取主板 CPU ID 及 C 盘卷序列号。增加“计算机名称”以降低同批次同型号硬件可能带来的碰撞率。
混淆加盐在原始特征码中加入动态“盐值(Salt)”,防止懂技术的用户直接推导原始字符串。这部分通过异或运算隐藏在 VBA 数组中。
哈希降维硬件信息组合后的字符串长且无规律,不适合作为机器码让用户手工复制或抄写。通过 DJB2 哈希算法变体,散列为 16 位紧凑格式(XXXX-XXXX-XXXX-XXXX)。
注册生成根据用户提交的 16 位机器码,加入管理员独占的“私有密钥(Secret Key)”,再次进行哈希运算生成配对的注册码。

3. 核心功能实现(附源码)

3.1 获取硬件指纹

在 VBA 中调用系统的 WMI 服务可以轻易获取硬件属性,这是该机制的基础。这里同时采集 CPU ID 与逻辑磁盘 C 盘序列号。

' 获取CPU标识符 (通过WMI)
Private Function GetCPUId() As String
    On Error GoTo ErrHandler
    Dim objWMI As Object, colItems As Object, objItem As Object

    Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
    Set colItems = objWMI.ExecQuery("Select ProcessorId From Win32_Processor")

    For Each objItem In colItems
        GetCPUId = Trim$(objItem.ProcessorId & "")
        If GetCPUId <> "" Then Exit For
    Next

    If GetCPUId = "" Then GetCPUId = "NOCPUID"
    Exit Function

ErrHandler:
    GetCPUId = "NOCPUID"
End Function

3.2 自定义哈希算法压缩长度

标准 MD5 会产出相对较长的文本,这里我们采用变种的轻量级 Hash 算法(类似 DJB2),利用位运算(AndXor),将其压制在 16 位十六进制的范围内。

' 核心哈希函数:将长字符串映射为 0~65535 之间的整型哈希值
Private Function Hash16(ByVal s As String, ByVal seed As Long) As Long
    Dim h As Long
    h = seed And &H7FFF&
    
    Dim i As Long
    For i = 1 To Len(s)
        ' 乘以 33 并加上 ASCII 值,使用 &H7FFFFFFF 防止 VBA 长整型溢出
        h = ((h And &HFFFF&) * 33 + Asc(Mid$(s, i, 1))) And &H7FFFFFFF
    Next i

    Hash16 = h And &HFFFF&
End Function

3.3 机器码与注册码的生成分离

“机器码”是给用户侧界面的,“注册码”是需要管理端工具单独生成的。二者在生成路径上的差异点在于核心加密密钥只存在于计算注册码的时候。

' 获取当前机器的机器码 (4组16进制)
Public Function GetMachineCode() As String
    ' 1. 采集硬件信息
    Dim rawInfo As String
    rawInfo = GetCPUId() & "|" & GetDiskSerial() & "|" & Environ("COMPUTERNAME")
    
    ' 2. 加入盐值防推断
    Dim combined As String
    combined = rawInfo & DecodeSalt()
    
    ' 3. 分段 Hash 映射
    Dim h1 As Long, h2 As Long, h3 As Long, h4 As Long
    h1 = Hash16(combined, &H1A3B)
    '...略

    GetMachineCode = Right$("0000" & Hex$(h1), 4) & "-" & Right$("0000" & Hex$(h2), 4) '...略
End Function

管理端由于持有私钥 DecodeKey(),当拿到机器码之后:

' 根据机器码生成对应防伪注册码
Private Function ComputeRegCode(ByVal mcClean As String) As String
    Dim combined As String
    ' 机器码加上私有密钥,进行不对称 Hash
    combined = mcClean & DecodeKey()

    Dim h1 As Long, h2 As Long, h3 As Long, h4 As Long
    h1 = Hash16(combined, &H5183)
    '...略
    
    ' 产出与该机器唯一匹配的授权识别码
    ComputeRegCode = Right$("0000" & Hex$(h1), 4) & "-" & Right$("0000" & Hex$(h2), 4) '...略
End Function

3.4 完整代码

新建一个通用模块,具体代码如下:

Option Compare Database
Option Explicit


' 获取当前机器的机器码
' 格式: XXXX-XXXX-XXXX-XXXX (十六进制)
Public Function GetMachineCode() As String
    Dim rawInfo As String
    rawInfo = GetCPUId() & "|" & GetDiskSerial() & "|" & Environ("COMPUTERNAME")

    Dim salt As String
    salt = DecodeSalt()

    Dim combined As String
    combined = rawInfo & salt

    Dim h1 As Long, h2 As Long, h3 As Long, h4 As Long
    h1 = Hash16(combined, &H1A3B)
    h2 = Hash16(combined, &H2C4D)
    h3 = Hash16(combined, &H3E5F)
    h4 = Hash16(combined, &H4A71)

    GetMachineCode = Right$("0000" & Hex$(h1), 4) & "-" & _
                     Right$("0000" & Hex$(h2), 4) & "-" & _
                     Right$("0000" & Hex$(h3), 4) & "-" & _
                     Right$("0000" & Hex$(h4), 4)
End Function

' 根据机器码生成注册码
Public Function GenerateRegCode(ByVal machineCode As String) As String
    Dim mcClean As String
    mcClean = Replace(UCase$(Trim$(machineCode)), "-", "")

    If Len(mcClean) <> 16 Then
        GenerateRegCode = "错误:机器码格式不正确,应为16位十六进制字符(XXXX-XXXX-XXXX-XXXX)"
        Exit Function
    End If

    GenerateRegCode = ComputeRegCode(mcClean)
End Function

' ==================== 内部实现 ====================

Private Function ComputeRegCode(ByVal mcClean As String) As String
    Dim combined As String
    combined = mcClean & DecodeKey()

    Dim h1 As Long, h2 As Long, h3 As Long, h4 As Long
    h1 = Hash16(combined, &H5183)
    h2 = Hash16(combined, &H6295)
    h3 = Hash16(combined, &H73A7)
    h4 = Hash16(combined, &H4B9)

    ComputeRegCode = Right$("0000" & Hex$(h1), 4) & "-" & _
                     Right$("0000" & Hex$(h2), 4) & "-" & _
                     Right$("0000" & Hex$(h3), 4) & "-" & _
                     Right$("0000" & Hex$(h4), 4)
End Function

Private Function Hash16(ByVal s As String, ByVal seed As Long) As Long
    Dim h As Long
    h = seed And &H7FFF&

    Dim i As Long
    For i = 1 To Len(s)
        h = ((h And &HFFFF&) * 33 + Asc(Mid$(s, i, 1))) And &H7FFFFFFF
    Next i

    Hash16 = h And &HFFFF&
End Function

Private Function DecodeKey() As String
    Dim b() As Variant
    b = Array(116, 12, 70, 120, 12, 81, 30, 108, 12, 92, 77, 12, 75, 127, 13, 15, 13, 10)
    Dim s As String, i As Long
    For i = 0 To UBound(b)
        s = s & Chr$(CLng(b(i)) Xor &H3F)
    Next i
    DecodeKey = s
End Function

' 解码盐值(运行时混淆)
Private Function DecodeSalt() As String
    Dim b() As Variant
    b = Array(23, 25, 27, 104, 106, 104, 99, 121, 8, 63, 61)
    Dim s As String, i As Long
    For i = 0 To UBound(b)
        s = s & Chr$(CLng(b(i)) Xor &H5A)
    Next i
    DecodeSalt = s
End Function

' 获取CPU标识符 (通过WMI)
Private Function GetCPUId() As String
    On Error GoTo ErrHandler
    Dim objWMI As Object
    Dim colItems As Object
    Dim objItem As Object

    Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
    Set colItems = objWMI.ExecQuery("Select ProcessorId From Win32_Processor")

    For Each objItem In colItems
        GetCPUId = Trim$(objItem.ProcessorId & "")
        If GetCPUId <> "" Then Exit For
    Next

    If GetCPUId = "" Then GetCPUId = "NOCPUID"
    Exit Function

ErrHandler:
    GetCPUId = "NOCPUID"
End Function

' 获取C盘卷序列号 (通过WMI)
Private Function GetDiskSerial() As String
    On Error GoTo ErrHandler
    Dim objWMI As Object
    Dim colItems As Object
    Dim objItem As Object

    Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
    Set colItems = objWMI.ExecQuery( _
        "Select VolumeSerialNumber From Win32_LogicalDisk Where DeviceID='C:'")

    For Each objItem In colItems
        GetDiskSerial = Trim$(objItem.VolumeSerialNumber & "")
        If GetDiskSerial <> "" Then Exit For
    Next

    If GetDiskSerial = "" Then GetDiskSerial = "NODISK"
    Exit Function

ErrHandler:
    GetDiskSerial = "NODISK"
End Function

3.5 创建窗体

这里创建一个简单的窗体给大家演示一下,具体窗体如下:

窗体的具体代码,就是调用一下函数:

Private Sub btnGenerateRegCode_Click()
    Me.txtGenerateRegCode = GenerateRegCode(Me.txtMachineCode)
End Sub

Private Sub btnMachineCode_Click()
   Me.txtMachineCode = GetMachineCode()
End Sub

3.6 运行测试

这里给大家看一下,运行效果:

4. 业务落地与使用方法

将上述底层方法封装完毕后,你只需要在 Access 中配置入口宏。

  1. 新建 AutoExec 宏,配置 RunCode 行为指向拦截函数 =CheckRegistration()
  2. 在该函数内,判断数据表中是否存在正确的授权记录。
  3. 若未授权,则中断主窗体加载,强行弹起注册窗体
  4. 用户复制屏幕上呈现的机器码发给开发者;开发者在脱机环境调用上述 ComputeRegCode() 函数算出激活码并交付。

5. 进阶内容(静态混淆与反逆向)

任何暴露在客户端的代码都有被逆向的可能,即使是 .accde,VBA P-Code 依然有可能被还原。所以私钥不写明文是基础中的基础。

我们可以运用异或运算(XOR)在内存中动态还原秘钥,提高破解门槛,具体的功能就不再说明了,如果可以,大家可以自行优化。

6. 总结

采用“硬件信息采集 + Hash运算压缩”组合成的这套方案,是给 Access 系统加上商业护城河的一条务实捷径。无需搭建云端激活服务,几段代码就能有效规避 90% 的随意白嫖行为。

如果你正苦于自己辛辛苦苦开发的局域网/单机桌面应用被客户随手 U 盘拷走,不妨把这套机制嵌进你的项目里,花 10 分钟的时间,将纯技术转化成可掌控的生产力。


Access 开发」 专注于 Microsoft Access 开发与企业级应用,提供以下服务:

📚 技术培训

Access VBA 从入门到精通(线上/线下)

Access + SQL Server 企业级开发实战

Access 系统性能优化与架构设计

💼 定制开发

企业 ERP/CRM/进销存等系统开发

旧系统升级与性能优化

🔧 技术支持

代码审查与重构建议

疑难问题远程诊断

一对一技术辅导

联系方式:

公众号后台留言

邮箱:will.miao@edonsoft.com

微信:edonsoft 公众号:access开发

技术改变业务,专注创造价值。

做企业金融数据分析这么多年,我们敢说,不少同行在跟踪JMG复牌时,都陷入过“手动盯盘”的内耗——明明想精准捕捉复牌节点、拿到第一手行情数据,却被繁琐的操作拖慢节奏,甚至错过关键信息?
最近我们集中跟进JMG复牌的相关动态,才真正摸清一个核心:复牌对市场节奏的影响,远比我们表面认知的更深刻。停牌可能只持续几天,也可能拉长到数周,但复牌的那一刻,股价的波动几乎瞬间定调,后续的走势很多时候都围绕这个初始反应展开。

但实际工作中,传统跟踪方式的痛点实在太突出:反复刷新财经网页、全程盯守公告推送,不仅浪费大量时间和精力,还经常错过复牌初期的黄金观察窗口;更麻烦的是,手动记录的数据零散杂乱,后续整理、清洗还要额外投入成本,完全不符合我们分析师“高效、精准”的工作逻辑,也和开发者的高效工作习惯相悖。

于是我们开始琢磨:既然接口能实现数据的自动化抓取,能不能用它来同步获取JMG复牌状态和当日行情?既能省去手动记录的冗余步骤,又能形成规范的观察素材,让我们把更多精力放在核心的数据分析上,而不是基础的操作内耗。

一、复牌数据的价值,不止是“恢复交易”那么简单

对我们企业金融数据分析师来说,JMG复牌从来不是单纯的交易状态切换,而是市场对停牌期间所有信息的集中反馈出口。

停牌阶段,股票暂停交易,我们能做的只有被动跟踪消息面,却无法捕捉市场的真实情绪和资金流向;一旦复牌,多空博弈的结果、资金的取舍倾向,都会瞬间体现在股价、成交量这些核心数据上,而这些数据,正是我们开展后续分析、判断市场走向的核心依据。

我们一直和同行交流时说:对分析师而言,及时掌握复牌状态,比单纯盯着实时股价更关键。因为复牌本身就是一个清晰的事件节点,它直接决定了我们下一步的数据分析方向——该重点关注哪些指标、该从哪个角度切入解读市场情绪,都和复牌状态紧密相关。

换个角度看,复牌是极具参考价值的市场样本。通过接口抓取复牌相关数据,不仅能保证信息获取的及时性和稳定性,还能将复牌当天的核心数据系统沉淀下来,形成可长期回溯、可反复复用的观察档案,为后续的策略复盘、标的深度研究提供可靠支撑。

二、接口抓取JMG复牌数据:核心字段+实操示例

跟踪JMG复牌,我们不需要冗余的无效数据,只需锁定三个核心字段,就能满足大部分分析需求:复牌状态、最新成交价、涨跌幅。

对我们这类既要做分析、又要懂基础开发的分析师来说,接口抓取的最大优势的就是“结构化输出”——无需从网页中复制粘贴、手动清洗数据,可直接对接后续的代码处理流程,大幅降低基础操作的时间成本,让我们能将更多精力投入到核心的数据分析工作中。

下面是我们日常实操中用到的Python示例,代码未做任何修改,各位同行可直接参考复用:

import json
import requests

base_url = "https://quote.alltick.co/quote-stock-b-api/trade-tick"
token = "你的_API_Token"

query = {
    "trace": "csdn_jmg_resume",
    "data": {"symbol_list": [{"code": "JMG"}]}
}

query_str = json.dumps(query).replace(' ', '').replace('"', '\\"')
full_url = f"{base_url}?token={token}&query={query_str}"

response = requests.get(full_url)
if response.status_code != 200:
    print("网络请求失败:", response.status_code)
else:
    result = response.json()
    statuses = result.get("data", [])
    if statuses:
        status_info = statuses[0]
        if status_info.get("status") == "resumed":
            print("jmg 已复牌,当前价格:", status_info.get("price"))
        else:
            print("jmg 尚未复牌")

三、复牌当日数据观察:关键窗口+容错技巧
结合多年实操经验,我们总结出一个规律:复牌后的首个交易小时,是市场情绪最集中的释放窗口。这段时间的股价波动、成交量变化,能最直观地反映市场对JMG复牌的态度,也是我们开展实时分析的核心关键。

借助接口抓取到的结构化数据,我们可以快速开展各类统计分析:对比开盘价与前收盘价的偏离幅度,判断市场的初始反应;分析涨跌幅的分布区间,解读多空力量的强弱;观察成交量的异动情况,捕捉资金流向;甚至可以通过绘制折线图,直观呈现股价波动趋势,让分析更具针对性和说服力。

不过在实操过程中,我们也踩过不少坑——接口偶尔会出现核心字段缺失的情况,若没有提前做好应对,很容易导致分析脚本中断,错过关键的数据分析时间。为此,我们在实践中总结出了一套容错逻辑,能有效规避此类问题,保证脚本长期稳定运行:

price = status_info.get("price")
change = status_info.get("change_percent")

if price is None or change is None:
    print("部分数据缺失,需要关注接口返回")
else:
    print(f"复牌首价: {price}, 涨跌幅: {change}")

这套简单的容错逻辑,能有效提升脚本的鲁棒性,即便接口偶尔出现小异常,也不会导致整个分析流程中断,非常适合长期自动化跟踪JMG复牌数据,尤其适合我们这类兼顾分析与基础开发的从业者。

四、复牌数据沉淀:从“零散记录”到“体系化笔记”

跟踪JMG复牌的这段经历,让我们对复牌的认知有了很大提升:它不仅是交易的重启,更是一个极具价值的市场信号,而接口抓取,正是将这个信号转化为有效分析素材的关键手段。

通过接口抓取数据,我们不仅能精准捕捉JMG的复牌时点,还能同步获取股价、成交量等核心指标,将复牌当天的所有关键数据,整理成结构化的市场观察笔记。长期积累下来,我们能清晰总结出复牌前后的市场情绪规律、资金流动特点,这些沉淀下来的素材,不管是用于标的研究、策略优化,还是风险预判,都能发挥重要作用。

相较于传统的手动刷新网页、零散记录数据的方式,将复牌状态与行情数据整合在同一个数据流中观察,不仅更高效、更规范,也更符合我们企业金融分析师+开发者的工作习惯——摆脱繁琐的基础操作,把更多精力放在核心的数据分析上,才能做出更精准的判断。

五、跟踪复牌数据的3个实用小习惯,高效不踩坑

结合长期的实操经验,我们总结了3个简单易执行的小习惯,分享给各位同行,帮助大家更高效地跟踪JMG复牌数据,少走弯路、避免内耗:

  1. 每日复盘前,优先检查JMG的停牌/复牌状态,提前锁定关键分析节点,避免错过核心数据;
  2. 复牌当天,第一时间抓取开盘价、涨跌幅等核心指标,做好数据快照,为当日的分析工作打好基础;
  3. 遇到数据缺失或接口异常时,及时打印日志、留存数据现场,方便后续定位问题、补充数据,保障分析工作的连续性。

这些操作看似简单,但能让我们对JMG复牌信息始终保持掌控感,让市场观察从“凭经验”转变为“靠数据”,也让我们的分析工作更有章法、更高效,尤其适合长期跟踪核心标的。

最后总结

对企业金融数据分析师而言,及时、稳定、结构化的数据,是做好分析工作的基础。跟踪JMG复牌这类核心标的,手动盯盘不仅效率低下、易出错,还会消耗大量的时间和精力,而通过接口实现数据抓取的自动化,能有效解决这些痛点,让我们聚焦核心分析工作,想要实现这一目标,不妨试试Alltick API。

在企业数字化的今天,Excel 依然是不可撼动的数据处理核心。然而,在传统的业务场景中,我们经常见到这样的画面:一份财务报表在群聊里反复传输,文件名从“结算单.xlsx”演变成“结算单_最终版_张三改_真的最后版.xlsx”;多人共同汇总数据时,必须排队等待,因为“文件正被他人占用”。

这种“文件传阅”式的协作模式,本质上是单机时代的产物。它带来的不仅是效率的低下,更是数据更新延迟、权限冲突以及变更无法追踪等一系列可能引发致命错误的安全隐患。

随着 SpreadJS V19 版本的发布,其协同插件(Collaboration Add-on)通过一套成熟的、专为企业级应用设计的协同框架,彻底打破了这一僵局。本文将作为系列文章的第一篇,带你深度走进 SpreadJS 协同功能的核心,探讨它如何助力企业实现真正的多人实时在线协同。

一、 企业级协作的“三大深坑”

在构建 Web 版 Excel 协作系统时,开发者往往会面临三个核心技术挑战:

  1. 数据一致性(Consistency): 当 A 用户在修改单元格 A1 的公式,B 用户同时删除了包含 A1 的行时,系统如何确保两边看到的数据最终是一致的?
  2. 实时性与性能(Real-time & Performance): 在处理万行以上的巨型表格时,频繁的 WebSocket 通信是否会卡顿?如何平衡“改哪同步哪”与“全量刷新”?
  3. 协作感(User Presence): 协同不是简单的后台数据同步,用户需要知道“谁正在跟我一起改”、“他在改哪里”,否则极易发生业务逻辑上的碰撞。

SpreadJS 协同插件正是为了填平这些“坑”而诞生的。

二、 SpreadJS 协同框架:支撑实时协作的技术基石

SpreadJS 的协同功能并非一个简单的接口,而是一个分层明确、高度解耦的技术框架。它由三个核心模块组成,共同构建了从底层通信到上层 UI 呈现的完整链路。

image.png

1.js-collaboration:核心通信枢纽

这是整个协作系统的“交通指挥官”。它基于 WebSocket 协议,负责客户端与服务器之间的双向数据同步和消息广播。

  • 房间管理: 它支持将用户隔离在不同的“房间(Room)”中。例如,财务部的协同环境与销售部互不干扰,每个房间代表一个独立的同步上下文。
  • 自动重连与心跳: 针对企业网络环境可能存在的不稳定性,它内置了心跳检测和断开后的自动重连功能,确保协作不因瞬时掉线而中断。

2.js-collaboration-ot:文档同步逻辑与冲突处理

如果说 js-collaboration 负责传消息,那么 js-collaboration-ot 则负责消息的“含义”。它引入了操作转换(OT, Operational Transformation)技术。

  • 意图同步: 它不只是同步结果,而是同步用户的操作意图(Op)。
  • 数据库适配: 该模块包含了标准化数据库适配器(支持 PostgreSQL, SQLite3 等),允许开发者轻松实现协作数据的持久化存储,解决“协同结束后数据去哪了”的问题。

3.js-collaboration-presence:实时用户状态共享

协同的精髓在于“人在现场”。此模块负责处理协作中的非业务数据:

  • 光标定位: 实时显示其他用户当前选中的单元格。
  • 文本高亮: 当其他用户正在编辑某个区域时,该区域会以特定颜色高亮显示,并附带用户名标识。

三、 核心工作机制:从 Op 到 ChangeSet 的艺术

在 SpreadJS 协同中,数据的同步并非粗暴地传输整个 JSON 结构,而是基于“操作(Op)”和“变更集(ChangeSet)”的精妙设计。

1.操作(Op)的原子化

每当用户在 SpreadJS 中进行一次修改(如设置值 setValue、添加行 addRows、调整缩放 updateZoom),系统都会将其记录为一个原子化的 Op。

2.变更集(ChangeSet)的封装

SpreadJS 提供了两种同步模式:

  • 单步模式(Single Mode): 每一个命令直接生成一个 ChangeSet 发送,适用于即时性要求极高的简单操作。
  • 批处理模式(Batch Mode): 这是企业开发中最推荐的模式。通过 startBatchOp()endBatchOp(),开发者可以将一系列同步操作(如初始化报表时的批量配置、迭代式数据插入)封装进一个原子性的 ChangeSet 中。

价值体现:

  • 性能优化: 减少了 WebSocket 的往返次数和服务器负载。
  • 事务性: 确保一组操作要么全部应用成功,要么全部不应用,避免出现文档状态“半生不熟”的尴尬。

四、 架构设计:客户端与服务器的完美配合

SpreadJS 的协同架构遵循标准的“客户端-服务器”模式。

image.png

  • 客户端(Client): SpreadJS 宿主工作簿通过 spread-sheets-collaboration-addon 插件监听底层数据模型的变化。当变更发生时,它生成 Op 并组装成 ChangeSet,通过协同客户端接口推送到服务器。同时,它也负责接收来自服务器的远程操作,并将其平滑地应用到本地视图中。
  • 服务器(Server):js-collaboration 构建的协同服务器不包含具体业务逻辑,它充当事件调度器的角色。它通过中间件(Middleware)校验用户权限,通过钩子(Hooks)拦截关键事件,并最终利用 OT 算法协调不同客户端提交的变更,确保全局唯一真值的产生。

五、 为何 SpreadJS 协同是企业级的首选?

市面上有很多协作工具,但 SpreadJS 协同插件在企业级应用中具备独特的优势:

1.深度集成 SpreadJS 专业能力

不同于普通的协作文档,SpreadJS 协同完整支持 Excel 的高级特性。无论是复杂的跨表引用公式、切片器(Slicer)、透视表(PivotTable),还是自定义单元格类型,都在协同的覆盖范围内。

2.细粒度的权限管控(BrowsingMode)

企业场景下,“全员可改”是灾难。SpreadJS 允许为不同用户分配:

  • 编辑模式: 拥有无限制的编辑权限,操作实时同步。
  • 查看模式: 仅能查看,但可以配置特定的本地操作(如允许本地筛选、排序、隐藏行),这些 UI 变动不会同步给他人,确保了个人分析与团队协作的平衡。

3.完善的版本追溯与回滚

基于 js-collaboration-ot 的历史记录管理功能,开发者可以轻松实现类似 Git 的版本回溯。利用 getOps 接口,可以查看任何时间点的操作历史;利用 fetchHistorySnapshot 接口,可以随时预览甚至恢复到之前的特定版本。

4.可定制化的协同逻辑

SpreadJS 提供了极其丰富的 API(如 on('connect'), on('message')),开发者可以在协同过程中插入自己的业务逻辑。比如:在用户提交特定敏感数据前,通过服务器中间件进行拦截审计。

六、 结语:协作效率的新起点

多人实时在线协同不再是大型云厂商的专利。通过 SpreadJS 协同插件,每一家企业都可以将专业的 Excel 处理能力与高效的实时协作完美融合,构建出属于自己的“高性能协作中台”。

告别“文件传阅”带来的版本混乱,拥抱“所见即所得”的团队效率。

在下一篇文章中,我们将进一步深入技术底层,为你解析 OT(操作转换)算法 的奥秘:SpreadJS 究竟是如何在毫秒级处理成百上千人的编辑冲突,并保证数据绝对一致的?敬请期待。

扩展链接

可嵌入您系统的在线Excel

一、 代码签名证书的主要类型

目前主流的代码签名证书主要分为标准代码签名证书(OV证书)  和扩展验证代码签名证书(EV证书)  两类。

1. 标准代码签名证书(OV代码签名证书)

这是最基础的商业级证书,主要面向发布常规软件的企业或独立开发者。

  • 验证级别:证书颁发机构(CA)会验证企业的工商信息(如营业执照)和域名所有权。
  • 适用场景:适用于常见的 .exe.dll.cab.msi 以及Java等应用程序的签名。
  • 特点:能够通过数字签名让用户确认软件来源,防止代码被篡改,价格相对EV证书更亲民。
2. 增强型代码签名证书(EV代码签名证书)

EV证书是当前行业内最高级别的代码签名证书,也是微软硬件认证(WHQL)的强制性要求。

  • 验证级别:采用最严格的身份审核标准,不仅验证企业法律地位,还需通过电话回访等流程确认。私钥强制存储在硬件令牌(USB Key)中,杜绝网络窃取风险 。
  • 适用场景:特别适用于内核驱动程序(.sys)金融软件以及需要在微软SmartScreen过滤器中立即建立信誉的应用程序。
  • 核心优势:使用EV证书签名的软件,能够绕过Windows Defender SmartScreen的初始拦截,极大提升软件的下载转化率和用户信任度 。

二、 如何选择适合你的证书?

在选择时,开发者应从“用户群体+软件类型”两个维度出发:

  • 如果你发布的是个人小工具、普通商业软件,且主要在正规下载站分发,选择OV代码签名证书即可满足基本的安全需求,性价比最高 。
  • 如果你开发的是硬件驱动、系统内核模块,或者希望软件在Windows 10/11系统中免受SmartScreen拦截,那么EV代码签名证书是唯一的选择 。
  • 特别注意:务必确保证书附带时间戳服务。这能保证即使你的证书过期了,之前签名的软件依然可以被系统信任 。

三、 为什么推荐JoySSL?

代码签名申请入口

直接访问JoySSL注册一个账号记得填写注册码230970获取免费安装服务。

在明确了OV和EV的选择逻辑后,选择哪家CA(证书颁发机构)同样关键。除了GlobalSign、DigiCert等国际大厂,近年来国产CA机构异军突起,其中JoySSL凭借其安全合规与高性价比,成为国内开发者的优质选择 。

1. 合规性与数据安全
JoySSL作为中国自主品牌,严格遵守《密码法》等国家法规。其所有证书验证流程及服务器均部署在国内,实现了数据不出境,这对于有等保合规需求的企业、政府及金融项目尤为重要 。

2. 产品线齐全,性价比高
JoySSL不仅提供SSL证书,在代码签名领域同样提供OV代码签名证书和EV代码签名证书。相比于部分国际品牌动辄数千元的价格,JoySSL在保障全球兼容性的同时,价格更具竞争力,并且提供更快捷的本地化技术支持。

3. 全面的兼容性与服务
JoySSL携手全球可信根证书,签名的软件能完美兼容Windows、Mac、Java等主流操作系统与平台 。此外,JoySSL针对首次尝试签名的开发者提供详细的图文教程及一对一技术支持,解决了新手操作上的痛点。

处理名单、日志、关键词时,很多人都会遇到同一个问题:只想保留有用的行,或者快速删掉无关内容。为了让普通用户不写代码也能完成这件事,我用 Vue 3(Nuxt 3) 开发了一个「文本行过滤/筛选」在线工具,打开网页粘贴文本就能直接用。

在线工具网址:https://see-tool.com/text-line-filter
工具截图:

这个工具常见的使用场景有:

  • 从长日志中只保留包含某个词的行
  • 批量删除空行、重复行、注释行
  • 按前缀或后缀筛选账号、订单号、URL
  • 导出前先清洗文本,让内容更整齐

使用步骤也很简单:

  1. 将原始文本粘贴到输入框(支持多行)。
  2. 选择筛选方式,如“包含关键词”“排除关键词”“正则匹配”“去重”“去空行”。
  3. 按需要开启大小写敏感、整词匹配等条件。
  4. 点击开始处理,结果会立即生成。
  5. 一键复制或下载处理后的文本。

为了让新手更容易上手,我把交互做得尽量直观:你可以看到命中行数和总行数,方便判断筛选是否准确;切换条件后结果会即时更新,减少来回试错。

这个工具不需要安装软件,电脑和手机浏览器都可以使用。文本处理在本地浏览器完成,不必上传原文,日常使用更省心。如果你经常整理文本、日志或名单,这类行级筛选工具会比手动逐行编辑快很多。