资讯动态

Gemini CLI SDK 实战指南:用 @google/gemini-cli-sdk 在 Node.js 中构建可编程的 Gemini Agent

发布时间:2026/9/7 23:02:40 来源:尧图企业网站定制
Gemini CLI SDK 实战指南用 google/gemini-cli-sdk 在 Node.js 中构建可编程的 Gemini Agent【免费下载链接】gemini-cliAn open-source AI agent that brings the power of Gemini directly into your terminal.项目地址: https://gitcode.com/GitHub_Trending/gemi/gemini-cli本篇指南围绕 packages/sdk/README.md 展开系统讲解 Gemini CLI 官方 SDK 的安装、Agent 创建、流式会话、自定义工具、会话上下文与技能加载等核心能力并结合仓库内packages/sdk包的源码agent.ts、session.ts、tool.ts、skills.ts、types.ts剖析其底层 Agent 循环、工具注册与错误处理机制帮助读者在自己的 Node.js 项目中把 Gemini 的终端智能体能力以编程方式嵌入自动化脚本、CI 流水线或服务端应用。一、SDK 是什么定位与实现状态Gemini CLI SDK 为 Gemini 模型与工具提供编程式接口programmatic interface让你无需启动交互式终端就能在代码中驱动一个具备完整 Agent 循环能力的 Gemini 会话。它在仓库中是packages/sdk这个独立 npm 包包名为google/gemini-cli-sdk。从 packages/sdk/package.json 可以确认其关键元信息包名google/gemini-cli-sdkLicense 为 Apache-2.0type: module纯 ESM 包使用import语法引入engines: { node: 20 }要求 Node.js 20 及以上运行时依赖google/gemini-cli-core以file:../core方式指向仓库内packages/core包即 CLI 本体共用的核心引擎、zod与zod-to-json-schema用于工具参数的声明式 schema 定义与向模型侧的 JSON Schema 转换。SDK 的公开 API 从 packages/sdk/src/index.ts 统一导出共五个模块export * from ./agent.js; // GeminiCliAgent export * from ./session.js; // GeminiCliSession export * from ./tool.js; // tool、Tool、SdkTool、ModelVisibleError、z export * from ./skills.js; // skillDir、SkillReference export * from ./types.js; // GeminiCliAgentOptions、SystemInstructions、SessionContext 等需要说明的是SDK 目前仍处于快速演进阶段。仓库中的设计文档 packages/sdk/SDK_DESIGN.md 明确标注了各功能的实现状态能力状态以 SDK_DESIGN.md 标注为准会话创建 / 会话恢复session()/resumeSession()已实现系统指令静态字符串 动态函数已实现自定义工具tool() Zod schema已实现自定义技能skillDir已实现SessionContextfs / shell 接口已实现自定义 Hooks / Subagents / Extensions / ACP 模式 / 审批策略未实现下文讲解的所有内容均以“已实现”部分为准未实现部分会在最后单独说明边界。二、安装按 packages/sdk/README.md 的说明安装方式只有一条命令npm install google/gemini-cli-sdk前提条件Node.js 20见 package.json 中engines字段代码中使用 ESM 语法import因为包声明为type: module运行时需要具备 Gemini 的认证配置——从源码看会话初始化时通过getAuthTypeFromEnv()读取环境变量来确定认证方式未设置时回退到AuthType.COMPUTE_ADCGoogle Cloud 工作负载身份详见 packages/sdk/src/session.ts 的initialize()方法。三、快速上手README 最简示例README 给出的最小可用示例如下原文继承自 packages/sdk/README.mdimport { GeminiCliAgent } from google/gemini-cli-sdk; async function main() { const agent new GeminiCliAgent({ instructions: You are a helpful assistant., }); const controller new AbortController(); const signal controller.signal; // Stream responses from the agent const stream agent.sendStream(Why is the sky blue?, signal); for await (const chunk of stream) { if (chunk.type content) { process.stdout.write(chunk.value.text || ); } } } main().catch(console.error);示例传达的三件核心事创建一个 Agent、用AbortController的 signal 控制取消、用for await消费流式响应。不过从当前源码结构看需要做一个重要补充packages/sdk/src/agent.ts 中的GeminiCliAgent类目前只暴露session()与resumeSession()两个方法流式发送的实现在GeminiCliSession.sendStream(prompt, signal?)上见 packages/sdk/src/session.ts。SDK_DESIGN.md 与仓库内示例采用的是“Agent → Session → sendStream”的两级结构这也是当前可运行的调用路径import { GeminiCliAgent } from google/gemini-cli-sdk; const agent new GeminiCliAgent({ instructions: You are a helpful assistant., }); // 创建新会话 const session agent.session(); // 也可以恢复既有会话 // const session await agent.resumeSession(some-session-id); const controller new AbortController(); for await (const event of session.sendStream(Why is the sky blue?, controller.signal)) { console.log(event); // JSON 流式事件 }sendStream是一个AsyncGeneratorServerGeminiStreamEvent事件类型沿用google/gemini-cli-core定义的GeminiEventType。从 session.ts 的实现可以看到源码至少处理了GeminiEventType.ToolCallRequest模型请求调用工具时产生这类事件模型响应文本等事件则直接透传给调用方。消费事件时建议按event.type做分支处理而不是假定每个 chunk 都有text字段。四、GeminiCliAgentOptions完整参数说明Agent 的全部可配置项定义在 packages/sdk/src/types.ts 的GeminiCliAgentOptions接口中。结合接口内的 JSDoc 注释与 session.ts 构造函数的实际使用方式完整参数表如下参数类型必填默认值说明instructionsstring \| ((ctx: SessionContext) string \| Promisestring)是无系统指令。可以是静态字符串也可以是接收SessionContext的动态函数下一节详述toolsArrayToolany否[]自定义工具列表每个工具由tool()辅助函数创建skillsSkillReference[]否[]技能目录引用由skillDir(path)生成modelstring否PREVIEW_GEMINI_MODEL_AUTO自动选择指定 Gemini 模型名称cwdstring否process.cwd()Agent 工作目录等价于gemini -p运行时加载工作区配置的目录debugboolean否false调试模式输出详细日志映射到 core 的debugModerecordResponsesstring否无将 Agent 响应记录到指定文件路径用于调试与回放fakeResponsesstring否无从指定文件加载预录制re-simulated响应用于确定性测试cwd参数值得展开session.ts 中它同时被写入ConfigParameters的targetDir与cwd字段resumeSession时也用它定位Storage见 agent.ts 中new Storage(cwd)。这意味着会话历史与项目级配置都锚定在cwd上多租户或多项目场景下务必显式指定。recordResponses/fakeResponses这对参数是 SDK 面向测试能力的关键设计仓库中 packages/sdk/test-data/ 目录下就有大量配套数据文件例如agent-static-instructions.json、agent-async-instructions.json、agent-resume-session.json、tool-success.json、tool-error-recovery.json等供集成测试回放确定性的模型响应见下文“测试与可回放性”一节。五、系统指令静态字符串与动态函数SDK 支持两种指令形式类型定义为 types.ts 中的SystemInstructionsexport type SystemInstructions | string | ((context: SessionContext) string | Promisestring);静态字符串会在GeminiCliSession构造时写入 core 的Config的userMemory字段出现在模型调用中 GEMINI.md 内容通常所在的位置动态函数则更强——从 session.ts 的sendStream实现可以看到每轮 Agent 循环开始时都会重新求值while (true)循环顶部若instructions是函数SDK 会组装当前SessionContext含最新 transcript、时间戳、fs、shell 等并await调用它求值结果通过this.config.setUserMemory(newInstructions)更新再调用client.updateSystemInstruction()让新指令在下一轮模型请求中生效。这意味着你可以实现“随对话状态演化”的系统指令例如在 SDK_DESIGN.md 中给出的例子const agent new GeminiCliAgent({ instructions: (ctx) The current time is ${new Date().toISOString()} in session ${ctx.sessionId}., });安全提示来自 types.ts 的官方注释动态指令函数会把SessionContext数据拼进提示词必须自行做消毒处理例如去除换行、]转义、防止会话内容反向注入系统指令。六、自定义工具tool() 辅助函数与错误处理自定义工具是 SDK 的核心卖点。tool()辅助函数、Tool接口与zZod 的再导出均定义在 packages/sdk/src/tool.ts。6.1 基本用法README 与 SDK_DESIGN.md 中给出的示例仓库内 examples/simple.ts 也有可运行的等价实现import { GeminiCliAgent, tool, z } from google/gemini-cli-sdk; const addTool tool( { name: add, description: add two numbers, inputSchema: z.object({ a: z.number().describe(first number to add), b: z.number().describe(second number to add), }), }, ({ a, b }) ({ result: a b }), ); const agent new GeminiCliAgent({ tools: [addTool], instructions: ... }); const session agent.session(); for await (const chunk of session.sendStream(what is 23 79?)) { console.log(chunk); }ToolDefinition的四个字段见 tool.tsname模型用来调用工具的唯一名称description发送给模型的工具说明直接影响模型“何时选用该工具”inputSchemaZod schema用于参数校验并且会被zodToJsonSchema转换后作为 JSON Schema 提供给模型SdkTool构造函数中的zodToJsonSchema(definition.inputSchema)sendErrorsToModel?默认false。为true时action 抛出的错误会作为Error: message文本送回模型供其自行纠正重试。action 的签名是(params: z.inferT, context?: SessionContext) Promiseunknownparams的类型由 Zod schema 静态推断拿到即是类型安全的返回值若不是字符串会被JSON.stringify(result, null, 2)序列化后作为llmContent回传给模型第二个参数context即下文详述的SessionContext让工具可以访问沙箱文件系统与 shell。6.2 面向模型的错误ModelVisibleErrortool.ts 中定义了一个专门的错误类export class ModelVisibleError extends Error { constructor(message: string | Error) { super(message instanceof Error ? message.message : message); this.name ModelVisibleError; } }SdkToolInvocation.execute()的 catch 分支处理逻辑清晰若抛出的错误是ModelVisibleError或工具定义声明了sendErrorsToModel: true则错误信息以Error: message形式作为工具响应回传模型同时带error元数据模型可以据此调整策略否则错误原样向外抛出中断本轮工具执行。这是“把可控反馈给模型、把真正的故障留给宿主程序”的分工设计写工具时应尽量抛出ModelVisibleError来表达可恢复的业务性失败。七、SessionContext工具内的文件系统与 Shell 能力SessionContext是 SDK 传给工具与动态指令函数的“环境句柄”接口定义在 types.ts与 SDK_DESIGN.md 中设计稿一致export interface SessionContext { sessionId: string; // 会话唯一标识 transcript: readonly Content[]; // 只读对话历史 cwd: string; // 会话工作目录 timestamp: string; // ISO 8601 时间戳 fs: AgentFilesystem; // 沙箱文件系统 shell: AgentShell; // 沙箱 shell agent: GeminiCliAgent; // 所属 Agent 实例 session: GeminiCliSession; // 当前会话实例 }两个关键子接口AgentFilesystemreadFile(path)返回Promisestring | null不存在或无权限返回nullwriteFile(path, content)返回Promisevoid策略拒绝时抛错。JSDoc 强调实现内部必须校验路径、防止..与空字节造成的路径穿越AgentShellexec(cmd, options?)返回AgentShellResult包含exitCode进程被杀时为null、outputstdoutstderr 合并、stdout、stderr与可选的errorAgentShellOptions支持env与环境合并、timeoutSeconds、cwd。SessionContext的实际构造发生在 session.ts 的sendStream中每一轮循环 SDK 都会new SdkAgentFilesystem(this.config)与new SdkAgentShell(this.config)见 fs.ts 与 shell.ts并把工具注册表克隆一份作用域副本scopedRegistry在其中把SdkTool替换为bindContext(context)后的实例——即每个工具调用绑定的都是本轮最新的上下文。仓库内 examples/session-context.ts 给出了完整可运行的用法定义一个无参数的get_context工具action 内读取context.sessionId、context.cwd、context.timestamp调用context.fs.readFile(package.json)与context.shell.exec(echo Hello from SDK Shell)最终把探测结果回传给模型。该示例同时展示了cwd参数如何让 Agent“知道”项目根目录cwd: process.cwd()。八、技能Skills用目录扩展 Agent 能力技能系统通过 packages/sdk/src/skills.ts 暴露API 极其精简export type SkillReference { type: dir; path: string }; export function skillDir(path: string): SkillReference { return { type: dir, path }; }一个技能是一个目录至少包含SKILL.md元数据与指令可选tools/子目录存放工具脚本目录结构如 SDK_DESIGN.md 所述skill-dir/ SKILL.md (Metadata and instructions) tools/ (Optional directory for tools) my-tool.js在 Agent 上加载import { GeminiCliAgent, skillDir } from google/gemini-cli-sdk; const agent new GeminiCliAgent({ instructions: You are a helpful assistant., skills: [ skillDir(./my-skill), // 加载单个技能目录 skillDir(./skills-collection), // 加载根目录下所有子技能 ], });加载时机在 session.ts 的initialize()中对每个type dir的引用调用 core 的loadSkillsFromDir(ref.path)结果通过skillManager.addSkills()注入只要技能非空就会先卸载再注册 core 的ActivateSkillTool使模型能通过激活技能工具按需使用技能内容。仓库中 packages/sdk/test-data/skills/pirate-skill/SKILL.md 就是一个真实的技能目录样例examples/simple.ts 中“always talk like a pirate”的指令正是围绕这类技能机制展开的演示风格。加载失败不会抛异常而是console.error后跳过该目录源码中有 TODO 标注未来改用正式 logger。九、会话生命周期initialize、sendStream 与 resumeSession把前面各节串起来一个完整的会话生命周期在源码中的路径如下均在 session.ts 与 agent.ts1. 初始化initialize()幂等getAuthTypeFromEnv() || AuthType.COMPUTE_ADC决定认证方式依次执行config.refreshAuth(authType)与config.initialize()加载技能、注册ActivateSkillTool把每个 SDK 工具包装成SdkTool注册进toolRegistry若会话是恢复的携带resumedData则把ConversationRecord.messages逐条映射为{ role: model | user, parts }形式的Content[]调用client.resumeChat(history, resumedData)重放历史。注意sendStream内部也会检查this.initialized未初始化时自动补一次initialize()调用方不必手动管理。2. Agent 循环sendStream(prompt, signal?)这是 SDK 最有含金量的部分一个典型的 while 循环可选重新求值动态指令并更新userMemoryclient.sendMessageStream(request, abortSignal, sessionId)发起流式请求逐事件yield给调用方同时收集GeminiEventType.ToolCallRequest事件若args是字符串会JSON.parse反序列化若本轮没有工具调用则break结束否则克隆注册表并绑定本轮SessionContext调用 core 的scheduleAgentTools(this.config, toolCallsToSchedule, { schedulerId: sessionId, toolRegistry, signal })执行全部工具把各工具响应的responseParts平铺为functionResponses作为下一轮request发回模型——如此往复直到模型不再请求工具产出最终回答。AbortSignal会一路透传到模型流与工具调度器取消是贯穿整个循环的。3. 恢复会话resumeSession(sessionId)agent.ts 中实现了与 CLI 共享的会话恢复逻辑基于Storage(cwd)列出项目 chat 文件listProjectChatFiles()先用sessionId前 8 位匹配文件名源码注释说明这是对文件命名约定的优化无候选时回退全量再逐个loadConversationRecord()精确比对完整sessionId。找不到时分别抛出No sessions found in chats 目录或Session with ID id not found。恢复后的会话继续走resumeChat重放历史与 CLI 的--resume体验对齐。十、会话内配置细节源码里的默认值session.ts 构造函数中写入ConfigParameters的一组默认值直接决定了 SDK 会话的行为边界值得逐一列出const configParams: ConfigParameters { sessionId: this.sessionId, targetDir: cwd, cwd, debugMode: options.debug ?? false, model: options.model || PREVIEW_GEMINI_MODEL_AUTO, userMemory: initialMemory, // 静态 instructions enableHooks: false, // 与 SDK_DESIGN.md 的 “Hooks: Not Implemented” 一致 mcpEnabled: false, extensionsEnabled: false, recordResponses: options.recordResponses, fakeResponses: options.fakeResponses, skillsSupport: true, adminSkillsEnabled: true, policyEngineConfig: { // TODO: Revisit this default when we have a mechanism for wiring up approvals defaultDecision: PolicyDecision.ALLOW, }, };可以推断当前 SDK 会话是策略默认放行PolicyDecision.ALLOW且明确关闭了 hooks / MCP / extensions 入口的轻量形态源码中的 TODO 注释也表明审批approvals机制尚未接入这与 SDK_DESIGN.md 的 “Approvals / Policies: Not Implemented” 互相印证。使用 SDK 驱动文件与 shell 操作时应自行在工具实现层做权限约束。十一、测试与可回放性SDK 自带了完整的测试分层可作为工程实践参考单元测试packages/sdk/src/tool.test.ts、packages/sdk/src/session.test.ts集成测试packages/sdk/src/agent.integration.test.ts、packages/sdk/src/tool.integration.test.ts、packages/sdk/src/skills.integration.test.ts配合 test-data/ 下的预录响应文件如tool-success.json、tool-error-recovery.json、agent-resume-session.json、skill-dir-success.json实现确定性的端到端验证配置packages/sdk/vitest.config.ts包级脚本见 package.jsontest/typecheck/lint。recordResponsesfakeResponses这对参数正是 SDK_DESIGN.md “Notes” 中提到的“用 mock 的模型 API 让测试接近端到端且保持确定性”思路的落地先录制真实响应再用fakeResponses回放从而让工具执行、错误恢复、会话恢复等逻辑都能离线验证。十二、当前边界与后续演进基于 packages/sdk/SDK_DESIGN.md 的状态标注与源码交叉验证当前版本的明确边界是未实现自定义 Hooks、Subagents、Extensions、ACP 模式、显式审批/策略 API源码中enableHooks: false、mcpEnabled: false、extensionsEnabled: false与之对应策略引擎默认ALLOW审批机制处于 TODO 状态README 的流式示例agent.sendStream与当前源码中GeminiCliAgent仅暴露session()/resumeSession()的结构存在出入实际开发请以“Agent → Session →sendStream”路径及 src/agent.ts、src/session.ts 为准事件消费按ServerGeminiStreamEvent/GeminiEventType分支处理更稳妥不同事件类型的value结构并不统一。设计文档同时给出了演进路线Hook 接口需从字符串事件名到请求/响应类型的强类型映射、审批流需同时兼容 CLI 触发的确认与开发者发起的用户提示HITL、子代理需明确消息上下文继承方式例如是否共享 sessionId。这些方向可作为跟踪该包后续版本的依据。小结Gemini CLI SDK 以极小的 API 面GeminiCliAgent、GeminiCliSession、tool、skillDir、SessionContext把 Gemini CLI 的核心 Agent 循环开放给了 Node.js 开发者用 Zod 声明类型安全的自定义工具用动态指令函数让系统提示随会话演化用SessionContext.fs/shell在沙箱边界内扩展工具能力用recordResponses/fakeResponses保证行为可回放、可测试。结合上文给出的参数表、调用链与源码路径packages/sdk/src/下各文件你既可以按 README 的三步式示例快速起步也可以下钻到session.ts的 while 循环理解每一轮“请求—工具—回填”的完整机制。【免费下载链接】gemini-cliAn open-source AI agent that brings the power of Gemini directly into your terminal.项目地址: https://gitcode.com/GitHub_Trending/gemi/gemini-cli创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价