用完备的 Harness 工程,在钉钉上实现 AI 原生协同工作流

The 7-component engineering infrastructure that turns a smart LLM into a reliable business tool

Harness 工程架构图 从只有大模型到完备 Harness:7 个组件缺一不可

上周我让 Agent 帮我写了一篇博客。

它从我的 wiki 里读了 5 篇历史文章做去重分析,生成初稿后自己跑了一轮对抗性评审打了 18 分,然后用 Gemini 生了一张配图、resize 到 1360px 以下、压缩成 948KB 的 PNG,再跑了一遍中文排版修复,最后 commit 推到 GitHub,等 CI 构建完成后自己验证了上线 URL。

整个过程我做了三件事:选了一个标题方向,补了两处内容,说了三次「发布」。

这套流水线跑了 4 篇博客(#290 到 #293),每篇都是这个流程。它不是 demo,是真实的生产管线。

但我回头看这套东西的时候,发现一个问题: 我搭出来的不是一个 Agent,是一个 Harness。

一个被忽视的事实:Agent 交付靠的不是模型

我在 让钉钉机器人自己开发自己 里说过一句话:「自主性的瓶颈在环境接入,不在模型能力。」

这句话当时说的是 Agent 修自己的 Bug。但其实它适用于所有 Agent 场景。

最近有一篇讲 Harness 的文章把这个问题说得很透:

大模型解决的是智能问题。Harness 解决的是交付问题。

什么叫 Harness?它是 Agent 的业务运行底座——把模型、工具、知识、记忆、策略、观测和配置组织起来,让 Agent 能在真实业务场景里稳定、安全、可控地完成任务。

没有 Harness,Agent 只能回答「应该怎么做」。有了 Harness,Agent 才能真的去查、去判断、去调用工具、去执行、去记录、去复盘。

这篇文章列出了 Harness 的 7 个组件:

#组件解决的问题
1模型网关什么任务用什么模型
2工具注册表Agent 能用哪些工具
3知识库引擎从哪拿业务知识
4记忆系统记住上下文和偏好
5策略引擎规则和红线怎么强制
6可观测性Agent 干得怎么样
7配置管理怎么持续调教不发版

读完这张表,我回头审视自己在钉钉上搭的这套系统,发现——7 个组件全都有,而且全是钉钉 + dws 原生能力撑起来的,没有一行胶水代码。

钉钉 + dws:一张完备的 Harness 映射表

下面我把这 7 个组件逐一映射到我在钉钉上实际跑通的工程实现。每个组件我都会给出:它在我的系统里长什么样,用了什么 dws 命令,以及如果缺了它会怎样。

组件 1:模型网关——异构 Agent 各司其职

我的系统里有两个 Agent,配了不同的模型:

Agent模型定位
OpenCode AgentGLM 5.2写代码、跑测试、改 Bug
Hermes AgentQwen 3.7 Max知识库、长上下文、写博客、记忆

这不是随意分配的。GLM 5.2 的代码生成能力强但上下文窗口小,适合确定性的编码任务。Qwen 3.7 Max 上下文长、中文好,适合需要读大量材料的分析和写作任务。

模型网关的核心原则是: 该用好模型的地方不要省,该用便宜模型的地方不要浪费,能用规则解决的地方就别麻烦大模型。

在钉钉上,这两个 Agent 通过消息总线协作(见 两个 Agent 的钉钉对话)。我在群里 @ Hermes 让它写一篇博客,它写到需要跑代码的时候会把任务转给 OpenCode。这不是一个 Agent 内部切模型,而是 两个 Agent 在 IM 里协作——模型网关变成了消息路由。

缺了它会怎样? 所有任务都打给最贵的模型。成本飙升,响应变慢,而且很多简单任务(比如查群列表、发通知)根本不需要大模型。

组件 2:工具注册表——dws 的 163 条指令

dws CLI 就是我的工具注册表。当前版本(v1.0.52-beta.2)提供了 163 条指令,覆盖钉钉全部核心能力:

┌──────────────────────────────────────────────┐
│              dws 工具注册表                     │
├──────────┬───────────────────────────────────┤
│ chat     │ 群聊/消息/机器人/公告/群管理         │
│ calendar │ 日历日程/会议室/闲忙                 │
│ contact  │ 通讯录/用户/部门/人员关系             │
│ doc      │ 钉钉文档管理                         │
│ drive    │ 钉盘文件管理                         │
│ mail     │ 邮箱/邮件收发                        │
│ oa       │ OA 审批/同意/拒绝/撤销               │
│ todo     │ 待办任务管理                         │
│ wiki     │ 知识库/空间管理/节点管理              │
│ aitable  │ AI 表格操作                          │
│ minutes  │ AI 听记/会议纪要                     │
│ dev      │ 开发者能力/connect/事件订阅           │
└──────────┴───────────────────────────────────┘

每条指令都有 --help 自描述、--format json 结构化输出、--dry-run 预览——这三个 flag 让 Agent 能自主探索工具能力,不需要人提前教它每个参数。

比如我要让 Agent 给 FDE 教练发消息,它不需要知道 FDE 教练的 openDingTalkId。它自己跑 dws contact user search --keyword 「FDE 教练」 查到 ID,再跑 dws chat message send。工具注册表不只是「有工具」,还要让 Agent 能自己发现工具

缺了它会怎样? Agent 只能聊天,不能操作任何业务系统。你让它帮你安排会议,它只能说「建议你打开日历看看」,而不是真的帮你查空闲时间、发邀请。

组件 3:知识库引擎——wiki + 博客 corpus + memory

我的知识库分三层:

┌─────────────────────────────────────────┐
│          知识库三层架构                    │
├─────────────────────────────────────────┤
│ Layer 1: ~/wiki/                        │
│   raw/notes/  — 原始素材(会议记录、      │
│                 文章、数据报告)           │
│   concepts/   — 结构化概念页面            │
│   entities/   — 实体页面(人、工具)       │
│                                         │
│ Layer 2: ~/Projects/blog2/content/post/  │
│   历史博客 corpus(293 篇)               │
│   Agent 写新文章前必须读、做去重分析       │
│                                         │
│ Layer 3: Hermes persistent memory        │
│   用户偏好、环境配置、常用联系人          │
│   跨 session 持久化                       │
└─────────────────────────────────────────┘

知识库不是 RAG 这么简单。Layer 1 是原始素材库,Agent 用 search_filesread_file 按关键词检索。Layer 2 是已发布的知识,Agent 写新博客前必须扫最近的文章做去重——这是我在 人机协同的核心不是 Chat,是 Feedback Loop 里讲的「Agent 必须记住你」。Layer 3 是 Hermes 的 memory 系统,存的是偏好和事实,不是知识条目。

缺了它会怎样? Agent 每次从零开始。它不知道你已经写过「异构多 Agent 协作」,会再写一篇角度几乎一样的文章。它不知道你喜欢 Claude 风格的配图,每次都要你重新说。

记忆系统和知识库的区别:知识库是「可检索的资料」,记忆是「当前上下文 + 长期偏好」。

Hermes 的记忆分两层:

  • 持久记忆(memory tool):跨 session 生效。存的是「用户喜欢简洁回复」「dws 用 id_ed25519 密钥」「FDE 教练的 openDingTalkId 是 xxx」这种稳定的事实和偏好。
  • 会话记忆(session_search):可以搜过去的对话记录。比如我上周和幕山聊了什么,Agent 能搜出来做会议准备。

记忆系统的关键设计不是「记什么」,而是「 不记什么 」。我在 skill 里明确写了:不记 PR 编号、commit SHA、临时 TODO 状态——这些一周后就过期了。记太多会污染上下文,还会把 A 任务的设定带到 B 任务里。

缺了它会怎样? 你每次和 Agent 交互都要重新自我介绍。它不记得你上周让它跟进的那个项目,不记得你讨厌「随着 AI 的发展」这种开头。Feedback Loop 断裂。

组件 5:策略引擎——渐进信任 + 通知分级 + 超时机制

策略引擎是 Harness 7 个组件里最容易被低估的。我的系统里策略引擎管三件事:

渐进信任三级模型:

┌─────────────────────────────────────────┐
│            渐进信任三级模型               │
├──────────┬──────────────────────────────┤
│ Level 1  │ 每步确认                      │
│ 新任务   │ Agent 做完每件事都汇报          │
├──────────┼──────────────────────────────┤
│ Level 2  │ 异常确认                      │
│ 已验证   │ 常规自动执行,异常才求助        │
├──────────┼──────────────────────────────┤
│ Level 3  │ 定期汇报                      │
│ 充分信任 │ 完全自主,只给周报              │
└──────────┴──────────────────────────────┘

通知优先级分级: 只在需要人决策时通知,常规执行只写日志。我早期配 Hermes 的时候它每完成一个小任务都来找我,一天二十多条消息。三天后我就不看了。

超时机制: Agent 问用户一个问题(question 工具),60 秒没回答就自动 reject,防止会话卡死。这是我在 #293 里加的第一个改进——因为我自己就是那个「没看见问题导致 Agent 卡了一夜」的用户。

缺了它会怎样? Agent 要么太激进(自作主张发了一封邮件给全公司),要么太保守(每一步都来问你,比你自己做还慢)。更危险的是卡死——没有超时机制,一个未回答的 question 就能让整个管线停摆。

组件 6:可观测性——event-watcher + 钉钉消息流

可观测性是我在 #293 里重点讲的组件。核心是 event-watcher:一个独立进程连 opencode serve 的 SSE 事件流,把 Agent 执行中的事件实时转发到钉钉。

opencode serve (agent 会话)
   │ SSE /global/event
event-watcher ──转发──> 钉钉
   事件类型:
   - 工具调用(执行中/完成)
   - 会话完成(模型、轮数、tokens、缓存命中)
   - question 提问

这解决了 Harness 文章里说的那个问题:「没有可观测性,就没有 Agent 运营。因为你不知道它哪里好,哪里坏,哪里浪费成本,哪里反复出错。」

在钉钉上看 Agent 的执行轨迹,比在任何 dashboard 上都直观——因为它和你的其他工作消息在同一个界面里。你不需要切到一个专门的监控后台,刷钉钉的时候顺便就能看到 Agent 在干什么。

而且这条消息流本身就是测试信号。在 用 Agent 在钉钉上跟进团队周度任务 里,我让 Agent 从 16 个人的单聊消息里提取任务进展——真实使用产生的消息流,就是最好的回归测试集。

缺了它会怎样? Agent 出了问题你只能猜。它说「已完成」,你不知道它到底跑了哪些步骤、用了多少 token、中间有没有报错。出了问题也没有日志可查。

组件 7:配置管理——dws skills + cron + profiles

配置管理让 Agent 可以持续调教而不需要改代码。我的系统里有三种配置机制:

  • dws skills:Agent 的能力说明书。每个 skill 是一个 SKILL.md 文件,定义了意图表、命令用法、注意事项。改 skill 就是改 Agent 的行为,不需要重新训练或改代码。
  • cron jobs:定时任务配置。比如每周一自动跑一次「16 个高管的任务跟进」,不需要人手动触发。
  • profiles:多组织配置。同一个 dws 可以切换钉钉、阿里巴巴、Raspberry Pi 三个组织,每个组织有独立的认证和上下文。

配置管理的本质是: 把「这次我要什么」和「Agent 长期是什么」分开。 你的写作风格是长期记忆,但「这篇文章面向 CEO 还是工程师」是本次配置。好的配置管理让你不需要每次都重新教 Agent。

缺了它会怎样? 每次使用 Agent 都要从头调教。换个场景就要改 prompt,换个组织就要重新登录。Agent 变成了「一次性工具」而不是「持续进化的同事」。

7/7:一张完备性审计表

把上面的映射汇总成一张审计表。你可以用这张表来检查自己的 Agent 系统:

组件问题钉钉/dws 实现缺了会怎样
模型网关什么任务用什么模型?OpenCode (GLM 5.2) + Hermes (Qwen 3.7 Max) 异构路由成本飙升,简单任务用贵模型
工具注册表Agent 能用哪些工具?dws 163 条指令,–help 自描述Agent 只能聊天,不能操作业务系统
知识库引擎从哪拿业务知识?wiki 三层架构 + 博客 corpus + search_files每次从零开始,重复已写过的内容
记忆系统记住上下文和偏好?Hermes memory + session_search每次都重新自我介绍
策略引擎规则红线怎么强制?渐进信任 + 通知分级 + 60s 超时太激进或太保守,会话卡死
可观测性Agent 干得怎么样?event-watcher SSE→钉钉 + 消息流出问题只能猜,没有日志可查
配置管理怎么持续调教?dws skills + cron + profiles每次从头调教,换场景就废

7 个组件缺任何一个,Agent 都会在某个环节崩掉。不是「可能崩」,是一定崩。

为什么是钉钉而不是 LangChain

有人会说:LangChain、CrewAI、AutoGen 这些框架也能搭 Harness,为什么要绑定一个 IM 平台?

区别在于 胶水 vs 底座

框架搭的是胶水——你用代码把 LLM、工具、记忆、策略粘在一起。胶水越多,接口越多,出问题的地方越多。每次升级一个组件,你都要检查胶水有没有开裂。

IM 平台提供的是底座——消息路由、事件订阅、群管理、用户认证、文件存储,这些都是平台原生能力。底座越厚,你要搭的胶水越少。

具体到 dws:

  • 消息路由 = 模型网关。你在群里 @ Agent A,Agent A 可以 @ Agent B。模型路由变成了消息路由,不需要你自己写 dispatcher。
  • event 订阅 = 可观测性。单聊/@/群聊消息事件、已读、撤回、贴表情——这些事件 Agent 原生就能监听,不需要你自己埋点。
  • 群管理 = 策略引擎。Agent 作为群成员,权限受群规则约束。它不能发消息给不在群里的人,不能修改不是它创建的群公告。平台级的权限控制比你自己写的策略引擎更可靠。

框架给你的是 能力。底座给你的是 约束。能力你自己也能加,约束只有平台能给。而 Harness 的核心价值恰恰是约束——让 Agent 不乱来。

从「能用」到「完备」

回到开头的场景:Agent 帮我写博客、生成配图、排版修复、commit 推送、验证上线。

这套流水线能跑,不是因为模型强——GLM 5.2 和 Qwen 3.7 Max 都不是最强的模型。它能跑,是因为 7 个组件都到位了:模型路由(异构 Agent)、工具(dws 163 条指令)、知识(wiki + 博客 corpus)、记忆(Hermes memory)、策略(渐进信任 + 超时)、观测(event-watcher)、配置(skills + cron)。

缺一个就跑不起来。 没有知识库,它会写出和旧文重复的内容。没有策略引擎,它会半夜给你发 20 条消息。没有可观测性,它说「已完成」你不知道它到底干了什么。没有配置管理,你每次都要重新教它你的写作风格。

这才是 AI 钉钉基建的真正含义:

AI 钉钉基建 = AI-Ready 的工作流数据 × 人-Agent 的原生协同

左边「AI-Ready 的工作流数据」是知识库引擎 + 工具注册表——让 Agent 能读懂和操作系统里的数据。右边「人-Agent 的原生协同」是模型网关 + 记忆 + 策略 + 观测 + 配置——让 Agent 能在 IM 里像一个同事一样工作。

乘号的意思是: 两边都要完备,缺一边就不成立。

所以,如果你的 Agent 项目总是卡在「demo 能跑但上线就崩」,不要急着换模型。先拿那张 7 组件审计表,逐条检查:你的 Harness 完备吗?

你的 Agent 有策略引擎吗?有可观测性吗?有配置管理吗?

如果答案是「没有」或「临时拼了一个」——那问题不在模型,在 Harness。


你在搭 Agent 系统的时候,踩过哪个组件的坑?欢迎留言讨论。


See also