AI大模型在个性化商品推荐与智能导购助手中的技术落地

又见面了,我是高佣返利省赚客APP研发者微赚!

在流量红利见顶的今天,淘客返利APP的竞争已从“价格战”转向“体验战”。传统的基于协同过滤或规则引擎的推荐系统,往往只能做到“千人一面”或简单的“猜你喜欢”,无法理解用户复杂的自然语言需求,更难以提供有温度的购物建议。省赚客APP研发团队近期引入了LLM(大语言模型)技术,重构了核心推荐链路,打造了能够理解上下文、具备推理能力的智能导购助手。本文将深入技术细节,分享如何通过RAG(检索增强生成)、向量数据库及Prompt工程,将大模型能力无缝集成到Java后端架构中。

构建基于RAG的商品知识增强检索

大模型存在“幻觉”问题,且缺乏实时的商品库存、价格及佣金数据。我们采用RAG架构,将省赚客海量的商品库、历史订单及用户画像向量化存储。当用户提问时,系统先检索相关上下文,再将其作为提示词的一部分喂给大模型,确保回答的准确性与时效性。

package juwatech.cn.provinceearn.ai.retrieval;

import juwatech.cn.provinceearn.ai.dto.VectorQueryRequest;
import juwatech.cn.provinceearn.ai.entity.ProductEmbedding;
import juwatech.cn.provinceearn.ai.repository.ProductVectorRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 商品知识检索服务
 * 利用向量数据库实现语义搜索,为大模型提供精准上下文
 * 
 * @author juwatech.cn
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductRetrievalService {

    private final VectorStore vectorStore;
    private final ProductVectorRepository productVectorRepository;

    /**
     * 执行语义检索
     * 将用户自然语言查询转化为向量,检索Top-K相关商品
     * @param query 用户查询文本,如“适合送老人的低糖食品”
     * @param topK 返回结果数量
     * @return 相关的商品文档片段
     */
    public List<String> retrieveRelevantProducts(String query, int topK) {
        log.info("Retrieving products for query: {}", query);
        
        // 构建搜索请求,设置相似度阈值
        SearchRequest searchRequest = SearchRequest.query(query)
                .withTopK(topK)
                .withSimilarityThreshold(0.75);

        // 执行向量搜索
        List<org.springframework.ai.vectorstore.Document> documents = vectorStore.similaritySearch(searchRequest);

        return documents.stream()
                .map(doc -> {
                    // 提取关键信息:商品名、价格、佣金率、卖点
                    String title = doc.getMetadata().getOrDefault("title", "").toString();
                    String price = doc.getMetadata().getOrDefault("price", "").toString();
                    String commission = doc.getMetadata().getOrDefault("commissionRate", "").toString();
                    String features = doc.getContent(); // 商品详细描述
                    
                    return String.format("商品:%s, 价格:%s元, 佣金:%s%%, 特点:%s", 
                            title, price, commission, features);
                })
                .collect(Collectors.toList());
    }

    /**
     * 混合检索策略:结合关键词匹配与向量语义
     * 解决纯向量检索在特定型号搜索上精度不足的问题
     */
    public List<ProductEmbedding> hybridSearch(String keyword, String semanticQuery) {
        // 1. ES关键词检索
        List<ProductEmbedding> keywordResults = productVectorRepository.findByTitleContaining(keyword);
        // 2. 向量语义检索 (略,调用上述vectorStore)
        // 3. 重排序 (Rerank) 逻辑融合
        return keywordResults; 
    }
}

智能导购助手的Prompt工程与流式响应

为了让AI像真人导购一样交流,我们设计了结构化的System Prompt,注入角色设定、回复约束及检索到的商品上下文。同时,为了提升用户体验,后端采用Server-Sent Events (SSE) 实现打字机效果的流式输出,避免用户长时间等待。

package juwatech.cn.provinceearn.ai.service;

import juwatech.cn.provinceearn.ai.retrieval.ProductRetrievalService;
import juwatech.cn.provinceearn.ai.dto.ChatResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.util.List;

/**
 * 智能导购对话服务
 * 整合RAG上下文与大模型推理能力,提供流式对话体验
 * 
 * @author juwatech.cn
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AiShoppingAssistantService {

    private final ChatClient chatClient;
    private final ProductRetrievalService retrievalService;

    private static final String SYSTEM_PROMPT = """
            你是一名专业的省赚客购物顾问,擅长根据用户需求推荐高性价比商品。
            请遵循以下规则:
            1. 必须基于提供的【参考商品列表】进行推荐,严禁编造不存在的商品或价格。
            2. 语气亲切自然,突出商品的优惠力度和返利金额。
            3. 如果用户未提供具体预算,主动询问。
            4. 输出格式:先简短分析需求,再列出推荐商品(含名称、原价、券后价、预估返利),最后给出购买建议。
            
            【参考商品列表】:
            {context}
            """;

    /**
     * 处理用户对话请求并返回流式响应
     */
    public SseEmitter chatStream(String userId, String userQuery) {
        SseEmitter emitter = new SseEmitter(60_000L); // 60秒超时

        // 异步处理,避免阻塞Web容器线程
        CompletableFuture.runAsync(() -> {
            try {
                // 1. 检索相关商品上下文
                List<String> contextDocs = retrievalService.retrieveRelevantProducts(userQuery, 5);
                String context = String.join("\n", contextDocs);
                
                if (context.isEmpty()) {
                    context = "暂无完全匹配的商品,请尝试推荐同类热门商品。";
                }

                // 2. 构建完整Prompt
                String fullPrompt = SYSTEM_PROMPT.replace("{context}", context);
                
                // 3. 调用大模型获取流式响应
                Flux<ChatResponse> responseFlux = chatClient.prompt()
                        .system(fullPrompt)
                        .user(userQuery)
                        .stream()
                        .content();

                responseFlux.doOnNext(chunk -> {
                    try {
                        // 发送SSE数据块
                        emitter.emit(SseEmitter.event()
                                .name("message")
                                .data(chunk, MediaType.TEXT_PLAIN), SseEmitter.SseEventType.EVENT);
                    } catch (Exception e) {
                        log.error("SSE emit error", e);
                        emitter.completeWithError(e);
                    }
                })
                .doOnComplete(emitter::complete)
                .doOnError(emitter::completeWithError)
                .subscribe();

            } catch (Exception e) {
                log.error("Chat processing failed", e);
                emitter.completeWithError(e);
            }
        });

        return emitter;
    }
}

用户画像的动态更新与反馈闭环

大模型不仅是输出端,更是数据采集器。我们将用户的对话记录、点击行为实时反馈给推荐系统,利用大模型提取用户隐式偏好(如“对价格敏感”、“偏好国货”),动态更新用户画像标签,形成“交互-学习-优化”的闭环。

package juwatech.cn.provinceearn.ai.analytics;

import juwatech.cn.provinceearn.ai.dto.UserInteractionLog;
import juwatech.cn.provinceearn.user.service.UserProfileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 用户偏好分析组件
 * 利用LLM从对话日志中提取结构化标签
 * 
 * @author juwatech.cn
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class UserPreferenceExtractor {

    private final ChatClient chatClient;
    private final UserProfileService userProfileService;

    /**
     * 分析对话日志,提取用户兴趣标签
     */
    public void analyzeAndUpdateProfile(String userId, String conversationHistory) {
        String extractionPrompt = """
                分析以下用户对话历史,提取用户的购物偏好标签。
                输出严格的JSON格式:{"tags": ["标签1", "标签2"], "price_sensitivity": "high/medium/low", "preferred_categories": ["类目1"]}
                
                对话历史:
                %s
                """.formatted(conversationHistory);

        String jsonResult = chatClient.prompt(extractionPrompt)
                .call()
                .content();

        try {
            // 解析JSON并调用用户服务更新画像
            // Map<String, Object> preferences = JsonUtil.parse(jsonResult);
            // userProfileService.updateTags(userId, preferences);
            log.info("Profile updated for user {}: {}", userId, jsonResult);
        } catch (Exception e) {
            log.warn("Failed to parse LLM output for profile update", e);
        }
    }
}

结语

通过引入RAG架构、流式对话接口及智能偏好分析,省赚客APP成功将大模型技术转化为实实在在的生产力。这不仅大幅提升了用户的搜索转化率和留存时长,更让冷冰冰的商品列表变成了有温度的购物顾问。未来,我们将继续探索多模态大模型在视频导购场景的应用,持续引领行业技术变革。

本文著作权归 省赚客app 研发团队,转载请注明出处!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐