2026山东大学软件学院项目实训(六)
一、基本信息
组号:69
组员:李重昊
负责模块:AI 工作流 —— 图片收集节点
二、任务概述
在 LangGraph4j 工作流中完成图片收集节点开发,根据用户自然语言需求自动规划并收集网站所需图片,为后续提示词增强与代码生成提供素材。具体包括:
- 封装 Pexels 内容图片搜索工具
- 封装 UnDraw 插画图片搜索工具
- 实现 Mermaid CLI + 腾讯云 COS 架构图绘制工具
- 接入 阿里云 DashScope Logo 文生图工具
- 实现 AI 图片收集规划服务,输出结构化
ImageCollectionPlan - 在 ImageCollectorNode 中通过
CompletableFuture并发调用四类工具并汇总结果
三、需求分析与方案设计
1.1 核心功能拆解
| 功能 | 说明 |
| 智能规划 | AI 分析用户提示词,确定需要的图片类型及参数 |
| 内容图片 | Pexels 关键词搜索实景/产品类配图 |
| 插画图片 | UnDraw 关键词搜索装饰性矢量插画 |
| 架构图片 |
Mermaid 代码转 SVG,上传 COS 获取 URL |
| logo |
DashScope 文生图按描述生成品牌标识 |
| 结果汇总 | 写入 WorkflowContext.imageList 供下游使用 |
1.2 业务处理流程
用户输入 originalPrompt
→ ImageCollectionPlanService(AI 规划)
→ ImageCollectionPlan(四类任务列表)
→ 并发调用四类 Tool
→ 汇总 List<ImageResource>
→ 写入 WorkflowContext.imageList
→ 流转至「提示词增强」节点
工作流中图片收集节点作为入口,与后续节点串联如下:
.addNode("image_collector", ImageCollectorNode.create())
.addNode("prompt_enhancer", PromptEnhancerNode.create())
.addNode("router", RouterNode.create())
.addNode("code_generator", CodeGeneratorNode.create())
.addNode("project_builder", ProjectBuilderNode.create())
// 添加边
.addEdge(START, "image_collector")
.addEdge("image_collector", "prompt_enhancer")
.addEdge("prompt_enhancer", "router")
.addEdge("router", "code_generator")
.addEdge("code_generator", "project_builder")
.addEdge("project_builder", END)
START → image_collector → prompt_enhancer → ... 表明图片收集是整个 Agent 工作流的第一步;收集到的图片 URL 将在后续节点拼入增强提示词,供代码生成使用。
1.3 技术方案选型
| 方案 | 优点 | 缺点 | 造型 |
| AI多轮工具调用 | 实现简单 | 耗时长、Token 多、易误输出代码 | 不采用 |
| 规划+节点内并发 | 性能好、改动小、逻辑集中 | 需手动管理线程池 | 主选 |
| LangGraph4j 并行分支 | 可视化清晰 | 需额外多个节点 | 扩展 |
三、数据模型设计
3.1 图片资源对象 ImageResource
所有工具统一返回该结构,便于在工作流中传递
public class ImageResource implements Serializable {
/**
* 图片类别
*/
private ImageCategoryEnum category;
/**
* 图片描述
*/
private String description;
/**
* 图片地址
*/
private String url;
category 标识用途,description 供 AI 理解图片语义,url 供前端或生成代码直接引用。
3.2 图片类型枚举
public enum ImageCategoryEnum {
CONTENT("内容图片", "CONTENT"),
LOGO("LOGO图片", "LOGO"),
ILLUSTRATION("插画图片", "ILLUSTRATION"),
ARCHITECTURE("架构图片", "ARCHITECTURE");
与四种工具一一对应,代码生成阶段可按类别决定图片在页面中的位置。
3.3 图片收集计划 ImageCollectionPlan
由 AI 结构化输出,使用 record 简化任务定义:
private List<ImageSearchTask> contentImageTasks;
private List<IllustrationTask> illustrationTasks;
private List<DiagramTask> diagramTasks;
private List<LogoTask> logoTasks;
public record ImageSearchTask(String query) implements Serializable {}
public record IllustrationTask(String query) implements Serializable {}
public record DiagramTask(String mermaidCode, String description) implements Serializable {}
public record LogoTask(String description) implements Serializable {}
各 record 字段与对应工具入参严格映射,节点调用时无需额外转换
四、四类图片收集工具实现
4.1 内容图片收集工具 ImageSearchTool
@Tool("搜索内容相关的图片,用于网站内容展示")
public List<ImageResource> searchContentImages(@P("搜索关键词") String query) {
List<ImageResource> imageList = new ArrayList<>();
try (HttpResponse response = HttpRequest.get(PEXELS_API_URL)
.header("Authorization", pexelsApiKey)
.form("query", query)
.form("per_page", SEARCH_COUNT)
.form("page", 1)
.execute()) {
// ...
imageList.add(ImageResource.builder()
.category(ImageCategoryEnum.CONTENT)
.description(photo.getStr("alt", query))
.url(src.getStr("medium"))
.build());
调用 Pexels /v1/search,Authorization 头传入 API Key;每次最多 6 张,取 medium 尺寸;失败返回空列表,不阻断整体流程。
4.2 插画图片收集工具UndrawIllustrationTool
@Tool("搜索插画图片,用于网站美化和装饰")
public List<ImageResource> searchIllustrations(@P("搜索关键词") String query) {
String apiUrl = String.format(unDrawApiUrl, query, query);
try (HttpResponse response = HttpRequest.get(apiUrl).timeout(10000).execute()) {
// ... 解析 pageProps.initialResults ...
imageList.add(ImageResource.builder()
.category(ImageCategoryEnum.ILLUSTRATION)
.description(title)
.url(media)
.build());
API 地址从配置读取,支持更换 UnDraw 的 Next.js buildId;解析 initialResults 中的 title 与 media;10 秒超时防止阻塞工作流。
4.3 架构图绘制工具 MermaidDiagramTool
@Tool("将 Mermaid 代码转换为架构图图片,用于展示系统结构和技术关系")
public List<ImageResource> generateMermaidDiagram(@P("Mermaid 图表代码") String mermaidCode,
@P("架构图描述") String description) {
File diagramFile = convertMermaidToSvg(mermaidCode);
String cosUrl = cosManager.uploadFile(keyName, diagramFile);
return Collections.singletonList(ImageResource.builder()
.category(ImageCategoryEnum.ARCHITECTURE)
.description(description)
.url(cosUrl)
.build());
Mermaid 转 SVG 核心逻辑:
String command = SystemUtil.getOsInfo().isWindows() ? "mmdc.cmd" : "mmdc";
String cmdLine = String.format("%s -i %s -o %s -b transparent",
command,
tempInputFile.getAbsolutePath(),
tempOutputFile.getAbsolutePath());
RuntimeUtil.execForStr(cmdLine);
先将 Mermaid 写入临时 .mmd,调用 mmdc 生成透明背景 SVG,再通过 CosManager 上传 COS 获得长期可访问 URL;自动区分 Windows/Linux 命令。
4.4 Logo 图片生成工具 LogoGeneratorTool
@Tool("根据描述生成 Logo 设计图片,用于网站品牌标识")
public List<ImageResource> generateLogos(@P("Logo 设计描述,如名称、行业、风格等,尽量详细") String description) {
String logoPrompt = String.format("生成 Logo,Logo 中禁止包含任何文字!Logo 介绍:%s", description);
ImageSynthesisParam param = ImageSynthesisParam.builder()
.apiKey(dashScopeApiKey)
.model(imageModel)
.prompt(logoPrompt)
.size("512*512")
.n(1)
.build();
// ... 解析返回 url ...
logoList.add(ImageResource.builder()
.category(ImageCategoryEnum.LOGO)
.description(description)
.url(imageUrl)
.build());
五、AI图片收集规划服务
5.1 系统提示词
## 输出要求
请严格按照 JSON 格式返回图片收集计划,包含以下字段:
- contentImageTasks: 数组,元素含 query 字段
- illustrationTasks: 数组,元素含 query 字段
- diagramTasks: 数组,元素含 mermaidCode 和 description 字段
- logoTasks: 数组,元素含 description 字段
注意:
- 如果某种类型的图片不需要,对应数组可以为空
- mermaidCode 要是有效的 Mermaid 语法代码
- 只规划图片收集任务,不要输出任何网站代码
5.2 AI服务接口与工厂
public interface ImageCollectionPlanService {
@SystemMessage(fromResource = "prompt/image-collection-plan-system-prompt.txt")
ImageCollectionPlan planImageCollection(@UserMessage String userPrompt);
}
@Bean
public ImageCollectionPlanService imageCollectionPlanService() {
return AiServices.builder(ImageCollectionPlanService.class)
.chatModel(chatModel)
.build();
}
复用 DeepSeek ChatModel,利用 LangChain4j 结构化输出,将 AI 回复直接映射为 ImageCollectionPlan,无需手写 JSON 解析。
六、图片收集工作节点实现
6.1 SpringContextUtil
节点通过静态 create() 创建,无法直接 @Resource 注入,故封装上下文工具:
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
6.2 ImageCollectorNode 核心逻辑
阶段一:AI 规划
ImageCollectionPlanService planService = SpringContextUtil.getBean(ImageCollectionPlanService.class);
ImageCollectionPlan plan = planService.planImageCollection(originalPrompt);
log.info("获取到图片收集计划,开始并发执行");
阶段二:四类工具并发执行
if (plan.getContentImageTasks() != null) {
ImageSearchTool imageSearchTool = SpringContextUtil.getBean(ImageSearchTool.class);
for (ImageCollectionPlan.ImageSearchTask task : plan.getContentImageTasks()) {
futures.add(CompletableFuture.supplyAsync(() ->
imageSearchTool.searchContentImages(task.query())));
}
}
// 插画、架构图、Logo 同理 ...
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
阶段三:汇总写入上下文
context.setCurrentStep("图片收集");
context.setImageList(collectedImages);
return WorkflowContext.saveContext(context);
七、总结
本次修改主要完善了AI生成网页的图片的一些显示功能,之前生成的图片都是随机的占位符。本次改动的工作量较大,我这次完成的是其中的部分配置。
然后这次成果的测试中我们发现编辑模式选择编辑块有一点问题,不能完全确定形状,而且会重新生成一个新版本覆盖之前的版本,这样可能比较消耗token,也是后续改善的方向。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)