1. 项目概述当Bard学会“使用工具”如果你和我一样一直在关注大语言模型LLM的进化那么“工具调用”这个能力绝对是近一年来最让人兴奋的突破之一。它让模型从一个“博学的聊天者”变成了一个能真正“动手做事”的智能体。而Google的Bard现已更名为Gemini在这方面走得相当靠前其API开放了与一系列Google自家及第三方服务的深度集成能力这就是我们今天要深入探讨的“Bard-API工具集成”。简单来说这个项目就是教你如何让Bard模型通过API调用去操作像Google Maps、YouTube、Google Flights、Google Hotels等12种强大的工具。这不再是简单的“帮我写一段去纽约的游记”而是变成“基于我下周五从上海出发的预算帮我规划一个为期三天的纽约行程查找并对比直飞航班与酒店标记出时代广场和中央公园附近的餐厅并附上相关YouTube旅行vlog作为参考”。后者才是工具集成带来的质变。对于开发者、产品经理或是任何想构建下一代AI应用的人来说掌握这套工具集成的玩法意味着你能创造出体验远超传统聊天机器人的智能助手。它适合那些已经对API调用有基本了解并希望将AI能力无缝嵌入到具体业务场景中的朋友。接下来我将以一个过来人的身份拆解这套工具集成的核心逻辑、实操细节以及那些官方文档里不会明说的“坑”。2. 核心思路与架构设计为什么是“工具调用”在深入代码之前我们必须先理解Bard-API工具集成的设计哲学。这不仅仅是多几个API端点那么简单它代表了一种范式转变。2.1 从“生成文本”到“执行任务”的范式转变传统的LLM API交互是线性的用户输入Prompt - 模型思考 - 模型输出文本。模型的所有“知识”都凝固在训练时的参数里它无法获取实时信息比如最新股价、航班动态也无法执行具体操作比如在地图上画个圈、发一封邮件。工具调用Tool Calling或函数调用Function Calling机制打破了这堵墙。其核心流程变为用户提出需求包含需要实时数据或具体操作的任务。模型理解与规划模型分析需求判断是否需要以及需要调用哪个工具。模型请求调用模型不会直接执行而是生成一个结构化的“工具调用请求”其中包含调用的函数名和精确的参数。开发者代码执行你的后端代码接收到这个结构化请求去真正调用对应的外部API如Google Maps API。返回结果给模型将API返回的原始数据通常是JSON传回给模型。模型组织与回复模型理解这些数据并将其整合成自然、友好的文本回复给用户。在这个过程中模型扮演的是“大脑”和“指挥官”的角色它负责理解意图、规划步骤、解析结果而你的代码和集成的外部服务则是“手”和“脚”负责执行具体动作。这种分工使得AI应用的能力边界得到了极大的扩展。2.2 Bard-API工具集的设计优势Google为BardGemini设计的这套工具集有以下几个显著特点深度原生集成对于Google系服务Maps, YouTube, Flights, Hotels, Workspace等其工具的参数设计和数据格式与官方API高度对齐甚至做了优化减少了开发者适配的复杂度。统一调用范式无论调用哪个工具在Bard-API的交互中都遵循同一套“工具调用”协议。你只需要在初始化客户端时声明可用的工具列表后续的交互模型会自动处理。多工具协同模型可以在一个对话回合内顺序或并行地规划调用多个工具。例如先调用Google Flights查航班再用Google Hotels查住宿最后用Google Maps计算机场到酒店的距离最终综合所有信息给出建议。安全与可控性工具调用权完全掌握在开发者手中。你可以精确控制哪些工具对模型可见并且能对模型传入的参数进行校验和过滤防止滥用。注意工具调用能力依赖于特定的模型版本。通常gemini-1.5-pro或gemini-1.5-flash等较新版本对工具调用的支持更好、更稳定。在开始前请务必确认你使用的模型支持此功能。3. 环境准备与工具声明搭建你的“工具箱”理论讲完我们开始动手。首先你需要准备好战场。3.1 基础环境配置假设你使用Python核心就是Google的google-generativeai库。pip install google-generativeai接下来获取API密钥。前往 Google AI Studio 创建一个项目并生成API密钥。请妥善保管此密钥不要将其硬编码在客户端代码中推荐使用环境变量。import os import google.generativeai as genai # 配置API密钥 GOOGLE_API_KEY os.environ.get(GOOGLE_API_KEY) genai.configure(api_keyGOOGLE_API_KEY)3.2 工具声明的艺术定义模型的“能力清单”这是最关键的一步。你需要以特定的JSON Schema格式告诉模型它可以使用哪些工具以及每个工具需要什么参数。以下是一个声明了Google Maps和YouTube工具的示例。请注意这里的参数定义需要与你实际计划调用的底层API保持一致。# 定义工具列表 tools [ { function_declarations: [ { name: get_places_nearby, # 工具函数名模型将调用这个名字 description: 根据地理位置和类型搜索附近的兴趣点如餐厅、酒店、加油站。, parameters: { type: OBJECT, properties: { location: { type: STRING, description: 中心点的经纬度坐标格式为纬度,经度或一个明确的地址字符串。 }, radius: { type: NUMBER, description: 搜索半径以米为单位。默认值为1500。 }, place_type: { type: STRING, description: 搜索的地点类型例如restaurant, cafe, hotel, museum, park。 } }, required: [location] } }, { name: search_youtube_videos, description: 在YouTube上搜索视频。, parameters: { type: OBJECT, properties: { query: { type: STRING, description: 搜索关键词。 }, max_results: { type: NUMBER, description: 返回的最大结果数量默认5。 } }, required: [query] } } // ... 可以继续添加其他工具如 get_directions, find_flights, search_hotels 等 ] } ] # 初始化模型并传入工具定义 model genai.GenerativeModel( model_namegemini-1.5-pro, # 使用支持工具调用的模型 toolstools # 将工具列表关联到模型 )实操心得一描述description是灵魂description字段至关重要。模型完全依靠这个描述来理解工具的用途和何时调用它。描述要精确、无歧义。例如get_places_nearby的描述明确指出了它是用来搜“附近的兴趣点”这能帮助模型区分它和另一个可能存在的工具get_place_details获取某个特定地点的详细信息。实操心得二参数设计遵循“最小可用”原则不要一股脑把底层API的所有参数都暴露给模型。只定义完成核心任务所必需的参数。过多的参数会增加模型理解的负担也可能导致它生成错误或复杂的调用。例如Google Maps Places API有几十个参数但我们只暴露了location,radius,place_type这三个最关键的。4. 核心交互流程与代码实现让模型“动”起来有了模型和工具定义接下来就是实现交互循环。我们将构建一个简单的聊天循环并处理模型的工具调用请求。4.1 对话历史管理与模型调用我们需要维护一个对话历史history这对于多轮对话和工具调用上下文至关重要。# 初始化对话历史 history [] def chat_with_model(user_input): global history # 将用户输入加入历史 history.append({role: user, parts: [user_input]}) # 调用模型传入整个历史 response model.generate_content(history) # 处理响应 for candidate in response.candidates: for part in candidate.content.parts: # 1. 检查是否是工具调用请求 if hasattr(part, function_call) and part.function_call: function_call part.function_call func_name function_call.name args dict(function_call.args) # 模型提供的参数 print(f\n[模型请求调用工具] 函数名: {func_name}, 参数: {args}) # 2. 执行对应的工具函数 result execute_tool(func_name, args) # 3. 将工具执行结果作为“函数响应”加入历史让模型继续处理 history.append({ role: function, parts: [genai.protos.Part( function_responsegenai.protos.FunctionResponse( namefunc_name, response{result: result} # 结果需要是字典格式 ) )] }) # 4. 有了新的函数响应需要再次调用模型让它基于结果生成回复 return chat_with_model() # 发送空消息触发模型继续 # 2. 如果是普通文本回复直接输出并加入历史 elif part.text: print(f\n[Bard]: {part.text}) history.append({role: model, parts: [part.text]}) return part.text return 未收到有效响应。4.2 工具执行器连接模型与真实APIexecute_tool函数是你的“工具执行中枢”。这里你需要实现每个声明了的工具函数的具体逻辑通常就是去调用对应的官方API。import requests import json def execute_tool(func_name: str, args: dict): 根据函数名和参数执行具体的工具 if func_name get_places_nearby: # 这里是调用 Google Places API 的示例 # 注意你需要先启用 Google Cloud 的 Places API 并获取一个单独的 API Key GOOGLE_PLACES_API_KEY os.environ.get(GOOGLE_PLACES_API_KEY) location args.get(location, ) radius args.get(radius, 1500) place_type args.get(place_type, ) # 构建API请求 url https://maps.googleapis.com/maps/api/place/nearbysearch/json params { location: location, radius: radius, type: place_type, key: GOOGLE_PLACES_API_KEY } try: resp requests.get(url, paramsparams) data resp.json() # 简化返回只提取核心信息给模型 places [] for place in data.get(results, [])[:5]: # 只取前5个 places.append({ name: place.get(name), vicinity: place.get(vicinity), rating: place.get(rating), types: place.get(types, []) }) return {status: success, places: places} except Exception as e: return {status: error, message: str(e)} elif func_name search_youtube_videos: # 这里是调用 YouTube Data API v3 的示例 # 同样需要先创建项目并启用 API获取 API Key 或 OAuth 2.0 凭证 YOUTUBE_API_KEY os.environ.get(YOUTUBE_API_KEY) query args.get(query, ) max_results args.get(max_results, 5) url https://www.googleapis.com/youtube/v3/search params { part: snippet, q: query, maxResults: max_results, key: YOUTUBE_API_KEY, type: video } try: resp requests.get(url, paramsparams) data resp.json() videos [] for item in data.get(items, []): vid item[id].get(videoId) snippet item[snippet] videos.append({ videoId: vid, title: snippet.get(title), channelTitle: snippet.get(channelTitle), publishedAt: snippet.get(publishedAt), description: snippet.get(description, )[:100] ... # 截断描述 }) return {status: success, videos: videos} except Exception as e: return {status: error, message: str(e)} else: return {status: error, message: f未知工具函数: {func_name}}实操心得三结果格式的“精加工”不要直接把原始API的庞大JSON扔回给模型。一方面这消耗大量Tokens增加成本另一方面无关信息会干扰模型的判断。你应该像上面的示例一样提取出最核心的字段如地点名、地址、评分视频ID、标题、频道组织成一个简洁明了的字典。这能显著提升模型回复的质量和速度。4.3 启动对话一个完整的例子现在让我们启动一次对话。# 开始对话 print(开始与Bard对话已集成工具。输入‘退出’结束。) while True: user_input input(\n[你]: ) if user_input.lower() in [退出, exit, quit]: break chat_with_model(user_input)当你输入“上海外滩附近有什么评价高的餐厅吗再找几个介绍上海美食的YouTube视频。”整个系统会这样工作模型分析你的请求识别出两个独立任务搜索附近餐厅、搜索YouTube视频。它可能首先生成一个工具调用请求给get_places_nearby参数为location: “上海外滩”, place_type: “restaurant”。你的execute_tool函数调用Google Places API返回精简后的餐厅列表。该结果作为“函数响应”被加入历史模型再次被触发。模型看到餐厅搜索结果接着生成第二个工具调用请求给search_youtube_videos参数为query: “上海美食”。再次执行工具获取视频列表。模型最终接收到所有数据组织成一段连贯的回答“在上海外滩附近我找到几家评价不错的餐厅例如XX和YY。此外关于上海美食这里有几个不错的YouTube视频推荐1. 《AAA》... 2. 《BBB》...”。5. 高级技巧与避坑指南掌握了基础流程下面这些经验能让你走得更稳、更远。5.1 处理复杂参数与模型“幻觉”有时模型生成的参数可能不完整或格式不对。例如它可能把location生成“外滩”而不是一个具体的坐标或标准地址字符串。你的execute_tool函数需要具备一定的鲁棒性。解决方案在调用真实API前对参数进行预处理和验证。对于地址可以前置一个地理编码服务如调用一次Google Geocoding API将其转换为坐标。对于数值型参数确保类型正确。def validate_and_preprocess_args(func_name, args): if func_name get_places_nearby: location args.get(location) # 简单判断是否为坐标格式粗略 if , in location and len(location.split(,)) 2: try: lat, lng map(float, location.split(,)) # 坐标基本验证 if -90 lat 90 and -180 lng 180: args[location] f{lat},{lng} else: # 不是有效坐标尝试当作地址处理这里简化实际应调用地理编码 pass except ValueError: # 不是数字当作地址字符串 pass # 如果location是中文地址可能需要处理编码等问题 args[location] requests.utils.quote(location) if % not in location else location return args5.2 控制成本与优化Token使用工具调用会增加交互轮次和上下文长度从而增加Token消耗和API成本。优化策略精简历史对于很长的对话可以考虑只保留最近几轮或与当前工具调用相关的历史而不是全部发送。gemini-1.5系列有超长上下文但合理管理历史仍是好习惯。精简工具响应如前所述务必对API返回数据进行裁剪只保留必要信息。设置超时与重试对真实API的调用可能失败要设置合理的超时和重试机制避免用户长时间等待。使用流式响应对于模型生成的文本部分可以使用流式响应generate_content(..., streamTrue)来提升用户体验感。5.3 扩展其他10种工具Google提到的12种工具可能还包括具体需查阅最新官方文档Google Flights搜索航班信息、价格趋势。Google Hotels搜索酒店、比价。Google Workspace (Gmail, Docs, Drive, Calendar)读写邮件、管理文档、查询日程。这里需要格外注意OAuth 2.0授权和用户数据安全。Google Search执行网页搜索可能通过Search API。自定义工具你甚至可以定义自己的工具比如连接公司内部的数据库查询系统、订单系统等。集成新工具的通用步骤研读官方API文档理解其端点、参数、认证方式API Key或OAuth。设计工具声明用清晰的name和description定义工具设计最小可用参数集。实现执行函数在execute_tool中添加新的分支处理认证、请求构建、错误处理和结果简化。测试与迭代用多样化的提示词测试工具调用是否准确根据结果调整工具描述或参数设计。5.4 安全性考量API密钥管理永远不要在前端代码或公开仓库中暴露API密钥。使用环境变量或安全的密钥管理服务。用户输入净化模型生成的参数在传入你的execute_tool函数前可能包含用户输入的一部分。要对这些参数进行安全检查防止注入攻击虽然风险较低但需有意识。权限最小化特别是对于Workspace这类能操作用户数据的工具遵循OAuth的范围最小化原则只请求应用必需的功能权限。用量限制与监控为你的应用设置API调用频率限制并监控异常调用模式防止滥用。6. 实战场景构建一个智能旅行规划助手让我们把以上所有知识串联起来构想一个更复杂的场景一个智能旅行规划助手。它集成了Flights、Hotels、Maps和YouTube工具。用户输入“帮我规划一个下周末从北京到杭州的旅行。想要周五晚上出发周日回预算5000元以内。找一下性价比高的航班和西湖边的酒店再推荐几个杭州必去的景点和美食视频。”系统工作流模型解析识别出时间、预算、目的地、对航班、酒店、景点、视频的需求。工具调用序列 a. 调用find_flights参数为origin: “北京”, destination: “杭州”, departure_date: “下周五”, return_date: “下周日”, max_price: 5000。 b. 收到航班结果后调用search_hotels参数为location: “杭州西湖”, check_in: “下周五”, check_out: “下周日”, max_price_per_night: 800根据剩余预算估算。 c. 同时或稍后调用get_places_nearby参数为location: “杭州西湖”, place_type: “tourist_attraction”搜索景点。 d. 调用search_youtube_videos参数为query: “杭州美食 攻略”。结果整合模型收到所有结构化数据后生成一份包含航班选项时间、价格、航司、酒店推荐名称、位置、价格、景点列表以及视频链接的个性化旅行建议并以友好的文本格式呈现。在这个流程中模型展现了强大的多步骤规划、信息整合和自然语言生成能力而这背后是你精心设计的工具集成架构在支撑。最后一点体会Bard-API的工具集成其强大之处在于将LLM的通用语言理解与专用工具的精准能力结合。开发者的角色从“对话设计者”转变为“生态构建者”。你提供的工具越可靠、描述越清晰模型就能发挥出越惊人的效用。开始动手吧先从集成一两个工具开始你会立刻感受到这种模式带来的不同。记住关键不是让模型知道一切而是让它知道在需要的时候可以如何调用那些知道一切的专家工具。
Bard-API工具集成实战:让大语言模型调用Google服务执行复杂任务
1. 项目概述当Bard学会“使用工具”如果你和我一样一直在关注大语言模型LLM的进化那么“工具调用”这个能力绝对是近一年来最让人兴奋的突破之一。它让模型从一个“博学的聊天者”变成了一个能真正“动手做事”的智能体。而Google的Bard现已更名为Gemini在这方面走得相当靠前其API开放了与一系列Google自家及第三方服务的深度集成能力这就是我们今天要深入探讨的“Bard-API工具集成”。简单来说这个项目就是教你如何让Bard模型通过API调用去操作像Google Maps、YouTube、Google Flights、Google Hotels等12种强大的工具。这不再是简单的“帮我写一段去纽约的游记”而是变成“基于我下周五从上海出发的预算帮我规划一个为期三天的纽约行程查找并对比直飞航班与酒店标记出时代广场和中央公园附近的餐厅并附上相关YouTube旅行vlog作为参考”。后者才是工具集成带来的质变。对于开发者、产品经理或是任何想构建下一代AI应用的人来说掌握这套工具集成的玩法意味着你能创造出体验远超传统聊天机器人的智能助手。它适合那些已经对API调用有基本了解并希望将AI能力无缝嵌入到具体业务场景中的朋友。接下来我将以一个过来人的身份拆解这套工具集成的核心逻辑、实操细节以及那些官方文档里不会明说的“坑”。2. 核心思路与架构设计为什么是“工具调用”在深入代码之前我们必须先理解Bard-API工具集成的设计哲学。这不仅仅是多几个API端点那么简单它代表了一种范式转变。2.1 从“生成文本”到“执行任务”的范式转变传统的LLM API交互是线性的用户输入Prompt - 模型思考 - 模型输出文本。模型的所有“知识”都凝固在训练时的参数里它无法获取实时信息比如最新股价、航班动态也无法执行具体操作比如在地图上画个圈、发一封邮件。工具调用Tool Calling或函数调用Function Calling机制打破了这堵墙。其核心流程变为用户提出需求包含需要实时数据或具体操作的任务。模型理解与规划模型分析需求判断是否需要以及需要调用哪个工具。模型请求调用模型不会直接执行而是生成一个结构化的“工具调用请求”其中包含调用的函数名和精确的参数。开发者代码执行你的后端代码接收到这个结构化请求去真正调用对应的外部API如Google Maps API。返回结果给模型将API返回的原始数据通常是JSON传回给模型。模型组织与回复模型理解这些数据并将其整合成自然、友好的文本回复给用户。在这个过程中模型扮演的是“大脑”和“指挥官”的角色它负责理解意图、规划步骤、解析结果而你的代码和集成的外部服务则是“手”和“脚”负责执行具体动作。这种分工使得AI应用的能力边界得到了极大的扩展。2.2 Bard-API工具集的设计优势Google为BardGemini设计的这套工具集有以下几个显著特点深度原生集成对于Google系服务Maps, YouTube, Flights, Hotels, Workspace等其工具的参数设计和数据格式与官方API高度对齐甚至做了优化减少了开发者适配的复杂度。统一调用范式无论调用哪个工具在Bard-API的交互中都遵循同一套“工具调用”协议。你只需要在初始化客户端时声明可用的工具列表后续的交互模型会自动处理。多工具协同模型可以在一个对话回合内顺序或并行地规划调用多个工具。例如先调用Google Flights查航班再用Google Hotels查住宿最后用Google Maps计算机场到酒店的距离最终综合所有信息给出建议。安全与可控性工具调用权完全掌握在开发者手中。你可以精确控制哪些工具对模型可见并且能对模型传入的参数进行校验和过滤防止滥用。注意工具调用能力依赖于特定的模型版本。通常gemini-1.5-pro或gemini-1.5-flash等较新版本对工具调用的支持更好、更稳定。在开始前请务必确认你使用的模型支持此功能。3. 环境准备与工具声明搭建你的“工具箱”理论讲完我们开始动手。首先你需要准备好战场。3.1 基础环境配置假设你使用Python核心就是Google的google-generativeai库。pip install google-generativeai接下来获取API密钥。前往 Google AI Studio 创建一个项目并生成API密钥。请妥善保管此密钥不要将其硬编码在客户端代码中推荐使用环境变量。import os import google.generativeai as genai # 配置API密钥 GOOGLE_API_KEY os.environ.get(GOOGLE_API_KEY) genai.configure(api_keyGOOGLE_API_KEY)3.2 工具声明的艺术定义模型的“能力清单”这是最关键的一步。你需要以特定的JSON Schema格式告诉模型它可以使用哪些工具以及每个工具需要什么参数。以下是一个声明了Google Maps和YouTube工具的示例。请注意这里的参数定义需要与你实际计划调用的底层API保持一致。# 定义工具列表 tools [ { function_declarations: [ { name: get_places_nearby, # 工具函数名模型将调用这个名字 description: 根据地理位置和类型搜索附近的兴趣点如餐厅、酒店、加油站。, parameters: { type: OBJECT, properties: { location: { type: STRING, description: 中心点的经纬度坐标格式为纬度,经度或一个明确的地址字符串。 }, radius: { type: NUMBER, description: 搜索半径以米为单位。默认值为1500。 }, place_type: { type: STRING, description: 搜索的地点类型例如restaurant, cafe, hotel, museum, park。 } }, required: [location] } }, { name: search_youtube_videos, description: 在YouTube上搜索视频。, parameters: { type: OBJECT, properties: { query: { type: STRING, description: 搜索关键词。 }, max_results: { type: NUMBER, description: 返回的最大结果数量默认5。 } }, required: [query] } } // ... 可以继续添加其他工具如 get_directions, find_flights, search_hotels 等 ] } ] # 初始化模型并传入工具定义 model genai.GenerativeModel( model_namegemini-1.5-pro, # 使用支持工具调用的模型 toolstools # 将工具列表关联到模型 )实操心得一描述description是灵魂description字段至关重要。模型完全依靠这个描述来理解工具的用途和何时调用它。描述要精确、无歧义。例如get_places_nearby的描述明确指出了它是用来搜“附近的兴趣点”这能帮助模型区分它和另一个可能存在的工具get_place_details获取某个特定地点的详细信息。实操心得二参数设计遵循“最小可用”原则不要一股脑把底层API的所有参数都暴露给模型。只定义完成核心任务所必需的参数。过多的参数会增加模型理解的负担也可能导致它生成错误或复杂的调用。例如Google Maps Places API有几十个参数但我们只暴露了location,radius,place_type这三个最关键的。4. 核心交互流程与代码实现让模型“动”起来有了模型和工具定义接下来就是实现交互循环。我们将构建一个简单的聊天循环并处理模型的工具调用请求。4.1 对话历史管理与模型调用我们需要维护一个对话历史history这对于多轮对话和工具调用上下文至关重要。# 初始化对话历史 history [] def chat_with_model(user_input): global history # 将用户输入加入历史 history.append({role: user, parts: [user_input]}) # 调用模型传入整个历史 response model.generate_content(history) # 处理响应 for candidate in response.candidates: for part in candidate.content.parts: # 1. 检查是否是工具调用请求 if hasattr(part, function_call) and part.function_call: function_call part.function_call func_name function_call.name args dict(function_call.args) # 模型提供的参数 print(f\n[模型请求调用工具] 函数名: {func_name}, 参数: {args}) # 2. 执行对应的工具函数 result execute_tool(func_name, args) # 3. 将工具执行结果作为“函数响应”加入历史让模型继续处理 history.append({ role: function, parts: [genai.protos.Part( function_responsegenai.protos.FunctionResponse( namefunc_name, response{result: result} # 结果需要是字典格式 ) )] }) # 4. 有了新的函数响应需要再次调用模型让它基于结果生成回复 return chat_with_model() # 发送空消息触发模型继续 # 2. 如果是普通文本回复直接输出并加入历史 elif part.text: print(f\n[Bard]: {part.text}) history.append({role: model, parts: [part.text]}) return part.text return 未收到有效响应。4.2 工具执行器连接模型与真实APIexecute_tool函数是你的“工具执行中枢”。这里你需要实现每个声明了的工具函数的具体逻辑通常就是去调用对应的官方API。import requests import json def execute_tool(func_name: str, args: dict): 根据函数名和参数执行具体的工具 if func_name get_places_nearby: # 这里是调用 Google Places API 的示例 # 注意你需要先启用 Google Cloud 的 Places API 并获取一个单独的 API Key GOOGLE_PLACES_API_KEY os.environ.get(GOOGLE_PLACES_API_KEY) location args.get(location, ) radius args.get(radius, 1500) place_type args.get(place_type, ) # 构建API请求 url https://maps.googleapis.com/maps/api/place/nearbysearch/json params { location: location, radius: radius, type: place_type, key: GOOGLE_PLACES_API_KEY } try: resp requests.get(url, paramsparams) data resp.json() # 简化返回只提取核心信息给模型 places [] for place in data.get(results, [])[:5]: # 只取前5个 places.append({ name: place.get(name), vicinity: place.get(vicinity), rating: place.get(rating), types: place.get(types, []) }) return {status: success, places: places} except Exception as e: return {status: error, message: str(e)} elif func_name search_youtube_videos: # 这里是调用 YouTube Data API v3 的示例 # 同样需要先创建项目并启用 API获取 API Key 或 OAuth 2.0 凭证 YOUTUBE_API_KEY os.environ.get(YOUTUBE_API_KEY) query args.get(query, ) max_results args.get(max_results, 5) url https://www.googleapis.com/youtube/v3/search params { part: snippet, q: query, maxResults: max_results, key: YOUTUBE_API_KEY, type: video } try: resp requests.get(url, paramsparams) data resp.json() videos [] for item in data.get(items, []): vid item[id].get(videoId) snippet item[snippet] videos.append({ videoId: vid, title: snippet.get(title), channelTitle: snippet.get(channelTitle), publishedAt: snippet.get(publishedAt), description: snippet.get(description, )[:100] ... # 截断描述 }) return {status: success, videos: videos} except Exception as e: return {status: error, message: str(e)} else: return {status: error, message: f未知工具函数: {func_name}}实操心得三结果格式的“精加工”不要直接把原始API的庞大JSON扔回给模型。一方面这消耗大量Tokens增加成本另一方面无关信息会干扰模型的判断。你应该像上面的示例一样提取出最核心的字段如地点名、地址、评分视频ID、标题、频道组织成一个简洁明了的字典。这能显著提升模型回复的质量和速度。4.3 启动对话一个完整的例子现在让我们启动一次对话。# 开始对话 print(开始与Bard对话已集成工具。输入‘退出’结束。) while True: user_input input(\n[你]: ) if user_input.lower() in [退出, exit, quit]: break chat_with_model(user_input)当你输入“上海外滩附近有什么评价高的餐厅吗再找几个介绍上海美食的YouTube视频。”整个系统会这样工作模型分析你的请求识别出两个独立任务搜索附近餐厅、搜索YouTube视频。它可能首先生成一个工具调用请求给get_places_nearby参数为location: “上海外滩”, place_type: “restaurant”。你的execute_tool函数调用Google Places API返回精简后的餐厅列表。该结果作为“函数响应”被加入历史模型再次被触发。模型看到餐厅搜索结果接着生成第二个工具调用请求给search_youtube_videos参数为query: “上海美食”。再次执行工具获取视频列表。模型最终接收到所有数据组织成一段连贯的回答“在上海外滩附近我找到几家评价不错的餐厅例如XX和YY。此外关于上海美食这里有几个不错的YouTube视频推荐1. 《AAA》... 2. 《BBB》...”。5. 高级技巧与避坑指南掌握了基础流程下面这些经验能让你走得更稳、更远。5.1 处理复杂参数与模型“幻觉”有时模型生成的参数可能不完整或格式不对。例如它可能把location生成“外滩”而不是一个具体的坐标或标准地址字符串。你的execute_tool函数需要具备一定的鲁棒性。解决方案在调用真实API前对参数进行预处理和验证。对于地址可以前置一个地理编码服务如调用一次Google Geocoding API将其转换为坐标。对于数值型参数确保类型正确。def validate_and_preprocess_args(func_name, args): if func_name get_places_nearby: location args.get(location) # 简单判断是否为坐标格式粗略 if , in location and len(location.split(,)) 2: try: lat, lng map(float, location.split(,)) # 坐标基本验证 if -90 lat 90 and -180 lng 180: args[location] f{lat},{lng} else: # 不是有效坐标尝试当作地址处理这里简化实际应调用地理编码 pass except ValueError: # 不是数字当作地址字符串 pass # 如果location是中文地址可能需要处理编码等问题 args[location] requests.utils.quote(location) if % not in location else location return args5.2 控制成本与优化Token使用工具调用会增加交互轮次和上下文长度从而增加Token消耗和API成本。优化策略精简历史对于很长的对话可以考虑只保留最近几轮或与当前工具调用相关的历史而不是全部发送。gemini-1.5系列有超长上下文但合理管理历史仍是好习惯。精简工具响应如前所述务必对API返回数据进行裁剪只保留必要信息。设置超时与重试对真实API的调用可能失败要设置合理的超时和重试机制避免用户长时间等待。使用流式响应对于模型生成的文本部分可以使用流式响应generate_content(..., streamTrue)来提升用户体验感。5.3 扩展其他10种工具Google提到的12种工具可能还包括具体需查阅最新官方文档Google Flights搜索航班信息、价格趋势。Google Hotels搜索酒店、比价。Google Workspace (Gmail, Docs, Drive, Calendar)读写邮件、管理文档、查询日程。这里需要格外注意OAuth 2.0授权和用户数据安全。Google Search执行网页搜索可能通过Search API。自定义工具你甚至可以定义自己的工具比如连接公司内部的数据库查询系统、订单系统等。集成新工具的通用步骤研读官方API文档理解其端点、参数、认证方式API Key或OAuth。设计工具声明用清晰的name和description定义工具设计最小可用参数集。实现执行函数在execute_tool中添加新的分支处理认证、请求构建、错误处理和结果简化。测试与迭代用多样化的提示词测试工具调用是否准确根据结果调整工具描述或参数设计。5.4 安全性考量API密钥管理永远不要在前端代码或公开仓库中暴露API密钥。使用环境变量或安全的密钥管理服务。用户输入净化模型生成的参数在传入你的execute_tool函数前可能包含用户输入的一部分。要对这些参数进行安全检查防止注入攻击虽然风险较低但需有意识。权限最小化特别是对于Workspace这类能操作用户数据的工具遵循OAuth的范围最小化原则只请求应用必需的功能权限。用量限制与监控为你的应用设置API调用频率限制并监控异常调用模式防止滥用。6. 实战场景构建一个智能旅行规划助手让我们把以上所有知识串联起来构想一个更复杂的场景一个智能旅行规划助手。它集成了Flights、Hotels、Maps和YouTube工具。用户输入“帮我规划一个下周末从北京到杭州的旅行。想要周五晚上出发周日回预算5000元以内。找一下性价比高的航班和西湖边的酒店再推荐几个杭州必去的景点和美食视频。”系统工作流模型解析识别出时间、预算、目的地、对航班、酒店、景点、视频的需求。工具调用序列 a. 调用find_flights参数为origin: “北京”, destination: “杭州”, departure_date: “下周五”, return_date: “下周日”, max_price: 5000。 b. 收到航班结果后调用search_hotels参数为location: “杭州西湖”, check_in: “下周五”, check_out: “下周日”, max_price_per_night: 800根据剩余预算估算。 c. 同时或稍后调用get_places_nearby参数为location: “杭州西湖”, place_type: “tourist_attraction”搜索景点。 d. 调用search_youtube_videos参数为query: “杭州美食 攻略”。结果整合模型收到所有结构化数据后生成一份包含航班选项时间、价格、航司、酒店推荐名称、位置、价格、景点列表以及视频链接的个性化旅行建议并以友好的文本格式呈现。在这个流程中模型展现了强大的多步骤规划、信息整合和自然语言生成能力而这背后是你精心设计的工具集成架构在支撑。最后一点体会Bard-API的工具集成其强大之处在于将LLM的通用语言理解与专用工具的精准能力结合。开发者的角色从“对话设计者”转变为“生态构建者”。你提供的工具越可靠、描述越清晰模型就能发挥出越惊人的效用。开始动手吧先从集成一两个工具开始你会立刻感受到这种模式带来的不同。记住关键不是让模型知道一切而是让它知道在需要的时候可以如何调用那些知道一切的专家工具。