FEATURED · 精选文章

ChatOllama 自动会话标题生成系统开发指南:从触发策略到源码级实现

发布时间 / 2026/9/18 16:25:13
来源 / 创域科博编辑部
栏目 / 资讯中心
ChatOllama 自动会话标题生成系统开发指南:从触发策略到源码级实现 ChatOllama 自动会话标题生成系统开发指南从触发策略到源码级实现【免费下载链接】chat-ollamaChatOllama is an open source agentic app for running AI agents across local and hosted models.项目地址: https://gitcode.com/GitHub_Trending/ch/chat-ollama本文面向 ChatOllama 的开发者与贡献者系统讲解会话标题自动生成功能的完整技术实现。内容以 docs/guide/README.md 开发者文档为骨架完整覆盖 会话标题生成完整指南 与 快速参考卡 中的全部架构、API、触发策略与集成示例并结合仓库内utils/autoTitleGeneration.ts、composables/useSessionTitle.ts、server/api/sessions/[id]/title.post.ts等源码进行深入剖析帮助读者理解其模块化设计、调用链与底层原理从而能够独立使用、集成和扩展这一能力。一、系统定位与架构总览ChatOllama 的会话标题生成系统Session Title Generation会在用户发出第一条消息后自动为会话生成有意义的标题替代“新对话”这类无信息量的默认占位。整套系统在设计上强调三个关键词模块化modular、可配置configurable、可复用reusable既能服务于聊天主流程也为文档摘要、批量处理、会话设置等未来场景预留了接入点。1.1 分层调用架构根据 docs/guide/session-title-generation.md 的架构说明系统分为四层数据流自顶向下┌─────────────────────────┐ ┌─────────────────────────┐ │ Chat Component │ │ Other Components │ │ │ │ (Future integrations) │ └───────────┬─────────────┘ └───────────┬─────────────┘ │ │ └──────────────┬───────────────┘ │ v ┌─────────────────────────┐ │ AutoTitleGenerator │ │ (utils/autoTitle...) │ └───────────┬─────────────┘ │ v ┌─────────────────────────┐ │ useSessionTitle() │ │ (composables/) │ └───────────┬─────────────┘ │ v ┌─────────────────────────┐ │ API Endpoint │ │ /api/sessions/*/title │ └─────────────────────────┘对应到仓库的实际文件这条链路是组件层components/Chat.vue在发送首条用户消息后调用标题生成工具层utils/autoTitleGeneration.ts中的AutoTitleGenerator类与createAutoTitleGenerator工厂负责封装触发条件Trigger与回调策略Composable 层composables/useSessionTitle.ts中的useSessionTitle()承载核心逻辑API 调用、数据库更新、触发判断API 层server/api/sessions/[id]/title.post.tsNuxt Nitro 服务端端点真正与 LLM 交互。1.2 快速参考中的流水线视角快速参考卡 docs/guide/session-title-quick-reference.md 用一条流水线浓缩了同一架构Component → AutoTitleGenerator → useSessionTitle() → API → LLM → Response ↓ ↓ ↓ ↓ ↓ ↓ UI Update Trigger Logic DB Update HTTP Request Title Generation可以看出组件只负责触发与 UI 更新触发判断在AutoTitleGenerator或 Trigger数据库写入与 HTTP 请求在 composable真正的标题生成发生在服务端 API。职责分离是这套设计的核心下面逐层展开。二、快速开始首条消息自动生成标题2.1 工厂函数createAutoTitleGenerator.forFirstMessage这是文档标注的“最常见用法”。在任意聊天组件中通过 utils/autoTitleGeneration.ts 暴露的工厂函数创建生成器!-- components/YourChatComponent.vue -- script setup import { createAutoTitleGenerator } from ~/utils/autoTitleGeneration // Setup auto title generation const autoTitleGenerator createAutoTitleGenerator.forFirstMessage((title) { // Update your UI when title is generated if (sessionInfo.value) { sessionInfo.value.title title emit(title-updated, title) } }) // In your message handler const onSendMessage async (messageContent) { // ... your existing message logic ... // Auto-generate title if conditions are met if (sessionInfo.value models.value.length 0) { const { family, name: model } parseModelValue(models.value[0]) autoTitleGenerator.attemptTitleGeneration( { messages: messages.value, sessionTitle: sessionInfo.value.title, messageContent: messageContent }, sessionInfo.value.id, model, family ) } } /script源码印证components/Chat.vue中正是这样接入的——它在 第 56-61 行 用createAutoTitleGenerator.forFirstMessage初始化生成器并在发送用户消息后第 224-238 行从targetModels[0]中通过parseModelValue解析出family与model再调用attemptTitleGeneration。2.2 工厂的触发策略实现forFirstMessage的内置 Trigger 在源码中如下与 composables/useSessionTitle.ts 中titleTriggers.firstUserMessage完全一致shouldGenerate: (context: { messages: any[], sessionTitle?: string }) { const hasNoTitle !context.sessionTitle || context.sessionTitle.trim() const userMessageCount context.messages.filter(m m.role user).length return hasNoTitle userMessageCount 1 }即两个条件同时满足才触发会话当前没有标题sessionTitle为空或全空白消息列表中恰好只有一条用户消息首条消息刚发出。extractMessage则负责从上下文中提取用于生成标题的内容且兼容多模态消息extractMessage: (context: { messageContent: any }) { const content context.messageContent if (Array.isArray(content)) { // 多模态内容只提取 text 类型的文本片段并拼接 return content .filter(item item.type text item.text) .map(item item.text) .join( ) } return content // 纯文本内容直接返回 }2.3attemptTitleGeneration的执行流程AutoTitleGenerator.attemptTitleGenerationutils/autoTitleGeneration.ts是入口方法开关检查若config.enabled false直接返回不做任何请求懒加载初始化await this.init()内部通过import(~/composables/useSessionTitle)动态导入 composable避免增加初始包体积委托给 composable调用useSessionTitle().generateTitleWithTrigger(trigger, context, model, family, sessionId, { onSuccess, onError })把标题成功回调映射到配置里的onTitleGenerated失败回调映射到onError。另外createAutoTitleGenerator.disabled()工厂返回一个enabled: false且shouldGenerate恒为false的生成器用于需要显式关闭标题生成的场景。三、高级用法自定义触发与直接 API 调用3.1 自定义触发器Custom Trigger当内置的“首条消息”触发条件不满足业务需要时可实现SessionTitleTrigger接口自定义触发逻辑import { useSessionTitle, type SessionTitleTrigger } from ~/composables/useSessionTitle // Custom trigger for specific scenarios const customTrigger: SessionTitleTrigger { shouldGenerate: (context) { // Your custom logic return context.messageCount 3 !context.hasTitle }, extractMessage: (context) { // Extract relevant content for title generation return context.lastUserMessage } } const { generateTitleWithTrigger } useSessionTitle() await generateTitleWithTrigger( customTrigger, context, model, family, sessionId, { onSuccess: (title) console.log(Generated:, title), onError: (error) console.error(Failed:, error) } )接口定义在 composables/useSessionTitle.ts 中export interface SessionTitleTrigger { shouldGenerate: (context: any) boolean // 是否应该生成标题 extractMessage: (context: any) string | null // 提取用于生成标题的消息内容 }generateTitleWithTrigger的源码逻辑保证了安全性shouldGenerate返回false或extractMessage提取结果为空字符串时都会提前返回null不发任何请求const generateTitleWithTrigger async (trigger, context, model, family, sessionId, options?) { if (!trigger.shouldGenerate(context)) return null const messageContent trigger.extractMessage(context) if (!messageContent?.trim()) return null return generateSessionTitle({ sessionId, model, family, userMessage: messageContent, ...options }) }3.2 直接 API 调用手动生成当需要完全掌控生成过程例如用户手动“重新生成标题”时直接使用generateSessionTitleimport { useSessionTitle } from ~/composables/useSessionTitle const { generateSessionTitle } useSessionTitle() const title await generateSessionTitle({ sessionId: 123, model: gpt-4, family: OpenAI, userMessage: Tell me about quantum computing, autoUpdate: true, // Auto-save to database style: technical, // Use technical prompt style maxWords: 8, onSuccess: (title) { console.log(Title generated:, title) }, onError: (error) { console.error(Generation failed:, error) } })3.3AutoTitleGenerator的完整配置除了工厂函数也可以直接实例化AutoTitleGenerator并在运行时通过updateConfig热更新配置例如跟随用户偏好开关const generator new AutoTitleGenerator({ enabled: true, // Enable/disable generation trigger: customTrigger, // When to generate onTitleGenerated: (title, sessionId) { // Called when title is successfully generated }, onError: (error, sessionId) { // Called when generation fails } }) // Update configuration later generator.updateConfig({ enabled: userPreferences.autoTitleGeneration })四、预置触发器Pre-built TriggersuseSessionTitle()返回对象中携带titleTriggers提供两个开箱即用的触发器。4.1titleTriggers.firstUserMessage触发条件源码实现见上文 2.2会话无标题 且 恰好只有 1 条用户消息。import { titleTriggers } from ~/composables/useSessionTitle const shouldGenerate titleTriggers.firstUserMessage.shouldGenerate({ messages: chatMessages, sessionTitle: currentTitle })4.2titleTriggers.onDemand无条件触发shouldGenerate恒返回true适合“用户手动点击刷新标题”的场景import { titleTriggers } from ~/composables/useSessionTitle // Always returns true const shouldGenerate titleTriggers.onDemand.shouldGenerate(context)其extractMessage对非字符串内容做了兜底若messageContent不是字符串则用JSON.stringify序列化确保总能提取出可用文本onDemand: { shouldGenerate: () true, extractMessage: (context: { messageContent: any }) { return typeof context.messageContent string ? context.messageContent : JSON.stringify(context.messageContent) } }五、API 参考客户端 Composable 与服务端端点5.1useSessionTitle()方法清单方法职责generateSessionTitle(options)主方法调用 API 并默认写入数据库支持完整回调generateTitleWithTrigger(trigger, context, model, family, sessionId, options?)智能生成仅当 Trigger 条件满足时才生成generateTitleAPI(model, family, userMessage, sessionId)底层方法只发 HTTP 请求不做数据库操作updateSessionInDB(sessionId, title)将新标题写入本地数据库IndexedDBgenerateSessionTitle的 Options 定义composables/useSessionTitle.tsinterface SessionTitleOptions { sessionId: number model: string family: string userMessage: string autoUpdate?: boolean // 是否自动写库默认 true onSuccess?: (title: string) void onError?: (error: any) void style?: concise | descriptive | technical | casual // 提示词风格 maxWords?: number // 默认 6 systemPrompt?: string // 自定义提示词覆盖 }注maxWords、style、systemPrompt会被透传给服务端端点composable 本身主要消费sessionId/model/family/userMessage/autoUpdate/onSuccess/onError。generateSessionTitle的实现逻辑源码要点const title await generateTitleAPI(model, family, userMessage, sessionId) if (title) { if (autoUpdate) await updateSessionInDB(sessionId, title) // 写库 onSuccess?.(title) return title } return null // catch 分支console.warn 记录 onError?.(error) return null5.2 数据库更新updateSessionInDB标题生成后写回本地客户端数据库clientDB.chatSessions并同步刷新updateTimeconst updateSessionInDB async (sessionId: number, title: string) { const { clientDB } await import(~/composables/clientDB) await clientDB.chatSessions.update(sessionId, { title, updateTime: Date.now() }) }这也是“实时更新”这一用户体验要求的落点服务端返回标题后前端立即写入本地库并触发 UI 回调。5.3 服务端 API 端点POST/api/sessions/:sessionId/title实现见 server/api/sessions/[id]/title.post.tsRequest Body{ model: string family: string userMessage: string systemPrompt?: string // 自定义提示词优先级高于 style maxWords?: number // 默认 6 style?: concise | descriptive | technical | casual // 默认 concise }Response{ title: string }服务端实现要点提示词模板表TITLE_PROMPTS每种 style 一个函数式模板均以Respond with only the title.约束模型只输出标题本身const TITLE_PROMPTS { concise: (maxWords) Generate a ${maxWords}-word title for this chat. Respond with only the title., descriptive: (maxWords) Generate a descriptive ${maxWords}-word title that captures the main topic of this chat. Respond with only the title., technical: (maxWords) Generate a technical ${maxWords}-word title focusing on the specific subject matter. Respond with only the title., casual: (maxWords) Generate a casual, friendly ${maxWords}-word title for this chat. Respond with only the title. }与聊天相同的模型工厂调用createChatModel(model, family, event)定义在 server/utils/models.ts确保标题生成使用与当前对话完全一致的模型与提供商配置——这正是博客 blogs/2025-09-09-improving-ai-chat-experience-with-smart-title-generation.md 中记录的“第二版”关键修复早期版本因未传递x-chat-ollama-keys请求头导致标题生成回退到本地 Ollama 而非用户正在使用的 Moonshot Kimi。组合消息llm.invoke([[system, prompt], [user, userMessage]])返回{ title }其中title经.trim()处理。5.4 模型一致性为什么标题 API 需要getKeysHeader客户端的generateTitleAPI在请求头中拼接了...getKeysHeader()utils/settings.ts 中定义为{ x-chat-ollama-keys: encodeURIComponent(JSON.stringify(keysStore.value)) }。该头携带用户在设置中配置的各模型提供商密钥与端点服务端通过server/middleware/keys.ts解析后注入event.context.keys最终由createChatModel按family从MODEL_FAMILIES映射或自定义模型列表中选取正确的 LLM 实例OpenAI / Azure OpenAI / Anthropic / Moonshot / Gemini / Groq / Ollama 等见 server/utils/models.ts 的createChatModel分支逻辑。这就是模型一致性的根本保障新功能必须复用基础设施认证、配置管理而不是重复造轮子。六、标题风格Title Stylesstyle参数决定服务端使用哪一套提示词仓库文档给出了四档风格及其示例输出Style说明示例输出concise简短直接Quantum Computing Basics / Quantum Computingdescriptive更详细的描述Understanding Quantum Computing Principles / Introduction to Quantum Computing Principlestechnical聚焦技术术语Quantum Superposition and Entanglement / Quantum Superposition and Entanglement Theorycasual友好口语化Learning About Quantum Stuff服务端默认style concise、maxWords 6通过systemPrompt传入自定义提示词时可以完全覆盖 style 模板const prompt systemPrompt || TITLE_PROMPTSstyle。七、集成场景示例文档提供了三类典型集成场景均可在真实业务中直接套用。7.1 文档摘要不写库利用autoUpdate: false让系统只返回标题不触碰会话数据库const { generateSessionTitle } useSessionTitle() const summarizeDocument async (docId: number, content: string) { const title await generateSessionTitle({ sessionId: docId, model: gpt-4, family: OpenAI, userMessage: content, style: descriptive, maxWords: 10, autoUpdate: false // Dont auto-save for docs }) await updateDocumentTitle(docId, title) // Handle the title manually }7.2 会话设置允许用户重新生成标题const regenerateTitle async () { const lastUserMessage messages.value .filter(m m.role user) .pop()?.content if (lastUserMessage) { const { generateSessionTitle } useSessionTitle() const newTitle await generateSessionTitle({ sessionId: currentSessionId, model: selectedModel, family: selectedFamily, userMessage: lastUserMessage, style: userPreferences.titleStyle }) if (newTitle) updateUI(newTitle) } }7.3 批量处理并行调用底层 API利用generateTitleAPI只做 HTTP 请求的特性配合Promise.allSettled对多个会话并行生成单个失败不影响整体const { generateTitleAPI } useSessionTitle() const processSessions async (sessions: Session[]) { const results await Promise.allSettled( sessions.map(session generateTitleAPI( session.model, session.family, session.firstMessage, session.id ) ) ) // Handle results... }八、最佳实践8.1 错误处理永不打断用户主流程标题生成是增强功能失败必须静默降级const generator createAutoTitleGenerator.forFirstMessage( (title) updateUI(title), (error) { console.warn(Title generation failed:, error) // Dont break the user experience } )源码层面generateSessionTitle的 try/catch 已保证任何异常都只console.warn 触发onError并返回null不会向上抛出。8.2 性能标题生成完全异步不阻塞 UIattemptTitleGeneration未 await 时即触发标题就绪后通过回调更新生成失败只记录日志不影响聊天功能高频率发消息场景建议防抖debounce避免重复请求AutoTitleGenerator.init()使用动态import()懒加载 composable避免增加初始包体积。8.3 用户体验生成期间展示加载状态完成后通过回调清除const [isGeneratingTitle, setIsGeneratingTitle] useState(false) const generator createAutoTitleGenerator.forFirstMessage( (title) { updateUI(title) setIsGeneratingTitle(false) } ) // Before generation setIsGeneratingTitle(true)8.4 配置化将标题生成做成用户可配置项并用updateConfig热更新const titleSettings { enabled: true, style: descriptive, maxWords: 8, autoGenerate: true } generator.updateConfig({ enabled: titleSettings.enabled })九、测试策略9.1 单元测试触发器逻辑import { titleTriggers } from ~/composables/useSessionTitle describe(Title Triggers, () { it(should generate on first user message, () { const context { messages: [{ role: user, content: Hello }], sessionTitle: } const shouldGenerate titleTriggers.firstUserMessage.shouldGenerate(context) expect(shouldGenerate).toBe(true) }) })9.2 集成测试完整生成链路import { useSessionTitle } from ~/composables/useSessionTitle describe(Session Title Generation, () { it(should generate and save title, async () { const { generateSessionTitle } useSessionTitle() const title await generateSessionTitle({ sessionId: 1, model: test-model, family: OpenAI, userMessage: Test message, autoUpdate: false }) expect(title).toBeTruthy() }) })可测试性设计贯穿源码纯逻辑Trigger 判断与副作用API 调用、写库分离错误边界清晰便于注入 mock。十、故障排查Troubleshooting10.1 常见问题清单标题没有生成检查触发条件是否满足首条消息且无标题确认model与family传参正确查看浏览器控制台是否有报错。API 报错确保模型提供商配置正确检查 API Key 与端点x-chat-ollama-keys头是否携带确认请求头包含认证信息。UI 未更新确认回调已正确连接检查sessionInfo是否为响应式reactive验证title-updated事件是否被父组件监听处理。10.2 调试清单来自快速参考卡✅ 模型model与家族family正确✅ 会话 ID 有效✅ 用户消息非空✅ 触发条件满足✅ API Key 已配置✅ 回调已连接✅ 浏览器控制台无错误10.3 调试模式通过回调打印日志快速定位const generator createAutoTitleGenerator.forFirstMessage( (title) { console.log(Title generated:, title) updateUI(title) }, (error) { console.error(Title generation error:, error) } )十一、迁移指南从旧系统升级若项目此前使用旧的标题生成逻辑例如composables/useGenerateSessionTitle.ts按以下三步迁移到当前 API1. 替换导入// Old import { generateSessionTitle } from ~/composables/useGenerateSessionTitle // New import { createAutoTitleGenerator } from ~/utils/autoTitleGeneration2. 更新组件逻辑从命令式到生成器模式// Old if (firstMessage) { generateSessionTitle(sessionId, model, family, message) } // New const generator createAutoTitleGenerator.forFirstMessage(onTitleGenerated) generator.attemptTitleGeneration(context, sessionId, model, family)3. 配置方式从位置参数改为选项对象// Old const title await generateSessionTitle(sessionId, model, family, message) // New const { generateSessionTitle } useSessionTitle() const title await generateSessionTitle({ sessionId, model, family, userMessage: message, style: concise })十二、扩展系统添加 Trigger 与 Style根据 docs/guide/session-title-generation.md 的 Contributing 章节扩展方向包括新增触发器扩展titleTriggers对象composables/useSessionTitle.ts实现SessionTitleTrigger接口新增风格在服务端 server/api/sessions/[id]/title.post.ts 的TITLE_PROMPTS中追加条目新增功能遵循关注点分离Component → Utility → Composable → API测试与文档为新功能补充测试用例并同步更新本指南。十三、文档导航与后续学习本指南所属的开发者文档体系位于 docs/guide/README.md包含会话标题生成完整指南架构总览、API 参考、集成示例、测试与迁移会话标题生成快速参考复制即用的代码片段、用例速查表与调试清单同目录下还有 知识库配置指南 等其他开发者文档。建议的开发学习路径通读主指南建立整体架构认知日常开发携带快速参考卡复制常用模式对照现有组件实现如components/Chat.vue中的接入方式理解落地细节运行测试确保改动不破坏现有行为结合 会话标题生成功能开发手记 了解该功能从“直接复制聊天逻辑”到“模块化重构”的三版演进过程以及模型一致性、提示工程、非阻塞设计等背后的工程取舍。本文内容基于 ChatOllama 仓库 docs/guide/README.md 开发者文档及其关联源码整理而成。【免费下载链接】chat-ollamaChatOllama is an open source agentic app for running AI agents across local and hosted models.项目地址: https://gitcode.com/GitHub_Trending/ch/chat-ollama创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻