news 2026/9/12 9:56:29

Composio × Google GenAI(Gemini)集成实战:从工具获取到函数调用的完整链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Composio × Google GenAI(Gemini)集成实战:从工具获取到函数调用的完整链路

Composio × Google GenAI(Gemini)集成实战:从工具获取到函数调用的完整链路

【免费下载链接】composioComposio powers 1000+ toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio

导读

本文基于仓库中的 ts/examples/google 示例,完整演示如何在 TypeScript 项目中用 Composio SDK 与 Google 的 GenAI(Gemini)模型集成:包括环境准备、依赖安装、工具获取,以及把 Composio 工具包装为 Gemini 的 Function Declaration 并执行函数调用的完整链路。读完本文,你将掌握GoogleProvider的底层工作原理(工具 Schema 转换、参数归一化、工具执行),并能独立搭建一个"任务输入 → Gemini 决策 → Composio 执行工具 → 返回结果"的可用 Agent 程序,同时了解如何通过会话(Session)与 MCP 端点做进阶集成。

示例概览:Composio 如何与 Gemini 协同工作

Composio 本身提供 1000+ 工具集成,但 Gemini 这类模型并不知道这些工具的存在。示例的核心思路是**"格式适配 + 回调执行"**:

  1. 通过 Composio SDK 获取工具定义;
  2. GoogleProvider把工具定义转换成 Gemini 能识别的FunctionDeclaration(函数声明)格式;
  3. 把声明随提示词一起交给 Gemini,模型在需要时返回functionCalls
  4. 程序把函数调用转交composio.provider.executeToolCall实际执行,并把结果回传给模型。

整个示例位于 ts/examples/google/src/index.ts,目录结构如下:

ts/examples/google/ ├── .env.example # 环境变量模板 ├── README.md # 官方示例说明 ├── package.json # 依赖与运行脚本 ├── tsconfig.json # TypeScript 配置 ├── CHANGELOG.md # 版本变更记录 └── src/ ├── index.ts # 主示例:函数调用流程 └── experimental.mcp.ts # 进阶:基于 Session + MCP 的示例

第一步:安装依赖

示例使用 pnpm 工作区管理依赖,进入示例目录后执行:

pnpm install

从 ts/examples/google/package.json 可以看到本示例的核心依赖:

依赖包作用
@composio/coreComposio SDK 核心,提供Composio客户端
@composio/googleGoogle GenAI Provider,负责工具格式适配与执行
@google/genaiGoogle 官方 GenAI SDK,用于调用 Gemini 模型
dotenv.env文件加载环境变量

示例脚本同样定义在 package.json 中:start使用 Bun 直接运行src/index.tsdev则开启文件监听模式,二者均在仓库根目录的 pnpm workspace 环境下可用。

第二步:配置环境变量

复制环境变量模板并填入密钥:

cp .env.example .env

根据 ts/examples/google/.env.example,需要配置两个变量:

变量说明
COMPOSIO_API_KEY在 Composio 控制台(app.composio.dev)创建,用于身份认证与工具访问
GEMINI_API_KEY在 Google AI Studio(aistudio.google.com)创建,用于调用 Gemini 模型

注意@composio/google的 README(ts/packages/providers/google/README.md)中提到的变量名为GOOGLE_API_KEY,而本示例使用GEMINI_API_KEY——两者指向同一个密钥,只是命名习惯不同。实际项目中请与你的代码读取方式保持一致。

第三步:运行示例

# 运行示例 pnpm start # 开发模式(文件变更自动重启) pnpm dev

示例运行时,控制台会依次输出:初始化信息 → 获取到的工具数量 → 待执行任务 → Gemini 的响应 → 工具调用名称 → 最终执行结果。

深入主流程:Composio × Gemini 函数调用全解析

ts/examples/google/src/index.ts 完整展示了上述链路,下面拆解每一步。

1. 初始化两个客户端

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY, }); const composio = new Composio({ apiKey: process.env.COMPOSIO_API_KEY, provider: new GoogleProvider(), });

关键点在于Composio构造函数中传入的provider: new GoogleProvider()GoogleProvider是 ts/packages/providers/google/src/index.ts 中定义的核心适配器,它继承了BaseNonAgenticProvider,负责"把 Composio 工具翻译成 Gemini 的 Function Declaration"以及"执行 Gemini 返回的函数调用"两个方向的工作。

2. 获取 Composio 工具

const tools = await composio.tools.get('default', 'HACKERNEWS_GET_USER'); console.log(`✅ Found ${tools.length} tools`);

composio.tools.get按名称获取工具定义,此处获取的是 Hacker News 的HACKERNEWS_GET_USER工具(用于查询指定用户的信息)。工具定义中包含了slugdescriptioninputParameters(JSON Schema 格式的参数描述)等字段,这些正是后续转换 Function Declaration 所需的原始素材。

3. 把工具声明交给 Gemini

const task = "Fetch the details of the user 'pg'"; const response = await ai.models.generateContent({ model: 'gemini-2.0-flash-001', contents: task, config: { tools: [{ functionDeclarations: tools }], }, });

tools数组被放进config.tools[0].functionDeclarations,这正是 Google GenAI 函数调用(Function Calling)的标准用法。模型会基于声明判断:完成该任务是否需要调用工具、调用哪个、参数传什么。

4. 执行模型返回的函数调用

if (response.functionCalls) { const functionCall = { name: response.functionCalls[0].name || '', args: response.functionCalls[0].args || {}, }; const result = await composio.provider.executeToolCall('default', functionCall); console.log(JSON.parse(result).data); } else { console.log(response.text); }

这是"非 Agent 型(Non-Agentic)"集成的典型形态:模型只负责"决策",不负责"执行"。当response.functionCalls存在时,程序取出函数名与参数,交给composio.provider.executeToolCall('default', functionCall)执行,返回的 JSON 字符串中.data字段即工具执行结果(此处为 Hacker News 用户pg的详情)。

源码级剖析:GoogleProvider 如何完成双向适配

理解了主流程后,再看 ts/packages/providers/google/src/index.ts 中GoogleProvider的三个关键方法,就能彻底明白示例背后的原理。

wrapTool:Composio 工具 → Gemini Function Declaration

wrapTool(tool: Tool): GoogleTool { const inputParameters = ensureObjectTypeOnProperties( deduplicateJsonSchemaRequiredArrays( dereferenceJsonSchema(tool.inputParameters ?? { type: 'object', properties: {} }, { onUnresolved: 'sentinel', }) ) ); return { name: tool.slug, description: tool.description || '', parameters: { type: 'object', description: tool.description || '', properties: inputParameters?.properties || {}, required: inputParameters?.required || [], } as unknown as Schema, }; }

这里完成了一次关键的Schema 管道处理,保证转换后的参数描述能被 Gemini 正确解析:

  • dereferenceJsonSchema:把 JSON Schema 中的$ref引用解析为内联定义(onUnresolved: 'sentinel'表示无法解析时保留哨兵值,避免报错中断);
  • deduplicateJsonSchemaRequiredArrays:去重required数组中重复的字段名;
  • ensureObjectTypeOnProperties:确保带properties的对象节点显式声明type: 'object'(Gemini 的 Schema 校验对此有严格要求)。

转换后工具的nametool.slugparameters则直接映射为 Gemini 的Schema。对应测试见 ts/packages/providers/google/test/google.test.ts,其中验证了"工具被包装为 Function Declaration 格式"以及"无inputParameters的工具也能安全处理"两种场景。

executeToolCall:Gemini 函数调用 → Composio 工具执行

async executeToolCall( userId: string, tool: GoogleGenAIFunctionCall, options?: ExecuteToolFnOptions, modifiers?: ExecuteToolModifiers ): Promise<string> { const payload: ToolExecuteParams = { // Models occasionally emit tool args as a JSON string rather than an object (issue #2406). arguments: normalizeToolArguments(tool.args, tool.name), connectedAccountId: options?.connectedAccountId, customAuthParams: options?.customAuthParams, customConnectionData: options?.customConnectionData, userId: userId, }; const result = await this.executeTool(tool.name, payload, modifiers); return JSON.stringify(result); }

executeToolCall的入参tool即 Gemini 返回的{ name, args }。值得注意的两点:

  1. normalizeToolArguments(tool.args, tool.name):模型偶尔会把参数以 JSON字符串而非对象的形式返回(源码注释中标注了 issue #2406),该工具函数负责把字符串参数归一化为对象,确保下游执行不会因类型不符而失败;
  2. 返回结果统一JSON.stringify为字符串,方便回传给模型作为functionResponse,也便于上层JSON.parse(result)使用。

此外,options支持connectedAccountId(指定已连接账号)、customAuthParams(自定义认证参数)、customConnectionData(自定义连接数据),这些是接入需鉴权工具(如 Gmail、GitHub)时的关键扩展点。

_isAgentic = false:为什么需要手动循环

GoogleProvider是"非 Agent 型"Provider(ts/packages/providers/google/test/google.test.ts 中明确断言provider._isAgenticfalse)。这意味着 Composio 不会替模型自动调度多轮工具调用,"模型返回函数调用 → 程序执行 → 结果回传 → 模型再决策"的循环必须由你编写。这也是示例主流程只处理一次functionCalls的原因——它演示的是单次调用;生产环境需要的是下面这种完整循环。

实战升级:完整的 Agentic Loop 写法

ts/packages/providers/google/README.md 给出了生产可用的多轮循环模板,它比示例更进一步:先把工具绑定到会话,再用while循环反复执行,直到模型输出纯文本:

import { Composio } from '@composio/core'; import { GoogleProvider } from '@composio/google'; import { GoogleGenAI, type Part } from '@google/genai'; const composio = new Composio({ provider: new GoogleProvider(), }); const ai = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY! }); // 为你的用户创建会话,绑定工具 const session = await composio.create('user_123'); const tools = await session.tools(); const chat = ai.chats.create({ model: 'gemini-3-pro-preview', config: { tools: [{ functionDeclarations: tools }], }, }); let response = await chat.sendMessage({ message: "Send an email to john@example.com with the subject 'Hello' and body 'Hello from Composio!'", }); // Agentic loop:不断执行工具调用,直到模型以文本作答 while (response.functionCalls && response.functionCalls.length > 0) { const parts: Part[] = []; for (const fc of response.functionCalls) { const result = await composio.provider.executeToolCall('user_123', { name: fc.name || '', args: (fc.args || {}) as Record<string, unknown>, }); parts.push({ functionResponse: { id: fc.id, name: fc.name, response: JSON.parse(result), }, }); } response = await chat.sendMessage({ message: parts }); } console.log(response.text);

与示例主流程相比,这个版本有两个重要差异:

  • 会话(Session)抽象composio.create('user_123')为指定用户创建会话并挂载工具,executeToolCall的第一个参数即该用户 ID——这是多用户场景下隔离连接与权限的正确姿势;
  • 多轮循环while循环支持一次任务需要连续调用多个工具(例如"查邮件 → 写摘要 → 发消息")的情况;functionResponse携带id与 Gemini 返回的函数调用一一对应,保证多工具并发时结果不错位。

进阶路径:通过 Session + MCP 端点集成

如果不想手动做 Schema 转换,ts/examples/google/src/experimental.mcp.ts 展示了一条更"声明式"的路径:让 Composio 托管一个 MCP(Model Context Protocol)端点,再通过标准 MCP 客户端把工具交给 Gemini。

核心步骤:

// 1. 创建绑定 Gmail 工具包的会话,暴露托管 MCP 端点 const session = await composio.sessions.create(externalUserId, { toolkits: ['gmail'], manageConnections: false, // 关闭连接管理工具,本示例用不到 mcp: true, }); // 2. 用 Streamable HTTP 传输连接 MCP 端点 const serverParams = new StreamableHTTPClientTransport(new URL(session.mcp.url), { requestInit: { headers: session.mcp.headers }, // 端点凭据 }); const mcpClient = new MCPClient({ name: 'composio-mcp-client', version: '1.0.0' }); await mcpClient.connect(serverParams); // 3. 用 @google/genai 提供的 mcpToTool 把 MCP 工具转成 Gemini 工具 const tools = [mcpToTool(mcpClient)]; // 4. 交给 Gemini 流式执行 const stream = await gemini.models.generateContentStream({ model: 'gemini-2.5-flash', contents: `Fetch the latest 2 emails and provide a detailed summary...`, config: { tools }, });

几个值得注意的实现细节:

  • sessions.createmcp: true让会话返回session.mcp.urlsession.mcp.headers,前者是端点地址,后者携带访问凭据,缺一不可;
  • manageConnections: false会关闭自动注入的连接管理工具,避免无关工具干扰模型;
  • MCP 客户端对象必须保持存活(不能被 GC 回收),直到从它上面取完工具;
  • 该文件注释为"experimental",说明 Session + MCP 属于演进中的能力,接入时建议锁定所依赖的@modelcontextprotocol/sdk版本。

这种方式的好处是:工具集的获取、鉴权、生命周期由 Composio 托管,客户端代码只需关心"连接 MCP → 转工具 → 调模型",适合接入 Gmail 这类需要 OAuth 鉴权的重型工具包。

自定义与继续探索

按 ts/examples/google/README.md 的指引,你可以基于此示例做三类改造:

  1. 更换工具:把HACKERNEWS_GET_USER换成其他工具 slug,或改用session.tools()/ 工具包(toolkit)方式批量挂载,例如 Gmail、GitHub、Slack 等;
  2. 实现业务逻辑:在main()中扩展多轮对话、结果格式化、持久化等逻辑;
  3. 增强健壮性:为executeToolCall增加错误捕获与重试,处理connectedAccountIdcustomAuthParams等鉴权参数。

仓库中还提供了同源对比示例,帮助你理解不同 Provider 的适配差异:

  • OpenAI 示例:展示与 OpenAI 的集成方式;
  • LangChain 示例:展示与 LangChain 框架的集成方式;
  • 更多示例:浏览完整的示例集合,包括工具路由(tool-router)、触发器(triggers)、会话管理(session-management)等场景。

如果你要深入源码,建议按以下顺序阅读:先看 示例主文件 理解使用形态,再读 GoogleProvider 实现 掌握 Schema 管道与执行细节,最后对照 Provider 测试 验证各行为的预期,即可完整把握 Composio 与 Gemini 的集成全貌。

【免费下载链接】composioComposio powers 1000+ toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

COMSOL仿真手性超材料光学特性与圆二色性分析

1. 项目背景与核心价值二维手性超材料在光学领域正引发新一轮研究热潮。这种由人工设计的微纳结构能够与圆偏振光产生独特的相互作用&#xff0c;在光学传感、量子通信和显示技术等领域展现出巨大潜力。作为一名长期使用COMSOL进行光学仿真的工程师&#xff0c;我发现通过建立精…

作者头像 李华
网站建设 2026/9/12 9:53:31

Claude Code UI Git 集成完整指南:5 个高频操作 + 5 个避坑点

Claude Code UI Git 集成完整指南&#xff1a;5 个高频操作 5 个避坑点 【免费下载链接】claudecodeui Use Claude Code, OpenCode, Cursor CLI, and Codex on mobile and web with CloudCLI (aka Claude Code UI). CloudCLI is a free open source webui/GUI that helps you …

作者头像 李华
网站建设 2026/9/12 9:53:07

Python 3.14新特性解析:性能优化与开发体验升级

1. Python 3.14 版本概述&#xff1a;当圆周率遇上编程语言作为2024年最受期待的Python版本&#xff0c;3.14这个特殊的版本号不仅是对数学常数π的致敬&#xff0c;更是Python语言发展史上的重要里程碑。这个版本在性能优化、标准库增强和语言特性三个方面带来了超过60项实质性…

作者头像 李华
网站建设 2026/9/12 9:49:38

医疗具身智能的数据瓶颈:高质量数据集的临床定义与实操路径

1. 为什么说“高质量数据集才是 AI 的真瓶颈”不是口号&#xff0c;而是徐汇医院里凌晨三点还在校对的标注员眼睛里的血丝“高质量数据集才是 AI 的真瓶颈”——这句话最近在技术圈刷屏&#xff0c;但很多人把它当成了一个抽象概念&#xff0c;像“算力不够”“模型太浅”一样&…

作者头像 李华
网站建设 2026/9/12 9:49:31

Manjaro下systemd优化微服务启动与资源管理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华