You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于LangChain、FastAPI与Meta Webhooks的WhatsApp机器人重复POST请求问题

WhatsApp聊天机器人重复触发Meta Webhook请求问题

我用LangChain、FastAPI和Meta Webhooks做了个WhatsApp聊天机器人,现在碰到个棘手的问题——用户发一条消息,AgentExecutor链会多次触发Meta Webhooks的200 OK POST请求。

下面是我的Webhook处理代码:

@router.post("/webhook")
async def webhook_events(request: Request):
    payload = await request.json()

    # print(json.dumps(payload, indent=4))
    message = ""
    # print(payload)
    if "contacts" in payload["entry"][0]["changes"][0]["value"]:
        user_name = payload["entry"][0]["changes"][0]["value"]["contacts"][0]["profile"]["name"]
        wa_id = payload["entry"][0]["changes"][0]["value"]["contacts"][0]["wa_id"]
        user_id = user_name.split(" ")[0] + "@" + wa_id

    if "messages" in payload["entry"][0]["changes"][0]["value"]:
        reciepient = payload["entry"][0]["changes"][0]["value"]["messages"][0]["from"]
        chat_history = RedisChatMessageHistory(user_id)
        memory = ConversationBufferMemory(
            chat_memory=chat_history,
            memory_key="chat_history",
            return_messages=True)
        if not chat_history.messages:
            chat_history.add_ai_message("Hi! What's your name? I'm MobSecBot, designed to help you with your mobile and security questions.")
            chat_history.add_user_message(f"Hi! My name is {user_name}.")
            expire_chat_history(r, f'message_store:{user_id}')

        agent_chain = agent_handler.init_chain(agent, memory)
        # agent_chain = initialize_agent(
        #             tools,
        #             llm,
        #             agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
        #             memory=memory,
        #             handle_parsing_errors="Check your output and make sure it conforms!")
        if "text" in payload["entry"][0]["changes"][0]["value"]["messages"][0]:
            message = payload["entry"][0]["changes"][0]["value"]["messages"][0]["text"]["body"]
            
            print(f"{reciepient}: {message}")
            try:
                response = agent_chain.run(message)
            except Exception as e:
                response = str(e)
                # response = response.removeprefix("Could not parse LLM output: `").removesuffix("`")
            print(f"MobSecBot: {response}")
        else:
            response = "Sorry! I can only respond to text messages for now."
        await messenger.send_message(response, reciepient)

参考图片:两张请求日志截图,显示了多次重复的200 OK POST请求记录。

问题排查和解决思路

1. Meta Webhook重试触发(最可能原因)

Meta的Webhook有重试机制:如果接口超过几秒没返回200,它会重复发送请求。你的代码里agent_chain.run(message)是同步阻塞调用,LLM调用、工具调用都很耗时,导致FastAPI没法快速给Meta回200,直接触发了重试,所以会出现多次请求记录。

解决办法:
用FastAPI的BackgroundTasks把Agent处理和消息发送逻辑放到后台,让接口先立刻返回200给Meta,避免重试:

from fastapi import BackgroundTasks

@router.post("/webhook")
async def webhook_events(request: Request, background_tasks: BackgroundTasks):
    payload = await request.json()

    message = ""
    user_id = None
    reciepient = None
    response = ""
    user_name = ""

    # 先快速解析所有必要参数,不做耗时操作
    if "contacts" in payload["entry"][0]["changes"][0]["value"]:
        user_name = payload["entry"][0]["changes"][0]["value"]["contacts"][0]["profile"]["name"]
        wa_id = payload["entry"][0]["changes"][0]["value"]["contacts"][0]["wa_id"]
        user_id = user_name.split(" ")[0] + "@" + wa_id

    if "messages" in payload["entry"][0]["changes"][0]["value"]:
        reciepient = payload["entry"][0]["changes"][0]["value"]["messages"][0]["from"]
        if "text" in payload["entry"][0]["changes"][0]["value"]["messages"][0]:
            message = payload["entry"][0]["changes"][0]["value"]["messages"][0]["text"]["body"]
        else:
            response = "Sorry! I can only respond to text messages for now."

    # 把耗时的Agent处理和消息发送丢到后台任务
    async def process_and_send():
        nonlocal response, user_id, reciepient, message, user_name
        if message and user_id:
            chat_history = RedisChatMessageHistory(user_id)
            memory = ConversationBufferMemory(
                chat_memory=chat_history,
                memory_key="chat_history",
                return_messages=True)
            if not chat_history.messages:
                chat_history.add_ai_message("Hi! What's your name? I'm MobSecBot, designed to help you with your mobile and security questions.")
                chat_history.add_user_message(f"Hi! My name is {user_name}.")
                expire_chat_history(r, f'message_store:{user_id}')

            agent_chain = agent_handler.init_chain(agent, memory)
            try:
                response = agent_chain.run(message)
            except Exception as e:
                response = str(e)
            print(f"{reciepient}: {message}")
            print(f"MobSecBot: {response}")
        if reciepient:
            await messenger.send_message(response, reciepient)

    if reciepient:
        background_tasks.add_task(process_and_send)

    # 立刻返回200,告诉Meta我收到了
    return {"status": "ok"}

2. Agent内部重复调用

检查你的agent_handler.init_chain配置的Agent,有没有设置成多次调用工具,或者工具内部逻辑触发了Webhook相关请求,导致循环触发。

解决办法:

  • 开启LangChain的DEBUG日志,打印Agent的思考和调用步骤,看是否有重复执行的环节。
  • 检查messenger.send_message方法,确认它不会触发Meta的Webhook回调,避免循环请求。

3. Redis聊天历史异常

如果Redis里的聊天历史有重复消息,可能导致Agent重复处理,间接引发多次请求。

解决办法:

  • 给初始消息添加判断逻辑,避免重复写入(比如检查历史里有没有初始问候再添加)。
  • 确认expire_chat_history方法正确设置了过期时间,避免残留的历史消息干扰。

内容的提问来源于stack exchange,提问作者Kushagra Punia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:28:10