基于LLM的面向小学学段的AI辅助学习app个人博客(六)

一、项目背景

在传统 AI 问答系统中,用户输入问题后需等待服务器返回完整结果才能显示,这种同步方式在遇到复杂问题或网络延迟时,会极大影响用户体验。而“流式调用”技术能将 AI 的思考过程与回答内容逐步展现,实现类似“边生成边展示”的效果,使交互更加自然、高效。

本项目基于 Flutter 实现一个支持多学科切换的 AI 问答助手,后端通过 /ai/deepseek-stream 接口提供流式响应能力。本文将聚焦该项目在流式调用上的技术设计与实现细节。


二、流式调用的设计目标

  1. 边接收边展示:用户无需等待完整响应,系统实时展示 AI 的“思考过程”与“最终回答”。

  2. 学科定制化问题上下文:支持“语文”“数学”“英语”等多个学科的上下文构造。

  3. 界面动态更新与用户可控性:支持展开/折叠 AI 的思考过程,提高可读性与可控性。


三、技术实现

1. 发起流式请求

final request = http.Request('POST', Uri.parse('http://localhost:8000/ai/deepseek-stream?content=${Uri.encodeComponent(content)}')); 
request.headers['token'] = (await SharedPreferences.getInstance()).getString('token') ?? ''; 
final streamedResponse = await request.send(); 
final response = await http.Response.fromStream(streamedResponse);

通过 http.Requestsend() 方法创建一个流式 POST 请求,传入拼接后的用户问题上下文。


2. 响应内容解析与动态更新

服务器返回数据格式如下:

data:<think> data:这是AI的思考内容... data:</think> data:这是AI的最终回答...

客户端通过解析每一行 data: 标签内容,判断是否处于思考/回答阶段并分段更新 UI。

if (line.contains('data:<think>')) 
    isThinking = true; 
else if (line.contains('data:</think>')) { 
    isThinking = false; 
    isAnswer = true; 
}

每解析到一段内容,通过 setState() 实时刷新消息内容:

setState(() { _messages.last["text"] = "思考过程:\n$thinking\n\n回答:\n$answer"; });

3. 界面体验优化

  • 学科选择器:支持用户选择问题所属学科,在构造上下文时自动添加前缀(如“数学题:...”)。

  • 思考过程折叠功能:通过点击“思考过程”文字控制展开/收起详细信息,避免内容冗长影响阅读。

  • 发送状态提示:当 AI 正在响应时,输入框禁用并显示 CircularProgressIndicator


四、开发中遇到的问题与优化

1. 中文响应乱码

  • 问题:服务器返回的中文文本显示为乱码。

  • 原因:未正确解码 response 内容。

  • 解决方案:使用 utf8.decode(response.bodyBytes) 对返回内容进行正确解码,确保中文字符完整显示。

2. 流式响应阻塞 UI

  • 问题:流式响应过程中,长文本处理导致 UI 卡顿,影响用户体验。

  • 原因:快速连续 setState() 调用导致主线程占用过高。

  • 解决方案:通过在每次 UI 更新后增加 await Future.delayed(Duration(milliseconds: 50)); 控制节奏,保持界面响应顺畅。

3. 学科未绑定上下文

  • 问题:AI 回答偏泛或与题目学科不符。

  • 原因:问题未加入明确学科标识,影响后端大模型理解。

  • 解决方案:在问题前添加如 "数学题:" 前缀,用于构造带有学科背景的上下文内容,提升回答准确性。

4. 思考过程与最终输出的区分显示逻辑

  • 问题:AI 响应中“思考过程”和“回答”混合在一起,用户难以区分两者,阅读体验差。

  • 实现机制

    • 后端以 data:<think>data:</think> 标记思考阶段;

    • 客户端通过标记位 isThinkingisAnswer 控制内容流入对应的变量。

  • 展示策略优化

    • 在 UI 中将“思考过程”部分折叠显示,点击可展开;

    • “回答”内容单独展示,避免与推理过程混淆;

    • 若无思考过程,仅展示最终回答内容。

setState(() { 
    if (thinking.isEmpty) { 
        _messages.last["text"] = "思考过程:\n$answer\n\n回答:\n$answer"; 
    } else {
         _messages.last["text"] = "思考过程:\n$thinking\n\n回答:\n$answer"; } 
});
  • 用户体验提升

    • 实现 AI 的“可解释性”,帮助用户理解答案来源;

    • 支持折叠功能,避免内容过长影响信息阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值