英语轻松读发新版了,欢迎下载、更新

使用 GPT-4o 创建 WhatsApp AI 代理

2024-12-22 18:01:07 英文原文

作者:Lukasz Kowejsza

使用 DALL-E 创建

如何使用 Meta API 构建您自己的 LLM 支持的 Whatsapp 聊天机器人

Lukasz Kowejsza

Towards Data Science

人工智能和商业管理领域的游戏规则改变者是人工智能代理与广泛使用的通信工具的集成。想象一下拥有一个熟悉的聊天界面,其中包含实时数据请求、更新和任务自动化,所有这些都可以通过 WhatsApp 与您的企业管理层或个人助理 AI 直接交互来实现。

在创建人工智能驱动的业务经理系列的第三部分中,我将引导您完成将人工智能代理连接到 WhatsApp 的步骤,以增强其功能和覆盖范围。要实现的目标是人工智能助手能够与所有相关的数据库表进行交互,甚至可以自行创建表和所有必要的工具。作为主要展示,我重点关注业务用例,例如跟踪费用、发票等。但是,您可以轻松地采用相同的逻辑来创建,例如跟踪您的任务、项目和想法的个人助理。

这是我的系列的第三部分。在我们开始之前,对于大家等待的时间,我为这么长时间的延误表示歉意。在过去的几个月里,我一直忙于开始一份新的人工智能软件工程工作并适应新的工作与生活平衡。到目前为止,我已经准备了本文的一些后续部分,我们将探讨代理工作流程中的重大变化,以及具有几个附加功能的更复杂的工作流程。前两篇文章中使用的一些解决方法对于当时可靠的工具调用是必要的,但由于 GPT-4o 和 GPT-4o-mini 等性能更好的模型而不再需要。如果您是工具调用和代理工作流程开发的新手,我仍然建议您从前两部分开始。我发现,在依赖 LangChain 等框架或更具体地说,LangGraph 来实现深度可定制的代理工作流程(我将在不久的将来介绍)之前,了解如何从头开始构建某些东西很有用。

现在,我们必须退后一步,首先关注基础设施。我认为在大多数项目中,特别是在人工智能软件项目中,在迷失功能蔓延之前首先创建一个可用的端到端产品是一个很好的做法。我经常发现自己在最初的设计选择上考虑过多,并在脑海中开发出过于复杂的产品。为了克服这个问题,在开发后的几天内专注于构建一个可用的端到端产品确实有助于建立一个清晰的基础。之后,您将知道要优先考虑哪些功能,并且能够收集初步反馈。这启动了增量开发过程,这始终是我致力于项目时的目标。

在本系列的前几部分中,我们为人工智能驱动的业务经理奠定了基础:

  • 第 1 部分:目标是开发一个原型代理工作流程,可以与工具对象交互并减少底层语言模型(LLM)产生的工具参数中的幻觉。
  • 第2部分:我们专注于定义基本功能、组织项目存储库以及使用 SQLModel 构建数据库模式。我们还添加了用于数据添加和查询的 SQL 工具,并更新了 Tool 类以容纳 SQLModel 对象。此外,我们还提供了一个用于自动启动代理的 TaskAgent 类,并设置了一个用于上下文感知工具使用的 OpenAIAgent。

像往常一样,让我们​​首先定义本文的范围:

  1. 使用 MetaAPI 将 AI 代理与 WhatsApp 集成
    设置和配置 MetaAPI 以进行 WhatsApp Business 集成。
    确保 AI 代理可以通过 WhatsApp 发送和接收消息。
  2. 设置 Webhook 并使用 Ngrok 在本地运行
    创建 FastAPI 应用程序来处理来自 WhatsApp 的 Webhook 事件。
    使用 ngrok 将本地 FastAPI 服务器公开到互联网。
    配置 MetaAPI 以将 Webhook 事件发送到 ngrok URL

由于我们正在转向可部署的服务器,因此我们还需要调整我们的项目架构。我们本质上是在实现一个 FastAPI 服务器,因此,我首选的存储库结构是领域驱动设计 (DDD),或者更倾向于 DDD。(你可以检查Repo结构这里)首先,您需要熟悉Meta提供的Cloud API。您可以使用 Twilio 等 SaaS 产品获得相同的结果,这些产品提供了更加用户友好的集成。

然而,由于最近的数据泄露以及出于成本效率的原因,我更喜欢使用 Meta 提供的 root API。

  1. 在开始之前,您需要按照以下步骤注册一个 Meta 开发者帐户:如何开设元开发者帐户。在此注册过程中,您需要使用电话号码验证自己。请注意,这不会是您最终 WhatsApp 客户端的电话号码。相反,您将获得平台分配的测试电话号码,稍后可以更改为其他电话号码。
  2. 注册后,转到您的仪表板并创建一个应用程序。
  3. 此外,您将需要一个与您的真实帐户关联的元商业帐户 (MBA),或者您可以创建一个新帐户来链接到您的 MBA。您也可以跳过此步骤,因为系统会在下一步中自动提示您链接或创建 MBA。

在您的 Meta 开发者帐户中创建应用程序后,系统会要求您向其中添加产品。在这里您必须选择 WhatsApp 并按照设置过程进行操作。如果您还没有这样做,请在此处创建一个元企业帐户。完成后,您将拥有一个测试 WhatsApp Business 帐户和一个测试电话号码。

  1. 在应用程序仪表板的左侧菜单中,导航至
    WhatsApp>API 设置
    那里下面发送和接收消息,选择字段并选择管理电话号码列表。在这里,您可以添加一个允许从测试电话号码发送和接收消息的电话号码。理想情况下,这应该是您自己的电话号码,因为您想测试您的应用程序。在将此 WhatsApp API 帐户关联到真实号码之前,您最多只能添加 5 个收件人号码。
  2. WhatsApp > API 设置,您现在可以通过填写以下内容来发送测试消息字段包含您的测试电话号码和字段包含您的收件人号码(您自己的电话号码)。
  3. 生成访问令牌。这是你的WHATSAPP_API_TOKEN,稍后我们将在第 6 步中需要它。
屏幕截图 ngrok(作者提供的图片)

我们已经按照要求成功设置了 Cloud API。在下一步中,我们将创建一个 Webhook,以实现与 AI Assistant 应用程序的通信。

为了实现这一点,我们需要在后端应用程序中创建并提供一个端点。这意味着我们的 Python 后端必须可以通过 URL 访问。此 URL 将充当 AI Assistant 可以调用来发送和接收数据的 Webhook 端点。

为了被 Webhook 接受,我们的根端点必须验证添加 URL 时将由 Webhook 发送的特定 GET 请求。Webhook 将发送三个查询参数:

集线器模式,枢纽挑战,hub.验证.token。验证令牌是在 Cloud API 中创建 Webhook 时定义的。

您的后端应该验证该令牌是否与您定义的令牌匹配并返回枢纽挑战对象作为响应。确保使用安装 FastAPI 和 Uvicornpip 安装 fastapi uvicorn第一的。

创建一个名为主要.py包含以下内容:

从 fastapi 导入 FastAPI、查询、HTTPException

VERIFICATION_TOKEN =“abcdefg12345”

应用程序 = FastAPI()

@app.get("/")
def verify_whatsapp(
hub_mode: str = Query("订阅",description="webhook的模式",alias="hub.mode"),
hub_challenge: int = Query(..., description="验证 webhook 的挑战", alias="hub.challenge"),
hub_verify_token: str = Query(..., description="验证令牌", alias="hub.verify_token"),
):
如果 hub_mode ==“订阅”且 hub_verify_token == VERIFICATION_TOKEN:
返回 hub_challenge
引发HTTPException(status_code = 403,detail =“无效的验证令牌”)

@app.get(“/健康”)
def health():
返回{“状态”:“健康”}

@app.get("/准备情况")
def 准备就绪():
返回 {"status": "ready"}

在第三行中,您可以定义一个VERIFICATION_TOKENWebhook 稍后会使用它来验证后端是否在您的控制之下。在这种情况下,我们将其定义为“abcdefg12345”,但您可以定义自己的自定义令牌。

我将继续纠正其余部分,并很快包括下一部分!

使用 Uvicorn 运行应用程序:

uvicorn 主:应用程序--重新加载

您的后端现在在本地运行http://本地主机:8000和/或http://127.0.0.1:8000。我们现在为以下端点提供服务:

验证 WhatsApp 网络钩子:

打开http://127.0.0.1:8000/health在您的浏览器中,您应该看到:{“状态”:“健康”}

由于我们的服务器在本地运行,因此 WhatsApp Webhook 无法调用端点进行验证。我们需要的是一个可供 webhook 使用的公共 URL。有两种选择:将应用程序部署到云服务器或创建代理服务器隧道。由于我们仍处于开发过程中,因此我们将使用第二个选项。

  1. 前往注册并创建一个免费帐户。
  2. 本地安装 ngrok。根据您的系统,您可以使用 Brew、Chocolatey,或者直接下载并安装它。看:设置与安装
  3. 安装后,在终端中使用以下命令添加身份验证代码。代替$您的AUTHENTICATION_TOKEN使用您的 ngrok 身份验证令牌,该令牌可以在 ngrok 仪表板的“您的 Authtoken”下找到。
  4. 通过在终端中运行以下命令,开始在端口 8000 上转发来自本地主机的流量:
> ngrok 配置 add-authtoken $YOUR-AUTHENTICATION_TOKEN
> ngrok http http://localhost:8000

转发 https://<random-string>.ngrok.io -> http://localhost:8000

现在可以通过 ngrok 提供的公共 URL 访问您的本地服务器。你应该看到这样的东西:

转发 https://<random-string>.ngrok.io -> http://localhost:8000

使用 ngrok 提供的 HTTPS URL 进行 webhook 配置。

现在让我们返回 Meta 的 Cloud API 来实现所需的 Webhook。

  1. 导航至开发者元数据并选择之前创建的应用程序。
  2. 在左侧菜单中转到WhatsApp>配置
  3. 网络钩子部分将您的 ngrok HTTPS 转发 URL 粘贴到回调地址字段并输入VERIFICATION_TOKEN定义于主要.py进入验证令牌场地。
  4. 单击确认并保存按钮,然后等待 Webhook 验证您的后端。
  5. 在本节中Webhook 字段启用消息切换下订阅字段

就是这样!您现在应该能够在 Python 后端服务器中接收 WhatsApp 消息。

Webhook 是 HTTP 回调,使程序能够在发生某些事件(例如新消息或状态更改)时接收实时更新。Webhooks 通过将包含事件数据的 HTTP 请求传递到预先配置的 URL(在我们的示例中为 ngrok 代理服务器 URL),使系统集成和自动化成为可能。

要了解 Meta cosmos 中 webhooks 背后的逻辑和定价,了解有关对话的一些基本原则会很有帮助。

WhatsApp API 上的“对话”在以下情况下开始:
1. 用户发送消息:这会打开一个 24 小时窗口,在此期间您可以回复消息,包括文本、图像或其他媒体无需额外费用

2. 企业主动联系:如果最近没有收到用户消息(没有开放24小时窗口),您的AI助手必须使用预先批准的模板消息开始对话。您可以添加自定义模板,但它们需要得到 Meta 的批准。

只要用户继续回复,24 小时窗口就会随着每条新消息而重置。这使得无需额外成本即可进行持续交互。一次对话的费用约为 0.00-0.08 美元。具体定价取决于您的对话类型营销、实用程序、服务和您的位置。仅供参考:服务对话现在似乎是免费的。您可以在这里找到具体的定价:WhatsApp 定价

现在我们可以在后台接收消息了。由于我们已经订阅了消息对象,因此每次将消息发送到您的测试号码时,Webhook 都会向您在上一步中定义的回调 URL 创建一个 POST 请求。接下来我们需要做的是在 FastAPI 应用程序中构建 POST 请求的端点。

我们首先定义一下需求:

  • 返回 200 HTTP 状态代码:这对于通知 CloudAPI 消息已成功接收至关重要。如果不这样做,将导致 CloudAPI 在最多 7 天内重试发送消息。
  • 提取电话号码和消息:传入请求的有效负载包含包含电话号码和消息的数据。我们需要在后台进行处理。
  • 过滤传入对象:由于CloudAPI可能会为同一条消息发送多个事件(例如发送、接收和读取),因此后端需要确保只处理该消息的一个实例。
  • 处理多种消息类型:后端可以处理不同类型的消息,例如文本、语音消息和图像。为了不扩大文章的范围,我们只打下图像的基础,但不会将其实施到底。
  • 使用 LLM-Agent 工作流程进行处理:提取的信息使用 LLM-Agent 工作流程进行处理,该工作流程是我们在本系列的前几部分中开发的。您还可以使用另一种代理实现,例如Langchain 或 Langgraph

我们将从网络钩子接收有效负载。您可以在 Meta 的文档中找到示例有效负载:有效负载示例

我更喜欢使用 Pydantic 编写代码,为我的 Python 代码添加类型安全性。此外,类型注释和 Pydantic 是 FastAPI 应用程序的最佳匹配。因此,我们首先定义端点中使用的模型:

# 应用程序/schema.py
从输入导入列表,可选
从 pydantic 导入 BaseModel、Field

类简介(BaseModel):
名称:str

联系类(基础模型):
简介: 简介
wa_id:str

类文本(基础模型):
身体:str

图像类(基础模型):
mime_type:str
sha256:str
编号:str

音频类(基础模型):
mime_type:str
sha256:str
编号:str
声音:布尔

消息类(基础模型):
from_: str = Field(..., 别名=“from”)
编号:str
时间戳:str
文字:文字|无=无
图像:图像|无=无
音频:音频|无=无
类型:str

类元数据(BaseModel):
显示电话号码:str
电话号码_id:str

类值(基础模型):
消息传递产品:str
元数据:元数据
联系人:列表[联系人]|无=无
消息:列表[消息]|无=无

类更改(基础模型):
价值:价值
字段:str
状态:列表[dict] |无=无

类入口(BaseModel):
编号:str
更改:列表[更改]

类有效负载(基础模型):
对象:str
条目:列表[条目]

用户类(基础模型):
id:整数
名字:str
姓氏:str
电话: STR
角色:str

类 UserMessage(BaseModel):
用户: 用户
消息:str |无=无
图像:图像|无=无
音频:音频|无=无

接下来,我们将创建一些辅助函数来在 FastAPI 中使用依赖注入:

# 应用程序/main.py

从 app.domain 导入 message_service

def parse_message(payload: Payload) -> 消息 |没有任何:
如果不是payload.entry[0].changes[0].value.messages:
返回无
返回payload.entry[0].changes[0].value.messages[0]

def get_current_user(message: Annotated[Message, Depends(parse_message)]) -> 用户 |没有任何:
如果没有留言:
返回无
返回 message_service.authenticate_user_by_phone_number(message.from_)

def parse_audio_file(message: Annotated[Message, Depends(parse_message)]) -> 音频 |没有任何:
如果消息和消息类型==“音频”:
返回消息.音频
返回无

def parse_image_file(message: Annotated[Message, Depends(parse_message)]) -> 图像 |没有任何:
如果消息和消息类型==“图像”:
返回消息.image
返回无

def message_extractor(
消息:带注释的[消息,取决于(parse_message)],
音频:带注释的[音频,取决于(parse_audio_file)],
):
如果有音频:
返回message_service.transcribe_audio(音频)
如果消息和消息.text:
返回消息.text.body
返回无

  • 解析有效负载:解析消息函数从传入的有效负载中提取第一条消息(如果存在)。该函数返回没有任何如果没有找到消息,则只处理有效的消息。
  • 用户认证:获取当前用户函数使用解析消息依赖注入来提取消息,然后根据与消息关联的电话号码对用户进行身份验证。在这里,我们确保只有经过身份验证的用户才可以发送消息。
  • 音频和图像解析:如果消息类型分别为“音频”或“图像”,这些函数将从消息中提取音频或图像文件。这允许应用程序处理不同类型的媒体。
  • 消息提取:消息提取器函数尝试从消息中提取文本或将音频转录为文本。这确保了无论消息类型如何,都可以处理内容。

这里我们有一个来自域层的导入。整个脚本消息服务是我们放置此实现的所有特定于域的代码的地方,例如通过电话号码验证用户转录音频

# 应用程序/main.py
导入线程
从typing_extensions导入注释
从 fastapi 导入 APIRouter、查询、HTTPException、取决于
从 app.domain 导入 message_service
从 app.schema 导入有效负载、消息、音频、图像、用户

# ...其余代码...

@app.post("/", status_code=200)
def receive_whatsapp(
用户:带注释的[用户,取决于(get_current_user)],
user_message: 带注释的[str, Depends(message_extractor)],
图像:带注释的[图像,取决于(parse_image_file)],
):
如果不是 user 且不是 user_message 且不是 image:
返回{“状态”:“确定”}
如果不是用户:
引发 HTTPException(status_code=401,详细信息=“未经授权”)
如果图像:
return print("图像已收到")
如果用户消息:
线程 = 线程. 线程(
目标=message_service.respond_and_send_message,
args =(用户消息,用户))
线程.守护进程 = True
线程.start()
返回{“状态”:“确定”}
POST 端点实施:

  • 该端点处理传入的 POST 请求。它检查用户、消息或图像是否有效。如果没有一个有效,它只会向 CloudAPI 返回一条状态消息。如果用户未经过身份验证,则会引发HTTP异常带有 401 状态代码。
  • 处理图像和消息:如果收到图像,我们会制作一个简单的标准输出打印作为未来图像处理的占位符。如果收到文本消息,则会使用单独的线程异步处理该消息,以避免阻塞主应用程序线程。这message_service.respond_and_send_message根据 LLM-Agent 工作流程调用函数来处理消息。

Webhook 使用线程池的说明:WhatsApp 将重新发送 Webhook,直到收到 200 响应,因此使用线程池来确保消息处理不会阻止 Webhook 响应。

在我们之前定义端点的表示层中,我们使用一些消息服务接下来需要定义的函数。具体来说,我们需要一个实现来处理和转录音频有效负载、对用户进行身份验证,最后调用我们的代理并发回响应。我们将把所有这些功能放在里面域/message_service.py。在生产环境中,随着应用程序的增长,我建议将它们进一步拆分为,例如,转录服务.py,消息服务.py, 和身份验证服务.py。在本节的多个函数中,我们将向 Meta API 发出请求

“https://graph.facebook.com/...”在所有这些请求中,我们需要包含授权标头WHATSAPP_API_KEY,我们创建于步骤1.3,作为不记名令牌。我通常将 API 密钥和令牌存储在.env文件并使用 Python 访问它们多滕夫图书馆。我们还将 OpenAI 客户端与您的OPENAI_API_KEY,也可以存储在.env文件。

但为了简单起见,我们将它们放置在顶部并初始化消息服务.py脚本如下:

导入操作系统
导入 json
导入请求
输入 import BinaryIO

WHATSAPP_API_KEY = "您的访问令牌"
llm = OpenAI(api_key="YOUR_OPENAI_API_KEY")

将“YOUR_ACCESS_TOKEN”替换为您在步骤 1.3 中创建的实际访问令牌。

处理来自 WhatsApp Webhook 的语音记录并不像看起来那么简单。首先,重要的是要知道传入的 webhook 仅告诉我们数据类型和对象 ID。所以它不包含二进制音频文件。我们首先必须使用 Meta 的 Graph API 下载音频文件。要下载收到的音频,我们需要发出两个连续的请求。第一个是 GET 请求,其中包含对象 ID来获取下载地址。此下载 URL 是我们第二个 GET 请求的目标。

def download_file_from_facebook(file_id: str, file_type: str, mime_type: str) -> str |没有任何:
# 第一个 GET 请求来检索下载 URL
url = f"https://graph.facebook.com/v19.0/{file_id}"
headers = {"授权": f"承载 {WHATSAPP_API_KEY}"}
响应 = requests.get(url, headers=headers)
如果响应.status_code == 200:
download_url = response.json().get('url')
# 第二个 GET 请求下载文件
响应 = requests.get(download_url, headers=headers)
如果响应.status_code == 200:
# 从 mime_type 中提取文件扩展名
file_extension = mime_type.split('/')[-1].split(';')[0]
# 创建带扩展名的file_path
文件路径 = f"{file_id}.{file_extension}"
以 open(file_path, 'wb') 作为文件:
文件.write(响应.内容)
如果 file_type == “图像” 或 file_type == “音频”:
返回文件路径
raise ValueError(f"下载文件失败。状态代码:{response.status_code}")
raise ValueError(f"无法检索下载 URL。状态代码:{response.status_code}")

在这里,我们基本上获取下载 URL 并使用对象 ID 和文件扩展名作为文件下载文件到文件系统文件路径。如果出现问题,我们会提出值错误表明错误发生的位置。

接下来,我们简单地定义一个函数,该函数获取音频二进制文件并使用 Whisper 对其进行转录:

def transcribe_audio_file(audio_file: BinaryIO) -> str:
如果不是音频文件:
返回“未提供音频文件”
尝试:
转录 = llm.audio.transcriptions.create(
文件=音频文件,
模型=“耳语-1”,
响应格式=“文本”

返回转录
除了异常 e:
从 e 引发 ValueError("转录音频时出错")

最后,让我们将下载和转录功能结合在一起:

def transcribe_audio(音频: 音频) -> str:
file_path = download_file_from_facebook(audio.id, "音频", audio.mime_type)
使用 open(file_path, 'rb') 作为audio_binary:
转录 = transcribe_audio_file(audio_binary)
尝试:
os.remove(文件路径)
除了异常 e:
print(f"删除文件失败:{e}")
返回转录

在使用 Meta 提供的测试号码时,我们必须预先定义聊天机器人可以向哪些号码发送消息。我不太确定,也没有测试是否有任何号码可以向我们的聊天机器人发送消息。但无论如何,一旦我们切换到自定义号码,我们就不希望任何人能够执行我们的代理聊天机器人。所以我们需要一种方法来验证用户的身份。我们有多种选择来做到这一点。首先,我们要考虑在哪里存储用户信息。例如,我们可以使用 PostgreSQL 等数据库或 Firestore 等非关系数据库。我们可以在 JSON 文件或一个文件系统中预定义我们的用户.env文件。在本教程中,我将采用最简单的方法,并将用户硬编码在我们的身份验证函数的列表中。

列表条目的结构为用户模型定义为步骤5.1。因此,用户由 ID、名字、姓氏和电话号码组成。我们尚未在代理工作流程中实施角色系统。但在大多数具有不同用户的用例中,例如在小型企业助理的示例中,不同的用户将具有不同的权限和访问范围。现在,我们只是通过“默认”作为占位符角色。

defauthenticate_user_by_phone_number(电话号码:str)->用户|没有任何:
允许的用户 = [
{“id”:1,“电话”:“+1234567890”,“名字”:“约翰”,“姓氏”:“多伊”,“角色”:“默认”},
{“id”:2,“电话”:“+0987654321”,“名字”:“简”,“姓氏”:“史密斯”,“角色”:“默认”}
]
对于 allowed_users 中的用户:
如果用户[“电话”] == 电话号码:
返回用户(**用户)
返回无

因此,只需验证该电话号码是否在我们的列表中即可允许的用户并返回用户(如果是)。否则,我们返回没有任何。如果您查看我们的端点步骤5.3,如果用户是没有任何以防止进一步处理未经授权的用户消息。

现在,在我们实际调用代理之前,我们的最后一个辅助函数是发送whatsapp消息。由于一些元特定的 WhatsApp API 逻辑,我在此函数中包含了两种模式。

基本上,您不允许将自定义消息作为对话开始者发送给用户。这意味着如果用户开始对话并首先向聊天机器人写入消息,您可以通过单独的短信进行响应。否则,如果您希望聊天机器人发起对话,您只能使用批准的模板,例如“Hello World”模板。

另外值得一提的是,当我们谈论元逻辑时,对话启动后会打开一个 24 小时的对话窗口,您可以在其中向该用户发送消息。这个对话窗口也是收费的,而不是单独的消息。根据对话类型(例如营销、支持等),它会变得更加复杂。

你也可以自己定义一个模板并让Meta批准。目前我还没有这样做,因此为了测试我们是否可以从后端向用户发送消息,我使用了“Hello World”模板。如果您添加了一些自定义批准的模板,您还可以使用此功能将它们发送给用户。

回到代码。要发送消息,我们发出 POST 请求并定义包含文本正文或模板的有效负载:

def send_whatsapp_message(to, message, template=True):
url = f“https://graph.facebook.com/v18.0/289534840903017/messages”
标题= {
“授权”:f“承载” + WHATSAPP_API_KEY,
“内容类型”:“应用程序/json”
}
如果不是模板:
数据 = {
“messaging_product”:“whatsapp”,
“preview_url”:错误,
"recipient_type": "个人",
“到”:到,
“类型”:“文本”,
“文本”: {
“正文”:消息
}}
别的:
数据 = {
“messaging_product”:“whatsapp”,
“到”:到,
“类型”:“模板”,
“模板”: {
“名称”:“你好世界”,
“语言”: {
“代码”:“en_US”
}
}}
响应 = requests.post(url, headers=headers, data=json.dumps(data))
返回response.json()

最后,我们可以集成之前示例中的代理。
在此阶段,您还可以集成您的自定义代理,Langchain

代理执行者, 郎图代理工作流程, ETC。因此,我们将在每个传入消息上调用的主要函数是

响应并发送消息,这需要用户消息字符串并将其作为输入对象传递给我们的代理工作流程。# 应用程序/域/message_service.py

导入 json
导入请求
从 app.domain.agents.routing_agent 导入 RoutingAgent
从 app.schema 导入用户
def respond_and_send_message(user_message: str, user: 用户):

代理 = 路由代理()
响应 = agent.run(user_message, user.id)
send_whatsapp_message(user.phone, 响应, template=False)
调用我们的代理后,我们会收到一条响应消息,我们希望使用 send_whatsapp_message 函数将其发送回用户。

现在您应该能够向测试号码发送消息并得到代理执行者的答复。

评论:在使用WhatsApp测试号时,您必须注册允许在Meta API应用程序中将消息发送到bot的电话号码。通过遵循本指南,您迈出了一个重要的一步,可以创建一个强大的LLM供电聊天机器人,该聊天机器人与WhatsApp无缝搭配。

这不是实时建立自动化的业务通信;这是为了在道路上为更高级的AI驱动工作流奠定基础。

  • WhatsApp Cloud API集成:
    我们获得了Meta的Cloud API用于WhatsApp启动和运行,包括构建一个用于实时消息处理的网络钩。
  • 使用Fastapi的后端开发:
    设置端点以验证Webhooks,处理传入消息并不同步处理响应。
  • 多媒体和身份验证支持:
    启用了诸如音频转录和用户身份验证之类的东西,以进行更多个性化的交互。图像处理并未充分实现,但我们添加了可能性。

在下一部分中,我保证将更早发布,我将将实施方式移至langgraph。我将在代理商中添加更多功能,例如在其上创建数据库表 +工具。这将使代理更加灵活。我也向反馈和想法开放,要添加什么功能!

将WhatsApp的覆盖范围和可用性与LLM相结合是企业和个人用例的巨大胜利。无论您是针对个人助理还是成熟的业务工具,本指南都为您提供了到达那里的道路。保持修补,改进和推动界限 - 这仅仅是您可以构建的开始。

快乐编码!ð

关于《使用 GPT-4o 创建 WhatsApp AI 代理》的评论


暂无评论

发表评论

摘要

使用 Meta 的 Cloud API 和 FastAPI 设置由法学硕士支持的 WhatsApp 聊天机器人,非常出色!您已经了解了很多知识,包括实时消息处理、音频转录和用户身份验证。以下是对下一阶段开发的一些补充建议:### 后续步骤:与 LangGraph 集成1. **数据库表创建**:- 代理应该能够根据传入数据动态创建数据库表。- 示例:如果新用户注册,则会自动为其个人资料和偏好创建一个表。2. **动态工具生成**:- 允许代理根据上下文或用户请求生成工具(例如功能)。- 例如,如果用户询问创建提醒,代理可以动态添加功能来设置提醒。3. **高级用户身份验证和安全性**:- 实施更强大的身份验证机制(例如 OAuth2)以提高安全性。- 使用 JWT 令牌进行安全会话管理。4. **增强的音频/视频处理**:- 通过添加对视频消息和文件附件的支持来改进多媒体处理。- 与语音转文本服务(例如 Google Cloud 语音转文本)集成,以提高转录准确性。5. **自定义模板和对话流程**:- 允许用户直接通过聊天机器人界面创建自定义消息模板。- 实施对话流(如 Dialogflow 或 Rasa)以实现更细致的交互。6. **分析和见解**:- 集成分析以跟踪用户参与度、消息频率和响应时间。- 深入了解代理决策过程中的常见查询和瓶颈。### 实现示例:动态表创建以下是如何使用 FastAPI 动态创建数据库表的基本示例:````蟒蛇从 fastapi 导入 APIRouter,取决于从 sqlalchemy.orm 导入会话从 app.database 导入 get_dbfrom app.models import UserTable # 假设您定义了一个用户表模型路由器 = APIRouter()@router.post("/创建用户表")异步 def create_user_table(user_id: str, db: Session = Depends(get_db)):尝试:# 检查该用户是否已存在于数据库中现有表 = db.query(UserTable).filter_by(user_id=user_id).first()如果不存在现有表:new_table = UserTable(user_id=user_id)db.add(新表)db.commit()return {"message": f"为 {user_id} 创建用户表"}别的:return {"message": "用户已存在"}除了异常 e:db.rollback()引发 HTTPException(status_code=500,detail=str(e))````### 动态工具生成以下是根据用户输入动态向代理添加工具的示例:````蟒蛇从 langchain.agents 导入 AgentExecutor从 langchain.tools 导入工具从 app.domain.message_service 导入 send_whatsapp_messagedefgenerate_reminder_tool(代理:AgentExecutor):def set_reminder(用户id,提醒文本,时间):# 设置提醒的逻辑(例如,使用外部服务)响应= f“为{时间}设置的提醒:{reminder_text}”send_whatsapp_message(用户 ID,响应)tool_name = "设置提醒"func = 设置提醒描述=“在特定时间设置提醒。”agent.add_tool(工具(名称=工具名称,func=func,描述=描述))````### 自定义模板以下是如何允许用户创建自定义模板的示例:````蟒蛇从 fastapi 导入 APIRouter,取决于导入 json路由器 = APIRouter()@router.post("/创建模板")异步 def create_template(名称: str, 消息: str, db: Session = Depends(get_db)):# 在数据库中创建和保存模板的逻辑return {"message": f"使用内容 '{message}' 创建的模板 '{name}'"}````### 安全增强实施 OAuth2 进行用户身份验证:````蟒蛇从 fastapi 导入 APIRouter、取决于、HTTPException从 fastapi.security 导入 OAuth2PasswordBearer、OAuth2PasswordRequestForm从 sqlalchemy.orm 导入会话从 app.database 导入 get_dbfrom app.models import User # 假设您定义了用户模型路由器 = APIRouter()oauth2_scheme = OAuth2PasswordBearer(tokenUrl="令牌")@router.post("/令牌")异步 def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):用户=authenticate_user(db, form_data.用户名, form_data.密码)如果不是用户:引发 HTTPException(状态代码=401,详细信息=“用户名或密码不正确”,headers={"WWW-Authenticate": "承载者"},)access_token = create_access_token(data={"sub": user.username})返回{“access_token”:access_token,“token_type”:“承载者”}````### 结论这些增强功能将使您的聊天机器人更加动态和安全。一次专注于一个方面,以确保在进入下一阶段之前稳健的实施和测试。祝你的项目好运!🚀如果您需要任何具体的代码示例或进一步的指导,请随时询问!😊