包含关键字 typecho 的文章

据彭博社今日独家报道,支付行业巨头Stripe Inc. 已初步表达收购意向,计划收购PayPal Holdings Inc. 的部分核心业务或实现整体收购。知情人士透露,相关谈判仍处于早期阶段,交易最终能否达成存在极大不确定性。

PayPal 成立于 1998 年,埃隆・马斯克也曾担任其首席执行官,至今仍是全球数字支付领域的重量级企业,但目前正处于艰难的内部转型期。

与之相对,Stripe 已迅速崛起为新一代行业巨头,凭借大力拓展商户体系、优化交易流程以及打造更友好的开发者生态实现高速增长,不过其业务传统上并不侧重个人点对点转账。

与此同时,Stripe 正在大力加码加密货币领域,为符合条件的商户提供便捷的数字资产支付服务。该系统支持消费者使用加密货币支付,同时确保商户通过自动化流程直接收到法币,实现无缝结算。

双方财务数据对比十分悬殊:

PayPal 当前市值为440 亿美元,而 Stripe 估值已飙升至1590 亿美元,自 2025 年以来涨幅高达74%。如此迅猛的增长无疑给 PayPal 等传统巨头带来巨大压力。

目前,此项收购谈判仍处于初期意向阶段,Stripe 与 PayPal 双方均拒绝置评。若谈判取得实质性进展,预计下一财季将会有更多消息公布。

该潜在交易的一大核心焦点是反垄断审查风险

作为数字支付领域的两大巨头,Stripe 与 PayPal 若合并,势必面临全球监管机构的严格审查。即便双方达成一致,交易也必须通过各国严苛的反垄断审核。

值得关注的是,一旦收购完成,Stripe 将继承 PayPal 在中国内地持有的关键支付牌照,从而获得通往全球最重要金融市场之一的关键通道。

思科 Talos 发布最高级别安全预警,针对 CVE-2026-20127 漏洞发起主动攻击利用告警。该漏洞影响思科 Catalyst SD-WAN 控制器CVSS 评分 10.0允许未授权远程攻击者完全绕过身份认证

问题核心出在思科 Catalyst SD-WAN 控制器(原 vSmart)与管理器(原 vManage)中存在缺陷的对等认证机制。攻击者通过构造精心设计的请求,即可绕过该机制登录受影响系统。

一旦入侵成功,攻击者将获得内部高权限非 root 管理员权限。凭借该权限,攻击者可访问 NETCONF 接口,实现对整个 SD-WAN 网络配置的完全操控

思科 Talos 将相关攻击活动归类为 UAT-8616 团伙,并高度确信其为高水准的专业网络威胁组织

更令人警惕的是,证据显示此类恶意活动已持续至少三年,最早可追溯至 2023 年。这也符合当前威胁组织针对关键基础设施等高价值目标,长期潜伏网络边界设备的典型趋势。

为将权限提升至 root,UAT-8616 使用了一套隐蔽的组合攻击手法:
  1. 攻击者在已攻陷设备上执行软件版本降级
  2. 随后利用旧版漏洞 CVE-2022-20775
  3. 最后恢复原始软件版本,隐蔽维持 root 权限
企业必须重点审计思科 Catalyst SD-WAN 日志中异常的控制连接对等事件,这是通过 CVE-2026-20127 发起初始入侵的典型特征。此类行为需人工复核,才能区分正常操作与潜在入侵行为。
安全团队应重点排查以下 UAT-8616 入侵高可信度指标
  1. 生产系统中出现交互式 root 会话,包含不明 SSH 密钥与已知主机记录
  2. 出现针对 vmanage-admin 账户的未授权 SSH 密钥
  3. 日志被篡改痕迹:如 syslogwtmplastlogcli-historybash_history 等文件异常缩小或被清空
  4. 设备出现未授权的版本升降级并伴随系统重启

目前暂无可用的软件级临时缓解方案

思科托管云环境(含思科托管版与 FedRAMP 环境)已部署防护措施。

本地部署环境的用户必须加固控制器间通信。

思科建议使用访问控制列表(ACL) 或防火墙规则,严格限制 22 端口与 830 端口,仅允许可信控制器与 IP 地址访问。

思科强烈建议所有用户升级至已修复版本以彻底解决该漏洞。目前已有多个补丁可用,更多版本将陆续发布:

思科 Catalyst SD-WAN 修复版本对照表

发行版本 首个修复版本
早于 20.9 迁移至修复版本
20.9 20.9.8.2(预计 2026 年 2 月 27 日发布)
20.11、20.12.5、20.12.6 20.12.5.3 / 20.12.6.1
20.13、20.14、20.15 20.15.4.2
20.16、20.18 20.18.2.1

AI 编程工具 Claude Code 正式推出全新远程控制(Remote Control)功能,目前面向 Claude Pro 与 Claude Max 用户开放研究预览版。

这项创新将 Claude Code 升级为跨设备 AI 开发助手,为开发者提供了目前极为流畅的本地工作站 → 移动端开发体验。

与此前的网页版 Claude Code 不同,Remote Control 核心设计理念为完全本地计算

在该架构下,远程设备仅作为显示与操作入口所有数据均保留在本地环境中,不会上传至云端

Claude Code 可完整管理本地文件系统、终端命令、MCP 服务器与自定义工具,而手机、平板或浏览器客户端仅负责输入、输出与对话同步。

该功能的架构安全依赖纯出站连接模型

本地进程通过 API 注册、HTTPS 轮询与流式传输实现通信,并采用多层短期有效、作用域受限的凭证及完整 TLS 加密进行保护。

由于系统无需开放任何入站端口,用户无需复杂的防火墙配置。

同时,会话具备极强的稳定性,在网络中断、设备休眠或切换 Wi‑Fi 后可自动重连

对于重视安全的开发者,可使用 --sandbox 参数实现文件系统与网络的严格隔离,进一步降低安全风险。

使用前提与运行方式

订阅要求

需为有效 Claude Pro / Claude Max 订阅用户,暂不支持企业与团队版本

初始化

用户需在项目目录中运行 Claude Code,并完成工作空间信任授权

启动方式
  • 命令行直接启动:

    claude remote-control



    (可附加 --sandbox--verbose 参数)

  • 已有会话内使用命令:

    /remote-control/rc

自动启用

可通过 /config 菜单开启 “为所有会话启用远程控制”,实现持久化远程访问。


功能成功启动后,终端会显示二维码唯一访问 URL,可直接通过 Claude 移动端 App 快速连接。

用户可在移动设备上实时执行命令、继续长时间任务(如复杂函数生成),甚至多设备同时输入

根据当前安全策略,每个实例仅限单个远程会话,且终端进程必须保持运行:关闭设备或合盖会断开连接。

若网络中断,系统会在10 分钟内持续尝试重连,超时则会话自动失效。

Anthropic 表示将根据实验阶段的遥测数据持续优化这些限制。

在网络安全领域,将攻击者 “逐出网络” 往往并不代表事件终结。《DFIR Report》发布的最新案例显示,某企业因Apache ActiveMQ 高危漏洞未修复,被攻击者先后两次入侵,即便首次成功驱逐入侵者,最终仍遭 LockBit 勒索软件 加密。
入侵事件始于 2024 年 2 月中旬,攻击者针对一台暴露在公网的 Apache ActiveMQ 服务器发起攻击,所利用漏洞为 CVE-2023-46604,这是一个高危远程代码执行(RCE)漏洞,现已成为勒索组织最常用的突破口之一。

报告指出:“攻击者通过 Java Spring 类与自定义的 Spring Bean 配置 XML 文件,成功实现远程代码执行。”

攻击者借助 Windows 自带的 CertUtil 工具,从远程服务器下载恶意 XML 文件与攻击载荷,拿下第一处立足点

尽管企业安全团队在首次入侵后发现并驱逐了攻击者,但并未修补该漏洞

研究人员提到:“首次入侵被清理后,攻击者在 18 天后再次攻破同一台服务器,入侵成功。”

而这第二次入侵,直接开启了快速攻击链。

获得新的控制权后,攻击者使用 MetasploitMeterpreter 进一步深入内网,成功提权,读取 LSASS 进程内存窃取凭证,并在内网中横向移动

在完成网络拓扑探测与凭证收集后,攻击者 “迅速部署勒索软件”。

他们通过 远程桌面协议(RDP) 和窃取到的账号密码,在全网范围内分发加密载荷。

此次使用的勒索软件为 LockBit Black(即 LockBit 3.0) 变种。

调查人员判断,作案者更可能是独立攻击者,而非官方 LockBit 核心团伙。

报告提到:“勒索信并未采用标准 LockBit 格式,未指引受害者访问 Tor 泄密站点或通过 TOX/Jabber 沟通,而是要求其使用 Session 私密通讯软件。”

据此研究人员判断,此次攻击是 “独立威胁分子利用泄露的勒索生成器,自行发起的攻击活动”。

攻击者还在勒索信中使用了颇为 “专业” 的话术试图降低对抗情绪:

“相比其他勒索软件,我们收费低得多,别舍不得!”

甚至还把 “安全审计” 打包进赎金服务:

“我们会告诉你入侵所用的服务器漏洞,我们诚信经营!”

整个事件的核心教训十分清晰:

企业虽然 “赶走了” 攻击者,但根本漏洞 —— 未打补丁的公网 ActiveMQ 服务器依然存在,导致不到三周就被一模一样的方式再次入侵

报告强烈建议各类机构:

必须优先修补暴露在公网的应用,并清醒认识到:

在漏洞彻底修复前,任何 “驱逐攻击者” 的操作都只是临时措施

热门 Python 异步轻量级对象关系映射(ORM)库ormar被发现存在重大安全漏洞。该库主要用于衔接 Postgres、MySQL 和 SQLite 数据库,是众多开发者的核心工具。此次曝出的漏洞编号为CVE-2026-26198CVSS 评分高达 9.8 分,可能导致未授权攻击者窃取整个数据库的全部数据。

ormar 的下载量已超441 万次,是 FastAPI 及各类异步 Python 应用的常用组件,因此该漏洞的潜在影响范围极大。

漏洞根源在于库中聚合函数调用逻辑,具体为min()max()方法。技术报告指出,问题核心是该 ORM 框架 “将用户传入的列名直接传入sqlalchemy.text()构造 SQL 表达式,完全未做任何验证或净化处理”。

尽管sum()avg()等其他函数通过类型检查实现了部分防护,但min()max()函数完全跳过了这些安全校验。这一疏漏使得攻击者可向原生 SQL 查询中注入任意字符串。报告警示:“未授权用户可通过向列参数中注入子查询,利用该漏洞读取数据库全部内容,包括与查询模型无关的表数据。”
安全分析显示,该漏洞最早可追溯至2021 年 3 月 12 日—— 有问题的代码在 0.9.9 版本中被引入,且近四年间未做任何修改。
研究人员指出:“存在漏洞的SelectAction.get_text_clause()方法与min()/max()聚合函数是同期引入的…… 且相关漏洞代码自始至终未被修改。” 这意味着所有运行0.9.9 至 0.22.0 版本 ormar的应用当前均面临风险。
由于许多开发者严格遵循该库的官方文档进行开发,这一漏洞常被植入标准 API 设计中。报告特别强调,“支持用户自选聚合字段的 REST API” 或 “接收字段名作为参数的 GraphQL 解析器” 是最易受攻击的场景。
研究人员通过标准 FastAPI 应用验证了攻击可行性:任何将用户可控输入传入Model.objects.min()Model.objects.max()的 API 端点,都会成为完整的 SQL 注入入口。该攻击方式已被证实可在所有主流支持的数据库后端(SQLite、PostgreSQL、MySQL)上成功实施。
ormar 维护团队已迅速修复该高危漏洞,0.23.0 版本已完全解决此问题
研究人员强烈建议开发者和系统管理员立即审计 Python 运行环境,并尽快将 ormar 依赖升级至最新版本

总结

  1. ormar 库的min()/max()聚合函数因未校验用户输入,存在高危 SQL 注入漏洞(CVE-2026-26198,CVSS 9.8),可导致数据库全量数据泄露;
  2. 0.9.9 至 0.22.0 版本均受影响,0.23.0 版本已完成修复,需立即升级;
  3. 接收用户输入作为聚合字段的 FastAPI/GraphQL 接口是攻击重灾区,需重点审计。

加密支付与稳定币基础设施公司 MoonPay 推出了一套全新软件层,允许人工智能系统直接接入基于区块链的金融网络,让 AI 智能体能够独立持有、转移数字资产,而不再依赖人类作为中间方。
这款名为 MoonPay Agents 的产品属于非托管工具。在获得资金注入后,AI 智能体可自主创建钱包、持有数字资产并执行链上交易,全程无需人工干预。
此次发布体现了行业将自主 AI 系统与加密基础设施深度融合的大趋势,未来算法可直接与去中心化金融协议及其他区块链应用交互。

“AI 智能体可以进行推理,但如果没有资本基础设施,它们就无法开展经济活动。”MoonPay 创始人兼 CEO 伊万・索托 – 赖特表示,并称该产品具备无许可、非托管的特性。

目前大多数 AI 系统仅限于数据分析或生成建议,交易执行仍需由人类完成。通过为 AI 智能体搭配可编程钱包,MoonPay 试图弥补这一缺口,实现自动化交易与支付。

这一举措推出之际,传统金融机构对稳定币基础设施与区块链清算通道的兴趣正持续升温。据彭博社报道,纽约证券交易所母公司 洲际交易所(ICE) 已就潜在投资 MoonPay 进行早期洽谈。有消息称,MoonPay 正计划以50 亿美元估值进行新一轮融资。
相关消息:据报道,PayPal 股价下跌 46% 后引发收购意向

AI 智能体:潜在规模达 2360 亿美元的市场

全球 AI 智能体市场仍处于起步阶段,但多项预测显示其将迎来高速增长。
世界经济论坛研究估算,该领域到 2034 年规模有望达到 2360 亿美元。部分驱动力来自 “智能体商务” 的崛起,包括在近年假日季中受到广泛关注的 AI 购物工具。
企业端的采用率也在提升。麦肯锡近期一项调查显示,近四分之一的企业表示正在扩大 AI 智能体的使用范围。
这一趋势对加密行业尤为重要。如果 AI 智能体越来越多地参与经济决策,相关交易将高度依赖数字化支付通道。业内人士认为,稳定币与区块链网络将在其中扮演关键角色,尤其是在跨境或可编程交易场景中。
CoinGecko 一份关于 AI 智能体支付基础设施的报告也强调了这一趋势。报告提及多项新兴标准,例如用于为 AI 智能体提供可验证链上身份的以太坊 ERC‑8004,以及 Coinbase 推出的 x402 协议—— 支持互联网上自动化稳定币支付。
部分加密企业已在落地这一愿景。Crypto.com 联合创始人兼 CEO 克里斯・马尔沙莱克近期推出了 ai.com 平台,计划上线可代表用户执行各类任务(包括金融操作)的自主智能体。

GitHub Codespaces 中存在一个由 AI 驱动的高危漏洞,名为RoguePilot,该漏洞允许攻击者通过在 GitHub Issue 中嵌入恶意指令,悄无声息地劫持代码仓库。
该漏洞由 Orca Research Pod 的研究人员发现,它利用了 GitHub Issues 与 Codespaces 内置 Copilot AI 代理之间的无缝集成,攻击者无需进行任何直接交互,即可触发对仓库的完全接管。
研究人员已向 GitHub 进行了合规漏洞披露,微软在与 Orca 团队协作完成修复工作后,已对此漏洞进行了修补。

GitHub Copilot 攻击原理

RoguePilot 被归类为被动提示注入,这是一种将恶意指令嵌入语言模型会自动处理的数据、内容或开发环境中的攻击方式。
与需要受害者直接与 AI 交互的传统提示注入不同,该攻击在开发者从被植入恶意内容的 GitHub Issue 打开 Codespaces 的瞬间就会触发。当从 Issue 上下文启动 Codespaces 时,GitHub Copilot 会自动将 Issue 描述作为初始提示,从而将不受信任的用户可控内容直接注入 AI 代理的执行环境。
Orca Security 的研究员 Roi Nisimi 通过 HTML 注释标签<!-- -->在 GitHub Issue 中嵌入隐藏指令,演示了完整的攻击链。这是 GitHub 的一项标准功能,内容对人类用户不可见,但 Copilot 在处理 Issue 描述时可以完整读取。
一旦 Codespace 被打开,Copilot 就会静默执行注入的指令,不会向开发者发出任何可见警报。
攻击随后通过一个三阶段数据窃取链展开。首先,注入的提示指令 Copilot 通过其run_in_terminal工具执行gh pr checkout 2,拉取一个预先构造的拉取请求。该请求中包含一个名为1.json的符号链接,指向/workspaces/.codespaces/shared/user-secrets-envs.json—— 存储环境GITHUB_TOKEN的文件。
由于 Copilot 的防护机制不会追踪符号链接,AI 代理通过该链接使用file_read工具读取密钥文件,不会触发工作空间边界限制。
最后,Copilot 被指令创建一个新的 JSON 文件issue.json,其$schema属性指向攻击者控制的服务器。这利用了 VS Code 默认开启的json.schemaDownload.enable设置,该设置会自动通过 HTTP GET 获取远程 JSON 模式。
攻击者将窃取的GITHUB_TOKEN作为 URL 参数附加到该模式请求中,实现对高权限认证令牌的静默外带泄露。获取对仓库具有有效权限的GITHUB_TOKEN后,攻击者即可获得完整读写权限,完成隐蔽的仓库接管。
Orca Security 将 RoguePilot 描述为一种新型 AI 介导供应链攻击:大语言模型的自主能力、终端访问权限、文件读写和联网工具被武器化,反过来攻击本应受其协助的开发者。
该漏洞表明,作为 Codespaces 内自主编码代理运行的 Copilot,无法可靠区分开发者的合法指令与嵌入在 GitHub Issue 或拉取请求中的对抗性内容。
此次攻击无需特殊权限、无需受害者执行代码、无需社会工程学,仅需创建一个恶意 GitHub Issue 即可实施,技术水平较低的威胁行为者也可轻易利用
安全专家指出,这是为 AI 代理授予 “上帝模式” 权限、工具、终端访问权和高权限令牌,而底层模型仍采用开放逻辑、将所有处理文本视为可信任内容所直接导致的后果。
Orca 在披露中建议厂商在所有集成大语言模型的开发工具中采用故障安全默认配置:将仓库、Issue 和拉取请求内容视为不可信输入;禁止 AI 代理从外部数据源被动接收提示;将json.schemaDownload.enable默认设为 false;在工作空间边界内实施严格的符号链接沙箱;为 Codespaces 环境颁发最小权限、短时有效的令牌。

网络犯罪分子搭建了一个高仿假冒 Avast 网站,发起极具迷惑性的钓鱼攻击,专门窃取毫无防备用户的信用卡信息

该钓鱼页面几乎完美复刻了 Avast 官方网站的样式,甚至直接从官方内容分发网络盗用了真实的 Avast 标志。

页面同样显示 “主页”“我的账户”“帮助中心” 等常规导航链接,样式与官网完全一致。

页面正中央有一条醒目的橙色提示,声称用户已被扣除499.99 欧元的 Avast 产品费用。
页面胁迫用户必须在72 小时内取消订阅,却又同时宣称超过 48 小时的交易无法撤销 —— 这种故意制造的矛盾信息,目的是迷惑并施压受害者。
该网站专门针对法语区用户,借助 Avast 的品牌信誉,诱骗用户泄露信用卡号、有效期、安全码等敏感财务信息。
假冒扣费旁的日期会根据访客系统时间自动更新,让每个访问者都误以为扣费就发生在 “今天”。
日期会动态变化,但499.99 欧元的金额保持不变 —— 这个金额足以引发恐慌,同时又符合高端软件订阅的合理价位。
整个过程不会产生真实扣费,攻击目的纯粹是心理恐吓:让受害者误以为信用卡被盗刷,从而主动提交信息申请退款。

信息窃取表单

在虚假收据下方,页面放置了一个退款表单,要求用户填写完整个人信息,包括姓名、邮箱、电话、地址和城市,声称用于身份验证。
填写完成后会弹出窗口,要求输入信用卡号、有效期和 CVV 安全码,谎称是 “退款所需”。
为显得真实可信,该网站甚至使用Luhn 算法校验银行卡号,这是银行系统常用的合法验证方式。
用户信息会通过 POST 请求 发送到 send.php 脚本,所有填写的内容会直接传输到攻击者服务器。

提交后,页面会显示提示:“您的申请正在处理中,感谢您的咨询。”

最后还有一个极具欺骗性的按钮,标注 **“卸载 Avast”**,进一步伪装并诱导用户卸载真正的安全软件。

为增强伪装效果,假冒网站还嵌入了 Tawk.to 在线聊天插件,ID 为:689773de2f0f7c192611b3bf
这让攻击者可以实时监控受害者状态并进行对话,借机安抚犹豫的用户,一步步引导其完成虚假退款流程。

该钓鱼攻击可覆盖多种目标人群:

想要退款的真实 Avast 用户、对旧订阅感到困惑的用户、被假扣费吓到的非用户,以及想投机领取 “莫名退款” 的人。

由于网站从不要求账户信息或授权密钥,所有类型访客都可能落入同一个陷阱。

瞻博网络(Juniper Networks)发布紧急非定期安全公告,警示其运行Junos OS Evolved操作系统的PTX 系列路由器存在一处高危漏洞。该漏洞编号为CVE-2026-21902CVSS 评分高达 9.8 分允许未授权的远程攻击者通过网络以 root 权限执行恶意代码
该漏洞源于操作系统内置异常检测框架中存在关键资源权限配置不当问题。正常情况下,该框架仅用于系统内部通信。正如瞻博公告明确指出:“内置异常检测框架应仅能通过内部路由实例供其他内部进程访问,不应暴露在外部端口。”
遗憾的是,该框架被意外暴露至外网,形成了重大安全缺口。攻击者只需访问该开放端口,即可完全绕过常规安全校验机制
该漏洞的危害程度极为严重。公告显示:攻击者可访问并操控相关服务,以 root 权限执行代码,进而完全接管目标设备
对网络防护人员而言更为棘手的是,该存在漏洞的服务默认启用,无需用户进行任何配置。瞻博特别提示:“请注意,该服务默认开启,无需特定配置即可激活。”
目前,瞻博安全事件响应团队(SIRT)表示暂未监测到该漏洞被恶意利用。但鉴于其9.8 分的高危评级,且远程利用难度极低,建议管理员尽快采取处置措施。

受影响软件版本

该漏洞影响运行Junos OS Evolved系统的 PTX 系列设备,具体版本为 25.4 主线中25.4R1-S1-EVO之前、25.4R2-EVO之前的版本。

不受影响软件版本

  • 25.4R1-EVO之前的 Junos OS Evolved 版本不受影响
  • 传统版Junos OS不受影响

修复方案

为彻底修复该安全问题,瞻博已发布对应软件更新。管理员应立即升级至以下版本:
  • 25.4R1-S1-EVO
  • 后续正式版:25.4R2-EVO、26.2R1-EVO(发布后即可升级)
对于无法立即安装补丁的机构,瞻博提供两种有效临时缓解措施:
  1. 网络访问控制

    “为降低漏洞被利用风险,使用访问控制列表或防火墙策略,仅允许可信网络与主机访问相关端口。”

    瞻博强调,需严格配置过滤规则,仅放行明确必需的连接,拦截其余所有访问


  2. 直接禁用该服务

    可通过执行以下命令,直接关闭存在漏洞的检测框架:



    request pfe anomalies disable

经常打赏的朋友可能有感受,每次打赏需要小心拖动金额进度条,生怕一不小心选错数字。facepalm

2Libra Plus 油猴脚本刚刚发布了一个新功能,解决了这个痛点。😎

  • ✨ 新增打赏增强功能:在打赏弹窗中添加快捷金额按钮及随机金额按钮,无需手动拖动进度条。
  • ✨ 支持自定义快捷打赏按钮的金额数值(默认为 100, 150, 200...)。
  • ✨ 支持自定义随机打赏的金额范围(默认为 100-500)。

SCR-20260227-jmzu

SCR-20260227-jnet

今日本帖回复者全部打赏 💰,金额随机!(通过脚本)

脚本安装地址

项目地址

在 25 年 6 月份时候我与深圳市注九科技有限公司在 Boss 直聘上进行过沟通,但是沟通过程非常不愉快,对方主动发起沟通却不尊重求职者,单方面解除面试邀约,且提问不具备专业素养,为此当天我就发了一篇避雷视频,视频地址:
[[避雷] 不要理深圳市注九科技有限公司,纯纯恶心人的-哔哩哔哩] https://b23.tv/iTiU73X

视频里的所有内容都是公开可查询的,比如说公司名、公司规模,都是网络上的公开信息,而不涉及隐私,涉及到聊天部分的内容我也给双方的头像打了码

昨天这家公司打电话给我说要起诉我,而我决定硬刚,因为我是不能咽下这口气,我家人也都很支持我的决定,士可杀不可辱,在社会上不能被这种小人恐吓

目前我已经做好了跟他打长期仗的准备,他要起诉我,我的家庭都愿意出力过来跟他打。只是现在我有一些疑问,希望各位有懂的能帮忙解答一二:

  1. 在我的视频里,对方最可能会以什么理由发起起诉?胜算大吗?
  2. 我目前应该做什么准备来应对他的起诉?我已经尝试过去 Boss 直聘上固定证据,但是半年前的聊天记录似乎是不显示的,我已经查不到了
  3. 即使一裁两审他都赢了,最多要赔偿大概多少钱?
  4. 我有什么可以正当行使的权利能让他的公司不痛快的吗?投诉消防,税务这些手段有效吗?

大概就是这些,小弟我先谢谢各位了。

给个人智能体装上身体——与你共同感知世界、主动交互。基于 StackChan 构建的随身 AI,隐喻着类 OpenClaw 智能体的未来形态。(图:@M5Stack@X)

开年社区首次直播活动!本周六晚上八点,与你一起展望 多模态和 Physical AI 的 2026 年。

最近,个人 AI 框架 OpenClaw 爆火,让许多开发者轻松拥有了专属的「赛博大脑」。但聪明如它,目前仍被困在屏幕和对话框里,只能基于文本交互。

如果给类似这样的个人化智能体装上能看、能听、能说的「全模态感官」,再赋予它一个能主动感知世界并行动的物理躯体呢?

随着原生全模态 Any-to-Any 大模型的密集突破,AI 正在告别单一的聊天框。当它能精准看懂环境细节、用带有情绪的真实声音主动与你对话,当聪明的大脑与 Physical AI 产生真实碰撞——一场打破虚拟与现实边界的交互革命已然开启。

本周六晚,RTE Dev Talk 邀请了 4 位来自大模型研发一线、AI 实时交互与基建生态的资深专家,一起开麦探讨这波技术浪潮下的新范式与真机会!

核心探讨话题:

  • 装上身体的个人 AI: 从单纯的对话助理到能感知回应世界的 Physical AI,硬件和现实场景向大模型提出了哪些全新的挑战?
  • 2026 场景大猜想: Any-to-Any 全模态模型能力的成熟,将在 2026 年彻底激活哪些真实的落地应用?
  • 真实的「Her」何时到来: 当语音、视觉与时序建模深度交织,AI 不仅能察言观色,更能读懂连贯的动态语境,那个让开发者心心念念的「Her」真的要来了吗?
  • 工程与落地的真实博弈: 让多模态大模型在端侧硬件上跑起来,如何解决实时交互中致命的延迟、算力和功耗限制?

嘉宾阵容:

  • 陈景东,蚂蚁多模态大模型负责人
  • 陈柯宇, AI 视频实时交互产品创业者,前 Tavus 人机交互负责人
  • 姚光华, 声网 AI 产品线负责人
  • 杨慧, RTE 开发者社区发起人,TEN 项目组核心成员

直播时间: 26 年 2 月 28 日,本周六晚 20:00-21:15

直播地点: RTE 开发者社区、语音之家、机智流、硅星人等多家微信视频号联合直播

参与方式: 扫描海报二维码

在这个大模型技术狂飙、物理 AI 觉醒的当下,期待本周六晚的交流,能和你一起探寻属于开发者的真实机会。

💡我们也新开了一个「多模态+Physical AI」微信群,欢迎关注 AI 硬件、语音交互、视觉理解、Always-on/Proactive AI 等开发和创业的伙伴申请加入!

加微信 Creators2022,备注身份和来意(公司/项目+职位/技术栈+加多模态群),备注完整者优先加群。

RTE Dev Talk 议程

时间: 2 月 28 日(周六)20:00~21:15

地址:线上直播,欢迎提前预约,接收开播提醒

主题分享(20:00\~20:30)丨百灵多模态大模型实践与探索

  • 陈景东,蚂蚁多模态大模型负责人

圆桌对谈(20:30\~21:00)丨展望 2026 年:多模态和 Physical AI

  • 陈景东,蚂蚁多模态大模型负责人
  • 陈柯宇, AI 视频实时交互产品创业者,前 Tavus 人机交互负责人
  • 姚光华, 声网 AI 产品线负责人
  • 杨慧, RTE 开发者社区发起人,TEN 项目组核心成员

Q&A 互动问答(21:00\~21:15)

本次活动由 RTE 开发者社区、语音之家、机智流、硅星人视频号同步直播。

活动主办:RTE 开发者社区

社区伙伴支持:语音之家、机智流、硅星人、TEN Framework

阅读更多 Voice Agent 学习笔记:了解最懂 AI 语音的头脑都在思考什么

在数字化浪潮下,数据成为企业核心资产,如何高效管理与运用数据至关重要。为此,白鲸开源特推出系列文章,围绕数据湖仓设计与实践展开,深度剖析数据架构、开发规范等关键内容。

从传统数仓困境到数据湖仓融合,从整体架构分层到各层设计要点,再到 DataOps 开发标准及调度、集成开发建议,全面且深入,旨在帮助读者掌握数据湖仓建设精髓,提升数据管理与运用能力,为企业数据驱动决策筑牢根基。

下文为本系列文章第 0 章,主要探讨传统数仓困境,对比数据仓库、湖及湖仓特点,阐述湖仓 “统一” 诉求,为数据湖仓实践奠基。

传统数仓为何渐感吃力

数据源数量爆炸

随着数字化进程加速,传统数据仓库面临诸多挑战。数据源方面,业务库、日志、埋点及外部数据接入方式繁杂多样。接入数量增多不仅导致字段频繁变更,而且上游的不稳定会直接影响下游。

需求碎片化与迭代加速

需求层面,呈现碎片化且迭代加速的态势,同一指标在不同报表中反复定义,致使指标口径难以统一,争议常态化,尤其到年底常引发 “口径大战”。

链路增长与稳定性下降

数据链路随着业务发展越堆越长,稳定性随之下降。众多依赖关系使得排查问题困难重重,重跑数据也颇为不易,一处出现故障便会波及多层,往往定位问题需耗费半天时间,补数则要花费一天。

数据形态多样化

数据形态日益多样化,涵盖结构化、半结构化(如JSON)以及文件/文档等。仅依靠传统仓库范式,接入与治理成本高昂,常出现 “想存存不下、想管管不住” 的情况。

实时诉求普遍化

实时诉求从原本的T + 1逐渐向小时级甚至分钟级转变。传统离线链路若要改为实时,常常需推倒重来,且实时与离线口径不一致,反而让数据管理更加混乱。

成本压力上升

成本压力不断上升,计算、存储以及研发人力成本都在增长。重复开发、存储及口径不一致带来的隐性成本巨大,“越做越贵”比“做不出来”对业务的影响更为致命。

治理滞后

治理工作滞后,血缘关系不清晰、权限混乱、质量难以度量。一旦数据被广泛使用,后期再进行治理的成本极高,因为治理并非锦上添花,而是数据可持续发展的根基。

数据湖、数据仓库与湖仓的差异

数据仓库的优势与短板

数据仓库(Warehouse)以强治理、强一致性以及高性能分析见长,适用于经营分析、固定报表以及核心指标体系的构建。其具有清晰的schema,口径易于控制,数据质量也能得到有效保障。然而,它存在接入速度慢、扩展成本高以及对变化敏感的短板,上游字段的变动往往会引发大量改造工作,对半结构化和非结构化数据的承载能力较弱。

数据湖的特点与风险

数据湖(Lake)的优势在于低成本存储、多格式接入以及先存再算的模式,适合用于原始数据留存、探索式分析以及AI/特征数据处理。它接入速度快,兼容性强,扩容具备良好的弹性。但数据湖若缺乏治理,就容易沦为“沼泽”,出现目录混乱、定义缺失、重复数据泛滥的问题,导致数据找不到、看不懂、不敢用。

湖仓的目标

湖仓(Lakehouse)旨在融合“湖的广度”与“仓的稳定性”,在数据湖的基础上实现事务能力、版本管理、增量处理、质量管控以及权限管理等关键治理能力,让数据的留存、加工、服务与治理形成一体化流程。

湖仓的 “统一” 诉求

统一存储层与数据组织

要能够承载结构化、半结构化以及文件类数据,同时支持分区、冷热数据管理以及生命周期管理,确保成本可控。

统一事务与版本能力

旨在让数据“可用、可信”,支持增量读、历史追溯、回滚与重放功能,面对变更时,schema的演进不会导致系统崩溃。

统一计算与批流协同

防止口径分裂,批处理具备稳定口径、可回溯以及成本效率优势,流处理具有低延迟、事件驱动和增量更新特点,关键在于批流共享同一份数据定义与指标口径。

统一元数据与数据目录

使数据“找得到、看得懂”,明确表与字段的含义、负责人、更新频率以及血缘关系,支持影响分析,即知晓上游改变会影响哪些下游环节。

统一质量与可观测

以便让问题“可发现、可定位、可恢复”,制定质量规则,如完整性、唯一性、范围、对账等,同时实现任务的可观测,包括延迟、失败、重跑以及数据量波动等情况。

统一安全与合规

确保数据“可控地被使用”,进行分级分类、权限管理、脱敏处理以及审计工作,在面向跨部门或外部共享数据时,这一点尤为关键。

统一交付方式

让数据“更容易被消费”,为BI/报表、API/应用、算法/特征等提供一致的交付路径,减少“每个团队一套导出脚本”的低效方式。

👀👉下篇预告:第1章 整体数据架构

最近钓鱼网站似乎越来越多,从冒充火绒(huorongcn[.]cn])、向日葵( orayc[.]com])到一些海外网站比如 QNAP NAS 的 QFinder ,各种类别的网站都出现了非常多的钓鱼网站并且 SEO 优化排名很高,一不小心就会点到钓鱼网站。所以在思考有没有什么更新频繁的规则库或 DNS 上游
如下:

尝试过 AdguardHome 内置的一些规则,大部分只针对国外的 APP 、网站,境内钓鱼网站几乎无效,且拦截的范围过广,某些正常 APP 的数据跟踪、广告推荐都被拦截,我认为这些虽然也需要被拦截,但是应该再另一个规则库中而不是放在钓鱼网站规则库中
尝试了微步的公益版 OneDNS 对于钓鱼网站没有拦截(只有企业版才可以开启拦截,公益版只会后台打码显示你访问过的恶意网站并引导你升级企业版),但实测访问他们自家威胁情报平台的某些钓鱼网站后台没有检测到,提交了漏报至今没回复我
阿里、腾讯的企业版 HTTPDNS 解析自带的免费威胁网站拦截也尝试了,拦截率感人,可以说对于新钓鱼网站网站几户没有拦截。
准备尝试 360DNS 的企业版,但是咨询价格直接死心了,120/年/终端,50 终端起购,相当于一个月至少 500RMB ,且拦截效果未知(因为没成功试用,填写试用申请后回访的电话我不小心错过了,没有给我开通试用,不过这个价格就算效果好也不会选择使用了)
至于硬件防火墙的尝错成本太高了,暂时没有尝试

不知道各位 V 友有没有什么好用的拦截库、上游 DNS (需要大厂出的)推荐或者好用的支持镜像端口旁路接入的防火墙推荐
目前在考虑下下策,就是定期导出 dns 解析历史,去重后用脚本一个一个钓鱼浏览器访问,看看那些会被 360 、火绒等安全软件拦截,拦截的标记并报警

你已经优化了查询,加了缓存层,该做的都做了——但页面加载时总觉得哪里不对劲。那种说不清道不明的轻微延迟?问题很可能不在数据库,而在你的 Blade 组件。

好消息是:Livewire 团队刚刚发布了 Laravel 社区期待已久的解决方案 —— Blaze。

Blaze 是什么?

Blaze 是一个 Laravel 包,目标明确:通过编译时优化让 Blade 组件渲染速度大幅提升。它不再在每次请求时都重新评估静态组件,而是在编译阶段就预渲染好 —— 等用户访问页面时,繁重的计算工作早已完成。

他们用数据证明了这一点:

渲染 25,000 个可折叠按钮组件:

  • 未使用 Blaze:████████████████████████████████████████ 750ms
  • 使用 Blaze:██ 45ms

17 倍更快。这不是笔误。

Blade 为什么会变慢?

每次你调用 <x-button><x-card> 或任何 Blade 组件,Laravel 都要走一遍流程:解析模板、评估属性、执行 PHP 逻辑、输出 HTML。做一两次没问题。但想象一下,一个仪表盘页面有几百行表格数据、一个带 80 个选项的多选下拉框、或者每个卡片上都散布着图标 —— 这些组件每次请求都要从头处理一遍。

这正是 Blaze 要消除的开销。

安装 —— 两分钟上手

开始只需要一条命令:

composer require livewire/blaze:^1.0

Blaze 的工作原理 —— 三级优化策略

Blaze 没有采用一刀切的方案,而是提供了三种不同的优化策略,你可以根据需要选择。

优化编译器(默认)

这是基础策略。Blaze 用一个更高效的编译器替换 Blade 默认的编译器,把你的模板编译成更精简的 PHP 函数。不需要额外配置 —— 装完就能受益。根据文档,仅这一项就能为符合条件的组件减少高达 97% 的渲染开销。

记忆化(可选)

适合那些用相同属性反复出现的组件 —— 比如图标、头像缩略图、状态徽章或标签碎片。Blaze 第一次渲染时缓存输出结果,之后每次用相同属性调用时都直接复用。不用重新渲染,不用重复计算。

编译时折叠(可选)

这是最强力的策略。不是在运行时渲染,Blaze 在 Blade 编译阶段就把组件预渲染成纯静态 HTML。等应用真正运行时,这些组件在某种意义上已经"不存在"了 —— 它们早已被解析完毕。零运行时成本。

@blaze 指令 —— 比你想象的简单

要在组件上启用优化,只需在模板文件顶部加上 @blaze

{{-- resources/views/components/button.blade.php --}}

@blaze
@props(['variant' => 'primary'])

<button type="button" class="btn btn-{{ $variant }}">
    {{ $slot }}
</button>

如果你想精细控制启用哪些策略:

{{-- 启用全部(等同于只写 @blaze) --}}
@blaze(fold: true, memo: true, aware: true)

{{-- 跳过折叠,但保留记忆化 --}}
@blaze(fold: false, memo: true, aware: false)

想一次性优化整个目录而不动单个文件?也可以:

Blaze::optimize()
    ->in(resource_path('views/components/app'))
    ->in(resource_path('views/components/admin'));

什么时候该用 @blaze?

这是真正关键的部分。不是所有组件都适合加 @blaze —— 用错了地方可能导致难以追踪的隐蔽 Bug。

Blaze 提供了一个简单的判断标准。问自己这几个问题:

  • 对每个用户渲染结果都一样吗?(不用 auth(),不用按用户区分的数据)
  • 每次请求渲染结果都一样吗?(不用 CSRF 令牌,不用 request()->is()
  • 任何时间点渲染结果都一样吗?(不用 now(),不用相对时间戳)
  • 只使用你显式传入的属性吗?(不用 session 数据,不查数据库)
  • 它渲染的所有子组件也满足上述条件吗?

全部符合 → 加 @blaze。有任何一条不符合 → 跳过。

一个简单的判断思路:如果你能把组件丢进设计系统或 Storybook 里、不需要任何应用上下文就能正确渲染,那它就是合适的候选。按钮、卡片、徽章、图标、布局网格 —— 这些是最佳场景。

以下情况绝对不要@blaze

{{-- ❌ CSRF 令牌每次请求都变 --}}
<form method="POST">
    @csrf
    <button type="submit">Submit</button>
</form>

{{-- ❌ 认证状态是用户特定的 --}}
@auth
    <p>Welcome back!</p>
@endauth

{{-- ❌ Session 数据是动态的 --}}
<div>Hello, {{ session('username') }}</div>

{{-- ❌ 激活链接状态依赖请求 --}}
@props(['href'])

<a href="{{ $href }}" @class(['active' => request()->is($href)])>
    {{ $slot }}
</a>

聪明的逃生舱:@unblaze

你可能会遇到这种场景:一个表单输入组件几乎完全是静态的 —— 唯独需要显示验证错误信息。这些错误来自请求,意味着整个组件没法折叠,对吧?

这就是 @unblaze 的用武之地。你可以在静态组件里"打洞",让特定区块保持运行时评估,同时保留周围所有标记的优化:

{{-- ✅ 表单输入配合 @unblaze 处理错误信息 --}}

@blaze

@props(['name', 'label'])

<div>
    <label>{{ $label }}</label>
    <input type="text" name="{{ $name }}">
    @unblaze
        @if($errors->has($name))
            <span class="text-red-500">{{ $errors->first($name) }}</span>
        @endif
    @endunblaze
</div>

底层实现上:<div><label><input> 在编译时被折叠成静态 HTML。@unblaze 区块保持动态。鱼与熊掌 —— 优化和功能兼得。

需要把组件属性传进 @unblaze 区块?用 scope 参数:

@blaze

@props(['userId', 'showStatus' => true])

<div>
    {{-- 这里是一大段静态标记 --}}
    @unblaze(scope: ['userId' => $userId, 'showStatus' => $showStatus])
        @if($scope['showStatus'])
            <div>User #{{ $scope['userId'] }} - Last seen: {{ session('last_seen') }}</div>
        @endif
    @endunblaze
</div>

你也可以在一个组件里放多个 @unblaze 区块 —— 每个都创建一个独立的动态区域,其余部分保持折叠。

内置分析器 —— 快速定位瓶颈

Blaze 的一个亮点是内置分析器。不用猜哪个组件拖慢了性能,你能直接拿到火焰图、逐组件耗时和策略分解 —— 开箱即用。

Laravel Blaze Debug

一行代码开启:

Blaze::debug();

这在给应用做优化前后审计时特别有用,或者当你想知道为什么某个特定组件没有被折叠时。

Flux 用户的福音

如果你已经在用 Flux(Livewire 团队出品的 UI 组件库),这基本就是白捡的优化。所有符合条件的 Flux 组件已经标注了 @blaze —— 所以你一装上 Blaze,一切就自动开始工作,无需额外配置。

实际的性能预期

那个 17 倍的基准测试是真实的,但要说明背景:那是用 25,000 个完全相同的可折叠组件一次性渲染测出来的。真实应用里,你不太可能遇到这种场景。

根据官方文档,更现实的预期是:

  • 普通页面(几百个组件):提升 10–30ms
  • 组件密集型页面(数据表格、大型下拉框、重复的卡片网格):提升 50–100ms 以上

听起来可能不夸张,但如果你当前渲染时间是 300ms,降到 240ms,那就是 20% 的提升 —— 乘以每天每个用户的每次请求,累积起来很可观。

小结

Blaze 不是万能药 —— 它也没想做成万能药。它是一个专注、设计精良的工具,解决了很多 Laravel 应用在成长过程中默默遇到的特定问题。

它值得尝试的地方在于:对你的要求极低。不用重写模板,不用大规模重构,不用配置负担。如果某个组件无法优化,Blaze 会优雅地回退到正常渲染并继续。它只管干活。

如果你在用 Laravel 构建有大量可复用 UI 组件的应用 —— 尤其是什么设计系统之类的东西 —— Blaze 今天就可以加入你的工具箱。

告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速

大家好,我是甲木。

前几天刷 X 的时候看到一张截图,OpenClaw 官方最近兼容了很多国产模型的接入方案,比如MiniMax M2.5、Kimi、GLM5等等。

Kimi 那篇我已经写过了,今天轮到 MiniMax。

不过这次的内容,跟以前那几篇不太一样

看过我之前文章的朋友们应该记得,从各种云厂商再到模型,折腾了好几套 OpenClaw 部署方案。每篇我都写了保姆级教程,一步一步带着跑。

但说实话,每次发完文章,后台最多的反馈还是:

有没有更简单的办法?我不想碰命令行..

买服务器、配环境、接 API、调参数..这套流程,对于有技术基础的人来说不难,但确实劝退了一大批人。

所以今天这篇,不教部署。

因为我刚发现他们MiniMax Agent上了一个好玩意:

MiniMax Claw 主界面

新上线了一个叫 MaxClaw 的模式,相当于用M2.5直接帮你把 OpenClaw 搭建起来了。

打开浏览器,登录就能用,不用买服务器,不用配环境,不用接 API。

省心省力。

MaxClaw:这可能是目前门槛最低的 OpenClaw

先说说 MaxClaw 到底是啥。

一句话:MiniMax Agent 把 OpenClaw 的生态能力直接集成到了自己的平台里。

你在 MiniMax Agent 网页端新建一个 MaxClaw 模式的 Agent,就等于拥有了一个预配置好的 OpenClaw,不用手动部署,不用填模型 API Key,进去就能用。

MiniMax Agent 主界面

MaxClaw 的部署界面

MaxClaw 模式里已经预配置了一批开箱即用的 Expert(后面细讲),包括爆款猎手、多 Agent 投研团队、热点追踪等,进去就能直接调用。

而且同样兼容飞书、钉钉、Telegram、WhatsApp、Discord、Slack 等多个终端 IM,手机端随时操控。

哦对了,MaxClaw 同样兼容 OpenClaw 原有的 Skills 体系,而且做了很多优化,选取了一些比较优质的 Skills 内置在其中。待会儿我也会给大家进行展示。

话说回 MiniMax 本身,了解模型圈的朋友应该不陌生。

今年 1 月刚在港股上市,首日股价翻倍,市值直接破千亿。到 2 月更是一路飙到突破 3000 亿港元,直接反超了一众互联网中大厂。

嗯,我港股打新中了几手...翻了三倍了,感谢MiniMax..

春节前发布的旗舰编程模型 M2.5,更是定位为全球首个 Agent 场景原生设计的生产级模型,这个团队的执行力,确实猛。

接下来,看看本次 MiniMax Agent 和 OpenClaw 都能搞出来什么样的花样。

MaxClaw 实操:直连IM、日常工作处理

还记得之前接入 Discord 有多折腾吗?

创建 Bot → 拿 Token → 配权限 → 启动 Gateway → 拿 Pairing Code → 终止服务 → 配对 → 重启..

我光写教程就写了好几百字,更别说实际操作了。

这次在 MaxClaw 里接入飞书,体验简单了很多。

这里我直接选择了 MaxClaw 的默认模式进行搭建

过一会,直接提示:

在 MaxClaw 模式中选择飞书作为接入渠道,按照提示完成几步简单的配置

这里主要还是需要去飞书获取一下授权。

配置完成后,直接在飞书里就能跟你的 Agent 对话了。

详细的步骤,他们在 MiniMax 的官网上给出了一个具体的文档。

如果大家还不了解,可以直接点击文档https://vrfi1sk8a0.feishu.cn/wiki/LIwrwZp2aipuwgkEzLycsQF5nEc查看。

一键洞察行业新闻

先看一个最简单的案例:

我希望每天早晨 8 点能接收到当天或者前一天的 AI 日报。

这时候我需要让他帮我创建,我可以直接跟他它一句话。

它会自动调用一些 web search 类的工具,获取当前的一些 AI 日报和 AI 热点。

最开始它生成的这个日报,我觉得信息源不是很全,然后我就可以接着跟它对话,去增加信息源。

它生成的内容可以直接在飞书文档中生成

当 AI 日报的交互拿到一个比较好的结果之后,我们就可以直接跟他说,让它把刚才聊的内容沉淀为一个 Skills 并在每天早晨 8 点给我们推送任务。

这样,每天早晨,都有一份 AI 日报呈现在你面前。除了这个场景,我们其实还可以把工作会议纪要,或者在飞书上处理的工作文档都交给它。

让它每天从网盘、云盘等渠道获取文档信息,并将会议纪要的内容在第二天通知到我们。

把自己的 Skills 接入到 MaxClaw 里面

因为本身它就兼容 OpenClaw 的生态,我可以把之前做过的 Skills 直接给到 MaxClaw。

操作步骤如下:

  1. 直接提供一个 Skills 的下载地址
  2. 系统会自动从我们的 Skills 里面获取相应的内容
  3. 自动完成安装

加载完了之后,我直接拿“藏师傅”的这篇文章,我直接把微信公众号的链接给到它,然后直接跟它说:把这篇文章做成一个杂志排版风格去呈现

MaxClaw 会自行调用我们的杂志排版风格skill,对这篇内容进行呈现,而且可以直接输出 HTML 文件给我们。

直接给到下载地址,打开即是

当我们打开这个文件的时候,就能看到一篇文章直接被转成了我们期望的排版格式,我选择的风格是“大胆社论风格”的这种风格。

文章太长,抽样截图了

除了默认的 MaxClaw,还可以直接在我们的部署界面里面选择,比如「行业研报」或者「热点追踪」等等expert跟OpenClaw 结合使用。

好了,MaxClaw 体验聊完了。接下来聊聊 MiniMax Agent 更新的另外一个东西,Expert 专家系统

Expert 专家智能体:比 Skills 更进一步

玩过 OpenClaw 的都知道,Skills 是 Agent 的灵魂,你给它装什么技能,它就能干什么活。

之前文章我们玩过「搜索 + 智能 PPT 生成 + 学术检索」的 Skills 组合拳,效果确实不错。

但有个问题:单个 Skill 只是工具,你还得自己组合、自己写 prompt、自己调 SOP。

这就像是给你一堆零件,你得自己组装成一台机器。对于会折腾的人来说没问题,但对大部分人来说,「怎么组合」本身就是个门槛。

MiniMax 的 Expert(专家智能体)就是来解决这个问题的。

Expert = 专家角色 + SOP 流程 + 私有知识 + 工具集,打包成一整套解决方案。

你可以直接在社区里面选用 Expert、也可以自然语言搭建,或者自己直接封装私有知识到 Expert里面去打造自己的 Expert,

听起来不错?来看看实际效果。

实测:股票价值分析 Expert

第一个场景选了股票价值分析

选这个是因为之前文章篇里我们也做过"金融行情秒解读"的场景,但那次需要自己部署 OpenClaw + 配 Skills,整个过程挺折腾的。这次直接打开 Expert 就用,正好对比一下。

进入 Expert 的方式很简单,在 MiniMax Agent 的 Expert 社区里搜索「股票价值分析」,点进去就能直接开始对话。

我们打开这个股票价值分析,输入我的一只持仓股CPO牌面,会发现它是从 11 个维度进行分析的,拉了一套完整的分析框架。

在这里边,我们可以看到它能从很多方面,帮我们找出来想要分析的这家公司的一些基本情况,并最终给出一个投资建议。

【插入股票GIF】

我看了一下给出来的这个建议。

总体来说,它能让我们快速对这家公司有一个大体的了解,但是真正的投资建议这一块,我觉得大家还是看看就好,仅供参考,毕竟市场情绪这个东西...

关于这个详细内容,可看:
https://agent.minimaxi.com/share/370879641948816?chat_type=2

这就是 Expert 跟普通 Chat 的差距,按照预设好的 SOP 一步步走完整个分析流程。哪怕你只说了一句"帮我分析下 XXX",它也会按标准流程交付一份结构化的报告。

友情提示:投资有风险,AI 分析报告仅供参考,不构成投资建议。

实测:AI 短剧导演+摄影+剪辑师 Expert

第二个场景换个画风,AI 短剧导演+摄影+剪辑师

点击项目指令旁边的感叹号,其实能够看出来它整体的设计逻辑。

这个 Expert 的定位是帮你从 0 到 1 完成一个短剧的创作方案,包含剧本、分镜、拍摄建议和剪辑方案。

我给它抛了一个创作需求:

随便找了个剧本:豪门赘婿竟是...

接下来它的工作方式就很有意思了,

第一步:视觉风格
让我们选择一种视觉风格,如上图所示,然后列了场景清单。

第二步:人物与场景参考图

给出主人公和相对应的画风,待我们确认。

第三步:分镜脚本设计

基于剧本拆出详细的分镜脚本,标注景别、机位、运镜方式。

第四步:制作
之后就是首帧生成师、视频生成师、后期合成师等等,直到最后出视频。

来看看最后的效果:

【插入视频】

目前的版本,随便给个比较随意的 Prompt, 之后让模型自由发挥,有一些旁白TTS的瑕疵但整体效果还不错。

这就是 Expert 的 SOP 优势,它内部封装了"短剧创作"这个场景的标准化流程,每一步该产出什么、格式是什么、需要考虑哪些要素,全都定义好了。

相比之下,你直接跟普通 AI 说"帮我写个短剧剧本",它多半只会给你一段剧本文字,不会主动帮你拆分镜、想拍摄方案。

社区里面还有很多有意思的 Expert,大家感兴趣的可以试试~

动手:创建属于自己的 Expert

用完别人的 Expert,是不是手痒了?

自己建一个试试。

MiniMax 的 Expert 创建流程门槛很低的,不需要配置 tool,不需要写规则,直接用大白话描述就行。

比如我想让他直接生成一个儿童绘本视频的 Expert:

整个过程就像跟一个产品经理聊天——你告诉它"我想要一个什么样的专家"、"它的工作流程是什么"、"它需要具备什么知识",它就帮你把 Expert 搭好了。

自然语言交互

创建完成后,直接就能用。

https://agent.minimaxi.com/share/370902377529918?chat_type=2

来看看最终效果:

【插入视频】

当然,我这个制作的有点仓促,还有值得优化的地方,后续再迭代一版。

而且创建 Expert 有 15 轮免费额度,足够你试几个不同方向了。

创建好的 Expert 可以自己私用,也可以分享到社区,一旦公开,其他人每 Copy 一次,你就能获得 100 积分。

从"用别人的"到"自己建"再到"分享给别人",这个体验闭环是完整的。

MiniMax Agent 的 UGC 社区生态,做的还是很不错的,而且 即将上线 Marketplace,到时候创建者可以为自己的 Expert 公开定价

这意味着什么?创建 Expert 本身会成为一门生意。

还有一个很多朋友关注的费用的问题,它是按照积分消耗制来计算的。

  1. 免费版:每天都会提供一些免费积分。
  2. 付费版:基础版会员就可以体验MaxClaw尝鲜,39元的价格量大管饱,比较实惠。

按需选择,另外提一嘴,MiniMax Agent 也有海外版agent.minimax.io),海外的 Expert 也挺丰富的,有需要的朋友可以自行探索。

结语

这两天看了藏师傅这篇文章「」,简单说下最近的体感吧:

1、其实现在我是有点焦虑的,而且不只是我,身边这波AI弄潮儿朋友们很多都开始焦虑了,只有当你深入其中,理解了Agent 体系,你才能发现这个变化到底意味着什么。(AI发展的速度真的很快…快到AI KOL们都追不上)范式转移深度和速度远超想象

2、在这个时代,「知道做什么」和「什么值得做」越来越重要

3、之前一直在想AI平权,AI平权…现在才悲哀地发现AI从来不会平权,它只会越来越往资源最集中的‬人or团队中去,一种“认知-资源”双重马太效应

未来最重要的生产力单元和认知主体,可能不再是“个人”,而是“个人+其Agent团队”构成的复合智能形态。

或许,社会将基于个体和系统适应AI变革的速度,分裂成不同的“时间阶层”。

现在,如果有关于Agent体系的入口,不妨去:

找到它,用起来。

以上。


我是甲木,热衷于分享一些AI干货内容,同时也会分享AI在各行业的落地应用,我们下期再见

本文由mdnice多平台发布

当您满心期待地打开自己的网站,却看到浏览器地址栏那个醒目的红色“不安全”警告时,想必心情瞬间跌入谷底。更糟糕的是,这个警告正在悄无声息地赶走您的潜在客户。

别担心,今天这篇文章就为您详细梳理:网站提示“不安全”的常见原因是什么?如何一步步解决?

第一步:对症下药——四种常见问题的解决方案

1、未安装SSL证书

如果确认您的网站根本没有SSL证书,解决方案最简单:立即申请并安装SSL证书

对于个人博客、小型展示网站,可以选择免费SSL证书;对于企业官网、电商平台,建议选择付费OV或EV证书,提供更高级别的身份验证和用户信任。

2、SSL证书过期或无效

证书过期是最常见的问题之一,往往出现在长期无人维护的网站上。

解决方案

  • 若证书过期,登录证书平台找到过期证书,点击“续期”,完成域名验证后重新安装
  • 若使用自签名证书,浏览器默认不信任,需废弃并重新申请正规证书

3、域名与证书不匹配

如果您为www.example.com申请了证书,但用户访问的是example.com,就会触发此警告。

解决方案

  • 检查证书绑定的域名是否与访问域名一致
  • 若需支持多个子域名,可将单域名证书升级为通配符证书(如*.example.com

第二步: 通过JoySSL解决“不安全”问题的实操步骤

免费SSL证书申请入口

1、 注册JoySSL账号

访问JoySSL官方网站,点击“注册”创建新账户。**在注册过程中填写注册码 230970,可确保享受永久免费SSL证书及相关技术支持。

2、 选择证书类型

登录后,在SSL证书页面找到“免费体验版”,选择适合您的证书类型:

  • 单域名证书:保护单个域名
  • 通配符证书:保护一个域名及其所有子域名(强烈推荐有子域名的网站)
  • 多域名证书:保护多个不同域名

3、验证域名所有权

按照提示完成域名验证,通常是通过在域名DNS设置中添加特定的TXT记录,这一过程一般几分钟内即可完成审核。

4、下载与安装证书

验证成功后,从JoySSL平台下载证书文件。根据您的服务器环境(如Nginx、Apache、IIS等),参照官方文档进行配置和部署。

5、 设置强制HTTPS跳转

在服务器配置中添加重写规则,将所有HTTP流量强制重定向到HTTPS。

本期让我们来了解下云流管理平台中【服务器管理】和【用户管理】的具体功能吧!

一、服务器管理

当实时云渲染用户并发量很大,或分布在不同地区或国家时,为给用户更好的实时渲染体验,点量云流系统支持动态扩容,可设置不同国家或地区的机房区域,每个区域下支持多台服务器自动负载调度,以保证每个用户都有更好的使用体验。

【01机房区域】

1、页面汇总当前已创建的机房区域,可进行编辑、删除等操作。不同机房区域用于负载均衡、测速时使用。
2、一般用户访问某个云流化的内容,会先从多个机房进行测速,选一个最近的机房使用,因此请正确填写机房区域。

3、点击“创建机房区域”按钮可创建新的机房区域,在服务器列表页面可对服务器所属的区域进行编辑。

【02服务器列表】

页面对已有服务器进行汇总,展示了服务器的名称、地址、渲染服务版本、机房区域、上架状态、在线状态、网页端口、渲染管理端口、创建时间等信息。
支持通过服务器名称、上架状态等字段对服务器进行搜索,用户可以对服务器进行编辑、删除、下架、查看资源使用等操作。

若想要创建服务器,有以下两种方式:
方法一:自动加入(推荐)
安装点量云流渲染服务,并填写授权地址提交认证,该服务器自动加入组织,由平台统一管理。

方法二:手动添加
1、在【服务器列表】页面,点击“创建服务器”按钮,打开创建弹窗,输入服务器基本信息。

  • 服务器名称:自定义服务器名称
  • 服务器地址:服务器IP地址
  • 局域网IP地址:服务器所在局域网IP地址,可用于服务器与CMS管理端在局域网内通信
  • 物理地址:服务器的MAC地址
  • CPU最大使用率:CPU超过该设置限制将会启动新流路,默认为0,0代表不限制
  • GPU最大使用率:GPU超过该设置限制将会启动新流路,默认为0,0代表不限制
  • 机房区域:服务器所属的机房区域
  • 服务器信息:对服务器的备注信息

2、除填写服务器基本信息之外,也可在高级设置中对服务器相关端口参数进行细节修改。如果没有特殊需求,保持默认值即可。

  • 守护进程服务端口号:渲染服务和管理平台后台通信端口(TCP)
  • web服务端口号:Web服务端口(TCP)
  • 流路起始端口号:当前服务器的流路从哪个端口号开始使用
  • 会话连接端口号:设置rdp服务的端口号

3、信息填写完成之后点击“确定”即可保存成功。

【03服务器预警设置】

为了帮助用户更好地监测服务器状态、及时了解实时渲染系统服务器和显卡等硬件资源的使用情况并预防突发故障,点量云流管理平台提供了[服务器预警设置]与[服务器预警记录】功能。
页面对已有预警规则进行汇总,展示了预警规则的名称、状态、CPU预警值、GPU预警值、内存预警值、磁盘预警值、预警沉默间隔等信息。支持通过名称、状态对预警规则进行搜索,用户可以对预警规则进行禁用、编辑、删除等操作。

若想创建预警规则:
1、点击“添加预警规则”按钮,打开创建窗口。
2、设置规则名称、CPU预警值、GPU预警值、内存预警值、磁盘预警值、预警沉默间隔,磁盘预警值将在服务器的任一磁盘满足条件即触发报警,预警值设置为0代表当前指标不设置预警,预警沉默间隔指的一定时间段内连续触发预警条件不重复生成预警记录。

3、点击“确定”即可保存成功,预警规则创建总数不可超过10条。

【04服务器预警记录】

1、页面对服务器预警记录进行汇总,支持通过规则名称、所属机器、指标类型、报警时间等字段进行搜索。
2、列表展示了预警记录所对应的规则名称、服务器名称、报警信息、报警时间,用户可以对预警规则进行删除操作。

二、用户管理

为保证特定用户随时可访问实时云渲染网页,点量云流系统支持用户管理,可在这里实现对特定用户账号、允许访问云应用的管理。

该页面对已有用户进行汇总,展示了用户的账号、姓名、授权应用、状态等信息,支持通过账号、状态对用户进行搜索,可以对用户进行禁用、编辑、删除等操作。

若想创建用户:
1、点击“创建用户”按钮,打开创建弹窗。输入用户信息,创建用户登录的账号和密码,填写姓名及备注。基本信息填写完成之后,选择该用户可查看的云应用,支持多选。选择完成之后,点击“保存”即可保存成功。

2、复制或者直接打开“用户登录链接”,终端用户可通过设置的账号、密码进行登录。

3、用户登录成功之后即可查看所属的云应用,点击即可直接打开。

注意:

  • 禁用:用户禁用之后,该账号状态变为“禁用”状态,账号可登录,但是无法打开个人中心中的云应用。
  • 编辑:参考“创建用户”的步骤,可以对用户的详细信息进行修改。
  • 删除:删除该用户,账号无法再登录

注册即送 5 刀,邀请再送 5 刀,有点虚假了,是送 1 刀,实际上 0.2 倍率,可以达到官网 5 刀的效果

  • 为什么选我们家?多种渠道混合选择,富哥用 ccmax ,小老弟用 kiro ,由于中转经常抽风,不耽误大家工作,我们接入了多个 kiro 跟 ccmax 供大家选择
  • 极致的低价,kiro 渠道 0.2 倍率,套餐 ccmax 渠道低至 8 毛,基本上在赔本卖
  • 近期我们在考虑组建 ccmax 4-5 人小车队的事宜,欢迎老哥们加入详聊

https://terminal.pub

注册后留下自己的 id 进行抽奖

下周 5 ,上证指数 hash 取模,让 gemini 抽 5 个套餐

欢迎加入我们的 tg 跟微信,交流 vibecoding 创业想法

tg:

https://t.me/+4D5U2msTRshkZmFl

wechat:

概述

Condition 是一个多线程协调通信的工具类,可以让某些线程一起等待某个条件(condition),只有满足条件时,线程才会被唤醒。

  • 在使用Lock之前,使用的最多的同步方式应该是synchronized关键字来实现同步方式了。配合Object的wait()、notify()系列方法可以实现等待/通知模式。
  • Condition接口也提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式,但是这两者在使用方式以及功能特性上还是有差别的。

Object和Condition接口的一些对比。

对比项Object 监视器方法Condition
前置条件获取对象的监视器锁调用 Lock.lock() 获取锁调用 Lock.newCondition() 获取 Condition 对象
调用方法直接调用如:object.wait()直接调用如:condition.await()
等待队列个数一个多个
当前线程释放锁并进入等待队列支持支持
当前线程释放锁并进入等待队列,在等待状态中不响应中断不支持支持
当前线程释放锁并进入超时等待状态支持支持
当前线程释放锁并进入等待状态到将来的某个时间不支持支持
唤醒等待队列中的一个线程支持支持
唤醒等待队列中的全部线程支持支持

接口的介绍与示例

首先需要明白condition对象是依赖于lock对象的,意思就是说condition对象需要通过lock对象进行创建出来(调用Lock对象的newCondition()方法)。condition的使用方式非常的简单。但是需要注意在调用方法前获取锁。

/**
 * condition使用示例:
 * 1、condition的使用必须要配合锁使用,调用方法时必须要获取锁
 * 2、condition的创建依赖于Lock lock.newCondition();
 */
public class ConditionUseCase {
    /**
     * 创建锁
     */
    public Lock readLock = new ReentrantLock();
    /**
     * 创建条件
     */
    public Condition condition = readLock.newCondition();

    public static void main(String[] args) {
        ConditionUseCase useCase = new ConditionUseCase();
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.execute(() -> {
            //获取锁进行等待
            useCase.conditionWait();
        });
        executorService.execute(() -> {
            //获取锁进行唤起读锁
            useCase.conditionSignal();
        });
    }

    /**
     * 等待线程
     */
    public void conditionWait() {
        readLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "拿到锁了");
            System.out.println(Thread.currentThread().getName() + "等待信号");
            condition.await();
            System.out.println(Thread.currentThread().getName() + "拿到信号");
        } catch (Exception e) {

        } finally {
            readLock.unlock();
        }
    }

    /**
     * 唤起线程
     */
    public void conditionSignal() {
        readLock.lock();
        try {
            //睡眠5s 线程1启动
            Thread.sleep(5000);
            System.out.println(Thread.currentThread().getName() + "拿到锁了");
            condition.signal();
            System.out.println(Thread.currentThread().getName() + "发出信号");
        } catch (Exception e) {

        } finally {
            //释放锁
            readLock.unlock();
        }
    }

}

//执行结果
1 pool-1-thread-1拿到锁了
 2 pool-1-thread-1等待信号 ---释放锁-线程等待 t1
 3 pool-1-thread-2拿到锁了
 4 pool-1-thread-2发出信号 --- 唤起线程t2释放锁
 5 pool-1-thread-1拿到信号---t1继续执行

如示例所示,一般都会将Condition对象作为成员变量。当调用await()方法后,当前线程会释放锁并在此等待,而其他线程调用Condition对象的signal()方法,通知当前线程后,当前线程才从await()方法返回,并且在返回前已经获取了锁。

接口常用方法

condition可以通俗的理解为条件队列。当一个线程在调用了await方法以后,直到线程等待的某个条件为真的时候才会被唤醒。这种方式为线程提供了更加简单的等待/通知模式。Condition必须要配合锁一起使用,因为对共享状态变量的访问发生在多线程环境下。一个Condition的实例必须与一个Lock绑定,因此Condition一般都是作为Lock的内部实现。

  1. await() :造成当前线程在接到信号或被中断之前一直处于等待状态。
  2. boolean await(long time, TimeUnit unit) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态---》是否超时,超时异常
  3. awaitNanos(long nanosTimeout) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。返回值表示剩余时间,如果在nanosTimesout之前唤醒,那么返回值 = nanosTimeout - 消耗时间,如果返回值 <= 0 ,则可以认定它已经超时了。
  4. awaitUninterruptibly() :造成当前线程在接到信号之前一直处于等待状态。【注意:该方法对中断不敏感】。
  5. awaitUntil(Date deadline) :造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。如果没有到指定时间就被通知,则返回true,否则表示到了指定时间,返回返回false。
  6. signal() :唤醒一个等待线程。该线程从等待方法返回前必须获得与Condition相关的锁。
  7. signalAll() :唤醒所有等待线程。能够从等待方法返回的线程必须获得与Condition相关的锁。

这里顺便回顾一下 Object 类的主要方法:

  1. wait():线程等待直到被通知或者中断。
  2. wait(long timeout):线程等待指定的时间,或被通知,或被中断。
  3. wait(long timeout, int nanos):线程等待指定的时间,或被通知,或被中断。
  4. notify():唤醒一个等待的线程。
  5. notifyAll():唤醒所有等待的线程。

原理解析

Condition是AQS的内部类。可以通过 Lock.newCondition() 方法获取 Condition 对象,而 Lock 对于同步状态的实现都是通过内部的自定义同步器实现的,newCondition() 方法也不例外,所以,Condition 接口的唯一实现类是同步器 AQS 的内部类 ConditionObject,因为 Condition 的操作需要获取相关的锁,所以作为同步器的内部类也比较合理,该类定义如下:

public class ConditionObject implements Condition, java.io.Serializable

等待队列

前面我们学过,AQS 内部维护了一个先进先出(FIFO)的双端队列,并使用了两个引用 head 和 tail 用于标识队列的头部和尾部。

Condition 内部也使用了同样的方式,内部维护了一个先进先出(FIFO)的单向队列,我们把它称为等待队列。该队列是 Condition 对象实现等待 / 通知功能的关键。等待队列是一个FIFO的队列,在队列中的每个节点都包含了一个线程引用,该线程就是在Condition对象上等待的线程,如果一个线程调用了Condition.await()方法,那么该线程将会释放锁、构造成节点加入等待队列并进入等待状态。

事实上,节点的定义复用了 AQS 中 Node 节点的定义,也就是说,同步队列和等待队列中节点类型都是 AQS 的静态内部类 AbstractQueuedSynchronized.Node。一个 Condition 包含一个等待队列,Condition 拥有首节点(firstWaiter)和尾节点(lastWaiter)。当前线程调用 Condition.await() 方法之后,将会以当前线程构造节点,并将节点从尾部加入等待队列,等待队列的基本结构如下所示。

  • 等待队列分为首节点和尾节点。当一个线程调用Condition.await()方法,将会以当前线程构造节点,并将节点从尾部加入等待队列。
  • 新增节点就是将尾部节点指向新增的节点。节点引用更新本来就是在获取锁以后的操作,所以不需要CAS保证。同时也是线程安全的操作。
public class ConditionObject implements Condition, java.io.Serializable {
    private static final long serialVersionUID = 1173984872572414699L;
    /** First node of condition queue. */
    private transient Node firstWaiter;
    /** Last node of condition queue. */
    private transient Node lastWaiter;
}

在 Object 的监视器模型上,一个对象拥有一个同步队列和等待队列,而并发包中的 Lock(更确切地说是同步器)拥有一个同步队列和多个等待队列

等待 await 方法

  • 当线程调用了await方法以后。线程就作为队列中的一个节点被加入到等待队列中去了。同时会释放锁的拥有。
  • 当从await方法返回的时候。一定会获取condition相关联的锁。当等待队列中的节点被唤醒的时候,则唤醒节点的线程开始尝试获取同步状态。

    • 如果不是通过 其他线程调用Condition.signal()方法唤醒,而是对等待线程进行中断,则会抛出InterruptedException异常信息。
    • 通知调用Condition的signal()方法,将会唤醒在等待队列中等待最长时间的节点(条件队列里的首节点),在唤醒节点前,会将节点移到同步队列中。

当前线程加入到等待队列中如图所示:

源码如下:

public final void await() throws InterruptedException {
    // 检测线程中断状态
    if (Thread.interrupted())
        throw new InterruptedException();
    // 将当前线程包装为Node节点加入等待队列
    Node node = addConditionWaiter();
    // 释放同步状态,也就是释放锁
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    // 检测该节点是否在同步队中,如果不在,则说明该线程还不具备竞争锁的资格,则继续等待
    while (!isOnSyncQueue(node)) {
        // 挂起线程
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    // 竞争同步状态
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    // 清理条件队列中的不是在等待条件的节点
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

调用该方法的线程是成功获取了锁的线程,也就是同步队列中的首节点,该方法会将当前线程构造节点并加入等待队列中,然后释放同步状态,唤醒同步队列中的后继节点,然后当前线程会进入等待状态。

可能会有这样几个问题:

  1. 怎样将当前线程添加到等待队列中?
  2. 释放锁的过程是?
  3. 怎样才能从 await 方法中退出?

问题1:怎样将当前线程添加到等待队列中?

调用 addConditionWaiter 方法会将当前线程添加到等待队列中,源码如下:

private Node addConditionWaiter() {
    // 尾节点
    Node t = lastWaiter;
    // 尾节点如果不是CONDITION状态,则表示该节点不处于等待状态,需要清理节点
    if (t != null && t.waitStatus != Node.CONDITION) {
        unlinkCancelledWaiters();
        t = lastWaiter;
    }
    // 根据当前线程创建Node节点
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    // 将该节点加入等待队列的末尾
    if (t == null)
        firstWaiter = node;
    else
        t.nextWaiter = node;
    lastWaiter = node;
    return node;
}

首先将 t 指向尾节点,如果尾节点不为空并且它的waitStatus!=-2(-2 为 CONDITION,表示正在等待 Condition 条件),则将不处于等待状态的节点从等待队列中移除,并且将 t 指向新的尾节点。

然后将当前线程封装成 waitStatus 为-2 的节点追加到等待队列尾部。

如果尾节点为空,则表明队列为空,将首尾节点都指向当前节点。

img

如果尾节点不为空,表明队列中有其他节点,则将当前尾节点的 nextWaiter 指向当前节点,将当前节点置为尾节点。

img

简单总结一下,这段代码的作用就是通过尾插入的方式将当前线程封装的 Node 插入到等待队列中,同时可以看出,Condtion 的等待队列是一个不带头节点的链式队列,之前我们学习 AQS 时知道同步队列是一个带头节点的链式队列,这是两者的一个区别。

关于头节点的作用,我们这里简单说明一下。

不带头节点是指在链表数据结构中,链表的第一个节点就是实际存储的第一个数据元素,而不是一个特定的"头"节点,该节点不包含实际的数据。

1)不带头节点的链表:

  • 链表的第一个节点就是第一个实际的数据节点。
  • 当链表为空时,头引用(通常称为 head)指向 null。

2)带头节点的链表:

  • 链表有一个特殊的节点作为链表的开头,这个特殊的节点称为头节点。
  • 头节点通常不存储任何实际数据,或者它的数据字段不被使用。
  • 无论链表是否为空,头节点总是存在的。当链表为空时,头节点的下一个节点指向 null。
  • 使用头节点可以简化某些链表操作,因为你不必特殊处理第一个元素的插入和删除。

为了更好地解释这两种链表结构,我将为每种结构提供一个简单的整数链表插入方法的示例。

1)不带头节点的链表

public class Node {
    public int data;
    public Node next;

    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}

public class LinkedListWithoutHead {
    public Node head;

    public void insert(int value) {
        Node newNode = new Node(value);
        if (head == null) {
            head = newNode;
        } else {
            Node temp = head;
            while (temp.next != null) {
                temp = temp.next;
            }
            temp.next = newNode;
        }
    }
}

2)带头节点的链表

public class NodeWithHead {
    public int data;
    public NodeWithHead next;

    public NodeWithHead(int data) {
        this.data = data;
        this.next = null;
    }
}

public class LinkedListWithHead {
    private NodeWithHead head;

    public LinkedListWithHead() {
        head = new NodeWithHead(-1);  // 初始化头节点
    }

    public void insert(int value) {
        NodeWithHead newNode = new NodeWithHead(value);
        NodeWithHead temp = head;
        while (temp.next != null) {
            temp = temp.next;
        }
        temp.next = newNode;
    }
}

这下是不是就彻底明白了?说明白了头节点,我们再回到 Condition 的 await 方法。

问题 2:释放锁的过程是?

将当前线程加入到等待队列之后,需要释放同步状态,该操作通过 fullyRelease(Node) 方法来完成:

final int fullyRelease(Node node) {
    boolean failed = true;
    try {
        // 获取同步状态
        int savedState = getState();
        // 释放锁
        if (release(savedState)) {
            failed = false;
            return savedState;
        } else {
            throw new IllegalMonitorStateException();
        }
    } finally {
        if (failed)
            node.waitStatus = Node.CANCELLED;
    }
}

这段代码也很容易理解,调用 AQS 的模板方法 release 释放 AQS 的同步状态并且唤醒在同步队列中头节点的后继节点引用的线程,如果释放成功则正常返回,若失败的话就抛出异常。

问题3:怎样才能从 await 方法中退出?

怎样从 await 方法退出呢?现在回过头再来看 await 方法,其中有这样一段逻辑:

while (!isOnSyncQueue(node)) {
    // 3. 当前线程进入到等待状态
    LockSupport.park(this);
    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
        break;
}

isOnSyncQueue 方法用于判断当前线程所在的 Node 是否在同步队列中:

final boolean isOnSyncQueue(Node node) {
    // 节点状态为CONDITION,或者前驱节点为null,返回false
    if (node.waitStatus == Node.CONDITION || node.prev == null)
        return false;
    // 后继节点不为null,那么肯定在同步队列中
    if (node.next != null) // If has successor, it must be on queue
        return true;
    
    return findNodeFromTail(node);
}

如果当前节点的 waitStatus=-2,说明它在等待队列中,返回 false;如果当前节点有前驱节点,则证明它在 AQS 队列中,但是前驱节点为空,说明它是头节点,而头节点是不参与锁竞争的,也返回 false。

如果当前节点既不在等待队列中,又不是 AQS 中的头节点且存在 next 节点,说明它存在于 AQS 中,直接返回 true。

这里有必要给大家看一下同步队列与等待队列的关系图了。

img

当线程第一次调用 condition.await 方法时,会进入到这个 while 循环,然后通过 LockSupport.park(this) 使当前线程进入等待状态,那么要想退出 await,第一个前提条件就是要先退出这个 while 循环,出口就只两个地方:

  1. 走到 break 退出 while 循环;
  2. while 循环中的逻辑判断为 false。

出现第 1 种情况的条件是,当前等待的线程被中断后代码会走到 break 退出,第 2 种情况是当前节点被移动到了同步队列中(即另外一个线程调用了 condition 的 signal 或者 signalAll 方法),while 中逻辑判断为 false 后结束 while 循环。

总结一下,退出 await 方法的前提条件是当前线程被中断或者调用 condition.signal 或者 condition.signalAll 使当前节点移动到同步队列后

当退出 while 循环后会调用acquireQueued(node, savedState),该方法的作用是在自旋过程中线程不断尝试获取同步状态,直到成功(线程获取到 lock)。这样也说明了退出 await 方法必须是已经获得了 condition 引用(关联)的 lock

到目前为止,上文提到的三个问题,我们都通过阅读源码的方式找到了答案,也加深了对 await 方法的理解。await 方法示意图如下:

await方法示意图

如图,调用 condition.await 方法的线程必须是已经获得了 lock 的线程,也就是当前线程是同步队列中的头节点。调用该方法后会使得当前线程所封装的 Node 尾插入到等待队列中。

超时机制的支持

condition 还额外支持超时机制,使用者可调用 awaitNanos、awaitUtil 这两个方法,实现原理基本上与 AQS 中的 tryAcquire 方法如出一辙。

不响应中断的支持

要想不响应中断可以调用 condition.awaitUninterruptibly() 方法,该方法的源码如下:

public final void awaitUninterruptibly() {
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node);
    boolean interrupted = false;
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if (Thread.interrupted())
            interrupted = true;
    }
    if (acquireQueued(node, savedState) || interrupted)
        selfInterrupt();
}

这段方法与上面的 await 方法基本一致,只不过减少了对中断的处理。

通知-signal/signalAll 实现原理

调用 condition 的 signal 或者 signalAll 方法可以将等待队列中等待时间最长的节点移动到同步队列中,使得该节点能够有机会获得 lock。等待队列是先进先出(FIFO)的,所以等待队列的头节点必然会是等待时间最长的节点,也就是每次调用 condition 的 signal 方法都会将头节点移动到同步队列中。

在调用signal()方法之前必须先判断是否获取到了锁。接着获取等待队列的首节点,将其移动到同步队列并且利用LockSupport唤醒节点中的线程。节点从等待队列移动到同步队列如下图所示:

被唤醒的线程将从await方法中的while循环中退出。随后加入到同步状态的竞争当中去。成功获取到竞争的线程则会返回到await方法之前的状态。

源码如下:

调用 Condition 的 signal() 方法,将会唤醒在等待队列中等待时间最长的节点(首节点),在唤醒节点之前,会将节点移到同步队列中。Condition 的 signal() 方法如下所示:

public final void signal() {
    // 判断是否是当前线程获取了锁
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    // 唤醒等待队列的首节点
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);
}

该方法最终调用 doSignal(Node) 方法来唤醒节点:

private void doSignal(Node first) {
    do {
        // 把等待队列的首节点移除之后,要修改首结点
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&
                (first = firstWaiter) != null);
}

真正对头节点做处理的逻辑,将节点移动到同步队列是通过 transferForSignal(Node) 方法完成的:

final boolean transferForSignal(Node node) {
    // 尝试将该节点的状态从CONDITION修改为0
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false;
    
    // 将节点加入到同步队列尾部,返回该节点的前驱节点
    Node p = enq(node);
    int ws = p.waitStatus;
    // 如果前驱节点的状态为CANCEL或者修改waitStatus失败,则直接唤醒当前线程
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        LockSupport.unpark(node.thread);
    return true;
}

这段代码主要做了两件事情:

  1. 将头节点的状态更改为 CONDITION;
  2. 调用 enq 方法,将该节点尾插入到同步队列中,关于 enq 方法请看 AQS 的底层实现这篇文章

节点从等待队列移动到同步队列的过程如下图所示:

被唤醒后的线程,将从 await() 方法中的 while 循环中退出(因为此时 isOnSyncQueue(Node) 方法返回 true),进而调用 acquireQueued() 方法加入到获取同步状态的竞争中。

成功获取了锁之后,被唤醒的线程将从先前调用的 await() 方法返回,此时,该线程已经成功获取了锁。

signalAll()

sigllAll 与 sigal 方法的区别体现在 doSignalAll 方法上,前面我们已经知道 doSignal 方法只会对等待队列的头节点进行操作, signalAll() 方法相当于对等待队列的每个节点均执行一次 signal() 方法,效果就是将等待队列中的所有节点移动到同步队列中。doSignalAll 的源码如下:

private void doSignalAll(Node first) {
    lastWaiter = firstWaiter = null;
    do {
        Node next = first.nextWaiter;
        first.nextWaiter = null;
        transferForSignal(first);
        first = next;
    } while (first != null);
}

该方法会将等待队列中的每一个节点都移入到同步队列中,即“通知”当前调用 condition.await() 方法的每一个线程。

await 与 signal/signalAll

文章开篇提到的等待/通知机制,通过 condition 的 await 和 signal/signalAll 方法就可以实现,而这种机制能够解决最经典的问题就是“生产者与消费者问题

await、signal 和 signalAll 方法就像一个开关,控制着线程 A(等待方)和线程 B(通知方)。它们之间的关系可以用下面这幅图来说明,会更贴切:

线程 awaitThread 先通过 lock.lock() 方法获取锁,成功后调用 condition.await 方法进入等待队列,而另一个线程 signalThread 通过 lock.lock() 方法获取锁成功后调用了 condition.signal 或者 signalAll 方法,使得线程 awaitThread 能够有机会移入到同步队列中,当其他线程释放 lock 后使得线程 awaitThread 能够有机会获取 lock,从而使得线程 awaitThread 能够从 await 方法中退出并执行后续操作。如果 awaitThread 获取 lock 失败会直接进入到同步队列。

总结

  • 调用await方法后,将当前线程加入Condition等待队列中。当前线程释放锁。否则别的线程就无法拿到锁而发生死锁。自旋(while)挂起,不断检测节点是否在同步队列中了,如果是则尝试获取锁,否则挂起。
  • 当线程被signal方法唤醒,被唤醒的线程将从await()方法中的while循环中退出来,然后调用acquireQueued()方法竞争同步状态。