智汇笔记项目实战(六):SophNet 大模型接入与多轮 RAG 流式联调——从中期验收到产品化 AI 工作台
摘要
中期检查过后,老师为我们 SophNet 账号充值约 400 元算力额度,于是我决定这周的任务是把之前跑通的轻量 RAG 原型打磨成可日常联调的AI 工作台。本周工作集中在四条线:(1)按 OpenAI 兼容协议接入 SophNet,密钥与 Git 仓库解耦;(2)在 FULLTEXT 召回之上增加多轮 sessionId、历史截断与清空接口;(3)新增 RAG 专用 SSE 流式接口,侧栏从假打字改为真实流式推送;(4)把 format/quiz 等 Agent 接到编辑器顶栏,并根据 llm/status 做按钮置灰。联调过程中还顺带打通了 Redis、MySQL 本地环境与注册登录链路。
一、本周任务概述:从中期「能讲」到「能天天用」
第十周我们完成了 MySQL FULLTEXT 召回、RagChatService、POST /api/ai/rag/chat 以及前端侧栏联调,但还是存在几处短板:
一、LLM 长期未配置,Map-Reduce 摘要、RAG 生成、format/quiz 只能降级,演示时看到的往往是检索片段,而不是模型总结。
二、RAG 侧栏虽然接了后端,回答仍是一次性返回,前端用 setInterval 模拟打字机,与第八周 SSE 摘要链路体验不一致,也无法中途停止。
三、后端 /api/ai/format、/api/ai/quiz 等接口早已存在,编辑器里没有入口,任务书要求的「多 Agent 可触达」在 UI 层不完整。
四、RAG 只有单轮,用户追问如「刚才第三点是什么」时,模型看不到上一轮上下文。
因此这周目标很明确:接上 SophNet 真模型、补齐多轮与流式、把 Agent 按钮露出来,让组员可以每天联调。

二、SophNet 接入:OpenAI 兼容网关与本地密钥管理
SophNet(https://www.sophnet.com/)提供 OpenAI 兼容的 Chat Completions 接口。官方文档(https://sophnet.com/docs/component/quickstart.html)说明:在项目下创建 API Key、启用 ChatCompletion 服务后,即可通过 Bearer Token 调用。我们控制台已启用 DeepSeek-V3.1 模型,RPM/TPM 额度对实训场景足够。
现有 LlmChatClient 按 {base-url}/chat/completions 封装,接入 SophNet 无需改 HTTP 协议,只需配置三项:
smartnotes.llm.base-url=https://www.sophnet.com/api/open-apis/v1
smartnotes.llm.api-key=******
smartnotes.llm.model=DeepSeek-V3.1
为避免密钥进仓库,新增 application-local.properties.example 作为模板,application.properties 增加 spring.config.import=optional:classpath:application-local.properties。开发者复制 example 为 application-local.properties,填入 Key 即可。backend/.gitignore 已忽略该文件。
GET /api/ai/llm/status 响应增加 model 与 providerHint 字段。前端侧栏和编辑器顶栏据此显示绿色「DeepSeek-V3.1」或灰色「LLM 未配置」——这是判断 SophNet 是否连上的最直观方式,不必在浏览器里直接访问需登录的接口。


三、本地环境打通:Redis + MySQL 是「能登录」的前置条件
本周联调里有一个容易误判的点:SophNet 配好了,但注册仍报「服务器内部错误」,控制台 401,容易以为是 LLM 或前端 Bug。实际排查下来,根因是本地基础设施未就绪。
注册与登录流程在后端会做两件事:向 MySQL user 表插入/查询用户,向 Redis 写入 Token。LoginInterceptor 校验 Token 时也查 Redis。因此:
Redis 未启动 → 注册 saveToken 失败 → 500 服务器内部错误
MySQL 密码不对或 smartnotes 库未初始化 → 任何用户接口 500
我本地的解决步骤是:
- 安装并启动 Memurai(Windows 兼容 Redis),在 127.0.0.1:6379 执行 PING 返回 PONG。
- 用 Navicat 连接 local-mysql,新建 smartnotes 库,执行 V1__init.sql 初始化 user、note 等表。
- 在 application-local.properties 写入本机 MySQL 真实密码。
- 重启后端,浏览器清除 localStorage 里的 smartnotes_token,重新注册。



四、多轮 RAG:sessionId 与内存会话服务
多轮能力由 RagChatSessionService 实现,按 userId 隔离,sessionId 用 UUID 生成,存在 JVM 内存 ConcurrentHashMap 中。主要配置:最多保留 4 轮历史(session-max-turns)、历史区字符预算约 2400(session-max-history-chars)、会话 TTL 120 分钟。
流程如下:
- 前端首次提问不传 sessionId,后端创建新会话,在 RagChatResultVO 或 SSE meta 里返回 sessionId。
- 后续提问带上同一 sessionId,RagChatService 拼 userPayload 时追加「对话历史」块,并注明历史仅供理解指代,事实仍以本轮检索材料为准。
- 每轮结束后 appendTurn 写入内存;用户点「新对话」调用 POST /api/ai/rag/session/clear,前后端一并重置。
这是「先跑通产品逻辑、再考虑 Redis 持久化会话」的务实选择。答辩时需说明:服务重启后会话丢失,但用户隔离与单机演示足够;结项前若有余力可把 Session 迁到 Redis。
RagQueryDTO 增加可选 sessionId;RagChatResultVO 增加 sessionId 字段,便于 Pinia 持久化。

五、RAG SSE 流式:与第八周摘要链路统一协议
第八周 AiSseController 已实现 POST /api/ai/stream/summarize,事件协议为 meta / delta / done / error。本周在同一 Controller 增加 POST /api/ai/stream/rag/chat,入参复用 RagQueryDTO。
LlmChatClient 仍是非流式 HTTP,RAG SSE 与摘要一样采用「先生成完整 answer,再按 24 字符步长伪流式推送」。meta 事件 JSON 包含 streamId、sessionId、citations、usedLlm。
前端 rag.js 封装 streamRagChat,基于 postSseStream(fetch + ReadableStream,支持 Bearer Token 与 AbortController)。aiChat store 改造后:收到 meta 更新 citations 与 sessionId;delta 直接 append 到 assistant 消息;stop() 通过 abort 断开 SSE,与摘要导入取消体验一致。
这样侧栏问答与一键导入在交互层统一。答辩演示可先 SSE 导入笔记,再在侧栏追问,叙事连贯。
六、编辑器 Agent 露出:排版与习题
HomeView 顶栏新增「AI 排版」「生成习题」,分别调用 POST /api/ai/format 与 POST /api/ai/quiz,以当前笔记 contentMd 为 text。成功后以分隔线追加到文末,不覆盖原文,方便对比 Agent 效果。
按钮与 llmConfigured 联动:SophNet 未配置时 disabled;onMounted 时 fetchLlmStatus。agentBusy 防止重复点击。
代码量不大,但产品意义明确:任务书要求的「不少于 3 套 Agent Prompt」不再只存在于 Postman,而是编辑器里一键可达。


七、工作量小结
本周新增/修改约 15+ 个文件:RagChatSessionService、AiSseController RAG 端点、DTO/VO 扩展、application-local 模板、GlobalExceptionHandler 异常日志、前端 rag.js / aiWorkbench.js、aiChat store SSE 改造、AiChatPanel 与 HomeView 工具栏等。开发与联调合计约 3~4 个晚上;SophNet Key 与模型名对齐、SSE meta 字段解析、多轮历史与检索材料优先级说明,以及 Redis/MySQL 环境排查,是主要耗时点。环境打通后的验收标志很简单:侧栏绿色 DeepSeek-V3.1 + 笔记有料时能召回并流式回答。
更多推荐
所有评论(0)