基于RexUniNLU的SpringBoot微服务智能客服系统开发指南

你是不是也遇到过这样的场景?客服团队每天要处理海量的用户咨询,从“这个商品什么时候发货”到“我的订单为什么被取消了”,问题五花八门。人工客服忙得焦头烂额,用户还得排队等待,体验大打折扣。更头疼的是,很多问题其实都是重复的,但每次都得人工回答一遍,效率实在太低。

我之前负责过一个电商平台的客服系统升级项目,就深有体会。团队每天要处理上万条咨询,高峰期根本忙不过来。后来我们尝试引入AI,但早期的方案要么识别不准,要么扩展性差,一个模型只能干一件事,换个业务场景就得重新开发,维护成本高得吓人。

直到我们发现了RexUniNLU这个模型,情况才彻底改变。它最大的特点就是“通用”——一个模型就能搞定命名实体识别、关系抽取、情感分类、文本匹配等多种自然语言理解任务。这意味着,我们可以用同一套技术底座,灵活应对客服场景下的各种需求,比如识别用户意图、提取关键信息、判断用户情绪等等。

今天,我就结合自己的实战经验,跟你详细聊聊怎么把RexUniNLU集成到SpringBoot微服务架构里,搭建一个既智能又灵活的客服系统。我会从最核心的模型API封装讲起,再到多轮对话的状态管理,最后给出一个完整的、可运行的电商客服场景示例。你跟着做一遍,就能掌握从零到一搭建智能客服的核心方法。

1. 项目准备与环境搭建

在开始敲代码之前,咱们先把基础环境准备好。这个环节看似简单,但很多问题都是出在环境配置上,所以咱们一步步来。

1.1 技术栈选型与项目初始化

我们这次搭建的系统,核心是SpringBoot微服务架构,AI能力则由RexUniNLU模型提供。整个技术栈我列在下面,都是目前比较主流和成熟的选择:

  • 后端框架: SpringBoot 3.x + Spring Cloud。SpringBoot负责快速构建单体服务,Spring Cloud用来处理后续可能的服务拆分与治理。
  • AI模型: RexUniNLU (中文-base版本)。选择它是因为其“零样本”和“通用”的特性,非常适合客服这种需求多变的场景,不需要为每个新问题都准备大量标注数据。
  • 模型调用: 使用ModelScope提供的Python SDK。虽然我们是Java项目,但可以通过单独部署一个Python服务来调用模型,两者间用HTTP接口通信,这是比较常见的解耦做法。
  • 数据库: MySQL + Redis。MySQL存结构化数据,比如对话历史、用户信息;Redis用来做缓存和存储多轮对话的临时状态,速度快。
  • 其他: Maven管理依赖,Docker方便环境部署。

首先,用Spring Initializr创建一个基础的SpringBoot项目。我习惯直接用IDEA的创建向导,选上这几个核心依赖:Spring Web, Spring Data JPA, Lombok, Redispom.xml文件里会自动引入它们。

1.2 RexUniNLU模型服务部署

我们的Java服务不会直接调用Python模型,而是通过一个轻量级的Python服务来中转。这样做的目的是将AI能力独立出来,方便以后升级模型或者扩展其他AI功能。

我们先来搭建这个Python模型服务。创建一个新的目录,比如叫 ai-model-service,然后准备以下文件。

第一个是 requirements.txt,用来声明Python依赖:

modelscope>=1.10.0
transformers>=4.30.0
flask>=2.3.0
flask-cors>=4.0.0
torch>=1.12.0

接下来是核心的服务文件 model_server.py。这个脚本使用Flask创建了一个简单的HTTP服务,提供了两个关键接口:一个用于测试模型是否加载成功,另一个用于处理实际的自然语言理解请求。

from flask import Flask, request, jsonify
from flask_cors import CORS
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks
import logging

# 设置日志,方便查看运行情况
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = Flask(__name__)
CORS(app)  # 允许跨域请求,方便Java服务调用

# 全局加载模型管道。注意,第一次加载会下载模型,可能需要一些时间。
# 我们这里以‘零样本分类’任务为例,这是客服意图识别的核心。
logger.info("正在加载RexUniNLU模型,请稍候...")
try:
    nlp_pipeline = pipeline(
        task=Tasks.zero_shot_classification, # 零样本分类任务
        model='iic/nlp_deberta_rex-uninlu_chinese-base' # 模型地址
    )
    logger.info("模型加载成功!")
except Exception as e:
    logger.error(f"模型加载失败: {e}")
    nlp_pipeline = None

@app.route('/health', methods=['GET'])
def health_check():
    """健康检查接口,用于测试服务是否正常"""
    if nlp_pipeline:
        return jsonify({"status": "healthy", "model": "RexUniNLU loaded"}), 200
    else:
        return jsonify({"status": "unhealthy", "error": "Model not loaded"}), 503

@app.route('/nlu/understand', methods=['POST'])
def natural_language_understanding():
    """自然语言理解核心接口
    请求体示例:
    {
        "text": "我想查询一下订单123456的物流信息",
        "schema": {
            "意图分类": ["查询物流", "投诉建议", "产品咨询", "售后申请", "其他"]
        }
    }
    """
    if not nlp_pipeline:
        return jsonify({"error": "Model service unavailable"}), 500

    data = request.get_json()
    user_text = data.get('text', '')
    schema = data.get('schema', {})

    if not user_text:
        return jsonify({"error": "Text is required"}), 400

    try:
        # 调用模型进行推理
        result = nlp_pipeline(user_text, schema)
        logger.info(f"处理成功: 输入-{user_text}, 输出-{result}")
        return jsonify(result), 200
    except Exception as e:
        logger.error(f"模型推理出错: {e}")
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    # 启动服务,监听5000端口,允许外部访问
    app.run(host='0.0.0.0', port=5000, debug=False)

写好之后,在这个目录下打开终端,运行下面几条命令就能启动服务了:

# 1. 创建虚拟环境(推荐,避免包冲突)
python -m venv venv

# 2. 激活虚拟环境
# 在Windows上: venv\Scripts\activate
# 在Mac/Linux上: source venv/bin/activate

# 3. 安装依赖
pip install -r requirements.txt

# 4. 启动服务
python model_server.py

看到控制台输出“模型加载成功!”和“Running on http://0.0.0.0:5000”,就说明你的模型服务已经就绪了。可以用浏览器或Postman访问一下 http://localhost:5000/health,应该会返回健康的状态。

2. SpringBoot微服务与AI能力集成

模型服务跑起来之后,接下来就是让我们的SpringBoot应用能够和它对话。这部分我们要完成两件事:一是封装一个好用、可靠的AI服务客户端;二是设计并实现一个能记住上下文的对话管理器。

2.1 封装RexUniNLU服务客户端

在SpringBoot项目里,我们创建一个专门负责和Python模型服务通信的组件。这样其他业务代码只需要调用这个组件,不用关心底层的HTTP细节。

首先,在 application.yml 配置文件里加上模型服务的地址:

ai:
  model:
    service:
      base-url: http://localhost:5000 # 你的Python模型服务地址
      health-path: /health
      nlu-path: /nlu/understand

然后,我们创建一个配置类来读取这些配置,并定义一个 ModelServiceClient

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
@ConfigurationProperties(prefix = "ai.model.service")
@Data
public class AiModelServiceConfig {
    private String baseUrl;
    private String healthPath;
    private String nluPath;

    public String getHealthUrl() {
        return baseUrl + healthPath;
    }

    public String getNluUrl() {
        return baseUrl + nluPath;
    }

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

接下来是重头戏,服务客户端本身。这里我们使用Spring的 RestTemplate 来发送HTTP请求,并处理可能的异常,比如网络超时或者模型服务挂掉。

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class RexUniNLUClient {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private AiModelServiceConfig config;

    /**
     * 检查AI模型服务是否健康
     */
    public boolean isServiceHealthy() {
        try {
            ResponseEntity<String> response = restTemplate.getForEntity(config.getHealthUrl(), String.class);
            return response.getStatusCode() == HttpStatus.OK;
        } catch (ResourceAccessException e) {
            log.warn("AI模型服务连接失败,可能未启动: {}", e.getMessage());
            return false;
        } catch (Exception e) {
            log.error("检查AI服务健康状态时发生未知错误", e);
            return false;
        }
    }

    /**
     * 核心方法:向模型发送文本和schema进行理解
     * @param text 用户输入的文本
     * @param schema 定义的意图分类schema
     * @return 模型返回的理解结果
     */
    public NLUResponse understandText(String text, Map<String, Object> schema) {
        if (!isServiceHealthy()) {
            throw new RuntimeException("AI模型服务不可用,请检查服务状态");
        }

        // 构造请求体
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("text", text);
        requestBody.put("schema", schema);

        // 设置HTTP头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);

        try {
            log.info("发送NLU请求,文本: {}", text);
            ResponseEntity<NLUResponse> response = restTemplate.postForEntity(
                    config.getNluUrl(),
                    requestEntity,
                    NLUResponse.class
            );

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                return response.getBody();
            } else {
                log.error("NLU请求返回异常状态: {}", response.getStatusCode());
                throw new RuntimeException("模型服务返回异常: " + response.getStatusCode());
            }
        } catch (ResourceAccessException e) {
            log.error("调用AI模型服务超时或网络错误", e);
            throw new RuntimeException("服务调用失败,请稍后重试", e);
        } catch (Exception e) {
            log.error("NLU处理过程发生错误", e);
            throw new RuntimeException("语义理解处理失败", e);
        }
    }

    /**
     * 定义模型返回结果的Java对象
     */
    @Data
    public static class NLUResponse {
        @JsonProperty("意图分类") // 映射模型返回的JSON字段名
        private Map<String, Double> intentClassification;
        // 可以根据模型返回的其他字段继续扩展,比如抽取的实体
    }
}

这个客户端类做了几件重要的事:健康检查、构造请求、发送HTTP调用、处理响应和异常。有了它,业务代码里调用AI理解就一句话的事,非常清爽。

2.2 设计对话状态管理与意图处理器

智能客服不是一问一答就结束的,用户可能会连续追问。比如用户先说“查订单”,客服问“订单号是多少?”,用户再回答“123456”。我们需要记住这个“查订单”的上下文,知道用户第二次说的“123456”是订单号。

这就是对话状态管理。一个简单的实现思路是,为每个用户会话(可以用一个唯一的sessionId标识)在Redis里存一个状态对象。这个对象记录当前对话进行到哪一步了,以及已经收集到了哪些信息。

我们先定义一个对话状态类:

import lombok.Data;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

@Data
public class DialogState implements Serializable {
    private String sessionId;
    private String currentIntent; // 当前识别出的主导意图,如“QUERY_LOGISTICS”
    private String currentStep;   // 在当前意图下的步骤,如“AWAITING_ORDER_NUMBER”
    private Map<String, String> slots; // 收集到的信息槽位,如 orderId: "123456"
    private long lastActiveTime; // 最后活跃时间,用于清理过期会话

    public DialogState(String sessionId) {
        this.sessionId = sessionId;
        this.slots = new HashMap<>();
        this.lastActiveTime = System.currentTimeMillis();
    }

    public void fillSlot(String key, String value) {
        this.slots.put(key, value);
        this.lastActiveTime = System.currentTimeMillis();
    }

    public boolean isSlotFilled(String key) {
        return slots.containsKey(key) && slots.get(key) != null;
    }
}

然后,我们创建一个 DialogManager 来管理这些状态。它依赖前面写的 RexUniNLUClient 来理解用户意图,并根据意图和当前状态,决定下一步该做什么、回复什么。

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class DialogManager {

    @Autowired
    private RedisTemplate<String, DialogState> redisTemplate;

    @Autowired
    private RexUniNLUClient nluClient;

    // 定义一些业务相关的意图和回复模板
    private static final Map<String, String> INTENT_PROMPT_MAP = Map.of(
            "查询物流", "请问您的订单号是多少?",
            "投诉建议", "请描述您遇到的问题或建议。",
            "产品咨询", "您想了解哪款产品呢?",
            "售后申请", "请提供您的订单号和遇到的问题。"
    );

    private static final String REDIS_KEY_PREFIX = "dialog:state:";

    /**
     * 处理用户输入的一句话,并返回客服回复
     */
    public DialogResponse processUserInput(String sessionId, String userInput) {
        // 1. 获取或创建当前会话的状态
        DialogState state = getOrCreateState(sessionId);

        // 2. 使用NLU模型理解用户当前输入的意图
        Map<String, Object> schema = Map.of("意图分类", INTENT_PROMPT_MAP.keySet().toArray());
        RexUniNLUClient.NLUResponse nluResult = nluClient.understandText(userInput, schema);

        String detectedIntent = parseTopIntent(nluResult);
        log.info("会话[{}] 识别出意图: {}", sessionId, detectedIntent);

        // 3. 对话逻辑处理(核心)
        String botReply;
        if (state.getCurrentIntent() == null) {
            // 情况A:新对话,刚识别出一个意图
            state.setCurrentIntent(detectedIntent);
            state.setCurrentStep("REQUEST_SLOT");
            botReply = INTENT_PROMPT_MAP.getOrDefault(detectedIntent, "请问有什么可以帮您?");
        } else if ("REQUEST_SLOT".equals(state.getCurrentStep())) {
            // 情况B:正在等待用户补充信息(如上一步问了订单号)
            // 这里简单处理,假设用户输入的就是所需信息(如订单号)
            state.fillSlot("requiredInfo", userInput); // 实际应根据意图定义具体槽位名
            state.setCurrentStep("SLOT_FILLED");
            botReply = "信息已收到,正在为您查询..."; // 这里应触发后续业务查询
            // 模拟查询后,重置状态或进入下一步
            state.setCurrentIntent(null);
            state.setCurrentStep(null);
        } else {
            // 其他情况处理
            botReply = "抱歉,我没太明白,您可以换个说法吗?";
        }

        // 4. 保存更新后的状态回Redis,并设置过期时间(如30分钟无活动则清除)
        saveState(state);

        return new DialogResponse(botReply, state.getCurrentIntent());
    }

    private DialogState getOrCreateState(String sessionId) {
        String key = REDIS_KEY_PREFIX + sessionId;
        DialogState state = redisTemplate.opsForValue().get(key);
        if (state == null) {
            state = new DialogState(sessionId);
        }
        return state;
    }

    private void saveState(DialogState state) {
        String key = REDIS_KEY_PREFIX + state.getSessionId();
        redisTemplate.opsForValue().set(key, state, 30, TimeUnit.MINUTES);
    }

    private String parseTopIntent(RexUniNLUClient.NLUResponse response) {
        if (response.getIntentClassification() == null || response.getIntentClassification().isEmpty()) {
            return "其他";
        }
        // 返回置信度最高的意图
        return response.getIntentClassification().entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse("其他");
    }

    @Data
    public static class DialogResponse {
        private String reply;
        private String currentIntent;
        // 可以附加其他信息,如抽取的实体
        public DialogResponse(String reply, String currentIntent) {
            this.reply = reply;
            this.currentIntent = currentIntent;
        }
    }
}

这个 DialogManager 是一个简化但完整的核心,它展示了如何将NLU的识别结果与业务对话逻辑结合起来。在实际项目中,processUserInput 方法里的逻辑会更复杂,可能会是一个状态机,针对每个意图定义不同的处理步骤和槽位填充规则。

3. 电商客服场景实战与API构建

环境搭好了,核心组件也写完了,现在我们来把它们组装起来,实现一个具体的电商客服功能,并对外提供清晰的API。

3.1 定义客服场景与意图Schema

电商客服最常见的问题就那么几类。我们针对“查询物流”这个场景来深入实现一下。用户完整的诉求可能是:“我的订单还没到,帮我查一下123456这个单子到哪了”。

这背后其实包含了两个任务:

  1. 意图识别:判断用户是想“查询物流”。
  2. 信息抽取:从句子中把订单号“123456”抽出来。

RexUniNLU的妙处就在于,它能通过不同的schema配置,同时完成这两类任务。我们修改一下之前模型服务的 /nlu/understand 接口调用方式,让它更强大。

RexUniNLUClient 里,我们可以增加一个专门处理复合任务的方法:

/**
 * 针对电商客服的复合理解:同时识别意图和抽取实体
 */
public ComplexNLUResponse understandForCustomerService(String text) {
    // 这是一个组合schema的例子,同时做零样本分类和命名实体识别
    Map<String, Object> complexSchema = new HashMap<>();
    complexSchema.put("意图分类", new String[]{"查询物流", "投诉建议", "产品咨询", "售后申请", "账户问题", "其他"});
    complexSchema.put("订单号", null); // null表示抽取该类型的实体

    Map<String, Object> requestBody = new HashMap<>();
    requestBody.put("text", text);
    requestBody.put("schema", complexSchema);

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);

    ResponseEntity<ComplexNLUResponse> response = restTemplate.postForEntity(
            config.getNluUrl(),
            requestEntity,
            ComplexNLUResponse.class
    );
    return response.getBody();
}

@Data
public static class ComplexNLUResponse {
    @JsonProperty("意图分类")
    private Map<String, Double> intentClassification;

    @JsonProperty("订单号")
    private List<String> orderNumbers; // 抽取出的实体列表
}

这样,一次模型调用,我们既能知道用户想干嘛,又能直接拿到他提到的订单号,效率非常高。

3.2 构建SpringBoot RESTful API

最后,我们创建一个控制器(Controller),把所有的能力通过HTTP接口暴露出去,供前端网页、APP或者小程序调用。

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.UUID;

@Slf4j
@RestController
@RequestMapping("/api/customer-service")
public class CustomerServiceController {

    @Autowired
    private DialogManager dialogManager;

    @GetMapping("/health")
    public ApiResponse<String> health() {
        return ApiResponse.success("智能客服系统运行正常");
    }

    @PostMapping("/chat")
    public ApiResponse<DialogManager.DialogResponse> chat(@RequestBody ChatRequest request) {
        // 如果请求中没有sessionId,则生成一个新的,代表新用户会话
        String sessionId = request.getSessionId() != null ? request.getSessionId() : generateSessionId();
        log.info("处理会话[{}]的请求: {}", sessionId, request.getUserInput());

        try {
            DialogManager.DialogResponse dialogResponse = dialogManager.processUserInput(sessionId, request.getUserInput());
            // 在返回中带上sessionId,客户端下次请求需要传回来
            return ApiResponse.success(dialogResponse).addExtra("sessionId", sessionId);
        } catch (Exception e) {
            log.error("处理用户对话失败", e);
            return ApiResponse.error("系统处理出错,请稍后重试");
        }
    }

    // 提供一个专门的意图分析接口,用于调试或特定场景
    @PostMapping("/analyze")
    public ApiResponse<RexUniNLUClient.ComplexNLUResponse> analyzeIntent(@RequestBody AnalyzeRequest request) {
        try {
            RexUniNLUClient.ComplexNLUResponse nluResponse = dialogManager.getNluClient().understandForCustomerService(request.getText());
            return ApiResponse.success(nluResponse);
        } catch (Exception e) {
            return ApiResponse.error("语义分析失败: " + e.getMessage());
        }
    }

    private String generateSessionId() {
        return "cs-" + UUID.randomUUID().toString().substring(0, 8);
    }

    @Data
    public static class ChatRequest {
        private String sessionId; // 可选,用于连续对话
        @NotBlank(message = "用户输入不能为空")
        private String userInput;
    }

    @Data
    public static class AnalyzeRequest {
        @NotBlank
        private String text;
    }

    // 简单的统一API响应封装
    @Data
    public static class ApiResponse<T> {
        private int code;
        private String message;
        private T data;
        private Map<String, Object> extra;

        public static <T> ApiResponse<T> success(T data) {
            ApiResponse<T> response = new ApiResponse<>();
            response.code = 200;
            response.message = "success";
            response.data = data;
            return response;
        }
        public static <T> ApiResponse<T> error(String message) {
            ApiResponse<T> response = new ApiResponse<>();
            response.code = 500;
            response.message = message;
            return response;
        }
        public ApiResponse<T> addExtra(String key, Object value) {
            if (this.extra == null) {
                this.extra = new HashMap<>();
            }
            this.extra.put(key, value);
            return this;
        }
    }
}

现在,你的智能客服系统就拥有完整的API了。启动你的SpringBoot应用(默认端口8080),就可以用Postman进行测试了。

测试示例:

  1. 发起新对话POST http://localhost:8080/api/customer-service/chat

    {
        "userInput": "帮我查一下物流"
    }
    

    返回

    {
        "code": 200,
        "message": "success",
        "data": {
            "reply": "请问您的订单号是多少?",
            "currentIntent": "查询物流"
        },
        "extra": {
            "sessionId": "cs-a1b2c3d4"
        }
    }
    
  2. 继续对话(使用返回的sessionId)POST http://localhost:8080/api/customer-service/chat

    {
        "sessionId": "cs-a1b2c3d4",
        "userInput": "订单号是123456"
    }
    

    返回

    {
        "code": 200,
        "message": "success",
        "data": {
            "reply": "信息已收到,正在为您查询...",
            "currentIntent": null
        }
    }
    

看到这个交互过程,你应该就能体会到整个系统是如何运作的了:前端收集用户输入,调用我们的API,后端通过DialogManager协调NLU理解和对话逻辑,最终生成回复。整个流程清晰,且每个模块职责分明。

4. 总结

走完这一整套开发流程,一个基于RexUniNLU和SpringBoot的智能客服系统核心骨架就搭建起来了。回顾一下,我们主要做了三件事:首先是部署了一个独立的、提供通用NLU能力的Python模型服务;然后是在SpringBoot项目中,通过封装HTTP客户端和设计对话状态管理器,将AI能力平滑地集成到了微服务架构中;最后,我们针对电商场景设计了具体的意图和实体抽取逻辑,并通过RESTful API对外提供服务。

这套方案的优点很明显。利用RexUniNLU的通用性,我们不需要为每个细分客服场景训练单独的模型,省去了大量的数据和标注成本。SpringBoot微服务的架构也让系统具备了良好的扩展性和维护性,后续如果想增加新的客服技能(比如退货政策查询),只需要在意图列表和对话逻辑里添加相应的处理即可,模型部分基本不用动。

当然,这只是一个起点。在实际生产环境中,你可能还需要考虑更多东西,比如给模型服务加上负载均衡和高可用、设计更复杂的多轮对话状态机、集成知识库进行更精准的问答、以及对整个系统的性能进行监控和优化。但无论如何,今天分享的这个框架和代码,已经为你打通了从AI模型到业务应用的关键路径。你可以基于它快速进行原型验证和功能开发,希望对你有所帮助。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

更多推荐