From f7a1b1996d92d96004a7a1ab1bf289516732c7e4 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Tue, 05 Aug 2025 17:04:20 +0800
Subject: [PATCH] feat(ai): 添加 AI 用户陪练功能

---
 src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java               |    6 
 src/main/java/cc/mrbird/febs/mall/controller/HSController.java                     |    2 
 src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java                   |   18 +
 src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java              |    5 
 src/main/java/cc/mrbird/febs/ai/res/ai/AiResponse.java                             |   16 +
 src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java          |  137 +++++++++++++++
 src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkController.java |   54 ++++++
 src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java     |    8 
 src/main/resources/application-test.yml                                            |    8 
 src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkDto.java               |   21 ++
 src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java      |   18 ++
 src/main/java/cc/mrbird/febs/ai/service/impl/AiServiceImpl.java                    |  147 ++++++++++++++++
 src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkAnswerDto.java         |   26 ++
 src/main/java/cc/mrbird/febs/ai/res/memberTalk/ApiMemberTalkVo.java                |   35 +++
 src/main/java/cc/mrbird/febs/ai/service/AiService.java                             |   14 +
 15 files changed, 510 insertions(+), 5 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkController.java b/src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkController.java
new file mode 100644
index 0000000..66212da
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkController.java
@@ -0,0 +1,54 @@
+package cc.mrbird.febs.ai.controller.memberTalk;
+
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkAnswerDto;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkDto;
+import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkVo;
+import cc.mrbird.febs.ai.service.AiMemberTalkService;
+import cc.mrbird.febs.common.entity.FebsResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+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;
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(value = "/api/ai/memberTalk")
+@Api(value = "ApiMemberTalkController", tags = "AI-用户陪练")
+public class ApiMemberTalkController {
+
+    private final AiMemberTalkService aiMemberTalkService;
+
+
+    @ApiOperation(value = "开始陪练", notes = "开始陪练")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "success", response = ApiMemberTalkVo.class)
+    })
+    @PostMapping(value = "/start")
+    public FebsResponse start(@RequestBody @Validated ApiMemberTalkDto dto) {
+
+        return aiMemberTalkService.start(dto);
+    }
+
+
+    @ApiOperation(value = "回答", notes = "回答")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "success", response = ApiMemberTalkVo.class)
+    })
+    @PostMapping(value = "/answer")
+    public FebsResponse answer(@RequestBody @Validated ApiMemberTalkAnswerDto dto) {
+
+        return aiMemberTalkService.answer(dto);
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkAnswerDto.java b/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkAnswerDto.java
new file mode 100644
index 0000000..09da7ba
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkAnswerDto.java
@@ -0,0 +1,26 @@
+package cc.mrbird.febs.ai.req.memberTalk;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author Administrator
+ */
+@Data
+@ApiModel(value = "ApiMemberTalkAnswerDto", description = "参数")
+public class ApiMemberTalkAnswerDto {
+
+
+    @NotBlank(message = "会话ID不能为空")
+    @ApiModelProperty(value = "会话ID", example = "10")
+    private String id;
+
+
+    @NotBlank(message = "回答不能为空")
+    @ApiModelProperty(value = "回答", example = "10")
+    private String reqContext;
+
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkDto.java b/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkDto.java
new file mode 100644
index 0000000..761c995
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkDto.java
@@ -0,0 +1,21 @@
+package cc.mrbird.febs.ai.req.memberTalk;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author Administrator
+ */
+@Data
+@ApiModel(value = "ApiMemberTalkDto", description = "参数")
+public class ApiMemberTalkDto {
+
+
+    @NotBlank(message = "ID不能为空")
+    @ApiModelProperty(value = "产品ID", example = "10")
+    private String id;
+
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/res/ai/AiResponse.java b/src/main/java/cc/mrbird/febs/ai/res/ai/AiResponse.java
new file mode 100644
index 0000000..14cf671
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/res/ai/AiResponse.java
@@ -0,0 +1,16 @@
+package cc.mrbird.febs.ai.res.ai;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * @author Administrator
+ */
+@Data
+@ApiModel(value = "AiResponse", description = "参数")
+public class AiResponse {
+
+    private String code;
+    private String description;
+    private String resContext;
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/res/memberTalk/ApiMemberTalkVo.java b/src/main/java/cc/mrbird/febs/ai/res/memberTalk/ApiMemberTalkVo.java
new file mode 100644
index 0000000..a93dd7d
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/res/memberTalk/ApiMemberTalkVo.java
@@ -0,0 +1,35 @@
+package cc.mrbird.febs.ai.res.memberTalk;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author Administrator
+ */
+@Data
+@ApiModel(value = "ApiMemberTalkVo", description = "参数")
+public class ApiMemberTalkVo {
+
+    /**
+     * 用户对话ID (UUID)
+     */
+
+    @ApiModelProperty(value = "会话ID")
+    private String memberTalkId;
+
+    /**
+     * 类型 1-AI提问 2-用户回答 3-AI分析结果
+     */
+
+    @ApiModelProperty(value = "类型 1-AI提问 2-用户回答 3-AI分析结果")
+    private Integer type;
+
+    /**
+     * 内容
+     */
+
+    @ApiModelProperty(value = "内容")
+    private String context;
+
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java b/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java
index 9e23d1a..c3a151e 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java
@@ -1,7 +1,10 @@
 package cc.mrbird.febs.ai.service;
 
 import cc.mrbird.febs.ai.entity.AiMemberTalkItem;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -13,4 +16,7 @@
 public interface AiMemberTalkItemService extends IService<AiMemberTalkItem> {
 
 
+    void add(String memberUuid, String id, int type, String resContext, Date createdTime);
+
+    AiMemberTalkItem getByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery);
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java b/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java
index 4ad489a..1101850 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java
@@ -1,8 +1,13 @@
 package cc.mrbird.febs.ai.service;
 
 import cc.mrbird.febs.ai.entity.AiMemberTalk;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkAnswerDto;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkDto;
+import cc.mrbird.febs.common.entity.FebsResponse;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.IService;
-import java.util.List;
+
+import java.util.Date;
 
 /**
  * AI用户对话训练记录 Service接口
@@ -13,4 +18,15 @@
 public interface AiMemberTalkService extends IService<AiMemberTalk> {
 
 
+    AiMemberTalk getById(String id);
+
+    FebsResponse start(ApiMemberTalkDto dto);
+
+    AiMemberTalk getByQuery(LambdaQueryWrapper<AiMemberTalk> query);
+
+    void updateTimeUpdate(Date nowTime, String id);
+
+    FebsResponse answer(ApiMemberTalkAnswerDto dto);
+
+    AiMemberTalk add(String memberUuid, String productId, Date nowTime);
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java b/src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java
index 40a8602..e3cdaf0 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java
@@ -1,10 +1,15 @@
 package cc.mrbird.febs.ai.service;
 
+import cc.mrbird.febs.ai.entity.AiMemberTalk;
 import cc.mrbird.febs.ai.entity.AiProductRoleLink;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.IService;
 
 /**
  * @author Administrator
  */
 public interface AiProductRoleLinkService extends IService<AiProductRoleLink> {
+
+    AiProductRoleLink getByQuery(LambdaQueryWrapper<AiProductRoleLink> query);
+
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiService.java b/src/main/java/cc/mrbird/febs/ai/service/AiService.java
new file mode 100644
index 0000000..116094d
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiService.java
@@ -0,0 +1,14 @@
+package cc.mrbird.febs.ai.service;
+
+import cc.mrbird.febs.ai.res.ai.AiResponse;
+
+/**
+ * @author Administrator
+ */
+public interface AiService {
+
+
+    AiResponse start(String productRoleId, String content);
+
+    AiResponse question(String promptTemplate,String linkId,String content);
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java
index fe9f1ab..c3dc6d5 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java
@@ -3,6 +3,7 @@
 import cc.mrbird.febs.ai.entity.AiMemberTalkItem;
 import cc.mrbird.febs.ai.mapper.AiMemberTalkItemMapper;
 import cc.mrbird.febs.ai.service.AiMemberTalkItemService;
+import cc.mrbird.febs.ai.utils.UUID;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
@@ -10,6 +11,7 @@
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -26,4 +28,20 @@
     private final AiMemberTalkItemMapper aiMemberTalkItemMapper;
 
 
+    @Override
+    public void add(String memberUuid, String id, int type, String resContext,Date createdTime) {
+        AiMemberTalkItem aiMemberTalkItem = new AiMemberTalkItem();
+        aiMemberTalkItem.setId(UUID.getSimpleUUIDString());
+        aiMemberTalkItem.setCreatedTime(createdTime);
+        aiMemberTalkItem.setMemberId(memberUuid);
+        aiMemberTalkItem.setMemberTalkId(id);
+        aiMemberTalkItem.setType(type);
+        aiMemberTalkItem.setContext(resContext);
+        aiMemberTalkItemMapper.insert(aiMemberTalkItem);
+    }
+
+    @Override
+    public AiMemberTalkItem getByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery) {
+        return aiMemberTalkItemMapper.selectOne(memberTalkItemQuery);
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java
index 2008dae..ddec2bb 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java
@@ -1,16 +1,30 @@
 package cc.mrbird.febs.ai.service.impl;
 
 import cc.mrbird.febs.ai.entity.AiMemberTalk;
+import cc.mrbird.febs.ai.entity.AiMemberTalkItem;
+import cc.mrbird.febs.ai.entity.AiProductRoleLink;
 import cc.mrbird.febs.ai.mapper.AiMemberTalkMapper;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkAnswerDto;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkDto;
+import cc.mrbird.febs.ai.res.ai.AiResponse;
+import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkVo;
+import cc.mrbird.febs.ai.service.AiMemberTalkItemService;
 import cc.mrbird.febs.ai.service.AiMemberTalkService;
+import cc.mrbird.febs.ai.service.AiProductRoleLinkService;
+import cc.mrbird.febs.ai.service.AiService;
+import cc.mrbird.febs.ai.utils.UUID;
+import cc.mrbird.febs.common.entity.FebsResponse;
+import cc.mrbird.febs.common.utils.LoginUserUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
-import java.util.List;
+import java.util.Date;
 
 /**
  * AI用户对话训练记录 Service实现类
@@ -24,6 +38,125 @@
 public class AiMemberTalkServiceImpl extends ServiceImpl<AiMemberTalkMapper, AiMemberTalk> implements AiMemberTalkService {
 
     private final AiMemberTalkMapper aiMemberTalkMapper;
+    private final AiProductRoleLinkService aiProductRoleLinkService;
+    private final AiMemberTalkItemService aiMemberTalkItemService;
+    private final AiService aiService;
 
 
+    @Override
+    public AiMemberTalk getById(String id) {
+        return aiMemberTalkMapper.selectById( id);
+    }
+
+    @Override
+    public FebsResponse start(ApiMemberTalkDto dto) {
+
+        String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid();
+        String productId = dto.getId();
+
+        LambdaQueryWrapper<AiProductRoleLink> productLinkQuery = Wrappers.lambdaQuery(AiProductRoleLink.class);
+        productLinkQuery.eq(AiProductRoleLink::getProductId,productId);
+        productLinkQuery.last("limit 1");
+        AiProductRoleLink aiProductRoleLink = aiProductRoleLinkService.getByQuery(productLinkQuery);
+        if(ObjectUtil.isNull(aiProductRoleLink)){
+            throw new RuntimeException("产品AI陪练不存在");
+        }
+
+        Date nowTime = new Date();
+        LambdaQueryWrapper<AiMemberTalk> query = Wrappers.lambdaQuery(AiMemberTalk.class);
+        query.eq(AiMemberTalk::getMemberId,memberUuid);
+        query.eq(AiMemberTalk::getProductId,productId);
+        query.last("limit 1");
+        AiMemberTalk aiMemberTalk = this.getByQuery(query);
+        if (ObjectUtil.isNull(aiMemberTalk)){
+            aiMemberTalk = this.add(memberUuid,productId,nowTime);
+        }
+
+        AiResponse aiResponse = aiService.start(aiProductRoleLink.getProductRoleId(),"开始出题");
+        if(aiResponse.getCode().equals("200")){
+            aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),1,aiResponse.getResContext(),nowTime);
+            this.updateTimeUpdate(nowTime,aiMemberTalk.getId());
+        }else{
+            throw new RuntimeException(aiResponse.getDescription());
+        }
+        ApiMemberTalkVo apiMemberTalkVo = new ApiMemberTalkVo();
+        apiMemberTalkVo.setMemberTalkId(aiMemberTalk.getId());
+        apiMemberTalkVo.setType(1);
+        apiMemberTalkVo.setContext(aiResponse.getResContext());
+
+        return new FebsResponse().success().data(apiMemberTalkVo);
+    }
+
+    @Override
+    public AiMemberTalk getByQuery(LambdaQueryWrapper<AiMemberTalk> query) {
+        return aiMemberTalkMapper.selectOne( query);
+    }
+
+    @Override
+    public void updateTimeUpdate(Date nowTime, String id) {
+        aiMemberTalkMapper.update(
+                null,
+                Wrappers.lambdaUpdate(AiMemberTalk.class)
+                .set(AiMemberTalk::getUpdatedTime,nowTime)
+                .eq(AiMemberTalk::getId,id));
+    }
+
+
+    public static final String ANSWER_FORMAT = "{}/n回答:{}/n请根据回答给出以下四个方面的总结,这个四个方面分别是亮点、建议、参考答案和核心知识点回顾。重点:四个方面的总结都是必须要有内容。";
+    @Override
+    public FebsResponse answer(ApiMemberTalkAnswerDto dto) {
+        String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid();
+        String memberTalkId = dto.getId();
+        AiMemberTalk aiMemberTalk = this.getById(memberTalkId);
+        if (ObjectUtil.isNull(aiMemberTalk)){
+            throw new RuntimeException("产品AI陪练对话不存在");
+        }
+
+        LambdaQueryWrapper<AiProductRoleLink> productLinkQuery = Wrappers.lambdaQuery(AiProductRoleLink.class);
+        productLinkQuery.eq(AiProductRoleLink::getProductId,aiMemberTalk.getProductId());
+        productLinkQuery.last("limit 1");
+        AiProductRoleLink aiProductRoleLink = aiProductRoleLinkService.getByQuery(productLinkQuery);
+        if(ObjectUtil.isNull(aiProductRoleLink)){
+            throw new RuntimeException("产品AI陪练不存在");
+        }
+
+        String reqContext = dto.getReqContext();
+
+        LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery = Wrappers.lambdaQuery(AiMemberTalkItem.class);
+        memberTalkItemQuery.eq(AiMemberTalkItem::getMemberId,memberUuid);
+        memberTalkItemQuery.eq(AiMemberTalkItem::getMemberTalkId,memberTalkId);
+        memberTalkItemQuery.eq(AiMemberTalkItem::getType,1);
+        memberTalkItemQuery.orderByDesc(AiMemberTalkItem::getCreatedTime);
+        memberTalkItemQuery.last("limit 1");
+        AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getByQuery(memberTalkItemQuery);
+        aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),2,reqContext,new Date());
+
+        String format = StrUtil.format(ANSWER_FORMAT, aiMemberTalkItem.getContext(), reqContext);
+        log.info("format:{}",format);
+        AiResponse aiResponse = aiService.start(aiProductRoleLink.getProductRoleId(), format);
+        if(aiResponse.getCode().equals("200")){
+            Date nowTime = new Date();
+            aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),3,aiResponse.getResContext(),nowTime);
+            this.updateTimeUpdate(nowTime,aiMemberTalk.getId());
+        }else{
+            throw new RuntimeException(aiResponse.getDescription());
+        }
+        ApiMemberTalkVo apiMemberTalkVo = new ApiMemberTalkVo();
+        apiMemberTalkVo.setMemberTalkId(aiMemberTalk.getId());
+        apiMemberTalkVo.setType(1);
+        apiMemberTalkVo.setContext(aiResponse.getResContext());
+
+        return new FebsResponse().success().data(apiMemberTalkVo);
+    }
+
+    @Override
+    public AiMemberTalk add(String memberUuid, String productId, Date nowTime) {
+        AiMemberTalk aiMemberTalk = new AiMemberTalk();
+        aiMemberTalk.setId(UUID.getSimpleUUIDString());
+        aiMemberTalk.setCreatedTime(nowTime);
+        aiMemberTalk.setMemberId(memberUuid);
+        aiMemberTalk.setProductId(productId);
+        aiMemberTalkMapper.insert(aiMemberTalk);
+        return aiMemberTalk;
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java
index 680f6c0..0568bb7 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java
@@ -1,8 +1,10 @@
 package cc.mrbird.febs.ai.service.impl;
 
+import cc.mrbird.febs.ai.entity.AiMemberTalk;
 import cc.mrbird.febs.ai.entity.AiProductRoleLink;
 import cc.mrbird.febs.ai.mapper.AiProductRoleLinkMapper;
 import cc.mrbird.febs.ai.service.AiProductRoleLinkService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -15,4 +17,10 @@
 @Service
 @RequiredArgsConstructor
 public class AiProductRoleLinkServiceImpl extends ServiceImpl<AiProductRoleLinkMapper, AiProductRoleLink> implements AiProductRoleLinkService {
+
+    private final AiProductRoleLinkMapper aiProductRoleLinkMapper;
+    @Override
+    public AiProductRoleLink getByQuery(LambdaQueryWrapper<AiProductRoleLink> query) {
+        return aiProductRoleLinkMapper.selectOne( query);
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiServiceImpl.java
new file mode 100644
index 0000000..0ef2ae9
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiServiceImpl.java
@@ -0,0 +1,147 @@
+package cc.mrbird.febs.ai.service.impl;
+
+import cc.mrbird.febs.ai.entity.AiProductRole;
+import cc.mrbird.febs.ai.res.ai.AiResponse;
+import cc.mrbird.febs.ai.service.AiProductRoleService;
+import cc.mrbird.febs.ai.service.AiService;
+import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionChoice;
+import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionRequest;
+import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
+import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
+import com.volcengine.ark.runtime.service.ArkService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.ConnectionPool;
+import okhttp3.Dispatcher;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class AiServiceImpl implements AiService {
+
+    private static final String CODE_SUCCESS = "200";
+    private static final String CODE_NOT_FOUND = "201";
+    private static final String CODE_ERROR = "500";
+
+    private final AiProductRoleService aiProductRoleService;
+
+    @Value("${ai.service.ak}")
+    private String ak;
+
+    @Value("${ai.service.sk}")
+    private String sk;
+
+    @Value("${ai.service.base-url}")
+    private String baseUrl;
+
+    private ArkService service;
+
+    @PostConstruct
+    public void init() {
+        ConnectionPool connectionPool = new ConnectionPool(10, 30, TimeUnit.SECONDS);
+        Dispatcher dispatcher = new Dispatcher();
+        this.service = ArkService.builder()
+                .dispatcher(dispatcher)
+                .connectionPool(connectionPool)
+                .baseUrl(baseUrl)
+                .ak(ak)
+                .sk(sk)
+                .build();
+    }
+
+    @PreDestroy
+    public void destroy() {
+        if (service != null) {
+            service.shutdownExecutor();
+        }
+    }
+
+    @Override
+    public AiResponse start(String productRoleId, String content) {
+        if (!StringUtils.hasText(productRoleId)) {
+            log.warn("productRoleId 不能为空");
+            return buildErrorResponse(CODE_NOT_FOUND, "AI陪练不存在");
+        }
+
+        AiProductRole aiProductRole = aiProductRoleService.getById(productRoleId);
+        if (aiProductRole == null) {
+            log.warn("未找到对应的角色配置,productRoleId: {}", productRoleId);
+            return buildErrorResponse(CODE_NOT_FOUND, "AI陪练不存在");
+        }
+
+        String promptTemplate = aiProductRole.getPromptTemplate();
+        String linkId = aiProductRole.getLinkId();
+
+        if (!StringUtils.hasText(promptTemplate) || !StringUtils.hasText(linkId)) {
+            log.warn("角色配置不完整,promptTemplate 或 linkId 为空,productRoleId: {}", productRoleId);
+            return buildErrorResponse(CODE_ERROR, "角色配置不完整");
+        }
+
+        return question(promptTemplate, linkId, content);
+    }
+
+    @Override
+    public AiResponse question(String promptTemplate, String linkId, String content) {
+        if (!StringUtils.hasText(promptTemplate) || !StringUtils.hasText(linkId) || !StringUtils.hasText(content)) {
+            log.warn("请求参数不完整,promptTemplate: {}, linkId: {}, content: {}", promptTemplate, linkId, content);
+            return buildErrorResponse(CODE_ERROR, "请求参数不完整");
+        }
+
+        final List<ChatMessage> messages = new ArrayList<>();
+        final ChatMessage systemMessage = ChatMessage.builder().role(ChatMessageRole.SYSTEM).content(promptTemplate).build();
+        final ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER).content(content).build();
+        messages.add(systemMessage);
+        messages.add(userMessage);
+
+        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
+                .model(linkId)
+                .messages(messages)
+                .temperature(1.0)
+                .topP(0.7)
+                .maxTokens(4096)
+                .frequencyPenalty(0.0)
+                .build();
+
+        try {
+            List<ChatCompletionChoice> choices = service.createChatCompletion(chatCompletionRequest).getChoices();
+            String result = choices.stream()
+                    .map(choice -> choice.getMessage().getContent())
+                    .filter(contentObj -> contentObj != null)
+                    .map(Object::toString)
+                    .collect(Collectors.joining());
+
+            return buildSuccessResponse(result);
+        } catch (Exception e) {
+            log.error("调用AI服务失败,modelId: {}, content: {}", linkId, content, e);
+            return buildErrorResponse(CODE_ERROR, "AI服务调用失败");
+        }
+    }
+
+    private AiResponse buildErrorResponse(String code, String description) {
+        AiResponse response = new AiResponse();
+        response.setCode(code);
+        response.setDescription(description);
+        return response;
+    }
+
+    private AiResponse buildSuccessResponse(String result) {
+        AiResponse response = new AiResponse();
+        response.setCode(CODE_SUCCESS);
+        response.setDescription("成功");
+        response.setResContext(result);
+        return response;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/controller/HSController.java b/src/main/java/cc/mrbird/febs/mall/controller/HSController.java
index 638717a..95235d0 100644
--- a/src/main/java/cc/mrbird/febs/mall/controller/HSController.java
+++ b/src/main/java/cc/mrbird/febs/mall/controller/HSController.java
@@ -18,7 +18,7 @@
     // 从环境变量中获取您的Key鉴权。此为默认方式,您可根据需要进行修改
     private static String ak = "AKLTZTQxZjMyZTUxMWJmNDEyNDkzNWExOGQ3ODllNzhhNmQ";
     private static String sk = "TmpFeE1qZ3haREExTW1JeE5HRTBZVGc1WlRRNVlqWXpORGd5TWpsak5HWQ==";
-    private static String ep_id = "ep-20250728114932-429wg";
+    private static String ep_id = "ep-20250805124033-lhxbf";
     // 此为默认路径,您可根据业务所在地域进行配置
     static String baseUrl = "https://ark.cn-beijing.volces.com/api/v3";
     static ConnectionPool connectionPool = new ConnectionPool(5, 1, TimeUnit.SECONDS);
diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml
index 0d6fbb2..7fb08b0 100644
--- a/src/main/resources/application-test.yml
+++ b/src/main/resources/application-test.yml
@@ -89,4 +89,10 @@
     path: /mnt/sdc/webresource/file/
 
 system:
-  job: false
\ No newline at end of file
+  job: false
+
+ai:
+  service:
+    ak: AKLTZTQxZjMyZTUxMWJmNDEyNDkzNWExOGQ3ODllNzhhNmQ
+    sk: TmpFeE1qZ3haREExTW1JeE5HRTBZVGc1WlRRNVlqWXpORGd5TWpsak5HWQ==
+    base-url: https://ark.cn-beijing.volces.com/api/v3
\ No newline at end of file

--
Gitblit v1.9.1