ARTICLE · 1105235
手搓一个 AI 助手,我踩过的那些坑
手搓一个 AI 助手,我踩过的那些坑很多人问我:现在这么多现成的助手,为什么要自己搭一个?实话说,做这件事的过程中,我从"这玩意儿几十行代码就能跑起来"的兴奋,一路走到"让它稳定跑一个月不崩"的疲惫。这篇文章不讲具体技术选型,只讲我在这个过程中真正想明白的事,以及踩过的坑。 这是动手之前最该问,却最容易被跳过的问题。 我一开始想要的很简单:一个能帮我查天气、记笔记、搜点东西、偶尔在微信里回我几句话的小助手。听起来不难。但"简单"是个陷阱——一旦你开始加"能不能也帮我看下浏览器""能不能定时提醒我",复杂度会翻着跟头往上长。 所以先把自己的需求钉死在纸面上,很重要。功能边界清晰,后面每一个技术决定才有依据。 不管外面包装得多花哨,一个 Agent 本质上只有三样东西: 大脑——一个大模型,负责理解和决策; 手脚——一组工具,能查资料、执行命令、读写文件; 循环——"思考 → 行动 → 观察 → 再思考",直到给出最终答案。 我第一次跑通的核心代码,短得让我自己都惊讶。它不会什么高深的东西,只会:把用户的话丢给模型,模型说"我要调用某个工具",我就去执行,把结果塞回对话,再问模型下一步。循环往复,直到模型说"答完了"。 给新手的第一条建议:先把这几十行跑通,再谈别的。框架是后来的事,不是前提。 跑通之后,我开始把它当"日常用品"用,问题就一个个冒出来了。它们都不性感,但每一个都能让你崩溃: 工具会掉线。那些通过子进程拉起来的工具,跑着跑着就悄悄死了,而我的程序毫无察觉,直到某次调用才报错。于是我开始明白:光会调用工具不够,你得会"探活",得会"拉不起来就重试"。 记忆是纸糊的。早期我以为"记住对话"就够了,后来发现重启一次全忘了。真正有价值的记忆——用户的偏好、环境的经验——必须落到盘上,而不是存在内存里。 它会伤到自己。有一次我让助手跑某个脚本,结果它想递归地再把自己启动一遍。我这才给它加了一道"别重复启动自己"的闸门。这类防护,用之前觉得多余,出事之后才觉得侥幸。 在所有这些坑里,最值得单独拿出来讲的,是一个让我查了很久的"灵异事件"。 我给它接了一个聊天通道,让用户能从手机发消息、收到回复。日志里一切正常:消息进来了、处理完了、发送接口也返回了成功——但对方就是收不到。 最后发现,问题出在"成功"的判断上。发送接口返回的是一个不完整的回执:只有一个"我收到了请求"的字段,而我真正该看的"业务结果"字段,根本就没返回。我的代码却把这种"半截成功"当成了成功,兴高采烈地打印了一个对勾。 教训极其深刻:凡是异步的通知、推送、回执,别只看"接口收没收到",一定要确认"事情到底办没办成"。半截的成功,比失败更坑,因为它连重试都不会触发。 顺带说一句,排查这类问题,学会看"原始返回"而不是"封装后的结果",能省下大量时间。 做"定时提醒"时,我犹豫过:到点了直接发出去,不行吗?为什么非要把"提醒"和"待发送"分开存? 做了一半我才懂。原因很朴素: "到点"是个瞬间判断,很快;"发送"是个慢动作,还可能失败。如果到点就发,一次发送卡住十几二十秒,后面的提醒全被堵死;发失败了,这条提醒就凭空消失了。 重启不能丢。如果"扫到 → 发送 → 标记完成"中间进程挂了,这条提醒就没了。必须有一个落盘的"待办",让程序重启后还能接着发。 于是我把它拆成两本账:一本是交办簿,记着"什么时间、提醒什么";一本是派工单,记着"现在要发、发给谁、发没发出去"。调度的人只负责把到点的交办转成派工单,发送的人只负责消化派工单,失败了就重试,重试不动就告警。 这个"生产者与消费者分离"的思路,几乎适用于所有"到点要做某事"的场景,提醒只是其中一个例子。 这是被问得最多的问题。我的答案很实在:它们根本不是同一个东西。 自己写,你得到的是透明和贴合。每一行都是你的,想改哪里改哪里,轻、快、精准地长在你自己的需求上;代价是一切都要自己扛——多通道、稳定性、安全、调度,每一个都得亲手补。 现成的平台,你得到的是成熟和省心,它早就把那些"通用工程问题"(多通道接入、失败重试、人工审批、安全隔离)替你解决了;代价是重、有学习成本、定制要顺着它的脾气来。 我在这个过程中撞到的每一个坑——消息会丢、提醒要排队、凭证会过期——回头一看,成熟平台大多已经内置了答案。这不是"谁更好"的问题,而是:你想当使用者,还是想当造轮子的人。 我的选择是折中的:架构和思路,参考成熟方案;实现上,坚持自己写。既学到了东西,又不至于在可靠的边界问题上反复交学费。 先跑通最小闭环。大脑加手脚加循环,几十行的东西,别急着上框架。跑通了,你对"agent 到底是什么"的理解会不一样。 把它当日常用品,而不是 demo。只有真正天天用,你才会遇到那些"假成功""掉线""重启丢数据"的坑。而这些坑,才是它从玩具变成工具的分水岭。 遇到通用难题,先看看别人怎么设计的。记忆怎么持久、任务怎么排队、失败怎么重试——这些都有人趟过。借鉴设计,不等于照搬实现。 最后想说:自己搭 Agent 这件事,最有价值的从来不是最后那个能跑的东西,而是你被迫去理解的那些"看不见的工程细节"。它们不性感,但恰恰是决定一个东西"能用五分钟"还是"能用一个季度"的分界线。 
愿你不只是在造一个 Demo,而是在造一件真正属于你的工具。
为什么不用现成的?——这是被问最多的一句。这篇文章不聊用了什么框架、什么语言,只说一件事:把一个 AI 助手从"能跑"养到"能用",中间到底要跨过多少坑。
一、先想清楚:你到底要它干嘛
二、最小骨架,其实就是三个零件
三、"能跑"和"能用"之间,隔着一堆工程问题
四、最典型的一个坑:消息通道的"假成功"
五、提醒功能教会我的:为什么一定要拆两层
六、自己写,还是用现成的平台?
七、给想动手的人,三条建议
