一、我为什么要做这个东西

每年高考完,最焦虑的不是分数,是填志愿。
尤其是普通家庭的孩子——没人脉、没"内行"指路,几百分的努力,可能因为一个信息差就被浪费。说到敢说真话,绕不开张雪峰:"这个专业别报""那个学校是照骗""普通家庭就该看就业倒推"——这些话,戳心,但有用。
可真人只有一个,他再能说,也覆盖不了几百万考生。
我的想法很简单:能不能做一个"AI 版张雪峰"——把张雪峰那套"用就业和数据说话、敢专业劝退"的报考逻辑装进一个 AI,让任何一个普通家庭的孩子,随时都能问上一句?
于是有了「峰哥志愿助手」——一个微信小程序,背后是一个会查官方就业/分数数据、会专业劝退、会排院校雷、会给冲稳保策略的 AI。
主意是好的。然后我就开始了长达数周的踩坑。
二、它到底是怎么搭起来的
一句话技术栈:
前端:微信小程序,自己写的聊天组件(流式对话、思考态、深度分析卡片)
后端:LangChain Agent,跑在腾讯 CloudBase 云函数(SCF)上
大脑:DeepSeek 模型 + 博查 WebSearch(让它能查实时数据,不靠瞎编)
知识:自建的分数线知识库 + 把张雪峰的报考方法论和说话风格,蒸馏进 system prompt
听起来很清爽对吧?接下来全是坑。
三、前端的坑:用户看不见,但能要命
前端有两个让我印象深刻的:
① 切个后台回来,白屏。用户聊到一半切出去回个微信,再切回来——白屏。原因是页面onShow没强制重绘。修法土但有效:切回来时塞一个setData({ _: Date.now() }),逼它重画一次。
② "停止"按钮,停了个寂寞,还在偷偷烧我的钱。我做了个停止生成的按钮。用户点了,前端确实不显示了。但我后来发现,后端的 AI 还在哗哗地生成、哗哗地花我的 token。因为我只在前端设了个"已停止"的标志,根本没真的去取消那个数据流。
后来得把流的引用挂住,点停止时真正调用异步迭代器的.return()去中止它。"看起来停了"和"真的停了",中间隔着我的钱包。
四、后端的坑:最贵的 bug 都很安静
① 一个不属于我的环境变量,把我的数据库写挂了。
我想记录用户行为日志,写进云数据库。结果一直报:access token env not consistency(access token 和环境对不上)。
查了半天,真凶是一个我为了别的功能配的环境变量
CLOUDBASE_APIKEY。腾讯的 SDK 有个"贴心"设定:只要它看到这个变量,就优先用它,直接无视云函数自动注入的临时凭据。于是我明明说"连到 A 环境",它却拿着 B 环境的钥匙去开门——当然对不上。
修法是绕开 SDK 的自作主张,手动指定临时凭据。这种坑最难受的地方在于:代码逻辑一点没错,错的是一个你以为无关的配置。
② 上线 10 分钟,整个服务 CRASH,用户只看到"网络异常"。
有一次部署完,线上直接崩了 10 分钟。日志里写着Cannot find module。
原因是部署时npm install
偶尔会漏装一个深层的可选依赖。它平时不报错,那次刚好没装上,函数一启动就挂。而用户那头,只会看到冷冰冰的四个字——"网络异常"。
教训:部署完别走,立刻去翻启动日志,看有没有Cannot find module、有没有duration=0ms这种启动即死的迹象。
③ AI 活在 2024 年。
用户问"今年的就业数据",它张口就是 2024 年的。因为模型的知识有截止日期,它不知道"今天"是哪天。修法是每次请求都把北京时间的当前日期注入进去,逼它用最新的。
五、最坑钱包的,是部署
这部分我被自己坑了不止一次。
部署成功 ≠ 上线。这句话我用真金白银学会的。
CloudBase 上我用了"预置并发"(提前开好实例、避免冷启动)。结果发现一个反直觉的事:我推了新代码、命令显示"成功",但所有用户请求还在走老代码。因为预置实例锁着旧的字节码,不会自动重启。
更狠的是钱:那些锁着旧代码的旧实例,只要不删,就一直按小时计费。哪怕没有一个用户走它。
我第一次忘了删,白白多付了几天冤枉钱。所以我现在把它刻进了项目的"必查清单":任何时候只要提到"部署/上线",强制问自己一句——旧的预置实例删干净了吗?
这事教会我:云服务的账单,往往不是用出来的,是忘出来的。
六、最大的幻觉:单测全绿,真机照崩
我写了不少单元测试。某个版本,89 个测试,89 个全过。我当时心里美滋滋,觉得稳了。
然后真机上一跑,前面那个鸿蒙卡死还在。
我才彻底想明白一件事:
单元测试保证的是"代码不崩",不是"体验不崩"。真机才是终审,不是初审。
从那以后我的规矩变成:单测 + 接口测试是前置门槛(不过这一关不准说"做完了"),但用户在真实手机上点的那一下,才是唯一的验收。
七、上线之后:真实数据长什么样
写代码的时候你以为你懂用户,上线之后,数据才会告诉你真相。
我拉了上线后某天的真实日志,挑几个有意思的:
用户问得最多的问题,是"我580分江苏物理类,能上哪些985/211?",一天被问了 8 次。
而且几乎都是点欢迎页引导词进来的——这说明一件事:用户懒得自己打字,你得把第一句话替他想好。我后来据此重排了引导词。
首字延迟大约 2.3 秒
:用户两秒多就能看到峰哥开始回话。至于一个完整回答要十几秒——这是我故意的:宁可让它多花几秒联网核对官方就业和分数数据,也绝不让它张口就编。报志愿这种事,快一点不重要,准才重要。
🖼 配图建议:放两张真机截图——
shot-analysis.jpg(深度分析卡片)+shot-tuitui.jpg(专业劝退),用真实界面证明"它真能干活",比任何描述都有说服力。
数据最大的价值,是它替你做决定:你以为用户想要 A,数据告诉你他们其实在点 B。
八、一个人,是怎么扛下这么多坑的
老实说,这些坑,靠我一个人是扛不动的。真正帮我扛住的,是我给自己定的一套和 AI 协作的工程纪律:
我把每一个用血换来的坑,都写进一个项目的**"重复踩坑榜"**——哪个坑、什么时候会复发,列成表。每次动手前先扫一眼。
我有一套持久化的记忆:把"这个 bug 的根因和修法"存成文件,下次不靠印象、靠记录。因为我发现,凭印象操作,就是重复踩同一个坑——那个 preset 计费的坑,我就是凭印象踩了第二次。
我定了条死规矩:任何改动,没过单测 + 接口测试,不准说"上线/完成",只能说"部署完成,验证中"。
这套东西本身,可能比那个小程序更值钱。因为坑会变,但**"怎么不重复踩坑"的纪律,是通用的。**
九、如果你也想从 0 做一个,我想说三句话
真机才是终审。
你的模拟器、你的单测、你的"我觉得没问题",都只是初审。
最贵的 bug 都很安静。
它不报错,它只是让你的账单变长、让某个你没有的设备卡死、让 AI 悄悄活在去年。部署完,永远多看一眼日志。
把坑写下来。
不是为了纪念,是为了不再踩。人的记忆会骗你,文档不会。
写在最后
做这个东西的初衷,是想让普通家庭的孩子,填志愿时也能有个像张雪峰那样"敢说真话"的参谋。
技术只是手段。那些 1rpx 的卡死、安静的账单、活在去年的 AI——折腾这一切,是为了让一个考完试、对着志愿表发愁的孩子,能在手机上问一句"我这分能上哪",然后几秒钟内,得到一个不哄他、用数据说话的回答。
现在,它真的上线了,真的有人在用。
如果你,或你身边正在填志愿的孩子,也需要一个敢说真话的参谋——
👇点下方小程序卡片,直接进「峰哥志愿助手」,把分数和省份告诉它,让它替你把把关。
夜雨聆风