01

AI 编程工具的崛起

从 Copilot 到 Agent——AI 编程助手这两年发生了什么

三代 AI 编程工具

你可能用过 GitHub Copilot,它帮你补全代码。但 Gemini CLI 和 Claude Code 是完全不同的东西——它们是能在你的终端里运行、读写文件、执行命令的AI Agent

✏️

第一代:补全工具

GitHub Copilot — 在 IDE 里自动补全代码,基于上下文预测下一行

💬

第二代:对话工具

ChatGPT / Claude.ai — 聊天框里讨论代码问题,但你要自己复制粘贴

🤖

第三代:Agent 工具

Gemini CLI / Claude Code — 在终端运行,直接读写文件、执行命令、完成整个功能

为什么 Google 要做 Gemini CLI?

2025 年 5 月,Google 开源了 Gemini CLI。定位很明确:给开发者提供一个终端版 AI Agent,和 Claude Code(Anthropic)、Codex CLI(OpenAI)直接竞争。

📦
免费额度很慷慨

用个人 Google 账号,每天 1000 次请求,每分钟 60 次,使用的是 Gemini 2.5 Pro 模型。这是目前市面上免费额度最高的 AI 编程 Agent。

知识点检测

你想让 AI 帮你把项目里所有 Python 2 风格的 print 语句改成 Python 3 风格,最适合用哪类工具完成?

02

核心角色

三大包如何分工协作

代码库地图

Gemini CLI 的源码按职责拆成了多个package。每个包各管一摊,互不干扰。打开 packages/ 目录,你会看到这样的结构:

packages/
cli/ 你看到的终端界面 — 用户交互层
core/ 大脑:AI 对话、工具执行、安全策略 — 核心逻辑层
sdk/ 积木:给其他开发者用的编程接口
a2a-server/ 协作:Agent-to-Agent 协议服务器
devtools/ 诊断:开发调试工具
vscode-ide-companion/ IDE 集成

其中最重要的是前三个:cli 负责你看到的界面,core 负责所有"思考"和"行动",sdk 让别人也能用这些能力。下面我们看看它们是怎么协作的。

一次完整的修复任务

当你告诉 Gemini CLI "帮我修个 bug"时,CLI(用户界面)、Core(大脑)、Gemini API(大模型)三者在后台是这样对话的:

注意到了吗?CLI 从头到尾只负责两件事:把用户的话转达给 Core,把 Core 的结果展示给用户。所有"读文件、调 AI、写文件"的脏活累活都是 Core 干的。

CLI 包 vs Core 包

我们来看看代码里是怎么体现这种分工的。先看 CLI 包的入口文件:

TypeScript // packages/cli/index.ts export { GeminiCli } from './src/core/initializer.js';
中文解释
CLI 包只做一件事:把 GeminiCli 这个类导出给别人用。
它连自己的实现都没有——直接导入了 core 包里的 initializer。
薄薄一层外壳,所有工作都委托给 core。

再看 Core 包——这里才是真正有料的地方。它的入口文件导出了 280 多行,前面几行是这样的:

TypeScript // packages/core/src/index.ts export * from './config/config.js'; export * from './core/turn.js'; export * from './core/geminiChat.js'; export * from './scheduler/scheduler.js'; export * from './tools/tools.js'; // ... 还有 40 多行
中文解释
config — 配置管理:加载 API 密钥、模型参数
turn — 对话轮次:管理你和 AI 的每一轮交互
geminiChat — AI 对话:跟 Gemini API 通信
scheduler — 调度器:编排多步骤任务的执行顺序
tools — 工具系统:读写文件、执行命令等能力
Core 导出了几乎所有核心能力。
💡
设计模式:关注点分离

这种分层设计(CLI 负责界面,Core 负责逻辑)是软件工程中最重要的模式之一——叫做"关注点分离"。你跟 AI 说"把 UI 和逻辑分开"时,AI 就知道该怎么做。

知识点检测

如果你想让 AI 助手多一个功能(比如支持语音输入),这个改动主要在哪个包?

03

智能循环

Agent Loop —— AI 如何一步步完成任务

AI 不是搜索引擎,而是一个循环

你跟 Gemini CLI 说"帮我重构这个文件",它不会像搜索引擎一样一次就给出最终答案。它会进入一个Agent Loop —— 一步步思考、选择工具、执行、再思考,循环往复直到任务完成。

1
用户提问

你输入指令,比如"把这个函数改成异步的"

2
AI 思考 → 决定用什么工具

AI 分析任务,决定需要先读文件(ReadFile)、再修改(Edit)、最后运行测试(Shell)

3
执行工具 → 拿到结果

执行 ReadFile 工具,拿到文件内容;执行 Edit 工具,修改代码

4
AI 再思考 → 需要更多工具吗?

AI 看到修改结果,判断是否还需要运行测试、检查类型错误……如果需要,回到第 2 步

5
任务完成 → 输出总结

所有步骤执行完毕,AI 给你一个总结:"已将 syncHandler 改为 async,并更新了所有调用点"

🗺️
像 GPS 导航一样

GPS 不是一步到位给你终点,而是"前方 500 米右转 → 继续直行 2 公里 → 左转到达目的地"。Agent Loop 也是这样——AI 一步步拆解任务、执行操作、根据结果调整下一步,直到抵达目标。

Turn 类:一次循环的核心代码

Agent Loop 的每一次"思考 + 工具调用"由 Turn 类负责。它向 Gemini API 发送消息,拿回 AI 的回复,提取文字内容和工具调用请求。

TypeScript export class Turn { private callCounter = 0; readonly pendingToolCalls: ToolCallRequestInfo[] = []; constructor( private readonly chat: GeminiChat, private readonly prompt_id: string, ) {} async *run( modelConfigKey: ModelConfigKey, req: PartListUnion, signal: AbortSignal, displayContent?: PartListUnion, role: LlmRole = LlmRole.MAIN, ): AsyncGenerator<ServerGeminiStreamEvent> { // 1. 向 Gemini API 发送消息流 const responseStream = await this.chat.sendMessageStream( modelConfigKey, req, this.prompt_id, signal, role, displayContent, ); // 2. 逐个处理流式响应 for await (const streamEvent of responseStream) { // 用户取消则立即中断 if (signal?.aborted) { yield { type: GeminiEventType.UserCancelled }; return; } const resp = streamEvent.value; // 3. 提取 AI 的文字回复 const text = getResponseText(resp); if (text) { yield { type: GeminiEventType.Content, value: text }; } // 4. 提取工具调用请求 const functionCalls = resp.functionCalls ?? []; for (const fnCall of functionCalls) { yield this.handlePendingFunctionCall(fnCall); } } } }
中文逐行解释
Turn 类:一次循环的执行单元
callCounter:记录这一轮调用了几次工具
pendingToolCalls:等待执行的工具调用列表
constructor:需要传入聊天对象和 prompt ID
 
run 方法:这是一个异步生成器(流式输出)
 
第 1 步:调用 sendMessageStream,向 Gemini API 发请求。注意是"流式"的——AI 的回复像打字一样一个字一个字返回
 
第 2 步:逐个处理 API 返回的流式事件
用户取消:如果用户按了 Ctrl+C,立即中断并发出 UserCancelled 事件
 
第 3 步:从响应中提取文字内容。AI 说了什么?"我来帮你修改这个函数……"
 
第 4 步:从响应中提取工具调用。AI 说"我需要调用 ReadFile 工具"。functionCalls 就是工具调用列表
每个 functionCall 都交给 handlePendingFunctionCall 处理,生成工具调用请求事件
💡
关键设计:yield(生成器)

run 方法用 async *run() 声明为异步生成器。每一步结果通过 yield 传出去——文字内容、工具调用、取消事件。这意味着调用方(Scheduler)可以实时拿到每一步的结果,而不需要等整个 Turn 跑完。

Scheduler:工具执行的总指挥

Turn 负责"跟 AI 说话",但 AI 说"我要调用 ReadFile"之后,谁来真正执行这个工具?答案是 Scheduler。它像一个项目经理——接收任务需求、检查安全策略、找人执行、把结果汇报回来。

U
用户
T
Turn
S
Scheduler
P
Policy
🔧
工具
Click "Next Step" to begin
Step 0 / 6
🔄
循环不停

注意最后一步——工具结果返回给 Turn 后,Turn 会把结果再次发给 Gemini API。AI 看到工具执行结果后会决定:继续调用工具(回到 Scheduler)还是输出最终答案。这就是 Agent Loop 的"循环"——一直转,直到 AI 认为任务完成。

四种运行模式

Agent Loop 的行为取决于你选的运行模式——主要区别在于"哪些操作需要你确认"。安全策略(Policy Engine)会根据模式决定是自动执行还是弹出确认框。

🛡️

Default 模式

每个危险操作都要确认——文件修改、命令执行、目录删除,全部弹确认框。安全但慢,适合新手。

✏️

Auto-Edit 模式

自动执行文件编辑操作,只确认 Shell 命令。AI 修改代码不用你一个个点确认,但跑命令还是需要你同意。日常开发最常用的模式。

🚀

YOLO 模式

全自动执行,不弹任何确认框。快但需要信任 AI。适合"帮我批量修复 50 个 lint 错误"这种重复性任务——你确信 AI 不会搞砸的时候用。

📋

Plan 模式

只规划不执行。AI 会分析你的需求,列出要做什么、用什么工具、按什么顺序——但不真的执行。适合先看 AI 的计划再决定是否执行。

当你跟 AI 说"帮我自动修复所有 bug"

它就是在 Auto-Edit 或 YOLO 模式下运行 Agent Loop。每一步 AI 都在"思考 → 选工具 → 执行 → 再思考"这个循环里。区别只是——执行工具之前,是直接干(YOLO)、还是只确认命令(Auto-Edit)、还是什么都确认(Default)。

知识点检测

AI 想要删除一个文件,在 Default 模式下会发生什么?

04

工具箱

20+ 内置工具如何赋予 AI 行动能力

AI 的双手:工具系统

没有工具的 AI 只是"会说不会做"的聊天机器人。Gemini CLI 给 AI 配备了 20+ 工具,让它能真正操作你的代码库——读文件、改代码、跑命令、搜网页,全都能自己来。

下面是 8 个最核心的内置工具:

📄
ReadFile

读取文件内容 —— AI 的"眼睛",能看懂你项目里的每一行代码

✏️
EditFile

精确编辑文件 —— AI 的"手术刀",只改该改的地方,不动其他代码

📝
WriteFile

创建/重写文件 —— AI 的"笔",能从零写出完整的新文件

🔍
Grep

搜索代码内容 —— AI 的"搜索雷达",在项目里找到任何关键词

📂
Glob

按模式匹配文件 —— AI 的"文件导航器",比如找出所有 .tsx 文件

💻
Shell

运行终端命令 —— AI 的"万能钥匙",npm installgit commit 都能执行

🌐
WebFetch

抓取网页内容 —— AI 的"浏览器",能读取文档页面、API 返回值

🔎
WebSearch

Google 搜索 —— AI 的"百科全书",随时查最新资料和解决方案

💡
关键洞察

这些工具不是"可选插件",而是 AI Agent 的核心能力。没有它们,AI 只能在聊天框里输出文本;有了它们,AI 才能真正动手干活。

Tool Registry:工具注册表

每个工具都实现了一个统一的 interface —— ToolInvocation。这是 Gemini CLI 工具系统的核心契约,源码在 packages/core/src/tools/tools.ts

TypeScript export interface ToolInvocation<TParams, TResult> { params: TParams; getDescription(): string; shouldConfirmExecute( abortSignal: AbortSignal ): Promise< ToolCallConfirmationDetails | false >; execute( options: ExecuteOptions ): Promise<TResult>; toolLocations(): ToolLocation[]; }
中文解读
params —— AI 传给工具的参数(要读哪个文件、从第几行开始)
getDescription() —— 返回工具操作的描述,显示在终端让你看到 AI 在干什么
shouldConfirmExecute() —— 安全机制!这个操作需要你确认吗?比如删文件需要你同意
execute() —— 真正执行操作:读取文件、运行命令、搜索代码……
toolLocations() —— 告诉系统这个操作会影响哪些文件(用于权限追踪)

这个 interface 的设计很巧妙:不管是内置工具还是未来通过 MCP 扩展的工具,只要实现这 5 个方法,就能被 AI 调用。这就是"插件化"的威力。

MCP:让 AI 学会新技能

MCP(Model Context Protocol)是一个标准化的插件协议,让 AI 助手可以连接外部服务。就像 USB 接口——只要符合标准,任何设备都能插上用。

🔌

标准化连接

任何实现了 MCP 协议的服务器,都能被 Gemini CLI 发现和使用。不需要为每个服务写专门的集成代码。

🔎

自动发现工具

MCP 客户端连接服务器后,自动获取可用的工具列表,就像浏览器发现网络上的打印机一样。

🛡️

安全可控

所有操作都经过 shouldConfirmExecute() 检查,你可以逐个批准或拒绝每一个 MCP 工具调用。

下面是 MCP 客户端发现工具的核心代码(packages/core/src/tools/mcp-client.ts):

TypeScript export class MCPDiscovery { async discoverTools(): Promise<DiscoveredMCPTool[]> { const tools = await this.client.listTools(); return tools.map(tool => new DiscoveredMCPTool( tool.name, tool.description, tool.inputSchema, this ) ); } }
中文解读
discoverTools() —— MCP 客户端连接外部服务器,获取所有可用工具
client.listTools() —— 向 MCP 服务器请求工具清单
tool.name —— 工具名称(如 "create_issue"、"query_database")
tool.description —— 工具的功能描述,AI 靠这个决定什么时候用
tool.inputSchema —— 定义工具需要的参数格式,AI 根据这个构造输入
DiscoveredMCPTool —— 把外部工具包装成和内置工具一样的格式

通过 MCP,Gemini CLI 可以连接:数据库(查询数据)、GitHub(创建 PR、管理 Issue)、浏览器(操作网页)、Slack(发消息)……任何实现了 MCP 协议的服务都能接入。

知识点检测

你想让 AI 助手能直接操作你的 GitHub 仓库(创建 PR、合并代码等),最合适的方式是?

05

安全与扩展

沙箱隔离、安全策略与生态系统

沙箱:给 AI 套上安全绳

AI 可以运行 Shell 命令——这很强大,也很危险。想象一下,AI 误删了你的项目文件,后果不堪设想。Gemini CLI 用沙箱技术限制 AI 的操作范围,把危险关进笼子。

三大平台各有不同的沙箱实现,但目标一致:让 AI 只能碰到你允许的东西。

🍎

macOS: Seatbelt

苹果系统自带的安全框架。Gemini CLI 启动时会生成一份沙箱配置,规定 AI 能读写哪些目录、能执行哪些命令。

🐧

Linux: Bubblewrap

一个轻量级容器隔离工具。AI 运行的命令被装进一个最小化的容器环境,与你的真实系统隔离开来。

🪟

Windows: 沙箱管理器

Windows 上使用专用的沙箱管理器实现隔离。同样确保 AI 的操作不会越界影响系统核心文件。

🔒
记住这个比喻

沙箱就像给 AI 一个"安全游乐场"——它可以在里面自由操作,但无法翻越围栏伤害你的系统。

Policy Engine:安全策略引擎

沙箱是物理隔离,策略引擎是逻辑检查。每次 AI 想执行操作,Policy Engine 都会拦下来问三个问题:

1

这是什么操作?

2

匹配安全规则

3

允许/拒绝/确认

具体来说:第一步,检查操作类型(读文件?写文件?运行命令?);第二步,匹配安全规则(这个路径允许吗?这个命令安全吗?);第三步,做出决策(允许/拒绝/需要确认)。

下面是 packages/core/src/scheduler/policy.tscheckPolicy 的核心逻辑:

TypeScript // packages/core/src/scheduler/policy.ts   function checkPolicy( toolName: string, toolCallRequest: ToolCallRequestInfo, config: Config, approvalMode: ApprovalMode, ): PolicyDecision { // 情况 1:YOLO 模式 → 全部放行 if (approvalMode === PRIORITY_YOLO_ALLOW_ALL) { return PolicyDecision.ALLOW; }   // 情况 2:有自定义策略 → 按策略执行 const toolPolicy = config.getToolPolicy(); if (toolPolicy) { const decision = toolPolicy .evaluate(toolName, toolCallRequest.args); if (decision !== PolicyDecision.UNSPECIFIED) return decision; }   // 情况 3:都不匹配 → 问用户 return PolicyDecision.ASK_USER; }
中文解释
这个函数接收四个参数:工具名、调用请求、配置、审批模式。
情况 1 — 如果是 YOLO 模式(全自动),直接返回 ALLOW,不问任何问题。这是最"大胆"的模式。
情况 2 — 如果配置了自定义策略(比如"禁止写 .env 文件"),就用策略去评估。策略说允许就允许,说拒绝就拒绝。
情况 3 — 前两种都不匹配时,默认行为是"问用户"——在终端弹出确认提示,让你来拍板。
三层逻辑,层层递进,确保每次工具调用都经过安全审查。

生态系统:Skills、Hooks、Extensions

Gemini CLI 不只是个安全壳——它还是一个可扩展的平台。三大扩展机制让你可以按需增强 AI 的能力:

1
Skills — 预制任务模板

让 AI 快速上手新领域。packages/core/src/skills/skillLoader.ts 负责加载技能定义。你可以把 Skill 想象成 AI 的"职业技能证书"——装上之后,AI 就懂得怎么完成这类任务。

2
Hooks — 前后置钩子

在工具执行前后插入自定义逻辑。比如每次提交代码前自动运行 lint、每次写文件后自动格式化。Hook 是自动化工作流的核心。

3
Extensions — 社区功能增强

社区贡献的功能增强,比如新的 MCP 服务器、自定义工具。Extensions 让 Gemini CLI 的能力没有上限——社区想要什么功能,就可以加什么功能。

大图:Gemini CLI 完整架构

把前面学过的所有知识拼成一张完整的架构图。点击每个组件查看详细说明:

扩展层 Extension Layer
🎯 Skills
🪝 Hooks
🧩 Extensions
模型层 Model Layer
🧠 Gemini API
📦 上下文管理
🗜️ 对话压缩
安全层 Security Layer
🛡️ Policy Engine
🔒 Sandbox
确认机制
工具层 Tool Layer
🔧 内置工具
🔌 MCP 工具
⚙️ 自定义工具
代理层 Agent Layer
💬 Agent Session
🔄 Turn Loop
📋 Scheduler
终端层 Terminal Layer
🖥️ 用户界面
🎨 主题
⌨️ 快捷键
点击上方任意组件查看详细说明。

最终测试

你的 AI 助手在 YOLO 模式下想运行 rm -rf /,会发生什么?

💡
关键理解

YOLO 模式跳过的是用户确认(策略引擎的 ASK_USER),但沙箱层面的限制依然生效。就像保安不查身份证了(跳过确认),但围墙还在(沙箱保护)。两层安全机制,各管各的。