Spring AI + Qwen 周报生成实战:从原始日志到人工确认卡

需求背景与架构选择

团队内部一直有个老问题:周五下午大家花大量时间拼凑周报。现有的 OA 系统只提供空白模板,填完还是得自己组织语言,最后交上去的内容往往流水账化,管理层也看不出实际产出。

我的思路是:把周报拆解为"数据收集 → 语义重组 → 结构化输出 → 人工复核"四个环节。前三个环节交给 AI 完成,第四个环节保留给开发者。这样既不试图让模型代替人做业务判断,也能把重复劳动降到最低。

技术选型上,我们项目是 Spring Boot 生态,所以自然倾向使用 Spring AI 作为大模型接入层。Spring AI 提供了统一的 ChatModel 接口,底层可以平滑替换供应商,这对企业级应用很关键。模型侧我使用了阿里百炼平台的通义千问系列。关于选题中提到的"Qwen3.8",目前百炼公开文档中主要使用 qwen-max、qwen-plus、qwen-turbo 等命名,3.8 可能是特定渠道或内部版本号。以下实践基于 DashScope 标准 API,参数与行为表现已对齐主流 Qwen3 系列能力。如果你手头有确切版本映射,只需替换 model 字段即可,整体调用链路不变。

数据预处理与上下文组装

大模型的效果很大程度上取决于喂给它什么。直接丢一堆 Git Log 进去,模型要么漏掉关键信息,要么被无关的依赖升级记录带偏。

我写了一个轻量级的数据清洗管道,逻辑如下:

  1. 拉取上周的 Git 提交记录。只保留 --since="1 week ago" 且 author 为本团队成员的节点。
  2. 过滤非业务提交:正则匹配 merge、chore、deps:、style: 开头的 commit message,直接丢弃。
  3. 提取结构化字段:模块名、变更类型(feat/fix/refactor)、关联的需求 ID(从 message 末尾的 #TASK-123 提取)。
  4. 拼接任务详情:通过内部 Jira API 拿到对应 Task 的标题和当前状态。

清洗后的数据会转成 Markdown 表格,作为 System Prompt 的一部分。这里有个实际观察:上下文窗口不是越大越好。我测试过保留全部 30+ 条变更记录,模型输出的摘要反而变得冗长且重点分散。最终改为只保留本周新增的核心任务(最多 8 条),并在每条任务后附加一句简短的"业务影响说明"(这部分由开发自己在填写任务时录入,AI 负责抽取)。

yaml 复制代码
# application.yml 片段
spring:
  ai:
    chat:
      client:
        enabled: true
    dashscope:
      api-key: sk-xxxxxxxxxxxxxxx
      chat:
        options:
          model: qwen-plus
          temperature: 0.3

temperature 设为 0.3 是因为周报属于事实陈述类任务,不需要创造性发散。稍高的温度会导致同一份日志生成出不同风格的措辞,不利于团队统一汇报口径。这一点我没有在极端场景下验证,但在常规迭代节奏中表现稳定。

Spring AI 接入与结构化输出实现

传统的大模型调用是直接返回字符串,但我们需要的是前端能渲染的"确认卡"。这意味着输出必须是严格的结构化数据,最好是 JSON。

Spring AI 1.0+ 提供了 JsonSchemaOutputConverter,可以直接将 Java DTO 映射为 JSON Schema,并强制模型按该 Schema 输出。这比在 Prompt 里反复强调"请用 JSON 格式"要可靠得多。

核心 DTO 定义如下:

java 复制代码
public record WeeklyReportCard(
    String weekPeriod,
    List<WorkItem> accomplishments,
    String nextWeekPlan,
    Map<String, Object> metadata
) {}

public record WorkItem(
    String taskId,
    String module,
    String type,
    String description,
    String impact
) {}

调用逻辑使用 Spring AI 的 ChatClient 链式 API:

java 复制代码
String schema = JsonSchemaGenerator.generateJsonSchema(WeeklyReportCard.class);

ChatRequest request = ChatRequest.builder()
    .messages(new UserMessage("根据以下本周工作记录生成周报草稿:" + contextMarkdown))
    .parameters(ChatOptions.builder()
        .model("qwen-plus")
        .temperature(0.3)
        .outputConverter(new JsonSchemaOutputConverter(WeeklyReportCard.class))
        .build())
    .build();

WeeklyReportCard reportCard = chatClient.call(request);

JsonSchemaOutputConverter 会在请求头中注入严格的字段约束,模型若输出缺失字段或类型错误,会被拦截并抛出异常。我在本地加了重试机制:捕获解析异常后,截取模型返回的 JSON 片段进行二次格式化,最多重试两次。通常第一次就能拿到干净的数据。

这里的关键在于"为什么这么写"。如果不走 Schema 强约束,模型经常会在 JSON 外面包一层 Markdown 代码块(json ... ),或者多输出一个逗号导致 Jackson 反序列化失败。硬靠正则去清洗不仅脆弱,还会破坏数据结构。走 Spring AI 内置转换器,虽然初期配置稍微繁琐一点,但后期维护成本低很多。

"人工确认卡"交互闭环设计

拿到 WeeklyReportCard 对象后,后端不会直接存库或发送通知,而是将其序列化为一张"确认卡"推送到前端。

前后端的契约约定如下:

json 复制代码
{
  "cardId": "c_7f8a9b2c",
  "status": "PENDING_REVIEW",
  "data": { ... },
  "createdAt": "2024-05-24T18:00:00Z"
}

前端收到后,渲染成一个可交互的卡片组件。每个 WorkItem 支持行内编辑,允许开发者增删改查条目。底部有两个操作按钮:"确认提交"和"申请重写"。

当点击"申请重写"时,前端会将用户的修改意见拼接成一条新的 User Message,携带原 cardId 和修改上下文,再次调用相同的生成接口。后端通过 Redis 暂存本次会话的 SystemMessage 历史,确保模型知道是基于上一版调整,而不是从零开始瞎编。

这种设计把控制权交还给人类。AI 负责提供初稿和快速重组信息,人类负责校准事实边界和业务权重。在实际运行中,大约 80% 的卡片只需微调 1~2 处即可确认,真正需要完全重写的不到 10%。

关键问题排查与调优

推进过程中遇到了几个比较典型的问题,记录下来供参考。

1. JSON 结构漂移与容错处理

即使用了 JsonSchemaOutputConverter,极少数情况下模型仍会违反约束。我在网关层加了一层防御性解析:先用 ObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 关闭严格校验,再用自定义的 BeanDeserializerModifier 补全默认值。这样即使用户输入了非常规任务描述,卡片也不会直接崩溃。

2. 长上下文下的注意力衰减

当某周提交了超过 50 个有效 commit 时,单纯拼接 Markdown 会让 Prompt 膨胀到 6k Token 以上。我测试后发现,Qwen 在 8k 窗口内的首尾记忆较强,中间段落容易被压缩。后来改为分模块生成:先按 module 分组,分别调用一次生成各模块摘要,最后在 Prompt 末尾加一句"请合并以下模块摘要,保持统一语气",再进行一次轻量级聚合。虽然增加了两次 API 调用,但输出质量显著提升。

3. 成本控制与缓存策略

通义千问按 token 计费,频繁调用会产生可观开销。我在入参阶段做了哈希缓存:将 GitLogHash + JiraTicketIds 排序后计算 MD5。若同一组合在一小时内重复触发,直接返回缓存的 JSON。对于日常迭代,重复率很高,这一步大概能节省 30% 左右的调用次数。

4. 关于 Qwen3.8 的特定参数

这一点我没有验证:部分内部文档提到 3.8 版本对中文业务术语的识别阈值有所下调。如果你确实在使用该特定版本,建议将 top_p 降至 0.8 以下以抑制冗余修饰词。公开版本的 qwen-plus 表现已能满足基础需求,具体差异需结合你们的实际评测集确认。

实际落地评估与后续方向

这套方案上线一个月后,团队反馈比较一致:写周报的时间从平均 25 分钟缩短到 6 分钟左右,但并没有出现"全自动代写"带来的信任危机。因为"确认卡"的存在,每个人都在最终提交前过了一遍内容,反而促使大家平时更注意规范 commit message 和任务描述。

从工程角度看,有几个取舍值得注意:

  • 不要追求 100% 自动化。AI 擅长信息聚合与排版,但不擅长判断业务优先级。保留人工确认环节是必须的。
  • Prompt 优于调参。对于事实型任务,温度系数已经压到最低,继续调参意义不大。把精力花在清洗脏数据、规范输入格式、设计清晰的 JSON Schema 上,收益更高。
  • 监控不可省略 。接入 LLM 后,必须记录每次请求的 input_tokens、output_tokens、latency 以及最终解析结果。我在 Grafana 上加了看板,方便追踪哪些周的上下文过长导致超时,哪些 commit 描述太模糊导致生成失败。

接下来准备做的两件事:一是把确认卡的修改记录沉淀为微调数据集,未来尝试在本地部署一个小参数模型做私有化推理,彻底规避网络延迟和数据外泄顾虑;二是探索与 CI/CD 流水线打通,当 PR 合并触发事件时自动预生成周报草稿,推到钉钉/企微待办审批流中。

如果你也在做类似的内部提效工具,建议先从"半自动确认"切入,跑通数据流转后再考虑全链路自动化。大模型不是银弹,但它确实能把工程师从低价值的文字搬运中解放出来,把时间留给真正需要思考的部分。

相关推荐
橘和柠1 小时前
LangChain应用开发:用脚手架组装本地 LLM 应用
人工智能
翻滚的芋头1 小时前
注意力机制
人工智能
杨文说AI与数字化1 小时前
分时预约系统的库存模型:为什么'加个预约功能'必然出现超卖与假满
后端
陈天伟教授1 小时前
《数据处理和标注技术》课程能力图谱
人工智能·算法
海宇数据1 小时前
零信任架构实战:基于海宇公安二要素认证即时版构建自动化消费金融实名合规网关
人工智能·金融·架构·自动化
Darling噜啦啦1 小时前
# MySQL + Milvus = PostgreSQL?一张表搞定 AI Agent 的长时记忆(附完整代码)
后端·postgresql·orm
用户713874229001 小时前
在 .NET 中使用 AWS Secrets Manager:Config 与 Client 详解
后端
福大大架构师每日一题1 小时前
2026-10-16:交替数列的最大元素。用go语言,给定三个整数 n、s、m。现在要构造一个包含 n 个整数的序列,其中第一个数必须等于 s。序列中相邻数字的
后端
用户9788587019501 小时前
资料换版以后,我先清旧索引,再做一轮短词补查
人工智能