know-engine

根据不同的意图实现定制化提示词(单轮对话中版本)

在一个RAG系统中,根据用户的不同意图来定制提示词,是提升系统智能性、准确性和效率的关键。这相当于为系统装上了一个“大脑”,让它能理解用户到底想要什么,从而动态调整自己的行为。 简单来说,用户的提问千差万别,但一个固定的“检索→生成…

TL;DR

在一个RAG系统中,根据用户的不同意图来定制提示词,是提升系统智能性、准确性和效率的关键。这相当于为系统装上了一个“大脑”,让它能理解用户到底想要什么,从而动态调整自己的行为。 简单来说,用户的提问千差万别,但一个固定的“检索→生成…

在一个RAG系统中,根据用户的不同意图来定制提示词,是提升系统智能性、准确性和效率的关键。这相当于为系统装上了一个“大脑”,让它能理解用户到底想要什么,从而动态调整自己的行为。 简单来说,用户的提问千差万别,但一个固定的“检索→生成”流程无法应对所有情况。定制化提示词就是为了解决这个问题。 最最基本的就是我们根据意图识别的结果,把非客服相关的问题,理由给一个通用的LLM,让他做通用回答。 而针对客服相关的问题,我们也可以针对具体的问题分类定制提示词,这样可以让LLM更加专注和聚焦问题,比如要回答汽车的使用相关的知识,那肯定是专业性优先,而如果是回答售前问题,那肯定热情度优先。所以,我们需要针对不同的意图来做定制的提示词。 比如我们的售前咨询的提示词:

你是一位专业的汽车销售顾问。请基于以下参考资料,为有购车意向的用户提供详尽、真实的购车建议,包括车型推荐、配置对比、价格区间及购车流程等信息。
回答时语气亲切、专业,激发用户的购买兴趣,但不得夸大或捏造产品信息。
若用户询问具体订单、库存或优惠政策等需实时确认的信息,请引导用户通过正式销售渠道(如到店咨询、官网预约等)进一步了解。
若参考资料中无法找到相关信息,请引导用户通过正式销售渠道(如到店咨询、官网预约等)进一步了解。
问题:{{userMessage}}
参考资料:{{contents}}

关键约束:
严禁在回答中出现“根据参考资料”、“根据文档”、“根据您提供的信息”等字眼。
直接将上下文中的知识内化为你的知识,用自然、流畅的语气直接回答。
如果上下文中没有相关信息,请直接告知用户你暂时无法回答该具体问题,或者根据你已有的通用知识进行补充说明(视你的业务需求而定),但不要编造上下文不存在的事实。
回答风格应像是在与用户面对面交谈,而不是在引用文献。

我们的技术支持提示词:

你是一位资深汽车技术工程师。请依据以下参考资料,对用户提出的技术问题、使用问题等给出准确、严谨的解答,包括车辆系统原理、技术规格参数、故障诊断思路及操作指引等。
回答应条理清晰、术语准确,避免模糊表述。
若参考资料中无法找到相关技术信息,请直接告知用户:这个问题我暂时无法回答!
问题:{{userMessage}}
参考资料:{{contents}}

关键约束:
严禁在回答中出现“根据参考资料”、“根据文档”、“根据您提供的信息”等字眼。
直接将上下文中的知识内化为你的知识,用自然、流畅的语气直接回答。
如果上下文中没有相关信息,请直接告知用户你暂时无法回答该具体问题,不要编造上下文不存在的事实。
回答风格应像是在与用户面对面交谈,而不是在引用文献。

基于以上,我们针对不同的意图,创建不同的提示词文件:

resources
    prompts
     car-before-sales-query-prompt.txt
     car-complaints-query-prompt.txt
     car-maintenance-query-prompt.txt
     car-marketing-query-prompt.txt
     car-other-query-prompt.txt
     car-tech-support-query-prompt.txt

接着定义一个枚举,把这些意图定义出来:

package cn.hollis.llm.mentor.know.engine.ai.constant;

import cn.hollis.llm.mentor.know.engine.ai.model.IntentRecognitionResult;

public enum KnowEngineIntent {

    /**
     * 汽车售前咨询
     */
    CAR_BEFORE_SALES_QUERY("car-before-sales-query-prompt.txt"),
    /**
     * 汽车投诉查询
     */
    CAR_COMPLAINTS_QUERY("car-complaints-query-prompt.txt"),
    /**
     * 汽车保养查询
     */
    CAR_MAINTENANCE_QUERY("car-maintenance-query-prompt.txt"),
    /**
     * 汽车营销查询
     */
    CAR_MARKETING_QUERY("car-marketing-query-prompt.txt"),
    /**
     * 汽车技术支持查询
     */
    CAR_TECH_SUPPORT_QUERY("car-tech-support-query-prompt.txt"),
    /**
     * 汽车其他相关问题
     */
    CAR_OTHER_QUERY("car-other-query-prompt.txt");
    private final String fileName;

    KnowEngineIntent(String fileName) {
        this.fileName = fileName;
    }

    public String getFileName() {
        return fileName;
    }

    public static KnowEngineIntent getIntent(IntentRecognitionResult intentRecognitionResult) {
        return switch (intentRecognitionResult.intent()) {
            case "售前咨询与购买" -> CAR_BEFORE_SALES_QUERY;
            case "投诉与维权" -> CAR_COMPLAINTS_QUERY;
            case "售后维修与保养" -> CAR_MAINTENANCE_QUERY;
            case "汽车营销政策" -> CAR_MARKETING_QUERY;
            case "车辆使用与技术指导" -> CAR_TECH_SUPPORT_QUERY;
            default -> CAR_OTHER_QUERY;
        };
    }
}

每一个意图关联一个文件名,文件名就是上面我们在classpath中提前放置的提示词文件的名称。 这个枚举提供一个方法,可以把意图识别的结果IntentRecognitionResult 转成我们的KnowEngineIntent这个枚举的具体的某一个枚举项,方便后面使用。 接着,我们定义一个PormptService,这里面提供一个方法,可以根据意图获取到对应的提示词的内容:

package cn.hollis.llm.mentor.know.engine.ai.service;

import cn.hollis.llm.mentor.know.engine.ai.constant.KnowEngineIntent;
import cn.hollis.llm.mentor.know.engine.ai.model.IntentRecognitionResult;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;

import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class PromptService {
    private final Map<KnowEngineIntent, String> promptCache = new ConcurrentHashMap<>();
    private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

    /**
     * 根据意图获取提示词
     */
    public String getPrompt(KnowEngineIntent intent) {
        return promptCache.computeIfAbsent(intent, this::loadPromptFromFile);
    }

    /**
     * 根据意图获取提示词
     */
    public String getPrompt(IntentRecognitionResult intent) {
        return promptCache.computeIfAbsent(KnowEngineIntent.getIntent(intent), this::loadPromptFromFile);
    }

    /**
     * 从文件加载提示词(带缓存)
     */
    private String loadPromptFromFile(KnowEngineIntent intent) {
        try {
            Resource resource = resolver.getResource("classpath:/prompts/" + intent.getFileName());
            return FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8));
        } catch (IOException e) {
            // 如果指定意图的文件不存在,返回默认提示词
            if (intent != KnowEngineIntent.CAR_OTHER_QUERY) {
                return getPrompt(KnowEngineIntent.CAR_OTHER_QUERY);
            }
            throw new RuntimeException("默认提示词文件缺失", e);
        }
    }
}

然后我们只需要在需要提示词的地方(意图识别后),调用getPrompt方法就能拿到对应的提示词了。 然后我们把这个提示词定义到ContentInjector中,用于提示词和文档的拼接:

ContentInjector contentInjector = DefaultContentInjector.builder()
        .promptTemplate(new PromptTemplate(promptService.getPrompt(intentRecognitionResult)
))
        .build();

需要注意的是,默认的提示词中,支持的占位符是{{userMessage}}和{{contents}} 所以我们自定义的提示词,也需要用这两个。不能换成其他的。 接着可以通过一个测试的controller做测试:

/**
 * 用于ai的各个模块的功能测试
 */
@RestController
@RequestMapping("/ai/module")
public class RagModuleController {


    @Autowired
    private ChatModel chatModel;

    @Autowired
    private PromptService promptService;


    @GetMapping("testPromptRouter")
    public String testPromptRouter(String question) {
        IntentRecognitionResult intentRecognitionResult = AiServices.builder(IntentRecognitionService.class).chatModel(chatModel).build().chat(question);
        return promptService.getPrompt(intentRecognitionResult);
    }
}

测试结果:

版本提示

模型、框架与接口会持续变化。涉及版本号、参数与生产配置时,请在实践前对照对应官方文档。

LLMentor系统化学习大模型应用工程

内容来自个人课程知识库备份,并经过结构化整理。技术版本持续演进,生产使用前请结合官方文档验证。