news 2026/8/6 0:34:28

如何设计一个 Agent 友好的 CLI

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何设计一个 Agent 友好的 CLI

以能让用户径直填 API Key 作为最简单的 CLI 授权方式, 但明显存在问题: API Key 一般长时间有效、具备全量权限且以明文形式存储, 一旦出现泄露情况风险极大, 并且没办法依照操作来细分权限。对于那种会被 Agent 主动调用以管理各类资源的 CLI 而言, 这种“一把钥匙开所有门”的方式风险实在太高。

因此, 在实际操作当中, 采用了OAuth 2.0 Grant(设备码流程)的解决办法, 用户于浏览器里进行登录操作且依据scope给予授权认可, CLI所获取到的是短期内具备有效性、能够进行刷新、可以实施精细授权、服务端能够随时予以吊销的token。整个运转过程包含三个步骤:

此外, 不少传统的CLI(像是gh、等等)会存在另外一种OAuth的实现情形, 是借助在本地启动一个临时HTTP, 用于接收浏览器回调的途径来达成的。然而, 它对于Agent可是不太利于其运行的, 这是由于Agent有可能运行在那种没有浏览器以及图形界面, 并且端口也未开放的服务器环境当中。而设备码流程是支持授权过程在任意一台机器的浏览器上予以完成的, CLI方面仅仅进行发起以及轮询这两项操作。在整个授权过程之中存在着两个关键阶段:

1. 分阶段轮询

当人类用户通过手动方式进行登录之时, CLI 能够出于自行动作的形式, 打开浏览器之后, 持续不断地执行轮询操作, 以此进入等待状态。至于 Agent 而言, 它遵循着这样一种循环模式, 先是执行命令, 再去获取结果, 接着在此基础上作出下一步的决定。然而, 要是此次工具调用之时, 既需要输出登录连接, 同时叉要开展不间断轮询操作, 那么登录链接便无法经由模型正常反馈给用户, 进而招致整场会话陷入阻塞状态。

所以, 于实现期间, 将Agent的登录予以拆分, 形成了异步的两个阶段。第一阶段, 立马返回, 返回的JSON当中, 除了验证URL以及设备码之外, 亦带有一个面向Agent的东西, 明确地告知它接下来应该运行何种命令:

linkai auth login --no-wait --json

进入第二阶段, 开启轮询操作, 每次最多会等待若干秒之后进行返回这一动作, 当出现超时且尚未完成的状况时, Agent能够借助下一次的工具调用再次展开轮询。

linkai auth login --device-code--wait 60 --json

在此处运用了–wait参数, 以此区分出了两类用户, 其中, 不进行传递(也就是默认情况下会阻塞直至设备码过期)的那种, 走的是人类的交互式登录路径, 而传递了–wait的情况, 就切换到了Agent的有界轮询路径。

2. 授权页面

授权登录该页面, 乃是用户直接进行交互以及做出决策的界面, 此情形下, 需要将三件事情清晰地展现出来:

三、命令与参数

这一部分讲述命令参数设计的详情, 针对单一命令而论, 从事开发的人员期望呈现清晰的表格以及按顺序排列给出回复, 然而智能代理则更加要求径直返回能够被分析解难条理条理分明的数据。

1. JSON 格式输出

首先, --json其作为一个全局参数, 它能够使得命令输出呈现出结构化的JSON格式数据, 如此一来, 只要在给予Agent的Skill当中约定“总是添加 --json参数这件事”,那么就会致使Agent能够获取到稳定且可解析的结构化数据。

2. 流式与非流式

跟大模型进行交互的这类命令, 人类习惯于那种流式(SSE)呈现的打字机效果, 然而 Agent 借助 Bash 调用的时候, 其输出会遭遇到管道重定向的情况, 流式会将相关内容切割成碎片, 这对解析并不利, 它更需要的其实是一次性给出的完整回复。

这里未将流式参数 (--/--no-) 当作必选项, 而是依据运行情况自动挑选默认值, 于终端环境中默认是流式, 在管道或者重定向(Agent 的典型情形)中默认是非流式, 并且在 --json 时强制为非流式, 显式传递参数能够进行覆盖。

3. 写操作试运行

支持 --dry-run 用于破坏性/变更类的命令, 它能够不实际发起请求, 只是去打印将要发送的 HTTP 请求, 如此一来 Agent 可以在真正执行之前对参数是否正确进行预检查, 还增进了一道安全校验。

4. 输出分流与退出码

接下来把结果通过走标准输出()这个方式进行呈现, 而过程信息则是采取走标准错误()的途径来处理。像等待进度、更新通知以及交互确认的问句等这类过程信息,要是将其输出到 , 那么就会对 Agent 针对 JSON 结构的解析产生影响, 在进行分流程处理之后, Agent 仅仅需要对标准输出展开处理就行。

也针对退出码进行了区分, 借此让 Agent 在失败之际能够判定究竟是应当重试还是停止, 于实现过程里设计拟定了这几个退出码: 0 代表成功;1 表示一般错误;2 为参数错误;3 是认证/权限问题;4 乃网络异常。当中权限不足(exit 3)之时, 会于错误信息内给出命令提示(比如 auth login --scope"..."), Agent 依据该提示会再度进行授权拉起, 而非持续反复重试。

四、Skill 设计

CLI凭借命令达成了一系列接口的封装, 接下来有待解决的是, 若任凭反复通过--help去查看参数, 显然试错成本过高, 因而需要一个用作配套的Skill, 这是给Agent看的, 表示让Agent知悉怎么精准调用这些命令的相关内容指引说明, 进而让Agent了解究竟该如何恰当地调用这些命令的CLI说明书。

斯吉尔的结构尽可能达成扁平模样, 一个主要的斯吉尔点卡作为入口之处, 各个模块的命令说明却放到正斜杠目录里头。

skills/linkai-cli/ ├── SKILL.md # 主入口:全局说明 + 各模块简介 + 决策流程 └── references/ # 按模块拆分的细节:auth / install / admin ...

这样的结构安装进Agent里, 就只会存在一个目录, 其原则是, 优先让Agent去看主Skill文件, 要是有谁需要了解模块细节, 那就再深入其中去查看。会有一些CLI, 把每个子模块都安装成一个Skill, 如此一来, 实际上并不友好, 一方面, Agent没有对整个CLI的全局视角, 另一方面, 大量的子Skill会让Agent的上下文消耗增加。

构建期间, Skill藉由go:embed被打包进二进制, 此与CLI版本严格锁定, 与此同时又实现了skill命令, 能一键完成技能安装。

还有一个细节方面的优化, 在主SKILL.md之中, 内置了一段安装方面的说明内容, 当Agent首先拿到Skill的时候, 比如说从Skill Hub里直接进行下载, 此时也能够依据引导, 顺利地实现CLI二进制软件的安装。

五、分发与更新

提升易用性的关键在于 CLI 的分发设计, 其主要分发两部分内容, 一部分是 CLI 二进制, 另一部分是 Agent Skill, 理想状态是让 Agent 能一句话就自行完成安装, 在实现方面建议尽量支持多种渠道, 要使得不同平台以及系统下的开发者和 Agent 都能够寻找到合适的渠道从而顺利进行下载, 比如:

方式命令

npm

npm i -g -cli

安装脚本

curl -fsSL .../.sh

brew .../

Go

go .../-cli@

下载二进制

在有Node环境的机器那儿, 借助npm进行安装是最为便捷的那种方式, 这是由于它能够将不同操作系统以及平台架构之间存在的差异给屏蔽掉, 会自动去挑选安装适宜的CLI二进制文件, 并且把它添加到环境变量里面。而一键安装脚本的话, 它是能够更好地适配没有依赖的环境的, 除了下载CLI之外, 它还会同对Skill进行一键部署, 使其分发到各个常用Agent的技能目录里头(像是Codex、Code等等这些)。

之所以说一份清晰的安装说明 (.md) 很关键, 是为了能让 Agent 进一步实现一句话装好, 要把从零安装所涉及的完整步骤写成指南, 如此一来用户只要把一句话发给 Agent 就能够一键完成 CLI 和Skill的初始化, 比如:

先进行阅读, 接着依据其中的步骤, 去安装CLI, 再去安装Skill, 随后开始运用起来。

版本更新是分发的延续,做了两层实现:

六、安全性

登录进行授权仅仅是第一道防护举措, 于 Agent 使用相应场景当中还存在着几个至关重要的要点:

有这样一种操作, 说是把权限依据以下标准进行最小化设置, 先来说说权限设定的这一方面, 权限的一个范围, 它采用资源冒号动作这样的格式去表示, 就像 app 与 read 组合成为什么呢 app:read, 还有 db 与 write 组合成 db:write 这样子的形式, 然后呢默认情况下它只会授权给予只读以及那种内容生成类型的权限。接着要说对于像变更、删除这类高危操作的情况, 必须要进行显式的某种设置才行, 只有这样做有什么好处, 好处在于哪怕 Agent 出现误操作的情况后, 它也没有能力越过 CLI 的权限管控。再讲讲 Token 存储这方面, 在 macOS 这个操作系统环境下, 会优先把凭证存放到系统钥匙串那个地方, 而在其他的平台上面, 就存储到文件里, 并且这个文件设置的权限是 0600 , 还要使用那种服从服务端能够进行撤销动作的 token, 这里说的可不包括那种需自行解析的 JWT , 在登出这个操作的时候, 要让服务端的 token 同步被吊销掉。再看看设备绑定这部分, 每个请求都要携带设备 ID , 那服务端呢会把关 token 于这种设备把设备 ID 与 token 进行某个绑定动作这样的行为, 这样做是为了降低 Token 出现泄露被人盗用的风险。最后说说危险字符过滤, 像是 CLI、AGent、内容、不可信来源, 网页, 外部输入啦都可能是 Agent 接收内容的源头, 这里蕴含着不可见攻击字符这样的有风险的因素, 像 Bidi 覆盖、零宽字符, 还有 ANSI 转义等等这些情况, 它们有可能在被执行指令之后改变命令原本意味着表达出的语义是什么样的, 或者制造出终端受到欺骗的情况!因此要在 CLI 用于接受用户输入指令这种交互的一侧就干脆拒绝这类会带来危险的字符, 并且在输出指令结果这另一侧要相应地同步把这类危险字母啥给给彻底除掉。小结

CLI的设计想法跟GUI产品截然不同, 同样身为CLI, 针对Agent和针对开发者存在诸多不同, 回味整个文本, 能够总结成几条思路:

实际上, 这些思路并非仅仅局限于 CLI, 结构化输出, 容错设计, 与之配套的 Skill, 顺畅的分发, 最小权限, 对于 API、SDK 以及其他面向 “人与 Agent 双用户” 的产品而言,同样适用。

本文相关的开源 CLI 项目:

WWw.msslke.cN/post/18129.html
WWw.msslke.cN/post/45411.html
WWw.msslke.cN/post/42621.html
WWw.msslke.cN/post/8276.html
WWw.msslke.cN/post/17329.html
WWw.msslke.cN/post/46070.html
WWw.msslke.cN/post/13116.html
WWw.msslke.cN/post/18992.html
WWw.msslke.cN/post/561.html
WWw.msslke.cN/post/34820.html
WWw.msslke.cN/post/25484.html
WWw.msslke.cN/post/10724.html
WWw.msslke.cN/post/42649.html
WWw.msslke.cN/post/39038.html
WWw.msslke.cN/post/34380.html
WWw.msslke.cN/post/15054.html
WWw.msslke.cN/post/31189.html
WWw.msslke.cN/post/39223.html
WWw.msslke.cN/post/29171.html
WWw.msslke.cN/post/13718.html
WWw.msslke.cN/post/45503.html
WWw.msslke.cN/post/32654.html
WWw.msslke.cN/post/22075.html
WWw.msslke.cN/post/42451.html
WWw.msslke.cN/post/45404.html
WWw.msslke.cN/post/32250.html
WWw.msslke.cN/post/1044.html
WWw.msslke.cN/post/5195.html
WWw.msslke.cN/post/24259.html
WWw.msslke.cN/post/14952.html
WWw.msslke.cN/post/24206.html
WWw.msslke.cN/post/10372.html
WWw.msslke.cN/post/39149.html
WWw.msslke.cN/post/34152.html
WWw.msslke.cN/post/43380.html
WWw.msslke.cN/post/7342.html
WWw.msslke.cN/post/31705.html
WWw.msslke.cN/post/24157.html
WWw.msslke.cN/post/28807.html
WWw.msslke.cN/post/15279.html
WWw.msslke.cN/post/32536.html
WWw.msslke.cN/post/113.html
WWw.msslke.cN/post/34172.html
WWw.msslke.cN/post/27674.html
WWw.msslke.cN/post/8609.html
WWw.msslke.cN/post/17888.html
WWw.msslke.cN/post/24623.html
WWw.msslke.cN/post/14061.html
WWw.msslke.cN/post/6377.html
WWw.msslke.cN/post/12215.html
WWw.msslke.cN/post/47907.html
WWw.msslke.cN/post/15056.html
WWw.msslke.cN/post/42663.html
WWw.msslke.cN/post/14986.html
WWw.msslke.cN/post/37052.html
WWw.msslke.cN/post/17461.html
WWw.msslke.cN/post/6351.html
WWw.msslke.cN/post/48422.html
WWw.msslke.cN/post/10219.html
WWw.msslke.cN/post/12395.html
WWw.msslke.cN/post/10424.html
WWw.msslke.cN/post/30277.html
WWw.msslke.cN/post/15732.html
WWw.msslke.cN/post/15799.html
WWw.msslke.cN/post/37662.html
WWw.msslke.cN/post/2815.html
WWw.msslke.cN/post/44266.html
WWw.msslke.cN/post/32524.html
WWw.msslke.cN/post/26707.html
WWw.msslke.cN/post/21860.html
WWw.msslke.cN/post/31208.html
WWw.msslke.cN/post/7264.html
WWw.msslke.cN/post/31550.html
WWw.msslke.cN/post/19147.html
WWw.msslke.cN/post/37201.html
WWw.msslke.cN/post/27407.html
WWw.msslke.cN/post/47868.html
WWw.msslke.cN/post/16726.html
WWw.msslke.cN/post/44774.html
WWw.msslke.cN/post/16988.html
WWw.msslke.cN/post/37342.html
WWw.msslke.cN/post/14645.html
WWw.msslke.cN/post/32880.html
WWw.msslke.cN/post/21901.html
WWw.msslke.cN/post/47804.html
WWw.msslke.cN/post/10037.html
WWw.msslke.cN/post/35458.html
WWw.msslke.cN/post/30028.html
WWw.msslke.cN/post/38696.html
WWw.msslke.cN/post/14122.html
WWw.msslke.cN/post/35443.html
WWw.msslke.cN/post/5180.html
WWw.msslke.cN/post/38311.html
WWw.msslke.cN/post/11075.html
WWw.msslke.cN/post/26138.html
WWw.msslke.cN/post/18430.html
WWw.msslke.cN/post/3696.html
WWw.msslke.cN/post/23053.html
WWw.msslke.cN/post/45844.html
WWw.msslke.cN/post/6300.html
WWw.msslke.cN/post/38039.html
WWw.msslke.cN/post/31893.html
WWw.msslke.cN/post/4352.html
WWw.msslke.cN/post/39105.html
WWw.msslke.cN/post/37488.html
WWw.msslke.cN/post/28207.html
WWw.msslke.cN/post/35159.html
WWw.msslke.cN/post/20346.html
WWw.msslke.cN/post/29327.html
WWw.msslke.cN/post/19146.html
WWw.msslke.cN/post/18203.html
WWw.msslke.cN/post/16672.html
WWw.msslke.cN/post/35168.html
WWw.msslke.cN/post/27335.html
WWw.msslke.cN/post/1329.html
WWw.msslke.cN/post/44184.html
WWw.msslke.cN/post/23664.html
WWw.msslke.cN/post/7105.html
WWw.msslke.cN/post/2400.html
WWw.msslke.cN/post/45818.html
WWw.msslke.cN/post/38653.html
WWw.msslke.cN/post/19950.html
WWw.msslke.cN/post/23818.html
WWw.msslke.cN/post/13187.html
WWw.msslke.cN/post/43577.html
WWw.msslke.cN/post/15182.html
WWw.msslke.cN/post/39894.html
WWw.msslke.cN/post/4077.html
WWw.msslke.cN/post/1714.html
WWw.msslke.cN/post/37505.html
WWw.msslke.cN/post/12264.html
WWw.msslke.cN/post/35807.html
WWw.msslke.cN/post/8029.html
WWw.msslke.cN/post/15380.html
WWw.msslke.cN/post/25527.html
WWw.msslke.cN/post/16001.html
WWw.msslke.cN/post/43078.html
WWw.msslke.cN/post/15535.html
WWw.msslke.cN/post/29875.html
WWw.msslke.cN/post/18361.html
WWw.msslke.cN/post/23617.html
WWw.msslke.cN/post/41099.html
WWw.msslke.cN/post/46661.html
WWw.msslke.cN/post/23544.html
WWw.msslke.cN/post/22760.html
WWw.msslke.cN/post/7452.html
WWw.msslke.cN/post/9475.html
WWw.msslke.cN/post/14112.html
WWw.msslke.cN/post/16435.html
WWw.msslke.cN/post/26390.html
WWw.msslke.cN/post/25691.html
WWw.msslke.cN/post/37856.html
WWw.msslke.cN/post/41213.html
WWw.msslke.cN/post/30292.html
WWw.msslke.cN/post/30750.html
WWw.msslke.cN/post/14507.html
WWw.msslke.cN/post/2339.html
WWw.msslke.cN/post/6907.html
WWw.msslke.cN/post/14405.html
WWw.msslke.cN/post/14709.html
WWw.msslke.cN/post/6331.html
WWw.msslke.cN/post/11166.html
WWw.msslke.cN/post/45316.html
WWw.msslke.cN/post/18506.html
WWw.msslke.cN/post/35323.html
WWw.msslke.cN/post/29053.html
WWw.msslke.cN/post/19432.html
WWw.msslke.cN/post/2427.html
WWw.msslke.cN/post/27942.html
WWw.msslke.cN/post/43353.html
WWw.msslke.cN/post/10814.html
WWw.msslke.cN/post/21592.html
WWw.msslke.cN/post/23007.html
WWw.msslke.cN/post/8757.html
WWw.msslke.cN/post/15934.html
WWw.msslke.cN/post/27138.html
WWw.msslke.cN/post/35182.html
WWw.msslke.cN/post/8635.html
WWw.msslke.cN/post/21075.html
WWw.msslke.cN/post/20849.html
WWw.msslke.cN/post/21818.html
WWw.msslke.cN/post/34146.html
WWw.msslke.cN/post/15291.html
WWw.msslke.cN/post/15761.html
WWw.msslke.cN/post/31245.html
WWw.msslke.cN/post/41588.html
WWw.msslke.cN/post/999.html
WWw.msslke.cN/post/31016.html
WWw.msslke.cN/post/45837.html
WWw.msslke.cN/post/8893.html
WWw.msslke.cN/post/34149.html
WWw.msslke.cN/post/24458.html
WWw.msslke.cN/post/6538.html
WWw.msslke.cN/post/38221.html
WWw.msslke.cN/post/11841.html
WWw.msslke.cN/post/32502.html
WWw.msslke.cN/post/9640.html
WWw.msslke.cN/post/6956.html
WWw.msslke.cN/post/25630.html
WWw.msslke.cN/post/16925.html
WWw.msslke.cN/post/46350.html
WWw.msslke.cN/post/1221.html
WWw.msslke.cN/post/26904.html
WWw.msslke.cN/post/21701.html
WWw.msslke.cN/post/35491.html
WWw.msslke.cN/post/9443.html
WWw.msslke.cN/post/43296.html
WWw.msslke.cN/post/36938.html
WWw.msslke.cN/post/25063.html
WWw.msslke.cN/post/35702.html
WWw.msslke.cN/post/9823.html
WWw.msslke.cN/post/7328.html
WWw.msslke.cN/post/47315.html
WWw.msslke.cN/post/33531.html
WWw.msslke.cN/post/46966.html
WWw.msslke.cN/post/34493.html
WWw.msslke.cN/post/22183.html
WWw.msslke.cN/post/31391.html
WWw.msslke.cN/post/13294.html
WWw.msslke.cN/post/20047.html
WWw.msslke.cN/post/27099.html
WWw.msslke.cN/post/16480.html
WWw.msslke.cN/post/23495.html
WWw.msslke.cN/post/1353.html
WWw.msslke.cN/post/12344.html
WWw.msslke.cN/post/2531.html
WWw.msslke.cN/post/28419.html
WWw.msslke.cN/post/4339.html
WWw.msslke.cN/post/41971.html
WWw.msslke.cN/post/1867.html
WWw.msslke.cN/post/1169.html
WWw.msslke.cN/post/27845.html
WWw.msslke.cN/post/13425.html
WWw.msslke.cN/post/25610.html
WWw.msslke.cN/post/33382.html
WWw.msslke.cN/post/42508.html
WWw.msslke.cN/post/14781.html
WWw.msslke.cN/post/579.html
WWw.msslke.cN/post/16668.html
WWw.msslke.cN/post/9750.html
WWw.msslke.cN/post/24127.html
WWw.msslke.cN/post/2880.html
WWw.msslke.cN/post/37067.html
WWw.msslke.cN/post/27169.html
WWw.msslke.cN/post/961.html
WWw.msslke.cN/post/35090.html
WWw.msslke.cN/post/7333.html
WWw.msslke.cN/post/46571.html
WWw.msslke.cN/post/29102.html
WWw.msslke.cN/post/41118.html
WWw.msslke.cN/post/44065.html
WWw.msslke.cN/post/36046.html
WWw.msslke.cN/post/39380.html
WWw.msslke.cN/post/41033.html
WWw.msslke.cN/post/38457.html
WWw.msslke.cN/post/29637.html
WWw.msslke.cN/post/24883.html
WWw.msslke.cN/post/33881.html
WWw.msslke.cN/post/36467.html
WWw.msslke.cN/post/27251.html
WWw.msslke.cN/post/13035.html
WWw.msslke.cN/post/12716.html
WWw.msslke.cN/post/24398.html
WWw.msslke.cN/post/19699.html
WWw.msslke.cN/post/3707.html
WWw.msslke.cN/post/25009.html
WWw.msslke.cN/post/1906.html
WWw.msslke.cN/post/33507.html
WWw.msslke.cN/post/4838.html
WWw.msslke.cN/post/35280.html
WWw.msslke.cN/post/29159.html
WWw.msslke.cN/post/2035.html
WWw.msslke.cN/post/11019.html
WWw.msslke.cN/post/25738.html
WWw.msslke.cN/post/27395.html
WWw.msslke.cN/post/39505.html
WWw.msslke.cN/post/43400.html
WWw.msslke.cN/post/41585.html
WWw.msslke.cN/post/36558.html
WWw.msslke.cN/post/44016.html
WWw.msslke.cN/post/4378.html
WWw.msslke.cN/post/8022.html
WWw.msslke.cN/post/61.html
WWw.msslke.cN/post/22476.html
WWw.msslke.cN/post/20927.html
WWw.msslke.cN/post/47820.html
WWw.msslke.cN/post/30613.html
WWw.msslke.cN/post/39075.html
WWw.msslke.cN/post/19514.html
WWw.msslke.cN/post/34037.html
WWw.msslke.cN/post/36054.html
WWw.msslke.cN/post/32713.html
WWw.msslke.cN/post/2102.html
WWw.msslke.cN/post/993.html
WWw.msslke.cN/post/38643.html
WWw.msslke.cN/post/4369.html
WWw.msslke.cN/post/34933.html
WWw.msslke.cN/post/33053.html
WWw.msslke.cN/post/38287.html
WWw.msslke.cN/post/31713.html

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/6 0:23:59

瑞学堂八月模拟赛题解

很荣幸能参与瑞学堂组织的八月模拟赛,这场赛事为备战CSP-J和CSP-S的同学们提供了一次宝贵的实战演练机会。我结合官方题解的思路与个人解题代码,对赛题做了一些整理和分析,希望能抛砖引玉,与同学们一起交流探讨、共同进步。由于个…

作者头像 李华
网站建设 2026/8/6 0:22:28

三阶阈值动态调控机制

import numpy as np from dataclasses import dataclass, field from enum import Enum from typing import List, Optional, Tuple# 全局常量配置(写入元协议固化参数) WINDOW_LEN 300 STEP_SIZE 30 DRIFT_SIGMA_THRESH 2.0STABLE_WINDOW_REQUIRED…

作者头像 李华
网站建设 2026/8/6 0:18:00

odt怎么转pdf?7款格式转换工具实测盘点,覆盖电脑手机免费方案

去年年底换城市,入职前要把一堆证件和材料打包发过去。花了两天把户口本、学历学位证、离职证明挨个拍照整理成odt文档,每份还加了目录和标题。结果临提交时,HR在钉钉上补了一句:“所有材料请以PDF格式提交,不接受其他…

作者头像 李华
网站建设 2026/8/6 0:06:41

解放双手的终极指南:MouseClick鼠标连点器5分钟快速上手

解放双手的终极指南:MouseClick鼠标连点器5分钟快速上手 【免费下载链接】MouseClick 🖱️ MouseClick 🖱️ 是一款功能强大的鼠标连点器和管理工具,采用 Qt Widget 开发 ,具备跨平台兼容性 。软件界面美观 &#xff0…

作者头像 李华