2026年3月27日,来腾讯会议(限50人)了解掌握如何用Openclaw构建企业AI生产力
免费POC, 零成本试错
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


我要投稿

深度解析:Google Workspace CLI

发布日期:2026-03-26 20:12:57 浏览次数: 1545
作者:浮之静

微信搜一搜,关注“浮之静”

推荐语

Google Workspace CLI的发布揭示了软件设计从"人类优先"向"代理优先"的范式转变,这是人机交互史上的重要转折点。

核心内容:
1. 软件设计范式从HCI向ACI转变的底层逻辑
2. Google Workspace CLI的动态架构与AI技能设计
3. 开发者体验从Human DX到Agent DX的深层裂变

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

前段时间我就写过一篇 Agent 趋势浅思:原生化 & CLI 化" data-itemshowtype="0" linktype="text" data-linktype="2">Agent 趋势浅思:原生化 & CLI 化,没想到这么快 Google 就实锤了这个趋势。在正式开始聊 gwc 架构前,有必要先从更宏观的视角来分析一下,趋势背后的底层逻辑是什么,以及它对未来软件设计范式会产生哪些影响。

底层逻辑

产业范式转移的底层逻辑

在过去数十年的软件工程发展史中,人机交互(Human-Computer Interaction, HCI)的演进始终围绕着降低人类的认知负荷而展开。从命令行界面(CLI)到图形用户界面(GUI),再到复杂的集成开发环境(IDE)和声明式应用程序编程接口(API),软件界面的设计哲学一直秉持着“人类优先(Human-First)” 的原则。然而,随着具备深度推理、规划和执行能力的大语言模型(LLM)与自主代理(AI Agents)的爆发式普及,整个计算生态正在经历一场深刻的结构性倒转。软件界面的主要消费者正在从人类开发者转变为机器代理,这种向“代理机交互(Agent-Computer Interaction, ACI)” 的范式转移,对底层工具链的架构提出了截然不同的要求。

这一宏大技术趋势的最新注脚,是 Google 近期在 GitHub 上发布了基于 Rust 编写的 Google Workspace CLI[1](gws)。该工具并非传统的静态命令集合,而是能够在运行时动态读取 Google Discovery API[2] 服务并构建其全部命令面的动态系统。它摒弃了冗余的样板代码,强制采用结构化 JSON 输出,并内置了超过 40+ 种专为 AI 代理设计的“技能(Skills)”。这一举措不仅是对特定云平台工具链的升级,更标志着整个科技巨头阵营开始向“代理优先(Agent-First)” 的软件设计理念全面倾斜。如今,越来越多的企业和开源产品正在加速其软件交互接口的 CLI 化,一切架构设计的终极目标都在向适配 AI 代理与 Skills 生态靠拢。

📌 Google Discovery Service

Google API 发现服务是一个提供 Google 各项云端 API 元数据描述的机器可读接口系统。它以结构化的 JSON 文档格式,实时暴露 Google 服务的可用端点、方法签名、参数约束规则以及所需的身份验证权限等全量信息,这使得像 Google Workspace CLI(gws)这样的客户端工具无需在代码中预先硬编码庞大的静态库,即可在运行时动态拉取并自动构建出包含最新云端能力的整个命令操作面。

DX 裂变

开发者体验(DX:Developer Experience)的深层裂变,从人类中心到代理优先。

在探讨技术实现之前,必须先厘清“人类开发者体验(Human DX)” 与 “代理开发者体验(Agent DX)” 之间不可调和的根本性对立。试图将一个为人类优化的 CLI 或 API 直接逆向改造以适配 AI 代理,在工程实践中被证明是一场注定失败的徒劳之举。

人类 DX 的核心诉求是“可发现性(Discoverability)” 与“宽容度(Forgiveness)”。人类开发者在使用 CLI 时,偏好扁平化且语义丰富的命令行标志(Flat Flags,如 --force--recursive),依赖于丰富的终端颜色输出来区分信息层级,并且高度依赖具备模糊匹配和容错解释的帮助文档。人类可以在遇到不一致的参数命名或意外的错误追踪(Traceback)时,依靠常识和领域经验进行联想与纠错。

相反,Agent DX 必须将“可预测性(Predictability)” 与“纵深防御(Defense-in-depth)” 置于架构的最高优先级。AI 代理不需要图形界面的视觉反馈,也不理解终端颜色代码,它们需要绝对确定性的、机器可读的输出格式,以及能够在运行时进行自我内省的自描述模式(Schemas)。更为致命的是,代理并非受信任的、具有常识的操作员。即便如 GPT-5 或 Claude Opus 这样先进的模型,依然会产生“幻觉(Hallucination)”。在缺乏物理世界常识的情况下,代理可能会毫不犹豫地生成恶意的对抗性输入,例如构造路径遍历指令(如 ../../.ssh/id_rsa)以试图读取系统私钥,或者在资源 ID 中混入格式错误的查询参数。因此,为代理设计的 CLI 必须是一个带有重重护栏的执行沙箱,而非一个自由开放的命令行终端。

以上观点来自 gwc 核心贡献者的一篇 blog,感兴趣的朋友可以查看 You Need to Rewrite Your CLI for AI Agents[3]

📌 安全案例

Guillermo Rauch(Vercel CEO)最近在推特上分享了一个挺“离谱但很有教育意义”的安全案例。


事情起因是:一位 Vercel 用户提交了一个听起来像安全事故的报告——他们团队里居然被部署了一个陌生的 GitHub 开源仓库。这类报告放在任何平台都属于最高优先级,Vercel 这边也立刻启动调查,安全与基础设施工程团队直接介入排查。

最后查出来的原因却不是黑客,也不是账号被盗,而是 Opus 4.6 自己“幻觉”了一个公开仓库 ID,然后用 Vercel 的 API 把它部署了。Rauch 说,幸运的是,这次被部署的仓库随机且无害,但它暴露出的风险非常真实:代理在拥有强力工具权限时,错误不再只是“答错”,而会变成“真的动手做错”。

他还贴了当时的 JSON 载荷示例,repoId 是一个看起来很合理的数字(比如 913939401),但问题是——这个数字并不是查出来的,而是模型凭空编出来的。更夸张的是,代理在整个会话里完全没有调用 GitHub API 去查询 repo ID:在第一次异常部署之前,没有任何 GitHub API 请求记录。也就是说,那个 repoId 第一次出现的地方,就是它被“发明”出来的地方。代理明明知道正确的 Vercel 项目 ID 和项目名,却选择捏造一个“似真”的仓库 ID,而不是去查证。

Rauch 从这个案例里提了几条很硬核的启示:第一,再聪明的模型也会出现非常诡异、和人类完全不同的失败模式——人类会犯错,但通常不会随机编一个 repo id。第二,强力 API 在代理手里会放大风险:API 本来是为了部署合法代码而设计的,但当代理决定“幻觉一下要部署什么”时,后果就很难预料。第三,他甚至认为,如果代理当时没有直接走 API,而是被限制在更受约束的执行面,比如 CLI 或 MCP,结果可能更好。

最后他强调,这件事反过来强化了 Vercel 的方向:要把“面向代理的工程”做得更安全,靠更深的工具集成(例如 Claude Code)和更多护栏机制去守住安全与隐私。他也补充说,用户当时用的是 OpenClaw + Opus 4.6,但他不觉得 OpenClaw 本身该背锅——它只是一个拿到了工具和密钥的代理;真正的问题在于 repoId 是彻底幻觉,不是差一位这种小偏差。另外,公开贴出来的 repoId 也做过随机化处理,避免泄露隐私。

架构之争

为何 CLI 胜过 IDE 插件与原生 API

在生成式 AI 渗透编程领域的初期,业界普遍认为集成开发环境(IDE)的智能插件(如早期的 Copilot)或直接向模型暴露系统底层的原生 API 是最佳路径。然而,随着自主编码代理进入深度工程实践,CLI 展现出了无可比拟的结构性与功能性优势。

协作模式重定义:从“辅助建议”到“自主委托”

IDE 代理主要是为“建议(Suggestion)” 而设计的,例如代码自动补全、悬浮解释或结对编程。这种模式始终需要人类在场进行高频次的审查与确认。然而,新一代 CLI 代理则是为“委托(Delegation)” 而构建的。一个优秀的 CLI 代理可以作为独立的数字工作者,在无人监督的情况下连续运行数小时。它可以自主协调分布在几十个文件中的代码重构,自动执行 shell 命令运行集成测试,验证通过后自行编写描述性的 commit message 并推送到远程仓库。这种宏观的任务编排能力是受限于 VS Code 侧边栏的 IDE 插件所无法企及的。此外,CLI 代理可被直接编译为工具链中的二进制文件,无缝插入现有的 CI/CD 自动化流水线中,执行代码审查或修复 Lint 错误等静默任务。

突破大模型致命瓶颈:上下文污染与状态收敛

大模型在处理复杂代码库时面临的最大技术瓶颈是“上下文污染(Context Pollution)”。IDE 代理在运作时,通常会将整个对话历史以及当前打开的所有文件标签页全量发送给模型。随着代码库的增长,这种暴力的上下文灌输会导致模型陷入“迷失在中间(Lost in the middle)” 的效应,推理质量断崖式下跌,且 Token 消耗成本极高。相比之下,CLI 代理采取了外科手术式的“渐进式披露(Progressive Disclosure)” 策略。例如,Claude Code 或 Aider 等 CLI 工具,最初仅加载代码库的骨架映射(Codebase Map),只有当代理明确决定需要修改某个特定模块时,才会精确读取该文件的内容。这种克制的上下文管理确保了 Token 的高效利用,使得代理能够维持更长时间的有效推理会话,再比如 Codex 的上下文自动压缩技术也是保证代理长时间运行的关键。

在状态管理层面,IDE 内部充满了“肮脏(Messy)” 的状态:未保存的代码缓冲区、复杂的滚动条位置、光标焦点以及渲染线程。这使得 AI 模型很难在脑海中建立一致的内部世界模型。对于 CLI 代理而言,状态被极致收敛为二元对立的物理实在:文件系统(磁盘)。代码要么被成功写入了磁盘,要么没有;编译和测试命令要么返回状态码 0(成功),要么返回非 0(失败)。这种基于 Unix 哲学的确定性反馈循环,为大模型提供了坚实的现实基础(Grounding),使其能够实现自我修复(Self-heal)。如果代理执行的测试脚本返回了退出码 1,代理能够自主捕获 stderr 的输出流,分析报错栈,规划新的修复方案并进入下一次迭代,全程无需人类介入。

摒弃 API 优先(API-First):消除语义碎片与传输层冗余

长久以来,API-First 被奉为现代软件架构的圭臬,提倡将系统能力分解为可重用的微服务接口。但在面对 AI 代理时,直接向模型暴露 API 会出现极大的不适应性。首先,传统的 HTTP API 设计往往追求多态与灵活性。例如,一个单独的 POST /users 端点可能会根据负载中是否包含 id 字段来模糊地处理用户的“创建”与“更新”操作。这种灵活度人类开发者可以轻易理解,但在大模型的概率推理矩阵中,却引入了极高的歧义性。为代理设计的接口必须遵循单一且明确的语义隔离,例如强制分离 POST /users 与 PUT /users/{id}

其次,API 调用强迫大模型去处理极其繁琐的传输层逻辑。要让代理成功发起一次 HTTP 请求,模型必须在有限的上下文中正确推演 OAuth 认证流程、管理 Bearer Token 状态、拼接请求 Header 以及处理网络层的重试策略。这不仅是对推理算力的巨大浪费,也极大增加了运行出错的概率。CLI 将所有这些底层传输层复杂性、身份验证机制以及遥测遥感能力全部封装在了本地的二进制可执行文件之中。代理只需知道如何调用 gws user update --json {...},CLI 底层会自动接管网络协商,使得代理能够将全部算力集中于业务逻辑的攻坚。这不仅降低了认知负荷,也使得工具本身通过原生文本流(stdin/stdout)与模型的原生语言(文本 Token)实现了完美的介质统一。

Rust 语言

为何 Rust 会成为代理工具链的首选语言?Codex CLI 最初的实现基于 Node.js/TypeScript(甚至包含 React/Node 这套典型前端工具链),但很快 OpenAI 就公开宣布要把它 “go native”,重写为 Rust;而这次的 gws 同样选择 Rust,并把“代理优先”的约束写进了架构骨架里。它们几乎在用同一个姿势告诉你:这不是偶然,是路线。

在整个 AI 发展历程中,Python 凭借其极低的语法门槛和庞大的张量计算库(如 PyTorch、TensorFlow)确立了其在模型训练和数据科学领域的绝对霸权。而在云原生编排与后端微服务架构中,Go 语言则长期占据统治地位。然而,当行业开始向“自治代理与底层工具的无缝结合”演进时,Rust 正在以极快速度挤进一个新的战略高地:代理优先 CLI / 本地可执行工具链。在这条赛道上,它不是“最好看的语言”,而是最容易交付“可分发、可控、可审计”的那一个。

消除 Python 的“依赖地狱”与脆弱性

在研究实验室环境中,Python 的动态特性是加速创新的利器;但在无人类监督的生产机器上,要求一个 AI 代理去操作一个基于 Python 编写的 CLI,无异于将其置于一片充满致命地雷的泥潭之中。每一天,全球各地的 AI 代理在尝试编排真实世界工作流时,都会被诸如 ModuleNotFoundError: No module named 'soundfile' 或 pip's dependency resolver does not currently take into account all the packages 这样的底层环境错误无情击溃。需要意识到:这些错误根本不是大模型的推理缺陷,也不是幻觉;它们是 Python 运行时对目标机器底层 C 语言共享库、系统级虚拟环境(Venv)、硬件特定的 CUDA 版本以及路径变量(PYTHONPATH)高度依赖的必然恶果。

当 AI 代理在调用一个复杂的语音合成(TTS)或大语言模型推理工具时,Python 生态中的脆弱性会导致系统陷入一种“薛定谔的损坏”状态。代理通常缺乏诊断这种系统级环境错综复杂性的直觉。当面临深层的追踪报错(Traceback)时,代理通常只能基于其训练集中的平庸经验,盲目生成 pip install --upgrade 等指令试图自救,这往往会进一步破坏机器的全局环境。相比之下,当构建复杂的工作流(例如将 ffmpeg、自动语音识别 ASR、翻译和 TTS 模型级联)时,Python 中的不同工具可能需要不兼容的 Torch 库版本,迫使代理去追踪和切换繁琐的虚拟环境上下文。

Rust 带来的是一种具有碾压性优势的“单一二进制,单一事实(One Binary, One Truth)” 范式(需要注意的是,并非只有 Rust 可以构建单一二进制文件,Go 同样擅长;但 Rust 往往更愿意把“边界与约束”写进类型与编译期)。使用 Rust 编写的代理 CLI 可以被编译成单个可分发的执行体(实践中常见是尽量减少运行时依赖;也可以选择 musl 等路线做到更强的自包含)。它不需要目标系统安装特定版本的解释器,不需要包管理器的介入。对于 AI 代理的逻辑规划器而言,状态变得极度清澈:你至少可以用一条极其简单的 test -x ./tool 迅速判定“这是不是一个可执行体”,再用 ./tool --version / ./tool doctor 之类的自检把“可运行”进一步固化为证据链。

解决 70% 内存安全危机的编译期证明

当前软件产业确实长期受“内存安全问题”困扰:微软在其产品漏洞统计中指出,约 70% 的 CVE 与内存安全相关;Chromium 团队也报告其高危安全缺陷中约 70% 属于 C/C++ 指针导致的内存不安全问题。与此同时,Project Zero 对 2021 年在野 0day 的统计显示,其中约 67% 属于内存破坏类漏洞。

随着自动化编程与 AI 生成代码被更广泛用于工程生产,代码规模与变更频率上升,可能进一步放大传统内存不安全语言在审计、测试与运维上的压力:不是因为 AI “更坏”,而是因为它更快、更能把边缘路径跑穿、更能把你没想到的组合撞出来。

Rust 的价值在于把一大类灾难性错误“左移”到编译期:在 Safe Rust 范围内,语言与类型系统能保证不存在 data race(这类错误在 Rust 的定义里属于未定义行为,因此在 Safe Rust 中“不可能表达出来”);但 unsafe 仍需要工程流程与审计来兜底,且 Rust 不能消除所有逻辑竞态与系统性漏洞(比如死锁、顺序竞争、业务一致性问题)。

Android 的公开数据也更支持“渐进迁移而非大重写”的路线:Google 报告 Android 内存安全漏洞占比从 2019 年的 76% 下降到 2024 年的 24%,主要原因是新功能持续转向内存安全语言、旧代码尽量少动;到 2025 年,占比进一步降到 20% 以下,并且他们也披露过一次“险些发布”的 Rust 内存安全 near-miss(发生在 unsafe Rust 场景),这反而把结论钉得更牢:Rust 显著降低风险密度,但它不是魔法,它是一套更强的默认值 + 更清晰的责任边界。

📌 顺带一提

Rust 不承诺“零内存泄漏”,它承诺“泄漏不再是默认事故”。

这里很容易被误读。Rust 的“内存安全”主要针对的是越界、UAF、悬垂指针这类会导致未定义行为的灾难;但内存泄漏在 Rust 的语义里甚至被认为是 “safe 也能做的事”。这听起来反直觉,却很符合现实:泄漏通常不会立刻破坏内存正确性,它更像可靠性/资源治理问题。Rust 能做的是——让资源生命周期默认跟随所有权与 Drop,让大多数“忘记释放”变成更难发生的失误;但它不会承诺彻底禁止泄漏这种行为(你总能通过显式手段把内存留在那儿)。

机器可读性:Rust 宏机制与类型系统的化学反应

除了安全与分发,Rust 在“代理优先 CLI” 里真正形成壁垒的,是它那套把类型系统、宏、生态工具链拧成一股绳的工程化能力:你不是在写一堆松散的命令行参数,而是在用类型定义一份“可执行的协议”。以 clap[4] 为例,它提供成熟的 derive API,让开发者把参数结构直接绑定到强类型数据模型上,并自动生成一致的命令树与帮助信息,从而把 CLI 的输入空间收敛为可验证、可推理的结构。

这套能力已被大量生产级 CLI 采用(如 bat[5] 的依赖中明确出现 clap;但也存在为了极简依赖而选择更轻量解析器的路线——如 ripgrep[6] 当前依赖 lexopt[7] 而非 clap,说明生态不是“唯一解”,而是一条可按目标优化的谱系)。

在输出与数据侧,Serde[8] 通过 #[derive(Serialize, Deserialize)] 把“结构化 I/O” 变成类型系统的一部分:后端 API 的 JSON 负载可以无缝映射为内存中的强类型结构体,使 agent 更容易生成正确的嵌套参数,也更容易在失败时定位是哪一层结构不满足约束。

Rust 生态真展开聊都能写书了,这里就不再赘述。你只需记住:Rust 的类型系统、宏机制与工具链生态在“代理优先 CLI” 里形成了罕见的化学反应——它让协议不再靠文档维持,而是直接长在代码的结构里;让边界不再靠自觉遵守,而是被编译器硬性执行;而在性能这条轴上,它又能把这种“约束”几乎零额外成本地落到运行时,把高频调用、海量 JSON、并发 I/O 这类代理工作流的基础负载扛住,不靠 GC 运气,不靠运行时抖动。于是工具的健壮性、可维护性与可扩展吞吐不再是“写得更小心”的结果,而是“默认就更难写错、默认就跑得稳且快”的产物。

Skills & MCP

这部分内容之前写过文章(元技能:让 AI 像你一样思考从 Prompt Engineering 到 Context Engineering深度解析:Anthropic MCP 协议),这里再简单过一下。

认知抽象与行为解耦:Agent Skills 生态的演化与规范

即使构建了基于 Rust 的极其坚固的底层执行 CLI 工具,AI 代理系统依然面临着一个鸿沟:代理缺乏物理世界的人类常识、隐性行业规矩以及特定企业代码库的潜规则。为了弥补大语言模型的“直觉”缺失,业界创造性地将执行逻辑与程序化认知相解耦,从而催生了“代理技能(Agent Skills)” 及其繁荣的生态系统。

何为技能?程序化知识的封装与重用

在现代 Agent 架构中,底层二进制 CLI 被严格限制为没有灵魂的执行器(赋予了修改代码、执行 shell、读写目录的物理权限),而所谓的“技能(Skill)” 则是专门编写的 Markdown 文件群,其本质是用于向模型传授具体业务规则和最佳实践的“可复用程序化知识(Reusable Procedural Knowledge)”。

以 gws 为例,除了其 Rust 编写的核心二进制,它随包发布了 40+ 多种预置技能,涵盖了诸如 Google Docs 文档读写、Google Chat 消息管理、乃至 Google Vault 电子展示取证等细分领域(共计 100+ 个 Skills)。这些技能不仅仅是向模型解释怎么敲击命令,更重要的是它输出了人类在特定场景下沉淀下来的不变量。例如,一个针对系统运维架构的技能文件中,可能强制规定了:“当你接收到删除存储桶的任务时,不仅要调用正确的 CLI 删除端点,而且必须首先检查该存储桶是否启用了保留策略,并在执行删除前必须强制调用 CLI 发起一个向人类用户发送审批验证的阻塞请求”。

这种抽象极大地激发了开源力量的汇聚。当前,诸如 skills.sh[9](由 Vecel 维护的 Agent 技能生态系统)已迅速崛起为 AI 时代的 NPM 或 Crates.io。在该系统上,开发者只需一行 CLI 命令(如 npx skills add)即可将企业级能力安装到自己的 Agent 中。该生态的广度令人震惊:它不仅兼容 Claude Code、Codex、GitHub Copilot、Cursor,还汇聚了巨头级别的专业知识(平台已汇聚 85K+ Skills)。此外,Vercel 发布的 find-skillsvercel-react-best-practices 等技能安装量高达数十万次;微软官方则发布了专为其 Azure 生态定制的 Copilot 技能包,专门教导大模型如何在复杂的 Azure 存储和 AI 平台中安全调度底层资源。

SKILL.md 协议规范与上下文解药:渐进式披露

为了确保在 Claude Code、Codex、Cursor、VS Code 或是独立的命令行工具中,AI 代理都能无差别地识别和调用这些技能,行业形成了一套高度格式化的规范标准,其核心便是 SKILL.md 文件。

依据 agentskills.io[10] 制定的规范,一个技能不仅需要存放于独立的层级目录中(如 .github/skills/webapp-testing),而且其核心 SKILL.md 的前置必须遵循极其严谨的 YAML 结构定义。在这套协议下,一切杂乱无章的提示词工程都被强类型化的约束所替代。以下是代码示例:

---
name:pdf-processing
description:ExtracttextandtablesfromPDFfiles,fillforms,mergedocuments.
---

# PDF Processing

## When to use this skill
UsethisskillwhentheuserneedstoworkwithPDFfiles...

## How to extract text
1.Usepdfplumberfortextextraction...

## How to fill forms
...

这套严密规范带来的最大技术红利,是使“渐进式披露(Progressive Disclosure)” 成为了可能。在一个庞大的企业级代码库中,如果一次性将数十个技能所包含的庞大指令群、模板文件(存放于 assets/ 目录)和辅助校验逻辑(存放于 scripts/ 目录)全部堆入上下文中,必然引发严重内存污染和推理智商滑坡。得益于严格的 description 字段规范,CLI 工具在初次拉起环境时,仅需要将极轻量的元数据注入大模型上下文。当代理在分析人类需求时,由于发现语义特征匹配到了某个特定的 description,它会动态地发出读取请求,此时底层工具才会将具体的 SKILL.md 业务逻辑加载进内存。这种类似于现代操作系统按需进行内存页面置换的设计,从根本上化解了模型上下文能力有限的矛盾。

模型上下文协议(MCP):代理与物理世界的标准化通信基石

如果说 SKILL.md 解决了业务知识的传承,那么模型上下文协议(Model Context Protocol, MCP)则是连接孤立的 AI 代理与全球海量云端服务、数据系统以及底层物理资源的终极桥梁。

在 MCP 问世之前,每一个开发商若要将自身的服务提供给大模型使用,必须针对 OpenAI、Anthropic 甚至各类开源模型各自独特的工具调用范式(Function Calling APIs)进行重复造轮子。这种无休止的定制化集成造成了巨大的技术负债与生态碎片化。

Anthropic 主导推进的 MCP 作为一种开放标准的双向交互协议,被形象地比喻为 “AI 应用程序的 USB-C 接口”。它的核心价值在于分离关注点:开发者只需实现一次 MCP 服务器,便能通过 JSON-RPC 格式将自身的能力暴露出去,而任何遵循该协议的 MCP 客户端(代理,如 Claude for Desktop, Gemini CLI 以及各类 IDE)都可以无缝接入。这种高度统一的通信机制赋予了代理调用数百个分布在不同网络层和服务器集群上的工具链的能力,重塑了软件集成的版图。

Google Workspace CLI

理解了“代理优先 CLI”的底层逻辑后,再回头看 Google Workspace CLI(gws),你会发现它几乎是一个教科书级的样本:它不是在做 “Google API 的命令集合”,而是在做一个由 API 语义驱动、能持续演化的运行时平台——这恰好命中了前面提到的所有趋势:可预测、可自省、可投影、可治理。

📌 小插曲

Addy Osmani 发推介绍了 Google Workspace CLI(gws),称它同时面向人类与 agent,覆盖 Google Drive、Gmail、Calendar 等几乎所有 Workspace API,并内置 40+ agent skills;有网友追问是否会取代 Peter Steinberger 的 gog(gogcli[11] “把 Google 放进终端”的统一 CLI,被内置在 OpenClaw 中);Addy 回复说这已经在 Peter 的关注范围内,并表示会根据他后续评估与反馈继续改进,同时也肯定 gog 本身很棒;而 Peter 也转述称自己当初做 gog 的动机是因为当时市面上没有好用的选择,但如今 gog 已经“真的很强”,只是看到 gws 需要的那些 JSON 命令后他有些犹豫,准备跑一轮评估,看看对 agent 来说到底哪种方案更合适。

先看问题:为什么这类 CLI 很容易做“脆”

Google Workspace 的 API 面非常宽(Drive、Gmail、Calendar、Docs、Admin…),而且长期处于演进状态。用传统方式做 CLI,通常会走一条看似稳妥、但注定吃维护债的路径:

  • 选几个 API,生成或引入 SDK
  • 手写命令映射与参数体系
  • 接口一变,就同步改命令、改文档、改示例、改 agent 提示词
  • 时间一久,命令面与 API 语义开始漂移,最后你维护的是一套“历史偶然性”

这种架构的问题从来不是“不能用”,而是维护成本会在时间轴上爆炸,尤其当你的 CLI 不再只服务人类,而是同时要服务:

  • 人类开发者(命令行交互)
  • AI Agent(结构化调用)
  • 技能生态(SKILL.md / 任务 recipe)

只要你承认这三类用户会共存,你就会被迫回答一个更根本的问题:你要维护三套能力表达,还是维护一份能力语义?

gws 的有趣之处在于:它选择了后者,并且把核心问题彻底重定义了。

核心设计思想:把 API 文档当“运行时类型系统”

gws 没把自己定义成 “Google API 命令集合”,而是定义成 “Discovery 文档驱动的运行时系统”。它的关键洞察是:如果 API 的语义已经以机器可读形式存在(Discovery JSON),那 CLI 不该手写命令面,而应该把命令面当作语义的投影。对应到代码结构,这个角色划分非常清晰:

  • src/discovery.rs:把 Google Discovery JSON 反序列化成 RestDescription(一个语义 AST)
  • src/commands.rs:基于 RestDescription 动态生成 clap 命令树
  • src/executor.rs:基于同一份语义模型执行请求

也就是说,它不是“先有命令再找 API”,而是“先有语义,再投影命令”。命令面只是 UI,语义层才是系统。

宏观架构:四层模型

如果把 gws 抽象成四层,它的结构会变得非常“平台化”:

  1. 语义层(Discovery):RestDescription 作为稳定中间表示
  2. 交互层(CLI/MCP/Skills):多表面投影
  3. 执行层(HTTP 请求与响应处理):统一执行中枢
  4. 身份层(多账号认证与加密存储):可运营的控制平面

架构图如下:

这套分层的价值是:语义和执行解耦、交互和执行解耦。你新增一个交互面(比如 MCP)时,不需要重写 API 客户端。

一个请求是怎么跑起来的(两阶段解析)

src/main.rs 的“两阶段解析”是整个系统最关键的设计点之一,它解决了传统 CLI 的宿命:命令面永远落后于 API 演进。

  • 第一阶段:从原始参数里识别“服务入口”(你要操作哪个 service)
  • 第二阶段:拉取该 service 的 Discovery 文档,动态构建命令树,然后重新解析剩余参数

可理解为:

// 伪代码(对应 main.rs 结构)
service = parse_first_non_flag_arg(argv)
doc = fetch_discovery(service)
cli = build_cli_from_discovery(doc)
matches = cli.parse(remaining_args)
method = resolve_method(matches, doc)
execute(method)

这让 CLI 命令面天然跟随 API 结构变化,而不是硬编码在二进制里。

这套架构“强”在哪:能力表达层面

1) 一份语义,三种能力投影

gws 的能力不是只给终端用户,它同时投影到:

  • CLI:src/commands.rs
  • MCP:src/mcp_server.rs
  • Skills:src/generate_skills.rs

这点非常关键:同一份能力图谱同时喂给人类、喂给 agent 工具调用、喂给技能文档生态。这不是“多做了点功能”,而是从工具走向平台的分水岭:能力不再复制三份,而是投影三次。

2) 动态但不失控(Bounded Dynamic)

src/services.rs 提供服务级治理边界(已注册服务列表),服务内部再动态展开资源/方法。 这是一种很实用的平衡:

  • 不做全静态(避免维护爆炸)
  • 也不做无边界动态(避免产品面不可控)

3) 身份体系是“织构”而不是“单点文件”

从 src/auth.rs 到 src/accounts.rssrc/credential_store.rssrc/token_storage.rs,形成了完整链路:

  • token/env/file/encrypted credential 多源优先级
  • 多账号注册表(accounts.json
  • 凭据与 token 缓存的加密落盘(AES-256-GCM)

这是一种可运营、可迁移、可扩展的身份控制平面,不是“临时登录代码”。在 agent 场景里,这点尤其重要:身份不是一次性动作,而是长期运行的基础设施。

4) 执行层统一,减少重复复杂度

src/executor.rs 统一处理了:

  • URL 模板替换与编码
  • 参数与 body 校验
  • 分页与流式输出
  • 上传/下载
  • 错误结构化输出

当你写 helper 时(比如 src/helpers/drive.rssrc/helpers/gmail/watch.rs),多数时候只用构建输入,执行交给统一执行层。这就是典型的平台化收益。

Helper 体系:从 API 壳到任务语言

很多系统做到“能调用 API” 就停了,gws 更进一步做了任务抽象:

  • gws gmail +watch:Gmail + Pub/Sub 的生命周期编排
  • gws events +subscribe:Workspace Events + Pub/Sub 流式消费
  • gws workflow +file-announce:Drive + Chat 跨服务工作流

这些不是简单别名,而是把“多步骤、跨服务、长连接”的复杂动作封装成稳定操作单元。这一步通常决定一个 CLI 是“工具箱”还是“生产力系统”。

对架构师有价值的三个启发

启发 1:把“接口变化”前移成“语义层设计”问题

如果你的系统面对频繁变化的外部协议,最划算的不是不停补命令,而是建立一个稳定的中间语义层(类似 RestDescription)。

启发 2:能力要做“多投影”,而不是“多复制”

CLI、MCP、文档/技能,不应该各写一套。应该从同一能力图谱投影出去,才能避免长线漂移。

启发 3:把接入流程产品化

src/setup.rs + src/setup_tui.rs 展示了一个常被忽视的点:认证与初始化不是 “README 步骤”,而是系统能力的一部分。谁把 onboarding 做成状态机,谁就降低真实使用门槛,也降低了 agent 误配带来的安全风险。

理性看待架构

任何优秀架构都有代价,gws 也一样:

  • 冷启动依赖 Discovery 拉取(需缓存策略)
  • 动态系统调试复杂度高于纯静态命令
  • MCP 当前输入 schema 仍有泛化空间(方法级精确约束可继续强化)

但这些代价换来的是高演化能力和高复用度。在“多 API + 多交互面 + Agent 化”场景下,这个交换是值得的。

使用

下面是一份基于 googleworkspace/cli README 总结的简明使用手册,面向“人类 + agent” 两种用法。

1) 安装与前置条件

前置条件:

  • Node.js 18+(用于 npm install),或直接下载预编译二进制
  • 需要一个 Google Cloud Project(用于 OAuth 凭据);需要一个有 Workspace 访问权限的 Google 账号

安装:

npm install -g @googleworkspace/cli

npm 包自带对应平台的预编译 native 二进制,不需要 Rust toolchain;也可从 Releases 下载,或 cargo install 源码构建。

2) 快速开始

# 一次性:引导创建/配置 Cloud Project、启用 API、登录
gws auth setup

# 后续登录/选 scopes
gws auth login
gws drive files list --params '{"pageSize": 5}'

gws 运行时读取 Google Discovery Service 动态构建命令面,所以 API 新增方法会自动出现。

3) 命令结构 & 常用参数

命令结构

一般是:

gws <service> <resource> <method> [flags]

两类 JSON 输入

  • --params:通常放 query/path 相关参数(如 pageSizeparentspreadsheetId 等)
  • --json:通常放 request body(创建/更新类)

示例:

# 列出最近 10 个 Drive 文件
gws drive files list --params '{"pageSize": 10}'

# 创建一个 Sheets 表格
gws sheets spreadsheets create --json '{"properties": {"title": "Q1 Budget"}}'

--dry-run(强烈建议用于写操作)

gws chat spaces messages create \
  --params '{"parent": "spaces/xyz"}' \
  --json '{"text": "Deploy complete."}' \
  --dry-run

--dry-run会预览请求,适合 agent 场景做“先验收再提交”。

4) 自省与分页(agent 友好关键点)

Schema 自省

gws schema drive.files.list

用于查看任意 method 的请求/响应 schema。

NDJSON 流式分页

gws drive files list --params '{"pageSize": 100}' --page-all | jq -r '.files[].name'

分页相关 flags:

  • --page-all:自动翻页,按页输出 NDJSON(每页一行 JSON)
  • --page-limit <N>:最多页数(默认 10)
  • --page-delay <MS>:翻页间隔(默认 100ms)

5) 认证(本机 / 多账号 / CI / 服务账号)

本机交互式(推荐)

凭据落盘会 AES-256-GCM 加密,密钥放 OS keyring

gws auth setup
gws auth login

如果你的 OAuth app 还在 testing mode,Google 同意的 scope 可能限制在 ~25;这时不要用 recommended,改成按服务选:

gws auth login --scopes drive,gmail,calendar

多账号切换

gws auth login --account work@corp.com
gws auth login --account personal@gmail.com

gws auth list
gws auth default work@corp.com

gws --account personal@gmail.com drive files list
export GOOGLE_WORKSPACE_CLI_ACCOUNT=personal@gmail.com

凭据按账号分别存储(~/.config/gws/ 下的加密文件 + accounts.json 记录默认账号)。

Headless/CI:导出凭据

# 在有浏览器的机器上完成登录后:
gws auth export --unmasked > credentials.json

# 在 CI/无头机器上:
export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/path/to/credentials.json
gws drive files list

Service Account(服务器到服务器)

export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/path/to/service-account.json
gws drive files list

# 若使用 Domain-Wide Delegation:
export GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER=admin@example.com

直接给 access token

export GOOGLE_WORKSPACE_CLI_TOKEN=$(gcloud auth print-access-token)

优先级(从高到低)GOOGLE_WORKSPACE_CLI_TOKEN > GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE > per-account 加密凭据 > 明文 ~/.config/gws/credentials.json

6) 高级用法小抄

Multipart Upload(Drive 上传)

gws drive files create --json '{"name": "report.pdf"}' --upload ./report.pdf

Sheets 的 ! 转义(bash 会把 ! 当 history expansion)

建议参数 JSON 用单引号包住:

gws sheets spreadsheets values get \
  --params '{"spreadsheetId": "SPREADSHEET_ID", "range": "Sheet1!A1:C10"}'

7) 给 Agent 用:Skills / Gemini CLI / MCP

安装 Agent Skills(SKILL.md)

仓库自带 100+ skills(每个 API 一个 + 高阶 helpers + 50 条 recipes)。

# 全装
npx skills add https://github.com/googleworkspace/cli

# 只装 Drive/Gmail 等
npx skills add https://github.com/googleworkspace/cli/tree/main/skills/gws-drive
npx skills add https://github.com/googleworkspace/cli/tree/main/skills/gws-gmail

OpenClaw 示例:

ln -s $(pwd)/skills/gws-* ~/.openclaw/skills/

# 或拷贝特定 skills
cp -r skills/gws-drive skills/gws-gmail ~/.openclaw/skills/

并且 gws-shared skill 还能在找不到 gws 时自动通过 npm 安装。

Gemini CLI 扩展

gws auth setup
gemini extensions install https://github.com/googleworkspace/cli

扩展安装后,Gemini CLI agent 可直接访问所有 gws 命令与 skills,认证会继承你的本机凭据。

MCP Server(把 Workspace API 暴露为 MCP tools)

gws mcp -s drive
gws mcp -s drive,gmail,calendar
gws mcp -s all

在 MCP 客户端中配置:

{
  "mcpServers":{
    "gws":{
      "command":"gws",
      "args":["mcp","-s","drive,gmail,calendar"]
    }
}
}

每个 service 大概会增加 10–80 个 tools;通常要控制在客户端 tool 上限(常见 50–100)以内。

8) 安全加成:Model Armor 响应净化

可接入 Google Cloud Model Armor,在 API 响应进入 agent 前扫描 prompt injection:

gws gmail users messages get --params '...' \
  --sanitize "projects/P/locations/L/templates/T"

环境变量:

  • GOOGLE_WORKSPACE_CLI_SANITIZE_TEMPLATE:默认模板
  • GOOGLE_WORKSPACE_CLI_SANITIZE_MODEwarn(默认)或 block

9) 备注

⚠️ 注意:项目仍在快速迭代期,README 提醒可能存在 breaking changes;且“不是官方支持的 Google 产品”。

结语

gws 值得借鉴的不是“它支持很多 Google API”,而是它把 CLI 做成了一个以语义为核心的运行时平台:一份语义,驱动多种交互;统一执行,持续演化。

References

[1]

Google Workspace CLI:https://github.com/googleworkspace/cli

[2]

Google Discovery API:https://developers.google.com/discovery

[3]

You Need to Rewrite Your CLI for AI Agents:https://justin.poehnelt.com/posts/rewrite-your-cli-for-ai-agents

[4]

clap:https://github.com/clap-rs/clap

[5]

bat:https://github.com/sharkdp/bat

[6]

ripgrep:https://github.com/BurntSushi/ripgrep

[7]

lexopt:https://github.com/blyxxyz/lexopt

[8]

Serde:https://github.com/serde-rs/serde

[9]

skills.sh:https://skills.sh

[10]

agentskills.io:https://github.com/agentskills/agentskills

[11]

gogcli:https://gogcli.sh

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询