Merge remote-tracking branch 'origin/master' into ci/daily-endurance

# Conflicts:
#	tools/regression_ci.py
This commit is contained in:
huanghuoguoguo
2026-10-28 12:15:19 +08:00
145 changed files with 5994 additions and 366 deletions
+54
View File
@@ -0,0 +1,54 @@
name: Refresh Context7 docs
# Re-index the public documentation in Context7 whenever the English docs change.
# Requires a repository secret CONTEXT7_API_KEY (context7.com/dashboard) and a
# Context7 library registered for this repository; both are one-time owner steps.
# Until the secret exists every run is a no-op instead of a failure.
on:
push:
branches: [master]
paths:
- "docs/en/**"
- "context7.json"
- ".github/workflows/context7-refresh.yml"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: context7-refresh
cancel-in-progress: true
jobs:
refresh:
name: Refresh Context7 library
runs-on: ubuntu-latest
timeout-minutes: 5
env:
CONTEXT7_API_KEY: ${{ secrets.CONTEXT7_API_KEY }}
CONTEXT7_LIBRARY: /langbot-app/langbot
steps:
- name: Skip when the Context7 API key is not configured
if: env.CONTEXT7_API_KEY == ''
run: |
echo "CONTEXT7_API_KEY is not configured; skipping the Context7 refresh."
echo "Add the secret and register the library, then re-run this workflow."
- name: Trigger Context7 refresh
if: env.CONTEXT7_API_KEY != ''
run: |
set -euo pipefail
body=$(printf '{"libraryName":"%s"}' "$CONTEXT7_LIBRARY")
code=$(curl -sS -o "$RUNNER_TEMP/refresh.json" -w '%{http_code}' \
-X POST https://context7.com/api/v1/refresh \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ${CONTEXT7_API_KEY}" \
-d "$body")
cat "$RUNNER_TEMP/refresh.json"
if [ "$code" -lt 200 ] || [ "$code" -ge 300 ]; then
echo "Context7 refresh failed with HTTP $code" >&2
exit 1
fi
echo "Requested a refresh of ${CONTEXT7_LIBRARY}."
+2 -2
View File
@@ -14,7 +14,7 @@ concurrency:
jobs:
sync:
if: github.repository == 'langbot-app/LangBot' && github.ref == 'refs/heads/master' && vars.DOCS_MIRROR_ENABLED == 'true'
if: github.repository == 'langbot-app/LangBot' && github.ref == 'refs/heads/master' && vars.DOCS_PUBLISH_ENABLED == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
defaults:
@@ -26,7 +26,7 @@ jobs:
with:
ref: master
fetch-depth: 0
# A PAT push triggers the mirror and Wiki workflows; GITHUB_TOKEN does not.
# A PAT push triggers the landing and Wiki workflows; GITHUB_TOKEN does not.
token: ${{ secrets.LANGBOT_WIKI_PUSH_TOKEN || secrets.RELEASE_UPLOAD_GITHUB_TOKEN }}
- uses: actions/setup-node@v7
with:
+1 -1
View File
@@ -57,7 +57,7 @@ jobs:
sync:
name: Publish to LangBot Wiki
if: github.event_name != 'pull_request' && github.repository == 'langbot-app/LangBot' && github.ref == 'refs/heads/master' && vars.DOCS_MIRROR_ENABLED == 'true'
if: github.event_name != 'pull_request' && github.repository == 'langbot-app/LangBot' && github.ref == 'refs/heads/master' && vars.DOCS_PUBLISH_ENABLED == 'true'
needs: build
runs-on: ubuntu-latest
timeout-minutes: 5
+2 -12
View File
@@ -1,4 +1,4 @@
name: Sync docs mirror and landing submodule
name: Sync landing docs from LangBot
on:
push:
@@ -15,7 +15,7 @@ concurrency:
jobs:
sync:
if: github.repository == 'langbot-app/LangBot' && github.ref == 'refs/heads/master' && vars.DOCS_MIRROR_ENABLED == 'true'
if: github.repository == 'langbot-app/LangBot' && github.ref == 'refs/heads/master' && vars.DOCS_PUBLISH_ENABLED == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
@@ -27,16 +27,6 @@ jobs:
- name: Test synchronization contracts
working-directory: docs
run: python3 -m unittest discover -s tests -p test_sync_landing_submodule.py -v
- name: Publish docs subtree (fast-forward only)
env:
GH_TOKEN: ${{ secrets.LANGBOT_WIKI_PUSH_TOKEN || secrets.RELEASE_UPLOAD_GITHUB_TOKEN }}
run: |
gh auth setup-git
git remote add docs-mirror https://github.com/langbot-app/langbot-docs.git
git fetch docs-mirror main
docs_sha=$(git subtree split --prefix=docs)
git merge-base --is-ancestor docs-mirror/main "$docs_sha"
git push docs-mirror "$docs_sha:refs/heads/main"
- name: Update landing submodule and production fork
working-directory: docs
env:
+1 -1
View File
@@ -44,7 +44,7 @@ Run tests in Linux to match CI; on Windows, use Linux containers through `wslc`
## Where to Look
- Public documentation source: `docs/`; published at https://langbot.app/docs/. `langbot-app/langbot-docs` is a generated subtree mirror; edit here.
- Public documentation source: `docs/`; published at https://langbot.app/docs/. `langbot-app/langbot-docs` is a legacy archive; edit here.
- Architecture map: `ARCHITECTURE.md`.
- Dev environment guide: https://langbot.app/docs/zh/develop/dev-config.
- Plugin runtime / CLI / SDK debugging: https://langbot.app/docs/zh/develop/plugin-runtime.
+1 -1
View File
@@ -348,4 +348,4 @@ When one of these changes, update the others if the behavior or contract changed
## Documentation repositories
The public documentation site lives in `docs/` and is built with Node.js 24 and Fumapress. Internal design and review notes live in `dev-docs/`. The `langbot-app/langbot-docs` repository is a fast-forward subtree mirror for the landing site submodule and Context7. See `dev-docs/DOCS_MIGRATION.md` for publication and cutover details.
The public documentation site lives in `docs/` and is built with Node.js 24 and Fumapress. Internal design and review notes live in `dev-docs/`. The landing site keeps its `docs` submodule path but tracks LangBot `master`, building from the nested `docs/` directory. The old `langbot-app/langbot-docs` repository can be archived; publication never writes to it. See `dev-docs/DOCS_MIGRATION.md` for publication and cutover details.
+1 -1
View File
@@ -189,4 +189,4 @@ Thanks to all [contributors](https://github.com/langbot-app/LangBot/graphs/contr
<img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>
[Documentation source](https://github.com/langbot-app/LangBot/tree/main/docs) · [langbot-docs mirror](https://github.com/langbot-app/langbot-docs)
[Documentation source](https://github.com/langbot-app/LangBot/tree/master/docs) · [langbot-docs archive](https://github.com/langbot-app/langbot-docs)
+1 -1
View File
@@ -213,4 +213,4 @@ LangBot **从设计上就对 Agent 友好** —— 你的编码 Agent(Claude C
If you're a code agent based on LLM, you should read [AGENTS.md](AGENTS.md) to understand the project structure and development process before you start any development.
-->
[文档源码](https://github.com/langbot-app/LangBot/tree/main/docs) · [langbot-docs mirror](https://github.com/langbot-app/langbot-docs)
[文档源码](https://github.com/langbot-app/LangBot/tree/master/docs) · [langbot-docs archive](https://github.com/langbot-app/langbot-docs)
+1 -1
View File
@@ -187,4 +187,4 @@ Gracias a todos los [colaboradores](https://github.com/langbot-app/LangBot/graph
<img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>
[Código fuente de la documentación](https://github.com/langbot-app/LangBot/tree/main/docs) · [langbot-docs mirror](https://github.com/langbot-app/langbot-docs)
[Código fuente de la documentación](https://github.com/langbot-app/LangBot/tree/master/docs) · [langbot-docs archive](https://github.com/langbot-app/langbot-docs)
+1 -1
View File
@@ -187,4 +187,4 @@ Merci à tous les [contributeurs](https://github.com/langbot-app/LangBot/graphs/
<img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>
[Sources de la documentation](https://github.com/langbot-app/LangBot/tree/main/docs) · [langbot-docs mirror](https://github.com/langbot-app/langbot-docs)
[Sources de la documentation](https://github.com/langbot-app/LangBot/tree/master/docs) · [langbot-docs archive](https://github.com/langbot-app/langbot-docs)
+1 -1
View File
@@ -187,4 +187,4 @@ LangBot をより良くするために貢献してくださったすべての[
<img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>
[ドキュメントのソース](https://github.com/langbot-app/LangBot/tree/main/docs) · [langbot-docs mirror](https://github.com/langbot-app/langbot-docs)
[ドキュメントのソース](https://github.com/langbot-app/LangBot/tree/master/docs) · [langbot-docs archive](https://github.com/langbot-app/langbot-docs)
+1 -1
View File
@@ -187,4 +187,4 @@ LangBot을 더 나은 프로젝트로 만들어 주신 모든 [기여자](https:
<img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>
[문서 소스](https://github.com/langbot-app/LangBot/tree/main/docs) · [langbot-docs mirror](https://github.com/langbot-app/langbot-docs)
[문서 소스](https://github.com/langbot-app/LangBot/tree/master/docs) · [langbot-docs archive](https://github.com/langbot-app/langbot-docs)
+1 -1
View File
@@ -187,4 +187,4 @@ LangBot **дружелюбен к агентам по своей архитек
<img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>
[Исходники документации](https://github.com/langbot-app/LangBot/tree/main/docs) · [langbot-docs mirror](https://github.com/langbot-app/langbot-docs)
[Исходники документации](https://github.com/langbot-app/LangBot/tree/master/docs) · [langbot-docs archive](https://github.com/langbot-app/langbot-docs)
+1 -1
View File
@@ -205,4 +205,4 @@ LangBot **從設計上就對 Agent 友善** —— 你的編碼 Agent(Claude C
<img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>
[文件原始碼](https://github.com/langbot-app/LangBot/tree/main/docs) · [langbot-docs mirror](https://github.com/langbot-app/langbot-docs)
[文件原始碼](https://github.com/langbot-app/LangBot/tree/master/docs) · [langbot-docs archive](https://github.com/langbot-app/langbot-docs)
+1 -1
View File
@@ -187,4 +187,4 @@ Cảm ơn tất cả [người đóng góp](https://github.com/langbot-app/LangB
<img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>
[Mã nguồn tài liệu](https://github.com/langbot-app/LangBot/tree/main/docs) · [langbot-docs mirror](https://github.com/langbot-app/langbot-docs)
[Mã nguồn tài liệu](https://github.com/langbot-app/LangBot/tree/master/docs) · [langbot-docs archive](https://github.com/langbot-app/langbot-docs)
+7
View File
@@ -0,0 +1,7 @@
{
"$schema": "https://context7.com/schema/context7.json",
"projectTitle": "LangBot",
"description": "Open-source platform for building AI agents and instant-messaging bots.",
"branch": "master",
"folders": ["docs/en"]
}
+64 -61
View File
@@ -1,69 +1,72 @@
# Documentation subtree and publication
# Documentation publication after the repository migration
Public docs live in `LangBot/docs/`. The former internal `docs/` directory is
`dev-docs/` (27 top-level entries, 87 tracked files at migration). Do not merge
this migration using GitHub squash or rebase: use a merge commit to retain the
subtree parent and original signed commits. Imported history is reachable through
the subtree merge's second parent. Use `git log <imported-docs-sha> -- <file>`
(with the original path relative to the docs repository) to see original authors.
A path-limited `git log docs/` or `--follow` does not reliably traverse the
unrelated-history import. The imported commit is
`51dddcb3f891d60bc38645e88b2dbd515344da81` (888 commits, including 452 signed
commit objects, all retained without rewriting).
Public docs live in `LangBot/docs/`; internal notes live in `dev-docs/`. The
original 27 top-level internal entries (87 files) were moved without loss.
The unsquashed subtree import retains all 888 commits, including 452 signed
objects, from `51dddcb3f891d60bc38645e88b2dbd515344da81`. Use
`git log 51dddcb3f891d60bc38645e88b2dbd515344da81 -- <original-path>` to inspect
the original authors. The import is already merged; do not rewrite that history.
## Local checks
## Publication source
With Node.js 24, run `npm ci`, `npm run typecheck`, `npm test`, and `npm run build`
inside `docs/`. Output is `docs/dist/`. The site remains mounted at `/docs/` with
canonical URL `https://langbot.app/docs`.
`langbot-app/langbot-docs` is a historical archive, not a writable mirror.
No publication step splits or pushes to that repository. The landing repository
keeps its submodule **path** `docs`, but its **URL** is
`https://github.com/langbot-app/LangBot.git`, tracking `master`. Consequently,
the landing build runs the documentation package inside `docs/docs/` and copies
`docs/docs/dist/public` to `public/docs`. The public URL stays
`https://langbot.app/docs/`; Vite's base path and canonical site URL are unchanged.
## Cutover after the PR is reviewed and merged
The main-repository synchronization job advances only the landing gitlink to
LangBot `master` and then synchronizes `RockChinQ/LangBot-LandingPage-Vue`.
It checks `.gitmodules` on the exact landing revision it updates, refuses old
repository configurations, and rejects rewinds/divergence. It never force-pushes.
1. Pause the legacy `sync-blog-articles.yml` workflow in `langbot-app/langbot-docs`
and let any running writer finish. Freeze direct commits to that repository.
Pause its legacy Wiki and landing sync workflows too, avoiding duplicate
publishers while switching ownership. Do not push disabling commits directly
to the mirror.
2. Fetch mirror `main` and confirm it is an ancestor of the new subtree split.
If it advanced since import, integrate it with an **unsquashed**
`git subtree pull --prefix=docs <mirror-url> main` through another reviewed PR
before cutover; reapply the inert mirror workflow files if necessary. Never
force-push or rewrite the mirror history.
3. The publication jobs read `LANGBOT_WIKI_PUSH_TOKEN` and fall back to the
existing `RELEASE_UPLOAD_GITHUB_TOKEN` when that secret is absent. The fallback
was verified on a scratch branch: it authenticates as the repository owner
with `repo` scope and push+admin on `LangBot`, `langbot-docs`,
`langbot-landing-page` and the production fork, and it can clone and push the
Wiki. It does not carry the `workflow` scope, so it cannot push changes to
`.github/workflows/**` in the mirror; the split only rewrites `docs/**`
content, so this is fine unless a future change edits the inert mirror stubs.
Adding a dedicated `LANGBOT_WIKI_PUSH_TOKEN` with the same access keeps the
blast radius of the fallback credential out of the docs pipeline. Do not
weaken branch protection to accommodate this migration.
4. Set LangBot repository variable `DOCS_MIRROR_ENABLED=true`. Dispatch
`sync-landing-submodule.yml` on master. It fetches full master history, runs
`git subtree split --prefix=docs`, verifies the current mirror head is an
ancestor, pushes without force, then advances only landing's `docs` gitlink.
The first split replaces legacy mirror workflows with inert manual stubs.
5. Dispatch `sync-github-wiki.yml` and `sync-blog-articles.yml` in LangBot.
The blog job now commits only docs article paths to LangBot master using the
dedicated token, so its push triggers the mirror and Wiki workflows.
6. Confirm the `docs` gitlink in `langbot-app/langbot-landing-page`, then confirm
production fork `RockChinQ/LangBot-LandingPage-Vue` matches upstream. This is
the actual fork in the existing sync script (not the similarly named fork
mentioned in the original migration proposal). Observe Cloudflare Pages
deployment and check `https://langbot.app/docs/`, localized pages, assets,
sitemap and canonical URLs. Verify Wiki pages after publication.
## Cutover order
The four root workflows own publication and validation. Nested workflow stubs
are intentionally inert when split into the mirror. No direct writes should be
made to the mirror after cutover; all edits belong in LangBot `docs/`.
1. Merge the paired landing PR: change `.gitmodules`, the pinned `docs` gitlink,
and `scripts/build-embedded-docs.mjs` together. Verify its full `pnpm build`.
2. Merge the main-repository publication changes. Keep publishers disabled until
both repositories are ready; the new flag is `DOCS_PUBLISH_ENABLED`, not
`DOCS_MIRROR_ENABLED`. The old flag does not enable these jobs.
3. Stop the old repository's Blog, Wiki and landing workflows and let any active
writers finish. The owner can archive `langbot-app/langbot-docs` once the
new publication chain is verified. Never write disabling commits to it as
part of the new publication chain.
4. Verify `LANGBOT_WIKI_PUSH_TOKEN`, or the existing `RELEASE_UPLOAD_GITHUB_TOKEN`
fallback, has access to LangBot, landing, production fork and Wiki. No token
value belongs in logs. Publication only updates gitlinks/content, never
workflow files in another repository, and no docs-mirror permission is needed.
5. Set `DOCS_PUBLISH_ENABLED=true` in LangBot. Dispatch
`sync-landing-submodule.yml` on **master**. It also brings the production fork
up to date; confirm the fork matches landing main and observe Cloudflare's
resulting deployment before accepting the cutover.
6. Dispatch `sync-github-wiki.yml` and `sync-blog-articles.yml` on **master**.
The Blog job commits only `docs/` article paths to LangBot using a token whose
pushes trigger subsequent landing/Wiki workflows. Wiki images and attribution
now point to LangBot `master/docs`, so new assets do not depend on the archive.
7. Check `/docs/`, the en/zh/ja guide pages, assets, sitemap, Markdown exports,
Wiki content and Blog idempotency. A successful Wiki build is not proof of
publication: inspect the separate publish job.
`docs/context7.json` continues to identify `langbot-app/langbot-docs` because that
repository remains available with the same tree layout and original history.
Verify Context7 ingestion after the first mirror update; no library re-registration
is needed merely to relocate the authoring source.
## Context7
Disable `DOCS_MIRROR_ENABLED` to pause publishers if cutover fails. A failed
mirror ancestry check must be investigated and reconciled, never bypassed by a
force push. Do not restore direct mirror writers while LangBot is authoritative.
The root `context7.json` follows the published Context7 schema and selects
`master:docs/en`. Context7's current parser indexes English documentation.
The old nested ownership configuration belonged to the legacy repository and
has been removed; it does not transfer ownership of a Context7 library.
The owner must add/refresh `https://github.com/langbot-app/LangBot` in Context7
and verify a result from `docs/en` after merge. The existing
`/langbot-app/langbot-docs` index is only a historical snapshot after archival.
Do not report an index refresh as complete solely because this config exists.
## Local validation and recovery
Use Node.js 24. In `docs/`, run `npm ci`, `npm run typecheck`, `npm test`, and
`npm run build`. In landing, initialize the submodule and run `pnpm install
--frozen-lockfile`, `pnpm test`, and `pnpm build`.
Disable `DOCS_PUBLISH_ENABLED` to pause publication. If landing still points at
the legacy repository or the production fork has diverged, reconcile through
reviewed changes; do not bypass the synchronization checks. Keep the last
working deployment available until the replacement passes verification.
@@ -21,7 +21,7 @@ Status: partial migration. The EBA adapter structure, manifest, converters, cach
| Event | Evidence | Notes |
| --- | --- | --- |
| `message.received` | adapter-live, unit | `C2C_MESSAGE_CREATE`, `DIRECT_MESSAGE_CREATE`, `GROUP_AT_MESSAGE_CREATE`, and `AT_MESSAGE_CREATE` map to common `MessageReceivedEvent`. A real WebSocket-mode QQ Official bot reached the LangBot pipeline on `dev.rockchin.top`; plugin JSONL evidence remains pending. |
| `message.received` | adapter-live, unit | `C2C_MESSAGE_CREATE`, `DIRECT_MESSAGE_CREATE`, `GROUP_AT_MESSAGE_CREATE`, `GROUP_MESSAGE_CREATE`, and `AT_MESSAGE_CREATE` map to common `MessageReceivedEvent`. Full-group mode has protocol regression coverage; the earlier live probe below covered the original message path. |
| `message.reaction` | unit | `MESSAGE_REACTION_ADD` and `MESSAGE_REACTION_REMOVE` map to common `MessageReactionEvent`. Live gateway evidence is pending. |
| `group.member_joined` | unit | `GUILD_MEMBER_ADD` and `GROUP_MEMBER_ADD` map to common `MemberJoinedEvent` when the gateway payload carries a group/guild/channel ID and member openid. |
| `group.member_left` | unit | `GUILD_MEMBER_REMOVE` and `GROUP_MEMBER_REMOVE` map to common `MemberLeftEvent`. Live gateway evidence is pending. |
@@ -29,6 +29,33 @@ Status: partial migration. The EBA adapter structure, manifest, converters, cach
| `bot.removed_from_group` | unit | `GUILD_DELETE` and `GROUP_DEL_ROBOT` map to common `BotRemovedFromGroupEvent`. |
| `platform.specific` | unit | Unmapped gateway events are emitted as structured `PlatformSpecificEvent`; live evidence is pending. |
## Full-group messages
After a group owner enables QQ's "receive all messages" permission, QQ delivers
`GROUP_MESSAGE_CREATE`, including messages that mention the bot. Both the EBA
and legacy adapters accept this event over WebSocket and unified Webhook, retain
the sender's `member_openid` (with the older `openid` alias as fallback), and use
the original message ID for passive group replies.
Ordinary messages and images do not receive a bot `At` component. A full-group
message receives that component only when QQ supplies a boolean `mentions[].is_you`
equal to `true` and a matching native `<@ID>` or `<@!ID>` token in its text. Only
the bot's own token is removed; mentions of other members remain text. Nicknames,
`bot: true` alone, and a text that looks like a mention do not authorize a reply.
The EBA component targets the adapter's configured bot account so existing
`is_at_bot` route filters continue to match.
Default EBA group routes requiring `is_at_bot` still exclude unmentioned group
messages. Custom event routes or plugin subscriptions may opt into ordinary
messages. This change does not alter QQ permissions, existing bot configuration,
event bindings, or plugin subscriptions.
`tests/unit_tests/platform/test_qqofficial_full_group_messages.py` exercises the
real adapters and shared QQ parser with external gateway/download/send transports
substituted. It covers text, images, self/other/unverified mentions, sender aliases,
legacy @-only mode, private messages, and passive reply targets. This is protocol
regression coverage, not a claim of a fresh live QQ probe of the whole upstream build.
## Common APIs
| API | Evidence | Notes |
+3 -1
View File
@@ -172,7 +172,9 @@ Stitch by `session_id` + `sequence`; the turn is complete when
## 7. Reset a session
Start a fresh conversation for a `session_id` (drops history):
Start a fresh conversation for a `session_id`. This resets Runner conversation
state and hides prior history from future model calls, while retaining monitoring
records. Other sessions are unaffected; an active task must finish before reset.
```
POST /bots/{bot_uuid}/reset
+5
View File
@@ -9,6 +9,11 @@ services:
container_name: langbot_plugin_runtime
volumes:
- ./data/plugins:/app/data/plugins
# Persist the v4 plugin artifact cache, dependency environments, and
# per-installation data. Without this, recreating the container throws
# away every installed plugin's environment and private data while
# data/plugins survives.
- ./data/plugin-runtime:/app/data/plugin-runtime
ports:
- 5401:5401
restart: on-failure
+24
View File
@@ -81,6 +81,25 @@ spec:
# Uncomment and modify if you have a specific StorageClass
# storageClassName: your-storage-class
---
# PersistentVolumeClaim for the v4 Plugin Runtime state
# Holds the plugin artifact cache, per-plugin dependency environments, and
# per-installation data. It must survive Pod restarts: rebuilding it forces
# every installed plugin to be re-downloaded and its environment rebuilt.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: langbot-plugin-runtime-state
namespace: langbot
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
# Uncomment and modify if you have a specific StorageClass
# storageClassName: your-storage-class
---
# ConfigMap for environment configuration
apiVersion: v1
@@ -160,6 +179,8 @@ spec:
volumeMounts:
- name: plugin-data
mountPath: /app/data/plugins
- name: plugin-runtime-state
mountPath: /app/data/plugin-runtime
resources:
requests:
memory: "512Mi"
@@ -189,6 +210,9 @@ spec:
- name: plugin-data
persistentVolumeClaim:
claimName: langbot-plugin-runtime-data
- name: plugin-runtime-state
persistentVolumeClaim:
claimName: langbot-plugin-runtime-state
restartPolicy: Always
---
+1 -1
View File
@@ -1,4 +1,4 @@
node_modules/
node_modules
.mintlify/
.DS_Store
/.omc
+1 -1
View File
@@ -1,6 +1,6 @@
# [LangBot](https://github.com/langbot-app/LangBot) 官方文档
> 文档源码位于 [LangBot/docs](https://github.com/langbot-app/LangBot/tree/main/docs),[langbot-docs](https://github.com/langbot-app/langbot-docs) 仅作为发布 mirror。
> 文档源码位于 [LangBot/docs](https://github.com/langbot-app/LangBot/tree/master/docs),[langbot-docs](https://github.com/langbot-app/langbot-docs) 将作为历史归档保留。
> [LangBot 代码仓库](https://github.com/langbot-app/LangBot)
> 这是 LangBot 4.0 的文档,3.0 文档请见 [langbot-docs 的 v3 分支](https://github.com/langbot-app/langbot-docs/tree/v3)
+1 -1
View File
@@ -1,4 +1,4 @@
> Edit documentation in [LangBot/docs](https://github.com/langbot-app/LangBot/tree/main/docs). The [langbot-docs repository](https://github.com/langbot-app/langbot-docs) is a generated publication mirror. Run the commands below from `LangBot/docs/`.
> Edit documentation in [LangBot/docs](https://github.com/langbot-app/LangBot/tree/master/docs). The [langbot-docs repository](https://github.com/langbot-app/langbot-docs) is retained as a historical archive. Run the commands below from `LangBot/docs/`.
# [LangBot](https://github.com/langbot-app/LangBot) Official Documentation
-4
View File
@@ -1,4 +0,0 @@
{
"url": "https://context7.com/langbot-app/langbot-docs",
"public_key": "pk_lYnjPxdPQabvC87DxU34F"
}
+16 -9
View File
@@ -749,6 +749,7 @@
{
"group": "Product Updates",
"pages": [
"en/articles/langbot-v411-event-driven-agents",
"en/articles/langbot-cloud-multi-user-workspaces"
]
},
@@ -763,6 +764,9 @@
{
"group": "Tutorials & Integrations",
"pages": [
"en/articles/dify-langbot-github-release-briefing",
"en/articles/dify-langbot-support-triage",
"en/articles/dify-langbot-writing-assistant",
"en/articles/langtars-remote-pc-control-dify-n8n",
"en/articles/connect-deepseek-to-wechat",
"en/articles/deploy-ai-bot-in-5-minutes",
@@ -1076,17 +1080,10 @@
{
"group": "产品动态",
"pages": [
"zh/articles/langbot-v411-event-driven-agents",
"zh/articles/langbot-cloud-multi-user-workspaces"
]
},
{
"group": "在线体验",
"pages": [
"zh/articles/langbot-wecom-customer-service-knowledge-base",
"zh/articles/langbot-telegram-sandbox-agent",
"zh/articles/langbot-wechat-official-account"
]
},
{
"group": "技术解析",
"pages": [
@@ -1098,13 +1095,19 @@
{
"group": "教程与集成",
"pages": [
"zh/articles/dify-langbot-github-release-briefing",
"zh/articles/dify-langbot-support-triage",
"zh/articles/dify-langbot-writing-assistant",
"zh/articles/langtars-remote-pc-control-dify-n8n",
"zh/articles/connect-deepseek-to-wechat",
"zh/articles/deploy-ai-bot-in-5-minutes",
"zh/articles/dify-agent-discord-telegram-slack",
"zh/articles/langflow-drag-and-drop-ai-bot",
"zh/articles/n8n-multi-platform-ai-chatbot",
"zh/articles/dify-langbot-rag-knowledge-base"
"zh/articles/dify-langbot-rag-knowledge-base",
"zh/articles/langbot-telegram-sandbox-agent",
"zh/articles/langbot-wechat-official-account",
"zh/articles/langbot-wecom-customer-service-knowledge-base"
]
},
{
@@ -1386,6 +1389,7 @@
{
"group": "製品アップデート",
"pages": [
"ja/articles/langbot-v411-event-driven-agents",
"ja/articles/langbot-cloud-multi-user-workspaces"
]
},
@@ -1400,6 +1404,9 @@
{
"group": "チュートリアルと連携",
"pages": [
"ja/articles/dify-langbot-github-release-briefing",
"ja/articles/dify-langbot-support-triage",
"ja/articles/dify-langbot-writing-assistant",
"ja/articles/langtars-remote-pc-control-dify-n8n",
"ja/articles/connect-deepseek-to-wechat",
"ja/articles/deploy-ai-bot-in-5-minutes",
@@ -0,0 +1,211 @@
---
title: "Turn GitHub Releases into Telegram Briefings with Dify and LangBot"
description: "Fetch a real GitHub release with Dify, extract the useful fields and let GPT-6 Astra write a sourced briefing. Connect the Workflow to LangBot with the correct input and output contract."
---
This article is synchronized from the LangBot Blog. [Read the canonical version](https://langbot.app/en/blog/dify-langbot-github-release-briefing).
Published 2026-09-16 · Author: LangBot Team
“What changed in the latest release?” sounds like a simple chatbot question. It becomes a data problem as soon as a repository ships something newer than the model knows.
We built an on-demand release briefing that reads GitHub first. Dify fetches the public release JSON, a code node keeps the useful fields, GPT-6 Astra writes a short summary, and LangBot returns it to the conversation. The example uses the public LangBot repository, and the same pattern works for other release feeds.
![The briefing comes from a live GitHub API request, with a source link.](/images/articles/source/images/dify-langbot/056-release-english-live-briefing.png)
*The briefing comes from a live GitHub API request, with a source link.*
## Start with a working Dify and LangBot installation
Start Docker Compose and Git, then follow the [Dify Docker Compose guide](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) and the [LangBot Docker guide](https://langbot.app/docs/en/deploy/langbot/docker/) to bring up both services. For Dify, clone the repository, enter `docker`, copy `.env.example` to `.env`, and start Compose. The LangBot guide includes the application image and plugin runtime configuration.
The screenshots come from a local installation of **Dify 1.17.1 and LangBot v4.10.11**. We mapped the browser ports to `8088` and `5368`. Those are custom demo ports; the default installations normally use `80` and `5300`. With the defaults, open `http://localhost` and `http://localhost:5300`. You do not need to change ports just to match a screenshot. Create your own administrator accounts and select **English** in both interfaces.
![The first-run screen of the local Dify deployment.](/images/articles/source/images/dify-langbot/00-dify-install.png)
*The first-run screen of the local Dify deployment.*
![The local LangBot installation before administrator setup.](/images/articles/source/images/dify-langbot/00-langbot-install.png)
*The local LangBot installation before administrator setup.*
The important requirement is that **the LangBot container can reach Dify**. Our two services share a Docker network, so the Runner uses `http://nginx/v1`, where `nginx` is Dify's service name. You can attach Dify's `nginx` service and LangBot to the same external network in their Compose configurations. For separate hosts, use a Dify HTTPS address reachable from LangBot and append `/v1`. Every `http://nginx/v1` example below refers to our shared network; replace it for your own deployment. Inside a container, `localhost` points back to that container.
## Connect GPT-6 Astra to Dify
Open **Integrations → Model Provider**, install the official **OpenAI-API-compatible** provider, and choose **Add Model**. We tested provider version 0.0.66 with an OpenAI-compatible gateway.
| Field | Tutorial setting |
| --- | --- |
| Model Name / endpoint model name | `gpt-6-astra` |
| Model Type / Completion mode | LLM / Chat |
| Model display name | GPT-6 Astra |
| API Base URL | Your provider's compatible endpoint, usually ending in `/v1` |
| API Key | Your own provider key |
| API Type | Chat Completions API |
| Context size / maximum-token ceiling | 32768 / 4096 for this example |
Those limits are conservative settings for this tutorial, not a statement of Astra's full specifications. Save the model and let Dify validate the connection. Replace the gateway shown in the screenshot with your own authorized endpoint. Model names and capabilities depend on your provider. This walkthrough retains the `gpt-6-astra` identifier used in the tested deployment.
![The custom model form, captured before entering the API key.](/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png)
*The custom model form, captured before entering the API key.*
## Create a Workflow with a clear input and output
Create a Dify **Workflow** named `Astra Release Briefing`. Each request is an independent read of the current release, so a Workflow fits naturally.
Connect these nodes:
`User Request → HTTP Request → Code → LLM → End`
![The complete five-node release workflow.](/images/articles/source/images/dify-langbot/045-release-workflow-overview.png)
*The complete five-node release workflow.*
### 1. Name the input for LangBot
In the Start node, add a required paragraph input named:
```text
langbot_user_message_text
```
LangBot's Dify Workflow Runner places the incoming message text in that field. If you call it `question` instead, the workflow may pass a manual Dify test and still fail when LangBot calls it with different input names.
![The required input is named to match the runner contract.](/images/articles/source/images/dify-langbot/049-release-workflow-input.png)
*The required input is named to match the runner contract.*
### 2. Read the latest public release
Use an HTTP Request node with GET:
```text
https://api.github.com/repos/langbot-app/LangBot/releases/latest
```
Add `Accept: application/vnd.github+json` and `User-Agent: LangBot-Dify-Tutorial`. This example reads public data without a GitHub token. Leave SSL verification enabled and choose sensible connection and read timeouts for your environment.
![The HTTP node fetches the latest release directly from GitHub.](/images/articles/source/images/dify-langbot/046-release-http-request-settings.png)
*The HTTP node fetches the latest release directly from GitHub.*
### 3. Extract the useful fields
Pass the HTTP node's `body` and `status_code` to a Code node. Keep only the information needed for a briefing:
```python
import json
def main(body: str, status_code: int) -> dict:
if status_code != 200:
return {"release": json.dumps({"error": f"GitHub HTTP {status_code}"})}
data = json.loads(body)
return {"release": json.dumps({
"repository": "langbot-app/LangBot",
"tag": data.get("tag_name"),
"published_at": data.get("published_at"),
"url": data.get("html_url"),
"notes": (data.get("body") or "")[:14000],
}, ensure_ascii=False)}
```
This removes avatars and unrelated API URLs from the model input. It also makes a non-200 response explicit. A transport failure can still stop the HTTP node before this code runs, which is why you should inspect failed workflow runs as well as successful ones.
![The Code node turns the raw response into a small release record.](/images/articles/source/images/dify-langbot/047-release-code-extraction-node.png)
*The Code node turns the raw response into a small release record.*
### 4. Write the briefing and return summary
Choose GPT-6 Astra in the LLM node. Ask it to answer in the user's language and include the repository, release tag, publication time, three useful highlights, and the source URL. Tell it to use only the supplied API data and to report missing data or an error instead of guessing.
Pass both `langbot_user_message_text` and the extracted `release` record into the user prompt. In End, map the LLM's `text` to an output named **`summary`**. This is the field LangBot expects from the workflow response.
![The final output maps the generated text to summary.](/images/articles/source/images/dify-langbot/054-release-summary-output-verified.png)
*The final output maps the generated text to summary.*
## Verify against GitHub, not against the screenshot
Our English and Chinese runs both retrieved `v4.10.11`, published on September 12, 2026 at 04:55:58 UTC. The briefing linked to that exact release and summarized changes in knowledge ingestion, monitoring, and platform compatibility.
![The English run includes a release tag, date, highlights, and source.](/images/articles/source/images/dify-langbot/056-release-english-live-briefing.png)
*The English run includes a release tag, date, highlights, and source.*
Your run may show a newer version. Compare the answer with the current API fields—`tag_name`, `published_at`, and `html_url`—rather than expecting the version in this article forever.
## Put LangBot in front of the app
Publish the saved version in Dify. Open **Access Point → Backend Service API → API Key** and create a key for this app.
In LangBot, choose **Create Pipelines**, name the pipeline `Astra Release Briefing`, and open **Configuration → AI**:
| Field | Value |
| --- | --- |
| Runner | Dify Service API |
| Base URL | `http://nginx/v1` |
| App Type | Workflow |
| API Key | The Dify app key you just created |
The Dify app key belongs here. The Astra provider key stays in Dify. Save the pipeline, then use **Debug Chat** to check the complete request and response path before adding a messaging platform.
![The LangBot pipeline settings, captured before entering the app key.](/images/articles/source/images/dify-langbot/078-langbot-release-workflow-settings.png)
*The LangBot pipeline settings, captured before entering the app key.*
## Ask for the briefing through LangBot
The English request through LangBot returned the same kind of source-linked briefing. I also tested Chinese output. One request hit a temporary upstream SSL interruption; a later retry succeeded. The failed run remains separate from the successful evidence.
![The workflow summary returned through LangBot.](/images/articles/source/images/dify-langbot/079-langbot-release-english-roundtrip.png)
*The workflow summary returned through LangBot.*
For Telegram or a Discord project channel, start with an on-demand command or mention trigger. This workflow reads the release when someone asks; scheduled delivery requires an additional scheduler and sending step.
To cover another repository, first duplicate the app and change the fixed API URL. Add a validated repository parameter only when you actually need it. A short, predictable integration is much easier to operate than an unrestricted URL-fetching bot.
## Connect it to Telegram and Discord
Choose **Create Bots** in LangBot, select your adapter, and enter credentials from that platform. After creating the bot, select the pipeline you just built. Check the pipeline's trigger rules for direct messages, group messages, and mentions before inviting it into a channel.
The measured path in this walkthrough is **LangBot → Dify → GPT-6 Astra → LangBot**. We inspected the real adapter forms below; we did not authorize a live Slack workspace, Discord server, Telegram bot, or LINE account for this demo.
| Platform | Setup path |
| --- | --- |
| Slack | Create a Slack app, grant the required bot scopes, install it to the workspace, and enter the Bot Token and Signing Secret in LangBot. Configure event subscriptions with the public HTTPS callback from the bot setup, verify it, and invite the bot to the intended channel. |
| Discord | Create an application and bot in the Developer Portal. Enter Client ID and bot Token, enable the required message intents, then invite the bot with the appropriate channel permissions. |
| Telegram | Create a bot with BotFather and enter its token. Start with a direct message; for groups, invite the bot and configure privacy mode and LangBot's trigger rules for the messages it should receive. |
| LINE | Create a Messaging API channel. Enter the Channel access token and Channel secret, configure the public HTTPS webhook, enable webhook delivery, and avoid conflicting automatic replies. |
| Mattermost | Enter the server URL and a Bot Account access token, then add that account to the relevant teams and channels. The adapter uses REST and WebSocket APIs. |
![The Discord adapter uses the application Client ID and bot token.](/images/articles/source/images/dify-langbot/059-platform-discord-fields.png)
*The Discord adapter uses the application Client ID and bot token.*
![The Telegram adapter uses a BotFather token and exposes reply options.](/images/articles/source/images/dify-langbot/060-platform-telegram-fields.png)
*The Telegram adapter uses a BotFather token and exposes reply options.*
The catalog also includes Matrix, Lark, DingTalk, WeCom, WeChat-related adapters, QQ, KOOK, OneBot v11, Satori, HTTP Bot, and Page Bot. See the [platform-specific LangBot guides](https://langbot.app/docs/en/usage/platforms/readme) for the permissions and networking required by each adapter. In particular, the local-only deployment above needs a suitable public HTTPS endpoint for webhook-based integrations such as Slack and LINE.
## Troubleshooting
When something fails, check the path in order: Dify preview, the published app version, LangBot's `/v1` base URL and app type, then the platform's event delivery. If you change Dify service passwords, keep Redis and Celery credentials aligned, and do the same for Sandbox and its code-execution client.
Our local proxy initially returned fake DNS addresses that Dify's SSRF proxy rejected. Correcting DNS fixed the plugin download without disabling network protections. For external API calls, inspect the run record after a retry rather than assuming that a transport error means the app configuration is wrong.
Project sources: [LangBot](https://github.com/langbot-app/LangBot) and [Dify](https://github.com/langgenius/dify). The deployment and screenshots are from September 16, 2026; later versions may move some controls.
## Further reading
- [A Dify Writing Assistant for Discord and Telegram with GPT-6 Astra and LangBot](https://langbot.app/en/blog/dify-langbot-writing-assistant)
- [Route Support Questions in Discord and LINE with Dify and LangBot](https://langbot.app/en/blog/dify-langbot-support-triage)
@@ -0,0 +1,184 @@
---
title: "Route Support Questions in Discord and LINE with Dify and LangBot"
description: "Use GPT-6 Astra and a Dify Question Classifier to separate account help, product questions and requests for human review. Test each route through LangBot before connecting Discord or LINE."
---
This article is synchronized from the LangBot Blog. [Read the canonical version](https://langbot.app/en/blog/dify-langbot-support-triage).
Published 2026-09-16 · Author: LangBot Team
A single support prompt can work surprisingly well—until the same bot receives an expired invitation, an export question, and an angry refund request. Those messages need different responses and different limits.
We built a three-route support assistant in Dify, then connected it through LangBot. GPT-6 Astra classifies the request and writes a reply for the selected route. The result is small enough to inspect: one classifier, three response nodes, and three outputs.
![The actual support Chatflow, with separate account, product, and human-review routes.](/images/articles/source/images/dify-langbot/039-triage-three-branch-overview.png)
*The actual support Chatflow, with separate account, product, and human-review routes.*
## Start with a working Dify and LangBot installation
Start Docker Compose and Git, then follow the [Dify Docker Compose guide](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) and the [LangBot Docker guide](https://langbot.app/docs/en/deploy/langbot/docker/) to bring up both services. For Dify, clone the repository, enter `docker`, copy `.env.example` to `.env`, and start Compose. The LangBot guide includes the application image and plugin runtime configuration.
The screenshots come from a local installation of **Dify 1.17.1 and LangBot v4.10.11**. We mapped the browser ports to `8088` and `5368`. Those are custom demo ports; the default installations normally use `80` and `5300`. With the defaults, open `http://localhost` and `http://localhost:5300`. You do not need to change ports just to match a screenshot. Create your own administrator accounts and select **English** in both interfaces.
![The first-run screen of the local Dify deployment.](/images/articles/source/images/dify-langbot/00-dify-install.png)
*The first-run screen of the local Dify deployment.*
![The local LangBot installation before administrator setup.](/images/articles/source/images/dify-langbot/00-langbot-install.png)
*The local LangBot installation before administrator setup.*
The important requirement is that **the LangBot container can reach Dify**. Our two services share a Docker network, so the Runner uses `http://nginx/v1`, where `nginx` is Dify's service name. You can attach Dify's `nginx` service and LangBot to the same external network in their Compose configurations. For separate hosts, use a Dify HTTPS address reachable from LangBot and append `/v1`. Every `http://nginx/v1` example below refers to our shared network; replace it for your own deployment. Inside a container, `localhost` points back to that container.
## Connect GPT-6 Astra to Dify
Open **Integrations → Model Provider**, install the official **OpenAI-API-compatible** provider, and choose **Add Model**. We tested provider version 0.0.66 with an OpenAI-compatible gateway.
| Field | Tutorial setting |
| --- | --- |
| Model Name / endpoint model name | `gpt-6-astra` |
| Model Type / Completion mode | LLM / Chat |
| Model display name | GPT-6 Astra |
| API Base URL | Your provider's compatible endpoint, usually ending in `/v1` |
| API Key | Your own provider key |
| API Type | Chat Completions API |
| Context size / maximum-token ceiling | 32768 / 4096 for this example |
Those limits are conservative settings for this tutorial, not a statement of Astra's full specifications. Save the model and let Dify validate the connection. Replace the gateway shown in the screenshot with your own authorized endpoint. Model names and capabilities depend on your provider. This walkthrough retains the `gpt-6-astra` identifier used in the tested deployment.
![The custom model form, captured before entering the API key.](/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png)
*The custom model form, captured before entering the API key.*
## Define what each route is allowed to do
This example uses a fictional help-desk product called Northstar Desk. Its few product rules are included directly in the branch prompts, so you do not need a pre-existing knowledge base or another tutorial.
| Route | Requests | Job |
| --- | --- | --- |
| Account | Login, invitations, workspace access | Explain the invitation recovery steps |
| Product | CSV export, trial limits, basic setup | Answer from the small set of supplied product rules |
| Human | Billing, refunds, enterprise pricing, complaints, unclear mixed requests | Explain that a human decision is needed and help the user prepare a concise request |
The Human branch produces handoff guidance. It does not create a ticket, notify an employee, or approve a refund. That distinction belongs in the prompt: otherwise the assistant may casually imply it has performed an action that the workflow never implemented.
## Build the classifier and three branches
Create a **Chatflow** named `Astra Support Router`. Connect User Input to a **Question Classifier**, choose GPT-6 Astra, and set its query variable to `sys.query`.
Add these categories:
```text
Account: login, invitation, password or workspace access
Product: usage, ticket export, setup and trial limits
Human: billing, refunds, enterprise pricing, angry complaints
or unclear mixed questions
```
![The category descriptions define the routing boundary.](/images/articles/source/images/dify-langbot/040-triage-classifier-settings.png)
*The category descriptions define the routing boundary.*
In the classifier's advanced instructions, tell it to choose Human when essential context is missing or the request needs authorization. Connect each branch to its own LLM node and Answer node.
Use GPT-6 Astra in each LLM node and pass the user query through `sys.query`. Give the branches different system instructions:
- **Account Reply:** invitations expire after 48 hours. Ask the workspace owner to resend from `Settings > Members`. Never request passwords. Ask one clarifying question if the problem is different.
- **Product Reply:** owners export CSV tickets from `Settings > Data > Export`; export links last 7 days. The trial lasts 14 days and supports 5 teammates and 2 inboxes. Say when the supplied notes do not cover a question.
- **Human Reply:** acknowledge the request and explain that a human must decide. Ask for a brief issue summary and a non-sensitive reference. Tell the user to contact their support team, without inventing an address, response-time promise, or completed action.
All three prompts ask for concise replies in the user's language. Keeping the branch instructions separate makes a later change easier to review: adjusting billing guidance does not also change the login instructions.
## Test the path, not only the wording
We ran an expired-invitation question, a CSV-export question, and a refund complaint. The preview identified the selected output for each run:
| Test | Observed output | Response |
| --- | --- | --- |
| Expired invitation | Account Output | Owner resend instructions and the 48-hour limit |
| Export tickets as CSV | Product Output | Correct menu path and 7-day availability |
| Refund complaint | Human Output | Human-review guidance without claiming a refund was issued |
![The account test follows the Account branch.](/images/articles/source/images/dify-langbot/041-triage-account-path-result.png)
*The account test follows the Account branch.*
![The export question follows the Product branch.](/images/articles/source/images/dify-langbot/043-triage-product-path-result.png)
*The export question follows the Product branch.*
Expand the workflow process in Preview when a result looks odd. A plausible sentence can hide an incorrect route. That is why the output name is part of the test, rather than treating every fluent answer as a pass.
## Put LangBot in front of the app
Publish the saved version in Dify. Open **Access Point → Backend Service API → API Key** and create a key for this app.
In LangBot, choose **Create Pipelines**, name the pipeline `Astra Support Router`, and open **Configuration → AI**:
| Field | Value |
| --- | --- |
| Runner | Dify Service API |
| Base URL | `http://nginx/v1` |
| App Type | Chat |
| API Key | The Dify app key you just created |
The Dify app key belongs here. The Astra provider key stays in Dify. Save the pipeline, then use **Debug Chat** to check the complete request and response path before adding a messaging platform.
![The LangBot pipeline settings, captured before entering the app key.](/images/articles/source/images/dify-langbot/053-langbot-triage-dify-settings.png)
*The LangBot pipeline settings, captured before entering the app key.*
## Run it through LangBot
The same expired-invitation question in LangBot returned the workspace-owner recovery steps. A later refund request in Chinese reached the human-review guidance. LangBot did not need its own copy of the classification rules.
![An account-support response returned through LangBot.](/images/articles/source/images/dify-langbot/055-langbot-triage-account-english.png)
*An account-support response returned through LangBot.*
Before putting this in a busy Discord server or a LINE support account, add ambiguous examples such as “I cannot log in and want a refund.” If those repeatedly land in Product, refine the category descriptions and classifier instructions.
When you are ready for a real handoff, add your existing ticketing or notification API to the Human branch and handle its success and failure explicitly. The example gives you a visible place to add that action later.
## Connect it to Discord and LINE
Choose **Create Bots** in LangBot, select your adapter, and enter credentials from that platform. After creating the bot, select the pipeline you just built. Check the pipeline's trigger rules for direct messages, group messages, and mentions before inviting it into a channel.
The measured path in this walkthrough is **LangBot → Dify → GPT-6 Astra → LangBot**. We inspected the real adapter forms below; we did not authorize a live Slack workspace, Discord server, Telegram bot, or LINE account for this demo.
| Platform | Setup path |
| --- | --- |
| Slack | Create a Slack app, grant the required bot scopes, install it to the workspace, and enter the Bot Token and Signing Secret in LangBot. Configure event subscriptions with the public HTTPS callback from the bot setup, verify it, and invite the bot to the intended channel. |
| Discord | Create an application and bot in the Developer Portal. Enter Client ID and bot Token, enable the required message intents, then invite the bot with the appropriate channel permissions. |
| Telegram | Create a bot with BotFather and enter its token. Start with a direct message; for groups, invite the bot and configure privacy mode and LangBot's trigger rules for the messages it should receive. |
| LINE | Create a Messaging API channel. Enter the Channel access token and Channel secret, configure the public HTTPS webhook, enable webhook delivery, and avoid conflicting automatic replies. |
| Mattermost | Enter the server URL and a Bot Account access token, then add that account to the relevant teams and channels. The adapter uses REST and WebSocket APIs. |
![The Discord adapter uses the application Client ID and bot token.](/images/articles/source/images/dify-langbot/059-platform-discord-fields.png)
*The Discord adapter uses the application Client ID and bot token.*
![LINE requires its channel access token and channel secret.](/images/articles/source/images/dify-langbot/061-platform-line-fields.png)
*LINE requires its channel access token and channel secret.*
The catalog also includes Matrix, Lark, DingTalk, WeCom, WeChat-related adapters, QQ, KOOK, OneBot v11, Satori, HTTP Bot, and Page Bot. See the [platform-specific LangBot guides](https://langbot.app/docs/en/usage/platforms/readme) for the permissions and networking required by each adapter. In particular, the local-only deployment above needs a suitable public HTTPS endpoint for webhook-based integrations such as Slack and LINE.
## Troubleshooting
When something fails, check the path in order: Dify preview, the published app version, LangBot's `/v1` base URL and app type, then the platform's event delivery. If you change Dify service passwords, keep Redis and Celery credentials aligned, and do the same for Sandbox and its code-execution client.
Our local proxy initially returned fake DNS addresses that Dify's SSRF proxy rejected. Correcting DNS fixed the plugin download without disabling network protections. For external API calls, inspect the run record after a retry rather than assuming that a transport error means the app configuration is wrong.
Project sources: [LangBot](https://github.com/langbot-app/LangBot) and [Dify](https://github.com/langgenius/dify). The deployment and screenshots are from September 16, 2026; later versions may move some controls.
## Further reading
- [A Dify Writing Assistant for Discord and Telegram with GPT-6 Astra and LangBot](https://langbot.app/en/blog/dify-langbot-writing-assistant)
- [Turn GitHub Releases into Telegram Briefings with Dify and LangBot](https://langbot.app/en/blog/dify-langbot-github-release-briefing)
@@ -0,0 +1,177 @@
---
title: "A Dify Writing Assistant for Discord and Telegram with GPT-6 Astra and LangBot"
description: "Build a basic Dify Chatbot for announcements, revisions and translations, then connect it to LangBot. Includes tested prompts, screenshots and Discord and Telegram setup guidance."
---
This article is synchronized from the LangBot Blog. [Read the canonical version](https://langbot.app/en/blog/dify-langbot-writing-assistant).
Published 2026-09-16 · Author: LangBot Team
A community announcement usually starts as a few rough notes: a date, a channel, and something people need to bring. The first draft is easy. The annoying part is reopening another app for every “make it shorter” or “turn that into a Telegram reminder.”
We built a small writing assistant that keeps those revisions in the conversation. Dify owns the prompt and chat history, GPT-6 Astra writes the response, and LangBot provides the messaging-platform entry point. Here is the complete setup, including the local deployment and the replies We tested.
![A real response from Dify and Astra, shown in LangBot Debug Chat.](/images/articles/source/images/dify-langbot/025-langbot-writing-english-roundtrip.png)
*A real response from Dify and Astra, shown in LangBot Debug Chat.*
## Start with a working Dify and LangBot installation
Start Docker Compose and Git, then follow the [Dify Docker Compose guide](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) and the [LangBot Docker guide](https://langbot.app/docs/en/deploy/langbot/docker/) to bring up both services. For Dify, clone the repository, enter `docker`, copy `.env.example` to `.env`, and start Compose. The LangBot guide includes the application image and plugin runtime configuration.
The screenshots come from a local installation of **Dify 1.17.1 and LangBot v4.10.11**. We mapped the browser ports to `8088` and `5368`. Those are custom demo ports; the default installations normally use `80` and `5300`. With the defaults, open `http://localhost` and `http://localhost:5300`. You do not need to change ports just to match a screenshot. Create your own administrator accounts and select **English** in both interfaces.
![The first-run screen of the local Dify deployment.](/images/articles/source/images/dify-langbot/00-dify-install.png)
*The first-run screen of the local Dify deployment.*
![The local LangBot installation before administrator setup.](/images/articles/source/images/dify-langbot/00-langbot-install.png)
*The local LangBot installation before administrator setup.*
The important requirement is that **the LangBot container can reach Dify**. Our two services share a Docker network, so the Runner uses `http://nginx/v1`, where `nginx` is Dify's service name. You can attach Dify's `nginx` service and LangBot to the same external network in their Compose configurations. For separate hosts, use a Dify HTTPS address reachable from LangBot and append `/v1`. Every `http://nginx/v1` example below refers to our shared network; replace it for your own deployment. Inside a container, `localhost` points back to that container.
## Connect GPT-6 Astra to Dify
Open **Integrations → Model Provider**, install the official **OpenAI-API-compatible** provider, and choose **Add Model**. We tested provider version 0.0.66 with an OpenAI-compatible gateway.
| Field | Tutorial setting |
| --- | --- |
| Model Name / endpoint model name | `gpt-6-astra` |
| Model Type / Completion mode | LLM / Chat |
| Model display name | GPT-6 Astra |
| API Base URL | Your provider's compatible endpoint, usually ending in `/v1` |
| API Key | Your own provider key |
| API Type | Chat Completions API |
| Context size / maximum-token ceiling | 32768 / 4096 for this example |
Those limits are conservative settings for this tutorial, not a statement of Astra's full specifications. Save the model and let Dify validate the connection. Replace the gateway shown in the screenshot with your own authorized endpoint. Model names and capabilities depend on your provider. This walkthrough retains the `gpt-6-astra` identifier used in the tested deployment.
![The custom model form, captured before entering the API key.](/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png)
*The custom model form, captured before entering the API key.*
## Build a basic Chatbot
In Dify Studio, choose **Create → Create from Blank → More basic app types → Chatbot**. Name it `Astra Writing Assistant`. A basic Chatbot is enough here: we need a clear prompt and conversation history, without a branching workflow.
![Dify keeps its basic Chatbot option under More basic app types.](/images/articles/source/images/dify-langbot/010-dify-create-basic-app.png)
*Dify keeps its basic Chatbot option under More basic app types.*
![Give the assistant a name and a specific job.](/images/articles/source/images/dify-langbot/011-dify-writing-app-create.png)
*Give the assistant a name and a specific job.*
Select GPT-6 Astra under **Configure model**, then add these instructions:
```text
You help a community manager turn rough notes into messages people can use.
Reply in the language of the user's request.
For an announcement, give: one clear headline, a short ready-to-send message,
and one optional reminder.
Preserve supplied dates, times, links, and requirements exactly.
Never invent missing event details, discounts, results, or promises.
If an essential detail is missing, ask one concise question.
Use a natural, direct tone. Avoid hype and excessive emojis.
Keep a typical reply under 180 words. When revising, use conversation context.
```
The most useful line is the one about preserving details. An announcement can survive plain wording. It cannot survive an invented RSVP link or the wrong time zone. We also kept the output short enough to be useful in a channel.
![The prompt gives the assistant a narrow job and clear boundaries.](/images/articles/source/images/dify-langbot/012-dify-writing-instructions.png)
*The prompt gives the assistant a narrow job and clear boundaries.*
For the first test, we entered:
> Write a Discord announcement: community demo day is September 22 at 18:00 UTC. Bring one bot demo. RSVP in #demo-day. Keep it friendly and under 100 words.
The response preserved the date, time, and channel. We then asked, “Make it shorter, and remove the optional reminder.” The second reply kept the details from the first turn without asking us to paste them again.
![The first English announcement generated in Dify.](/images/articles/source/images/dify-langbot/016-writing-english-first-reply.png)
*The first English announcement generated in Dify.*
![A follow-up instruction revises the existing announcement.](/images/articles/source/images/dify-langbot/019-writing-english-context-revision.png)
*A follow-up instruction revises the existing announcement.*
Publish the updated configuration with **Publish Update**. This step matters: an external caller should receive the version you just tested, rather than an older prompt still attached to the published app.
![The published app exposes a backend API for LangBot.](/images/articles/source/images/dify-langbot/023-writing-access-point-api.png)
*The published app exposes a backend API for LangBot.*
## Put LangBot in front of the app
Publish the saved version in Dify. Open **Access Point → Backend Service API → API Key** and create a key for this app.
In LangBot, choose **Create Pipelines**, name the pipeline `Astra Writing Assistant`, and open **Configuration → AI**:
| Field | Value |
| --- | --- |
| Runner | Dify Service API |
| Base URL | `http://nginx/v1` |
| App Type | Chat |
| API Key | The Dify app key you just created |
The Dify app key belongs here. The Astra provider key stays in Dify. Save the pipeline, then use **Debug Chat** to check the complete request and response path before adding a messaging platform.
![The LangBot pipeline settings, captured before entering the app key.](/images/articles/source/images/dify-langbot/007-langbot-dify-runner-config.png)
*The LangBot pipeline settings, captured before entering the app key.*
## Test the same task through LangBot
We asked LangBot for a two-sentence Telegram reminder. The reply came back through Dify with the supplied date and time intact. A later request switched the same conversation to Chinese, which also worked.
For a community server, we would start with mention-based triggers in a single channel. Let members ask for a draft, shorten it, and adjust the tone before they decide to post it. That small loop is already useful for release announcements, event reminders, and repeated support replies.
![The writing assistant answering through the LangBot pipeline.](/images/articles/source/images/dify-langbot/025-langbot-writing-english-roundtrip.png)
*The writing assistant answering through the LangBot pipeline.*
## Connect it to Discord and Telegram
Choose **Create Bots** in LangBot, select your adapter, and enter credentials from that platform. After creating the bot, select the pipeline you just built. Check the pipeline's trigger rules for direct messages, group messages, and mentions before inviting it into a channel.
The measured path in this walkthrough is **LangBot → Dify → GPT-6 Astra → LangBot**. We inspected the real adapter forms below; we did not authorize a live Slack workspace, Discord server, Telegram bot, or LINE account for this demo.
| Platform | Setup path |
| --- | --- |
| Slack | Create a Slack app, grant the required bot scopes, install it to the workspace, and enter the Bot Token and Signing Secret in LangBot. Configure event subscriptions with the public HTTPS callback from the bot setup, verify it, and invite the bot to the intended channel. |
| Discord | Create an application and bot in the Developer Portal. Enter Client ID and bot Token, enable the required message intents, then invite the bot with the appropriate channel permissions. |
| Telegram | Create a bot with BotFather and enter its token. Start with a direct message; for groups, invite the bot and configure privacy mode and LangBot's trigger rules for the messages it should receive. |
| LINE | Create a Messaging API channel. Enter the Channel access token and Channel secret, configure the public HTTPS webhook, enable webhook delivery, and avoid conflicting automatic replies. |
| Mattermost | Enter the server URL and a Bot Account access token, then add that account to the relevant teams and channels. The adapter uses REST and WebSocket APIs. |
![The Discord adapter uses the application Client ID and bot token.](/images/articles/source/images/dify-langbot/059-platform-discord-fields.png)
*The Discord adapter uses the application Client ID and bot token.*
![The Telegram adapter uses a BotFather token and exposes reply options.](/images/articles/source/images/dify-langbot/060-platform-telegram-fields.png)
*The Telegram adapter uses a BotFather token and exposes reply options.*
The catalog also includes Matrix, Lark, DingTalk, WeCom, WeChat-related adapters, QQ, KOOK, OneBot v11, Satori, HTTP Bot, and Page Bot. See the [platform-specific LangBot guides](https://langbot.app/docs/en/usage/platforms/readme) for the permissions and networking required by each adapter. In particular, the local-only deployment above needs a suitable public HTTPS endpoint for webhook-based integrations such as Slack and LINE.
## Troubleshooting
When something fails, check the path in order: Dify preview, the published app version, LangBot's `/v1` base URL and app type, then the platform's event delivery. If you change Dify service passwords, keep Redis and Celery credentials aligned, and do the same for Sandbox and its code-execution client.
Our local proxy initially returned fake DNS addresses that Dify's SSRF proxy rejected. Correcting DNS fixed the plugin download without disabling network protections. For external API calls, inspect the run record after a retry rather than assuming that a transport error means the app configuration is wrong.
Project sources: [LangBot](https://github.com/langbot-app/LangBot) and [Dify](https://github.com/langgenius/dify). The deployment and screenshots are from September 16, 2026; later versions may move some controls.
## Further reading
- [Route Support Questions in Discord and LINE with Dify and LangBot](https://langbot.app/en/blog/dify-langbot-support-triage)
- [Turn GitHub Releases into Telegram Briefings with Dify and LangBot](https://langbot.app/en/blog/dify-langbot-github-release-briefing)
+4
View File
@@ -7,6 +7,7 @@ Product updates, engineering deep dives, tutorials, integrations, and announceme
## Product Updates
- [LangBot 4.11: Event-Driven Agents, Plugin Runners, and a Workspace Assistant](/en/articles/langbot-v411-event-driven-agents) — 2026-10-15
- [The new LangBot Cloud is here — and multi-user Workspaces are now in open source](/en/articles/langbot-cloud-multi-user-workspaces) — 2026-08-25
## Engineering
@@ -17,6 +18,9 @@ Product updates, engineering deep dives, tutorials, integrations, and announceme
## Tutorials & Integrations
- [Turn GitHub Releases into Telegram Briefings with Dify and LangBot](/en/articles/dify-langbot-github-release-briefing) — 2026-09-16
- [Route Support Questions in Discord and LINE with Dify and LangBot](/en/articles/dify-langbot-support-triage) — 2026-09-16
- [A Dify Writing Assistant for Discord and Telegram with GPT-6 Astra and LangBot](/en/articles/dify-langbot-writing-assistant) — 2026-09-16
- [LangTARS: Open-Source AI Agent for Remote PC Control — Works with Dify, n8n & 10+ Messaging Platforms](/en/articles/langtars-remote-pc-control-dify-n8n) — 2026-03-23
- [How to Connect DeepSeek R1 to WeChat, Discord & Telegram in 5 Minutes (FREE)](/en/articles/connect-deepseek-to-wechat) — 2026-02-21
- [Deploy Your Own AI Bot to Discord, Telegram & WeChat in 5 Minutes](/en/articles/deploy-ai-bot-in-5-minutes) — 2026-02-17
@@ -0,0 +1,132 @@
---
title: "LangBot 4.11: Event-Driven Agents, Plugin Runners, and a Workspace Assistant"
description: "Explore LangBot 4.11 with real screenshots: route platform events to agents, install independent AgentRunner plugins, manage resources through the Workspace Assistant, and upgrade existing pipelines."
---
This article is synchronized from the LangBot Blog. [Read the canonical version](https://langbot.app/en/blog/langbot-v411-event-driven-agents).
Published 2026-10-15 · Author: LangBot Team
LangBot is an open-source AI chatbot and agent platform that connects messaging platforms, large language models, knowledge bases, and plugins to help you build, deploy, and manage AI assistants.
Most chatbots start with a simple loop: receive a message, generate a reply. Real collaboration involves more than messages, though. A new member joins a community, someone reacts to an answer, or a colleague clicks a card button. Each can be the beginning of a task.
**LangBot 4.11 makes these events configurable entry points for agents, with routing and execution tracking.** Together with plugin-based AgentRunners and the new Workspace Assistant, the release separates three practical questions: what triggers the work, what executes it, and how you manage it.
## 1. Event-driven agents: more than the next message
Event-Based Agents, or EBA, extend processing beyond ordinary messages to platform events such as member joins and departures, message recalls, reactions, and card clicks. In this release, 13 platform adapters have been rebuilt on the EBA architecture.
That does not mean every platform offers identical event coverage. Available events still depend on the platform, adapter, and bot permissions. The shared foundation is what happens after an event reaches LangBot: it can be routed to a suitable processor.
![Routing platform events to processors](/images/articles/source/images/langbot-411/eba-event-routing.png)
*Event Routing example from the official 4.11 release notes.*
### Start with the scenario
Event Routing provides common scenarios, such as welcoming new members or handling departures, as starting points for rules. You then choose the processor responsible for the work.
For example, a community could send ordinary questions to a knowledge-base Pipeline, route joins to an Agent that welcomes members and explains community rules, and use a plugin processor for events requiring fixed business logic. This is a configuration pattern, not a preconfigured integration: check platform support and permissions, then test each route before enabling it.
The benefit is a cleaner separation between platform connectivity and business behavior. You can revise the welcome flow without rewriting the chatbot integration, or change the question-answering strategy without combining every behavior into one prompt.
### Pipeline, Agent, or plugin processor?
![Three processor types in a running LangBot 4.11 instance](/images/articles/source/images/langbot-411/processor-types.png)
*The processor creation screen in the fresh LangBot 4.11.0 instance used for this article.*
- **Pipeline:** handles message events through a fixed sequence. A good fit for direct AI replies, knowledge-base questions, and established message-processing flows.
- **Agent:** follows natural-language instructions to handle different events, or delegates processing to an external agent platform. Useful when a task requires contextual decisions.
- **Plugin processor:** runs plugin code for explicitly declared event types. A good fit for deterministic rules and specialized integrations.
Not everything needs to become an agent. Keep clear rules in code, predictable question-answering in a Pipeline, and use an Agent where judgment adds value.
### Debug the event, not just the reply
The event debugger lets you edit an event payload through a form and inspect execution logs and details. It helps validate fields and processing behavior before testing on the real messaging platform. A successful debug run does not replace verification of platform connectivity, permissions, and actual callbacks.
Platform improvements accompany the new architecture, including Slack Socket Mode, DingTalk card interactions, WeChat typing indicators, and OneBot WebSocket support. Check the relevant platform documentation for the exact capabilities and setup requirements.
## 2. Plugin-based AgentRunners: update execution independently
LocalAgent, Dify, Coze, and n8n runners have moved from the core application into official Marketplace plugins. New runners include Codex, Claude Code, and ACP.
![Official runners in the live extension marketplace](/images/articles/source/images/langbot-411/marketplace-live.png)
*The Official Runner section loaded from the Marketplace in our running instance. Marketplace listings evolve independently of the Core release.*
For users, the practical change is straightforward: **install the runners you need and update them independently**. Use LocalAgent for models, tools, and knowledge retrieval, or connect an existing Dify application or n8n workflow without building a separate messaging integration for each execution backend.
For developers, AgentRunner Protocol v1 provides an extension boundary for implementing a runner without adding platform-specific execution logic directly to Core.
![AgentRunner plugins featured in the release notes](/images/articles/source/images/langbot-411/runner-plugins-marketplace.png)
*Runner examples from the official release notes. Each runner still has its own account, API, and execution-environment requirements.*
Plugin-based execution is not unrestricted execution. Runners can access only the tools and platform APIs authorized in the current context. The Marketplace displays certification badges, and Core verifies certified plugin signatures. These mechanisms address provenance and authorization; still read the plugin documentation and check its compatibility with your deployment.
### What happens to existing Pipelines?
The migration flow installs required plugins and backs up the original configuration. After upgrading, complete migration on the Pipelines page, then review the selected runner, model, knowledge bases, and tools.
**Migrated Pipelines start fresh sessions.** Legacy custom runners must be rewritten as plugin runners. Offline deployments can choose **Data only** migration and install the runner plugins manually. The [4.11 configuration migration map](https://github.com/langbot-app/LangBot/blob/v4.11.0/docs/pipeline-migration-config-map.zh-CN.md) provides the detailed mappings in Chinese.
## 3. Workspace Assistant: configuration through confirmed actions
The new Workspace Assistant is for the people managing LangBot, rather than end users chatting with a bot. It can inspect resources in the current Workspace and help create or configure resources such as Pipelines and knowledge bases through conversation.
![Workspace Assistant alongside the execution dashboard](/images/articles/source/images/langbot-411/workspace-assistant.png)
*The assistant's initial screen in our fresh instance. A LangBot Account or a configured model is required before use. The zero-value monitoring data is the genuine empty state of this new Workspace.*
Start with a read-only question such as “What models, knowledge bases and Pipelines are available?” Then ask for a task such as creating a knowledge-base question-answering application. The useful distinction is not merely replacing a form with a chat box: the assistant can inspect existing resources before proposing a configuration.
**Every write requires confirmation before execution.** Review the proposed resource, parameters, and scope before approving a change. This makes configuration easier to find while keeping the administrator in control of modifications.
## 4. Operations that match the new execution model
### Follow executions, not only message counts
With events going to Pipelines, Agents, or plugins, debugging requires a view of the whole execution. LangBot 4.11 adds unified execution views, tool-call tracing, and a live in-flight panel.
A useful troubleshooting sequence is to check whether the event arrived, which processor received it, and whether model and tool calls completed. This separates connectivity problems from routing mistakes and execution failures instead of treating every missing reply as the same issue.
### Account security and an operation trail
![Passkey and two-factor authentication settings](/images/articles/source/images/langbot-411/account-security.png)
*The account settings in our running instance. Passkeys and two-factor authentication are not enabled on this demonstration account.*
The release adds WebAuthn passkey sign-in and TOTP two-factor authentication, alongside operation logs that record changes and support integrity checks. In a shared Workspace, these features help strengthen sign-in and establish who changed what. Passkeys also depend on browser secure-context requirements; configure them on an appropriate HTTPS deployment.
Media handling now uses content-addressed, deduplicated storage to reduce growth of `langbot.db` caused by repeated media. For command-line operations, `lbctl` and API keys provide management and diagnostic entry points that can fit into existing operational workflows.
## 5. A clearer first run—and an upgrade checklist
![Selecting a platform in the first-run wizard](/images/articles/source/images/langbot-411/onboarding.png)
*The live onboarding wizard starts with a platform, then moves through bot setup and AI engine configuration.*
New users can follow the sidebar tour and scenario-based bot wizard. Validate a simple question-and-answer flow first, then add knowledge retrieval, tools, and event routes. Introducing one capability at a time makes failures easier to understand.
For an existing deployment:
1. **Back up first.** Preserve `data/` or your PostgreSQL database and deployment configuration. Upgrading from the latest v4.10.x is recommended.
2. **Upgrade Core and its matching Runtime.** Check service connectivity. The 4.11.0 release pins SDK `0.7.11`; do not leave an older Runtime in place.
3. **Migrate Pipelines and update plugins.** Review the resulting runner configuration and remember the fresh-session boundary.
4. **Verify a real business flow.** Test an existing message conversation before expanding to event routes and authorized tools.
5. **Review telemetry and configuration changes.** New execution telemetry is enabled by default and excludes message content; disable that telemetry with `space.disable_telemetry: true`. Configuration adds `media_cache`, `api.host`, and `runner.admin_plugins`, and removes `force_box_session_id_template`. See the [data collection policy](https://langbot.app/docs/en/insight/data-collection-policy) and release notes.
## Get started with LangBot 4.11
The release connects three decisions: **which event starts a task, which runner or processor handles it, and how to manage and observe the result**. Keep familiar chat-based flows where they work, then introduce community interactions and event-driven tasks incrementally.
- [Download v4.11.0 and read the full release notes](https://github.com/langbot-app/LangBot/releases/tag/v4.11.0)
- [Read the deployment and usage documentation](https://langbot.app/docs/en/insight/guide)
- [Try LangBot Cloud](https://cloud.langbot.app)
Thanks to everyone who contributed code, testing, documentation, and feedback. This article focuses on the main product changes; the complete contributor list is in the release notes.
*Image sources: the event-routing and runner-overview images come from the v4.11.0 GitHub Release. The other five screenshots were captured from an independently launched official `rockchin/langbot:v4.11.0` instance. Screenshots use English for consistent cross-language reference. No production bots were connected, and the demo screens are not presented as evidence of production task execution.*
+1 -1
View File
@@ -111,7 +111,7 @@ You need to first deploy and start LangBot, ensuring that Plugin Runtime is runn
<Info title="Runtime has two startup modes:">
- `Stdio` mode: When you start LangBot using source code without the startup parameter `--standalone-runtime`, LangBot will automatically start Plugin Runtime as a subprocess and communicate with Plugin Runtime through `stdio` (standard input/output streams). In this case, Runtime will load plugins from the `data/plugins` directory in the LangBot root directory and listen on port `5401` of the LangBot host as a debug port.
- `Stdio` mode: When you start LangBot using source code without the startup parameter `--standalone-runtime`, LangBot will automatically start Plugin Runtime as a subprocess and communicate with Plugin Runtime through `stdio` (standard input/output streams). In this case, Runtime will load plugins from the `data/plugins` directory in the LangBot root directory and listen on the LangBot host debug port (default `5401`, overridable via the port in `plugin.display_plugin_debug_url`).
- `WebSocket` mode:
- Production environment: When you start LangBot using the official `docker-compose.yaml`, Plugin Runtime will run in a separate container, and LangBot will communicate with Plugin Runtime in WebSocket mode due to the startup parameter `--standalone-runtime`. The 5401 port of the Runtime container will be mapped to the 5401 port of the host as default.
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

@@ -0,0 +1,213 @@
---
title: "Turn GitHub Releases into Telegram Briefings with Dify and LangBot"
description: "Fetch a real GitHub release with Dify, extract the useful fields and let GPT-6 Astra write a sourced briefing. Connect the Workflow to LangBot with the correct input and output contract."
---
この記事は LangBot Blog から同期されています。 [Blog の原文を読む](https://langbot.app/en/blog/dify-langbot-github-release-briefing).
公開日:2026-09-16 · 著者:LangBot Team
> この記事の日本語版はまだ公開されていないため、英語版を掲載しています。
“What changed in the latest release?” sounds like a simple chatbot question. It becomes a data problem as soon as a repository ships something newer than the model knows.
We built an on-demand release briefing that reads GitHub first. Dify fetches the public release JSON, a code node keeps the useful fields, GPT-6 Astra writes a short summary, and LangBot returns it to the conversation. The example uses the public LangBot repository, and the same pattern works for other release feeds.
![The briefing comes from a live GitHub API request, with a source link.](/images/articles/source/images/dify-langbot/056-release-english-live-briefing.png)
*The briefing comes from a live GitHub API request, with a source link.*
## Start with a working Dify and LangBot installation
Start Docker Compose and Git, then follow the [Dify Docker Compose guide](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) and the [LangBot Docker guide](https://langbot.app/docs/en/deploy/langbot/docker/) to bring up both services. For Dify, clone the repository, enter `docker`, copy `.env.example` to `.env`, and start Compose. The LangBot guide includes the application image and plugin runtime configuration.
The screenshots come from a local installation of **Dify 1.17.1 and LangBot v4.10.11**. We mapped the browser ports to `8088` and `5368`. Those are custom demo ports; the default installations normally use `80` and `5300`. With the defaults, open `http://localhost` and `http://localhost:5300`. You do not need to change ports just to match a screenshot. Create your own administrator accounts and select **English** in both interfaces.
![The first-run screen of the local Dify deployment.](/images/articles/source/images/dify-langbot/00-dify-install.png)
*The first-run screen of the local Dify deployment.*
![The local LangBot installation before administrator setup.](/images/articles/source/images/dify-langbot/00-langbot-install.png)
*The local LangBot installation before administrator setup.*
The important requirement is that **the LangBot container can reach Dify**. Our two services share a Docker network, so the Runner uses `http://nginx/v1`, where `nginx` is Dify's service name. You can attach Dify's `nginx` service and LangBot to the same external network in their Compose configurations. For separate hosts, use a Dify HTTPS address reachable from LangBot and append `/v1`. Every `http://nginx/v1` example below refers to our shared network; replace it for your own deployment. Inside a container, `localhost` points back to that container.
## Connect GPT-6 Astra to Dify
Open **Integrations → Model Provider**, install the official **OpenAI-API-compatible** provider, and choose **Add Model**. We tested provider version 0.0.66 with an OpenAI-compatible gateway.
| Field | Tutorial setting |
| --- | --- |
| Model Name / endpoint model name | `gpt-6-astra` |
| Model Type / Completion mode | LLM / Chat |
| Model display name | GPT-6 Astra |
| API Base URL | Your provider's compatible endpoint, usually ending in `/v1` |
| API Key | Your own provider key |
| API Type | Chat Completions API |
| Context size / maximum-token ceiling | 32768 / 4096 for this example |
Those limits are conservative settings for this tutorial, not a statement of Astra's full specifications. Save the model and let Dify validate the connection. Replace the gateway shown in the screenshot with your own authorized endpoint. Model names and capabilities depend on your provider. This walkthrough retains the `gpt-6-astra` identifier used in the tested deployment.
![The custom model form, captured before entering the API key.](/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png)
*The custom model form, captured before entering the API key.*
## Create a Workflow with a clear input and output
Create a Dify **Workflow** named `Astra Release Briefing`. Each request is an independent read of the current release, so a Workflow fits naturally.
Connect these nodes:
`User Request → HTTP Request → Code → LLM → End`
![The complete five-node release workflow.](/images/articles/source/images/dify-langbot/045-release-workflow-overview.png)
*The complete five-node release workflow.*
### 1. Name the input for LangBot
In the Start node, add a required paragraph input named:
```text
langbot_user_message_text
```
LangBot's Dify Workflow Runner places the incoming message text in that field. If you call it `question` instead, the workflow may pass a manual Dify test and still fail when LangBot calls it with different input names.
![The required input is named to match the runner contract.](/images/articles/source/images/dify-langbot/049-release-workflow-input.png)
*The required input is named to match the runner contract.*
### 2. Read the latest public release
Use an HTTP Request node with GET:
```text
https://api.github.com/repos/langbot-app/LangBot/releases/latest
```
Add `Accept: application/vnd.github+json` and `User-Agent: LangBot-Dify-Tutorial`. This example reads public data without a GitHub token. Leave SSL verification enabled and choose sensible connection and read timeouts for your environment.
![The HTTP node fetches the latest release directly from GitHub.](/images/articles/source/images/dify-langbot/046-release-http-request-settings.png)
*The HTTP node fetches the latest release directly from GitHub.*
### 3. Extract the useful fields
Pass the HTTP node's `body` and `status_code` to a Code node. Keep only the information needed for a briefing:
```python
import json
def main(body: str, status_code: int) -> dict:
if status_code != 200:
return {"release": json.dumps({"error": f"GitHub HTTP {status_code}"})}
data = json.loads(body)
return {"release": json.dumps({
"repository": "langbot-app/LangBot",
"tag": data.get("tag_name"),
"published_at": data.get("published_at"),
"url": data.get("html_url"),
"notes": (data.get("body") or "")[:14000],
}, ensure_ascii=False)}
```
This removes avatars and unrelated API URLs from the model input. It also makes a non-200 response explicit. A transport failure can still stop the HTTP node before this code runs, which is why you should inspect failed workflow runs as well as successful ones.
![The Code node turns the raw response into a small release record.](/images/articles/source/images/dify-langbot/047-release-code-extraction-node.png)
*The Code node turns the raw response into a small release record.*
### 4. Write the briefing and return summary
Choose GPT-6 Astra in the LLM node. Ask it to answer in the user's language and include the repository, release tag, publication time, three useful highlights, and the source URL. Tell it to use only the supplied API data and to report missing data or an error instead of guessing.
Pass both `langbot_user_message_text` and the extracted `release` record into the user prompt. In End, map the LLM's `text` to an output named **`summary`**. This is the field LangBot expects from the workflow response.
![The final output maps the generated text to summary.](/images/articles/source/images/dify-langbot/054-release-summary-output-verified.png)
*The final output maps the generated text to summary.*
## Verify against GitHub, not against the screenshot
Our English and Chinese runs both retrieved `v4.10.11`, published on September 12, 2026 at 04:55:58 UTC. The briefing linked to that exact release and summarized changes in knowledge ingestion, monitoring, and platform compatibility.
![The English run includes a release tag, date, highlights, and source.](/images/articles/source/images/dify-langbot/056-release-english-live-briefing.png)
*The English run includes a release tag, date, highlights, and source.*
Your run may show a newer version. Compare the answer with the current API fields—`tag_name`, `published_at`, and `html_url`—rather than expecting the version in this article forever.
## Put LangBot in front of the app
Publish the saved version in Dify. Open **Access Point → Backend Service API → API Key** and create a key for this app.
In LangBot, choose **Create Pipelines**, name the pipeline `Astra Release Briefing`, and open **Configuration → AI**:
| Field | Value |
| --- | --- |
| Runner | Dify Service API |
| Base URL | `http://nginx/v1` |
| App Type | Workflow |
| API Key | The Dify app key you just created |
The Dify app key belongs here. The Astra provider key stays in Dify. Save the pipeline, then use **Debug Chat** to check the complete request and response path before adding a messaging platform.
![The LangBot pipeline settings, captured before entering the app key.](/images/articles/source/images/dify-langbot/078-langbot-release-workflow-settings.png)
*The LangBot pipeline settings, captured before entering the app key.*
## Ask for the briefing through LangBot
The English request through LangBot returned the same kind of source-linked briefing. I also tested Chinese output. One request hit a temporary upstream SSL interruption; a later retry succeeded. The failed run remains separate from the successful evidence.
![The workflow summary returned through LangBot.](/images/articles/source/images/dify-langbot/079-langbot-release-english-roundtrip.png)
*The workflow summary returned through LangBot.*
For Telegram or a Discord project channel, start with an on-demand command or mention trigger. This workflow reads the release when someone asks; scheduled delivery requires an additional scheduler and sending step.
To cover another repository, first duplicate the app and change the fixed API URL. Add a validated repository parameter only when you actually need it. A short, predictable integration is much easier to operate than an unrestricted URL-fetching bot.
## Connect it to Telegram and Discord
Choose **Create Bots** in LangBot, select your adapter, and enter credentials from that platform. After creating the bot, select the pipeline you just built. Check the pipeline's trigger rules for direct messages, group messages, and mentions before inviting it into a channel.
The measured path in this walkthrough is **LangBot → Dify → GPT-6 Astra → LangBot**. We inspected the real adapter forms below; we did not authorize a live Slack workspace, Discord server, Telegram bot, or LINE account for this demo.
| Platform | Setup path |
| --- | --- |
| Slack | Create a Slack app, grant the required bot scopes, install it to the workspace, and enter the Bot Token and Signing Secret in LangBot. Configure event subscriptions with the public HTTPS callback from the bot setup, verify it, and invite the bot to the intended channel. |
| Discord | Create an application and bot in the Developer Portal. Enter Client ID and bot Token, enable the required message intents, then invite the bot with the appropriate channel permissions. |
| Telegram | Create a bot with BotFather and enter its token. Start with a direct message; for groups, invite the bot and configure privacy mode and LangBot's trigger rules for the messages it should receive. |
| LINE | Create a Messaging API channel. Enter the Channel access token and Channel secret, configure the public HTTPS webhook, enable webhook delivery, and avoid conflicting automatic replies. |
| Mattermost | Enter the server URL and a Bot Account access token, then add that account to the relevant teams and channels. The adapter uses REST and WebSocket APIs. |
![The Discord adapter uses the application Client ID and bot token.](/images/articles/source/images/dify-langbot/059-platform-discord-fields.png)
*The Discord adapter uses the application Client ID and bot token.*
![The Telegram adapter uses a BotFather token and exposes reply options.](/images/articles/source/images/dify-langbot/060-platform-telegram-fields.png)
*The Telegram adapter uses a BotFather token and exposes reply options.*
The catalog also includes Matrix, Lark, DingTalk, WeCom, WeChat-related adapters, QQ, KOOK, OneBot v11, Satori, HTTP Bot, and Page Bot. See the [platform-specific LangBot guides](https://langbot.app/docs/en/usage/platforms/readme) for the permissions and networking required by each adapter. In particular, the local-only deployment above needs a suitable public HTTPS endpoint for webhook-based integrations such as Slack and LINE.
## Troubleshooting
When something fails, check the path in order: Dify preview, the published app version, LangBot's `/v1` base URL and app type, then the platform's event delivery. If you change Dify service passwords, keep Redis and Celery credentials aligned, and do the same for Sandbox and its code-execution client.
Our local proxy initially returned fake DNS addresses that Dify's SSRF proxy rejected. Correcting DNS fixed the plugin download without disabling network protections. For external API calls, inspect the run record after a retry rather than assuming that a transport error means the app configuration is wrong.
Project sources: [LangBot](https://github.com/langbot-app/LangBot) and [Dify](https://github.com/langgenius/dify). The deployment and screenshots are from September 16, 2026; later versions may move some controls.
## Further reading
- [A Dify Writing Assistant for Discord and Telegram with GPT-6 Astra and LangBot](https://langbot.app/en/blog/dify-langbot-writing-assistant)
- [Route Support Questions in Discord and LINE with Dify and LangBot](https://langbot.app/en/blog/dify-langbot-support-triage)
@@ -0,0 +1,186 @@
---
title: "Route Support Questions in Discord and LINE with Dify and LangBot"
description: "Use GPT-6 Astra and a Dify Question Classifier to separate account help, product questions and requests for human review. Test each route through LangBot before connecting Discord or LINE."
---
この記事は LangBot Blog から同期されています。 [Blog の原文を読む](https://langbot.app/en/blog/dify-langbot-support-triage).
公開日:2026-09-16 · 著者:LangBot Team
> この記事の日本語版はまだ公開されていないため、英語版を掲載しています。
A single support prompt can work surprisingly well—until the same bot receives an expired invitation, an export question, and an angry refund request. Those messages need different responses and different limits.
We built a three-route support assistant in Dify, then connected it through LangBot. GPT-6 Astra classifies the request and writes a reply for the selected route. The result is small enough to inspect: one classifier, three response nodes, and three outputs.
![The actual support Chatflow, with separate account, product, and human-review routes.](/images/articles/source/images/dify-langbot/039-triage-three-branch-overview.png)
*The actual support Chatflow, with separate account, product, and human-review routes.*
## Start with a working Dify and LangBot installation
Start Docker Compose and Git, then follow the [Dify Docker Compose guide](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) and the [LangBot Docker guide](https://langbot.app/docs/en/deploy/langbot/docker/) to bring up both services. For Dify, clone the repository, enter `docker`, copy `.env.example` to `.env`, and start Compose. The LangBot guide includes the application image and plugin runtime configuration.
The screenshots come from a local installation of **Dify 1.17.1 and LangBot v4.10.11**. We mapped the browser ports to `8088` and `5368`. Those are custom demo ports; the default installations normally use `80` and `5300`. With the defaults, open `http://localhost` and `http://localhost:5300`. You do not need to change ports just to match a screenshot. Create your own administrator accounts and select **English** in both interfaces.
![The first-run screen of the local Dify deployment.](/images/articles/source/images/dify-langbot/00-dify-install.png)
*The first-run screen of the local Dify deployment.*
![The local LangBot installation before administrator setup.](/images/articles/source/images/dify-langbot/00-langbot-install.png)
*The local LangBot installation before administrator setup.*
The important requirement is that **the LangBot container can reach Dify**. Our two services share a Docker network, so the Runner uses `http://nginx/v1`, where `nginx` is Dify's service name. You can attach Dify's `nginx` service and LangBot to the same external network in their Compose configurations. For separate hosts, use a Dify HTTPS address reachable from LangBot and append `/v1`. Every `http://nginx/v1` example below refers to our shared network; replace it for your own deployment. Inside a container, `localhost` points back to that container.
## Connect GPT-6 Astra to Dify
Open **Integrations → Model Provider**, install the official **OpenAI-API-compatible** provider, and choose **Add Model**. We tested provider version 0.0.66 with an OpenAI-compatible gateway.
| Field | Tutorial setting |
| --- | --- |
| Model Name / endpoint model name | `gpt-6-astra` |
| Model Type / Completion mode | LLM / Chat |
| Model display name | GPT-6 Astra |
| API Base URL | Your provider's compatible endpoint, usually ending in `/v1` |
| API Key | Your own provider key |
| API Type | Chat Completions API |
| Context size / maximum-token ceiling | 32768 / 4096 for this example |
Those limits are conservative settings for this tutorial, not a statement of Astra's full specifications. Save the model and let Dify validate the connection. Replace the gateway shown in the screenshot with your own authorized endpoint. Model names and capabilities depend on your provider. This walkthrough retains the `gpt-6-astra` identifier used in the tested deployment.
![The custom model form, captured before entering the API key.](/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png)
*The custom model form, captured before entering the API key.*
## Define what each route is allowed to do
This example uses a fictional help-desk product called Northstar Desk. Its few product rules are included directly in the branch prompts, so you do not need a pre-existing knowledge base or another tutorial.
| Route | Requests | Job |
| --- | --- | --- |
| Account | Login, invitations, workspace access | Explain the invitation recovery steps |
| Product | CSV export, trial limits, basic setup | Answer from the small set of supplied product rules |
| Human | Billing, refunds, enterprise pricing, complaints, unclear mixed requests | Explain that a human decision is needed and help the user prepare a concise request |
The Human branch produces handoff guidance. It does not create a ticket, notify an employee, or approve a refund. That distinction belongs in the prompt: otherwise the assistant may casually imply it has performed an action that the workflow never implemented.
## Build the classifier and three branches
Create a **Chatflow** named `Astra Support Router`. Connect User Input to a **Question Classifier**, choose GPT-6 Astra, and set its query variable to `sys.query`.
Add these categories:
```text
Account: login, invitation, password or workspace access
Product: usage, ticket export, setup and trial limits
Human: billing, refunds, enterprise pricing, angry complaints
or unclear mixed questions
```
![The category descriptions define the routing boundary.](/images/articles/source/images/dify-langbot/040-triage-classifier-settings.png)
*The category descriptions define the routing boundary.*
In the classifier's advanced instructions, tell it to choose Human when essential context is missing or the request needs authorization. Connect each branch to its own LLM node and Answer node.
Use GPT-6 Astra in each LLM node and pass the user query through `sys.query`. Give the branches different system instructions:
- **Account Reply:** invitations expire after 48 hours. Ask the workspace owner to resend from `Settings > Members`. Never request passwords. Ask one clarifying question if the problem is different.
- **Product Reply:** owners export CSV tickets from `Settings > Data > Export`; export links last 7 days. The trial lasts 14 days and supports 5 teammates and 2 inboxes. Say when the supplied notes do not cover a question.
- **Human Reply:** acknowledge the request and explain that a human must decide. Ask for a brief issue summary and a non-sensitive reference. Tell the user to contact their support team, without inventing an address, response-time promise, or completed action.
All three prompts ask for concise replies in the user's language. Keeping the branch instructions separate makes a later change easier to review: adjusting billing guidance does not also change the login instructions.
## Test the path, not only the wording
We ran an expired-invitation question, a CSV-export question, and a refund complaint. The preview identified the selected output for each run:
| Test | Observed output | Response |
| --- | --- | --- |
| Expired invitation | Account Output | Owner resend instructions and the 48-hour limit |
| Export tickets as CSV | Product Output | Correct menu path and 7-day availability |
| Refund complaint | Human Output | Human-review guidance without claiming a refund was issued |
![The account test follows the Account branch.](/images/articles/source/images/dify-langbot/041-triage-account-path-result.png)
*The account test follows the Account branch.*
![The export question follows the Product branch.](/images/articles/source/images/dify-langbot/043-triage-product-path-result.png)
*The export question follows the Product branch.*
Expand the workflow process in Preview when a result looks odd. A plausible sentence can hide an incorrect route. That is why the output name is part of the test, rather than treating every fluent answer as a pass.
## Put LangBot in front of the app
Publish the saved version in Dify. Open **Access Point → Backend Service API → API Key** and create a key for this app.
In LangBot, choose **Create Pipelines**, name the pipeline `Astra Support Router`, and open **Configuration → AI**:
| Field | Value |
| --- | --- |
| Runner | Dify Service API |
| Base URL | `http://nginx/v1` |
| App Type | Chat |
| API Key | The Dify app key you just created |
The Dify app key belongs here. The Astra provider key stays in Dify. Save the pipeline, then use **Debug Chat** to check the complete request and response path before adding a messaging platform.
![The LangBot pipeline settings, captured before entering the app key.](/images/articles/source/images/dify-langbot/053-langbot-triage-dify-settings.png)
*The LangBot pipeline settings, captured before entering the app key.*
## Run it through LangBot
The same expired-invitation question in LangBot returned the workspace-owner recovery steps. A later refund request in Chinese reached the human-review guidance. LangBot did not need its own copy of the classification rules.
![An account-support response returned through LangBot.](/images/articles/source/images/dify-langbot/055-langbot-triage-account-english.png)
*An account-support response returned through LangBot.*
Before putting this in a busy Discord server or a LINE support account, add ambiguous examples such as “I cannot log in and want a refund.” If those repeatedly land in Product, refine the category descriptions and classifier instructions.
When you are ready for a real handoff, add your existing ticketing or notification API to the Human branch and handle its success and failure explicitly. The example gives you a visible place to add that action later.
## Connect it to Discord and LINE
Choose **Create Bots** in LangBot, select your adapter, and enter credentials from that platform. After creating the bot, select the pipeline you just built. Check the pipeline's trigger rules for direct messages, group messages, and mentions before inviting it into a channel.
The measured path in this walkthrough is **LangBot → Dify → GPT-6 Astra → LangBot**. We inspected the real adapter forms below; we did not authorize a live Slack workspace, Discord server, Telegram bot, or LINE account for this demo.
| Platform | Setup path |
| --- | --- |
| Slack | Create a Slack app, grant the required bot scopes, install it to the workspace, and enter the Bot Token and Signing Secret in LangBot. Configure event subscriptions with the public HTTPS callback from the bot setup, verify it, and invite the bot to the intended channel. |
| Discord | Create an application and bot in the Developer Portal. Enter Client ID and bot Token, enable the required message intents, then invite the bot with the appropriate channel permissions. |
| Telegram | Create a bot with BotFather and enter its token. Start with a direct message; for groups, invite the bot and configure privacy mode and LangBot's trigger rules for the messages it should receive. |
| LINE | Create a Messaging API channel. Enter the Channel access token and Channel secret, configure the public HTTPS webhook, enable webhook delivery, and avoid conflicting automatic replies. |
| Mattermost | Enter the server URL and a Bot Account access token, then add that account to the relevant teams and channels. The adapter uses REST and WebSocket APIs. |
![The Discord adapter uses the application Client ID and bot token.](/images/articles/source/images/dify-langbot/059-platform-discord-fields.png)
*The Discord adapter uses the application Client ID and bot token.*
![LINE requires its channel access token and channel secret.](/images/articles/source/images/dify-langbot/061-platform-line-fields.png)
*LINE requires its channel access token and channel secret.*
The catalog also includes Matrix, Lark, DingTalk, WeCom, WeChat-related adapters, QQ, KOOK, OneBot v11, Satori, HTTP Bot, and Page Bot. See the [platform-specific LangBot guides](https://langbot.app/docs/en/usage/platforms/readme) for the permissions and networking required by each adapter. In particular, the local-only deployment above needs a suitable public HTTPS endpoint for webhook-based integrations such as Slack and LINE.
## Troubleshooting
When something fails, check the path in order: Dify preview, the published app version, LangBot's `/v1` base URL and app type, then the platform's event delivery. If you change Dify service passwords, keep Redis and Celery credentials aligned, and do the same for Sandbox and its code-execution client.
Our local proxy initially returned fake DNS addresses that Dify's SSRF proxy rejected. Correcting DNS fixed the plugin download without disabling network protections. For external API calls, inspect the run record after a retry rather than assuming that a transport error means the app configuration is wrong.
Project sources: [LangBot](https://github.com/langbot-app/LangBot) and [Dify](https://github.com/langgenius/dify). The deployment and screenshots are from September 16, 2026; later versions may move some controls.
## Further reading
- [A Dify Writing Assistant for Discord and Telegram with GPT-6 Astra and LangBot](https://langbot.app/en/blog/dify-langbot-writing-assistant)
- [Turn GitHub Releases into Telegram Briefings with Dify and LangBot](https://langbot.app/en/blog/dify-langbot-github-release-briefing)
@@ -0,0 +1,179 @@
---
title: "A Dify Writing Assistant for Discord and Telegram with GPT-6 Astra and LangBot"
description: "Build a basic Dify Chatbot for announcements, revisions and translations, then connect it to LangBot. Includes tested prompts, screenshots and Discord and Telegram setup guidance."
---
この記事は LangBot Blog から同期されています。 [Blog の原文を読む](https://langbot.app/en/blog/dify-langbot-writing-assistant).
公開日:2026-09-16 · 著者:LangBot Team
> この記事の日本語版はまだ公開されていないため、英語版を掲載しています。
A community announcement usually starts as a few rough notes: a date, a channel, and something people need to bring. The first draft is easy. The annoying part is reopening another app for every “make it shorter” or “turn that into a Telegram reminder.”
We built a small writing assistant that keeps those revisions in the conversation. Dify owns the prompt and chat history, GPT-6 Astra writes the response, and LangBot provides the messaging-platform entry point. Here is the complete setup, including the local deployment and the replies We tested.
![A real response from Dify and Astra, shown in LangBot Debug Chat.](/images/articles/source/images/dify-langbot/025-langbot-writing-english-roundtrip.png)
*A real response from Dify and Astra, shown in LangBot Debug Chat.*
## Start with a working Dify and LangBot installation
Start Docker Compose and Git, then follow the [Dify Docker Compose guide](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) and the [LangBot Docker guide](https://langbot.app/docs/en/deploy/langbot/docker/) to bring up both services. For Dify, clone the repository, enter `docker`, copy `.env.example` to `.env`, and start Compose. The LangBot guide includes the application image and plugin runtime configuration.
The screenshots come from a local installation of **Dify 1.17.1 and LangBot v4.10.11**. We mapped the browser ports to `8088` and `5368`. Those are custom demo ports; the default installations normally use `80` and `5300`. With the defaults, open `http://localhost` and `http://localhost:5300`. You do not need to change ports just to match a screenshot. Create your own administrator accounts and select **English** in both interfaces.
![The first-run screen of the local Dify deployment.](/images/articles/source/images/dify-langbot/00-dify-install.png)
*The first-run screen of the local Dify deployment.*
![The local LangBot installation before administrator setup.](/images/articles/source/images/dify-langbot/00-langbot-install.png)
*The local LangBot installation before administrator setup.*
The important requirement is that **the LangBot container can reach Dify**. Our two services share a Docker network, so the Runner uses `http://nginx/v1`, where `nginx` is Dify's service name. You can attach Dify's `nginx` service and LangBot to the same external network in their Compose configurations. For separate hosts, use a Dify HTTPS address reachable from LangBot and append `/v1`. Every `http://nginx/v1` example below refers to our shared network; replace it for your own deployment. Inside a container, `localhost` points back to that container.
## Connect GPT-6 Astra to Dify
Open **Integrations → Model Provider**, install the official **OpenAI-API-compatible** provider, and choose **Add Model**. We tested provider version 0.0.66 with an OpenAI-compatible gateway.
| Field | Tutorial setting |
| --- | --- |
| Model Name / endpoint model name | `gpt-6-astra` |
| Model Type / Completion mode | LLM / Chat |
| Model display name | GPT-6 Astra |
| API Base URL | Your provider's compatible endpoint, usually ending in `/v1` |
| API Key | Your own provider key |
| API Type | Chat Completions API |
| Context size / maximum-token ceiling | 32768 / 4096 for this example |
Those limits are conservative settings for this tutorial, not a statement of Astra's full specifications. Save the model and let Dify validate the connection. Replace the gateway shown in the screenshot with your own authorized endpoint. Model names and capabilities depend on your provider. This walkthrough retains the `gpt-6-astra` identifier used in the tested deployment.
![The custom model form, captured before entering the API key.](/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png)
*The custom model form, captured before entering the API key.*
## Build a basic Chatbot
In Dify Studio, choose **Create → Create from Blank → More basic app types → Chatbot**. Name it `Astra Writing Assistant`. A basic Chatbot is enough here: we need a clear prompt and conversation history, without a branching workflow.
![Dify keeps its basic Chatbot option under More basic app types.](/images/articles/source/images/dify-langbot/010-dify-create-basic-app.png)
*Dify keeps its basic Chatbot option under More basic app types.*
![Give the assistant a name and a specific job.](/images/articles/source/images/dify-langbot/011-dify-writing-app-create.png)
*Give the assistant a name and a specific job.*
Select GPT-6 Astra under **Configure model**, then add these instructions:
```text
You help a community manager turn rough notes into messages people can use.
Reply in the language of the user's request.
For an announcement, give: one clear headline, a short ready-to-send message,
and one optional reminder.
Preserve supplied dates, times, links, and requirements exactly.
Never invent missing event details, discounts, results, or promises.
If an essential detail is missing, ask one concise question.
Use a natural, direct tone. Avoid hype and excessive emojis.
Keep a typical reply under 180 words. When revising, use conversation context.
```
The most useful line is the one about preserving details. An announcement can survive plain wording. It cannot survive an invented RSVP link or the wrong time zone. We also kept the output short enough to be useful in a channel.
![The prompt gives the assistant a narrow job and clear boundaries.](/images/articles/source/images/dify-langbot/012-dify-writing-instructions.png)
*The prompt gives the assistant a narrow job and clear boundaries.*
For the first test, we entered:
> Write a Discord announcement: community demo day is September 22 at 18:00 UTC. Bring one bot demo. RSVP in #demo-day. Keep it friendly and under 100 words.
The response preserved the date, time, and channel. We then asked, “Make it shorter, and remove the optional reminder.” The second reply kept the details from the first turn without asking us to paste them again.
![The first English announcement generated in Dify.](/images/articles/source/images/dify-langbot/016-writing-english-first-reply.png)
*The first English announcement generated in Dify.*
![A follow-up instruction revises the existing announcement.](/images/articles/source/images/dify-langbot/019-writing-english-context-revision.png)
*A follow-up instruction revises the existing announcement.*
Publish the updated configuration with **Publish Update**. This step matters: an external caller should receive the version you just tested, rather than an older prompt still attached to the published app.
![The published app exposes a backend API for LangBot.](/images/articles/source/images/dify-langbot/023-writing-access-point-api.png)
*The published app exposes a backend API for LangBot.*
## Put LangBot in front of the app
Publish the saved version in Dify. Open **Access Point → Backend Service API → API Key** and create a key for this app.
In LangBot, choose **Create Pipelines**, name the pipeline `Astra Writing Assistant`, and open **Configuration → AI**:
| Field | Value |
| --- | --- |
| Runner | Dify Service API |
| Base URL | `http://nginx/v1` |
| App Type | Chat |
| API Key | The Dify app key you just created |
The Dify app key belongs here. The Astra provider key stays in Dify. Save the pipeline, then use **Debug Chat** to check the complete request and response path before adding a messaging platform.
![The LangBot pipeline settings, captured before entering the app key.](/images/articles/source/images/dify-langbot/007-langbot-dify-runner-config.png)
*The LangBot pipeline settings, captured before entering the app key.*
## Test the same task through LangBot
We asked LangBot for a two-sentence Telegram reminder. The reply came back through Dify with the supplied date and time intact. A later request switched the same conversation to Chinese, which also worked.
For a community server, we would start with mention-based triggers in a single channel. Let members ask for a draft, shorten it, and adjust the tone before they decide to post it. That small loop is already useful for release announcements, event reminders, and repeated support replies.
![The writing assistant answering through the LangBot pipeline.](/images/articles/source/images/dify-langbot/025-langbot-writing-english-roundtrip.png)
*The writing assistant answering through the LangBot pipeline.*
## Connect it to Discord and Telegram
Choose **Create Bots** in LangBot, select your adapter, and enter credentials from that platform. After creating the bot, select the pipeline you just built. Check the pipeline's trigger rules for direct messages, group messages, and mentions before inviting it into a channel.
The measured path in this walkthrough is **LangBot → Dify → GPT-6 Astra → LangBot**. We inspected the real adapter forms below; we did not authorize a live Slack workspace, Discord server, Telegram bot, or LINE account for this demo.
| Platform | Setup path |
| --- | --- |
| Slack | Create a Slack app, grant the required bot scopes, install it to the workspace, and enter the Bot Token and Signing Secret in LangBot. Configure event subscriptions with the public HTTPS callback from the bot setup, verify it, and invite the bot to the intended channel. |
| Discord | Create an application and bot in the Developer Portal. Enter Client ID and bot Token, enable the required message intents, then invite the bot with the appropriate channel permissions. |
| Telegram | Create a bot with BotFather and enter its token. Start with a direct message; for groups, invite the bot and configure privacy mode and LangBot's trigger rules for the messages it should receive. |
| LINE | Create a Messaging API channel. Enter the Channel access token and Channel secret, configure the public HTTPS webhook, enable webhook delivery, and avoid conflicting automatic replies. |
| Mattermost | Enter the server URL and a Bot Account access token, then add that account to the relevant teams and channels. The adapter uses REST and WebSocket APIs. |
![The Discord adapter uses the application Client ID and bot token.](/images/articles/source/images/dify-langbot/059-platform-discord-fields.png)
*The Discord adapter uses the application Client ID and bot token.*
![The Telegram adapter uses a BotFather token and exposes reply options.](/images/articles/source/images/dify-langbot/060-platform-telegram-fields.png)
*The Telegram adapter uses a BotFather token and exposes reply options.*
The catalog also includes Matrix, Lark, DingTalk, WeCom, WeChat-related adapters, QQ, KOOK, OneBot v11, Satori, HTTP Bot, and Page Bot. See the [platform-specific LangBot guides](https://langbot.app/docs/en/usage/platforms/readme) for the permissions and networking required by each adapter. In particular, the local-only deployment above needs a suitable public HTTPS endpoint for webhook-based integrations such as Slack and LINE.
## Troubleshooting
When something fails, check the path in order: Dify preview, the published app version, LangBot's `/v1` base URL and app type, then the platform's event delivery. If you change Dify service passwords, keep Redis and Celery credentials aligned, and do the same for Sandbox and its code-execution client.
Our local proxy initially returned fake DNS addresses that Dify's SSRF proxy rejected. Correcting DNS fixed the plugin download without disabling network protections. For external API calls, inspect the run record after a retry rather than assuming that a transport error means the app configuration is wrong.
Project sources: [LangBot](https://github.com/langbot-app/LangBot) and [Dify](https://github.com/langgenius/dify). The deployment and screenshots are from September 16, 2026; later versions may move some controls.
## Further reading
- [Route Support Questions in Discord and LINE with Dify and LangBot](https://langbot.app/en/blog/dify-langbot-support-triage)
- [Turn GitHub Releases into Telegram Briefings with Dify and LangBot](https://langbot.app/en/blog/dify-langbot-github-release-briefing)
+4
View File
@@ -7,6 +7,7 @@ LangBot Blog の製品アップデート、技術解説、チュートリアル
## 製品アップデート
- [LangBot 4.11:イベント駆動エージェントとプラグイン化された Runner](/ja/articles/langbot-v411-event-driven-agents) — 2026-10-15
- [新しい LangBot Cloud が公開—オープンソース版もマルチユーザー Workspace に対応](/ja/articles/langbot-cloud-multi-user-workspaces) — 2026-08-25
## エンジニアリング
@@ -17,6 +18,9 @@ LangBot Blog の製品アップデート、技術解説、チュートリアル
## チュートリアルと連携
- [Turn GitHub Releases into Telegram Briefings with Dify and LangBot](/ja/articles/dify-langbot-github-release-briefing) — 2026-09-16
- [Route Support Questions in Discord and LINE with Dify and LangBot](/ja/articles/dify-langbot-support-triage) — 2026-09-16
- [A Dify Writing Assistant for Discord and Telegram with GPT-6 Astra and LangBot](/ja/articles/dify-langbot-writing-assistant) — 2026-09-16
- [LangTARS:Dify・n8n と連携するオープンソース PC 操作 Agent](/ja/articles/langtars-remote-pc-control-dify-n8n) — 2026-03-23
- [DeepSeek R1 を WeChat・Discord・Telegram に5分で接続する方法](/ja/articles/connect-deepseek-to-wechat) — 2026-02-21
- [AI Bot を Discord・Telegram・WeChat に5分でデプロイ](/ja/articles/deploy-ai-bot-in-5-minutes) — 2026-02-17
@@ -0,0 +1,132 @@
---
title: "LangBot 4.11:イベント駆動エージェントとプラグイン化された Runner"
description: "LangBot 4.11 の主要機能を実機スクリーンショットで紹介。イベントルーティング、AgentRunner のプラグイン化、Workspace Assistant、運用機能と移行手順を解説します。"
---
この記事は LangBot Blog から同期されています。 [Blog の原文を読む](https://langbot.app/ja/blog/langbot-v411-event-driven-agents).
公開日:2026-10-15 · 著者:LangBot Team
LangBot は、複数のメッセージングサービス、大規模言語モデル、ナレッジベース、プラグインを接続し、AI アシスタントの構築・デプロイ・管理を支援するオープンソースの AI チャットボット・エージェントプラットフォームです。
チャットボットの基本は「メッセージを受け取り、返信する」ことです。ただ、実際のチームやコミュニティでは、会話以外にも作業のきっかけがあります。新しいメンバーの参加、回答へのリアクション、カードのボタンクリック。こうした操作も、次の処理につなげたい場面があります。
**LangBot 4.11 では、これらのイベントを設定可能な入り口として扱い、エージェントに渡し、実行状況を追跡できるようになりました。** AgentRunner のプラグイン化と Workspace Assistant により、「何をきっかけに、どの実行方式で処理し、どう管理するか」を整理しやすくなっています。
## 1. イベント駆動:次のメッセージを待つだけではない Bot へ
Event-Based Agents(EBA)は、通常のメッセージに加え、参加・退出、メッセージの撤回、リアクション、カード操作などのプラットフォームイベントを処理対象にします。今回のリリースでは、13 のプラットフォームアダプターが EBA アーキテクチャに基づいて書き直されました。
すべてのプラットフォームで同じイベントが使えるわけではありません。受信できるイベントは、プラットフォーム、アダプター、Bot に付与した権限によって異なります。共通化されたのは、受信したイベントを適切なプロセッサーへ渡す仕組みです。
![イベントの種類に応じてプロセッサーへ振り分ける設定](/images/articles/source/images/langbot-411/eba-event-routing.png)
*4.11 正式版リリースノートに掲載されたイベントルーティングの例。*
### まずは実現したいシナリオから
イベントルーティングでは、新規メンバーへの歓迎や退出時の処理といった、よく使うシナリオからルールを作成し、担当するプロセッサーを選べます。
たとえば、通常の質問はナレッジベースを使う Pipeline、新規参加者への案内は Agent、固定の業務ルールが必要なイベントはプラグインプロセッサーへ、と分担できます。これは構成例であり、そのまま動く設定ではありません。利用するイベントと権限を確認し、各ルートをテストしてから有効にしてください。
プラットフォームとの接続と業務処理を分けられるため、歓迎の手順が変わっても Bot の接続部分まで作り直す必要がありません。質問への回答方針も、ほかの振る舞いと一つのプロンプトに詰め込まずに管理できます。
### Pipeline・Agent・プラグインプロセッサーの使い分け
![実機で表示した三種類のプロセッサー作成画面](/images/articles/source/images/langbot-411/processor-types.png)
*この記事用に起動した LangBot 4.11.0 のプロセッサー作成画面。*
- **Pipeline**:メッセージイベントを決まった順序で処理します。AI による直接返信、ナレッジベースへの質問、既存のメッセージ処理に向いています。
- **Agent**:イベントへの対応を自然言語で指示し、AI に判断と実行を任せるか、外部の Agent プラットフォームへ接続します。状況に応じた判断が必要な処理に適しています。
- **プラグインプロセッサー**:プラグインが対応を宣言したイベントをコードで処理します。決定的なルールや専用の連携処理に向いています。
すべてを Agent に置き換える必要はありません。明確なルールはコードへ、定型的な質疑応答は Pipeline へ、判断が必要な部分は Agent へ。役割を分けるほうが、運用時にも理解しやすくなります。
### デバッグもイベントを中心に
イベントデバッガーでは、フォームでイベントデータを編集し、実行ログと詳細を確認できます。実際のチャットサービスで試す前に、入力フィールドや処理結果を確認する用途に便利です。ただし、デバッグ実行だけで接続・権限・実際のコールバックまで確認できるわけではありません。
関連するプラットフォーム改善には、Slack Socket Mode、DingTalk のカード操作、WeChat の入力中表示、OneBot WebSocket などがあります。対応範囲と設定方法は各プラットフォームのドキュメントを参照してください。
## 2. AgentRunner のプラグイン化:実行方式を独立して更新
これまで Core に組み込まれていた LocalAgent、Dify、Coze、n8n などの Runner は、拡張マーケットの公式プラグインへ移行しました。Codex、Claude Code、ACP などの Runner も追加されています。
![稼働中のインスタンスから開いた公式 Runner の一覧](/images/articles/source/images/langbot-411/marketplace-live.png)
*実機から読み込んだ拡張マーケットの Official Runner セクション。掲載内容は Core と独立して更新されます。*
利用者にとっての主な変化は、**必要な Runner を選んでインストールし、個別に更新できること**です。LocalAgent でモデル・ツール・知識検索を使う構成も、既存の Dify アプリや n8n ワークフローをチャットにつなぐ構成も、共通の Bot 接続基盤で扱えます。
開発者は AgentRunner Protocol v1 に基づいて独自の Runner を実装できます。特定の実行基盤向けの処理を Core に直接組み込む必要がなくなり、拡張の境界が明確になります。
![リリースノートに掲載された AgentRunner プラグイン](/images/articles/source/images/langbot-411/runner-plugins-marketplace.png)
*正式版リリースノートの Runner 一覧例。必要なアカウント、API、実行環境は Runner ごとに設定します。*
プラグイン化は、すべての権限を無条件に渡すことではありません。Runner が呼び出せるのは、現在のコンテキストで許可されたツールとプラットフォーム API です。マーケットには認証バッジが表示され、Core は認証プラグインの署名を検証します。出所の確認と権限管理に加え、導入前に説明を読み、自分の環境での動作条件も確認してください。
### 既存の Pipeline はどう移行する?
移行機能は必要なプラグインをインストールし、元の設定をバックアップします。アップグレード後に Pipelines 画面で移行を実行し、Runner、モデル、ナレッジベース、ツールの設定を見直してください。
**移行後の Pipeline は新しいセッションから開始します。** 旧式のカスタム Runner はプラグイン Runner として書き直す必要があります。オフライン環境では「データのみ移行」を選び、Runner プラグインを手動でインストールできます。詳しい対応関係は[設定移行マップ(中国語)](https://github.com/langbot-app/LangBot/blob/v4.11.0/docs/pipeline-migration-config-map.zh-CN.md)を参照してください。
## 3. Workspace Assistant:確認してから反映する対話型の設定
新しい Workspace Assistant は、Bot と会話するエンドユーザーではなく、LangBot を管理する人のための機能です。現在の Workspace にあるリソースを調べ、対話を通じて Pipeline やナレッジベースなどの作成・設定を支援します。
![実機の Workspace Assistant と実行状況ダッシュボード](/images/articles/source/images/langbot-411/workspace-assistant.png)
*新しいインスタンスでの初期画面。利用には LangBot Account へのログイン、またはモデル設定が必要です。監視データのゼロ表示は、この新規 Workspace の実際の空状態です。*
まずは「使えるモデル、ナレッジベース、Pipeline は?」といった読み取り専用の質問から始められます。そのうえで、ナレッジベースを使う質問応答アプリの作成を依頼します。単にフォームをチャットに置き換えるのではなく、現在あるリソースを確認したうえで設定案を出せる点が重要です。
**書き込み操作は、確認を受けてから実行されます。** 対象リソース、パラメーター、変更範囲を見てから承認してください。設定項目を探す手間を減らしつつ、変更の判断は管理者に残す仕組みです。
## 4. 新しい実行方式を支える運用機能
### メッセージ数だけでなく、実行の流れを見る
一つのイベントが Pipeline、Agent、プラグインのいずれかへ渡るようになると、問題の切り分けには処理全体の見通しが必要です。4.11 では統一実行ビュー、ツール呼び出しの追跡、処理中のタスクを示すリアルタイムパネルが追加・更新されました。
調査するときは、イベントを受信したか、どのプロセッサーへ渡ったか、モデルやツールの呼び出しが完了したか、の順に確認すると整理しやすくなります。「返信がない」という現象だけで、接続とルーティングと実行の問題を一緒に扱わずに済みます。
### アカウント保護と操作の追跡
![Passkey と二要素認証の設定画面](/images/articles/source/images/langbot-411/account-security.png)
*実機のアカウント設定。撮影用アカウントでは Passkey と二要素認証をまだ有効にしていません。*
WebAuthn による Passkey ログイン、TOTP による二要素認証に対応しました。また、変更内容を記録し、完全性を検証できる操作ログが追加されています。複数人で管理する Workspace では、ログイン保護と「誰が何を変えたか」の確認に役立ちます。Passkey はブラウザーのセキュアコンテキスト要件なども満たす必要があるため、適切な HTTPS 環境で設定してください。
メディアは内容に基づいて重複を排除して保存され、同じメディアによる `langbot.db` の肥大化を抑えます。さらに、`lbctl` と API Key による管理・診断が使えるため、コマンドラインを既存の運用手順に組み込むこともできます。
## 5. はじめての設定と、既存環境のアップグレード
![初回セットアップでプラットフォームを選択する画面](/images/articles/source/images/langbot-411/onboarding.png)
*実機の導入ウィザード。プラットフォームの選択から、Bot 設定、AI エンジンの設定へ進みます。*
新規ユーザーはサイドバーのガイドとシナリオ別の Bot 作成ウィザードを使えます。最初にシンプルな質疑応答を確認し、その後にナレッジベース、ツール、イベントルートを足していくと、問題が起きたときに原因を追いやすくなります。
既存環境では、次の順序で進めることをおすすめします。
1. **バックアップを取得する。** `data/` または PostgreSQL データベースと、現在のデプロイ設定を保存します。最新の v4.10.x からの更新を推奨します。
2. **Core と対応する Runtime を更新する。** 接続状態を確認してください。4.11.0 は SDK `0.7.11` に固定されているため、古い Runtime を混在させないようにします。
3. **Pipeline を移行し、プラグインを更新する。** 移行後の Runner 設定と、新しいセッションになる点を確認します。
4. **実際の利用経路をテストする。** 既存のメッセージ応答を先に確認し、その後でイベントルートや許可したツールを試します。
5. **テレメトリーと設定変更を確認する。** 新しい実行テレメトリーは既定で有効ですが、メッセージ内容は含みません。このテレメトリーは `space.disable_telemetry: true` で無効化できます。設定には `media_cache`、`api.host`、`runner.admin_plugins` が追加され、`force_box_session_id_template` は削除されました。[データ収集ポリシー(英語)](https://langbot.app/docs/en/insight/data-collection-policy)とリリースノートを参照してください。
## LangBot 4.11 を使い始める
4.11 がつなぐのは、**タスクのきっかけ、処理する実行方式、そして管理・観察の方法**です。従来のメッセージ応答はそのまま活かしながら、コミュニティでのやり取りやイベント起点の処理を少しずつ追加できます。
- [v4.11.0 と正式版リリースノート](https://github.com/langbot-app/LangBot/releases/tag/v4.11.0)
- [デプロイ・利用ドキュメント](https://langbot.app/docs/ja/insight/guide)
- [LangBot Cloud を利用する](https://cloud.langbot.app)
開発、テスト、ドキュメント、フィードバックに協力してくださった皆さんに感謝します。本記事は主要な製品更新に絞って紹介しました。貢献者の一覧は正式版リリースノートをご覧ください。
*画像について:イベントルーティングと Runner 一覧の二枚は v4.11.0 GitHub Release から引用しています。残る五枚は、この記事用に公式イメージ `rockchin/langbot:v4.11.0` を独立して起動し、実際の画面から撮影しました。各言語版で見比べやすいように UI は英語で統一しています。本番 Bot への接続は行っていません。*
+339
View File
@@ -22,6 +22,13 @@
"sourceLocale": "en",
"fallback": false
},
{
"locale": "en",
"slug": "dify-langbot-github-release-briefing",
"page": "en/articles/dify-langbot-github-release-briefing",
"sourceLocale": "en",
"fallback": false
},
{
"locale": "en",
"slug": "dify-langbot-rag-knowledge-base",
@@ -29,6 +36,20 @@
"sourceLocale": "en",
"fallback": false
},
{
"locale": "en",
"slug": "dify-langbot-support-triage",
"page": "en/articles/dify-langbot-support-triage",
"sourceLocale": "en",
"fallback": false
},
{
"locale": "en",
"slug": "dify-langbot-writing-assistant",
"page": "en/articles/dify-langbot-writing-assistant",
"sourceLocale": "en",
"fallback": false
},
{
"locale": "en",
"slug": "langbot-cloud-multi-user-workspaces",
@@ -50,6 +71,13 @@
"sourceLocale": "en",
"fallback": false
},
{
"locale": "en",
"slug": "langbot-v411-event-driven-agents",
"page": "en/articles/langbot-v411-event-driven-agents",
"sourceLocale": "en",
"fallback": false
},
{
"locale": "en",
"slug": "langbot-v490-rag-plugin-architecture",
@@ -106,6 +134,13 @@
"sourceLocale": "zh",
"fallback": false
},
{
"locale": "zh",
"slug": "dify-langbot-github-release-briefing",
"page": "zh/articles/dify-langbot-github-release-briefing",
"sourceLocale": "zh",
"fallback": false
},
{
"locale": "zh",
"slug": "dify-langbot-rag-knowledge-base",
@@ -113,6 +148,20 @@
"sourceLocale": "zh",
"fallback": false
},
{
"locale": "zh",
"slug": "dify-langbot-support-triage",
"page": "zh/articles/dify-langbot-support-triage",
"sourceLocale": "zh",
"fallback": false
},
{
"locale": "zh",
"slug": "dify-langbot-writing-assistant",
"page": "zh/articles/dify-langbot-writing-assistant",
"sourceLocale": "zh",
"fallback": false
},
{
"locale": "zh",
"slug": "langbot-cloud-multi-user-workspaces",
@@ -134,6 +183,13 @@
"sourceLocale": "zh",
"fallback": false
},
{
"locale": "zh",
"slug": "langbot-v411-event-driven-agents",
"page": "zh/articles/langbot-v411-event-driven-agents",
"sourceLocale": "zh",
"fallback": false
},
{
"locale": "zh",
"slug": "langbot-v490-rag-plugin-architecture",
@@ -190,6 +246,13 @@
"sourceLocale": "en",
"fallback": true
},
{
"locale": "ja",
"slug": "dify-langbot-github-release-briefing",
"page": "ja/articles/dify-langbot-github-release-briefing",
"sourceLocale": "en",
"fallback": true
},
{
"locale": "ja",
"slug": "dify-langbot-rag-knowledge-base",
@@ -197,6 +260,20 @@
"sourceLocale": "en",
"fallback": true
},
{
"locale": "ja",
"slug": "dify-langbot-support-triage",
"page": "ja/articles/dify-langbot-support-triage",
"sourceLocale": "en",
"fallback": true
},
{
"locale": "ja",
"slug": "dify-langbot-writing-assistant",
"page": "ja/articles/dify-langbot-writing-assistant",
"sourceLocale": "en",
"fallback": true
},
{
"locale": "ja",
"slug": "langbot-cloud-multi-user-workspaces",
@@ -218,6 +295,13 @@
"sourceLocale": "en",
"fallback": true
},
{
"locale": "ja",
"slug": "langbot-v411-event-driven-agents",
"page": "ja/articles/langbot-v411-event-driven-agents",
"sourceLocale": "ja",
"fallback": false
},
{
"locale": "ja",
"slug": "langbot-v490-rag-plugin-architecture",
@@ -445,6 +529,11 @@
"sha256": "1e2ee21c697ab9c2320094874889e2ac0bd2fc44efb529eafa4d895393ca5691",
"bytes": 161907
},
{
"path": "/images/articles/langbot-wechat-official-account-qr.png",
"sha256": "233aede79ed71fd721f1f77c839d726b9dd8ed667f5e951d994c19f962c6bff5",
"bytes": 14931
},
{
"path": "/images/articles/source/images/article-mcp/01-init-page.png",
"sha256": "b392e42d582c8c1723a2eb63596801b9d459df0465377246d9a4015edcae1ca0",
@@ -555,6 +644,231 @@
"sha256": "5ff0078633e30e8d8d8efa5abf686fbe13993b06cee383d2e7b9afec16639712",
"bytes": 11535
},
{
"path": "/images/articles/source/images/dify-langbot/00-dify-install.png",
"sha256": "395d9d5af74ef23be4e38d78addba382db83685831d6adf8e3a739675927f739",
"bytes": 48447
},
{
"path": "/images/articles/source/images/dify-langbot/00-langbot-install.png",
"sha256": "e5ef7e954b4f27b50a5ea82cb551d33b4e6c288bd6948d146e6046c87b7a4717",
"bytes": 42532
},
{
"path": "/images/articles/source/images/dify-langbot/007-langbot-dify-runner-config.png",
"sha256": "969e3095144b6f1671413e10e0d75304d8f9b593bb5ee38567f094ef3253773e",
"bytes": 98420
},
{
"path": "/images/articles/source/images/dify-langbot/010-dify-create-basic-app.png",
"sha256": "34d5ad8474a7dede1d8a57c36951a3991076a104144e884646ecdd06cec08a56",
"bytes": 69242
},
{
"path": "/images/articles/source/images/dify-langbot/011-dify-writing-app-create.png",
"sha256": "3296b7f25e30825817ed0034d078be68c369750b0f72959a2794d1aac8b2e800",
"bytes": 82300
},
{
"path": "/images/articles/source/images/dify-langbot/012-dify-writing-instructions.png",
"sha256": "da31119dc383c45110d2ba7b122a1a4d0c5b348f7ab5c92660bce65a7387ed88",
"bytes": 91695
},
{
"path": "/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png",
"sha256": "5c1c99021ce25747f0baf2d70619b2a550c9e72d51c0c867317f39ce16dc4dec",
"bytes": 82204
},
{
"path": "/images/articles/source/images/dify-langbot/016-writing-english-first-reply.png",
"sha256": "7e2cbbc517ef47d20b577a7e37a5b04094dff7b321f117daed0f4461dfd218be",
"bytes": 120236
},
{
"path": "/images/articles/source/images/dify-langbot/019-writing-english-context-revision.png",
"sha256": "28767ff8cf9c97c1a5f2cd02401cb7d3d8112197615c883857e074f0ca3b9036",
"bytes": 136430
},
{
"path": "/images/articles/source/images/dify-langbot/022-writing-chinese-first-reply.png",
"sha256": "088bd387dd9855f506fb61b777a3b3bc11445b266963e27d7355447f6f366385",
"bytes": 108973
},
{
"path": "/images/articles/source/images/dify-langbot/023-writing-access-point-api.png",
"sha256": "a431e9acda90e2685feeaa3a7353cf1b80c8ceb85ce1faf9da8f004ea9d22380",
"bytes": 63099
},
{
"path": "/images/articles/source/images/dify-langbot/025-langbot-writing-english-roundtrip.png",
"sha256": "4ccbd575d3f544c050ce26cdda2f1996c12ed5875b024b0ec68fc2d5e8f0f8a2",
"bytes": 65801
},
{
"path": "/images/articles/source/images/dify-langbot/026-langbot-writing-chinese-roundtrip.png",
"sha256": "b6de9ea94a9a9d9b8a57760425293ee3985e97f051efa2e9ff092cb64ae30ac8",
"bytes": 83068
},
{
"path": "/images/articles/source/images/dify-langbot/039-triage-three-branch-overview.png",
"sha256": "dbef83edb2f04159e03a5bbeb5c004e09e250b022fdc6f845b045dd694e49773",
"bytes": 100101
},
{
"path": "/images/articles/source/images/dify-langbot/040-triage-classifier-settings.png",
"sha256": "be1b06fe3754a5c7fcfd3f7c5f3cdd7192aac469ac94e08e66286b39c01672df",
"bytes": 121451
},
{
"path": "/images/articles/source/images/dify-langbot/041-triage-account-path-result.png",
"sha256": "db7b607df345ca0c26a44ccacc0bf51853dcf485832f4ee49e2264e700f8fa47",
"bytes": 100428
},
{
"path": "/images/articles/source/images/dify-langbot/043-triage-product-path-result.png",
"sha256": "5a61bc6b11cd58224dd517254a94ca3f8b66ef35bc6e5595ed43e900b90b3400",
"bytes": 99485
},
{
"path": "/images/articles/source/images/dify-langbot/045-release-workflow-overview.png",
"sha256": "dc8cdf1c8b4c17b060be6945780a72ebbf913b3e773fa3f671b34a55a90065b2",
"bytes": 80979
},
{
"path": "/images/articles/source/images/dify-langbot/046-release-http-request-settings.png",
"sha256": "c3f7259c4630a29d5570916d63780b0bd2425d84fc8664d899680eb7e77ea4af",
"bytes": 114686
},
{
"path": "/images/articles/source/images/dify-langbot/047-release-code-extraction-node.png",
"sha256": "705f3f60f43b92457112c3d20666daf397346d5567f5cf532392c81194fd23e6",
"bytes": 100014
},
{
"path": "/images/articles/source/images/dify-langbot/049-release-workflow-input.png",
"sha256": "4ff4d328a044b486cdcb207dcdb4f12c99bf8bd0e1fbce8577f7edc3cbcafa52",
"bytes": 111912
},
{
"path": "/images/articles/source/images/dify-langbot/050-triage-human-review-chinese.png",
"sha256": "87c4e990534acb3dbf19d0033d17ed4bb772da14aee0713aa38781ccfccbf171",
"bytes": 114977
},
{
"path": "/images/articles/source/images/dify-langbot/053-langbot-triage-dify-settings.png",
"sha256": "6211531960bd863619238b41ad48842e43d21323864159674a61db089df18c4a",
"bytes": 101283
},
{
"path": "/images/articles/source/images/dify-langbot/054-release-summary-output-verified.png",
"sha256": "1f16403a2c8ee4c8adee05e36c5f094bc7d7316f45d5aac1c1275c75bfac6e84",
"bytes": 87480
},
{
"path": "/images/articles/source/images/dify-langbot/055-langbot-triage-account-english.png",
"sha256": "476c5f68d231fe296737422fa3049b01b9c5064f830aa9743b067b94f2d99fee",
"bytes": 69092
},
{
"path": "/images/articles/source/images/dify-langbot/056-release-english-live-briefing.png",
"sha256": "4ad4f72bbefc03cf746b31cd9fb84935f037ac657dd111586dbc02665633a4e3",
"bytes": 116517
},
{
"path": "/images/articles/source/images/dify-langbot/059-platform-discord-fields.png",
"sha256": "ad46d06df6370e52e1baf2e611e5427f139efb7f3186b3bce705f8c270ad11fa",
"bytes": 59659
},
{
"path": "/images/articles/source/images/dify-langbot/060-platform-telegram-fields.png",
"sha256": "e91de974825bb4f390bf1505c06fdba4f288bd1c35d8f7dfdd95f4a8d032fb91",
"bytes": 69438
},
{
"path": "/images/articles/source/images/dify-langbot/061-platform-line-fields.png",
"sha256": "260b460f2be769b1888f8ed0ee92fcca095a55ea896b4cf658083af6cdfeaacc",
"bytes": 68738
},
{
"path": "/images/articles/source/images/dify-langbot/062-platform-lark-fields.png",
"sha256": "2112231900edebf0ed28c2b9678aa95be0a338b01adf723028db8b150196773d",
"bytes": 89713
},
{
"path": "/images/articles/source/images/dify-langbot/063-platform-dingtalk-fields.png",
"sha256": "0a9dc591fd65b3e5dd14932f288b38540543f162e742b5bd19c2d2b8337b49b2",
"bytes": 87438
},
{
"path": "/images/articles/source/images/dify-langbot/064-platform-wecombot-fields.png",
"sha256": "441821ebe51b1863180a8c787b176f47609e9f7974fdeea85481c5936aa868f6",
"bytes": 86405
},
{
"path": "/images/articles/source/images/dify-langbot/066-platform-onebot-v11-fields.png",
"sha256": "75988e0e76dd85f0b629c3769de55a963263a8f846bfdcea9035a60c628351e1",
"bytes": 74079
},
{
"path": "/images/articles/source/images/dify-langbot/075-release-chinese-live-briefing.png",
"sha256": "0dc0d9e9fd3196dca8e96a1d61c86535c09cbc20599f9bbadaa59a9f53b47c8d",
"bytes": 119317
},
{
"path": "/images/articles/source/images/dify-langbot/076-langbot-triage-human-chinese.png",
"sha256": "522a80eb09c6aec93301ae22507340b992e98c3a75fbd6f8850eb1f59afc3474",
"bytes": 94537
},
{
"path": "/images/articles/source/images/dify-langbot/078-langbot-release-workflow-settings.png",
"sha256": "fcf07ab431b203da8742f8bc646262c01e1639e44103f35f95f528b4302b4690",
"bytes": 102591
},
{
"path": "/images/articles/source/images/dify-langbot/079-langbot-release-english-roundtrip.png",
"sha256": "2db1b8dbac02a637aa844072c81db588e8cba50062c312ec64898e5ff660d1e6",
"bytes": 113719
},
{
"path": "/images/articles/source/images/dify-langbot/082-release-chinese-reply-detail.png",
"sha256": "f8a96b5411c7d84c05cde603de04f73ec2989e1748c22bb470457383ee3887d9",
"bytes": 39159
},
{
"path": "/images/articles/source/images/langbot-411/account-security.png",
"sha256": "df3fdf37a6482236cd231fd99c8e874241fa367fb25adc77af01ddcc6f10100f",
"bytes": 136563
},
{
"path": "/images/articles/source/images/langbot-411/eba-event-routing.png",
"sha256": "ea34a28e6c588a2a44e22fd7fb61bcd7f7699199af516dd25a865700ff837058",
"bytes": 85003
},
{
"path": "/images/articles/source/images/langbot-411/marketplace-live.png",
"sha256": "c93730f8a7d5d01d7c807ce9f00e708a44bd1e0f8618d37302088ae6c9d4036c",
"bytes": 155568
},
{
"path": "/images/articles/source/images/langbot-411/onboarding.png",
"sha256": "bb310d862fc44f095a20744e478a1991474bb8781880256a2d611e38fc106000",
"bytes": 104698
},
{
"path": "/images/articles/source/images/langbot-411/processor-types.png",
"sha256": "6d388a741a1cb12fe57a962b57b9094b3efa3249fe117c8397a8a7154781311b",
"bytes": 111538
},
{
"path": "/images/articles/source/images/langbot-411/runner-plugins-marketplace.png",
"sha256": "61cebdd8018aaf762be24ffcc5dd0b18cb392b33674e1b9ec7f4d4ef809568db",
"bytes": 140348
},
{
"path": "/images/articles/source/images/langbot-411/workspace-assistant.png",
"sha256": "ffb00eeb539ef28bd3db99db394eb799b052e5ff201fb2cbff4718a3985d24b2",
"bytes": 138965
},
{
"path": "/images/articles/source/images/plugin-system/architecture.png",
"sha256": "85028534d0a6246bd25f110189a6734f6176e1765fc64bf5eeb3248137e7292d",
@@ -589,6 +903,31 @@
"path": "/images/articles/source/images/sandbox-skills/skills.png",
"sha256": "6ad86d972c7438fbef898d9d339f3f17a30277bf1626e8a9dd11b0b46583c817",
"bytes": 362173
},
{
"path": "/images/articles/telegram-sandbox-qr.png",
"sha256": "8b4ead3dacb357fd28b650d2a6761b265effdeecc8e6a3f1f9feed10122da04b",
"bytes": 5583
},
{
"path": "/images/articles/telegram-sandbox.jpg",
"sha256": "0dab8f9c9c6846f8ac3b8848d118bca3528868254a7249d0d26772175eabae84",
"bytes": 349163
},
{
"path": "/images/articles/wecom-customer-service-qr.png",
"sha256": "3d2c2be11af63528a1b09871157ba58b4f3b64d7ddcbdf4420b99ecd41984c3b",
"bytes": 202053
},
{
"path": "/images/articles/wecom-customer-service.jpg",
"sha256": "2b94049e6265ffb1ac67cde661c596780d7fcfaeae46517ebd82f4dbfe3a1e19",
"bytes": 310163
},
{
"path": "/images/articles/wecom-knowledge-base-config.png",
"sha256": "0e4b12cec9bccf7c8a4958e9a53d312707ad818ac4376b707a20e8793af8f8be",
"bytes": 112097
}
]
}
+3 -3
View File
@@ -73,7 +73,7 @@ def rewrite_url(source: PurePosixPath, target: str, *, image: bool = False) -> s
return target
if image:
path = parsed.path.lstrip("/") if parsed.path.startswith("/") else (source.parent / parsed.path).as_posix()
return urlunsplit(("https", "raw.githubusercontent.com", f"/langbot-app/langbot-docs/main/{path}", parsed.query, parsed.fragment))
return urlunsplit(("https", "raw.githubusercontent.com", f"/langbot-app/LangBot/master/docs/{path}", parsed.query, parsed.fragment))
return resolve_doc_target(source, target) or target
@@ -235,7 +235,7 @@ def build(root: Path, output: Path) -> int:
home = [
"# LangBot Documentation",
"",
"This GitHub Wiki is automatically synchronized from [langbot-app/langbot-docs](https://github.com/langbot-app/langbot-docs).",
"This GitHub Wiki is automatically synchronized from [LangBot/docs](https://github.com/langbot-app/LangBot/tree/master/docs).",
"",
]
for language, label in LANGUAGES.items():
@@ -246,7 +246,7 @@ def build(root: Path, output: Path) -> int:
(output / "Home.md").write_text("\n".join(home).rstrip() + "\n", encoding="utf-8")
(output / "_Sidebar.md").write_text(build_sidebar(root, titles), encoding="utf-8")
(output / "_Footer.md").write_text(
"Automatically synchronized from [langbot-app/langbot-docs](https://github.com/langbot-app/langbot-docs).\n",
"Automatically synchronized from [LangBot/docs](https://github.com/langbot-app/LangBot/tree/master/docs).\n",
encoding="utf-8",
)
return len(documents)
+36
View File
@@ -9,6 +9,12 @@ import process from "node:process";
const ROOT = path.resolve(import.meta.dirname, "..");
const ARTICLE_LOCALES = ["en", "zh", "ja"];
// These documentation-only articles are not owned by the Blog synchronizer.
const LOCAL_ARTICLES = {
en: [],
zh: ["langbot-telegram-sandbox-agent", "langbot-wechat-official-account", "langbot-wecom-customer-service-knowledge-base"],
ja: [],
};
const MAX_IMAGE_BYTES = 25 * 1024 * 1024;
const LANGUAGE_CONFIG = {
en: { mintlify: "en", tab: "Articles", introTitle: "LangBot Articles", introDescription: "Product updates, engineering deep dives, tutorials, integrations, and announcements from the LangBot Blog.", sourceLabel: "This article is synchronized from the LangBot Blog.", sourceAction: "Read the canonical version", fallbackLabel: "", overviewGroup: "Browse", groups: { updates: "Product Updates", engineering: "Engineering", tutorials: "Tutorials & Integrations", announcements: "Announcements" } },
@@ -225,6 +231,8 @@ async function renderArticle(sourceRoot, post, locale, fallback, assetRoot, imag
const config = LANGUAGE_CONFIG[locale];
const title = locale === "ja" && fallback ? (JAPANESE_TITLES[post.slug] || post.data.title) : post.data.title;
let body = post.body;
// Root-relative Blog links belong to the landing site, not the embedded docs.
body = body.replace(/(\]\()\/(en|zh|ja)\/blog\//g, "$1https://langbot.app/$2/blog/");
const refs = imageReferences(body);
for (const ref of refs) if (!imageCache.has(ref.url)) imageCache.set(ref.url, await materializeImage(sourceRoot, ref.url, assetRoot));
if (post.data.cover?.image && !imageCache.has(post.data.cover.image)) imageCache.set(post.data.cover.image, await materializeImage(sourceRoot, post.data.cover.image, assetRoot));
@@ -254,6 +262,7 @@ function navigationTab(locale, posts) {
const groups = [{ group: config.overviewGroup, pages: [`${locale}/articles/index`] }];
for (const key of ["updates", "engineering", "tutorials", "announcements"]) {
const pages = posts.filter((post) => post.group === key).map((post) => articlePage(locale, post.slug));
if (key === "tutorials") pages.push(...LOCAL_ARTICLES[locale].map((slug) => articlePage(locale, slug)));
if (pages.length) groups.push({ group: config.groups[key], pages });
}
return { tab: config.tab, groups };
@@ -282,6 +291,13 @@ async function validateGenerated(manifest) {
}
}
}
for (const locale of ARTICLE_LOCALES) {
for (const slug of LOCAL_ARTICLES[locale]) {
const file = path.join(ROOT, locale, "articles", `${slug}.mdx`);
await readRegularFileWithin(path.join(ROOT, locale, "articles"), file, "local article", "utf8");
}
for (const image of await referencedImagesIn(path.join(ROOT, locale, "articles"))) referencedImages.add(image);
}
const mirroredMetadata = await imageMetadata(ROOT);
const mirroredImages = new Set(mirroredMetadata.map((image) => image.path));
for (const image of mirroredImages) if (!referencedImages.has(image)) failures.push(`unreferenced mirrored image: ${image}`);
@@ -340,6 +356,9 @@ async function main() {
if (!args.source) throw new Error("Pass --source /path/to/langbot-landing-page or set LANGBOT_LANDING_REPO");
if (!existsSync(path.join(args.source, "src/content/blog"))) throw new Error(`Not a LangBot landing repository: ${args.source}`);
const { byLocale, slugs } = await loadPosts(args.source);
for (const slug of Object.values(LOCAL_ARTICLES).flat()) {
if (slugs.includes(slug)) throw new Error(`Blog slug collides with a local article: ${slug}`);
}
const outputRoot = await mkdtemp(path.join(tmpdir(), "langbot-docs-article-sync-"));
const assetRoot = args.check ? outputRoot : ROOT;
const imageCache = new Map();
@@ -362,6 +381,23 @@ async function main() {
localePosts.set(locale, renderedPosts);
await writeFile(path.join(outputRoot, locale, "articles", "index.mdx"), renderIndex(locale, renderedPosts));
}
// Preserve local articles and their assets before replacing generated directories.
for (const locale of ARTICLE_LOCALES) {
for (const slug of LOCAL_ARTICLES[locale]) {
const source = path.join(ROOT, locale, "articles", `${slug}.mdx`);
const content = await readRegularFileWithin(path.join(ROOT, locale, "articles"), source, "local article", "utf8");
await writeFile(path.join(outputRoot, locale, "articles", `${slug}.mdx`), content);
if (args.check) {
for (const match of content.matchAll(/!\[[^\]]*\]\((\/images\/articles\/[^)]+)\)/g)) {
const image = path.join(ROOT, match[1].slice(1));
const bytes = await readRegularFileWithin(path.join(ROOT, "images/articles"), image, "local article image");
const target = path.join(outputRoot, match[1].slice(1));
await mkdir(path.dirname(target), { recursive: true });
await writeFile(target, bytes);
}
}
}
}
if (!args.check) {
const referencedImages = await referencedImagesIn(outputRoot);
for (const file of await listFiles(path.join(ROOT, "images/articles"))) {
+17 -5
View File
@@ -1,12 +1,14 @@
#!/usr/bin/env python3
"""Advance only the landing docs gitlink, then sync its production fork."""
import argparse
import base64
import configparser
import json
import os
import urllib.error
import urllib.request
SOURCE = "langbot-app/langbot-docs"
SOURCE = "langbot-app/LangBot"
TARGET = "langbot-app/langbot-landing-page"
DEPLOY = "RockChinQ/LangBot-LandingPage-Vue"
@@ -25,14 +27,24 @@ def api(method, path, data=None):
return json.load(response)
def head(call, repo):
return call("GET", repo + "/git/ref/heads/main")["object"]["sha"]
def head(call, repo, branch="main"):
return call("GET", repo + "/git/ref/heads/" + branch)["object"]["sha"]
def sync(call=api, dry_run=False):
for attempt in range(5):
source = head(call, SOURCE) # Coalesce queued events onto current main.
source = head(call, SOURCE, "master")
parent = head(call, TARGET)
# Check the same target revision used to build the candidate tree. Never
# put a LangBot SHA into a gitlink still configured for the old repository.
modules = call("GET", TARGET + "/contents/.gitmodules?ref=" + parent)
config = configparser.ConfigParser(interpolation=None)
config.read_string(base64.b64decode(modules["content"]).decode("utf-8"))
section = 'submodule "docs"'
if (config.get(section, "path", fallback=None) != "docs"
or config.get(section, "url", fallback=None) != "https://github.com/langbot-app/LangBot.git"
or config.get(section, "branch", fallback=None) != "master"):
raise RuntimeError("Landing docs must point to LangBot/master before synchronization")
commit = call("GET", TARGET + "/git/commits/" + parent)
tree = call("GET", TARGET + "/git/trees/" + commit["tree"]["sha"])
entry = next(item for item in tree["tree"] if item["path"] == "docs")
@@ -52,7 +64,7 @@ def sync(call=api, dry_run=False):
"tree": [{"path": "docs", "mode": "160000", "type": "commit", "sha": source}],
})
candidate = call("POST", TARGET + "/git/commits", {
"message": "docs: sync langbot-docs@" + source[:12],
"message": "docs: sync LangBot@" + source[:12],
"tree": updated["sha"], "parents": [parent],
"author": {"name": "github-actions[bot]", "email": "41898282+github-actions[bot]@users.noreply.github.com"},
})
+2 -1
View File
@@ -23,7 +23,8 @@ function links(node, result = []) {
}
test("every sitemap page has meaningful canonical Markdown and HTML discovery", async () => {
assert.equal(urls.length, 509 + zhOnlyArticleRoutes.length);
const manifest = JSON.parse(await readFile(path.join(root, "scripts/blog-articles-manifest.json"), "utf8"));
assert.equal(urls.length, 473 + zhOnlyArticleRoutes.length + manifest.articles.length);
for (const url of urls) {
const route = relative(url);
const text = await read(`${route}.md`);
+16
View File
@@ -58,6 +58,7 @@ test("generated articles use only non-empty Wiki-local images", () => {
const file = path.join(root, `${article.page}.mdx`);
assert.ok(existsSync(file), `missing ${article.page}.mdx`);
const content = readFileSync(file, "utf8");
assert.doesNotMatch(content, /\]\(\/(?:en|zh|ja)\/blog\//, `${article.page} has a Blog link relative to the docs mount`);
const imageUrls = [...content.matchAll(/!\[[^\]]*\]\(([^)]+)\)/g)].map((match) => match[1]);
for (const imageUrl of imageUrls) {
assert.match(imageUrl, /^\/images\/articles\//, `${article.page} hotlinks ${imageUrl}`);
@@ -72,3 +73,18 @@ test("generated articles use only non-empty Wiki-local images", () => {
}
}
});
test("documentation-only articles and their images survive Blog synchronization", () => {
for (const pages of Object.values(extraArticlePages)) {
for (const page of pages) {
const content = readFileSync(path.join(root, `${page}.mdx`), "utf8");
assert.ok(content.length > 100, `${page} is empty`);
for (const [, url] of content.matchAll(/!\[[^\]]*\]\((\/images\/articles\/[^)]+)\)/g)) {
const bytes = readFileSync(path.join(root, url.slice(1)));
const image = manifest.images.find((item) => item.path === url);
assert.ok(image, `${page}: ${url} missing from image manifest`);
assert.equal(createHash("sha256").update(bytes).digest("hex"), image.sha256);
}
}
}
});
+7 -3
View File
@@ -14,6 +14,10 @@ import {
} from "../scripts/prepare-fumapress.mjs";
const root = path.resolve(import.meta.dirname, "..");
const articleManifest = JSON.parse(await readFile(path.join(root, "scripts/blog-articles-manifest.json"), "utf8"));
// The fixed documentation baseline excludes synchronized Blog pages.
const expectedDocuments = 299 + articleManifest.articles.length;
test("Mintlify locales are mapped to public URL locales", () => {
assert.equal(mapMintlifyLocale("en"), "en");
@@ -170,8 +174,8 @@ test("MDX compatibility normalization removes internal .html route suffixes", ()
test("canonical MDX and nested OpenAPI sources are discovered", async () => {
const docs = JSON.parse(await readFile(path.join(root, "docs.json"), "utf8"));
const pages = await collectMdxDocuments(root);
assert.equal(pages.length, 335);
assert.deepEqual(Object.fromEntries([...pages.reduce((acc, page) => acc.set(page.split("/", 1)[0], (acc.get(page.split("/", 1)[0]) ?? 0) + 1), new Map()).entries()]), { en: 106, zh: 123, ja: 106 });
assert.equal(pages.length, expectedDocuments);
assert.deepEqual(Object.fromEntries([...pages.reduce((acc, page) => acc.set(page.split("/", 1)[0], (acc.get(page.split("/", 1)[0]) ?? 0) + 1), new Map()).entries()]), Object.fromEntries(Object.entries({ en: 94, zh: 111, ja: 94 }).map(([locale, count]) => [locale, count + articleManifest.articles.filter((article) => article.locale === locale).length])));
assert.deepEqual(collectOpenApiSources(docs), [
{ locale: "en", source: "openapi/service-api-en.json", directory: "en/api-reference" },
{ locale: "zh", source: "openapi/service-api-zh.json", directory: "zh/api-reference" },
@@ -216,7 +220,7 @@ test("prebuild is deterministic and preserves local assets and SEO files", async
const first = await prepareFumapress({ root, outRoot: temp });
const second = await prepareFumapress({ root, outRoot: temp });
assert.deepEqual(first, second);
assert.equal(first.documents, 335);
assert.equal(first.documents, expectedDocuments);
assert.equal(first.fallbackDefaults, 0);
assert.equal(first.localeOnlyDocuments, 17);
assert.equal(first.redirects, 103);
+5 -1
View File
@@ -6,6 +6,10 @@ import { collectMdxDocuments } from "../scripts/prepare-fumapress.mjs";
import { zhOnlyArticleRoutes } from "./article-routes.mjs";
const root = path.resolve(import.meta.dirname, "..");
const articleManifest = JSON.parse(await readFile(path.join(root, "scripts/blog-articles-manifest.json"), "utf8"));
// The fixed documentation baseline excludes synchronized Blog pages.
const expectedDocuments = 299 + articleManifest.articles.length;
const publicRoot = path.join(root, "dist/public");
test("the documentation keeps a neutral base with custom section and TOC treatments", async () => {
@@ -46,7 +50,7 @@ function staticHtmlForUrlPath(urlPath) {
test("all canonical localized documents have static HTML", async () => {
const documents = await collectMdxDocuments(root);
assert.equal(documents.length, 335);
assert.equal(documents.length, expectedDocuments);
const missing = [];
for (const document of documents) {
try {
+3 -2
View File
@@ -35,6 +35,7 @@ test("every localized HTML payload includes the preference client provider", asy
}
}
for (const locale of ["en", "zh", "ja"]) await visit(path.join(root, locale));
// 509 canonical content pages plus one framework 404 page per locale.
assert.equal(count, 515);
// Every sitemap page plus one framework 404 page per locale.
const sitemap = await readFile(path.join(root, "sitemap.xml"), "utf8");
assert.equal(count, [...sitemap.matchAll(/<loc>/g)].length + 3);
});
+1 -1
View File
@@ -36,7 +36,7 @@ description: "ignored"
self.assertIn("> **提示**", output)
self.assertIn("[模型文档](zh-usage-models-readme)", output)
self.assertIn(
"https://raw.githubusercontent.com/langbot-app/langbot-docs/main/images/ui.png",
"https://raw.githubusercontent.com/langbot-app/LangBot/master/docs/images/ui.png",
output,
)
+22 -2
View File
@@ -1,4 +1,5 @@
"""Offline API-contract tests; the workflow run verifies real GitHub writes."""
import base64
import importlib.util
from pathlib import Path
import unittest
@@ -10,8 +11,9 @@ spec.loader.exec_module(sync)
class FakeAPI:
def __init__(self, already=False, conflict=False, status="ahead"):
def __init__(self, already=False, conflict=False, status="ahead", migrated=True):
self.calls = []
self.migrated = migrated
self.pin = "new-docs" if already else "old-docs"
self.landing = "landing-parent"
self.deploy = "old-deploy"
@@ -20,7 +22,12 @@ class FakeAPI:
def __call__(self, method, path, data=None):
self.calls.append((method, path, data))
if path.endswith("/git/ref/heads/main"):
if "/contents/.gitmodules?ref=" in path:
repo = "LangBot" if self.migrated else "langbot-docs"
branch = "master" if self.migrated else "main"
content = f'[submodule "docs"]\npath = docs\nurl = https://github.com/langbot-app/{repo}.git\nbranch = {branch}\n'
return {"content": base64.b64encode(content.encode()).decode()}
if "/git/ref/heads/" in path:
sha = "new-docs" if path.startswith(sync.SOURCE + "/") else self.deploy if path.startswith(sync.DEPLOY + "/") else self.landing
return {"object": {"sha": sha}}
if method == "GET" and "/git/commits/" in path:
@@ -83,3 +90,16 @@ class SyncTests(unittest.TestCase):
with self.assertRaises(RuntimeError):
sync.sync(api)
self.assertTrue(all(m == "GET" for m, p, d in api.calls))
def test_reads_master_and_does_not_contact_archived_repository(self):
api = FakeAPI()
sync.sync(api)
self.assertIn(("GET", "langbot-app/LangBot/git/ref/heads/master", None), api.calls)
self.assertFalse(any("langbot-app/langbot-docs/" in p for _, p, _ in api.calls))
def test_old_submodule_configuration_fails_before_any_write(self):
for already in [False, True]:
api = FakeAPI(already=already, migrated=False)
with self.assertRaisesRegex(RuntimeError, "must point to LangBot/master"):
sync.sync(api)
self.assertTrue(all(m == "GET" for m, _, _ in api.calls))
@@ -76,9 +76,9 @@ Please always maintain a friendly and professional attitude. If you need to use
![AI Capability Config](/images/articles/external/8f4b3820ed5b-14-langbot-pipeline-ai-capability.png)
选择 **Dify Service API** 作为运行器:
选择 **Dify Service API** 作为 Runner:
![选择 Dify 运行器](/images/articles/external/efa6fcae9c58-15-langbot-runner-dropdown.png)
![Select Dify Runner](/images/articles/external/efa6fcae9c58-15-langbot-runner-dropdown.png)
填写配置:
- **Base URL**: `https://api.dify.ai/v1`
@@ -0,0 +1,224 @@
---
title: "在飞书里查询 GitHub 更新:Dify Workflow + GPT-6 Astra + LangBot 实战"
description: "让 Dify 实时请求 GitHub API,代码节点提取版本信息,GPT-6 Astra 生成有来源的简报,再由 LangBot 返回。详解 Workflow 输入、HTTP、Code 和 summary 输出。"
---
本文同步自 LangBot Blog。 [阅读 Blog 原文](https://langbot.app/zh/blog/dify-langbot-github-release-briefing).
发布于 2026-09-16 · 作者:LangBot Team
项目更新一多,群里的问题也很固定:“最新版本是什么?”“这次有哪些变化值得看?”直接让模型凭记忆回答,碰上刚发布的版本就不靠谱。
我们做了一个按需查询的 GitHub 简报助手:用户发消息后,Dify 真正请求 GitHub API,代码节点抽取发布信息,GPT-6 Astra 写成简短摘要,再由 LangBot 返回。下面用 LangBot 自己的公开仓库做例子;同样的方法也可以用在你关注的其他公开项目。
![真实 API 数据生成的中文简报,保留版本、时间与 GitHub 原文链接。](/images/articles/source/images/dify-langbot/082-release-chinese-reply-detail.png)
*真实 API 数据生成的中文简报,保留版本、时间与 GitHub 原文链接。*
## 先把 Dify 和 LangBot 跑起来
先安装 Docker Compose 和 Git,再分别按 [Dify Docker Compose 部署文档](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) 与 [LangBot Docker 部署文档](https://langbot.app/docs/en/deploy/langbot/docker/) 启动两个服务。Dify 的基础步骤是克隆仓库、进入 `docker` 目录、将 `.env.example` 复制为 `.env`,再启动 Compose;LangBot 的文档提供完整的镜像和插件运行时配置。
本文截图来自 **Dify 1.17.1、LangBot v4.10.11** 的本机环境。我们把浏览器端口分别映射为 `8088` 和 `5368`;这是演示环境的自定义映射,官方默认部署通常分别使用 `80` 和 `5300`。如果沿用官方默认值,就打开 `http://localhost` 和 `http://localhost:5300`,不用为了对齐截图而改端口。各自创建管理员账户,并把界面语言设为 **English**。
![本地 Dify 的首次初始化页面。](/images/articles/source/images/dify-langbot/00-dify-install.png)
*本地 Dify 的首次初始化页面。*
![本地 LangBot 的首次初始化页面。](/images/articles/source/images/dify-langbot/00-langbot-install.png)
*本地 LangBot 的首次初始化页面。*
接入时最重要的是 **LangBot 容器能访问 Dify**。本次两个服务加入同一个 Docker 网络,因此 Runner 的 Base URL 使用 `http://nginx/v1`,其中 `nginx` 是 Dify 的服务名。你可以在两个 Compose 配置中为 Dify 的 `nginx` 和 LangBot 服务加入同一个外部网络;如果分别部署在不同主机,则填写 LangBot 能访问的 Dify HTTPS 地址并加上 `/v1`。下文表格里的 `http://nginx/v1` 都指本次共享网络环境,不能直接套到所有部署。容器内的 `localhost` 指向容器自己。
## 在 Dify 中配置 GPT-6 Astra
进入 **Integrations → Model Provider**,安装官方 **OpenAI-API-compatible** 插件,再点 **Add Model**。本次使用的插件版本是 0.0.66。
| 字段 | 本次设置 |
| --- | --- |
| Model Name / model name for API endpoint | `gpt-6-astra` |
| Model Type / Completion mode | LLM / Chat |
| Model display name | GPT-6 Astra |
| API Base URL | 你自己的 OpenAI 兼容服务地址,通常以 `/v1` 结尾 |
| API Key | 你的模型服务密钥 |
| API Type | Chat Completions API |
| Model context size / Upper bound for max tokens | 本教程设为 32768 / 4096 |
最后一行是这次演示的工作上限,不是对 Astra 完整规格的声明。保存时让 Dify 做连接验证,成功后再建应用。截图中的网关只是本次测试环境,实际使用时换成你自己的服务。模型参数和可用接口以所选服务为准。模型名称以你选用的服务实际提供的标识为准,本文保留本次实测的 `gpt-6-astra`。
![添加自定义模型。API Key 在截图前保持为空,实际运行时已配置。](/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png)
*添加自定义模型。API Key 在截图前保持为空,实际运行时已配置。*
## 用 Workflow,把数据获取放在模型之前
在 Dify 新建 **Workflow**,命名 `Astra Release Briefing`。这次不是 Chatflow,因为每条请求都可以独立查询最新发布记录。
流程是:
`User Request → HTTP Request → Code → LLM → End`
![实际运行的 GitHub 简报工作流。](/images/articles/source/images/dify-langbot/045-release-workflow-overview.png)
*实际运行的 GitHub 简报工作流。*
### 1. 用户输入字段要与 LangBot 对上
在 Start / User Request 节点添加必填段落字段:
```text
langbot_user_message_text
```
LangBot 的 Dify Workflow Runner 会把当前消息文本放到这个字段中。不要随手改成 `question` 或 `prompt`,否则你在 Dify 手动测试能跑,接入 LangBot 时却可能缺少必填参数。
![工作流运行表单中的输入变量名称。](/images/articles/source/images/dify-langbot/049-release-workflow-input.png)
*工作流运行表单中的输入变量名称。*
### 2. HTTP 节点读取 GitHub
方法选 GET,地址:
```text
https://api.github.com/repos/langbot-app/LangBot/releases/latest
```
请求头加上 `Accept: application/vnd.github+json` 和 `User-Agent: LangBot-Dify-Tutorial`。这是读取公开发布记录,本例不需要 GitHub Token。保留 SSL 验证,按实际网络设置连接和读取超时。
![HTTP 节点直接查询 GitHub Releases API。](/images/articles/source/images/dify-langbot/046-release-http-request-settings.png)
*HTTP 节点直接查询 GitHub Releases API。*
### 3. 代码节点缩小传给模型的数据
把 HTTP 的 `body` 和 `status_code` 分别传给代码节点。核心逻辑如下,完整代码在 DSL 中:
```python
import json
def main(body: str, status_code: int) -> dict:
if status_code != 200:
return {"release": json.dumps({"error": f"GitHub HTTP {status_code}"})}
data = json.loads(body)
return {"release": json.dumps({
"repository": "langbot-app/LangBot",
"tag": data.get("tag_name"),
"published_at": data.get("published_at"),
"url": data.get("html_url"),
"notes": (data.get("body") or "")[:14000],
}, ensure_ascii=False)}
```
保留标签、发布时间、链接和发布说明就够了。没有必要把作者头像、各种 API URL 等字段全部塞进模型上下文。这里的代码只做提取,没有修改 GitHub 数据。
![代码节点把原始 JSON 转成精简的发布资料。](/images/articles/source/images/dify-langbot/047-release-code-extraction-node.png)
*代码节点把原始 JSON 转成精简的发布资料。*
### 4. LLM 写摘要,End 返回 summary
LLM 选择 GPT-6 Astra。提示词要求:用用户的语言回答,包含仓库、版本、发布时间、三个实用变化和原文链接;只使用 API 返回的资料,出错时说明查询失败。把用户输入和代码节点的 `release` 都放进 User 消息。
在 End 节点,把 LLM 的 `text` 映射到名为 **`summary`** 的输出。这个名字同样是接入约定,不能只看着节点连线完整就忽略它。
![End 节点把模型文本返回为 summary。](/images/articles/source/images/dify-langbot/054-release-summary-output-verified.png)
*End 节点把模型文本返回为 summary。*
## 先核对数据,再看摘要
我分别运行了英文和中文请求。两次都读取到 `v4.10.11`,发布时间为 2026-09-12 04:55:58 UTC,并附上对应的 GitHub Release 链接。摘要提到了知识库导入、监控统计和平台兼容性变化。
![英文请求的真实运行结果。](/images/articles/source/images/dify-langbot/056-release-english-live-briefing.png)
*英文请求的真实运行结果。*
![同一条工作流根据用户语言生成中文简报。](/images/articles/source/images/dify-langbot/075-release-chinese-live-briefing.png)
*同一条工作流根据用户语言生成中文简报。*
“最新”会随仓库发布变化,复现时不必追求和截图相同的版本号。应检查它是否与 API 当前返回的 `tag_name`、`published_at`、`html_url` 对得上。
## 用 LangBot 接住消息入口
在 Dify 点 **Publish**,发布当前版本。然后进入 **Access Point → Backend Service API → API Key**,创建这个应用自己的密钥。
打开 LangBot,点 **Create Pipelines**,命名为 `Astra Release Briefing`。进入 **Configuration → AI**:
| 字段 | 值 |
| --- | --- |
| Runner | Dify Service API |
| Base URL | `http://nginx/v1` |
| App Type | Workflow |
| API Key | 刚创建的 Dify 应用密钥 |
这里粘贴的是 **Dify 应用密钥**,不是前面配置 Astra 的模型密钥。一个负责调用应用,一个负责调用模型,别混用。保存后打开 **Debug Chat**,先验证整条调用链,再接平台。
![LangBot 的 Dify Runner 配置;截图时尚未填入应用密钥。](/images/articles/source/images/dify-langbot/078-langbot-release-workflow-settings.png)
*LangBot 的 Dify Runner 配置;截图时尚未填入应用密钥。*
## 工作流接进聊天之后
我从 LangBot 发了英文查询,收到完整简报和来源链接。中文查询曾遇到一次上游 SSL 连接临时中断,重试后成功;这也提醒我们,截图里的成功运行不代表外部 API 永远可用。
![LangBot 收到工作流的英文 summary 输出。](/images/articles/source/images/dify-langbot/079-langbot-release-english-roundtrip.png)
*LangBot 收到工作流的英文 summary 输出。*
![中文重试成功后的简报内容。](/images/articles/source/images/dify-langbot/082-release-chinese-reply-detail.png)
*中文重试成功后的简报内容。*
如果接到飞书项目群,建议先设置提及触发。需要时问一次,就查一次,避免机器人反复刷屏。本文做的是按需查询;定时推送需要额外增加调度与发送逻辑。
扩展到其他仓库时,可以先复制应用并替换固定 API URL。等规则稳定后再加入仓库参数、输入校验和限流,不要让任意用户输入直接变成不受限制的请求地址。
## 接到飞书、钉钉、企业微信,以及其他消息平台
在 LangBot 点 **Create Bots**,选择适配器,填写平台提供的凭据。创建后把机器人绑定到刚才的流水线;检查 Trigger 中的私聊、群聊和提及规则,再按平台要求发布或邀请机器人。
本次实测覆盖 **LangBot → Dify → GPT-6 Astra → LangBot 回复**。以下是实际界面核对过的接入方式,平台账户与群聊没有在本次演示中授权连接。
| 入口 | 配置方式 |
| --- | --- |
| 飞书 / Lark | 选 Lark;可扫码创建应用,也可手填 App ID、App Secret、与平台一致的 Bot Name。中国平台域名选 Feishu,默认使用长连接;开发者后台配置消息权限、事件并发布应用。 |
| 钉钉 | 选 DingTalk;扫码或填写 Client ID、Client Secret。Robot Code 需从开发者后台复制;按文档配置 Stream 接收消息、机器人名称和需要的卡片模板。 |
| 企业微信智能机器人 | 选 WeComBot;长连接用 BotId、Secret,填写机器人名称。Webhook 模式另配 Corpid、Token、EncodingAESKey。两套模式不要混填。 |
| 企业微信内部应用 / 微信客服 | 分别选 WeCom 或 WeComCustomerService,按各自后台填写企业与应用凭据、Token、EncodingAESKey,完成 HTTPS 回调和可信 IP 配置。内部应用不能直接当群机器人使用。 |
| 微信个人会话 | 选 OpenClaw WeChat,通过界面的二维码授权登录,按适配器说明接入。 |
| 微信公众号 | 选 Official Account,填写 App ID、App Secret、Token、EncodingAESKey,配置公网回调与 IP 白名单。根据接口限制选择回复模式;耗时较长时可能需要用户再发一条消息取回结果。 |
| QQ:OneBot v11 | 运行兼容 OneBot v11 的协议端,配置反向 WebSocket 到 LangBot 的监听端口,两侧 Access Token 保持一致;演示环境的 Compose 把主机 2288 映射到容器 2280。 |
| QQ 官方机器人 | 选 QQ Official API;可扫码绑定或填写 App ID、Secret。当前界面说明 Token 可留空;接收模式、沙箱范围、发布审核以 QQ 官方及适配器文档为准。 |
![钉钉适配器的凭据、Robot Code 与卡片配置。](/images/articles/source/images/dify-langbot/063-platform-dingtalk-fields.png)
*钉钉适配器的凭据、Robot Code 与卡片配置。*
![企业微信智能机器人的长连接与 Webhook 配置项。](/images/articles/source/images/dify-langbot/064-platform-wecombot-fields.png)
*企业微信智能机器人的长连接与 Webhook 配置项。*
LangBot 的适配器列表还包括 Discord、Slack、Telegram、LINE、Mattermost、Matrix、KOOK、Satori、HTTP Bot、Page Bot 和 WeChatPad。每种适配器需要的权限、回调和协议不同,不是填一个通用 Token 就全部接通。完整入口见 [LangBot 平台文档](https://langbot.app/docs/zh/usage/platforms/readme)。
如果只是想先模拟 QQ 消息,可以使用 matcha 之类的 OneBot 测试端;本文展示的对话来自 LangBot 自带 Debug Chat,没有把模拟对话当作真实群消息。
## 几个容易卡住的地方
遇到问题先按链路定位:Dify 预览能否回复、应用是否已 Publish、LangBot 的 Base URL 是否包含 `/v1`、应用类型是否正确,最后才看平台事件是否到达。如果改过 Dify 服务密码,Redis 与 Celery、Sandbox 与代码执行客户端的配置必须成对修改。
本机部署还遇到过代理软件返回虚拟 DNS 地址,导致 Dify 的 SSRF 代理拒绝插件下载。修好 DNS 后恢复,没必要关掉证书校验或内网访问保护。一次外部 API 的临时失败也不能当作模型或平台已经接通的证明,重试后仍应检查运行记录。
项目入口:[LangBot](https://github.com/langbot-app/LangBot) 和 [Dify](https://github.com/langgenius/dify)。截图和测试日期为 2026 年 9 月 16 日,后续版本的菜单名称可能会变化。
## 继续阅读
- [把群公告交给 Dify:用 GPT-6 Astra 和 LangBot 搭建 QQ、飞书写作助手](https://langbot.app/zh/blog/dify-langbot-writing-assistant)
- [让客服问题走对分支:Dify + LangBot 钉钉、企业微信机器人实战](https://langbot.app/zh/blog/dify-langbot-support-triage)
@@ -0,0 +1,197 @@
---
title: "让客服问题走对分支:Dify + LangBot 钉钉、企业微信机器人实战"
description: "用 GPT-6 Astra 和 Dify Question Classifier 区分账户、产品与人工复核请求,再接入 LangBot。三条分支逐一测试,说明回复规则与真实交接的边界。"
---
本文同步自 LangBot Blog。 [阅读 Blog 原文](https://langbot.app/zh/blog/dify-langbot-support-triage).
发布于 2026-09-16 · 作者:LangBot Team
把所有客服问题塞给同一段提示词,刚开始挺省事。后来你会发现,登录失败、功能咨询、退款投诉混在一起,机器人经常用同一种口气回复,还容易在不该承诺的地方说得太满。
这次我们把流程拆成三条:账户问题给排查步骤,产品问题给使用说明,需要授权的事情提示人工复核。Dify 的 Question Classifier 决定走哪条路,GPT-6 Astra 生成对应回复,LangBot 把同一个应用接到钉钉、企业微信或 QQ。
![实际部署的三分支客服 Chatflow。](/images/articles/source/images/dify-langbot/039-triage-three-branch-overview.png)
*实际部署的三分支客服 Chatflow。*
## 先把 Dify 和 LangBot 跑起来
先安装 Docker Compose 和 Git,再分别按 [Dify Docker Compose 部署文档](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) 与 [LangBot Docker 部署文档](https://langbot.app/docs/en/deploy/langbot/docker/) 启动两个服务。Dify 的基础步骤是克隆仓库、进入 `docker` 目录、将 `.env.example` 复制为 `.env`,再启动 Compose;LangBot 的文档提供完整的镜像和插件运行时配置。
本文截图来自 **Dify 1.17.1、LangBot v4.10.11** 的本机环境。我们把浏览器端口分别映射为 `8088` 和 `5368`;这是演示环境的自定义映射,官方默认部署通常分别使用 `80` 和 `5300`。如果沿用官方默认值,就打开 `http://localhost` 和 `http://localhost:5300`,不用为了对齐截图而改端口。各自创建管理员账户,并把界面语言设为 **English**。
![本地 Dify 的首次初始化页面。](/images/articles/source/images/dify-langbot/00-dify-install.png)
*本地 Dify 的首次初始化页面。*
![本地 LangBot 的首次初始化页面。](/images/articles/source/images/dify-langbot/00-langbot-install.png)
*本地 LangBot 的首次初始化页面。*
接入时最重要的是 **LangBot 容器能访问 Dify**。本次两个服务加入同一个 Docker 网络,因此 Runner 的 Base URL 使用 `http://nginx/v1`,其中 `nginx` 是 Dify 的服务名。你可以在两个 Compose 配置中为 Dify 的 `nginx` 和 LangBot 服务加入同一个外部网络;如果分别部署在不同主机,则填写 LangBot 能访问的 Dify HTTPS 地址并加上 `/v1`。下文表格里的 `http://nginx/v1` 都指本次共享网络环境,不能直接套到所有部署。容器内的 `localhost` 指向容器自己。
## 在 Dify 中配置 GPT-6 Astra
进入 **Integrations → Model Provider**,安装官方 **OpenAI-API-compatible** 插件,再点 **Add Model**。本次使用的插件版本是 0.0.66。
| 字段 | 本次设置 |
| --- | --- |
| Model Name / model name for API endpoint | `gpt-6-astra` |
| Model Type / Completion mode | LLM / Chat |
| Model display name | GPT-6 Astra |
| API Base URL | 你自己的 OpenAI 兼容服务地址,通常以 `/v1` 结尾 |
| API Key | 你的模型服务密钥 |
| API Type | Chat Completions API |
| Model context size / Upper bound for max tokens | 本教程设为 32768 / 4096 |
最后一行是这次演示的工作上限,不是对 Astra 完整规格的声明。保存时让 Dify 做连接验证,成功后再建应用。截图中的网关只是本次测试环境,实际使用时换成你自己的服务。模型参数和可用接口以所选服务为准。模型名称以你选用的服务实际提供的标识为准,本文保留本次实测的 `gpt-6-astra`。
![添加自定义模型。API Key 在截图前保持为空,实际运行时已配置。](/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png)
*添加自定义模型。API Key 在截图前保持为空,实际运行时已配置。*
## 先定义三类问题,再画流程
演示产品是一个虚构的帮助台产品 Northstar Desk。本文用到的规则直接写在三个分支中,不依赖另一篇教程或预先存在的知识库。
| 分支 | 适合的问题 | 回复任务 |
| --- | --- | --- |
| Account | 登录、邀请链接、工作区访问 | 说明邀请有效 48 小时,指导所有者重新发送邀请 |
| Product | 导出工单、试用限制、基础设置 | 回答已给定的产品规则和操作路径 |
| Human | 退款、收费、企业报价、投诉、混合不清的问题 | 说明需要人工决定,收集简短说明并给出联系支持团队的建议 |
第三条分支的作用是生成交接提示。本例没有连接工单系统,也不会真的通知客服,所以回复不能写“已转交”“退款已批准”。以后接入工单 API 时,再把真实执行结果接到这条分支。
## 在 Dify 创建分流 Chatflow
新建 **Chatflow**,名称为 `Astra Support Router`。从 User Input 连到 **Question Classifier**,模型选择 GPT-6 Astra,Query Variable 指向 `sys.query`。
添加三类,说明尽量写清楚范围:
```text
Account: login, invitation, password or workspace access
Product: usage, ticket export, setup and trial limits
Human: billing, refunds, enterprise pricing, angry complaints
or unclear mixed questions
```
![分类节点里的类别说明会直接影响路由结果。](/images/articles/source/images/dify-langbot/040-triage-classifier-settings.png)
*分类节点里的类别说明会直接影响路由结果。*
在 Advanced Setting 中补充一句:缺少关键信息、需要授权或者混合问题不明确时,选择 Human。分类器的三条出口分别连接一个 LLM 节点,再各自接 Answer。
三个 LLM 都选 GPT-6 Astra,用户消息引用 `sys.query`,但系统规则分别写:
- **Account Reply**:邀请链接有效 48 小时;请工作区所有者到 `Settings > Members` 重新发送。不要索要密码。其他账户问题先问一个澄清问题。
- **Product Reply**:所有者从 `Settings > Data > Export` 导出 CSV,链接保留 7 天;试用 14 天、5 名成员、2 个收件箱。规则没覆盖的内容直接说明。
- **Human Reply**:理解诉求,解释需要人工决定,请对方提供简短问题描述和非敏感参考信息,联系其支持团队。不要编造客服地址、承诺处理时效或声称已经执行。
共用规则只有几条:跟随用户语言、简短、不要重复冗长开场。把业务规则分在对应节点里,以后修改退款交接话术时,就不用担心顺便改坏登录帮助。
## 每个分支都要实际跑一次
我们在 Preview 中做了三组测试:
| 输入 | 实际路径 | 结果 |
| --- | --- | --- |
| My invitation link expired... | Account Output | 建议让所有者重新发邀请,说明 48 小时有效期 |
| How do I export tickets as a CSV? | Product Output | 返回导出路径和 7 天有效期 |
| 我对收费很不满意,要求退款,马上处理。 | Human Output | 说明需人工审核,不声称退款已经执行 |
![账户问题走 Account 分支。](/images/articles/source/images/dify-langbot/041-triage-account-path-result.png)
*账户问题走 Account 分支。*
![产品问题走 Product 分支。](/images/articles/source/images/dify-langbot/043-triage-product-path-result.png)
*产品问题走 Product 分支。*
![退款诉求走 Human 分支,输出人工复核建议。](/images/articles/source/images/dify-langbot/050-triage-human-review-chinese.png)
*退款诉求走 Human 分支,输出人工复核建议。*
注意看预览里的 **Workflow Process succeeded** 和具体的 Output 名称。只读最后一段回答,容易错过“答得似乎没错,但实际上走错了分支”的问题。
## 用 LangBot 接住消息入口
在 Dify 点 **Publish**,发布当前版本。然后进入 **Access Point → Backend Service API → API Key**,创建这个应用自己的密钥。
打开 LangBot,点 **Create Pipelines**,命名为 `Astra Support Router`。进入 **Configuration → AI**:
| 字段 | 值 |
| --- | --- |
| Runner | Dify Service API |
| Base URL | `http://nginx/v1` |
| App Type | Chat |
| API Key | 刚创建的 Dify 应用密钥 |
这里粘贴的是 **Dify 应用密钥**,不是前面配置 Astra 的模型密钥。一个负责调用应用,一个负责调用模型,别混用。保存后打开 **Debug Chat**,先验证整条调用链,再接平台。
![LangBot 的 Dify Runner 配置;截图时尚未填入应用密钥。](/images/articles/source/images/dify-langbot/053-langbot-triage-dify-settings.png)
*LangBot 的 Dify Runner 配置;截图时尚未填入应用密钥。*
## 在 LangBot 中验证分流仍然有效
我们先在 LangBot 问邀请链接失效,得到 `Settings > Members` 的建议;再用中文提出退款诉求,得到人工复核提示。Dify 的分类逻辑不用在 LangBot 里再写一遍。
![LangBot 中的账户问题回复。](/images/articles/source/images/dify-langbot/055-langbot-triage-account-english.png)
*LangBot 中的账户问题回复。*
![同一应用处理中文退款诉求,保持人工审核边界。](/images/articles/source/images/dify-langbot/076-langbot-triage-human-chinese.png)
*同一应用处理中文退款诉求,保持人工审核边界。*
上线前可以再加一小组混合问题:“无法登录,而且我要退款”“不知道该找谁”。如果这些问题总被分进 Product,先调整类别描述和分类指令,再考虑换模型。
这个方案最适合把重复支持工作先分清楚。接下来要做真实交接,就在 Human 分支调用已有工单或通知服务,并把成功、失败结果分别呈现给用户。不要把“生成一句交接话术”当成已经完成交接。
## 接到钉钉、企业微信、QQ,以及其他消息平台
在 LangBot 点 **Create Bots**,选择适配器,填写平台提供的凭据。创建后把机器人绑定到刚才的流水线;检查 Trigger 中的私聊、群聊和提及规则,再按平台要求发布或邀请机器人。
本次实测覆盖 **LangBot → Dify → GPT-6 Astra → LangBot 回复**。以下是实际界面核对过的接入方式,平台账户与群聊没有在本次演示中授权连接。
| 入口 | 配置方式 |
| --- | --- |
| 飞书 / Lark | 选 Lark;可扫码创建应用,也可手填 App ID、App Secret、与平台一致的 Bot Name。中国平台域名选 Feishu,默认使用长连接;开发者后台配置消息权限、事件并发布应用。 |
| 钉钉 | 选 DingTalk;扫码或填写 Client ID、Client Secret。Robot Code 需从开发者后台复制;按文档配置 Stream 接收消息、机器人名称和需要的卡片模板。 |
| 企业微信智能机器人 | 选 WeComBot;长连接用 BotId、Secret,填写机器人名称。Webhook 模式另配 Corpid、Token、EncodingAESKey。两套模式不要混填。 |
| 企业微信内部应用 / 微信客服 | 分别选 WeCom 或 WeComCustomerService,按各自后台填写企业与应用凭据、Token、EncodingAESKey,完成 HTTPS 回调和可信 IP 配置。内部应用不能直接当群机器人使用。 |
| 微信个人会话 | 选 OpenClaw WeChat,通过界面的二维码授权登录,按适配器说明接入。 |
| 微信公众号 | 选 Official Account,填写 App ID、App Secret、Token、EncodingAESKey,配置公网回调与 IP 白名单。根据接口限制选择回复模式;耗时较长时可能需要用户再发一条消息取回结果。 |
| QQ:OneBot v11 | 运行兼容 OneBot v11 的协议端,配置反向 WebSocket 到 LangBot 的监听端口,两侧 Access Token 保持一致;演示环境的 Compose 把主机 2288 映射到容器 2280。 |
| QQ 官方机器人 | 选 QQ Official API;可扫码绑定或填写 App ID、Secret。当前界面说明 Token 可留空;接收模式、沙箱范围、发布审核以 QQ 官方及适配器文档为准。 |
![钉钉适配器的凭据、Robot Code 与卡片配置。](/images/articles/source/images/dify-langbot/063-platform-dingtalk-fields.png)
*钉钉适配器的凭据、Robot Code 与卡片配置。*
![QQ 的 OneBot v11 方案需要反向 WebSocket 监听地址和端口。](/images/articles/source/images/dify-langbot/066-platform-onebot-v11-fields.png)
*QQ 的 OneBot v11 方案需要反向 WebSocket 监听地址和端口。*
LangBot 的适配器列表还包括 Discord、Slack、Telegram、LINE、Mattermost、Matrix、KOOK、Satori、HTTP Bot、Page Bot 和 WeChatPad。每种适配器需要的权限、回调和协议不同,不是填一个通用 Token 就全部接通。完整入口见 [LangBot 平台文档](https://langbot.app/docs/zh/usage/platforms/readme)。
如果只是想先模拟 QQ 消息,可以使用 matcha 之类的 OneBot 测试端;本文展示的对话来自 LangBot 自带 Debug Chat,没有把模拟对话当作真实群消息。
## 几个容易卡住的地方
遇到问题先按链路定位:Dify 预览能否回复、应用是否已 Publish、LangBot 的 Base URL 是否包含 `/v1`、应用类型是否正确,最后才看平台事件是否到达。如果改过 Dify 服务密码,Redis 与 Celery、Sandbox 与代码执行客户端的配置必须成对修改。
本机部署还遇到过代理软件返回虚拟 DNS 地址,导致 Dify 的 SSRF 代理拒绝插件下载。修好 DNS 后恢复,没必要关掉证书校验或内网访问保护。一次外部 API 的临时失败也不能当作模型或平台已经接通的证明,重试后仍应检查运行记录。
项目入口:[LangBot](https://github.com/langbot-app/LangBot) 和 [Dify](https://github.com/langgenius/dify)。截图和测试日期为 2026 年 9 月 16 日,后续版本的菜单名称可能会变化。
## 继续阅读
- [把群公告交给 Dify:用 GPT-6 Astra 和 LangBot 搭建 QQ、飞书写作助手](https://langbot.app/zh/blog/dify-langbot-writing-assistant)
- [在飞书里查询 GitHub 更新:Dify Workflow + GPT-6 Astra + LangBot 实战](https://langbot.app/zh/blog/dify-langbot-github-release-briefing)
@@ -0,0 +1,183 @@
---
title: "把群公告交给 Dify:用 GPT-6 Astra 和 LangBot 搭建 QQ、飞书写作助手"
description: "从基础 Chatbot 开始,把零散信息变成群公告,再通过 LangBot 连续追问、压缩和翻译。含真实部署截图、提示词和 QQ、飞书接入说明。"
---
本文同步自 LangBot Blog。 [阅读 Blog 原文](https://langbot.app/zh/blog/dify-langbot-writing-assistant).
发布于 2026-09-16 · 作者:LangBot Team
群里要发一条活动通知,手头往往只有几句零散信息:时间、地点、报名方式,还得再花几分钟调整口吻。真正烦的不是写第一版,而是“短一点”“别那么正式”“换成企微群通知”这几轮来回。
这次我们把这件事做成了一个聊天助手:Dify 管提示词和会话,GPT-6 Astra 负责改写,LangBot 负责把入口放到平时就在用的消息平台里。下面从部署开始,做一个可以继续追问和改稿的应用。
![实际链路:在 LangBot 里把英文提醒改成中文飞书群提醒。](/images/articles/source/images/dify-langbot/026-langbot-writing-chinese-roundtrip.png)
*实际链路:在 LangBot 里把英文提醒改成中文飞书群提醒。*
## 先把 Dify 和 LangBot 跑起来
先安装 Docker Compose 和 Git,再分别按 [Dify Docker Compose 部署文档](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) 与 [LangBot Docker 部署文档](https://langbot.app/docs/en/deploy/langbot/docker/) 启动两个服务。Dify 的基础步骤是克隆仓库、进入 `docker` 目录、将 `.env.example` 复制为 `.env`,再启动 Compose;LangBot 的文档提供完整的镜像和插件运行时配置。
本文截图来自 **Dify 1.17.1、LangBot v4.10.11** 的本机环境。我们把浏览器端口分别映射为 `8088` 和 `5368`;这是演示环境的自定义映射,官方默认部署通常分别使用 `80` 和 `5300`。如果沿用官方默认值,就打开 `http://localhost` 和 `http://localhost:5300`,不用为了对齐截图而改端口。各自创建管理员账户,并把界面语言设为 **English**。
![本地 Dify 的首次初始化页面。](/images/articles/source/images/dify-langbot/00-dify-install.png)
*本地 Dify 的首次初始化页面。*
![本地 LangBot 的首次初始化页面。](/images/articles/source/images/dify-langbot/00-langbot-install.png)
*本地 LangBot 的首次初始化页面。*
接入时最重要的是 **LangBot 容器能访问 Dify**。本次两个服务加入同一个 Docker 网络,因此 Runner 的 Base URL 使用 `http://nginx/v1`,其中 `nginx` 是 Dify 的服务名。你可以在两个 Compose 配置中为 Dify 的 `nginx` 和 LangBot 服务加入同一个外部网络;如果分别部署在不同主机,则填写 LangBot 能访问的 Dify HTTPS 地址并加上 `/v1`。下文表格里的 `http://nginx/v1` 都指本次共享网络环境,不能直接套到所有部署。容器内的 `localhost` 指向容器自己。
## 在 Dify 中配置 GPT-6 Astra
进入 **Integrations → Model Provider**,安装官方 **OpenAI-API-compatible** 插件,再点 **Add Model**。本次使用的插件版本是 0.0.66。
| 字段 | 本次设置 |
| --- | --- |
| Model Name / model name for API endpoint | `gpt-6-astra` |
| Model Type / Completion mode | LLM / Chat |
| Model display name | GPT-6 Astra |
| API Base URL | 你自己的 OpenAI 兼容服务地址,通常以 `/v1` 结尾 |
| API Key | 你的模型服务密钥 |
| API Type | Chat Completions API |
| Model context size / Upper bound for max tokens | 本教程设为 32768 / 4096 |
最后一行是这次演示的工作上限,不是对 Astra 完整规格的声明。保存时让 Dify 做连接验证,成功后再建应用。截图中的网关只是本次测试环境,实际使用时换成你自己的服务。模型参数和可用接口以所选服务为准。模型名称以你选用的服务实际提供的标识为准,本文保留本次实测的 `gpt-6-astra`。
![添加自定义模型。API Key 在截图前保持为空,实际运行时已配置。](/images/articles/source/images/dify-langbot/014-dify-astra-model-settings.png)
*添加自定义模型。API Key 在截图前保持为空,实际运行时已配置。*
## 创建一个足够简单的 Chatbot
在 Dify Studio 点 **Create → Create from Blank → More basic app types → Chatbot**。命名 `Astra Writing Assistant`。这个需求只需要提示词和聊天记忆,用基础 Chatbot 就能做完整。
![展开基础应用类型,选择 Chatbot。](/images/articles/source/images/dify-langbot/010-dify-create-basic-app.png)
*展开基础应用类型,选择 Chatbot。*
![给写作助手命名,说明它负责什么。](/images/articles/source/images/dify-langbot/011-dify-writing-app-create.png)
*给写作助手命名,说明它负责什么。*
在 **Configure model** 选 GPT-6 Astra,然后把下面的指令放到 Instructions:
```text
You help a community manager turn rough notes into messages people can use.
Reply in the language of the user's request.
For an announcement, give: one clear headline, a short ready-to-send message,
and one optional reminder.
Preserve supplied dates, times, links, and requirements exactly.
Never invent missing event details, discounts, results, or promises.
If an essential detail is missing, ask one concise question.
Use a natural, direct tone. Avoid hype and excessive emojis.
Keep a typical reply under 180 words. When revising, use conversation context.
```
我们特意把“保留时间和报名方式”写进了规则。群公告最怕的不是文笔一般,而是模型把晚上 8 点改成下午 8 点,或者顺手编出一个报名链接。指令用英文写不影响中文回复;`Reply in the language...` 会跟随用户语言。
![写作助手的完整提示词编辑区。](/images/articles/source/images/dify-langbot/012-dify-writing-instructions.png)
*写作助手的完整提示词编辑区。*
先在右侧 **Debug & Preview** 输入:
> 帮我写一条飞书群公告:9月22日晚上8点举行机器人分享会,每人带一个机器人案例,在群里回复“报名”即可参加。口吻自然,100字以内。
实测回复保留了活动时间、案例要求和“报名”方式。接着可以继续说“删掉最后的提醒,只留两句话”。对于这种任务,第二轮是否记得上一轮,比第一次是否写得漂亮更有用。
![Dify 中的中文公告回复,日期和报名方式来自输入。](/images/articles/source/images/dify-langbot/022-writing-chinese-first-reply.png)
*Dify 中的中文公告回复,日期和报名方式来自输入。*
英文测试也做了一遍:先要求写 Discord demo day 通知,再让它缩短并删除可选提醒。第二轮沿用了第一轮给定的日期、UTC 时间和频道。
![多轮改写测试:继续修改已有公告。](/images/articles/source/images/dify-langbot/019-writing-english-context-revision.png)
*多轮改写测试:继续修改已有公告。*
基础 Chatbot 的改动需要通过 **Publish Update** 发布。不要只改了提示词就直接去平台测试,否则外部接口可能仍在使用上一个版本。
![Access Point 同时提供 Web App 和 Backend Service API。](/images/articles/source/images/dify-langbot/023-writing-access-point-api.png)
*Access Point 同时提供 Web App 和 Backend Service API。*
## 用 LangBot 接住消息入口
在 Dify 点 **Publish**,发布当前版本。然后进入 **Access Point → Backend Service API → API Key**,创建这个应用自己的密钥。
打开 LangBot,点 **Create Pipelines**,命名为 `Astra Writing Assistant`。进入 **Configuration → AI**:
| 字段 | 值 |
| --- | --- |
| Runner | Dify Service API |
| Base URL | `http://nginx/v1` |
| App Type | Chat |
| API Key | 刚创建的 Dify 应用密钥 |
这里粘贴的是 **Dify 应用密钥**,不是前面配置 Astra 的模型密钥。一个负责调用应用,一个负责调用模型,别混用。保存后打开 **Debug Chat**,先验证整条调用链,再接平台。
![LangBot 的 Dify Runner 配置;截图时尚未填入应用密钥。](/images/articles/source/images/dify-langbot/007-langbot-dify-runner-config.png)
*LangBot 的 Dify Runner 配置;截图时尚未填入应用密钥。*
## 在 LangBot 再试一次
我们先发了一条英文 Telegram 提醒,拿到回复后继续要求改成中文飞书群提醒。最终回复保留了“9月22日晚上8点”和“每人带一个机器人案例”,说明 Dify 的会话上下文已经通过 LangBot 串起来了。
![LangBot 调用 Dify 返回英文活动提醒。](/images/articles/source/images/dify-langbot/025-langbot-writing-english-roundtrip.png)
*LangBot 调用 Dify 返回英文活动提醒。*
实际使用时,可以把这类助手放到运营群或项目群里,用提及触发。它适合把草稿变成能发送的文本:活动预告、版本通知、会议提醒、FAQ 回复。消息发送前仍由群成员决定是否采用,这样也方便继续改稿。
## 接到QQ、微信、飞书,以及其他消息平台
在 LangBot 点 **Create Bots**,选择适配器,填写平台提供的凭据。创建后把机器人绑定到刚才的流水线;检查 Trigger 中的私聊、群聊和提及规则,再按平台要求发布或邀请机器人。
本次实测覆盖 **LangBot → Dify → GPT-6 Astra → LangBot 回复**。以下是实际界面核对过的接入方式,平台账户与群聊没有在本次演示中授权连接。
| 入口 | 配置方式 |
| --- | --- |
| 飞书 / Lark | 选 Lark;可扫码创建应用,也可手填 App ID、App Secret、与平台一致的 Bot Name。中国平台域名选 Feishu,默认使用长连接;开发者后台配置消息权限、事件并发布应用。 |
| 钉钉 | 选 DingTalk;扫码或填写 Client ID、Client Secret。Robot Code 需从开发者后台复制;按文档配置 Stream 接收消息、机器人名称和需要的卡片模板。 |
| 企业微信智能机器人 | 选 WeComBot;长连接用 BotId、Secret,填写机器人名称。Webhook 模式另配 Corpid、Token、EncodingAESKey。两套模式不要混填。 |
| 企业微信内部应用 / 微信客服 | 分别选 WeCom 或 WeComCustomerService,按各自后台填写企业与应用凭据、Token、EncodingAESKey,完成 HTTPS 回调和可信 IP 配置。内部应用不能直接当群机器人使用。 |
| 微信个人会话 | 选 OpenClaw WeChat,通过界面的二维码授权登录,按适配器说明接入。 |
| 微信公众号 | 选 Official Account,填写 App ID、App Secret、Token、EncodingAESKey,配置公网回调与 IP 白名单。根据接口限制选择回复模式;耗时较长时可能需要用户再发一条消息取回结果。 |
| QQ:OneBot v11 | 运行兼容 OneBot v11 的协议端,配置反向 WebSocket 到 LangBot 的监听端口,两侧 Access Token 保持一致;演示环境的 Compose 把主机 2288 映射到容器 2280。 |
| QQ 官方机器人 | 选 QQ Official API;可扫码绑定或填写 App ID、Secret。当前界面说明 Token 可留空;接收模式、沙箱范围、发布审核以 QQ 官方及适配器文档为准。 |
![飞书适配器支持域名选择、扫码创建和手工配置。](/images/articles/source/images/dify-langbot/062-platform-lark-fields.png)
*飞书适配器支持域名选择、扫码创建和手工配置。*
![QQ 的 OneBot v11 方案需要反向 WebSocket 监听地址和端口。](/images/articles/source/images/dify-langbot/066-platform-onebot-v11-fields.png)
*QQ 的 OneBot v11 方案需要反向 WebSocket 监听地址和端口。*
LangBot 的适配器列表还包括 Discord、Slack、Telegram、LINE、Mattermost、Matrix、KOOK、Satori、HTTP Bot、Page Bot 和 WeChatPad。每种适配器需要的权限、回调和协议不同,不是填一个通用 Token 就全部接通。完整入口见 [LangBot 平台文档](https://langbot.app/docs/zh/usage/platforms/readme)。
如果只是想先模拟 QQ 消息,可以使用 matcha 之类的 OneBot 测试端;本文展示的对话来自 LangBot 自带 Debug Chat,没有把模拟对话当作真实群消息。
## 几个容易卡住的地方
遇到问题先按链路定位:Dify 预览能否回复、应用是否已 Publish、LangBot 的 Base URL 是否包含 `/v1`、应用类型是否正确,最后才看平台事件是否到达。如果改过 Dify 服务密码,Redis 与 Celery、Sandbox 与代码执行客户端的配置必须成对修改。
本机部署还遇到过代理软件返回虚拟 DNS 地址,导致 Dify 的 SSRF 代理拒绝插件下载。修好 DNS 后恢复,没必要关掉证书校验或内网访问保护。一次外部 API 的临时失败也不能当作模型或平台已经接通的证明,重试后仍应检查运行记录。
项目入口:[LangBot](https://github.com/langbot-app/LangBot) 和 [Dify](https://github.com/langgenius/dify)。截图和测试日期为 2026 年 9 月 16 日,后续版本的菜单名称可能会变化。
## 继续阅读
- [让客服问题走对分支:Dify + LangBot 钉钉、企业微信机器人实战](https://langbot.app/zh/blog/dify-langbot-support-triage)
- [在飞书里查询 GitHub 更新:Dify Workflow + GPT-6 Astra + LangBot 实战](https://langbot.app/zh/blog/dify-langbot-github-release-briefing)
+4 -6
View File
@@ -7,14 +7,9 @@ description: "同步自 LangBot Blog 的产品动态、技术解析、教程、
## 产品动态
- [LangBot 4.11:从消息回复走向事件驱动智能体](/zh/articles/langbot-v411-event-driven-agents) — 2026-10-15
- [LangBot Cloud 新版上线:多用户 Workspace 也来到开源版](/zh/articles/langbot-cloud-multi-user-workspaces) — 2026-08-25
## 在线体验
- [企业微信客服:体验 LangBot 知识库](/zh/articles/langbot-wecom-customer-service-knowledge-base) — 2026-09-17
- [Telegram:体验 LangBot 沙箱 Agent](/zh/articles/langbot-telegram-sandbox-agent) — 2026-09-17
- [LangBot 公众号:体验基础 AI 问答](/zh/articles/langbot-wechat-official-account) — 2026-09-17
## 技术解析
- [LangBot v4.10.0:Agent 沙箱与技能——让 Agent 真正像开发者一样工作](/zh/articles/langbot-v4100-sandbox-skills) — 2026-06-04
@@ -23,6 +18,9 @@ description: "同步自 LangBot Blog 的产品动态、技术解析、教程、
## 教程与集成
- [在飞书里查询 GitHub 更新:Dify Workflow + GPT-6 Astra + LangBot 实战](/zh/articles/dify-langbot-github-release-briefing) — 2026-09-16
- [让客服问题走对分支:Dify + LangBot 钉钉、企业微信机器人实战](/zh/articles/dify-langbot-support-triage) — 2026-09-16
- [把群公告交给 Dify:用 GPT-6 Astra 和 LangBot 搭建 QQ、飞书写作助手](/zh/articles/dify-langbot-writing-assistant) — 2026-09-16
- [LangTARS:开源 AI Agent 远程控制电脑 — 支持接入 Dify 和 n8n 工作流](/zh/articles/langtars-remote-pc-control-dify-n8n) — 2026-03-23
- [5分钟将 DeepSeek R1 接入微信、企业微信与 Discord (免费教程)](/zh/articles/connect-deepseek-to-wechat) — 2026-02-21
- [5 分钟部署你的 AI 机器人到 Discord、Telegram 和微信](/zh/articles/deploy-ai-bot-in-5-minutes) — 2026-02-17
@@ -0,0 +1,132 @@
---
title: "LangBot 4.11:从消息回复走向事件驱动智能体"
description: "LangBot 4.11 正式发布:事件路由让机器人响应入群、回应与卡片交互,AgentRunner 插件化连接不同智能体,工作区助手让配置更直观。附实机截图与升级指南。"
---
本文同步自 LangBot Blog。 [阅读 Blog 原文](https://langbot.app/zh/blog/langbot-v411-event-driven-agents).
发布于 2026-10-15 · 作者:LangBot Team
LangBot 是一个开源的 AI 聊天机器人与智能体平台,支持多种即时通讯平台、大语言模型、知识库和插件,帮助你构建、部署和管理 AI 助手。
过去,搭建一个聊天机器人通常从“收到消息,然后回复”开始。但真正的协作不只发生在消息里:新成员加入群组、用户对一条回复作出表情回应、同事点击卡片按钮,都可能是一个任务的起点。
**LangBot 4.11 的核心变化,是把这些事件变成可以配置、交给智能体处理、并追踪执行过程的入口。** 配合插件化的 AgentRunner 和新的工作区助手,LangBot 在连接聊天平台的同时,也让“由谁处理、怎么处理、如何管理”变得更清楚。
## 一、事件驱动:机器人不再只等待下一条消息
4.11 引入事件驱动智能体(Event-Based Agents,EBA)。除了普通消息,入群、退群、消息撤回、表情回应、卡片点击等平台事件,也可以进入处理流程。本次发布中,13 个平台适配器已经基于 EBA 架构重写。
这不意味着每个平台都有完全相同的事件能力。实际能收到哪些事件,仍取决于对应平台、适配器以及机器人权限。变化在于:收到事件之后,LangBot 有了一套统一的路由和处理方式。
![事件路由可按平台事件选择处理器](/images/articles/source/images/langbot-411/eba-event-routing.png)
*4.11 正式版发布说明中的事件路由示例。*
### 从场景出发,而不是先写一段胶水代码
在「事件路由」中,可以从欢迎新成员、处理成员离开等常见场景建立规则,再决定由哪个处理器执行。
例如,一个社区可以把普通问题交给知识库问答 Pipeline,把新成员加入交给负责欢迎与介绍规则的 Agent,再把需要固定业务逻辑的事件交给插件处理器。这是配置思路示例;实际启用前,需要确认平台事件支持和所需权限,并测试对应路由。
这种组织方式的好处是,**平台接入与业务处理不必绑成一块**。欢迎流程变了,可以调整处理器;问答策略变了,可以修改 Pipeline,而不必把所有行为塞进同一段提示词。
### Pipeline、Agent、插件处理器,分别适合什么?
![实机中的三类处理器创建界面](/images/articles/source/images/langbot-411/processor-types.png)
*本文新启动的 LangBot 4.11.0 实例:创建处理器时,先选择处理方式。*
- **Pipeline**:处理消息事件,适合直接生成回复、知识库问答和已有的消息处理流程。它仍是固定步骤清晰、容易配置的选择。
- **Agent**:用自然语言描述不同事件该如何处理,由 AI 执行,或者交给外部 Agent 平台。适合需要结合上下文作判断的任务。
- **插件处理器**:由插件代码处理其声明支持的事件类型。适合规则明确、需要确定性逻辑或专门集成的场景。
不需要为了“用上智能体”而把每个流程都改成 Agent。明确的规则交给代码,稳定的问答交给 Pipeline,需要判断的部分再交给 Agent,往往更容易维护。
### 调试也围绕事件展开
事件调试器允许以表单编辑事件数据,查看运行日志和执行详情。配置好路由之后,可以先检查事件字段和处理结果,再到真实聊天平台验证。调试事件有助于定位问题,但不替代对平台连接、权限和真实回调的验证。
平台侧也有相应改进,包括 Slack Socket Mode、钉钉卡片交互、微信“正在输入”提示和 OneBot WebSocket 等;具体支持范围以对应平台文档为准。
## 二、AgentRunner 插件化:选择执行方式,不必等待 Core 发版
另一项重要变化是运行器与主程序的解耦。LocalAgent、Dify、Coze、n8n 等原内置运行器迁移为扩展市场中的官方插件,并新增 Codex、Claude Code、ACP 等运行器。
![实机扩展市场中的官方运行器入口](/images/articles/source/images/langbot-411/marketplace-live.png)
*实机访问扩展市场,可看到官方 Runner 专区。市场内容独立更新,展示状态以访问时为准。*
对于用户,最直接的变化是:**按需安装运行器,并独立更新它们**。你可以使用 LocalAgent 的模型、工具和知识检索能力,也可以把已有的 Dify 应用或 n8n 工作流接到聊天平台,不必为了不同的执行方式维护不同的机器人接入方案。
这也给开发者留下更清晰的扩展边界:实现 AgentRunner Protocol v1,就可以编写自己的运行器,而不必把特定平台的逻辑直接加入 Core。
![发布说明展示的多种 AgentRunner 插件](/images/articles/source/images/langbot-411/runner-plugins-marketplace.png)
*4.11 正式版发布说明中的运行器插件示例。不同 Runner 的账号、API、运行环境要求仍需分别配置。*
插件化并不等于把所有能力无条件交给插件。运行器只能调用当前上下文授权的工具与平台 API;扩展市场展示认证徽章,Core 校验认证插件的签名。认证与权限控制解决的是来源和授权问题,使用前仍应阅读插件说明,确认它适合自己的部署环境。
### 升级时,已有 Pipeline 怎么办?
4.11 提供迁移入口,自动安装所需插件,并备份原配置。升级后,在「流水线」页面完成迁移,再检查运行器、模型、知识库和工具配置。
需要特别留意:**迁移后的流水线会开始新会话**。旧版自定义 Runner 也需要改写为插件 Runner。离线环境可以选择「仅迁移数据」,再手动安装运行器插件。完整映射关系见 [4.11 迁移说明](https://github.com/langbot-app/LangBot/blob/v4.11.0/docs/pipeline-migration-config-map.zh-CN.md)。
## 三、工作区助手:把配置过程变成可确认的对话
WebUI 新增的工作区助手,面向的是管理 LangBot 的人,而不是聊天群中的终端用户。它可以查询当前工作区的资源,并通过对话帮助创建和配置流水线、知识库等资源。
![工作区助手与统一监控界面](/images/articles/source/images/langbot-411/workspace-assistant.png)
*实机中的工作区助手初始界面。此截图展示尚未配置模型的新工作区;使用前需要登录 LangBot Account 或配置可用模型。监控中的零值是这个新实例的真实空状态。*
你可以从“当前有哪些模型、知识库和流水线?”这样的只读查询开始,再提出“帮我创建一个知识库问答应用”。重点不是把表单换成聊天框,而是让助手先理解当前资源,再提出具体配置。
**所有写操作都需要确认后才会执行。** 因此,在让助手新建或修改资源时,应先核对它提出的对象、参数和影响范围,再确认。助手降低了寻找配置入口的成本,也保留了管理者对变更的控制。
## 四、让日常运维跟得上新的执行方式
### 统一看执行,而不只看消息数量
当一个事件可能由 Pipeline、Agent 或插件处理时,排查问题需要看到完整的执行过程。4.11 更新了统一执行视图、工具调用追踪和实时处理中面板。
日常检查可以按这条顺序进行:先看事件有没有进入,再看交给了哪个处理器,最后查看模型与工具调用是否完成。这样更容易区分平台接入问题、路由配置问题和执行阶段的问题,而不是仅凭“机器人没有回复”猜测原因。
### 账号安全与操作记录
![账号设置中的 Passkey 与两步验证](/images/articles/source/images/langbot-411/account-security.png)
*实机账号设置展示 Passkey 和两步验证入口;截图中的演示账号尚未启用这些功能。*
4.11 新增 WebAuthn Passkey 登录和 TOTP 两步验证,并提供记录每次操作变更的操作日志及完整性校验。对于多人维护的工作区,这些能力分别帮助加强登录保护、追踪“谁改了什么”。Passkey 的使用还需要满足浏览器安全上下文等条件,应在合适的 HTTPS 部署环境中配置。
媒体存储也有调整:媒体按内容去重存储,减少重复媒体导致的 `langbot.db` 膨胀。此外,`lbctl` 和 API Key 提供了管理与诊断实例的命令行入口,适合把日常检查接入已有运维流程。
## 五、新用户更容易开始,老用户按步骤升级
![实机新手引导中的平台选择](/images/articles/source/images/langbot-411/onboarding.png)
*新手引导从平台选择开始,再进入机器人配置与 AI 引擎设置。*
第一次使用 LangBot,可以跟随侧边栏引导和场景化机器人创建向导,从平台、机器人配置、AI 引擎逐步完成设置。建议先验证一个简单问答流程,再添加知识库、工具和事件路由,避免同时引入太多变量。
已有实例升级,建议按下面的顺序处理:
1. **先备份** `data/` 目录或 PostgreSQL 数据库,建议从最新 v4.10.x 升级,并保留当前部署配置。
2. **升级 Core 与配套 Runtime**,检查服务连接状态。4.11.0 正式版固定使用 SDK `0.7.11`,不要混用旧 Runtime。
3. **完成流水线迁移并更新插件**,检查迁移后的运行器及配置,注意新会话边界。
4. **验证真实业务链路**:先测试一个已有的消息问答,再逐步验证新事件路由和授权工具。
5. **检查遥测与配置变化**:新增执行遥测默认开启,不含消息内容;可用 `space.disable_telemetry: true` 关闭这一遥测。配置新增 `media_cache`、`api.host`、`runner.admin_plugins`,移除 `force_box_session_id_template`。详见[数据收集政策](https://langbot.app/docs/zh/insight/data-collection-policy)及正式发布说明。
## 开始使用 LangBot 4.11
4.11 的价值不在于新增了多少配置项,而在于把三个问题连起来:**什么事件触发任务、由什么执行方式处理、怎样安全地管理和观察它。** 你可以继续保留熟悉的消息问答,也可以逐步把社区协作、业务通知与交互任务放进同一套管理界面。
- [查看 v4.11.0 正式版与完整更新说明](https://github.com/langbot-app/LangBot/releases/tag/v4.11.0)
- [阅读部署与使用文档](https://langbot.app/docs/zh/insight/guide)
- [使用 LangBot Cloud](https://cloud.langbot.app)
感谢所有参与本次版本开发、测试、文档和问题反馈的贡献者。本文围绕主要更新展开,完整贡献者名单见正式发布说明。
*配图说明:事件路由与运行器插件总览来自 v4.11.0 GitHub Release,其余五张截图来自为本文独立运行的官方 `rockchin/langbot:v4.11.0` 实例。实机截图使用英文界面便于跨语言对照;没有连接生产机器人,也没有将演示界面描述为真实业务运行结果。*
@@ -120,9 +120,9 @@ http://localhost:7860/flow/{flow-id}
![LangBot Pipeline AI Tab](/images/articles/external/3c7d6bc96738-08-langbot-pipeline-ai-tab.png)
配置**运行器**,选择 **Langflow API**:
配置 **Runner**,选择 **Langflow API**:
![LangBot 运行器下拉菜单](/images/articles/external/ef9bbef78165-09-langbot-runner-dropdown.png)
![LangBot Runner Dropdown](/images/articles/external/ef9bbef78165-09-langbot-runner-dropdown.png)
填写 Langflow 配置:

Some files were not shown because too many files have changed in this diff Show More