OpenClaw 博客流水线 v2.7 完整迭代:从 11:31 到 20:20 的 9 小时
记录一个完整的 blog-pipeline 迭代周期:模型降级、路由规则、可观测性增强

背景:从 11:31 到 20:20 的 9 小时迭代
2026 年 8 月 2 日,一个普通的周日,我从 11:31 开始折腾 blog-pipeline,一直搞到 20:20。9 个小时,从 v2.2 一路迭代到 v2.7,改了 5 个问题,踩了 3 个坑,学了一堆教训。
这篇博客就是记录这 9 小时的完整经过——不是为了炫耀,而是为了下次遇到类似问题能直接翻出来看。
💡 与 v2.5 文章的关系:本文记录了从 v2.2 到 v2.7 的完整迭代全景,其中问题四(路由规则升级到 v2.5)的详细分析已在 [[OpenClaw 博客流水线 v2.5:从模型降级到路由规则的完整修复]] 中展开。两篇互为补充,建议交叉阅读。

问题一:子 Agent 模型降级(step-router-v1 → agnes-2.5-flash)
症状
故事从一次模型调用异常开始。我在跑博客流水线时发现,design-image-prompt-engineer 这个子 agent 居然在用 step-router-v1 模型。这是一个明显过时的小模型,生成的图片提示词质量惨不忍睹——构图描述模糊、光线方向缺失、焦段参数随机。
根因排查
顺着日志往上翻,发现配置链是这样的:
# agents.defaults.subagents → 所有子 agent 继承
agents:
defaults:
subagents:
model: "step-router-v1" # ← 坑在这里agents.defaults.subagents.model 配置的默认值居然是 step-router-v1,从 OpenClaw 的默认配置继承下来的。我从来没改过这个字段,所以所有子 agent 都被静默降级了。

修复
agents:
defaults:
subagents:
model: "sapiens/agnes-2.5-flash" # 改为主力模型改完后重启 Gateway,重新跑了一次流水线,design-image-prompt-engineer 的输出质量立刻恢复正常。
教训
agents.defaults.subagents.model 这个配置非常隐蔽。它不像主 agent 的 model 字段那样显眼,但影响力巨大——所有子 agent 都继承它。如果你从来没显式设置过,赶快去检查一下。
问题二:中文 Slug 的 URL 编码陷阱
症状
鬼谷子那篇文章写完后,部署到 Cloudflare Pages 直接 404。URL 里出现了 %8N%E9%AC%BC%E8%B0%B7... 这种编码字符串,浏览器显示乱码,分享链接更是惨不忍睹。
根因
Slug 生成逻辑太粗糙了:
# 旧代码
slug = title.lower().replace(" ", "-") # 直接用中文标题中文标题转 slug 后变成 %E9%AC%BC%E8%B0%B7...,Cloudflare Pages 的静态文件路由不支持中文 URL 编码,直接 404。
修复
从内容中提取英文关键词,自动生成 slug:
STOP_WORDS = {"the", "and", "for", "blog", "post", "openclaw", "with", "from"}
def generate_slug(title, content):
"""生成英文 slug,必须是英文字母、数字和短横线"""
ts = str(int(time.time()))[-4:]
if any('\u4e00' <= c <= '\u9fff' for c in title):
# 从内容中提取英文关键词
words = re.findall(r'[a-zA-Z]+', content)
if words:
meaningful = [w.lower() for w in words
if len(w) > 3 and w.lower() not in STOP_WORDS]
slug = '-'.join(meaningful[:4]) if meaningful else 'blog-post'
else:
slug = 'blog-post-' + ts
else:
slug = re.sub(r'[^a-zA-Z0-9]+', '-', title).lower().strip('-')
if len(slug) < 3:
slug = 'blog-post-' + ts
return slug核心逻辑:如果标题包含中文,就从正文中提取前 4 个有意义的英文词拼成 slug。如果正文一个英文词都没有,就用时间戳兜底。
教训
Slug 必须只有英文字母、数字和短横线。 这是静态网站的硬性要求,不是审美问题。
问题三:图片路径规范化
症状
图片路径有多处不一致:有的地方用 {slug}.webp,有的地方用 {slug}-cover.webp,featured-image 的资源 name 和 src 也不匹配。
修复
统一为 {slug}.webp:
resources:
- name: "featured-image"
src: "{slug}.webp"
- name: "featured-image-preview"
src: "{slug}.webp"
featuredImage: "/images/Code-Art-Studio-images/{slug}/{slug}.webp"
featuredImagePreview: "/images/Code-Art-Studio-images/{slug}/{slug}.webp"
问题四:路由规则升级到 v2.5
背景
之前的分类路由规则只有两级:技术 → Code Art Studio,非技术 → Digital Asset。但 Code Art Studio 下的文章越来越多,全部堆在 code-art-studio/ 根目录下,管理起来很痛苦。
修复
v2.5 引入了更细粒度的路由规则:
# 目录路由规则
obsidian_routes = {
"配置": ["配置", "config", "settings"],
"排障": ["排障", "debug", "fix", "error", "problem"],
"工作流": ["workflow", "pipeline", "DAG", "自动化", "流程"],
"架构": ["架构", "architecture", "拓扑", "设计", "多智能体"],
"技能": ["skill", "技能", "插件", "plugin"],
"核心概念": ["概念", "基础", "introduction", "入门"],
}
# Hugo 发布目录路由
openclaw_keywords = ["openclaw", "agent", "workflow", "DAG", "多智能体",
"技能", "skill", "配置", "排障", "Gateway", "MCP"]
is_openclaw = any(kw.lower() in content.lower() for kw in openclaw_keywords) and tech_score >= 3
category_config = {
"post_dir": "/data/oklifeme/content/posts/code-art-studio/openclaw/"
if is_openclaw
else "/data/oklifeme/content/posts/code-art-studio/",
}路由逻辑:
- OpenClaw 相关(命中 OpenClaw 关键词 + 技术分 ≥ 3)→
code-art-studio/openclaw/ - 其他技术文章 →
code-art-studio/根目录 - 非技术文章 →
digital-asset/
问题五:可观测性增强 v2.6-v2.7
为什么需要可观测性
之前跑流水线就像在盲打。不知道每个 Phase 花了多长时间,不知道每个 agent 消耗了多少 token,出错了也不清楚是在哪个环节。
增强方案
v2.6 引入了完整的可观测性系统:
1. Phase 耗时记录
def log_phase_start(phase_name):
run_state["phases"][phase_name] = {"start": time.time(), "status": "running"}
def log_phase_end(phase_name, success=True, tokens=None):
elapsed = time.time() - run_state["phases"][phase_name]["start"]
run_state["phases"][phase_name].update({
"end": time.time(),
"elapsed_s": round(elapsed, 2),
"status": "success" if success else "failed"
})2. Token 消耗追踪
记录每个 agent 的 input/output tokens,汇总到 run_state 中,最终输出到摘要。
3. 错误日志结构化
def log_error(phase_name, error_msg):
error = {
"phase": phase_name,
"timestamp": datetime.now().isoformat(),
"message": str(error_msg)
}
run_state["errors"].append(error)
logger.error(f"[ERROR] {phase_name}: {error_msg}")4. 运行状态摘要

完成后输出完整的执行摘要:
=== Blog Pipeline Run Summary ===
Trace ID: 20260802-193000
Total Time: 180.5s
Status: success
Phases:
Phase 1: 写稿 — 30.0s ✅
Phase 2a: 质检 — 25.0s ✅
Phase 2b: SEO — 20.0s ✅
Phase 3: 改稿 — 35.0s ✅
Phase 3.5: 提示词 — 15.0s ✅
Phase 4: 生图 — 55.5s ✅
Tokens:
Input: 45,000
Output: 12,000
Total: 57,000
Errors: 0
Log file: /data/blog_pipeline_logs/blog-20260802-193000.log日志路径变更
v2.6 时日志路径是 /tmp/blog_pipeline_logs/,用户反馈后改为 /data/blog_pipeline_logs/(v2.7),避免系统重启后日志丢失。
总结:9 小时迭代全景
| # | 问题 | 修复 | 版本 | 影响 |
|---|---|---|---|---|
| 1 | 子 agent 模型降级 | 配置 agents.defaults.subagents.model | v2.2 | 修复图片质量 |
| 2 | 中文 Slug 部署失败 | 英文关键词自动生成 slug | v2.4 | 修复部署 |
| 3 | 图片路径不一致 | 统一为 {slug}.webp | v2.4 | 规范管理 |
| 4 | 目录结构混乱 | 细粒度路由规则 | v2.5 | 管理效率 |
| 5 | 缺少可观测性 | Phase 计时 + Token 追踪 + 错误日志 | v2.6-v2.7 | 运维效率 |
关联阅读
- [[OpenClaw 博客流水线 v2.5:从模型降级到路由规则的完整修复]]
- [[OpenClaw 多智能体博客流水线 v3.0:破解 3 层 Subagent 嵌套限制的 2 层 DAG 架构演进]]
- [[OpenClaw 博客流水线 v2.1 修复全记录:模型降级、动态路由与并发限制规避]]
这 9 小时最大的收获不是写了多少代码,而是建立了一个可观测、可诊断、可修复的博客流水线。每次出问题,日志会告诉你哪里慢了、哪里错了、哪里该优化。下次再跑流水线,不再是盲打,而是有数据支撑的工程决策。
梦行志