作者:来自 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 中找到。
`
1. [
2. {
3. "name": "Mushroom Risotto",
4. "ingredients": ["arborio rice", "mushrooms", "parmesan", "butter", "white wine", "vegetable stock", "shallots", "garlic"],
5. "allergens": ["dairy"],
6. "procedure": "Toast rice in butter. Add wine and reduce. Gradually add warm stock while stirring. Fold in sautéed mushrooms and finish with parmesan.",
7. "prep_time_minutes": 35,
8. "category": "main",
9. "dietary": ["vegetarian"]
10. },
11. {
12. "name": "Seafood Risotto",
13. "ingredients": ["arborio rice", "shrimp", "mussels", "calamari", "white wine", "fish stock", "garlic", "parsley", "butter"],
14. "allergens": ["shellfish", "dairy"],
15. "procedure": "Toast rice in butter with garlic. Add wine and reduce. Gradually add warm fish stock. Add seafood in final minutes. Finish with parsley.",
16. "prep_time_minutes": 40,
17. "category": "main",
18. "dietary": []
19. },
20. {
21. "name": "House Vinaigrette",
22. "ingredients": ["olive oil", "red wine vinegar", "dijon mustard", "honey", "garlic", "salt", "pepper"],
23. "allergens": [],
24. "procedure": "Whisk mustard, vinegar, honey, and minced garlic. Slowly stream in olive oil while whisking. Season with salt and pepper.",
25. "prep_time_minutes": 5,
26. "category": "sauce",
27. "dietary": ["vegan", "gluten-free"]
28. },
29. ...
30. ]
`AI写代码
创建 indices、inference endpoint 和加载数据
要在 Elasticsearch 中创建 indices 并导入数据,你可以运行本文准备好的 notebook,地址在 这里。
在 Serverless 环境中,在 Elasticsearch 里创建具有相应权限的 API key 已经成为必需操作。
`
1. POST /_security/api_key
2. {
3. "name": "google-adk-api-key",
4. "expiration": "30d",
5. "role_descriptors": {
6. "mcp-access": {
7. "cluster": [
8. "all"
9. ],
10. "indices": [
11. {
12. "names": [
13. "*"
14. ],
15. "privileges": [
16. "all"
17. ],
18. "allow_restricted_indices": false
19. }
20. ],
21. "applications": [
22. {
23. "application": "kibana-.kibana",
24. "privileges": [
25. "feature_agentBuilder.all",
26. "feature_actions.read",
27. "feature_inference.all",
28. "feature_advancedSettings.read"
29. ],
30. "resources": [
31. "space:default"
32. ]
33. }
34. ],
35. "run_as": [],
36. "metadata": {},
37. "transient_metadata": {
38. "enabled": true
39. }
40. }
41. }
42. }
`AI写代码
为了实现语义搜索能力,我们将使用 jina-embeddings-v5-text-small,这是一个高质量的检索( retrieval )模型。
`
1. INFERENCE_ID = "jina-embeddings"# Create inference endpoint with Jina embeddings v5
2. inference_config = {
3. "service": "elastic",
4. "service_settings": {"model_id": "jina-embeddings-v5-text-small"},
5. }
7. es_client.inference.put(
8. task_type="text_embedding", inference_id=INFERENCE_ID, body=inference_config
9. )
11. print(f"✅ Inference endpoint '{INFERENCE_ID}' created successfully")
`AI写代码
现在我们需要创建 index mappings ,包括包含 dataset 中相关数据的 fields 。我想强调 semantic_field ,这个 field 将用于使用之前创建的 jina-embeddings inference endpoint 进行 semantic search 。这个 field 将包含所有使用 copy_to property 的 fields 的内容。
`
1. INDEX_NAME = "knowledge"es_client.indices.exists(index=INDEX_NAME)
3. knowledge_mapping = {
4. "properties": {
5. "name": {"type": "text", "copy_to": "semantic_field"},
6. "ingredients": {"type": "text", "copy_to": "semantic_field"},
7. "allergens": {"type": "keyword", "copy_to": "semantic_field"},
8. "procedure": {"type": "text", "copy_to": "semantic_field"},
9. "prep_time_minutes": {"type": "integer"},
10. "category": {"type": "keyword", "copy_to": "semantic_field"},
11. "dietary": {"type": "keyword", "copy_to": "semantic_field"},
12. "semantic_field": {
13. "type": "semantic_text",
14. "inference_id": INFERENCE_ID,
15. },
16. }
17. }
`AI写代码
最后,我们使用 bulk API 来导入数据。
`
1. def build_bulk_actions(documents, index_name):
2. for doc in documents:
3. yield {"_index": index_name, "_source": doc}
6. with open("dataset/knowledge.json", "r") as f:
7. docs = json.load(f)
9. success, failed = helpers.bulk(
10. es_client,
11. build_bulk_actions(docs, INDEX_NAME),
12. refresh=True,
13. )
14. print(f"{success} documents indexed successfully")
`AI写代码
使用 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 ,代码如下:
`
1. recipe_search_tool = {
2. "id": "recipe_semantic_search",
3. "type": "index_search",
4. "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.",
5. "tags": ["semantic"],
6. "configuration": {
7. "pattern": INDEX_NAME,
8. },
9. }
11. response = requests.post(
12. f"{KIBANA_ENDPOINT}/api/agent_builder/tools",
13. headers=KIBANA_HEADERS,
14. json=recipe_search_tool,
15. )
`AI写代码
我们正在创建一个单一的 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 连接到 Elasticsearch
Google ADK 通过 MCP 使用三个组件连接到 Agent Builder:Agent、McpToolset 和 StdioConnectionParams。整个连接过程只需要大约 30 行 Python 代码。
要配置环境以使用 ADK Streaming,从而启用语音和视频通信,请参考本教程。
完成应用程序 setup 后,你可以将 agent.py 文件的内容替换为下面的代码片段:
`
1. import os
3. from dotenv import load_dotenv
4. from google.adk.agents import Agent
5. from google.adk.tools.mcp_tool import McpToolset
6. from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
7. from mcp.client.stdio import StdioServerParameters
9. load_dotenv()
11. KIBANA_ENDPOINT = os.getenv("KIBANA_ENDPOINT")
12. ELASTIC_API_KEY = os.getenv("ES_API_KEY")
14. # Elastic Agent Builder MCP connection
15. AUTH_HEADER = f"ApiKey {ELASTIC_API_KEY}"
17. root_agent = Agent(
18. model="gemini-2.5-flash-native-audio-latest",
19. ,
20. instruction="""You are a kitchen assistant that helps chefs during busy dinner service.
21. You can answer questions about recipes.
23. Use the Elasticsearch tools to search the cooking-recipes index and provide quick answers like:
24. - Does a dish contain specific allergens (e.g., shellfish)?
25. - Recipes that can be prepared with given ingredients
26. - I would like to prepare a seafood dish
27. - Find recipes by category or dietary restrictions
29. Always be concise and practical - chefs need quick answers!""",
30. tools=[
31. McpToolset(
32. connection_params=StdioConnectionParams(
33. server_params=StdioServerParameters(
34. command="npx",
35. args=[
36. "-y", # Auto-confirm install
37. "mcp-remote",
38. f"{KIBANA_ENDPOINT}/api/agent_builder/mcp",
39. "--header",
40. f"Authorization:{AUTH_HEADER}",
41. ],
42. ),
43. timeout=30,
44. session_read_timeout_seconds=120,
45. ),
46. tool_filter=["recipe_semantic_search"],
47. )
48. ],
49. )
`AI写代码
它使用了三个关键的 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 say | Response |
|---|---|
| Does 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. |
视频演示
Events 视图
Web interface 允许你对 agent 执行的 operations 进行 debug。在左侧菜单中,你可以找到 Events view,其中可以查看 event calls 的详细信息。
在函数调用中,你可以在 Elasticsearch 中找到已执行的查询,以及在函数响应中,通过语义搜索检索到的命中结果。发送到 Elasticsearch 的查询:
命中结果(hits response):
使用摄像头的视频演示
如前所述,我们可以使用 webcam 与 Gemini 模型进行对话。为了展示该功能,我们将用手写的方式询问以下订单中是否有任何包含 gluten 的菜品。
Video
如你所见,响应非常快。现在我们来看看模型发送到 Elasticsearch 的内容。
在这种情况下,模型向 Elasticsearch 触发了四次 semantic search 请求,每一道菜对应一次请求。一个有趣的点是,模型按照列表中的顺序发起这些请求,这意味着它能够识别订单的组织结构。这为许多有用的用例打开了可能性,但这将是未来文章的内容。
结论
我们通过三种技术的协同工作,构建了一个连接 Elasticsearch 的语音接口:
| 组件角色 | |
|---|---|
| Elastic Agent Builder | semantic search 层,带 hosted MCP server |
| Google ADK with LiveAPI | 双向实时语音流 |
| MCP | 连接 ADK 与 Agent Builder 的标准协议 |
关键点在于 Agent Builder 已经内置了 hosted MCP server。这意味着任何支持 MCP 的 agent(Google ADK、Claude Desktop 或 LangChain)都可以直接与你的 Elasticsearch 数据通信,而无需编写自定义集成。
我们涵盖的内容
-
为 semantic search 和 analytics 设置 Elasticsearch indices
-
使用多个 data sources 配置 Agent Builder
-
通过 MCP server 将 ADK 连接到 Agent Builder
kitchen assistant 模式适用于任何 hands-busy 场景:仓库工人查询库存、护士访问病历,或技术人员查询维护手册。voice 和 video input 结合 Elasticsearch 的 search 能力,打开了传统界面难以覆盖的用例空间。
原文:Google ADK voice assistant for Elasticsearch - Elasticsearch Labs