(9)批量生成文章并同步存入 MySQL 和 Redis

目录

利用我现有的 Java 业务逻辑,结合大模型(LLM)自动生成能力,编写一个集成测试类。


🍥一、技术选型

  1. LangChain4j (ChatLanguageModel):调用我本地的 Ollama (Gemma 3),让它扮演不同领域的学者。
  2. Spring Boot Test / CommandLineRunner:用于触发批量执行逻辑。
  3. 现有业务 Service (PostService):直接复用我写好的 publishArticle 方法。

🍥二、具体实现步骤(附流程图)

  1. 准备种子数据(学科与用户)
    在数据库里先手动准备好几个用户(User ID: 1, 2, 3...)和话题(Topic ID: 1, 2, 3...)。
  2. 编写批量生成脚本 (DataGeneratorService)
    在 src/test/java 下或者 service 包下创建一个工具类。
  3. 写一个单元测试来触发脚本

🍥三、核心代码实现

1. 文章生成Prompt设计

需要考虑能被程序解析所以提示词中采用格式约束,减少数据清洗的成本。

java 复制代码
// 在 DataGeneratorService 中定义指令模板
String promptTemplate = """
    你是一个【%s】领域的资深专家。
    请撰写一篇前沿的学术博客,要求:
    1. 标题必须具有专业性(包含行业黑话)。
    2. 正文约300字,逻辑严密,描述该领域的一个具体技术问题或趋势。
    3. 严格遵守输出格式,不得包含任何开场白:
       标题: [此处填标题]
       内容: [此处填正文]
    """;

// 调用时动态注入学科名称
String finalPrompt = String.format(promptTemplate, topic.getName());
String aiResponse = chatModel.generate(finalPrompt);

2. 数据解析逻辑

大模型的输出有时会带有不可控的空格或换行,直接解析容易报错。于是我利用较为健壮的边界搜索算法提取核心内容。

利用try-catch 捕获和边界判定。

java 复制代码
/**
 * 健壮的文本提取逻辑
 * @param text  LLM返回的全文本
 * @param start 标识符(如"标题:")
 * @param end   结束标识符(如"内容:")
 */
private String parse(String text, String start, String end) {
    try {
        int startIndex = text.indexOf(start);
        if (startIndex == -1) return "未知标题";
        startIndex += start.length();

        int endIndex = (end == null || text.indexOf(end) == -1) 
                       ? text.length() 
                       : text.indexOf(end);

        // 过滤首尾空格及特殊字符
        return text.substring(startIndex, endIndex).trim();
    } catch (Exception e) {
        log.error("解析文本块失败: {}", e.getMessage());
        return "数据解析异常";
    }
}

3. 自动化的Ingestion Pipeline(双路写入)

这是整个流程的灵魂:复用生产环境的业务逻辑。通过调用现有的 postService,确保了每一条合成数据都完美经历了 MySQL 持久化与 Redis 向量化。

利用 MyBatis 的 useGeneratedKeys,使向量库中的 articleId 元数据与 MySQL 的自增 ID 严丝合缝地关联(PostMapper.xml中)。

java 复制代码
public void generateBatchData(int countPerTopic) {
        // 1. 动态获取数据库里现有的所有分类
        List<Topic> dbTopics = topicMapper.findAll();
        if (dbTopics.isEmpty()) {
            System.err.println("❌ 数据库 topic 表是空的,请先添加分类!");
            return;
        }

        for (Topic topic:dbTopics) {
            for (int i = 0; i < countPerTopic; i++) {
                // 1. 让 AI 产生一篇伪学术文章
                String prompt = String.format(
                        "你是一个%s领域的专家。请写一篇简短的学术博客。要求:" +
                                "1. 标题新颖且具有专业性。2. 正文约300-500字,包含具体的专业术语。3. 只返回结果,格式为 标题:xxx 内容:xxx",
                        topic.getTitle()
                );

                String aiResponse = chatModel.generate(prompt);


                // 构造 Post 对象
                Post post = new Post();
                post.setTitle(parse(aiResponse, "标题:", "内容:"));
                post.setContent(parse(aiResponse, "内容:", null));

                // 2. 使用数据库里真实的 ID
                post.setTopic_id(topic.getId());

                // 设置一个默认的 userID(确保该用户在 user 表里存在)
                post.setUser_id(1L);

                // 4. ⭐ 触发核心业务逻辑
                // 此处会同步触发:MySQL保存 -> 文本切片 -> 语义向量化 -> RedisStack存入
                postService.publishArticle(post);

                System.out.println("已为分类 [" + topic.getTitle() + "] 生成文章");
            }
        }
    }

🍥四、效果展示

前端:

Redis Stack:

相关推荐
瀚高PG实验室2 小时前
pgvector 安装及使用示例
数据库·瀚高数据库
2401_887724502 小时前
Pandas 中使用交叉表为分类列生成计数型宽表结构
jvm·数据库·python
justjinji2 小时前
PHP函数如何识别PCI设备厂商ID_PHP获取扩展卡硬件标识【说明】
jvm·数据库·python
2201_761040592 小时前
怎么监控MongoDB副本集的复制缓冲区积压_复制流速率评估
jvm·数据库·python
2402_854808372 小时前
Layui tab选项卡如何动态根据ID值进行程序化切换
jvm·数据库·python
m0_377618232 小时前
mysql如何设置字段为自动递增_使用alter table添加auto increment
jvm·数据库·python
Wyz201210242 小时前
Navicat导入HTML网页报错怎么跳过_忽略错误记录高级选项
jvm·数据库·python
InfinteJustice2 小时前
CSS Grid布局如何实现响应式卡片网格_结合媒体查询调整列数
jvm·数据库·python
2301_813599552 小时前
HTML函数开发用金属机身笔记本散热更好吗_材质对温控影响【指南】
jvm·数据库·python