作者:大洪讲AI
更新时间:2026年6月
本章目标:完成前后端项目初始化,集成豆包API,实现第一个可调用的聊天接口


前言

上一章我们介绍了整个项目的背景、技术栈和整体规划。从本章开始,我们将正式进入代码开发阶段。

本章我们将完成:

  1. Spring Boot后端项目初始化
  2. Vue3前端项目初始化
  3. 集成豆包API,配置大模型Bean
  4. 实现第一个最简单的聊天接口
  5. 前后端联调,验证大模型调用正常

所有代码都经过验证,直接复制就能跑通,全程没有任何坑。


一、后端项目初始化(Spring Boot 2.7.18)

我们使用Spring Boot 2.7.18,这是Java8兼容的最后一个稳定版,兼容性最好,企业中使用最广泛。

1.1 创建Spring Boot项目

打开IDEA,新建项目:

  1. 选择「Spring Initializr」
  2. 填写项目信息:
    • Group:org.example
    • Artifact:ai-kefu-backend
    • Java版本:8
    • 打包方式:Jar
  3. 选择依赖:
    • Spring Web
    • MyBatis Framework
    • MySQL Driver
    • Lombok
  4. 点击「Finish」完成项目创建

1.2 修改pom.xml,添加完整依赖

打开pom.xml,替换为以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>ai-kefu-backend</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ai-kefu-backend</name>
    <description>AI智能客服系统后端</description>

    <properties>
        <java.version>1.8</java.version>
        <langchain4j.version>0.31.0</langchain4j.version>
        <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
    </properties>

    <dependencies>
        <!-- Spring Boot核心依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <!-- MyBatis-Plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>

        <!-- MySQL驱动 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- LangChain4j 核心 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-core</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <!-- LangChain4j OpenAI兼容客户端(用于调用豆包API) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

点击IDEA右上角的「Reload All Maven Projects」刷新依赖。

1.3 配置application.yml

删除默认的application.properties,新建application.yml

# 服务器配置
server:
  port: 8080
  servlet:
    context-path: /

# 数据库配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/ai_kefu?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456 # 替换为你的MySQL密码
    driver-class-name: com.mysql.cj.jdbc.Driver

# MyBatis-Plus配置
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      id-type: auto

# 豆包API配置
doubao:
  api-key: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 替换为你上一章申请的API Key
  endpoint: https://ark.cn-beijing.volces.com/api/v3/chat/completions
  model-name: doubao-pro-32k
  embedding-model-name: doubao-embedding

# 缓存配置
spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=1000,expireAfterWrite=1h
    cache-names:
      - qaCache

# 自定义配置
ai:
  cache:
    enabled: true

重要说明

  • 请将doubao.api-key替换为你自己的API Key
  • 请将spring.datasource.password替换为你的MySQL密码
  • 确保MySQL中已经创建了ai_kefu数据库(可以先创建一个空数据库,后面再建表)

1.4 创建统一返回结果类AjaxResult

新建文件:src/main/java/org/example/model/vo/AjaxResult.java

package org.example.model.vo;

import lombok.Data;

@Data
public class AjaxResult<T> {
    private int code;
    private String msg;
    private T data;

    public static <T> AjaxResult<T> success(T data) {
        AjaxResult<T> result = new AjaxResult<>();
        result.setCode(200);
        result.setMsg("success");
        result.setData(data);
        return result;
    }

    public static <T> AjaxResult<T> error(String msg) {
        AjaxResult<T> result = new AjaxResult<>();
        result.setCode(500);
        result.setMsg(msg);
        return result;
    }
}

这是整个项目统一的返回结果格式,所有接口都返回这个格式。

1.5 配置大模型Bean

新建文件:src/main/java/org/example/config/AiConfig.java

package org.example.config;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
public class AiConfig {

    @Value("${doubao.api-key}")
    private String doubaoApiKey;

    @Value("${doubao.endpoint}")
    private String doubaoEndpoint;

    @Value("${doubao.model-name}")
    private String doubaoModelName;

    @Value("${doubao.embedding-model-name}")
    private String doubaoEmbeddingModelName;

    // 默认参数
    private static final int DEFAULT_MAX_TOKENS = 4096;
    private static final double DEFAULT_TEMPERATURE = 0.7;
    private static final long DEFAULT_TIMEOUT = 60000; // 60秒超时

    /**
     * 同步聊天模型(用于意图识别、对话总结)
     */
    @Bean
    public ChatLanguageModel doubaoChatModel() {
        String baseUrl = doubaoEndpoint.replace("/chat/completions", "");
        return OpenAiChatModel.builder()
                .baseUrl(baseUrl)
                .apiKey(doubaoApiKey)
                .modelName(doubaoModelName)
                .maxTokens(DEFAULT_MAX_TOKENS)
                .temperature(DEFAULT_TEMPERATURE)
                .timeout(Duration.ofMillis(DEFAULT_TIMEOUT))
                .build();
    }

    /**
     * 流式聊天模型(用于聊天,打字机效果)
     */
    @Bean
    public StreamingChatLanguageModel doubaoStreamingChatModel() {
        String baseUrl = doubaoEndpoint.replace("/chat/completions", "");
        return OpenAiStreamingChatModel.builder()
                .baseUrl(baseUrl)
                .apiKey(doubaoApiKey)
                .modelName(doubaoModelName)
                .maxTokens(DEFAULT_MAX_TOKENS)
                .temperature(DEFAULT_TEMPERATURE)
                .timeout(Duration.ofMillis(DEFAULT_TIMEOUT))
                .build();
    }

    /**
     * 嵌入模型(用于RAG文档向量化)
     */
    @Bean
    public EmbeddingModel doubaoEmbeddingModel() {
        String baseUrl = doubaoEndpoint.replace("/chat/completions", "");
        return OpenAiEmbeddingModel.builder()
                .baseUrl(baseUrl)
                .apiKey(doubaoApiKey)
                .modelName(doubaoEmbeddingModelName)
                .timeout(Duration.ofMillis(DEFAULT_TIMEOUT))
                .build();
    }
}

为什么用OpenAiChatModel调用豆包?
因为豆包API完全兼容OpenAI的接口规范,所以我们可以直接使用LangChain4j的OpenAI客户端来调用豆包API,不需要额外的依赖。

1.6 实现第一个聊天接口

新建文件:src/main/java/org/example/controller/ChatController.java

package org.example.controller;

import dev.langchain4j.model.chat.ChatLanguageModel;
import org.example.model.vo.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.Data;

@RestController
@RequestMapping("/api/chat")
public class ChatController {

    @Autowired
    @Qualifier("doubaoChatModel")
    private ChatLanguageModel chatModel;

    @Data
    public static class ChatRequest {
        private String message;
    }

    /**
     * 最简单的同步聊天接口
     */
    @PostMapping("/simple")
    public AjaxResult<String> simpleChat(@RequestBody ChatRequest request) {
        String response = chatModel.generate(request.getMessage());
        return AjaxResult.success(response);
    }
}

1.7 启动项目并测试

  1. 启动Spring Boot项目,控制台没有报错说明启动成功
  2. 打开Postman,发送POST请求到http://localhost:8080/api/chat/simple
  3. 请求体:
    {
        "message": "你好,介绍一下你自己"
    }
    
  4. 正常情况下会收到豆包的回复:
    {
        "code": 200,
        "msg": "success",
        "data": "你好!我是豆包,是字节跳动开发的AI助手。我可以帮你解答问题、写代码、写文案、聊天等等。有什么我可以帮你的吗?"
    }
    

✅ 后端项目初始化完成,豆包API调用正常!


二、前端项目初始化(Vue3 + Vite + Element Plus)

2.1 创建Vue3项目

打开CMD,执行以下命令:

npm create vite@latest ai-kefu-web -- --template vue

进入项目目录,安装依赖:

cd ai-kefu-web
npm install
npm install element-plus axios

2.2 配置Element Plus

修改src/main.js

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')

2.3 配置Vite代理

修改vite.config.js,添加代理配置,解决跨域问题:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true
      }
    }
  }
})

2.4 创建基础聊天页面

修改src/App.vue

<template>
  <div class="app">
    <div class="chat-container">
      <div class="chat-header">
        <h1>AI智能客服</h1>
      </div>

      <div class="chat-content" ref="chatContentRef">
        <div
          v-for="(msg, index) in messageList"
          :key="index"
          :class="['message', msg.role]"
        >
          <div class="message-content">{{ msg.content }}</div>
        </div>
      </div>

      <div class="chat-input">
        <el-input
          v-model="inputMessage"
          placeholder="请输入您的问题..."
          @keyup.enter="handleSend"
          :disabled="isLoading"
        ></el-input>
        <el-button
          type="primary"
          @click="handleSend"
          :loading="isLoading"
        >
          发送
        </el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, nextTick } from 'vue'
import axios from 'axios'

const messageList = ref([])
const inputMessage = ref('')
const isLoading = ref(false)
const chatContentRef = ref(null)

// 滚动到底部
const scrollToBottom = async () => {
  await nextTick()
  if (chatContentRef.value) {
    chatContentRef.value.scrollTop = chatContentRef.value.scrollHeight
  }
}

// 发送消息
const handleSend = async () => {
  const content = inputMessage.value.trim()
  if (!content || isLoading.value) return

  inputMessage.value = ''
  isLoading.value = true

  // 添加用户消息
  messageList.value.push({ role: 'user', content })
  await scrollToBottom()

  try {
    // 调用后端接口
    const res = await axios.post('/api/chat/simple', { message: content })
    
    // 添加AI回复
    messageList.value.push({ role: 'ai', content: res.data.data })
    await scrollToBottom()
  } catch (error) {
    console.error('请求失败:', error)
    messageList.value.push({ role: 'ai', content: '抱歉,系统出错了,请稍后再试。' })
  } finally {
    isLoading.value = false
  }
}
</script>

<style scoped>
.app {
  width: 100vw;
  height: 100vh;
  background-color: #f5f7fa;
  display: flex;
  justify-content: center;
  align-items: center;
}

.chat-container {
  width: 800px;
  height: 80vh;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  display: flex;
  flex-direction: column;
}

.chat-header {
  padding: 20px;
  border-bottom: 1px solid #e6e6e6;
  text-align: center;
}

.chat-header h1 {
  margin: 0;
  font-size: 24px;
  color: #303133;
}

.chat-content {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
}

.message {
  margin-bottom: 16px;
  max-width: 70%;
  display: flex;
}

.message.user {
  margin-left: auto;
  justify-content: flex-end;
}

.message.ai {
  margin-right: auto;
  justify-content: flex-start;
}

.message-content {
  padding: 12px 16px;
  border-radius: 8px;
  line-height: 1.5;
}

.message.user .message-content {
  background-color: #409eff;
  color: white;
}

.message.ai .message-content {
  background-color: #f5f7fa;
  color: #303133;
}

.chat-input {
  padding: 20px;
  border-top: 1px solid #e6e6e6;
  display: flex;
  gap: 10px;
}

.chat-input .el-input {
  flex: 1;
}
</style>

2.5 启动前端项目并测试

在前端项目目录下执行:

npm run dev

打开浏览器访问http://localhost:3000,输入问题并发送,应该能正常收到AI的回复。

✅ 前端项目初始化完成,前后端联调成功!


三、常见问题排查

问题1:启动后端时报数据库连接错误

  • 检查MySQL服务是否正常启动
  • 检查application.yml中的数据库地址、用户名和密码是否正确
  • 检查是否已经创建了ai_kefu数据库

问题2:调用聊天接口返回401错误

  • 检查doubao.api-key是否正确
  • 检查API Key是否有对应的模型权限
  • 检查豆包开放平台的账户是否有余额

问题3:前端请求跨域

  • 检查vite.config.js中的代理配置是否正确
  • 确保后端服务运行在8080端口

问题4:Maven依赖下载失败

  • 检查网络是否正常
  • 切换为阿里云Maven镜像

四、本章总结

本章我们完成了:

  1. ✅ Spring Boot 2.7.18后端项目初始化
  2. ✅ 集成MyBatis-Plus和MySQL
  3. ✅ 配置豆包API,创建三个大模型Bean
  4. ✅ 实现第一个同步聊天接口
  5. ✅ Vue3前端项目初始化
  6. ✅ 集成Element Plus和Axios
  7. ✅ 前后端联调成功,能正常调用大模型

现在我们已经有了一个最基础的聊天系统,虽然还很简单,但已经能正常和大模型对话了。


下章预告

下一章我们将实现SSE流式聊天,也就是ChatGPT同款的打字机效果,让聊天体验更加流畅自然。

关注我,第一时间收到更新通知!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐