作者:来自 Elastic Enrico Zimuel
通过一个实际示例学习如何使用 Mastra 和 Elasticsearch 构建具备代理能力的 AI 应用。
Agent Builder 现已正式发布。通过 Elastic Cloud Trial开始使用,并在此查看 Agent Builder 文档。
在本文中,我们将介绍如何使用 Mastra TypeScript 框架构建与 Elasticsearch 交互的具备代理能力的应用。
我们最近为 mastra-ai/mastra 开源项目做出了贡献,新增了将 Elasticsearch 作为向量数据库的支持。通过这一新功能,你可以在 Mastra 中原生使用 Elasticsearch 来存储 embedding。除了向量之外,Elasticsearch 还提供了一整套高级功能来满足所有上下文工程需求(例如 hybrid search 和 reranking)。
本文详细介绍了如何创建一个 agent 来实现基于 Elasticsearch 的检索增强生成(RAG)架构。我们将展示一个演示项目,其中使用 agentic 方法与存储在 Elasticsearch 中的科幻电影数据语料进行交互。该项目可在 elastic/mastra-elasticsearch-example 获取。
Mastra
Mastra 是一个用于创建具备代理能力的 AI 应用的 TypeScript 框架。
Mastra 中的项目结构如下所示:
`
1. src/
3. ├── mastra/
4. │ ├── agents/
5. │ │ └── weather-agent.ts
6. │ ├── tools/
7. │ │ └── weather-tool.ts
8. │ ├── workflows/
9. │ │ └── weather-workflow.ts
10. │ ├── scorers/
11. │ │ └── weather-scorer.ts
12. │ └── index.ts
13. ├── .env.example
14. ├── package.json
15. └── tsconfig.json
`AI写代码
在 Mastra 中,你可以构建 agents、tools、workflows 和 scores。
Agent 是一个类,接收输入消息并生成输出响应。agent 可以使用 tools、大型语言模型(LLMs)和 memory(见图 1)。
图 1:展示 agent 在 Mastra 中工作原理的示意图。
Agent 的 tools 使其能够与 “外部世界” 交互,例如与 web API 通信或执行内部操作,如查询 Elasticsearch。memory 组件对于存储对话历史至关重要,包括过去的输入和输出。存储的上下文使 agent 能够利用过去的交互,为未来的问题提供更有信息量和更相关的响应。
Workflows 允许你使用清晰、结构化的步骤定义复杂任务序列,而不是依赖单个 agent 的推理(见图 2)。它们让你完全控制任务如何拆分、数据如何在任务间流动以及何时执行。Workflows 默认使用内置执行引擎运行,也可以部署到 workflow runners。
图 2:Mastra 中 workflow 的示例。
在 Mastra 中,你还可以定义 scores,它们是使用模型评分、规则和统计方法评估 agent 输出的自动化测试。Scorers 返回分数:数值(通常在 0 到 1 之间),用于量化输出满足评估标准的程度。这些分数使你能够客观地跟踪性能、比较不同方法,并识别 AI 系统中需要改进的部分。Scorers 可以使用你自己的 prompts 和评分函数进行自定义。
Elasticsearch
运行演示项目时,需要有一个运行中的 Elasticsearch 实例。你可以在 Elastic Cloud 激活免费试用,或使用 start-local 脚本在本地安装:
`curl -fsSL https://elastic.co/start-local | sh`AI写代码
这将在你的计算机上安装 Elasticsearch 和 Kibana,并生成用于配置 Mastra 集成的 API key。
API key 会作为上一个命令的输出显示,并存储在 elastic-start-local 文件夹中的 .env 文件中。
安装并配置演示
我们创建了一个 elastic/mastra-elasticsearch-example 仓库,其中包含演示项目的源代码。仓库中的示例展示了如何在 Mastra 中创建一个 agent,实现基于 RAG 架构从 Elasticsearch 检索文档。
我们为演示提供了一个关于科幻电影的数据集。从 Kaggle 上的 IMDb 数据集中提取了 500 部电影。
第一步是使用 npm 安装项目依赖,命令如下:
`npm install`AI写代码
接下来需要配置 .env 文件,其中包含设置。可以通过复制 .env.example 文件的结构来生成该文件,命令如下:
`cp .env.example .env`AI写代码
现在可以编辑 .env,添加缺失的信息:
`
1. OPENAI_API_KEY=
2. ELASTICSEARCH_URL=
3. ELASTICSEARCH_API_KEY=
4. ELASTICSEARCH_INDEX_NAME=scifi-movies
`AI写代码
Elasticsearch 索引的名称是 scifi-movies。如果需要,可以使用 .env 变量 ELASTICSEARCH_INDEX_NAME 修改它。
我们使用 OpenAI 作为 embedding 服务,这意味着你需要在 OPENAI_API_KEY env 变量中提供 OpenAI 的 API key。
示例中使用的 embedding 模型是 openai/text-embedding-3-small,embedding 维度为 1536。
为了生成最终答案,我们使用了 openai/gpt-5-nano 模型以降低成本。
RAG 架构允许使用较低性能(通常也更便宜)的最终 LLM 模型,因为答案的基础事实由检索组件(此例中为 Elasticsearch)处理。
较小的 LLM 主要负责两个任务:
-
重述/embedding 查询:将用户的自然语言问题转换为向量 embedding,以进行语义搜索。
-
综合答案:将高度相关的检索上下文块(文档/电影)整合为连贯的、最终的、人类可读答案,遵循提供的 prompt 指令。
由于 RAG 流程提供了答案所需的精确事实上下文,最终 LLM 不需要庞大或复杂,也不必在自身参数中拥有所有知识(这是大型、高成本模型的优势)。它本质上充当 Elasticsearch 提供的上下文的高级文本总结器和格式化器,而非完整的知识库。这使得使用 gpt-5-nano 等模型在成本和延迟上得到优化成为可能。
配置完 .env 文件后,可以使用以下命令将电影数据摄取到 Elasticsearch:
`npx tsx src/utility/store.ts`AI写代码
你应该会看到如下输出:
`
1. 🚀 Starting ingestion of 500 movies from 500_scifi_movies.jsonl...
2. Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 1/500 (0%) | ok:1 | fail:0 | chunks:1 | eta:19m 33s | current:Capricorn One
3. Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 2/500 (0%) | ok:2 | fail:0 | chunks:2 | eta:10m 32s | current:Doghouse
4. Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 3/500 (1%) | ok:3 | fail:0 | chunks:3 | eta:7m 33s | current:Dinocroc
5. Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 4/500 (1%) | ok:4 | fail:0 | chunks:7 | eta:6m 10s | current:Back to the Future
6. Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 5/500 (1%) | ok:5 | fail:0 | chunks:9 | eta:5m 14s | current:The Projected Man
7. Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 6/500 (1%) | ok:6 | fail:0 | chunks:11 | eta:4m 41s | current:I, Robot
8. ...
9. ✅ Ingestion complete in 1m 46s. Success: 500, Failed: 0, Chunks: 693.
`AI写代码
scifi-movies 索引的 mapping 包含以下字段:
- embedding:dense_vector,1536 维,使用 cosine similarity。
- description:text,包含电影描述。
- director:text,包含导演姓名。
- title:text,包含电影标题。
我们使用 title + description 生成 embedding。由于 title 和 description 是两个独立字段,将二者拼接可确保生成的 embedding 向量同时捕获电影的特定唯一身份(title)和丰富的描述性上下文(description),从而获得更准确、全面的语义搜索结果。这个组合输入为 embedding 模型提供了更好的文档内容单一表示,以进行相似性匹配。
运行演示
可以使用以下命令运行演示:
`npm run dev`AI写代码
该命令将在 localhost:4111 启动一个 Web 应用,以访问 Mastra Studio(见图 3)。
图 3:Mastra Studio 截图,展示了 Elasticsearch Agent 示例。
Mastra Studio 提供一个交互式 UI 用于构建和测试你的 agents,同时提供一个 REST API,将你的 Mastra 应用作为本地服务暴露出来。这让你可以立即开始构建,而无需担心集成问题。
我们提供了一个 Elasticsearch Agent,使用 Mastra 的 createVectorQueryTool 作为工具,通过 Elasticsearch 执行语义搜索。这个 agent 使用 RAG 方法搜索相关文档(即 movies)来回答用户的问题。
这个 agent 使用以下 prompt:
`
1. You are a helpful assistant that answers questions based on the provided context.
2. Follow these steps for each response:
4. 1. First, carefully analyze the retrieved context chunks and identify key information.
5. 2. Break down your thinking process about how the retrieved information relates to the query.
6. 3. Draw conclusions based only on the evidence in the retrieved context.
7. 4. If the retrieved chunks don't contain enough information, explicitly state what's missing.
9. Format your response as:
10. THOUGHT PROCESS:
11. - Step 1: [Initial analysis of retrieved chunks]
12. - Step 2: [Reasoning based on chunks]
14. FINAL ANSWER:
15. [Your concise answer based on the retrieved context]
17. Important: When asked to answer a question, please base your answer only on the context provided in the tool.
18. If the context doesn't contain enough information to fully answer the question, please state that explicitly and stop it.
19. Do not add more information than what is present in the retrieved chunks.
20. Remember: Explain how you're using the retrieved information to reach your conclusions.
`AI写代码
如果你点击 Mastra Studio > Agents 菜单并选择 Elasticsearch Agent,你可以使用聊天系统测试这个 agent。例如,你可以用以下问题询问有关 sci-fi movies 的信息:
`Find 5 movies or TV series about UFOs.`AI写代码
你会注意到,agent 会执行 vectorQueryTool。你可以点击被调用的工具查看输入和输出。在执行结束时,LLM 会根据来自 Elasticsearch 的 scifi-movies 索引的上下文回答你的问题(图 4)。
图 4:使用 Elasticsearch Agent 的 LLM 响应。
Mastra 内部执行以下步骤:
- 向量转换:用户的问题 “Find 5 movies or TV series about UFOs” 被转换为向量 embedding,使用 OpenAI 的 openai/text-embedding-3-small 模型。
- 向量搜索:该 embedding 随后用于通过向量搜索查询 Elasticsearch。
- 结果检索:Elasticsearch 返回与查询高度相关的 10 部 movies(即向量最接近用户查询向量的那些)。
- 答案生成:检索到的 movies 和原始用户问题被发送给 LLM,具体为 openai/gpt-5-nano。LLM 处理这些信息并生成最终答案,确保满足用户要求的五个结果。
Elasticsearch Agent
这里报告了 Elasticsearch Agent 的源代码。
`
1. import { Agent } from "@mastra/core/agent";
2. import { ElasticSearchVector } from '@mastra/elasticsearch';
3. import { createVectorQueryTool } from '@mastra/rag';
4. import { ModelRouterEmbeddingModel } from "@mastra/core/llm";
5. import { Memory } from "@mastra/memory";
7. const es_url = process.env.ELASTICSEARCH_URL;
8. const es_apikey = process.env.ELASTICSEARCH_API_KEY;
9. const es_index_name = process.env.ELASTICSEARCH_INDEX_NAME;
10. const prompt = 'insert here the previous prompt';
12. const esVector = new ElasticSearchVector({
13. id: 'elasticsearch-vector',
14. url: es_url,
15. auth: {
16. apiKey : es_apikey
17. }
18. });
20. const vectorQueryTool = createVectorQueryTool({
21. vectorStore: esVector,
22. indexName: es_index_name,
23. model: new ModelRouterEmbeddingModel("openai/text-embedding-3-small")
24. });
26. export const elasticsearchAgent = new Agent({
27. id: "elasticsearch-agent",
28. name: "Elasticsearch Agent",
29. instructions: prompt,
30. model: 'openai/gpt-5-nano',
31. tools: { vectorQueryTool },
32. memory: new Memory(),
33. });
`AI写代码
vectorQueryTool 是用于实现 RAG 示例中检索部分的工具。它使用 Elastic 为 Mastra 提供的 ElasticSearchVector 实现。
这个 agent 是 agent 类的一个对象,使用 vectorQueryTool、prompt 和 memory。如你所见,为了将 Elasticsearch 连接到 agent,我们需要的代码非常少。
结论
本文展示了将 Elasticsearch 与 Mastra 框架集成以构建复杂 agentic AI 应用的简单性和强大功能。具体来说,我们演示了如何创建一个 RAG agent,能够对索引在 Elasticsearch 中的 sci-fi movie 数据语料库执行语义搜索。
一个关键要点是 Elastic 对 Mastra 开源项目的直接贡献,为 Elasticsearch 作为向量存储提供原生支持。这种集成显著降低了入门门槛,如 Elasticsearch Agent 源代码所示。使用 ElasticSearchVector 和 createVectorQueryTool,将 Elasticsearch 连接到你的 agent 的完整设置只需要极少的配置代码行数。
Elasticsearch 提供了多种高级功能以增强结果相关性。例如,hybrid search 通过结合词汇搜索和向量搜索显著提升准确性。另一个有趣的功能是在 hybrid search 结束时使用最新 Jina 模型进行 reranking。要了解更多这些技术,请参考 Elasticsearch Labs 的以下文章:
- Elasticsearch hybrid search — Valentin Crettaz
- Jina 模型简介、功能及在 Elasticsearch 中的应用 — Scott Martens
我们还鼓励你探索提供的示例,并开始使用 Mastra 和 Elasticsearch 构建你自己的数据驱动 agents。有关 Mastra 的更多信息,你可以查看官方文档。