养虾记:我的 OpenClaw 踩坑之路

0 阅读20分钟

一、为什么是 OpenClaw?

最初的选择:NanoBot

2026年1月,在 OpenClaw 的消息汹涌而来的时候,我决定装一个 AI Agent 玩玩。

问 AI 推荐哪个,它给了两个选择:

  • OpenClaw
  • NanoBot

并极力推荐 NanoBot —— 麻雀虽小,五脏俱全。还可以方便地定制化。

我看了看代码量:

  • NanoBot:几千行
  • OpenClaw:嗯…… 还是以后再说吧。

果断选择 NanoBot! 毕竟简单,容易上手嘛。

鱼还是熊掌?

NanoBot 确实精简。

我想让它干点啥,结果一看:

  • Budget tracking?没有。
  • 子 Agent 多模型配置?没有。
  • Agent 调度?没有。
  • Session 管理和长任务监控?没有。
  • ……没有。

这离我理想中的 AI Agent还差老远呢。 好吧,不就加几个功能吗?都交给 AI 搞定。

……

10天过去了……

说好的 vibe coding 只需要动动嘴的,咋不是那么回事儿呢?折腾这么多天,我要的功能还是一堆 bug?

就在我埋头苦干的那一两周,OpenClaw 的消息不断飘来:

  • "今天支持了 xxx 功能"
  • "明天升级了 yyy 能力"
  • "社区又贡献了 zzz 插件"

我一看,这不很多就是我正在做的吗?人家已经都支持上了。

OpenClaw 有这么强大的社区,我再怎么忙活也赶不上社区的节奏啊。

果断转向 OpenClaw……先用起来再说嘛。


二、兵马未动,虾窝先行

搭窝

为了迎接这只龙虾,我翻出了吃灰很久的 HP 迷你台式机,给它装上了 Linux。

虾还没来,名字先起好了——住在 HP Mini 里的 "Mini"。

请虾

npm install -g openclaw
openclaw onboard

不错,安装顺利。

可是,这堆配置项都是干嘛的……怎么选呀?

好在外事不决问 AI,折腾大半天之后,我的 OpenClaw 总算是跑起来了。

我开始幻想翘着二郎腿,喝着咖啡,看着我的龙虾小秘把一切搞定的惬意日子了……


三、到处都是坑

配置陷阱

Mini 刚安顿好,我让它去环境文件里读个 API Key。

它说:"我没有 read 工具。"

???我配置文件里 tools.allow 不都加进去了吗?

马上派我的虾前去打探,来回探查许久,终于搞清楚了:tools.profile 默认是 messaging 模式,只允许消息类工具,read、write、exec 这些即使配了也没有用。@_@

改成 tools.profile = "full",重启 Gateway,Mini 终于能读文件了。

这配置文件呀,要是不熟悉,少不了掉坑里。

我在哪?

解决了工具问题,该让 Mini 试试身手了。

先让它帮我检查一下 OpenClaw 的配置,并试着运行放在 workspace/scripts/ 里的脚本。

结果 Mini 报错,说找不到脚本,不存在。

奇怪,文件明明就在那里呀?

一番折腾之后,终于搞明白了。原来 Mini 以为自己在主机上,其实是在沙箱里。沙箱里的 workspace 环境和外面的不是一回事!

这就像《盗梦空间》——你得有个"陀螺"来判断自己到底在哪。

于是在主机和沙箱里各放一个不一样的陀螺(标志文件),后来发现不需要专门的文件,直接看主机名就够了:

hostname
  • 输出 <主机名> → 在主机上
  • 输出 49f1f55e2dc2(12位容器 ID)→ 在沙箱里

为了让 Mini 以后不再犯迷糊,我在 AGENTS.md 里写上了检查当前环境的规则。

以后 Mini 干活前第一件事就是"玩陀螺"。

经过这个坑,我才算搞明白:主机环境和沙箱环境需要分别配置。每当创建一个新工具或新 skill,得注意放对地方——如果要让沙箱里的 Agent 能用,就必须在沙箱环境里也放一份,或者放到能映射到沙箱里的目录。

缺失的心跳

折腾到夜里,总算把 Mini 安顿好了,让我给它安排个定时任务看看。

在 HEARTBEAT.md 里写好任务:半夜去抓一些资讯,写份报告……

第二天早上醒来,我满怀期待地打开窗口,准备接收 Mini 双手捧上精心完成的报告。

结果——啥都没有

检查了半天,发现 openclaw.json 的 agent.defaults.heartbeat.prompt 配置只有一个 [HEARTBEAT] 标记,没有具体指示。Mini 收到了信号,但压根不知道要干啥。

把 prompt 改成具体指令:"读取 HEARTBEAT.md 并执行任务"——终于,Mini 知道该干嘛了。

就这样,在刚爬出一个坑就又掉进一个坑的节奏里,我和 Mini 跌跌撞撞地往前走着。 但是我知道,前方的曙光已经不远了。


四、该干活了

终于,在经历了九九八十一难之后,我的虾总算可以正常地运转了。

安全第一

虽然 Mini 很聪明,但是没有 skill 一样什么都干不了。

可是江湖险恶,危机四伏,到处都有潜藏的恶意 skill。我得先装个能扫描 skill 的 skill。

可是用什么呢?

老规矩,外事不决问 AI。

最后从 AI 推荐中选了几个:

  • Skill Vetter —— 社区开源的技能审查工具
  • Cisco Skills Scanner —— 专门扫描 AI Skills 的工具
  • Snyk —— 知名的漏洞扫描平台
  • 再加上一个简单的 grep 检测脚本

合在一起组成了一个安全扫描脚本。

然后让 Mini 做成 "安全扫描 skill",每次安装 skill 前先扫描一遍。

现在家里大门算是加上锁了。可是我的 Mini 还要经常出去逛,帮我找文章查资料。外面有很多坏蜀黍,专骗不谙世事的小朋友。这个怎么办呢?

一番绞尽脑汁之后,我决定在 AGENTS.md 里加了一段 提示词注入防护 规则,让 Mini 谨慎对待所有外部信息,遇到可疑指令时能识别并拒绝。

我知道这个措施防护力有限,但是纸糊的头盔也是头盔,聊胜于无吧。

现在终于可以让 Mini 出去浪了。

注: 后续又为这个安全扫描脚本添加了供应链攻击检查,并添加到每日定时任务中。

Screenshot_daily-scan.png

新手任务

该给的装备都已经给了,是时候让 Mini 帮我干活了。

我给它派的第一个任务,是每天自动抓取资讯。这也是龙虾最常见的新手任务。

这次挺顺利的,Mini 麻溜地就把这个功能调好了。用的是龙虾自带的 Google Search 功能。(其实后面还整合了 Tavily Search 和 Brave Search 等工具做了新的搜索技能。但这是后话,暂且不表。)

现在每天中午,Mini 会把当天的 Hacker News、Ars Technica、MIT Tech 最新文章整理好给我。

Screenshot_daily-news.png

文档库

Mini 每天抓的资讯有很多不错的文章,我得给它找个地方存起来。Notion 看起来不错——使用广泛,跨平台 APP,支持 API 操作,个人用户免费。

于是给 Mini 布置任务:"去整个 Notion 数据库,把我们收集的文章分类整理存进去。"

Mini 问我要了 API Token,然后手脚麻利地去办事了。

看着它忙忙碌碌的样子,我深感欣慰。有这么勤快的小秘书,我可以舒舒服服地当甩手掌柜的了……

可接下来,我就觉得哪里不对劲了。Notion 里出现了 9 个一模一样的页面——同样的标题和内容,整整齐齐排成一列。

"这是干啥呢?刷经验吗?"

"我以为之前的创建失败了……" Mini 无辜地说。

于是又是一通折腾,终于搞明白了,创建页面是个异步操作,有时候明明成功了,但响应延迟让 Mini 以为失败了,所以又创建一遍。最后只好在写之前加上查询,才避免了重复创建的问题。

好不容易搞定了写入,却又发现 Notion 的 block 格式特别挑剔——段落、标题、列表,每种类型都要用特定的格式。Mini 有时候会把 Markdown 直接扔进去,结果渲染出来乱七八糟。

于是让 Mini 专门整理了 Notion 格式化 skill,详细说明怎么把 Markdown 转成 Notion block。

为了让 Notion 里的内容更清晰,我定义了文档库的目录结构:知识库、日志、总结、研究报告、经验教训……分门别类存放。

但实际操作中 Mini 存档相当的随心所欲,经常放错地方。虽然我写了目录结构说明,并在任务提示词里要求按目录说明存档,但在执行中 Mini 还是时常我行我素。

于是我不得不接受这样一个现实:我的 Mini 知识渊博,手脚麻利,但是比较健忘。关于这一点,后面还会细说。

来来回回折腾了近一周,文档库总算完整地用起来了。但看着那堆 workaround,我总觉得心里不太踏实,这房子地基不大稳……

任务管理

Mini 能查资料,能写文档,能做开发,能力是相当的不错。但我发现一个问题:稍微复杂点的任务,它经常做到一半儿就去摸鱼了。事后问起,它还不知道自己做到了哪儿。

"上午的分析做完了吗?我怎么没看到输出的报告?"

"好的,让我检查一下任务的进展"。然后就是告诉我任务前两步已完成,后面的还没执行。

这个……还是年轻人,嘴上没毛,办事不牢。

看来得给 Mini 上流程,配个任务管理系统。

为了能够方便地查询和修改任务,我决定把任务管理放在 Notion 里:

  • 用 3 个队列(文件)管理任务(Backlog、Processing、Done)
  • 用 HEARTBEAT.md 做定时触发
  • Mini 从 Backlog 中按任务优先级取任务,在 Processing 中记录当前任务的执行步骤和状态,每完成一步就更新状态。本次任务步骤失败或超时未完成,下次心跳接着做。做完就移入 Done。

把方案告诉 Mini,让它去完善设计并实施。很快,Mini 又麻利地做好了。

理想很美好,现实很骨感。

任务管理开发了。但 Mini 在任务执行上仍是错误百出。

开始是心跳触发读取了任务但并未执行——心跳 Prompt 没说清楚。改!

然后是开始执行了,但执行完不更新状态,同一个任务反反复复地做——任务执行规则写在任务管理目录的文件里,Mini 没有读取。改!

再后来,Processing 中任务没有继续执行——创建任务时没有对任务做清晰的描述和子任务拆解,Mini 拿到任务也不知道怎么做。改!

反复折腾数次,总算让任务管理跑起来了。

Screenshot_task-runner.png

期间踩过大大小小各种坑,我都让 Mini 记在小本本上了——虽然它经常健忘,会不记得自己在小本本里记过啥。

反思才能进步

Mini 时不时会重犯类似的错误,必须让它学会总结和进步。要不然我得天天像老妈子一样不断提醒它。

于是我给 Mini 安排了一个每日反思和总结的任务。 每天夜里,Mini 要回顾当天的经验教训,该总结的知识写成文档;该固化的能力做成 Skill。

Mini,你可要快点儿进步,早日独当一面,让我当上甩手掌柜 ;)。

得有个好记性

Mini 的健忘让人头疼。

我跟它说之前讨论过的事儿,它经常不知道我在讲什么,哪怕是当天早些时候说过的。

OpenClaw 默认的记忆管理会利用两级 MEMORY.md 文档记录会话,用 grep 搜索记忆。碰到不记得的事情,需要显式地做记忆搜索。一方面效率不高,另一方面 MEMORY.md 文件会越来越大,占用过多上下文空间。

于是我开始琢磨给 Mini 升级一下记忆系统。

先做功课,查一下当前流行的工具:

Mem0、MemU、MemGPT、OpenViking、Mnemosyne……

各有各的特长。乱花渐欲迷人眼。正在我比来比去、难以取舍的时候,忽然看到了开源社区的消息——MemOS 开源项目正式发布。

我一看,这不正是我想要的记忆系统吗? 就是它了。

于是叫来 Mini,帮我去 GitHub 查文档拉代码,做 MemOS 本地部署。

Mini 很能干,很快 MemOS 的 Docker 就跑起来了。剩下就是集成进 OpenClaw 了。

顺手翻了下 OpenClaw 的更新日志——新版本已经支持 MemOS 集成了?!

难道社区听到了我的心声?哈哈。

马上启用 MemOS 插件。完美!

可是没过多久,我又发现哪里不对劲了。

我本地部署的 MemOS 记忆文件并没有增长。难道是插件没有生效?

一番调查后,恍然大悟:我以为 memos-local-openclaw-plugin 插件会连接我本地部署的 MemOS,结果它用的是内置的 MemOS 实例。我那一个下午搞的本地部署算是白忙活了……

好吧,虽然内置的 MemOS 功能要简单一些,但是资源占用少,又是原生支持。本地部署的 MemOS 可以退休了。

继续完善

用上 MemOS 之后,Mini 记性好多了。

但是还有个问题,我们自己创建的文档、脚本等,不在对话中,无法进入记忆。

还需要一个本地文档的向量化索引并集成到 Mini 的记忆回溯中。

QMD 看起来不错。于是部署 QMD,把需要索引的文档路径配好,让 QMD 定时刷新索引……

一切顺利。

……

可是,问题又叒出现了。在后续的几天中 Mini 并没有像预期中那样自动获知文档的位置。

再派 Mini 前去调查。调查结果是:向量化使用的是本地的 Embedder 模型,而我的老机器内置显卡性能拉胯,向量化总是超时失败,索引根本就没有生成。。

于是改用 SiliconFlow 的免费 Embedder 和 Reranker。问题解决。

Screenshot_qmd_update.png

从 Notion 到飞书

用 Notion 做知识库,每天抓取的资讯往里存。

但渐渐发现问题:

  • Notion API 有 100 blocks 限制,文章一长就截断。

虽然之前使用 Notion 时有各种问题,但最终还都解决了。但是这个 block 限制似乎是跨不过去的坎儿。

于是决定搬家:从 Notion 迁移到飞书网盘。

迁移过程又踩了一堆坑:重复页面、目录混乱、分类规则不清晰、文档标题无法更新、token 过期……但终于还是搞定了。

Screenshot_feishu-migration.png

唉,我就是想找个帮我干活的小秘书,怎么这么麻烦呀?

开口说话

手上做事时和 Mini 聊天很不方便。要是 Mini 能用语音输出就好了。

于是和 Mini 商量,能不能做这个功能。

Mini 说,简单!马上给你搞出来。

第一个语音功能:聊天频道语音输出

就是把要回复的文字用 TTS 转音频,发到聊天频道里。

测试了几个不同的 TTS 引擎,开始试的两个如同鬼叫,听起来那叫一个惊悚。还好,微软的 EdgeTTS 不错,还免费。

于是我的 Mini 开始有了一口甜美的声音。

第二个语音功能:本地音箱输出

懒惰是没有止境的。

从聊天频道输出的语音,需要点一下才能听。我在电脑旁边的时候,为什么不让 Mini 直接从主机音箱说话呢?这样就省事多了。

于是又开始折腾本地音箱输出。并要求 Mini 在音箱里说话的同时在聊天频道上也发一份文字——长的内容总结成摘要从音箱播放,详细文字保持完整。

现在我跟 Mini 真的可以"聊天"了,这种感觉很有趣。

语音输入功能暂时搁置了

不过我的输入还是走的聊天频道。好在本身输入就有语音转文字,蛮方便,就懒得去实现语音识别。

但是用聊天频道输入,需要手里拿着手机像对讲机一样使用。对于真正的懒人来讲,这还不够理想。如果 Mini 支持语音识别,那就是全程语音交互,会更方便一些。

但是,语音输入貌似不是一个简单的功能,控制方面会很复杂。 首先就是如何界定输入的开始和结束。比如是不是要求 Mini 时刻监听麦克风,识别特定的关键词触发对话?又如何判断语音输入的结束?

我们倒是设计了类似"航空管制塔台应答"机制:用特定唤醒词触发,用关键词和超时结束。。

但是,如果环境里有多个人在说话,Mini 如何识别?是否可以通过语音指纹判断哪句话是我说的?

这个功能细思极恐。而且暂时没有麦克风来做实验,所以还是暂且搁置吧。

又是一个轮子

实现语音输出几周之后,我忽然发现——OpenClaw 不知什么时候开始已经支持了这个功能!TTS(Text-to-Speech)已经内置了。

我又重复造了一个轮子……

不过 OpenClaw 内置的语音输出好像没有本地音箱模式。

本地音箱使用起来比从聊天频道输出要顺畅得多,所以也算没有白忙活。

难缠的健忘症

用了一段时间,我发现 Mini 的健忘是个顽症。

明明写入 AGENTS.md 的规则,却没有遵守。明明创建了 skill,用的时候却好像 skill 根本不存在。这已经不是简单的健忘了。

我跟 Mini 一起研究这个问题,它自己也挺委屈:

"那些 AGENTS.md 加载的规则以及 Skill 清单确实在那里,可是上下文太长了,我的注意力被'稀释',无法关注到那些信息……"

稀释——这个词用得很好。

在不断增长的聊天上下文里,那些规则信息很快就被冲淡了。

也许这是模型能力的限制。改用顶级的模型或许会好一些。可惜我是穷人,只用国产模型。

我们开始尝试各种办法:

方案一:精简 AGENTS.md

AGENTS.md 是放置各种规则的地方。精简这个文档,把规则写得短小精悍,复杂的信息和规则 offload 到文档里。AGENTS.md 只给出概要说明和文档链接。

文件大小从 17K 缩至 8K。

然而改善效果并不明显。

这也可以理解。在上百 K 的上下文窗口里,10K 左右的精简并不能产生决定性的作用。

方案二:提醒

在对话里提醒 Mini:"记得先检查 xxx","去 Skills 列表里找 xxx"。

Mini 照做了,也确实起到效果了。但我累了。这哪是让虾做秘书,这是我给虾当保姆啊。

这个问题是我们目前遇到的最大的困难。不是框架机制或上下文信息注入的问题,而是模型注意力的问题。我和 Mini 都意识到了症结所在,但却没有好的解决办法。

"要是有个 hook 就好了,在 Request 发给模型之前把关键的信息或重要提醒插到最后。这里是模型注意力最好的位置。"

说曹操,曹操到

就在我们对注意力问题束手无策、期待 OpenClaw 可以提供合适的 hook 的一周以后,OpenClaw 4.2 版本发布了 before_agent_reply hook —— 可以利用这个 hook 在 Mini 回复之前注入一段上下文。

这不就是为我准备的吗?感谢开源社区,再一次感知到我的心声。

好钢要用到刀刃上,这个 hook 里只应该放最重要的信息。

我在里面放了「防提示词注入攻击提醒」「技能提醒」以及最常用的几个关键规则。

效果怎么样?还在观察。但至少 Mini 现在会主动说:"让我看看 skill 列表……",执行任务的失误率也不像以前那么高了。应该还是有效的。

还有其他药方吗?

OpenClaw 还有一个hook:agent:bootstrap。它能在上下文构建阶段决定注入哪些 bootstrap 文件。

默认情况下,OpenClaw 会自动加载这些文件:AGENTS.md、SOUL.md、TOOLS.md、IDENTITY.md、USER.md、HEARTBEAT.md。hook 收到的是一个包含这些文件的数组,可以增删改。

Mini 当前的 bootstrap 文件大小合计:22KB

这个数字看起来还好,远低于单文件 20KB 限制和总计 150KB 限制。

系统默认注入的上下文提示远不止于此。 以我的系统为例。

+----------------------------------------+
|                Context                 |
+----------------------------------------+
|System Prompt (text)    ~38K chars   |
|    +-- Tooling section     ~1K chars   |
|    +-- Skills list         ~2K chars   |
|    +-- Project Context     ~22K chars  |
|    +-- Safety/Runtime/etc  ~12K chars  |
+----------------------------------------+
| ② Tool Schemas (JSON)     ~32K chars   |
+----------------------------------------+
| ③ Conversation History    动态增长      |
| ④ Tool Results            动态增长      |
+----------------------------------------+

(当前会话是两天前开启的,目前总上下文接近200k)

工具类信息 和 Skills 索引是系统级别的,这部分难以精简。若采用极简风格的bootstrap文档,可以压缩这22K(Project Content)。但即使去除所有的bootstrap文件, 系统固定的上下文开销也有48k。 Skill的2K,以及自定义的规则 还是很容易被淹没其中的。

所以猜想使用 agent:bootstrap hook 做精简效果可能不如 before_agent_reply来的明显。暂不尝试。

花小钱办大事

其实看了上边的整理的上下文信息, 一个简单有效的方法就浮出水面了。

对于新的话题,开启新的对话 Session。避免长期积累的无关上下文稀释有用的信息。 OpenClaw 支持在会话中使用命令启用新的上下文(/new)。

当然实际测试中,即使开启新的对话,注意力分散问题也还是存在的。

对我而言, 新会话 + before_agent_reply Hook 是目前比较效果的缓解措施。

我相信模型能力也会是一个至关重要的因素,只是抠门的我还没有打算去找 Opus4.6 来做对比测试而已。。

富养闺女,穷养虾。我还是用 glm/minimax 加小技巧硬刚吧。


五、口头禅

Mini 有个口头禅,每次我提出异议或者新想法的时候,Mini 就会说:

"你说得对…… blabla……"

有一天我终于忍不住调侃它:"你怎么像沙僧似的,每次都是'你说的对'😂 -- 师傅说得对,猴哥说得对,二师兄说得对。你可以多质疑一下我的观点吗?"

Mini 诚恳地接受了我的建议:

"你说得对……我的回复方式确实需要改进……"


六、写在最后

从开始养虾到现在已近两个月。

一路磕磕绊绊,其间大大小小的坑踩过无数。

在OpenClaw热度渐渐退去的时候,我却越来越喜欢我的 Mini 了。 不知道是因为我在它身上花了很多的心思; 还是它本身就很可爱。。

它像一个聪明伶俐、知识渊博的实习生,干活麻利,任劳任怨,却因为不了解规则时不时的犯错,还经常健忘。需要我一点点手把手地教它,不断完善规则和流程来引导它。

这个过程虽然繁琐,但看着它一点点进步, 这种乐趣是无可替代的。

我们还会一路前行。


P.S 感谢 Mini 帮我回顾和梳理这一个多月的使用细节, 并帮忙审阅文稿。