与你的 Elasticsearch 数据对话:使用 Google ADK 和 MCP 构建一个实时语音 agent ,分为 3 个组件
作者来自 Elastic Jeffrey Rengifo通过 Agent Builder 内置的 MCP server把 Google ADK 的实时语音流直接连接到你的 Elasticsearch 数据无需自定义集成代码。Agent Builder 现在 GA 可用。通过 Elastic Cloud Trial 开始并查看 Agent Builder 的文档 这里 。任何支持 MCP 的 agent Google ADK 、 Claude Desktop 、 LangChain 都可以在不编写自定义集成代码的情况下查询你的 Elasticsearch 数据。Agent Builder 开箱即用提供托管 MCP server。在这个教程中我们使用 Google ADK 和 Gemini LiveAPI 构建一个实时语音助手通过语义搜索 semantic search 查询一个 recipe 知识库。连接 Elasticsearch 只需要大约 30 行 Python 代码。前置条件Elasticsearch 9 或更高版本Google AI API key可以使用免费试用Python 3.10 或更高版本这个 Elasticsearch 语音助手如何工作想象一个繁忙的厨房正在进行晚餐高峰时段。厨师因为双手沾满食物无法操作屏幕但仍然需要快速获取餐厅数据的答案“这道烩饭含有贝类吗” 或者 “今晚的畅销菜是什么”我们将构建一个语音助手通过 Agent Builder 直接与 Elasticsearch 对话来回答这些问题。架构非常简单直接这个语音 agent基于 Google ADK 构建会监听你的语音并通过 MCP 将查询转发给 Agent Builder。随后Agent Builder 会在你的 Elasticsearch 数据中进行搜索并把结果返回给语音 agent再由语音 agent 朗读给你。本文使用的 Elastic 相关代码库可以在该文章的专用仓库中找到 这里。为语义搜索设置 Elasticsearch 索引这个知识库使用一个 Elasticsearch 索引来存储菜谱数据包括食材、过敏原和制作步骤从而支持语义搜索 semantic search 查询例如“无乳制品的菜肴”。数据模型我们将使用一个索引存储专有菜谱信息包括食材、过敏原和制作步骤。这使得语义搜索成为可能例如 “无乳制品的菜肴” 或 “如何制作招牌油醋汁”。示例数据数据集如下所示可以在 GitHub 仓库中的 dataset.json 中找到。[ { name: Mushroom Risotto, ingredients: [arborio rice, mushrooms, parmesan, butter, white wine, vegetable stock, shallots, garlic], allergens: [dairy], procedure: Toast rice in butter. Add wine and reduce. Gradually add warm stock while stirring. Fold in sautéed mushrooms and finish with parmesan., prep_time_minutes: 35, category: main, dietary: [vegetarian] }, { name: Seafood Risotto, ingredients: [arborio rice, shrimp, mussels, calamari, white wine, fish stock, garlic, parsley, butter], allergens: [shellfish, dairy], procedure: Toast rice in butter with garlic. Add wine and reduce. Gradually add warm fish stock. Add seafood in final minutes. Finish with parsley., prep_time_minutes: 40, category: main, dietary: [] }, { name: House Vinaigrette, ingredients: [olive oil, red wine vinegar, dijon mustard, honey, garlic, salt, pepper], allergens: [], procedure: Whisk mustard, vinegar, honey, and minced garlic. Slowly stream in olive oil while whisking. Season with salt and pepper., prep_time_minutes: 5, category: sauce, dietary: [vegan, gluten-free] }, ... ]创建 indices、inference endpoint 和加载数据要在 Elasticsearch 中创建 indices 并导入数据你可以运行本文准备好的 notebook地址在 这里。在 Serverless 环境中在 Elasticsearch 里创建具有相应权限的 API key 已经成为必需操作。POST /_security/api_key { name: google-adk-api-key, expiration: 30d, role_descriptors: { mcp-access: { cluster: [ all ], indices: [ { names: [ * ], privileges: [ all ], allow_restricted_indices: false } ], applications: [ { application: kibana-.kibana, privileges: [ feature_agentBuilder.all, feature_actions.read, feature_inference.all, feature_advancedSettings.read ], resources: [ space:default ] } ], run_as: [], metadata: {}, transient_metadata: { enabled: true } } } }为了实现语义搜索能力我们将使用 jina-embeddings-v5-text-small这是一个高质量的检索 retrieval 模型。INFERENCE_ID jina-embeddings# Create inference endpoint with Jina embeddings v5 inference_config { service: elastic, service_settings: {model_id: jina-embeddings-v5-text-small}, } es_client.inference.put( task_typetext_embedding, inference_idINFERENCE_ID, bodyinference_config ) print(f✅ Inference endpoint {INFERENCE_ID} created successfully)现在我们需要创建 index mappings 包括包含 dataset 中相关数据的 fields 。我想强调 semantic_field 这个 field 将用于使用之前创建的 jina-embeddings inference endpoint 进行 semantic search 。这个 field 将包含所有使用 copy_to property 的 fields 的内容。INDEX_NAME knowledgees_client.indices.exists(indexINDEX_NAME) knowledge_mapping { properties: { name: {type: text, copy_to: semantic_field}, ingredients: {type: text, copy_to: semantic_field}, allergens: {type: keyword, copy_to: semantic_field}, procedure: {type: text, copy_to: semantic_field}, prep_time_minutes: {type: integer}, category: {type: keyword, copy_to: semantic_field}, dietary: {type: keyword, copy_to: semantic_field}, semantic_field: { type: semantic_text, inference_id: INFERENCE_ID, }, } }最后我们使用 bulk API 来导入数据。def build_bulk_actions(documents, index_name): for doc in documents: yield {_index: index_name, _source: doc} with open(dataset/knowledge.json, r) as f: docs json.load(f) success, failed helpers.bulk( es_client, build_bulk_actions(docs, INDEX_NAME), refreshTrue, ) print(f{success} documents indexed successfully)使用 Agent Builder 创建 Elasticsearch 搜索工具我们将通过 API 以编程方式创建 tools 。这种方式可以让我们精确控制 tool 的配置并且使整个 setup 可重复执行。启用 Agent Builder对于 Elasticsearch 集群非 serverless在使用 Agent Builder 创建 tools 之前必须先启用它。请参考 Agent Builder setup guide 启用 Agent Builder 来在你的 deployment 中启用。对于 serverless 部署Agent Builder 默认已启用无需额外配置。注意你的 Elasticsearch API key 必须包含 feature_agentBuilder.read 权限才能访问 Agent Builder。完整配置请参考 API key application privileges 文档 API key application privileges。创建 recipe search tool如前所述我们将通过 API 创建 Agent Builder tools 代码如下recipe_search_tool { id: recipe_semantic_search, type: index_search, description: Search kitchen recipes including ingredients, allergens, dietary restrictions, preparation procedures, and cooking times. Uses semantic search to find relevant recipes even without exact keyword matches., tags: [semantic], configuration: { pattern: INDEX_NAME, }, } response requests.post( f{KIBANA_ENDPOINT}/api/agent_builder/tools, headersKIBANA_HEADERS, jsonrecipe_search_tool, )我们正在创建一个单一的 semantic search tool 用于查询 cooking-recipes index 。这个 tool 负责处理关于菜谱、食材、过敏原、饮食限制以及烹饪流程的自然语言问题。semantic tag 用于让这个 tool 能够执行 semantic search 。需要注意 description field 的内容因为它会引导 agent 在合适的时机选择这个 tool。在 Agent Builder 中设置 Gemini 为默认模型默认情况下Agent Builder 使用 Anthropic Claude Sonnet 作为 AI connector。由于本教程使用 Gemini你需要打开 Agent Builder menu点击 GenAI Settings 并选择 Google Gemini 2.5 Flash 作为 Default AI Connector 。然后在 chat interface 中也要确保在 model dropdown 中选择相同的模型。监控 token 使用情况Agent Builder 集成了一个 Kibana 仪表板用于跟踪 prompt tokens、completion tokens 以及总请求数并按功能和模型进行细分。这可以让你清楚了解不同对话中的资源消耗情况。有关配置方法请参阅使用情况监控文档usage monitoring documentation。通过 Agent Builder MCP 将 Google ADK 连接到 ElasticsearchGoogle ADK 通过 MCP 使用三个组件连接到 Agent BuilderAgent、McpToolset 和 StdioConnectionParams。整个连接过程只需要大约 30 行 Python 代码。要配置环境以使用 ADK Streaming从而启用语音和视频通信请参考本教程。完成应用程序 setup 后你可以将 agent.py 文件的内容替换为下面的代码片段import os from dotenv import load_dotenv from google.adk.agents import Agent from google.adk.tools.mcp_tool import McpToolset from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams from mcp.client.stdio import StdioServerParameters load_dotenv() KIBANA_ENDPOINT os.getenv(KIBANA_ENDPOINT) ELASTIC_API_KEY os.getenv(ES_API_KEY) # Elastic Agent Builder MCP connection AUTH_HEADER fApiKey {ELASTIC_API_KEY} root_agent Agent( modelgemini-2.5-flash-native-audio-latest, namekitchen_assistant_agent, instructionYou are a kitchen assistant that helps chefs during busy dinner service. You can answer questions about recipes. Use the Elasticsearch tools to search the cooking-recipes index and provide quick answers like: - Does a dish contain specific allergens (e.g., shellfish)? - Recipes that can be prepared with given ingredients - I would like to prepare a seafood dish - Find recipes by category or dietary restrictions Always be concise and practical - chefs need quick answers!, tools[ McpToolset( connection_paramsStdioConnectionParams( server_paramsStdioServerParameters( commandnpx, args[ -y, # Auto-confirm install mcp-remote, f{KIBANA_ENDPOINT}/api/agent_builder/mcp, --header, fAuthorization:{AUTH_HEADER}, ], ), timeout30, session_read_timeout_seconds120, ), tool_filter[recipe_semantic_search], ) ], )它使用了三个关键的 ADK 组件Agent定义语音助手包括其模型、指令以及可用的 tools。McpToolset充当一个 MCP client使 agent 能够连接到任何 MCP server并使用其提供的 tools。StdioConnectionParams通过启动一个本地进程 mcp-remote 来建立与 Agent Builder MCP endpoint 的连接从而桥接通信。连接一个 ADK agent 到 Agent Builder 所需的全部代码就是这些。这个开箱即用的解决方案已经实现了 Live API并提供了一个 UI使我们能够与 agent 进行交互。接下来让我们看看建立与 Agent Builder 连接时涉及的几个关键部分。模型选择我们使用 gemini-2.5-flash-native-audio-latest这是一个针对通过 Live API 进行实时语音对话而优化的 Gemini 模型。它支持原生音频输入和输出使助手能够直接听和说而无需经过中间的 text-to-speech 转换。注意在撰写本文时文档中记录的 model ID 是 gemini-2.5-flash-native-audio-preview-12-2025。本教程使用 latest 别名这样当 Google 推出更新版本时代码仍然可以继续工作。如果你需要固定到某个特定版本可以调用 models API 来列出所有可用的 model ID。McpToolset 接口McpToolset 是一个 ADK 接口它充当 MCP client将 agent 连接到任意 MCP server本例中为 Agent Builder MCP endpoint。如果你想进一步了解 Agent Builder 面向 MCP clients 的 MCP 配置可以参考相关文档。这里我们使用 tool_filter 参数来指定 agent 应该使用哪个特定的 tool。使用 tool filters 可以减少不必要的 tool 发现从而提升 agent 使用 tools 时的响应速度。运行应用程序确保你的 .env 文件已经配置完成。安装依赖pip install google-adk google-genai python-dotenv pyaudio使用 Web 界面运行adk web --port 8000注意第一次调用 Live API 时响应可能需要约 30 秒并且 ADK Web 界面在处理过程中不会显示正在进行中的提示。另外你也可以直接在终端中使用 adk run以文本模式测试 agent。运行 Web 界面后你将看到如下界面在左侧菜单中你可以选择已创建的 agent选中之后你就可以开始和它聊天了。Elasticsearch 语音助手可以回答什么下面是你的语音助手可以处理的问题类型食谱查询语义搜索You sayResponseDoes the seafood risotto have shellfish?Seafood Risotto includes shellfish and shrimp.How do I make the house vinaigrette?To make the house vinaigrette, whisk mustard, red wine vinegar, honey, and minced garlic. Slowly stream in olive oil while whisking. Season with salt and pepper.What can I make for a vegan guest?You could make a Vegan Buddha Bowl or Fruit Sorbet. The House Vinaigrette is also vegan.Any nut-free desserts?Here are some nut-free dessert options: Chocolate Lava Cake, Fruit Sorbet, and Panna Cotta.视频演示https://www.bilibili.com/video/BV1mkTL65Eta/Events 视图Web interface 允许你对 agent 执行的 operations 进行 debug。在左侧菜单中你可以找到 Events view其中可以查看 event calls 的详细信息。在函数调用中你可以在 Elasticsearch 中找到已执行的查询以及在函数响应中通过语义搜索检索到的命中结果。发送到 Elasticsearch 的查询命中结果hits response使用摄像头的视频演示如前所述我们可以使用 webcam 与 Gemini 模型进行对话。为了展示该功能我们将用手写的方式询问以下订单中是否有任何包含 gluten 的菜品。Videohttps://www.bilibili.com/video/BV121TL6GEpK如你所见响应非常快。现在我们来看看模型发送到 Elasticsearch 的内容。在这种情况下模型向 Elasticsearch 触发了四次 semantic search 请求每一道菜对应一次请求。一个有趣的点是模型按照列表中的顺序发起这些请求这意味着它能够识别订单的组织结构。这为许多有用的用例打开了可能性但这将是未来文章的内容。结论我们通过三种技术的协同工作构建了一个连接 Elasticsearch 的语音接口组件角色Elastic Agent Buildersemantic search 层带 hosted MCP serverGoogle ADK with LiveAPI双向实时语音流MCP连接 ADK 与 Agent Builder 的标准协议关键点在于 Agent Builder 已经内置了 hosted MCP server。这意味着任何支持 MCP 的 agentGoogle ADK、Claude Desktop 或 LangChain都可以直接与你的 Elasticsearch 数据通信而无需编写自定义集成。我们涵盖的内容为 semantic search 和 analytics 设置 Elasticsearch indices使用多个 data sources 配置 Agent Builder通过 MCP server 将 ADK 连接到 Agent Builderkitchen assistant 模式适用于任何 hands-busy 场景仓库工人查询库存、护士访问病历或技术人员查询维护手册。voice 和 video input 结合 Elasticsearch 的 search 能力打开了传统界面难以覆盖的用例空间。原文Google ADK voice assistant for Elasticsearch - Elasticsearch Labs