4.1 提示词工程基础

4.1.1 提示词的重要性

提示词工程是AI应用开发中的核心技能,直接影响AI模型的输出质量。Spring AI提供了强大的提示词管理和模板系统。

提示词设计原则: 1. 明确性:指令清晰、具体 2. 上下文:提供充分的背景信息 3. 结构化:使用格式化的输入 4. 示例驱动:提供few-shot示例 5. 约束条件:明确输出格式和限制

4.1.2 Spring AI提示词架构

// Prompt类层次结构
public class Prompt {
    private final List<Message> instructions;
    private final ChatOptions chatOptions;
    
    public Prompt(String text) {
        this(List.of(new UserMessage(text)));
    }
    
    public Prompt(List<Message> instructions) {
        this(instructions, null);
    }
    
    public Prompt(List<Message> instructions, ChatOptions chatOptions) {
        this.instructions = instructions;
        this.chatOptions = chatOptions;
    }
}

// 消息类型
public abstract class Message {
    protected final String content;
    protected final Map<String, Object> properties;
}

public class SystemMessage extends Message {
    public SystemMessage(String content) {
        super(content);
    }
}

public class UserMessage extends Message {
    public UserMessage(String content) {
        super(content);
    }
}

public class AssistantMessage extends Message {
    public AssistantMessage(String content) {
        super(content);
    }
}

4.2 提示词模板系统

4.2.1 基础模板使用

// PromptTemplateService.java
package com.example.springai.service;

import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class PromptTemplateService {
    
    /**
     * 基础字符串模板
     */
    public String createBasicPrompt(String userInput) {
        String template = """
            你是一个专业的AI助手。请根据以下用户输入提供帮助:
            
            用户输入:{input}
            
            请提供详细、准确的回答。
            """;
        
        PromptTemplate promptTemplate = new PromptTemplate(template);
        return promptTemplate.create(Map.of("input", userInput)).getContents();
    }
    
    /**
     * 系统消息模板
     */
    public String createSystemPrompt(String role, String task, String context) {
        String template = """
            你是一个{role}。你的任务是{task}。
            
            背景信息:
            {context}
            
            请按照以下要求回答:
            1. 保持专业性
            2. 提供具体建议
            3. 考虑实际可行性
            """;
        
        PromptTemplate promptTemplate = new PromptTemplate(template);
        Map<String, Object> variables = Map.of(
            "role", role,
            "task", task,
            "context", context
        );
        
        return promptTemplate.create(variables).getContents();
    }
    
    /**
     * 从资源文件加载模板
     */
    public String createFromResource(Resource templateResource, Map<String, Object> variables) {
        PromptTemplate promptTemplate = new PromptTemplate(templateResource);
        return promptTemplate.create(variables).getContents();
    }
    
    /**
     * 多消息模板
     */
    public String createMultiMessagePrompt(String systemRole, String userQuery) {
        SystemPromptTemplate systemTemplate = new SystemPromptTemplate(
            "你是一个{role}。请专业地回答用户问题。"
        );
        
        PromptTemplate userTemplate = new PromptTemplate(
            "用户问题:{query}\n\n请提供详细回答。"
        );
        
        String systemPrompt = systemTemplate.create(Map.of("role", systemRole)).getContents();
        String userPrompt = userTemplate.create(Map.of("query", userQuery)).getContents();
        
        return systemPrompt + "\n\n" + userPrompt;
    }
}

4.2.2 高级模板功能

// AdvancedPromptService.java
package com.example.springai.service;

import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.stereotype.Service;

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

@Service
public class AdvancedPromptService {
    
    /**
     * Few-shot学习模板
     */
    public String createFewShotPrompt(String task, List<Map<String, String>> examples, String input) {
        String template = """
            任务:{task}
            
            示例:
            {examples}
            
            现在请处理以下输入:
            输入:{input}
            输出:
            """;
        
        String examplesText = examples.stream()
            .map(example -> String.format("输入:%s\n输出:%s", 
                example.get("input"), example.get("output")))
            .collect(Collectors.joining("\n\n"));
        
        PromptTemplate promptTemplate = new PromptTemplate(template);
        Map<String, Object> variables = Map.of(
            "task", task,
            "examples", examplesText,
            "input", input
        );
        
        return promptTemplate.create(variables).getContents();
    }
    
    /**
     * 链式思维(Chain of Thought)模板
     */
    public String createChainOfThoughtPrompt(String problem) {
        String template = """
            问题:{problem}
            
            请按照以下步骤思考:
            
            步骤1:理解问题
            - 问题的核心是什么?
            - 需要什么信息?
            
            步骤2:分析方法
            - 可以使用什么方法?
            - 每种方法的优缺点?
            
            步骤3:逐步解决
            - 具体的解决步骤
            - 每一步的推理过程
            
            步骤4:验证答案
            - 答案是否合理?
            - 是否还有其他可能?
            
            最终答案:
            """;
        
        PromptTemplate promptTemplate = new PromptTemplate(template);
        return promptTemplate.create(Map.of("problem", problem)).getContents();
    }
    
    /**
     * 角色扮演模板
     */
    public String createRolePlayPrompt(String role, String scenario, String objective) {
        String template = """
            【角色设定】
            你现在是:{role}
            
            【场景描述】
            {scenario}
            
            【目标任务】
            {objective}
            
            【行为准则】
            1. 完全沉浸在角色中
            2. 使用符合角色身份的语言和思维方式
            3. 基于角色的专业知识和经验回答
            4. 保持角色的一致性
            
            现在开始扮演这个角色,准备好了吗?
            """;
        
        PromptTemplate promptTemplate = new PromptTemplate(template);
        Map<String, Object> variables = Map.of(
            "role", role,
            "scenario", scenario,
            "objective", objective
        );
        
        return promptTemplate.create(variables).getContents();
    }
    
    /**
     * 结构化输出模板
     */
    public String createStructuredOutputPrompt(String input, String outputFormat) {
        String template = """
            请分析以下内容并按照指定格式输出:
            
            输入内容:
            {input}
            
            输出格式要求:
            {format}
            
            请严格按照格式要求输出,不要添加额外的解释。
            """;
        
        PromptTemplate promptTemplate = new PromptTemplate(template);
        Map<String, Object> variables = Map.of(
            "input", input,
            "format", outputFormat
        );
        
        return promptTemplate.create(variables).getContents();
    }
    
    /**
     * 多语言模板
     */
    public String createMultiLanguagePrompt(String content, String sourceLanguage, String targetLanguage) {
        String template = """
            请将以下{sourceLanguage}内容翻译成{targetLanguage}:
            
            原文:
            {content}
            
            翻译要求:
            1. 保持原意不变
            2. 语言自然流畅
            3. 符合目标语言的表达习惯
            4. 保留专业术语的准确性
            
            译文:
            """;
        
        PromptTemplate promptTemplate = new PromptTemplate(template);
        Map<String, Object> variables = Map.of(
            "content", content,
            "sourceLanguage", sourceLanguage,
            "targetLanguage", targetLanguage
        );
        
        return promptTemplate.create(variables).getContents();
    }
}

4.3 模板资源管理

4.3.1 模板文件组织

src/main/resources/
├── prompts/
│   ├── chat/
│   │   ├── general-chat.st
│   │   ├── technical-support.st
│   │   └── creative-writing.st
│   ├── analysis/
│   │   ├── text-analysis.st
│   │   ├── sentiment-analysis.st
│   │   └── code-review.st
│   ├── generation/
│   │   ├── code-generation.st
│   │   ├── content-creation.st
│   │   └── documentation.st
│   └── system/
│       ├── system-messages.st
│       └── safety-guidelines.st

4.3.2 模板资源加载器

// PromptResourceLoader.java
package com.example.springai.service;

import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

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

@Service
public class PromptResourceLoader {
    
    private final Map<String, String> templateCache = new ConcurrentHashMap<>();
    
    /**
     * 加载模板文件
     */
    public String loadTemplate(String templatePath) {
        return templateCache.computeIfAbsent(templatePath, this::loadTemplateFromFile);
    }
    
    /**
     * 从文件加载模板
     */
    private String loadTemplateFromFile(String templatePath) {
        try {
            Resource resource = new ClassPathResource("prompts/" + templatePath);
            return resource.getContentAsString(StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new RuntimeException("无法加载模板文件: " + templatePath, e);
        }
    }
    
    /**
     * 创建模板实例
     */
    public PromptTemplate createTemplate(String templatePath) {
        String templateContent = loadTemplate(templatePath);
        return new PromptTemplate(templateContent);
    }
    
    /**
     * 创建并填充模板
     */
    public String createPrompt(String templatePath, Map<String, Object> variables) {
        PromptTemplate template = createTemplate(templatePath);
        return template.create(variables).getContents();
    }
    
    /**
     * 清除缓存
     */
    public void clearCache() {
        templateCache.clear();
    }
    
    /**
     * 预加载常用模板
     */
    public void preloadTemplates() {
        String[] commonTemplates = {
            "chat/general-chat.st",
            "analysis/text-analysis.st",
            "generation/code-generation.st",
            "system/system-messages.st"
        };
        
        for (String template : commonTemplates) {
            loadTemplate(template);
        }
    }
}

4.3.3 模板文件示例

<!-- src/main/resources/prompts/chat/general-chat.st -->
你是一个专业的AI助手,名字叫{assistantName}。

你的特点:
- 友好、耐心、专业
- 能够理解用户的需求
- 提供准确、有用的信息
- 承认不知道的事情

当前对话上下文:
{context}

用户问题:{userMessage}

请根据上下文和用户问题,提供有帮助的回答。
<!-- src/main/resources/prompts/analysis/text-analysis.st -->
请对以下文本进行{analysisType}分析:

文本内容:
{text}

分析要求:
{requirements}

请按照以下格式输出分析结果:

## 分析摘要
[简要概述]

## 详细分析
{detailedFormat}

## 结论
[主要发现和建议]
<!-- src/main/resources/prompts/generation/code-generation.st -->
请生成{language}代码来实现以下功能:

功能描述:
{description}

技术要求:
{requirements}

代码规范:
- 使用清晰的变量和函数命名
- 添加适当的注释
- 遵循{language}的最佳实践
- 包含错误处理

{#if examples}
参考示例:
{examples}
{/if}

请提供完整的代码实现:

4.4 动态提示词生成

4.4.1 上下文感知提示词

// ContextAwarePromptService.java
package com.example.springai.service;

import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

@Service
public class ContextAwarePromptService {
    
    private final PromptResourceLoader promptResourceLoader;
    
    public ContextAwarePromptService(PromptResourceLoader promptResourceLoader) {
        this.promptResourceLoader = promptResourceLoader;
    }
    
    /**
     * 基于用户历史生成个性化提示词
     */
    public String createPersonalizedPrompt(String userId, String currentQuery, List<String> chatHistory) {
        // 分析用户偏好
        UserPreference preference = analyzeUserPreference(chatHistory);
        
        Map<String, Object> variables = Map.of(
            "userId", userId,
            "currentQuery", currentQuery,
            "preferredStyle", preference.getStyle(),
            "expertiseLevel", preference.getExpertiseLevel(),
            "recentTopics", String.join(", ", preference.getRecentTopics()),
            "timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        );
        
        return promptResourceLoader.createPrompt("chat/personalized-chat.st", variables);
    }
    
    /**
     * 基于时间的动态提示词
     */
    public String createTimeAwarePrompt(String query) {
        LocalDateTime now = LocalDateTime.now();
        String timeContext = getTimeContext(now);
        
        Map<String, Object> variables = Map.of(
            "query", query,
            "timeContext", timeContext,
            "currentTime", now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
            "dayOfWeek", now.getDayOfWeek().toString()
        );
        
        return promptResourceLoader.createPrompt("chat/time-aware-chat.st", variables);
    }
    
    /**
     * 基于领域的专业提示词
     */
    public String createDomainSpecificPrompt(String domain, String query, String expertiseLevel) {
        Map<String, Object> variables = Map.of(
            "domain", domain,
            "query", query,
            "expertiseLevel", expertiseLevel,
            "domainKnowledge", getDomainKnowledge(domain),
            "terminology", getDomainTerminology(domain)
        );
        
        return promptResourceLoader.createPrompt("domain/" + domain.toLowerCase() + "-expert.st", variables);
    }
    
    /**
     * 分析用户偏好
     */
    private UserPreference analyzeUserPreference(List<String> chatHistory) {
        // 简化的偏好分析逻辑
        UserPreference preference = new UserPreference();
        
        // 分析对话风格
        long formalCount = chatHistory.stream()
            .mapToLong(msg -> countFormalWords(msg))
            .sum();
        
        preference.setStyle(formalCount > chatHistory.size() * 2 ? "formal" : "casual");
        
        // 分析专业程度
        long technicalCount = chatHistory.stream()
            .mapToLong(msg -> countTechnicalTerms(msg))
            .sum();
        
        if (technicalCount > chatHistory.size() * 3) {
            preference.setExpertiseLevel("expert");
        } else if (technicalCount > chatHistory.size()) {
            preference.setExpertiseLevel("intermediate");
        } else {
            preference.setExpertiseLevel("beginner");
        }
        
        // 提取最近话题
        preference.setRecentTopics(extractTopics(chatHistory));
        
        return preference;
    }
    
    /**
     * 获取时间上下文
     */
    private String getTimeContext(LocalDateTime dateTime) {
        int hour = dateTime.getHour();
        
        if (hour >= 6 && hour < 12) {
            return "早上好!新的一天开始了";
        } else if (hour >= 12 && hour < 18) {
            return "下午好!希望你今天过得愉快";
        } else if (hour >= 18 && hour < 22) {
            return "晚上好!辛苦了一天";
        } else {
            return "夜深了,注意休息";
        }
    }
    
    /**
     * 获取领域知识
     */
    private String getDomainKnowledge(String domain) {
        return switch (domain.toLowerCase()) {
            case "programming" -> "编程语言、算法、数据结构、软件工程";
            case "medicine" -> "医学诊断、治疗方案、药物知识、医疗程序";
            case "finance" -> "投资理论、风险管理、金融产品、市场分析";
            case "education" -> "教学方法、课程设计、学习理论、教育技术";
            default -> "通用知识和常识";
        };
    }
    
    /**
     * 获取领域术语
     */
    private String getDomainTerminology(String domain) {
        return switch (domain.toLowerCase()) {
            case "programming" -> "变量、函数、类、对象、算法、数据结构";
            case "medicine" -> "症状、诊断、治疗、药物、病理、生理";
            case "finance" -> "资产、负债、收益、风险、投资、回报";
            case "education" -> "课程、教学、学习、评估、反馈、目标";
            default -> "基础术语";
        };
    }
    
    // 辅助方法
    private long countFormalWords(String text) {
        String[] formalWords = {"请", "您", "敬请", "恳请", "谢谢", "感谢"};
        return java.util.Arrays.stream(formalWords)
            .mapToLong(word -> text.split(word, -1).length - 1)
            .sum();
    }
    
    private long countTechnicalTerms(String text) {
        String[] technicalWords = {"算法", "数据结构", "API", "框架", "架构", "设计模式"};
        return java.util.Arrays.stream(technicalWords)
            .mapToLong(word -> text.split(word, -1).length - 1)
            .sum();
    }
    
    private List<String> extractTopics(List<String> chatHistory) {
        // 简化的话题提取逻辑
        return List.of("编程", "技术", "学习");
    }
    
    /**
     * 用户偏好类
     */
    public static class UserPreference {
        private String style;
        private String expertiseLevel;
        private List<String> recentTopics;
        
        // Getters and Setters
        public String getStyle() { return style; }
        public void setStyle(String style) { this.style = style; }
        
        public String getExpertiseLevel() { return expertiseLevel; }
        public void setExpertiseLevel(String expertiseLevel) { this.expertiseLevel = expertiseLevel; }
        
        public List<String> getRecentTopics() { return recentTopics; }
        public void setRecentTopics(List<String> recentTopics) { this.recentTopics = recentTopics; }
    }
}

4.4.2 A/B测试提示词

// PromptABTestService.java
package com.example.springai.service;

import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class PromptABTestService {
    
    private final PromptResourceLoader promptResourceLoader;
    private final Random random = new Random();
    private final Map<String, ABTestMetrics> testMetrics = new ConcurrentHashMap<>();
    
    public PromptABTestService(PromptResourceLoader promptResourceLoader) {
        this.promptResourceLoader = promptResourceLoader;
    }
    
    /**
     * A/B测试提示词选择
     */
    public ABTestResult selectPromptVariant(String testName, Map<String, Object> variables) {
        ABTestConfig config = getTestConfig(testName);
        String selectedVariant = selectVariant(config);
        
        String prompt = promptResourceLoader.createPrompt(
            config.getVariantPath(selectedVariant), 
            variables
        );
        
        return new ABTestResult(testName, selectedVariant, prompt);
    }
    
    /**
     * 记录测试结果
     */
    public void recordTestResult(String testName, String variant, boolean success, double score) {
        ABTestMetrics metrics = testMetrics.computeIfAbsent(
            testName + ":" + variant, 
            k -> new ABTestMetrics()
        );
        
        metrics.recordResult(success, score);
    }
    
    /**
     * 获取测试统计
     */
    public Map<String, ABTestMetrics> getTestStatistics(String testName) {
        return testMetrics.entrySet().stream()
            .filter(entry -> entry.getKey().startsWith(testName + ":"))
            .collect(java.util.stream.Collectors.toMap(
                entry -> entry.getKey().substring(testName.length() + 1),
                Map.Entry::getValue
            ));
    }
    
    /**
     * 选择变体
     */
    private String selectVariant(ABTestConfig config) {
        double rand = random.nextDouble();
        double cumulative = 0.0;
        
        for (Map.Entry<String, Double> entry : config.getVariantWeights().entrySet()) {
            cumulative += entry.getValue();
            if (rand <= cumulative) {
                return entry.getKey();
            }
        }
        
        return config.getVariantWeights().keySet().iterator().next();
    }
    
    /**
     * 获取测试配置
     */
    private ABTestConfig getTestConfig(String testName) {
        // 这里可以从配置文件或数据库加载
        return switch (testName) {
            case "chat-style" -> new ABTestConfig(
                Map.of(
                    "formal", 0.5,
                    "casual", 0.5
                ),
                Map.of(
                    "formal", "chat/formal-chat.st",
                    "casual", "chat/casual-chat.st"
                )
            );
            case "code-generation" -> new ABTestConfig(
                Map.of(
                    "detailed", 0.4,
                    "concise", 0.4,
                    "example-driven", 0.2
                ),
                Map.of(
                    "detailed", "generation/detailed-code.st",
                    "concise", "generation/concise-code.st",
                    "example-driven", "generation/example-code.st"
                )
            );
            default -> throw new IllegalArgumentException("未知的测试: " + testName);
        };
    }
    
    /**
     * A/B测试配置
     */
    public static class ABTestConfig {
        private final Map<String, Double> variantWeights;
        private final Map<String, String> variantPaths;
        
        public ABTestConfig(Map<String, Double> variantWeights, Map<String, String> variantPaths) {
            this.variantWeights = variantWeights;
            this.variantPaths = variantPaths;
        }
        
        public Map<String, Double> getVariantWeights() { return variantWeights; }
        public String getVariantPath(String variant) { return variantPaths.get(variant); }
    }
    
    /**
     * A/B测试结果
     */
    public static class ABTestResult {
        private final String testName;
        private final String variant;
        private final String prompt;
        
        public ABTestResult(String testName, String variant, String prompt) {
            this.testName = testName;
            this.variant = variant;
            this.prompt = prompt;
        }
        
        public String getTestName() { return testName; }
        public String getVariant() { return variant; }
        public String getPrompt() { return prompt; }
    }
    
    /**
     * A/B测试指标
     */
    public static class ABTestMetrics {
        private int totalRequests = 0;
        private int successfulRequests = 0;
        private double totalScore = 0.0;
        
        public synchronized void recordResult(boolean success, double score) {
            totalRequests++;
            if (success) {
                successfulRequests++;
            }
            totalScore += score;
        }
        
        public synchronized double getSuccessRate() {
            return totalRequests == 0 ? 0.0 : (double) successfulRequests / totalRequests;
        }
        
        public synchronized double getAverageScore() {
            return totalRequests == 0 ? 0.0 : totalScore / totalRequests;
        }
        
        public synchronized int getTotalRequests() { return totalRequests; }
        public synchronized int getSuccessfulRequests() { return successfulRequests; }
    }
}

4.5 提示词优化策略

4.5.1 提示词质量评估

// PromptQualityEvaluator.java
package com.example.springai.service;

import org.springframework.ai.chat.ChatModel;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class PromptQualityEvaluator {
    
    private final ChatModel chatModel;
    
    public PromptQualityEvaluator(ChatModel chatModel) {
        this.chatModel = chatModel;
    }
    
    /**
     * 评估提示词质量
     */
    public PromptQualityScore evaluatePrompt(String promptText, List<String> testInputs) {
        double totalScore = 0.0;
        int validResponses = 0;
        
        for (String input : testInputs) {
            try {
                String fullPrompt = promptText.replace("{input}", input);
                Prompt prompt = new Prompt(fullPrompt);
                ChatResponse response = chatModel.call(prompt);
                String output = response.getResult().getOutput().getContent();
                
                double score = evaluateResponse(input, output);
                totalScore += score;
                validResponses++;
                
            } catch (Exception e) {
                // 记录错误但继续评估
                System.err.println("评估失败: " + e.getMessage());
            }
        }
        
        double averageScore = validResponses > 0 ? totalScore / validResponses : 0.0;
        return new PromptQualityScore(averageScore, validResponses, testInputs.size());
    }
    
    /**
     * 评估单个响应质量
     */
    private double evaluateResponse(String input, String output) {
        double score = 0.0;
        
        // 相关性评分(0-30分)
        score += evaluateRelevance(input, output) * 30;
        
        // 完整性评分(0-25分)
        score += evaluateCompleteness(output) * 25;
        
        // 准确性评分(0-25分)
        score += evaluateAccuracy(output) * 25;
        
        // 清晰度评分(0-20分)
        score += evaluateClarity(output) * 20;
        
        return Math.min(score, 100.0);
    }
    
    /**
     * 评估相关性
     */
    private double evaluateRelevance(String input, String output) {
        // 简化的相关性评估
        String[] inputWords = input.toLowerCase().split("\\s+");
        String outputLower = output.toLowerCase();
        
        long matchingWords = java.util.Arrays.stream(inputWords)
            .filter(word -> word.length() > 3)  // 忽略短词
            .mapToLong(word -> outputLower.contains(word) ? 1 : 0)
            .sum();
        
        return Math.min(1.0, (double) matchingWords / Math.max(1, inputWords.length));
    }
    
    /**
     * 评估完整性
     */
    private double evaluateCompleteness(String output) {
        // 基于长度和结构的完整性评估
        if (output.length() < 50) return 0.3;
        if (output.length() < 100) return 0.6;
        if (output.length() < 200) return 0.8;
        return 1.0;
    }
    
    /**
     * 评估准确性
     */
    private double evaluateAccuracy(String output) {
        // 简化的准确性评估
        // 检查是否包含常见的错误指示词
        String[] errorIndicators = {"不确定", "可能", "也许", "不知道", "无法确定"};
        
        long errorCount = java.util.Arrays.stream(errorIndicators)
            .mapToLong(indicator -> output.contains(indicator) ? 1 : 0)
            .sum();
        
        return Math.max(0.0, 1.0 - (errorCount * 0.2));
    }
    
    /**
     * 评估清晰度
     */
    private double evaluateClarity(String output) {
        // 基于句子结构和可读性的清晰度评估
        String[] sentences = output.split("[.!?]+");
        
        if (sentences.length == 0) return 0.0;
        
        double avgSentenceLength = (double) output.length() / sentences.length;
        
        // 理想句子长度在20-100字符之间
        if (avgSentenceLength >= 20 && avgSentenceLength <= 100) {
            return 1.0;
        } else if (avgSentenceLength < 20) {
            return avgSentenceLength / 20.0;
        } else {
            return Math.max(0.0, 1.0 - (avgSentenceLength - 100) / 200.0);
        }
    }
    
    /**
     * 提示词质量分数
     */
    public static class PromptQualityScore {
        private final double score;
        private final int validResponses;
        private final int totalTests;
        
        public PromptQualityScore(double score, int validResponses, int totalTests) {
            this.score = score;
            this.validResponses = validResponses;
            this.totalTests = totalTests;
        }
        
        public double getScore() { return score; }
        public int getValidResponses() { return validResponses; }
        public int getTotalTests() { return totalTests; }
        public double getSuccessRate() { return (double) validResponses / totalTests; }
        
        public String getGrade() {
            if (score >= 90) return "A";
            if (score >= 80) return "B";
            if (score >= 70) return "C";
            if (score >= 60) return "D";
            return "F";
        }
    }
}

4.5.2 提示词优化建议

// PromptOptimizer.java
package com.example.springai.service;

import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

@Service
public class PromptOptimizer {
    
    /**
     * 分析提示词并提供优化建议
     */
    public PromptOptimizationReport analyzeAndOptimize(String prompt) {
        List<OptimizationSuggestion> suggestions = new ArrayList<>();
        
        // 检查长度
        suggestions.addAll(analyzeLengthIssues(prompt));
        
        // 检查结构
        suggestions.addAll(analyzeStructureIssues(prompt));
        
        // 检查清晰度
        suggestions.addAll(analyzeClarityIssues(prompt));
        
        // 检查指令明确性
        suggestions.addAll(analyzeInstructionClarity(prompt));
        
        // 生成优化版本
        String optimizedPrompt = generateOptimizedPrompt(prompt, suggestions);
        
        return new PromptOptimizationReport(prompt, optimizedPrompt, suggestions);
    }
    
    /**
     * 分析长度问题
     */
    private List<OptimizationSuggestion> analyzeLengthIssues(String prompt) {
        List<OptimizationSuggestion> suggestions = new ArrayList<>();
        
        if (prompt.length() < 50) {
            suggestions.add(new OptimizationSuggestion(
                "LENGTH_TOO_SHORT",
                "提示词过短,可能缺乏足够的上下文信息",
                "添加更多背景信息和具体要求",
                "HIGH"
            ));
        } else if (prompt.length() > 2000) {
            suggestions.add(new OptimizationSuggestion(
                "LENGTH_TOO_LONG",
                "提示词过长,可能影响模型理解",
                "精简内容,突出核心要求",
                "MEDIUM"
            ));
        }
        
        return suggestions;
    }
    
    /**
     * 分析结构问题
     */
    private List<OptimizationSuggestion> analyzeStructureIssues(String prompt) {
        List<OptimizationSuggestion> suggestions = new ArrayList<>();
        
        // 检查是否有明确的任务描述
        if (!containsTaskDescription(prompt)) {
            suggestions.add(new OptimizationSuggestion(
                "MISSING_TASK_DESCRIPTION",
                "缺少明确的任务描述",
                "在开头添加清晰的任务说明",
                "HIGH"
            ));
        }
        
        // 检查是否有输出格式要求
        if (!containsOutputFormat(prompt)) {
            suggestions.add(new OptimizationSuggestion(
                "MISSING_OUTPUT_FORMAT",
                "缺少输出格式说明",
                "指定期望的输出格式和结构",
                "MEDIUM"
            ));
        }
        
        return suggestions;
    }
    
    /**
     * 分析清晰度问题
     */
    private List<OptimizationSuggestion> analyzeClarityIssues(String prompt) {
        List<OptimizationSuggestion> suggestions = new ArrayList<>();
        
        // 检查模糊词汇
        String[] vagueWords = {"一些", "可能", "大概", "差不多", "类似"};
        for (String word : vagueWords) {
            if (prompt.contains(word)) {
                suggestions.add(new OptimizationSuggestion(
                    "VAGUE_LANGUAGE",
                    "包含模糊词汇: " + word,
                    "使用更具体、明确的表达",
                    "MEDIUM"
                ));
                break;
            }
        }
        
        // 检查句子长度
        String[] sentences = prompt.split("[.!?]+");
        for (String sentence : sentences) {
            if (sentence.trim().length() > 150) {
                suggestions.add(new OptimizationSuggestion(
                    "LONG_SENTENCES",
                    "存在过长的句子",
                    "将长句拆分为多个短句",
                    "LOW"
                ));
                break;
            }
        }
        
        return suggestions;
    }
    
    /**
     * 分析指令明确性
     */
    private List<OptimizationSuggestion> analyzeInstructionClarity(String prompt) {
        List<OptimizationSuggestion> suggestions = new ArrayList<>();
        
        // 检查是否包含动作词
        String[] actionWords = {"分析", "生成", "创建", "解释", "总结", "比较", "评估"};
        boolean hasActionWord = java.util.Arrays.stream(actionWords)
            .anyMatch(prompt::contains);
        
        if (!hasActionWord) {
            suggestions.add(new OptimizationSuggestion(
                "MISSING_ACTION_WORDS",
                "缺少明确的动作指令",
                "使用具体的动作词(如:分析、生成、解释等)",
                "HIGH"
            ));
        }
        
        return suggestions;
    }
    
    /**
     * 生成优化后的提示词
     */
    private String generateOptimizedPrompt(String originalPrompt, List<OptimizationSuggestion> suggestions) {
        StringBuilder optimized = new StringBuilder();
        
        // 添加结构化开头
        optimized.append("## 任务描述\n");
        
        // 如果原提示词缺少任务描述,添加一个
        boolean needsTaskDescription = suggestions.stream()
            .anyMatch(s -> "MISSING_TASK_DESCRIPTION".equals(s.getType()));
        
        if (needsTaskDescription) {
            optimized.append("请根据以下要求完成任务:\n\n");
        }
        
        // 添加原始内容(可能经过修改)
        String processedContent = originalPrompt;
        
        // 应用一些基本优化
        processedContent = processedContent.replaceAll("一些", "具体的");
        processedContent = processedContent.replaceAll("可能", "应该");
        
        optimized.append(processedContent);
        
        // 如果缺少输出格式,添加一个
        boolean needsOutputFormat = suggestions.stream()
            .anyMatch(s -> "MISSING_OUTPUT_FORMAT".equals(s.getType()));
        
        if (needsOutputFormat) {
            optimized.append("\n\n## 输出要求\n");
            optimized.append("请按照以下格式输出结果:\n");
            optimized.append("1. 简要概述\n");
            optimized.append("2. 详细内容\n");
            optimized.append("3. 总结建议\n");
        }
        
        return optimized.toString();
    }
    
    // 辅助方法
    private boolean containsTaskDescription(String prompt) {
        String[] taskIndicators = {"任务", "要求", "请", "需要", "目标"};
        return java.util.Arrays.stream(taskIndicators)
            .anyMatch(prompt::contains);
    }
    
    private boolean containsOutputFormat(String prompt) {
        String[] formatIndicators = {"格式", "输出", "结果", "返回", "显示"};
        return java.util.Arrays.stream(formatIndicators)
            .anyMatch(prompt::contains);
    }
    
    /**
     * 优化建议
     */
    public static class OptimizationSuggestion {
        private final String type;
        private final String description;
        private final String recommendation;
        private final String priority;
        
        public OptimizationSuggestion(String type, String description, String recommendation, String priority) {
            this.type = type;
            this.description = description;
            this.recommendation = recommendation;
            this.priority = priority;
        }
        
        // Getters
        public String getType() { return type; }
        public String getDescription() { return description; }
        public String getRecommendation() { return recommendation; }
        public String getPriority() { return priority; }
    }
    
    /**
     * 优化报告
     */
    public static class PromptOptimizationReport {
        private final String originalPrompt;
        private final String optimizedPrompt;
        private final List<OptimizationSuggestion> suggestions;
        
        public PromptOptimizationReport(String originalPrompt, String optimizedPrompt, List<OptimizationSuggestion> suggestions) {
            this.originalPrompt = originalPrompt;
            this.optimizedPrompt = optimizedPrompt;
            this.suggestions = suggestions;
        }
        
        // Getters
        public String getOriginalPrompt() { return originalPrompt; }
        public String getOptimizedPrompt() { return optimizedPrompt; }
        public List<OptimizationSuggestion> getSuggestions() { return suggestions; }
        
        public int getHighPrioritySuggestions() {
            return (int) suggestions.stream()
                .filter(s -> "HIGH".equals(s.getPriority()))
                .count();
        }
    }
}

4.6 提示词管理控制器

4.6.1 提示词API

// PromptController.java
package com.example.springai.controller;

import com.example.springai.service.*;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/prompts")
public class PromptController {
    
    private final PromptTemplateService promptTemplateService;
    private final AdvancedPromptService advancedPromptService;
    private final ContextAwarePromptService contextAwarePromptService;
    private final PromptABTestService promptABTestService;
    private final PromptQualityEvaluator promptQualityEvaluator;
    private final PromptOptimizer promptOptimizer;
    
    public PromptController(
            PromptTemplateService promptTemplateService,
            AdvancedPromptService advancedPromptService,
            ContextAwarePromptService contextAwarePromptService,
            PromptABTestService promptABTestService,
            PromptQualityEvaluator promptQualityEvaluator,
            PromptOptimizer promptOptimizer
    ) {
        this.promptTemplateService = promptTemplateService;
        this.advancedPromptService = advancedPromptService;
        this.contextAwarePromptService = contextAwarePromptService;
        this.promptABTestService = promptABTestService;
        this.promptQualityEvaluator = promptQualityEvaluator;
        this.promptOptimizer = promptOptimizer;
    }
    
    /**
     * 创建基础提示词
     */
    @PostMapping("/basic")
    public String createBasicPrompt(@RequestBody String userInput) {
        return promptTemplateService.createBasicPrompt(userInput);
    }
    
    /**
     * 创建系统提示词
     */
    @PostMapping("/system")
    public String createSystemPrompt(
            @RequestParam String role,
            @RequestParam String task,
            @RequestParam String context
    ) {
        return promptTemplateService.createSystemPrompt(role, task, context);
    }
    
    /**
     * 创建Few-shot提示词
     */
    @PostMapping("/few-shot")
    public String createFewShotPrompt(
            @RequestParam String task,
            @RequestBody Map<String, Object> request
    ) {
        @SuppressWarnings("unchecked")
        List<Map<String, String>> examples = (List<Map<String, String>>) request.get("examples");
        String input = (String) request.get("input");
        
        return advancedPromptService.createFewShotPrompt(task, examples, input);
    }
    
    /**
     * 创建链式思维提示词
     */
    @PostMapping("/chain-of-thought")
    public String createChainOfThoughtPrompt(@RequestBody String problem) {
        return advancedPromptService.createChainOfThoughtPrompt(problem);
    }
    
    /**
     * 创建个性化提示词
     */
    @PostMapping("/personalized")
    public String createPersonalizedPrompt(
            @RequestParam String userId,
            @RequestParam String query,
            @RequestBody List<String> chatHistory
    ) {
        return contextAwarePromptService.createPersonalizedPrompt(userId, query, chatHistory);
    }
    
    /**
     * A/B测试提示词
     */
    @PostMapping("/ab-test/{testName}")
    public PromptABTestService.ABTestResult abTestPrompt(
            @PathVariable String testName,
            @RequestBody Map<String, Object> variables
    ) {
        return promptABTestService.selectPromptVariant(testName, variables);
    }
    
    /**
     * 记录A/B测试结果
     */
    @PostMapping("/ab-test/{testName}/result")
    public void recordABTestResult(
            @PathVariable String testName,
            @RequestParam String variant,
            @RequestParam boolean success,
            @RequestParam double score
    ) {
        promptABTestService.recordTestResult(testName, variant, success, score);
    }
    
    /**
     * 获取A/B测试统计
     */
    @GetMapping("/ab-test/{testName}/stats")
    public Map<String, PromptABTestService.ABTestMetrics> getABTestStats(@PathVariable String testName) {
        return promptABTestService.getTestStatistics(testName);
    }
    
    /**
     * 评估提示词质量
     */
    @PostMapping("/evaluate")
    public PromptQualityEvaluator.PromptQualityScore evaluatePrompt(
            @RequestBody Map<String, Object> request
    ) {
        String promptText = (String) request.get("prompt");
        @SuppressWarnings("unchecked")
        List<String> testInputs = (List<String>) request.get("testInputs");
        
        return promptQualityEvaluator.evaluatePrompt(promptText, testInputs);
    }
    
    /**
     * 优化提示词
     */
    @PostMapping("/optimize")
    public PromptOptimizer.PromptOptimizationReport optimizePrompt(@RequestBody String prompt) {
        return promptOptimizer.analyzeAndOptimize(prompt);
    }
}

4.7 本章总结

4.7.1 核心要点

  1. 提示词工程:设计有效提示词的原则和技巧
  2. 模板系统:Spring AI的模板管理和动态生成
  3. 高级技术:Few-shot学习、链式思维、角色扮演
  4. 质量评估:提示词效果评估和优化建议
  5. A/B测试:提示词变体测试和性能比较

4.7.2 最佳实践

  1. 结构化设计:使用清晰的提示词结构
  2. 上下文管理:提供充分的背景信息
  3. 模板复用:建立提示词模板库
  4. 持续优化:基于反馈不断改进
  5. 测试验证:使用A/B测试验证效果

4.7.3 练习题

基础练习

  1. 创建一个代码生成的提示词模板
  2. 实现一个简单的Few-shot学习示例
  3. 设计一个文本分析的提示词

进阶练习

  1. 实现上下文感知的个性化提示词
  2. 创建A/B测试系统比较不同提示词效果
  3. 开发提示词质量评估工具

高级练习

  1. 构建智能提示词优化系统
  2. 实现多轮对话的上下文管理
  3. 创建领域特定的提示词生成器

下一章我们将学习向量数据库与文档处理的相关技术。