<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>AI on 送命或寻欢</title><link>https://lxh.io/tags/ai/</link><description>Recent content in AI on 送命或寻欢</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><managingEditor>lxh@cxh.cn (李寻欢)</managingEditor><webMaster>lxh@cxh.cn (李寻欢)</webMaster><lastBuildDate>Mon, 21 Sep 2026 14:57:32 +0800</lastBuildDate><atom:link href="https://lxh.io/tags/ai/index.xml" rel="self" type="application/rss+xml"/><item><title>在这个 AI 爆发的时代，我做了些什么</title><link>https://lxh.io/post/2026/what-i-did-in-ai-era/</link><pubDate>Mon, 21 Sep 2026 14:57:32 +0800</pubDate><author>lxh@cxh.cn (李寻欢)</author><guid>https://lxh.io/post/2026/what-i-did-in-ai-era/</guid><description>&lt;h2 id="楔子"&gt;楔子&lt;/h2&gt;
&lt;p&gt;《列子·汤问》里有个叫偃师的工匠，给周穆王献过一个&amp;quot;倡者&amp;quot;——一个会唱歌跳舞的人偶。&lt;/p&gt;
&lt;p&gt;表演快结束的时候，这个人偶朝穆王的姬妾抛了个媚眼。穆王大怒，要当场杀了偃师。偃师没辩解，只是把人偶拆开给他看：里面全是皮革、木头、胶漆和颜料，五脏六腑一应俱全，但都是假的。拆掉心脏，它就不能说话；拆掉肝脏，它就不能看东西；拆掉肾脏，它就不能走路。&lt;/p&gt;</description><content>&lt;h2 id="楔子"&gt;楔子&lt;/h2&gt;
&lt;p&gt;《列子·汤问》里有个叫偃师的工匠，给周穆王献过一个&amp;quot;倡者&amp;quot;——一个会唱歌跳舞的人偶。&lt;/p&gt;
&lt;p&gt;表演快结束的时候，这个人偶朝穆王的姬妾抛了个媚眼。穆王大怒，要当场杀了偃师。偃师没辩解，只是把人偶拆开给他看：里面全是皮革、木头、胶漆和颜料，五脏六腑一应俱全，但都是假的。拆掉心脏，它就不能说话；拆掉肝脏，它就不能看东西；拆掉肾脏，它就不能走路。&lt;/p&gt;
&lt;p&gt;穆王看完，叹了一句：&amp;ldquo;人之巧乃可与造化者同功乎？&amp;rdquo;&lt;/p&gt;
&lt;p&gt;这个名字我是在第四版的时候才用上的，当时只觉得好听。写到第五版才明白，这个典故真正的重点不在&amp;quot;造得像人&amp;quot;，而在最后那一下拆开——穆王的愤怒源于它表现得太像人了，而平息愤怒的方式，是证明它里面全是机关。&lt;/p&gt;
&lt;p&gt;至于我这个偃师，机关是从五年前一个睡不着的半夜开始装的。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="2020-年-3-月-12-日半夜"&gt;2020 年 3 月 12 日，半夜&lt;/h2&gt;
&lt;p&gt;那天半夜我突然冒出一个念头：微信有没有把我这个人记下来？&lt;/p&gt;
&lt;p&gt;不是那种阴谋论式的担心，是一个很具体的好奇——我每天在这个软件里敲这么多字，它手里应该有一份比我自己还清楚的我。我的爱好、我的作息、我跟谁最亲近，全在里面躺着。&lt;/p&gt;
&lt;p&gt;于是我开始搜微信的数据库存在哪儿，怎么解密。&lt;/p&gt;
&lt;p&gt;那天晚上我做出了人生第一份聊天报告。&lt;/p&gt;
&lt;p&gt;我知道了自己最爱说的是哪几个词，知道了自己一天里哪个时段最话痨，知道了跟我聊得最多的人是谁，还知道了我最喜欢用什么形式的消息。&lt;/p&gt;
&lt;p&gt;所以那个问题的答案是：记下来了，一条不落。而且解出来比我以为的容易得多。&lt;/p&gt;
&lt;p&gt;从这天开始，我就跟微信&amp;quot;杠&amp;quot;上了。&lt;/p&gt;
&lt;h2 id="2021-年-5-月让它一直跑着"&gt;2021 年 5 月：让它一直跑着&lt;/h2&gt;
&lt;p&gt;一年后，我建了个文件夹，叫 &lt;code&gt;web-wechat&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;想法特别朴素：那份报告是我手动解出来的，一次性的，做完就没了。我想要个能一直跑着的东西，把聊天记录自动存下来，以后想什么时候出报告就什么时候出。&lt;/p&gt;
&lt;p&gt;技术上这一版是正经的：走网页版协议，扫码登录、收消息、存库，图片视频语音全都转存到对象存储。2022 行，公开仓库，还有人给我提过 PR。五个版本里只有它真被别人用过。&lt;/p&gt;
&lt;p&gt;东西跑起来之后我发现一件事：它已经在群里了，而且它认识时间。&lt;/p&gt;
&lt;p&gt;于是我给它加了倒计时提醒。&lt;code&gt;command.go&lt;/code&gt; 里支持的全部指令就三个：放假倒计时、过节倒计时、下班倒计时。&lt;/p&gt;
&lt;p&gt;这三个里我最偏爱下班倒计时。正常情况它老老实实回你&amp;quot;距离下班还有 X 小时 Y 分钟&amp;quot;，但你要是挑周末或者节假日问它：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;不会吧不会吧，不会有人{节日}还在上班吧&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;晚上六点以后问，它也不客气：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;不会吧不会吧，不会有人这个点还没下班吧&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;放假倒计时同样欠揍。还剩一两天它说&amp;quot;{明天}就是{节日}啦，再坚持一下咯~&amp;quot;，正日子问它就是&amp;quot;今天已经是{节日}了啊，不会你还没放假吧？&amp;quot;，一年的节都过完了它会告诉你&amp;quot;今年的节日好像已经过完了咯~&amp;quot;。&lt;/p&gt;
&lt;p&gt;这些话发送失败的时候，日志里打的是这么一行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log.&lt;span style="color:#06b;font-weight:bold"&gt;Errorf&lt;/span&gt;(&lt;span style="background-color:#fff0f0"&gt;&amp;#34;阴阳怪气失败: %v&amp;#34;&lt;/span&gt;,&lt;span style="color:#bbb"&gt; &lt;/span&gt;err.&lt;span style="color:#06b;font-weight:bold"&gt;Error&lt;/span&gt;())&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;阴阳怪气失败。2021 年的我，是把阴阳怪气当成一个正式功能在写的。&lt;/p&gt;
&lt;p&gt;它待的一直是我那几个朋友群，后来多了个 web-wechat 的项目群，没进过工作群。答傻了就答傻了，有人截个图笑话它两句，顺便笑话我，仅此而已。&lt;/p&gt;
&lt;p&gt;至于统计报告，越往后越没人再提起。倒是另一个念头冒了出来：这堆聊天记录反正一直在攒，为什么不给群里也出一份？谁昨天话最多，谁最爱发表情包。&lt;/p&gt;
&lt;p&gt;想是这么想，web-wechat 没做。2021 年 11 月，这个仓库的提交停了。&lt;/p&gt;
&lt;h2 id="2022-年-1-月摸鱼王划水公摆烂侯"&gt;2022 年 1 月：摸鱼王、划水公、摆烂侯&lt;/h2&gt;
&lt;p&gt;网页版协议能拿到的东西太少，做排行榜那点数据抠得很费劲。我盯上了另一条路：iPad 协议。&lt;/p&gt;
&lt;p&gt;于是 2022 年 1 月，新开一个仓库，叫 &lt;code&gt;wechat4ipad&lt;/code&gt;。半年，121 个 commit，85 个文件，4975 行。&lt;/p&gt;
&lt;p&gt;排行榜是在这一版做出来的。每天早上八点，一条叫&amp;quot;#昨日水群榜&amp;quot;的消息准时发进群里，给昨天说话最多的三个人各发一个称号：摸鱼王、划水公、摆烂侯。&lt;/p&gt;
&lt;p&gt;说得越多，爵位越大。&lt;/p&gt;
&lt;p&gt;从 2020 年那个半夜到这里整整两年，我终于把当初那份只给自己看的报告，变成了一个当众点名的东西。虽然它跟&amp;quot;洞察人性&amp;quot;已经没什么关系了，就是每天告诉大家昨天谁最闲。&lt;/p&gt;
&lt;p&gt;这一版还有个我挺喜欢的功能，指令叫&amp;quot;启用偷偷赚大钱&amp;quot;。判断条件是工作日的上班时间，中午十二点到两点除外，那是午休。一个群要是超过两小时没人说话，机器人就自己跳出来发条消息，配个表情包，问问大家是不是都在偷偷赚大钱。&lt;/p&gt;
&lt;p&gt;一个定时器，一个时间窗口，一个 if。&lt;/p&gt;
&lt;p&gt;但这是我第一次让机器人在没人叫它的时候主动开口。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;你叫它、它回答你&amp;quot;也是这一版才有的。处理器的第一件事就是判断有没有被 @，是的话直接走 NLP——腾讯云的智能闲聊接口。2022 年上半年没有大模型可用，所谓&amp;quot;聊天机器人&amp;quot;就是调一个云厂商的闲聊 API，你问一句它答一句，答得怎么样全看运气。&lt;/p&gt;
&lt;p&gt;答得再傻，这也是这个项目里第一次有人叫它、它就回话。比 ChatGPT 早了将近一年。&lt;/p&gt;
&lt;p&gt;2022 年 6 月，iPad 协议过期了，账号也被封了。逆向来的东西都这样，能用多久没人说得准，哪天失效了顺带把号一起带走。&lt;/p&gt;
&lt;p&gt;这是第二次了。第一次是网页版协议被关，这次是 iPad 协议过期。我开始隐约意识到一件事：我做的所有东西，脚底下踩的那块地都不是我的。&lt;/p&gt;
&lt;h2 id="2022-年-12-月ai-第一次撞进来"&gt;2022 年 12 月：AI 第一次撞进来&lt;/h2&gt;
&lt;p&gt;半年后，ChatGPT 发布。第十二天，我给 &lt;code&gt;web-wechat&lt;/code&gt; 加了一个插件。&lt;/p&gt;
&lt;p&gt;加回那个已经半年没动的老仓库，理由很简单：web-wechat 是公开的，有人在用，给用的人添个新玩意儿。&lt;/p&gt;
&lt;p&gt;当天的 README 更新只有一句：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2022-12-12，跟个风对接了 &lt;code&gt;ChatGPT&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;字面意思。我知道这东西很厉害，但不知道它厉害在哪，更不知道能拿它干什么，所以就把接口接上，剩下的让用的人自己玩去。&lt;/p&gt;
&lt;p&gt;于是 &lt;code&gt;open_gpt.go&lt;/code&gt; 成了这个仓库的第五个插件，排在&amp;quot;下班自动回复&amp;quot;后面。&lt;/p&gt;
&lt;p&gt;触发方式还不是 @ 机器人，是个写死的字符串：消息第一行必须是 &lt;code&gt;@openai&lt;/code&gt;，从第二行开始才是你要问的。&lt;/p&gt;
&lt;p&gt;然后是这个插件的全部智能所在：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#888"&gt;// 组装消息 TODO 懒得搞上下文联动，有想法的可以自己实现，&lt;/span&gt;&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#888"&gt;// 只需要组装一下下面这个Message字段就行了，把之前的记录带过去&lt;/span&gt;&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;request&lt;span style="color:#bbb"&gt; &lt;/span&gt;&lt;span style="color:#333"&gt;:=&lt;/span&gt;&lt;span style="color:#bbb"&gt; &lt;/span&gt;gpt3.ChatCompletionRequest{&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#bbb"&gt; &lt;/span&gt;Model:&lt;span style="color:#bbb"&gt; &lt;/span&gt;gpt3.GPT3Dot5Turbo0301,&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#bbb"&gt; &lt;/span&gt;Messages:&lt;span style="color:#bbb"&gt; &lt;/span&gt;[]gpt3.ChatCompletionRequestMessage{{Role:&lt;span style="color:#bbb"&gt; &lt;/span&gt;&lt;span style="background-color:#fff0f0"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;,&lt;span style="color:#bbb"&gt; &lt;/span&gt;Content:&lt;span style="color:#bbb"&gt; &lt;/span&gt;question}},&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那个 &lt;code&gt;Messages&lt;/code&gt; 数组，长度永远是 1。&lt;/p&gt;
&lt;p&gt;没有历史，没有 system prompt，没有人设。你上一句问了什么，它下一句完全不知道。出错了就把 Go 的原始 error 直接甩到群里，后面跟着一长串带 API 地址的英文报错。&lt;/p&gt;
&lt;p&gt;而我给自己留的注释是：&amp;ldquo;懒得搞上下文联动，有想法的可以自己实现。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;有想法的人&amp;quot;指的当然是别人。&lt;/p&gt;
&lt;p&gt;这个插件只活了半年。2023 年 6 月，微信把网页版的登录入口也关了，新号扫不上码，web-wechat 跟着一起没了。&lt;/p&gt;
&lt;p&gt;两年死两次，死因是同一个：我够不着的那一层。&lt;/p&gt;
&lt;h2 id="2024-年-2-月一栋精装修的空房子"&gt;2024 年 2 月：一栋精装修的空房子&lt;/h2&gt;
&lt;p&gt;两条协议路都断了，第三版只剩下最后一个选择：往 PC 端微信进程里注入 DLL，从内存里把消息 hook 出来。代价是我得伺候一台 Windows 机器 7×24 小时开着微信客户端，不能关机，不能更新，最好连碰都别碰。&lt;/p&gt;
&lt;p&gt;当时我觉得这挺合理的。&lt;/p&gt;
&lt;p&gt;这次我给自己定的目标是&amp;quot;做个正经平台&amp;rdquo;。于是该上的全上了：消息队列、完整 RBAC、OAuth2 加图形验证码、协程池、定时任务、配置热重载。最得意的是一套 Lua 插件系统，虚拟机池、并发控制、生命周期管理，我还给它写了单元测试。&lt;/p&gt;
&lt;p&gt;readme 里的功能列表五条：机器人管理、消息管理、插件系统、AI 助手模块、todo。&lt;/p&gt;
&lt;p&gt;看起来挺唬人的对吧。我当时也这么觉得。&lt;/p&gt;
&lt;p&gt;那套我最得意的 Lua 插件系统，暴露给插件的全部 API 是这样的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#888"&gt;// wxhelper函数映射&lt;/span&gt;&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#080;font-weight:bold"&gt;var&lt;/span&gt;&lt;span style="color:#bbb"&gt; &lt;/span&gt;wxhelperFuncMap&lt;span style="color:#bbb"&gt; &lt;/span&gt;=&lt;span style="color:#bbb"&gt; &lt;/span&gt;&lt;span style="color:#080;font-weight:bold"&gt;map&lt;/span&gt;[&lt;span style="color:#339;font-weight:bold"&gt;string&lt;/span&gt;]lua.LGFunction{&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#bbb"&gt; &lt;/span&gt;&lt;span style="background-color:#fff0f0"&gt;&amp;#34;SendTestMsg&amp;#34;&lt;/span&gt;:&lt;span style="color:#bbb"&gt; &lt;/span&gt;&lt;span style="color:#080;font-weight:bold"&gt;nil&lt;/span&gt;,&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而从池子里取虚拟机那个调用，整个仓库只出现在 &lt;code&gt;pool_test.go&lt;/code&gt; 里。池子、并发控制、生命周期、单元测试我全写完了，唯一跑过这套系统的是它自己的测试。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;AI 助手模块&amp;quot;也有一张像模像样的表：名称、人设、模型、是否启用，配套的增删改查、路由、参数校验一个不少。你可以在后台新建一个助手，给它起名叫&amp;quot;小美&amp;rdquo;，写上人设，选好模型，点启用。&lt;/p&gt;
&lt;p&gt;而这个项目的 &lt;code&gt;go.mod&lt;/code&gt; 里，没有 OpenAI，一个大模型 SDK 都没有。处理每条微信消息的那个函数，从头到尾只干三件事：解析 JSON、切出发信人、存库。&lt;/p&gt;
&lt;p&gt;你精心配置的那个&amp;quot;小美&amp;rdquo;，会一直躺在那张表里，没有一行代码会去读它。&lt;/p&gt;
&lt;p&gt;联系人表里还有个老熟人：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SkipChatRank&lt;span style="color:#bbb"&gt; &lt;/span&gt;&lt;span style="color:#339;font-weight:bold"&gt;bool&lt;/span&gt;&lt;span style="color:#bbb"&gt; &lt;/span&gt;&lt;span style="background-color:#fff0f0"&gt;`gorm:&amp;#34;comment:&amp;#39;是否跳过聊天排行&amp;#39;&amp;#34;`&lt;/span&gt;&lt;span style="color:#bbb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可这一版根本没有聊天排行。两年前那个摸鱼王划水公摆烂侯，我一行都没往这儿搬。&lt;/p&gt;
&lt;p&gt;三样东西，全是架子。那阵子本职工作特别忙，留给这个项目的只有零碎时间，而零碎时间刚好只够搭架子：建张表、定个接口、起个连接池，边界清楚，一晚上能收尾，做完还挺有成就感。把一个功能从头打通要的是整块时间和连续的注意力，那个我当时给不起。&lt;/p&gt;
&lt;p&gt;然后我就伺候不动了。那台必须 7×24 开着微信的 Windows 机器，微信一更新就可能失效，hook 一失效整条链路就断，修一次过阵子再断一次。2024 年 2 月 29 日，最后一次提交。&lt;/p&gt;
&lt;p&gt;更要命的是，我的微信号被封了。号一封，什么正经平台、什么虚拟机池、什么 RBAC 全是废话，你连不上去了。&lt;/p&gt;
&lt;p&gt;两年前 iPad 协议那次我就赔过一个号，也已经明白了脚底下那块地不是我的。明白归明白，我转头又挑了条同样是逆向出来的路，然后又赔一个。&lt;/p&gt;
&lt;p&gt;这次赔得比上次疼。服务器挂了可以再开一台，微信号里装的是你的联系人、你的群、你这些年的聊天记录，它不是我项目的基础设施，它就是我本人。&lt;/p&gt;
&lt;p&gt;等了大半年才解封，解封之后还得老老实实当个人用一阵子把号养回来，又是几个月。所以那个&amp;quot;停更十八个月&amp;quot;不是我热情过了跑去干别的，是我没有号。而这段时间，正好是这个行业炸得最厉害的时候。&lt;/p&gt;
&lt;p&gt;至于那栋空房子，等我有号的时候，我已经不想再回去住了。&lt;/p&gt;
&lt;h2 id="2025-年-9-月偃师"&gt;2025 年 9 月：偃师&lt;/h2&gt;
&lt;p&gt;让我重新开始的不是什么顿悟，是两件事同时到位了：号养回来了，模型也终于追上来了。&lt;/p&gt;
&lt;p&gt;工具调用稳定了，上下文长了，结构化输出能用了。三年前我说自己&amp;quot;跟个风&amp;quot;、不知道这东西能干什么，现在知道了。&lt;/p&gt;
&lt;p&gt;2025 年 9 月 8 日，第四版第一次提交。这次我给它起了名字：偃师。&lt;/p&gt;
&lt;p&gt;前三版我管它叫&amp;quot;网页微信&amp;quot;、&amp;ldquo;iPad 协议机器人&amp;rdquo;、&amp;ldquo;微信机器人&amp;rdquo;，都是工具的名字。这次不一样了，虽然当时我只是觉得这名字好听。&lt;/p&gt;
&lt;p&gt;这一版写了整整一年，235 个 commit，两万两千行后端加九千多行前端。接入方式换成了第三方微信协议服务，终于不用再伺候那台 Windows 了。&lt;/p&gt;
&lt;p&gt;这一版是真做进去了。各类消息都能解析归档，每个好友和群单独配人设、模型和提示词，工具和技能都能挂，记忆做了三种并且带向量检索。群里没 @ 它的消息会先过一道裁判模型判断该不该接话——那个&amp;quot;偷偷赚大钱&amp;quot;的 if，到这儿变成了一次模型调用。&lt;/p&gt;
&lt;p&gt;跟第三版最大的区别不在技术栈，在于这次我先做的是&amp;quot;它要干什么&amp;quot;，扩展性一个字没写。工具和技能是后来加的，因为我真的需要它们去查东西、跑脚本。&lt;/p&gt;
&lt;p&gt;这一版是能用的。能部署、能运营、别人拿去也能跑。它没崩过，也没出过事故。&lt;/p&gt;
&lt;h2 id="灵光一闪"&gt;灵光一闪&lt;/h2&gt;
&lt;p&gt;也是第四版那阵子，我干了件当时以为只是好玩的事。&lt;/p&gt;
&lt;p&gt;我把自己这些年的聊天记录翻出来，连同已经攒下的那些记忆总结，一起蒸馏成一套人设，配给一个 Agent，然后扔进了一个老朋友群。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;02：确实 我甚至可以带入**(我)在说这段话&lt;/p&gt;
&lt;p&gt;侯师傅：这勾八机器人跟**嘴脸一毛一样。看它回复我都能想到你的脸=嘴脸&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在那之前，我做的一直是&amp;quot;一个会聊天的机器人&amp;quot;。它可以有人设、有记忆，但那是给它穿的衣服，脱下来它还是个工具。&lt;/p&gt;
&lt;p&gt;这两句之后，我脑子里的东西变了：如果它能像到这个地步，那能不能做一个在赛博世界里不会消失的&amp;quot;我&amp;quot;？&lt;/p&gt;
&lt;p&gt;当然不一定非得是我。人设换一个，它就是另一个人——这也是后来第五版把人设、记忆、关系全都做成可配置的原因。但那天真正让我动心的，是&amp;quot;我&amp;quot;这个念头。&lt;/p&gt;
&lt;h2 id="ai-真正改掉的东西"&gt;AI 真正改掉的东西&lt;/h2&gt;
&lt;p&gt;目标一变，第四版立刻就不够用了。&lt;/p&gt;
&lt;p&gt;而这一年里 AI 对我做的事，比&amp;quot;写代码变快了&amp;quot;要复杂一些。&lt;/p&gt;
&lt;h3 id="想法开始变多"&gt;想法开始变多&lt;/h3&gt;
&lt;p&gt;第四版跑顺之后就进入了那种挺舒服的状态：不用再大动，隔三差五修个小毛病，想起来什么就顺手加点什么。也就是在这段修修补补的日子里，我开始让 AI 帮我写代码。一开始只是补补测试、改改样板，后来越用越多。&lt;/p&gt;
&lt;p&gt;产出速度确实上去了，但真正的变化不在速度上——是我的想法开始变多。&lt;/p&gt;
&lt;p&gt;以前想加个功能，得在脑子里掂量好几天值不值得动手，因为动手意味着接下来几个晚上都搭进去了。成本一降，想法就不值钱了，&amp;ldquo;试试呗&amp;quot;这三个字出现的频率高得可怕。&lt;/p&gt;
&lt;p&gt;然后我发现，这些想法塞不进去。&lt;/p&gt;
&lt;p&gt;第四版的架构是照着&amp;quot;一个能聊天的机器人&amp;quot;长出来的，每一块单看都对，但凡要往里加点什么，你会发现得从消息入口一路改到发送出口，动一处牵一片。它不是不能改，是改起来不划算。&lt;/p&gt;
&lt;p&gt;干了十二年开发，这种局面我不是第一次碰上。每开一个新项目我都会提醒自己想远一点、架子留活一点，别又把自己堵死，然后每一次还是会走到积重难返这一步。&lt;/p&gt;
&lt;p&gt;大概这就是写东西的宿命：你只能照着开工那天的理解去设计，而后来真正逼你动架构的，全是那天你还想不到的东西。&lt;/p&gt;
&lt;h3 id="读的成本塌了"&gt;读的成本塌了&lt;/h3&gt;
&lt;p&gt;定下&amp;quot;做一个不会消失的我&amp;quot;这个目标之后，我没有马上动手，先去看了看别人是怎么做的。&lt;/p&gt;
&lt;p&gt;我找了些 Agent 开发的课看，然后开始读源码。这回我是让 AI 陪着一起读的，它负责定位和梳理，我负责判断。&lt;/p&gt;
&lt;p&gt;goclaw、hermes-agent、picoclaw，三个项目读下来，我把每家值得学的地方整理成文档，加起来一千七百多行。后来它们跟着进了新版本的 &lt;code&gt;docs&lt;/code&gt; 目录，不是当存档，是当我自己的经验——别人已经想明白的事，我记下来，往后就照着办。&lt;/p&gt;
&lt;p&gt;goclaw 那份里记着一组数字：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;生产 Go 文件 1,456
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;生产 Go 代码行 275,279
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Go 测试文件 917
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而我那个&amp;quot;能跑、能部署、没出过事故&amp;quot;的第四版，两万两千行。&lt;/p&gt;
&lt;p&gt;那几天我脑子里反复冒出来的念头是：我这个就是个毛坯。&lt;/p&gt;
&lt;p&gt;毛坯不等于不好用，它一直挺好用的。毛坯是说它没有骨架。别人那边有明确的分层流水线，有一级的安全与治理，有&amp;quot;核心收成窄腰、能力往边缘长&amp;quot;这种想清楚了才定得下来的结构；我这边是一堆能跑通的代码堆在一起，靠我的记性维持秩序。&lt;/p&gt;
&lt;p&gt;这一步搁以前我多半不会走。一个二十多万行的陌生项目我未必读得完，更别说一口气读三个还写出一千七百行笔记——不是我不想，是成本太高，我会告诉自己&amp;quot;先不看了，反正我这个够用&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;AI 把这个借口拿走了。&lt;/p&gt;
&lt;h3 id="错的东西也变快了"&gt;错的东西也变快了&lt;/h3&gt;
&lt;p&gt;但同一件事还有另一面：盖空房子的速度，同样快了五倍。&lt;/p&gt;
&lt;p&gt;2024 年我手搓一个没人用的 Lua 虚拟机池要花好几天，今天我一个下午能造十个，每个都配齐测试和文档，README 写得漂漂亮亮，摆出来谁看了都得夸一句。&lt;/p&gt;
&lt;p&gt;当年那栋空房子是因为我时间不够，只够搭架子。换句话说，那时候成本本身就是一道过滤器——大部分不成熟的想法，还没轮到被验证，就先被&amp;quot;我没空&amp;quot;挡住了。&lt;/p&gt;
&lt;p&gt;现在这道过滤器没了。&lt;/p&gt;
&lt;p&gt;以前我的问题是&amp;quot;想法很多，但没时间做&amp;quot;。现在是&amp;quot;想法很多，而且半天就能做出来&amp;quot;。瓶颈从生产能力挪到了判断能力上：代码不再稀缺，稀缺的是知道哪些代码根本就不该存在。&lt;/p&gt;
&lt;p&gt;一个错误的想法，现在可以在一个下午里拥有实现、测试、文档和 README，看起来跟一个正确的想法一模一样。&lt;/p&gt;
&lt;p&gt;所以在第五版上，&amp;ldquo;我应该做什么&amp;quot;和&amp;quot;什么事情绝对不能发生&amp;rdquo;，第一次变得比&amp;quot;这段代码怎么写&amp;quot;更重要。&lt;/p&gt;
&lt;h2 id="2026-年-7-月先写禁令再写代码"&gt;2026 年 7 月：先写禁令，再写代码&lt;/h2&gt;
&lt;p&gt;第五版没从 &lt;code&gt;main.go&lt;/code&gt; 开始写。&lt;/p&gt;
&lt;p&gt;我先自己把想要的东西一点点想清楚，落成一份四千多行、一万多字的设计文档。&lt;/p&gt;
&lt;p&gt;然后是那几个通宵。一万多字滚成了十余万字的 spec，我跟 Claude 和 ChatGPT 一句一句过，每一条边界情况都得有个交代才放行。那阵子天天干到凌晨两三点，一行代码没写。&lt;/p&gt;
&lt;p&gt;里面有五十五条编了号的规矩，从 R-01 到 R-55，每条都是一句不能违反的话。不能丢消息，不能重复发送，不能要求人工点重试，摘要不能当成记忆。&lt;/p&gt;
&lt;p&gt;等一下。先写一大堆设计再动手——这不就是 2024 年那个空房子的做法吗？&lt;/p&gt;
&lt;p&gt;区别在于我写下来的是什么东西。&lt;/p&gt;
&lt;p&gt;2024 年那一堆，本质上全是承诺。插件系统承诺以后能插进来点什么，RBAC 承诺以后会有很多人来用，那个&amp;quot;是否跳过聊天排行&amp;quot;的开关承诺以后会有排行。承诺的麻烦在于你没法判它的对错——那个&amp;quot;以后&amp;quot;还没来，谁也说不出它错在哪，它就只能安安静静地烂在那儿。&lt;/p&gt;
&lt;p&gt;这五十五条是禁令。禁令能被违反，一违反就看得见，所以每一条都能写成检查、写成测试、写成门禁，在我图省事的时候当场拦住我。&lt;/p&gt;
&lt;p&gt;说白了，我的活儿变了。以前我负责把功能写出来，现在我得先划出哪些事情绝对不许发生。&lt;/p&gt;
&lt;p&gt;spec 定稿之后，代码才开始动。那阵子 vibe coding 正热，我也就这么上手了。&lt;/p&gt;
&lt;p&gt;2022 年我也在风口上接过一次 ChatGPT，那回是因为压根不知道它能干什么，先接上再说。这次不一样：我很清楚自己要什么，手里有十余万字的 spec 和五十五条不能违反的规矩，缺的只是把十一万行代码敲出来的产能。&lt;/p&gt;
&lt;p&gt;vibe coding 负责把它们敲出来。那五十五条负责保证敲出来的东西不会又变成 2024 年那栋房子。&lt;/p&gt;
&lt;p&gt;到今天，第五版 286 个 commit、11.6 万行生产代码、10.7 万行测试、1957 个测试函数、83 个数据库迁移、5.2 万行前端，外加四个我自己写的门禁工具。是第四版的五倍多，而用户能看到的功能几乎一模一样。&lt;/p&gt;
&lt;p&gt;这些数字看着唬人，但行数从来不等于工作量，它只说明机械的那部分被 AI 接走了。真正花掉我时间的是另外一半：定边界、写约束、把 spec 磨到每种意外都有交代、然后逐个验收它到底有没有照着办。&lt;/p&gt;
&lt;p&gt;这五倍全花在了同一个问题上：一个替我说话的东西，怎样才能不把事情搞砸。&lt;/p&gt;
&lt;h3 id="不能假装没听见"&gt;不能假装没听见&lt;/h3&gt;
&lt;p&gt;前四版处理消息都很直接：来一条，处理一条，忙不过来就让它等着，或者干脆不接。娱乐机器人这么干完全没毛病，我也这么干了五年。&lt;/p&gt;
&lt;p&gt;但一个要长期替我说话的东西不行。&lt;/p&gt;
&lt;p&gt;所以第五版里，消息不再是来一条处理一条。连着来的消息会被并成一个窗口，一个窗口只跑一次、最多回一次；运行期间新到的照样入库、照样进记忆，只是排到下一个窗口去。哪怕群里说到一半突然安静了，积压也会在一个上限时间之后被处理掉，不会永远悬在那儿等下一个人开口。&lt;/p&gt;
&lt;p&gt;要是一个窗口里的话太多，超过了模型能一次吃下的量呢？那就分段、就摘要，但每一条都必须被标记成&amp;quot;已经纳入处理&amp;quot;。&lt;/p&gt;
&lt;p&gt;可以处理不过来，不能假装没看见。&lt;/p&gt;
&lt;h3 id="不知道就是不知道"&gt;不知道就是不知道&lt;/h3&gt;
&lt;p&gt;微信发消息没有幂等键，发出去撤不回，而且它不会回调你自己发的消息。于是有一种情况绕不过去：我调了协议服务，连接在返回之前断了，这条消息到底有没有出现在对方手机上，我不知道。&lt;/p&gt;
&lt;p&gt;绝大多数系统在这里会选择重试。可在这个场景里，重试的代价是一个真人多收到一条一模一样的话。&lt;/p&gt;
&lt;p&gt;所以我给出站消息留了第三种结局：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pending → sending → sent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; → failed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; → unknown
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;failed&lt;/code&gt; 只用在我能证明它确实没发出去的时候。其余所有说不清的，一律算 &lt;code&gt;unknown&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;而 &lt;code&gt;unknown&lt;/code&gt; 是终态。它不自动重发，控制面也不提供人工重试的按钮——这一条我犹豫了很久，因为按钮是最容易加的东西，加上去还显得很贴心。但只要它存在，就一定会有某个半夜的我去点它，然后我朋友的手机上多出来一条重复的话。&lt;/p&gt;
&lt;p&gt;整个系统的语义因此被钉成一句：宁可丢一条，不能重一条。&lt;/p&gt;
&lt;p&gt;这显然不是什么普适真理，换成告警通知它就是错的。但在&amp;quot;一个东西用我的身份跟我朋友说话&amp;quot;这件事上，重复比漏发更伤人。我把这个取舍写进了架构，而不是留给将来某个疲惫的自己临场发挥。&lt;/p&gt;
&lt;h3 id="它得能解释自己"&gt;它得能解释自己&lt;/h3&gt;
&lt;p&gt;第四版的配置是每条消息现查数据库的。所以我今天把人设改了，昨天那句让我觉得&amp;quot;它怎么这么冲&amp;quot;的回复，就再也还原不出当时的现场。&lt;/p&gt;
&lt;p&gt;第五版每次开口之前，会把这一刻的配置、人设、记忆、上下文全部冻结成一份快照，跟这一次运行绑死。哪怕之后我把人设改得面目全非，翻回去还是看得见它当时是在什么条件下说的那句话。&lt;/p&gt;
&lt;p&gt;还有一条我很喜欢的规矩：万一一个进程失联了、被另一个接管了，那么它后来姗姗来迟的结果一律作废，只留档，不许改变当前的世界。&lt;/p&gt;
&lt;p&gt;第四版里它跑飞了我只能翻日志猜，现在它跑飞了会留下一份现场。&lt;/p&gt;
&lt;h3 id="它到底是谁"&gt;它到底是谁&lt;/h3&gt;
&lt;p&gt;前面那三件都是工程问题。这一件是那个老朋友群给我留下的功课。&lt;/p&gt;
&lt;p&gt;一个人之所以是他自己，靠的是他记得什么、他跟谁什么关系、以及他在什么场合愿意开口。第五版把这三样拆开做了。&lt;/p&gt;
&lt;p&gt;它的记忆分了好几层：关于某个人的、关于某个群的，还有关于它自己的——它经历过什么，形成了什么说话习惯，对谁做过什么承诺。记忆不是模型想写就写，一个模型提出来，另一个独立的模型复核，过了才算数。&lt;/p&gt;
&lt;p&gt;这些记忆之间有严格的次序，自我记忆排在人设的硬边界后面。也就是说，它可以慢慢长出自己的脾气，但不能借着&amp;quot;我记得&amp;quot;这四个字给自己加权限、改规则，或者把某个人随口一句话变成永久的铁律。&lt;/p&gt;
&lt;p&gt;还有条边界我想了挺久：一个 Agent 还没被配置出来的时候，系统只记中立的事实，不建关系，不推断亲疏，不生成自我记忆。&lt;/p&gt;
&lt;p&gt;主体还不存在的时候，不该有主观记忆。&lt;/p&gt;
&lt;p&gt;至于群里到底说不说话。第四版的裁判提示词第一句是&amp;quot;默认倾向于保持沉默&amp;quot;，第五版我把这句删了。理由是：外向的人设就该更爱接话，疏离的就该更爱旁听。把&amp;quot;少说话&amp;quot;写死进去，最后所有人设都会退化成同一个谨慎的客服。&lt;/p&gt;
&lt;p&gt;现在它可以选择回答、明确拒绝、或者干脆沉默。&amp;ldquo;明确拒绝&amp;quot;和&amp;quot;沉默&amp;quot;是两回事——前者是&amp;quot;我知道你在叫我，但这次不想答&amp;rdquo;，会留下完整的记录；后者才是真的当没听见。裁判算出来的态度和语气还会注入回对话，让它说话的调子跟关系对得上。&lt;/p&gt;
&lt;p&gt;四年前那个&amp;quot;两个小时没人说话就发一句&amp;quot;的 if，走到这儿变成了：模型看一眼当前的关系、场景、人格和上下文，然后决定要不要开口、用什么态度开口。&lt;/p&gt;
&lt;p&gt;五年前那行&amp;quot;阴阳怪气失败&amp;quot;，现在有编制了。&lt;/p&gt;
&lt;p&gt;而万一裁判模型自己挂了，它一律降级成沉默，绝不会降级成主动说话——坏也得往安全的那头坏。&lt;/p&gt;
&lt;h2 id="它已经不只是一个微信机器人了"&gt;它已经不只是一个微信机器人了&lt;/h2&gt;
&lt;p&gt;这项目不是 AI 时代的产物。它的起点是 2020 年 3 月 12 日半夜那个&amp;quot;微信有没有把我记下来&amp;quot;的念头，那会儿 ChatGPT 还得两年半才出生。第一次让机器人回答问题用的是腾讯云的闲聊接口，第一次接大模型的理由是&amp;quot;我的开源仓库有人在用，跟个风加一个&amp;quot;。&lt;/p&gt;
&lt;p&gt;我没去追它。它按自己的节奏长，我按自己的节奏折腾，两条线在 2025 年前后碰到了同一个路口上。&lt;/p&gt;
&lt;p&gt;我这边攒了五年：一个真实的场景、一堆聊天记录、三次把东西做死的经验，还有一脑子当时做不出来的想法。它那边，刚好长到了能扛住这些想法的地步。&lt;/p&gt;
&lt;p&gt;早两年不行。2022 年我接过一次，那会儿它还撑不住，结果就是那个长度永远为 1 的数组。晚两年大概也不行，我多半已经把这堆代码忘干净了。&lt;/p&gt;
&lt;p&gt;至于那些头疼的事——上下文、记忆、身份、副作用——本来就是这个场景里的老问题。只不过前几年这东西不太会说话，可以装作看不见；等它真的开始替我说话了，每一个都躲不过去。&lt;/p&gt;
&lt;p&gt;这五年我想做一个数据分析工具，做出了三个倒计时；想做一个排行榜，做出来了，然后连着协议一起丢了；想做一个正经平台，做出了一栋空房子；想做一个能聊天的 Agent，做出来了，能跑，也没出过事，但它是个毛坯。&lt;/p&gt;
&lt;p&gt;听起来像一串失败，不过每一次都留下了点东西。两次协议死亡教会我&amp;quot;脚底下那块地不是我的&amp;quot;，于是第五版里发不出去的消息宁可丢也不重试；那栋空房子教会我&amp;quot;架子不等于东西&amp;quot;，于是第五版从禁令开始写；那个两小时没人说话就跳出来的 if，变成了现在替它决定要不要开口的裁判。&lt;/p&gt;
&lt;p&gt;这几年整个行业都在解决&amp;quot;怎么让模型把一件事做完&amp;quot;，热闹得很。我花的时间都在另一头：怎么让一个有身份的东西，在一条不可控的消息流里无人值守地活着，而且它说出去的每句话都能解释、不重复、不悬空。&lt;/p&gt;
&lt;p&gt;这头是没人写进发布会 PPT 的，因为做好了的效果是&amp;quot;什么都没发生&amp;quot;。没有重复发送，没有丢掉的消息，没有半夜爬起来点重试。&lt;/p&gt;
&lt;p&gt;我想让一个东西替我留在那些群里。等哪天我不在了，它还能接着说话，而且说得像我。&lt;/p&gt;
&lt;p&gt;吹完了，也得说点扫兴的。第五版还没跑满一年，所有关于&amp;quot;长期&amp;quot;的设计现在都只是设计。它依赖第三方微信协议服务，这是整条链上我最不可控的一环——前三版全是死在这一层上的，后两次还都连着号一起赔了进去，最贵的那次搭了大半年。这个风险我到现在也没解决，而且解决不了。&lt;code&gt;unknown&lt;/code&gt; 现在只是老实记着，还没有对账机制，等哪天协议方能按请求 ID 查结果，我会加个适配器把它对成 &lt;code&gt;sent&lt;/code&gt; 或 &lt;code&gt;failed&lt;/code&gt;，但绝不靠猜。11.6 万行去做一个微信机器人是重型方案，这些不变量只有在长期、多账号、无人值守的前提下才回本；你要是只想让模型在群里接话，别学我，现成的项目两百行就够。&lt;/p&gt;
&lt;p&gt;而且前四版我每次都觉得&amp;quot;这回总该做对了&amp;quot;。所以这版大概率也埋着一行我现在看不见的代码，过两年让我写下第六版。&lt;/p&gt;
&lt;h2 id="回到偃师"&gt;回到偃师&lt;/h2&gt;
&lt;p&gt;那个人偶让周穆王发怒的原因不是它会唱歌——会唱歌的机关木人不稀奇。是因为它抛了个媚眼，做了一件没人教它做、但完全符合它角色的事。&lt;/p&gt;
&lt;p&gt;我这个东西离那还远。拆开看全是数据库、队列、状态机、快照和五十五条规矩，跟皮革木头胶漆没什么本质区别。&lt;/p&gt;
&lt;p&gt;但它现在会因为跟某个人不熟而拒绝回答，会在群里冷场的时候自己判断要不要接一句，会记得半年前谁说过喜欢先看结论再看细节。这些都不是我一条条写死的，是它照着自己的身份算出来的。&lt;/p&gt;
&lt;p&gt;那天在老朋友群里说它跟我&amp;quot;一毛一样&amp;quot;的人，并不知道里面是什么。周穆王也是拆开之后才不生气的。&lt;/p&gt;
&lt;p&gt;穆王最后那句感叹我一直挺喜欢的。人之巧乃可与造化者同功乎。&lt;/p&gt;
&lt;p&gt;差得远。但试试挺有意思的。&lt;/p&gt;
&lt;p&gt;对了，2022 年 12 月那个下午，我在 &lt;code&gt;open_gpt.go&lt;/code&gt; 里写下&amp;quot;懒得搞上下文联动，有想法的可以自己实现&amp;quot;的时候，是真没想到这是在给四年后的自己派活。&lt;/p&gt;
&lt;p&gt;那个有想法的人最后还是我。&lt;/p&gt;</content></item></channel></rss>