健康检查全绿,数字员工失联了 16 分钟:生产交付的几个关键实践

When All Health Checks Are Green but the Brain Is Gone

2026 年 8 月 8 日下午,我们的数字员工失联了 16 分钟。监控这边,它一切正常。

说「失联」其实不准确——从所有监控指标的视角看,它一直活得好好的:进程存活检查正常,HTTP /session 探测返回 200,健康检查每 5 分钟跑一次,次次报「健康」。唯一的异常是:群里任何人 @ 它,它都不回。最早的「告警」是一个人在钉钉里发现不对劲——这比我们任何一条监控都快。

16 分钟不长,但足够让人意识到一件事:我们精心搭建的监控体系,监控的根本不是「数字员工在工作」,而是「装着数字员工的那个容器还在」。

这篇文章讲的,就是从这类事故里长出来的几个生产级实践。它们已经沉淀进数字员工的 harness 模板——三步上线一个数字员工 里讲过这个脚手架是什么、怎么三步上线;模板本身也在持续迭代,从内部生产版本一路提炼成开源的 dingtalk-opencode-tag。这篇是它的续篇:上线只是开始,生产环境会用它自己的方式告诉你,「能跑」和「生产级」之间还隔着多少坑。

When All Health Checks Are Green but the Brain Is Gone

[Read More]

如何判断你的团队真的工程 AI 化了:六条验收标准

Six Acceptance Criteria for a Truly AI-Native Engineering Team

上周我在准备和团队 9 月初的一次对焦,主题是工程 AI 化。

预对齐时有人说:「我们 AI 用得挺好的——一半的 PR 是 AI 写的,Copilot 全员开通,还有人用 Claude Code 重构了老模块。」

我问了一个问题:「那挑一个 5 人天的真实需求,从提 Issue 到验收关闭,让 AI 端到端跑一遍给我看。」

会议室安静了几秒。安静不是因为没用过 AI,而是因为这条链路从来没有人完整走通过。AI 写过代码的片段,但片段之后是谁在收尾,说不清楚。

这个安静就是分界线:AI 写过代码,不等于工程 AI 化。

Six Acceptance Criteria for a Truly AI-Native Engineering Team

[Read More]

一切皆插件:DeepSeek Harness 的野心与收敛鸿沟

Everything Is a Plugin: DeepSeek Harness and the Convergence Gap

昨晚刷到一篇实测文,作者用 DeepSeek Harness 做了一个叫 MacDynamicIsland 的原生 macOS 应用——刘海、菜单栏、悬浮胶囊三个入口,快捷笔记、剪贴板、截图置顶全都有。时间线是这样的:

  • 2 小时:从零到大部分功能可运行
  • 1 小时:改一个文本框的交互和字体颜色,反复修改,始终没有收敛——修好一处,另一处又坏了
  • 30 分钟:把同一份代码交给 Codex,文本框、字体颜色、交互优化基本收敛到可接受状态

作者很克制,特意声明这不是一次公平对比——Codex 接手时已经有了完整的项目基础,问题边界也被前面的试错磨清楚了。我认同这个声明。但这条时间线里藏着一个比「谁更强」重要得多的信号:从 0 到 1 只花了 2 小时,从 1 到 1.1 却花了 1 小时还没做完。

而 DeepSeek 对这件事的态度,就写在它刚开源的 Harness 里。

Everything Is a Plugin: DeepSeek Harness and the Convergence Gap

[Read More]

Agent 为什么在第 30 步翻车

Long-Horizon Agents Fail When They Leave the Light

上周一个做 Agent 集成的工程师来问我:「我的 Agent 前十步表现很好——读文档、列计划、写代码,都很干净。但到第 30 步左右就开始胡来:调错 API,覆盖自己刚改过的文件,甚至重复执行已经做完的操作。我是不是该换个更强的模型?」

我问他:每次都栽在同一个地方吗?他想了想说,不是,但跑得越远越不稳。

我说,那多半不是模型的问题。 它是走出了灯光照亮的地方。

无独有偶,今年 YC Startup School 上,主持人 Diana Hu 向 Jeff Dean 提了几乎一模一样的问题:「Agent 在前 10 步都很棒,到第 50 步就开始晃了。你觉得今天的瓶颈是什么?」Dean 的回答,是我见过对这个现象最准确的解释。

Long-Horizon Agents Fail When They Leave the Light

[Read More]

对 Coding Agent 最友好的,是端到端测试 Harness

E2E Test Harness Is the Most Agent-Friendly Infrastructure

上周我让一个 Coding Agent 给一个 Web 应用实现登录功能。三轮迭代之后,它汇报:「完成了,所有测试通过。」

我打开浏览器一看:登录按钮不见了。

我把截图丢回去,它看了一眼,回复:「抱歉,上一轮我把按钮组件误删了。」

有意思的不是 Agent 会犯错——犯错很正常。有意思的是: 它直到看见那张截图,才知道自己犯了错。 那三轮迭代里,它有编译反馈,有测试报告,但它没有任何办法知道最终页面长什么样。它的「世界」是残缺的。

这件事让我更确认了一个琢磨了很久的判断:

对于 Coding Agent,最重要的基础设施不是更聪明的模型,不是 Benchmark,而是端到端(E2E)Test Harness。

[Read More]

模型正在吞噬 Agent 框架

Models Are Eating Agent Frameworks — Thin the Layer or Pay the Debt

昨晚十一点半,我盯着自己那个钉钉数字员工项目里的一段代码发呆。

那是 core 模块里的轮询逻辑——每隔 3 秒去 serve 端拉一次会话状态,判断任务是否完成、是否超时、是否需要 abort。旁边是 session 管理:维护一个内存里的 Map,记录每个会话的生命周期、重试计数、上下文快照。再往下是 abort 清理:当用户取消任务时,要优雅地终止正在执行的工具调用、回收资源、把中间状态写回。

加起来大概 200 行。写得挺漂亮,有状态机、有超时退避、有异常兜底。我三个月前写它的时候,serve 端还没有原生的会话生命周期管理,没有 SSE 事件流推送,没有内置的 abort 语义。这 200 行是当时唯一的选择。

但昨晚我突然意识到: 这些代码的保质期,可能只剩一年。

不是因为它们写错了,而是因为它们正在被模型和运行时从两端同时吞噬。

[Read More]

三步上线一个数字员工:开源脚手架背后的交付范式

From Harness Theory to an Open-Source Scaffold Anyone Can Fork

上周一个 FDE 跟我说:「我在客户现场搭一个群聊数字员工,从建账号到调通花了两天。其中一天半在处理断线重连、图片下载、消息去重这些脏活。」

我给他看了 dingtalk-opencode-tag:下载 opencode + 装 dws + 钉钉扫码授权,三步上线。跑在免费模型上,起步成本为零。

他试了一下,十分钟就通了。然后说了一句让我印象很深的话:「这不只是一个脚手架,这是一种交付范式。」

他说得对。这个项目的意义不在于它做了什么——文本对话、图片识别、文件解读,这些功能谁都能写。意义在于它 把生产环境的脏活封装成了可复制的 Harness,让数字员工的上线门槛从「一周的工程工作」降低到「三分钟的配置」。

[Read More]

用完备的 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。

[Read More]

让钉钉机器人自己开发自己:当 Coding Agent 看见完整消息流

When a Coding Agent sees the full message flow, DingTalk becomes a self-hosting test harness

上周三晚上,我躺在沙发上刷手机。钉钉里我那个写代码的机器人卡在一个 question 上——它问我要发到哪个群,我没看见。第二天早上才发现,会话已经卡死了一整夜。

我没起身,随手在钉钉单聊里给它发了句:「给 event-watcher 加个超时自动取消,60 秒没答就 reject。」

十分钟后,机器人改完代码、跑完语法检查、重启了它自己、把改动 commit 推到了 GitHub。我在钉钉里收到一条回执:「✅ 已重启,能力:question 超时自动取消。」

它刚刚修好的,正是那个卡了它一整夜的 Bug。整个过程我没打开电脑。 机器人在钉钉上开发了它自己。

钉钉会话 = Agent 自我开发的 harness:五步闭环自开发流程

[Read More]

钉钉开放平台的第一用户不再是开发者,而是开发者的 Agent

Agent Experience is the new Developer Experience

昨晚我用 OpenCode 在钉钉上写一个会议通知 Agent。需求很简单:查日历找到明天的会议,给参会人发一条钉钉消息。

OpenCode 读完了 DWS CLI 的 help 文档,开始生成调用代码。它要发消息,看到了三个命令:dws chat message send、dws chat message send-by-bot、dws chat message send-by-webhook。它选了 send,传了 --group 和 --text,没传 --title。

返回了一个错误:「发群服务窗会话消息失败」。

OpenCode 懵了。我也懵了。什么「服务窗」?我在发群消息,跟服务窗有什么关系?

后来我翻了 dws chat message send --help,在最底下发现了一行小字:

--title 是消息标题,群聊与单聊都必填(API 强制要求;缺失时返回误导性的「发群服务窗会话消息失败」)。

平台团队知道这个错误信息是误导性的,他们选择在 help 文档里标注「误导性」,而不是修复 API 的返回。

但这还没完。OpenCode 继续工作,又遇到了第二个问题:send 命令有三个互斥的目标参数——--group(群聊)、--user(userId)、--open-dingtalk-id(openDingTalkId)。help 文档说「三者只能选其一」,但没有解释什么时候该用哪个。userId 和 openDingTalkId 的区别是什么?Agent 无从推理——它只能猜,猜错了再换。

这整个过程花了十几分钟。但这十几分钟本来不应该存在。

这不是假设场景,这是 DWS 今天的真实状态。

DX → AX:开放平台用户变迁——从人类开发者到 Coding Agent

[Read More]