DEV Community

Rock
Rock

Posted on

Wiring Dify into WeCom Customer Service: install a Runner plugin, let an Agent own message.received

Scenario

The knowledge base, prompts and tools live in a Dify application; the WeCom customer-service side only answers customers. Today every question is retyped into Dify's chat box and the answer copied back — the two are not connected.

On 4.10 the only route was a pipeline: Dify as a provider (Dify service API), wired into one pipeline. That duplicated the orchestration — Dify canvas plus LangBot's own model, prompt and conversation settings — and one pipeline served one bot.

4.11 makes a processor an Agent, whose Runner comes from a plugin. Connecting Dify to WeCom customer service becomes three configuration actions, walked below on a local instance.

How it works in 4.11

Runners are marketplace plugins. Dify is the official langbot-team/DifyAgent plugin, runner id plugin:langbot-team/DifyAgent/default (official docs docs/agent-runner-pluginization/OFFICIAL_RUNNER_PLUGINS.md:29 maps the old dify-service-api runner to it). It sits in Batch 1, "traditional service API runner" (:45), and the old built-in runner code provides no runtime fallback (:22).

Connection details live in the processor's runner config. Choose Agent mode, pick Dify Agent, then fill Dify-side values; DOM readings here (measured 2026-10-16): 基础 URL (http://dify:5001/v1), API 密钥, 超时 (30), 过期 (3600), 身份 (发送者).

Event routing maps events to processors; the first match wins. Matching picks by priority from high to low, then list order, and runs exactly one response target (official docs docs/event-based-agents/04-event-routing.md:118-119) — so a second route on message.received would not make Dify run twice.

Adapters declare a platform's events. This one declares message.received, message.deleted, wecomcs.enter_session and more, plus send_message, reply_message, get_message, get_user_info (source LangBot/src/langbot/pkg/platform/adapters/wecomcs/adapter.py:79-99). Route-editor presets follow those declarations (source LangBot/web/src/app/home/bots/components/bot-form/EventBindingsEditor.tsx:1554-1559). Support depends on the adapter and platform — check the support matrix first.

Hands-on steps

Fire up a local instance to try this on (the exact commands used in the recorded run):

docker network create a4
docker run -d --name a4-core --network a4 --restart on-failure -e TZ=Asia/Shanghai \
  -e BOX__ENABLED=false -e SPACE__DISABLE_TELEMETRY=true -p 15800:5300 \
  -v "$PWD/deploy/a4/data:/app/data" rockchin/langbot:v4.11.0
docker run -d --name a4-runtime --network a4 --network-alias langbot_plugin_runtime --restart on-failure \
  -e TZ=Asia/Shanghai -e SPACE__DISABLE_TELEMETRY=true -v "$PWD/deploy/a4/data/plugins:/app/data/plugins" \
  rockchin/langbot:v4.11.0 uv run --no-sync -m langbot_plugin.cli.__init__ rt
Enter fullscreen mode Exit fullscreen mode

Admin account demo@langbot.local / LangBot411!demo (local demo value — replace with your own).

  1. Create the WeCom customer-service bot: Bots → New → platform 企业微信客服 (WeCom Customer Service); 企业ID, 密钥, 令牌 and 消息加解密密钥 are required, Webhook 回调地址 is optional (real traffic needs a public URL). Fields per LangBot/src/langbot/pkg/platform/sources/wecomcs.yaml (spec.legacy: true). This instance keeps demo values.

Bot wizard: 企业微信客服 (WeCom Customer Service) selected

  1. Install the Dify Agent runner plugin: Marketplace → search Dify → 「Dify Agent」 → install. Measured progress text (2026-10-16): 「已完成」「100%」「包大小: 169.8 KB」「安装成功」; the installed card carries aria-label="已安装 Dify Agent".

Marketplace search for Dify: the Dify Agent card

Installed plugin card: Dify Agent by langbot-team

  1. Create the Agent: Processors → New → Agent mode → runner Dify Agent (the processor here is dify-wecomcs-agent).

Runner picker listing installed plugins

  1. Fill in the Dify connection: 基础 URL must be reachable from the runtime container (alias dify here, hence http://dify:5001/v1, local demo value — replace with your own); API 密钥 is app-demo-dify-key here (local demo value — replace with your own); 超时 30, 过期 3600, 身份 发送者.

Runner config: base URL, API key, timeout, expiry, identity

  1. Bind the event route: bot detail page (/home/bots?id=<uuid> — a query parameter, not a path segment; source LangBot/web/src/app/home/bots/page.tsx:7-8) → event routing → route 1 is 收到消息 message.received; switch its processor from ⚙️ 企业微信客服 流水线 to 🤖 dify-wecomcs-agent, then reload.
  2. Check the route: the route-check reply, measured verbatim on 2026-10-16, is 已命中路由 | 目标处理器 | Agent · dify-wecomcs-agent | 命中规则 | 第 1 条路由 | 诊断步骤 | 已选择第 1 条路由。

Route check: target Agent · dify-wecomcs-agent

  1. Run one event-debug pass: Agent detail → event debug → run test with 「请问你们支持私有化部署吗?」.

Event debug: Dify received the question, answered by the local endpoint

Verify

The first check is the route-check reply quoted in step 6. For the second, read the Dify endpoint's log. This walkthrough used a local Dify-compatible endpoint (container lang7-dify, deploy/a4/dify-stub.py, alias dify, host 127.0.0.1:18710 → 5001, implementing only POST /v1/chat-messages):

docker logs lang7-dify
Enter fullscreen mode Exit fullscreen mode

One measured request line, verbatim:

[2026-10-16T16:28:29] POST /v1/chat-messages auth=Bearer app-dem... body={"inputs": {}, "query": "请问你们支持私有化部署吗?", "user": "lb_3ae22b5eaf4cf199693bee82712ae06f5ea6c21128cd9feab3dc347985a5e56", "response_mode": "streaming", "conversation_id": "", "files": []}
Enter fullscreen mode Exit fullscreen mode

On your own deployment, look for a POST /v1/chat-messages whose query is the sentence you sent.

Do not read multi-turn continuity into this. The session fired three times (16:28:29, 16:28:50, 16:38:28), each with an empty conversation_id; delivery and a returned answer are all this proves. [Inference] The runner plugin reads the id from ctx.state.conversation["external.conversation_id"] and passes an empty string when none is there, so the first call cannot carry one; later calls would only if the plugin writes Dify's returned conversation_id back into state. Official docs ask external runners to keep that id in plugin storage or context runtime state rather than LangBot's internal conversation uuid structure (official docs docs/agent-runner-pluginization/OFFICIAL_RUNNER_PLUGINS.md §6). To be confirmed.

Limits and caveats

  • Not a real Dify deployment. Replace 基础 URL and API 密钥 with your own Dify site's values (local demo value — replace with your own).
  • No real WeCom customer message entered the system. Real traffic needs 企业ID, 密钥, 令牌, 消息加解密密钥 and a public callback URL; this instance keeps demo values. Verified here: the configuration taking effect, plus the Agent ↔ Dify round trip — not a customer on a phone. Support depends on the adapter and platform — check the support matrix first.
  • Debug platform actions are simulated. The page says: 「平台工具使用 Mock:Agent 真实调用工具,回复、发送等平台动作模拟执行,不发送真实消息。其他工具仍按实际配置执行。」 (measured 2026-10-16) — a passing debug run shows the configuration is live, not that WeCom-side delivery matches.
  • Multi-turn continuity is unverified. All three triggers carried an empty conversation_id.
  • One response target per event. A second route on the same event does not make Dify run twice, and the old pipeline should not stay on that event.
  • The runner is a plugin. Old built-in runners get no runtime fallback (official docs docs/agent-runner-pluginization/OFFICIAL_RUNNER_PLUGINS.md:22); another environment needs the plugin installed too.

Summary and next steps

Connecting Dify to WeCom customer service on 4.11 is three configuration actions: install langbot-team/DifyAgent, create an Agent-mode processor holding the Dify 基础 URL and API 密钥, and point the bot's message.received route at it. This walkthrough exercised the message reaching Dify and an answer coming back.

The migration reference is frozen at pipeline-migration-config-map.zh-CN.md, mapping a Dify provider from an old pipeline to its replacement plugin and config. See the v4.11.0 release for the change list; the series' second and third articles cover runner-plugin provenance and the 4.10 → 4.11 upgrade. A hosted option is worth evaluating separately if you would rather not maintain an instance (space.langbot.app) — this article covers self-hosted deployments only.

Top comments (0)