← 返回首頁 部落格 English version

企業微信機器人 + 自部署 AI 服務 30 分鐘復現

從建立自建應用到在企業微信裡收到第一條 AI 訊息(含 4 個報錯修法)

2026-08-15 · Leo · 教程 · 15 分鐘閱讀
TL;DR — 一份 30 分鐘復現清單:企業微信管理後臺 → 建立自建應用 → 配接收訊息回撥(AES 解密)→ 跑通 AI 服務 → 在企業微信裡收到第一條訊息。文末 4 個常見報錯和修法,每一條都來自真實踩坑。
⚠️ 先避一個最大的坑:企業微信「群機器人」的 webhook 只能往外發訊息,收不到員工發來的訊息。要做能對話的 AI 助手,必須走自建應用 + 接收訊息回撥,本文全流程按這個走。

第 1 步:企業微信後臺建立自建應用

📌 建立應用 + 拿 CorpID / AgentId / Secret 5 分鐘
  1. 登入 work.weixin.qq.com(企業管理員)→ 應用管理 → 自建 → 建立應用
  2. 填應用名/頭像 → 建立後進入應用詳情,記錄三個值:
    • CorpID(我的企業 → 企業資訊 → 最底部)
    • AgentId(應用詳情頁,純數字)
    • Secret(應用詳情 → Secret → 檢視,關頁面後要重置才能再看)
  3. 應用詳情 → 企業可信 IP:填你伺服器的公網出口 IP(少了它調 API 報 60020,見文末報錯 3)
  4. 應用詳情 → 接收訊息 → 設定 API 接收:填 Token(自己編一串隨機字串)和 EncodingAESKey(點隨機生成)
  5. 「接收訊息」頁會要你填回撥 URL——先不填,第 3 步用 ngrok 拿到公網地址再回來填

第 2 步:寫一個能過回撥驗證的最小服務

🐍 Python Flask 回撥 + AES 解密 8 分鐘

企業微信回撥驗證比飛書多一層:GET 請求帶 msg_signatureechostr 是 AES 加密的,必須先解密再原樣返回。這段程式碼直接拷:

import hashlib, base64, struct
from flask import Flask, request, Response
from Crypto.Cipher import AES

app = Flask(__name__)

TOKEN = "你填的Token"
AES_KEY = "你填的EncodingAESKey"  # 43位,程式碼裡補一個"="
CORP_ID = "你的CorpID"

def decrypt_msg(encrypted):
    key = base64.b64decode(AES_KEY + "=")
    cipher = AES.new(key, AES.MODE_CBC, key[:16])
    plain = cipher.decrypt(base64.b64decode(encrypted))
    pad = plain[-1]
    plain = plain[:-pad]                      # 去 PKCS7 填充
    plain = plain[16:]                        # 去 16 位元組隨機串
    msg_len = struct.unpack("!i", plain[:4])[0]
    return plain[4:4 + msg_len].decode()      # 訊息體

def verify_signature(signature, timestamp, nonce, echostr):
    s = "".join(sorted([TOKEN, timestamp, nonce, echostr]))
    return hashlib.sha1(s.encode()).hexdigest() == signature

@app.route("/wecom/callback", methods=["GET"])
def verify_url():
    args = request.args
    if verify_signature(args["msg_signature"], args["timestamp"],
                        args["nonce"], args["echostr"]):
        return Response(decrypt_msg(args["echostr"]), mimetype="text/plain")
    return "signature error", 403

@app.route("/wecom/callback", methods=["POST"])
def receive_msg():
    # 企業微信 POST 的訊息體是 { Encrypt: "..." },同樣先驗籤再解密
    # 解密後是 XML:text + Content + FromUserName...
    # 這裡先列印日誌,第 4 步換成 AI 呼叫
    return Response("success", mimetype="text/plain")

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

⚠️ 依賴:pip install flask pycryptodome。企業微信要求回撥返回純文字 success(不是 JSON),返回別的會一直重試推送。

第 3 步:ngrok 暴露本地服務,填回撥 URL

🌐 公網回撥地址 2 分鐘
  1. 執行:ngrok http 8080(或 cloudflared / bore 都行)
  2. 複製 https://xxxx.ngrok-free.app 這樣的 URL
  3. 回企業微信「接收訊息」→ 填 https://xxxx.ngrok-free.app/wecom/callback → 儲存
  4. 儲存時企業微信會立刻 GET 一次驗證 URL——你的 verify_url() 返回解密後的 echostr 就透過,看到「儲存成功」即通

第 4 步:把回撥裡的 XML 換成 AI 呼叫

🤖 接 AI 服務 + 主動發訊息 10 分鐘

POST 回撥解密後是 XML,用 xml.etree 解析,然後調 AI,再用「傳送應用訊息」API 回給員工:

import requests, xml.etree.ElementTree as ET

def get_access_token():
    url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
    r = requests.get(url, params={"corpid": CORP_ID, "corpsecret": SECRET},
                     timeout=10)
    return r.json()["access_token"]          # 2 小時有效,建議快取

def send_to_user(user_id, content):
    token = get_access_token()
    url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"
    requests.post(url, params={"access_token": token}, json={
        "touser": user_id,                    # UserID,不是手機號/姓名
        "msgtype": "text",
        "agentid": AGENT_ID,
        "text": {"content": content}
    }, timeout=10)

# 在 receive_msg() 裡(解密出 xml_str 後):
root = ET.fromstring(xml_str)
user_id = root.findtext("FromUserName")      # 發訊息的員工 UserID
content = root.findtext("Content")           # 員工發的文字

reply = ask_ai(content)                       # 調你的自部署 AI 服務
send_to_user(user_id, reply)

第一次跑通後,再加:

第 5 步:設定可見範圍、正式上線

🚀 上線 5 分鐘
  1. 應用詳情 → 可見範圍:先選一個部門(如 IT 部)小範圍試點
  2. 把 ngrok 地址換成本機 Nginx 反代(proxy_pass http://127.0.0.1:8080)或直接部署到伺服器
  3. 企業微信「我的企業 → 微信外掛」——員工在企業微信裡就能搜到你的應用
  4. 給應用發條訊息 → 收到 AI 回覆 → 完成

踩過的 4 個報錯(30 分鐘夠踩完)

報錯 1:儲存回撥 URL 一直提示「驗證失敗」

企業微信驗證 URL 時 GET 帶 msg_signature,不是飛書那種 challenge 原樣返回。最常見兩個原因:驗簽字串沒按 Token/timestamp/nonce/echostr 排序後拼接;或者 echostr 沒解密直接返回了密文。

✅ 修法:按上面程式碼順序來——排序拼接 → SHA1 → 比對 → AES 解密(去隨機串、去 4 位元組長度、去 PKCS7 填充)→ 返回明文。任何一步錯都「驗證失敗」且無詳細日誌,逐行對。
報錯 2:回撥一直收不到 / 企業微信反覆重試推送

回撥處理必須返回純文字 success(Content-Type: text/plain)。返回 JSON 或 HTTP 非 200,企業微信會按 3s/10s/1min 間隔反覆重試,日誌刷屏。

✅ 修法:return Response("success", mimetype="text/plain")。收到訊息先回 success 再去處理 AI(非同步),避免 AI 慢導致超時重試。
報錯 3:調 API 報 60020「not allow to access from your ip」

企業微信所有 API 校驗伺服器出口 IP。你本地除錯時 IP 一直在變,呼叫就報 60020。

✅ 修法:應用詳情 → 企業可信 IP → 把伺服器固定公網 IP 加進去(最多 120 個)。本地除錯可以臨時加自己當前出口 IP,或者全走伺服器代理。
報錯 4:訊息發出去了(API 返回 0),員工卻收不到

最常見兩個原因:touser 傳的是姓名/手機號,但 API 只認 UserID(通訊錄裡那個字母數字 ID);或者應用可見範圍沒包含這個員工。

✅ 修法:回撥 XML 裡 FromUserName 就是 UserID,直接拿來當 touser 最穩。傳送前確認該員工在應用可見範圍內。

30 分鐘後你會有...

下一步(按重要性排):

  1. 加知識庫(最重要,能解決 80% 業務問題)
  2. 加記憶(使用者上次問過什麼)
  3. 接其他 IM(飛書 / 釘釘)——飛書版教程見 04 篇
🤝 整過了一遍,仍然想找現成的?
📧 278946228@qq.com(一般 24 小時內回)