🎯 流式改造优化阶段
🎯 流式改造优化阶段:
流式改造的需求分析:
为了提升用户体验,让用户能实时看到AI生成代码的过程,而不是等待最终结果,需要将原来的同步调用改造为流式输出。
1. 配置流式模型
-
在yaml配置文件中新增streaming-chat-model配置,设置最大token防止截断
-
保持与原有chat-model相同的参数,但使用不同的Bean
-
支持流式响应的模型配置
# 流式响应不支持结构化输出,复制的时候需要注释掉
# strict-json-schema: true
# response-format: json_object
2. 服务工厂改造
-
在AiCodeGeneratorServiceFactory中注入StreamingChatModel
-
修改AI服务创建方式,从简单的create()改为builder()模式
-
同时支持同步和流式两种模型,保持向后兼容
3. AI服务接口扩展
-
在原有接口基础上新增流式方法generateHtmlCodeStream()和generateMultiFileCodeStream()
-
关键差异:返回值从结构化对象(HtmlCodeResult)改为字符串流(Flux
) -
使用相同的@SystemMessage注解,保持提示词一致性
4. 解析器登场
❓ 问题:为什么流式输出需要解析器,而结构化输出不需要?
✅ 答案:
-
结构化输出:AI直接返回JSON格式,LangChain4j自动转换为对象
-
流式输出:AI返回的是字符串片段流,包含
html、css等标记,需要正则表达式提取纯代码
解析器工作原理:
-
定义三种正则模式:HTML_CODE_PATTERN、CSS_CODE_PATTERN、JS_CODE_PATTERN
2.两个解析方法:parseHtmlCode()处理单文件,parseMultiFileCode()处理多文件
3.提取逻辑:用正则匹配```标记包围的代码块,提取纯净代码内容
4.容错处理:如果没找到代码块,将整个内容作为代码处理
5. 门面类流式方法改造
核心逻辑变化:
原来:AI服务 → 结构化对象 → 文件保存
现在:AI服务 → 字符串流 → 拼接完整字符串 → 解析器处理 → 结构化对象 → 文件保存
实现细节:
-
使用StringBuilder在doOnNext()中实时收集字符串片段
-
在doOnComplete()中触发解析和保存逻辑
-
调用原始的CodeParser静态方法解析完整字符串
return result
.doOnNext(chunk -> {
// 实时收集代码片段
codeBuilder.append(chunk);
})
.doOnComplete(() -> {
// 流式返回完成后保存代码
try {
String completeHtmlCode = codeBuilder.toString();
HtmlCodeResult htmlCodeResult = CodeParser.parseHtmlCode(completeHtmlCode);
// 保存代码到文件
File savedDir = CodeFileSaver.saveHtmlCodeResult(htmlCodeResult);
log.info("保存成功,路径为:" + savedDir.getAbsolutePath());
} catch (Exception e) {
log.error("保存失败: {}", e.getMessage());
}
});
两段相似代码(下一节优化)
-
复用原有的CodeFileSaver保存文件
-
错误处理和日志记录
6. 统一入口扩展
-
新增generateAndSaveCodeStream()方法,与原有的generateAndSaveCode()并行存在
-
保持相同的参数和分发逻辑,但调用流式处理方法
-
用户可以根据需要选择同步或流式调用
/**
* 统一入口:根据类型生成并保存代码(流式)
*
* @param userMessage 用户提示词
* @param codeGenTypeEnum 生成类型
*/
public Flux<String> generateAndSaveCodeStream(String userMessage, CodeGenTypeEnum codeGenTypeEnum) {
if (codeGenTypeEnum == null) {
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "生成类型为空");
}
return switch (codeGenTypeEnum) {
case HTML -> generateAndSaveHtmlCodeStream(userMessage);
case MULTI_FILE -> generateAndSaveMultiFileCodeStream(userMessage);
default -> {
String errorMessage = "不支持的生成类型:" + codeGenTypeEnum.getValue();
throw new BusinessException(ErrorCode.SYSTEM_ERROR, errorMessage);
}
};
}
7. 测试验证
-
编写单元测试验证解析器功能正确性
-
测试流式调用的完整流程
-
使用collectList().block()阻塞等待流式完成,验证最终结果
🔑 关键认知总结:
-
解析器的回归:流式输出重新需要解析器,因为AI返回的是原始文本流
2.代码复用:巧妙复用了原有的文件保存器和结构化对象
3.用户体验提升:用户可以实时看到生成过程,而不是等待最终结果
4.架构兼容性:同时支持同步和流式两种调用方式
流式改造的本质:将"等待完整结果"变为"实时收集片段+最终解析"的模式!

浙公网安备 33010602011771号