CHAT-203 P1 | ChatSession 自动标题生成规则 #84

Closed
opened 2026-06-06 16:23:22 +08:00 by wangdl · 3 comments
Owner

目标

根据 scope 自动生成初始标题,首条用户消息后生成 autoTitle。

初始标题

  • knowledge_base: 知识库名 · 新对话
  • material: 资料名 · 新对话
  • knowledge_item: 知识点名 · 新对话
  • folder: 分类名 · 新对话
  • multi_source: 多来源对话 · N 个来源
  • global: 新对话

自动标题(首条消息后)

取用户第一条消息前 20 个中文字符,去掉废词。

## 目标 根据 scope 自动生成初始标题,首条用户消息后生成 autoTitle。 ## 初始标题 - knowledge_base: 知识库名 · 新对话 - material: 资料名 · 新对话 - knowledge_item: 知识点名 · 新对话 - folder: 分类名 · 新对话 - multi_source: 多来源对话 · N 个来源 - global: 新对话 ## 自动标题(首条消息后) 取用户第一条消息前 20 个中文字符,去掉废词。
wangdl added this to the M7:ChatScope 会话系统 — 学习对象绑定的上下文会话 milestone 2026-06-06 16:23:22 +08:00
Author
Owner

完成情况

交付物

Service 层 — 提取 autoTitle + generateTitle 方法 (rag-chat.service.ts):

private async autoTitle(session, content: string) {
  // 仅在标题为默认值"新对话"时自动更新
  if (!session.title || session.title === "新对话") {
    const title = this.generateTitle(content);
    await this.prisma.chatSession.update({
      where: { id: session.id },
      data: { title },
    });
  }
}

private generateTitle(content: string): string {
  const cleaned = content.trim().replace(/\s+/g, " ");
  if (cleaned.length <= 40) return cleaned;
  // 尝试在词边界截断,避免中文被切碎
  const truncated = cleaned.slice(0, 40);
  const lastSpace = truncated.lastIndexOf(" ");
  const cut = lastSpace > 20 ? lastSpace : 40;
  return cleaned.slice(0, cut) + "…";
}

规则说明

规则 行为
仅默认标题触发 title === "新对话" 时才自动生成,用户手动改过的标题不覆盖
首条消息触发 sendMessage 和 sendMessageStream 都在首次发消息时调用 autoTitle
短消息 (<40字) 直接使用整条消息作为标题
长消息 (≥40字) 截取前 40 字符,尽量在空格/词边界截断,末尾加 …
空白压缩 多空格/换行合并为单个空格,保持标题整洁
用户手动改标题 通过 PATCH /sessions/:id 修改后,不再自动覆盖

涉及文件

文件 变更
src/modules/rag-chat/rag-chat.service.ts 新增 autoTitle + generateTitle,sendMessage/sendMessageStream 改用新方法
## 完成情况 ### 交付物 **Service 层** — 提取 `autoTitle` + `generateTitle` 方法 (`rag-chat.service.ts`): ```typescript private async autoTitle(session, content: string) { // 仅在标题为默认值"新对话"时自动更新 if (!session.title || session.title === "新对话") { const title = this.generateTitle(content); await this.prisma.chatSession.update({ where: { id: session.id }, data: { title }, }); } } private generateTitle(content: string): string { const cleaned = content.trim().replace(/\s+/g, " "); if (cleaned.length <= 40) return cleaned; // 尝试在词边界截断,避免中文被切碎 const truncated = cleaned.slice(0, 40); const lastSpace = truncated.lastIndexOf(" "); const cut = lastSpace > 20 ? lastSpace : 40; return cleaned.slice(0, cut) + "…"; } ``` ### 规则说明 | 规则 | 行为 | |------|------| | 仅默认标题触发 | `title === "新对话"` 时才自动生成,用户手动改过的标题不覆盖 | | 首条消息触发 | sendMessage 和 sendMessageStream 都在首次发消息时调用 autoTitle | | 短消息 (<40字) | 直接使用整条消息作为标题 | | 长消息 (≥40字) | 截取前 40 字符,尽量在空格/词边界截断,末尾加 … | | 空白压缩 | 多空格/换行合并为单个空格,保持标题整洁 | | 用户手动改标题 | 通过 PATCH /sessions/:id 修改后,不再自动覆盖 | ### 涉及文件 | 文件 | 变更 | |------|------| | src/modules/rag-chat/rag-chat.service.ts | 新增 autoTitle + generateTitle,sendMessage/sendMessageStream 改用新方法 |
Author
Owner

test

test
Author
Owner

完成情况

交付物

Service 层 — 提取 autoTitle + generateTitle 方法:

private async autoTitle(session, content: string) {
  if (!session.title || session.title === "新对话") {
    const title = this.generateTitle(content);
    await this.prisma.chatSession.update({ where: { id: session.id }, data: { title } });
  }
}

private generateTitle(content: string): string {
  const cleaned = content.trim().replace(/\s+/g, " ");
  if (cleaned.length <= 40) return cleaned;
  const truncated = cleaned.slice(0, 40);
  const lastSpace = truncated.lastIndexOf(" ");
  const cut = lastSpace > 20 ? lastSpace : 40;
  return cleaned.slice(0, cut) + "…";
}

规则

规则 行为
仅默认标题触发 title === "新对话" 时才自动生成
首条消息触发 sendMessage / sendMessageStream 首次调用
短消息 <=40字 直接作为标题
长消息 >40字 截取前40字符,词边界截断+…
空白压缩 多空格/换行合并为单个空格
手动标题保护 PATCH 改过的标题不再自动覆盖

涉及文件

文件 变更
src/modules/rag-chat/rag-chat.service.ts 新增 autoTitle + generateTitle
## 完成情况 ### 交付物 **Service 层** — 提取 `autoTitle` + `generateTitle` 方法: ```typescript private async autoTitle(session, content: string) { if (!session.title || session.title === "新对话") { const title = this.generateTitle(content); await this.prisma.chatSession.update({ where: { id: session.id }, data: { title } }); } } private generateTitle(content: string): string { const cleaned = content.trim().replace(/\s+/g, " "); if (cleaned.length <= 40) return cleaned; const truncated = cleaned.slice(0, 40); const lastSpace = truncated.lastIndexOf(" "); const cut = lastSpace > 20 ? lastSpace : 40; return cleaned.slice(0, cut) + "…"; } ``` ### 规则 | 规则 | 行为 | |------|------| | 仅默认标题触发 | title === "新对话" 时才自动生成 | | 首条消息触发 | sendMessage / sendMessageStream 首次调用 | | 短消息 <=40字 | 直接作为标题 | | 长消息 >40字 | 截取前40字符,词边界截断+… | | 空白压缩 | 多空格/换行合并为单个空格 | | 手动标题保护 | PATCH 改过的标题不再自动覆盖 | ### 涉及文件 | 文件 | 变更 | |------|------| | src/modules/rag-chat/rag-chat.service.ts | 新增 autoTitle + generateTitle |
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/api-server#84
No description provided.