当前最热门的ai话题估计都是围绕着deepseek展开的。我也趁着这波热度来学习并记录一下。
目前主要有无代码平台:Dify 和Coze
javaAi的编码平台有:SpringAi 和 LangChain4j
当前模型可选择:OpenAi、阿里百炼、DeepSeek、智谱清言、硅基流动、Ollma(本地ai容器)
开源库:LangChain4j 。 使用它可接入各大模型,便于java开发者对大模型的api调用与集成。
使用阿里百炼平台进行测试 链接
使用硅基流动链接
新建一个sprintboot项目,采用maven管理依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
</dependency>
<!-- 加载bom 后,所有langchain4j引用不需要加版本号 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId>
<version>0.36.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
yaml 配置文件:
langchain4j:
open-ai:
chat-model:
# 课程测试 KEY,需要更换为实际可用 KEY
api-key: sk-xx
model-name: qwen-turbo
# 百炼兼容OpenAI接口规范,base_url为https://dashscope.aliyuncs.com/compatible-mode/v1
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
本人进行复制操作时遇到的问题:在拷贝yaml配置文件的时候漏了 langchain4j: 节点,导致spring注入依赖没有办法匹配到配置文件,因此报错:
@Bean
@ConditionalOnProperty({"langchain4j.open-ai.chat-model.api-key"})
OpenAiChatModel openAiChatModel(Properties properties) {
ChatModelProperties chatModelProperties = properties.getChatModel();
return OpenAiChatModel.builder().baseUrl(chatModelProperties.getBaseUrl()).apiKey(chatModelProperties.getApiKey()).organizationId(chatModelProperties.getOrganizationId()).modelName(chatModelProperties.getModelName()).temperature(chatModelProperties.getTemperature()).topP(chatModelProperties.getTopP()).stop(chatModelProperties.getStop()).maxTokens(chatModelProperties.getMaxTokens()).maxCompletionTokens(chatModelProperties.getMaxCompletionTokens()).presencePenalty(chatModelProperties.getPresencePenalty()).frequencyPenalty(chatModelProperties.getFrequencyPenalty()).logitBias(chatModelProperties.getLogitBias()).responseFormat(chatModelProperties.getResponseFormat()).strictJsonSchema(chatModelProperties.getStrictJsonSchema()).seed(chatModelProperties.getSeed()).user(chatModelProperties.getUser()).strictTools(chatModelProperties.getStrictTools()).parallelToolCalls(chatModelProperties.getParallelToolCalls()).timeout(chatModelProperties.getTimeout()).maxRetries(chatModelProperties.getMaxRetries()).proxy(ProxyProperties.convert(chatModelProperties.getProxy())).logRequests(chatModelProperties.getLogRequests()).logResponses(chatModelProperties.getLogResponses()).customHeaders(chatModelProperties.getCustomHeaders()).build();
}
chatAi :LLM API 调用
@Bean
public ChatLanguageModel chatLanguageModel() {
return OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName("qwen-turbo")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
@Bean
public ChatAssistant chatAssistant(ChatLanguageModel chatLanguageModel){
return AiServices.create(ChatAssistant.class,chatLanguageModel);
}
chat流式输出
使用spring controller进行web端的调用
/**
* 测试controller
* lp
* 2025年02月19日15:54:39
* */
@RestController
@RequiredArgsConstructor
@RequestMapping("/test01")
public class ChatTestController01 {
private final StreamChatAssistant streamChatAssistant;
/**
* 前端流式调用
* @param question
* http://127.0.0.1:8080/test01/chat/stream?question="hello"
* */
@GetMapping("/chat/stream")
public Flux<String> chat(@RequestParam("question") String question){
return streamChatAssistant.chat(question);
}
}
chat 的记忆持久化:ChatMemory、实现ChatMemoryStore接口进行自定义持久存储。
在默认情况下持久化内容存储存在内存中
问题解决:有两个 TestBean 类型的 bean注入问题时候。
为了明确指定在创建 时使用哪一个 TestBean,可以在参数上使用 @Qualifier 注解。
以下是具体的修改步骤:
在需要注入的地方使用 @Qualifier 注解:
参数中添加 @Qualifier("TestBean01"),以明确指定使用 TestBean01 这个 bean。
如果你需要在其他地方使用 TestBean02,也可以类似地使用 @Qualifier("TestBean02")。
提示词工程:系统级提示词、用户提示词模板
SystemMessage具有高优先级,能有效地指导模型的整体行为
1. 使用 @UserMessage 和 @V 注解:
public interface AiAssistant {
@SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'")
@UserMessage("请回答以下法律问题:{{question}}")
String answerLegalQuestion(@V("question") String question);
}
2. 使用 @StructuredPrompt 定义结构化提示:
@Data
@StructuredPrompt("根据中国{{legal}}法律,解答以下问题:{{question}}")
class LegalPrompt {
private String legal;
private String question;
}
3. 使用 PromptTemplate 渲染:
// 默认 form 构造使用 it 属性作为默认占位符
PromptTemplate template = PromptTemplate.from("请解释中国法律中的'{{it}}'概念。");
Prompt prompt = template.apply("知识产权");
System.out.println(prompt.text()); // 输出: 请解释中国法律中的'知识产权'概念。
// apply 方法接受 Map 作为参数
PromptTemplate template2 = PromptTemplate.from("请解释中国法律中的'{{legal}}'概念。");
Prompt prompt2 = template2.apply(Map.of("legal", "知识产权"));
System.out.println(prompt2.text());
Json格式化输出数据
让大模型输出我们想要的格式的数据方式有几种:指定类型、根据枚举、自定义pojo类
原理为:使用提示词限定结果的输出
/**
* 返回一个pojo自定义数据类型
* 可以使用@Description 注解帮助大模型理解字段含义
* */
@UserMessage("从数据中提取 person 信息 {{it}}")
Person extractPerson(String text);
@Data
class Person {
@Description("姓名") // 增加字段描述,让大模型更理解字段含义
private String name;
private LocalDate birthDate;
}
-------
请求:
method: POST
- url: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions
- headers: [Authorization: Bearer sk-cf...b4], [User-Agent: langchain4j-openai]
- body: {
"model" : "qwen-turbo",
"messages" : [ {
"role" : "user",
"content" : "从数据中提取 person 信息 我叫小明,今年18岁,我是一个学生,我的生日是2005年8月10日\nYou must answer strictly in the following JSON format: {\n\"name\": (姓名; type: string),\n\"birthDate\": (type: date string (2023-12-31))\n}"
} ],
"temperature" : 0.7
}
结果:
{"choices":[{"message":{"role":"assistant","content":"```json\n{\n \"name\": \"小明\",\n \"birthDate\": \"2005-08-10\"\n}\n```"}
注意点:如果没有提取到对应的数据,可能会导致返回的内容错误或者出现异常,需要对大模型额外针对错误数据进行提示处理:
@UserMessage("从数据中提取 person 信息 {{it}}。如果没有提取到,则直接回复:“(name=null, birthDate=1900-01-01)")
Person extractPerson(String text);
函数调用: 触发外部操作:如发送邮件、控制智能家居设备等
方式:
编码注入函数、注解注入函数、动态工具配置
@Bean
public FunctionAssistant functionAssistant(ChatLanguageModel chatLanguageModel) {
// 工具说明 ToolSpecification
ToolSpecification toolSpecification = ToolSpecification.builder()
.name("invoice_assistant")
.description("根据用户提交的开票信息,开具发票")
.addParameter("companyName", type("string"), description("公司名称"))
.addParameter("dutyNumber", type("string"), description("税号"))
.addParameter("amount", type("number"), description("金额"))
.build();
// 业务逻辑 ToolExecutor
ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
String arguments1 = toolExecutionRequest.arguments();
System.out.println("arguments1 =>>>> " + arguments1);
return "开具成功";
};
return AiServices.builder(FunctionAssistant.class)
.chatLanguageModel(chatLanguageModel)
.tools(Map.of(toolSpecification, toolExecutor))
.build();
}
动态函数调用:
接入GraalVM,实现动态函数调用,直接执行代码给出结果,而不是通过推理
CodeExecutionEngine engine = new GraalVmJavaScriptExecutionEngine();
String code = """
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
fibonacci(10)
""";
String result = engine.execute(code);
ChatAssistant assistant = AiServices.builder(ChatAssistant.class)
.chatLanguageModel(chatLanguageModel)
.tools(new GraalVmJavaScriptExecutionTool())
.build();
String chat = chatAssistant.chat("What is the square root of 485906798473894056 in scientific notation?");
System.out.println(chat);
引入的 graalVm 依赖,通过GraalVmJavaScriptExecutionTool类实现了JavaScript代码的动态执行
函数增强搜索:
接入SearchApi 实现大模型直接访问web进行查询数据
public interface ChatAssistant {
@SystemMessage("""
1. 搜索支持:你的职责是为用户提供基于网络搜索的支持。
2. 事件验证:如果用户提到的事件尚未发生或信息不明确,你需要通过网络搜索确认或查找相关信息。
3. 网络搜索请求:使用用户的查询创建网络搜索请求,并通过网络搜索工具进行实际查询。
4. 引用来源:在最终回应中,必须包括搜索到的来源链接,以确保信息的准确性和可验证性。
""")
String chat(String message);
}
@Bean
public ChatAssistant chatAssistant(ChatLanguageModel chatLanguageModel) {
SearchApiWebSearchEngine searchEngine = SearchApiWebSearchEngine.builder()
.apiKey("p8SZVNAweqTtoZBBTVnXttcj")// 测试使用
.engine("google")
.build();
WebSearchTool webSearchTool = WebSearchTool.from(searchEngine);
return AiServices.builder(ChatAssistant.class).chatLanguageModel(chatLanguageModel).tools(webSearchTool).build();
}
String chat = chatAssistant.chat("20241008 上证指数是多少");
System.out.println(chat);
截至2024年10月8日,A股市场迎来了国庆节后的首个交易日,主要指数表现强劲。具体到上证指数,开盘时涨幅达到了10.13%,但之后的走势有所调整,最终收盘时上证指数报收于3489.78点,涨幅为4.59%。这一天,沪深两市的成交额均非常活跃,接近或超过3.5万亿元人民币。
以上信息来源于多个新闻源,包括财新网、观察者网、中国新闻网、新浪财经等,您可以点击提供的链接查看更详细的信息和报道背景。请注意,这些数据和分析仅供参考,市场情况可能会随时变化。
向量化及存储:
Embedding模型是将文本数据(如词汇、短语或句子)转换为数值向量的工具,将文本映射到高维空间中的点,使语义相似的文本在这个空间中距离较近.
@Value("${dashscope.api.key}")
private String apiKey;
private String qdrantHost="127.0.0.1";
private int qdrantPort=6334;
public static String collectionName="testEmbedding01";
/**
* 创建Qdrant客户端
* */
@Bean
public QdrantClient qdrantClient() {
QdrantGrpcClient.Builder grpcClientBuilder = QdrantGrpcClient.newBuilder(qdrantHost, qdrantPort, false);
return new QdrantClient(grpcClientBuilder.build());
}
/**
*使用OpenAI的Embedding模型进行文本向量化
* 这里使用的是阿里百炼平台 text-embedding-v3 向量模型
* */
@Bean
public EmbeddingModel embeddingModel() {
return OpenAiEmbeddingModel.builder()
.apiKey(apiKey)
.modelName("text-embedding-v3")
.logResponses(true)
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
/**
* 配置Qdrant Embedding Store
* */
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
return QdrantEmbeddingStore.builder()
.host(qdrantHost)
.port(qdrantPort)
.collectionName(collectionName)
.build();
}
文本向量化分类:
过TextClassifier接口,结合向量模型,可以完成文本信息的分类,可以应用到性格,心理等测试之中
/**
* 简单的例子:
* 通过TextClassifier,以及文本向量化分类(只支持枚举类型的分类)
* */
@Bean
public EmbeddingModelTextClassifier<PersonalityTrait> textClassifier(EmbeddingModel embeddingModel) {
return new EmbeddingModelTextClassifier(embeddingModel, PersonalityTraitExamples.examples);
}
/**
* 文本向量化分类 测试
* 使用textClassifer,通过EmbeddingModel 向量大模型,最后根据枚举类型得到分类结果
* 可以应用在性格判断,比如说心理方面的评估
* */
@Test
void textClassifier() {
List<PersonalityTrait> personalityTraitList= textClassifier.classify("我最喜欢和别人一起工作了,让我可以学到东西,也可以帮助到其他人,收获很多,通过帮助团队的人,我们可以一起进步和学习");
System.out.println("返回最匹配的性格分类");
System.out.println(personalityTraitList);
}
RAG:检索增强生成(Retrieval-Augmented Generation,简称RAG)是一种结合大型语言模型(LLM)和外部知识库的技术
两个阶段:索引(预处理和存储文档数据为向量数据)和检索(将用户搜索转换为向量进行搜索查询)
检索增强器(Retrieval Augmentor)
@Bean
public ChatAssistant assistant(ChatLanguageModel chatLanguageModel, EmbeddingStore<TextSegment> embeddingStore) {
DefaultRetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
.queryTransformer() // 查询增强
.contentRetriever() // 内容源 单个直接配置
.queryRouter(new DefaultQueryRouter())// 多个内容源,路由
.contentAggregator() // 匹配结果聚合
.contentInjector() // 结果提示词注入
.executor() // 并行化
.build();
return AiServices.builder(ChatAssistant.class)
.chatLanguageModel(chatLanguageModel)
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.retrievalAugmentor(retrievalAugmentor)
.build();
}
@SpringBootTest
public class OllamaTest {
//首先在装有ollama的电脑上启动 : ollama serve, 然后启动模型:ollama run deepseek-r1:7b
String url = "http://192.168.110.77:11434";
String modelName = "deepseek-r1:7b" ;
String embedingModel="bge-m3:latest";
@Test
void test(){
LanguageModel model = OllamaLanguageModel.builder()
.baseUrl(url)
.modelName(modelName)
.build();
String result = model.generate("你是谁").content();
System.out.println(result);
}
}