作者:来自 Elastic Jeffrey Rengifo
了解如何将 Elasticsearch 与 Microsoft 365 Copilot Chat 和 Microsoft Teams 中的 Copilot 搭配使用。
Elasticsearch 原生集成了业界领先的生成式 AI 工具和提供商。查看我们的网络研讨会,了解超越 RAG 基础的内容,或构建可投入生产的应用程序 Elastic Vector Database。
为了为你的使用场景构建最佳的搜索解决方案,现在可以开始免费云试用,或者在本地机器上尝试 Elastic。
本文将指导你如何将 Elasticsearch 与 Microsoft Copilot 集成。我们将构建一个能够从你的 Elasticsearch 文档中检索并使用数据的自定义代理。
什么是 Microsoft Copilot
Microsoft Copilot 是一个 AI 助手,帮助你在 Microsoft 生态系统产品中完成各类任务,提供类似于 ChatGPT 的功能,满足各种生产力需求。
通过使用 Microsoft Copilot Studio 和图形界面,你可以构建自定义 agent,并为它们配置 actions。这些 actions 会连接到你的 API,以获取数据并响应用户查询。
action 是 agent 可用来帮助你完成任务的工具。这些 actions 可以连接到平台内置的连接器,或连接到 API。OpenAPI JSON 规范为描述你的 API 提供了一种标准格式,使 Copilot 能理解它的功能、可用的端点,以及如何正确构造查询,包括自动填充参数。
我们将构建一个 agent,用于提供存储在 Elasticsearch 中的发票信息,通过 API 连接。这个 agent 将运行在 Microsoft Teams 上,作为个人助手使用。
本教程将引导你完成以下步骤:
-
构建 API
-
设置 Elasticsearch 数据
-
配置 Copilot 和 agent
-
使用 agent
本文中引用的所有代码和文件都可以在这个 GitHub 仓库中找到。
构建 API
我们将创建一个查询 Elasticsearch 的简单 API。我们会在 Jupyter notebook 中使用 FastAPI 来构建它。
`%pip install fastapi pyngrok uvicorn nest-asyncio elasticsearch==9 -q`AI写代码
在导入这些工具之前,让我们先回顾一下已安装的工具:
- fastapi, uvicorn:生成一个用于访问 Elasticsearch 的 HTTP 服务器。
- pyngrok:为本地服务器创建一个安全的公共 IP 地址(隧道),使 Copilot agent 能通过互联网访问它。这个和花生壳有点类似。
- elasticsearch:Elasticsearch 的 Python 客户端。
- nest-asyncio:在 Notebook 环境中创建服务器所需。
`
1. import os
2. from datetime import datetime
4. import nest_asyncio
5. import uvicorn
7. from fastapi import FastAPI, Query
8. from pyngrok import conf, ngrok
10. from elasticsearch.helpers import bulk
11. from elasticsearch import Elasticsearch
`AI写代码
要在 Copilot agent 中使用这个 API,我们需要让它可以通过互联网访问。因此,我们将使用 ngrok 创建一个隧道,把 API 连接到互联网。在这里创建一个 ngrok 账户并获取一个 auth token。
让我们来配置环境变量:
`
1. os.environ["ELASTICSEARCH_ENDPOINT"] = (
2. "Elasticsearch_endpoint"
3. )
4. os.environ["ELASTICSEARCH_API_KEY"] = (
5. "Elasticsearch_api_key"
6. )
7. os.environ["NGROK_AUTH_TOKEN"] = "ngrok-token"
8. INDEX_NAME = "invoices"
`AI写代码
现在,实例化 Elasticsearch 客户端:
`
1. _client = Elasticsearch(
2. os.environ["ELASTICSEARCH_ENDPOINT"],
3. api_key=os.environ["ELASTICSEARCH_API_KEY"],
4. )
`AI写代码
让我们启动服务器并创建以下端点:
/search/semantic
根据用户的查询执行语义搜索。
/search/by-date
根据日期范围执行搜索。
在这两种情况下,Elasticsearch 都会返回每个查询的一组文档。
`
1. app = FastAPI()
3. @app.get("/search/semantic")
4. async def search_semantic(query: str = Query(None)):
5. # ... full code in the GitHub repository ...
8. @app.get("/search/by-date")
9. async def search_by_date(from_date: str = Query(None), to_date: str = Query(None)):
10. # ... full code in the GitHub repository ...
`AI写代码
让我们配置隧道并运行服务器。
`
1. conf.get_default().auth_token = os.environ["NGROK_AUTH_TOKEN"]
2. ngrok_tunnel = ngrok.connect(8000)
4. print("Public URL:", ngrok_tunnel.public_url)
6. nest_asyncio.apply()
7. uvicorn.run(app, port=8000)
`AI写代码
你获得的 Public URL 将提供给我们的 Microsoft Copilot agent。
`
1. Public URL: https://81c1-181-237-140-155.ngrok-free.app
3. INFO: Started server process [77882]
4. INFO: Waiting for application startup.
5. INFO: Application startup complete.
6. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
`AI写代码
设置 Elasticsearch 数据
映射
我们将索引一系列发票,其中包含所提供服务的描述、日期、参考 URL、总金额和描述。
我们还会将需要用于语义搜索的属性复制到一个名为 semantic_field 的字段类型中。
`
1. _client.indices.create(
2. index=INDEX_NAME,
3. body={
4. "mappings": {
5. "properties": {
6. "id": {"type": "keyword"},
7. "file_url": {"type": "keyword"},
8. "issue_date": {"type": "date"},
9. "description": {"type": "text", "copy_to": "semantic_field"},
10. "services": {
11. "type": "object",
12. "properties": {
13. "name": {
14. "type": "text",
15. "copy_to": "semantic_field",
16. },
17. "price": {"type": "float"},
18. },
19. },
20. "total_amount": {
21. "type": "float",
22. },
23. "semantic_field": {"type": "semantic_text"},
24. }
25. }
26. },
27. )
`AI写代码
索引数据
我们将上传一组不同的发票。数据集可以在这里找到。
让我们创建一个函数,遍历发票数组,并使用 bulk API 将其索引到 Elasticsearch 中。
`
1. def build_data():
2. for doc in invoices:
3. yield {"_index": INDEX_NAME, "_source": doc}
6. try:
7. success, errors = bulk(_client, build_data())
8. print(f"{success} documents indexed successfully")
10. if errors:
11. print("Errors during indexing:", errors)
13. except Exception as e:
14. print(f"Error: {str(e)}, please wait some seconds and try again.")
`AI写代码
Copilot 和代理配置
使用 Copilot chat 需要一个 Office 365 账户。如果你没有,可以在这里创建试用账户。
创建代理和操作
创建账户后,访问主 Copilot Studio 网站,按照以下说明操作:
-
按照微软的步骤创建一个代理(create an agent)。
-
一个 action 是一个 API 端点。这个例子里,你需要添加两个:一个用于语义文本查询,另一个用于基于日期的查询。
为此,你需要先生成你刚创建的 API 的 OpenAPI JSON 参考。你可以在专门为本文准备的 GitHub 仓库里找到 OpenAPI 规范文件。在 OpenAPI 配置中,把已有的 'host' 值替换成 ngrok 生成的 URL。注意去掉 'https://' 前缀,只保留主机名和端口。
-
点击 Settings 并启用 Generative AI,以便使用 GenAI 处理对话。根据 Copilot 在对话中检测到的内容,选择 Actions、Knowledge 和 Topics。
-
点击 Overview,然后向下滚动,你会找到 Knowledge 部分。关闭选项 Allow the AI to use its own general knowledge。这样可以防止代理使用其训练中的通用信息进行回答,因为我们希望它们专注于我们的 Elasticsearch 文档。
-
如果你使用的是 ngrok 免费层,必须设置请求头 'ngrok-skip-browser-warning',其值可以是任意内容。这样可以绕过 ngrok 要求的浏览器验证步骤,因为免费通道可能会被滥用。为此,前往 “Actions > [Action] > Inputs > Ngrok Skip Browser Warning”,点击 “How will the agent fill this input?”,选择 “Set as value”。在 Value 中填写任意值后点击 “Save”,这样你就可以通过 ngrok 通道使用这些端点了。
让代理在 Copilot 中可见
要在 Microsoft 365 或 Microsoft Teams 中使用该代理,你必须按照以下步骤操作:
-
在 Copilot Studio 中,进入 Channels,然后点击 Teams + Microsoft 365:
-
取消选择 “Make agent available in Microsoft 365 Copilot Chat” 选项。这个选项只适用于你想在 Microsoft 365 Copilot 中使用代理的情况,而我们是要在 Microsoft Teams 中使用它。
-
现在点击 “Add channel”。
-
将代理添加到频道后,点击 “See agent in Teams”,然后直接将其添加到 Teams 中。
添加完成后,你就可以在 Copilot 中通过输入 @ 并从选项中选择该代理来开始使用它。
使用代理
首次使用 actions 时,Copilot 会提示权限问题,并在需要你授权每个 action 时显示一个框,点击 Connect 即可授予权限。每个 action 只需授权一次。
你现在已经可以开始使用代理了。
要测试语义搜索,我们可以向代理询问有关餐饮费用的发票:
`Which invoices have billed items related to food comsumption?`AI写代码
让我们来看一下回答结果:
得益于语义搜索功能,Copilot 能够找到那些虽然没有包含 “food” 一词,但包含像 “dinner” 和 “lunch” 这类词的发票。
在 API 日志中,我们可以验证被调用的端点和 Copilot 生成的查询。在这个例子里,查询是 “food consumption”。
在这个文件中找到 JSON 格式的查询内容,以及 Elasticsearch 针对前一个查询返回的原始命中结果。
现在,让我们通过查询特定时间范围内开具的发票,来测试日期范围搜索:
`invoices between 20 of April and 22 of April`AI写代码
以下是结果:
- Invoice ID: INV-0011
- Description: Business lunch with client
- Services: Lunch at La Terraza Bistro - $85.00
- Total Amount: $85.00
- Issue Date: 2025-04-20
- View Invoice
- Invoice ID: INV-0012
- Description: Hotel accommodation during client visit
- Services: 3-night stay at Hotel Central - $450.00
- Total Amount: $450.00
- Issue Date: 2025-04-21
- View Invoice
- Invoice ID: INV-0013
- Description: Team-building activity
- Services: Escape room experience for team - $200.00
- Total Amount: $200.00
- Issue Date: 2025-04-22
- View Invoice
通过查看 API 请求,我们可以确认 Copilot 正确地解析了数据和所选的端点:
范围查询如下所示,你还可以看到 Elasticsearch 返回的数据。
结论
本文中,我们成功地将 Elasticsearch 与 Microsoft Copilot 集成,创建了一个能够访问我们索引的个人助理。
通过使用带有清晰描述的 API OpenAI 规范,代理能够有效地选择并调用合适的端点。
这种架构类似于 Model Context Protocol(MCP),在未来的文章中,我们将探讨 Microsoft Copilot 与 MCP 以及 Elasticsearch MCP 服务器的新集成。
原文:Improving Copilot capabilities using Elasticsearch - Elasticsearch Labs