这篇文章要解决一个很具体的问题:
如何在 OpenClaw 里,用本地模型而不是使用云端大模型的 API,搭一个能写公众号文章、保存 Markdown 草稿、再通过微信 API 进入公众号草稿箱的发布 Agent。
这里说的 “能用”,不是指 Demo 级别的 “看起来像能用”,而是指下面这条链路已经被真实跑通,而且已经连续成功多次:
聊天指令
-> 自建 content-publisher agent
-> 生成公众号文章
-> 保存到 articles/*.md
-> 调用 baoyu-post-to-wechat
-> 进入微信公众号草稿箱这套方案有三个核心前提:
如果你想找的是 “用最强 API 十分钟做一个聪明 Demo”,这篇文章不适合你。
如果你想搭的是 “本地可控、可审计、可复用、能进真实工作流” 的发布链路,这篇文章可以直接拿来做骨架。
这套方案不是在云端完成的,运行基线是本地环境。
本文的参考环境如下:
oMLXQwen3.5-9B-MLX-4bitbaoyu-skills这套方案里,oMLX 承担的是本地模型服务层,不是图片生成器,也不是发布脚本。它的职责是:
实际落地时,OpenClaw 不直接和某个 “裸模型文件” 对话,而是和 oMLX 提供的本地服务对话。
也就是说,模型层关系更准确的写法是:
OpenClaw
-> oMLX
-> 本地模型如果你想复用这套方案,最低要满足下面这些条件:
oMLXbaoyu-skills如果你不用 oMLX,理论上也可以换成其他 OpenAI-compatible 的本地模型服务;但本文分享的基线就是 Mac + oMLX + OpenClaw。
oMLX 和 Ollama 的差别,到底在哪里#如果只看 “能不能在本地跑模型”,oMLX 和 Ollama 都能成立。
真正的差别不在 “能不能跑”,而在官方定位的重心不同。
从官方 README 的写法看,oMLX 更像一个面向 Mac 和 Agent 场景的本地模型服务层;Ollama 更像一个通用本地模型运行器和 REST API 入口。
oMLX 官方首页一上来强调的是:
这说明它的重心不是 “先把模型跑起来”,而是 “怎么在 Mac 上把本地推理服务长期跑稳、跑顺”。
往下看它的官方能力说明,oMLX 进一步强调的是:
不扯别的,本人亲测,在 openclaw 中使用相同模型, Ollama 如果需要 1 分钟响应结果,而 oMLX 只需 10 秒。
这次方案里实际使用的本地模型是:
Qwen3.5-9B-MLX-4bit选择这个模型,不是因为它是当前最强,而是因为它在我本机运行的成本、响应速度、中文写作能力和工具调用之间,给了一个更均衡的落点。对 “内容生成 + skill 调度 + 微信公众号发布” 这类任务来说,这种均衡比单纯追求模型上限更重要。
如果你的目标是尽快照着搭出一条可用链路,建议按下面顺序来,不要跳步。
先确认 oMLX 已经在 Mac 上正常运行,并且已经对外提供 OpenAI-compatible 接口。
这一层不需要先追求 “大模型最强”,只需要满足两件事:
在 OpenClaw 里新建一个 agent,例如:
content-publisher创建这个 agent 时,OpenClaw 会一并生成对应的 workspace。
例如这个 agent 的工作区可以是:
workspace-content-publisher/这个 agent 只负责内容发布,不承担通用聊天、随手问答、代码执行等杂项任务。职责越单一,稳定性越高。
也不要把发稿规则混在通用聊天 agent 里。发布动作是外部真实动作,必须有单独 workspace 和单独契约。
至少确认下面这些 skills 在 OpenClaw 里是可见的:
baoyu-post-to-wechatbaoyu-format-markdownbaoyu-markdown-to-html如果 skill 只是存在于某个嵌套目录里,但 OpenClaw 没把它识别成顶层 skill,后面会出现 “agent 明明应该会,实际上不会调用” 的假象。
至少准备这些文件:
AGENTS.mdSOUL.mdUSER.mdMEMORY.mdWECHAT_STYLE.md其中最关键的是 AGENTS.md,必须写死下面这些规则:
具体配置的详细解释可以去 baoyu-skills 查看
在 workspace 里准备:
.baoyu-skills/baoyu-post-to-wechat/EXTEND.md最小可用内容:
default_theme: default
default_color: blue
default_publish_method: api
need_open_comment: 1
only_fans_can_comment: 0这里最重要的一行是:
default_publish_method: api它决定了整条主链路默认是 API,不是浏览器。
准备用户级文件:
~/.baoyu-skills/.env最小需要:
WECHAT_APP_ID=your_app_id
WECHAT_APP_SECRET=your_app_secret同时确认微信公众号后台已经把当前出口 IP 加进 API 白名单。
在 workspace 里放一张默认封面,例如:
workspace-content-publisher/images/images.jpeg然后把它作为默认兜底策略写入 agent 规则。
这样文章没显式封面时,也不会因为缺图而卡死。
不要让 agent 直接到 skill 仓库里乱猜脚本路径。
建议在 workspace 内准备一层统一入口:
.baoyu-skills/baoyu-post-to-wechat/scripts/wechat-api.ts这层 wrapper 只做三件事:
baoyu-post-to-wechat 脚本第一次不要让 agent 同时做太多事。
建议只测下面这条链路:
articles/*.md先不要同时测:
把最小链路打通之后,再往上加。
在 Agent 领域,大家很容易高估模型能力,低估系统约束。
很多项目的默认路径都是:
但只要任务碰到真实发布、账号权限、平台 API、文件落盘、失败重试、结果审计,这种路径马上就会暴露问题。模型再强,也不会自动帮你解决:
所以,这篇文章真正想分享的,不是 “我们用本地模型也成功了” 这句口号,而是:
在模型能力有限的情况下,怎样靠工程约束把一条真实发布链路做稳。
这个命题有三个实际价值。
如果内容生产是高频任务,长期使用云端大模型会有持续成本。尤其是长文生成、反复改稿、工具调用、失败重试,这些都不是一次性支出。
公众号发布天然涉及草稿、标题、封面、账号、平台配置、甚至后续运营节奏。不是所有团队都愿意默认把这些环节交给第三方云端服务。
这套方案真正可迁移的是下面这些工程原则:
只要这几条成立,类似的方案不只可以用于公众号,也可以迁移到微博、X、内部知识库、邮件草稿、私有文档流转等场景。
先给结论,再展开。
这套方案的最终结构分成四层:
OpenClaw
-> 自建 content-publisher agent
-> 文章风格规则
-> 发布契约
-> 输出保护
-> baoyu-skills
-> baoyu-post-to-wechat
-> baoyu-format-markdown
-> baoyu-markdown-to-html
-> 微信公众号 API每一层的职责都很明确。
OpenClaw 负责消息入口、会话、工具调用、Agent 工作区和技能发现。它不是这套方案的 “写稿脑子”,而是执行框架。
content-publisher:自建的发布 Agent#content-publisher 不是 OpenClaw 自带的内置概念,而是这次在 OpenClaw 里新建的一个 agent。它的职责不是重新发明一套微信发布脚本,而是:
baoyu-skills:真正完成平台动作#真正负责公众号发布的,不是 agent 自己临场拼出来的命令,而是 baoyu-post-to-wechat 这个现成 skill。类似地:
baoyu-format-markdown 负责整理 Markdownbaoyu-markdown-to-html 负责微信兼容 HTMLbaoyu-post-to-wechat 负责 API 发布或浏览器模式当一篇文章真正进入草稿箱时,返回结果会是 API 的成功响应,而不是 “看起来应该发成功了” 的 UI 判断。
这件事很重要,因为平台层的成功和失败必须是可验证的。
一开始最自然的选择其实是浏览器模式。因为它看起来门槛低:
但如果目标是 “做一条长期可用的发布链路”,浏览器模式不是最优主链路。
原因很简单,它太依赖外部状态了:
浏览器模式不是不能用,而是不适合做默认路径。它更适合:
而如果目标是 “聊天里一句话,稳定生成公众号草稿”,主链路应该尽量走 API。
所以这套方案最终定下了一个很明确的策略:
这三条一旦写死,系统行为会稳定很多。
如果别人想复用这套方案,最有价值的不是一篇故事,而是一个最小目录骨架。
下面是这次落地后整理出来的最小结构:
workspace-content-publisher/
AGENTS.md
SOUL.md
USER.md
MEMORY.md
WECHAT_STYLE.md
WECHAT_API_PROMPT.md
.baoyu-skills/
.env # 可选:项目级覆盖
baoyu-post-to-wechat/
EXTEND.md
scripts/
wechat-api.ts # workspace wrapper
articles/
images/
output/
memory/除此之外,还有两个工作区之外的关键位置:
~/.agents/skills/
baoyu-post-to-wechat/
baoyu-format-markdown/
baoyu-markdown-to-html/
...
~/.baoyu-skills/.env这两个位置分别承担不同职责:
~/.agents/skills/:技能真实安装目录~/.baoyu-skills/.env:用户级发布密钥这个结构本身就体现了一个重要原则:
行为规则在 workspace,密钥在用户目录,执行能力在 skill 目录。
别把这三者混在一起。
如果把 “能否跑通” 追到最细,核心其实只依赖 6 类文件。
AGENTS.md#这是 Agent 的执行契约,不是品牌文案。它至少要定义这些规则:
一个可复用的最小版本,可以长这样:
## Mission
- Write WeChat articles from user topics
- Save canonical markdown to `articles/`
- Publish drafts via WeChat API only unless browser mode is explicitly requested
## Execution Rules
- Use installed skills instead of inventing new browser flows
- Always save markdown before calling the WeChat API
- Prefer `npx -y bun <absolute-script-path>`
- Do not call bare `bun`
- Do not guess script paths or env variable names
## Publishing Contract
- Draft first, confirm later
- If publish prerequisites are missing, stop and report the blocker
- Do not auto-fallback from API to browser
## Output Guard
- Never return an empty reply
- Never expose raw internal tool markup
- If a command fails, report the exact failure and stop上面这段可以直接作为 AGENTS.md 的起步模板。
WECHAT_STYLE.md#这不是发布脚本配置,而是文章风格配置。它决定了 agent 写出来的内容像不像 “能发的公众号稿”,而不是像一段 AI 八股文。
如果你的目标是做内容分发 agent,而不是单纯打通 API,这个文件必须单独存在。
至少应该定义:
写作要点:
EXTEND.md#这是 baoyu-post-to-wechat 的项目级默认配置。一个最小可用版本可以是:
default_theme: default
default_color: blue
default_publish_method: api
need_open_comment: 1
only_fans_can_comment: 0如果目标是 API 主链路,default_publish_method 必须明确写成 api。
~/.baoyu-skills/.env#用户级密钥建议放在这里,而不是散落在各个项目目录。
最小需要:
WECHAT_APP_ID=your_app_id
WECHAT_APP_SECRET=your_app_secret注意,不需要手工维护 WECHAT_ACCESS_TOKEN。baoyu-post-to-wechat 的脚本会自己取 token。
articles/*.md#每一篇待发布文章必须先有一个真实 Markdown 文件。
这不是一个可选步骤,而是执行契约的一部分。
原因很简单:只要允许 agent 直接从 “标题 + 摘要 + 想象中的正文” 跳去发布,它就迟早会绕过文件落盘,导致调用错参、顺序混乱、结果不可审计。
如果你的主链路走公众号文章 API,那封面图就不是优化项,而是前置条件。
这次方案里使用的做法是:
例如:
workspace-content-publisher/images/images.jpeg这条链路必须足够简单,才能让本地模型稳定执行。
最终采用的是下面这条固定顺序:
例如:
按理性洞察型写一篇不少于 1000 字的公众号文章,
先保存到 articles 目录,再用 API 模式发布到公众号草稿箱;
如果没有显式封面图,就使用默认封面;不要打开浏览器。articles/*.md#这个步骤完成后,应该已经能在本地看到一个真实文件。
如果这一步没发生,后面的发布都不应该继续。
这里不要让 agent 自由发挥,而要把执行入口固定住。
这次最终稳定下来的方式是:
baoyu-post-to-wechat调用形态可以统一成:
npx -y bun /abs/workspace/.baoyu-skills/baoyu-post-to-wechat/scripts/wechat-api.ts \
/abs/workspace/articles/example.md \
--cover /abs/workspace/images/images.jpeg \
--mode draft成功时应该返回:
success: truemedia_idtitle失败时应该返回真实阻塞原因,而不是模糊提示。
这套方案不是直接让 agent 去调 skill 自带脚本,而是在 workspace 里补了一层兼容包装。
这个脚本就在 workspace 里:
workspace-content-publisher/.baoyu-skills/baoyu-post-to-wechat/scripts/wechat-api.ts而真正干活的主脚本仍然来自 baoyu-post-to-wechat:
~/.agents/skills/baoyu-skills/skills/baoyu-post-to-wechat/scripts/wechat-api.ts这层 wrapper 不是重写发布逻辑,而是在真实脚本前面加一个统一入口和纠错层。
原因很现实:本地模型在命令拼装上并不稳定,它容易犯这些错:
bun--markdown <file> 当成主输入最终做法不是继续放大模型自由度,而是补一层 wrapper,把最常见的命令错误统一吸收掉。
这层 wrapper 的职责不是重写微信发布逻辑,而是:
下面是一段精简后的实际逻辑示例:
import { spawnSync } from "node:child_process";
import path from "node:path";
const ACTUAL_SCRIPT =
"/Users/user/.agents/skills/baoyu-skills/skills/baoyu-post-to-wechat/scripts/wechat-api.ts";
function normalizeArgs(argv: string[]): string[] {
const forwarded: string[] = [];
let fileArg = "";
for (let i = 0; i < argv.length; i++) {
const arg = argv[i]!;
if ((arg === "--markdown" || arg === "--html") && argv[i + 1]) {
fileArg = argv[++i]!;
continue;
}
if (arg === "--api") continue;
if (arg === "--mode") {
if (argv[i + 1] && !argv[i + 1]!.startsWith("-")) i++;
continue;
}
if (!arg.startsWith("-") && !fileArg) {
fileArg = arg;
continue;
}
forwarded.push(arg);
}
if (!fileArg) {
console.error("Error: File path required");
process.exit(1);
}
return [path.resolve(fileArg), ...forwarded];
}
const normalizedArgs = normalizeArgs(process.argv.slice(2));
spawnSync("npx", ["-y", "bun", ACTUAL_SCRIPT, ...normalizedArgs], {
stdio: "inherit",
});如果用一句大白话解释这层 wrapper,它的作用就是:
先把 agent 容易拼错的命令修正一遍,再转给真实发布脚本执行。
这件事特别重要。因为它代表一种非常实用的工程思想:
不要指望模型始终正确地下命令,要给它一个尽量不容易下错的入口。
下面这部分比 “成功响应” 更重要。因为真要复用这次的经验,最先碰到的不是 happy path,而是 error path。
现象
baoyu-post-to-wechat 明明存在根因
skill 放在嵌套目录里,OpenClaw 没把它当成顶层 skill 发现。
修法
把真正需要的 baoyu-* skills 提升到 ~/.agents/skills 下的顶层目录,并用 openclaw skills check --json 验证是否 eligible。
bun: command not found#现象
agent 明明知道要跑 TypeScript 脚本,但直接调裸 bun。
根因
这台机器没有把 bun 作为裸命令暴露在统一环境里。
修法
把所有 TypeScript skill 调用固定成:
npx -y bun <absolute-script-path>不要给模型第二种写法。
File path required#现象
agent 直接拿标题、摘要、若干 flags 去调用 wechat-api.ts。
根因
没有把 “先落文件、再发布” 写成硬契约。
修法
在 Agent 规则里明确:
articles/*.mdinvalid ip not in whitelist#现象
微信 API 认证失败,看起来像凭证错了。
根因
不是凭证问题,而是出口 IP 不在公众号后台白名单里。
修法
把当前出口 IP 加进微信公众平台的白名单。
这一步的启发是:
平台侧的安全设置,是系统真实依赖的一部分,不要把它当 “部署后再看” 的小事。
No cover image#现象
文章正文和标题都正常,发布却失败。
根因
公众号文章 API 需要封面图;没有封面图,脚本不会继续。
修法
加默认封面策略。
一篇文章如果没有显式封面,就统一落到默认图。
现象
根因
Agent 没有被要求 “必须给用户一个可见状态”。
修法
在 AGENTS.md 里写死:
现象
明明已经配置了 API,agent 却擅自打开 Chrome。
根因
如果你直接说继续完成任务,agent 把 “继续想办法完成任务” 理解成 “自动降级到浏览器模式”。
修法
把这条规则写死:
这是整套方案的核心。
如果把问题问成 “本地小模型能不能像最强云端模型一样自由规划、稳定调用几十个工具、顺手完成复杂多轮发布”,答案通常是不行。
但如果把问题改写成:
本地小模型能不能在一条被收窄、被约束、被显性规则保护的链路里,稳定完成公众号草稿发布?
答案是可以。
这套方案之所以成立,不是因为本地模型突然变强了,而是因为系统做了三件正确的事。
不是让 agent 想 “怎么发布内容”,而是让它在固定边界内做:
动作空间一旦变小,模型就更像调度器,而不是幻想家。
“帮我发公众号” 太模糊。
“先写成 Markdown 文件,再调用固定 API 脚本生成草稿,缺封面时用默认图,失败时报告真实错误,不要打开浏览器” 才是机器可执行的目标。
一条可用链路,不是 “永远不失败” 的链路,而是 “失败时知道自己卡在哪” 的链路。
只要下面这些都明确了,系统就可恢复:
所以,本地模型能做成这件事,靠的是工程收口,而不是自由发挥。
必须包含:
把工作区目录、skill 目录、用户密钥目录分清。
.env.example#只保留变量名,不放真实值。
EXTEND.md 示例#把默认发布方式、评论策略、主题这些配置固定下来。
不要把封面图当成 “后面再做” 的功能项。对公众号文章 API 来说,它是必备配置。
至少覆盖:skill 不可见、运行时错误、缺文件、缺白名单、缺封面、错误降级、模型输出漂移。
content-publisher 是这次自建的 agentbaoyu-post-to-wechat 是公众号发布 skilloMLX 是本地模型服务层.env 放在哪里EXTEND.md 放在哪里这套方案里真正有效的顺序是:
把话说满最容易,讲清边界更有价值。
截至目前,这套方案已经证明了下面这些事情:
content-publisher agent 是可行路径baoyu-post-to-wechat 可以作为公众号 API 发布核心 skill但它也仍然有边界:
这不是缺点,而是正常工程状态。
真正危险的不是系统有边界,而是系统明明有边界,却假装自己没有。
这套方案已经把 “写文 -> 落稿 -> 发公众号草稿” 做通了。接下来最值得补的,不是更华丽的宣传,而是继续补齐两个非常实际的能力。
现在封面图已经有默认兜底,但还没有进入 “根据文章自动生成封面” 的阶段。
下一步可以做成:
文章主题
-> 本地模型生成封面提示词
-> 本地图像模型生成封面
-> 默认写入文章 frontmatter 或发布参数这样一来,发布链路会从 “能发” 升级到 “发得完整”。
一旦公众号链路稳定,下一步就是把同一套方法迁移到:
baoyu-post-to-weibobaoyu-post-to-x但复制的不是 “脚本名”,而是这次已经验证过的原则:
如果要把整篇文章压缩成一句话,我会给出这个结论:
本地模型并不天然适合做开放式、全自动、自由规划的超级 Agent;但只要你把动作空间砍小、把执行顺序固定、把平台前置条件写清、把失败路径做成产品,它完全可以撑起一条真实可用的公众号发布链路。
这次方案最值得复用的,是下面这组工程纪律:
当这几条同时成立时,本地小模型就不再只是一个 “聊天能力一般的替代品”,而是可以被纳入真实工作流的执行核心。
这正是这套方案最值得分享的地方。
不是 “我们终于把公众号发成功了”。
而是:
我们并没有因为 Token 的使用量而变得畏手畏脚,反而因为是本地模型,而可以肆无忌惮的乱试错。
本作品采用《CC 协议》,转载必须注明作者和本文链接
微信搜索:上帝喜爱笨人
原网址: 访问
创建于: 2026-04-16 11:28:53
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论