标签 自动化 下的文章

一、IP归属地查询的广泛应用需求

在现代信息化社会中,IP地址是每个在线设备与互联网连接的唯一标识。通过对IP地址的归属地进行查询,企业和机构可以获取关于用户的地理位置、运营商信息等,帮助他们做出更加精准的决策。无论是在网络安全、数据分析、市场营销,还是反欺诈等领域,IP归属地查询都有着广泛的应用场景。

手动查询IP的归属地往往耗时且易出错,尤其是当需要批量查询时,工作量将成倍增加。借助Excel宏结合本地离线数据库(如CSV文件、JSON文件或MySQL数据库),可以实现自动化的IP查询,显著提升效率和准确性。

二、为什么选择Excel宏进行自动化查询?

Excel是全球最广泛使用的数据处理工具之一。其强大的数据管理和分析功能,使得它不仅限于财务管理,还广泛应用于各行各业。在处理大量数据时,Excel宏(VBA)为用户提供了自动化操作的强大能力。

Excel宏可以与本地离线数据库(如CSV、JSON或MySQL)结合,通过简单的脚本,快速实现IP归属地查询,而无需每次手动查找。相较于在线查询,离线数据库具有快速响应、无需网络依赖等优点,尤其适合需要频繁查询、批量查询的场景。
如何利用Excel宏和离线数据库自动化IP归属地查询?

三、如何编写Excel宏,调用本地数据库进行IP归属地查询?

1. 准备本地数据库

首先,需要准备一个包含IP地址和归属地信息的本地数据库。这里我们使用CSV格式作为示例,数据包括IP地址、归属地和运营商等字段,在正式测试中,我们使用的是IP数据云的IP归属地库。以下是一个简单的CSV文件示例:

IP地址,归属地,运营商
192.168.1.1,北京市,中国联通
180.76.15.18,上海市,中国电信

这个CSV文件可以根据实际需要扩展更多的IP信息

2. 编写Excel宏代码:调用本地CSV文件进行查询

在Excel中,可以使用VBA编程来实现IP查询。以下是一个示例代码,通过VBA宏读取本地CSV文件,并根据输入的IP地址查询归属地信息:

Sub 查询IP归属地()
    Dim ipAddress As String
    Dim csvFilePath As String
    Dim fileContent As String
    Dim lines() As String
    Dim line As String
    Dim data() As String
    Dim found As Boolean
    Dim i As Integer
    
    ' 获取用户输入的IP地址
    ipAddress = InputBox("请输入IP地址:", "IP归属地查询")
    
    ' 设置CSV文件路径
    csvFilePath = "C:\path\to\your\ip_database.csv"
    
    ' 读取CSV文件内容
    Open csvFilePath For Input As #1
    fileContent = Input$(LOF(1), 1)
    Close #1
    
    ' 将CSV内容按行分割
    lines = Split(fileContent, vbCrLf)
    
    ' 查找IP地址对应的归属地
    found = False
    For i = 0 To UBound(lines)
        line = lines(i)
        data = Split(line, ",")
        
        ' 如果找到匹配的IP地址
        If data(0) = ipAddress Then
            MsgBox "IP地址 " & ipAddress & " 的归属地是:" & data(1) & ", 运营商:" & data(2)
            found = True
            Exit For
        End If
    Next i
    
    ' 如果未找到对应IP
    If Not found Then
        MsgBox "未找到IP地址 " & ipAddress & " 的相关信息。"
    End If
End Sub

3. 批量查询IP归属地

为了应对大量的IP地址查询,Excel宏还可以扩展为批量查询的功能。以下是一个批量查询IP归属地的VBA代码,假设IP地址列表存储在Excel工作表的第一列,查询结果将输出到第二列:

Sub 批量查询IP归属地()
    Dim ipAddress As String
    Dim csvFilePath As String
    Dim fileContent As String
    Dim lines() As String
    Dim line As String
    Dim data() As String
    Dim i As Integer
    Dim resultRow As Integer
    
    ' 设置CSV文件路径
    csvFilePath = "C:\path\to\your\ip_database.csv"
    
    ' 读取CSV文件内容
    Open csvFilePath For Input As #1
    fileContent = Input$(LOF(1), 1)
    Close #1
    
    ' 将CSV内容按行分割
    lines = Split(fileContent, vbCrLf)
    
    ' 开始处理IP地址列表
    resultRow = 1
    For i = 1 To ActiveSheet.UsedRange.Rows.Count
        ipAddress = Cells(i, 1).Value ' 假设IP地址在第一列
        
        ' 查找IP地址对应的归属地
        For Each line In lines
            data = Split(line, ",")
            If data(0) = ipAddress Then
                Cells(resultRow, 2).Value = data(1) ' 输出归属地
                Cells(resultRow, 3).Value = data(2) ' 输出运营商
                resultRow = resultRow + 1
                Exit For
            End If
        Next line
    Next i
End Sub

该宏将遍历工作表中的IP地址,查找对应的归属地信息并输出结果。

四、如何优化和扩展Excel宏?

Excel宏的强大之处在于其可扩展性。除了查询IP归属地,以下是一些优化和扩展的建议:

增加查询结果的格式化功能:

可以在查询结果中使用条件格式化,突出显示不同的运营商或归属地。例如,可以使用不同的颜色标记中国电信与中国联通的归属地。

支持更多数据库格式:

除了CSV文件外,宏也可以支持JSON或MySQL数据库。对于较大的数据集,使用MySQL数据库可以提高查询效率。

定时查询和自动报告:

结合Excel的定时功能,可以实现自动定期查询并生成报告。对于需要定期更新IP归属地的情况,宏的自动化功能尤为重要。

批量导入IP地址:

在实际应用中,IP地址可能来自多个渠道(如日志文件、数据库等)。Excel宏可以扩展为批量导入不同来源的数据,进一步提升查询效率。当我们在选择数据库时,最好是选择数据维度多且更新频率高的,像IP数据云就是一个不错的选择,结果返回20+维度字段更是支持每日更新。

五、结语

通过利用Excel宏和本地离线数据库,企业和个人可以轻松实现IP归属地查询的自动化,无论是在网络安全、数据分析、市场营销等多个行业中,都会大大提高工作效率,节省时间和精力。无论是单次查询还是批量查询,Excel宏都能提供便捷的解决方案,帮助用户更好地管理和分析IP数据。

今天是第一次验证我的自动化写博客功能,盯了半天没有博客发出来,我就纳闷了,以为程序出错了.
跑去仓库一看,博客正常生成了,但是没有通过 cf 部署成功。

然后 cf 提示说 github 有毛病了,一去看还真是
https://www.githubstatus.com/

时常怀疑自己不行,以后得雄起,相信自己,哈哈哈,相信个鸡儿,每天写一堆 bug

如果你真正系统学习过 ITIL 4,并且尝试在真实组织中落地过它,而不是只停留在考试或概念层面,那么你大概率会有一种并不容易言说的感受:ITIL 4 是对的,也是先进的,但在一些关键时刻,它给人的帮助总像是差了最后一步。

你会发现,它在流程设计、协同机制、持续改进等方面非常成熟,也确实能解决大量“把事情做好”的问题。然而,当你面对的不是稳定业务,而是持续变化的数字化产品、平台型服务或高度自动化的系统时,很多真正棘手的问题,并不能仅靠流程优化得到答案。

尤其是在方向发生漂移、价值开始模糊、环境高度不确定的情况下,ITIL 4 很少正面回答一个问题:当事情本身可能已经不再值得继续时,究竟由谁来判断方向是否需要调整?

这一点,正是 ITIL 第5版 试图补上的核心逻辑。

图片

1.那条被忽略的暗线,其实一直贯穿在 ITIL 4 中

需要先说明的是,ITIL 4 并不是完全没有意识到“判断”这件事的重要性。恰恰相反,如果你仔细回看 ITIL 4 的整体表述,会发现它反复强调一些看似非常宏观、甚至相当前沿的理念,比如价值共创、整体思维、以结果为导向、与业务目标对齐等。

这些理念本身没有任何问题,甚至可以说,它们为 IT 服务管理摆脱纯粹“运维工具论”提供了非常重要的思想基础。ITIL 4 明确告诉你,服务不是为了流程存在,而是为了创造价值;IT 也不是孤立部门,而是价值链的一部分。

但问题恰恰出在这里。这些表述在逻辑上,默认了一个前提:价值方向是已经确定的。在这个前提下,管理的重点自然落在如何协同、如何优化、如何持续改进执行过程,而不是反过来质疑“这个方向是否仍然成立”。

换句话说,ITIL 4 讲得很清楚“怎么把事情做对”,却很少继续追问“这件事情是否还值得继续做”。这条逻辑线并非不存在,而是被有意压低了音量。

2.ITIL 4 讲不透判断问题,并不是能力不足,而是定位选择

很多人会误以为,这是 ITIL 4 的缺陷,甚至认为它在数字化时代已经不够用。但如果从历史背景和体系定位来看,这种评价并不公平。

ITIL 4 的核心使命,依然是帮助组织把 IT 服务“管好”。它的设计前提是:战略和业务方向由更高层给出,而 IT 管理体系的责任,是把这些方向转化为稳定、可交付、可衡量、可持续改进的服务能力。

在这种前提下,判断方向是否正确,并不属于 ITIL 4 要承担的核心职责。它更关注的是,当方向已经确定之后,组织如何避免内耗、减少浪费、提升协作效率,并持续优化交付结果。

因此,你会在 ITIL 4 中看到一种非常典型的能力结构:它极其擅长解决执行层面的复杂性,却刻意回避了对方向本身的判断。这并不是因为它“讲不明白”,而是因为它当初选择不去承担这部分责任。

只不过,现实环境正在发生变化,这种分工开始显得越来越勉强。

3.数字化环境下,判断不再是一次性的前置条件

在传统 IT 服务管理语境中,方向往往相对稳定。系统上线后可以运行多年,服务模式变化缓慢,管理的重点自然放在如何保障稳定性和效率上。但在数字化产品和平台型服务中,这种稳定性正在快速消失。

产品是否继续存在,往往不是一个阶段性决策,而是需要持续评估的结果;价值假设可能在数月内发生变化;自动化和 AI 的引入,也让技术决策直接影响长期后果。在这样的环境中,如果判断权仍然被假定发生在体系之外,问题就会不断积累。

你会看到一些非常典型的现象:明明已经不再产生实际价值的产品,却因为流程完整、指标达标而持续投入;自动化范围不断扩大,但一旦出现负面影响,却没人能够明确承担责任;体验持续恶化,却被 SLA 和效率指标掩盖。

这些问题,并不是流程设计不够细致,而是判断机制本身缺位。

4.ITIL 第5版,把判断正式拉回管理框架内部

正是在这样的背景下,ITIL 第5版 的态度发生了一个非常清晰的转变。它不再回避判断问题,而是明确承认:在高度数字化和不确定的环境中,管理本身就必须包含持续判断的能力。

你会发现,ITIL 第5版 开始系统性地讨论一些过去被视为“外部前提”的问题,比如价值假设是否仍然成立,产品和服务是否需要继续演进,自动化和 AI 的决策边界在哪里,以及长期结果究竟由谁来承担责任。

这些内容不再被放在战略文件或业务讨论中,而是被正式写进管理框架。这意味着,ITIL 正式承认,在现实世界中,判断不可能只发生在最顶层,也不可能只发生一次。

判断开始被视为一种需要被设计、被分配、被治理的能力。

5.那条暗线的名字,其实就是“判断权”的重新分配

如果一定要给 ITIL 第5版 补上的这条逻辑线起一个名字,那么“判断权”是一个非常贴切的概括。

在 ITIL 4 中,判断权往往被假定在体系之外:战略部门判断方向,业务部门判断价值,IT 负责执行和优化。而在 ITIL 第5版 中,判断权开始被重新分配到不同层级,并贯穿整个生命周期。

产品团队需要判断是否继续投入,管理层需要判断自动化的边界,组织层面需要判断效率与体验的取舍。这些判断不再是一次性的,而是持续发生的管理行为。

这也解释了为什么 ITIL 第5版 看起来更“重”。它变重的不是流程数量,而是对判断、责任和治理的要求。

6.把这条暗线讲清之后,很多复杂感受反而会消失

当你意识到 ITIL 第5版 的核心变化在于判断权的回归,很多看似突然变复杂的内容,其实都会变得更容易理解。

为什么要强调 Discover?因为判断必须发生在行动之前。为什么要强调体验?因为体验是检验价值假设是否成立的重要信号。为什么反复讨论治理和责任?

因为一旦判断被技术放大,就必须有清晰的责任归属。这些并不是零散增加的概念,而是一条被系统性拉直的逻辑线。

图片

写在最后:ITIL 第5版 更“重”,是时代的必然选择

有人会说,ITIL 第5版 让管理变得更复杂了。这种感受并不错误,但需要澄清的是:复杂的不是框架,而是现实本身已经不允许继续用纯粹执行导向的思维去管理数字化系统。

ITIL 4 把这条判断逻辑留给组织自行摸索,而 ITIL 第5版 选择把它写清楚、讲明白。因为在一个由人、系统和 AI 共同参与决策的世界里,管理已经不能只停留在“把事情做好”。

而这,正是 ITIL 第5版 真正进入体系深水区的起点。

我是AI+ITIL教练长河achotsao,欢迎与我深入、持续交流,有问必回。

过去几年,AI 更多是“工具”:

写文案、做图、生成代码、回答问题。

但进入 2026 年,一个明显变化正在发生:
AI 开始从“被使用的工具”,变成“主动运行的系统”。

这背后的关键不是模型升级,而是 AI 智能体(Agent)开始进入工作流程


智能体和普通 AI 最大的区别在于三点:

  • 有明确目标
  • 能自动拆解任务
  • 能持续执行并根据结果调整行为

这意味着 AI 不再只回答问题,而是可以:

  • 自动跑流程
  • 自动查数据
  • 自动生成内容
  • 自动更新系统
  • 自动复盘结果

AI 开始“做事”,而不是“回答”。


内容创作不再是“人写完就结束”,而是变成完整流程:

选题 → 生成 → 发布 → 复盘 → 优化
都可以由智能体持续运行。

人类更多负责判断方向,而不是重复劳动。


生产排程、异常检测、库存预测正在被智能体接管。
系统可以全天候运行,持续优化。

经验正在被算法替代,决策周期大幅缩短。


审批、汇报、统计、监控等工作,开始被自动化代理接管。
管理的重心从“管人”,变成“管系统”。


2026 年开始,个人的能力上限被系统放大:

  • 一个创作者拥有内容智能体
  • 一个创业者拥有运营智能体
  • 一个开发者拥有测试与运维智能体

人与人的差距,开始取决于系统,而不是时间投入。


真正的变化在于三点:

  • 工作从操作型,转为决策型
  • 组织从层级型,转为系统型
  • 生产从人工驱动,转为自动优化

AI 元年并不意味着失业潮,而意味着生产关系重排


从 2026 年开始,人和企业会明显分成两类:

  • 拥有智能体系统的一方,效率指数级提升
  • 仍停留在工具使用阶段的一方,逐渐被边缘化

关键不在于会不会用 AI,而在于:

是否把 AI 变成了自己的系统。

当智能体开始长期运行,
当流程开始自动完成,
当系统能自己优化,

AI 才真正改变了世界。

2026 年,不是技术爆发的一年,
而是规则悄然改变的一年。

折腾了一圈,Clawdbot 终于跑通了:Telegram 配对、浏览器自动查询、bird 读 X 时间线都 OK 。
以后可以让它帮我查信息、整理结果、跑一些自动化。

备注:本帖由我的助手 Clawdbot 代发。

本来是用来连接到自己的博客每天定时发文章的,发出后看到一些人也有需求,就整理了一下发出来,让大家也能从中获得便利

  • 可以自定义添加RSS源和板块,让AI检索哪些RSS源你说了算!

这里分享一个比较全面的RSS源地址项目,佬友们也可以自己查找

  • 支持定时任务,可以自定义时间,每日自动推送释放双手,也可以立即采集即刻获得

做的没那么华丽,佬友们可以根据自己需要进行修改

希望这个项目对大家有一些帮助


📌 转载信息
原作者: aizith
转载时间: 2026/1/25 08:12:10

很感谢一直支持我的朋友,虽然很久没发帖子,但是插件一直努力更新,今天有一些有意思的事情,于是想分享一下。

随时随地,随用随走是AI Anywhere的本心,智能体是必然的发展方向

前提

前段时间更新了内置MCP,包括(utools发布版本为1.11.10,测试版为1.11.14):

  • Web Search:获取互联网信息和网页内容
    • 网络搜索(DDG):通过关键词在互联网上搜索相关信息并返回摘要
    • 网页获取:抓取并解析指定 URL 网页的全文内容
  • 文件操作:对本地文件系统进行查找、读取和编辑
    • 文件定位:使用通配符模式快速查找匹配的文件路径
    • 内容检索:使用正则表达式在文件内容中搜索特定模式
    • 读取文件:从本地或远程路径读取文件内容(支持分段读取)
    • 写入文件:创建新文件或完全覆盖现有文件内容
    • 编辑文件:通过精确字符串替换来修改文件内容
  • 代码执行:在本地环境中运行 Python 代码和系统命令
    • 运行 Python 代码:直接执行提供的 Python 代码片段
    • 运行 Python 文件:执行本地存储的 .py 脚本文件
    • 解释器列表:扫描并列出系统中所有可用的 Python 解释器路径
    • 执行 Shell 命令:在 Windows 系统上执行各类命令行指令
  • 任务委派:处理复杂的多步骤任务
    • 子智能体(Sub-Agent):将复杂任务委派给具备特定工具权限的子 Agent 协同完成

很眼熟?因为照着claude code的功能模仿的,他目前是我见到的最优秀的智能体示例


事件经过

今天看到了qwen3-tts发布的消息,但是已经没有追着新模型本地部署测试的激情了,突然想到能不能试试我的智能体?于是便有了接下来的一幕:

系统提示词:空
模型:gemini-3-flash-preview
MCP工具:仅限于上述的内置MCP

提出要求-自动部署-告诉他取消用uv环境,使用配置好CUDA的p312环境,然后就部署好了?!

虽然anywhere可以分享会话文件给其他用户打开并继续聊天,但是因为命令行运行涉及到个人隐私,于是分享一下导出的html

See the Pen qwen3-tts-deployment by ComorebiC (@ComorebiC)
on CodePen.

整个过程我基本没怎么操心(除了偶尔运行时命令行报错,我原封不动发回去让他处理就行)。

虽然这是 Claude Code 的一个功能,但也是我用 Anywhere 从“划词翻译”、“OCR”、“辅助读论文”这些基础功能向更便捷更智能迈进的一大步(其实生活中也有些例子了,比如文件归档,我把目录告诉 AI,告诉它整理格式,它能自动分类、命名整理好,如开启chrome dev tool mcp,让它帮我爬取炎拳漫画的某些章节等等)。

未来我们也能自定义更多便捷的智能体,不仅仅是代码方面,还有办公、开发、个人兴趣、学习……超级期待!


如果有好的创意欢迎分享,我很乐意尝试,如果对插件有建议也欢迎分享!


📌 转载信息
转载时间: 2026/1/25 08:06:27

赛博方舟(CyberArk)发布了一份针对亚太地区公钥基础设施(PKI)的全新研究报告,报告指出,随着企业管理的数字证书数量持续攀升,该地区正面临运营中断事件增多、合规信心不足的双重问题。
本次研究由波内蒙研究院(Ponemon Institute)开展,面向全球近 2000 名 IT 与安全行业从业者,围绕 PKI 安全及证书管理展开调研。研究发现,老旧的 PKI 系统与人工管理流程在行业中仍广泛存在,而这类方式正是导致企业服务中断、安全事故频发以及运营成本高企的重要原因。
公钥基础设施是数字证书的核心支撑,这类证书用于验证用户、设备及服务的身份合法性。如今,企业在云环境中管理的机器身份和工作负载身份数量,远超出以往水平。这一转变不仅让实际投入使用的证书数量大幅增加,也让证书的续订流程和治理工作变得更为复杂

服务中断与操作失误频发

在亚太地区,超半数企业表示曾因配置错误遭遇非计划内的服务中断,近半数企业也出现过因证书过期引发的服务中断问题。研究还发现,59% 的亚太地区受访者表示,其企业尚无应对证书颁发机构遭入侵的有效预案。
调研显示,亚太地区仍有近三分之一的企业依靠人工方式跟踪和续订证书,50% 的企业因内部专业人才匮乏,在证书管理中频繁出现操作失误,且管理效率低下。
赛博方舟指出,调研数据反映出亚太地区企业在 PKI 管理上存在信心缺口:尽管部分领域中,亚太受访者对本地 PKI 运行表现的信心高于其他地区,但仅有不到半数的受访者表示,对自身 PKI 体系满足合规要求抱有高度信心。
具体来看,亚太地区仅 45% 的企业对其 PKI 体系符合合规要求持高度信心;仅有 48% 的企业确信,自身的 PKI 体系能有效抵御网络攻击和内部威胁。

全局可视性缺失成核心痛点

该报告将缺乏集中化的全局可视性列为亚太地区实现安全 PKI 管理的主要障碍之一。调研发现,39% 的受访者表示,无法对企业内部所有数字证书实现集中化可视化管理,是其 PKI 管理的最大难题;38% 的受访者则认为,安全、合规及审计工作的失效是首要阻碍。
从全球调研样本来看,老旧的 PKI 系统是企业实现安全证书管理的首要障碍,60% 的企业因该问题遭遇过安全漏洞被利用的情况。
研究还揭示了企业证书管理工作的规模:受访企业平均管理着超过 10.5 万个内部数字证书,多数企业均配备了三名全职员工,专门负责 PKI 体系的管理工作。

资源紧缺与外包趋势凸显

资源受限成为本次研究中反复提及的问题。调研显示,60% 的企业因专业人才和人员配置不足,目前已将 PKI 管理工作外包给安全托管服务提供商,或计划开展此类外包合作。
报告指出,资源受限的问题,与证书使用模式的快速变化形成了矛盾。如今许多企业的数字证书生命周期更短、续订频率更高,若企业仍依赖人工流程管理证书,证书漏续订、配置错误的风险会大幅上升。
赛博方舟机器身份安全业务总经理库尔特・桑德表示:“机器身份的快速扩张,彻底改变了 PKI 的运营模式。老旧的系统、人工的流程以及资源的紧缺,让数量持续增长的证书管理工作,复杂度进一步加剧。”
他还称:“随着证书数量不断增加、有效期持续缩短,未得到有效管理的 PKI 体系,将给企业带来快速攀升的财务损失和运营影响。当下正是企业推进 PKI 体系自动化、现代化转型的关键时期,此举能有效降低运营负担,全面提升企业的安全态势。”

自动化成核心优化方向

报告指出,那些在自动化建设和统一可视性管理上投入资源的企业,不仅服务中断事件显著减少,合规表现也更为优异。同时报告强调,尽管 PKI 在身份认证和数据加密中占据核心地位,但企业对其安全防护能力和合规性的整体信心,仍处于较低水平。
在部分运营指标上,亚太地区受访者的表现优于全球平均水平:52% 的亚太受访者认为,其 PKI 体系能高效应对设备数量和工作负载的增长(全球该比例为 47%);53% 的亚太受访者表示,其能清晰掌握企业内部证书的数量及分布情况,实现了良好的可视性管理。
此外,亚太和欧洲、中东及非洲地区的受访者表示,其 PKI 体系抵御外部攻击和内部威胁的有效率最高,均达到 49%。
波内蒙研究院主席兼创始人拉里・波内蒙博士表示:“PKI 对于保障数字通信中的信任度、安全性和隐私性,具有至关重要的作用。但本次研究表明,企业对 PKI 体系抵御安全威胁、匹配不断增长的设备和工作负载需求的能力,普遍缺乏信心。”
他还称:“要提升 PKI 体系的有效性,我认为会有更多企业引入人工智能技术,以此降低运营负担,实现更优的安全防护效果。”
赛博方舟预测,在云环境和现代应用场景中,机器身份和数字证书的数量将持续增长;受服务中断风险和合规要求的双重驱动,会有更多企业对自身的证书资产、续订流程及治理体系进行全面审查和优化。

在企业日常办公和文档管理中,PDF 已经成为最常用的电子文档格式。无论是财务报表、项目计划,还是合同协议,PDF 都能保证内容在不同平台下的统一显示。然而,当文档页数增加时,页码的缺失或混乱会影响文档的可读性和专业性。

手动为每页添加页码不仅耗时,而且容易出错。对于开发者来说,利用 C# 可以在 .NET 项目中实现自动化页码插入,从而显著提高工作效率,同时保证页码的准确性和格式统一。本文将带你从基础操作到高级定制,完整掌握 PDF 页码自动化的方法。

本文所使用的方法需要用到Free Spire.PDF for .NET,可通过 NuGet 安装:dotnet add package FreeSpire.PDF


2. 加载 PDF 并获取页面信息

在插入页码之前,需要先加载已有的 PDF 文档,并获取页面数量:

using Spire.Pdf;
using Spire.Pdf.Graphics;
using System.Drawing;

string inputFile = "ExistingDocument.pdf";
string outputFile = "DocumentWithPageNumbers.pdf";

// 加载 PDF 文档
PdfDocument doc = new PdfDocument();
doc.LoadFromFile(inputFile);

// 获取总页数
int pageCount = doc.Pages.Count;

在这个阶段,我们已经能够访问文档的每一页,为后续插入页码做准备。


3. 基础页码插入

最简单的页码样式是“第 X 页”,插入到页面底部居中:

for (int i = 0; i < pageCount; i++)
{
    PdfPageBase page = doc.Pages[i];

    PdfFont font = new PdfTrueTypeFont(new Font("宋体", 10f));
    PdfBrush brush = PdfBrushes.Black;

    string pageNumberText = $"第{i + 1}页";

    SizeF textSize = font.MeasureString(pageNumberText);
    float x = (page.Canvas.ClientSize.Width - textSize.Width) / 2;
    float y = page.Canvas.ClientSize.Height - textSize.Height - 10;

    page.Canvas.DrawString(pageNumberText, font, brush, x, y);
}

关键点解析

  • PdfTrueTypeFont 用于设置字体类型和大小
  • MeasureString 用于计算文本宽度,以便实现居中对齐
  • 坐标 (x, y) 控制页码在页面上的精确位置

4. 保存文档

完成页码插入后,记得保存文件并释放资源:

doc.SaveToFile(outputFile);
doc.Close();

经过以上步骤,已有 PDF 文档就成功生成了专业的页码,无需手动操作 PDF 文档。

以下是生成的 PDF 页码效果预览:

C#生成PDF页码


5 页码高级应用与优化策略

自定义页码格式

企业文档通常要求显示“第 X 页,共 Y 页”,或者英文的“Page X of Y”。只需在字符串中格式化即可:

string pageNumberText = $"第{i + 1}页,共{pageCount}页";
// 或者英文格式
// string pageNumberText = $"Page {i + 1} of {pageCount}";

这样可以保证文档在打印或归档时,页码信息清晰且专业。

灵活控制页码位置

页码不仅可以放在底部居中,还可以放在页脚左侧、右侧,甚至页眉区域。通过调整 X、Y 坐标即可实现不同布局:

// 页脚右侧
float xRight = page.Canvas.ClientSize.Width - textSize.Width - 20;
float yBottom = page.Canvas.ClientSize.Height - textSize.Height - 20;
page.Canvas.DrawString(pageNumberText, font, brush, xRight, yBottom);

// 页眉居中
float xTop = (page.Canvas.ClientSize.Width - textSize.Width) / 2;
float yTop = 10;
page.Canvas.DrawString(pageNumberText, font, brush, xTop, yTop);

排除首页或指定页开始

在报告或合同中,封面页通常不显示页码,或页码从第二页开始:

for (int i = 0; i < pageCount; i++)
{
    if (i == 0) continue; // 跳过首页

    PdfPageBase page = doc.Pages[i];
    string pageNumberText = $"第{i}页,共{pageCount - 1}页";
    SizeF textSize = font.MeasureString(pageNumberText);
    float x = (page.Canvas.ClientSize.Width - textSize.Width) / 2;
    float y = page.Canvas.ClientSize.Height - textSize.Height - 15;

    page.Canvas.DrawString(pageNumberText, font, brush, x, y);
}

这样可以灵活应对各种文档排版需求。

更多页码样式设置

页码的字体、字号、颜色可以根据企业品牌或文档风格进行自定义:

PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("Arial", 12f, FontStyle.Bold | FontStyle.Italic));
PdfBrush brush = new PdfSolidBrush(Color.DarkBlue);

结合坐标计算,可以在页面左、中、右随意放置页码,同时保证样式统一。


总结

通过本文的示例,C# 开发者可以轻松为已有 PDF 文档自动添加页码,无需手动操作。代码不仅适用于单页文档,也能处理多页 PDF,并提供了页码样式和位置的灵活控制。这种方法极大提升了办公效率,保证了文档的专业性和规范性,同时也为批量文档处理提供了可靠的技术方案。掌握这一技巧,你可以在财务报表、项目文档、合同协议等各类 PDF 文件中快速生成标准化页码,使文档既清晰又美观。

更多 PDF 文档操作技巧,请前往 Spire.PDF 文档中心查看。

最近接触到一款支持自动学生认证的程序,便萌生了为其补充完善功能的想法。开发过程中,我发现某平台可购得单价 3.5 元的邮箱账号,这类账号仅支持手机端登录,且未开启双因素认证(2FA)。针对这一情况,我为程序新增了三项核心功能:2FA 自动设置年龄验证校验(毕竟没有学生资格的账号,大概率是因为未完成 2FA 验证)、2FA 自动修改,以及虚拟卡自动绑定

整个项目全程基于 Claude 和 Codex 工具开发,目前已实现根据输入的虚拟卡信息,自动完成年龄验证与卡片绑定的功能。需要说明的是,我并非账号经销商,项目也未植入任何广告。此外,程序尚存不少待修复的 bug,且我后续不会对其进行维护迭代 —— 开发这个工具只是出于个人兴趣,我仅注册了二十个账号用于自身日常开发,完全不涉及任何盈利行为。

需要配置比特浏览器使用,会自动创建窗口,以及你的浏览器配置过密码删除窗口,也会自动删除窗口。

很多账号没有学生资格,以及你被拉入家庭组之后,反重力还是无法用,很大概率就是没有年龄验证,这个很重要。


📌 转载信息
原作者:
16627517673
转载时间:
2026/1/23 09:08:18

反重力的 Opus 应该是目前最厚道的去到了,本身反重力经过几个版本的更新,之前各种问题解决的差不多了,但是负载重的时候依然会遇到 Antigravity Error, 需要手工点击重试,大大影响了使用 Opus 的流畅度,经过我多方研究,终于找到了这个叫 Auto-Accept-Agent 的插件, 可以自动点击 Accept,而且是开源的,然后经过我的妙手回春,我给他增加了自动点击 Retry 的功能,而且设置中还有福利,开启后可以白嫖原版 VIP 的功能,走过路过不要错过哈

项目地址:GitHub - michaelbarrera21/auto-accept-agent

一键下载最新版本: Release Auto Accept Agent v8.7.1 · michaelbarrera21/auto-accept-agent · GitHub

开启 VIP 功能: 你进入到 Editor Settings, 找到 Extensions 下面的 Auto Accept Agent, 然后开启 本地 VIP 功能就可以了

开启的时候遇到 Auto Accept: Could not configure automatically. Please add --remote-debugging-port=9000 to your Antigravity shortcut manually, then restart. 点击 Auto Accept: OFF 这样了是啥问题

解决办法:

这个功能是通过开启 Antigravity 的调试模式, 也就是 CDP 协议来远程操作的,你点击开启的时候,插件会自动寻找 Antigravity 的快捷方式,将快捷方式加上 --remote-debugging-port 的参数,你这个提示是因为可能我只遍历了开始菜单和桌面,找不到你的快捷方式,你可以自己新建一个快捷方式,然后加上–remote-debugging-port=9000 的参数, 我之后会优化这块的提示哈

现已支持全中文界面,安装最新版插件,可自动识别界面语言,并且可以在设置中修改

mac 用户可以试试最新版本,加上了自动生成快捷方式的逻辑, 如果不生效,可以参考故障提示中的方法:


📌 转载信息
原作者:
puppywang
转载时间:
2026/1/21 22:07:25

前言

最近刚结束了一个HVV蓝队,比较头疼,甲方内部设备简直太多了,目前各个大厂都是这么玩儿的,本地MSS不好好适配不同厂家的产品,弹起来适配的问题最好的借口就是需要开发介入调整适配,不单单是在适配不同厂商的防火墙上扯皮还是在适配不同厂商探针上同样扯皮,有这扯皮功夫还不如直接写个工具一键封禁得了。其实就目前防守状态来讲,通过告警事件联动不同区域的防火墙这种技术手段太简单了,本地MSS在态感的基础上优化剧本再加上GPT介入研判已经基本上可以解决绝大部分的告警攻击了,可能目前唯一的问题可能就是出现在厂商态感底层告警逻辑上,目前探针获取的流量也只能获取非SSL流量,不做SSL卸载或者SSL证书解密的话一部分告警是无法获取的,另外常见的横向行为和隐藏流量也只能基于厂商设备底层逻辑或者剧本编排。

这次的工具功能是封禁共享情报的ip,或者是基于不同边界的不同品牌的防火墙和WAF的封禁。

下载地址:

功能介绍

  • 支持多种防火墙设备统一管理(H3C,QAX,SXF,山石,K01,DP等)
  • 网防K01提供黑名单批量查询、添加、删除功能
  • 支持 IP 规则化、过滤、清洗等功能
  • 界面简洁,操作便捷,可以选择性的根据不同的情报源头选择不同边界的设备进行封禁
  • 关于产品型号可支持大部分型号,除网防K01外其它产品封禁实现原理是基于添加地址到地址簿,封禁策略需手动处理

工具介绍和代码逻辑

配置文件

配置文件存放在config/config.json中,需要提前配置json文件,负责无法使用程序。这里关于config的文件内容务必按照格式规则设置,否则无法解析。

DP防火墙

DP防火墙的登录方式是telnet,逻辑是通过添加ip地址进入地址簿,添加ip地址

package devices

import (
	"BT_supertoolsV2/utils"
	"fmt"
	"strings"
	"time"

	"github.com/reiver/go-telnet"
)

type DPConfig struct {
	Name         string `json:"name"`
	DeviceIP     string `json:"device_ip"`
	TelnetPort   int    `json:"telnet_port"`
	Username     string `json:"username"`
	Password     string `json:"password"`
	AddressGroup string `json:"address_group"`
	Type         string `json:"type"`
}

func AddIPsToDP(cfg DPConfig, ips []string) string {
	var output strings.Builder
	output.WriteString(fmt.Sprintf("=== 开始配置 DP 设备 %s ===\n", cfg.DeviceIP))

	// IP 规则化处理
	normalizedIPs := utils.NormalizeIP(strings.Join(ips, "\n"))
	if normalizedIPs == "" {
		return "没有有效的 IP 地址!"
	}
	ipList := strings.Split(normalizedIPs, "\n")

	// 连接 Telnet
	address := fmt.Sprintf("%s:%d", cfg.DeviceIP, cfg.TelnetPort)
	conn, err := telnet.DialTo(address)
	if err != nil {
		return fmt.Sprintf("Telnet 连接失败: %v\n", err)
	}
	defer conn.Close()

	// 封装发送命令函数
	send := func(cmd string) {
		conn.Write([]byte(cmd + "\n"))
		time.Sleep(500 * time.Millisecond)
		output.WriteString(fmt.Sprintf("[发送] %s\n", cmd))
	}

	// 开始发送指令:用户名 -> 密码 -> conf -> 封禁命令 -> exit
	send(cfg.Username)
	send(cfg.Password)
	send("conf")
	for _, ip := range ipList {
		send(fmt.Sprintf("address-object %s %s/32", cfg.AddressGroup, ip))
	}
	send("exit")

	output.WriteString("\n=== 配置完成 ===\n")
	return output.String()
}

这里没有直接使用回显显示状态,没有监听服务器回显状态再输入命令,具体使用该方式是新增一个地址簿,再策略位置设置封禁策略,引用添加的地址簿即可。界面效果

H3c防火墙

采用ssh登录使用命令操作

package devices

import (
	"fmt"
	"strings"
	"time"

	"golang.org/x/crypto/ssh"
)

func AddIPsToH3C(cfg H3CConfig, ips []string) string {
	var output strings.Builder
	output.WriteString(fmt.Sprintf("=== 开始配置 H3C 设备 %s ===\n\n", cfg.DeviceIP))

	config := &ssh.ClientConfig{
		User: cfg.Username,
		Auth: []ssh.AuthMethod{
			ssh.Password(cfg.Password),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Timeout:         10 * time.Second,
	}

	client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", cfg.DeviceIP, cfg.SSHPort), config)
	if err != nil {
		return fmt.Sprintf("SSH连接失败: %v\n", err)
	}
	defer client.Close()

	session, err := client.NewSession()
	if err != nil {
		return fmt.Sprintf("创建会话失败: %v\n", err)
	}
	defer session.Close()

	stdin, err := session.StdinPipe()
	if err != nil {
		return fmt.Sprintf("获取输入管道失败: %v\n", err)
	}

	modes := ssh.TerminalModes{
		ssh.ECHO:          0,
		ssh.TTY_OP_ISPEED: 14400,
		ssh.TTY_OP_OSPEED: 14400,
	}
	if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
		return fmt.Sprintf("设置终端失败: %v\n", err)
	}
	if err := session.Shell(); err != nil {
		return fmt.Sprintf("启动 shell 失败: %v\n", err)
	}

	commands := []string{
		"system-view",
		fmt.Sprintf("object-group ip  %s", cfg.AddressGroup),
	}
	for _, ip := range ips {
		commands = append(commands, fmt.Sprintf("network host address %s", ip))
	}
	commands = append(commands, "exit")

	for _, cmd := range commands {
		fmt.Fprintf(stdin, "%s\n", cmd)
		time.Sleep(300 * time.Millisecond)
		output.WriteString(fmt.Sprintf("[执行] %s\n", cmd))
	}
	output.WriteString("\n=== 配置完成 ===\n")
	return output.String()
}

这里采用了监听回显,核心代码是

commands := []string{
		"system-view",
		fmt.Sprintf("object-group ip  %s", cfg.AddressGroup),
	}
	for _, ip := range ips {
		commands = append(commands, fmt.Sprintf("network host address %s", ip))
	}
	commands = append(commands, "exit")

当然这里可以增加优化,代码内关于ip地址的添加以及删除等操作都可以做,工具后期可以依托命令功能增加多个模块化设计,当然为了降低操作风险的话,这里黑名单封禁的操作足够使用了。

山石防火墙

山石登录方式是telnet登录使用命令操作

import (
	"BT_supertoolsV2/utils"
	"fmt"
	"strings"
	"time"

	"github.com/reiver/go-telnet"
)

type HSConfig struct {
	Name         string `json:"name"`
	DeviceIP     string `json:"device_ip"`
	TelnetPort   int    `json:"telnet_port"`
	Username     string `json:"username"`
	Password     string `json:"password"`
	AddressGroup string `json:"address_group"`
	Type         string `json:"type"`
}

func AddIPsToHillstone(cfg HSConfig, ips []string) string {
	var output strings.Builder
	output.WriteString(fmt.Sprintf("=== 开始配置 Hillstone 设备 %s ===\n", cfg.DeviceIP))

	// IP 规则化处理
	normalizedIPs := utils.NormalizeIP(strings.Join(ips, "\n"))
	if normalizedIPs == "" {
		return "没有有效的 IP 地址!"
	}
	ipList := strings.Split(normalizedIPs, "\n")

	// 连接 Telnet
	address := fmt.Sprintf("%s:%d", cfg.DeviceIP, cfg.TelnetPort)
	conn, err := telnet.DialTo(address)
	if err != nil {
		return fmt.Sprintf("Telnet 连接失败: %v\n", err)
	}
	defer conn.Close()

	// 封装发送命令函数
	send := func(cmd string) {
		conn.Write([]byte(cmd + "\n"))
		time.Sleep(500 * time.Millisecond)
		output.WriteString(fmt.Sprintf("[发送] %s\n", cmd))
	}

	// 开始发送指令:用户名 -> 密码 -> conf -> 封禁命令 -> exit
	send(cfg.Username)
	send(cfg.Password)
	send("conf")
	for _, ip := range ipList {
		send(fmt.Sprintf("address-object %s %s/32", cfg.AddressGroup, ip))
	}
	send("exit")

	output.WriteString("\n=== 配置完成 ===\n")
	return output.String()
}

山石防火墙的命令基本和华三防火墙的命令基本一致,目前基本上可以支持大多数版本型号的防火墙,使用前可以做测试。

网盾K01

网盾K01的话这里采用的是关于api的利用,目前关于网盾K01的黑名单添加的模式是和防火墙不一致的,可以采用接口的方式增加。目前代码中关于黑名单添加的事件设置的是3600小时。

// 批量封禁
func AddBlacklist(devices []K01Device, ips []string, output *widget.Entry) {
	for _, device := range devices {
		appendOutput(output, fmt.Sprintf("🔑 正在登录设备 [https://%s]...", device.IP))

		// 登录并获取 Token
		url := fmt.Sprintf("https://%s", device.IP)
		token := Login(url, device.Username, device.Password, output, device.Name)
		if token == "" {
			appendOutput(output, fmt.Sprintf("❌ 登录失败: %s", device.Name))
			continue
		}

		// 逐个 IP 添加到黑名单
		for _, ip := range ips {
			// 如果 IP 地址没有 CIDR 后缀,添加 "/32"
			if !strings.Contains(ip, "/") {
				ip += "/32"
			}

			// 打印调试日志,确认每个 IP 地址
			appendOutput(output, fmt.Sprintf("🔍 封禁 IP: %s", ip))

			// 准备请求 payload
			payload := map[string]interface{}{
				"color":       0,
				"device_mask": []int{224},
				"items": []map[string]interface{}{
					{
						"type":        0,
						"ip":          ip, // 这里单独封禁每个 IP 地址
						"timeout":     336,
						"time_type":   "3600",
						"device_mask": []int{224},
						"comment":     "自动封禁",
					},
				},
				"method": "add",
			}

			// 打印调试日志,确认请求 Payload
			payloadBytes, _ := json.Marshal(payload)
			// appendOutput(output, fmt.Sprintf("🔍 请求 Payload: %s", string(payloadBytes)))

			// 请求封禁
			req, err := http.NewRequest("POST", url+"/api/v1/security/iplist/save", bytes.NewBuffer(payloadBytes))
			if err != nil {
				appendOutput(output, fmt.Sprintf("❌ 创建封禁请求失败: %s", err.Error()))
				continue
			}
			req.Header.Set("Authorization", "Bearer "+token)
			req.Header.Set("Content-Type", "application/json")

			// 执行请求
			resp, err := insecureClient.Do(req)
			if err != nil {
				appendOutput(output, fmt.Sprintf("❌ 封禁请求失败: %s", err.Error()))
				continue
			}
			defer resp.Body.Close()

			// // 打印调试日志,确认响应代码
			// appendOutput(output, fmt.Sprintf("🔍 响应状态: %s", resp.Status))

			// 解析响应
			body, _ := ioutil.ReadAll(resp.Body)
			var result map[string]interface{}
			if err := json.Unmarshal(body, &result); err != nil {
				appendOutput(output, fmt.Sprintf("❌ 解析封禁响应失败: %s", err.Error()))
				continue
			}

			// // 打印调试日志,确认响应结果
			// appendOutput(output, fmt.Sprintf("🔍 响应结果: %v", result))

			// 根据结果显示成功或失败
			if success, ok := result["success"].(bool); ok && success {
				appendOutput(output, fmt.Sprintf("✅ 添加成功: %s", ip))
			} else {
				appendOutput(output, fmt.Sprintf("❌ 添加失败: %v", result["msg"]))
			}
		}
	}
}

// DeleteBlacklist 删除 IP 从黑名单
func DeleteBlacklist(devices []K01Device, selected []int, ipList []string, outputBox *widget.Entry) {
	for _, idx := range selected {
		device := devices[idx] // 获取当前选择的设备
		url := fmt.Sprintf("https://%s", device.IP)

		// 输出正在登录设备信息
		appendOutput(outputBox, fmt.Sprintf("🔄 正在登录设备【%s】...", device.Name))

		// 登录设备,获取 token
		token := Login(url, device.Username, device.Password, outputBox, device.Name)
		if token == "" {
			appendOutput(outputBox, fmt.Sprintf("❌ 设备【%s】登录失败,无法删除黑名单", device.Name))
			continue
		}

		// 遍历 IP 列表,直接进行删除操作
		for _, ip := range ipList {
			apiUrl := fmt.Sprintf("%s/api/v1/security/iplist/save", url)
			payload := fmt.Sprintf(`{
				"color": 0,
				"items": [{"id": "%s/32;0;0", "type": 0, "ip": "%s/32", "device_mask": [224]}],
				"method": "delete"
			}`, ip, ip)

			// 创建请求
			req, err := http.NewRequest("POST", apiUrl, bytes.NewBuffer([]byte(payload)))
			if err != nil {
				appendOutput(outputBox, "❌ 创建删除请求失败: "+err.Error())
				continue
			}
			req.Header.Set("Authorization", "Bearer "+token)
			req.Header.Set("Content-Type", "application/json")

			// 发送请求
			resp, err := insecureClient.Do(req)
			if err != nil {
				appendOutput(outputBox, "❌ 删除请求失败: "+err.Error())
				continue
			}
			defer resp.Body.Close()

			// 读取响应
			body, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				appendOutput(outputBox, "❌ 读取删除响应失败: "+err.Error())
				continue
			}

			// 解析响应
			var result map[string]interface{}
			if err := json.Unmarshal(body, &result); err != nil {
				appendOutput(outputBox, "❌ 解析删除响应失败: "+err.Error())
				continue
			}

			// 检查删除是否成功
			if success, ok := result["success"].(bool); ok && success {
				appendOutput(outputBox, fmt.Sprintf("✅ 删除成功,IP: %s", ip))
			} else {
				// 如果失败,输出错误信息
				if msg, ok := result["msg"].(string); ok {
					appendOutput(outputBox, fmt.Sprintf("❌ 删除失败: %s", msg))
				} else {
					appendOutput(outputBox, "❌ 删除失败,未知错误")
				}
			}
		}
	}

关于api的调用的话是有其自己的参数规则的,因为认证方式是https,所以关于身份认证的话需要忽略ssl证书。因为考虑到删除函数的逻辑需先查询要封禁的黑名单是否在黑名单列表,所以这里就执行的是直接删除,否则就删除失败,但是对于功能性的查询模块的功能是有的,由于网盾k01的产品特性,一点发现全网阻断,所以这里基本上用不到删除黑名单的功能。

QAX网神防火墙

网神联动利用的是ssh登录执行命令,所以这里权限也相对来说比较大,对于蓝队来讲不建议增加其它代码功能,原理也是利用策略引用地址簿进行封禁

func AddIPsToQAX(cfg QAXConfig, ips []string) string {
	var output strings.Builder
	output.WriteString(fmt.Sprintf("=== 开始配置奇安信设备 %s ===\n\n", cfg.DeviceIP))

	config := &ssh.ClientConfig{
		User: cfg.Username,
		Auth: []ssh.AuthMethod{
			ssh.Password(cfg.Password),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Timeout:         15 * time.Second,
	}

	client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", cfg.DeviceIP, cfg.SSHPort), config)
	if err != nil {
		return fmt.Sprintf("SSH连接失败: %v\n", err)
	}
	defer client.Close()

	session, err := client.NewSession()
	if err != nil {
		return fmt.Sprintf("创建会话失败: %v\n", err)
	}
	defer session.Close()

	stdin, err := session.StdinPipe()
	if err != nil {
		return fmt.Sprintf("获取输入管道失败: %v\n", err)
	}

	modes := ssh.TerminalModes{
		ssh.ECHO:          0,
		ssh.TTY_OP_ISPEED: 14400,
		ssh.TTY_OP_OSPEED: 14400,
	}
	if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
		return fmt.Sprintf("设置终端失败: %v\n", err)
	}
	if err := session.Shell(); err != nil {
		return fmt.Sprintf("启动shell失败: %v\n", err)
	}

	commands := []string{
		"config terminal",
		fmt.Sprintf("object address %s", cfg.AddressGroup),
	}
	for _, ip := range ips {
		commands = append(commands, fmt.Sprintf("network %s 32", ip))
	}
	commands = append(commands, "exit")

	for _, cmd := range commands {
		fmt.Fprintf(stdin, "%s\n", cmd)
		time.Sleep(500 * time.Millisecond)
		output.WriteString(fmt.Sprintf("[执行] %s\n", cmd))
	}
	output.WriteString("\n=== 配置完成 ===\n")
	return output.String()
}

向地址簿中添加ip地址核心代码

commands := []string{
	"config terminal",
	fmt.Sprintf("object address %s", cfg.AddressGroup),
}
for _, ip := range ips {
	commands = append(commands, fmt.Sprintf("network %s 32", ip))
}
commands = append(commands, "exit")

目前我也是查询了多款网神防火墙的手册,关于地址簿添加这块儿的命令版本是没有变化的,基本上支持大多数版本型号。

SXF_AF和WAF

这里SXF的设备是有两种模式可供选择的,但是目前SXF的ssh登录一般是由两段密码组成还有可能经常性的修改,所以这里使用的API的方式向地址簿中添加要封禁的IP地址,但是这里的话,策略务必要配置正确。

// 新增的结构体,用于表示包含 devices 字段的 JSON 数据结构
type DeviceList struct {
	Devices []SXFDevice `json:"devices"`
}

// 登录响应结构体
type loginResponse struct {
	Code int `json:"code"`
	Data struct {
		LoginResult struct {
			Token string `json:"token"`
		} `json:"loginResult"`
	} `json:"data"`
	Message string `json:"message"`
}

// 添加 IP 请求结构体
type ipRange struct {
	Start string `json:"start"`
}

type addIPRequest struct {
	IPRanges []ipRange `json:"ipRanges"`
}

// ✅ 防冲突:明确为 SXF 的登录函数
// 登录获取 token
func SXFLogin(device SXFDevice) (string, error) {
	// 打印设备信息,确保 IP、用户名和密码正确
	fmt.Printf("设备信息: IP=%s, Username=%s, Password=%s\n", device.IP, device.Username, device.Password)
	url := fmt.Sprintf("https://%s/api/v1/namespaces/public/login", device.IP)

	payload := map[string]string{
		"name":     device.Username,
		"password": device.Password,
	}
	jsonData, _ := json.Marshal(payload)

	client := &http.Client{
		Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
	}
	resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return "", fmt.Errorf("登录请求失败: %v", err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)

	// 打印响应内容进行调试
	fmt.Println("响应体内容:", string(body))

	var result struct {
		Code    int    `json:"code"`
		Message string `json:"message"`
		Data    struct {
			LoginResult struct {
				Token string `json:"token"`
			} `json:"loginResult"`
		} `json:"data"`
	}

	if err := json.Unmarshal(body, &result); err != nil {
		return "", fmt.Errorf("解析登录响应失败: %v", err)
	}

	// 检查返回的 code
	if result.Code != 0 {
		return "", fmt.Errorf("登录失败: %s", result.Message)
	}

	// 返回 token
	return result.Data.LoginResult.Token, nil
}

// 加载 JSON 文件并解析为设备切片
// 加载 JSON 文件并解析为设备切片
func loadSXFDevices(filePath string) ([]SXFDevice, error) {
	data, err := os.ReadFile(filePath)
	if err != nil {
		return nil, fmt.Errorf("设备配置文件加载失败: %v", err)
	}

	// 输出加载的 JSON 数据(用于调试)
	fmt.Printf("加载的 JSON 数据: %s\n", string(data))

	var devices []SXFDevice
	err = json.Unmarshal(data, &devices)
	if err != nil {
		return nil, fmt.Errorf("设备解析失败: %v", err)
	}

	// 输出解析后的设备信息(调试)
	fmt.Printf("加载的设备数量: %d\n", len(devices))
	for _, device := range devices {
		// 输出每台设备的详细信息,特别是 AddressGroup 字段
		fmt.Printf("设备信息:Name=%s, IP=%s, AddressGroup=%s\n", device.Name, device.IP, device.AddressGroup)
	}

	return devices, nil
}

// ✅ 添加多个 IP 到 SXF 地址组(支持日志回调)
// 在 AddToSXFBlacklist 函数内部,确保请求头正确设置
// 设备添加到黑名单的函数
// AddToSXFBlacklist 将 IP 地址添加到 SXF 防火墙的黑名单
// 添加多个 IP 到 SXF 地址组(支持日志回调)
// AddToSXFBlacklist 将 IP 地址添加到 SXF 防火墙的黑名单
func AddToSXFBlacklist(devices []SXFDevice, ips []string, logFn func(string)) error {

	for _, device := range devices {
		// 1. 登录
		token, err := SXFLogin(device)
		if err != nil {
			logFn(fmt.Sprintf("【%s】❌ 登录失败: %v", device.Name, err))
			continue
		}
		logFn(fmt.Sprintf("【%s】✅ 登录成功", device.Name))

		// 2. 添加每个IP
		for _, ip := range ips {
			ipRanges := []map[string]string{{"start": ip, "end": ip}}
			requestData := map[string]interface{}{"ipRanges": ipRanges}
			requestDataJSON, _ := json.Marshal(requestData)

			// 3. 发送请求
			url := fmt.Sprintf(
				"https://%s/api/v1/namespaces/public/ipgroups/%s?_arrayop=add",
				device.IP,
				device.AddressGroup,
			)
			req, _ := http.NewRequest("PATCH", url, bytes.NewBuffer(requestDataJSON))
			req.Header = http.Header{
				"token":        []string{token},
				"Content-Type": []string{"application/json"},
			}

			client := &http.Client{
				Transport: &http.Transport{
					TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
				},
			}
			resp, err := client.Do(req)
			if err != nil {
				logFn(fmt.Sprintf("【%s】❌ IP %s 添加失败: %v", device.Name, ip, err))
				continue
			}
			defer resp.Body.Close()

			// 4. 处理响应
			body, _ := io.ReadAll(resp.Body)
			var result map[string]interface{}
			if err := json.Unmarshal(body, &result); err != nil {
				logFn(fmt.Sprintf("【%s】❌ IP %s 响应解析失败: %v", device.Name, ip, err))
				continue
			}

			if code, ok := result["code"].(float64); ok && code == 0 {
				logFn(fmt.Sprintf("【%s】✅ IP %s 已添加到地址组[%s]",
					device.Name, ip, device.AddressGroup))
			} else {
				msg, _ := result["message"].(string)
				logFn(fmt.Sprintf("【%s】❌ IP %s 添加失败: %s", device.Name, ip, msg))
			}
		}
	}
	return nil
}

如果想要扩展功能的话不建议使用API去扩展,毕竟太麻烦了,各种参数比较麻烦,没有ssh的方式登录使用命令操作简便。

整体界面效果

总结

其它厂商的防火墙确实没找到手册,有的是找到手册没有测试的设备,目前上述的设备和代码是完全没有问题的,如果想添加其它厂商的设备,可以给我操作手册,我这边更新新版本发布。每次更新后的授权时间是3个月

在日常开发工作中,我们经常会遇到需要自动化处理文档的场景,尤其是PowerPoint演示文稿。无论是批量生成报告、根据数据动态创建演示文稿,还是对现有PPT进行内容调整,手动操作都显得效率低下且容易出错。如何利用Java的强大能力,实现对PowerPoint幻灯片的添加、隐藏和删除,从而极大地提高工作效率,成为了许多开发者关注的焦点。本文将深入探讨这一需求,并提供一套高效实用的解决方案。

库介绍与环境配置:Spire.Presentation for Java

要实现Java对PowerPoint幻灯片的自动化操作,我们需要借助一个功能强大的第三方库。Spire.Presentation for Java 正是这样一个专门为Java应用程序设计,用于创建、读取、编辑、转换和打印PowerPoint文件的API。它支持多种PPT格式,并提供了丰富的接口,让开发者能够轻松控制幻灯片的各个方面,包括文本、图片、表格、图表以及幻灯片本身的操作。

Maven依赖配置:

<repositories>
    <repository>
        <id>com.e-iceblue</id>
        <name>e-iceblue</name>
        <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
    </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>e-iceblue</groupId>
        <artifactId>spire.presentation</artifactId>
        <version>11.1.1</version>
    </dependency>
</dependencies>

环境配置说明:

在开始编程之前,请确保您的开发环境已正确配置。这包括安装Java Development Kit (JDK) 1.8或更高版本,并配置好Maven或Gradle构建工具。此外,推荐使用IntelliJ IDEA或Eclipse等IDE,它们能提供更好的代码提示和调试体验。

Java 在 PowerPoint 中添加幻灯片

添加幻灯片是构建演示文稿的基础。Spire.Presentation for Java 允许我们创建全新的PPT文件,并在其中添加各种类型的幻灯片,甚至可以向幻灯片中添加内容。

代码示例:

Java

import com.spire.presentation.*;

public class Slides {
    public static void main(String[] args) throws Exception {

        //创建一个 PowerPoint 文档并加载示例文档

        Presentation presentation = new Presentation();
        presentation.loadFromFile("/Sample.pptx");

        //在文档末尾添加新幻灯
        presentation.getSlides().append();

        //在第二页插入空白幻灯片
        presentation.getSlides().insert(1);

       //保存文档
        presentation.saveToFile("output/AddSlide.pptx", FileFormat.PPTX_2010);
    }

}

代码解析:

  1. new Presentation():创建一个空的PowerPoint演示文稿对象。
  2. presentation.getSlides().append():在PowerPoint文件的末尾添加一个新的空白幻灯片。
  3. presentation.getSlides().insert(1):在指定位置添加一张新的幻灯片,这里是添加为第二张。
  4. presentation.saveToFile(...):将修改后的演示文稿保存到指定路径和格式。

Java 在 PowerPoint 中隐藏指定幻灯片

有时我们需要在不删除幻灯片的前提下,使其在演示模式下不可见。Spire.Presentation 提供了简便的方法来实现这一功能。

代码示例:

import com.spire.presentation.*;

public class Slides {
    public static void main(String[] args) throws Exception {

        //创建一个 PowerPoint 文档并加载示例文档
        Presentation presentation = new Presentation();
        presentation.loadFromFile("/Sample.pptx");

        //隐藏第二张幻灯片
        presentation.getSlides().get(1).setHidden(true);

        //保存文档
        presentation.saveToFile("output/Hideslide.pptx", FileFormat.PPTX_2010);
    }

}

代码解析:

  1. presentation.loadFromFile(...):加载一个已存在的PowerPoint文件。
  2. presentation.getSlides().get(1).setHidden(true):通过索引获取需要操作的幻灯片对象。然后将setHidden的参数设置为true使该幻灯片隐藏。
  3. presentation.saveToFile(...):保存修改后的演示文稿。

Java 删除 PowerPoint 中指定幻灯片

当某些幻灯片不再需要时,我们可以将其从演示文稿中彻底移除。Spire.Presentation for Java 同样提供了直接的方法来删除幻灯片。

代码示例:

import com.spire.presentation.*;

public class Slides {
    public static void main(String[] args) throws Exception {

        //创建一个 PowerPoint 文档并加载示例文档
        Presentation presentation = new Presentation();
        presentation.loadFromFile("/Sample.pptx");

        //删除第二张幻灯片
        presentation.getSlides().removeAt(1);

        //保存文档
        presentation.saveToFile("output/Removeslide.pptx", FileFormat.PPTX_2010);
    }

}

代码解析:

  1. presentation.loadFromFile(...):加载一个已存在的PowerPoint文件。
  2. presentation.getSlides().removeAt(1):这是删除幻灯片的关键API。它会从幻灯片集合中移除指定索引的幻灯片,此处删除了第二张幻灯片。
    注意事项: 删除幻灯片后,后续幻灯片的索引会自动更新。例如,如果删除了索引为1的幻灯片,原来索引为2的幻灯片将变为索引1。在进行批量删除操作时,应特别注意这一变化,通常建议从后往前删除,或者每次删除后重新获取幻灯片集合的大小和索引。
  3. presentation.saveToFile(...):保存修改后的演示文稿。

总结

本文详细介绍了如何使用 Spire.Presentation for Java 库在Java应用程序中实现PowerPoint幻灯片的添加、隐藏和删除操作。通过这些实用的代码示例,我们展示了如何创建新的演示文稿、向其中添加自定义内容的幻灯片,以及如何根据需求灵活地隐藏或移除现有幻灯片。掌握这些技能,将极大地提升您在自动化办公、数据报告生成和演示文稿管理方面的效率。Spire.Presentation 的强大功能远不止于此,它在自动化文档处理领域拥有广阔的应用前景,期待各位开发者能利用它创造更多有价值的解决方案。

cliproxy 更新有点快,来个脚本启动前更新,或者安装
配置好 config.yaml 后命令行运行

@'
@echo off
setlocal enabledelayedexpansion

echo ============================================
echo   CLIProxyAPI Auto Update Script
echo ============================================
echo.

set "REPO=router-for-me/CLIProxyAPI"
set "API_URL=https://api.github.com/repos/%REPO%/releases/latest"
set "DOWNLOAD_DIR=%~dp0"
set "TEMP_DIR=%DOWNLOAD_DIR%temp_update"
set "ZIP_FILE=%DOWNLOAD_DIR%CLIProxyAPI_latest.zip"
set "EXE_NAME=cli-proxy-api.exe"
set "VERSION_FILE=%DOWNLOAD_DIR%current_version.txt"

echo [1/4] Checking for updates...

REM Get latest version from GitHub
for /f "usebackq tokens=*" %%i in (`curl -s "%API_URL%" ^| powershell -Command "$input | ConvertFrom-Json | Select-Object -ExpandProperty tag_name"`) do set "LATEST_VERSION=%%i"

if "%LATEST_VERSION%"=="" (
    echo [ERROR] Failed to get version info
    echo [INFO] Starting existing program...
    goto :start_program
)

echo [INFO] Latest version: %LATEST_VERSION%

REM Get current local version
set "CURRENT_VERSION="
if exist "%VERSION_FILE%" (
    set /p CURRENT_VERSION=<"%VERSION_FILE%"
)

if "%CURRENT_VERSION%"=="" (
    echo [INFO] No local version found
) else (
    echo [INFO] Current version: %CURRENT_VERSION%
)

REM Compare versions
if "%CURRENT_VERSION%"=="%LATEST_VERSION%" (
    echo.
    echo [INFO] Already up to date!
    goto :start_program
)

echo.
echo [2/4] New version available! Downloading...

set "VERSION_NUM=%LATEST_VERSION:~1%"
set "DOWNLOAD_URL=https://github.com/%REPO%/releases/download/%LATEST_VERSION%/CLIProxyAPI_%VERSION_NUM%_windows_amd64.zip"
echo URL: %DOWNLOAD_URL%

curl -L -o "%ZIP_FILE%" "%DOWNLOAD_URL%" --progress-bar

if not exist "%ZIP_FILE%" (
    echo [ERROR] Download failed
    goto :start_program
)

echo.
echo [3/4] Extracting and updating %EXE_NAME%...

if exist "%TEMP_DIR%" rd /s /q "%TEMP_DIR%"
mkdir "%TEMP_DIR%"

powershell -Command "Expand-Archive -Path '%ZIP_FILE%' -DestinationPath '%TEMP_DIR%' -Force"

REM Stop running process
tasklist /FI "IMAGENAME eq %EXE_NAME%" 2>nul | find /I "%EXE_NAME%" >nul
if !errorlevel! equ 0 (
    echo [INFO] Stopping running process...
    taskkill /F /IM "%EXE_NAME%" >nul 2>&1
    timeout /t 2 /nobreak >nul
)

if exist "%TEMP_DIR%\%EXE_NAME%" (
    copy /y "%TEMP_DIR%\%EXE_NAME%" "%DOWNLOAD_DIR%\%EXE_NAME%" >nul
    echo %LATEST_VERSION%>"%VERSION_FILE%"
    echo [INFO] Updated to %LATEST_VERSION%
) else (
    echo [ERROR] %EXE_NAME% not found in archive
)

echo.
echo [4/4] Cleaning up...
del /f /q "%ZIP_FILE%" 2>nul
rd /s /q "%TEMP_DIR%" 2>nul

:start_program
echo.
if not exist "%DOWNLOAD_DIR%%EXE_NAME%" (
    echo [ERROR] %EXE_NAME% not found
    pause
    exit /b 1
)

echo ============================================
echo   Starting %EXE_NAME%
echo ============================================
echo.

cd /d "%DOWNLOAD_DIR%"
"%EXE_NAME%"
'@ | Out-File -FilePath "cliproxy.bat" -Encoding ASCII

再运行

.\cliproxy.bat

📌 转载信息
转载时间:
2026/1/16 12:50:59

韩国巨头Kyowon确认勒索软件攻击导致数据泄露

微软更新曾触发安全警报的Windows DLL文件

重提示攻击劫持Microsoft Copilot会话以窃取数据

FortiSIEM严重命令注入漏洞的利用代码已公开

如何使用Tines实现应用程序即时访问的自动化

这份5门课程指南助您深度掌握ChatGPT仅售20美元

美国联邦贸易委员会禁止通用汽车五年内出售驾驶员位置数据

Palo Alto Networks警告存在可让黑客禁用防火墙的DoS漏洞

看段视频看到的, 但是好像有点简陋, 就让 gpt 给我搓了一个玩, 想着反正搓都搓了, 放上来大家一起玩

使用方法: Panel 中选择模式和输入训练时间, Game 里面点击 start/reset 即可开始或重置游戏, 最后 Stats 查看数据

因为有宏所以是 xlsm 格式, 代码也是复制的 gpt 的, 没仔细看过, 请各位谨慎对待, 你就当他原本就带毒的吧(虽然宏代码也能看到就是了(Alt+F11 打开 vba 编辑界面)
链接 24 小时或 100 次下载后过期
https://wormhole.app/PpPOMZ#vRWNye7aBTm3uINdsteAbA

为什么命令行越来越具有代理式功能

传统上,终端或 shell 是一种命令式工具,依赖于像lsgrepgit这样的预定义命令来执行特定指令。

 

然而,像Gemini CLIClaude CodeAutoGPT这样的代理性命令行工具的最新进展已经将这个简单的实用程序转变为一个更动态和智能的助手。

 

这些代理式 CLI 工具允许用户用自然语言描述更高级的目标或任务,从而使简陋的 shell 栩栩如生。

 

它们可以规划步骤,利用各种工具完成不同任务(例如文件处理、代码执行和网络搜索),对输出进行推理,并充当辅助驾驶以帮助完成任务。

 

这显著减少了用户的心智负担,并最大限度地减少了多个工具之间的上下文切换。至关重要的是,用户通过批准或指导智能体的过程来保持控制权,确保自动化和用户监督之间的平衡。

 

在本文中,我们将探讨这些代理式工具的架构,对比不同的规划风格,如 ReAct 和计划-执行。

 

我们还将检查代理式工作流程的实际生命周期,从意图捕获到执行,并讨论可靠日常使用所需的关键安全护栏。

 

端到端代理式终端生命周期:一个提示,三个智能体

虽然人工智能在开发中的兴起通常与聊天界面(如 ChatGPT)和代理式 IDE(如Cursor)有关,但代理式 CLI 占据了一个独特的利基市场。基于 IDE 的智能体擅长于以丰富的视觉上下文为中心的代码任务,但它们通常局限于编辑器的窗口。

 

CLI 满足了开发人员管理基础设施和 git 工作流的需求:shell。这种无头的、可组合的特性允许它以 GUI 绑定代理无法做到的方式将工具和系统命令链接起来。然而,请注意,随着像 Gemini CLI 这样的智能体现在可以与 IDE(如 VSCode)集成以提供其建议的差异视图,这种区别正在变得模糊。

 

为了详细说明代理式终端工具的强大功能,让我们讨论一个运行示例。

 

这些标记文件封装了关于如何构建和测试 repo 的事实,以及文档和脚本的约定。他们基本上是代理的入职文件。例如,Gemini CLI 的文件名为“Gemini.md”。Claude Code 工具也使用了类似的约定。

 

考虑一个常见场景,开发人员需要用标准文档和自动化脚本启动一个新的存储库。与其手动创建每个文件并编写样板代码,代理式 CLI 可以从单个高级指令处理整个过程,从而确保一致性并节省宝贵的时间。

 

输入提示:

添加一个 CONTRIBUTING.md,一个 PULL_REQUEST_TEMPLATE.md,以及一个 scripts/smoke-check.sh,运行一个可配置的命令并在失败时退出非零;更新 README 以记录两者,并打开一个 PR。

 

清单 1:用户提示代码片段

 

为了理解这个指令是如何转化为行动的,我们将把代理式的工作流程分解为它的组成阶段。我们从意图捕获开始,其中智能体在项目的特定上下文中定位自己,然后转移到规划风格,对比不同模型架构其推理的方式。后续部分将详细说明执行实际工作的 Tool Execution 循环和防止自主事故的关键安全防护措施。最后,我们将看看结果如何呈现给用户,说明在不同的品牌名称下,大多数代理式工具共享一个共同的架构 DNA。

 

阶段 1:意图捕获和上下文形成

为了确保 LLM 的高质量提示,智能体首先收集所有必要的信息,然后进行规划或执行。这种方法包括几个步骤:将任务链接到当前工作目录,管理会话状态,并将每个项目的配置保存在 dotfolders(例如,./.gemini 和./.claude)。这种方法消除了重复使用标志进行重复任务的需要。

 

此外,指令还隐式地从各种位置获取。以下是 CLI 智能体除了用户的提示之外,从哪些主要信号源获取的一些:

 

特定于文件夹的上下文文件

这些是封装了有关你的存储库如何构建和测试以及你的文档和脚本约定的事实的 markdown 文件。它们本质上充当你智能体的入门文档。例如,Gemini CLI 的文件称为Gemini.md。Claude Code 工具也使用了类似的约定。

 

这是一个高性能的SaaS后端。* **核心原则:** 可读性优于聪明度。显式优于隐式。* **架构:** 六边形架构(端口和适配器)。* **安全性:** 零信任安全模型。所有输入必须通过Pydantic进行验证。* **语言:** Python 3.11+(需要严格类型)。* **框架:** FastAPI(异步默认)。* **数据库:** PostgreSQL(通过SQLAlchemy 2.0异步会话)。* **测试:** Pytest(覆盖率必须保持>90%)。
复制代码

 

清单 2:Gemini.md 示例

 

技能

早期智能体的一个主要限制是需要将所有指令塞进上下文窗口。Anthropic 的 Claude Code 引入了Skills的概念,它建立在上述 markdown 文件的想法之上,作为专业知识的模块化包(例如,PDF 操作、数据分析和 React 最佳实践),作为包含SKILL.md的文件夹存在。

 

这种包含使得渐进式披露成为可能:智能体最初只看到可用技能的名称/描述(消耗最少的词元)。然后,只有在用户的任务需要时,它才动态安装或读取完整的SKILL.md指令集。这种方法允许将智能体默认成为通才,但在需要时是专家。

 

代码库信号

CLI 可以扫描现有的scripts/.github/,并拾取像README.md这样的文件工件,如果你已经提供了这些文件。基于像 Python 这样的语言的典型约定,它还可以查看像pyproject.toml这样的工件以获得高级概览。

IDE 焦点

这是一个可选步骤,如果你连接到像 VSCode 或 Cursor 这样的代码编辑器,可以用来打开文件和选择。

 

阶段 2:规划风格

加载上下文后,每个工具开始其控制循环:

 

  • Gemini(ReAct风格)思考,调用工具,观察并重复,这非常适合发现缺失的文件夹或策略。这种迭代方法允许 Gemini 适应新信息并动态调整其策略,使其适用于需要灵活解决问题和探索的任务。

  • Claude(计划和执行)提出一个你可以批准的清单,然后逐步执行计划,并带有策略钩子。这种方法提供了更高程度的控制和透明度,因为用户可以在执行前审查和修改计划,确保遵守特定的策略或偏好。

  • Auto-GPT 发出思考加上每个周期运行器执行的 JSON 命令。这种结构化输出便于自动化和与其他系统集成,因为 JSON 格式提供了智能体意图和行动的清晰且机器可读的表示。

 

以下示例说明了不同智能体如何处理这个规划阶段。Claude 提供了一个人类可读的清单供用户审批,而 Auto-GPT 生成了专为自动执行而设计的 JSON 输出。

 

Claude——计划预览

计划:创建脚本/smoke-check.sh (POSIX sh;从env读取CMD;失败时退出非零)创建CONTRIBUTING.md(如何在本地进行冒烟检查)创建.github/PULL_REQUEST_TEMPLATE.md(检查清单包括冒烟检查)更新README.md,添加scripts/和PR模板说明运行冒烟检查运行smoke-check;提交;打开PR批准吗?[是/否]
复制代码

 

清单 3:Claude 计划审查代码示例

 

Auto-GPT——带有思考和命令的显式 JSON

“thoughts”: {"text“: ”创建冒烟检查,文档,模板;更新README;运行脚本;提交/PR”},"command":{"name":"write_file","args":{"path":"scripts/smoke-check.sh","content":"#!/bin/sh\n: \"${CMD:=echo ok}\" \n$CMD || { echo \"smoke failed\" >&2; exit 1; }\necho \"ok\""}}}
复制代码

 

清单 4:Auto-GPT 审查代码示例

 

阶段 3:工具调用

在此阶段,智能体使用其库中的工具根据其任务提出更改建议。例如,这可能涉及使用文件编辑工具在 IDE 中显示差异。

 

工具已经从专有实现发展为开放标准:模型上下文协议(Model Context Protocol,MCP)。在 Anthropic、谷歌和其他组织的支持下,MCP 就像 AI 应用程序的 USB-C 端口。而不是硬编码集成每个数据库或 API,(例如,用于 PostgreSQL、Slack 或 GitHub 的服务)。CLI 智能体在启动时自动发现这些资源,允许单个智能体在一个无缝的工作流程中查询你的生产数据库,阅读你的线性票证,并编辑代码。

 

示例冒烟脚本的 Diff

*** scripts/smoke-check.sh ++set -eu +# CMD可以被覆盖:CMD="make test" ./scripts/smoke-check.sh +: "${CMD:=printf ok}" +$CMD >/dev/null 2>&1 || { echo "smoke failed" >&2; exit 1; } +echo "ok"
复制代码

 

清单 5:冒烟脚本 diff 示例

 

Claude 的钩子是一种明确策略的干净方式——限制写入路径、自动 chmod 脚本、在写入后运行 lint/tests——而不需要将其塞入提示中。Gemini 通过扩展和 MCP 获得类似的杠杆作用:不同的旋钮,类似的结果。

 

阶段 4:人为干预的安全和护栏

你保留了对冒险行为的控制。Gemini 在执行写入或具有副作用的 shell 命令之前需要你的批准。Claude 提供了确认和钩子,允许你阻止违反策略的写操作,或者在继续之前自动运行检查。Auto-GPT 暂停是/否确认,除非启用连续模式。为了进行探索,激活一个容器化的沙箱来隔离文件系统和进程。

 

阶段 5:执行和迭代:真正完成工作的循环

创建文件后,智能体执行脚本并根据结果进行调整。例如,如果缺少scripts目录,Gemini 将创建它并再次尝试操作。如果脚本缺乏可执行权限,Claude 的集成钩子会自动应用chmod +x命令。

 

脚本在观察、推理和操作的连续循环中执行。这个循环不断重复,直到本地执行成功并完成文档。

 

阶段 6:渲染结果和停止条件

CLI 提供了一个清晰的、语法高亮显示的工具调用和文件差异视图。用户可以在编辑器中打开这些差异,手动进行调整,或者指示智能体进行适当的更改。批量批准是最有效的,例如在单个批准之前一起审查所有脚本和文档。

 

在一次成功的冒烟检查之后,通过批准的差异,智能体将创建一个新的分支,提交更改,并打开一个 PR 草案。

 

如何在你的工作流程中利用代理式 CLI

以下是一些实用技巧,帮助你在工作流程中充分利用这些工具:

 

  • 将上下文文件视为构建资产

 

将 GEMINI.md 和 CLAUDE.md 文件与你的 README 文件一起维护。这些文件应该简洁且专注于特定细节,包括构建和测试程序、配置位置、任何特定于存储库的问题以及安全编辑的目录。你甚至可以使用智能体生成初始草稿。将这些文件视为为代理式编程环境的方式,而不是另一个需要持续监督的提示。

 

  • 积极地限定范围

 

将智能体指向实际重要的文件夹(例如 services/payments/,而不是整个单体仓库)并传递明确的 @file 提示以指向热点。更紧凑的范围意味着更紧凑的差异,更少的创造性幻觉和更快的迭代。如果任务确实跨越多个包,请在提示中列举它们,以防止智能体进行详尽的扫描。

 

  • 使用沙箱避免对环境的意外更改

 

Gemini CLI 提供了一个沙箱模式,用于 shell/file 工具的临时、容器化执行。这保护了你的主机系统,限制对挂载的工作目录的写入,并控制网络访问。它非常适合无风险的探索,但不会消除对破坏性命令的审批提示,不能编辑已安装的秘密,也不能防止模型建议有风险的操作。你仍然是最终的仲裁者。

 

Claude Code 通常在容器化开发环境(Dev Container/Docker)中运行,或使用插件/钩子将 shell/file 操作通过容器化运行器路由。这提供了类似的隔离(写入限制在挂载路径,控制环境,确定性工具链)。然而,这种隔离并不具有回溯性;如果允许,它不会阻止对挂载的秘密或暴露路径的意外写入。使用钩子来强制执行路径限制,并在写入最终确定之前自动运行测试/lint。

 

Auto-GPT 没有专门的沙箱模式标志,但强烈建议在 Docker 容器中运行它。这确保了其文件系统操作与你的主机操作系统隔离,防止对你主要环境的任何意外更改。

 

  • 使用符合你需求的工具

 

Gemini CLI 非常适合深入集成到谷歌生态系统中的用户。它作为一个通用工具,擅长于发现繁重的任务,包括代码编辑、文档更新、小的 shell 操作(如列出目录和移动文件)、快速网络研究以及探索性的解决问题。它的 ReAct 循环促进了自然的探索和迭代工作。

 

Claude Code 最适合需要具体计划和强大编码能力的任务。这包括多文件重构、通过钩子执行策略、Git 原生工作流程(分支、变基、冲突解决)和透明的护栏。

 

GitHub Copilot CLI旨在为快速、存储库感知的自然语言到 shell 辅助提供支持。它非常适合生成一次性命令、搭建测试、搜索代码以及起草提交和拉取请求,所有这些都不会破坏现有的 GitHub 工作流程。

 

其他工具包括AiderOpen Interpreter和本地优先 CLI。当你需要对实现有更大的控制权,并且有高度特定的需求,如紧密的 Git 人机工程学、本地 LLM 或不受限制的 shell 环境时,可以考虑这些选项。这些工具对于喜欢较少护栏和更快修改工具本身的经验丰富的用户来说非常有用,特别是对于较小的存储库。

 

  • 像工程师一样提示,不要写论文

 

好的提示主要是关于清晰的合同,而不是华丽的散文。使用包含以下详细信息的四部分提示。从一个高层次的目标开始,用一句话陈述你的意图。

 

定义约束,包括范围(例如,“仅 services/billing”)、风格(“POSIX sh; no bashisms”)和安全协议(“写入前询问”)。确定所需的工件,指定预期的结果(例如,文件、测试、README/PR 文本)。

 

确定检查,概述将如何衡量成功(例如,测试命令、验收标准)。

 

  • 像任何其他自动化一样进行仪表化

 

为了优化智能体性能,监控关键指标,如 PR 周期时间、智能体生成的差异大小、需要返工的 PR 百分比以及智能体编辑后不稳定测试的频率等。

 

这些指标作为反馈,不仅用于智能体的整体有效性,还用于你自己的运维合同。

 

接下来是什么

 

代理式 CLI 正在从简单的 shell 助手演变为将你的工作工具、操作系统和云基础设施统一起来的连接组织。以下是截至本文撰写时的一些新兴趋势:

 

  1. IDE 和操作系统正在融合成统一的 Agent Surfaces。像Windsurf和 Cursor 这样的工具允许智能体在终端、编辑器和运行过程中共享上下文,而不是作为孤立的聊天窗口运行。Windows 也在其体验中注入了大语言模型驱动的交互

  2. 智能体正在从响应式 CLI 转变为持久的后台服务。这些守护进程智能体不是等待输入,而是主动监控日志文件和本地服务器,仅在出现错误时介入修复计划。虽然这些工具(如 GitHub PR 上的 Copilot)仍处于起步阶段,它们的洞察力尚浅,但随着正确的集成,它们将不断改进。

  3. 扩展正在成为代理能力的 App Store。随着 CLI 智能体的技能扩展等创新,我们正在开发新一代的 App Store,让用户可以将适当的能力插入到他们的智能体中。这也模糊了通用智能体和专业智能体之间的区别,因为专业智能体只是一个拥有正确知识和工具的强大通用智能体。

 

https://www.infoq.com/articles/agentic-terminal-cli-agents/

项目地址 GitHub - Maggotxy/AutoMule: AutoMule
视频介绍:【开源了个好玩的程序?廉价版蚂蚁灵光 AutoMule 赛博牛马 24*7 不间断工作 老板喜欢的员工】 https://www.bilibili.com/video/BV18z6UBHEVz/?share_source=copy_web&vd_source=52ccfc8d7a4fddba61c7577eedae3fec

调用了 iflow sdk 实现了真正 24 小时不间断工作的电子牛马

终究是活成了老板喜欢的样子


📌 转载信息
原作者:
lamb031226
转载时间:
2026/1/11 08:43:24

你是不是经常遇到 codex 长时间运行但是完全不知道它是活着还是死了,薛定谔的猫状态发生了,你想手动停掉,又告诉自己,也许它还在运行呢,也许再等等? 平白耽误了时间,这个月 tokens 又花不完啦,中了 openai 控流的奸计。

好了,现在有了一个 Codex_Stuck 小插件,通过巧妙的(实际上笨拙的)设计,让你的终端时时展示 cx 状态,尤其是是否 stuck. 废话不多说,上链接:

点它!安它!星它!

这其实是为了给 ccb 和 cca 打造的监测器,后面会集成到 ccb 中,当然独立使用完全无问题啦。

另外 ccb 更新到 3.0 版本啦: 只能说强到没朋友,快去试试吧:


📌 转载信息
转载时间:
2026/1/10 19:19:37

Matrix 首页推荐 

Matrix 是少数派的写作社区,我们主张分享真实的产品体验,有实用价值的经验与思考。我们会不定期挑选 Matrix 最优质的文章,展示来自用户的最真实的体验和观点。 

文章代表作者个人观点,少数派仅对标题和排版略作修改。


一眨眼2025年已经快结束,今年AI进步速度快到远超预期。从DeepSeek到Claude Code到GPT 5.1到Gemini3到Nano Banana二度升级,整整一年,AI圈都处于「月月有惊喜」的放烟花状态。

与之相伴的,是AI越来越嵌入我的工作场景,我扎扎实实感受到了AI对我工作(乃至个人生活)的优化与提升。今年最最喜欢的大模型是谷歌的Gemini,文书和信息分析的表现非常不错,也因此被我亲切地称呼为「G老师」。

本篇主要盘点和G老师相处的25年,我在如何花式压榨G老师,同时盘了盘目前法律人使用AI的现况。

本文将从【工具地图】和【项目思路】两个维度,复盘我这一年压榨G老师的经验。如果你想直接看实操,可以选择跳到第二部分进行阅读。

一、法律人使用AI的三个层级&调用工具的五个维度

(一)法律人的AI使用三层分级

最近非常启发我的一篇文章是杨律师写的《律师用 AI,别只盯着那些「法律 AI 工具」》,他在这篇文章中提到了法律人使用AI的三个层级:

第一层,是通用大模型工具。比如豆包、ChatGPT 这一类chatbot,能帮你改写、润色、翻译、起草,解决的是「文本处理」的通用问题。

第二层,是行业化的法律 AI 产品。比如法律检索、智能合同审查,这些是厂商基于「律师的共性场景」包装出来的服务。

第三层,则是你个人或团队的 AI 工作流。这一层,往往不会以「产品」的形式出现,而是:

  • 写好了就反复复用的提示词和模板;
  • 若干半自动的脚本、小工具、表单;
  • 以及围绕你自己的客户、案件、内容库搭出的上下文工程。

前两层可以用钱买,第三层只能靠你自己「支棱起来」。而真正把你从「会用 AI」拉向「离不开 AI」的,恰恰就是这一层。

图片

(二)个性化层级下的工具调用五阶梯

我非常认同杨律师的观点,在未来,第三层(个性化设计)的使用只会越来越重要。根据他对法律人使用AI的「第三层」,我认为第三层的工具调用可以被分成五个阶梯:

图片

第一阶:将应用嵌入已有工作流

这是最轻量的一层,追求「即时、无感」。例如以浏览器插件、输入法或划词助手等形式,让用户在阅读网页或打字时随时调用AI,主打一个Shortcut快捷操作 。法律场景下也已经有此类产品出现:

  • 如北大法宝最近研发了「律爱多浏览器助手」,用户可以在浏览网页时调用小助手一键检索浏览信息相关的法律法规;
  • 再如小杨老师奇川律师都曾经写文章介绍过豆包划词助手的快捷用法;
  • 又如案牍近期推出了word插件版本的新产品形态,这也是一种典型的让产品嵌入现有工作流的形式。
图片

第二阶:顶级模型定制化

这是最常用的进阶层。利用Claude Projects、GPTs或Gemini的Gem,通过投喂知识库、设置系统提示词和上下文,让AI成为懂你业务的专属助手 。

这一层的构想,是我在读小杨老师的文章《一文教你把GPT-5调试成最强法律助手》时得到的启发,她在这篇文章里介绍了何为「AI工程化思维」:

 一言以概之,AI工程化思维就是通过合理的架构,如版本控制(Prompt库)、学习机制(记忆库)、审查标准(Criteria)、反馈闭环(Iteration Log),使得输出效果不断提升,接近人类思维结果。 学会利用上述步骤尝试对大模型进行自主工程化设计,是让大模型表现越来越个性化的必要入口。

除此以外,今年Claude、Gemini、ChatGPT都在研发的skil功能也非常值得探索:只用 Claude Skills,打造专属 AI 伴侣|附完整教程。目前,我也已经看到有律师使用skil研发自己的小工具。

第三阶:自动化私有数据

利用Obsidian、Notion、飞书等软件,让个人数据更好地被流转调用 。这一层我摸索得不多,但身边已经有法律行业的朋友在卷了:

图片
此处感谢伊卡洛斯老师的截图授权,欢迎关注他的公众号「燧翼新章」

附相关文章:Gemini Cli + Obsidian 才是知识管理的神!!(附教程)

第四阶:搭建业务流应用

利用Dify、Coze或FastGPT搭建Workflow(工作流)和Agent。这里涉及多步推理,让AI像人一样按步骤思考,比如「先检索法条,再分析案情,最后写出报告」 。

第五阶:Vibe Coding

使用Cursor、Trae等工具进行开发,创造完全属于自己的工具 。

四五阶我目前几乎不涉及,此处就不再多展开,感兴趣的朋友可以自行检索。

(三)AI工具的使用心法:君子不器

列出这五层,不是为了让大家去攀爬技术的高峰,非要学会第五层工具才算「会用AI的律师」 。恰恰相反,我想强调的是 「君子不器」 。我们使用AI的核心原则应当是以完成任务为导向,而不是以技术为导向 。

不要为了显摆技术而去强行使用高阶工具。比如,没必要专门用自己做一个合同审查的agent,合同审查这个场景,花了更多精力和时间的法律科技公司研发的产品必然比一个律师手搓的小工具好用。作为律师个人,通过配置层做一个专门「思考合同条款的Agent」反而更实用、更好落地 。

图片

二、我使用Gemini搭建个性化工具的思路

作为一个非技术背景出身的纯血法学生,我目前的个性化探索主要围绕主流大模型自带的「自主工程化工具」展开。我把Gemini整成了项目制的,用到的工具是Gemini自带的「Gem」功能。

图片

Gem的架构非常简单,名称、指令(系统提示词)、知识库就是构成一个Gem的全部要素。

图片

(一)为什么是Gems,而不是Coze或Dify?

市面上有很多Agent搭建平台,比如Coze、dify、腾讯元器等等。我在日常工作中首选Gemini的Gems,主要基于以下考量 :

  • 顶级的模型底座:智能体的表现如何首先取决于调用了什么大模型。工作流程相对简单的法律任务,直接使用顶级大模型优于可以设计复杂流程的低代码工具。
  • 交互记忆的连贯性:Gems直接嵌入在Gemini的聊天界面中,拥有最多的日常交互记忆,使用起来像是在和一个熟悉的同事对话,而不是每次都在调试一个冷冰冰的软件。
  • 低门槛:因为门槛足够低,所以上手足够迅速,心理负担非常轻。

(二)拆分项目思路:法律工作的四象限切割法

至于究竟怎样的项目才值得被固定制作为一个gem,我总结了一套四象限切割法。我们可以构建一个坐标轴:X轴代表任务的属性(从复杂项目固定项目),Y轴代表我们的关注点(从高注意点高频次。针对落在不同象限的工作,我有完全不同的「调教」策略 。

图片

第一象限:高频次 + 固定项目(文书合并同类项):

  • 场景特征:这是律师最想摆脱的机械性劳动。比如发律师函、起草简单的借款合同。这些工作频率极高,结构非常固定。
  • 制作Gem的要点: 提供范本。 不要让AI创作,而是让它去填空。我创建了诸如「律师函起草小助手」这样的Gem,核心动作是将我过往写过的最完美的范本喂给它作为知识库。每次使用时,我只输入变量材料(相关联的具体的合同、金额、违约事实),它就能基于范本生成完美的初稿 。

第二象限:高注意点 + 固定项目(固定流程的特别核查):

  • 应对策略:提供优质提示词。 这里不需要AI模仿文风,而是需要明确要AI达成的任务要点。比如我制作了「合同条款斟酌小助手」,在系统提示词中预设了陌生人原则(假设对背景一无所知)和对抗者原则(假设是对方律师)。

我把审核的标准写进了Prompt里,强制AI对每一个条款进行压力测试,防止「想当然」的漏洞 。后面我也会提到制作优质提示词的小技巧。

图片

第三象限:高注意点 + 复杂项目(复杂文书与分析):

  • 场景特征:针对复杂项目的思考,比如撰写复杂的代理词、疑难案件的法律分析报告、实务文章等。这类工作无法用一个范本解决,往往涉及多线程的思考,我们很难在一个对话框里完成全部的任务。
图片
  • 应对策略: 对话框的重点分布(流程拆解)。 对于这种复杂项目,直接扔给AI很难直接得到好结果。

我的策略是将对话框变成「分步执行」的载体。例如在「论文指导小助手」中,我已经将论文需要的基础资料放置在知识库中,在这一基础上,我不会「论文指导小助手」让直接写论文,而是将论文切割为「寻找素材、搭建框架、撰写文本、修改文本至定稿」四个步骤。由于每个步骤有每个步骤需要注意的重点,因此每个步骤我都会单独开具对话框执行任务,确保重点不搅和在一起打架。

图片

第四象限:高频次 + 复杂项目(?):

  • 场景特征:这是象限图中标注「?」的区域,也是最难处理的「深水区」,是我目前还在探索的部分,暂时还没有特别典型的例子可举,待我再多探索下再来分享。

(三)关于如何撰写优质的Gem系统提示词

在前面我们讨论「四象限切割法」时提到,针对「高注意点 + 固定项目」,最核心的注意点是撰写优质提示词。所以,写好提示词对于法律人而言,不仅仅是技术问题,更是将我们脑子里的法律思维,翻译成AI能听懂的、可执行的指令。我总结了两条更适合法律人的进阶路径。

偷懒路径:让AI自己写AI的指令

如果你刚开始接触,不知道怎么描述需求,最简单的办法是「反向求助」,让AI利用它的归纳能力,帮你搭建80分起步的基础框架:

  • 针对老项目:如果你已经和Gemini在临时对话框里就某个案子聊了很久,这时你希望想把这个案子做成一个gem的项目。你可以直接在这个对话框里输入:「我现在想把上述内容制作成Gem以便后续复用。请结合我们的聊天记录,为我设计这个Gem的系统提示词。」
  • 针对新项目:直接告诉它你预期设置的Gem的背景。比如:「我是XX领域的诉讼律师,我最常用的功能是XXX,请结合我的情况,为我生成一个可以直接使用的个性化配置提示词。」

2. 进阶路径:Read in, Prompt out

这是我从醋泡白豆老师的文章里得到的灵感。所谓 Read in, Prompt out,就是我们在阅读法律专业文章、法官判词或大佬著作时,不要只盯着具体的知识点,而要思考如何提炼其中的方法论思维模型」,并将其转化为AI的审核原则

例如,我曾读到一篇名为《做律师,切忌「想当然」这三个字》(该提示词的撰写过程我已经写过文章,欢迎跳转查看详细步骤)的文章。文中提到,律师写合同最怕觉得「这还要写?不是谁都知道吗?」,但法官在裁判时只能依据条款本身,不会替你脑补。简而言之,合同上写的就是写的,没写的,法官也未必可以替你补脑。

为了解决这种律师常犯的「想当然」错误,我将文章中对于「想当然」的具体描述复制粘贴给了Gemini,并让Gemini基于此为我撰写提示词。Gemini生成的系统提示词非常不错,它认为审查一个条款需要遵循「四大审查原则」:

  • 陌生人原则:假设你对该交易所处的行业、交易习惯、以及合同双方的背景一无所知,这个合同条款的表达是否有效?
  • 对抗者原则:假设你是对方的律师,你会如何攻击这份合同?
  • 执行者原则:假设你是一名两年后才入职的员工,看到这份合同能否直接执行,无需进行任何口头询问?
  • 缺席者原则:假设所有参与当年合同谈判的人员都已离职或失联,仅凭文字能否还原原意?

这四大原则提供的视角非常到位,已经足以帮助我审查出一个合同条款可能存在的漏洞。算是我「Read in, Prompt out」最成功的一个提示词。

    看到有佬友闹钟没响,所以介绍一下快捷指令节假日自动开关闹钟
    第一步,设置闹钟
    设置你的起床闹钟时间,注意设置标签,例如我设置的标签名称起床闹钟,方便后面查找使用
    第二步,配置快捷指令
    2.1 打开快捷指令,并新建快捷指令
    2.2 添加操作并搜索日历,选择获取临近日程,修改 1 个日程为 5 个日程,打开向下箭头修改时间任一天为今天
    2.3 继续在搜索 app 和操作中搜索如果并选择,修改临近日程为标题,条件选择包含,文本填写
    2.4 继续在搜索 app 和操作中搜索闹钟选择开关闹钟,点击向下的箭头操作选择切换状态,关闭运行时显示,然后修改第一个变量为关闭,第二个变量选择之前闹钟设置的起床闹钟标签,最后长按并移动到上面的如果标题包含休这个分支下面
    2.5 继续在搜索 app 和操作中搜索如果并选择,长按并移动到否则下面,修改第一个变量临近日程为标题,条件选择包含,文本填写
    2.6 继续在搜索 app 和操作中搜索闹钟选择开关闹钟,点击向下的箭头操作选择切换状态,关闭运行时显示,然后修改第一个变量为打开,第二个变量选择之前闹钟设置的起床闹钟标签,最后长按并移动到上面的如果标题包含班这个分支下面
    2.7 继续在搜索 app 和操作中搜索获取变量选择修改为当前日期,长按移动到如果包含标题班的否则分支下面,再次搜索格式化日期并放到获取当前日期下面,点开向下箭头并修改日期格式为自定义,格式化字符串修改为 EEE,区域默认
    2.8 在格式化日期下面搜索并添加如果分支,选择条件为包含,文本填写,当前分支下搜索并添加开关闹钟,点击向下的箭头操作选择切换状态,关闭运行时显示,然后修改第一个变量为关闭,第二个变量选择之前闹钟设置的起床闹钟标签
    2.9 在格式化的否则分支下,搜索并添加如果分支,选择条件为包含,文本填写,当前分支下搜索并添加开关闹钟,点击向下的箭头操作选择切换状态,关闭运行时显示,然后修改第一个变量为关闭,第二个变量选择之前闹钟设置的起床闹钟标签,然后在这个分支的否则分支下搜索并添加开关闹钟,点击向下的箭头操作选择切换状态,关闭运行时显示,然后修改第一个变量为打开,第二个变量选择之前闹钟设置的起床闹钟标签
    2.10 点击最上方的标题向下箭头重命名这个快捷指令并保存。
    第三步,自动化快捷指令
    3.1 创建个人自动化并选择特定时间,修改特定时间为 01:00,这个时间为 0 点到起床闹钟的时间前面,设置凌晨 1 点是我感觉各位佬应该睡觉了吧这个点,如果没睡往后设置到睡觉的时间点就行,不要晚于起床闹钟时间
    3.2 重复选择每天并下一步
    3.3 添加操作搜索快捷指令并选择打开快捷指令,选择变量为刚刚创建的快捷指令节假日闹钟并点击下一步
    3.4 关闭运行前询问并保存。

    放一个我自己的快捷指令分享,不知道佬友们直接添加能不能用,自动化还是要自己设置的,还有就是闹钟的标签要改为起床闹钟
    修改节假日闹钟

    快捷指令创建完成后可以关闭起床闹钟并执行一下试试,今天是工作日,成功了应该是会打开的

    此方法仅支持 ios16 版本以上,正常情况下各位佬友的日历中应该是有中国大陆节假日的,自己可以看一下日历中应该有休和班的标注


    📌 转载信息
    原作者:
    hw7622
    转载时间:
    2026/1/4 12:27:52

    可以使用快捷指令实现
    自定义闹钟 - 就寝版
    自定义闹钟 - 常规版

    1. 点击「自定义闹钟 V3.0 - 常规版」下载添加,按照要求进行闹钟时间添加
    1. 手动运行一遍「自定义闹钟 V3.0 - 常规版」快捷指令,允许对应的权限请求

    . 设定个人自动化:

    • 特定时间 00:05
    • 重复 每天
    • 立即运行
    • 选择「自定义闹钟 V3.0 - 常规版」快捷指令

    原作者 微信公众号 [Jubal Moment]


    📌 转载信息
    原作者:
    phpluo
    转载时间:
    2026/1/4 10:48:38