ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring Boot 3 + LangChain4j 构建 AI 应用生成平台:微服务架构与 Agent 编排实践

Spring Boot 3 + LangChain4j 构建 AI 应用生成平台:微服务架构与 Agent 编排实践 简介编程导航AI加微服务全栈新项目是一套面向企业级人工智能应用开发与技术学习者的完整工程源码以前后端分离和微服务架构组织深度融合LangChain4j框架覆盖智能体编排、检索增强生成、工具调用、对话记忆等核心AI能力帮助后端工程师快速掌握大模型应用平台从设计到落地的全流程。压缩包共387个文件以287个Java源文件为主辅以Vue/TypeScript前端代码、XML/JSON配置文件、SQL初始化脚本及环境配置等整体约618KB代码按整洁架构分为应用层、领域层、基础设施层与接口层层次清晰。平台内置ReAct、计划执行等多种智能体运行引擎兼容多个主流大模型接口并提供用户认证、知识库管理、任务调度等完整业务功能配套架构设计说明书、智能体开发指南和接口契约文档可直接用于二次开发与私有化部署。目前已有26人学习适合具备一定后端基础、希望深入理解微服务与人工智能结合实战的开发者。1. AI 应用生成平台Spring Boot 3 LangChain4j 组合能做到什么程度做 AI 应用生成平台真正难的从来不是调通一个大模型接口而是怎么把 Agent、多路召回、工具调用这些概念落到 Java 后端代码里并且让整个链路在微服务架构下稳定跑起来。这套基于 Spring Boot 3 LangChain4j 的全栈微服务项目把大厂 AI 应用生成的完整流程搬到了 JVM 生态用户提交需求主 Agent 拆任务多路召回上下文子 Agent 分别做分析、生成和校验最终交付可运行的产物。它示范的不是某个 demo而是一条能直接复现的工程路径。适合读这篇文章的人有两类一是想用 Spring Boot 3 微服务架构做 AI 应用交付的 Java 工程师二是全栈开发者想找到 Agent 编排、多路召回、微服务拆分和部署验证的完整参考。如果你只是想学怎么调大模型 HTTP API这个项目对你来说反而偏重。下面从架构选型开始一步步拆到代码和踩坑细节。2. 架构与选型微服务边界怎么切、LangChain4j 在系统里承担什么角色2.1 Spring Boot 3 的升级重点AOT、虚拟线程与 JDK 21Java 后端团队做 AI 应用第一个要决策的是基础框架。Spring Boot 3 作为底座不是因为它“新”而是因为 AI 场景的两个硬性需求它接得住。第一个需求是高并发下的 I/O 吞吐。一次 Agent 任务要串行调用多个模型接口单次调用耗时 210 秒是常态期间线程基本都在等网络 I/O。如果团队还停留在 JDK 8 的线程池模型Tomcat 默认 200 个线程很快就被打满用户请求全部排队。Spring Boot 3.2 之后对 JDK 21 的虚拟线程有了完整支持配置虚拟线程后阻塞型任务不再占满平台线程吞吐量提升非常明显。这在 AI 生成场景下几乎是刚需因为模型响应慢且不可控你再怎么做连接池优化都补不回线程被阻塞占用的损失。第二个需求是启动效率和部署密度。微服务一旦拆分到 5 个以上每个服务的启动时间直接关系到交付效率。Spring Boot 3 在启动链路上做了不少优化如果配合 GraalVM native image启动时间能从秒级降到毫秒级。但注意native image 对反射、动态代理的限制很多LangChain4j 这种大量使用动态代理的框架和 GraalVM 的兼容性要额外验证常规部署不用强上。第三个变化是依赖体系迁移到了 Jakarta EE 9。对老项目这是体力活但对新项目是利好后续接 Spring Cloud Alibaba、OpenFeign、Nacos 时版本兼容性会顺畅很多。版本搭配上我建议按这个原则来Spring Boot 3.0 和 3.1 配 JDK 173.2 及以上可以上 JDK 21。项目 POM 里锁定的 Spring Boot 版本决定了你的 JDK 选择不要本机装了个 JDK 21 就强行跑老版本 Boot启动报 UnsupportedClassVersionError 只是第一步后面 AOP 代理、字节码操作都会出问题。2.2 LangChain4jJVM 生态里的 Agent 框架解决了什么问题Java 团队做 AI 应用通常有三条路。第一条是直接封装大模型 HTTP API自己管理对话历史、工具调用协议、重试降级代码不难但逻辑散落每个项目都要重写一遍。第二条是引入 Python 的 LangChain 或 LlamaIndex 做成独立 AI 服务Java 系统通过 HTTP 调用坏处是要维护两套技术栈部署链路变长。第三条就是 LangChain4j——在 JVM 生态里复刻 LangChain 的核心抽象让 Java 工程师用一套语言完成 AI 应用开发。LangChain4j 提供了四个关键能力。ChatLanguageModel 统一了各家模型提供方的接口OpenAI、通义千问、本地 Ollama 都能通过统一接口接入切换模型时只动配置不动业务代码。ChatMemory 负责对话上下文管理不用再手动维护每轮消息的 history 数组框架自带滑动窗口和内存管理。Tool 机制是 Agent 的入口Java 方法加上注解就能暴露给模型调用框架自动处理 function calling 的参数解析、调用、结果回填。AiServices 则是把模型、工具、记忆组装成完整 Agent 的构建器。这套项目的 Agent 实现正是建立在 Tool 机制之上。用户提一个需求LangChain4j 把需求交给大模型模型根据工具的描述决定调用哪个工具工具执行完返回结果模型继续推理直到任务完成。整个循环是框架驱动的开发者只需要实现工具类里的具体业务逻辑。跟 Python LangChain 相比LangChain4j 的组件数量少很多没有复杂的 Chain 和 Graph 抽象学习曲线平缓出问题追查代码路径也快。它的短板是 API 还在快速迭代版本升级可能引入 breaking changes这个放到第五章避坑部分详细说。2.3 微服务边界AI 生成服务、Agent 调度与业务系统怎么切微服务拆分没有万能答案但 AI 应用生成平台有一条清晰的划分逻辑模型调用相关的服务必须独立Agent 编排和业务系统解耦剩下的按领域模型切。这个项目给出的拆分方案很典型服务职责核心依赖gateway 网关路由转发、统一鉴权、限流Spring Cloud Gatewayuser 用户服务用户、权限、配额管理MySQL Redisai-agent 调度服务Agent 编排、多路召回、多 AI 协作LangChain4j 模型 APIai-executor 执行服务代码生成、构建校验、产物组装Docker Mavenasset 产物服务产物存储、版本管理、下载MinIO MySQL为什么模型调用和 Agent 编排要独立拆服务最核心的原因是故障隔离。模型 API 的响应时间不可控一次请求可能 3 秒返回也可能 30 秒超时。如果 ai-agent 服务和 user 服务混在一起模型服务抖动会直接拖垮用户业务链路。拆开之后ai-agent 可以独立扩缩容、独立配超时重试模型调用失败只影响 AI 链路不影响用户登录、权限这些核心功能。Agent 调度和执行拆分考虑的是资源隔离。ai-agent 编排消耗 CPU 做逻辑推理ai-executor 执行时要拉起 Docker 容器跑构建任务两者资源画像完全不同混在一起会互相争抢。而且执行服务是整条链路里最容易出问题的地方构建环境偶发异常、内存不够、镜像拉取失败独立部署方便定点排查。服务间通信也要设计好。同步链路用 OpenFeign 没问题但 AI 任务链路必须设置超时和降级推荐的模式是用户提交需求后网关层直接返回“任务已受理”ai-agent 把任务放入 MQ 异步执行前端通过 WebSocket 接收进度推送。这种异步模式跟大厂 AI 应用平台的产品体验一致用户不需要盯着浏览器转圈等待。3. Agent 核心机制多路召回、多 AI 协作与工具调用的实现逻辑3.1 多路召回为什么必要单一模型上下文撑不住真实业务先明确一个前提大模型的上下文窗口是有限的即便支持上百万 token 的模型把业务知识、用户需求、历史案例全部塞进去效果也不会好。首先是花费问题token 按量计费一次生成可能烧掉几十上百块的额度其次是效果问题上下文越长模型越容易抓不住重点生成的代码质量反而下降。所以生产环境里的 AiAgent 一定会做多路召回根据用户需求从多个数据源拉取相关内容拼装成上下文后再交给模型。这个项目里做了三层召回第一层是结构化数据检索。从 MySQL 或 PostgreSQL 里查用户偏好、项目模板、历史配置。比如用户说“做一个带支付的后台系统”先从模板表里匹配出最接近的后台模板把模板的技术栈、目录结构、依赖清单查出来。这层查的是确定性数据不需要模型参与。第二层是向量相似度检索。把历史生成过的项目描述、代码片段、需求文档切成块做 embedding 后存进向量库。用户提新需求时把需求文本 embedding 后做相似度查询取最相关的历史项目片段。这层解决的是“语义相近但关键词不同”的检索问题。第三层是外部能力查询。调用企业内部的 API拿到最新的依赖版本、安全公告、标准规范。比如生成代码时需要知道当前某个依赖的最新稳定版本这个信息不在项目自己的数据库里要从外部系统拉。三层召回结果合并后按相关度排序并截断再拼进 prompt。关键参数是召回数量和截断阈值。我用向量检索时习惯把 top_k 控制在 10 条左右相关性分数阈值设在 0.35低于这个分数的直接丢弃。top_k 太大会塞入大量无关内容太小则召回不足模型会“凭感觉”编造信息。3.2 多 AI 协作主 Agent 拆任务、子 Agent 执行与结果校验多 AI 协作在项目里的形态是主从 Agent 模式。主 Agent 负责理解用户需求、拆分任务清单、派发任务、汇总结果子 Agent 负责具体的执行环节。一次完整的生成链路是这样的用户输入“帮我生成一个带登录、订单管理、支付模拟的后台管理系统”。主 Agent 不直接写代码先做需求分析输出任务清单后端需要一个 Spring Boot 项目骨架、用户模块、订单模块前端需要管理后台页面数据库需要建表 SQL部署需要 Dockerfile。接着主 Agent 把任务逐项派发给不同子 Agent。需求分析 Agent 产出需求规格说明架构 Agent 根据规格选定技术栈和模块边界代码生成 Agent 按模块批量生成代码文件测试 Agent 对生成的代码做静态检查和单元测试最后汇总 Agent 把各部分合成完整项目交付。每一步的输出是下一步的输入链路是串行的。串行链路的好处是单个子 Agent 的上下文很短只关注自己负责的部分生成质量比一个 Agent 从头写到尾高得多。成本是整体耗时变长一次完整生成可能需要 35 分钟因此异步执行加进度推送是必须的不能靠一个 HTTP 请求等 5 分钟。任务粒度是编排里最容易拍脑袋的参数。拆得太大子 Agent 上下文超长效果退化到和单 Agent 一样拆得太细服务间通信开销大而且链路每一步都有失败概率步骤越多整体失败率越高。我的经验判断标准是单个子 Agent 的输出文件数控制在 10 个以内单次生成代码量控制在 300 行以内超过就继续拆。这个阈值不是理论推导出来的是反复调出来的血泪经验。3.3 LangChain4j 工具调用Agent 怎么操作微服务接口多 AI 协作不是模型之间互相聊天子 Agent 执行任务时必须操作外部系统查模板库、写文件、调构建接口、存产物。LangChain4j 的 Tool 机制就是这层的桥梁。看一个简化示例查询项目模板和写入产物文件Slf4j Component public class AssetTool { private final TemplateService templateService; private final AssetService assetService; Tool(当用户需求中包含项目类型或技术栈关键词时调用此方法获取可选代码模板参数 projectType 为用户指定的技术栈名称) public ListTemplateInfo getTemplates(String projectType) { return templateService.listByType(projectType); } Tool(把生成的代码文件写入产物存储系统返回写入结果参数 path 是相对路径content 是文件完整内容) public String writeFile(String path, String content) { assetService.save(path, content); log.info(产物已写入: {}, path); return SUCCESS; } }这段代码背后LangChain4j 做了大量隐性工作。模型在推理时如果判断需要查模板会在响应里返回一个 function call 请求框架拦截后把参数反序列化调用 getTemplates 方法再把返回值包装成 FunctionResult 消息回传给模型。模型拿到结果继续推理走下一步流程。开发者要做的只是加上 Tool 注解并把方法描述写清楚。关于 Tool 方法的描述有个特别容易踩的坑description 不能只写功能名。写“获取代码模板列表”模型经常拿不准什么时候调用改成“当用户需求中包含项目类型或技术栈关键词时调用参数传用户指定的技术栈名称”命中率会显著提升。原因是模型本质上是靠描述文本理解工具用途的描述写得越具体工具调用的路由越准。按我调这类系统的习惯主 Agent 和子 Agent 之间的协作也可以用工具机制实现。主 Agent 派发任务本质上是调用一个提交任务给执行系统的工具任务描述、上下文、期望输出作为参数传入。代码层面多 AI 协作就是一个主 Agent 绑定多个派发工具每个工具对应一种任务类型剩下的事交给模型决策。4. 本地复现全流程项目结构、配置参数与核心代码实战4.1 项目结构解压后先看哪几个目录拿到 .zip 解压之后先别急着跑花十分钟把目录结构和 POM 依赖理顺。这套项目是多模块 Maven 工程典型结构如下ai-app-platform/ ├── pom.xml # 父 POM管理依赖版本和插件 ├── gateway-service/ # 网关路由、鉴权、限流 ├── user-service/ # 用户账号、权限、配额 ├── ai-agent-service/ # Agent 编排多路召回、多 AI 协作 ├── ai-executor-service/ # 执行代码生成、构建、产物组装 ├── asset-service/ # 产物存储、版本管理 ├── common/ # 公共模块DTO、工具类、异常定义 └── sql/ # 初始化脚本建库、建表、种子数据父 POM 是整个工程的核心所有子模块的 Spring Boot 版本、LangChain4j 版本、中间件客户端版本都统一在这里管理。子模块不单独指定版本号继承父 POM避免模块间依赖版本不一致导致运行时冲突。用 IDEA 导入时选择作为 Maven 项目导入等依赖全部解析完再动代码。第一次导入可能耗时较长LangChain4j 和 Spring Cloud 相关的依赖数量不小耐心等。sql 目录里的初始化脚本也建议先看一遍。它定义了基础的表结构用户表、项目模板表、生成任务表、产物表。任务表的设计基本决定了整个平台的调度逻辑重点看字段任务状态、任务类型、关联的 Agent ID、上下文 JSON、产物 ID。这些字段是后面异步任务和进度推送的数据基础。4.2 Spring Boot 3 与 LangChain4j 配置application.yml 的关键参数配置集中在 ai-agent-service 模块LangChain4j 的核心配置项包括模型端点、API Key、超时和召回参数。敏感信息通过环境变量占位不要硬编码在配置文件里。spring: application: name: ai-agent-service datasource: url: jdbc:mysql://${DB_HOST:localhost}:3306/ai_app_platform username: ${DB_USERNAME:root} password: ${DB_PASSWORD:root} data: redis: host: ${REDIS_HOST:localhost} port: 6379 langchain4j: chat-model: provider: openai base-url: ${LLM_BASE_URL:https://api.openai.com} api-key: ${LLM_API_KEY:sk-xxx} model-name: ${LLM_MODEL:gpt-4o-mini} temperature: 0.2 timeout: 30s embedding-model: provider: openai model-name: text-embedding-3-small app: recall: vector-top-k: 10 vector-min-score: 0.35 db-max-results: 20temperature 参数是最值得调的。代码生成场景建议 0.10.3这个区间内的输出稳定性和代码规范性最好。如果调到 0.7 以上模型“创造力”上来了代码风格飘忽不定注释乱写甚至会出现编造不存在的 API。对生成代码来说确定性比创造性重要得多。多路召回的三个参数是这层配置的精华。vector-top-k 控制向量检索返回条数10 是初始推荐值vector-min-score 是相关性下限低于 0.35 的结果直接丢弃防止无关内容污染上下文db-max-results 限制结构化查询的最大返回数防止模板和配置数据刷爆上下文窗口。这三者的关系是召回宁可少而精不能多而杂上下文太长模型抓不住重点。4.3 核心代码实现Agent 定义、任务拆分与结果聚合看懂了配置重点看 ai-agent-service 里的核心代码。Agent 的定义方式直接决定了整条链路的行为逻辑先看主 AgentSlf4j Service public class MainAgentService { private final MainAgent mainAgent; private final AgentTaskExecutor taskExecutor; public MainAgentService(ChatLanguageModel chatModel, ContextRetriever contextRetriever, AgentTaskExecutor taskExecutor) { this.taskExecutor taskExecutor; this.mainAgent AiServices.builder(MainAgent.class) .chatLanguageModel(chatModel) .tools(contextRetriever, taskExecutor) .build(); } public String handleRequirement(String requirement) { AgentContext context mainAgent.analyzeRequirement(requirement); taskExecutor.submit(context); return TASK_ACCEPTED; } }public interface MainAgent { SystemMessage(你是 AI 应用生成平台的主控 Agent。你的职责是分析用户需求拆解任务清单通过工具派发任务给子 Agent最后汇总结果。你只负责编排和调度不直接生成代码。) AgentContext analyzeRequirement(UserMessage String requirement); }这段代码里有两个设计点值得细看。第一SystemMessage 是 Agent 人设的载体提示词把职责边界写得很死——主 Agent 只编排不写代码。这样模型才不会被带偏需求分析阶段就开写代码把编排任务搅乱。第二AiServices.builder 把模型、工具、接口绑定成代理应用代码里只需要调用 analyzeRequirement 方法框架内部把方法调用解码成模型请求再把模型响应编码回 Java 对象。任务拆分逻辑这里没有硬编码规则而是靠系统提示词约束模型自行输出任务清单。好处是能覆盖各种没见过的需求坏处是模型输出的任务粒度不稳定同一个需求跑两次结果可能不一样。所以拆出来的任务清单在派发前必须加一层校验逻辑检查任务类型是否合法、任务描述是否完整、任务间依赖是否有环。这层校验通常在主 Agent 的返回处理器里做校验失败就重新调用一次模型让它补齐。子 Agent 的执行层简化如下Slf4j Component public class CodeGenAgent { private final SubAgent subAgent; public CodeGenAgent(ChatLanguageModel chatModel) { this.subAgent AiServices.builder(SubAgent.class) .chatLanguageModel(chatModel) .build(); } public GenerationResult execute(SubTask task) { return subAgent.generate(task.getDescription()); } }public interface SubAgent { SystemMessage(你是代码生成 Agent。基于需求描述生成规范、可运行的代码文件。只输出代码内容不要输出解释。) GenerationResult generate(UserMessage String description); }子 Agent 不用绑工具它只负责从描述到代码的生成。生成结果的格式是固定的 GenerationResult 对象——包含文件列表、代码内容、依赖清单这个结构体是后续汇总和构建的输入。整体链路就是主 Agent 编排、子 Agent 执行、结果结构化输出的模式。5. 避坑清单版本兼容、模型超时与分布式调度的五个真实问题5.1 LangChain4j 版本迭代用得好好的代码升级后编译不过现象按网上教程升级 LangChain4j 到新版本后编译报错。常见的有 Tool 注解包路径找不到、AiServices.builder 方法签名变了、ChatMemory 接口被重命名。原因LangChain4j 从 0.19 到 0.36 迭代了十几个版本API 一直在调整。尤其是 2024 年那段时间几乎每个 minor 版本都有 breaking changes包路径和方法签名频繁变动网上大量教程对应的都是老版本。解决项目 POM 里锁定 LangChain4j 版本不要随意升级。升级前必须看官方 release notes 里标出来的 breaking changes 列表。如果项目锁定的是 0.3x 版本写代码时参考同版本文档不要拿新版本的教程代码硬套那大概率翻车。5.2 Spring Boot 3 与 JDK 版本匹配本机新版本跑不动项目现象本地 JDK 用 21 跑项目启动报 UnsupportedClassVersionError或运行一段时间后出现 CGLIB 代理创建失败、Bean 实例化异常。原因Spring Boot 3.0 和 3.1 的基线是 JDK 173.2 才开始完整支持 JDK 21。而且部分中间件客户端在 JDK 21 下有兼容性问题比如某些版本的 Nacos 客户端在 JDK 21 下连接池初始化异常。解决以项目 POM 锁定的 Spring Boot 版本为准反向决定 JDK 版本。Spring Boot 3.0/3.1 用 JDK 173.2 用 JDK 21不要本机装了新版本就强行跑。如果项目里用了 Nacos优先用 Spring Cloud Alibaba 2023.x 对应的客户端版本这个组合在 JDK 21 下经过验证。5.3 大模型调用超时一次抖动拖垮整个生成链路现象模型 API 偶发响应慢默认 10 秒超时导致 Agent 任务失败配置了重试后大量并发请求同时重试直接把模型 API 打爆。原因超时设置太短重试策略没有退避机制。AI 场景下模型接口的响应时间分布很宽简单查询可能 1 秒返回复杂推理可能要 30 秒固定短超时误杀正常请求而失败后立即重试会让所有请求在同一时刻扎堆。解决超时时间按链路耗时的两倍设置建议 3060 秒重试用指数退避初始等待 1 秒翻倍最大等 30 秒重试次数不超过 2 次。实现对项目来说就是 RestTemplate 或 WebClient 的 RequestConfig 里配置 connectionTimeout 和 readTimeout重试逻辑做在独立的重试拦截器里不要散落在业务代码中。5.4 微服务链路追踪缺失任务失败成了黑匣子现象AI 生成任务失败了日志看了半天不知道是 Agent 编排时模型返回格式不对还是执行服务构建失败还是产物存储异常。原因服务拆到 5 个以上没有引入链路追踪日志分散在各个模块排查问题全靠肉眼搜关键字。解决引入 Micrometer Tracing 或 SkyWalking。Feign 调用链路上通过 RequestInterceptor 把 traceId 透传到下游服务每个服务打印日志时带上 traceId。这样一次 Agent 任务的完整调用链可以串联起来哪个环节慢了、哪个环节失败了一目了然。项目里如果用 OpenFeign注意拦截器要加到全局配置里不然只有部分 Feign Client 带上了 traceId。5.5 向量召回结果为空或乱入embedding 维度不一致现象多路召回结果为空或者召回来的内容明显不相关Agent 上下文被污染生成结果驴唇不对马嘴。原因两种常见情况。第一数据写入向量库时没有同步做 embedding旧的索引数据没有向量。第二切换了 embedding 模型新模型的向量维度跟索引定义不一致查询时报维度错误或因为向量的语义空间不同导致相似度计算失真。解决写入向量库时同步生成 embedding不要在离线脚本里批量补切换 embedding 模型时必须重建向量索引这个操作要纳入发布流程不能漏。维度不一致的问题在启动时加一次配置校验读取索引维度跟当前模型维度做比对不一致直接启动失败宁可报错也不能带病运行导致线上数据混乱。6. 进阶用法Agent 输出质量验证与 RAG 增强的实操路径项目跑通之后下一步要解决的是“生成质量怎么度量、怎么提升”。质量验证建议从三个指标入手。任务完成率一次 Agent 任务成功交付产物的比例低于 80% 说明编排链路有问题优先排查 SystemMessage 的职责描述。代码可编译率生成产物能通过 Maven 编译的比例低于 60% 说明代码生成 Agent 的上下文质量差检查多路召回的阈值设置。单次任务耗时均值超过 5 分钟用户体验会很差需要优化模型选择或拆分粒度。指标名称 目标值 采集方式 任务完成率 ≥ 80% 异步任务表状态统计 代码可编译率 ≥ 60% 执行服务构建结果统计 单次任务耗时 ≤ 5分钟 链路追踪 span 时长统计关于 RAG 增强我建议按这个路径落地。第一步把历史生成过的项目文档、代码片段、需求规格说明切成 500800 字符的块做 embedding 入库。第二步在 ContextRetriever 里把向量召回的结果和结构化查询合并按相关度排序后截断。第三步在 SystemMessage 里加一句约束“你必须基于已提供的上下文信息生成代码不得编造不存在的依赖或 API”。这三步做完生成质量一般会有明显提升。提示词里的约束语句要具体比如“不得编造不存在的依赖版本”而不是笼统的“请认真生成”。模型对抽象指令的服从性远不如具体约束。调 Agent 和调人有点像指令越具体执行越到位。整理这个项目的过程里我一直在想微服务架构、LangChain4j、多路召回这些概念单独拿出来都不新鲜真正难的是把它们组合起来跑通一条完整链路并且把异常场景处理干净。版本兼容、超时重试、链路追踪、向量召回任何一个环节松懈都会在产品环境里加倍还回来。现在每做一个 AI 项目我都会强制把链路追踪、超时策略、上下文校验这三件事放进上线清单的第一页——希望帮到你。本文还有配套的精品资源点击获取
返回列表