前言多说无益,我直接讲一件让我决定动手的事。市面上的情绪日记应用,我前后换了七八个,没有一个能让我连续记满两个月。有的模板太重,每次打开要回答一长串问题;有的又太轻,只让选个表情,写不了几句真实想法。有一次加班到凌晨,关灯之后突然想把积了好几天的烦躁写下来,结果翻遍手机桌面,愣是找不到一个能在三十秒内让我把话说完的入口。与其天天将就,不如自己动手。于是我做了这个小程序,专记情绪,最近又给它接上了通用大模型接口,用AI帮我做情绪复盘和每周总结。这篇就把它从需求到落地的完整过程拆开讲,包括为什么市面产品不合适、技术选型怎么定、记录交互怎么设计、AI接入有哪些坑,以及用了大半年后的真实感受。如果你也在考虑给自己做个顺手的小工具,或者打算给现有日记产品加一个智能分析模块,这篇应该有参考价值。
1. 市面日记应用都差在哪:不是不好用,是结构性问题
先说结论,现在市面上的日记应用不是不好看、不好用,而是在“记录情绪”这件事上普遍存在三个结构性问题。你换再多App,也绕不开这些坑。
1.1 模板化记录让情绪成了单选题
大多数情绪日记产品的交互是:先让选一个当前心情表情,再选几个预设标签,最后写一句话。看起来很快,但我真实用下来发现,这种设计把情绪表达变成了单选题。情绪是混合的、模糊的、会叠加的。“工作推进得还算顺利,但一天会开七个小时会,整个人又被掏空”这种状态,你说它是开心还是疲惫?两个都对,但单选任何一个都会失真。
模板化还有另一个问题:选项是产品方定的,不是你的。预设标签永远是“开心、感恩、平静、焦虑、悲伤”这一套,我每天想表达的高频情绪反而是“烦躁但不想发火”“累但精神亢奋”“孤独但享受独处”。这些标签根本不存在,我只能选最接近的“烦躁”,写完之后自己都觉得记录被扭曲了。记录一旦失真,后面所有的统计和分析都是建立在一个错误样本上的,越看越没参考价值。
1.2 统计功能停留在频次,而不是理解
大部分日记产品的统计模块长得很漂亮,有连续打卡天数、每月情绪饼图、年度热力图,但仔细看会发现,它们统计的是“你点了什么标签”,不是“你真正写了什么”。举个例子,某个星期我工作压力特别大,几乎每天都会在文字里反复提到“项目延期”“沟通成本”“睡不够”,但我情绪标签选的是“焦虑”。如果产品只统计标签,那本周结论就是“焦虑6次”,至于焦虑的来源、以及“项目延期”和“睡不够”之间的相关性,完全看不出来。
我想要的统计是:从文本本身出发,知道我这周频繁出现的关键主题是什么,情绪强度的波动曲线是怎样的,以及我的身体感受和情绪之间有没有关联。这些东西靠传统聚合统计做不到,得靠语义理解。这也是我后来决定接入大模型的核心原因,不是为了加一个喊口号的“AI助手”,而是真的需要一个能读懂文本的分析层。
1.3 数据在自己手里这点,比想象中重要
用了很多日记产品后,另一个越来越强烈的感受是:数据不完全是我的。有些产品导出只能生成图片长文,我在上面记录了两年的文字,导出来是一张一张jpg,根本没法检索,也没法再处理。我试着找过一些第三方工具做迁移,但大部分要么不提供结构化导出接口,要么导出的格式残缺。
这件事对我的影响是:每次换产品,历史数据基本等于作废。个人工具的第一资产就是历史数据,尤其是情绪日记这种时间序列数据,只有积累得够久才能看到趋势。我不能接受自己写的东西被锁在一个无法导出的格式里。所以自建项目的首要原则之一,就是存储结构必须是我自己能掌控的,随时能导出成JSON或Markdown。这点可能在选型时感受不深,等写满半年再回头看,就变成了刚需。
按我自己的使用体验,把市面产品的现状和我的真实需求放在一起,差距大致是这样的:
| 我的需求 | 多数产品给到的方案 |
|---|---|
| 打开后30秒内完成记录 | 先选模板、再进编辑器,来回好几步 |
| 支持混合、矛盾的复合情绪 | 只能选一个表情 |
| 从日记文本里理解情绪变化 | 统计标签点击次数 |
| 自动总结周期内的趋势与因素 | 一句固定文案加油打气 |
| 数据随时可导出、可加工 | 导出成图片长文或索性不支持 |
这五个差异点基本决定了我后来全部的设计方向。
2. 技术方案怎么定:小程序+云函数+大模型接口,为什么不是App
需求清楚之后,接下来是技术选型。这个项目从第一天起就是单人开发、单人使用,所以我最看重的不是功能上限,而是维护负担。一个要养服务器、做版本兼容、应付审核的东西,再厉害我也坚持不了几个月。
2.1 个人项目先算维护成本,再谈技术先进性
我先排除了原生App:我只需要在手机上快速记录,没有复杂的本地能力需求,采用原生开发需要维护两个平台,成本直接翻倍。我也排除了纯网页:手机浏览器的打开路径太长,记录这种高频小动作,需要的是一个在桌面、容易被唤起、可以保存状态的入口。小程序刚好卡在中间,打开成本低,不需要安装更新,自带云开发环境,后端能直接跑云函数,我就把方案定成了小程序加云函数。
说实话,这个选择在技术圈里可能不够“优雅”,但它是个人项目的平衡解:前端用小程序原生框架,后端逻辑全扔云函数里,数据放文档型数据库。没有单独的服务器,没有容器,没有反向代理,连域名配置都省了。对我这种白天还要写业务代码的人来说,晚上能和家人聊聊天,比维护一套高可用系统重要得多。
2.2 数据流设计:输入、分析、存储三条线分开
接手过的项目越多,越明白一个道理:功能可以乱,数据流不能乱。这个小程序的数据流我从一开始就定了三条线,各走各的。
输入线:记录页写文本、点标签、选身体感受,提交后立刻写入集合,不给用户等待时间。
分析线:新记录写入后触发云函数,拉取文本内容调用大模型API,返回结构化情绪分析,再把结果作为新字段更新到原记录上。
存储线:原始文本和AI分析结果分开存字段。AI分析字段随时可以清空重算,原始文本永远保留。
这样设计的好处是,AI只是“附加注解”,不是“唯一解释”。如果有一天大模型接口用不了了,历史记录还在,标签数据还在,我可以退回纯手动模式,也不会丢失任何内容。实际开发时这个感受很深:有几次我把提示词改坏了,批量重算数据,结果是旧的AI分析字段直接覆盖成新格式,但原始文本纹丝不动,才能快速发现问题并回退。
2.3 成本预算:免费额度为主,按需叠加
既然是一个人用,成本必须可控。我把账算了一遍:日常记录一天大约3到5条,每条文本100到200字,加上系统提示词,单次调用大概消耗1000到1500个token。按常见商用大模型接口的市场价格估算,一个月也就几块钱;加上云函数和数据库的免费额度,总体使用成本基本可以控制在两位数以内。对个人项目来说,这个数完全在可接受范围。
为了再压一点成本,我做了两个小策略。文本少于一定字数的不调大模型,直接用标签归档;同一个自然日内文本完全重复的记录,只分析一次,后面的直接复用结果。这两个策略其实还顺手带来一个副作用:大幅降低了无效调用,整个分析通道的响应也快了很多。
3. 情绪日记的核心设计:记录器的交互逻辑比想象中更讲究
工具类产品最怕的不是功能不够,而是用户不愿意打开。日记工具尤其如此,它的核心指标只有一个:能不能让你在一个情绪刚产生的时刻,用最低的阻力把感受留下来。这个交互设计我前后改了三个版本,最后稳定下来的方案值得单独说说。
3.1 怎么记才不会被放弃:30秒法则
我给记录页定了个硬性指标,从打开页面到完成提交,不能超过30秒。这个时间参考了日常使用场景:大多数人写日记的冲动发生在通勤路上、睡觉前、刚结束一场糟心会议的时刻。这些场景有一个共性,注意力窗口极短,超过半分钟,手一滑就切去刷信息流了。
为了守住30秒,我把页面元素精简成三层。最上面是文本输入框,默认聚焦弹出键盘,打开就能打字;中间是情绪标签区,只放一排横滑可选的大按钮;最下面是一个身体感受选择行和提交按钮。视觉上几乎看不到多余的装饰,整个页面打开的一瞬间,用户的目光自然会落在输入框上。我试过把情绪标签放在输入框前面,结果发现很多人会先点标签、再写文字,记录出来的东西非常僵硬。把文本输入放在最前面之后,内容自然了很多。
3.2 情绪标签体系的四象限结构
标签不能太少,太少装不下混合情绪;也不能太多,太多会增加选择负担。我第一版做了27个标签,结果使用一周后发现,大量时间花在了“这个标签到底选哪个”上,这完全违背了30秒法则。后来我参考经典的情绪维度理论,把标签体系收敛成四象限结构,每个象限只保留3个核心标签,全平台一共12个。
| 唤醒度/愉悦度 | 正向 | 负向 |
|---|---|---|
| 高唤醒 | 兴奋、开心、满足 | 愤怒、焦虑、烦躁 |
| 低唤醒 | 平静、安心、轻松 | 疲惫、低落、无力 |
这套结构好处很明显。一是覆盖率足够高,日常绝大部分情绪都能在这12个词里找到落脚点。二是它保留了维度的可计算性,每个标签背后都对应一组愉悦度和唤醒度数值,可以直接用来生成图表,不依赖AI结果也能完成基础趋势统计。三是它允许同时选多个标签,比如“兴奋”和“疲惫”可以共存,这比单选情绪表情真实得多。
3.3 一次完整的记录流程长什么样
最终稳定下来的记录流程是这样的:打开页面,键盘弹出,先打字,写完核心内容之后,再从12个标签里点1到2个,选择身体感受(可跳过),按提交。整个链条只有一次必填操作,就是文本输入。标签可以不选,身体感受可以不选,但至少写一句话。
提交之后的反馈我刻意做得很轻,只有一个简短的“已记录”文字提示,没有弹窗、没有连续打卡提示、没有“你真棒”。打卡和鼓励机制是很多日记产品的标配,但我个人认为,情绪日记需要的是安全感和低压力,而不是源源不断的激励压力。今天心情差到只能写三个字,那也是记录,不需要被鼓励成一个“坚持了多少天”的数字。
我还给记录页加了一个很不起眼但使用率非常高的入口:首页上除了“写今天的日记”以外,还有一个“补充刚才的想法”按钮,点开之后默认带出最近一条记录的引用,让人补充几句。实际使用中,相当一部分有效记录是靠这个入口完成的,因为情绪往往不是一次性表达完的,人会在半小时后想到更多细节。这个小小的补充机制,让我后半段的分析数据密度高了很多。
4. AI接入的细节:不是简单调API,是让模型输出能入库的结构化情绪分析
接入大模型是整个项目里最让我兴奋、也最折磨的一段。最初我以为只是做个自然语言理解接口,直接喂文本让它总结一下就行。做了才发现,难的不是调用,而是让大模型在“生成一段像样的句子”之外,把结果变成能入库、能统计、能召回的结构化数据。
4.1 提示词是怎么设计的
提示词的第一版只有一句话:“请分析下面这段情绪日记。”结果输出是一大段散文,时效高但没法用。后来我按自己的需求重构了提示词,把它拆成五块:角色设定、任务边界、输入内容、输出格式、约束条件。
角色设定让模型以“温和的心理观察助手”身份工作,而不是一个泛泛的AI客服。
任务边界明确只分析文本中直接出现的内容,不允许推断日记之外的背景。
输入内容直接用分隔符框起来,避免复制过程出错。
输出格式是重点,我让它一定要返回一份JSON,字段包括情绪标签、愉悦度、唤醒度、摘要、相关事件因素、一条温和建议。
约束条件强调“不要输出JSON以外的任何解释”,这件事后文会说,不约束会血泪教训。
下面是我现在仍在用的提示词结构示例:
{ "system": "你是一个温和的心理观察助手,只依据用户日记文本做情绪分析,不推断文本之外的背景。", "user": "以下是一条情绪日记,请分析其中的情绪并返回JSON。\\n\\n【日记内容】\\n{input_text}\\n\\n【输出要求】\\n返回一个JSON对象,字段如下:\\n- label: 主要情绪标签,用简短中文,如:工作压力、人际消耗、自我否定、平静满足等\\n- valence: 愉悦度,范围-1到1之间的小数,负数表示偏负向情绪\\n- arousal: 唤醒度,范围0到1之间的小数,表示情绪激烈程度\\n- summary: 用两句话概括用户的状态和原因\\n- drivers: 列出造成该情绪的主要事件因素,最多3个\\n- suggestion: 给出一条温和、可操作的建议,不超过30字\\n不要输出JSON以外的任何文字。" }这样设计之后,每次调用返回的就是一条非常干净、可以直接写入数据库的JSON。后面所有趋势统计、周报生成,都基于这些字段,不再依赖于读散文。
4.2 JSON输出不稳定,我用了哪几招兜底
提示词再怎么约束,模型偶尔还是会“偷懒”。我踩得最深的坑有三个。
第一是JSON会被包裹在markdown代码块里。这大概是训练数据留下的习惯,模型觉得输出代码就得加三引号。如果我没处理就直接入库,JSON解析失败,记录页面会报错。解决方式是写一个清理函数:从返回文本中提取第一处左大括号和最后一处右大括号之间的内容,再丢进解析器。这招基本能兼容绝大多数情况。
第二是字段偶尔会缺。升级模型版本后,有时候它会漏掉suggestion或者drivers,如果代码里直接取字段,会得到空指针。我后来把所有解析都改成了“字段默认值兜底”的方式,缺失的字段填一个预设值,比如drivers缺了就返回空数组,宁可少数据也不让整条记录写入失败。
第三是情绪分数偶尔给得太极端。有的日记明明只是轻微失落,模型却给了-0.9的valence,这会严重影响图表曲线。我加了一层简单截断:超过正负0.9的值,一律压回0.9,避免被个别异常样本带偏整条趋势线。
如果你也打算做类似功能,我的建议是:不要相信模型每次都守规矩,把解析这层做得足够防御性,比你精心雕琢提示词更救命。
// 云函数中的解析兜底方案示意 function extractJson(raw) { const start = raw.indexOf('{'); const end = raw.lastIndexOf('}'); if (start === -1 || end === -1 || end <= start) { throw new Error('no valid json in response'); } return JSON.parse(raw.slice(start, end + 1)); } function safeParse(raw) { const data = extractJson(raw); return { label: data.label || '未分类', valence: Math.max(-0.9, Math.min(0.9, Number(data.valence) || 0)), arousal: Math.max(0, Math.min(1, Number(data.arousal) || 0.5)), summary: data.summary || '', drivers: Array.isArray(data.drivers) ? data.drivers.slice(0, 3) : [], suggestion: data.suggestion || '先休息一下,给自己一点空间。', }; }4.3 调用成本控制与异步分析策略
成本问题在单条调用时感觉不明显,但使用久了就会发现,免费的额度根本不够我每天持续调。我后来把整个分析流程改成了异步模式:用户提交记录后,文本立刻写入数据库,页面马上显示提交成功,云函数在后台慢慢调用大模型,分析结果几秒后回写入原记录。用户体感是“秒提交”,AI分析则是后台悄悄进行。
这个异步化还解决了一个更隐蔽的问题:大模型接口的响应时间不稳定。有时候几百毫秒就返回,有时候要等七八秒。如果做成同步等待,用户提交完就要盯着页面转圈,体验非常差。改异步之后,页面永远不等待AI,AI高峰期慢一点也无所谓,反正最终数据会补上。
另外我加了一个去重缓存的机制:针对同一天、文本长度近似且前二十个字完全相同的记录,直接复用之前的分析结果。个人记录场景里面,这种重复率不低,比如“今天也很累”这句话,我一个月至少会写十几次。缓存命中后可以节省90%左右的重复调用。
5. 数据复盘视图与隐私边界:和商用产品最大的不同
记录只是第一步,我真正想要的是周期性回顾。过去用别人的产品,回顾功能大多是产品方帮你写好的,今天和昨天比,情绪涨没涨,然后给你一句“保持好心情”之类的空话。自己做,我想把回顾做成真正能看懂的私人报告。
5.1 情绪周报的生成逻辑
每周日晚,系统会跑一个定时任务,把过去七天的记录文本、情绪标签、AI摘要打包在一起,再调一次大模型,生成一份以叙述为主的周报初稿。周报里包含四个部分:情绪主旋律、高频触发因素、睡眠或身体状态关联、下周建议。
这一步的提示词和单条分析不同,我要求它综合多条记录,找共性,而不是重复每条记录的摘要。它输出的是一段能直接读给周日晚上的自己听的文字。我最喜欢的一句周报是:“本周主旋律是消耗感,主要集中在两件事:一是连续三天的会议跨到了晚上十点,二是你对自己没推进完的计划有些自责。”这种粒度,靠我自己回顾是写不出来的。
周报生成之后,还是会存成结构化字段:主情绪标签、本周平均愉悦度、趋势方向、事件因素列表。这样我可以去周报页面只看趋势曲线,不看文字,需要细节再展开。
5.2 数据可视化:少即是多的热力图
图表这块一开始我做了很多,折线图、雷达图、柱状图,结果真正每天都会打开看的,反而是一个最简单的月历热力图。每个日期格子按当天平均愉悦度填充颜色,越偏正向越接近蓝色,越偏负向越接近暖黄色,中间是灰色。一眼看过去,这个月的高光时刻和低谷日子清清楚楚,完全不需要复杂解释。
我后来把复杂的雷达图全部下掉了,不是它不好,而是个人工具不需要展示型报表。情绪记录页的数据可视化应该以“让上周的自己被这周的自己看见”为目标,而不是“做一张可以发朋友圈的数据大屏”。颜色块热力图带来了一个意外的正向循环:人会更注意自己有哪些颜色块,也会更自然地追问“为什么这周三特别暖”,这种追问本身促进了记录质量。
5.3 隐私处理:原始文本可导出,分析字段可重算
隐私是情绪类工具的底线。我的做法很直白:第一,所有记录文本存在自己的云数据库里,不会因为调试日志被打印到任何外部系统;第二,云函数在调用大模型接口时,只传当前这一条记录的文本内容和必要上下文,不传用户ID、不传历史记录全文;第三,数据导出功能做成了一键导出JSON,原始文本、标签、分析结果都在里面,格式干净,拿到哪都能接着用。
还有一个细节,第三方接口的调用日志会记录请求内容,我不想让完整日记文本出现在这类日志里。于是我在发送前会先做一次本地截断:如果文本超过500字,只保留前400字做情绪分析。对于情绪分析这个任务,400字的信息量已经足够,同时隐私暴露面也大幅缩小。
5.4 刻意不做的功能:没有社区、没有好友、没有排行榜
这些社交属性功能我全部没有做,而且短期内也不打算加。原因很简单:情绪日记是私人空间,一旦引入社交,记录动作会受到“观众视角”污染。人会下意识美化自己的情绪,倾向展示正面内容,回避那些真正需要处理的阴暗和脆弱面。我要的是一个怎么难看怎么记录都不会有压力的地方,而不是一个情绪才艺展示区。没有点赞、没有评论、没有好友互相监督,这个工具才能持续记录真实的样本。
6. 用了大半年后的体验复盘,以及给自建同类工具的人几点建议
项目上线到现在,我自己已经连续使用了八个月。这八个月里,我记录了两百七十多条情绪日记,覆盖了过去大半年里几乎所有重要节点:项目加班、连着下雨的周末、一次长谈后的释然、普通得毫无波澜的周三下午。这款小程序从第一版到现在,最大的价值不在于AI分析有多聪明,而在于我终于找到了一个让自己愿意持续记录的情绪容器。
6.1 真实使用习惯变化
过去的日记应用我最多用两周就放弃,这次能坚持八个月,除了“自己写的狗粮自己吃”的成分,产品上的关键改变有两个。一个是30秒法则真正稳住了记录频率,我很多条记录只有两三句话,但它们保留了最真实的现场感受。另一个是补充记录机制,让我可以从一条短记录延展出更完整的事情经过。整体来看,我日均记录0.8到1.2条,不算高频,但胜在稳定,几乎没有连续断档超过三天的情况。
AI分析在这个过程中的角色也很明确:它不是一个必须回应的助手,而是一个安静陪伴的复盘者。我提交完记录后不看它,等到周日统一打开周报,反而能让我在情绪冷静之后重新理解当时的自己。这种时间差很重要,情绪激烈时写下的文字往往带着滤镜,隔上几天再通过AI摘要审视,会有完全不同的体感。
6.2 三个最容易返工的点,提前避坑
第一,标签体系不要贪多。我第一版27个标签带来的不是细致,而是选择困难。情绪表达天然是模糊的,给太多选项反而让人卡在“我到底该选哪个”这种思路上,这不是记录,这是审查自己。12个标签覆盖绝大多数场景,特殊情绪完全可以写到文本里让AI捕捉。
第二,图表宁可简单也不能浮夸。我花时间做的雷达图和周曲线,使用率低到可以忽略。真正高频的是月历色块。如果你在做类似项目,先从最朴素的热力图开始,用到觉得不够再往上加,不要一开始就铺开一堆大屏可视化。
第三,AI字段必须做兼容处理。模型更新后,字段格式或取值范围发生变化很常见。所有从API拿回来的数据,都要经过默认值兜底、范围截断、缺失补充,再写入数据库。否则某天模型换了个签名,你历史数据里可能会突然出现一堆解析失败、图表为空的脏记录。
6.3 后续想加的方向
后面我准备做两件事。一是录音入口,有时候不想打字,对着手机讲两三句话反而更容易表达;这个场景用语音转文字解决很合适,成本也低。二是做一个简单的“主题聚类”,把所有记录中反复出现的drivers脚本聚类,看看自己过去半年里有多少次在同一个根源上消耗情绪。这一步本质上已经超出了日记工具,更像一个轻量的自我数据分析工具。等它跑一段时间,如果效果不错,我再单独写一篇分享出来。