docs = new ArrayList<>();
+
+ // AI搜索:先处理choices中的AI回答
+ if (searchType == SearchType.AI && respNode.contains("choices")) {
+ ONode choicesArray = respNode.get("choices");
+ if (choicesArray.isArray() && choicesArray.count() > 0) {
+ ONode firstChoice = choicesArray.get(0);
+ if (firstChoice.contains("message")) {
+ String aiContent = firstChoice.get("message").get("content").getString();
+ if (aiContent != null && !aiContent.trim().isEmpty()) {
+ docs.add(new Document(aiContent.trim())
+ .title("Solon AI智能回答")
+ .metadata("type", "ai_answer")
+ .metadata("source", "baidu_ai_search"));
+ }
+ }
+ }
+ }
+
+ // 处理references中的搜索结果(基础搜索和AI搜索都有)
+ if (respNode.contains("references")) {
+ ONode referencesArray = respNode.get("references");
+ if (referencesArray.isArray()) {
+ for (ONode ref : referencesArray.ary()) {
+ String content = ref.get("content").getString();
+ String title = ref.get("title").getString();
+ String url = ref.get("url").getString();
+
+ if (content != null && !content.trim().isEmpty()) {
+ Document doc = new Document(content.trim());
+
+ if (title != null && !title.trim().isEmpty()) {
+ doc.title(title.trim());
+ }
+
+ if (url != null && !url.trim().isEmpty()) {
+ doc.url(url.trim());
+ }
+
+ // 添加百度搜索相关元数据
+ if (ref.contains("id")) {
+ doc.metadata("id", ref.get("id").getString());
+ }
+ if (ref.contains("date") && ref.get("date").getString() != null) {
+ doc.metadata("date", ref.get("date").getString());
+ }
+ if (ref.contains("type")) {
+ doc.metadata("type", ref.get("type").getString());
+ } else {
+ doc.metadata("type", "web"); // 默认为web类型
+ }
+ if (ref.contains("web_anchor")) {
+ doc.metadata("web_anchor", ref.get("web_anchor").getString());
+ }
+ if (ref.contains("icon")) {
+ doc.metadata("icon", ref.get("icon").getString());
+ }
+
+ // 标记来源
+ doc.metadata("source", "baidu_search");
+
+ docs.add(doc);
+ }
+ }
+ }
+ }
+
+ // 如果没有解析到任何内容,抛出异常
+ if (docs.isEmpty()) {
+ throw new IOException("No content found in BaiduAiSearch response: " + respJson.substring(0, Math.min(200, respJson.length())));
+ }
+
+ // 使用嵌入模型进行相似度排序
+ if (embeddingModel != null) {
+ //如果有嵌入模型设置,则做相互度排序和二次过滤
+ embeddingModel.embed(docs);
+
+ float[] queryEmbed = embeddingModel.embed(condition.getQuery());
+ return SimilarityUtil.refilter(docs.stream()
+ .map(doc -> SimilarityUtil.score(doc, queryEmbed)),
+ condition);
+ } else {
+ return docs;
+ }
+ }
+
+ /**
+ * 搜索类型枚举
+ */
+ public enum SearchType {
+ /**
+ * 基础搜索:仅返回搜索结果,不传model参数
+ */
+ BASIC,
+ /**
+ * AI搜索:结合大模型进行智能总结,传入model参数
+ */
+ AI
+ }
+
+ /**
+ * Builder模式构建器
+ */
+ public static class BaiduAiSearchRepositoryBuilder {
+ private final SearchType searchType;
+ private AiConfig config = new AiConfig();
+ private String model;
+ private EmbeddingModel embeddingModel;
+
+ private BaiduAiSearchRepositoryBuilder(SearchType searchType) {
+ this.searchType = searchType;
+ }
+
+ /**
+ * 设置百度AppBuilder API Key(必填)
+ */
+ public BaiduAiSearchRepositoryBuilder apiKey(String apiKey) {
+ config.setApiKey(apiKey);
+ return this;
+ }
+
+ /**
+ * 设置API URL(必填 百度官方地址)
+ */
+ public BaiduAiSearchRepositoryBuilder apiUrl(String apiUrl) {
+ config.setApiUrl(apiUrl);
+ return this;
+ }
+
+ /**
+ * 设置大模型名称(仅AI搜索模式有效,可选,默认为ernie-3.5-8k)
+ *
+ * 支持的模型包括:
+ * - ernie-3.5-8k
+ * - ernie-4.0-turbo-8k(支持图文混排场景)
+ * - ernie-4.0-turbo-128k(支持图文混排场景)
+ * - deepseek-r1
+ * - deepseek-v3
+ * 等
+ */
+ public BaiduAiSearchRepositoryBuilder model(String model) {
+ this.model = model;
+ return this;
+ }
+
+ /**
+ * 设置嵌入模型(可选,用于相似度排序)
+ */
+ public BaiduAiSearchRepositoryBuilder embeddingModel(EmbeddingModel embeddingModel) {
+ this.embeddingModel = embeddingModel;
+ return this;
+ }
+
+ /**
+ * 构建BaiduAiSearchRepository实例
+ */
+ public BaiduAiSearchRepository build() {
+ return new BaiduAiSearchRepository(config, searchType, model, embeddingModel);
+ }
+ }
+}
diff --git a/solon-ai-rag-searchs/solon-ai-search-baidu/src/test/java/features/ai/BaiduAiSearchTest.java b/solon-ai-rag-searchs/solon-ai-search-baidu/src/test/java/features/ai/BaiduAiSearchTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e96c5093655846f41bc005bbae38a3ed1128a976
--- /dev/null
+++ b/solon-ai-rag-searchs/solon-ai-search-baidu/src/test/java/features/ai/BaiduAiSearchTest.java
@@ -0,0 +1,174 @@
+package features.ai;
+
+import org.junit.jupiter.api.Test;
+import org.noear.solon.ai.chat.ChatResponse;
+import org.noear.solon.ai.chat.message.ChatMessage;
+import org.noear.solon.ai.rag.Document;
+import org.noear.solon.ai.rag.search.BaiduAiSearchRepository;
+import org.noear.solon.test.SolonTest;
+
+import java.util.List;
+
+/**
+ * 百度AI搜索Repository测试
+ *
+ * @author Yangbuyi
+ * @date 2025/07/22
+ */
+@SolonTest
+public class BaiduAiSearchTest {
+
+ /**
+ * 测试百度基础搜索 + ChatModel增强回答
+ */
+ @Test
+ public void basicSearchWithChatModel() throws Exception {
+ BaiduAiSearchRepository repository = TestUtils.getBaiduBasicSearchRepository();
+ String query = "今日上海天气如何?";
+
+ List context = repository.search(query);
+
+ //打印搜索结果
+ System.out.println("=== 百度基础搜索结果 ===");
+ context.forEach(doc -> {
+ System.out.println("标题: " + doc.getTitle());
+ System.out.println("内容: " + doc.getContent().substring(0, Math.min(100, doc.getContent().length())) + "...");
+ System.out.println("URL: " + doc.getUrl());
+ System.out.println("---");
+ });
+
+ //打印AI回答
+ ChatResponse resp = TestUtils.getChatModel()
+ .prompt(ChatMessage.ofUserAugment(query, context))
+ .call();
+ System.out.println("\n=== ChatModel增强回答 ===");
+ System.out.println(resp.getMessage());
+ }
+
+ /**
+ * 测试百度基础搜索 + 模板方式
+ */
+ @Test
+ public void basicSearchWithTemplate() throws Exception {
+ BaiduAiSearchRepository repository = TestUtils.getBaiduBasicSearchRepository();
+ String query = "solon框架是谁开发的?";
+
+ List context = repository.search(query);
+
+ ChatResponse resp = TestUtils.getChatModel()
+ .prompt(ChatMessage.ofUserTmpl("${query} \n\n 请参考以下内容回答:${context}")
+ .paramAdd("query", query)
+ .paramAdd("context", context)
+ .generate())
+ .call();
+
+ //打印搜索结果
+ System.out.println("=== 百度基础搜索结果 ===");
+ context.forEach(doc -> {
+ System.out.println("标题: " + doc.getTitle());
+ System.out.println("内容: " + doc.getContent().substring(0, Math.min(100, doc.getContent().length())) + "...");
+ System.out.println("来源: " + doc.getMetadata().get("source"));
+ System.out.println("---");
+ });
+
+ //打印AI回答
+ System.out.println("\n=== ChatModel增强回答 ===");
+ System.out.println(resp.getMessage());
+ }
+
+ /**
+ * 测试百度AI搜索(直接返回智能总结)
+ */
+ @Test
+ public void aiSearchDirect() throws Exception {
+ BaiduAiSearchRepository repository = TestUtils.getBaiduAiSearchRepository();
+ String query = "如何解决交通拥堵问题?";
+
+ List results = repository.search(query);
+
+ //打印AI搜索结果
+ System.out.println("=== 百度AI搜索结果 ===");
+ results.forEach(doc -> {
+ System.out.println("类型: " + doc.getMetadata().get("type"));
+ System.out.println("标题: " + doc.getTitle());
+ System.out.println("内容: " + doc.getContent());
+ if (doc.getUrl() != null) {
+ System.out.println("URL: " + doc.getUrl());
+ }
+ System.out.println("来源: " + doc.getMetadata().get("source"));
+ System.out.println("---");
+ });
+ }
+
+ /**
+ * 测试百度AI搜索 + 进一步ChatModel处理
+ */
+ @Test
+ public void aiSearchWithChatModel() throws Exception {
+ BaiduAiSearchRepository repository = TestUtils.getBaiduAiSearchRepository();
+ String query = "deepseek-r1模型的特点是什么?";
+
+ List aiResults = repository.search(query);
+
+ // 从AI搜索结果中提取AI回答作为基础,进一步处理
+ String aiAnswer = aiResults.stream()
+ .filter(doc -> "ai_answer".equals(doc.getMetadata().get("type")))
+ .map(Document::getContent)
+ .findFirst()
+ .orElse("");
+
+ if (!aiAnswer.isEmpty()) {
+ ChatResponse resp = TestUtils.getChatModel()
+ .prompt(ChatMessage.ofUserTmpl("基于以下AI搜索结果,请总结要点并补充说明:\n\n${aiAnswer}")
+ .paramAdd("aiAnswer", aiAnswer)
+ .generate())
+ .call();
+
+ System.out.println("=== 百度AI搜索原始回答 ===");
+ System.out.println(aiAnswer);
+
+ System.out.println("\n=== ChatModel进一步处理 ===");
+ System.out.println(resp.getMessage());
+ }
+
+ // 打印所有搜索结果
+ System.out.println("\n=== 完整搜索结果 ===");
+ aiResults.forEach(doc -> {
+ System.out.println("类型: " + doc.getMetadata().get("type"));
+ System.out.println("标题: " + doc.getTitle());
+ System.out.println("内容: " + doc.getContent().substring(0, Math.min(200, doc.getContent().length())) + "...");
+ System.out.println("---");
+ });
+ }
+
+ /**
+ * 测试对比:基础搜索 vs AI搜索
+ */
+ @Test
+ public void compareBasicVsAiSearch() throws Exception {
+ String query = "最新的AI技术发展趋势";
+
+ // 基础搜索
+ BaiduAiSearchRepository basicRepo = TestUtils.getBaiduBasicSearchRepository();
+ List basicResults = basicRepo.search(query);
+
+ // AI搜索
+ BaiduAiSearchRepository aiRepo = TestUtils.getBaiduAiSearchRepository();
+ List aiResults = aiRepo.search(query);
+
+ System.out.println("=== 基础搜索结果 (" + basicResults.size() + "条) ===");
+ basicResults.forEach(doc -> {
+ System.out.println("标题: " + doc.getTitle());
+ System.out.println("内容: " + doc.getContent().substring(0, Math.min(100, doc.getContent().length())) + "...");
+ System.out.println("---");
+ });
+
+ System.out.println("\n=== AI搜索结果 (" + aiResults.size() + "条) ===");
+ aiResults.forEach(doc -> {
+ System.out.println("类型: " + doc.getMetadata().get("type"));
+ System.out.println("标题: " + doc.getTitle());
+ System.out.println("内容: " + doc.getContent().substring(0, Math.min(150, doc.getContent().length())) + "...");
+ System.out.println("---");
+ });
+ }
+}
diff --git a/solon-ai-rag-searchs/solon-ai-search-baidu/src/test/java/features/ai/TestUtils.java b/solon-ai-rag-searchs/solon-ai-search-baidu/src/test/java/features/ai/TestUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9c9ebc18f709dfd77ccce0e680c4318c0c8064f
--- /dev/null
+++ b/solon-ai-rag-searchs/solon-ai-search-baidu/src/test/java/features/ai/TestUtils.java
@@ -0,0 +1,68 @@
+package features.ai;
+
+import org.noear.solon.ai.chat.ChatModel;
+import org.noear.solon.ai.embedding.EmbeddingModel;
+import org.noear.solon.ai.rag.search.BaiduAiSearchRepository;
+
+/**
+ * 测试工具
+ *
+ * @author yangbuyiya
+ * @date 2025/07/22
+ */
+public class TestUtils {
+
+ public static String apiKey = ""; // 需要替换为实际的API Key
+ public static String apiUrl = "https://qianfan.baidubce.com/v2/ai_search/chat/completions";
+
+ /**
+ * 获取聊天模型
+ *
+ * @return {@link ChatModel }
+ */
+ public static ChatModel getChatModel() {
+ final String apiUrl = "http://127.0.0.1:11434/api/chat";
+ final String provider = "ollama";
+ final String model = "llama3.2";//"DeepSeek-V3"; //deepseek-reasoner//deepseek-chat
+
+ return ChatModel.of(apiUrl).provider(provider).model(model).build(); //4.初始化语言模型
+ }
+
+ /**
+ * 获取百度AI基础搜索Repository
+ */
+ public static BaiduAiSearchRepository getBaiduBasicSearchRepository() {
+
+ return BaiduAiSearchRepository.ofBasic()
+ .apiKey(apiKey)
+ .apiUrl(apiUrl)
+ .build();
+ }
+
+ /**
+ * 获取百度AI搜索Repository(智能总结模式)
+ */
+ public static BaiduAiSearchRepository getBaiduAiSearchRepository() {
+
+ return BaiduAiSearchRepository.ofAI()
+ .apiKey(apiKey)
+ .apiUrl(apiUrl)
+ .model("ernie-3.5-8k") // 可选择其他模型如 deepseek-r1, ernie-4.0-turbo-8k 等
+ .build();
+ }
+
+
+ /**
+ * 获取嵌入模型
+ *
+ * @return {@link EmbeddingModel }
+ */
+ public static EmbeddingModel getEmbeddingModel() {
+ String apiUrl = "https://dashscope.aliyuncs.com/api/v1/services/embeddings/text-embedding/text-embedding";
+ String apiKey = "sk-1ffe449611a74e61ad8e71e1b35a9858";
+ String provider = "dashscope";
+ String model = "text-embedding-v3";//"llama3.2"; //deepseek-r1:1.5b;
+
+ return EmbeddingModel.of(apiUrl).apiKey(apiKey).provider(provider).model(model).batchSize(10).build();
+ }
+}
diff --git a/solon-ai-rag-searchs/solon-ai-search-baidu/src/test/java/features/ai/example/BaiduAiSearchExample.java b/solon-ai-rag-searchs/solon-ai-search-baidu/src/test/java/features/ai/example/BaiduAiSearchExample.java
new file mode 100644
index 0000000000000000000000000000000000000000..a31907331b54a8285c9c9ee1b2e18469c68d7d50
--- /dev/null
+++ b/solon-ai-rag-searchs/solon-ai-search-baidu/src/test/java/features/ai/example/BaiduAiSearchExample.java
@@ -0,0 +1,158 @@
+package features.ai.example;
+
+import features.ai.TestUtils;
+import org.noear.solon.ai.rag.Document;
+import org.noear.solon.ai.rag.search.BaiduAiSearchRepository;
+
+import java.util.List;
+
+/**
+ * 百度AI搜索Repository使用示例
+ *
+ * @author yangbuyiya
+ * @date 2025/07/22
+ */
+public class BaiduAiSearchExample {
+
+ static String apiUrl = "https://qianfan.baidubce.com/v2/ai_search/chat/completions";
+
+ public static void main(String[] args) throws Exception {
+ // 你的百度AppBuilder API Key https://console.bce.baidu.com/iam/#/iam/apikey/list
+ String apiKey = TestUtils.apiKey;
+
+ // 示例1:基础搜索
+ basicSearchExample(apiKey);
+
+ // 示例2:AI搜索
+ aiSearchExample(apiKey);
+
+ // 示例3:自定义配置
+ customConfigExample(apiKey);
+ }
+
+ /**
+ * 基础搜索示例
+ */
+ public static void basicSearchExample(String apiKey) throws Exception {
+ System.out.println("=== 基础搜索示例 ===");
+
+ // 创建基础搜索Repository
+ BaiduAiSearchRepository repository = BaiduAiSearchRepository.ofBasic()
+ .apiKey(apiKey)
+ .apiUrl(apiUrl)
+ .build();
+
+ // 执行搜索
+ String query = "今日上海闵行区天气";
+ List results = repository.search(query);
+
+ // 输出结果
+ System.out.println("搜索查询: " + query);
+ System.out.println("结果数量: " + results.size());
+
+ results.forEach(doc -> {
+ System.out.println("标题: " + doc.getTitle());
+ System.out.println("内容: " + doc.getContent().substring(0, Math.min(100, doc.getContent().length())) + "...");
+ System.out.println("URL: " + doc.getUrl());
+ System.out.println("类型: " + doc.getMetadata().get("type"));
+ System.out.println("来源: " + doc.getMetadata().get("source"));
+ System.out.println("---");
+ });
+ }
+
+ /**
+ * AI搜索示例
+ */
+ public static void aiSearchExample(String apiKey) throws Exception {
+ System.out.println("\n=== AI搜索示例 ===");
+
+ // 创建AI搜索Repository
+ BaiduAiSearchRepository repository = BaiduAiSearchRepository.ofAI()
+ .apiKey(apiKey)
+ .apiUrl(apiUrl)
+ .model("ernie-3.5-8k") // 可选择其他模型
+ .build();
+
+ // 执行搜索
+ String query = "如何解决交通拥堵问题?";
+ List results = repository.search(query);
+
+ // 输出结果
+ System.out.println("搜索查询: " + query);
+ System.out.println("结果数量: " + results.size());
+
+ results.forEach(doc -> {
+ String type = (String) doc.getMetadata().get("type");
+ System.out.println("类型: " + type);
+ System.out.println("标题: " + doc.getTitle());
+
+ if ("ai_answer".equals(type)) {
+ // AI回答通常较长,完整显示
+ System.out.println("AI回答: " + doc.getContent());
+ } else {
+ // 搜索结果显示摘要
+ System.out.println("内容: " + doc.getContent().substring(0, Math.min(200, doc.getContent().length())) + "...");
+ System.out.println("URL: " + doc.getUrl());
+ }
+ System.out.println("来源: " + doc.getMetadata().get("source"));
+ System.out.println("---");
+ });
+ }
+
+ /**
+ * 自定义配置示例
+ */
+ public static void customConfigExample(String apiKey) throws Exception {
+ System.out.println("\n=== 自定义配置示例 ===");
+
+ // 创建自定义配置的Repository
+ BaiduAiSearchRepository repository = BaiduAiSearchRepository.of(BaiduAiSearchRepository.SearchType.AI)
+ .apiKey(apiKey)
+ .apiUrl(apiUrl)
+ .model("ernie-4.0-turbo-8k") // 使用showSupportedModels里面的模型
+ .build();
+
+ // 执行搜索
+ String query = "DeepSeek-R1模型的特点和优势";
+ List results = repository.search(query);
+
+ // 输出结果
+ System.out.println("搜索查询: " + query);
+ System.out.println("使用模型: deepseek-r1");
+ System.out.println("结果数量: " + results.size());
+
+ results.forEach(doc -> {
+ System.out.println("类型: " + doc.getMetadata().get("type"));
+ System.out.println("标题: " + doc.getTitle());
+ System.out.println("内容: " + doc.getContent().substring(0, Math.min(300, doc.getContent().length())) + "...");
+ System.out.println("---");
+ });
+ }
+
+ /**
+ * 支持的模型列表示例
+ */
+ public static void showSupportedModels() {
+ System.out.println("\n=== 支持的模型列表 ===");
+ System.out.println("1. ernie-3.5-8k (默认)");
+ System.out.println("2. ernie-4.0-turbo-8k (支持图文混排)");
+ System.out.println("3. ernie-4.0-turbo-128k (支持图文混排)");
+ System.out.println("4. ernie-4.0-8k-preview");
+ System.out.println("5. deepseek-r1");
+ System.out.println("6. deepseek-v3");
+ System.out.println("7. ernie-4.5-turbo-32k");
+ System.out.println("8. ernie-4.5-turbo-128k");
+ }
+
+ /**
+ * API Key获取说明
+ */
+ public static void showApiKeyGuide() {
+ System.out.println("\n=== API Key获取指南 ===");
+ System.out.println("1. 访问百度AppBuilder控制台");
+ System.out.println("2. 点击API Key进行创建");
+ System.out.println("3. 服务选择:千帆AppBuilder");
+ System.out.println("4. 确定即可获得API Key");
+ System.out.println("5. 格式:Bearer+");
+ }
+}