会议纪要别再手抄了:n8n + LangBot + GPT-6,给钉钉和企微做任务清单机器人
会议结束时,群里通常已经有一大段纪要。真正容易掉下来的,是三件小事:谁来做、什么时候交、哪件事还没人接。再漂亮的摘要,如果没有变成能核对的清单,第二天照样要翻聊天记录。
这次我把“纪要 → 结构化任务 → 保存草稿 → 聊天回执”连了起来。GPT-6 Astra 负责提取,n8n 校验并调用保存接口,LangBot 提供钉钉、企业微信等消息入口。重点是任务真的写进数据库,而不是回复里说一句“已保存”。

这篇要搭建的完整工作流
1. 从零启动 n8n 和 LangBot
准备 Docker Compose 和一个能调用 gpt-6-astra 的兼容 API 凭据。实测版本是 n8n 2.39.6 / LangBot 4.10.11,界面切为 English。这里的模型 ID 来自本次使用的网关;换供应商时请确认自己的模型名与接口路径。
新建目录,把下面内容保存为 compose.yaml。
name: langbot-n8n-astra
services:
n8n:
image: docker.n8n.io/n8nio/n8n:2.39.6
environment:
TZ: Asia/Shanghai
GENERIC_TIMEZONE: Asia/Shanghai
N8N_HOST: localhost
N8N_PORT: 5678
N8N_PROTOCOL: http
N8N_EDITOR_BASE_URL: http://localhost:5690
WEBHOOK_URL: http://localhost:5690/
N8N_DIAGNOSTICS_ENABLED: 'false'
N8N_PERSONALIZATION_ENABLED: 'false'
ports:
- '127.0.0.1:5690:5678'
volumes:
- n8n_data:/home/node/.n8n
- ./workflows:/imports:ro
restart: unless-stopped
demo-api:
image: python:3.12-alpine
command: [python, /app/demo-api.py]
volumes:
- ./demo-api.py:/app/demo-api.py:ro
- ./data/demo:/data
restart: unless-stopped
runtime:
image: rockchin/langbot:v4.10.11
command: [uv, run, --no-sync, -m, langbot_plugin.cli.__init__, rt]
volumes:
- ./data/langbot/plugins:/app/data/plugins
restart: unless-stopped
langbot:
image: rockchin/langbot:v4.10.11
depends_on: [runtime, n8n]
environment:
TZ: Asia/Shanghai
BOX__ENABLED: 'false'
PLUGIN__RUNTIME_WS_URL: ws://runtime:5400/control/ws
API__WEBUI_URL: http://localhost:5370
API__WEBHOOK_PREFIX: http://localhost:5370
volumes:
- ./data/langbot:/app/data
ports:
- '127.0.0.1:5370:5300'
restart: unless-stopped
volumes:
n8n_data:
同目录保存 demo-api.py。下面这个小服务只包含虚构订单和会议任务草稿,完整代码可直接运行。
"""Local synthetic order/task service. No real customer data or external writes."""
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
import sqlite3
from pathlib import Path
Path('/data').mkdir(exist_ok=True)
db = sqlite3.connect('/data/tasks.sqlite')
db.execute('CREATE TABLE IF NOT EXISTS meetings (id TEXT PRIMARY KEY, payload TEXT NOT NULL)')
ORDERS = {
'DEMO-1001': {'order_id':'DEMO-1001','status':'shipped','carrier':'Demo Express','tracking':'DEMO-TRACK-901','estimated_delivery':'2026-09-20','items':['USB-C Hub']},
'DEMO-1002': {'order_id':'DEMO-1002','status':'processing','carrier':None,'tracking':None,'estimated_delivery':None,'items':['Desk Lamp']},
}
class Handler(BaseHTTPRequestHandler):
def reply(self, data, code=200):
body=json.dumps(data,ensure_ascii=False).encode();self.send_response(code);self.send_header('Content-Type','application/json');self.end_headers();self.wfile.write(body)
def do_GET(self):
if self.path.startswith('/orders/'):
key=self.path.rsplit('/',1)[-1];self.reply({'found':key in ORDERS,'order':ORDERS.get(key),'source':'Synthetic tutorial order database'})
elif self.path=='/tasks':
self.reply({'meetings':[json.loads(x[0]) for x in db.execute('SELECT payload FROM meetings ORDER BY rowid DESC LIMIT 20')]})
else:self.reply({'service':'LangBot tutorial demo API','fixtures':True})
def do_POST(self):
if self.path!='/tasks':return self.reply({'error':'Not found'},404)
try:
obj=json.loads(self.rfile.read(int(self.headers.get('Content-Length','0'))));key=obj['meeting_id']
if not isinstance(obj.get('tasks'),list) or not key:raise ValueError('Invalid task payload')
db.execute('INSERT INTO meetings VALUES (?,?) ON CONFLICT(id) DO UPDATE SET payload=excluded.payload',(key,json.dumps(obj,ensure_ascii=False)));db.commit()
self.reply({'saved':True,'meeting_id':key,'task_count':len(obj['tasks']),'record':obj})
except (ValueError,KeyError):self.reply({'error':'Invalid task payload'},400)
HTTPServer(('0.0.0.0',8080),Handler).serve_forever()
mkdir -p workflows
docker compose up -d
docker compose ps
打开 http://localhost:5690 创建 n8n 本地管理员,再打开 http://localhost:5370 初始化 LangBot;可跳过快速创建机器人,先建流水线。端口只绑定本机,适合跟做。数据存储在 Docker 卷与 data 目录中,重启容器不会清空。

n8n 首次启动的本地账户界面
LangBot 4.10.11 的 n8n 入口在流水线里。若你使用更新版本,入口可能迁移到 Runner 插件,别把本文的菜单位置当作所有版本都一样。
2. 搭建工作流,把每一步写清楚
准备一段虚构会议记录,开头写唯一的会议编号。这个编号是保存接口的主键:同一编号重新提取会更新同一份草稿,不会无限追加副本。
模型返回 meeting_id、summary 和 tasks。每个任务都有 owner、task、due_date;原文没交代的人和日期必须是 null。Validate Task JSON 会解析返回内容并检查任务数组;Save Draft Tasks 才发起真正的 HTTP POST。只有保存接口成功返回,最后才回复“已保存”。
本例附带的 Python 服务使用 SQLite,数据留在 examples/data/demo 对应的挂载目录。它是为了把整条链路跑清楚准备的演示服务,不是钉钉待办或生产项目管理系统。替换成你自己的任务系统时,主要改保存节点和权限映射。

完整工作流:消息进入后,数据沿节点流动
在 n8n 新建工作流,按图添加节点,并保持下面的节点名称一致;表达式会用名称读取上游结果。配置如下。
| 节点 | 类型 | 关键设置 |
|---|---|---|
| Chat Webhook | webhook | POST; Path: astra-meeting; Respond: Using Respond to Webhook Node |
| GPT-6 Astra - Extract Tasks | httpRequest | POST; https://newapi.rockchin.top/v1/chat/completions; Header Auth |
| Validate Task JSON | code | Run Once for All Items; JavaScript |
| Save Draft Tasks | httpRequest | POST; http://demo-api:8080/tasks |
| Reply to LangBot | code | Run Once for All Items; JavaScript |
| Respond to Chat | respondToWebhook | Text; Content-Type: application/json; charset=utf-8 |

JSON 校验:未知字段不要编造

调用本地任务接口,保存会议草稿
模型凭据和请求体
在 n8n Credentials 新建 Header Auth:Name 填 Authorization,Value 填 Bearer YOUR_API_KEY。回到模型 HTTP Request 节点,选择 Generic Credential Type → Header Auth,绑定这个凭据。不要把真实 Key 写进 Code 节点或导出的工作流。LangBot 不会自动把自己的模型凭据传给 n8n。
打开 Send Body → JSON → Using JSON,切换 Expression,填入下面表达式。示例 URL 是本次网关的 OpenAI 兼容地址;使用自己的服务时连同模型 ID 一起调整。
{{
JSON.stringify({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"Extract meeting action items. Return JSON only: {meeting_id:string,summary:string,tasks:[{owner:string|null,task:string,due_date:string|null}]}. Preserve the supplied meeting ID. Do not invent owners, deadlines or completed actions. Use null when unknown. Respond in the language of the notes. This is a draft extraction, not a message to assignees.",
},
{
role: "user",
content: JSON.stringify(
$("Chat Webhook").first().json.body.chatInput,
),
},
],
stream: false,
max_tokens: 1500,
response_format: { type: "json_object" },
})
}}
Code 节点内容
Validate Task JSON
const text = $json.choices[0].message.content;
const d = JSON.parse(text.replace(/^```(?:json)?\s*|\s*```$/g, ""));
if (!d.meeting_id || !Array.isArray(d.tasks))
throw new Error("Invalid meeting schema");
for (const t of d.tasks) {
if (typeof t.task !== "string" || !t.task.trim())
throw new Error("Empty task");
t.owner = t.owner || null;
t.due_date = t.due_date || null;
}
return [{ json: d }];
Reply to LangBot
const d = $json.record;
const lines = d.tasks.map(
(t, i) =>
`${i + 1}. ${t.task} | Owner: ${t.owner || "Unassigned"} | Due: ${t.due_date || "Not specified"}`,
);
return [
{
json: {
response: `Meeting ${d.meeting_id} — ${$json.task_count} draft tasks saved.\n${d.summary}\n\n${lines.join("\n")}\n\nReview before assigning. No notifications were sent.`,
},
},
];
保存接口的 JSON Body:
{{
JSON.stringify($json)
}}
连线与最终返回
- Chat Webhook → GPT-6 Astra - Extract Tasks
- GPT-6 Astra - Extract Tasks → Validate Task JSON
- Validate Task JSON → Save Draft Tasks
- Save Draft Tasks → Reply to LangBot
- Reply to LangBot → Respond to Chat
最后的 Respond to Chat 是 Respond to Webhook 节点。Respond With 选 Text,在 Options 添加响应头 Content-Type: application/json; charset=utf-8,Response Body 切到 Expression:
{{
JSON.stringify($json).replace(
/[\u007f-\uffff]/g,
(c) => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0"),
)
}}
这仍然是 JSON 响应,只是把非 ASCII 字符转义后传输。我在当前 LangBot 版本的长中文回复中遇到过分块解码乱码,这个返回方式已通过复测;接收端解析 JSON 后显示的仍是正常中文。最终对象必须包含字符串 response。模型 HTTP Request 的 Options → Timeout 设置为 90000 毫秒。
配置完成后点击 Publish。本文 n8n 2.39.6 用这个按钮启用生产 Webhook;不要只点 Execute workflow 后把 /webhook-test/ 地址填给 LangBot。

明确返回 JSON,并兼容中英文内容
3. 让 LangBot 调用它
在 LangBot 新建一条流水线,打开 Configuration → AI,Runner 选 n8n Workflow API。填写:
- Webhook URL:
http://n8n:5678/webhook/astra-meeting - Output Key:
response - Timeout:
150 - Webhook Response Handling: Forward as chat reply
- Authentication Type: None(仅限本文隔离的本地演示网络)
这里最容易填错的是主机名。浏览器访问的是 localhost:5690;LangBot 容器访问同一 Compose 网络里的 n8n,应该用服务名 n8n:5678。在容器里填 localhost,会指向 LangBot 容器自己。
本机演示没有开放公网 Webhook。跨主机部署时应配置 HTTPS,并把 n8n Webhook 的 Header Auth / Basic Auth 与 LangBot 对应认证设置对齐。不要直接公开本文未鉴权的演示接口。

LangBot 中的 n8n Runner 设置;按本案例替换 Webhook 路径
保存后打开 Debug Chat,发送:
会议编号 DEMO-MEETING-ZH。陈晨在 2026-09-21 前整理接口检查清单;李明排查 Webhook 报错,没有约定截止日期;新人指南需要更新,负责人还没定。请提取行动项并保存草稿。

从 LangBot Debug Chat 走通的真实请求与回复
实测保存了三条任务:第一条有负责人和日期;第二条只有负责人;第三条两项都没有。数据库读回结果与 n8n 的保存节点输出一致,没约定的内容保持空值。
还有一个容易被忽略的边界:提取任务不等于已经指派任务。这里保存的是草稿,没有给任何同事发通知。正式接入待办系统前,应增加确认或审批步骤,并限制谁能更新哪场会议的草稿。模型生成的会议编号也需要与原始请求核对。

n8n 执行记录,可以逐节点核对输入与输出
可以直接读回数据库接口,核对保存记录:
docker compose exec demo-api python -c "import urllib.request; print(urllib.request.urlopen('http://localhost:8080/tasks').read().decode())"

保存节点返回的真实任务记录
4. 接到自己的消息平台
本文已经实际验证 LangBot Debug Chat → n8n → 模型/数据接口 → LangBot 回复。没有使用真实飞书、钉钉、企微或 QQ 账号收发消息,下面是平台接入步骤,不把配置说明当作实投结果。
| 平台 | 在平台侧准备什么 | LangBot 里怎么接 |
|---|---|---|
| 飞书 | 企业自建应用、机器人能力、收发消息权限、事件订阅 | 选 Lark,填 App ID / App Secret;国内飞书可用长连接。Webhook 模式按页面给出的回调地址配置。配置 |
| 钉钉 | 企业应用机器人,启用 Stream 推送 | 选 DingTalk,填 Client ID / Client Secret;卡片回复另配模板与权限。配置 |
| 企业微信应用 | 企业 ID、应用 Secret、通讯录同步 Secret;消息接收 Token / EncodingAESKey | 选 WeCom,先保存机器人,再把生成的回调 URL 填回企微后台。配置 |
| 企微智能机器人 / 微信客服 | 对应机器人或客服接口凭据 | 分别选 WeComBot / WeComCustomerService,按对应适配器配置,不能混用应用机器人凭据。机器人、客服 |
| 微信公众号 | AppID / AppSecret、Token / EncodingAESKey、服务器 IP 白名单 | 选 Official Account,填凭据,把 LangBot 回调 URL 填入服务器配置,使用安全模式。配置 |
| QQ 官方机器人 | QQ 开放平台应用、AppID / Token / AppSecret、测试范围及 IP 白名单 | 选 QQ Official API,按所选模式配置事件回调,并把机器人加入允许的群或频道。配置 |
| QQ / OneBot v11 | 已运行的 OneBot 实现,例如 NapCat | 选 OneBot v11,对齐反向 WebSocket 地址、端口和访问令牌;本地演示也可用协议模拟器。配置 |
| 个人微信 | 对应微信适配器的服务或登录状态 | 按当前版本选 OpenClaw WeChat / WeChatPad 等适配器;各协议能力和登录方式不同。当前平台列表 |
| Slack / Discord / Telegram / LINE | 各平台机器人凭据;需要回调的平台准备公网 HTTPS | 分别选择同名适配器,再绑定本文流水线。Slack、Discord、Telegram、LINE |
此外还有 KOOK、Matrix、Mattermost、Satori、HTTP Bot 和网页机器人入口,完整清单以所安装版本的 Create Bot 为准。

LangBot 英文界面的平台选择入口
创建机器人后,把它的流水线绑定为刚才保存的这一条,再开启机器人。群聊还需要检查 Trigger 中的 @ 或前缀规则;机器人在线但不回复,不一定是 n8n 的问题。回调型平台需要公网 HTTPS,长连接或轮询型平台则按对应适配器要求配置网络。
5. 出问题时,从这三处查
- Webhook 404:检查是否已 Publish,以及填的是生产
/webhook/地址。 - n8n 成功但聊天没正文:查看最终 JSON 是否有字符串
response,并确认 Output Key 一致。 - 模型节点 401、超时或空结果:核对 n8n 自己绑定的模型凭据、完整接口 URL、模型 ID 和该次执行数据。LangBot 和 n8n 的模型配置不是一份。
我更愿意先把输入、数据来源和返回字段固定下来,再考虑多加几个模型或平台。LangBot 的价值在这里很直观:业务步骤留在 n8n,换一个消息入口时,主要处理的是适配器和流水线绑定,而不是重写整套业务。
参考:LangBot n8n 配置、LangBot 源码、n8n 源码与版本。
本文配置与截图来自本地实际运行;示例输入为虚构数据。文章使用 AI 辅助整理,并依据执行记录核对。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)