整理自项目模拟面试,覆盖流式消息处理、HTTP streaming、Markdown 渲染、角色配置、FCM 拉活、模型微调与评估
本地会话组装 -> HTTP 流式请求 -> chunk 增量回调 -> UI 边收边展示 -> 结束后统一落库。system prompt、roleId、modelIdstream=1 发到聊天接口ResponseBody 的流onReceiving(chunk, received, beforeLength, afterLength) 往上层回调received 更新当前 assistant 消息,实现边生成边展示WAITING:已创建占位消息,等待服务端返回GENERATING:已经收到 chunk,正在持续生成SUCCEEDED:流正常结束FAILED:网络异常、次数不足、内容违规、token 超限等INTERRUPT:用户主动点击 StopHTTP POST + 流式响应读取,本质上属于 HTTP streaming,不是 WebSocket。| 方案 | 通信模型 | 适用场景 | 特点 |
|---|---|---|---|
| HTTP streaming | 单次 HTTP 请求,服务端持续写响应体 | AI 问答、长文本生成 | 接入成本低,和现有 HTTP 体系兼容 |
| SSE | 基于 HTTP 的单向事件流 | 服务端持续推文本/事件 | 比较标准化,适合单向流式输出 |
| WebSocket | 双向长连接 | IM、协同编辑、强实时双向交互 | 更灵活,但连接管理复杂 |
response.body().source() 后,可以在循环里持续 read(...)readTimeout 控制的是“两次成功读取数据之间,最多允许等多久”connectTimeout 按普通接口设置readTimeout 比普通接口更保守requestId 找到当前流式请求interruptedonEnd(INTERRUPT)cancel callcancel OkHttp CallTransfer-Encoding: chunkedchunked transferframe + stream 传输Markwon 把 Markdown 解析成 Spanned,再交给 TextView 原生渲染。parse(md) 把 Markdown 解析成 ASTrender(node) 把 AST 转成 SpannedsetParsedMarkdown(...) 设置到 TextViewPrism4jFixTablePluginJLatexMathPluginRoleInfoassets/config.json 做冷启动和离线兜底roleId 存 memory、persona 等信息briefIntrofirstMessageroleIdmodelIdsystemPromptmemorypersonafcmTokenFirebaseMessagingServiceaction 分发到不同推送处理器FirebaseMessagingServicepush_role_config.json 里选角色和文案| 知识点 | 速记 |
|---|---|
| AI 流式消息 | 本地组装上下文,HTTP 流式接收,chunk 增量渲染,结束统一落库 |
| HTTP streaming | 仍然是 HTTP,不是 WebSocket;请求一次,响应持续写 |
| OkHttp 读流 | ResponseBody 是可持续消费的字节流,持续 read() 即可 |
| Stop 处理 | 当前实现更偏客户端软中断,保留部分结果,不等于服务端瞬时停算 |
| Markdown 渲染 | Markwon 把 Markdown AST 转成 Spanned,原生 TextView 渲染 |
| 角色配置 | 公共角色配置 + 用户个性化配置,两层解耦 |
| FCM 拉活 | 借系统推送通道触达用户,再通过通知点击把访问拉回 App |
| 模型微调 | 重点是数据处理、格式转换、部署和批量效果评估 |