文档解析模块:U3W-AI 的 AI 驱动文档解析系统
在 U3W-AI 实习期间独立开发的文档解析模块,Spring Boot 后端 + Vue 3 前端 + 腾讯元器工作流
文档解析模块:U3W-AI 项目的 AI 驱动文档解析系统
项目背景
这是我在 U3W-AI 实习期间独立开发的一个文档解析功能模块。用户上传文档(PDF/Word/TXT),后端配合腾讯元器智能体工作流自动解析文档内容,最终返回结构化结果。整个过程异步进行:上传后立即返回,AI 解析完成后通过回调通知。
我同时负责了后端(Spring Boot + MyBatis-Plus)和前端(Vue 3 + Element Plus)的开发,以及腾讯元器工作流的配置。
系统架构
前端上传文档 → 后端接收 → 调用内部 /upload 接口存储文件
→ 调用腾讯元器 API 提交工作流任务 → 立即返回(异步)
→ 元器工作流处理完成后 HTTP 回调后端 → 更新解析结果
→ 前端轮询 /status 接口获取解析状态
后端实现
后端代码位于 WxFbsir-business/src/main/java/com/wx/fbsir/business/documentparse/,包含标准四层结构:
controller/DocumentParseController.java # API 接口层
service/IDocumentParseService.java # 服务接口
service/impl/DocumentParseServiceImpl.java # 业务实现
mapper/DocumentParseMapper.java # 数据库访问
domain/DocumentParse.java # 实体类
核心业务流程图
uploadAndParse()
├─ 1. 参数校验(文件非空、提示词非空)
├─ 2. 生成文档ID(DOC-XXXXXXXXXX 格式)
├─ 3. 调用内部 /upload 接口上传文件
├─ 4. 替换文件 URL 域名(localhost:8080 → 内网穿透域名)
├─ 5. 创建 DocumentParse 记录(状态=0 处理中)
├─ 6. 调用 triggerDocumentParse()(@Async 异步触发)
└─ 7. 立即返回记录 ID,不等待 AI 结果
updateParsedContent() ← 腾讯元器工作流回调
├─ 1. 根据 documentId 查找记录
├─ 2. 保存 parsedContent
└─ 3. 更新 processStatus=1(已完成)
/status/{id} ← 前端轮询
└─ 返回轻量级状态(不含大字段内容)
关键设计:异步处理架构
// Controller 层触发异步,解决 @Async 同类调用失效问题
@PostMapping("/uploadAndParse")
public AjaxResult uploadAndParse(@RequestParam("file") MultipartFile file, ...) {
// ... 参数校验、上传文件 ...
// 同步创建记录
DocumentParse documentParse = documentParseService.createDocumentParseAndProcess(...);
// 从 Controller 调用 @Async 方法(确保 AOP 代理生效)
documentParseService.triggerDocumentParse(...); // @Async 在外部调用时生效
// 立即返回
return success(result);
}
这是一个很容易踩坑的细节:Spring 的 @Async 注解基于 AOP 代理实现。如果在同一个 Service 类内部调用 this.triggerDocumentParse(),AOP 代理不会拦截,方法会同步执行。必须从 Controller(或另一个 Service)调用才能让 @Async 生效。代码注释里特意标注了这一点。
状态管理
public class DocumentParse {
private Long id; // 主键
private Long userId; // 用户ID
private String documentId; // 文档ID(自动生成:DOC-XXXXXXXXXX)
private String documentName; // 文档名称
private String prompt; // 用户提交的提示词
private String parsedContent; // 解析后的内容(由工作流回调写入)
private String agentTaskId; // 腾讯元器任务ID
private Integer processStatus; // 0-处理中, 1-已完成, 2-失败
private String errorMessage; // 错误信息
}
状态流转:
处理中(0) → 已完成(1) ← 工作流回调
→ 失败(2) ← 异常或超时
超时保护
启动一个5 分钟超时检查定时器:
// 提交工作流任务后,启动延迟 5 分钟的检查
scheduler.schedule(() -> {
DocumentParse doc = documentParseMapper.selectDocumentParseById(documentParseId);
if (doc != null && doc.getProcessStatus() == 0) {
// 5 分钟了还没收到回调,标记为失败
updateDocumentParseStatus(documentParseId, 2, "工作流回调超时", null);
}
}, 5, TimeUnit.MINUTES);
这个设计防止了工作流回调丢失时记录永远卡在"处理中"状态。
前端实现
前端代码位于 WxFbsir-ui/src/views/business/content/documentparse/index.vue(1163 行),API 层在 WxFbsir-ui/src/api/business/content/documentparse/documentParse.js。
UI 布局
┌──────────────────────┬──────────────────────┐
│ 文档解析助手 │ 解析内容 │
│ ┌──────────────┐ │ │
│ │ 文件拖拽上传 │ │ (包含解析内容和) │
│ │ [提示词输入] │ │ (提示词显示) │
│ │ [上传并解析] │ │ │
│ └──────────────┘ │ │
│ ┌──────────────────┐│ │
│ │ 解析记录列表 ││ │
│ │ 记录1 已完成 ││ │
│ │ 记录2 处理中 ││ │
│ │ 记录3 失败 ││ │
│ └──────────────────┘│ │
└──────────────────────┴──────────────────────┘
轮询机制
前端在提交解析任务后启动每 5 秒轮询,检查解析状态:
const startPollingParse = (parseId, documentId) => {
let pollCount = 0
const maxPolls = 60 // 最多轮询 5 分钟
const pollInterval = setInterval(async () => {
pollCount++
await loadParses() // 刷新列表
const parse = parseList.value.find(p => p.id === parseId)
if (parse.processStatus === 1) {
clearInterval(pollInterval)
ElNotification({ title: '解析完成', type: 'success' })
} else if (parse.processStatus === 2) {
clearInterval(pollInterval)
ElNotification({ title: '解析失败', type: 'error' })
}
// status=0 继续轮询
}, 5000) // 每 5 秒
}
智能体配置界面
用户在首次使用前需要配置腾讯元器智能体。配置通过加密的方式存储:
const MASKED_VALUE = '***已加密***'
// 配置自动加密,回显时显示已加密标记
配置项包括:
- 智能体 ID(appid)
- 智能体名称
- API 密钥(appkey)
- API 端点
腾讯元器工作流
工作流配置从 F:\wxfb\U3W-AI\docs\workflows\export-文档解析工作流.zip 中导出,包含完整的节点定义。
工作流流程:
开始 → 文档解析节点 → 大模型处理 → HTTP回调 → 结束
大模型配置
使用 lke-deepseek-v3 模型,温度 0.6,最大 4096 tokens。提示词设计确保了输出质量:
你是一个专业的文档分析助手。你将收到两个输入参数:
1. {{context}} - 解析后的文档内容
2. {{prompt}} - 用户提交的任务提示词
重要要求:
- ✅ 必须基于文档内容回答,不要编造信息
- ✅ 严格按照用户提示词的要求执行
- ✅ 给出完整、准确、可直接使用的结果
- ❌ 不要说"让我先分析"、"接下来我将"等过程性表述
- ❌ 不要询问用户是否需要修改或补充
设计思路是让 LLM 一次性完成所有任务,避免多轮对话增加延迟和 token 消耗。
文件处理流程
工作流中的文件处理策略:
- 后端上传文件到服务器
- 将文件 URL(域名替换为内网穿透地址)传递给腾讯元器
- 工作流中先做文档内容解析(将 PDF/Word 转为文本)
- 解析后的文本作为
context参数传入 LLM
踩坑记录
1. @Async 同类调用失效
这是最隐蔽的问题。Spring 的 @Async 通过 AOP 代理实现,同类内部 this.method() 调用不经过代理。必须在 Controller 层或另一个 Service 中调用。
2. 域名替换
文件上传到本地后获取的 URL 是 http://localhost:8080/...,但腾讯元器工作流需要通过外网访问文件。需要把 URL 中的 localhost:8080 替换为内网穿透域名。
3. 5 分钟超时保护
工作流回调如果因为网络问题丢失,记录会永远卡在"处理中"状态。通过定时器在 5 分钟后检查状态,超过时间仍未完成则标记为失败,用户看到后可以重试。
4. 前端轮询 vs WebSocket
当前使用轮询(每 5 秒查询状态),对于 demo 阶段够用。如果是高并发生产环境,应该改为 WebSocket 推送——后端解析完成后主动通知前端,减少不必要的轮询请求。
5. 配置加密
API 密钥在数据库中加密存储,前端显示时用 ***已加密*** 标记,防止密钥泄露。这是一个基本但重要的安全实践。
总结
这个文档解析模块是我在 U3W-AI 实习期间独立完成的完整功能模块,涵盖了:后端(Spring Boot CRUD + @Async + 工作流回调)、前端(Vue 3 + Element Plus 上传 + 轮询 + 配置管理)、AI 编排(腾讯元器工作流 + DeepSeek V3 LLM)。从产品设计到前后端实现到运维配置,完整的交付经验。