[{"content":"技术 2026.06.15 怎么安卓17的源代码还不公布啊？现在谷歌更新安卓源代码的频率是越来越低了。\n2026.03.04 immortalwrt主站终于恢复了\n2026.02.25 immortalwrt主站已经快挂了一周了\n2026.01.12 EvoltionX最先合并了Android16 qpr2\n2025.12.20 steam今天全面推64位了,steamtools等劫持steamworker api工具全部失效\n2025.12.08 hugo博客的最后更新时间lastmod使用:git,将产生bug,返回空数值，导致博客的最后更新时间显示为0001-01-01\n只能用个偏门的方法来修这个问题了,hugo对git info的支持简直就是一坨,只能先写一个脚本,把所有文件的修改日期改成git info里面的提交日期,然后在每次build前执行一遍脚本了\n2025.12.07 cloudflare ui界面更新了，感觉网站的寻找效率更高了\n2025.12.03 11月12日 Google:我们将Android16 qpr1源代码开源\n12月2日 Lineageos:我们完成了Lineageos23.1对Android16 qpr1的适配\n12月3日 Google:我们将Android16 qpr2源代码开源\n随后Lineageos:Google！！！F**k you\n2025.12.02 愈战愈败,愈败愈战,愈战愈败败败败败\u0026hellip;\u0026hellip;\u0026hellip;.\n2025.05.02 也是给手机刷上windows了(第一次看见手机刷windows还是在初中,直想尝试，但当时手上没有适配了uefi的设备)\n您的浏览器不支持视频播放 2025.07.05 成功为我的小米12s编译出来了类原生系统(一直有这个想法，但以前电脑配置不够，没办法弄) 生活 2026.06.15 体育课白跑一趟。\n2026.02.26 幸好在开学前一天,银行卡的解封申请通过了\n2026.02.25 和昨天一样，一下子把仙王的日常生活的后面两季看完了，不得不说，攒了几年的番，一个下午看完，真的是太爽了。到时候顺便把狐妖小红娘也给补了。\n2026.02.24 想当初刚看伍六七的时候还是初中，当时还只出了一两季。后面因为学习忙，就没怎么看。现在伍六七已经出到第5季了，感觉时间过得真快。一个下午把后面的剧情全给看完了，可惜第6季已经快一两年了，还没有出。\n2026.02.14 文字有时或许是填补空虚的唯一途径\n2026.01.22 我靠，大一上就英语挂科了,我真的是没招,英语真的是我的一生之敌呀。看来保研是不用想(虽然本来也没怎么想),这一学年的评奖评优和入党也没戏了。现在只希望补考能过。\n2025.01.01 不同的年龄段看同一本书，每个时期能感受到的东西都不一样。\n2025.12.26 燕云已游玩365天\n2025.12.25 ai是个很神奇的东西,可以让聪明人工作效率翻倍,也会让蠢人变得更蠢(或者说ai把他们蠢的一面表现出来了).网上已经出现有一大堆人用ai说的话来作为论证材料的了,无语了\n2025.12.15 真的是老了，刚开始看小说都是挑500万字以上的看，现在只能看得下一两百万字的轻小说了，成长周期太长的小说，现在有点看不下去了，有点浮躁了。\n2025.12.08 666\n2025.12.06 牢了青几个小时,终于打过了\n2025.12.05 打燕云的boss青，打的有点红温了\n2025.12.02 拔个河能把我的腰扭伤，脆皮大学生竟是我自己\n2024.06.12 趁国补入手新电脑，6700买了机械革命蛟龙16pro,r9-8945hx + 5070,32+1tb\n","date":"2025-12-02T00:00:00Z","permalink":"/p/talk/","title":"随记"},{"content":"前言 有一次在linux.do上逛的时候,发现了一个有趣的项目(page-agent),可以用自然语言让ai控制网页，不像传统的自动化网页方案，需要利用Python使用有头或者无头浏览器之类的。这个项目直接是作为js脚本，直接可以嵌入或hook在浏览器中,不需要依赖Python或者其他的东西,更简单易用，好上手。 思考 不过很可惜，原项目是完全基于网页dom文本化的操作方案，网页上的图片信息并不会输出在给ai的文本信息里面，也就是说无法识别网页图片，并且在在网页的文字识别上也加了很多限制，有时候有一些网站的有效信息无法被正常识别。于是乎我想研究一下，看一下能不能在原项目的基础上，让它支持识别图片，并且可以识别更多的网页文字。在经过几天的努力，也是终于把这两个问题给搞定了。\n改进方法 一、让 AI 识别图片：将图片链接注入 DOM 树 原项目在生成 DOM 树字符串时，默认的属性白名单 r 中 不包含 src，因此 \u0026lt;img\u0026gt; 标签的链接不会传递给 AI。此外，图片元素通常不被标记为“可交互”，导致其属性在 F() 函数中根本不会被提取。\n修改步骤：\n将 src 加入属性白名单\n在 flatTreeToString 函数的开头，r 数组中添加 'src'，这样 src 属性就会在 matchAttributes 中被匹配并输出。\n在 dom_tree_default 的 F() 函数中手动提取 \u0026lt;img\u0026gt; 的属性\n原代码只有满足 k(e)（交互元素）或 iframe/body 的元素才会提取属性。我们在 F() 中增加一个分支：当 e.tagName.toLowerCase() === 'img' 时，手动将其所有属性复制到 r.attributes 对象中。\n在 flatTreeToString 中为 \u0026lt;img\u0026gt; 特殊输出\n在 u() 函数中，当遇到 e.tagName === 'img' 时，直接输出 \u0026lt;img src=\u0026quot;...\u0026quot; alt=\u0026quot;...\u0026quot; /\u0026gt; 格式，并附带 [图片链接: ...] 标记，便于 AI 识别。为了避免输出 data:image 等内嵌图片，用正则过滤掉 Base64 链接。\n效果：\nAI 收到的 \u0026lt;browser_state\u0026gt; 中会出现如 [图片链接: https://example.com/photo.jpg] 的信息，AI 知道这是一张图片，可以调用后续的工具来识别。\n二、突破文字识别限制：移除文本节点的可见性过滤 原项目对文本节点的输出设有多重限制：\nl(e) 检查：若文本位于可交互元素内部则跳过。 isTopElement 检查：只有父元素是“顶层元素”（未被遮挡、不在视口外）时才输出。 isVisible 检查：父元素必须可见（offsetWidth/Height \u0026gt; 0 且 CSS 未隐藏）。 这些限制导致许多嵌套较深或位置特殊的文本（如 Monaco 编辑器内的代码、被 overflow: hidden 包裹的内容）无法被 AI 读取。\n修改步骤：\n移除 l(e) 检查：在 flatTreeToString 中删除 if (l(e)) return; 这一行。 移除 isTopElement 检查：将文本输出的条件从 e.parent.isTopElement 改为直接忽略，只保留 e.parent.isVisible（或完全去掉，保留所有可见文本）。 放宽 x(e) 函数：在 dom_tree_default 中，将 x(e) 改为始终返回 true，让所有文本节点都被视为可见，不会被丢弃。 可选：移除 C(e) 中的尺寸检查：如果希望进一步解除限制，可将 C(e) 中的 offsetWidth \u0026gt; 0 \u0026amp;\u0026amp; offsetHeight \u0026gt; 0 条件改为始终 true，但这会导致大量不可见元素被纳入，建议谨慎。 效果：\n现在几乎所有可见的文本节点都会被输出，包括代码编辑器内部的代码、被遮挡的说明文字、侧边栏小字等。AI 的上下文信息量显著增加，但同时 token 消耗也会上升，可根据实际场景调整。\n三、让 AI 自主调用图片识别工具 仅让 AI “看到”图片链接还不够，还需要让它能够理解图片内容。我们增加一个自定义工具 recognize_image，AI 可以调用它来识别指定 URL 的图片，并将结果写回图片的 alt 属性。\n工具定义（使用 Zod 进行参数校验）：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 recognize_image: { description: \u0026#39;识别指定 URL 的图片内容，将识别结果写入该图片的 alt 属性，并返回描述文本。\u0026#39;, inputSchema: z.object({ imageUrl: z.string().url(), }), execute: async function (input, { signal }) { const { imageUrl } = input; // 优先尝试直接使用 URL，失败则转换为 Base64 // 调用视觉 API（如 Qwen-VL、GPT-4V 等） const response = await fetch(\u0026#39;...\u0026#39;, { ... }); const description = ...; // 从 API 响应中提取描述 // 查找页面中对应的 img 元素，写入 alt const img = document.querySelector(`img[src=\u0026#34;${imageUrl}\u0026#34;]`); if (img) img.alt = description; return `图片识别完成，描述为：“${description}”`; } } 总结 于是乎，在经过了以上这些操作，成功让原项目支持了图片识别以及解除了一些网页文字识别的限制。以下是我改进版的仓库地址 https://github.com/iliaoke/page-agent\n","date":"2026-06-14T00:00:00Z","permalink":"/p/pageagent/","title":"Page-agent项目改进日志"},{"content":"前言 弄到了一个白嫖的校园网账号,但是触发设备连接上限了(电脑只要开热点，wifi就无法访问互联网),我手机电脑无法同时连接,于是便有了接下来这篇教程\n原因解析 当电脑连接WIFI的时候,网络适配器中的wlan网卡便是已连接的状态 此时我们打开热点,在网络适配器中会自动创建一个新的本地连接的网卡 在默认情况下,热点的网卡会自动寻找可以访问互联网的网卡，作为上级网卡. 但是由于校园网有检测,当热点网卡的流量转发到wlan时,校园网就会检测到有多个设备，从而断开访问 解决方法 通过手动设置热点网卡的上级网卡到其他的网卡,然后其他网卡的流量(经过这个网卡，对流量进行处理)再流入wlan,这样便不会被校园网检测. 于是我们便要用到clash/singbox这样的代理工具的tun模式创造另外一个网卡(其实也可以用wintun驱动手动创建,不过得手动配置一些东西，比较麻烦) 不一定需要添加clash的代理配置文件,只要打开tun模式即可. 此时网络适配器中将会多出一张其他的网络设备 此时右击该网卡属性点击共享，然后设置共享的网络为本地连接(相当手动指定热点的上级网络),便可以实现绕过校园网检测 ","date":"2026-03-09T00:00:00Z","permalink":"/p/bypass-campus-wifi/","title":"最简单的绕过校园网多设备热点检测方案"},{"content":"原理解析 (特别注意:有一些路由器的系统是不支持设置vlanid的,所以建议所有路由器都为openwrt软路由，方便操作.)\n在传统方案中,当光猫设置桥接模式,软路由负责拨号,此时光猫的其他网口在正常情况下是无法工作的,因为光猫此时只做光电转换，不做路由ip下发.\n此时我们便需要用到一项技术实现光猫在桥接模式下光猫的其他网口也能正常工作.这便是vlanid.vlanid并不只有单线复用这一个功能,它也可以用来划分局域网,从本质上来讲，它的作用就是给流量打上标记.\n当光猫桥接主路由拨号时,其他房间网口的流量是流向光猫的网口,在流量没有打vlanid标识的情况下，光猫也不知道要把这些流量弄到哪里去,所以光猫其他网口便无法正常通讯.\n所以这个时候我们便用vlanid来实现单线复用(即一条网线，负责实现两个功能,也就是说我们主路由与光猫连接的那根网线既负责主路由的拨号，又负责主路由dhcp服务器下发ip到光猫的其他网口),我们在其他网口的房间里的路由器里面设置vlanid,然后在光猫的管理员后台里也设置的vlanid,最后在主路由里面设置一样的vlanid.就这样在三台设备中都设置了vlanid,设备就知道这些流量该如何传输.\n具体操作 在房间的子路由中把wan接口删除,只留lan口,然后在设备中添加连接网线的网口的vlan设备,然后把这个设备添加到br-lan的网桥设备集合之中 在光猫的管理员后台(不同的型号的光猫进入管理员后台的方法不同，有一些甚至进不去管理员后台，这里就不细讲了),把对应连接方式的lan口绑定全部取消,然后设置对应网口的vlanid和vlan绑定 以上这张图中，网络连接二是用于主路由和光猫拨号的，而网络连接五则是用于设置vlanid来实现单线复用的。\n在主路由进行和子路由中一样的操作,只是这一次不用把wan口删除了,把wan口对应的连接端口设置vlanid,然后也一并添加到br-lan中即可完成配置 完成了以上三个步骤,就可以实现光猫在桥接模式下，房间的子路由仍然可以接收到主路由下发的ip了\n","date":"2026-02-25T00:00:00Z","permalink":"/p/openwrt-vlan/","title":"openwrt25.10设置vlan实现单线复用"},{"content":"2026年软路由系统分析和推荐 截止到目前为止,还在持续维护更新的软路由系统有openwrt系,ikuai,RouterOS.\n三大系统简述 ikuai系统不开源,可玩性和软件生态上比openwrt和RouterOS差,但是稳定,适用于对稳定性和兼容性要求比较高的工作环境，比如说企业. Routeros系统是开源的,基于linux,但是软件生态和可玩性也不如openwrt,Linux内核版本也较低,主打的也是偏稳定向的. openwrt系统是开源的,相当于阉割魔改版之后的linux（linux可以干的,openwrt通过补全环境和其他方法，基本都可以干,如docker,php,python等）,且积极更新Linux内核和对应s组件依赖,社区力量和软件包是远远大于另外两个软路由系统的,由于openwrt系统非常轻量，所以适配的硬件特别广.而另外两个软路由系统对硬件的要求多相对较高,而openwrt各种嵌入式设备也可以刷入,很多厂商的硬路由openwrt也会适配.所以对于个人玩家来说,强烈推荐openwrt系. openwrt系分支 而openwrt系又主要分openwrt官方系统,immortalwrt,kwrt,lead,x-wrt,istoreos\nopenwrt官方系统: 是所有其他分支的源头，更新速度最快,但是软件包源服务器是在国外，国内用户无法直接更新里面的软件包,而且官方服务器里面的软件包数量很少.\nimmortalwrt: 基于openwrt源代码轻量改动,可以看成openwrt中国特供版,而且极大的丰富了软件包数量,有很多github上面的第三方的软件包，以及把软件包服务器改成了在国内,还有一些其他的优化以及添加了更多的硬件支持,但是每当openwrt新的版本出来,immortalwrt需要过一小段时间才能适配完\nkwrt: 基于openwrt,可以看成在openwrt源代码的基础上，自己写了一套代码流程来自定义一些东西,有自己自建的软件仓库,里面软件的数量是openwrt系里面最多的,构建系统镜像的时候还可以提前自定义后台IP地址，宽带账号之类的东西,但是魔改的比较多，特别容易出bug（比如我的r2s固件直接开不了机）,而且这个系统作者的名声在圈内不太好,合并上游系统速度还算及时(immortal需要一点时间)\nlede: 准确来说是lean的lede,最原始的lede是openwrt里面分出来，后面又重新与openwrt合并,而github上面的lede是lean(作者)基于最后的lede源代码的个人维护版本,也就是说基于的openwrt主线版本已经十分老旧了,这个系统的优点是有一些闭源驱动，性能非常强大,但由于已经和新版的openwrt代码相差很大，所以很多软件包已经不兼容了.\nx-wrt: 基于openwrt的主线分支(不是release分支),所以代码更新速度很快,有自己的软件仓库，国内用户可以直连,相对于官方的系统，已经内置集成的一些功能\nistoreos: 基于openwrt以前的分支,一般不会基于最新的主线分支，一般会隔一两个大版本,有自己的软件源，国内用户可直接连,主要就是ui和功能改动,openwrt官方系统或其他分支系统也可以安装istoreos的软件包来实现成istoreos的ui和功能.主打的是将路由器和nas结合，里面内置了很多跟nas有关的功能。\n结论 综上所述目前软路由系统，我个人推荐openwrt系,openwrt系里面结合更新速度和软件包数量以及稳定性,lede基于的主线版本太老,istoreos更新上游的速度较慢,kwrt魔改openwrt有点多(不是基于源代码魔改),稳定性较差.x-wrt特色不是很强,所以我个人综合起来更推荐immortalwrt\n","date":"2026-02-18T00:00:00Z","permalink":"/p/routeros-choose/","title":"2026年软路由系统分析和推荐"},{"content":"关于LLM的几种工具扩展方法的区别和见解 LLM本身只能当做聊天对话机器,他只可以接收对话，然后返回回答,本身是不能干任何额外的事情.\n我们使用ai的一些扩展功能，比如联网搜索和其他的工具本质上是让AI返回指定参数,交由外部工具去完成,然后在拿外部工具执行到的信息作为上下文,再返回给AI,llm只是决策者而并非执行者,工具真正的逻辑执行部分和判断部分需要人为的完成.\n而市面上主流的LLM主要有以下几种方法扩展工具\n1.Tool Calls(很少使用) 这个是一些大语言模型本身自带的功能,可以让用户自定义一段工具介绍，然后让LLM在适当的时候返回工具调用的结构体,然后由用户解析结构体执行程序之后，再返回获取到的结果来完善上下文\n缺点: LLM和工具的衔接部分需要自己人为书写,比如需要判断LLM有没有返回工具调用信息,如果返回了，要根据返回的信息进行选择调用,写的工具越复杂，衔接部分需要花费的时间就越大,并且不同的模型的Tool Calls返回的信息可能还有所不同，不同模型的Tool Calls标准不一样，同一个工具需要对不同的模型单独做适配,所以并不流行(不过算是最早的给llm扩展工具的方法)\n2.Mcp(流行) 这是一套严格的标准,不会像Tool Calls一样可能因为模型的问题，返回的结构体有所差异,有mcp客户端,还有mcp服务器,工具的连接方式有远程，也有本地调用,是一套很完善的规则.\n缺点: 因为调用流程过于严谨和繁琐,所以很容易引起llm上下文直接爆炸,让llm抓不到重点,对话越到后面效果越差。部署和开发也相对麻烦,因为有服务端，客户端，还有一些七七八八.而Tool Calls,可以直接在一个片段代码里面完成开发.\n3.Skills(流行) 这个是最近claude推出,我对他的理解是最高级别的prompt,这个严格来说并不是一个标准,而是共识,更偏向于一个技术理念,需要IDE自己去实现这个理念（Claude开源了他们官方skills的实现）,不像mcp和Tool Calls是有一定的标准的,要严格按照官方的标准来。\nSkills某种程度上来说和Tool Calls有点类似,但是他不需要写LLM和工具之间的桥接代码,并且还可以完成一些prompt才可以做的事，比如说自定义一下语气和注意事项.\nTool Calls每写一个工具，我需要自己再写程序去判断LLM返回的工具调用信息，然后再去执行运算(并且还可能因为不同的模型返回的信息有差异而导致兼容性问题),而放到Skills,我只需要自定义一段话,不需要写具体的代码(工具本身是要写代码的，只是调用不需要写代码),比如在特定的时候执行某个文件目录下面的某个代码片段传入某些参数,相当于把桥接部分交由了程序本身(如Vscode和windsurf)去执行,所以说需要程序去适配Skills,它是共识和理念，而不是一套标准.(不过当流行起来的时候，共识理念最终也会成为大家默认的标准)\n总结 总结:以上三种给LLM扩展工具的方式,我个人对未来最看好的是Skills,我认为把这套逻辑和共识再进行优化加强是完全可以比过Tool Calls和mcp。Tool Calls桥接部分比较麻烦,一切运转都要依靠代码,还有兼容性问题;mcp开发部署繁琐,且容易引起上下文爆炸,LLM运行缓慢.Skills恰好能解决这两者的缺点\n","date":"2026-02-02T00:00:00Z","permalink":"/p/llm-tool-calls/","title":"我对几种LLM扩展工具的区别与使用心得"},{"content":"Hugo 全自动修正文章修改时间的最佳实践（Serverless 场景） 在使用 Hugo 构建静态博客时，文章的修改时间（Last Modified Time） 是一个非常重要但又容易踩坑的问题，尤其是在 Serverless / CI 自动部署 场景下。\nHugo 官方目前提供了多种用于确定文章修改时间的方式：\nHugo 支持的修改时间来源 :filemodtime\n使用文件本身的最后修改时间作为文章的修改时间。\nlastmod\n需要在文章 Front Matter 中手动维护 lastmod 字段。\n:git\n使用 Git 中该文件的最后一次提交时间作为修改时间（依赖 gitinfo）。\ndate\n使用文章的发布时间作为修改时间。\n各方案的自动化可行性分析 在上述方案中：\n✅ 可自动化\n:filemodtime :git ❌ 不适合全自动\nlastmod（需要人工维护） date（语义不符） :filemodtime 在 Serverless 场景下的问题 使用 Hugo 的一个重要原因，正是为了 方便地将网站部署到 Serverless 平台（如 Cloudflare Pages、Vercel、Netlify 等）。\n然而在 Serverless / CI 场景中：\n每次部署都会重新 git clone 仓库 所有文件的 文件系统修改时间 都会变成「拉取时间」 这会导致： 所有文章的修改时间被错误地更新为“本次部署时间” 完全失去文章真实修改时间的意义 因此，:filemodtime 在默认情况下并不适合 Serverless 场景。\n:git 方案的现实问题 理论上，:git 是最理想的方案：\n修改时间与 Git 提交严格一致 完全自动化 不依赖文件系统时间戳 但在实际使用中：\n即使开启了 enableGitInfo = true 某些情况下 :git 无法正确生效 在 CI / Serverless 环境中尤为明显 不确定这是环境限制、Git shallow clone、还是 Hugo 本身的 Bug，但结果是：该方案在实践中不够稳定。\n最终解决方案：修改文件时间戳为Git 提交时间 + :filemodtime 综合以上问题，我最终总结出了一套最适合 Serverless 管理的全自动方案：\n核心思路 在 Hugo 构建之前，将文件的修改时间戳“伪装”为 Git 最后提交时间。\n具体流程如下：\nHugo 中使用 :filemodtime 作为文章修改时间来源 1 2 [frontmatter] lastmod = [\u0026#39;:fileModTime\u0026#39;] 将脚本放在文件夹根目录 将自动执行脚本的命令和正式部署命令合二为一(这里需要注意的是一般的serverless平台拉取项目只是浅层克隆不会把文件的最后提交信息给拉取过来，所以我们要在最前面要执行完整的拉取命令。) 1 git fetch --unshallow \u0026amp;\u0026amp; chmod +x 1.sh \u0026amp;\u0026amp; ./1.sh \u0026amp;\u0026amp; hugo 这样就可以做到：\n✅ 修改时间与 Git 提交时间一致 ✅ 完全自动化 ✅ 与 Serverless / CI 环境完美兼容 自动同步 Git 提交时间到文件修改时间的脚本 下面的脚本用于：\n将当前目录下所有文件的最后修改时间，统一修改为对应的 Git 最后提交时间\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # （此处放置你的脚本内容） #!/bin/bash # git-set-filetime.sh # 功能：将 git 仓库中所有被追踪文件的修改时间改为最后一次提交时间 # 确保当前目录是 git 仓库 if [ ! -d \u0026#34;.git\u0026#34; ]; then echo \u0026#34;Error: 当前目录不是 git 仓库根目录\u0026#34; exit 1 fi # 获取所有被追踪文件（包含特殊字符/空格/中文） git ls-files -z | while IFS= read -r -d \u0026#39;\u0026#39; file; do # 获取最后一次提交的 Unix 时间戳 timestamp=$(git log -1 --format=\u0026#34;%ct\u0026#34; -- \u0026#34;$file\u0026#34;) if [ -n \u0026#34;$timestamp\u0026#34; ]; then # 使用 touch 修改文件修改时间 # -d \u0026#34;@$timestamp\u0026#34; 表示从 Unix 时间戳设置时间 touch -d \u0026#34;@$timestamp\u0026#34; \u0026#34;$file\u0026#34; echo \u0026#34;Updated: $file -\u0026gt; $(date -d \u0026#34;@$timestamp\u0026#34; \u0026#39;+%Y-%m-%d %H:%M:%S\u0026#39;)\u0026#34; else echo \u0026#34;Skipped (not tracked): $file\u0026#34; fi done echo \u0026#34;All tracked files\u0026#39; modification times updated.\u0026#34; ","date":"2026-01-25T00:00:00Z","permalink":"/p/hugo-add-lastmod-to-posts/","title":"Hugo自动修正文章最后修改时间的最佳方案"},{"content":"Android Root 发展历程和方案分析 Android Root 顾名思义即给安卓系统获取根权限，让用户拥有系统级权限，极大提升系统可玩性。\n一般来说，Root 需要先解锁 bootloader（BL），解锁的目的，是让用户有权限刷写各个分区，从而能：\n更换系统（system / vendor / product 等） 更换内核（boot ） 注入 Root / 模块方案 注意：解锁 BL ≠ 必然 Root，也可以只刷机不 Root。\n主流 Root 方案按时间大致可以排成这样：\nKingRoot → SuperSU → Magisk → SKRoot（小众） → KernelSU → APatch\n一、Root 实现思路：按技术路线分类 用户态 Root（User-space Root） 不直接修改内核代码 修改 boot.img → ramdisk → init 脚本，在早期启动阶段插入自己的用户态 root 程序 通过 用户态守护进程 管理权限（例如 magiskd） 一般依赖一个 管理 App 配合使用（授权弹窗、模块管理等） 代表方案：Magisk 优点：对内核无强依赖，兼容面最广 缺点：本质不在内核，某些内核安全策略/厂商定制下会有局限 内核态 Root（Kernel-space Root） 直接在内核中 Hook 权限相关函数 / LSM / syscall 在内核层修改 cred、capabilities 等结构，获得最高权限 部分方案需要内核源码（早期 KernelSU），部分不需要（APatch、SKRoot） 代表方案：KernelSU、APatch、SKRoot 优点：权限层级最高，可做更“隐蔽”和细粒度的控制 缺点：与内核版本/厂商定制强相关，适配成本较高 漏洞 Root（Exploit-based Root） 利用系统或内核漏洞临时/半永久获取 Root 通常依赖特定 Android / 内核版本，系统一更新就失效 代表方案：KingRoot 等一键 Root 工具 优点：用户体验简单，历史上对锁 BL 的机器也有机会 缺点：完全吃漏洞红利，维护性差，安全风险高 二、按时间线看典型方案 KingRoot：漏洞驱动的早期 Root 主要活跃在 Android 4.4 ~ 6.0 时代 通过 内核 / 系统漏洞（如提权漏洞）获得 Root 多为 临时或半永久 Root，重启或 OTA 后经常失效 随着漏洞不断被修复，这类方案很快被淘汰 定位：\n完全基于漏洞的时代产物，如今更多是历史意义。\nSuperSU：system 分区注入 su 的经典方案 思路：直接修改 system.img，在 /system/bin 或 /system/xbin 注入 su 二进制 通过 su 的 setuid 机制实现提权 典型适用 Android 4.x ~ 6.x，system 还比较“好改”的时代 随着： system 分区逐渐只读 / 受更严格完整性保护 Magisk 引入 systemless Root SuperSU 很快失去优势。\n定位：\n传统“改 system.img 注入 su”的代表\nMagisk：用户态 systemless Root 的时代 Magisk 把 Root 方式拉到了一个新高度。\n核心实现 修改 boot.img → ramdisk → init： 用 magiskinit 接管早期启动，作为“第一个用户态进程” 启动 root 守护进程 magiskd /system/bin/su 在 Magisk 中 只是前端/中转： 解析参数 → 连接 magiskd → 由 magiskd 以 root fork/exec 真正的命令 提权的决策和执行在 magiskd 中完成，而不是在 su 本身 不在 system 分区直接写入文件，做到 systemless\n（实际上是用挂载/覆盖的方式“虚拟出”修改过的系统视图） 关键特点 首创 magic mount 模块系统： 在不实际修改系统文件的情况下，实现对 /system、/vendor 等目录的文件覆盖 极大提升“玩机模块生态” 强兼容性： 只要能改 boot.img中的init脚本，大多数内核版本都能使用 依赖管理 App（Magisk App）： 管理模块、处理 su 授权弹窗、升级/卸载 局限 纯用户态方案，需要搭配app 模块生态与内核态模块（如 APatch 的 KPM ）相比，在内核能力利用上略逊一筹 不支持kernelsu后来的模块webui功能,需要额外安装app解决 SKRoot：早期“内核 Root + su 环境注入”的探索者 时间上早于目前主流内核 Root（KernelSU / APatch） 无需内核源码： 离线分析目标内核镜像（ELF/镜像格式） 找到如 do_execve 等关键函数与 task_struct/cred/seccomp 的偏移 插入自定义 shellcode 实现内核级提权 号称“隐藏性很强”： 没有模块系统 常见用法是：针对单个或少数进程注入 su 环境 通过 PATH / so 寄生等方式，让特定 APP 获得 su，而不是全局暴露 适配范围：大致 3.10 ~ 6.6 内核 优点：\n不依赖内核源码，适配范围相对广 su 环境可以“定向注入”，对其他进程很隐蔽 缺点：\n没有完整的模块系统，操作较繁琐 生态小众，文档和社区支持相对较弱 KernelSU：主流内核态 Root + overlayfs 模块 基本定位 代表性的 内核态 Root： 在内核中安装 hook（LSM / cred 修改等） 在执行 /system/bin/su 时，内核直接修改进程 cred 实现提权 /system/bin/su 在 KernelSU 中是真正的 提权入口： 它触发内核 hook 提权是在内核里完成的，而不是转发给某个守护进程（区别于 Magisk） 技术路径演进 早期：通过 谷歌GKI 内核（已被官方淘汰） / 内核源码集成（已被官方淘汰） 集成 KernelSU 现在主流：LKM（ko 模块）方式： 把修改封装成内核模块加载进 GKI 内核 同一大版本Gki内核编译出来的ko模块具有一定通用性,所以安装体验上不需要内核源代码 但 ko 的编译仍依赖内核的源码，只是这部分由项目方/维护者完成 对用户体验来说“不需要自己改源码” 模块系统：元模块（支持overlyfs/magic mount或者自定义挂载方式） 默认使用 overlayfs 实现模块系统(首创)： 支持对 /system 等只读分区做“上层覆盖”(模块安装后通常需要 重启才能生效对/system的修改) 对比 Magisk 的 magic mount： overlayfs 是内核特性，语义更标准 但实时性稍差，多数变更需要重启 特点与限制 特点：\n内核态 su：安全模型清晰，可做细粒度 App profile（按 UID/GID 控制权限大小） 官方overlayfs 模块系统：结构正规，可与 GKI 思路统一 限制：\n对低版本 / 非 GKI 内核兼容性差 一些魔改了内核且不开源的gki设备对谷歌官方gki内核支持差,刷了可能开不了机 官方更推荐搭配 5.10以上的 GKI 内核搭配ko模块使用 APatch：无需源码的 kpimg 内核 Root + KPM 模块 在内核 Root 方案中，APatch 的技术路线是目前最“工程化 + 通用”的一类。\n核心实现方式 仍然是 内核态 Root，但： 不需要内核源码 使用 KernelPatch 工具链解析并 patch 目标内核镜像 通过在内核镜像中注入 kpimg： 修改内核启动入口 / early init 流程 把自定义 hook 注入到内核的启动过程 重启后，kpimg 会在早期阶段接管部分逻辑，实现： Root 提权 内核 hook（supercall / inline hook） 启动用户态守护/事件（apd 等） 兼容性 内核版本范围广：3.18 ~ 6.12 不依赖 GKI，不要求厂商公开内核源码 对各家定制内核更友好（因为是直接对内核二进制镜像做符号分析与 patch） 特点 KPM 内核模块：\n在已经被 kpimg 接管的内核里，动态加载 KPM 模块 支持对内核函数进行 hook，部分 hook 即时生效 无/system/bin/su文件，通过监听拦截/system/bin/su或su指令来实现提权 模块系统 + Lua 脚本：\n用户态 apd 管理模块目录、事件（post-fs-data / boot-completed 等） 最新版本中可以用 Lua 替代传统 shell 脚本，增强复杂逻辑可维护性 不依赖内核源码的工程化链路：\n用 tools/kallsym.c、tools/patch.c 等做符号解析、patch 用 kernel/patch/android/user_init.sh 等把 apd 接到系统启动阶段 支持kernelsu的元模块挂载方案(2026.1.12补)\n三、综合对比与结论 技术路线对比（简表） 方案 类型 是否改内核代码 是否需源码 是否依赖 App su 角色 模块系统 KingRoot 漏洞 Root 否 否 需要 各家自定义 无 / 简单补丁 SuperSU system 注入 su 否 否 可选 传统 setuid su 无 Magisk 用户态 Root 间接（不改内核） 否 强依赖 /system/bin/su中转到 magiskd magic mount SKRoot 内核 Root 是（patch 镜像） 否 有工具/库 隐藏 su + 进程定向注入 无完整模块系统 KernelSU 内核 Root 是（源码/GKI/LKM） 技术层面上需要 App 非必须 /system/bin/su 触发内核提权 元模块 APatch 内核 Root 是（kpimg patch） 否 App 非必须 内核 hook su/execve 等 APM/KPM + Lua 目前最主流的三款root方案分析 Magisk：\n适合追求 广泛兼容 + 成熟模块生态 的用户，一般设备能解锁 boot.img 就能用。\nKernelSU：\n适合有 GKI 内核，且希望在内核层面细控 Root 权限（App profile）的人，\n更偏“官方化”的内核模块方案，但对旧机型支持有限 可以自定义挂载\nAPatch：\n从技术理念上最“硬核”，不依赖源码、支持广泛内核版本，\n内核模块 hook + Lua 模块系统，对研究者 / 高级玩家非常友好。\n","date":"2025-12-09T00:00:00Z","permalink":"/p/android-root/","title":"Android Root 的演进与抉择"},{"content":"前言: 用ai也用了这么久了,今天想谈一下自己对AI的理解.从chatgpt刚问世开始,我就在开始使用大模型.也算是最早使用大模型的那批人.随着大模型的发展愈演愈烈,也衍生出了很多分支比如AI IDE,应用内集成AI聊天助手,大模型识别图像等等.\n而随着AI能干的事越来越多,有些人产生了自我怀疑(我能做的事AI都能做,那还需要我干什么),而另外一部分人则产生了依赖(你看ai都是这么说的了(盲目相信AI)).\n而我也用大模型用了这么久了,今天便在这里谈一下我自己的认知\n我的认知 我始终认为Ai始终是作为一个工具,用来提升工作效率,而非核心.大模型本身的特点就注定了有一些工作是无法代替人类.比如项目的一些宏观设计和管理,一些最新的技术的使用和获取.它是一个超大知识的集合体,它的作用是降低我在知道该怎么做的情况下，让我避免去查代码文档，一步一步慢慢实现功能所带来的时间成本.而不是想做什么，跟AI说一句话，让他帮我实现就行了,我们要做的是工程师，是设计师，而不是让AI作为核心，我们负责提要求。不然就相当于我们是甲方，AI是乙方。我们应该当的是boss，是甲方,AI当我们底下的员工，来负责完成我设计的东西（乙方需求）。\n所以在我看来,使用AI无非就两个档次 初级者:什么都不懂,只知道自己想要什么,反正让AI完成就行了。(这在学习的初期确实可以很快带来成就感,但始终无法避免一个问题,你不懂的始终不懂，懂的是AI而不是你,你并没有任何的核心竞争力) 真正掌握AI的人:自己设置架构，自己设置语法要求,自己设置UI层级和UI设计风格,规定使用的技术栈,让AI按照自己的规定去完成对应的工作。AI是提升效率的工具，而不是自己的大脑,真正应该怎么做，应该是自己知道，而不是AI知道。 所以在这个时代,有人害怕ai,有人依赖AI,那我的答案是掌握AI. ","date":"2025-12-09T00:00:00Z","permalink":"/p/ai-understanding/","title":"谈谈我对AI的一些理解"},{"content":"AI IDE 工具推荐 为什么使用 AI IDE？ 传统 AI 聊天无法： 实时读取本地文件 兼顾项目的宏观框架管理 偏商业化的 AI IDE： 一般不允许自定义第三方服务商接口 强制使用平台模型收取订阅费 实时读取本地文件 适配开发的执行流程与逻辑 因此，为了高效开发和项目管理，需要使用 AI IDE。\nAI IDE 的能力评价指标 硬实力：自带模型能力 软实力：上下文补全与逻辑能力 通过插件、执行策略、隐藏的上下文prompt 等实现 两者缺一不可 AI 编程工具分类 1. CLI 命令行AI开发工具 开发效率比 IDE 差 文件引用需手动输入 不适合宏观项目管理 适合单一功能的改进 代表工具： OpenAI Codex★★★(也有vscode 插件版本,但开发效率不如集成式ai ide,仍然是片段式更改) Claude Code★★★(也有vscode 插件版本,但开发效率不如集成式ai ide,仍然是片段式更改) OpenCode（开源）（可自定义服务商接口，但上下文能力较弱） 2. IDE AI 开发工具 直接从文件管理器拖入文件即可 支持项目级宏观管理 国内 AI IDE Trae 特有 Solo 模式（和普通模式感觉主要是 UI 差别，在功能上感觉差的不是很大，可能隐藏 prompt 有所优化） 可使用规定的国内其他服务商接口 Qoder 无特色 上下文消耗快 无法使用国外模型或其他接口 通义灵码 无特色 无法使用国外模型或其他接口 国内 IDE 的共性 喜欢构建工作区文件全量索引，每次提问前先查索引文件，消耗大量上下文 token，有时查找的文件过多反而忽略关键问题 国内模型编码能力较弱，且不允许使用国外更强的模型 方便支付订阅, 界面中文支持较好 国外 AI IDE GitHub Copilot★★\nVSCode 插件形式 适合片段式的文件 上下文补全能力较弱 无法全面定制化 Cline★★（开源）\n可自定义任意服务商 VSCode 插件形式 适合片段式的文件 上下文补全能力较弱 无法全面定制化 Kilo（开源）\n可使用规定的第三方服务商api VSCode 插件形式 适合片段式的文件 上下文补全能力较弱 无法全面定制化 Cursor★★★\n基于 VSCode 深度定制 自研模型 Composer 1 (专为编程训练, 功能强大) 可使用规定的其他服务商 API agent可以直接连接github远程储存库(特色功能) 预设 Prompt 优秀输出质量高，但免费额度少，订阅贵 亮眼功能： 浏览器设计模式：可以直接在ide里面打开网页，并且选择元素，方便设计网页 debug：可以根据log寻找隐藏bug kiro 电脑安装闪退，我用不了(哭)\nWindsurf★★★\n基于 VSCode 深度定制 自研模型 SWE-1.5 (专为编程训练, 功能强大) 亮眼功能： Memories：可以根据对话和习惯生成对应的记忆（ai自动生成记忆，以在对话之间保持上下文连贯性） DeepWiki：独家功能,定位项目中关键函数或变量，了解用途和在项目其他地方引用 (方便学习他人的开源项目) CodeMap：独家功能,用于分析现有项目代码结构,可以根据输入的问题生成项目代码实现的流程图,点击流程图可以定位对应代码实现的部分（对于解剖他人项目的功能实现很有用） 浏览器设计模式：可以直接在ide里面打开网页，并且选择元素，方便设计网页 对话消息互通：独家功能,不同对话之间可以选择互通消息，如两个不同的项目,具有一定的关联性，我们就可以通过这个功能实现两个项目在对话层面上的互通，而不需要ai去研究另外一个项目的代码，防止添加过多的内容，导致上下文混乱 免费额度高，价格便宜 支持规定的其他服务商 API Zen Editor（开源）\n可使用任意服务商接口 自带免费额度高 上下文补全能力较弱 总结推荐 综合价格、模型能力和上下文补全能力，我个人首推 Windsurf DeepWiki、CodeMap 和消息互通是其最大亮点，让其上下文补全能力非常强大 其他 AI IDE 在 UI 功能上同质化严重，差别主要在 AI 模型、执行逻辑和预设 Prompt 如果不考虑开发效率，单论编码能力,openai的codex和claude code这种命令行式开发可能是最强的一批,其次就是cursor和windsurf ","date":"2025-12-08T00:00:00Z","permalink":"/p/ai-ide/","title":"如何选择最适合你的 AI IDE 与扩展插件"},{"content":"Android内核编译 以编译5.10以上的内核为例,所需资源:\n一台配置较好的电脑 linux系统 内核源代码 编译链工具 linux系统 各大Linux系统(Ubuntu系/arch系/fedora系/Wsl2)都可以，网上教程多以Ubuntu lts版本为例(便于找依赖和教程) 内核源代码 从github上搜索自己机型的内核源代码\n如https://github.com/Evolution-X-Devices/kernel_xiaomi_sm8450(项目名一般采用 kernel_厂家名_芯片组代号 的形式,5.10之后都是gki内核,所以内核名称基本是以芯片组命名如sm8450,有些项目也可能是按机型代号命名，而不是芯片组)\n编译链工具 5.10以上的内核一般采用纯clang/llvm进行编译(低版本内核也可尝试，但有可能能成功编译但会开不了机)\nClang/llvm Clang 一般情况下采用的是google的正式分支,也可以采用测试分支\n编译过程 更新环境依赖 以Ubuntu24.04为例,执行以下命令安装依赖\n1 sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc tar xz-utils cpio findutils 克隆内核源代码和编译链工具 内核:git clone https://github.com/Evolution-X-Devices/kernel_xiaomi_sm8450.git --depth=1\n编译链工具:git clone https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86.git --depth=1\ndepth=1只拉取文件，不拉取历史提交，可以极大减少下载时间\n如果想拉取其他的测试分支，也可以在后面加-b 测试分支名字\n如拉取测试版的编译链则添加-b mirror-goog-main-prebuilts\n设置环境变量 注:以下操作需要在同一个终端环境下执行，因为添加的变量是临时变量\n此时在你的工作目录下面应该会有两个文件夹，一是内核文件夹，二是编译链工具文件夹\n打开终端,执行cd 编译链工具文件夹路径,当前目录下应该会有若干个clang-rxxxx子文件夹，选择后缀数字最大的最新版本即可,将它下面的/bin添加到环境变量中\n1 export PATH=\u0026#34;$PATH:/../../编译链工具文件夹/clang-rxxxx/bin\u0026#34; 然后再cd 内核源代码文件夹\n设置编译环境变量\n1 2 3 4 5 6 7 8 export ARCH=\u0026#34;arm64\u0026#34; export SUBARCH=\u0026#34;arm64\u0026#34; export CC=\u0026#34;clang\u0026#34; export LLVM=1 export LLVM_IAS=1 export HOSTCC=clang export LD=ld.lld export CLANG_TRIPLE=\u0026#34;aarch64-linux-gnu-\u0026#34; 如果电脑的内存不太够，可以额外设置\n1 export LTO=thin 执行编译命令 1 2 make ARCH=\u0026#34;arm64\u0026#34; gki_defconfig make -j$(nproc --all) 第一行命令是加载配置文件gki_defconfig,他所在的目录是/内核源代码/arch/arm64/configs/gki_defconfig（可以自行修改里面的配置项）\n编译出来的内核二进制文件会在/内核源代码/arch/arm64/boot/Image\n打包内核 由于没有编译kernel-devicetree,也没ramdisk,所以无法和内核二进制文件打包成boot.img刷入手机分区(也可以用magiskboot把手机原本的boot.img进行解包，把其中的内核二进制文件替换之后,再打包就行了)\n这个时候就需要AnyKernel3对内核二进制文件进行打包\n详细教程参考\nhttps://github.com/tiann/KernelSU/discussions/952\n刷入内核 可以在twrp或一些用于刷写内核的app中刷入打包后的AnyKernel3.zip\n注意 不同型号内核以及不同版本的编译器，可能对依赖和代码语法要求也有所不同，需要自行解决。\n","date":"2025-12-05T00:00:00Z","permalink":"/p/android-gki-kernel-compile/","title":"GKI 内核不完全编译实战"},{"content":"Steam假入库到底是什么？ 淘宝上有很多低价的steam游戏cdk,但购买之后实际是运行脚本入库(有自己steam账号信息泄露的风险),可以在本地游玩.（换台设备重新登录账号，假入库游戏将会被清空。）\n实际上账号并没有拥有游戏,别人是看不到你的账号拥有该游戏的\n假入库原理分析: Steam购买游戏相当于购买游戏的游玩资格，购买完成后，将会下载游戏的清单文件(相当于下载列表),然后steam会用游戏的depot key(正版购买用户自动下发)对清单文件进行解密下载,下载完成后，打开游戏会调用steamwork api进行验证当前运行的steam账号是否拥有该游戏,认证通过后即可正常游玩。\n我们可以在其中做些手脚,便可以实现假入库。\n游戏清单文件是可以公开找到的，但是需要正版账号的depot key解密才可以解密下载(游戏每一个版本的清单文件对应着一个depot key,所以想要玩到最新的游戏内容，密钥文件也需要及时更新)。假入库的商家可能会根据爬虫或者其他技术手段(如通过木马病毒从其他steam玩家账号中提取depot key)，可以搞到最新的游戏depot key\n通过解密清单将游戏完整下下来后,通过steamtool/GreenLuma hook注入自己的.dll文件,对steam原有的steamwork api进行劫持,便可以实现让游戏认为账号已经获取了该游戏的游玩权限。\n于是乎通过以上手段，便实现了一套完整的steam游戏假入库\n在steam游戏破解游玩方面,主要有两种破解方法\n一是对steam客户端进行crak 让steam认为你拥有该游戏的游玩权限,再搭配实时获取别人最新的depot key,便可实现几乎与正版购买一致的游戏体验(云存档,成就系统等等)\n弊端: 无法使用联机功能 别人看不到你库中的游戏(无伤大雅,除非你想要通过玩游戏来证明自己的老资历,在某盒软件舆论战中占上风) 系统重装后，steam假入库游戏入库数据会消失(要玩的时候重新入一下库就行了，问题不大) 典型代表: steamtool (闭源，国人大佬开发,功能强大) GreenLuma(原版纯命令行,操作较难,闭源,外国论坛发布) GreenLuma_CN(原版加上前端，方便操作) 二是对游戏文件本身进行修改 对游戏文件夹本身进行修改,内置一个模仿steam api行为的第三方轻量steam client,实现steam游戏脱离steam官方客户端运行,方便游戏在互联网上传播\n弊端: 不方便游戏新版本的更新和获取 无法使用steam官方客户端的一些功能 典型代表: gbe_fork steam-auto-crak 其他: steamlan/gbe 通过模仿steam lan api,可以实现游戏在线/离线模式下局域网联机,而不需要走steam官方服务器 steamless 移除steam端的d加密(不会绕过游戏游玩验证,并且非steam的d加密无法破解，比如说黑猴,需要使用别人的d加密密钥才可以认证游玩) 总结: Steam假入库商家通常通过劫持steam根目录的hid.dll文件进行自定义操作,hook核心一般采用steamtool,加上不知道哪里搞来的清单depot key源,由于是黑箱代码,无法准确判断是否含有其他的木马病毒,来获取自己steam的一些信息,对账号造成隐性风险,所以不建议使用淘宝上的 steam假入库。\n辨别方法: 由于steam假入库这件事已经有一定的知名度了,有些商家也学聪明了，把正版的激活流程放在介绍页，然后下面配一行小字，如果正版激活不行(100%是不成功的)，再采用其他方法(他们自己的脚本).\n主要由以下两个方法判断:\ncdk价格过低的，100%都是假入库 直接询问客服是否可以在手机上通过steam客户端cdk激活（假入库的脚本程序无法在手机上运行） 解除假入库 使用steam解锁文件管理器删除假入库的游戏 然后删除steam根目录的hid.dll(steam更新64位后,hid.dll劫持的方案已经失效了,换别的方案了) 最后严肃声明，本文章仅供技术探讨，支持正版从我做起 ","date":"2025-12-03T00:00:00Z","permalink":"/p/steam-fake-inventory/","title":"Steam 假入库那些事"},{"content":"主流代理核心简介（代理核心 + 前端 UI） 所有代理工具本质上都是 代理核心 + 前端图形界面（UI） 组成。\n前端 UI 可以千变万化，但真正承担流量处理的 代理核心只有少数几种。\n以下是目前主流、最常见的核心介绍。\nClash(更新停滞) Clash 是一个最初由 Go 编写的多协议代理核心（原项目已删除）。\n使用广泛，生态庞大。\n特点：\n使用统一的 YAML 配置，无需因平台不同而修改 GUI 客户端数量最多、生态最大 跨平台兼容性极强 缺点：\n原项目已停止维护 新协议支持较慢（如 Reality、Hysteria2 等） Mihomo（Clash Meta）★★★ MetaCubeX 社区维护的 Clash 增强版，也是目前最主流的 Clash 继承者。\n特点：\n完全兼容 Clash 配置 支持现代协议（Reality、Hysteria2、TUIC 等） 活跃维护，性能更高 Sing-Box（sb）★★ 由 SagerNet 开发的现代化代理核心，目前增长最快、架构最先进。\n特点：\n极度轻量，理论性能高 高度可定制的网络与路由配置 支持大量现代协议 跨平台优秀 缺点：\n配置难度高，对新手不友好 GUI 生态较少 V2Ray(更新缓慢) 由 v2fly 社区维护的原始 V2Ray 核心。\n特点：\n配置灵活 结构成熟 较为轻量 缺点：\n开发速度慢 新协议支持不佳 配置复杂 GUI 生态弱 Xray V2Ray 的增强版核心，由 XTLS 项目维护。\n特点：\n完全兼容 V2Ray 配置 支持 Reality 支持 XTLS，性能大幅提升 性能明显高于官方 V2Ray 缺点：\n配置复杂 GUI 生态较弱 dae 基于 eBPF 的 Linux / 路由器高性能代理引擎，更像“下一代分流框架”。\n特点：\n基于 eBPF，性能极高 几乎不占 CPU 延迟极低 路由分流能力极强 缺点：\n仅支持 Linux / OpenWRT 配置复杂 GUI少 各操作系统主流GUI代理客户端(整体按照知名度排序) Windows v2rayN★★ — 支持 Xray / sing-box / clash/others 内核,支持Windows/Linux/macOS Clash Verge Rev★★ — 内置 Mihomo内核,支持 Linux/macOS/Windows Mihomo Party★★★(推荐) - 支持linux/windows/macos Karing — 基于 sing-box 内核,支持Android/ios/linux/windows/macos Sparkle★★ — 基于 Mihomo 内核，支持 Windows / macOS / Linux Clash Mi —支持android/ios/Windows / macOS / Linux FlClash — 基于 Mihomo 内核,支持Android/linux/windows、macos GUI.for.Clash — Windows / macOS / Linux Pandora-Box — 基于 Mihomo 内核,支持linux/windows/macos macOS Surge★★★ — 付费高级客户端,支持ios/macos Quantumult X★★★ — 付费,支持ios/macos Loon — 付费,支持ios/macos v2rayN — 支持 Xray / sing-box / clash/others 内核,支持Windows/Linux/macOS Clash Verge Rev — 内置 Mihomo 内核,支持 Linux/macOS/Windows Mihomo Party - 支持linux/windows/macos Karing — 基于 sing-box 内核,支持Android/ios/linux/windows/macos Sparkle — 基于 Mihomo 内核，支持 Windows / macOS / Linux FlClash — 基于 Mihomo 内核,支持Android/linux/windows、macos Clash Mi —支持android/ios/Windows / macOS / Linux GUI.for.Clash — Windows / macOS / Linux Stash★★ — 基于 sing-box（付费） Pandora-Box — 基于 Mihomo 内核,支持linux/windows/macos Linux v2rayN★★ — 支持 Xray / sing-box / clash/others 内核,支持Windows/Linux/macOS Clash Verge Rev★★ — 内置 Mihomo 内核,支持 Linux/macOS/Windows Mihomo Party★★★ - 支持linux/windows/macos Karing — 基于 sing-box 内核,支持Android/ios/linux/windows/macos Sparkle — 基于 Mihomo 内核，支持 Windows / macOS / Linux FlClash — 基于 Mihomo 内核,支持Android/linux/windows、macos Clash Mi —支持android/ios/Windows / macOS / Linux GUI.for.Clash — 支持 Linux/macOS/Windows Pandora-Box — 基于 Mihomo 内核,支持linux/windows/macos Android Clash Meta for Android★★★(推荐) Karing — 基于 sing-box 内核,支持Android/ios/linux/windows/macos Clash Mi —支持android/ios/Windows / macOS / Linux FlClash★★ — 基于 Mihomo 内核,支持Android/linux/windows、macos iOS Surge★★★ — 付费高级客户端,支持ios/macos Shadowrocket★★★ — 付费,支持多协议 Quantumult X★★★ — 付费,支持ios/macos Loon — 付费,支持ios/macos Karing — 基于 sing-box 内核,支持Android/ios/linux/windows/macos Clash Mi —支持android/ios/Windows / macOS / Linux HarmonyOS NEXT ClashBox — 独苗这一块 路由器（OpenWRT / Linux） OpenClash★★ - OpenWRT 上主流的 Clash 客户端 OpenWrt-nikki★★★(推荐) — 基于clash核心 daed — 基于dae内核 Passwall2 openwrt-nekobox — 基于 Sing-box核心 总结 小白无脑选择clash系客户端，有其他要求可自定义选择。\n","date":"2025-12-03T00:00:00Z","permalink":"/p/proxy-tools/","title":"代理工具的选择"},{"content":"博客框架我们应该如何选择？ 博客大体上可以分为静态博客和动态博客。\n动态博客采用的是前端+后端的模式,而静态博客就是纯前端静态文件（方便托管）\n动态博客的优缺点: 优点: 适合大型博客或者论坛 自带后台管理评论 功能集成很多，适合小白，基本不需要额外去弄什么 缺点: 资源占用大 必须依赖服务器运行，不可使用静态host主机/serverless服务提供商(cloudflare/vercle/github pages) 网站加载速度相对较慢 有一定的运维成本(服务器/防火墙等费用) 静态博客的优缺点: 优点: 加载速度相对较快 资源占用少。 可以将网站交给serverless服务商托管（白嫖党狂喜，不需要专门的服务器） 缺点: 要有一定的web技术功底，会手动改配置文件、布局,写文章模板 框架集成的功能较少，如评论功能，音频播放器，需要自行对接第三方接口（不过很多静态博客主题里面已经把功能模板写好了，只需要更换接口地址就行） 缺乏统一的后台管理功能 动态博客框架 WordPress★★★ 世界知名动态博客框架，主题资源插件丰富，教程多。 Typecho 轻量级动态博客框架，主打一个快速部署，快速上线 Halo★★ 界面很漂亮，资源插件相对来说比较丰富，社区正在逐步发展，安装部署方法较为麻烦，比较吃服务器性能 静态博客框架 Hexo★★★ node.js开发,教程很多，社区插件主题资源丰富，缺点是当文章数量\u0026gt;1k时，构建速度会显著减缓 Hugo★★★ go语言开发,使用go template模板，学习门槛相对其他的来说高点。运行build效率很高,支持热加载,更改不需要刷新网页页面即可生效。教程资源丰富,社区插件资源也很多，稍逊hexo,最大的优势是当文章数量很多时，构建静态网站的速度可以快其他框架几倍. Jekyll★★ 资源插件相对较少,界面简洁直观,但有github官方支持,可以直接将存入仓库的md文件转换成网页 VitePress 资源插件丰富，可扩性强,常用于构建文档，不用于博客 Astro★★ 新一代静态框架,0 javascript的技术理念让网站首页加载起来非常快,采用服务端渲染的技术理念 可局部初始化组件为spa,增强网站运行效率,可搭配其他前端框架组件使用，但主题资源相对较少。 总结 对于零基础的小白，想搭建博客，首先推荐动态博客框架，首选wordpress,有一定技术基础，搭建自己个人的轻量博客推荐静态框架,首选hexo/hugo,想要更快的构建速度和热加载，选择hugo.如果想尝试更先进的技术理念和更快的首页加载速度，可以尝试astro\n杂谈 本站采用hugo构建,github仓库储存,cloudflare远程克隆部署,评论功能对接waline。\n","date":"2025-12-02T00:00:00Z","permalink":"/p/blog-framework-choose/","title":"博客框架的选择"},{"content":"这段时间闲着没事，想做一个 Telegram Bot 来玩玩。了解了一下，可实施的开发方案还挺多的，Java/Python 等等都有相对应的库。但是奈何我没有服务器，无法进行传统的前后端开发。\n于是乎，我想到了另一种开发思路：利用 Cloudflare 提供的 Serverless 无状态 JavaScript Worker 以及 Telegram Bot 官方支持的 Webhook 功能来实现无服务器聊天机器人。\n实现原理 我们在聊天机器人的界面发送命令：\n1 /chat 聊天内容 通过设置 Webhook 地址指向 Worker，Worker 中写好处理指令的代码，截取 /开始 后面的文字，然后转发给 Cloudflare 官方提供的免费的大语言模型后端，然后再处理返回的信息，最后再通过 Telegram Bot API 再返回消息到客户端。\n这样便实现了无服务器的聊天 AI Bot，但是这有个缺点：用户的每一次聊天都是单独的一次请求，bot没有上下文记忆,因为 Worker 本身是个无状态的js执行器，所以这个 Bot 其实相当于是一个图形化的终端命令请求器。\n但是 Cloudflare 有提供免费的额外的 KV 数据库，于是我们再改动一下代码： 用户发来的文字不直接请求大语言模型后端 而是先存入 KV 数据库 最后将 KV 数据库里的数据一起再发给大语言模型后端 处理返回的信息 返回 Telegram 客户端 于是Worker通过外挂KV数据库，最终便实现了带有记忆的无服务器聊天 AI 机器人。\n实现源代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 const TELEGRAM_BOT_TOKEN = \u0026#34;\u0026#34;; const CF_API_TOKEN = \u0026#34;\u0026#34;; async function run(model, input) { const response = await fetch( `https://api.cloudflare.com/client/v4/accounts/1f5b3d5417456835c8191a2ec42f449e/ai/run/${model}`, { headers: { Authorization: `Bearer ${CF_API_TOKEN}` }, method: \u0026#34;POST\u0026#34;, body: JSON.stringify(input), } ); return await response.json(); } async function sendTelegramMessage(chat_id, text) { try { await fetch(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`, { method: \u0026#34;POST\u0026#34;, headers: { \u0026#34;Content-Type\u0026#34;: \u0026#34;application/json\u0026#34; }, body: JSON.stringify({ chat_id, text, parse_mode: \u0026#34;MarkdownV2\u0026#34;, }), }); } catch (err) { console.error(\u0026#34;发送 Telegram 消息失败:\u0026#34;, err); } } export default { async fetch(request, env, ctx) { if (request.method !== \u0026#34;POST\u0026#34;) return new Response(\u0026#34;ok\u0026#34;, { status: 200 }); try { const data = await request.json(); console.log(\u0026#34;Telegram Update:\u0026#34;, JSON.stringify(data)); const message = data.message; if (!message?.text) return new Response(\u0026#34;ok\u0026#34;, { status: 200 }); const text = message.text; const match = text.match(/^\\/chat(?:@\\w+)?(?:\\s+([\\s\\S]+))?$/); const arg = match ? (match[1] || \u0026#34;\u0026#34;).trim() : \u0026#34;\u0026#34;; console.log(\u0026#34;完整消息文本:\u0026#34;, text); console.log(\u0026#34;命令参数:\u0026#34;, arg); if (!arg) { await sendTelegramMessage(message.chat.id, \u0026#34;请在 /chat 后输入要生成的内容，例如：/chat 写一个小故事\u0026#34;); } else { let history = await env.bot.get(message.chat.id); history = history ? JSON.parse(history) : []; history.push({ role: \u0026#34;user\u0026#34;, content: arg }); await env.bot.put(message.chat.id, JSON.stringify(history)); const aiResponse = await run(\u0026#34;@cf/openai/gpt-oss-120b\u0026#34;, { instructions: \u0026#39;你是liaoke的私人中文AI助手，简洁地回答用户的问题。\u0026#39;, reasoning: { \u0026#34;effort\u0026#34;: \u0026#34;medium\u0026#34; }, input: history, }); console.log(\u0026#34;AI 原始响应:\u0026#34;, JSON.stringify(aiResponse)); const reasonText = aiResponse?.result?.output ?.filter(o =\u0026gt; o.type === \u0026#34;reasoning\u0026#34;) ?.map(o =\u0026gt; o.content?.map(c =\u0026gt; c.text).join(\u0026#34;\\n\u0026#34;)) .filter(Boolean) .join(\u0026#34;\\n\\n\u0026#34;) || \u0026#34;AI 无法生成内容\u0026#34;; const outputText = aiResponse?.result?.output ?.filter(o =\u0026gt; o.type === \u0026#34;message\u0026#34;) ?.map(o =\u0026gt; o.content?.map(c =\u0026gt; c.text).join(\u0026#34;\\n\u0026#34;)) .filter(Boolean) .join(\u0026#34;\\n\\n\u0026#34;) || \u0026#34;AI 无法生成内容\u0026#34;; const escapeMD = (text) =\u0026gt; { if (!text) return \u0026#34;\u0026#34;; return text .replace(/\\\\/g, \u0026#34;\\\\\\\\\u0026#34;) .replace(/`/g, \u0026#34;\\\\`\u0026#34;) .replace(/_/g, \u0026#34;\\\\_\u0026#34;) .replace(/\\*/g, \u0026#34;\\\\*\u0026#34;) .replace(/\\[/g, \u0026#34;\\\\[\u0026#34;) .replace(/\\]/g, \u0026#34;\\\\]\u0026#34;) .replace(/~/g, \u0026#34;\\\\~\u0026#34;) .replace(/\u0026gt;/g, \u0026#34;\\\\\u0026gt;\u0026#34;) .replace(/#/g, \u0026#34;\\\\#\u0026#34;) .replace(/\\+/g, \u0026#34;\\\\+\u0026#34;) .replace(/-/g, \u0026#34;\\\\-\u0026#34;) .replace(/=/g, \u0026#34;\\\\=\u0026#34;) .replace(/\\|/g, \u0026#34;\\\\|\u0026#34;) .replace(/\\{/g, \u0026#34;\\\\{\u0026#34;) .replace(/\\}/g, \u0026#34;\\\\}\u0026#34;) .replace(/\\./g, \u0026#34;\\\\.\u0026#34;) .replace(/!/g, \u0026#34;\\\\!\u0026#34;); }; const messageMD = ` 🧠 推理过程： \\`\\`\\` ${escapeMD(reasonText)} \\`\\`\\` 💬 最终回答： ${escapeMD(outputText)} `; await sendTelegramMessage(message.chat.id, messageMD); history.push({ role: \u0026#34;assistant\u0026#34;, content: outputText }); await env.bot.put(message.chat.id, JSON.stringify(history)); console.log(\u0026#34;AI 输出发送给用户:\u0026#34;, messageMD); } return new Response(\u0026#34;ok\u0026#34;, { status: 200 }); } catch (err) { console.error(\u0026#34;解析 JSON 或处理失败:\u0026#34;, err); return new Response(\u0026#34;error\u0026#34;, { status: 400 }); } }, }; ","date":"2025-10-20T00:00:00Z","permalink":"/p/cloudflare-worker-telegram-bot/","title":"用cloudflare worker实现telegram bot | 开发日记"}]