AI 数据采集系统的架构演进与工程化实践:从 LLM 调用到完整数据处理流水线
本文以求职派的岗位信息采集业务为例,介绍如何基于 Spring AI、LangGraph4J 构建一套支持多模态、工具调用、结构化输出、异步调度的 AI 数据采集系统,并总结其中可复用的架构设计思想。
一、业务背景:AI 数据采集要解决什么问题?
传统岗位信息采集依赖人工录入或固定规则爬虫,面临三个问题:
-
数据来源复杂: 招聘信息可能来自网页、Excel、CSV、图片等。
-
数据格式不统一: 不同招聘网站的岗位字段和描述存在差异。
-
采集效率低: 人工提取、清洗和录入的成本较高。
因此,我们希望通过大模型实现自动化采集:
用户提交数据源
↓
识别输入格式
↓
获取原始数据
↓
LLM 提取岗位信息
↓
结构化解析与校验
↓
数据清洗
↓
保存草稿 / 正式发布
系统的核心目标不是简单调用大模型,而是将不同来源的非结构化数据,稳定地转换成符合业务规范的结构化数据。
二、整体架构设计
整个系统按照职责可以拆分为五个层次。
用户 / 管理后台
│
▼
数据接入层
Text / HTML / URL
CSV / Excel / Image
│
▼
AI 能力层
┌──────────┼──────────┐
│ │ │
Model Tools Memory
Router MCP Context
│ │ │
└──────────┼──────────┘
▼
数据处理层
Extract / Validate
Normalize / Publish
│
▼
任务调度层
Task Pool / Scheduler
Retry / State Machine
│
▼
数据持久化层
Task / Draft / Job
五层各司其职:
| 层级
|
核心职责
|
数据接入层
|
统一处理不同输入格式
| |
AI 能力层
|
模型调用、工具调用、上下文管理
| |
数据处理层
|
数据提取、校验、清洗、发布
| |
任务调度层
|
异步执行、状态管理、失败恢复
| |
持久化层
|
保存任务、草稿和正式数据
|
这里最重要的思想是:将 AI 能力与业务流程、任务调度和数据存储解耦。
三、AI 采集能力的七步演进
1. 基础能力:通过 Spring AI 接入大模型
最初的采集流程非常简单:
原始文本
↓
构造 Prompt
↓
调用 LLM
↓
解析结果
↓
保存数据库
例如,用户提交一段招聘信息,系统通过 Prompt 要求模型提取公司名称、岗位名称、薪资、学历等字段。
这一阶段解决的是:如何将 AI 能力接入已有的 Spring Boot 业务系统。
但它只能处理相对简单的文本输入。
2. 多模态:统一处理不同数据源
真实业务中的输入格式并不统一。
求职派支持六类输入:
| 输入类型
|
处理方式
|
纯文本
|
直接交给文本模型
| |
HTML
|
提取正文或表格后解析
| |
HTTP 链接
|
调用网页抓取工具
| |
CSV
|
解析行列数据
| |
Excel
|
解析工作表
| |
图片
|
使用视觉模型提取信息
|
对于图片,系统需要选择支持视觉能力的模型。
因此,这里可以抽象出一个重要设计:
输入类型识别 + 模型能力路由。
不同的数据源采用不同的预处理方式,而不是将所有原始数据直接塞进大模型。
3. 多轮对话:解决模型输出截断
当一份 Excel 包含大量岗位时,大模型可能因为输出长度限制,无法一次返回全部数据。
求职派采用多轮续写机制:
第一次调用 LLM
↓
检查 JSON 是否完整
↓
不完整
↓
携带历史上下文继续生成
↓
合并采集结果
这一设计引入了 Memory,用于保存采集过程中的对话上下文。
但需要注意:
JSON 闭合只能判断语法是否可能完整,不能保证数据没有遗漏。
更稳妥的方案是:
-
对大文件分批处理。
-
每批独立进行结构化提取。
-
通过源记录 ID 去重。
-
统计输入记录与输出记录数量。
-
对失败批次独立重试。
这样能够减少长上下文造成的遗漏和重复问题。
4. Function Calling:让模型具备外部数据获取能力
大模型无法仅凭自身参数获取实时网页内容。
因此,系统通过 Function Calling 注册网页抓取工具。
用户提交 URL
↓
LLM 判断需要获取网页
↓
调用 WebFetchTool
↓
获取网页正文
↓
LLM 提取岗位信息
对于 JavaScript 动态渲染页面,可以进一步通过 MCP 接入浏览器自动化工具。
这里要区分两个概念:
-
Function Calling:模型决定调用什么工具及其参数。
-
MCP:提供连接外部工具与服务的标准化协议。
核心思想:模型负责理解和决策,工具负责执行确定性的外部操作。
实际开发中,还需要限制 URL 访问范围,防止 SSRF,并设置抓取超时、响应大小限制和工具调用次数上限。
5. 结构化输出:让 AI 结果变成业务数据
大模型返回的自然语言不能直接作为数据库记录。
因此,需要定义统一的岗位信息结构。
例如:
JSON
{
"companyName": "某科技公司",
"jobName": "Java开发工程师",
"city": "杭州",
"salaryMin": 15000,
"salaryMax": 25000
}
通过 JSON Schema 约束输出格式,并映射成 Java 对象。
完整处理流程:
LLM 输出
↓
JSON 解析
↓
Schema 校验
↓
业务规则校验
↓
字段标准化
↓
保存草稿
需要明确:
结构化输出不等于数据正确。
即使 JSON 格式合法,仍然可能出现薪资错误、公司名称虚构、字段缺失等问题。
因此必须增加业务校验,必要时保留原始数据来源供人工审核。
6. 多模型路由:根据任务选择合适的模型
不同采集任务对模型能力要求不同。
例如:
文本任务 → 文本模型
图片任务 → 视觉模型
复杂提取 → 更强的推理模型
系统通过 ModelProvider 抽象不同模型供应商,由 ModelRouter 根据输入类型和模型能力选择模型。
业务 Agent
↓
ModelRouter
↓
ModelProvider
↓
具体模型
这种设计将业务逻辑与模型供应商解耦。
后续更换模型时,只需要修改模型配置或增加 Provider 实现,不需要重新编写采集业务。
此外,可以结合任务复杂度、模型价格、上下文长度和失败率制定路由策略。
7. 异步任务池:解决耗时、限流与失败恢复
AI 采集可能耗时数分钟,不适合同步等待 HTTP 请求完成。
因此,系统采用任务池模式。
用户提交任务
↓
任务入库(INIT)
↓
立即返回任务 ID
↓
后台调度器领取任务
↓
更新状态(RUNNING)
↓
执行 AI 采集
↓
SUCCESS / FAILED
求职派采用 Spring Event 触发执行,并通过定时扫表进行补偿。
数据库负责保存任务状态,避免仅依赖内存事件导致任务无法恢复。
任务状态可以设计为:
INIT
↓
RUNNING
├── SUCCESS
└── FAILED
↓
RETRY
工程上还需要考虑以下问题:
| 问题
|
解决方案
|
任务重复执行
|
原子领取任务 + 幂等约束
| |
模型调用失败
|
有界重试 + 退避策略
| |
服务异常退出
|
超时任务恢复
| |
并发超限
|
信号量 / 限流 / 并发控制
| |
任务长期失败
|
失败终态 + 人工处理
|
原文采用的原子布尔锁只能解决单实例并发问题,多实例部署需要数据库原子抢占或分布式锁。
四、进一步演进:使用 LangGraph4J 编排采集工作流
当采集逻辑越来越复杂,简单的线性调用已经不够。
因此引入 LangGraph4J,将采集流程拆分为四个节点。
TaskClassify
识别数据源类型
TaskGather
执行数据采集
DraftWasher
清洗与标准化
DraftPublish
校验并发布数据
每个节点通过共享状态传递数据,使用条件边控制执行流程。
例如:
-
输入格式不支持,终止执行。
-
采集结果为空,终止执行。
-
数据校验失败,保留草稿而不发布。
执行进度可以通过 SSE 推送给前端。
这里要区分任务调度与工作流编排:
任务调度解决任务什么时候执行、失败如何恢复。
工作流编排解决任务内部执行哪些步骤、节点之间如何流转。
两者属于不同层次,可以组合使用。
五、架构设计中的关键取舍
| 设计选择
|
适用场景
|
演进方向
|
Spring Event
|
单体、低并发
|
可靠消息队列
| |
单线程任务池
|
任务量小、限流严格
|
并发调度 + 限流
| |
内存 Memory
|
短期采集上下文
|
持久化检查点
| |
多轮续写
|
中小规模文本
|
分批提取 + 结果合并
| |
自动发布
|
高可信数据源
|
数据校验 + 人工审核
|
架构设计需要根据实际业务规模逐步演进,而不是一开始就引入所有分布式组件。
六、可以复用到哪些业务?
这套架构并不局限于岗位信息采集。
| 场景
|
可复用的能力
|
招聘信息采集
|
网页解析、信息提取、结构化入库
| |
简历解析
|
PDF / 图片解析、字段提取
| |
发票识别
|
多模态识别、金额校验
| |
合同审查
|
文档分块、条款提取、规则校验
| |
商品信息采集
|
网页抓取、属性标准化、数据去重
|
只要业务符合:
非结构化输入 → AI 理解 → 结构化数据 → 业务处理
就可以复用这套架构。
七、总结
AI 数据采集系统的演进,本质上经历了三个阶段:
第一阶段:AI 能力接入。
通过 Spring AI 实现基础模型调用,并支持多模态、上下文管理和工具调用。
第二阶段:数据工程化。
通过 JSON Schema、业务校验、标准化和草稿机制,将模型输出转换成可信的业务数据。
第三阶段:执行流程工程化。
通过任务池、异步调度、失败补偿和 LangGraph4J 工作流,提高系统的可靠性与可维护性。
最终形成一条完整的数据处理链路:
数据接入
↓
模型与工具调用
↓
结构化提取
↓
数据校验与清洗
↓
草稿持久化
↓
审核与发布
核心架构思想:AI 负责处理非结构化信息,确定性程序负责校验和控制业务规则,任务系统负责保证执行过程可追踪、可恢复。
这才是从一个简单的 LLM Demo 演进为实际 AI 业务系统的关键。