纯情 发布的文章

📰 今日新闻精选:

  • 交通运输部:“五一” 假期高速日均车流量约为 6400 万辆,5 月 1 日预计达 7000 万辆创历史新高
  • 气象预测 “五一” 假期及节后将有两轮大范围降雨来袭,两部门部署防汛减灾工作
  • 上海文旅局:即日起上海居民可赴金门、马祖旅游;上海将建世界最高无轴摩天轮 “上海之门”,预计年底开工
  • 北京:5 月 1 日起全域禁飞禁售无人机,禁止运输、携带无人机进京,大疆在京门店已下架相关产品
  • 北京市电动自行车登记新规发布:十年有效期满后可申请延期一年,5 月 1 日起正式实施
  • 民政部:截至 3 月底,全国城市低保平均标准每人每月 835 元,农村低保平均标准每人每月 623 元
  • 六大行一季度成绩揭晓:营收、归母净利润双双增长,合计净利 3569.36 亿元,日均赚超 39.6 亿元
  • 深圳再松绑楼市限购:深户家庭核心区可购 3 套,社保满 1 年非深户可购 2 套,公积金贷款额度最高提至 351 万
  • 广西一制糖公司带薪放假 94 天,从五一休息到八月初引关注,网友调侃:还能投简历吗
  • 我国矿产资源家底公布:稀土、钨、锡等 14 种矿产储量居世界第一,煤炭、钒、钛等 17 种矿产产量居世界第一
  • 美媒:美国出台新规,拒绝向害怕回国的人发放旅行签证;美国将发行印有特朗普肖像的护照,纪念建国 250 周年
  • 美媒:美国防部正式申请更名为 “战争部”,预计相关调整成本将超过 5000 万美元
  • 泰媒:泰国前总理他信获准于 5 月 11 日假释出狱,免戴电子监控手环
  • 俄媒:佩斯科夫称军事装备方阵不参加今年 5 月 9 日红场阅兵;俄罗斯没有退出欧佩克 + 的计划
  • 美媒:特朗普称美国准备长期封锁伊朗,禁止本国个人或实体向伊朗缴纳霍尔木兹海峡通行费;伊朗官员称将以前所未有的军事行动回应美国海盗行为

📅 今日信息:

  • 公历:2026-04-30 星期四 金牛座
  • 农历:二〇二六年三月十四
  • 公历纪念日:全国交通安全反思日
  • 下一节气:2026-05-05,立夏
  • 今年进度:32.88%(已过 120 天,剩余 244 天)

🌟 历史上的今天

  • 1789 年,乔治·华盛顿在纽约联邦大厅宣誓就任美国第一任总统,当时他紧张到手抖,差点念错誓词。
  • 1905 年,爱因斯坦发表《论动体的电动力学》,提出狭义相对论,但他自己后来承认:那个“追光”思想实验其实是他 16 岁做的白日梦。

📰 今日新闻精选:

  • 交通运输部:“五一” 假期高速日均车流量约为 6400 万辆,5 月 1 日预计达 7000 万辆创历史新高
  • 气象预测 “五一” 假期及节后将有两轮大范围降雨来袭,两部门部署防汛减灾工作
  • 上海文旅局:即日起上海居民可赴金门、马祖旅游;上海将建世界最高无轴摩天轮 “上海之门”,预计年底开工
  • 北京:5 月 1 日起全域禁飞禁售无人机,禁止运输、携带无人机进京,大疆在京门店已下架相关产品
  • 北京市电动自行车登记新规发布:十年有效期满后可申请延期一年,5 月 1 日起正式实施
  • 民政部:截至 3 月底,全国城市低保平均标准每人每月 835 元,农村低保平均标准每人每月 623 元
  • 六大行一季度成绩揭晓:营收、归母净利润双双增长,合计净利 3569.36 亿元,日均赚超 39.6 亿元
  • 深圳再松绑楼市限购:深户家庭核心区可购 3 套,社保满 1 年非深户可购 2 套,公积金贷款额度最高提至 351 万
  • 广西一制糖公司带薪放假 94 天,从五一休息到八月初引关注,网友调侃:还能投简历吗
  • 我国矿产资源家底公布:稀土、钨、锡等 14 种矿产储量居世界第一,煤炭、钒、钛等 17 种矿产产量居世界第一
  • 美媒:美国出台新规,拒绝向害怕回国的人发放旅行签证;美国将发行印有特朗普肖像的护照,纪念建国 250 周年
  • 美媒:美国防部正式申请更名为 “战争部”,预计相关调整成本将超过 5000 万美元
  • 泰媒:泰国前总理他信获准于 5 月 11 日假释出狱,免戴电子监控手环
  • 俄媒:佩斯科夫称军事装备方阵不参加今年 5 月 9 日红场阅兵;俄罗斯没有退出欧佩克 + 的计划
  • 美媒:特朗普称美国准备长期封锁伊朗,禁止本国个人或实体向伊朗缴纳霍尔木兹海峡通行费;伊朗官员称将以前所未有的军事行动回应美国海盗行为

📅 今日信息:

  • 公历:2026-04-30 星期四 金牛座
  • 农历:二〇二六年三月十四
  • 公历纪念日:全国交通安全反思日
  • 下一节气:2026-05-05,立夏
  • 今年进度:32.88%(已过 120 天,剩余 244 天)

🌟 历史上的今天

  • 1789 年,乔治·华盛顿在纽约联邦大厅宣誓就任美国第一任总统,当时他紧张到手抖,差点念错誓词。
  • 1905 年,爱因斯坦发表《论动体的电动力学》,提出狭义相对论,但他自己后来承认:那个“追光”思想实验其实是他 16 岁做的白日梦。

今晚深圳炸锅了!!

深圳楼市史诗级核弹爆炸💥 核心区彻底放开,零社保也能买!

就在刚刚!深圳甩出五年最猛新政,
直接撕开福田、南山、宝安核心区限购大口子。

✅ [深户直接第三套]
福田/南山/宝安新安,深户家庭直接解锁 3 套资格,
核心资产随便买,彻底打破多年限购天花板!

✅ [非深户零社保入场]
全国首例!持深圳居住证,**不用社保、不用个税**,
直接买核心区 1 套房,全国有钱人闭眼冲!

✅ [公积金贷款史诗级加码]
家庭最高贷到**351 万**,个人最高 189 万!
相比商贷省下的利息,直接换一辆豪华保时捷!

这不是普通松绑,是楼市分水岭时刻!
从今天起,深圳告别防守,进入核心资产自由流通时代!

接下来,压力给到了北上了。 #楼市 #房地产

大家好,我是 XiaDown (下蛋)的作者。

之前在 V2EX 看到过 tiny-rdm ,印象挺深。自己平时也写 Go ,一直想找个机会做一款基于 Wails 的桌面工具。后来 Wails 3 慢慢可用了,就用它做了这个项目:下蛋 / XiaDown

它的定位比较简单:把视频/音频下载、在线音乐播放和本地资源整理放在一个桌面应用里

项目地址:

做这个的原因

一开始主要是自己的需求。

找素材、做内容、写代码的时候,经常会遇到两个比较碎的场景:

  1. 看到一个视频或音频素材,想先下载下来,最好字幕、封面、元信息也能一起保留。
  2. 工作时会放 Lo-Fi 或在线音乐,但不太想在下载工具、浏览器、播放器之间来回切。

所以就做了 XiaDown 。它不是想替代专业剪辑软件,也不是想做成复杂的媒体中心,更像是一个每天可以开在后台的桌面媒体工具。

现在能做什么

主要功能:

  • 基于 yt-dlp 下载视频和音频,支持保存字幕、封面等素材。
  • 下载完成后可以继续转码,并在本地资源库里管理。
  • 可以播放 YouTube Lo-Fi 电台和 YouTube Music 。
  • 支持搜索歌曲、艺人、歌单,播放队列、歌词、封面等基础能力。
  • 喜欢的在线曲目可以继续保存到本地。
  • 支持主题、强调色、侧边栏样式、精灵等个性化外观。
  • 依赖和更新会在应用内维护,尽量减少首次配置成本。

支持平台:

  • macOS Apple Silicon / Intel
  • Windows x64 安装版 / 便携版

技术栈

主要是:

  • Go
  • Wails 3
  • React
  • SQLite
  • yt-dlp
  • FFmpeg

前端是 Vite + React ,桌面壳用 Wails 3 ,后端主要负责下载、转码、资源库、依赖维护、浏览器连接和系统能力。

这次做下来,Wails 3 给我的感觉是很适合 Go 开发者做这种“有本地能力、又需要现代前端界面”的桌面应用。虽然还在 alpha ,但整体开发体验已经能支撑一个完整工具了。

适合谁

我觉得比较适合:

  • 经常整理视频/音频素材的人
  • 剪辑、内容创作、课程资料归档
  • 工作时喜欢放 Lo-Fi 或在线音乐的人
  • 想要一个本地资源库来沉淀下载内容的人

如果只是偶尔下载一个链接,命令行 yt-dlp 本身已经很好用; XiaDown 更偏向“长期作为一个桌面工具使用”。

平时也不会这样,偶然的。问题是大人被这一折腾,睡不着了,就打开电脑灌水。

因此我就有疑问:得亏就一个娃。那种有三个娃的,万一哪天大娃在两点半醒来,二娃在三点半醒来,三娃在四点半醒来,那大人岂不是整夜也没法睡觉了?不是要累死了吗?

CLIProxyAPIPlus 项目是一个为 CLI 提供 OpenAI/Gemini/Claude/Codex 兼容 API 接口的代理服务器。

不带 Plus 的主线项目,支持为以下主线提供商进行反代:

Providersintroduction
AntigravityAntigravity AI OAuth
GeminiGoogle Gemini CLI OAuth
Claude (Anthropic)Anthropic Claude Code OAuth
CopilotGitHub Copilot CLI, by GitHub Device Code workflow
CodexOpenAI Codex,OAuth
VertexGoogle Vertex API OAuth

带 Plus 的项目,除了支持以上主线提供商,还支持一些社区维护的其他第三方提供商,如:

Providersintroduction
CursorCursor IDE OAuth
KiloKilocode OAuth
KimiKimi AI Token
KiroAWS CodeWhisperer OAuth
GitLabGitLab OAuth
CodeBuddyCodeBuddy IDE OAuth

我维护了一个 Plus 版本的 Docker 镜像,并且主线提供商与主线项目 CLIProxyAPI 保持同步,第三方提供商与 CLIProxyAPIPlus 项目删库前保持一致。

Docker 镜像地址:
https://hub.docker.com/r/leic4u/cli-proxy-api-plus

GitHub 与主线项目同步的 Plus 仓库:
https://github.com/leic4u/CLIProxyAPIPlus

欢迎大家使用。

PS:我是登了 4 个反重力,4 个 Codex,一个 Kiro,一个 CodeBuddy 在上面,做了下模型映射后,免费额度就完全够我用了。

不需要输入 claude 再开始,直接 bash 输入,我要查询磁盘空间,自动帮你 du 执行,不用再记命令了,帮我解压文件,查找 cpu 高占用进程,发挥你的想象。
似乎只是使用路径变短,接入 bash ,不知道跟腾讯和阿里的 bash ai 什么区别。
用过的大佬说说场景

事情有是这样的,去年祼职,一个是公司本身收益不好,绩校考核变得很严重,还有一些迟到加班等小事,在同一家公司也工作 5 年了。
另外就是想着 AI 是一个机会,趁现在出来全职干能不能争取一些机会。
多件事,综合在一起,然后就辞职了。

但是创业路上,工作与创业相差太多了,意外太多了。
最开始就是做图片转口播,图片转视频用的 wan2.2 ,然后声音克隆用了 indexTTS2 ,但当时经验不足,尝试用 wav2lip 还在调试中。
然后还没做出来,百度的绘想、字节的即梦,还有可灵,都升级后可以在线对口型的,消耗积分不多,效果秒杀我这边还在开发中的系统。
还没上线就失败了。
之后又研究了一些其它项目,都是伪需求,失败的事就不多说了。

今年的大模型升级的更快了,打击更大,浪费了整整一年,心好累。

所以想着,放弃吧,从小事做起,想到社区帮帮哪位介绍一下,从赚十块钱的事做起,求助。

我家现在是卖水果的,但我不适合卖东西,特别是市场的人,人太直了,当时在我爸的档口差点和一个老人打起来了。想着还是从网络上这种更适合我。

求助。

https://discord.gg/tn5hmx5z

图片不知道咋发。反正就是能够成功。进去点击申请个邮箱,注册下就可以了,全自动。

You've successfully subscribed to ChatGPT Plus.

Enjoy your first month free. After your first month, your subscription will automatically renew monthly. You can cancel at any time.

Manage your subscription 。。。。

不会编程,没有技术背景的小白,喜欢搞搞电脑,从最初的软路由开始入坑到后来慢慢玩到虚拟机 PVE ,Docker 等等,发现这个开源的世界广阔无边但是处处都有门槛,写个命令行错一个字都不行,Linux 随便一个错误改动就整个机子瘫痪,错误代码日志长篇大论,每个 docker 容器都要看文档一行一行配置,服务之间的联动也常常要写配置文档,少一个缩紧都过不去。

在折磨了不知道多少个日夜之后,antigravity 来了,codex 来了,Gemini CLI ,他们都来了。

一个 Linux 里装上 Gemini CLI ,告诉它我要做什么,全部代码一瞬间都写出来了,自动部署,验证,看日志,修复,维护升级,记录等等,突然之间就像真正的“如虎添翼”,所有的开源软件服务都在眼前,GitHub 里面的每一个应用只要愿意都能随时用上,再也没有所谓的门槛了。

不知道有没有人能理解我的这种感觉,回头看之前的玩机过程简直就像婴儿学步一样艰难,现在在 AI 的加持下就跟开了挂一样。每天都有新发现,新奇的玩意出现,电脑的世界一下子都能抱到怀里慢慢把玩了。

Langcli 是一款在终端中使用的交互式 AI 编程助手, 它是基于Claude code 泄露的代码进行二次开发而成。

Langcli 具有以下优势:

  1. 使用用法与 Claude code 是完全一样

    Langcli 是基于 Claude code 泄露的代码二次开发而成,它保留了 Claude code 绝大部分的功能,且使用方法与 Claude code 完全一致。

  2. 支持主流的 LLM 大模型

    Langcli 通过与LangRouter 平台深度集成,你可以在一个正在工作的 session 中根据需求随意使用、切换主流的 LLM 模型(包括 Claude OPUS 4.6, Deepseek v4 flash, Deepseek v4 pro, Kimi K2.6, GLM 5.1, Minimax M2.5 等),而不会中断你的上下文。

  3. 大幅降低 LLM 模型的使用成本

    在使用 Langcli 进行项目开发过程,由于在工作会话 session 中可以根据需求自由切换 LLM 大模型,你可以使用经济的 LLM 模型处理简易的大部分任务,而使用较贵的 Claude OPUS 处理复杂的少部分任务,这样你可以节省大量的 Tokens 花费。根据部分社区成员统计,部分项目可以节省 90%的 Tokens 花费。

  4. 轻松使用 web 搜索功能

    仅需要 LangRouter 平台的一个 api-key ,你不单可以使用主流的 LLM 模型进行项目开发,还可以为 Langcli 编程助手装备上 web 搜索功能,助你进一步提高开发效率。省去了额外配置其它的 api-key 才能使用 web 搜索功能的麻烦。

  5. 不担心封号

    天下苦 Anthropic 封号久已。LangRouter 平台通过合法的美国公司向 Anthropic 签订批量的采购合同,既不存在封号的问题,又可以向终端客户提供优惠的 Claude OPUS 、Claude sonnet 模型 api 。

有朋友对这款工具同样感兴趣吗?
我体验了 2 天,感觉体验很棒。尤其是 Langcli + deepseek v4 pro 组合,简直是王炸。对于简单任务,动态切换到 v4 flash 模型,速度飞快。

image

如上图,小弟之前托朋友境外充值的 Claude 5x 账号今早被封了。

咨询( 1 ):目前想在新的 gmail 账号上重新充值,求助各位佬友推荐可靠充值渠道

咨询( 2 ):朋友的境外银行卡被 anthropic 一并封杀了,现在充不了新账户。佬友们知道什么原因吗?可有御敌良策?

背景
年前领到大礼包,待业在家至今
个人情况
普通二本 - 30 岁 - 长三角三线城市 - JavaBoy - 毕业就在做开发 - 去年结婚 - 暂时没准备要娃
上一段工作经历是国内新能源车企小厂在本市的子公司,自我进来之后业务线就一直萎缩,直到今年部门撤裁,领了礼包
目前简历上的 title 给到自己一个架构师,虽然干活没啥问题,但是知道自己差的还是很多
面临的问题
本地的机会很少,找工作只能降薪。
去外地找,我担心竞争力不足,虽然提薪了,但会工作时间拉得巨长,时薪反而降低。
找工作情况

  1. 本地外包:离家近,估计大小周+每周有 2 天晚上加班,降薪 12%
  2. 外地初创企业:离本市 200 公里,尚未投简历但同事可内推,具身智能赛道,996,周末有加班费,涨薪 30%

外包这边已经过了 2 轮面,现在在谈薪阶段,不过我猜应该也没多少空间。
纠结,要不要选这个还算可以的外包 😕

一个越来越难用的防火墙

如果你用过 Cloudflare 的防火墙,你可能经历过这样的困境:想同时根据 IP 和 URI 拦截某个请求,发现做不到。想说"来自某个 AS 号、且访问路径包含 /wp-admin"的请求才拦截,也做不到。

这不是功能没有,而是架构本身的限制。这篇博客完整讲述了 Cloudflare 是如何一步步从"每个维度单独一套规则"演进到"支持任意组合的表达式防火墙"的,以及为什么最终选择用 Rust 来构建核心匹配引擎。

原文博客: https://blog.cloudflare.com/how-we-made-firewall-rules/


旧系统是怎么工作的

Cloudflare 最早的防火墙能力非常原始:只能针对 IP 地址进行封禁。

if request IP equals 203.0.113.1 then block

随着需求增加,逐渐加入了 CIDR 范围、ASN、国家、User Agent、URI 匹配,还有 Rate Limiting、Zone Lockdown 等功能。但这些功能在实现层面是相互独立的,每一个都只处理单一维度。

到 2017 年,这个防火墙的能力可以被一句话总结:

你可以按任何条件拦截流量,前提是你只挑一个条件。

这些规则在实现上分为两类:

Lookup 匹配:针对 IP、CIDR、ASN、国家、User Agent 这类字段,构造一个 KV 键(比如 zone:www.example.com_ip:203.0.113.1)去全局分布式存储里查。O(1) 复杂度,性能极好,但只能查单一字段的值。如果要组合两个字段,就需要把所有可能的组合都写进 KV,键的数量会爆炸。

正则匹配:针对 URI 的 Page Rules,把所有规则合并成一个大正则:

^(?<block__1>(?:.*/wp-admin/index.php))|(?<block__2>(?:.*/xmlrpc.php))$

正则的命名捕获组被用来编码动作类型。这个方案在 URI 匹配场景下出乎意料地好用,但一旦要同时匹配 URI 加 IP 范围,就没有自然的扩展方式。


灵感:Wireshark

工程师们很早就意识到,新方案的核心应该是一个表达式语言。最初的方案是用 JSON 来表达 DSL:

{
  "And": [
    { "Equals": { "host": "www.example.com" } },
    { "Or": [
      { "Regex": { "path": "^(?:.*/wp-admin/index.php)$" } },
      { "Regex": { "path": "^(?:.*/xmlrpc.php)$" } }
    ]}
  ]
}

计算机处理没问题,但人看起来费力。在把这个 JSON 翻译成"人类语言"时,工程师意识到这个结构非常眼熟——这不就是 Wireshark 的过滤器语法吗?

Wireshark 是网络协议分析工具,它的 Display Filter 语法长这样:

http.host eq "www.example.com" and (http.request.path ~ "wp-admin" or http.request.path ~ "xmlrpc.php")

简洁,人类可读,机器可解析,而且对安全工程师来说几乎零学习成本——他们每天排查攻击时就在用 Wireshark。

Cloudflare 决定借鉴这套语法,但不做 Wireshark 那样的离线数据包分析。他们要的是实时过滤:HTTP 请求进来,毫秒内判断是否匹配,给出处理动作。


核心引擎:wirefilter

基于这个思路,Cloudflare 用 Rust 实现了一个名为 wirefilter 的库(名字向 Wireshark 致敬)。

它做几件事:

  • 定义字段及其类型,比如 ip.src 是 IP 类型,http.host 是字符串类型
  • 给定一张请求属性表(由 HTTP 服务器填充)
  • 解析和校验表达式语法,检查字段名是否合法、操作符是否适用于该字段类型
  • 将表达式应用到请求属性表,返回 true/false

请求属性表的字段覆盖了一条 HTTP 请求的完整信息:

字段示例值
http.hostwww.example.com
http.request.uri.path/articles/index
http.request.methodGET
ip.src203.0.113.1
ip.geoip.countryGB
ip.geoip.asnum64496
ssltrue

wirefilter 被集成到了两个地方:用 Go 写的 REST API(负责校验用户输入的表达式),以及用 Lua 写的边缘代理(负责在请求进来时实际执行匹配)。

Go 侧的集成大致是这样:

var scheme = filterexpr.Scheme{
    "http.host":             filterexpr.TypeString,
    "http.request.uri":      filterexpr.TypeString,
    "ip.src":                filterexpr.TypeIP,
    "ip.geoip.country":      filterexpr.TypeString,
    "ssl":                   filterexpr.TypeBool,
}

expressionHash, err := filterexpr.ValidateFilter(scheme, expression)

Lua 侧则负责在每次请求时填充属性表,然后拿 wirefilter 来做实际的匹配。


为什么选 Rust

这个问题的答案比较直接:需要保证 API 侧和边缘代理侧的行为完全一致

如果分别用 Go 和 Lua 各写一套实现,任何微小的差异都可能被攻击者利用——比如在 Go 侧判断为合法的规则,在 Lua 侧匹配逻辑略有不同,就可能绕过防火墙。

用一个共享库来封装匹配逻辑,Go 和 Lua 都通过 FFI 调用它,能从根本上消除这种不一致。

在候选语言里,C 和 C++ 有内存安全问题,Go 和 Lua 已经被排除(正是问题所在),JavaScript Worker 方案在性能和集成上有额外复杂度。Rust 在性能、内存安全、低内存占用、以及可以被其他产品复用(比如 Spectrum)这几个维度上综合表现最优。


规则优先级:一个云环境特有的问题

新系统支持复杂表达式后,随之而来的是一个新问题:怎么确定规则之间的执行顺序?

传统防火墙(iptables、家用路由器)用的是显式顺序:规则 1 到规则 N,匹配到第一条就停止。每次改动都重新发布全部规则,顺序是确定的。

但在云端这不可行。一个大客户可能有几十万条规则,每次改动都要重新发布全部规则代价太高,而且在分布式环境下,两条规则同时发布时可能出现竞态条件。

Cloudflare 的解决方案是 priority 值,是一个 int32,数字越小优先级越高。两条规则优先级相同时,再按动作类型排序:

  1. Log(最高优先级)
  2. Allow
  3. Challenge(CAPTCHA)
  4. JavaScript Challenge
  5. Block(最低优先级)

这套设计有几个好处:

  • 单条规则独立发布,发布速度不受规则总数影响
  • 优先级不要求唯一,可以给一批规则设置相同的优先级值,起到分组的效果
  • 如果你有一个已有的顺序化规则系统,可以直接把顺序号映射成 priority 值导入进来

字段命名的远见

注意到 wirefilter 的字段都有 http. 前缀了吗?这遵循了 Wireshark Display Filter Reference 的命名约定,而不只是一个风格习惯。

这意味着这套引擎从设计上就不是 HTTP 专属的。只要定义了对应协议的字段(比如 smtp.fromdns.query),同一套匹配引擎就可以用于 SMTP、DNS 或者 Layer 4 的流量过滤。Cloudflare 的 Spectrum 产品(支持任意 TCP/UDP 协议的代理)就是这套架构向前延伸的方向。


小结

这篇文章描述了一个典型的工程演进路径:从一堆各自独立、能用但不能组合的功能,到一套统一的、基于表达式的过滤引擎。

几个值得记住的设计决策:

把核心逻辑下沉为库,而不是在每个调用方分别实现。这是保证多语言环境下行为一致的唯一可靠手段,也是选 Rust 写 wirefilter 的直接动因。

表达式语言借鉴成熟工具的语法。Wireshark Display Filter 对安全工程师是零学习成本,从调查工具到防护工具的语法迁移是自然的。

云环境的顺序问题不能用传统方式解决。priority 值而非显式顺序,单条独立发布而非全量重发,是针对分布式环境做的专门设计。

字段命名是架构意图的一部分http.host 而不只是 host,这个前缀埋下了未来扩展到其他协议的伏笔。

日常使用QClaw进行内容产出与素材整理时,多数使用者都会陷入一种共性困扰,系统给出的呈现形态总是随性散漫,无法贴合实际使用场景的规整需求。想要条理清晰的结构化内容,到手却是杂乱堆砌的零散文字,想要层次分明的规整版式,最终呈现的排版总是混乱无序。反复手动调整版式结构,会大量消耗时间与精力,原本用来提升效率的辅助工具,反而变成了额外的负担。其实这款工具本身具备极强的形态定制潜力,只是大部分使用者只停留在基础使用层面,没有深入摸索输出形态的调控逻辑。

长期深耕这类智能工具的实操摸索与应用沉淀后,会发现多数人对格式调控的理解都停留在浅层认知里。单纯在需求末尾简单标注版式要求,根本达不到精准定制的效果,系统要么直接忽略相关描述,要么过度解读给出偏离预期的内容形态。智能模型在接收需求指令时,会先完成整体语义拆解与逻辑梳理,默认通用化呈现模式适配所有模糊需求。通用化模板侧重普适性,不会贴合个人使用习惯与场景属性,这也是为什么同样的指令,不同人得到的成品质感天差地别。只有把版式细节、排布逻辑、呈现规范都梳理清楚,才能让输出效果稳定贴合预设方向。在日常文案梳理、素材汇总的场景里,层级化文本排布是使用率最高的需求,也是最容易出现错乱问题的环节。很多人只会笼统要求做出分层排版,最终成品常常出现层级颠倒、段落穿插、多余分层的问题,整体阅读逻辑被彻底打乱。想要规避这类问题,核心在于提前梳理好完整的排布框架,把每一层内容的定位、篇幅区间、衔接逻辑都清晰传递出去。明确整体开篇铺垫内容,再划分主体板块的排布顺序,每个板块内部再规划细分内容的呈现节奏,让模型清晰知晓每一部分的定位与作用,从根源上避免层级混乱的情况出现。

把控好基础框架之后,还能进一步细化文字排布的细节规范,控制单段内容的篇幅节奏与行文风格。柔和自然的行文语气,适配日常分享类素材,简洁凝练的表达调性,适合专业类梳理内容。提前界定好文字疏密与表达风格,生成的内容不需要二次润色调整,就能直接投入使用。成熟的使用者都会养成提前规划版式框架的习惯,不再依赖系统默认模式,让每一次产出都能直接匹配使用场景,省去反复修改调整的繁琐步骤。规整化汇总类内容创作中,规整行列排布的呈现形式有着不可替代的实用价值,也是很多使用者难以把控的板块。常常会遇到行列数量不符、内容错位排布、结构残缺的状况,反复重新生成依旧达不到理想效果。打造规整行列内容的关键,在于提前敲定核心归类维度,先梳理好需要展示的核心类目,确定横向与纵向的排布逻辑,再对应填充各类目下的具体信息。模糊的汇总需求只会让模型自主判断结构,自然容易出现各种偏差,清晰的类目界定才是稳定产出的核心前提。

面对结构相对复杂的多层级汇总素材,还可以搭建嵌套式排布形态,这类形态在多维度信息梳理中作用显著。复杂排布模式对指令精准度要求更高,需要清晰划分主体区域与附属区域的对应关系,明确每一处嵌套位置的展示方向与信息类型。只要指令逻辑足够清晰,就能实现多层级规整呈现,满足深度信息梳理的需求,这也是普通简易工具很难做到的优势所在。文本类规整产出之外,结构化素材整理也是高频应用方向,这类内容同样需要严格把控外在呈现样式。不少时候整体内容逻辑没有问题,但排布疏密、段落间距、行文节奏杂乱,会大幅降低阅读观感。调控这类呈现效果,需要提前设定好基础排布规范,统一整体的疏密节奏,理顺段落之间的衔接节奏,让整体观感协调统一。规范好外在形态之后,成品的规整度与可读性都会大幅提升,后续使用时可以直接复用,不用再花费时间做格式优化。

各类基础版式之外,日常素材整理还会用到分段罗列、引用标注、间隔分区等辅助呈现样式,这些细节元素同样有着对应的调控逻辑。所有形态定制的核心逻辑保持一致,都是用具象清晰的描述,替代笼统模糊的需求表达。想要有序罗列内容,就明确标注排布标识与条目数量,想要凸显重点内容,就界定好专属呈现样式,让每一处细节需求都能被精准捕捉。很多人容易忽略一个关键要点,形态定制可以和内容创作需求融合在一起,同一组指令中既能界定创作主题与核心方向,也能同步规划全程排布样式。按照使用顺序规划开篇铺垫、中间主体、末尾总结的排布结构,搭配对应的版式规范,模型就会按照预设流程依次产出完整内容,全程无需人工介入调整,完整实现一站式规整产出。

长期高频使用的各类版式框架,都可以整理成固定套用模板,后续同类场景直接调取使用,不用每次都重新梳理定制指令。模板只需要锁定基础排布框架与核心规范,保留内容创作的灵活空间,既可以保证输出稳定性,又能适配不同主题的创作需求。过于僵硬的模板会限制内容自然度,留有适度弹性空间的框架,才能平衡规整性与文字质感,让成品不会显得生硬刻板。多轮连续的素材创作场景中,还可以依托上下文延续固定版式习惯,前期确定好整套呈现规范,后续同类创作就能自动沿用对应样式,不用重复标注格式需求。这种延续性适配能大幅简化操作流程,适合长期系统化产出的使用模式。同时需要分清指令优先级,临时调整的新式样指令,会优先覆盖过往延续的规范,灵活切换就能适配不同临时场景的定制需求。

多数人都会下意识觉得形态定制是一套复杂难懂的体系,需要钻研各类专业规范与专属逻辑,实际上整套操作都依托自然语言就能完成。不需要额外学习陌生规则,只需要摒弃笼统化表述,把心中预想的呈现模样,细致完整地描述出来。描述的细节越贴合自身使用习惯,最终成品的契合度就越高,所谓定制化掌控,本质就是精准传递自身的审美与使用需求。不同细节粒度的需求描述,最终呈现的成品质感有着天壤之别。只给出核心主题的模糊指令,成品散漫无序,几乎没有复用价值;补充基础版式要求后,整体框架趋于规整,但细节依旧存在瑕疵;完整梳理框架、篇幅、风格、排布的全维度需求,就能直接拿到可直接使用的成品。这一组明显的差异对比,足以说明指令细节度,才是决定最终产出质量的核心关键。

市面上很多使用者会感慨智能工具适配度不高,产出效果达不到预期,根源从来不在工具本身,而是需求传递的精准度不足。智能模型只能依托接收的指令完成创作,无法自主揣测使用者的隐性需求。掌握形态定制的核心思路之后,就能彻底摆脱被动接收默认成品的状态,主动掌控每一次产出的规整度与适配性。任何实用指令体系,都需要经过反复调试、校验、优化的过程,不存在一次就能完美适配所有场景的通用模板。每次产出完成后,对照实际使用需求梳理偏差之处,微调描述逻辑与细节规范,多次打磨之后,就能沉淀出适配个人使用习惯的专属指令。慢慢积累适配不同场景的定制方案,后续各类素材整理、内容创作工作,都能实现高效落地。

系统化沉淀各类定制方案之后,日常工作与素材整理的效率会得到明显提升,以往耗时很久的规整排版工作,现在只需要简单确定需求方向,就能拿到成型素材。看似简单的版式调控技巧,实则打通了智能工具与个人工作流程的适配通道,让辅助工具真正融入日常节奏,而不是单独存在的陌生程序。放眼整体应用领域,QClaw的定制化潜力还有很大挖掘空间,动态适配类排布、多样式融合呈现这类进阶方向,还在等待使用者慢慢探索打磨。根据内容属性自主微调版式结构,同一文档内融合多种规整样式,这些进阶玩法能进一步拓宽使用边界,适配更多复杂专业的产出场景。持续深耕实操细节,就能不断解锁新的使用方式,让工具价值发挥到极致。

所有智能辅助工具的熟练运用,都离不开持续实操摸索与经验总结,没有速成的捷径。只是单纯套用他人的方法,永远只能停留在基础使用阶段,结合自身场景不断测试、调整、感悟,才能真正吃透内在逻辑。慢慢摸清定制化输出的底层规律,就会发现规整化产出并不复杂,轻松就能打造专属自己的高效创作模式。

凌晨三点的办公室里,屏幕上的加载圈还在固执地转动,一份耗时两个多小时的全行业深度调研刚推进到三分之二,网络波动的弹窗毫无征兆地跳了出来。刷新页面的瞬间,所有进度烟消云散,只剩下空白的输入框和满屏的无力感。这是几乎所有深度使用智能工具的人都经历过的至暗时刻,长任务中断带来的不仅是时间的浪费,更是创作节奏的彻底打乱。很多人不知道的是,QClaw早已内置了完整的断点续传体系,只是绝大多数使用者都停留在“接着写”的原始阶段,白白浪费了这个能让工作效率翻倍的核心功能。绝大多数人处理长任务中断的方式,都是直接在新的输入框里敲下“接着上面的内容继续写”,然后祈祷系统能读懂自己的意思。这种做法的成功率不足三成,更多时候得到的是逻辑断裂的内容、重复的论述、甚至完全偏离主题的展开。系统无法凭空还原中断前的上下文状态,它不知道已经写了哪些内容,不知道哪些观点已经论证过,不知道原本的结构框架是什么,更不知道你想要的行文风格和细节要求。这种盲目的续传方式,本质上是把所有的判断压力都丢给了系统,最终的结果自然不尽如人意。

想要真正掌握断点续传的精髓,首先要理解它的底层运行逻辑。QClaw的断点续传从来不是简单的文本拼接,而是基于上下文状态的完整重建。系统在处理长任务时,会在内存中维护一个动态的状态快照,这个快照包含了任务的核心目标、已完成内容的逻辑脉络、未完成部分的执行计划以及所有的风格约束参数。当中断发生时,这个状态快照会随之消失,续传的本质就是手动重建这个状态快照,让系统回到中断前的那个精确的执行节点。很多人会犯的第一个错误,就是把已生成的全部内容原封不动地粘贴到新的输入框里,以为这样就能完整还原上下文。这种做法对于几千字以内的短任务或许有效,但对于上万字的长任务来说,只会导致上下文窗口溢出。系统的上下文承载能力是有限的,当输入的内容超过这个阈值时,它会自动丢弃最早的部分信息,最终导致对整体任务目标的理解出现偏差。正确的做法不是复制全部内容,而是提取已完成内容的核心逻辑骨架,用最精简的语言描述清楚已经写了什么。

提取逻辑骨架是断点续传中最关键的一步,也是最能体现使用者水平的一步。一个好的逻辑骨架应该包含三个核心部分:首先是任务的整体目标和结构框架,明确整个长任务分为哪几个大的板块,每个板块的核心内容是什么;其次是已完成部分的进度节点,精确到最后一个完整的逻辑段落,而不是最后一句话;最后是已论证的核心观点和关键论据,避免后续内容出现重复或者矛盾。把这三个部分用清晰的语言组织起来,就能用不到十分之一的篇幅,还原90%以上的上下文状态。在重建了基础的逻辑骨架之后,接下来需要补充原始任务的所有约束条件。很多人在续传时会忘记这一步,导致续传的内容在风格、篇幅、细节程度上和前面的内容出现明显的差异。原始任务的约束条件包括但不限于:整体的字数要求、每个板块的篇幅分配、行文的风格调性、专业术语的使用规范、数据的呈现方式、案例的选取标准等等。把这些约束条件明确地写在续传指令里,才能保证续传的内容和前面的内容保持高度的一致性。

完成了状态重建之后,不要急于要求系统一次性续传完剩下的所有内容。长任务之所以容易中断,就是因为执行时间过长,中间任何一点微小的波动都可能导致失败。正确的做法是采用增量续传的策略,把剩下的内容按照逻辑结构分成若干个独立的小块,一块一块地进行续传。每完成一个小块,就做一次状态同步,确认这部分内容符合要求之后,再继续下一个小块。这样即使中途再次中断,也只会损失当前小块的进度,而不会影响已经完成的部分。增量续传的块大小需要根据任务的性质来灵活调整,一般来说,每个块的内容控制在两千字左右比较合适。这个长度既能保证内容的完整性和连贯性,又能把单次执行时间控制在一个相对安全的范围内。对于逻辑联系特别紧密的内容,可以适当增大块的大小;对于相对独立的内容,则可以适当减小块的大小。通过这种分而治之的方式,可以把长任务的失败风险降到最低,同时也能让你在整个过程中保持对任务进度的掌控。

在进行每一次增量续传时,都需要在指令中明确当前块的内容范围和具体要求。不要只说“继续写下一部分”,而是要说“接下来写第三部分的第二小节,主要内容是分析市场竞争格局中的头部企业优势,重点对比三家企业的核心竞争力,每个企业的分析篇幅控制在三百字左右,延续前文的对比分析风格”。这种精确的指令能够让系统准确地知道自己接下来要做什么,从而生成符合预期的内容。很多人在续传过程中会遇到一个非常头疼的问题,就是衔接处的生硬感。前一段的最后一句话和后一段的第一句话之间明显脱节,读起来非常不流畅。解决这个问题的方法很简单,就是在续传指令中附上上一个块的最后两到三句话。系统会根据这几句话的语境,自然地过渡到接下来的内容,从而消除衔接处的断点痕迹。这个小小的技巧,能够让续传的内容看起来就像是一次性生成的一样,毫无破绽。

对于特别复杂的长任务,比如生成一本完整的电子书或者一份上百页的行业报告,最好的做法是在任务开始之前就预先设置好断点。在制定任务计划的时候,就把整个任务划分成若干个天然的断点,一般来说,每个大的章节结束的地方就是一个理想的断点。每完成一个章节,就主动保存一次当前的状态,包括这个章节的核心内容总结和下一个章节的执行计划。这样即使中途出现任何意外,都可以从最近的一个断点继续开始,而不会损失太多的进度。预先设置断点还有一个额外的好处,就是能够让你在长任务的执行过程中获得阶段性的成就感。长任务最容易让人放弃的原因,就是看不到即时的反馈,感觉遥遥无期。通过预先设置断点,把一个漫长的大任务分解成一个个清晰可见的小目标,每完成一个小目标就能获得一次正向反馈,从而保持持续的动力。这种任务管理的思维方式,不仅适用于智能工具的使用,也适用于所有类型的长期工作。

很多人以为断点续传只能在同一个会话中进行,一旦关闭了页面或者切换了设备,就只能重新开始。其实这是一个非常普遍的误解,QClaw完全支持跨会话甚至跨设备的断点续传。只要你能够准确地重建中断前的状态快照,无论是在电脑上还是在手机上,无论是在今天还是在一周之后,都可以无缝地继续之前的任务。这对于需要长时间跨度完成的长任务来说,是一个非常重要的功能。跨会话续传的关键在于状态的持久化保存。每次完成一个增量块之后,除了保存生成的内容之外,还要同步保存当前的状态信息。这些状态信息包括:整体任务的进度、已完成内容的逻辑骨架、下一个增量块的内容要求、所有的风格约束参数。把这些信息整理成一段简短的文字,保存在本地的文档里,下次需要续传的时候,只需要把这段文字粘贴到输入框里,就能立刻回到上次中断的地方。

续传完成之后,不要急着直接使用最终的内容,一定要进行一次全面的校验和整合。首先要通读全文,检查各个部分之间的逻辑是否连贯,有没有出现前后矛盾的地方;其次要检查所有的数据和论据是否准确一致,有没有出现重复或者遗漏;最后要检查整体的风格是否统一,有没有出现某个部分的语气和其他部分明显不同的情况。对于发现的问题,进行针对性的修改和调整,确保最终的成品质量。在进行内容校验的时候,要特别注意各个断点衔接处的内容。这些地方是最容易出现问题的,也是最能体现续传质量的地方。如果发现某个衔接处比较生硬,可以手动调整一下前后的语句,让过渡更加自然流畅。对于一些比较重要的长任务,甚至可以专门生成一段过渡文字,把前后两个部分无缝地连接起来。经过这样的打磨之后,没有人能看出来这份内容是经过多次断点续传生成的。

除了基础的文本续传之外,QClaw的断点续传体系还支持更加复杂的增量修改任务。很多时候,我们需要对已经生成的内容进行大规模的修改和调整,这个过程同样可能会中断。处理这种情况的方法和普通的续传类似,首先要明确已经修改了哪些部分,修改的方向和要求是什么,然后把剩下的修改任务分成若干个小块,逐个进行处理。这样可以避免因为一次修改过多内容而导致的中断和返工。对于同时处理多个长任务的使用者来说,建立一个完善的断点管理体系是非常有必要的。可以用一个专门的文档来记录所有正在进行的长任务的状态,包括任务名称、整体目标、当前进度、下一个断点的位置、以及所有的约束参数。每次完成一个断点的任务之后,就更新这个文档的状态。这样无论同时处理多少个任务,都能做到井井有条,不会出现混乱和遗忘的情况。

很多资深的使用者都会根据自己的工作习惯,总结出一套专属的断点续传模板。这些模板包含了状态重建、增量续传、风格保持等所有必要的元素,每次需要续传的时候,只需要把对应的信息填入模板中即可。使用模板不仅能够大幅提高续传的效率,还能保证每次续传的指令质量,避免因为遗漏某些重要信息而导致的续传失败。经过不断的优化和完善,这些模板会变得越来越贴合个人的使用习惯,成为提升工作效率的利器。随着使用经验的积累,你会逐渐发现,断点续传不仅仅是一个解决任务中断问题的功能,更是一种全新的长任务管理思维。它让我们不再害怕长任务的中断,不再因为一次意外就前功尽弃。它教会我们把复杂的大任务分解成简单的小任务,学会在过程中不断地保存状态、总结进度、调整方向。这种思维方式的转变,比掌握任何具体的技巧都更加重要,它能够让我们在面对任何复杂的工作时,都能保持从容和高效。

QClaw的断点续传体系还有很多潜力等待着我们去挖掘,比如基于历史会话的自动状态恢复、智能断点推荐、多任务并行的断点管理等等。这些功能的不断完善,将会让长任务的处理变得越来越轻松。但无论技术如何发展,核心的逻辑永远不会改变:清晰的任务分解、精确的状态描述、增量式的执行方式。掌握了这些核心逻辑,你就能在任何情况下都游刃有余地处理各种长任务,让智能工具真正成为你工作中的得力助手。

内容结构概览

  1. 引言 —— 背景与问题缘起

    • Cloudflare Firewall Rules 的需求
    • 为什么选择 Rust
  2. 解析器的设计

    • Wireshark DSL 语法的歧义性挑战
    • 三种解析方案的对比
    • 为何放弃解析器生成器,选择手动解析
    • Rust Trait 驱动的解析器架构
  3. 执行引擎的演进

    • 初版:直接 AST 解释执行
    • 优化一:用固定数组替代 HashMap,实现 2x 加速
    • 关于 JIT 的思考与放弃原因
  4. 核心方案:闭包动态分发

    • Fn trait 与动态分发的原理
    • 将 AST 编译为闭包树
    • 性能、安全、灵活性三者的平衡
  5. 彩蛋:WebAssembly 支持

    • wasm-bindgen 与 wasm-pack
    • 20 行代码暴露解析器给前端


在系统编程领域,有一类工程问题天然具有代表性:如何在安全、性能与可维护性之间找到真正的平衡点。Cloudflare 工程团队在构建防火墙规则引擎时,用 Rust 给出了一份值得拆解的答案。

这篇文章基于 Cloudflare 官方博客 Building fast interpreters in Rust,系统梳理其中的工程决策,适合对编译原理、Rust 或系统设计有兴趣的读者。


背景:为什么要自己造这个轮子

Cloudflare 的防火墙规则系统,需要让用户用类似 Wireshark 的过滤语法来描述规则,例如:

ip.addr == 192.168.0.1
http.request.uri matches "gl=se$"

规则需要在 Go、Lua、C、C++ 以及 Workers(JavaScript)等多种环境中运行,并且要满足以下几个硬性指标:

  • 性能:规则执行路径在关键链路上,延迟敏感
  • 内存安全:生产环境不容许内存漏洞
  • 低内存占用:边缘节点资源受限
  • 可复用性:需要被多个产品集成

在这个约束组合下,Cloudflare 选择了 Rust,并将这个库以 wirefilter 的名字开源。


第一关:解析器怎么写

Wireshark 语法的歧义陷阱

DSL 设计中,解析器是第一道关口。Wireshark 语法看上去简单,但藏着一个不小的歧义问题。

考虑这个值:2f:31:32:33:34:35:36:37

同时是合法的 IPv6 地址,也是合法的字节序列。究竟该如何解析,取决于字段的类型:

ipv6.addr == 2f:31:32:33:34:35:36:37   → 解析为 IPv6 地址
http.request.uri == 2f:31:32:33:34:35:36:37  → 解析为字节序列

类似地,80 既可以是端口号(整数),也可以是 HTTP 响应体中的单字节(0x80)。

这意味着解析器不能独立运行——它必须带着一份预先定义好的 Schema(字段名到类型的映射)才能完成解析。

为什么不用解析器生成器

面对这个需求,常见的三类方案分别是:

  1. 手动字符解析:用状态机、正则或原生字符串 API
  2. 解析器组合子(Parser Combinators):如 nomcombine
  3. 解析器生成器:如 pestLALRPOP 等,通过语法描述自动生成解析器

解析器生成器通常基于独立的词法分析阶段,而这个问题要求词法与类型上下文绑定,大多数生成器做不到。即使用 LALRPOP 这类允许自定义 Lexer 的方案,复杂度也逼近手写,却多了一层黑盒。

最终团队选择了手动解析——在 Rust 中,字符串默认有边界检查,API 丰富,安全性有保证。

Rust Trait 驱动的解析架构

团队将解析器设计为实现统一 Trait 的类型:

pub trait Lex<'i>: Sized {
    fn lex(input: &'i str) -> LexResult<'i, Self>;
}

pub trait LexWith<'i, E>: Sized {
    fn lex_with(input: &'i str, extra: E) -> LexResult<'i, Self>;
}
  • Lex:用于不依赖上下文的解析(如字段名、字面量)
  • LexWith:用于需要 Schema 的上下文感知解析

顺序解析时,直接链式调用:

let input = skip_space(input);
let (op, input) = CombinedExpr::lex_with(input, scheme)?;
let input = skip_space(input);
let input = expect(input, ")")?;

选择分支时,用 Rust 原生的模式匹配:

if let Ok(input) = expect(input, "(") {
    // 括号表达式
} else if let Ok((op, input)) = UnaryOp::lex(input) {
    // 一元操作符
} else {
    // 其他情况
}

对于枚举类型的解析,用宏来减少重复:

lex_enum!(#[repr(u8)] OrderingOp {
    "eq" | "==" => Equal = EQUAL,
    "ne" | "!=" => NotEqual = LESS | GREATER,
    "ge" | ">=" => GreaterThanEqual = GREATER | EQUAL,
    ...
});

这种方式兼具解析器组合子的无状态清晰性,又保留了完整的语言控制权。


第二关:执行引擎怎么快

初版:直接 AST 解释

最初的执行引擎很直接——让每个 AST 节点实现一个 execute 方法:

trait Expr<'s> {
    fn execute(&self, ctx: &ExecutionContext<'s>) -> bool;
}

ExecutionContext 本质上是一个 HashMap,存储字段名到运行时值的映射。执行时递归遍历 AST,在 Map 里查字段值。

功能正确,但 HashMap 查找的开销不可忽视。

优化:用固定数组替代 HashMap

关键洞察在于:Schema 是提前已知的,字段数量是固定的。因此完全可以用一个定长数组来存运行时值,用字段在 Schema 中的下标来索引,彻底省掉哈希计算。

实现上,用 IndexMap(一个保留插入顺序、支持按下标访问的 HashMap 替代品)替换 Schema 内部的 HashMap,在解析阶段就把字段名解析为下标并存入 AST:

pub struct ExecutionContext<'e> {
    scheme: &'e Scheme,
    values: Box<[Option<LhsValue<'e>>]>,
}

执行时直接按下标取值,不再涉及任何哈希。

效果立竿见影:

匹配耗时
优化前2,548 ns/iter
优化后1,227 ns/iter

2 倍的性能提升,且类型错误的检测时机提前到了赋值时,而非执行时,可用性也随之改善。

关于 JIT:想过,但放弃了

"下一步就加 JIT,性能飞起来"——这是 DSL 工程中几乎人人都有过的想法。

但 Cloudflare 团队经过评估后选择放弃,原因很实际:

存储问题:如果静态编译每条规则,需要为 x86-64、ARM、WASM 等多平台分别编译,并维护存储,规则一旦更新逻辑就要全量重编译。

JIT 的代价:JIT 编译发生在运行时,生成原生代码本身就有相当的时间开销,很容易抵消执行加速带来的收益。

安全风险:动态生成代码并标记为可执行内存,本质上是引入了一个运行时的信任边界,这在边缘安全产品中是需要格外谨慎的事。


核心方案:闭包树取代 AST 解释

既然 JIT 不用,有没有一种方式,在不生成原生代码的前提下,尽量逼近 JIT 的运行时性能?

Cloudflare 的答案是:将 AST 编译成一棵闭包树

Fn trait 与动态分发

Rust 的 Fn trait 系列(FnFnMutFnOnce)允许将闭包装箱为 Box<dyn Fn(...)>,在运行时通过动态分发调用。

核心结构如下:

pub(crate) struct CompiledExpr<'s>(Box<dyn 's + Fn(&ExecutionContext<'s>) -> bool>);

impl<'s> CompiledExpr<'s> {
    pub(crate) fn new(closure: impl 's + Fn(&ExecutionContext<'s>) -> bool) -> Self {
        CompiledExpr(Box::new(closure))
    }

    pub fn execute(&self, ctx: &ExecutionContext<'s>) -> bool {
        self.0(ctx)
    }
}

每个 AST 节点通过 compile() 方法转化为一个闭包,闭包可以捕获所需的数据,也可以嵌套调用其他闭包。

闭包套闭包:组合逻辑的自然表达

以 IP 范围检查为例,在编译阶段就可以把 IPv4 和 IPv6 分开处理并缓存:

RhsValues::Ip(ranges) => {
    let mut v4 = Vec::new();
    let mut v6 = Vec::new();
    for range in ranges {
        match range.clone().into() {
            ExplicitIpRange::V4(r) => v4.push(r),
            ExplicitIpRange::V6(r) => v6.push(r),
        }
    }
    let v4 = RangeSet::from(v4);
    let v6 = RangeSet::from(v6);
    CompiledExpr::new(move |ctx| {
        match cast!(ctx.get_field_value_unchecked(field), Ip) {
            IpAddr::V4(addr) => v4.contains(addr),
            IpAddr::V6(addr) => v6.contains(addr),
        }
    })
}

逻辑组合(AND / OR / XOR)同样用闭包嵌套表达:

match op {
    CombiningOp::And => {
        CompiledExpr::new(move |ctx| items.iter().all(|item| item.execute(ctx)))
    }
    CombiningOp::Or => {
        CompiledExpr::new(move |ctx| items.iter().any(|item| item.execute(ctx)))
    }
    ...
}

最终整棵表达式树变成一个单一的顶层闭包,调用它就等于执行整条规则。

这个方案的收益清单

  • 解耦:执行逻辑与 AST 结构完全分离,可以各自演进
  • 零原生代码生成:运行时只调用静态验证过的 Rust 函数,没有安全边界问题
  • 编译开销极低:装箱闭包的代价远低于真正的代码生成
  • 性能意外提升:相较于原始 AST 解释,动态分发带来了约 10~15% 的运行时性能改善

这个结果起初令团队意外——动态分发通常被认为有额外开销,但实测中,闭包树消除了大量递归调用的中间状态,缓存局部性反而更好。

唯一的代价是:相比于真正的 JIT 内联展开,每层闭包仍然有一次虚函数调用开销。但对这个场景而言,这个代价完全可以接受。


彩蛋:20 行代码暴露给前端

Cloudflare 的防火墙规则编辑器有一个 UI,需要在前端实时校验用户输入的规则语法。理想状态是前后端共用同一套解析器。

Rust 对 WebAssembly 的支持恰好提供了这个可能。

借助 wasm-bindgen,只需约 20 行代码就能将解析器暴露为 WASM 模块:

#[wasm_bindgen]
pub struct Scheme(wirefilter::Scheme);

#[wasm_bindgen]
impl Scheme {
    #[wasm_bindgen(constructor)]
    pub fn try_from(fields: &JsValue) -> Result<Scheme, JsValue> {
        fields.into_serde().map(Scheme).map_err(into_js_error)
    }

    pub fn parse(&self, s: &str) -> Result<JsValue, JsValue> {
        let filter = self.0.parse(s).map_err(into_js_error)?;
        JsValue::from_serde(&filter).map_err(into_js_error)
    }
}

配合 wasm-pack,可以自动生成 npm 包并发布。这意味着同一套 Rust 代码可以同时服务于:

  • 后端边缘节点的规则执行
  • 前端编辑器的实时语法校验
  • 甚至 Cloudflare Workers 中的规则运行

总结与思考

Cloudflare 这个案例的核心工程价值在于,它展示了几个在实践中常被忽视的判断:

第一,不是所有问题都适合用现成工具解决。 解析器生成器省事,但一旦 DSL 有上下文相关的歧义,生成器的边界就到了。手写解析器在 Rust 里并不可怕。

第二,性能优化要先找对瓶颈。 HashMap 查找看起来"很快",但在高频执行路径上,换成数组下标索引就能带来 2 倍提升。数据结构的选择往往比算法优化影响更直接。

第三,JIT 不是银弹。 编译代价、存储复杂性、安全边界,这些隐性成本在边缘场景下完全可以让 JIT 得不偿失。闭包树在这里是一个工程上更务实的折中。

第四,语言特性可以成为架构工具。 Rust 的 Fn trait 和动态分发,不只是语言细节,而是可以用来构建可组合执行引擎的设计原语。

如果你正在设计一个嵌入式规则引擎、DSL 解释器,或者类似的执行框架,这套思路有相当强的参考价值。


原文链接:https://blog.cloudflare.com/building-fast-interpreters-in-rust/

开源仓库:https://github.com/cloudflare/wirefilter

视频版:https://www.bilibili.com/video/BV1Kk9kBAEJv

最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。

每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。

安装

在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。

接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。

然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。

项目与任务列表

我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。

我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。

接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。

这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。

在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。

这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。

过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。

我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。

我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。

左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。

权限控制与沙箱

接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。

Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。

Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。

Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。

Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。

如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。

所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。

上下文

在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。

不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。

在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。

下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。

说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。

两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。

AI 生图

Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。

我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。

我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。

然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。

接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令:

我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。

这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。

在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。

这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。

在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。

我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。

在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。

这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。

计划模式与内置浏览器

在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。

我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。

我们在 Codex 里面打开计划模式,输入我们的需求:

把这个项目改造成 next js 框架

在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。

代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。

如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。

在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。

代码管理

Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。

在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词:

把项目初始化成一个 git 工程,注意排除掉不需要的文件。

Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。

初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。

除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。

我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。

创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。

Git 回滚

本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。

我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。

当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交,

填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。

这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。

我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。

不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash ,

这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。

我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。

Git worktree

接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。

找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。

这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求:

优化一下客户评价部分,多写几个评价,做一个动画轮播效果,

开始。然后我们来到第二个分支,创建一个新的对话:

优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。

我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。

两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。

两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

今天 HR 通知我被裁了,正式离职的时间是五月份月底,我还差 10 天左右工龄满 5 年,公司给的赔偿是 N=5 ,工龄满 5 年时也不再发放年假。我想咨询一下这是否合理合法?