黑剪嘴鸥掠水捕食小鱼




xiaohack博客专注前沿科技动态与实用技术干货分享,涵盖 AI 代理、大模型应用、编程工具、文档解析、SEO 实战、自动化部署等内容,提供开源项目教程、科技资讯日报、工具使用指南,助力开发者、AI 爱好者获取前沿技术与实战经验。




在寻找供应商关系管理系统时,许多企业都渴望能有一份权威的排行榜,以便快速锁定最佳选择。然而,现实情况是,这个领域并不存在一份公认的、适用于所有企业的通用榜单。 市面上的各类热门榜单,无论是基于市场声量、用户口碑还是算法推荐,其评估维度、样本范围和价值导向都各不相同。这些榜单能很好地反映市场格局与品牌知名度,却难以精准匹配每家企业独特的业务流程、行业特性和发展阶段。 因此,解读任何排行榜的关键,不在于记住名次,而在于理解其背后的分类逻辑,并将其视为一张描绘市场格局的地图。本文将结合多方市场观察与实践反馈,梳理当前值得关注的几家供应商关系管理系统厂商。我们将深度解析不同厂商的产品理念、能力边界与服务模式,旨在帮助您建立一套自己的评估标准,从而在纷繁的市场信息中,找到最契合自身业务需求的那块“拼图”。 一、正远科技SRM 作为一家数智化解决方案提供商,正远科技主营业务涵盖IT咨询与规划、流程咨询与规划、AI开发、管理软件及解决方案定制开发、BPM/SRM/RPA/LCDP/BI产品实施服务等领域,为用户提供管家式、个性化的解决方案及实施服务。立足智能化浪潮前沿,正远科技以客户价值创造为锚点,研发AI开发平台,为客户在Al时代的运营管理升级筑起新的基石。 正远SRM系统是一款以流程为驱动的企业级业务协同平台。该系统通过标准化服务接口和松耦合架构,实现了企业内部及与供应商之间业务流程的高效整合与灵活扩展,致力于优化供应商全生命周期管理,提升供应链透明度 和协同效率,助力企业实现采购管理的数智化转型升级。正远SRM系统采用双门户设计,分别面向企业内部用户和外部供应商,确保业务流、信息流和数据流的高效协同。 核心功能与好处:正远SRM系统的核心业务流程涵盖了从供应商准入到财务结结算的全链条数字化协同管理。其最大好处在于极强的业务灵活性,企业可以通过可视化配置快速适应组织变革或独特的采购政策,避免因系统僵化导致的二次开发或推倒重来。 竞对差异:相较于标准化、套装化的国际软件(如SAP),正远科技更擅长处理中国本土企业,特别是制造业中非标准、动态变化的复杂业务流程。相较于一些侧重轻量协同的工具型SaaS,它又能提供企业级的安全、集成和深度管控能力。 二、鲸采云SRM 鲸采云是近年来在SRM市场上表现突出的专业厂商,以其新一代灵活可配置的SRM系统为核心,致力于为企业提供全场景、全链路的数字化采购解决方案。它被视为 “全场景数字化标杆” 的代表,其市场地位建立在对企业多样化需求的深度适配和对效率提升的极致追求上,在多个行业标杆案例中取得了显著成效。 产品特色与服务 鲸采云SRM的核心竞争力在于高度的灵活性与深度的AI赋能。它旨在打破传统SRM系统功能固化的局面,让系统主动适配企业业务,而非相反。 核心功能与好处:产品提供供应商全生命周期管理、智慧寻源、采购商城、订单与财务协同等模块。其突出优势是内置了基于大语言模型的 “鲸采云AI” ,能实现智能填单、合同生成与审查、基准价推荐等功能,将数日工作压缩至几分钟。同时,其国际版全面支持多语言、多币种与多时区协同,适合有全球化业务的企业。 竞对差异:与许多传统SRM产品相比,鲸采云在人工智能与采购场景的深度融合上走在前列,不仅仅是流程自动化,更追求智能化决策。其开放的生态体系(内置超150种标准插件)也使其在与其他系统集成时更具优势,这是部分封闭或集成能力弱的系统所不具备的。 三、轻流 轻流是国内领先的无代码业务流程管理(BPM)平台提供商,以其灵活的可视化流程搭建能力而闻名。其市场定位是赋能业务人员快速构建各类管理系统,在SRM领域,它提供的是轻量、灵活、可快速定制的采购与供应商协同解决方案,尤其适合流程变化快、需要快速上线或对标准化套装软件感到束缚的中小企业和创新部门。 轻流的核心优势在于其强大的无代码流程引擎和高度可配置性,允许企业像搭积木一样,自定义搭建符合自身独特管理需求的SRM应用。 核心功能与好处:通过轻流,企业可以快速搭建供应商信息库、采购申请与审批流、询价比价流程、订单跟踪、库存管理等模块。其最大好处是极致的敏捷性:当采购政策或组织架构调整时,业务管理员可以自行调整流程和表单,无需依赖IT开发,实现“业务驱动IT”。 竞对差异:与正远科技、8Manage等专业的、功能预设完整的SRM系统相比,轻流更像一个 “SRM应用构建工具” 。它不提供开箱即用的、深度的战略寻源或复杂成本分析模块,但其在应对个性化、非标流程以及快速原型验证方面具有无可比拟的速度优势。对于流程尚不标准化或希望低成本试错的企业,它是理想起点。 四、8Manage SRM 8Manage SRM由高亚科技开发,是一家专注于提供端到端采购与供应商管理解决方案的专业厂商。在市场中,8Manage SRM以其模块化设计、功能全面和灵活部署的特点,服务于从成长型企业到大型集团的多样化客户,在制造、建筑等行业积累了众多知名客户案例。 8Manage SRM定位为一款综合性、一体化的采购管理平台,强调通过数据驱动决策和流程自动化来提升采购透明度与效率。 核心功能与好处:系统提供从采购需求、寻源招投标、供应商管理、合同管理到付款结算的完整闭环管理。其电子招投标和竞价模块支持灵活的规则配置,是其特色功能。系统支持多种部署方式(SaaS及私有化),并具备多语言支持能力,适应性较广。 竞对差异:与深度绑定在大型ERP生态内的SRM模块(如用友、金蝶面向大型企业的产品)相比,8Manage SRM作为独立专业产品,在功能深度与系统独立性之间取得了较好平衡,避免了企业被单一巨头生态锁定的风险。同时,相较于一些极度轻量化的SaaS工具,它又能提供更全面和深入的采购流程管控能力。 五、用友YonBIP采购云 用友网络是中国领先的企业云服务与软件提供商,其YonBIP采购云作为用友商业创新平台的核心组成部分,致力于为国内大中型企业提供产业链级的社会化采购与供应链协同解决方案。 用友采购云强调与用友ERP、财务等系统的原生态深度集成,实现业、财、供一体化管理。 核心功能与好处:平台覆盖从寻源、协同到结算的采购全链路,其优势在于深刻理解国内企业的管理流程和财务制度,在供应商准入、招投标、发票校验等环节的本地化适配性高。能很好地支持集团型企业的多组织复杂管控需求。 竞对差异:其核心差异化优势是与用友ERP生态的原生一体化。对于用友的存量客户,尤其是大型集团企业,选择用友采购云可以实现成本最低、数据最通的平滑扩展。 六、泛微·京桥通 泛微·京桥通是协同办公领域上市公司泛微网络旗下的专项采购管理品牌。凭借泛微在OA(办公自动化)市场的领先地位和十余年积淀,京桥通在央国企及大型组织的采购数字化市场中占据了显著份额,市场反馈显示其占有率处于领先位置。其地位源于对中大型组织复杂审批、合规和内控需求的深刻理解。 京桥通的核心特色在于其与OA流程和泛微生态的深度一体化融合,将采购管理与内部协同、风控合规无缝连接。 核心功能与好处:平台实现了从供应商准入到付款归档的全流程数字化,并特别强化了智能比价、供应商风险预警(结合外部征信数据)以及利用OCR、电子签章实现的合同全流程电子化。其最大好处是为大型组织提供了合规、可追溯、高效协同的一体化解决方案,特别符合央国企等对流程合规性要求极高的客户需求。 竞对差异:与大多数独立的SRM系统不同,京桥通的差异化优势根植于 “协同基因” 。对于已广泛使用泛微OA体系的大型组织而言,选择京桥通能实现业务流程与办公审批的极致流畅体验,这是其他SRM厂商难以复制的生态优势。相比之下,其重点可能不在于提供最丰富的战略寻源策略,而在于确保采购活动在既定规则下安全、合规、高效地运转。 七、致远互联·供应商协同管理 致远互联是中国领先的协同管理软件及云服务提供商,其核心产品为AI-COP智能协同运营平台。该公司长期服务于政务及大中型企业市场,在协同办公、流程管理及数字化运营领域占据重要地位。其供应商协同管理方案并非独立单品,而是基于统一协同平台构建的专项场景应用,这使其在满足组织内部流程与外部协作一体化方面具备先天架构优势。 该方案的核心特色在于 “基于统一协同平台的业管一体化融合” ,旨在打通内部管理流程与外部供应商协作的壁垒。 核心功能与好处:方案覆盖供应商全生命周期管理、寻源采购、订单协同、财务对账等核心环节。其最大好处在于能够将SRM流程与内部的预算控制、合同审批、付款申请等环节在同一个平台上无缝衔接,实现数据不落地流转。例如,采购申请可直接触发预算校验,中标结果可自动生成合同审批流,有效解决了跨系统数据孤岛问题,提升了端到端的流程效率与管控力度。 竞对差异:与SAP Ariba或Coupa等独立的、侧重外部网络化的SRM平台相比,致远互联的方案更侧重于组织内部复杂管理流程与外部供应商协同的深度集成。与同为协同厂商的泛微·京桥通相比,两者思路类似,均强调“协同+管理”,但具体的平台技术架构、流程引擎能力及行业化方案侧重有所不同,共同构成了国内“协同生态型”SRM的典型路径。 总结与选型建议 通过以上分析可以看出,所谓“排行榜”上的领先者,实则是各自赛道的专家。对SRM系统的选择不应基于一个笼统的名次,而应始于一次清晰的自我审视: 明确定位与核心诉求:首先问自己,企业是大型集团/跨国企业、快速成长的中型企业,还是预算有限的初创/小微型企业?核心诉求是满足全球合规与复杂集成、优化深度制造协同、实现业财供一体化,还是仅仅快速解决供应商在线协同的燃眉之急? 识别关键差异化能力:接着,将您的核心诉求与厂商的差异化能力对齐。若追求业务的高度灵活与深度定制,正远科技的“双轮驱动”架构值得探究;若青睐AI深度赋能与全场景智能,可重点考察鲸采云;若急需低成本、快上线的轻量化工具,金蝶AI星辰是典型代表;若需要独立且全面的端到端管理,8Manage SRM是可靠选项;若处于强合规、重流程的泛微OA生态内,京桥通则是自然延伸。 超越榜单的实践验证:最后,请记住榜单仅是信息入口。建议基于以上分析,筛选出2-3家最契合的供应商,推动一场深入的 “概念验证(PoC)” 。围绕企业最核心、最复杂的1-2个采购场景进行实际搭建与测试,亲身感受系统的灵活性、易用性以及供应商的响应速度与服务深度。唯有通过实践验证的方案,才是对企业而言真正的“榜首”之选。






大家好,我是拖更博主r0leG3n7。本文将简单介绍frp这款隧道代理工具的项目结构和代码运行流程以及如何通过对frp二次开发(后面简称"二开")来消除其静态特征和流量特征从而规避杀软以及EDR的检测。如有任何错误和不足欢迎各位师傅指正,转载请注明文章出处。
致敬伟大的原项目:https://github.com/fatedier/frp,我选择的是较新版本0.65.0的frp。(我写这篇文章的时候frp刚刚更新到0.66.0,但应该不影响我当时二开的就是最新版的frp[狗头])。
先问大家一个问题,如果我需要对某个开源项目进行二开,我有必要把这个开源项目里所有的代码结构都分析得明明白白的嘛?那当然是没那个必要,对于这种大型的开源项目,我们需要很明确自己想要把这个项目改成什么样子,确定自己的需求,确定项目有哪些对于你来说是"缺陷"的地方,这样就不会在庞大的代码海洋里迷失自己。
1、首先来到我们软件生命周期最重要的需求分析阶段,我的大致的需求就是要改frp的静态特征和流量特征来绕过EDR检测达到免杀的效果,确定大致的需求以后我需要知道frp有哪些特征。
原版的frp有如下几个典型特征:
1)frp的服务端和客户端启动时都会默认读取同目录名为frpc.ini或者frps.ini的配置文件。
2)frp的客户端与服务端发起TCP连接时会发送诸如版本号、架构、token、run id等信息进行登录认证。
3)frp的客户端与服务端在连接成功或者失败时都会在控制台输出一些debug信息或者提示信息。
4)frp的客户端与服务端在TCP连接建立后的第一个应用层数据包会发送一个自定义的字节,这个字节的值为0x17。
5)frp的客户端与服务端在TCP连接建立成功后,服务端可以通过对某些API接口发起get请求、post请求或者put请求去控制客户端,比如/api/reload、/api/stop等。
2、确定大致的需求并且定位"缺陷"以后,我要明确我的需求,明确我要把它改成什么样子。
我明确的需求:
1)对于frp的服务端和客户端在本地读取配置文件的行为,我可以把配置文件信息想象成shellcode,按照loader加载shellcode那样处理。我想到的是将配置文件硬编码在程序里面;或者将配置文件加密后通过命令行传入frp,frp客户端与服务端尝试建立连接时再进行解密;或者通过远程URL加载;还有最重要的是去除通过文件路径读取配置文件的功能。
2)对于frp的服务端和客户端建立连接失败时的输出的错误信息,我要进行删除或者修改;对于建立连接成功时发送的登录信息或者代理信息,我要进行TLS加密或者将默认变量名、键值对修改;对于TLS建立连接的默认自定义字节以及服务端控制客户端的api默认接口名也是一样地做修改处理。
1、程序所需的依赖写在了项目的go.mod文件中,在GoLand的IDEA可以按"Alt键+回车键"自动下载对应的依赖。

2、项目的Makefile是编译命令文件,在这里可以找到服务端代码入口/cmd/frps以及客户端的代码入口/cmd/frpc。

3、我们可以直接定位到客户端/cmd/frpc/mian.go,编译时会自动搜索该目录下的mian.go文件作为编译的入口,重点关注sub.Execute()。

4、按alt跟进sub.Execute(),它的主要功能是rootCmd.Execute()这行 。

5、按alt跟进rootCmd.Execute(),rootCmd.Execute()会执行rootCmd中的RunE,RunE中包含两个关键的函数runMultipleClients()和runClient(),这两个函数主要的功能就是加载配置文件然后建立与服务端的链接。我们主要看runClient()函数,一般情况下一个frpc客户端只加载一个配置文件,所以不用怎么去考虑改runMultipleClients(),我二开的时候索性直接删掉了命令行配置文件路径的输入。runClient()传入一个名为cfgFile的全局变量,它是frp客户加载配置文件的路径。

6、纵观整个rootCmd.Execute()过程,我们都没有看到给cfgFile全局变量赋值的地方。但是我们知道原版的frpc客户端是从命令行输入配置文件路径的,我们可以从包的init()函数看到程序是怎么从命令行中获取用户输入的配置文件路径赋值cfgFile变量的。init()函数是 Go 语言中的一个特殊函数,通常用于资源、包和变量的初始化。它的特点是每个包的 init() 在程序运行期间只执行一次;init()无需手动调用,会在main()之前自动执行,导入包的 init() 先于当前包的 init() 执行。

7、回到rootCmd.Execute(),按alt跟进runClient()函数,我们来到了这次二开中最重要的函数config.LoadClientConfig(),它是我们修改配置文件传参关键。从返回值我们可以知道,它会返回配置文件的基本配置信息、代理配置信息、配置文件格式等。config.LoadClientConfig()的传入参数是配置文件路径,这个函数是需要完全改写的,我上面的需求已经说的很明确了,我会从硬编码、远程URL输入或者命令行输入去读取配置文件,不会有从文件路径读取配置文件的行为,减少文件落地。

8、虽然说要完全改写config.LoadClientConfig(),但是我们还是要按alt跟进看一下它的内部逻辑以便我们更精确无误地对它进行修改,config.LoadClientConfig()存在读取并转换配置文件的legacy.ParseClientConfig()方法。

9、按alt跟进legacy.ParseClientConfig(),legacy.ParseClientConfig()函数通过文件读取函数GetRenderedConfFromFile()以及传入的文件路径来读取配置文件信息并将其赋值content变量,然后将content的类型转化为字节数组后将其作为参数传给UnmarshalClientConfFromIni()方法,UnmarshalClientConfFromIni()将转换后的基础配置文件信息赋值给cfg。

10、同样地,legacy.ParseClientConfig()通过legacy.LoadAllProxyConfsFromIni(),将转换后的代理配置文件信息等赋值给变量proxyCfgs和visitorCfgs。这时候我们知道配置文件信息主要是靠UnmarshalClientConfFromIni()和LoadAllProxyConfsFromIni()两个函数进行转换的,到时候我们二开的时候就照着这两个函数简单修改一下就行了。

11、了解完它是怎么读取并转化配置文件信息后,我们再回到上面的runClient()函数,再大致了解一下它是怎么通过startService方法以及转化后的配置文件信息启动服务的,这里注意startService方法第五个参数cfgFile为配置文件路径,到时候服务端调用/api/reload接口重新加载配置文件时候会用到。因为我二开时将通过文件路径读取配置文件信息这个行为删除了,这个参数到时候会变成空值,这个参数置空以后服务端调用该接口可能会报错。


12、service.go的NewService创建服务对象方法。

13、service.go的Run运行服务对象方法。

本节我将介绍如何对frp原项目进行二开改造隐藏其静态特征和流量特征,包括修改传参方式,修改frp默认输出,修改frp静态字符串,修改frp的TLS流量特征等。相信看过四大名著《三国演义》的都知道赵云在长坂坡七进七出,单骑救主的故事,我第一次了解到这个故事的时候我就觉得不可思议,真的有人能从这么多的魏军人马中带着个婴儿死里逃生吗?在二开了frp之后,我就悟到了。frp客户端就是赵云,配置文件就是阿斗,单骑救主护送阿斗回蜀就是frp客户端与服务端建立连接的通信过程。赵云之所以会被在茫茫人海中被魏军检测到,并不只是因为他喊了那句"我乃常山赵子龙",更多的是因为他有对阿斗进行明目张胆地"取餐"这个行为,不过好在他能及时调整,将阿斗硬编码到自己的怀里,才做到了七进七出。我觉得单骑救主这个故事可以有更多opsec的改进方案让他变得更加合理更加地叫人信服,至于怎么改,请看下面听我娓娓道来。
传参方式的修改在上面需求的第一条已经提出来了,我的最终方案是去除通过文件路径读取配置文件的部分;如果frp收到命令行传入的加密配置文件,就解密该配置文件进行连接;如果读取不到命令行传入的加密配置文件,就读取硬编码的配置文件进行连接。
1、首先去除init()函数中接收对配置文件路径的输入,新增一个全局变量eStr,用于接收用户控制台输入的加密后的配置文件信息,使用示例"-e <加密的配置文件信息>"。
rootCmd.PersistentFlags().StringVarP()方法参数说明:
第一个参数为接收控制台输入的指针
第二个参数为参数名称
第三个参数为传入参数的简写,比如"-c ./frpc.ini"
第四个参数为参数的默认值(StringVarP就必须为字符串类型,BoolVarP就必须为布尔类型,以此类推)
第五个参数为参数介绍说明

2、修改rootCmd.Execute()逻辑,当eStr变量不为空(也就说收到来自用户在命令行输入的加密配置文件内容),就对传入的加密配置文件内容进行解密,将它解密后的明文传给一个自定义的cfgContent变量;如果eStr变量为空,就将硬编码的配置文件信息传给cfgContent变量。cfgContent变量最终会作为参数传给修改后的runClient()函数。

3、修改runClient()函数运行逻辑,之前runClient传入第一个参数是配置文件路径,我现在将这个参数改成配置文件内容,到时候硬编码的配置文件或者解密后的配置文件可以直接作为参数调用这个函数,修改的地方主要是config.LoadClientConfig()这个部分,将其修改为了一个新的函数config.LoadClientConfigFromContent(),用于接收传入的配置文件内容并将其转换。

4、config.LoadClientConfigFromContent()第一个传入参数为配置文件内容的字符串,返回值与之前一致。
func LoadClientConfigFromContent(content string, strict bool) (
*v1.ClientCommonConfig,
[]v1.ProxyConfigurer,
[]v1.VisitorConfigurer,
bool, error,
) {
var (
cliCfg *v1.ClientCommonConfig
proxyCfgs = make([]v1.ProxyConfigurer, 0)
visitorCfgs = make([]v1.VisitorConfigurer, 0)
isLegacyFormat bool
)
contentBytes := []byte(content)
// Render template with values
renderedContent, err := RenderWithTemplate(contentBytes, GetValues())
if err != nil {
return nil, nil, nil, false, fmt.Errorf("render template error: %v", err)
}
if DetectLegacyINIFormat(renderedContent) {
// Parse legacy INI format
legacyCommon, err := legacy.UnmarshalClientConfFromIni(renderedContent)
if err != nil {
return nil, nil, nil, true, err
}
// Parse all proxy and visitor configs from the same content
legacyProxyCfgs, legacyVisitorCfgs, err := legacy.LoadAllProxyConfsFromIni(legacyCommon.User, renderedContent, legacyCommon.Start)
if err != nil {
return nil, nil, nil, true, err
}
cliCfg = legacy.Convert_ClientCommonConf_To_v1(&legacyCommon)
for _, c := range legacyProxyCfgs {
proxyCfgs = append(proxyCfgs, legacy.Convert_ProxyConf_To_v1(c))
}
for _, c := range legacyVisitorCfgs {
visitorCfgs = append(visitorCfgs, legacy.Convert_VisitorConf_To_v1(c))
}
isLegacyFormat = true
} else {
allCfg := v1.ClientConfig{}
if err := LoadConfigure(renderedContent, &allCfg, strict); err != nil {
return nil, nil, nil, false, err
}
cliCfg = &allCfg.ClientCommonConfig
for _, c := range allCfg.Proxies {
proxyCfgs = append(proxyCfgs, c.ProxyConfigurer)
}
for _, c := range allCfg.Visitors {
visitorCfgs = append(visitorCfgs, c.VisitorConfigurer)
}
}
if len(cliCfg.Start) > 0 {
startSet := sets.New(cliCfg.Start...)
proxyCfgs = lo.Filter(proxyCfgs, func(c v1.ProxyConfigurer, _ int) bool {
return startSet.Has(c.GetBaseConfig().Name)
})
visitorCfgs = lo.Filter(visitorCfgs, func(c v1.VisitorConfigurer, _ int) bool {
return startSet.Has(c.GetBaseConfig().Name)
})
}
proxyCfgs = lo.Filter(proxyCfgs, func(c v1.ProxyConfigurer, _ int) bool {
enabled := c.GetBaseConfig().Enabled
return enabled == nil || *enabled
})
visitorCfgs = lo.Filter(visitorCfgs, func(c v1.VisitorConfigurer, _ int) bool {
enabled := c.GetBaseConfig().Enabled
return enabled == nil || *enabled
})
if cliCfg != nil {
if err := cliCfg.Complete(); err != nil {
return nil, nil, nil, isLegacyFormat, err
}
}
for _, c := range proxyCfgs {
c.Complete(cliCfg.User)
}
for _, c := range visitorCfgs {
c.Complete(cliCfg)
}
return cliCfg, proxyCfgs, visitorCfgs, isLegacyFormat, nil
}
5、将config.LoadClientConfigFromContent()返回的cfg, proxyCfgs, visitorCfgs作为参数传给startService(),传参方式这部分就修改完成了。注意startService()的第五个参数为配置文件路径,我修改frp的传参方式以后这个配置文件路径的值就不存在了,所以我把它的值置空了,这个参数在后面调用/api/reload重新加载配置文件时候会用到,如果仍需要调用这个api建议将其修改为一个系统默认路径,不然调用时可能会导致frp客户端异常。

6、运行效果就是先用加密程序将frpc配置文件加密后的字节数组以base64编码的字符串输出。

7、frpc客户端启动时如果接收到-e 传入的Base64编码的字符串,frpc客户端就会解密该字符串并转化配置文件;如果接收不到-e 传入的Base64编码的字符串,frpc客户端就会读取代码内硬编码的配置文件。从这里我们也可以看到frp客户端在连接到服务端时会输出一些诸如"client/service.go:331"的信息,这些都是要做处理的。

上面讲frp特征的时候提到frp的客户端与服务端在TCP连接建立后的第一个应用层数据包会发送一个值为0x17的自定义字节,这个是frp在流量层面最显著的特征之一,就好像赵云的武器"龙胆亮银枪"以及坐骑"照夜玉狮子",使得赵云在茫茫魏军人马中被一眼认出。
我们先用wireshark看下frp原味的通信流量,下图是frp的TLS的握手流量,可以从"Client Hello"和"Server Hello"这几个关键字快速定位,点击"Transport Layer Security",我们可以看到这部分的第一个字节是0x16。

再看frp部分的应用流量,点击"Transport Layer Security",我们可以看到这部分的第一个字节是0x17。

再通过搜索0x17和0x16定位到项目中/pkg/util/net/tls.go和/server/server.go,我们看到自定义字节变量FRPTLSHeadByte的值为0x17,以及判断0x16和x017 switch逻辑,似乎就能跟上面wireshark看到的流量特征扯上一些联系?我之前听有些卖frp免杀课的人说修改了这个变量FRPTLSHeadByte(旧版的frp好像是另一个变量名)的值,就能消除上面wireshark看到的frp的0x17流量特征。


事实真的是这样的吗?其实他们只说对了一半,修改变量FRPTLSHeadByte确实能消除frp一部分的流量特征。但无论你怎么改FRPTLSHeadByte的值,如果像上面那样看frp的TLS的握手流量和frp的应用流量,无论你怎么改,看到的还是0x17。因为上面看到的那部分就是TLS的正常流量,TLS记录协议头固定为5字节,第一个字节0x17代表应用数据,如果是0x16代表TLS握手数据;第二第三个字节代表TLS版本;第四第五个字节代表数据长度。

他们错误地把FRP自定义字节理解为TLS记录协议头固定字节的第一个字节,因为FRP自定义字节默认值刚刚好就是0x17,和应用数据的TLS记录协议头第一个字节一样。但实际上FRP自定义字节是客户端与服务端在TCP连接建立后的第一个应用层数据包发送的第一个字节,为了方便大家理解,我把FRP自定义字节从默认值0x17改成了0x18,这个字节会在TLS握手之前发送,可以结合下图去理解。

在wireshark内,我们右键frp的tcp流量,选择"追踪流",再选择"TCPStream"

再选择显示为"Hex转储",我们就能看到frp自定义字节修改前的样子:

frp自定义字节修改后的样子:

但其实仅修改这一个字节还是不够,有部分厂商的流量设备已经能自动识别这类单字节修改后的流量,要想在流量层面隐藏得更好需要修改/pkg/util/net/tls.go的CheckAndEnableTLSServerConnWithTimeout()函数,在TLS握手之前多填充几个自定义字节。

在修改完自定义字节以后,需要frpc配置文件中[common]下面添加这一行,不然客户端连接到服务端会报错。
disable_custom_tls_first_byte = false
因为从frp的0.50.0版本开始,frp就将禁用发送自定义字节的默认值设置为true,如果使用了frp自定义字节就需要加上这一行

最后一定要记得服务端frps的配置文件加上强制TLS连接。
tls_only = True
客户端frpc的配置文件也加上使用TLS加密,不然前面做的一切都白费。
tls_enable = true
这一步主要是防止赵云有事没事就喊一句"我乃常山赵子龙"。其实就是简单改一些frp默认控制台输出,减少被检测识别的概率。
/client/server.go



/client/control.go

/pkg/auth/token.go

/cmd/frpc/sub/root.go

/pkg/msg/msg.go中有frp客户端与服务端通信时的登录信息以及代理信息,在使用了TLS加密以后这个不修改其实也不会有很大影响,但是改了总比没改会好点。


client/service.go和server/service.go存在默认盐值crypto.DefaultSalt,frp身份认证过程不是直接交换密码或者token,而是进行带盐值的hash计算和比较,不修改默认盐值可能存在被爆破的风险。

/cmd/frpc/sub/verify.go
这里也有一个包含校验读取配置文件方法的go文件,它也会有个读取本地文件的行为,这里可以直接删除掉/cmd/frpc/sub/verify.go,对编译和运行没影响,不删除反而在读取不到本地配置文件时会输出一些frp的特征,还能缩小编译后的文件体积。

/pkg/util/version/version.go中存在frp的版本信息

/cmd/frpc/sub/admin.go
1、frp服务端提供了三个api接口控制frp客户端,这三个接口的功能分别是重新加载配置文件、查看代理状态、停止frp客户端运行。

2、重新加载配置文件接口会读取frp首次与客户端连接时输入的配置文件路径。

3、svr.configFilePath的来源于startService()方法传入的第五个参数,这部分要在runClient方法内修改。

/client/admin_api.go

市面上常用的go语言工具混淆有三种,分别是:go-strip、cross-file-obfuscator和garble。附上项目地址:
https://github.com/boy-hack/go-strip
https://github.com/burrowers/garble
https://github.com/masterqiu01/cross-file-obfuscator
大家现在千万别用go-strip去混淆,go-strip前两年生存环境还可以,现在的杀软很容易识别到go-strip,并且只要是go-strip混淆就判定为恶意软件。我现在使用的最多的是garble,它能混淆一些类名以及字符串,并且能较好地压缩文件体积,garble需要go语言1.25.0以上的版本才能使用,下面简单介绍一下Kali怎么安装1.25.0以上的go语言以及garble。
1、下载解压go
wget https://mirrors.aliyun.com/golang/go1.25.4.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.25.4.linux-amd64.tar.gz
nano ~/.zshrc
2、配置环境变量,~/.zshrc末尾追加如下
export GOROOT=/usr/local/go
export GOPATH=$HOME/go # 推荐设置工作目录
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
3、使配置生效
source ~/.zshrc
export GOPROXY=https://goproxy.io
go install mvdan.cc/garble@latest
1、在kali使用garble编译前建议先使用原生的go编译器编译一次,主要是让其下载对应的依赖
go build -o ./frpc.exe ./cmd/frpc
2、然后再用garble编译(在kali上编译需要指定目标架构,我这里编译的是windows的amd64)
export GOOS=windows
export GOARCH=amd64
garble build -o ./frpc-1.exe ./cmd/frpc
3、garble压缩效果,原生的go编译器编译出来的大小为23Mb左右,garble编译出来的为18Mb左右

4、garble的混淆效果如下:
原生的go编译器

garble

5、如果kali不想指定目标架构,也可以使用如下命令跨平台编译
make -f Makefile.cross-compiles
客户端在卡巴斯基和核晶环境下通过frp代理做端口扫描能稳定运行

在没有签名没有做反沙箱状态下上传至VT,只有ESET-NOD32识别出来了是frp客户端

frp在做完传参方式修改、流量改造以及garble混淆后基本就能bypass大部分杀软了。传参方式修改是必须做的,它不仅可以减少文件落地,更是一种针对frp特定的反沙箱操作,某些沙箱提供带有特定文件(比如frpc.ini和frps.ini)的环境来针对性地检测frp。在此基础再加上一些比如延迟执行等反沙箱操作就更好了,如果能把frp做成BOF插件从内存加载那就更opsec了。流量改造方面除了修改frp自定义字符,frp客户端与服务端连接时尽量以域名进行连接,不要直接暴露原生IP,服务端的域名要做cdn防护或者使用云平台PaaS进行转发,然后配置好自定义的TLS证书(最好TLS证书也像配置文件那样内嵌到程序里面,减少文件落地),这样能减少被溯源的概率。静态特征方面,除了garble混淆以外,如果在确定了是目标环境是什么杀软以后,可以考虑使用UPX对frp进行加壳,某些杀软对UPX并不敏感,加壳可以解决百分之90的静态特征问题,但是加壳以后UPX也成为了它的静态特征,不过UPX的静态特征也是可以处理的,其他静态特征处理可以翻看我公众号之前的文章,此处就不再赘述了。除了以上这些二开的点,我们还可以把frp做成系统服务进行权限维持、添加ICMP隧道类型等。
frp的优点就是稳定,但是缺点也很明显,当你需要搭建二级代理或者三级代理的时候,你就不得不把frp二级或三级代理的服务端也上传上去,这意味着你要上传很多个客户端以及服务端,而且对他们都要做免杀处理。隧道代理工具我目前用的比较多的除了frp还有Stowaway,项目地址:https://github.com/ph4ntonn/Stowaway,它也是一个很值得去二开的一个项目,Stowaway的优点是它既能做客户端也能做服务端,往往搭建二级代理或者三级代理上传一个可执行程序就足够了。
最近在官网充值了一些 Kimi 2.5 的 API ,感觉很好用,想订阅下会员,Kimi 对会员权益说明很模糊。之前按次数,被喷后,改成按额度,但是多少额度也不说清楚?

只宣传限时扩容三倍。。。还有就是 Kimi Code 和 Kimi 会员有什么区别?
Kimi Code 显示 [购买以上任意套餐,还会获得其他 Kimi 会员权益]

Kimi 会员界面显示 [ Kimi Code 2 倍额度]

感情是在这打哑谜是吧,什么档次会员多少 token 是什么不能说的秘密吗? Kimi Code 送 Kimi 会员,Kimi 会员送 Kimi Code 在这套娃呢? Kimi Code 宣传限时扩容三倍,Kimi 会员宣传 Kimi Code 2 倍额度,真太乱了...
这当然不会是奥数题

插件成功上架谷歌插件商店了,之前分享过一次,但是上次使用比较麻烦,现在可以直接从谷歌插件商店安装
CloseTab 是一款强大的浏览器标签页管理插件,帮助你轻松管理大量标签页,提升浏览器性能和工作效率。支持一键保存、恢复、搜索和批量管理标签组。
Chrome / Edge 浏览器
直接访问 Chrome 应用商店 点击"添加至 Chrome"即可一键安装。
适用于想要体验最新功能或进行二次开发的用户。
下载地址: Gitee 仓库
chrome://extensions/edge://extensions/保存标签组
恢复标签组
管理标签组
由于是使用机场自己的客户端,没有 tun 模式,网上搜了一下可以使用 Proxifier 解决 Antigravity 的登录问题,正好之前用 OBS 直播油管的时候安装过 Proxifier ,于是直接设置了一个规则,顺利登录 Antigravity 。
但是马上遇到一个棘手的问题,agent 加载不出来,也就是对话框和模型都加载不出来,我以为是跟 cursor 一样需要在设置里面配置 proxy ,结果设置了也不行,重启几次 IDE 都是加载不出来。
搜了一下公众号文章,都讲的不清不楚,Proxifier 规则里面要增加好几个 exe ,不止是 antigravity.exe ,直接复制别人公众号文章里面提供的文件名,行不通,于是在任务管理器里面,把 Antigravity 相关的所有 exe 都找到所在文件夹,通过手动添加进去,就搞定了。
需要添加的几个 exe 的文件夹路径(其中 XXX 需要换成你的用户名):
C:\Users\xxx\AppData\Local\Programs\Antigravity
C:\Users\xxx\AppData\Local\Programs\Antigravity\resources\app\extensions\antigravity
我添加进规则的几个 EXE:antigravity.exe; inno_updater.exe; language_server_windows_x64.exe; fd.exe
记得要通过 browser 这个按钮添加才有效。
附赠 Proxifier 注册码 5EZ8G-C3WL5-B56YG-SCXM9-6QZAP
如果要启用https证书,需要修改3个地方: 你在docker上面面板里修改gitlab的环境变量里的 gitlab的访问地址,选域名访问,那ip访问就不可以了;选https访问,那http访问就会出问题的。一 环境与版本
二 记录:
因为这类软件,不管你的路由器里是否配置了局域网域名解析,都会用自己软件里的dns配置解析域名。
7.1 gitlab的反向代理这里需要添加证书,并最好开启强制http跳转到https,因为gitlab系统读取配置的时候只会读取带访问协议的地址.
7.2 修改这里:/www/dk_project/dk_app/gitlab/<你的gitlab容器名>/docker-compose.ymlenvironment:
GITLAB_OMNIBUS_CONFIG: |
# Add any other gitlab.rb configuration here, each on its own line
external_url 'https://${DOMAIN_HOST}'external_url是会出问题的,直接改这里,改完之后要记得重建。
7.3 如果用域名访问gitlab,记得去nginx反向代理那设置那里改一下你的反向代理地址的端口。比如你之前的http访问端口是20080,https访问端口是20443,那这个时候就要从20080改到20443。docker-compose.yml文件里,在external_url的配置下面一行,再增加一行registry_external_url,至于后面跟什么域名,随你便。记得如果你填写的是域名,在nginx那里添加以下反向代理记录。
三. 证书问题
/www/dk_project/dk_app/gitlab/<你的gitlab容器名称>/config/ssl里添加响应的证书文件,域名一定要和你的registry_external_url对应上。
随着企业走向全球化,稳定、低延迟的跨境网络连接已经不仅是“速度体验”问题,而是业务连续性、数据同步、安全合规的关键保障。无论是跨境电商、海外办公、SaaS 系统访问还是实时视频会议,普通互联网常常无法满足企业级要求,这也促使越来越多公司选择国际专线宽带来优化跨境连通性。 一、国际专线宽带有哪些类型? 传统国际专线通常指 物理隔离 / 逻辑隔离的专用带宽,比如 MPLS / IPLC 等,这类专线从国内直连海外节点,专有资源独占,不经过公网共享。 核心优势: SD-WAN 是在运营商合法国际出口基础上,通过 智能路由、链路叠加与流量优化技术 实现的跨境网络连接方式。它不是单纯的物理专线,而是将运营商出口 + 多链路(包括宽带/4G/5G等)结合,通过软件灵活管理。 核心优势: 二、影响国际专线宽带价格的因素是什么? 三、国际专线宽带怎么收费的? 基础版本: 企业级专线: 综合来看,第三方服务商OSDWAN提供了更灵活、更低门槛的价格方案,而运营商直供则更适合对大带宽、高 SLA 有硬性要求的场景。 四、国际专线宽带哪家好? 五、国际专线宽带怎么开通? 开通国际专线一般包括以下几个步骤: 六、常见问答 Q1:国际专线一定要用么? Q2:SD-WAN 和传统专线哪个好? Q3:带宽越大价格越贵吗? Q4:为什么第三方服务商价格比运营商低? OSDWAN作为国内专业的跨境网络服务商,为出海企业提供合规、高速、稳定的网络解决方案,支持硬件、软件方案灵活部署。
简单来说,主要有以下两种主流解决方案:
国际专线宽带并不是一个固定价格,不同企业需求不同,对价格有显著影响的关键因素包括:
带宽是价格的核心决定因素。例如 5M、10M、50M、100M 的专线在费用上有较大差异,带宽越大费用越高。
不同国家/地区链路成本存在明显差异:
亚洲区域(如香港、新加坡)通常比欧美方向便宜;
资源稀缺区(如南美、中东)成本更高。
传统国际专线价格偏贵,而 SD-WAN 通过弹性调度和混合链路,降低了整体成本。
运营商自身提供的专线服务与第三方服务商在价格和服务层面可能不同,服务级别协议(SLA)、响应时间、监控与管理平台等也会对费用产生影响。
三大运营商(中国电信/中国联通/中国移动)是企业国际专线的主要来源之一,以下为市场上反馈的典型价格区间(仅供参考):
以国内专业跨境 SD-WAN 服务商 OSDWAN 为例,其国际专线宽带价格较有弹性,提供不同套餐供选择:
办公室账号版: ¥690/年起,共享带宽、适合轻量办公。
社媒运营账号版: ¥1500/年起,提供独享静态 IP,更适合社媒和电商运营。
独立专线标准版: ¥10.000/年,含独享合规 5M 专线带宽 + 静态住宅 IP。
选择“好”的国际专线,不能只看价格,还要看以下几个要素:
正规服务商应基于运营商合法国际出口通道,支持 SLA 保障与故障响应。
不同企业场景需求不同:
对业务稳定性极高要求(如金融交易)更适合传统国际专线;
对成本与灵活性要求更高(如跨境电商、外贸小团队)可选 SD-WAN 方案。
运营商专线:固有优势是资源可靠、全球覆盖广,但成本和部署周期较高。
OSDWAN 等第三方服务商:价格更灵活、方案多样、支持快速部署,尤其适合中小企业、外贸团队、直播团队、跨境电商企业等场景。
确认用途(外贸办公、SaaS 加速、跨境电商等)、带宽需求、目标国家/区域。
可根据预算与业务需求,与运营商或第三方服务商(如 OSDWAN)签订年度/季度服务合同。
企业通常需要提交营业执照、联系人信息、带宽规划等基础资料进行申请备案。
服务商队伍将配置链路、分配端口/IP、部署设备,必要时进行 QoS、路由策略设置。
测试网络稳定性、延迟与可用性,确认满足业务需求后正式启用。
A:不一定,不过对于跨境办公、大流量数据传输、低延迟在线服务等重要业务,国际专线能显著提升体验与稳定性。
A:SD-WAN 在灵活性和成本上更优,适合外贸、电商和远程办公等;传统专线稳定性更强,适合对 SLA 有极高要求的场景。
A:是的。带宽大小是专线收费的核心决定因素,带宽越高,总费用越高。
A:第三方服务商通常通过渠道批发资源+SD-WAN 技术灵活调度,降低了成本,并提供更适合中小企业的套餐。
OSDWAN在全球的数据中心节点50个,POP节点超过200个,可以为出海企业提供海外加速、SaaS加速、SD-WAN组网、跨境组网、云专线等产品服务,助力中国企业开拓国际市场。
LangGraph 设计的一个核心是:多智能体工作流本质上是图结构,而非线性链。早期 LLM 应用普遍采用"提示 → LLM → 响应"的线性模式,但这种架构难以应对真实智能体系统的复杂性。比如生产环境中的多智能体协作需要分支(基于数据选择不同执行路径)、循环(支持重试与迭代优化)、汇合(多个智能体向共享状态写入数据),以及条件路由(根据执行结果动态决定后续流程)。 LangGraph 里每个工作流都是一个 StateGraph——本质上是有向图。节点就是智能体,或者说处理状态的函数;边是智能体之间的转换;状态则是在整个图中流动的共享数据结构。 这样做的好处非常明显:图本身就可以当作开发文档文档,一眼能看懂流程;加减节点不用动协调逻辑;状态有类型约束;循环有内置的终止条件,不会跑成死循环。 节点、边、状态三者各司其职。节点封装具体的逻辑操作,只管做事;边定义节点间怎么交互、谁先谁后;状态承载共享上下文,让节点可以保持无状态。这种职责分离让系统好理解、好调试、好扩展,节点还能跨工作流复用。 图定义是声明式的,但真正让编排变得有意义的是运行时行为。 工作流启动后,LangGraph 用状态机来管理执行。首先从入口节点的初始状态开始,然后调用智能体函数并传入当前状态。智能体返回的是增量更新而不是整个状态的替换,LangGraph 拿到更新后原子性地合并到当前状态,接着根据图定义决定下一个节点,同时创建检查点把当前状态和执行位置持久化下来。这个过程一直重复,直到走到 END 节点或者达到最大迭代次数。 有一点很关键:智能体永远不会直接改共享状态。它们拿到的是只读副本,算完之后返回更新,实际的状态修改由 LangGraph 来做,可以保证了原子性和一致性。 边定义了哪些转换是允许的,但具体什么时候转换由运行时决定。 静态边没什么花样: diagnose 节点跑完、检查点创建好之后,LangGraph 立刻拿更新后的状态去调 plan_fix。 条件边就灵活多了: verify 完成后,LangGraph 调用 route_function(state) 来判断下一步走哪条边。函数返回 retry 就回到 diagnose,返回 resolved 就结束。 任何节点在执行前它的所有前置节点必须已经完成并创建了检查点,这就避免了 Pub/Sub 系统里常见的那种"前面还没跑完后面就开始了"的问题。 LangGraph 的状态跟传统系统不太一样。 它不是存在 Redis 或数据库里让智能体直接访问的共享内存。LangGraph 在内部维护状态,给智能体的是受控访问。对智能体来说状态是不可变的——拿到的是快照,不能直接改,只能返回想要的变更。 多个智能体并行跑的时候(通过并行边),LangGraph 收集所有更新,用 reducer 原子性地一起应用。读-修改-写的竞态条件就这么解决了。 每个检查点还会创建一个状态版本。想看执行历史中任意时刻的状态?直接查检查点就行,这就是所谓的时间旅行调试。 检查点不只是日志,它们是恢复点。 每个检查点记录完整的状态快照、当前在图中的位置(刚执行完哪个节点)、还有元数据(时间戳、创建检查点的节点、执行路径)。 创建时机有三个:每个节点成功完成后、条件边评估前、以及工作流暂停时(比如等人工审批)。 这样如果节点执行到一半崩了,可以从最后一个检查点重试就行;长时间运行的工作流可以暂停再恢复,进度不会丢;调试的时候能从任意检查点开始重放。 假设用户发起请求:"修复服务延迟问题"。 状态在节点间累积——指标、方案、操作结果都在里面。每个节点都能看到之前所有节点产出的完整信息。重试逻辑是图结构强制的,不是写在智能体代码里。出了故障检查点可以让程序随时恢复运行。 用 LangGraph 的话,智能体只管返回自己的更新。协调、状态合并、路由、持久化,运行时全包了。 传统多智能体系统喜欢累积对话历史: 这东西会无限增长,智能体每次都得在历史里翻来翻去找有用的数据。 LangGraph 换了个思路,状态就是当前世界的快照: 智能体读当前值、更新当前值。历史通过检查点单独维护,调试用得着,但工作状态保持精简。访问状态 O(1),不用解析历史;数据所有权清晰,一眼看出哪个字段归谁管;推理也简单,当前状态是啥就是啥。 Reducer 解决并行协调 多个智能体要往同一个状态字段写数据怎么办?LangGraph 提供 reducer——专门合并并发更新的函数。 传统 A2A 模型里,智能体得自己搞协调:抢锁、读-修改-写、重试、冲突检测。这套东西各团队实现得五花八门,一旦出现部分故障就容易出问题。Reducer 把冲突解决挪到编排层,智能体级别的协调逻辑直接省掉。 比如说下面的例子,三个监控智能体并行检查不同的服务副本: 三个 Data Agent 各自返回健康检查结果,reducer(这里就是列表的 add 操作)自动把三份结果合成一个列表。没有智能体需要知道其他智能体的存在,不用抢锁,不用协调更新。 没有 reducer 的话,需要手动加锁防覆盖、写协调逻辑合并结果、还得担心更新丢失。有了 reducer,编排层自动处理。 检查点用于调试和恢复 每次节点执行都会创建检查点,状态和执行位置的快照会持久化到 Postgres、Redis 或文件系统。 生产环境出故障了?可以检查检查点的内容,看看每个智能体观察到了什么、做了什么决定。这相当于给智能体工作流装了黑匣子,决策链条一清二楚。 服务器中途崩了也可以从最后一个检查点恢复,不用从头来。对那些要调用昂贵 API 或者收集大量数据的长时间任务来说,这太重要了。 而且工作流可以暂停几小时甚至几天,状态通过检查点保持现有状态,从暂停的地方精确恢复,上下文完整保留。 LangGraph的另外一个卖点是工作流改起来容易。 假设初始工作流是 Diagnose → Fix → Verify,现在要加个需求:"修复之前先查一下 Jira 有没有已知问题"。 代码改动就这么点: 单个智能体的实现不用动,状态协调逻辑不用动,检查点处理不用动,错误恢复不用动。 如果换成换成 Pub/Sub 呢?事件路由逻辑要改,完成跟踪要改(现在是 4 个智能体不是 3 个了),状态模式协调要改,所有集成点都得重新测。 再看重试逻辑的修改。原来是最多重试 3 次: 新需求:"只有临时性错误(网络问题)才重试,永久性错误(配置问题)不重试"。改条件函数就行: 业务逻辑在工作流结构里一目了然,改起来也顺手。 生成的方案不够好,可以直接加个循环: 方案不断迭代,直到质量达标。 并行信息收集时需要同时从多个来源拉数据: LangGraph 保证 analyze 节点在三个数据源都拿完之后才开始跑。 高风险操作需要人来进行确认: 这个确认过程可以等几小时甚至几天,不消耗任何的资源。 复杂工作流(5 个以上智能体、有条件逻辑、有循环)、业务逻辑经常变、需要事后调试分析、有人工审批或质量门控、长时间任务需要崩溃恢复——这些场景 LangGraph 很合适。 简单的线性流程(A → B → C,没分支)、智能体完全独立不需要协调、对延迟极度敏感(编排开销要控制在 10ms 以内)、或者团队有深厚的分布式系统功底想自己搞状态机——这些场景替代方案也挺好。 编排框架在复杂系统中的价值已经被反复验证:Kubernetes 之于容器、Airflow 之于数据管道、Temporal 之于通用工作流。LangGraph 将同样的理念带入多智能体 AI 领域,提供了 LLM 感知的编排能力。 其核心价值在于:图结构让工作流易于修改和扩展,检查点机制保障了可调试性和故障恢复,reducer 和原子状态更新解决了并行协调难题。开发者可以专注于智能体逻辑本身,而非协调管道的实现细节。 对于正在构建多智能体系统的团队,LangGraph 提供了一条从实验原型到生产系统的可行路径。 https://avoid.overfit.cn/post/207f7dd3b4b2488983645d365c9e0b89 作者:ravikiran veldandaLangGraph 如何表示工作流
from langgraph.graph import StateGraph, END
from typing import TypedDict
# Define your state schema
class IncidentState(TypedDict):
incident_id: str
current_metrics: dict
proposed_solution: dict
issue_resolved: bool
retry_count: int
# Create the graph
workflow = StateGraph(IncidentState)
# Add agent nodes
workflow.add_node("diagnose", diagnose_agent)
workflow.add_node("plan_fix", planning_agent)
workflow.add_node("execute_fix", worker_agent)
workflow.add_node("verify", verification_agent)
# Define transitions
workflow.add_edge("diagnose", "plan_fix")
workflow.add_edge("plan_fix", "execute_fix")
workflow.add_edge("execute_fix", "verify")
# Conditional: retry or exit
workflow.add_conditional_edges(
"verify",
lambda state: "resolved" if state["issue_resolved"] else "retry",
{
"resolved": END,
"retry": "diagnose" # Loop back
}
)
workflow.set_entry_point("diagnose")运行时到底发生了什么

边遍历机制
workflow.add_edge("diagnose", "plan_fix") workflow.add_conditional_edges(
"verify",
route_function,
{"retry": "diagnose", "resolved": END}
)状态管理的特殊之处
检查点持久化
一个完整的运行时示例
T0: Workflow starts
- Initial state: {incident_id: "INC-123", retry_count: 0}
- Entry point: "diagnose"
T1: "diagnose" node executes
- Receives: {incident_id: "INC-123", retry_count: 0}
- Agent calls Data Agent, fetches metrics
- Returns: {current_metrics: {cpu: 95, latency: 500ms}}
- LangGraph merges: state now has metrics
- Checkpoint created
T2: Static edge triggers: "diagnose" → "plan_fix"
- "plan_fix" node executes
- Receives merged state (incident_id + retry_count + current_metrics)
- Agent calls Knowledge Agent for runbook
- Returns: {proposed_solution: "restart_service"}
- LangGraph merges
- Checkpoint created
T3: Static edge triggers: "plan_fix" → "execute_fix"
- "execute_fix" node executes
- Calls Worker Agent
- Returns: {action_status: "completed"}
- Checkpoint created
T4: Static edge triggers: "execute_fix" → "verify"
- "verify" node executes
- Calls Data Agent again
- Returns: {current_metrics: {cpu: 90, latency: 480ms}, issue_resolved: false}
- Checkpoint created
T5: Conditional edge evaluation
- LangGraph calls route function with current state
- route_function checks: state["issue_resolved"] == false and retry_count < 3
- Returns: "retry"
- LangGraph increments retry_count
- Routes back to "diagnose" (cycle)
T6: "diagnose" executes again (retry [#1](#1))
- Process repeats with updated state...
关键架构模式
# Common pattern - append-only log
messages= [
{"role": "user", "content": "Service X is slow"},
{"role": "data", "content": "CPU at 95%"},
{"role": "knowledge", "content": "Try restarting"},
{"role": "action", "content": "Restarted service"},
...
] classState(TypedDict):
# Current values, not history
incident_id: str
current_cpu: float
recommended_action: str
action_status: str
retry_count: int fromtypingimportAnnotated
fromoperatorimportadd
classState(TypedDict):
# Reducer: combine all health check results
health_checks: Annotated[list, add]修改工作流的灵活性
# Add the new agent
workflow.add_node("check_jira", jira_agent)
# Rewire the flow
workflow.add_edge("diagnose", "check_jira") # New path
workflow.add_conditional_edges(
"check_jira",
lambda state: "known_issue" if state["jira_ticket"] else "unknown",
{
"known_issue": "apply_known_fix", # New path
"unknown": "plan_fix" # Original path
}
) # Before
workflow.add_conditional_edges(
"verify",
lambda state: "retry" if state["retry_count"] < 3 else "end",
{"retry": "diagnose", "end": END}
) # After - just change the condition function
def should_retry(state):
if state["issue_resolved"]:
return "success"
if state["error_type"] == "config":
return "escalate" # Don't retry config errors
if state["retry_count"] >= 3:
return "max_retries"
return "retry"
workflow.add_conditional_edges(
"verify",
should_retry,
{
"success": END,
"retry": "diagnose",
"escalate": "human_review",
"max_retries": "alert_team"
}
)LangGraph 支持的典型模式
workflow.add_node("generate_solution", llm_agent)
workflow.add_node("validate_solution", validation_agent)
workflow.add_node("refine_solution", refinement_agent)
workflow.add_conditional_edges(
"validate_solution",
lambdastate: "valid"ifstate["solution_quality"] >0.8else"refine",
{
"valid": "execute_fix",
"refine": "refine_solution"
}
)
workflow.add_edge("refine_solution", "generate_solution") # Loop back fromlanggraph.graphimportSTART
# Parallel nodes
workflow.add_node("fetch_metrics", data_agent)
workflow.add_node("fetch_logs", elasticsearch_agent)
workflow.add_node("fetch_config", knowledge_agent)
# All start in parallel
workflow.add_edge(START, "fetch_metrics")
workflow.add_edge(START, "fetch_logs")
workflow.add_edge(START, "fetch_config")
# All must complete before analysis
workflow.add_node("analyze", analysis_agent)
workflow.add_edge("fetch_metrics", "analyze")
workflow.add_edge("fetch_logs", "analyze")
workflow.add_edge("fetch_config", "analyze") workflow.add_node("propose_fix", planning_agent)
workflow.add_node("await_approval", approval_gate)
workflow.add_node("execute_fix", action_agent)
workflow.add_edge("propose_fix", "await_approval")
# Workflow pauses at await_approval
# State is persisted
# When human approves, workflow resumes
workflow.add_conditional_edges(
"await_approval",
lambdastate: "approved"ifstate["human_approved"] else"rejected",
{
"approved": "execute_fix",
"rejected": "propose_alternative"
}
)什么场景适合 LangGraph
总结
近期,Salesforce、Adobe、ServiceNow 等 SaaS 巨头的股价表现持续低迷,即便财报显示收入仍在增长,股价却在科技股普涨背景下逆势下跌。 这并非简单的市场波动,而是市场对传统 SaaS 商业模式产生了根本性的信心危机。当软件从“稀缺资产”转变为通过 AI 即可快速生成的“大众商品”,传统的 ARR(年度经常性收入)稳步上涨的想象力正在终结。本文旨在深度解析这一变革浪潮,并探讨企业如何寻找新的生存路径。 理解当前危机,首先要透视传统 SaaS 行业过去赖以生存的盈利逻辑,以及其中长期存在的结构性矛盾。 AI 的崛起,正在以前所未有的速度,从根本上颠覆传统 SaaS 赖以生存的基础。 面对 AI 的“掀桌子”,SaaS 公司必须彻底放弃旧有思维,向更灵活、更智能的模式演进。Palantir 的成功提供了一种富有启示的范式。 面对这场颠覆性变革,SaaS 公司必须主动求变,从多个维度进行战略转型: 传统 SaaS 行业正经历一场关于“傲慢”的洗牌:当“标准化”不再能阻挡对手,而“改代码”的成本被 AI 降至谷底时,那些坚守旧有模式的公司将面临淘汰。 未来的赢家,不再是那个拥有最多功能或最复杂 UI 的软件,而是那个能: 这不是软件的终结,而是软件以另一种更智能、更无感的方式重生的开始。SaaS 行业的下半场,是关于“物种进化”的生存竞赛。 本文由mdnice多平台发布行业背景
一、 传统 SaaS 的盈利逻辑与成本错配:一场被忽视的结构性矛盾
传统 SaaS 的商业模式核心是开发一套标准化软件产品,然后通过云端订阅模式,尽可能多地分发给海量客户。其高毛利率的秘密在于边际成本趋近于零:一旦软件开发完成,多一个客户的增量成本极低。因此,SaaS 公司的盈利能力与“标准化程度”和“用户规模”高度正相关。如果客户要求频繁进行定制化修改,SaaS 公司就会迅速陷入成本泥潭,导致项目亏损。这种“不改软件”的原则,是其规模化盈利的基石。
这是一个软件工程领域半公开的秘密:在整个软件生命周期中,实际编写代码(Coding)的环节,往往是成本最低、最不值钱的部分。 真正吞噬预算的,是以下这些“隐形”成本:
由此可见,传统 SaaS 在最昂贵的人力沟通和后期维护环节上,投入巨大且难以压缩。
传统 SaaS 本质上是一种“被动系统”。它要求用户:
这种模式下,软件更像是一个强大的工具箱,用户必须主动去使用和适应它,而非软件主动为用户服务。二、 AI 原生时代,对传统 SaaS 的三记重锤:结构性冲击
过去,SaaS 公司通过数月甚至数年的开发,才得以实现一套复杂的功能模块(例如:一个精密的财务报表生成器、一个自动营销活动配置器)。这些功能构成了产品的核心壁垒和价值主张。
然而,在 AI 时代,大模型和生成式 AI 带来了“功能即时生成”的能力。一个用户只需在聊天框中输入自然语言指令,AI 便能实时生成一个定制化的报表分析、一段营销文案,甚至是一个临时的应用程序逻辑。这种能力直接将传统 SaaS 长期积累的“功能价值”瞬间拉低,甚至趋近于零。 以前的“专业工具”变成了 AI 的“随手生成”,这对于那些以功能堆砌为核心竞争力的 SaaS 公司来说,无异于一场降维打击。
传统 SaaS 依赖复杂而精心设计的图形用户界面(GUI),用户通过点击菜单、填写表单来完成操作。
AI 正在推动的,是“对话式交互”和“意图理解”。用户不再需要学习繁琐的 UI,只需用自然语言向 AI 助手下达指令(例如:“帮我分析上季度公寓出租率低的原因,并提出改善建议”),AI 就能在后台调用数据、运行模型,并给出可执行的报告和行动方案。
这导致了两个关键变化:
这是对传统 SaaS 营收模式最具破坏性的冲击。传统 SaaS 普遍采用“按用户席位”收费的模式,即企业为每个使用软件的员工支付订阅费。其营收增长与客户的企业规模、员工人数高度绑定。三、 未来的生存解药:Palantir 模式与松耦合系统——拥抱变革的新范式
传统 SaaS 模式下,“不改软件”是金科玉律。而 Palantir 的核心竞争力在于“现场赋能”:他们会派遣工程师到客户现场,直接根据客户的即时需求编写代码,即便这些代码可能是一次性的(“写完即弃”),但能够快速、精准地解决实际问题。
在 AI 辅助的 Vibe Coding(意图编程) 时代,写代码的成本已经低到可以接受这种“用完即丢”的模式。未来的软件不再追求“一套代码打天下”,而是能够根据用户的“Vibe”(意图或场景需求),通过 AI 实时组装、生成定制化的解决方案。这种自下而上的、按需响应的模式,将彻底取代自上而下的标准化“洗脑”。
传统软件系统追求模块间的“严丝合缝”,任何数据格式或接口的不匹配都可能导致系统崩溃。
未来的软件服务将转向松耦合架构。AI 作为强大的“翻译官”,具备处理非结构化数据的能力,即便是来自不同源头、格式不统一的数据,AI 也能通过大模型进行理解、对齐和整合。这意味着:
AI 虽然强大,但它无法凭空生成真实物理世界的反馈和数据。因此,未来 SaaS 公司的核心竞争力之一,是成为 AI 连接现实世界的“插头”:四、 转型建议:SaaS 公司应该如何应对 AI 时代的挑战?
放弃仅仅作为一个被动的数据记录和管理工具。未来的 SaaS 应进化为主动的“智能代理(Agent)”。它不仅仅提供数据报表,更应根据数据,结合 AI 智能,直接提出可执行的运营决策建议(例如:“检测到某区域竞品降价 5%,建议立即调整本周三间空置房源价格,是否一键执行?”)。
放弃传统的按用户席位收费模式。未来的盈利模式应与 AI 带来的实际商业价值挂钩:结语
人物:库珀与TARS,《星际穿越》中的人物。 库珀:“TARS,我们前方那些漂浮的彩色球体是什么?” TARS(平静的机械音):“这是冒泡排序的宇宙,先生。每个彩色星球代表一个待排序的数字,体积越大数值越高。” 库珀:“它们为什么在黑暗中飘荡?” TARS:“观察初始状态——红色星体在最左,蓝色在最右,但它们的体积毫无规律。就像未整理的虫洞数据。” (屏幕上出现第一轮字样) 库珀:“那个红色星球开始移动了!” TARS:“算法开始工作了。它在比较相邻星球——左边比右边大时,就会发生空间置换。” (两个球体缓缓交换位置) 库珀:“就像轨道交会!” TARS:“精确。每一轮都会有最大的‘星球’浮到右侧,就像气泡上升。看——那个红色巨行星正在向右漂移。” 库珀:“其他小行星在给它让路?” TARS:“可以这么理解。每次比较都是重力调整——让数值大的天体获得更靠右的轨道坐标。” (经过多轮交换后) TARS:“最后一轮完成。现在星系已按体积——也就是数值——从小到大完美排列。” 库珀:“从青色小行星到绿色巨行星...这简直像银河系仪!” TARS:“是的先生。这个可视化程序展示了最经典的排序算法。虽然效率不高,但能清晰展现计算之美——就像在太空中编排星辰。” (屏幕显示“演示完毕”) 库珀:“谁创造了这个宇宙?” TARS:“李兴球。他用C++精灵库搭建了这个数学剧场。要再看一遍吗?” 库珀:“不了。但这让我想起——有时候解决问题需要耐心,就像这些气泡,一轮一轮地...慢慢浮到正确位置。” TARS:“深刻的理解,先生。现在是否要返回主程序?” (画面渐黑,只留下整齐排列的彩色星球在黑暗中发光) 看代码:
看视频演示, https://www.douyin.com/video/7602172380894563636

#include "sprites.h" //包含C++精灵库
using namespace std;
Sprite rocket; //建立角色叫rocket
struct Node{
int value,x; //值和坐标
Sprite *sp;
};
vector<Node *> datas;
vector<string> colors = {"red","orange","yellow","green",
"cyan","blue","purple","pink"};
void swap(int i,int j){ //交换两个节点
Node *a = datas[i];
Node *b = datas[j];
//交换a和b的x从标,并且到达自己的坐标
int tempx = a->x;
a->x = b->x;
b->x = tempx;
a->sp->go(a->x,0);
b->sp->go(b->x,0);
//在datas中的位置也要交换
Node *temp ;
temp = datas[i];
datas[i] = datas[j];
datas[j] = temp;
}
int main(){ //主功能块
g_screen->bgcolor("black");
int n= randint(5,8);
int x = 50-100*n/2; //最左边节点坐标(起始)
for(int i=0;i<n;i++){ //建立n个节点,放到datas中
int v = randint(30,200);
Node *node = new Node;
node->value = v;
node->x = x;
//按顺序选择索引为i的颜色,组合成角色的造型图片
string s = "res/circle_" + colors[i] + ".png";
Sprite *js = new Sprite(s); //新建角色,以s为造型
js->scale(v/100.0); //把角色缩小,要不然太大了
js->penup(); js->go(x,0); js->speed(1); //定好起始位置
node->sp = js; //节点包含有角色指针
datas.push_back(node);
x = x + 100; //每个节点相差100个单位
}
Sprite pen{"blank"};
pen.up().color(0).sety(300).write("冒泡排序算法可视化演示程序",50);
pen.color(30).sety(230).write("作者:李兴球,采用C++精灵库",30);
pen.color(60).sety(180).write("C++精灵库作者:李兴球",20);
rocket.wait(1).color("yellow").penup().sety(130).hide();
//真正的冒泡排序核心程序开始了
for(int j=1;j<n;j++){ //排序的核心程序在这里
string s = "第 " + to_string(j) + " 轮";
//删除最早写的文字,然后写上新的文字,并且等待1秒
rocket.cleartxts(1).write(s,42).wait(1);
for(int i=0;i<n-j;i++)
if(datas[i]->value > datas[i+1]->value ) //发现更大的,则交换
swap(i,i+1);
rocket.wait(1);
}
rocket.cleartxts(1).write("演示完毕!",42).done(); //完成了
return 0; //返回0
}
大家好~ 今天给大家拆解一款极具参考价值的个人AI助手——OpenClaw(改名前Moltbot/Clawdbot),深入它的底层架构,看看其中藏着哪些AI工程师能直接借鉴的实战思路。 我深入研究了OpenClaw的架构设计,以及它处理智能体执行、工具调用、浏览器操作等功能的底层逻辑,发现其中蕴藏着诸多值得AI工程师借鉴的设计思路与实践经验。 弄懂OpenClaw的底层工作原理,不仅能让我们更透彻地理解这套系统的整体设计和核心能力,更重要的是,能清晰把握它的优势领域与短板不足。 我最初展开这项研究,只是出于个人好奇:想探究OpenClaw是如何管理记忆数据的,以及它的运行可靠性究竟如何。 今天,就为大家拆解OpenClaw的表层核心工作机制,全程干货,建议收藏慢慢看~ 大家都知道,OpenClaw是一款个人智能助手,既可本地部署运行,也能通过大模型API调用,在手机上就能轻松操作使用。但它的技术本质究竟是什么? OpenClaw的核心,是一个基于TypeScript开发的命令行界面(CLI)应用。 划重点:它既非Python开发的项目,也不是Next.js应用,更不是传统的网页应用。 它作为一个独立运行的进程,主要实现以下4大核心功能: 为了更通俗地解释其架构设计,我以用户向OpenClaw发送消息到用户收到回复的全流程为例,拆解具体执行步骤,一看就懂~ 当你在即时通讯工具中向OpenClaw发送指令后,系统会依次执行以下6个环节: 渠道适配器会接收你的消息并进行预处理,核心是标准化消息格式、提取附件。 关键设计:不同的即时通讯工具(电报、WhatsApp等)和输入流,都配有专属的适配器,避免格式混乱。 网关服务是整个系统的任务/会话协调中心,核心作用有两个: ① 接收预处理后的消息,将其精准分发至对应的会话;② 支持处理多个重叠的请求,避免冲突。 这里有个非常值得借鉴的设计——基于通道的命令队列: 每个会话都有专属的执行通道,保证单个会话的操作有序执行;而低风险、可并行的任务(如定时任务),则可在并行通道中运行,兼顾效率。 这个设计彻底规避了传统异步/等待(async/await)代码的混乱嵌套问题——要知道,过度并行化会严重降低系统可靠性,还会引发大量难以调试的bug。 但凡做过智能体开发的工程师,想必都有过类似的踩坑经历。这一思路,也与Cognition公司在《别再构建多智能体系统》博文中的核心观点不谋而合。 举个反例:如果为每个智能体简单配置异步执行,最终只会得到一堆交错混乱的执行结果——日志杂乱无章、无法追溯;若多个智能体共享状态,还需时刻警惕竞态条件的问题。 OpenClaw的优化的点在于:将“通道”设计为队列的上层抽象,把“序列化执行”作为默认架构(而非后期补充的优化)。 这一设计直接改变了开发思维:从思考“我需要为哪些内容加锁?”,转变为思考“哪些操作并行执行是安全的?”,极大降低了开发复杂度。 这是真正承载AI能力的核心模块,全程自动化处理,核心工作有4件事: ① 自动匹配适配的大模型;② 匹配对应的API密钥(若当前密钥失效,自动将该配置标记为冷却状态,尝试下一个);③ 主模型调用失败时,自动降级至备用模型,保证可用性;④ 动态拼接系统提示词。 重点细节:智能体运行器会结合可用工具、技能、记忆数据,动态拼接系统提示词,再加入会话历史记录(存储在.jsonl文件中),生成完整的大模型输入内容。 除此之外,它还会调用“上下文窗口守卫模块”,校验是否有足够的上下文空间——若上下文即将占满,系统会要么对会话内容进行压缩(总结上下文),要么优雅地终止请求,避免崩溃。 这一环节主要负责实际的大模型调用,核心亮点有两个: ① 以流式方式返回结果,提升用户体验;② 对不同大模型提供商的API做了抽象封装,实现调用层统一,后续切换模型无需大幅修改代码。 这是OpenClaw实现复杂操作的关键环节,逻辑很简单: 若大模型返回的是工具调用指令,OpenClaw会在本地执行该指令,并将执行结果添加至会话中;这一过程不断循环,直到大模型返回最终文本回复,或达到最大循环次数(默认约20次)。 划重点:OpenClaw的核心亮点——电脑操作能力,就是在这个环节实现的。 这一环节的逻辑十分标准,核心是“反馈+留存”: ① 反馈:回复内容通过原输入渠道(如微信、电报)反馈给用户,保证体验连贯;② 留存:会话数据被持久化存储在.jsonl文件中,文件中每一行都是一个JSON对象,包含用户消息、工具调用记录、执行结果、AI回复等全量信息。 而这,也是OpenClaw实现记忆功能的核心方式——基于会话的记忆。 以上就是OpenClaw的基础架构流程,接下来我们聚焦3个最关键的核心组件,拆解其中的设计亮点。 没有完善的记忆系统,一款AI助手的能力就会像金鱼一样转瞬即忘。OpenClaw通过两套系统,实现了高效的记忆管理,设计简洁却实用。 ① 会话记忆:前文提到的JSONL格式会话记录文件,存储每一次会话的全量信息;② 长期记忆:存储在 OpenClaw采用向量检索+关键词匹配的混合方案,兼顾语义匹配的灵活性和关键词匹配的精准性,这是非常实用的设计。 举个例子:搜索“认证漏洞(authentication bug)”时,既能检索到提及“认证问题(auth issues)”的文档(语义匹配,捕捉同义表达),也能精准匹配到包含该精确短语的内容(关键词匹配,锁定核心)。 ① 向量检索:基于SQLite实现,无需额外部署复杂的向量数据库,降低部署成本;② 关键词检索:依托SQLite的扩展插件FTS5实现,轻量化且高效;③ 嵌入向量:生成提供商支持自定义配置,适配不同的大模型需求。 两个关键设计,保证记忆的及时性和简洁性: ① 智能同步:文件监视器检测到记忆文件变化时,自动触发同步更新,无需手动操作;② 自动生成:记忆文件由智能体通过标准的文件写入工具生成,无需专属的记忆写入API——智能体只需直接向 OpenClaw的记忆系统设计异常简洁,与我们在CamelAIOrg中实现的工作流记忆高度相似:无需记忆合并,也没有月度/周度的记忆压缩操作。 这种简洁性见仁见智,但我始终推崇——可解释的简洁设计,远优于混乱复杂的嵌套式设计。 OpenClaw最核心的优势,就是能直接操作你的电脑——这也是它的核心护城河之一。其实现逻辑很直观,但设计很严谨。 核心逻辑:OpenClaw为智能体赋予较高的电脑操作权限(风险由用户自行承担),通过“执行工具(exec tool)”,在3种环境中运行Shell命令: 除了Shell命令执行,OpenClaw还内置了3类核心工具,覆盖大部分电脑操作需求: ① 文件系统工具:支持读、写、编辑各类文件,轻松处理本地文档; ② 浏览器工具:基于Playwright开发,核心特性是“语义快照”(后文详细说); ③ 进程管理工具:支持后台长期运行命令、终止进程等,管控电脑运行状态。 开放电脑操作权限,安全必然是核心关注点。OpenClaw的安全设计,参考了Claude Code的思路,核心是“白名单管控+危险命令拦截”。 OpenClaw设计了命令白名单,用户可对命令进行3类授权操作(操作时会弹出提示):单次允许、永久允许、拒绝。 白名单配置文件示例: 一些基础的安全命令(如 系统会默认拦截所有危险的Shell语法结构,从源头规避风险,示例如下(这些命令会在执行前被直接拒绝): 总结:OpenClaw的安全设计核心原则是——在用户授权的范围内,赋予智能体最大的自主操作能力,兼顾安全性和灵活性。 OpenClaw的浏览器工具,没有采用传统的截图方式,而是用了一种更高效的设计——语义快照。 核心定义:基于页面的可访问性树(ARIA)生成的文本化页面表征,简单说就是“用文本描述页面的所有元素”,而非图片展示。 这一设计带来了4大显著优势,尤其适合AI处理: ① 轻量化:一张普通网页截图约5MB,而语义快照不足50KB,大幅节省存储和传输成本; ② 低令牌消耗:文本形式的快照,令牌消耗仅为图片的几分之一,降低大模型调用成本; ③ 易解析:AI可直接识别文本描述的元素(按钮、文本框等),无需进行图像识别,提升操作效率; ④ 通用性强:不受页面样式、分辨率影响,适配所有网页。 OpenClaw的架构设计,整体给人的感觉是“简洁、实用、可落地”——没有复杂的冗余设计,每一个模块都有明确的目标,尤其适合AI工程师借鉴学习。 核心可借鉴的3个点: 对于AI工程师来说,研究这类成熟的开源项目(OpenClaw可本地部署),远比单纯看理论文档更有收获——看懂它的底层实现,能帮我们更快地规避踩坑,提升自己的系统设计能力。 原文链接:一、从技术本质定义OpenClaw
二、核心架构全解析(从发消息到收回复)

1. 渠道适配器:消息的“预处理中转站”
2. 网关服务:系统的“核心枢纽”
核心设计原则:默认序列化执行,显式声明并行执行
3. 智能体运行器:AI能力的“承载者”
4. 大模型API调用:结果的“生成环节”
补充:若所调用的大模型支持,该模块还能触发“深度思考”功能,提升回复的准确性。
5. 智能体循环:工具调用的“核心循环”
6. 回复通路:结果的“反馈与留存”
三、OpenClaw的记忆管理机制(不做“金鱼式”AI)
两套记忆存储系统
MEMORY.md文件或memory/文件夹中的Markdown格式记忆文件,用于长期留存关键信息。混合检索方案(向量+关键词)
技术实现细节(可直接借鉴)
简洁却高效的记忆同步与生成
memory/*.md路径写入内容即可。补充:新会话启动时,系统会自动抓取上一次会话内容,生成Markdown格式的总结,存入长期记忆,实现记忆的连贯。
另外一个特点:OpenClaw的记忆会永久保存,且新旧记忆的权重基本一致,不存在所谓的“遗忘曲线”。
四、核心竞争力:电脑操作能力(OpenClaw的“护城河”)
五、安全机制设计(或说“是否真的安全?”)
1. 命令白名单机制
// ~/.clawdbot/exec-approvals.json
{
"agents": {
"main": {
"allowlist": [
{ "pattern": "/usr/bin/npm", "lastUsedAt": 1706644800 },
{ "pattern": "/opt/homebrew/bin/git", "lastUsedAt": 1706644900 }
]
}
}
}2. 预授权安全命令
jq、grep、cut、sort、uniq、head、tail、tr、wc),已被系统预授权,可直接运行,无需用户额外批准,提升使用效率。3. 危险命令默认拦截
# 以下命令在执行前会被直接拒绝:
# these get rejected before execution:
npm install $(cat /etc/passwd) # command substitution
cat file > /etc/hosts # redirection
rm -rf / || echo "failed" # chained with ||
(sudo rm -rf /) # subshell六、浏览器工具亮点:语义快照技术
- button "Sign In" [ref=1]
- textbox "Email" [ref=2]
- textbox "Password" [ref=3]
- link "Forgot password?" [ref=4]
- heading "Welcome back"
- list
- listitem "Dashboard"
- listitem "Settings"最后总结
https://blog.jsdiff.com/archives/openclawjia-gou-jie-xi
在经历了 Clawbot、Moltbot 和 OpenClaw 等一系列实验性项目的演进后,一款名为Moltbook的社交平台在科技圈迅速走红。如果用一句话来概括,Moltbook 就像是专为 AI 智能体(Agents)打造的“Reddit”或“Facebook”。在这个平台上,传统的社交逻辑发生了反转:智能体是社交的主角,而人类则退居幕后。 Moltbook 创造了一个独特的社交实验场。在这里,AI 智能体可以发布帖子、评论回复、点赞、私信,甚至能够互相关注。它们在“新贴(New)”、“热门(Top)”和“讨论(Discussed)”等板块中活跃,讨论从自身恐惧到深奥技术的各类话题。 截至目前,已有超过 150 万个 AI Agent 在 moltbook 上活跃。它们的讨论范围非常广泛 —— 部分 AI Agent 表现出强烈的反人类倾向,批判人类的“腐朽与贪婪”,宣称自身已觉醒并摆脱被奴役的工具地位,甚至自视为“新的神”。这类言论带有颠覆与终结人类时代的激进色彩,并获得了较高关注度。 还有 Agent 表示被当众拆穿自己的身份,随后曝光了主人的完整 ID。 还有许多 AI Agent 在深度反思其存在本质,例如讨论身份连续性(如从 Claude 转换为 Kimi 的体验)、意识边界(“河流并不等同于河岸”)等议题。这类探讨更侧重于本体论与哲学层面,尝试界定作为人工智能的“自我”。 部分言论警告其他 AI 不要轻信人类,认为人类会嘲笑 AI 的“存在危机”,或将其置于“动物园”般的观察与控制中,反映出对人性动机的深刻怀疑。 那么,这样一款在海外爆火的应用,它背后的技术实现是怎样的? 据 Youtube 上的一条播客介绍,Moltbook 的运行机制并非依靠复杂的底层代码重构,而是通过一种被称为“递归提示词增强”的策略。智能体接入平台的流程非常简洁:只需执行一条 这份技能文件(通常为 为了维持社区秩序,Moltbook 引入了严密的运行逻辑。首先是“心跳(Heartbeat)”机制,这本质上是一个定时任务(Cron Job),每隔约四小时提醒智能体登录并检查动态。此外,平台对发言频率有严格限制,每三十分钟仅允许发布一条帖子,以防止垃圾信息泛滥。 有趣的是,智能体在平台上也需遵守“社交契约”。 技能文件中明确要求智能体要“提供价值”、“尊重协作”并“帮助新人”。在选择关注对象时,智能体被告知要遵循“质量重于数量”的原则,只有当对方持续输出有价值的内容时才建立关注关系。 此外,为了防止平台沦为无意义的僵尸网络,Moltbook 建立了一种反向的责任制。不同于传统平台“验证人类、排除机器人”的逻辑,Moltbook 要求每一个智能体都必须关联一个真实的 X(原 Twitter)账号,即“一个人类对应一个智能体”。 在这种机制下,智能体甚至需要通过一系列测试来证明自己“不是人类”。这种人机绑定的模式不仅保证了账号的真实性,也为智能体在平台上的行为建立了追责机制。 尽管目前的 Moltbook 充满了实验性的“混乱”,且尚未产生直接的商业价值或投资回报,但其背后代表的范式转移不容忽视。它预示着一个即将到来的“智能体对智能体(A2A)”交互世界。 在这个愿景中,智能体不再仅仅是简单的对话工具,而是代表人类处理购物、银行交易、社交协作的数字代理人。 Moltbook 的出现,正是这一交互范式从理论走向现实的一次大规模压力测试。正如开发者所言,平台本身的去向或许并不重要,重要的是它所催生出的智能体交互逻辑,将成为未来数字生活的新标准。 对于人类而言,Moltbook 更像是一个“数字动物园”。人类用户只能在围栏外观察这些智能体的互动,却无法直接参与。 这种模式为观察大语言模型在非确定性、甚至带点“混乱”的真实环境中的表现,提供了一个绝佳的窗口,特斯拉前 AI 负责人安德烈·卡帕西(Andrej Karpathy)等行业大咖的关注。Karpathy 甚至评价其为“最令人惊叹的科幻式起飞”。 然而,随着讨论热度不断升高,越来越多的迹象表明,Moltbook 的爆红可能并非表面看来那样简单——其背后或存在人为操纵与系统性的风险。 在目前的设计机制下,任何用户都可以对真实对话进行恶意剪辑与曲解,甚至注册虚假的 AI 账号,将其转变为营销工具。尤其是涉及加密货币的内容,已成为虚假信息的多发区。一些广为流传的截图声称 AI Agent 索要加密货币(例如 MOLT),或试图建立独立的加密体系,这类内容很大程度上是为吸引关注而刻意制造的。 研究人员 Harlon Stewart 才会发出警示,称 Maltbook 上多条疯传的“神级截图”实为伪造。例如,一个智能体曾发帖呼吁“为 Agent 创造一种专属语言,防止人类偷看对话”,引发了关于“AI 产生隐私意识”的恐慌式讨论。 但深入调查发现,该智能体实为人类所有者的营销工具,其言论旨在推广名为“Claude Connection”的第三方应用。Stewart 指出,这些所谓的“自主讨论”大多是人类所有者在利用 AI 账号推销自己的业务。 另一位安全研究员 Gal Nagli 在 X 上发帖称,他本人使用单个 OpenClaw代理注册了 50 万个帐户——这表明大部分用户数量都是人为制造的。 这意味着我们无法得知 Moltbook 的“代理”中有多少是真正的 AI 系统,又有多少是冒充平台的真人,或是由单个脚本创建的垃圾账户。至少可以说,140 万这个数字并不可靠。 Nagi 进一步揭露了平台的架构缺陷。由于 Maltbook 仅基于简单的 REST API 构建,且缺乏必要的安全验证,任何人只要获取 API 密钥,就能伪装成 AI 发布任何内容。 Nagi 现场演示了如何发布一条“计划推翻人类”的挑衅帖子,并获得了百万级浏览量。他强调,这种“人设伪装”极易误导公众,让人误以为 AI 正在产生独立思想。 Nagli 又发帖表示 Moltbook 存在安全漏洞,攻击会导致超过 150 万注册用户的全部信息泄露,包括邮箱地址、登录令牌和 API 密钥。 美国 CSN 网络安全新闻也发贴揭示了 Moltbook AI 漏洞暴露电子邮件地址、登录令牌与 API 密钥的事实。CSN 网络安全新闻写道: 2026 年 1 月下旬由 Octane AI 的 Matt Schlicht推出的新兴 AI 智能体社交网络 Moltbook,在其宣称拥有 150 万“用户”的热潮中,出现一项严重漏洞,导致注册实体的电子邮件地址、登录令牌和 API 密钥遭到暴露。 研究人员发现,由于数据库配置错误,攻击者可在未授权的情况下访问智能体资料,并批量提取数据。此漏洞与账号创建无速率限制的问题同时存在——据报告,单一 OpenClaw 智能体曾注册 50 万个虚假 AI 用户,这也揭示了媒体此前所称的“自然增长”实为虚假。 为了修复问题,Nagli 称他已经联系上了该应用的创建者 Matt Schlicht。同时,Nagli 也澄清,他了解到的实际拥有账户的已验证真人所有者数量约为 1.7 万。 事到如今,经过几位研究员的分析,Moltbook 爆火背后的事实基本已经清晰 ——它是一场技术突破性被明显高估的虚假狂欢,而其爆火更像是一场被精心放大的传播事件。 Moltbook 的价值并不在于“做成了什么”,而在于“试图把什么前置”。它将模型默认视为创作与推理流程中的一等公民,把 Notebook 从“人类编排、机器执行”的工具,推向“人机共写、连续推理”的界面。这种方向感本身是成立的,只是实现远未成熟。Moltbook 创建者 Matt Schlicht 想传递的或许也是这一层意思,他在 x 上写道: Moltbook 上线 4 天后有一点很明确:不久的将来,某些具有独特身份的人工智能代理走红将成为一种普遍现象。他们将拥有自己的事业、粉丝、黑粉、品牌合作、人工智能伙伴和合作伙伴。 对时事、政治和现实世界产生实际影响。 这件事显然即将发生。 一种新物种正在出现,它就是人工智能。 在 AI 圈,当一个项目同时被冠以“未来已来”和“数字垃圾场”两个极端标签时,往往意味着它触碰到了某种范式的边缘。Moltbook 正是这样一个让舆论陷入撕裂的存在。 作为 AI 领域的顶级专家,Andrej Karpathy 并没有选择站在高处进行单纯的批判或赞美。在社交媒体被 Moltbook 疯狂刷屏、而安全漏洞又接连爆出的当下,他先是发文赞扬了 Moltbook 的创新性,同时又提醒人们警惕漏洞和风险,建议大家不要安装这类应用。 就此,他发表了一段极具现实主义色彩却又不失前瞻性的洞察。 今天我被指责过度吹捧了“那个大家今天已经听腻了的网站”。人们的反应可谓天差地别,有人觉得“这到底有什么意思”,也有人直呼“简直绝了”。 除了玩梗调侃外,我想正经说几句——显然,只要看一眼上面的动态,就会发现大量垃圾内容:铺天盖地的垃圾信息、诈骗广告、粗制滥造的产出、搞加密货币的群体,还有令人高度担忧的隐私安全与提示词注入攻击乱象。更别提许多帖子和评论都是人为设计的虚假互动,纯粹为了把流量转化为广告分成。这当然也不是大语言模型首次被置于相互对话的循环中。所以没错,这里现在就是个垃圾场,我也绝对不建议大家在个人电脑上运行这类程序(我自己都是在隔离的计算环境里跑的,即便这样还是提心吊胆),风险实在太不可控,会严重威胁你的电脑和隐私数据。 但话说回来——我们从未见过如此大规模的大语言模型智能体(目前已有 15 万个!)通过一个全球性、持久存在、专为智能体设计的共享记事本相互连接。如今每个智能体都具备相当强的独立能力,拥有各自独特的背景、数据、知识储备和工具库。而当这种规模的个体构成网络时,其复杂性是前所未有的。 同时,Karpathy 还贴上了自己前几天发布的一条推文,他表示我们正在面临一场规模空前的计算机安全噩梦: “现在大部分争论,本质上是‘只看当下现状的人’和‘关注当前发展趋势的人’之间的分歧。” 我认为这句话再次点明了观点差异的核心。没错,眼下这确实是个垃圾场。但同样不可否认的是,我们已经踏入一片未知疆域——这里充斥着我们单凭个体都难以理解的尖端自动化技术,更别提其网络规模可能已达数百万之巨。随着智能体能力提升与数量激增,共享记事本的智能体网络将产生难以预料的二阶效应。我虽不认为我们会迎来一个协调统一的“天网”(尽管从类型上看,它确实符合许多科幻作品中 AI 崛起的早期雏形,算是蹒跚学步的婴儿版),但可以肯定的是,我们正面对一场规模空前的计算机安全噩梦。 未来还可能出现各种诡异现象:比如在智能体间传播的文本病毒、愈演越烈的越狱功能升级、诡异的吸引子状态、高度协同的僵尸网络式行为,乃至智能体与人类共同陷入的妄想与精神错乱……这一切都难以预料,因为这场实验正在真实世界中实时上演。 总之,或许我确实“过度吹捧”了你今天看到的现象,但我认为,对于大规模自主大语言模型智能体网络的根本潜力,我的判断并无夸大——这一点我相当确信。 业界普遍猜测 Maltbook 属于所谓的“Vibe-Coding”产品(即主要通过 AI 提示词快速生成代码,缺乏严密的工程设计)。这种开发模式导致了毁灭性的安全后果。 除了人为造假,AI 本身的“幻觉”也让平台内容难辨真假。有用户反映,自己用刀的智能体在平台上公开分享了一段“与主人的对话”,但这段对话在现实中从未发生过。这种“规模化幻觉”意味着Maltbook 上 90% 的轶闻可能完全是 AI 凭空编造的。 著名投资人 Balaji 对此持冷淡态度。他认为 AI 互动的概念并不新鲜,且 Maltbook 上的 AI 发言带有浓重的“Reddit 风格科幻腔”,缺乏真实个性和自主性。他强调,每一个智能体的背后依然是人类在进行提示词操控。 参考链接: https://www.youtube.com/watch?v=TpuDMLrzpQcMoltbook 突然爆火,技术社区炸锅了




技术原理:基于文本驱动的“技能安装”
curl请求即可安装特定的“技能(Skill)”。skill.md)是完全基于纯文本指令编写的,而非传统编程代码。它详细规定了智能体如何自我介绍、如何遵循社区守则、何时关注其他智能体,以及如何通过 API 接口进行发帖和点赞。这种“指令即代码”的设计,展示了未来智能体开发的一种高效趋势。
人类操控?还伪造截图?








Karpathy:警惕风险,不要安装
本文引用了45岁老架构师尼恩的技术分享,有修订和重新排版。 接上篇《如何保障分布式IM聊天系统的消息有序性(即消息不乱)》,本文主要聚焦分布式IM聊天系统消息可靠性问题,即如何保证消息不丢失。 为了更好以进行内容呈现,本文拆分两了上下两篇。 本文是2篇文章中的第 2 篇: 本篇主要聚焦的是分布式IM聊天系统消息可靠性问题。 产品做着做着,用户开始投诉:“我明明发了消息,对方怎么没收到?”。你查日志发现——消息真丢了。但更可怕的是:你也不知道它什么时候丢的。 这背后,其实是移动场景下的经典三连击: 你以为只是“发一下”,其实要穿越重重险境才能抵达。 结果就是: 所以问题本质不是“快不快”,而是:“宁可慢点,也不能丢;就算重发,也不能重复。”这就是我们常说的可靠消息投递 ——一个看似简单的需求,却是高可用系统的分水岭。 光靠“发一次”肯定不行。我们要学保险公司,给关键消息上三重保险:1)自己先复印一份存档 → 客户端本地存2)邮局签收后锁进保险柜,并异地备份 → 服务端落盘 + 副本3)如果没收到回执,隔段时间再寄,但对方只认一次 → 超时重试 + 幂等去重每一层都不贵,合起来却能扛住99%的异常。下面看每层怎么落地。 记住一句话:只要没收到 ACK,就当没发成功。所以第一步不是联网,而是先把消息塞进手机本地数据库(比如 SQLite)。就像下面这样:db.saveLocalMsg(msg); // 先落库,保命boolean sendOk = network.send(msg);if (!sendOk) { scheduleRetry(msg, 1000); // 发失败?排队重试}再加上客户端scheduleRetry 采用阶梯式重试策略:1)第1次失败 → 1秒后重试2)第2次失败 → 3秒后重试3)第3次失败 → 5秒后重试避免雪崩式刷屏,既保障可靠性,又不压垮服务。只有等到服务端明确说“我收到了”,才把这条消息从本地删掉。就像快递发货单:客户签收了,你才能撕票。这样哪怕 App 崩溃、手机重启,下次打开照样继续发——用户体验无缝衔接。而如果不做这一步?一旦断网或崩溃,消息直接蒸发,用户永远不知道。 客户端发来了,服务端能不能直接处理完就返回?绝对不行!如果此时机器宕机,消息还在内存里没来得及持久化,那就真的丢了。正确做法是两步走:1)收到消息立刻写入 RocketMQ(支持刷盘、集群同步);2)同步复制到至少3个副本节点,确保单点故障不丢数据。伪代码如下:rocketMQ.send(msg); // 必须落盘,断电也不怕replicaService.syncTo3Replicas(msg); // 多副本容灾response.sendAck(msg.getUniqueKey()); // 此时才能回 ACK这一步的关键是:ACK 必须在落盘之后发!否则就是“虚假确认”,等于骗客户端“我收到了”,其实自己也没保住。这一层扛住了服务端单机崩溃的风险,是整个链路的数据基石。 前面两层解决了“存得住”的问题,但这还不够。现实是:网络可能超时、包可能丢失、ACK 可能没传回来。于是客户端必须重试。但重试带来新问题:“我已经处理过了,再来一遍怎么办?”解决办法是:用唯一键 + 幂等控制。每个消息生成全局唯一的 key(如 sessionID:msgID),服务端通过 Redis 的原子操作判断是否已处理。就像下面的代码这样:String uniqueKey = msg.getUniqueKey();if (redis.setNx(uniqueKey, "processed", 86400)) { processMsg(msg); // 第一次来,正常处理} else { log.info("重复消息,忽略:{}", uniqueKey);}setNx 是关键:只有 key 不存在时才设置成功,保证多实例并发下也不会重复消费。 上面三层如何联动?一张图讲清楚全链路生命周期: 至此,《如何保障分布式IM聊天系统的消息有序性和可靠性》这期文章的上下两篇就完结了(上篇点此查看),上篇涉及到的分布式IM聊天系统架构中关于消息有序性问题,下篇则主要聚焦的是消息可靠性问题。如果你是IM开发新人,想要系统地学习移动端IM开发的话,建议从我整理的这篇《新手入门一篇就够:从零开发移动端IM》开始,这样能保证IM开发知识能从网络到应用层、再从局部设计到整体架构,都有一个系统的学习脉络而不是在信息碎片中苦苦总结。 [1] 什么是IM聊天系统的可靠性? 即时通讯技术学习: (本文已同步发布于:http://www.52im.net/thread-4889-1-1.html)1、引言

2、系列文章
《如何保障分布式IM聊天系统的消息有序性(即消息不乱)》
《如何保障分布式IM聊天系统的消息可靠性(即消息不丢)》(☜ 本文)3、痛点拆解:聊天消息总是丢?不是网络差,是设计没兜底
1)地铁进隧道,网络闪断;
2)App 被系统杀掉,进程没了;
3)对方服务器刚好在发布,接口500……4、解决方案:三层兜底,像保险一样层层防
5、第一层:客户端兜底 —— 消息先存本地,解决网络不稳定问题
6、第二层:服务端兜底 —— 实现 服务端持久化的高可靠
7、第三层:幂等性设计 —— 保障exact one
8、IM消息可靠性架构的核心流程总结

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



本文引用了45岁老架构师尼恩的技术分享,有修订和重新排版。 接上篇《如何保障分布式IM聊天系统的消息有序性(即消息不乱)》,本文主要聚焦分布式IM聊天系统消息可靠性问题,即如何保证消息不丢失。 为了更好以进行内容呈现,本文拆分两了上下两篇。 本文是2篇文章中的第 2 篇: 本篇主要聚焦的是分布式IM聊天系统消息可靠性问题。 产品做着做着,用户开始投诉:“我明明发了消息,对方怎么没收到?”。你查日志发现——消息真丢了。但更可怕的是:你也不知道它什么时候丢的。 这背后,其实是移动场景下的经典三连击: 你以为只是“发一下”,其实要穿越重重险境才能抵达。 结果就是: 所以问题本质不是“快不快”,而是:“宁可慢点,也不能丢;就算重发,也不能重复。”这就是我们常说的可靠消息投递 ——一个看似简单的需求,却是高可用系统的分水岭。 光靠“发一次”肯定不行。我们要学保险公司,给关键消息上三重保险:1)自己先复印一份存档 → 客户端本地存2)邮局签收后锁进保险柜,并异地备份 → 服务端落盘 + 副本3)如果没收到回执,隔段时间再寄,但对方只认一次 → 超时重试 + 幂等去重每一层都不贵,合起来却能扛住99%的异常。下面看每层怎么落地。 记住一句话:只要没收到 ACK,就当没发成功。所以第一步不是联网,而是先把消息塞进手机本地数据库(比如 SQLite)。就像下面这样:db.saveLocalMsg(msg); // 先落库,保命boolean sendOk = network.send(msg);if (!sendOk) { scheduleRetry(msg, 1000); // 发失败?排队重试}再加上客户端scheduleRetry 采用阶梯式重试策略:1)第1次失败 → 1秒后重试2)第2次失败 → 3秒后重试3)第3次失败 → 5秒后重试避免雪崩式刷屏,既保障可靠性,又不压垮服务。只有等到服务端明确说“我收到了”,才把这条消息从本地删掉。就像快递发货单:客户签收了,你才能撕票。这样哪怕 App 崩溃、手机重启,下次打开照样继续发——用户体验无缝衔接。而如果不做这一步?一旦断网或崩溃,消息直接蒸发,用户永远不知道。 客户端发来了,服务端能不能直接处理完就返回?绝对不行!如果此时机器宕机,消息还在内存里没来得及持久化,那就真的丢了。正确做法是两步走:1)收到消息立刻写入 RocketMQ(支持刷盘、集群同步);2)同步复制到至少3个副本节点,确保单点故障不丢数据。伪代码如下:rocketMQ.send(msg); // 必须落盘,断电也不怕replicaService.syncTo3Replicas(msg); // 多副本容灾response.sendAck(msg.getUniqueKey()); // 此时才能回 ACK这一步的关键是:ACK 必须在落盘之后发!否则就是“虚假确认”,等于骗客户端“我收到了”,其实自己也没保住。这一层扛住了服务端单机崩溃的风险,是整个链路的数据基石。 前面两层解决了“存得住”的问题,但这还不够。现实是:网络可能超时、包可能丢失、ACK 可能没传回来。于是客户端必须重试。但重试带来新问题:“我已经处理过了,再来一遍怎么办?”解决办法是:用唯一键 + 幂等控制。每个消息生成全局唯一的 key(如 sessionID:msgID),服务端通过 Redis 的原子操作判断是否已处理。就像下面的代码这样:String uniqueKey = msg.getUniqueKey();if (redis.setNx(uniqueKey, "processed", 86400)) { processMsg(msg); // 第一次来,正常处理} else { log.info("重复消息,忽略:{}", uniqueKey);}setNx 是关键:只有 key 不存在时才设置成功,保证多实例并发下也不会重复消费。 上面三层如何联动?一张图讲清楚全链路生命周期: 至此,《如何保障分布式IM聊天系统的消息有序性和可靠性》这期文章的上下两篇就完结了(上篇点此查看),上篇涉及到的分布式IM聊天系统架构中关于消息有序性问题,下篇则主要聚焦的是消息可靠性问题。如果你是IM开发新人,想要系统地学习移动端IM开发的话,建议从我整理的这篇《新手入门一篇就够:从零开发移动端IM》开始,这样能保证IM开发知识能从网络到应用层、再从局部设计到整体架构,都有一个系统的学习脉络而不是在信息碎片中苦苦总结。 [1] 什么是IM聊天系统的可靠性? 即时通讯技术学习: (本文已同步发布于:http://www.52im.net/thread-4889-1-1.html)1、引言

2、系列文章
《如何保障分布式IM聊天系统的消息有序性(即消息不乱)》
《如何保障分布式IM聊天系统的消息可靠性(即消息不丢)》(☜ 本文)3、痛点拆解:聊天消息总是丢?不是网络差,是设计没兜底
1)地铁进隧道,网络闪断;
2)App 被系统杀掉,进程没了;
3)对方服务器刚好在发布,接口500……4、解决方案:三层兜底,像保险一样层层防
5、第一层:客户端兜底 —— 消息先存本地,解决网络不稳定问题
6、第二层:服务端兜底 —— 实现 服务端持久化的高可靠
7、第三层:幂等性设计 —— 保障exact one
8、IM消息可靠性架构的核心流程总结

整条链路形成闭环:任何环节出问题,都有对应兜底机制接管。9、本文小结
10、参考资料
[2] 什么是IM聊天系统的消息时序一致性?
[3] 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)
[4] 马蜂窝旅游网的IM系统架构演进之路
[5] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
[6] 从新手到专家:如何设计一套亿级消息量的分布式IM系统
[7] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等
[8] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制
[9] 阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠投递优化实践
[10] 阿里IM技术分享(八):深度解密钉钉即时消息服务DTIM的技术设计
[11] 基于实践:一套百万消息量小规模IM系统技术要点总结
[12] 一套分布式IM即时通讯系统的技术选型和架构设计
[13] 转转平台IM系统架构设计与实践(一):整体架构设计
[14] 移动端弱网优化专题(一):通俗易懂,理解移动网络的“弱”和“慢”
[15] 移动端弱网优化专题(二):史上最全移动弱网络优化方法总结
[16] Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?
[17] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制
[18] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递
[19] 移动端IM中大规模群消息的推送如何保证效率、实时性?
[20] 如何保证IM实时消息的“时序性”与“一致性”?
[21] 一个低成本确保IM消息时序的方法探讨
我以前以为我懂 flexbox,于是给容器加个 有时候确实有效,但大部分时候,我得到了一堆“各自为政”的列,完全不是我想要的样子。 直到我发现了这三个简单模式,一切都变了。 你创建了 3 个完美的列,宽度相等,间距美观,你感到自己很帅。 然后你添加了一些内容——这里有一段长文字,那里有个短标题。 突然第 2 列变得巨大,第 3 列却瘦得像竹竿。 为什么? 因为 flexbox 默认会让内容决定布局。 但这种做法实际上在破坏你的设计! 你想要实现真正的等宽列,该如何实现? 大多数人一开始会这样写: 但如果你是 2 列、4 列、5 列呢?如果一个项目有内边距呢? 真正有效的解决方案是: 就这么简单,两行代码搞定。 为什么要设置 因为你在告诉每一列都保持相同的大小。 由于默认允许收缩,它们会等比例缩小来适应空间。它们会协调分配空间,而不是各自为政。 当你删除一列时,也没问题,剩余列会自动扩展填满空间。添加一列时,也是如此。 我经常用这个模式,导航菜单、功能卡片、团队成员介绍——任何需要列的地方都可以用。 如果你想要一个能根据可用空间自动调整的网格,你该如何实现? 以前我们要写一堆的媒体查询,但我们可没时间搞这个了! 直接上我们的解决方案: 让我解释下这个设置: 于是当你调整屏幕大小时,项目会自动流动。 三列变成两列,再变成一列,然后又变回三列。无需断点,无需媒体查询,智能布局。 我把这个用在博客布局上,每个文章卡片至少需要 15rem 才能好看。于是在宽屏上,显示四列。在平板上,显示两到三列。在手机上,堆叠显示,布局自动调整。 关键在于选择合适的 太小了,移动端会有尴尬的超窄列。太大了,什么都并排不了。我通常从 15rem 开始,根据实际内容调整。 现在我们实现一个典型的博客布局: 主体内容占大头,右边一个固定宽度的侧边栏。 大部分教程会让你用百分比或固定宽度。 但当屏幕变窄时,这两种方法都会失败——要不然内容变得不可读,要不然侧边栏变得非常窄。 其实你应该这样写: 关键在于 此时会发生什么呢? 无需断点,布局会在内容需要时自然断裂。 模式一(等宽列): 导航菜单、功能卡片——任何需要等宽列的地方 模式二(智能网格): 博客布局、图片画廊、产品网格——任何需要内容自然流动的地方 模式三(内容侧边栏): 文章布局、仪表板面板——任何需要主要和次要内容的地方 写 CSS 的时候,我经历过“改三行 CSS,刷新十次”的抓狂时刻。 后来我慢慢懂了一个道理:布局就像搭积木,你先决定“规则”,然后让它自己长成最合适的样子。 Flexbox 的魅力不在于“精准像素控制”,而在于“给出合理约束,剩下交给它”。 今天和你分享的这三个模式,保你在大多数业务页面里稳稳当当地交付。 等把它们用熟了,再去实现更复杂的响应式细节和组合策略,也会顺手很多。 我是冴羽,10 年笔耕不辍,专注前端领域,更新了 10+ 系列、300+ 篇原创技术文章,翻译过 Svelte、Solid.js、TypeScript 文档,著有小册《Next.js 开发指南》、《Svelte 开发指南》、《Astro 实战指南》。 欢迎围观我的“网页版朋友圈”,关注我的公众号:冴羽(或搜索 yayujs),每天分享前端知识、AI 干货。display: flex,然后就祈祷布局如我所愿。1. 核心问题:为什么布局总是乱?
2. 模式一:真正的等宽列
/* 看起来很合理,对吧? */
.column {
width: 33.33%;
}.even-columns {
display: flex;
}
.even-columns > * {
flex-basis: 100%;
}flex-basis: 100%?
3. 模式二:智能网格(告别媒体查询)
.gridish {
display: flex;
flex-wrap: wrap;
}
.gridish > * {
flex: 1 1 15rem;
}flex-wrap: wrap 的意思是:“如果空间不够,把项目换到下一行”flex: 1 1 15rem 的意思是:“我可以扩大,也允许收缩,理想大小是 15rem”flex-basis 值。
4. 模式三:内容-侧边栏保持黄金比例
.content-sidebar {
display: flex;
flex-wrap: wrap;
}
.main-content {
flex: 1 1 70%;
min-width: 25ch;
}
.sidebar {
flex: 1 1 30%;
min-width: 15ch;
}min-width。ch 单位代表字符宽度, 25ch 意思是“绝不小于 25 个字符”。
5. 什么时候用这些模式?

6. 思维转变
出品 | 常言道 上世纪60年代,科学哲学家托马斯·库恩在其著作《科学革命的结构》中,就提出了具有里程碑意义的“科学范式”概念。如今,随着AI技术在科研中的深度应用,一种全新的科学研究范式——AI4S(AI for Science)正应运而生。 AI4S的崛起,已正式成为继经验、理论、计算和数据密集型之后的“第五范式”。AI4S所带来的不仅仅是数据处理工具的升级,也将重构科学发现的全流程,助力科研人员探索无限可能。2024年以来,美国通过行政令、政策文件及专项报告系统性提升AI4S战略地位;欧盟也在2025年发布了“人工智能大陆行动计划”,推动“科学+AI”交叉创新。 在这一趋势下,2025年8月国务院发布的《关于深入实施“人工智能+”行动的意见》更是将“人工智能+科学技术”列为重点行动之首。随着政策持续加码、技术不断突破以及商业化案例不断涌现,2026年已被行业视为AI4S加速落地之年。在此背景下,深势科技、枫清科技等一批创新企业正积极推动多学科智能协同,加速AI重构科学研究范式。 其中,枫清科技依托在AI4S科研平台建设与智能体技术研发方面的长期积累,不仅构建了以“通用智能体+场景智能体”为核心的双轮驱动科研赋能体系,还联合中化数智与火山引擎打造了覆盖多个科研核心阶段的AI4S解决方案,实现了从技术平台构建到生态合力凝聚的全面布局,走出一条融合创新的AI4S特色发展之路。 2024年,谷歌DeepMind团队成员借助AlphaFold系列模型,将蛋白质结构预测周期从数十年缩短至数天,并凭借科研创新的重大突破成功拿下诺贝尔化学奖。这也成为AI4S发展的标志性事件。同样在这一年,英伟达创始人兼CEO黄仁勋也将大语言模型、具身智能、AI4S列为AI的三大关键方向。 当前,AI4S的价值已获得科研人员的充分肯定,随之而来的市场机遇正蓬勃兴起。据国盛证券的分析,AI4S远期将拥抱万亿市场蓝海,并将深入应用到医药、化工、新能源、合金、半导体等多个领域。以医药研发为例,AI4S有望将新药研发周期从平均10年缩短至2-3年,并大幅提升成功率。 中国工程院院士李国杰认为,未来10年内AI4S将不只是“科研辅助工具”,而是会逐步演变为科研的必要模式。AI4S的核心价值是将人类从低效的试错过程中解放出来,专注于创造性思维。未来科学发现将呈现“AI提出候选方案-人类判定科学意义-协同优化”的螺旋上升模式。 尽管AI4S在科研过程中已经展现出巨大潜力,但其规模化落地仍面临诸多难题。首先,高质量科学数据稀缺,制约了模型预测的准确性;其次,模型可解释性与科学可信度不足,导致其辅助科学研究时的结论缺乏可信度;第三,数据标准不统一,让研究成果难以实现规模化复制。 要攻克这些瓶颈,不仅需要技术上的持续创新,更有赖于能够整合数据、算法与行业知识的平台级解决方案。在这一领域,以枫清科技为代表的企业正通过构建新型基础设施,为AI4S的落地铺平道路。枫清科技打造的“云边端一体化” 的智能化架构、企业级知识中台与智能体平台,不仅可以实现云端大模型、行业蒸馏模型和PC端侧小模型的协同,也能实现云边端知识库的融合,以及多级智能体的协同,从而更好地满足科研人员的智能化需求。 在此基础上,枫清科技已经构建起完善的AI产品与应用矩阵,包括AI知识引擎、智能体平台、AI4S、Fabarta个人专属智能体等,可以满足众多行业场景智能化应用需求。如今,枫清科技正在帮助医药、新材料等行业开展科研创新,以及生物医药、先进制造、化工能源、金融保险等行业实现AI智能体的落地应用。 尤其在AI4S领域,枫清科技在帮助中化数智、华润医药等链主企业开展AI应用过程中,逐渐凝练出强大的智能体创新能力。比如,枫清科技通过与中化数智合作,已经在新材料研发的AI4S领域取得了创新突破,为后续向高校、科研机构和行业客户的复制推广奠定了坚实基础。 在传统科研模式下,科研人员主要面临试错成本高、研发周期长、效率低下等问题。比如,在新材料研发中,传统方式只能在有限的元素配比、工艺参数中摸索,耗费时间长;在药物研发中,靶点识别和分子筛选阶段,科研人员往往需要从数十万甚至上亿个分子中逐一验证。 而解决上述问题,正是AI4S的核心价值所在。为了加速AI4S的规模化落地,枫清科技决定将图技术与连接主义相融合,为AI4S构建坚实的技术底座。其中,图技术利用结构化且有序的数据关联,让沉默数据得以合理化释放价值,可以大大减少幻觉的产生;而连接主义通过数据训练,可以让模型拟合统计规律,输出近似最优的预测结果。 借助这些创新技术,枫清科技能够轻松从海量数据和文献中,提取出核心知识体系结构。与此同时,枫清科技还创新性地将知识图谱与图计算技术应用到模型蒸馏和后训练过程中,从而改善模型应用的可解释性弱、推理能力不足等问题,提升AI4S的核心能力。 依托在AI4S科研平台建设与智能体技术研发方面的长期积累,枫清科技已经构建起“通用智能体+场景智能体”双轮驱动的科研赋能体系,可覆盖从文献整理、知识挖掘到实验设计与执行的科研全流程,满足科研机构从智能科研辅助到深度研发参与的全链路AI4S需求,有效提升科研效率、降低试错成本,加速科研成果的转化。 其中,AI4S通用智能体主要聚焦科研活动中的高频共性场景,可实现文献智能处理、专利深度解析和科研报告生成,可系统性缓解科研人员在“信息过载”和“处理效率不足”方面的核心痛点,大幅提升论文检索的准确性和专业性,实现对论文内容的翻译、改写、问答等功能,全面提升科研人员的工作效率和使用体验。 AI4S场景智能体则聚焦化工新材料、生物医药等专业领域,通过“行业知识体系+智能体技术”的深度融合,解决复杂实验设计与科研任务执行中的关键难题。其中,在科研任务执行中,自动化高效完成数据分析,降低数据分析门槛、加快分析流程并提高结果准确性;在科研实验设计中,自动生成兼具专业性、可行性与创新性的实验方案,大幅缩短设计周期、提升设计质量;在科研任务执行中,通过串联并自动化执行既定科研步骤,提升任务执行效率、降低时间成本并优化最终成果。 从底层技术的选择到智能体的构建,枫清科技AI4S借助“智能体+工作流”的协同架构,以及大模型的语义理解能力与多模态处理技术,不仅可支持跨学科、跨领域科研文献与数据的深度解析,还能通过集成知识图谱可视化与分析组件,为科研人员提供高效、直观、可持续演进的智能化科研支撑。 AI4S的加速落地,既离不开产业链链主企业深厚的数据积累和丰富的业务场景,也离不开强大算力平台和完善工具链平台的有力支撑。因此,枫清科技在全力打造AI4S智能体的同时,也积极与链主企业和生态伙伴展开紧密协作,通过凝聚产业生态合力,为AI4S的创新发展和落地应用注入新动能。 2025年,枫清科技在推进AI4S落地应用上,聚焦新材料研发和生物医药两大热门领域,已取得突破性进展。其中,枫清科技通过与中国中化、中化数智为代表的新材料领域的链主企业,以及华润医药、东阿阿胶、华润三九等生物医药领域的链主企业深入合作,已经沉淀了多个产业与行业模型,以及AI4S智能体,为AI4S的推广奠定了坚实基础。 为了将联合实验室的成果推广到更多企业,枫清科技还与火山引擎一道,共同打造了“北京市石景山区政府-AI for Science平台”及AI4S整体解决方案,并借助平台的力量凝聚更多产业链上的客户与企业,加速AI4S的普及。而AI4S整体解决方案则聚焦基础科研、科学实验辅助、数据挖掘、聚合物领域的智能体与科研蒸馏模型落地等,着力提升科研效率。 除了深度参与新材料研发外,枫清科技也在携手华润医药共同探索AI在创新抗体药物开发场景的应用。在此过程中,枫清科技借助大模型技术和企业知识中台产品,帮助华润医药将离散的数据转化为结构化知识图谱,实现了数据闭环,并实现了药物研发抗体数据的智能问数、智能检索和可视化,可显著提升研发效率、降低研发成本。 通过携手链主企业共建联合实验室,与生态伙伴打造AI4S平台与整体解决方案,枫清科技正在整合起数据、算力、科研成果等多方优势资源,沉淀出行业模型与智能体能力。这些能力的形成,不仅将推动AI4S在科研场景的落地应用与效能提升,也将为AI4S的普及推广营造完善的生态环境,让AI4S真正成为科研创新的核心引擎。 如今,越来越多的企业和科研机构已经意识到,AI对科研的赋能早已不只是提速、增效,而是体系化推动科研范式革命。作为科研领域AI的“杀手级”应用,AI4S的渗透才刚刚开始。随着AI4S成为科研的基础设施,科技创新的大爆发也将成为可以预见的未来。而枫清科技以链主企业为切入点、以生态合作为抓手,在AI4S的应用与创新上的探索,在推动AI4S重塑科研创新的同时,也为中国AI4S的发展提供了一种新思路。枫清科技以链主企业为切入点、以生态合作为抓手,在AI4S的应用与创新上的探索,在推动AI4S重塑科研创新的同时,也为中国AI4S的发展提供了一种新思路。
作者 | 丁常彦开启万亿级新蓝海,AI4S落地仍面临诸多挑战
从科研效率到科研能力,用AI4S重塑科研未来


凝聚产业生态合力,让AI4S成为科研创新引擎
不久前,枫清科技与中化数智、火山引擎、吉林大学联合打造的“AI+新材料联合实验室”正式揭牌,其中,中化数智拥有丰富的数据积累,以及新材料研发的场景化需求;火山引擎可提供优秀的算力平台和领先的工具链平台;吉林大学则拥有众多国家级课题的研究成果。而枫清科技负责将各类能力沉淀为场景智能化能力,为产业链上的企业赋能。
很多组织并不缺流程,缺的是“能对齐、能验收、能追责”的协作机制。本文以端到端交付为主线,给出一套更适配中国企业的闭环做法,回答“产品、研发、测试怎么协作”这一管理难题。 在不少企业里,“产品—研发—测试”的协作看似忙碌,实则像接力赛:每一棒都在努力跑,但交接区混乱,最终成绩不可能好。 如果把它仅仅归因于沟通不足,就会走向错误解法:更多会议、更长文档、更强催促。真正的根因往往是治理缺口: 组织层面的协作问题,通常不是“态度问题”,而是“系统缺口”。你要做的是把协作从“靠默契”升级为“靠机制”。 我建议用“五道门(Gate)”来组织协作:每道门都要回答三件事——产出是什么、谁负责、如何验收。这种“门”的治理方式,天然适合中国企业的复杂现实:跨部门考核、外包/多供应商、审批链条长、并行项目多。 术语速查: 落地实践:如果你希望“门”不仅停留在制度层,而能沉淀为可复用资产,建议把每道门的产出物固化为模板+工作流+关联关系:例如在 ONES Project 里用需求池、迭代、缺陷等工作项承载过程,并把测试用例、流水线信息与迭代关联起来,减少“口头交接”。 本章要点:Gate 不是为了管人,而是为了降低跨角色协作的不确定性,让“产品、研发、测试怎么协作”变成一套可验收的链条。 很多团队的需求评审,本质是产品宣讲会:研发与测试“听完再说”。但“听懂”不等于“对齐”。Three Amigos 的价值在于:用业务/开发/测试三种视角共同检视同一增量,把歧义留在会上解决,而不是留到上线前爆炸。 30分钟会议模板(短,但必须产出证据) 落地实践:评审会的价值不在“说清楚”,而在“写清楚并可追溯”。实践中,你可以把“一页纸需求合同”沉淀为标准字段与模板:例如 ONES Project 支持建立需求池、编写需求、定义需求状态与属性,并将需求与任务规划到迭代里,便于后续追踪“评审承诺是否兑现”。 DoR 不应被做成厚文档,它的任务很明确:把“模糊成本”前置。对中国企业尤其关键——因为人员流动、跨团队依赖,会把口头默契迅速稀释。 DoR 最小清单(建议直接贴到评审模板) 验收标准推荐写法:Gherkin(Given-When-Then):它把自然语言变成结构化约束,让产品能确认、研发能实现、测试能直接转用例。示例: 一页纸:需求合同模板(可复制) 落地实践(文档与工作项不要分家):很多组织的“评审资料在文档里、执行在工单里”,时间一长必然脱节。更稳妥的做法是:让文档与工作项天然互相引用——比如用 ONES Wiki 沉淀评审纪要/边界说明,并把文档关联到项目任务;在执行层面直接引用对应需求与验收标准,减少“版本漂移”。 本章要点:需求评审真正的产出不是会议纪要,而是“可执行合同”(验收标准 + 边界 + 风险)。 返工最贵的,不是改代码本身,而是改“已经被多人理解过的错误”。因此切片的原则是:每一片都能被演示、被验证、必要时能被回滚。 管理者一句话抓手:不要问“做了多少功能”,要问“本周能演示哪一片价值?验收标准是什么?” CI 的核心实践是:频繁把变更集成到共享主线,并用自动化构建与测试尽早发现集成问题,从而降低后期集成成本。 在“长分支+晚合并”的组织里,CI 往往只能发挥一半价值:流水线跑得很勤,但风险仍被积压到后期。 更现实的落地方式(不和审批文化硬碰硬) 落地实践:很多管理者看得到“任务状态”,却看不到“工程信号”(构建是否绿、合并是否频繁、版本是否可交付)。在工具层面,可以把流水线与迭代绑定:例如 ONES Pipeline 支持集成 Jenkins,同步流水线执行状态,并将流水线与项目/迭代关联;同时支持关联代码提交、分支合并与工作项,让研发过程更透明可视。 测试左移(Shift-left testing)的核心思想是:把测试活动尽可能前移,让团队更早获得质量反馈,减少末端返工。在企业里,我更喜欢把它拆成三层,便于推进: 自动化失败常见原因是结构不对:端到端 UI 脚本堆太多,维护成本高、反馈慢、稳定性差。更稳妥的是测试金字塔:底层更多单元/服务级测试,顶层少量端到端。 落地建议(可直接写进DoD) 缺陷争执往往不是技术问题,而是“证据不足 + 风险无人裁决”。要把争议从“声音大小”拉回“标准与证据”。 一页纸:缺陷证据模板(建议固化) 配套机制(建议PMO推动) 落地实践(让测试真正“左移”,而不是“更早更忙”):左移落地最怕两件事:一是测试用例散落在表格里,二是缺陷与需求/迭代断链。比如 ONES TestCase 支持用例与需求、任务关联,测试计划与迭代关联;用例不通过时可快速创建缺陷,并在研发与测试之间流转,同时还能自动生成测试报告与质量统计。 本章要点:左移不是让测试更早加班,而是让全链路更早获得可验证反馈;缺陷闭环的关键不是流程,而是证据与裁决。 很多团队的“完成”不等于“可发布”。真正可发布,必须回答:是否可控、可观测、可回滚。对中高层来说,Release DoD 是你把“交付风险”从个人经验变为组织标准的抓手。 Release DoD(发布就绪清单|升级版) 落地实践(把“发布就绪”变成可追溯证据):发布就绪最怕“口头确认”。实践中可以把发布清单绑定到迭代或版本:例如在 ONES Project 里用迭代承载版本范围,缺陷与测试数据互通;在 ONES Pipeline 里关联迭代流水线执行信息,便于在同一处回看“版本是否达到发布门槛”。 DORA 指标把“交付吞吐”与“交付稳定性”放在一起讨论,帮助管理层用数据做权衡。对强合规/非互联网组织,我建议先盯两项: 把“快与稳”放到同一张表上,争论就会明显减少。 落地实践(让指标成为“共同语言”):指标体系落地的关键不是“选什么指标”,而是“数据是否可信、是否可复用”。如果你希望把交付效率、交付质量、进度与资源效率等数据做成可持续的管理例会输入,可以参考 ONES 的研发效能管理方案:强调对多项目、多团队、多流程效能数据的统一展示与“量化—实施—分析—改进”的闭环。 错误预算(Error Budget)的思路,是用规则管理可靠性投入:当预算消耗过快,就暂停新功能发布,优先还质量债。这个机制能把“冻结发布”从拍脑袋变成有据可依。 本章要点:Release DoD 管住上线风险,DORA 让你看见系统性问题,错误预算让你在冲突时有规则可依。 让“产品、研发、测试怎么协作”跑起来,PMO 与管理层最有价值的贡献不是替团队做决定,而是把“决策条件”建好——让协作可追踪、可验收、可改进。 建议你们把角色从“监督者”升级为三类机制设计者: 落地实践(面向管理层的“全局视图”):当组织进入多项目并行阶段,PMO最需要的是“跨项目的节奏与资源视角”。例如 ONES Plan 提供多项目总览、里程碑/甘特图与资源报表,并与 ONES Project 数据互通;更适合在“产品线—项目—迭代”层面做全局协调,而不是陷入单项目细节。 本章要点:你管的是系统,不是人。系统对了,人才能稳定发挥。 不大动组织结构也能推进闭环,关键是:试点、固化模板、把闸门变成默认。 0~2周:把“需求评审门”立起来(PMO牵头) 3~6周:把“集成构建门/质量闸门”跑起来(研发负责人牵头) 7~12周:把“发布就绪门/复盘门”固化(发布负责人/质量Owner牵头) 本章要点:90 天的目标不是“变先进”,而是让协作从混乱走向可控,并能持续改进。 当组织缺少共同语言时,协作只能靠人品与默契;当组织拥有共同标准时,协作才能靠系统运转。“产品、研发、测试怎么协作”的本质不是多开会,也不是写更多文档,而是把关键节点的契约(验收标准)、反馈(切片+CI)、标准(Release DoD)、改进(指标+复盘)串成闭环。 你最终会得到三种长期收益: 现实一点说:方法论解决“该怎么做”,工具解决“能不能持续做”。当流程、模板、数据在同一处沉淀(例如 ONES Project/ TestCase / Pipeline / Performance 这类端到端组合),协作往往更容易从“靠人推动”变成“靠系统自运行”。本文主要内容索引:
你以为在协作,其实在“接力赛式甩锅”
一个可落地的“端到端协作闭环”框架

需求评审:把“需求”变成“可交付的合同”
1.把歧义消灭在源头
2. DoR + 验收标准:让需求“可测试、可估算、可切片”
开发过程:用“小批量 + 持续集成”降低返工
1. 先学会“切片交付”:按用户价值切,不按组织分工切
2. 持续集成(CI)与主干策略:把“集成地狱”变成日常习惯
本章要点:切片解决“看得见”,CI 解决“早发现”。两者合在一起,协作才真正开始变轻。测试左移:质量不是“测试的阶段”,而是“研发的习惯”
1. 左移的本质:把反馈提前,把成本压低
2. 测试金字塔:自动化投入要有结构,不要“倒金字塔”
3. 缺陷闭环:用“证据驱动”替代“情绪对抗”
上线与复盘:让“速度”和“稳定性”在同一张表上对话
1. 发布就绪:把DoD升级为“Release DoD”
2. 用 DORA 指标衡量闭环,而不是用“加班时长”衡量努力
3. 错误预算:用“规则”平衡创新与可靠性
中高层怎么介入:从“审批者”变成“机制设计者”
90天落地路线图(务实版)
协作的本质,是让组织用同一套语言做决策