← 博客首页 实验室总入口 SKills实验室 实验索引 / 道合君客服值守
无尘阁 · 自研 Skill
LAB / SKILLS · 自研 · v1.0.0 · 2026-11-08

客户半夜发来一句「在吗」,谁来替你回?

自研 WorkBuddy Skill · 道合君客服值守 · 29 个文件 / 235 KB

这是一个在 Windows 上常驻的值守程序。个人微信里出现新消息,它把「客户说了什么 + 上文下文」交给 WorkBuddy 判断语气和意图,生成贴着原话的回复再发回去;只有课程安排、收费报价、合同方案、投诉这几类必须由人拍板的事,才截图转交。企业微信一个字节都不碰,只在出现未读红点时截图通知,绝不自动回复。

自研 个人微信自动回复 企业微信只读 WorkBuddy 当大脑 Windows 常驻
5条铁律
4层判断链路
23个脚本
5717行代码
01 / WHAT IT DOES

它到底干了什么

一句话:客户随时说话,程序先接住;拿不准的那几条,才交给人。

做培训、做服务的人都躲不开一件事:客户不问时间。晚上十点四十来一句「老师,那个课怎么报」,第二天早上才看见,人已经凉了。可要真做到秒回,等于把自己钉在屏幕上,一天什么都干不成。

这个值守程序站的就是这个位置。它每 60 秒巡检一次两个微信窗口,读到新消息就判一次:这条能不能自己回。能回的当场回,回不了的截图转给李雪。客户那边永远有人应,人这边不用盯着。

关键的一条设计是回复不靠模板。早先的版本用关键词规则,客户说一句「接口请写在我服务器上,配置在 D 盘那个文档里」,规则引擎只答得出「收到,您说的我记下了」——客户一眼就看出来这是机器人。现在把整段对话交给 WorkBuddy 读一遍,让它判断意图、写一句贴合原话的回复,再发回去。实测一次 33 到 41 秒。

第二条设计是企业微信按只读处理。个人微信能回就回,企业微信一个字节都不写:不点击、不输入、不激活窗口。理由写在下面这一节里,代价是真金白银掉过两次登录。

判断

先分清是哪一类事

投诉、起诉、退款、赔偿这类硬拦截,直接转交,不问任何人。剩下的才轮到判断能不能自己回。

口径

不报价、不承诺、不替公司决定

人设写在 persona.md 里,称呼「您」、一到两句、结尾不强行追问,给客户的每一句话都要过这道口径。

防重

同一句话不回第四遍

90 秒内回过的跳过,同一个人一小时最多三条。没有这两道闸,时间读歪的时候同一行会被反复判成新消息。

为什么企业微信一个字节都不许碰

企微有一套输入注入检测。只要注入事件带上 LLMHF_INJECTED 标记,它就判定「设备环境异常」,直接退回扫码页。已经因此掉过两次登录,两次都发生在做 dry run 的时候——只激活窗口、点一下、输入几个字再清空,连回车都没按。

所以读企微只用 PrintWindow:它不需要窗口在前台,也不产生任何输入事件。写操作入口一律先查 send.WRITABLE = {"wechat": True, "wework": False}。

02 / WHEN TO USE

什么时候该把它翻出来

触发词:微信自动回复 / 监控微信新消息 / 客服值守 / 装一下那个监控 / 企业微信有红点通知李雪 / 转交给梦由 / 这个监控怎么又停了 / 开机自启没生效。

场景它交付什么
下班后被客户堵住客户问在不在、问课程怎么走、问开了没,它当场回一句像人说的话,不用等第二天。
客户问价格先回「这个我请李雪跟您确认一下,稍后回复您」,同时把对话截图发给李雪,让能拍板的人接手。
企业微信攒了红点只截图通知,不回一句话。人自己看,人自己回。
早上开工扫一眼半夜压住没回的消息,早上第一轮巡检重新判成新消息,照常处理。
程序自己挂了守护循环 20 秒后自动拉起;真起不来,日志里留一行,doctor.py 能查是哪个窗口不可读。

不适合拿它做的事也说清楚:它不碰群聊和公众号,只看单聊;不给企业微信发一个字;不报价、不承诺时间、不签任何确认——这三条是口径,写在人设里,任何一层都不许越过;不替人做决定,遇到必须由人拍板的事只转交,不猜。

03 / HOW IT DECIDES

两个窗口,两套读法

企业微信能走无障碍接口,个人微信是 Qt 自绘的,只能截屏认字。同一个判断,读法完全两套。

链路 A · 个人微信OCR 读屏
  1. 列表抓图:PrintWindow 抓窗口,不激活、不移动、不点击
  2. 未读判定:红点在头像右上角,不在列表右边缘
  3. 名字识别:绿底白字那行读不出,改用聊天区标题当名字
  4. 点开读正文:点之前重新扫一遍定位行——回过一条,会话就跳到最上面
  5. 回复或转交:判断通过就发,四类事截图转交
链路 B · 企业微信UI Automation
  1. 红点汇总:只看侧边栏那个汇总数字
  2. 只读抓图:PrintWindow,不需要窗口在前台
  3. 红点亮着才动:没红点说明人自己看过了,什么都不做
  4. 截图发李雪:当场裁剪落地,不留到后面再读
  5. 永不自动回复:写操作在这条链路上是关死的
合流 · 四层判断brain.decide
硬拦截:投诉 / 起诉 / 退款 / 赔偿→快路径:整句全是寒暄词→WorkBuddy 读一遍再生成→规则引擎兜底

四层任意一层挂了,下面的照常接手。客户永远有人应,程序也不会因为模型超时就装死。

怎么向 WorkBuddy 提问

WorkBuddy 是 Electron 应用,聊天文字通过 UI Automation 暴露出来,get_app_state(window_id, mode="text") 能拿到屏幕上全部可见文字,还带坐标。这一段不需要 OCR,准确率 100%——整套方案能成立,靠的就是这一条。

提问的协议也刻意做得简单:只要它回两行中文标签,不要 JSON。中文标签在文字流里不会和正文混淆,正则一抓就准。

# 发给 WorkBuddy 的要求:只回两行
动作:回复        (或者:转交)
内容:给客户看的话,40 字以内

这几十秒里窗口会被切到前台。如果检测到输入框里已经有内容,说明人正在里面打字,这一条就主动让开,退回规则引擎——不抢人的键盘。

读个人微信,四个绕不过去的坑

坑怎么处理
选中态读不出上次点开的那行是绿底白字,OCR 直接吐空。反相、二值化、加白边、各种倍率都试过,无效。最后一招是绕开:用聊天区顶部的标题当名字。
时间丢一位21:41 被读成 21 1,解析成 02:11,判成旧消息静默丢掉。现在给时间串打置信度,四位数字对不上就只登记、不推水位。
偏旁被拆开「你」读成「亻+尔」,码位反而变多,打分逻辑主动选了错的版本。现在给偏旁倒扣分,再按表还原。
红点找错地方区域开在列表右边缘,永远返回 0。真实位置是头像右上角,行顶往下 12 像素。

还有一条比时间更可靠的判据:红点是微信自己画的,不受 OCR 错字影响。红点亮着就强制按新消息处理,宁可多回一次,不许漏一条。

04 / STRUCTURE

包里装了什么

29 个文件,235 KB。主流程一份、人设一份、踩坑记录一份、脚本二十三个。

daohu-cs-monitor/
├── SKILL.md                  主流程:五条铁律 + 判断链路 + 故障对照表(8 KB)
├── config.json                人设、转交对象、安静时段、限频
├── persona.md                 回复口径:硬性规则 + 八种场景话术
├── install.py                 一键部署:复制程序、建 state/、写开机自启
├── run-monitor.bat            守护循环:进程挂了 20 秒自动重启
├── references/
│   └── lessons.md             十五条踩坑记录,每条都付过代价(8 KB)
└── scripts/                   23 个脚本,5717 行
    ├── monitor.py             主循环:巡检 → 判定 → 回复 / 转交(625 行)
    ├── brain.py               决策:四层判断的具体实现(709 行)
    ├── wbbrain.py             把 WorkBuddy 当大脑:提问、读回、解析(447 行)
    ├── send.py                发消息:写操作唯一入口,先查 WRITABLE
    ├── capture.py             PrintWindow 抓图,零触碰
    ├── layout.py              自适应布局:窗口尺寸变了不用重标定
    ├── ocr.py                 OCR 封装,返回带坐标的文本行
    ├── ledger.py              台账:每个会话处理到哪条、时间置信度
    ├── inbox.py / watch.py      巡检:零触碰扫描与被动监控
    ├── wx.py / ww.py          两个客户端的各自适配
    ├── kimicu.py              kimi-cu 的 stdio MCP 客户端封装
    ├── llm.py                 HTTP 模型接口(CLI 那条路已经放弃)
    ├── doctor.py              开工自检:两个窗口读不读得到
    ├── notify.py              给李雪补发一句话,手工救场用
    └── winlist / winlib / winfix / act / probe / wwgeo / setkey

主脚本各管一段

脚本职责
monitor.py主循环。每轮先巡检,判出新消息就交给 brain,处理成功了才推水位。
brain.py四层判断的落地点。硬拦截、快路径、模型、规则,一层层往下走。
wbbrain.py整套方案的心脏。找到 WorkBuddy 那个任务、把对话喂进去、等它答完、把两行标签读回来。
send.py所有写操作的唯一出口。发之前先过口径清洗,内部人名一律拦掉。
ledger.py台账。记水位、记处理次数、记最近一次失败,还负责给 OCR 时间打分。
layout.py窗口布局自适应。微信换个尺寸、换台显示器,不用重新量坐标。
install.py换机器时唯一的入口。复制程序、建目录、写启动项,然后打印剩下三件手工活。

跑之前得备齐

依赖用在哪
Windows 10 / 11整套实现都长在 Win32 上:窗口枚举、PrintWindow、命名互斥体
Python 3.13全部脚本;run-monitor.bat 里写死了 WorkBuddy 自带那个解释器路径
微信 PC 版保持登录,窗口可见(最小化也认,但是别关掉)
企业微信同上。只读,不产生任何输入事件
WorkBuddy 并登录回复由它生成。没开就退回关键词规则,不装死
Pillow + winocr截屏与识别,走系统的 OCR 引擎,不要额外装模型
kimi-cu.exe读窗口文字与点开会话的通道
05 / RULES

值守的规矩

五条铁律,改代码之前先读一遍。每一条下面都压着一次事故。

#铁律为什么
1企业微信一个字节都不许碰注入事件带标记,企微判定设备环境异常,直接踢出登录。掉过两次。
2企微只认红点,不按时间判人在企微里自己回过消息,列表时间照样前进。按时间判必然误报。
3企微永不自动回复写操作关死。改这一个开关,等于让企微再掉一次登录。
4个人微信能回就回默认转交是错的——客户问天气也转给李雪,等于让她当人形应答机。
5不该回的时候别回22:30 到 08:00 压着不推水位;同一个人一小时最多三条;群聊与公众号不碰。

三道闸,防止对着同一句话回三遍

第一道是时间置信度:四位数字对不上,就只登记发现时间,不推水位。第二道是 90 秒冷却,刚回过的那一行直接跳过。第三道是每小时三条上限。三道闸合起来,同一个客户不会连着收到三条一模一样的「在的,您说」。

安静时段那条也值得单独说:半夜给客户回消息,比不回更像机器人。这段时间返回「压住」,但是不推水位,早上第一轮巡检会重新把它判成新消息,照常处理,不算漏。

踩过的坑,都留了处理办法

问题处理方式
转交截图发给了李雪自己的窗口截图文件名写死成同一个,先截客户后截李雪,后者覆盖前者。现在文件名带时间戳和序号,并且当场裁剪落地。
转交文案里写了同事名字给客户的兜底话术里混进了内部交接说明。现在发给客户的话要过清洗,内部人名一律拦掉。
发现阶段就推了水位处理失败也当成已经处理,那条消息永远不再处理。现在只有处理成功之后才推水位。
点开的是别人行号用的是上一轮扫描的位置,只要回过一条,后面全错一格。现在点开前重新扫一遍,按名字定位。
WorkBuddy 的任务名会自己变发完第一句,标题就从设置那句话改成别的。现在反过来记:哪些标题不是我们的,剩下那一个就是。
一句话被拆成七行UI Automation 会把一句话按行吐出来。必须先拼成一条再正则,否则只取第一行就是半句话。
命令行调不动 WorkBuddy桌面版装的是精简 CLI,要靠主程序握手才认身份,外部调用一律返回未登录。这条路已经放弃,改走读屏。
06 / DOWNLOAD

拿走它

解压后先跑 python install.py,程序会自己装到 %USERPROFILE%\WorkBuddy\daohu-msg 并写好开机自启,然后打印剩下要手工做的三件事。

道合君客服值守 v1.0.0

29 个文件 · 235 KB 原始体积 · ZIP 102 KB · 含主流程、人设口径、十五条踩坑记录、二十三个脚本与一键部署

文件 daohu-cs-monitor.zip 大小 102 KB 版本 1.0.0 发布 2026-11-08

装法

:: 1. 解压,进目录
:: 2. 一键部署(默认装到 %USERPROFILE%\WorkBuddy\daohu-msg)
python install.py

::    想换目录就带个参数
python install.py D:\tools\daohu

:: 3. 先跑一轮看看日志,不动微信
python scripts\monitor.py --once

:: 4. 没问题就前台常驻(或双击 run-monitor.bat)
python scripts\monitor.py --interval 60 --auto-reply

部署完还有三件手工活,install.py 会把它们再打印一遍:把微信和企业微信都打开、保持窗口可见;打开 WorkBuddy 并登录;改 config.json 里的 targets.alert_contact,改成那台机器微信里李雪的备注名——必须跟备注一字不差,否则找不到人。

注意:技能目录里的 scripts/ 是可移植母版,不要从技能目录直接启动。它没有 state/,起来以后台账从零开始,会把所有老会话当成新消息再回一遍。请走 install.py 装到独立目录。