Harness 的本质:驾驭控制流与数据流

用 Hermes Agent 搭了个全自动内容发布系统,三天里推翻了两次架构。最后想明白一件事:Harness 就两个维度——控制流决定"谁来做决策",数据流决定"数据长什么样"。

大模型本质上就是一个函数——你扔一句话进去,它吐一句话出来。但它自己决定不了先做什么、后做什么、出了错怎么办。这些控制流的事,得交给代码来管。

如果你让大模型自己管流程,就是用一个不靠谱的东西去管另一个不靠谱的东西。让代码管流程、把大模型压成一个只管输入输出的函数,才是正道。

从一个具体问题说起

我有一个英文 WordPress 站,内容来源是中文平台。手动流程就是:找文章、读原文、改写英文、登录后台发布。每天重复,枯燥耗时。

需求拆开很简单:采集、改写、发布。三步。

目标是用 Hermes Agent 的定时任务实现全部自动化。但这个过程中,我真正解决的不是"怎么采集"、"怎么改写"这些技术问题,而是反复在想一个更底层的问题:

整个流程中,谁在做决定?

这不是一个工程问题,这是一个关于编排模式的问题。


什么是 Harness

当你把 LLM 引入一个系统,不管是做内容改写、代码生成还是流程自动化,你都绕不开一个核心问题:怎么驾驭它?

LLM 不是普通函数。你给它同样的输入,它可能给你不同的输出。它有理解力,但理解力不等于可靠性。它有创造力,但创造力不等于可重复性。

Harness 就是解决这个问题的工程实践:在系统中,以什么方式使用 LLM,让它既能干活,又不失控。

这不是一个新问题。每次有新技术进来,都会面对类似的 harness 问题——怎么驾驭数据库(ORM),怎么驾驭微服务(编排),怎么驾驭分布式(一致性协议)。LLM 只是给了这个问题一个新的维度。

三天的实践让我走过了三种 harness 模式。每一种都是对"怎么驾驭 LLM"的不同回答。


第一种 Harness:让 LLM 驾驭一切

最初的方案非常"AI 原生"。

我写了一个 SKILL.md,用自然语言描述整个流程——"先从信息源采集文章,提取正文,检查是不是广告,如果不是,用 Keystem 模型分析视角,再用 Mimeng 风格改写成英文,最后发布到 WordPress"。然后让 Hermes Agent 读这个文件,自己决定每一步调用哪个 Python 脚本。

这个 harness 模式的隐含假设是:LLM 是驾驭者,Markdown 是缰绳,Python 是马。

SKILL.md(意图声明)
    ↓
  LLM(驾驭者)
    ↓
Python 脚本(执行工具)

然后频繁跟 Agent 沟通——提需求、测试、改。大部分时候能跑通。但不对劲的地方逐渐暴露:

控制流失控: 同一篇文章,LLM 有时候先采集再检查质量,有时候先检查质量再采集。有时候它会跳过某个步骤,理由是"我认为不需要"。有时候它多调用了一次 LLM,因为它"忘记了之前已经分析过"。

数据流失控: LLM 的输出是自由格式的自然语言。下游的 LLM 需要"理解"上一步的输出,才能决定下一步做什么。但"理解"本身是概率性的——有时候它把标题当成了正文,有时候它忽略了 FAQ 部分,有时候输出的 JSON 格式不对。

由于需要调用改写风格的 SKILL.md,上下文爆炸,质量不可控,格式不可控。

当 LLM 同时驾驭控制流和数据流,系统行为就不可预测。

更深的问题是成本。每次执行,LLM 都要把整份流程文档读一遍、理解一遍、决策一遍。定时任务每天跑 24 次,每次都要花 token 让 LLM "想清楚要做什么"——而这个"什么"从来没有变过。

我在为一个确定性的流程,反复支付"理解"的成本。

这种 harness 模式适合什么场景?适合探索期。当你还不知道流程是什么的时候,你需要 LLM 的"理解力"帮你试错。事实上,用 Hermes Agent 和 SKILL.md 快速原型的方式,让我在第一天就跑通了整个链路。没有这个阶段,我根本不知道 Python 代码应该编排什么。

但它不适合生产。让 LLM 驾驭一切的前提是:流程还不确定。一旦确定了,就应该把驾驭权收回来。


第二种 Harness:用代码驾驭 LLM

意识到问题后,我做了激进的改变:用 Python 编排全流程,LLM 只在具体任务中被调用。

Python(驾驭者)
    ↓ 决定执行顺序
    ↓ 决定是否跳过/重试
    ↓ 决定错误处理
    ↓
  LLM(被驾驭的工具)
    ↓ 只负责:判断质量、分析视角、生成内容

这个 harness 模式完全反转了:代码是驾驭者,LLM 是被驾驭的工具。

我用 Python 定义了明确的流程:先采集,逐条去重,通过去重的做质量检查,通过检查的做改写,改写完的发布。每一步的输入输出都是强类型。每一步的错误处理都是确定的。失败的留在缓冲区,下一轮自动重试。

同时,我也开始给数据流加上结构约束:

  • 采集器必须输出 FetchResult(title/url/content/sync_id)
  • LLM 的输入是结构化 prompt,输出必须是 JSON(title/content/faq/tags)
  • publisher 的输入必须符合 WordPress API 规范

效果立竿见影:

  • 可靠性从"看运气"变成"每次都一样"
  • LLM 调用从 4 次压缩到 2 次(合并 prompt)
  • token 消耗减半
  • 定时任务可以稳定跑了

但代价也很清楚:灵活性没了。

加一个新平台要写代码。改一个流程要改代码。调整策略要改代码。所有"变化"都变成了"改代码→测试→部署"这个链条。

而实际上,有些东西变的频率是不一样的。模型会换,源会加,标签策略会调整——这些是高频变化。采集→去重→检查→改写→发布——这个主流程从确定之后就没变过。

用同一种 harness 方式处理不同频率的变化,是第二种模式的根本问题。


第三种 Harness:分层驾驭

第三种模式不是折中,而是真正想清楚之后的结果。

核心洞察:不同层次的决策,应该用不同的介质来驾驭;不同层次的数据,应该用不同的约束来管理。

控制流(谁来驾驭)                数据流(什么约束)
┌─────────────────┐          ┌─────────────────┐
│ Python 代码      │          │ FetchResult schema│
│ 流程编排,几乎不变│          │ JSON 结构约束     │
├─────────────────┤          ├─────────────────┤
│ config.json     │          │ config schema    │
│ 策略配置,经常变  │          │ 字段定义          │
├─────────────────┤          ├─────────────────┤
│ LLM             │          │ prompt + JSON    │
│ 内容智能,每篇不同│          │ 输入输出结构化     │
├─────────────────┤          ├─────────────────┤
│ SKILL.md        │          │ 设计文档          │
│ 设计意图,偶尔更新│          │ 记录数据契约       │
└─────────────────┘          └─────────────────┘

换模型?改 config.json。加一个新信息源?写一个采集器模块 + config.json 加一行配置,路由自动识别。改写风格变了?改 prompt 配置。主流程变了?这很少发生,改代码。

该确定的确定,该灵活的灵活,该智能的智能。

这种 harness 模式吸收了第一种的"声明式"优点(配置驱动),保留了第二种的"确定性"优势(代码编排),同时把 LLM 的能力严格限定在它真正擅长的范围内。


数据流转中的 Harness 契约

决策权分配解决的是控制流问题——谁来驾驭下一步。但还有一个同等重要的问题:数据以什么形态在系统中流动。

这个认知来自一个具体的教训:去重。

最初没有去重,同一篇文章被采集、改写、发布了三次。解决方案是给每篇文章一个唯一标识(sync_id)。但这个标识不是随便起的——它必须满足一个约束:在数据流转的全生命周期中,同一份内容始终映射到同一个 ID。

平台sync_id 格式生成规则
Hacker Newshn-{item_id}从 URL 中的 item ID 提取
信息源 Awspm-{category}-{id}从文章 URL 结构化提取
信息源 Bzhihu-hot-{qid}从热榜链接的 qid 提取
信息源 Czhihu-daily-{story_id}从日报 API 的 story_id 提取

sync_id 同时承担了三个角色:

  • 去重数据库的主键——判断这篇文章是否已经处理过
  • 缓冲区文件的文件名——采集和发布解耦的桥梁
  • WordPress meta field 的值——发布后反查的依据

一个标识,三处复用。如果这三个环节用了不同的标识方式,系统就会分裂——去重认为是新文章,缓冲区里其实已经有了,WordPress 上已经发布过了。

sync_id 不是一个技术细节。它是数据流转的 harness 契约。

再看其他环节,每一个交接点都有类似的结构约束:

采集器输出 → 必须是 FetchResult(title/url/content/sync_id)
                 ↓
去重检查 → sync_id 必须唯一
                 ↓
LLM 输出 → 必须是 JSON(title/content/faq/tags)
                 ↓
publisher 输入 → tags 必须是 ID 不是 name
                 ↓
WordPress → meta field 必须在主题中注册

任何一环的结构不匹配,下游就会报错。而这类错误往往是最难调试的——因为数据"看起来是对的",但格式或类型不对。

我踩过几个坑:

采集器输出没有 content 字段。 下游的质量检查和改写都需要正文内容,但采集器默认只返回了标题和 URL。结果 LLM 收到空内容,生成了一篇"基于标题猜测"的文章。

LLM 输出的 JSON 引号未转义。 内容里有双引号,破坏了 JSON 结构。直接 json.loads() 失败。需要多层 fallback 解析。

publisher 传了 tag name 而不是 ID。 WordPress Posts API 的 tags 字段只接受 integer ID。传了 ["AI", "Tech"] 进去,API 静默忽略,标签全丢了。

这些都不是逻辑错误,都是结构错误。逻辑错误会报异常,结构错误往往静默失败——数据流转过去了,但结果是错的,而且你不知道哪里错了。


Harness 的两个正交维度

回过头看,整个系统的设计其实是两个正交维度的交织:

                控制流                    数据流
            (谁来做决定)            (数据长什么样)
模式一       LLM 驾驭                  自由格式
模式二       Python 驾驭               强类型约束
模式三       分层驾驭                  分层约束

模式一不仅让 LLM 驾驭控制流,也放任数据以自由格式流动——LLM 的输出不需要符合任何 schema,下游的 LLM 自己"理解"就好。这在探索阶段没问题,但到了生产阶段,"理解"本身就是不确定性。

模式三不仅分层分配了驾驭权,也在每一层的边界上定义了数据契约:

config.json → 定义了 source 的 schema(name/type/url/platform)
采集器 → 必须输出 FetchResult
缓冲区 → JSON 文件,字段固定
LLM → 输入输出都是结构化 prompt + JSON
publisher → 输入必须符合 WP API 规范

控制流的可靠性来自驾驭权的确定性分配。数据流的可靠性来自每一层边界的结构约束。两者缺一不可。

单独做好一个不够。我见过只有控制流约束、没有数据流约束的系统——流程是对的,但每一步的数据格式全靠"默契",一旦 LLM 输出变了一点,整条链路就断。也见过只有数据流约束、没有控制流约束的系统——每个接口都有 schema,但调用顺序完全由 LLM 决定,今天走 A→B→C,明天走 B→A→C。

Harness 的本质是同时驾驭控制流和数据流。


Harness 的演进路径

三种模式不是三种技术方案,而是三个认知阶段:

模式一          模式二          模式三
LLM 驾驭一切   代码驾驭 LLM    分层驾驭
  ←————————————————————————————→
  灵活但不可靠   可靠但不灵活    分层可控

大多数自动化项目的 harness 演进路径是:

先让 LLM 驾驭一切(探索),再用代码驾驭 LLM(固化),最后用分层驾驭平衡确定性与灵活性(生产)。

走完这三个阶段,你就完成了从"探索"到"生产"的跨越。而这个跨越的本质,是驾驭权的一次次重新分配。


一个更深的问题

走完三种模式之后,我开始想一个更根本的问题:

当 LLM 变得越来越强大,模式一会不会重新成为最优解?

如果 LLM 的理解力足够强、输出足够稳定、成本足够低——我们还需要用代码来驾驭它吗?还需要结构化约束来管理数据流吗?

我觉得短期内答案还是"需要"。原因不是 LLM 不够强,而是确定性是一种独立于智能的属性。

一个足够聪明的人,也不适合做流水线——不是因为他做不好,而是因为他每次做出来的东西不完全一样。而自动化系统需要的恰恰是:同样的输入,永远是同样的输出。

LLM 擅长的是理解和创造。代码擅长的是确定性和可重复性。配置擅长的是隔离变化。文档擅长的是传递意图。

它们解决的是不同的问题。不是能力高低的问题,是性质不同的问题。

Harness 的目标从来不是"让 LLM 做最多的事",而是"让 LLM 在对的地方做对的事"。


写在最后

三天时间,两次推翻,从 SKILL.md 驱动到 Python 编排,最终落地到分层 harness 架构。这个过程教会我的不是怎么写代码,而是怎么思考两个正交的问题:

控制流:谁来驾驭? 把驾驭权分配给合适的层——流程交给代码,策略交给配置,理解力交给 LLM。

数据流:什么约束数据? 在每一层的边界上定义结构契约——输入是什么格式,输出是什么格式,标识怎么生成,失败怎么处理。

如果你也在用 Hermes Agent 或类似的 AI Agent 平台构建自动化系统,建议在动手之前先问自己两个问题:

在这个流程里,你希望谁来驾驭?数据在每一层之间流动时,长什么样?

把这两个问题想清楚,Harness 自然就清楚了。


附:WordPress 自动化内容发布 Agent 开发心得

一、项目背景

构建一个自动化内容发布系统:从多个中文内容源采集文章 → AI 改写为英文 → 发布到 WordPress 站点。整个流程需要全自动运行(定时任务),不用人盯。

二、架构演进过程

最初的形态:Markdown 驱动

最早的方案是用 SKILL.md 定义流程意图,让大模型读完之后理解"要干嘛",然后调用对应的 Python 脚本。

SKILL.md(流程定义)
    ↓ 大模型读取理解
    ↓ 决定调用哪个脚本
Python 脚本(工具)

本质:大模型是操作系统,markdown 是程序,Python 是系统调用。

好处是灵活——改 markdown 就能改流程。但问题一堆:

  1. 不靠谱 — 大模型每次都要重新理解流程,可能理解错
  2. 费钱 — 每次执行都要 LLM 读完整个流程文档
  3. 不适合定时任务 — 自动化场景不能依赖 LLM 的"理解力"

演进为:代码驱动

最终方案改成 Python 编排全流程,LLM 只在具体环节被调用:

main.py(Python 编排)
    ↓ Python 决定流程
    ↓ 调 LLM 做内容改写
    ↓ 调 WordPress API 发布
LLM 只是被调用的组件

本质:Python 是操作系统,LLM 是一个函数。

两种模式的对比

维度Markdown 驱动代码驱动
谁做决策大模型Python 逻辑
可靠性取决于 LLM 理解力确定性执行
灵活性高(改 md 即改流程)低(改代码)
成本高(每次 LLM 理解全流程)低(LLM 只做具体任务)
适合场景探索期、流程未定型生产环境、流程已定型

最终选择代码驱动的原因:

  1. 定时任务要可靠——LLM 不能每次都重新理解流程
  2. 成本要可控——4 次 LLM 调用压缩到 2 次
  3. 流程已定型——采集→改写→发布,不需要 LLM 决定"下一步做什么"

但保留了配置驱动的灵活性——换模型、换源、换标签策略,只改 config.json,不动代码。这吸收了 markdown 驱动的"声明式"优点。

三、最终架构

wp-agent/
├── config.json                # 配置(凭证/分类/LLM/常量)
├── main.py                    # 入口(--fetch / --publish / --status)
├── readme.md                  # 说明
├── SKILL.md                   # Hermes 技能文档
├── core/                      # 基础模块
│   ├── config.py              #   配置加载器(读 JSON + .env)
│   ├── models.py              #   FetchResult 数据模型
│   ├── dedup.py               #   SQLite 去重 + 状态追踪
│   ├── buffer.py              #   中间缓冲区(raw/)
│   └── lock.py                #   进程锁(防并发)
├── fetchers/                  # 采集层
│   ├── router.py              #   路由(配置驱动,动态加载)
│   ├── discover.py            #   自动发现(RSS/API)
│   ├── extractor.py           #   正文提取(trafilatura)
│   ├── hackernews.py          #   HN 采集器
│   ├── woshipm.py             #   人人都是产品经理采集器
│   └── zhihu.py               #   知乎采集器(热榜+日报)
├── transformer/               # 改写层
│   └── ai_trans.py            #   Keystem + Mimeng 双 skill 改写
├── publisher/                 # 发布层
│   └── publisher.py           #   WordPress 发布
└── data/                      # 运行数据
    ├── dedup.db               #   去重数据库
    └── raw/                   #   采集缓冲区

核心设计原则

  1. 配置驱动 — 加新平台只改 config.json,不改代码
  2. 契约明确 — 每个函数的输入输出都是强类型
  3. 解耦优先 — 采集和发布通过 raw/ 缓冲区隔开
  4. 失败隔离 — 单条失败不影响其他,留在 raw/ 下次重试
  5. 零人工干预 — 定时任务全自动,锁防并发,限额可配
  6. LLM 尽量少调 — 4→2 次,合并 prompt 省延迟和 token

四、关键决策与思考

配置格式:YAML → JSON

最初用 YAML,需要 PyYAML 依赖。系统权限问题装不上,改成 JSON。Python 标准库直接解析,零外部依赖。

采集和发布解耦

最初是串行流程:discover → fetch → transform → publish,全在一个进程里。

问题:采集快(秒级),改写慢(分钟级),串行导致采集被改写拖住了。

解决方案:加 raw/ 缓冲区

之前:fetch → transform → publish(串行,一个卡全部卡)
现在:fetch → raw/ → publish(解耦,各自独立调度)

LLM 调用优化:4 次 → 2 次

最初每篇文章需要 4 次 LLM 调用:

次数调用作用
1quality_check判断是否广告/新闻稿
2KEYSYSTEM_PROMPT分析视角和框架
3MIMENG_PROMPT写文章
4_generate_faq生成 FAQ

优化后合并为 2 次:

次数合并内容作用
1质量检查 + Keystem 分析一次调用搞定判断+分析
2Mimeng 写作 + FAQ 生成一次调用搞定写作+FAQ

效果:速度提升约 50%,token 消耗减半。

Keystem + Mimeng 双 Skill 联动

改写流程是两个 skill 的协作:

  • Keystem(思考内核):选模型/视角,提供分析框架和深度观点
  • Mimeng(写作引擎):造爆点标题,情绪驱动行文,输出最终 HTML

流程:Keystem 先想(选哪个模型、从什么角度分析)→ Mimeng 再写(用爆文风格把分析包装成能传播的内容)。

Mimeng 的 6 条写作铁律被完整保留在 prompt 里:

  1. 首段情绪钩子——第一段就要抓住读者
  2. 现象命名——给现象起一个能传播的名字
  3. 每 2-3 段一个 <strong> 金句
  4. 态度鲜明,不中立
  5. 情绪曲线完整:低→中→高→爆发→收尾
  6. 站在读者立场

标签策略:随机抽 → 从已有标签选

最初是随机从固定池里抽标签,跟文章内容完全无关。

问题:标签不一致,WordPress 标签越来越多越来越乱。

最终方案:LLM 从 WordPress 已有标签里选 2-4 个,没有合适的才创建新的。

已有标签 → 优先选(保持一致性)
没有合适的 → 允许新建(SEO 增长)
publisher 自动创建 WP 里不存在的标签

正文提取:HTML 正则 → trafilatura

最初用正则表达式从 HTML 提取正文,大部分网站抓不到内容。

解决方案:用 trafilatura(专门做正文提取的库),提取质量远超正则。

# 之前(正则,不可靠)
title_match = re.search(r'<h1[^>]*>(.*?)</h1>', html, re.DOTALL)

# 现在(trafilatura,可靠)
result = trafilatura.extract(html, include_comments=False, include_tables=True)

sync_id 设计:去重主键

每篇文章有唯一标识,格式按平台区分:

平台格式示例
Hacker Newshn-{item_id}hn-48714529
人人都是产品经理wspm-{category}-{article_id}wspm-ai-6422934
知乎热榜zhihu-hot-{qid}zhihu-hot-2056091282
知乎日报zhihu-daily-{story_id}zhihu-daily-9790812

sync_id 同时作为:

  • dedup.db 的主键
  • raw/ 缓冲区的文件名
  • WordPress meta field _site_sync_unique_id 的值

WordPress Meta Field

发布时写入三个 meta field:

Field用途
_site_sync_unique_id原文唯一标识,用于反查
_site_source_url原文链接
_site_faq_itemsFAQ 结构化数据,single 页面模板读取渲染

注意:这些 meta field 得在 WordPress 主题里用 register_post_meta 注册,不然 API 不返回。

WordPress API 的 Tags 字段

Posts API 的 tags 字段只接受 integer ID,不接受 string name:

// ❌ 不支持
"tags": [{"name": "AI"}]

// ✅ 只支持
"tags": [17, 23]

所以 publisher 得做 name → ID 转换:GET /wp/v2/tags?search={name} 查是否已存在,不存在就 POST 创建。

Cloudflare 403 问题

Python 的 urllib 默认不带 User-Agent,被 Cloudflare 拦截(error code: 1010)。

解决方案:所有 HTTP 请求统一加浏览器 UA:

req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0")

知乎源:热榜 + 日报

知乎有两个数据源,API 不一样:

APIsync_id 格式
知乎热榜RSSHub RSSzhihu-hot-{qid}
知乎日报daily.zhihu.com APIzhihu-daily-{story_id}

热榜的 RSSHub URL 是 XML 格式,得用 XML 解析器(不是 HTML 正则)。

进程锁:防并发

定时任务每小时触发一次,如果 publish 跑了 45 分钟,下一轮可能还没跑完就又触发了。

解决方案:锁文件机制

publish 开始 → 创建 data/publish.lock
publish 运行中 → 新触发看到锁 → 跳过
publish 结束 → 删除锁
锁超过 30 分钟自动过期(防死锁)

配置驱动的路由

采集器路由不用硬编码,从 config.json 读取平台规则:

"platforms": {
    "hn": { "domain": "ycombinator.com", "fetcher": "fetchers.hackernews" },
    "woshipm": { "domain": "woshipm.com", "fetcher": "fetchers.woshipm" }
}

加新平台只需:

  1. 写一个 fetchers/new_platform.py(实现 fetch(url) -> FetchResult
  2. 在 config.json 加一条平台配置

router.py 不用改任何代码,自动识别 + 动态加载。

自动发现层

定时任务得自动发现新内容,不能靠手动传 URL。

从 config.json 的 sources 配置自动拉取:

"sources": [
    { "name": "HN Front Page", "type": "hn_algolia", "url": "...", "platform": "hn" },
    { "name": "RSS Feed", "type": "rss", "url": "...", "platform": "woshipm" },
    { "name": "知乎热榜", "type": "zhihu_hot", "url": "...", "platform": "zhihu" },
    { "name": "知乎日报", "type": "zhihu_daily", "url": "...", "platform": "zhihu" }
]

支持的源类型:hn_algoliarsszhihu_hotzhihu_daily。加新源类型只需在 discover.py 加一个解析函数。

质量检查:过滤广告/新闻稿

在改写前加一步 LLM 快速检查:

source_content → quality_check(只看前500字)
    ├─ REJECT → 跳过(广告/新闻稿/软文)
    └─ PASS → 继续改写

一次 LLM 调用过滤广告,省掉了后面 3 次无用的改写调用。

JSON 解析容错

LLM 输出的 JSON 经常格式不标准(引号没转义、换行等)。多层 fallback 解析:

  1. 直接 json.loads()
  2. {} 之间的内容再解析
  3. 用正则提取 title/content/FAQ 字段

LLM 模型选择

测了 4 个免费模型:

模型速度质量状态
glm-5.2中等✅ 好最终选用
deepseek-v4-flash✅ 好备选
flash-lite❌ 差不推荐
u1-fast--404 不可用

最终选定 glm-5.2,质量稳定。

五、踩过的坑

  1. 循环导入 — fetcherRouter 和 hackernews_fetcher 互相引用 → 抽出 models.py
  2. Cloudflare 403 — urllib 没有 User-Agent → 统一加浏览器 UA
  3. LLM 输出非标准 JSON — 内容里有引号/换行 → 多层 fallback 解析
  4. sync_id 假 ID — 测试时硬编码假 ID → 必须从 URL 生成
  5. 标签 name vs ID — WP API posts 只接受 tag ID → publisher 做转换
  6. meta field 名称 — 实际名称和预期不一致 → 必须跟 WP 主题一致
  7. cron 脚本路径 — 相对路径找不到 → 改成绝对路径
  8. 知乎热榜解析 — 当 HTML 解析 RSS XML → 改用 XML 解析器
  9. 批量归档误操作 — 手动移动所有 raw 文件 → 代码逻辑对但手动操作搞错了
  10. 模型质量差异 — flash-lite 输出内容短且差 → 选定 glm-5.2

六、定时任务设计

两个独立的定时任务,通过 raw/ 缓冲区解耦:

每小时整点   → fetch(采集,不涉及 LLM)
每小时15分   → publish(改写+发布,带锁防并发)
  • fetch 秒级结束,publish 是分钟级
  • 锁机制防止 publish 并发
  • raw/ 只保留没处理的,处理完自动删
  • 失败的留在 raw/ 下次重试

七、待优化

  • 知乎热榜 Cloudflare 403 问题
  • LLM 响应慢时的超时处理
  • dedup.db 历史数据清理策略
  • 多模型自动切换(主模型挂了自动切备选)
  • 采集器并发(3 个源同时拉取)
  • 更多内容源扩展(Twitter、Reddit、微博等)

八、核心结论

Markdown 驱动适合探索期,代码驱动适合生产期。

最好的做法是混合模式

  • Python 编排主流程(确定性、可靠)
  • LLM 做具体任务(改写、判断)
  • config.json 做策略配置(灵活性)
  • SKILL.md 做文档说明(可读性)

四个各司其职,既可靠又灵活。

本文作者:ZKCOI

文章名称:Harness 的本质:驾驭控制流与数据流

文章链接:https://www.zkcoi.com/365up/ai-agent/4810.html

本站资源仅供个人学习和交流,如若转载,请注明出处,详见《免责声明》

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
ZKCOIZKCOI
上一篇 2026年7月3日 上午11:08
下一篇 2026年7月3日 下午10:14

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系博主

立即联系
一般有空就回复

qrcode_web

微信扫码联系我

insert_link 友情链接
分享本页
返回顶部