diff --git a/__release/solon-ai-bundle1/pom.xml b/__release/solon-ai-bundle1/pom.xml index f4449e34c9c71d865850ff7bb93d1cda23538d7a..7ee6d66f51334808310a868048b7dabfa6a9046d 100644 --- a/__release/solon-ai-bundle1/pom.xml +++ b/__release/solon-ai-bundle1/pom.xml @@ -43,5 +43,7 @@ ../../solon-ai-rag-repositorys/solon-ai-repo-qdrant ../../solon-ai-rag-repositorys/solon-ai-repo-redis ../../solon-ai-rag-repositorys/solon-ai-repo-tcvectordb + + ../../solon-ai-rag-searchs/solon-ai-search-baidu - \ No newline at end of file + diff --git a/solon-ai-rag-searchs/solon-ai-search-baidu/README.md b/solon-ai-rag-searchs/solon-ai-search-baidu/README.md new file mode 100644 index 0000000000000000000000000000000000000000..74c423e2577ed611a2ed6400f909cb15fb9aaf0c --- /dev/null +++ b/solon-ai-rag-searchs/solon-ai-search-baidu/README.md @@ -0,0 +1,33 @@ +# Solon AI Search Baidu + +**solon-ai-search-baidu** 是 Solon AI 生态系统的一部分,提供对百度 AI 搜索服务的集成支持。该模块实现了 `Repository` 接口,支持基础搜索和 AI 智能搜索两种模式。 + +## 🔧 配置 + +### 1. 获取 API Key + +访问 [百度智能云控制台](https://console.bce.baidu.com/iam/#/iam/apikey/list) 获取 AppBuilder API Key: + +1. 登录百度智能云控制台 +2. 进入"API Key管理"页面 +3. 点击"创建API Key" +4. 选择服务:千帆AppBuilder +5. 确认创建,获得 API Key + +### 2. API Key 格式 + +``` +格式:bce-v3/ALTAK-xxxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx +``` + +## 📖 快速开始 + +参考以下测试代码: + +- **基础使用示例**: [BaiduAiSearchExample.java](src/test/java/features/ai/example/BaiduAiSearchExample.java) +- **完整测试用例**: [BaiduAiSearchTest.java](src/test/java/features/ai/BaiduAiSearchTest.java) +- **测试工具配置**: [TestUtils.java](src/test/java/features/ai/TestUtils.java) + + + +**注意**: 使用本模块需要有效的百度AppBuilder API Key,请确保遵守百度的服务条款和使用限制。 \ No newline at end of file diff --git a/solon-ai-rag-searchs/solon-ai-search-baidu/pom.xml b/solon-ai-rag-searchs/solon-ai-search-baidu/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..8b7b1ddeb304f40c47a6d9b69f1734f75b43851b --- /dev/null +++ b/solon-ai-rag-searchs/solon-ai-search-baidu/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + org.noear + solon-ai-parent + 3.4.0 + ../../solon-ai-parent/pom.xml + + + solon-ai-search-baidu + ${project.artifactId} + jar + + + + org.noear + solon-ai + + + + org.noear + solon-test + test + + + + org.noear + solon-logging-simple + test + + + + diff --git a/solon-ai-rag-searchs/solon-ai-search-baidu/src/main/java/org.noear.solon.ai.rag.search/BaiduAiSearchRepository.java b/solon-ai-rag-searchs/solon-ai-search-baidu/src/main/java/org.noear.solon.ai.rag.search/BaiduAiSearchRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..4145881340c8b3702fcd5e19d133915d9ff7db21 --- /dev/null +++ b/solon-ai-rag-searchs/solon-ai-search-baidu/src/main/java/org.noear.solon.ai.rag.search/BaiduAiSearchRepository.java @@ -0,0 +1,308 @@ +/* + * Copyright 2017-2025 noear.org and authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.noear.solon.ai.rag.search; + +import org.noear.snack.ONode; +import org.noear.solon.ai.AiConfig; +import org.noear.solon.ai.embedding.EmbeddingModel; +import org.noear.solon.ai.rag.Document; +import org.noear.solon.ai.rag.Repository; +import org.noear.solon.ai.rag.util.QueryCondition; +import org.noear.solon.ai.rag.util.SimilarityUtil; +import org.noear.solon.lang.Nullable; +import org.noear.solon.net.http.HttpUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * 百度AI搜索Repository(支持基础搜索和AI搜索) + *

+ * 基于百度AI搜索V2接口实现的Repository,支持两种搜索模式: + * - 基础搜索:返回搜索结果列表,不传model参数 + * - AI搜索:结合大模型进行智能总结,传入model参数 + *

+ * + *

+ * API文档参考:API文档参考 + *

+ * + * @author yangbuyiya + * @since 3.0 + */ +public class BaiduAiSearchRepository implements Repository { + + private final AiConfig config; + private final SearchType searchType; + private final String model; + private final @Nullable EmbeddingModel embeddingModel; + + /** + * 私有构造函数,使用Builder模式创建实例 + */ + private BaiduAiSearchRepository(AiConfig config, SearchType searchType, String model, EmbeddingModel embeddingModel) { + this.config = config; + this.searchType = searchType != null ? searchType : SearchType.BASIC; + this.model = model != null ? model : "ernie-3.5-8k"; + this.embeddingModel = embeddingModel; + } + + /** + * 创建基础搜索Builder实例 + */ + public static BaiduAiSearchRepositoryBuilder ofBasic() { + return new BaiduAiSearchRepositoryBuilder(SearchType.BASIC); + } + + /** + * 创建AI搜索Builder实例 + */ + public static BaiduAiSearchRepositoryBuilder ofAI() { + return new BaiduAiSearchRepositoryBuilder(SearchType.AI); + } + + /** + * 创建指定类型的Builder实例 + */ + public static BaiduAiSearchRepositoryBuilder of(SearchType searchType) { + return new BaiduAiSearchRepositoryBuilder(searchType); + } + + @Override + public List search(QueryCondition condition) throws IOException { + String query = condition.getQuery(); + if (query == null || query.trim().isEmpty()) { + return new ArrayList<>(); + } + + // 创建HttpUtils实例 + HttpUtils httpUtils = config.createHttpUtils(); + + // 构建请求体 + ONode requestBody = new ONode(); + + // 构建messages(两种模式都需要) + ONode messagesArray = requestBody.getOrNew("messages").asArray(); + ONode message = messagesArray.addNew(); + message.set("role", "user"); + message.set("content", query.trim()); + + // 根据搜索类型添加不同参数 + if (searchType == SearchType.AI) { + // AI搜索:需要传入model参数 + requestBody.set("model", model); + requestBody.set("stream", false); + requestBody.set("enable_corner_markers", true); + requestBody.set("enable_deep_search", false); // 默认不开启深搜索,后续扩展 + requestBody.set("enable_followup_queries", false); // 默认不开启追问,后续扩展 + } + // 基础搜索:不传model参数,将自动识别为基础搜索模式 + + // 支持limit参数 + if (condition.getLimit() > 0) { + ONode resourceTypeFilter = requestBody.getOrNew("resource_type_filter").asArray().addNew(); + resourceTypeFilter.set("type", "web"); + resourceTypeFilter.set("top_k", condition.getLimit()); + } + + // 设置认证头 + httpUtils.header("X-Appbuilder-Authorization", "Bearer " + config.getApiKey()); + httpUtils.header("Content-Type", "application/json"); + + // 发送请求 + String respJson = httpUtils.bodyOfJson(requestBody.toJson()) + .post(); + + return parseResponse(respJson, condition); + } + + /** + * 解析响应结果 + */ + private List parseResponse(String respJson, QueryCondition condition) throws IOException { + ONode respNode = ONode.load(respJson); + + // 检查错误 + if (respNode.contains("code")) { + int code = respNode.get("code").getInt(); + String message = respNode.get("message").getString(); + if (code != 0) { + throw new IOException("BaiduAiSearch error (code=" + code + "): " + message); + } + } + + List 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+"); + } +}