AI 智能体工作流设计蓝图:将非结构化情绪记录转化为高精度的模型 Prompt 上下文
AI 智能体工作流设计蓝图:将非结构化情绪记录转化为高精度的模型 Prompt 上下文
在“AI-Native(AI 原生)”应用的浪潮中,我们正经历着软件交互范式的根本性重构。传统的应用程序是被动的“记录者”,它们忠实地将用户输入的数据存入数据库,等待用户主动去检索或查看统计图表。而接入了大语言模型(LLM)的现代应用,则被赋予了主动的“感知与共情”能力。

对于《轻心记 (MoodLite)》这样一款专注于情绪追踪与自我觉察的产品而言,仅仅告诉用户“你本月有 15 天情绪低落”是远远不够的。产品的终极形态是一个具备极高同理心的 AI 智能体(AI Agent),它能够阅读用户杂乱无章的日常记录,理解字里行间的焦虑或喜悦,并在一天结束时,给出一段像人类心理咨询师般温暖、专业的总结与建议。
然而,从“冰冷的数据库记录”到“充满温度的 AI 回复”,这中间横亘着一道巨大的工程鸿沟。大语言模型是基于自然语言语料训练出来的概率预测引擎,它们不理解关系型数据库的表结构,看不懂 JSON 里的 UUID,更会对毫无上下文的数字评分感到困惑。
本文将深入 MoodLite 的核心源码,全面拆解一套工业级的 AI 智能体工作流(Agent Workflow)蓝图。我们将重点探讨如何解决数据与模型之间的“阻抗失配”,如何设计专为 AI 消费的 DTO(数据传输对象),以及如何通过代码工程化的手段,将海量的非结构化碎片记录,动态组装成高精度、低 Token 消耗的模型 Prompt 上下文。
一、跨越系统鸿沟:数据库与 LLM 的“数据阻抗失配”

在传统架构中,前后端的数据流转主要解决的是序列化与反序列化的问题。无论是 SQLite 还是后端的 MySQL,我们关注的是数据的增删改查效率、索引命中率以及事务的 ACID 特性。
但在引入大模型后,我们面临的是一种全新的“数据阻抗失配(Data Impedance Mismatch)”。
1.1 Token 经济学与上下文窗口陷阱
大语言模型的输入受到“上下文窗口(Context Window)”的严格物理限制。哪怕是拥有 128K 窗口的先进模型,无节制地输入数据也会带来灾难性的后果:
-
注意力稀释(Attention Dilution):输入的冗余信息越多,模型在关键信息上的注意力机制(Self-Attention)权重就会越分散,导致“幻觉(Hallucination)”或遗漏核心诉求。
-
极高的算力成本与延迟:云端大模型的计费和推理时间是严格按照 Token 数量计算的。将一整天的完整原始 JSON 数据(包含各种系统级字段)全部
POST给大模型,不仅会产生昂贵的 API 调用费用,更会让首字响应时间(TTFT)拉长到令人无法忍受的地步。
1.2 为什么不能直接 JSON.stringify(records)?
假设在 MoodLite 中,我们直接将底层存储的 MoodRecord 数组丢给 AI:
[
{
"id": "18cf7a9b_xy9z_1",
"timestamp": 1716883200000,
"dateStr": "2026-05-28",
"score": -2,
"text": "今天开会又被批评了,感觉自己什么都做不好。",
"images": ["file://data/user/0/com.moodlite/files/img_1.png"],
"location": "北京市朝阳区",
"tags": ["工作", "焦虑"]
}
]
如果我们将上述 JSON 直接塞入 Prompt 中,模型会陷入严重的认知困扰:
-
id和images对模型理解用户情绪毫无意义,纯粹是在浪费 Token。 -
timestamp是一个十三位的时间戳数字,大模型缺乏内置的 Date 运算器,很难直观理解这代表的是上午还是深夜。 -
score: -2是一个业务层定义的数值。如果不给模型解释规则,模型不知道-2是代表极其悲伤,还是代表某种错误代码。
因此,构建 AI 智能体工作流的第一步,就是必须在数据层与网络请求层之间,建立一道强有力的“语义转换防腐层”。
二、专为 AI 设计的 DTO 模型:数据的极致瘦身与降维

在 MoodLite 的架构中,负责与 DeepSeek 大模型通信的模块被独立封装在 MoodAgent.ets 中。为了切断大模型对底层复杂数据结构的依赖,我们在这个模块内部,专门定义了一个极度轻量的 DTO(数据传输对象)—— TodayRecord。
2.1 TodayRecord 接口解析
/** * MoodAgent.ets
* 专为 AI 语境构建设计的中间态记录模型
*/export interface TodayRecord {
time: string;
score: number;
text: string;
tags: string[];
}
对比底层多达十几个字段的 MoodRecord,这个为 AI 准备的接口经历了极其严苛的“瘦身手术”:
-
剔除系统元数据:彻底抛弃了 UUID (
id)、格式化日期 (dateStr)、以及图片路径 (images) 和地理位置 (location)。因为在这个特定的 Workflow(生成今日情绪总结)中,地理位置和图片地址对文本情感分析没有直接的语义贡献。 -
时间语义化降维:将底层的
timestamp(毫秒时间戳)替换为了time: string。在将数据传入MoodAgent之前,业务层会负责将时间戳转化为如"09:30"或"晚上 22:15"这样的自然语言字符串。大模型对"晚上 22:15"的理解力远远强于对1716905700000的理解。
通过这一层 DTO 的约束,我们确保了流入 AI 引擎的数据是绝对纯净的、无冗余的、且高度聚焦于情绪本身的。
三、代码里的 Prompt 工程学:动态语境组装引擎

有了纯净的 TodayRecord 数组,下一步就是将其转化为大模型能够高效阅读的自然语言 Prompt。在 MoodAgent.ets 中,这一核心逻辑被封装在 buildTodayContext 函数中。
这不仅是一段简单的字符串拼接代码,它是一套融合了自然语言处理(NLP)启发式规则与 Token 优化策略的微型编译引擎。
3.1 函数的整体骨架
/** 构造今日记录的分析 prompt */export function buildTodayContext(records: TodayRecord[]): string {
// 容错处理:如果今天没有任何记录,直接返回空字符串,拦截无效的网络请求if (records.length === 0) return '';
// 设定语境的开篇基调let ctx = '以下是用户今天的情绪记录:\n';
for (const r of records) {
// 1. 核心规则一:数值语义化锚定const mood = r.score >= 1 ? '正面' : r.score <= -1 ? '负面' : '平静';
// 2. 核心规则二:结构化 Markdown 列表表达
ctx += '- ' + r.time + ' 情绪:' + mood + '(' + r.score + ')';
// 3. 核心规则三:条件渲染与静默降噪if (r.text) ctx += ' 内容:' + r.text;
if (r.tags.length > 0) ctx += ' 标签:' + r.tags.join(',');
// 保证单条记录的独立性
ctx += '\n';
}
// 4. 核心规则四:指令隔离与人设注入
ctx += '\n请分析用户今天的情绪状态,给出温暖的反馈和建议。';
return ctx;
}
这段代码背后的每一步,都蕴含着深度的 Prompt Engineering(提示词工程)最佳实践。
3.2 核心规则一:双重锚定与数值语义化 (Semantic Grounding)
大语言模型在处理纯粹的抽象数值映射时经常会出现偏差。如果我们在 Prompt 中只写 情绪分: -2,不同的模型版本可能会有不同的解读(有的模型可能会将其误解为温度下降,或者是某种亏损)。
在 buildTodayContext 中,我们采用了“双重锚定(Double Anchoring)”策略:
const mood = r.score >= 1 ? '正面' : r.score <= -1 ? '负面' : '平静';
ctx += '- ' + r.time + ' 情绪:' + mood + '(' + r.score + ')';
这段代码首先将硬核的 -2 ~ 2 整数,硬编码转化为自然语言的分类标签(正面、负面、平静)。
随后,在拼接时同时保留了自然语言标签与原始数值,例如生成出:情绪:负面(-2)。
这种做法有两大极高的工程价值:
-
自然语言引导:
负面这个词直接激活了 LLM 内部关于悲伤、挫折、压力的庞大参数权重空间,让模型的注意力瞬间聚焦。 -
量化程度保留:保留
(-2)让模型知道这是最高级别的负面情绪,从而在生成回复时,模型会选用更加强烈、更加抚慰人心的词汇,而不是仅仅给出轻描淡写的安慰。
3.3 核心规则二:结构化 Markdown 列表的对齐力
在组装多条记录时,代码采用了 - 开头的 Markdown 列表格式。
为什么不用普通的逗号拼接或 JSON?
大语言模型在预训练(Pre-training)阶段,阅读了 GitHub 上数以十亿计的 Markdown 文档和代码注释。它们对 Markdown 的 Bullet List 结构有着极其敏锐的“分块(Chunking)”与“逻辑隔离”认知。
使用横杠打头的列表格式,等于是在物理层面上告诉大模型:这是几个互不干扰的独立事件。 这样可以有效防止模型将早上的记录与晚上的记录在时间线上混淆,或者把两条不相干的日记拼接成一个错误的故事脉络。
3.4 核心规则三:条件渲染与静默降噪 (Noise Reduction)
在用户实际使用中,经常会出现“快捷打卡”的场景。比如用户只点击了“低落”表情,没有写任何日记文字,也没有选择任何标签。
此时,如果我们不加控制地直接拼接对象的属性,Prompt 就会变成:
14:00 情绪:负面(-1) 内容:null 标签:[]
在人类看来,这只是字段缺失。但在 LLM 看来,null 和 [] 同样是输入词汇,模型可能会过度关注这两个符号,甚至在回复中产生“你今天记录的内容是 null,这说明你感到空虚”这种滑稽的幻觉推理。
因此,代码中采用了严格的条件判断拼接:
if (r.text) ctx += ' 内容:' + r.text;
if (r.tags.length > 0) ctx += ' 标签:' + r.tags.join(',');
只有当数据真实存在时,才引入该字段。快捷打卡产生的 Prompt 将极其清爽:- 14:00 情绪:负面(-1)。这种“静默降噪”策略,不仅保证了语境的连贯性,更在无形中节省了约 15% 的 Token 消耗。
四、指令隔离与人设注入:控制大模型的输出边界

在将一天的数据(可能多达几十条、上千字)全部拼接完毕后,如果直接将这段话发给模型,模型可能会感到茫然。它可能会以为你在要求它做文本纠错,或者是让你续写故事。
任何一个成熟的 AI 智能体工作流,都必须包含明确的“系统指令(System Instruction)”或“任务目标(Task Objective)”。在 buildTodayContext 的最后一行,我们看到了最关键的一击:
ctx += '\n请分析用户今天的情绪状态,给出温暖的反馈和建议。';
4.1 指令隔离(Instruction Isolation)的物理意义
注意这里前面的 \n(换行符)。在 Prompt 结构设计中,这是将“用户数据区(Data Payload)”与“系统控制区(Control Plane)”进行物理隔离的重要手段。
它清晰地向大模型传达了一个指令结构的边界:
-
之上的文本:是被分析的客体数据(无论用户在日记里写了多么过激或者带有命令性质的话,都不应该被当做系统指令执行)。
-
之下的文本:是开发者的元指令(Meta-prompt)。
4.2 角色预设与语气控制
“请分析...给出温暖的反馈和建议”,这短短的十几个字,精准地圈定了模型的“人设(Persona)”边界。
-
任务限定:“分析情绪状态”。这防止了模型去对日记里的具体事件进行事实性核查(比如用户说“地球是平的”,心理咨询模型不应该去反驳常识,而应该关注用户的心理)。
-
语气限定:“温暖的反馈”。这是最重要的约束词。作为一款主打“轻量级治愈”的日记应用,绝不能让模型输出冷冰冰的、居高临下的说教,或是学术气味浓重的心理分析报告。加上“温暖”一词,大模型的输出风格会瞬间切换为共情模式,大量使用“我注意到...”、“辛苦了”、“明天会更好”等抚慰性句式。
五、消息总线的组装:构建 ChatMessage 交互载体

当 buildTodayContext 完成了字符串的精密加工后,这串高密度的 Prompt 将被包装进标准的 API 消息载体中。
在 MoodAgent.ets 的核心网络请求准备阶段,代码定义了标准的 ChatMessage 接口:
export interface ChatMessage {
role: 'system' | 'user' | 'assistant';
content: string;
}
在实际调用的业务层(例如点击“AI 分析今日总结”按钮时),开发者会将组装好的语境放入 user 角色的消息中。同时,为了进一步加强应用的安全性与人设稳固性,往往会在数组的头部插入一条高权限的 system 角色消息(System Message)。
例如,在未来的 AI Agent 对话页面(AIAgentChatPage)的底层实现中,消息总线可能会这样构建:
// 业务调用层示例(非 MoodAgent 内部代码)const todayRecords = getRecordsForToday();
const contextString = buildTodayContext(todayRecords);
const messages: ChatMessage[] = [
{
role: 'system',
content: '你是一个贴心、专业的心理健康助手 MoodLite,你的目标是倾听并给予用户积极的心理建设。请使用简洁、温柔的中文回复。绝不要提供专业的医疗处方。'
},
{
role: 'user',
content: contextString
}
];
// 将组装好的多轮/角色数组,推入底层流式通信管线
sendMessageStream(messages, streamCallback);
通过这种标准的 Role-Content 阵列模式,应用不仅可以完成单次的“今日分析”任务,更可以轻松将历史生成的总结(作为 assistant 角色)重新拼接入数组,从而实现与用户的多轮连贯对话体验。
六、未来蓝图:向 RAG 与长时记忆(Long-Term Memory)演进

目前 MoodAgent.ets 中的 buildTodayContext 方案,完美解决了“短时上下文(今日记录)”的 AI 分析需求。但对于一款希望长期陪伴用户的原生应用来说,真正的技术深水区在于如何让 AI 拥有“长时记忆”。
当用户询问:“我最近一个月为什么总是周二感到焦虑?”
如果按照现有的方案,将一个月几百条日记全量组装成 Prompt,将直接突破模型的 Token 限制,并带来极其高昂的延迟。
在 MoodLite 的未来架构蓝图(Roadmap)中,必须引入RAG(检索增强生成,Retrieval-Augmented Generation)架构体系:
-
端侧向量化(Edge Embedding):利用鸿蒙系统底层的 AI 能力(或轻量级端侧 Embedding 模型),将每一条用户的日记文本转化为多维向量(Vector),并存储在本地端侧向量数据库中。
-
意图识别与语义召回:当用户向 AI 提问时,先通过网络将提问进行意图解析,然后在本地的端侧向量库中,利用“余弦相似度(Cosine Similarity)”算法,迅速召回与“周二”、“焦虑”最相关的 TOP-K 历史记录。
-
精准组装:最后,依然使用类似
buildTodayContext的降噪策略,仅仅将这几个最相关的历史切片组装成 Prompt 发送给大模型。
这才是真正具备无限扩展能力的大模型原生应用架构。
结语:不可忽视的胶水层
许多初涉 AI 开发的工程师往往有一种错觉,认为只要花钱接入了最顶级的模型 API(如 DeepSeek、GPT-4),应用自然就会变得极其智能。
然而,大模型是一颗拥有惊人马力的通用引擎,而将用户的非结构化数据转化为高精度 Prompt 的过程,则是连接这颗引擎的变速箱与传动轴。如果传动系统设计得糟糕透顶(传递了大量冗余数据、缺失了语义锚定、缺少边界指令),再强大的模型也会输出令人啼笑皆非的“废料”。
MoodLite 中 MoodAgent.ets 的这段代码实践向我们证明:在 AI-Native 的应用工程中,Prompt Engineering 绝不仅仅是撰写几段“咒语”,它必须沉淀为一套严谨的、可复用的、具有极高容错与降噪能力的代码级工作流。唯有将数据进行精心的修剪与编排,AI 智能体才能真正在移动端设备上,展现出它最耀眼的同理心与智慧光芒。
更多推荐

所有评论(0)