聊天助手合规提示词、Persona、多轮推荐卡片与全屏体验更新
本次更新概览
今天主要围绕 EQAI 聊天助手的服务端行为和前端使用体验做了一轮整理。整体架构保持不变:
ChatBox
↓
/api/chat
↓
RAG
↓
DeepSeek
↓
reply + recommendedCards本次没有把推荐逻辑搬到前端,也没有改变 DeepSeek API 的调用入口。核心变化集中在:
- system prompt 增加面向中国用户的合规和心理支持边界
- 聊天助手增加两类固定 Persona,并由后端根据用户需求自动选择
- RAG 检索从只看最新一句,调整为结合最近几轮用户输入
- 当 LLM 回复中明确提到量表名时,后端会反查量表并补充推荐卡片
- 当内置量表不适合或用户想要额外题目时,支持在聊天中生成临时文本自测
- ChatBox 增加全屏模式,方便连续阅读多轮对话
- 为今天新增的 RAG、推荐卡片和全屏逻辑补充中文注释
合规 system prompt
更新文件:
src/lib/deepseek.ts
聊天助手的 system prompt 增加了面向中国用户的合规约束,包括:
- 不生成违法违规内容
- 不生成危害国家安全、分裂主义、民族仇恨、暴力、色情等内容
- 不鼓励自伤、自杀、违法犯罪等行为
- 不诱导用户提供隐私、商业秘密等敏感信息
- 不通过情感操纵或诱导依赖影响用户
- 面对心理困扰时保持支持、客观、谨慎,不替代专业医疗诊断
- 面对明显心理危机时,引导用户及时联系家人、专业机构、医疗资源或紧急帮助
这些规则放在服务端 system prompt 中,而不是前端限制。这样无论 ChatBox UI 如何变化,LLM 的基础行为边界都由后端统一控制。
Persona 自动选择
更新文件:
src/lib/deepseek.tssrc/app/api/chat/route.ts
聊天助手现在支持两个固定 Persona:
- Persona A:年轻职业女性,温柔、耐心、自然,适合职业发展、大学生活、个人成长、情绪压力等场景
- Persona B:三十多岁女性,已婚有孩子,更成熟、有生活经验,适合孩子教育、亲子问题、家庭关系等场景
后端会根据最近几轮消息选择 Persona:
- 命中孩子、家长、父母、亲子、家庭、教育等关键词时,优先 Persona B
- 其他情况默认 Persona A
system prompt 明确要求助手不要直接告诉用户当前使用哪个 Persona。Persona 只影响表达风格和沟通角度,不改变“帮助用户澄清需求并推荐合适量表”的主要职责。
信息不足时先澄清
更新文件:
src/lib/deepseek.tssrc/lib/scaleRag.tssrc/app/api/chat/route.ts
当用户第一轮输入较模糊时,例如:
最近有点累助手不会马上推荐量表,而是先问 1-2 个澄清问题,例如区分工作压力、情绪困扰、睡眠问题等方向。
后端也配合做了处理:明显信息不足时,recommendedCards 暂不返回,避免前端在澄清阶段提前展示不稳定的卡片。
多轮上下文 RAG
更新文件:
src/app/api/chat/route.ts
之前 RAG 只使用最新一条用户消息。这样在多轮澄清场景中会丢失上下文。例如:
用户:最近有点累
AI:主要是工作压力、情绪困扰,还是睡眠问题呢?
用户:对工作有点提不起劲如果只看第二句,RAG 只能看到“对工作有点提不起劲”,可能不足以稳定定位用户需求。
现在 /api/chat 会把最近几轮用户输入合并成一个检索 query,例如:
最近有点累。对工作有点提不起劲这样 DeepSeek 和 RAG 都能看到更完整的对话背景,推荐卡片也更容易和文本回复保持一致。
LLM 回复量表名补卡
更新文件:
src/app/api/chat/route.tssrc/lib/scaleRag.ts
之前 recommendedCards 只来自 RAG top-k。如果 DeepSeek 在回复文本里明确提到了某个量表名,但 RAG top-k 没有返回对应条目,就会出现“文本里推荐了量表,但下方没有卡片”的问题。
现在后端推荐卡片来源按以下顺序合并:
1. RAG top-k 检索结果 2. LLM 回复文本中明确提到的量表名 3. 如果仍然没有明确量表,则不显示卡片
新增的 findScaleRagEntriesMentionedInText() 会尝试匹配:
- CSV 中完整量表名
- 去掉
【简单分量表 S1】等类型前缀后的量表名 - 去掉括号英文名后的中文量表名
这样当 LLM 回复中出现类似 EQAI人际关系压力量表、EQAI负面情绪管理量表 的明确名称时,后端可以反查出对应卡片并返回给前端。
临时文本自测
更新文件:
src/lib/deepseek.tssrc/app/api/chat/route.ts
今天新增了聊天内临时文本自测能力,用于处理两类场景:
- 用户明确要求额外测试题目、自定义测试或生成小测试
- 多轮澄清后仍然没有合适的内置推荐卡片
如果用户明确要求生成测试,后端会给 DeepSeek 追加临时文本量表指令:
- 如果用户没有指定题目数量,默认生成少于 10 题,建议 6-8 题
- 使用简单的 1-5 分作答格式
- 明确说明该量表只是沟通和自我观察工具,不是正式标准化测评或临床诊断
- 要求用户按顺序回复分数,例如
3,4,2,5,3,4 - 用户回复分数后,助手计算总分和平均分,并给出谨慎解释和建议
如果用户没有明确要求生成测试,但第二轮及以后仍没有任何推荐卡片,后端不会直接让 LLM 出题,而是在原回复底部追加一句友好询问:
如果你愿意,我也可以根据你刚才描述的情况,临时生成一个少于 10 题的简短自测量表,帮助你先做一个初步梳理。为了避免重复打断流程,后端还增加了两个状态判断:
- 如果上一轮助手已经开始生成临时文本量表题目,就不再追加这句邀请
- 如果用户正在提交分数或要求分析结果,也不再追加这句邀请
这样临时自测流程会保持连续:出题、用户作答、算分与解释,不会在每轮回复末尾重复提示“是否需要生成测试”。
ChatBox 全屏模式
更新文件:
src/components/ChatBox.tsx
ChatBox 增加了全屏/退出全屏按钮:
- 浮动聊天框支持全屏
- 首页 inline 聊天框也支持临时全屏
- 关闭浮动聊天框时会自动重置全屏状态
全屏模式做了更紧凑的视觉处理:
- 视口边距缩小
- header 高度缩小
- 消息区 padding 和消息间距缩小
- 气泡、选项、推荐卡片和输入框尺寸略微压缩
普通非全屏聊天窗口保持原有尺寸和视觉风格不变。
前端推荐卡片渲染确认
更新文件:
src/components/ChatBox.tsx
今天检查了推荐卡片在前端的挂载方式。当前 ChatBox 的设计是每条 assistant message 都可以携带自己的 recommendedCards:
recommendedCards?: RecommendedCard[]渲染时也是在 messages.map(...) 内部按消息逐条渲染,因此推荐卡片不会只绑定第一轮或最后一轮回复。后端只要在该轮返回 recommendedCards,前端就会显示在对应助手回复下方。
中文注释整理
更新文件:
src/app/api/chat/route.tssrc/lib/scaleRag.tssrc/components/ChatBox.tsx
今天同步清理和补充了注释:
/api/chat注释说明现在使用多轮上下文 RAG,并会合并 RAG 与 LLM 明确提到的量表/api/chat注释说明了临时文本自测的触发条件、出题状态判断和算分阶段判断scaleRag.ts注释说明了 baseScore、同义词扩展、LLM 文本量表名反查、默认推荐排序和多轮上下文 family hint 的作用ChatBox.tsx注释说明了全屏模式只改变容器尺寸和显示密度,不改变消息和推荐卡片的数据结构- 对旧版本地关键词 fallback 补充说明:当前自由输入统一由
/api/chat处理,旧逻辑默认不会执行
验证结果
本次修改后运行:
npx tsc --noEmit
npm run lint两项均通过。
建议测试用例
模糊输入后补充方向
用户:最近有点累
AI:先问澄清问题
用户:对工作有点提不起劲预期:
- AI 根据多轮上下文回复
- 下方出现与工作压力、情绪状态或动力相关的推荐卡片
LLM 文本提到量表名
用户:我想了解 EQAI人际关系压力量表 和 EQAI负面情绪管理量表预期:
- 如果回复中明确出现这些量表名,下方应出现对应推荐卡片
全屏阅读
打开 ChatBox → 点击全屏按钮 → 连续进行多轮对话预期:
- 聊天框覆盖视口但保留边距
- 同屏能看到更多消息和推荐卡片
- 点击退出全屏后恢复普通尺寸
临时文本自测
用户:我想做一个自定义测试,看看最近是不是缺乏目标感预期:
- AI 生成少于 10 题的简短文本自测
- 题目使用 1-5 分作答
- 不显示正式量表推荐卡片
用户:3,4,2,5,3,4预期:
- AI 计算总分和平均分
- 给出非诊断性质的解释和建议
- 不再重复追加“是否需要生成自测”的邀请