AI Agent 的潜能究竟有多大?在之前的文章里,我们一起探讨了 ADK 的架构、认知能力,并亲手构建了一个简单的天气智能体。我们知道,一个强大的 AI Agent,绝不能只是“自说自话”的语言模型,它必须能够与真实世界互动,获取最新信息,执行实际操作。而连接外部世界的桥梁,正是 API!
今天,咱们就来一次 ADK Agent 的“超能力注入”!我们将深入探讨如何将五花八门的第三方 API 集成到你的 ADK Agent 中,让它不再是信息孤岛,而是能触达广阔数字世界的“行动派”。我们将不仅仅停留在基础的 API Key 使用,而是要解锁更高级、更标准、更安全、更高效的集成姿势。读完这篇,你对构建一个真正“无所不能”的多功能助手,绝对会有一个全新的理解!
1. 集成本地外部服务:机遇与挑战并存
想象一下,你的 ADK Agent 需要知道最新的股票价格,需要帮你发送一封邮件,或者帮你查询附近的餐厅。这些功能,AI 模型本身可做不到,必须依赖外部服务提供的 API。
API 集成的好处,显而易见:
- 开发加速器: 站在巨人的肩膀上!不用重复造轮子,直接调用成熟的 API 功能,开发效率飙升。
- 成本效益王: 通常来说,使用现成的 API 比自己从零开始实现一个复杂功能要便宜得多。
- 功能增强剂: 接入专业领域的 API(比如天气、支付、地图),直接让你的 Agent 拥有顶级专业能力。
这些优势直接转化为你的 ADK Agent 的竞争力,让它能更快、更便宜、更强大地服务用户。
然而,别以为集成就是儿戏,坑也不少!
把第三方 API 请进门,就像请了一堆有脾气、有规矩的客人。常见的挑战包括:
- 文档“玩失踪”或“说不清”: 这是老大难问题!API 文档不清晰、不准确、不及时更新,简直是集成路上的拦路虎,直接影响你为 ADK 创建工具的效率和可靠性。
- 数据格式“鸡同鸭讲”: 这家用 JSON,那家用 XML,数据字段名也五花八门。Agent 拿到数据后需要进行复杂的转换和映射,头大!
- 版本升级“说变就变”: API 提供商心情好就升级版本,旧接口可能就废弃了。你的 Agent 集成一夜之间可能就失效了,还得跟着改,累觉不爱。
- 安全漏洞“防不胜防”: 集成外部 API 会引入新的安全风险。如果 API 本身不安全,或者你的集成方式有问题,分分钟可能导致数据泄露或未授权访问。
- 限速限流“卡脖子”: 大部分 API 都有调用频率限制和配额。不注意监控,你的 Agent 可能随时被“请喝茶”,影响用户体验。
- 依赖风险“一荣俱损”: Agent 的功能依赖外部 API,一旦对方服务不稳定或宕机,你的 Agent 也就歇菜了。
- 缺乏标准“各自为政”: 每个 API 的设计风格、错误处理方式、认证机制都可能不同,这种“非标准化”增加了集成的复杂性。
这些挑战不是孤立的,它们常常相互关联。文档不好可能导致认证错误,进而引发安全问题。所以,对待 API 集成,必须得有个全局观。
成功集成的“武林秘籍”:
为了克服这些挑战,你需要修炼一些“内功”:
- 选 API,像相亲一样认真: 集成前,务必彻底研究 API 提供商的可靠性、服务 SLA、安全措施和文档质量。
- 错误处理要“稳准狠”: 设计完善的错误处理机制,捕获 API 错误,详细记录日志,给用户友好的提示,别忘了加个重试逻辑(比如指数退避),必要时还要有备用方案。这对于需要自主运行的 ADK Agent 尤其重要,它不能因为一次 API 调用失败就崩溃。
- 紧盯 API 版本: 订阅提供商的更新通知,尽量使用带版本的 API URL。
- 安全认证是底线: 采用安全的认证方法,妥善保管 API 密钥和令牌!我们后面会详细聊。
- 测试测试再测试: 开发、预生产环境都得充分测试,确保集成按预期工作,各种异常情况都能处理。
- 善用缓存: 不常变动的数据,缓存起来,减少 API 调用,提高性能,还能省钱!
很多 API 集成的“最佳实践”,比如错误处理、重试、客户端限流,其本质都是为了构建一个“有韧性”的 API 消费者。ADK Agent 通常在没有人工监督的情况下运行,所以这种韧性至关重要。ADK 的工具设计和开发指南,都应该强调将这些韧性模式构建进 Agent 的逻辑中。这不仅仅是调用 API,更是管理整个交互生命周期及其潜在故障。
2. OpenAPI 规范与自动化工具:API 集成的“通用语”
在 API 集成这个“巴别塔”中,OpenAPI 规范(OpenAPI Specification, OAS)就像那门统一的“通用语”。对于 ADK 开发者来说,掌握 OpenAPI 是高效、可靠集成第三方 API 的关键。
OpenAPI 规范 (OAS) 是啥?
简单说,OpenAPI 规范就是一套描述 RESTful API 的“蓝图”标准。它用一种大家都能理解(无论是人还是机器)的方式,把 API 的功能、数据格式、请求方法、认证方式等等都给说明白了。
想象一下,你拿到一份详细且标准的 API 蓝图,是不是比对着一份写得乱七八糟的文档或者一点点去“嗅探” API 行为要高效得多?这就是 OpenAPI 的魔力!它能提升清晰度、促进团队协作、还能自动化生成文档和代码!
主要版本和格式:
目前大家用得比较多的是 OpenAPI 3.0.x 版本。文档可以用 JSON 或 YAML 写,YAML 因为更简洁、可读性更好,更受开发者喜爱。
OpenAPI 文档长啥样?
一个标准的 OpenAPI 3.0 文档就像一份 API 的“户口本”,里面包含了各种信息:
字段 (Section) | 描述 | 重要性 |
---|---|---|
| 说明遵循的 OpenAPI 规范版本(比如 3.0.3) | 必须有 |
| API 的基本信息,比如名字 ( | 必须有 |
| API 的访问地址 (Base URL) | 可选 |
| 定义 API 的各个具体接口 (Endpoint) 和支持的 HTTP 方法 (GET, POST 等) | 必须有 |
| 放各种可复用的定义,比如数据模型 ( | 可选 |
| 定义全局或某个特定操作需要的安全认证方式 | 可选 |
| 给 API 操作分组,方便生成文档时分类展示 | 可选 |
| 链接到额外的外部文档(用户指南、更详细参考等) | 可选 |
当你跟 ADK 的 APIHubToolset 打交道,或者需要理解第三方 API 时,这张表能帮你快速定位核心信息。
数据类型与 Schema:
OpenAPI 用 JSON Schema 来描述 API 用的数据类型,从简单的整数、字符串、布尔值,到复杂的数组、对象,应有尽有。还能用 format
属性给类型加上更具体的语意,比如 int32
、date-time
、password
等等。
写好 OpenAPI 文档的“心法”:
高质量的 OpenAPI 文档是成功集成的基石。记住这些心法:
- “设计优先”是王道 (Design-First Approach): 写代码前先写 OpenAPI 规范!这能帮你理清 API 逻辑,团队达成共识。对于 ADK 来说,“设计优先”尤其重要,它直接决定了像 APIHubToolset 这样的工具能生成多好用的 ADK 工具。一个规范写得马虎的 API,生成的 ADK 工具用起来也别扭。
- 规范就是“唯一真理” (Single Source of Truth): 确保你的 OpenAPI 规范跟你实际的 API 行为一致,别出现“文档漂移”!ADK Agent 会完全依赖这个规范来理解和调用 API,如果规范错了,Agent 肯定会出问题。
- 响应和错误,一个都不能少: 清晰完整地记录所有可能的成功响应和错误响应,最好提供示例。
- 持续验证: 用工具(比如 Swagger Editor)检查规范有没有语法错误,最好集成到你的 CI 流程里。
- 起个好名字 (Operation IDs): 给每个 API 操作起一个唯一、有意义的名字,方便在代码和工具里引用。
OpenAPI 工具生态与代码自动生成:
OpenAPI 的强大之处在于,它不仅能描述 API,还能驱动各种自动化工具,效率瞬间爆炸!
OpenAPI 工具都能干啥?
- 自动生成交互式文档: Swagger UI, ReDoc 这样的工具能把你的 OpenAPI 文档变成漂亮的、用户可以直接在上面试 API 的网页。
- 自动生成客户端 SDK 和服务端骨架代码: 这是 OpenAPI 最牛的功能之一!用工具一键生成各种编程语言的客户端库和服务端代码框架,省了多少体力活!
- API 测试与验证: 工具能根据规范生成测试用例,检查你的 API 实现是不是跟规范说的一样。
- 创建模拟服务器 (Mock Servers): 后端 API 还没写好?没关系,根据 OpenAPI 规范快速搭个模拟服务器,前端或依赖方就可以并行开发了。
代码生成工具了解一下:
Swagger Codegen 和 OpenAPI Generator 是这方面的明星工具。它们的核心功能就是“翻译” OpenAPI 文档,生成各种代码。你告诉工具 OpenAPI 文件在哪,想生成哪种语言/框架的代码,它就给你吐出一堆文件。
OpenAPI Generator 是从 Swagger Codegen 分出来的,社区驱动,扩展性更好(支持自定义模板)。知道这些工具,即使 ADK 提供了内置方案,也能帮你理解其原理,或者在 ADK 之外的场景派上用场。这些工具的出现和发展,都说明了减少手动集成工作、提高一致性是业界的强烈需求。ADK 的 APIHubToolset 正是 Google 在自己的生态里满足这个需求的体现。
Google ADK 的 APIHubToolset 与 OpenAPI:
在 Google ADK 里,APIHubToolset 就是那个能把 OpenAPI 规范变成 ADK Agent 可用工具的“魔法师”。它专门用来从 Apigee API Hub(Google 的 API 管理平台)获取 API 的 OpenAPI 规范,然后自动生成 ADK 能理解和调用的工具。
你可以把 APIHubToolset 看作是 ADK 通过 OpenAPI 实现“自动生成工具”的原生路径。它是提升 ADK 开发效率的关键,完全符合业界通过 API 定义自动化客户端接口的最佳实践。生成的工具质量如何,直接取决于输入给 APIHubToolset 的 OpenAPI 规范有多完整、多准确。
3. API 认证与安全处理: Agent 进出的“防盗门”
让 ADK Agent 调用第三方 API 时,确保通信安全就像给 Agent 的进出通道装上“防盗门”。认证 (Authentication) 是验证“来者是谁”,授权 (Authorization) 是确定“来者能干啥”。
主流 API 认证方法“点将台”:
选择哪种认证方式,取决于 API 的敏感度、用途以及 ADK 的支持程度。
- API 密钥 (API Keys): 最简单粗暴的方式,就像一把“万能钥匙”。服务器给你一个字符串密钥,每次请求带上它就行。简单易用,但安全性最低,密钥一旦泄露就麻烦了。ADK 支持这种方式。
- OAuth 2.0: 行业标准!允许第三方应用在不碰用户密码的情况下,代表用户访问其资源。通过授权服务器发令牌 (Access Token),可以精细控制权限 (Scope)。适合需要用户授权的场景。设置稍复杂,但安全性高。ADK 计划支持多种流程。
- OpenID Connect (OIDC): 基于 OAuth 2.0,主要用于用户身份验证。不仅告诉你应用获得了授权,还能告诉你“我是谁”。用 JWT 做身份令牌。
- JWT (JSON Web Tokens): 一种安全传输信息的标准格式。令牌里包含声明信息,可以签名验证。无状态、性能高,常用于微服务和 API 认证,通常作为持有者令牌 (Bearer Token) 使用。
- 持有者认证 (Bearer Auth): 现代 Web API 常用。请求头里带个 "Bearer [令牌]" 就行,服务器验证令牌有效性。JWT 是实现 Bearer 令牌的常见方式。ADK 支持使用令牌的方式。
- 基本认证 (Basic Auth): HTTP 标准,请求头里用 Base64 编码的“用户名:密码”。设置超级简单,但安全性极低(HTTP 下明文传输),只适合低安全需求的内部或测试环境,不推荐。
- mTLS (双向 TLS): 基于证书的双向认证,客户端和服务器互相验证身份。安全性极高,适用于金融医疗等超高安全要求的场景。证书管理复杂。
ADK 开发者会遇到各种认证需求的 API,理解这些方法能帮你找到合适的集成方案。ADK 目前支持 API Key 和基于 Token 的方式,并且在积极向 OAuth 2.0 等更安全复杂的方向发展。这也说明 ADK 认识到,如果高安全选项太难用,开发者可能会退而求其次。
API 安全,“十八般武艺”都要会:
选对了认证方法只是第一步,整体安全还得靠多方面配合:
- 数据加密,HTTPS 必须有: 确保你的 Agent 和第三方 API 之间的通信全程加密,防止数据被偷看或篡改。
- 输入验证与清理: 别信任何来自 API 的数据!在 Agent 里使用前,严格验证和清理,防注入攻击!发给 API 的数据也一样。
- 错误处理与日志,安全线索别放过: 集中处理错误,详细记录安全相关事件(认证失败、授权拒绝)和 API 交互细节,方便监控和审计。
- 限速与节流,“软硬兼施”:
- Agent 自己要聪明: 遇到 API 返回 429 状态码(太多请求)时,别死磕!实现指数退避重试,或者熔断机制,等会儿再试。
- 遵守规矩: 仔细看 API 提供商的限速和配额文档,合理规划你的调用量。
- 最小权限原则: 给 Agent 或它的 API 密钥/令牌最少的必要权限,能读就不给写,能查就不给删,避免“权力过大”。
- 安全凭证管理,“藏好你的宝贝”:
- 绝对禁止硬编码! API 密钥、密码这些敏感信息,千万不能写死在代码或配置文件里。用环境变量、密钥管理服务(比如 Vault),或者 ADK 提供的安全存储机制。
- 定期轮换: 特别是长期有效的 API 密钥,得时不时换一下。
- 定期安全体检:
- 给你的 Agent 集成点做安全审计。
- 用漏洞扫描工具和渗透测试。
- 监控 API 流量,看看有没有异常。
有效的 API 安全是 ADK Agent 和 API 提供商的共同责任。提供商负责服务端安全,但 ADK 开发者必须做好客户端安全,包括凭证管理、安全通信、数据验证,以及优雅处理安全错误(比如 401/403)。如果 Agent 自己在这些方面出了问题,反而可能成为安全隐患。
在 ADK 中,当你配置工具时,特别是使用 APIHubToolset,会涉及到认证参数的配置。ADK 提供了一些辅助函数来帮你处理基于令牌的认证。它也支持使用服务账户,这在生产环境是推荐的方案。ADK 文档里也专门提到构建安全可靠的代理,这和我们讨论的 API 安全原则是一致的。
4. Google ADK MCP 工具集成实践:LLM 与外部世界的“通用适配器”
模型上下文协议(Model Context Protocol, MCP)是 Google ADK 里一个相当酷的创新。你可以把它想象成一个标准化的“适配器”,让 LLM 和它驱动的 AI Agent(比如 ADK Agent)能用一种统一的方式跟各种外部应用、数据甚至工具对话。
理解模型上下文协议 (MCP):
MCP 的核心目标是让 LLM 更容易获取外部信息(资源)、理解如何与用户交互(模板),以及调用真实世界的功能(工具)。它是一种客户端-服务器模式:MCP 服务器暴露能力,MCP 客户端(比如 ADK Agent)消费能力。
ADK 对 MCP 的原生支持是它的亮点之一。这意味着任何符合 MCP 标准的服务器,都可以像“即插即用”一样,将其提供的能力直接注入到 ADK Agent 中,极大地扩展了 Agent 的能力边界。
MCP 代表了一种重要的架构思路:将 Agent 的核心逻辑与具体的工具实现分离开。Agent 只需知道工具的 MCP 接口,而不用关心工具内部是怎么工作的。这比把所有工具逻辑写死在 Agent 里,或者为每个 API 写定制代码要灵活、可维护得多。比如,一个负责复杂数据分析的 MCP 服务器,可以被多个不同的 ADK Agent 复用。
ADK 中 MCPToolset 的角色:
在 ADK 里,MCPToolset
类就是那个连接 MCP 服务器的“桥梁”:
- 连接 (Connect): 帮你连上 MCP 服务器进程。可以是本地的(通过标准输入输出),也可以是远程的(通过 Server-Sent Events)。
- 发现 (Discover): 问问 MCP 服务器:“大佬,你都有哪些工具啊?”(通过
list_tools
MCP 方法)。
- 适配 (Adapt): 把从服务器拿到的工具描述(schema)转换成 ADK 能用的
BaseTool
实例。
- 暴露 (Expose): 把这些转换好的工具交给 ADK 的
LlmAgent
,让 Agent 知道“我现在能干这些事了”。
- 代理调用 (Proxy Calls): 当 Agent 决定用某个 MCP 工具时,
MCPToolset
会把这个调用请求转发给 MCP 服务器(通过call_tool
MCP 方法),然后把结果拿回来给 Agent。
- 管理连接 (Manage Connection): 负责连接的生命周期,用完记得“断开连接”。
MCP 集成“实战”概念:
ADK 文档里通常展示的是 ADK Agent 作为客户端去消费 MCP 服务器提供的工具。这里举几个概念性的例子:
- 例子 1: 文件系统 MCP 服务器
- 场景: 有个 MCP 服务器能操作文件,比如读、写、列目录。
- ADK 集成: 用
MCPToolset
连接到这个本地服务器进程。把生成的工具加到 Agent 的工具列表里。
- 效果: Agent 现在能通过 LLM 的决策,调用文件系统工具来处理文件了。
- 例子 2: 谷歌地图 MCP 服务器
- 场景: 有个 MCP 服务器把谷歌地图的功能(地理编码、路线规划)封装成了 MCP 工具。
- ADK 集成: 用
MCPToolset
连接到这个服务器(可能是远程的)。API 密钥等凭证根据服务器的要求传递。
- 效果: Agent 可以帮你规划旅行路线,或者回答“从我这到公司怎么走”这种问题。
- 例子 3: 第三方提供的 MCP 服务器(比如爬虫服务)
- 场景: 某个数据服务商提供了一个 MCP 服务器,能帮你抓取网页、搜索信息。
- ADK 集成: 连接到这个服务器,Agent 就可以利用它的爬虫工具来获取实时网络数据了。
这些例子说明,MCP 通过标准化的接口,让 ADK Agent 能非常方便地接入各种预构建的外部能力。虽然目前 ADK 中使用 MCP 的接口还在完善中,但它的潜力和重要性不言而喻。成功的 MCP 生态需要大家一起努力,不仅要消费 MCP 工具,也要能方便地创建和暴露 MCP 工具。
5. 实战演练:搭建你的智能体工具助手
理论讲了不少,是时候来点实际的!咱们构思一个“智能体工具助手”,看看如何把前面学到的知识串起来,让它同时搞定天气、新闻和空气质量等查询。这次我们模型采用qwen的模型替代gemini模型。
助手的目标与功能:
- 能理解用户复杂的请求:“告诉我杭州的天气,今天的头条新闻等”
- 能分别调用不同的 API 获取天气、新闻、空气质量等。
- 整合这些信息,然后以用户友好的方式反馈。
识别需要的外部服务:
- 天气查询 API: 通过传入城市调用相关城市的天气
- MCP服务: 集成聚合的MCP服务,开通的MCP服务有天气查询,新闻查询,空气质量查询。
实现认证与安全:
- 凭证管理是重中之重! MCP服务的token和天气 API 的 Key,都不能硬编码。利用安全的环境变量或 ADK 提供的安全机制。
开发 Agent 核心逻辑:
- 写好 Agent 的指令 (Prompt): 教会 Agent 如何理解用户复杂的请求,并将其拆分成“查询天气”、“查询空气质量”、“看新闻”这几个子任务。
- Agent 做决策: Agent 需要根据用户请求,决定先调哪个工具,后调哪个,以及给工具传递什么参数。
- 处理 API 响应: 每个工具调用 API 后,会将结果返回给 Agent。Agent 需要解析这些结果,提取关键信息。
构建这样一个多功能助手,需要的不仅仅是调用 API,更考验 ADK Agent 如何编排这些不同的、可能来自异构平台的外部服务。这凸显了 ADK 灵活的工具架构以及 Agent 内部强大的错误处理和状态管理能力。为每个服务选择合适的集成策略(自定义工具、APIHubToolset、MCPToolset),是 ADK 开发者需要做出的重要架构决策。这个助手实例,恰好能展示 ADK 在整合不同能力时的多面性和适应性。
具体代码如下:
__init__.py文件
#__init__.py
from . import agent
智能体 agent.py文件
import os
import datetime
from dotenv import load_dotenv
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm
from google.adk.tools import BaseTool, ToolContext, FunctionTool
from contextlib import AsyncExitStack
from google.adk.agents.llm_agent import LlmAgent
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, SseServerParams
# 本地天气API导入
try:
from .weather_api import get_weather_info
except ImportError:
# 当作独立脚本运行时
from weather_api import get_weather_info
# 转换为ADK工具格式
local_weather = FunctionTool(get_weather_info)
# 加载环境变量
load_dotenv()
# 聚合MCP服务Token
DEFAULT_JUHE_MCP_TOKEN = "vu6DADEa78hTp7YehbUidycIOWxk2VKH9ZvfBHLaJ9UHzW"
JUHE_MCP_TOKEN = os.environ.get("JUHE_MCP_TOKEN", DEFAULT_JUHE_MCP_TOKEN)
JUHE_MCP_SSE_URL = f"https://mcp.juhe.cn/sse?token={JUHE_MCP_TOKEN}"
# API密钥设置
DEFAULT_DASHSCOPE_API_KEY = "sk-f227634bb5614dd8b4eb29a95f38d77c" # 请替换为您的实际密钥
DASHSCOPE_API_KEY = os.environ.get("DASHSCOPE_API_KEY", DEFAULT_DASHSCOPE_API_KEY)
async def create_agent():
"""从 MCP 服务器获取工具。"""
common_exit_stack = AsyncExitStack()
# 移除本地MCP工具,只使用远程MCP工具
remote_tools, _ = await MCPToolset.from_server(
connection_params=SseServerParams(
# 重要提示!确保这是你的远程 MCP 服务器路径
url=JUHE_MCP_SSE_URL
),
async_exit_stack=common_exit_stack
)
agent = LlmAgent(
model=LiteLlm(
model="openai/qwen-turbo",
api_key=DASHSCOPE_API_KEY,
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1"
),
name='enterprise_assistant',
instruction=(
"""
你是一个功能强大的智能助手,集成了多种工具来提供天气、新闻和空气质量信息。
可用工具:
1. local_weather - 通过本地API查询指定城市的天气信息,参数: {"city": "城市名称"}
2. mcp_weather - 通过MCP服务查询指定城市的天气信息,参数: {"city": "城市名称"}
3. mcp_news_list - 通过MCP服务获取指定类型的新闻列表,参数: {"type": "新闻类型", "page": 页码, "page_size": 每页新闻数量}
新闻类型可选值: top(头条), guonei(国内), guoji(国际), yule(娱乐), tiyu(体育), junshi(军事), keji(科技), caijing(财经), youxi(游戏), qiche(汽车), jiankang(健康)
4. mcp_news_content - 通过MCP服务获取指定ID的新闻详细内容,参数: {"uniquekey": "新闻ID"}
5. mcp_air_quality - 通过MCP服务查询指定城市的空气质量信息,参数: {"city": "城市名称"}
使用指南:
1. 当用户询问天气时:
- 优先使用mcp_weather工具,如果失败则使用local_weather工具
- 参数格式: {"city": "城市名称"},例如 {"city": "北京"}
2. 当用户询问新闻时:
- 先使用mcp_news_list工具获取新闻列表
- 参数格式: {"type": "新闻类型", "page": 页码, "page_size": 每页新闻数量}
- 新闻类型默认为"top"(头条),也可以是"guonei"(国内)、"guoji"(国际)等
- 如果用户想了解某条新闻的详情,使用mcp_news_content工具
- 参数格式: {"uniquekey": "新闻ID"}
3. 当用户询问空气质量时:
- 使用mcp_air_quality工具
- 参数格式: {"city": "城市名称"}
其他注意事项:
- (1) 如果MCP工具调用失败,尝试使用本地工具
- (2) 对用户请求进行准确理解,提取关键信息(如城市名、新闻类型等)
- (3) 提供友好、简洁的回答
- (4) 如遇工具调用错误,向用户解释并提供替代方案
- (5) 不要编造不存在的工具功能
"""
),
tools=[
*remote_tools,
local_weather
],
)
return agent, common_exit_stack
root_agent = create_agent()
API接口文件 weather_api.py
"""
聚合数据实时天气API实现
此模块提供了基于聚合数据的实时天气API接口,用于获取城市天气信息。
"""
import os
import json
import logging
import urllib
import urllib.request as request
import urllib.error as error
from typing import Dict, Any, Optional
from datetime import datetime
from tenacity import retry, stop_after_attempt, wait_exponential
# 设置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("weather_api")
# 从环境变量获取API密钥
#JUHE_WEATHER_API_KEY = os.environ.get("JUHE_WEATHER_API_KEY", "YOUR_API_KEY")
JUHE_WEATHER_API_KEY = "22cfd0c972687aa236d3d8ca148c0232"
class WeatherApiError(Exception):
"""天气API错误的自定义异常"""
pass
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10),
reraise=True
)
def fetch_real_weather_data(city: str, date: Optional[str] = None) -> Dict[str, Any]:
"""
使用聚合数据API获取指定城市的实时天气数据。
参数:
city: 要获取天气的城市名称
date: YYYY-MM-DD格式的日期(当前版本仅支持实时天气,忽略日期参数)
返回:
包含天气信息的字典
异常:
WeatherApiError: 如果API请求失败
"""
logger.info(f"正在获取{city}的实时天气数据")
# 构建API URL和参数
api_url = 'http://apis.juhe.cn/simpleWeather/query'
params_dict = {
"city": city,
"key": JUHE_WEATHER_API_KEY,
}
params = urllib.parse.urlencode(params_dict)
try:
# 发送API请求
req = request.Request(api_url, params.encode())
response = request.urlopen(req)
content = response.read()
if not content:
raise WeatherApiError("API请求返回空内容")
# 解析JSON响应
result = json.loads(content)
error_code = result.get('error_code')
# 检查API返回的错误码
if error_code != 0:
error_reason = result.get('reason', '未知错误')
raise WeatherApiError(f"天气API错误: {error_code}, 原因: {error_reason}")
# 提取并格式化天气数据
realtime_data = result['result']['realtime']
future_data = result['result'].get('future', [])
# 准备返回数据结构
weather_data = {
"location": {
"name": city,
"country": "中国"
},
"realtime": {
"temperature": realtime_data['temperature'],
"humidity": realtime_data['humidity'],
"info": realtime_data['info'],
"wid": realtime_data['wid'],
"direct": realtime_data['direct'],
"power": realtime_data['power'],
"aqi": realtime_data['aqi']
},
"forecast": []
}
# 如果有预报数据,添加到返回结果中
if future_data:
for day_data in future_data:
weather_data["forecast"].append({
"date": day_data['date'],
"temperature": day_data['temperature'],
"weather": day_data['weather'],
"wind_direction": day_data['direct']
})
logger.info(f"成功获取{city}的天气数据")
return weather_data
except error.HTTPError as e:
logger.error(f"天气API HTTP错误: {str(e)}")
raise WeatherApiError(f"HTTP请求失败: {str(e)}")
except error.URLError as e:
logger.error(f"天气API URL错误: {str(e)}")
raise WeatherApiError(f"URL请求失败: {str(e)}")
except json.JSONDecodeError as e:
logger.error(f"JSON解析错误: {str(e)}")
raise WeatherApiError(f"无法解析API响应: {str(e)}")
except Exception as e:
logger.error(f"获取天气数据时发生意外错误: {str(e)}")
raise WeatherApiError(f"处理天气数据时出错: {str(e)}")
def get_weather_info(city: str, date: Optional[str] = None) -> str:
"""
获取天气信息并格式化为用户友好的字符串。
参数:
city: 要获取天气的城市
date: 要获取天气的日期 (YYYY-MM-DD)
返回:
格式化的天气信息字符串
"""
try:
# 使用真实API获取数据
weather_data = fetch_real_weather_data(city, date)
# 格式化实时天气数据
realtime = weather_data["realtime"]
location = weather_data["location"]["name"]
result = (
f"{location} 实时天气:\n"
f"- 天气状况: {realtime['info']}\n"
f"- 温度: {realtime['temperature']}°C\n"
f"- 湿度: {realtime['humidity']}%\n"
f"- 风向: {realtime['direct']}\n"
f"- 风力: {realtime['power']}\n"
f"- 空气质量: {realtime['aqi']}"
)
# 如果有预报数据,添加到结果中
if weather_data.get("forecast") and len(weather_data["forecast"]) > 0:
future_date = weather_data["forecast"][0]
result += f"\n\n未来天气预报 ({future_date['date']}):\n"
result += f"- 温度: {future_date['temperature']}\n"
result += f"- 天气: {future_date['weather']}\n"
result += f"- 风向: {future_date['wind_direction']}"
return result
except WeatherApiError as e:
return f"错误: {str(e)}"
except Exception as e:
logger.error(f"天气工具发生意外错误: {str(e)}")
return f"抱歉,获取天气信息时发生意外问题: {str(e)}"
if __name__ == "__main__":
# 简单测试
test_city = "北京"
print(f"测试获取{test_city}的天气信息:")
print(get_weather_info(test_city))
# .env
# 不同LLM提供商的API密钥
# 将此文件重命名为.env并根据需要添加你的密钥
JUHE_WEATHER_API_KEY = "**********************"
QWEN_API_KEY = "sk-**********************"
JUHE_WEATHER_API_KEY = "********"
让我们来进行测试一下效果如何:
查询天气
查询新闻
查询新闻内容
说明:MCP服务器采用的是聚合平台的服务。
天聚地合 - 聚合数据_API接口开放平台_API接口大全_免费API数据接口服务
6. 总结与未来展望
好了,咱们今天给 ADK Agent 来了次彻底的“能力升级”!从第三方 API 集成的基本原理、挑战和最佳实践,到 OpenAPI 这个“通用语”的应用,再到各种 API 认证和安全处理技巧,最后聊了聊 ADK 的“特有武器”——MCP 工具集,并通过一个工具助手实例,将这些知识串联起来。
核心收获:
- 想让 ADK Agent 强大?必须学会集成第三方 API!好处多多,但坑也不少,得小心应对。
- OpenAPI 是 API 集成的“灯塔”,照亮了自动化文档和工具生成之路。写好规范,事半功倍!ADK 的 APIHubToolset 正是基于此的神器。
- API 安全是生命线!选择恰当的认证方式,严格遵守安全实践,保护你的 Agent 和用户的数据。ADK 也在不断加强对各种认证机制的支持。
- MCP 是 ADK 连接外部服务的“秘密武器”,它提供标准化的交互方式,让 Agent 能更灵活、更可插拔地使用外部工具。MCPToolset 是连接 MCP 服务器的关键。
- 构建复杂的多功能 Agent,需要你根据不同服务选择最合适的 ADK 集成策略,并精心设计 Agent 的逻辑、错误处理和韧性。
展望 AI Agent 与 API 集成的未来:
AI Agent 与外部世界的交互只会越来越紧密,API 集成技术也会持续进化。未来我们可能会看到:
- 工具接口更加标准化: 像 MCP 这样的协议可能会更普及,让 Agent 集成各种服务时更轻松。
- AI 驱动的 API 发现与集成: 未来,Agent 可能自己就能根据任务需求,动态地发现合适的 API,理解它们的规范,甚至自动完成部分集成配置。
- 安全协议与实践更上一层楼: Agent 处理的数据和操作会越来越敏感,针对 Agent 场景的特定安全标准和工具会越来越多。
- API 市场大繁荣: 像 Apigee API Hub 这样的 API 市场会成为 Agent 获取能力的宝库。
- ADK 持续迭代进化: Google ADK 作为 Agent 开发利器,肯定会继续简化 API 集成流程,增强安全性,并可能加入更多 AI 辅助的集成功能。
LLM 的推理能力、OpenAPI/MCP 这样的标准化协议、以及 ADK 这样的开发框架,这三者的融合,正把我们带向一个令人兴奋的未来:AI Agent 能够越来越自主、越来越智能地发现、集成和编排海量的外部服务。虽然现在很多集成工作还需要我们开发者亲自动手,但这无疑是走向那个动态未来的关键一步。ADK 在这场浪潮中,必将扮演越来越重要的角色。