如果你最近在折腾个人 AI Agent,大概率逃不开两个关键词:OpenClaw 和 Skill。再加一个飞书,三件套凑齐,基本就是一套能真正在日常工作里跑起来的智能体工作流。我花了两周时间,把这套东西从部署到飞书机器人接入,再到手写 Skill 完整走了一遍,过程中踩坑无数,尤其是飞书消息被截断、session 文件锁超时这类问题,网上资料少得可怜,全靠翻日志猜原因。这篇文章不写废话,直接把 OpenClaw 怎么装、飞书应用怎么建、Skill 怎么写,以及我实际遇到的那些报错和排查思路全部分享给你。无论你是刚听说 OpenClaw 的小白,还是已经在写 Skill 的老手,都能在这里找到可以直接抄作业的部分。
先说一个结论:OpenClaw 本身不是一个大模型,也不是一个聊天机器人,而是一个把大模型、消息渠道、可扩展技能串起来的 Agent 运行时框架。飞书在其中扮演的是 "Channel" 的角色,也就是用户和 Agent 之间的交互入口。Skill 则是挂载在 Agent 上的能力包,让 Agent 不只是会聊天,还能真正去调接口、算数据、写表格。理解了这三层关系,后文所有的配置和代码就都有了解释。
1. 先搞清楚三个概念:OpenClaw、Channel、Skill
1.1 OpenClaw 到底是什么,和 WorkBuddy 怎么选
先说个很多人纠结的问题:OpenClaw 和 WorkBuddy 哪个好?我的看法是,这俩不是同一类东西,硬比意义不大。如果你要的是一个开箱即用、界面友好的个人助手,WorkBuddy 的完成度更高,装完基本就能聊。但如果你想把 Agent 接到飞书群里、想让 Agent 自己调用脚本干活、想把手里的技能资产做成可复用可分享的 Skill 包,OpenClaw 这种偏框架型的方案明显更灵活。
OpenClaw 的定位可以拆成三层理解:
- Runtime 层:负责管理 Agent 的生命周期、对话上下文、会话持久化和并发控制。你看到的 session 锁、超时日志都在这一层。
- Channel 层:对接不同的消息平台。飞书、Microsoft Teams、Discord、Slack、Telegram 都是 Channel。OpenClaw 的核心思路就是"一套 Agent,多平台入口",所以很多人问怎么选择 Channel,答案取决于你团队成员平时用哪个 IM。
- Skill 层:Agent 的扩展能力。每个 Skill 是一组指令加脚本,Agent 根据用户问题的意图自动匹配并加载对应的 Skill。
我自己选 OpenClaw 的原因很实在:团队用飞书,我需要一个能接进飞书群、能读多维表格、能处理审批数据的 Agent,而不是又一个网页聊天框。WorkBuddy 我装过,上手确实快,但一旦涉及自定义脚本和飞书 API 深度联动,还是 OpenClaw 这类框架更对味。
1.2 Skill 和 Agent 的边界在哪里
热词里有一堆 "xxx skill"——数学建模 skill、前端开发 skills、仓颉 skill、ponytail skill,说明大家已经开始把 Skill 当成一种可分享、可复用的资产。但很多人分不清 Skill 和 Agent 的区别,我打一个比方:
Agent 是"员工",它有人设、有记忆、有固定的工作上下文。Skill 是这个人"会用的工具",比如会写 Python、会用飞书 API、会做数学建模。员工可以换,工具可以随时加。所以你在 OpenClaw 里通常只需要一个主 Agent,但可以挂十几个 Skill。只有当某个任务需要完全独立的对话记忆、独立的 Prompt 体系和独立的调度逻辑时,才值得把它拆成一个新 Agent。我的判断标准很简单:有明确输入输出的重复性任务,做成 Skill;需要独立人格、独立上下文场景,才考虑新 Agent。
1.3 为什么偏偏是飞书
飞书作为 Channel 的优势,用过的人都懂。审批、日历、云文档、多维表格、群消息全在一个 App 里,Agent 接进来之后能干的远不止聊天。你可以让它在群里自动发日报,可以让它把审批数据回填到多维表格,可以把它拉进一个群当值班助理。这不是网页聊天能做到的体验——消息是异步的,你随手转发一条消息给机器人,它就能开始干活。
这也是我把标题定为"OpenClaw 飞书 Skill 开发"的原因:三件套组合起来,才是一个完整的可落地方案,而不是三个孤立的概念。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 部署 OpenClaw:从零到跑通
2.1 安装前的环境准备
OpenClaw 的安装方式和你选的版本有关,但无论哪种方式,有两样东西是跑不掉的:Node.js 运行时(通常要求 18 或更高版本)和 Python 3.10+(部分 Skill 脚本要跑 Python)。如果你只在 Windows 上玩,装个 WSL2 或者直接用原生 Windows 版本都行,区别不大。
这里提一句热词里的 "windowshub 安装",本质上是 Windows 下的一键安装引导。我的建议是:能上 Linux 就尽量上 Linux。倒不是说 Windows 跑不起来,而是 OpenClaw 的很多脚本和 cron 定时任务在 Linux 下更省心,部署完用 systemd 守护进程也方便。我自己是在一台闲置的 Linux 小主机上跑的,成本低,还能 7×24 在线。
模型侧的配置是大头。OpenClaw 本身不自带模型,你需要配置一个模型提供商。常见的选择是 OpenAI 系、Anthropic 系,以及国内的千问(Qwen)等。热词里专门有一条"openclaw 配置千问",说明国内用户跑通的第一道坎基本都在这里。我把千问的配置单独拉出来说:只要在模型配置里把 provider 指定为 qwen,填上 DashScope 的 API Key 和模型名(比如 qwen-max),基础对话就能跑起来。选国内模型的好处是延迟低、稳定性好,不用额外折腾网络,实测下来写写脚本、做做文本处理完全够用。
2.2 安装实操:Linux 和 Windows 两条路径
以我常用的 Linux 路径为例,大致是这几步:
- 下载对应平台的压缩包或直接用 git 拉源码:
git clone <仓库地址> && cd openclaw - 安装依赖:
npm install,如果涉及 Python Skill,再补pip install -r requirements.txt - 复制配置模板:
cp openclaw.example.json openclaw.json - 编辑
openclaw.json,填模型 API Key 和默认模型 - 启动:
npm start或./openclaw serve
Windows 下原理一样,只是把安装步骤换成解压 zip 或者走 windowshub 的引导流程,装完同样改配置文件启动。
启动后多留意启动日志。如果日志里能看到 Agent 初始化完成、Channel 等待连接,说明底层已经 OK。我见过不少人卡在启动这一步,其实九成是配置 JSON 里多了个逗号,或者 API Key 填错了位置。先跑一个最小配置,确认本地能对话,再往里面加 Channel,这个顺序不要反。
2.3 配置文件里的三个关键块
OpenClaw 的配置虽然各家版本字段略有差异,但核心跑不出三块:模型配置、Agent 配置、Channel 配置。我贴一份自己正在用的简化配置,字段名以你实际版本为准,结构可以参考:
json复制{
"model": {
"provider": "qwen",
"apiKey": "sk-你的密钥",
"model": "qwen-max"
},
"agents": {
"main": {
"name": "主助手",
"persona": "你是一个擅长处理飞书办公场景的助理,做事严谨,优先调用可用 Skill。",
"skillsPath": "./skills"
}
},
"channels": {
"feishu": {
"type": "feishu",
"appId": "cli_xxx",
"appSecret": "你的飞书应用密钥",
"mode": "websocket"
}
}
}
注意几个细节:
- 密钥不要直接写死在配置里。我习惯用环境变量注入,比如
"apiKey": "${QWEN_API_KEY}",这样配置文件和密钥分离,换机器、换环境都方便。 skillsPath指向 Skill 目录,这个字段决定了你后面写的 Skill 能不能被 Agent 发现。- Channel 配置先留空,等飞书应用建好了再填,避免启动报错。
3. 飞书侧配置:机器人应用创建全流程
OpenClaw 装好之后,最难的是飞书这边的应用创建。因为飞书开放平台的权限和事件订阅逻辑,跟普通聊天软件不太一样,新手最容易在这里卡住。这一节我按步骤拆开讲,你照着操作就行。
3.1 在飞书开放平台创建企业自建应用
打开飞书开放平台(open.feishu.cn),进入开发者后台,点"创建企业自建应用"。这里一定要选企业自建,而不是商店应用——自建应用发版简单,适合内部工具和私人助理。创建后你会拿到两个核心凭证:
- App ID:形如
cli_xxxxx,应用唯一标识。 - App Secret:应用密钥,调用 API 时换 token 用。
拿到凭证后,第一步不是写代码,而是去"应用能力"里开启机器人能力。这一步很多人会漏,结果 OpenClaw 那边怎么发消息都报错。机器人能力开启后,应用才具备收发消息的资格。
然后去"权限管理"里申请权限。我最低限度会开这几项:
| 权限标识 | 作用 |
|---|---|
im:message |
读取用户发给机器人的消息 |
im:message:send_as_bot |
以机器人身份发送消息 |
im:chat:readonly |
读取群信息(用于拿 chat_id) |
bitable:app |
读写多维表格(后面 Skill 要用) |
权限这里多说一句:飞书权限不是申请了就立刻生效,需要创建版本并发布,发布后应用内的权限才真正激活。热词里那条"飞书没有 cli 权限",十有八九就是版本没发、或者权限申请了但没重新发布导致的。排查顺序永远是:确认权限已申请 → 确认版本已发布 → 确认应用状态为"已发布"。
3.2 事件订阅:本地开发首选长连接
飞书机器人要收到用户消息,必须配置事件订阅。事件订阅有两种模式:
- 网页回调(Webhook)模式:飞书把事件 POST 到你提供的公网 URL 上。本地开发时还得内网穿透,麻烦。
- 长连接模式:应用通过 WebSocket 与飞书服务器建立长连接,事件直接推过来,不需要公网地址。
我在本地和 Linux 小主机上都用的长连接模式,省去公网暴露的麻烦。在开放平台"事件订阅"里把请求地址配置为长连接模式,然后添加事件 im.message.receive_v1(接收消息事件)。这样用户私聊机器人、或者在群里 @ 机器人,事件都会推送到 OpenClaw。
配置长连接时,飞书开放平台会让你填写一个校验信息,本质是双向验证应用身份。OpenClaw 的飞书 Channel 一般已经内置了这个处理逻辑,你只要把 App ID 和 Secret 填对,通道就能自己完成握手。
3.3 把飞书 Channel 接进 OpenClaw
飞书应用建好,回到 openclaw.json 把 Channel 配置填上:
json复制"channels": {
"feishu": {
"type": "feishu",
"appId": "cli_你的应用ID",
"appSecret": "你的应用密钥",
"mode": "websocket"
}
}
启动 OpenClaw 后,日志里如果出现飞书 Channel 已连接的提示,说明通道通了。这时候去飞书里找到你的应用机器人,发一句 "你好" 试试。如果机器人有反应,恭喜你,OpenClaw 和飞书的链路已经打通,接下来才是重头戏——Skill 开发。
4. Skill 开发核心:理解 Skill 的骨骼和血肉
4.1 Skill 到底长什么样
Skill 在 OpenClaw 里通常是一个目录,里面有一份说明文件和若干脚本。一个最小可用的 Skill 结构是这样的:
text复制skills/
feishu-approval/
SKILL.md
scripts/
fetch_approval.py
send_table.py
这里的灵魂是 SKILL.md,它就是 Agent 的"使用说明书"。文件开头是 YAML 格式的元信息,后面是正文。为什么说 SKILL.md 是灵魂?因为 Agent 不是把每个 Skill 的代码都加载到上下文里,而是先看你的 description,判断当前用户需求是否匹配这个 Skill,匹配了才加载完整内容。所以 description 写得好不好,直接决定 Skill 能不能被正确触发。
我见过太多人把 description 写成 "处理审批相关事情",这种太泛的写法会导致 Agent 在需求模糊时犹豫不决。好的 description 要包含触发场景、适用对象、典型问法。举个例子:
markdown复制---
name: feishu-approval-summary
description: 当用户需要查看审批汇总、导出审批记录、或把审批结果同步到飞书多维表格时使用。典型触发问法包括"帮我统计本周审批"、"把审批数据写入表格"、"给 XX 群发一份审批汇总"。
version: 1.0.0
---
这样写,Agent 一看就明白:什么场景该用、需要做什么、边界在哪里。
4.2 SKILL.md 正文怎么组织
元信息下面就是正文。我的组织习惯分四块:能力说明、调用方式、参数说明、注意事项。其中调用方式部分要写得非常具体,因为 Agent 会照着它一步步执行。它不是一个给人类看的 PDF,而是一份给 LLM 看的标准作业程序。
比如:
markdown复制# 飞书审批汇总 Skill
## 能力说明
完成三类任务:
1. 拉取指定时间范围内的审批实例
2. 把审批结果写入多维表格
3. 将汇总结果以表格形式发送到指定飞书群
## 调用方式
按以下顺序执行:
1. 运行 `python scripts/fetch_approval.py --days 7` 获取原始数据
2. 运行 `python scripts/send_table.py --file result.csv` 发送结果
3. 如果写入多维表格,调用 `python scripts/write_bitable.py --table <table_id> --file result.csv`
## 注意事项
- 发送消息前检查文本长度,超过 1500 字必须分片
- 所有密钥从环境变量读取,禁止写在脚本里
- 数据为空时直接告诉用户,不要假装执行成功
括号里的提示很关键。Agent 是语言模型,它执行任务时的行为高度依赖你写的这些边界条件。你写了"数据为空时必须如实告知",它就真的不会瞎编结果。这是 Skill 开发中最容易忽略、却最能体现专业度的细节。
4.3 脚本怎么和 Agent 协作
SKILL.md 里提到的 Python 脚本,作用是给 Agent 提供"手"——大模型擅长理解和规划,但不擅长稳定地执行精确的 API 调用。脚本负责把那些确定性操作封装好,Agent 只需要决定"什么时候调、传什么参数、怎么解读结果"。
这里有一个设计原则:脚本的输入输出必须严格结构化。你写给 Agent 用的脚本,不是给自己用的工具,接口越简单越好。尽量用命令行参数传参,用 JSON 或 CSV 输出结果,避免交互式输入。因为 Agent 没法和你一样跟脚本对话,它只能通过命令行组装参数、读取输出。
我自己的脚本模板都是固定的一套:argparse 解析参数,结果走 stdout 输出 JSON,错误走 stderr 并给非零退出码。这样 Agent 能清晰地判断脚本是否成功。
5. 实操:一个完整的飞书场景 Skill 从开发到上线
5.1 选一个真实场景:审批汇总 + 表格发送
纸上谈兵没有意义,我们直接做一个能跑的场景。热词里"飞书机器人发送表格""飞书多维表格"出现频率极高,说明这是大家最普遍的需求。所以我们的目标定为:一个 Skill,让用户用一句话触发"统计最近一周审批,并把结果表格发送到指定飞书群"。
这个场景拆解后包含三个动作:
- 拉取审批数据(飞书审批 API)
- 对数据做简单汇总(脚本内处理)
- 把汇总结果作为表格消息发送到群聊(飞书消息 API)
三个动作都可以用 Python 实现,而 SKILL.md 负责告诉 Agent"什么时候用、按什么顺序执行"。这就是前面说的骨骼和血肉的关系。
5.2 核心脚本:获取 token 和发送表格消息
写脚本前先讲一个基础知识:飞书 API 需要 tenant_access_token,这个 token 用 App ID 和 App Secret 换,有效期通常两小时。每次调用前先换 token 是通用做法。下面是一个极简的 token 获取函数:
python复制import os, requests
APP_ID = os.getenv("FEISHU_APP_ID")
APP_SECRET = os.getenv("FEISHU_APP_SECRET")
def get_token():
resp = requests.post(
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": APP_ID, "app_secret": APP_SECRET},
timeout=10,
)
data = resp.json()
if data.get("code") != 0:
raise RuntimeError(f"get token failed: {data}")
return data["tenant_access_token"]
然后是发送表格消息。飞书的"表格消息"有两种实现方式:一种是发富文本消息(post),里面带表格结构;另一种是发消息卡片,用卡片里的表格组件。我实测下来,消息卡片对长内容的展示效果更好,也不容易被截断。简化版本用 post 消息就够了,核心代码如下:
python复制def send_table(chat_id, table_rows, token):
# table_rows: [["姓名", "审批类型", "状态"], ...]
post_content = {
"zh_cn": {
"title": "审批汇总",
"content": []
}
}
# 第一行列头加粗
header = [{"tag": "text", "text": cell} for cell in table_rows[0]]
post_content["zh_cn"]["content"].append(header)
for row in table_rows[1:]:
cells = [{"tag": "text", "text": str(cell)} for cell in row]
post_content["zh_cn"]["content"].append(cells)
body = {
"receive_id": chat_id,
"msg_type": "post",
"content": json.dumps(post_content, ensure_ascii=False),
}
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json; charset=utf-8",
}
resp = requests.post(
"https://open.feishu.cn/open-apis/im/v1/messages",
params={"receive_id_type": "chat_id"},
headers=headers,
json=body,
timeout=10,
)
return resp.json()
这里的 chat_id 是群的唯一标识,可以在飞书群里添加一个"群机器人"后,通过请求 im/v1/chats 接口拿到,也可以在飞书管理后台查看。
5.3 把脚本包装成 Skill
脚本写好后,放到 skills/feishu-approval/scripts/ 下,然后在 SKILL.md 里写清楚调用顺序。关键在于给 Agent 留的操作指引要足够细,包括:
- 默认查询天数是多少(比如 7 天)
- 表头应该包含哪些列
- 结果如何格式化
- 错误时如何反馈
我写完这个 Skill 后的第一轮实测就翻车了:我告诉 Agent "发送上周的审批汇总",它直接把脚本路径当成参数传了。后来我在 SKILL.md 里加了"脚本路径固定,不要修改;只需要传 --days 参数"这样的显式约束,这个问题才消失。这个经验告诉所有写 Skill 的人:LLM 真的很会自由发挥,你必须在文档里把自由发挥的空间堵死。
5.4 在飞书里验证整个链路
Skill 开发完成后,把文件放进 skillsPath 目录,重启 OpenClaw(或者如果版本支持 Skill 热加载,直接触发重载),然后去飞书里对机器人说:"帮我把最近 7 天的审批汇总发到测试群。"
此时观察 OpenClaw 日志,你会看到 Agent 是怎么"思考"的:它有没有匹配到 feishu-approval-summary 这个 Skill?它是先跑了哪个脚本?参数传对没有?这条日志链路就是日后排查问题的地图。实测下来,一个 Skill 从写完到能稳定被触发,通常要调 2~3 轮,主要调的就是 description 的措辞和 SKILL.md 里的指令粒度。
6. 高频问题排查实录:那些让我熬夜的坑
6.1 session file locked (timeout 60000ms) 到底怎么办
热词里那条 agent failed before reply: session file locked (timeout 60000ms) 我太熟了,第一次看到直接懵了。这个报错的本质是:会话文件被锁住了,新的请求等不到锁释放,60 秒后超时失败。
什么情况下会锁住?常见的有三种:
- 你同时给机器人发了多条消息,多个请求并发争用同一个 session 文件。
- 上一个请求还在处理中,你就手动 Ctrl+C 杀掉了 OpenClaw 进程,锁文件没来得及清理。
- 某个 Skill 脚本卡住了,Agent 一直没返回,后续消息全部排队等锁。
排查思路按顺序来:
- 先看是不是并发导致的:同一个时间点只发一条消息,问题消失就说明是并发锁。
- 再看锁文件残留:找到 session 目录下的
.lock文件,手动删掉,重启 OpenClaw。 - 最后看有没有脚本卡死:翻日志,找到上一个会话在调什么脚本,检查脚本是不是在等网络响应超时。
我的根治方案是给 OpenClaw 前面加一层简单的消息队列/串行化,确保同一个 session 的请求严格排队。如果你不想上队列,至少要养成"一次只聊一句"的使用习惯,尤其是在调 Skill 的时候。
6.2 飞书输出容易被截断
热词里"openclaw在飞书输出容易被截断"这个问题,我也遇到。原因很简单:飞书消息有长度限制,长文本、长表格在消息里放不下时会被截断,或者直接发送失败。很多人以为是 OpenClaw 的 bug,其实是消息格式和长度的问题。
我的处理办法是三层兜底:
第一层,分片发送。 在脚本里把输出内容按长度切块,每块控制在 1500 字以内,逐条发送。代码逻辑前面已经给过,就是循环发送。第二层,改用消息卡片。 卡片对长内容的展示比普通文本宽容得多,还支持折叠,适合日报、汇总类内容。第三层,让 Agent 学会总结。 在 SKILL.md 里明确要求"内容过长时先给出结论摘要,再附明细",从源头减少超长输出。
三层都做好之后,被截断的情况基本绝迹。
6.3 权限相关:CLI 权限和接口无权限的排查
热词里"飞书没有 cli 权限"我一开始没看懂,后来结合上下文才明白,这多半是指调用飞书开放接口时返回了权限相关错误。这类问题有一个统一的排查清单:
| 检查项 | 操作 |
|---|---|
| 权限是否已申请 | 开放平台 → 权限管理 → 确认对应 scope 已添加 |
| 版本是否已发布 | 开放平台 → 版本管理与发布 → 创建版本并发布 |
| 应用是否启用 | 确认应用状态不是"停用"或"审核中" |
| token 是否过期 | 检查 tenant_access_token 是否在两小时有效期内 |
| 是否用了错误的 token 类型 | 部分接口要求 user_access_token,不能混用 |
只要这五项都过一遍,90% 的权限报错能解决。剩下 10% 是飞书侧的数据权限问题,比如多维表格的协作者权限没开,API 就算有权限也读不到数据。
6.4 一套通用的分层排查思路
OpenClaw + 飞书 + Skill 这个链路太长,出了问题容易不知道从哪看起。我总结了三个排查层:
- 飞书层:在开放平台的调试工具里直接调 API,验证接口、权限、参数是否正确。如果飞书调试工具里都报错,问题一定在飞书配置。
- OpenClaw 层:看 OpenClaw 日志,确认 Channel 是否连上、Agent 是否收到消息、有没有匹配到 Skill、调用了什么脚本。日志里每条记录都有时间戳,按时间线理一遍,问题位置基本就锁定了。
- 脚本层:单独在终端里运行 Skill 脚本,传同样的参数,看脚本本身能不能跑通。脚本独立能跑通,问题就在 Agent 的指令理解上;脚本独立跑不通,问题就在脚本本身。
这套顺序帮我快速定位了至少十个疑难杂症。记住一个原则:永远先隔离,再谈修复。 不要一上来就改配置,先把问题锁定在某一个环节。
7. 个人体会与扩展思路
踩了这么多坑之后,我最大的体会是:Skill 开发的重点不在写代码,而在写约束。代码是确定性执行,LLM 是概率性理解,你要做的不是在代码里堆功能,而是通过 SKILL.md 让"不确定性"尽可能变成"确定性"。description 写精准一点,指令写死一点,参数写明确一点,Agent 的表现就会稳定很多。
最后分享一个小技巧:我给自己写了一个 reload-skill 的小 Skill,专门负责扫描 skills 目录的变更并重新加载,省得每次改完脚本都要重启 OpenClaw。这个小工具本身也是 Skill 机制的自举——用 Skill 来管理 Skill,体验很神奇,也印证了这套框架最大的价值:它把"给 Agent 造工具"这件事,也变成了 Agent 能干的活。
至于后续扩展,我准备把一些通用场景——比如多维表格查询、日报生成、会议纪要整理——都各做一个规范化的 Skill 包,像 "book to skill" 那样整理成文档,方便直接分享给团队用。Skill 这个生态真正跑起来,靠的不是一个写得很炫的脚本,而是一套清晰、可复用、能让别人也看得懂的标准。希望这篇指南,能让你少走我走过的弯路。
