向量大模型
向量大模型拓展指南
拓展概述
BladeX平台的向量大模型基于LangChain4j定制开发,支持OpenAI、HuggingFace、Qianfan、Ollama等主流向量模型提供商。采用标准化接口设计,兼容LangChain4j生态中的所有向量模型。本指南详细介绍如何扩展新的向量大模型,包括架构设计、代码实现和最佳实践。
技术特色
- 标准化接口设计:遵循LangChain4j的EmbeddingModel规范,兼容性强
- 广泛生态支持:支持LangChain4j生态中的所有向量模型
- 统一抽象管理:通过模板类实现不同提供商的统一管理
- 高性能优化:优化的批量处理和缓存机制,提升向量化效率
- 灵活配置管理:支持数据库配置和属性文件配置,动态更新
🏗️ 一、技术架构了解
1.1 向量模型模块结构
rag/engine/provider/
├── AbstractEmbeddingModelTemplate.java     # 抽象模板基类
├── EmbeddingModelTemplate.java             # 向量模型接口
├── RagFactory.java                         # 向量模型工厂
├── builder/
│   └── BladeEmbeddingModelBuilder.java     # 向量模型构建器
└── model/
    ├── OpenAIEmbeddingModelTemplate.java   # OpenAI实现
    ├── HuggingFaceEmbeddingModelTemplate.java # HuggingFace实现
    ├── QianfanEmbeddingModelTemplate.java  # 千帆实现
    ├── OllamaEmbeddingModelTemplate.java   # Ollama实现
    └── GitHubModelsEmbeddingModelTemplate.java # GitHub Models实现1.2 支持的向量模型提供商
BladeX平台目前支持以下向量大模型:
| 提供商 | 状态 | 特点 | 适用场景 | 
|---|---|---|---|
| OpenAI | ✅ 已支持 | 高质量向量,多维度选择 | 通用文本向量化 | 
| HuggingFace | ✅ 已支持 | 开源模型丰富,免费使用 | 研究开发环境 | 
| Qianfan | ✅ 已支持 | 百度千帆,中文优化 | 中文文本处理 | 
| Ollama | ✅ 已支持 | 本地部署,隐私保护 | 私有化部署 | 
| GitHub Models | 🔨 示例扩展 | 免费试用,开发友好 | 开发测试环境 | 
| Cohere | ⏳ 可扩展 | 多语言支持 | 国际化应用 | 
| Voyage AI | ⏳ 可扩展 | 专业向量服务 | 企业级应用 | 
1.3 核心组件架构
🔧 二、核心组件详解
2.1 向量模型接口 (EmbeddingModelTemplate)
向量模型接口定义了统一的向量化操作规范:
public interface EmbeddingModelTemplate {
    /**
     * 获取模型名称
     */
    String getName();
    
    /**
     * 获取向量维度
     */
    int getDimension();
    
    /**
     * 获取原始的向量模型实例
     */
    EmbeddingModel getEmbeddingModel();
    
    /**
     * 将文本转换为向量
     */
    Embedding embedText(String text);
    
    /**
     * 批量将文本转换为向量
     */
    List<Embedding> embedTexts(List<String> texts);
    
    /**
     * 将文档转换为向量
     */
    Embedding embedDocument(Document document);
    
    /**
     * 批量将文档转换为向量
     */
    List<Embedding> embedDocuments(List<Document> documents);
}核心功能特性:
- 统一接口规范:标准化的向量化操作接口
- 批量处理支持:支持单个和批量文本向量化
- 文档级处理:支持Document对象的向量化
- 维度信息获取:提供向量维度查询功能
2.2 抽象模板类 (AbstractEmbeddingModelTemplate)
抽象模板类提供了通用的向量化处理逻辑:
public abstract class AbstractEmbeddingModelTemplate implements EmbeddingModelTemplate {
    
    protected final String name;
    protected final int dimension;
    protected final EmbeddingModel embeddingModel;
    
    protected AbstractEmbeddingModelTemplate(String name, int dimension, EmbeddingModel embeddingModel) {
        this.name = name;
        this.dimension = dimension;
        this.embeddingModel = embeddingModel;
    }
    
    @Override
    public String getName() {
        return name;
    }
    
    @Override
    public int getDimension() {
        return dimension;
    }
    
    @Override
    public EmbeddingModel getEmbeddingModel() {
        return embeddingModel;
    }
    
    @Override
    public Embedding embedText(String text) {
        try {
            Response<Embedding> response = embeddingModel.embed(text);
            return response.content();
        } catch (Exception e) {
            throw new RuntimeException("文本向量化失败: " + e.getMessage(), e);
        }
    }
    
    @Override
    public List<Embedding> embedTexts(List<String> texts) {
        try {
            Response<List<Embedding>> response = embeddingModel.embedAll(texts);
            return response.content();
        } catch (Exception e) {
            throw new RuntimeException("批量文本向量化失败: " + e.getMessage(), e);
        }
    }
}主要职责:
- 通用逻辑封装:封装常用的向量化操作逻辑
- 异常处理统一:统一的异常处理和错误信息包装
- 性能优化:批量处理优化和缓存机制
- 接口标准化:确保所有实现类遵循统一规范
2.3 向量模型工厂 (RagFactory)
工厂类负责根据配置创建对应的向量模型实例:
@RequiredArgsConstructor
public class RagFactory {
    
    public EmbeddingModelTemplate createEmbeddingModelTemplate(String name, ModelConfig config) {
        BladeEmbeddingModelBuilder builder = BladeEmbeddingModelBuilder.builder()
            .name(name)
            .dimension(config.getDimension())
            .modelType(config.getModelType())
            .modelName(config.getModelName())
            .apiKey(config.getApiKey())
            .secretKey(config.getSecretKey())
            .baseUrl(config.getBaseUrl())
            .timeout(config.getTimeout())
            .build();
            
        return switch (config.getModelType()) {
            case RagConstant.MODEL_TYPE_OPENAI -> builder.buildOpenAI();
            case RagConstant.MODEL_TYPE_OLLAMA -> builder.buildOllama();
            case RagConstant.MODEL_TYPE_HUGGINGFACE -> builder.buildHuggingFace();
            case RagConstant.MODEL_TYPE_QIANFAN -> builder.buildQianfan();
            case RagConstant.MODEL_TYPE_GITHUB -> builder.buildGitHubModels();
            default -> {
                log.warn("不支持的向量模型类型: {}", config.getModelType());
                yield null;
            }
        };
    }
}主要职责:
- 模型类型识别:根据配置自动识别向量模型提供商
- 实例创建管理:创建对应的向量模型实例并进行配置验证
- 配置参数转换:将数据库配置转换为模型配置对象
- 异常处理:处理不支持的模型类型和配置错误
2.4 模型构建器 (BladeEmbeddingModelBuilder)
构建器类提供了灵活的向量模型创建方式:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BladeEmbeddingModelBuilder {
    private String name;
    private int dimension;
    private String modelType;
    private String modelName;
    private String apiKey;
    private String secretKey;
    private String baseUrl;
    private Long timeout;
    
    /**
     * 构建OpenAI向量模型
     */
    public OpenAIEmbeddingModelTemplate buildOpenAI() {
        return new OpenAIEmbeddingModelTemplate(this);
    }
    
    /**
     * 构建GitHub Models向量模型
     */
    public GitHubModelsEmbeddingModelTemplate buildGitHubModels() {
        return new GitHubModelsEmbeddingModelTemplate(this);
    }
    
    /**
     * 构建Ollama向量模型
     */
    public OllamaEmbeddingModelTemplate buildOllama() {
        return new OllamaEmbeddingModelTemplate(this);
    }
    
    /**
     * 构建HuggingFace向量模型
     */
    public HuggingFaceEmbeddingModelTemplate buildHuggingFace() {
        return new HuggingFaceEmbeddingModelTemplate(this);
    }
}核心特性:
- 建造者模式:提供灵活的配置方式
- 类型安全:编译时检查配置参数
- 扩展友好:易于添加新的向量模型类型
- 配置验证:内置配置参数验证机制
🚀 三、扩展新的向量模型
3.1 创建GitHub Models实现类
基于LangChain4j的GitHub Models集成,展示完整的实现过程:
@Slf4j
public class GitHubModelsEmbeddingModelTemplate extends AbstractEmbeddingModelTemplate {
    
    private static final int DEFAULT_DIMENSION = 1536;
    private static final String DEFAULT_MODEL = "text-embedding-3-small";
    
    public GitHubModelsEmbeddingModelTemplate(BladeEmbeddingModelBuilder builder) {
        super(
            builder.getName(),
            builder.getDimension() > 0 ? builder.getDimension() : DEFAULT_DIMENSION,
            createGitHubModelsEmbeddingModel(
                builder.getModelName(),
                builder.getApiKey(),
                builder.getTimeout()
            )
        );
    }
    
    /**
     * 创建GitHub Models向量模型实例
     */
    private static EmbeddingModel createGitHubModelsEmbeddingModel(String modelName, 
            String gitHubToken, Long timeout) {
        try {
            GitHubModelsEmbeddingModel.GitHubModelsEmbeddingModelBuilder builder = 
                GitHubModelsEmbeddingModel.builder()
                    .gitHubToken(gitHubToken)
                    .modelName(StringUtil.isBlank(modelName) ? DEFAULT_MODEL : modelName)
                    .logRequestsAndResponses(false)
                    .maxRetries(3);
                    
            if (timeout != null && timeout > 0) {
                builder.timeout(Duration.ofMillis(timeout));
            }
            
            return builder.build();
        } catch (Exception e) {
            log.error("创建GitHub Models向量模型失败", e);
            throw new RuntimeException("创建GitHub Models向量模型失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取支持的模型列表
     */
    public static List<String> getSupportedModels() {
        return Arrays.asList(
            "text-embedding-3-small",
            "text-embedding-3-large",
            "text-embedding-ada-002"
        );
    }
    
    /**
     * 获取模型的默认维度
     */
    public static int getDefaultDimension(String modelName) {
        return switch (modelName) {
            case "text-embedding-3-small" -> 1536;
            case "text-embedding-3-large" -> 3072;
            case "text-embedding-ada-002" -> 1536;
            default -> DEFAULT_DIMENSION;
        };
    }
}3.2 注册到工厂和构建器
在RagConstant中添加常量:
public class RagConstant {
    // 现有常量...
    public static final String MODEL_TYPE_GITHUB = "github";
    public static final String PREFIX_GITHUB = "github-";
}在BladeEmbeddingModelBuilder中添加构建方法:
/**
 * 构建GitHub Models向量模型
 */
public GitHubModelsEmbeddingModelTemplate buildGitHubModels() {
    return new GitHubModelsEmbeddingModelTemplate(this);
}在RagFactory中添加case:
return switch (modelType) {
    case RagConstant.MODEL_TYPE_OPENAI -> builder.buildOpenAI();
    case RagConstant.MODEL_TYPE_GITHUB -> builder.buildGitHubModels();  // 新增
    case RagConstant.MODEL_TYPE_OLLAMA -> builder.buildOllama();
    case RagConstant.MODEL_TYPE_HUGGINGFACE -> builder.buildHuggingFace();
    case RagConstant.MODEL_TYPE_QIANFAN -> builder.buildQianfan();
    default -> {
        log.warn("不支持的向量模型类型: {}", modelType);
        yield null;
    }
};3.3 添加Maven依赖
在pom.xml中添加GitHub Models的依赖:
<!-- GitHub Models向量模型支持 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-github-models</artifactId>
    <version>1.0.1-beta6</version>
</dependency>
<!-- 核心LangChain4j依赖 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j</artifactId>
    <version>1.0.1-beta6</version>
</dependency>3.4 前端配置支持
在前端model.vue中添加GitHub Models配置:
const MODEL_CONFIG = {
  // 现有配置...
  github: {
    label: 'GitHub Models',
    value: 'github',
    group: ['embedding'],
    baseUrl: 'https://models.inference.ai.azure.com',
    icon: 'img/embedding/github.png',
    models: [
      'text-embedding-3-small',
      'text-embedding-3-large',
      'text-embedding-ada-002'
    ]
  }
}
// 在向量模型配置表单中添加GitHub特定配置
const getModelSpecificConfig = (type) => {
  const configs = {
    github: {
      apiKeyLabel: 'GitHub Token',
      apiKeyPlaceholder: '请输入GitHub Personal Access Token',
      defaultModel: 'text-embedding-3-small',
      supportedModels: [
        { label: 'text-embedding-3-small (1536维)', value: 'text-embedding-3-small' },
        { label: 'text-embedding-3-large (3072维)', value: 'text-embedding-3-large' },
        { label: 'text-embedding-ada-002 (1536维)', value: 'text-embedding-ada-002' }
      ]
    }
  }
  return configs[type] || {}
}🎛️ 四、高级特性实现
4.1 批量处理优化
实现高效的批量向量化处理:
@Override
public List<Embedding> embedTexts(List<String> texts) {
    if (texts == null || texts.isEmpty()) {
        return Collections.emptyList();
    }
    
    // 分批处理,避免单次请求过大
    int batchSize = getBatchSize();
    List<Embedding> allEmbeddings = new ArrayList<>();
    
    for (int i = 0; i < texts.size(); i += batchSize) {
        int endIndex = Math.min(i + batchSize, texts.size());
        List<String> batch = texts.subList(i, endIndex);
        
        try {
            Response<List<Embedding>> response = embeddingModel.embedAll(batch);
            allEmbeddings.addAll(response.content());
        } catch (Exception e) {
            log.error("批量向量化失败,批次: {}-{}", i, endIndex, e);
            throw new RuntimeException("批量向量化失败: " + e.getMessage(), e);
        }
    }
    
    return allEmbeddings;
}
/**
 * 获取批处理大小
 */
protected int getBatchSize() {
    // 不同提供商的批处理大小限制不同
    return switch (getProviderType()) {
        case "openai", "github" -> 100;
        case "huggingface" -> 50;
        case "ollama" -> 10;
        default -> 20;
    };
}4.2 缓存机制实现
添加向量缓存以提升性能:
@Component
public class EmbeddingCacheManager {
    
    private final Cache<String, Embedding> embeddingCache;
    
    public EmbeddingCacheManager() {
        this.embeddingCache = Caffeine.newBuilder()
            .maximumSize(10000)
            .expireAfterWrite(Duration.ofHours(24))
            .recordStats()
            .build();
    }
    
    public Embedding getOrCompute(String cacheKey, Function<String, Embedding> computer) {
        String cacheKey = generateCacheKey(cacheKey);
        return embeddingCache.get(cacheKey, key -> computer.apply(key));
    }
    
    /**
     * 生成缓存键
     */
    private String generateCacheKey(String text) {
        return DigestUtils.md5Hex(text);
    }
    
    /**
     * 获取缓存统计信息
     */
    public CacheStats getCacheStats() {
        return embeddingCache.stats();
    }
}4.3 异步处理支持
实现异步向量化处理:
@Service
public class AsyncEmbeddingService {
    
    private final ExecutorService executorService;
    private final EmbeddingModelTemplate embeddingModel;
    
    public AsyncEmbeddingService(EmbeddingModelTemplate embeddingModel) {
        this.embeddingModel = embeddingModel;
        this.executorService = Executors.newFixedThreadPool(10);
    }
    
    /**
     * 异步文本向量化
     */
    public CompletableFuture<Embedding> embedTextAsync(String text) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return embeddingModel.embedText(text);
            } catch (Exception e) {
                throw new RuntimeException("异步向量化失败: " + e.getMessage(), e);
            }
        }, executorService);
    }
    
    /**
     * 异步批量文本向量化
     */
    public CompletableFuture<List<Embedding>> embedTextsAsync(List<String> texts) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return embeddingModel.embedTexts(texts);
            } catch (Exception e) {
                throw new RuntimeException("异步批量向量化失败: " + e.getMessage(), e);
            }
        }, executorService);
    }
}4.4 多模型路由策略
实现智能的模型选择策略:
@Component
public class EmbeddingModelRouter {
    
    private final Map<String, EmbeddingModelTemplate> modelTemplates;
    private final LoadBalancer loadBalancer;
    
    /**
     * 根据文本特征选择最适合的模型
     */
    public EmbeddingModelTemplate selectModel(String text, String language) {
        // 根据语言选择模型
        if ("zh".equals(language)) {
            return modelTemplates.get("qianfan");  // 中文优先使用千帆
        }
        
        // 根据文本长度选择模型
        if (text.length() > 8000) {
            return modelTemplates.get("openai-large");  // 长文本使用大模型
        }
        
        // 默认使用负载均衡
        return loadBalancer.selectModel(modelTemplates.values());
    }
    
    /**
     * 根据成本效益选择模型
     */
    public EmbeddingModelTemplate selectCostEffectiveModel(List<String> texts) {
        int totalTokens = texts.stream().mapToInt(String::length).sum();
        
        if (totalTokens < 1000) {
            return modelTemplates.get("github");  // 小量文本使用免费模型
        } else if (totalTokens < 10000) {
            return modelTemplates.get("openai-small");  // 中等文本使用小模型
        } else {
            return modelTemplates.get("huggingface");  // 大量文本使用开源模型
        }
    }
}🧪 五、测试验证指南
5.1 单元测试
为新向量模型创建完整的单元测试:
@ExtendWith(MockitoExtension.class)
class GitHubModelsEmbeddingModelTemplateTest {
    @Mock
    private BladeEmbeddingModelBuilder mockBuilder;
    
    private GitHubModelsEmbeddingModelTemplate embeddingTemplate;
    
    @BeforeEach
    void setUp() {
        when(mockBuilder.getName()).thenReturn("test-github");
        when(mockBuilder.getDimension()).thenReturn(1536);
        when(mockBuilder.getModelName()).thenReturn("text-embedding-3-small");
        when(mockBuilder.getApiKey()).thenReturn("test-token");
        when(mockBuilder.getTimeout()).thenReturn(30000L);
        
        embeddingTemplate = new GitHubModelsEmbeddingModelTemplate(mockBuilder);
    }
    
    @Test
    void testEmbedText() {
        // 测试单个文本向量化
        String testText = "Hello, world!";
        
        Embedding embedding = embeddingTemplate.embedText(testText);
        
        assertThat(embedding).isNotNull();
        assertThat(embedding.vector()).hasSize(1536);
        assertThat(embedding.vector().get(0)).isInstanceOf(Float.class);
    }
    
    @Test
    void testEmbedTexts() {
        // 测试批量文本向量化
        List<String> testTexts = Arrays.asList(
            "Hello, world!",
            "How are you?",
            "Nice to meet you!"
        );
        
        List<Embedding> embeddings = embeddingTemplate.embedTexts(testTexts);
        
        assertThat(embeddings).hasSize(3);
        embeddings.forEach(embedding -> {
            assertThat(embedding).isNotNull();
            assertThat(embedding.vector()).hasSize(1536);
        });
    }
    
    @Test
    void testGetSupportedModels() {
        // 测试支持的模型列表
        List<String> supportedModels = GitHubModelsEmbeddingModelTemplate.getSupportedModels();
        
        assertThat(supportedModels).isNotEmpty();
        assertThat(supportedModels).contains("text-embedding-3-small");
        assertThat(supportedModels).contains("text-embedding-3-large");
    }
    
    @Test
    void testGetDefaultDimension() {
        // 测试默认维度获取
        int dimension1 = GitHubModelsEmbeddingModelTemplate.getDefaultDimension("text-embedding-3-small");
        int dimension2 = GitHubModelsEmbeddingModelTemplate.getDefaultDimension("text-embedding-3-large");
        
        assertThat(dimension1).isEqualTo(1536);
        assertThat(dimension2).isEqualTo(3072);
    }
}5.2 集成测试
创建端到端的集成测试:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {
    "blade.rag.embedding-models.github-test.model-type=github",
    "blade.rag.embedding-models.github-test.model-name=text-embedding-3-small",
    "blade.rag.embedding-models.github-test.api-key=${GITHUB_TOKEN}",
    "blade.rag.embedding-models.github-test.dimension=1536"
})
class GitHubModelsIntegrationTest {
    @Autowired
    private RagFactory ragFactory;
    
    @Test
    void testGitHubModelsIntegration() {
        // 测试工厂创建
        ModelConfig config = new ModelConfig();
        config.setModelType("github");
        config.setModelName("text-embedding-3-small");
        config.setApiKey(System.getenv("GITHUB_TOKEN"));
        config.setDimension(1536);
        
        EmbeddingModelTemplate template = ragFactory.createEmbeddingModelTemplate("github-test", config);
        
        assertThat(template).isNotNull();
        assertThat(template).isInstanceOf(GitHubModelsEmbeddingModelTemplate.class);
        assertThat(template.getName()).isEqualTo("github-test");
        assertThat(template.getDimension()).isEqualTo(1536);
    }
    
    @Test
    void testRealApiCall() {
        // 测试真实API调用(需要有效的GitHub Token)
        String githubToken = System.getenv("GITHUB_TOKEN");
        assumeTrue(githubToken != null, "需要设置GITHUB_TOKEN环境变量");
        
        ModelConfig config = new ModelConfig();
        config.setModelType("github");
        config.setApiKey(githubToken);
        
        EmbeddingModelTemplate template = ragFactory.createEmbeddingModelTemplate("github-real", config);
        
        String testText = "This is a test for GitHub Models embedding.";
        Embedding embedding = template.embedText(testText);
        
        assertThat(embedding).isNotNull();
        assertThat(embedding.vector()).isNotEmpty();
    }
}5.3 性能测试
验证向量模型的性能表现:
@Test
void testPerformance() {
    GitHubModelsEmbeddingModelTemplate template = createTestTemplate();
    List<String> testTexts = generateTestTexts(100);
    
    // 预热
    template.embedTexts(testTexts.subList(0, 10));
    
    // 性能测试
    long startTime = System.currentTimeMillis();
    List<Embedding> embeddings = template.embedTexts(testTexts);
    long endTime = System.currentTimeMillis();
    
    long duration = endTime - startTime;
    double avgLatency = (double) duration / testTexts.size();
    
    log.info("向量化性能: 总时间={}ms, 平均延迟={}ms/text", duration, avgLatency);
    
    assertThat(embeddings).hasSize(100);
    assertThat(avgLatency).isLessThan(100); // 平均延迟应小于100ms
}
private List<String> generateTestTexts(int count) {
    List<String> texts = new ArrayList<>();
    for (int i = 0; i < count; i++) {
        texts.add("This is test text number " + i + " for performance testing.");
    }
    return texts;
}📊 六、性能优化策略
6.1 连接池优化
配置HTTP客户端连接池:
@Configuration
public class EmbeddingHttpConfig {
    
    @Bean
    public HttpClient embeddingHttpClient() {
        return HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .executor(Executors.newFixedThreadPool(20))
            .build();
    }
    
    @Bean
    public WebClient embeddingWebClient() {
        return WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(
                HttpClient.create()
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
                    .responseTimeout(Duration.ofSeconds(30))
                    .keepAlive(true)
                    .wiretap(true)
            ))
            .build();
    }
}6.2 批处理优化
实现智能批处理策略:
@Component
public class BatchEmbeddingProcessor {
    
    private final Map<String, List<EmbeddingRequest>> pendingRequests = new ConcurrentHashMap<>();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
    
    @PostConstruct
    public void init() {
        // 定时处理批次
        scheduler.scheduleAtFixedRate(this::processBatches, 100, 100, TimeUnit.MILLISECONDS);
    }
    
    /**
     * 添加向量化请求到批次
     */
    public CompletableFuture<Embedding> addRequest(String modelName, String text) {
        EmbeddingRequest request = new EmbeddingRequest(text, new CompletableFuture<>());
        
        pendingRequests.computeIfAbsent(modelName, k -> new ArrayList<>()).add(request);
        
        return request.getFuture();
    }
    
    /**
     * 处理所有待处理的批次
     */
    private void processBatches() {
        pendingRequests.forEach((modelName, requests) -> {
            if (requests.size() >= getBatchSize(modelName) || 
                isTimeoutReached(requests.get(0))) {
                processBatch(modelName, new ArrayList<>(requests));
                requests.clear();
            }
        });
    }
    
    private void processBatch(String modelName, List<EmbeddingRequest> requests) {
        try {
            EmbeddingModelTemplate template = getTemplate(modelName);
            List<String> texts = requests.stream()
                .map(EmbeddingRequest::getText)
                .collect(Collectors.toList());
            
            List<Embedding> embeddings = template.embedTexts(texts);
            
            // 返回结果
            for (int i = 0; i < requests.size(); i++) {
                requests.get(i).getFuture().complete(embeddings.get(i));
            }
        } catch (Exception e) {
            // 处理异常
            requests.forEach(request -> 
                request.getFuture().completeExceptionally(e));
        }
    }
}6.3 缓存策略优化
实现多级缓存策略:
@Component
public class MultiLevelEmbeddingCache {
    
    private final Cache<String, Embedding> l1Cache;  // 内存缓存
    private final RedisTemplate<String, Embedding> l2Cache;  // Redis缓存
    
    public MultiLevelEmbeddingCache(RedisTemplate<String, Embedding> redisTemplate) {
        this.l2Cache = redisTemplate;
        this.l1Cache = Caffeine.newBuilder()
            .maximumSize(5000)
            .expireAfterWrite(Duration.ofMinutes(30))
            .removalListener((key, value, cause) -> {
                // L1缓存淘汰时写入L2缓存
                if (cause == RemovalCause.SIZE || cause == RemovalCause.EXPIRED) {
                    l2Cache.opsForValue().set((String) key, (Embedding) value, Duration.ofHours(24));
                }
            })
            .build();
    }
    
    public Embedding getOrCompute(String cacheKey, Function<String, Embedding> computer) {
        // 1. 尝试L1缓存
        Embedding embedding = l1Cache.getIfPresent(cacheKey);
        if (embedding != null) {
            return embedding;
        }
        
        // 2. 尝试L2缓存
        embedding = l2Cache.opsForValue().get(cacheKey);
        if (embedding != null) {
            l1Cache.put(cacheKey, embedding);  // 回写L1缓存
            return embedding;
        }
        
        // 3. 计算并缓存
        embedding = computer.apply(cacheKey);
        l1Cache.put(cacheKey, embedding);
        
        return embedding;
    }
}🔍 七、监控和调试
7.1 指标收集
添加详细的性能指标:
@Component
public class EmbeddingMetrics {
    
    private final MeterRegistry meterRegistry;
    private final Counter requestCounter;
    private final Timer embeddingTimer;
    private final Gauge cacheHitRate;
    
    public EmbeddingMetrics(MeterRegistry meterRegistry, EmbeddingCacheManager cacheManager) {
        this.meterRegistry = meterRegistry;
        this.requestCounter = Counter.builder("embedding.requests.total")
            .description("Total embedding requests")
            .register(meterRegistry);
        this.embeddingTimer = Timer.builder("embedding.duration")
            .description("Embedding processing duration")
            .register(meterRegistry);
        this.cacheHitRate = Gauge.builder("embedding.cache.hit.rate")
            .description("Embedding cache hit rate")
            .register(meterRegistry, cacheManager, manager -> 
                manager.getCacheStats().hitRate());
    }
    
    public void recordRequest(String provider, String model, int textCount, 
            boolean success, Duration duration) {
        requestCounter.increment(
            Tags.of(
                Tag.of("provider", provider),
                Tag.of("model", model),
                Tag.of("success", String.valueOf(success))
            )
        );
        
        embeddingTimer.record(duration, 
            Tags.of(
                Tag.of("provider", provider),
                Tag.of("model", model),
                Tag.of("batch_size", String.valueOf(textCount))
            )
        );
    }
}7.2 健康检查
实现向量模型健康检查:
@Component
public class EmbeddingHealthIndicator implements HealthIndicator {
    
    private final Map<String, EmbeddingModelTemplate> embeddingModels;
    
    @Override
    public Health health() {
        Health.Builder builder = Health.up();
        boolean allHealthy = true;
        
        for (Map.Entry<String, EmbeddingModelTemplate> entry : embeddingModels.entrySet()) {
            String modelName = entry.getKey();
            EmbeddingModelTemplate template = entry.getValue();
            
            try {
                // 测试向量化
                Embedding testEmbedding = template.embedText("health check");
                
                if (testEmbedding != null && !testEmbedding.vector().isEmpty()) {
                    builder.withDetail(modelName, "UP");
                } else {
                    builder.withDetail(modelName, "DOWN - 空向量响应");
                    allHealthy = false;
                }
            } catch (Exception e) {
                builder.withDetail(modelName, "DOWN - " + e.getMessage());
                allHealthy = false;
            }
        }
        
        return allHealthy ? builder.build() : builder.down().build();
    }
}7.3 日志配置
配置结构化日志:
@Aspect
@Component
public class EmbeddingLoggingAspect {
    
    @Around("execution(* org.springblade.modules.aigc.rag.engine.provider.model.*.*(..))")
    public Object logEmbeddingOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        
        String requestId = UUID.randomUUID().toString();
        MDC.put("requestId", requestId);
        MDC.put("operation", methodName);
        
        try {
            log.info("开始向量化操作: method={}, args={}", methodName, args.length);
            
            long startTime = System.currentTimeMillis();
            Object result = joinPoint.proceed();
            long duration = System.currentTimeMillis() - startTime;
            
            log.info("向量化操作完成: duration={}ms", duration);
            
            return result;
        } catch (Exception e) {
            log.error("向量化操作失败: {}", e.getMessage(), e);
            throw e;
        } finally {
            MDC.clear();
        }
    }
}🚨 八、常见问题解决
8.1 编译问题
常见编译错误
Q: LangChain4j依赖冲突
- 原因: 版本不兼容或依赖传递冲突
- 解决: 使用Maven dependency:tree检查冲突,排除冲突依赖
Q: 找不到EmbeddingModel类
- 原因: 缺少LangChain4j核心依赖
- 解决: 添加langchain4j核心依赖
8.2 运行时问题
运行时异常
Q: API调用失败
- 检查: API密钥、网络连接、请求格式
- 解决: 验证配置参数,查看API文档
Q: 向量维度不匹配
- 检查: 模型配置的维度与实际输出是否一致
- 解决: 更新配置或使用正确的模型
8.3 性能问题
性能优化建议
Q: 向量化速度慢
- 检查: 批处理大小、网络延迟
- 优化: 调整批处理参数、使用缓存
Q: 内存占用过高
- 检查: 缓存策略、向量存储
- 优化: 调整缓存大小、使用压缩存储
💡 九、最佳实践总结
9.1 开发规范
编码规范
- 命名一致性:向量模型实现类命名遵循{Provider}EmbeddingModelTemplate格式
- 异常处理:统一使用RuntimeException包装异常,提供清晰的错误信息
- 日志记录:在关键操作点添加结构化日志
- 配置验证:在构造函数中验证必要的配置参数
- 文档完善:为每个新模型编写详细的使用文档
9.2 性能考虑
性能要求
- 批处理优化:合理设置批处理大小,平衡延迟和吞吐量
- 缓存策略:实现多级缓存,减少重复计算
- 连接池管理:配置合适的连接池参数
- 异步处理:对于大批量处理使用异步方式
9.3 扩展建议
扩展指导
- 遵循LangChain4j规范:严格按照LangChain4j的接口设计
- 充分测试:编写完整的单元测试和集成测试
- 性能监控:添加必要的性能指标和监控
- 文档维护:及时更新相关文档和示例代码
- 社区贡献:考虑将通用实现贡献给LangChain4j社区
通过遵循本指南,开发者可以快速、安全地为BladeX平台添加新的向量大模型支持,充分利用LangChain4j生态系统的强大能力,实现高质量的文本向量化服务。
