Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Spring AI实战之二:Chat API基础知识大串讲(重要)

Spring AI实战之二:Chat API基础知识大串讲(重要)

作者头像
程序员欣宸
发布于 2024-05-27 00:14:48
发布于 2024-05-27 00:14:48
2.2K18
代码可运行
举报
文章被收录于专栏:实战docker实战docker
运行总次数:8
代码可运行
欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

Spring AI实战全系列链接
  1. Spring AI实战之一:快速体验(OpenAI)
  2. Spring AI实战之二:Chat API基础知识大串讲(重要)
  3. SpringAI+Ollama三部曲之一:极速体验
  4. SpringAI+Ollama三部曲之二:细说开发
本篇概览
  • 如果说前文是最简单的介绍Spring AI,满足Java程序员的好奇心,那么本篇就是正儿八经的基础课了:梳理Spring AI框架中的Chat核心API、类、接口,SpringAI的能力就是依靠它们释放出来的
  • 本篇的目标:学习SpringAI库的最基本的类、接口、API,并了解它们的具体用途
用一个问题开篇
  • 首先回答一个问题,为什么标题是Chat API基础知识,而不是Spring AI基础知识?
  • 因为Spring AI内部由很多部分组成,Chat只是其中之一,或者说大模型提供的能力有很多,聊天只是其中一部分,SpringAI提供的能力如下所示
  • 所以,Spring AI的内容很多,Chat只是其中一部分,但是这部分非常重要且基础,适合用来入门
  • 接下来开始正式学习吧,东西不多,总结下来就是:六个概念+三个层次,掌握了它们,各种大模型都能轻松驾驭了
关于Chat API的六个核心概念和三个层次
  • 从业务逻辑上看,Chat API涉及到六个概念,分为三类,如下图所示
  1. client:这个好理解,代表各模型的客户端,负责请求和响应的
  2. prompt:理解成请求的最外层封装,里面有message和option
  3. message:这个好理解了,发送到大模型的内容,另外还包含了一些属性在里面,以及消息类型
  4. option:相当于参数、控制项,例如本次对话的temperature(值越小,大模型回答越严谨,值越大,大模型回答越有创造性)
  5. response:响应对象,里面封装了大模型返回的信息,主要是generation
  6. geenration:这里面是具体的返回内容
  7. 再来看三个层次,前面我们知道SpringAI支持大模型的多种能力,聊天只是其中一种,因此就有一个代表最顶层的抽象层,与大模型有关的各种能力,都在此有个定义,然后是代表各种能力的抽象层,如聊天、图片、嵌入式处理等,最后是每一种能力在各类具体大模型上的实现,如下图所示
  • 到现在为止咱们还没有看一行代码一个API,但是从理论上对Chat API的定位、关系已经基本了解了,是时候结合代码来看了
官方图
  • 下图来自官方文档,结合前面的分析来看一下,后面有导读
  • 先看最下面橙色这层,中间是client,这里有两种,ModelClient代表了常规的请求响应,StreamingModelClient代表了流式响应(数据并非一次性传输,而是建立链接后源源不断的输出)
  • client的左侧是request,里面包含了option,至于prompt,那是Chat的概念,所以不会出现在橙色这一层
  • client右侧是response,同样只有抽象的ResponseMeta和ResultMetaData,generation是Chat的概念,不会在橙色这一层出现
  • 再往上看,绿色的就是功能抽象层了,ChatClient继承了ModelClient,Prompt继承了ModelRequest,代表Chat领域的请求,同理CharResponse继承了ModelResponse
  • 有了理论基础,一张官方图就让我们看清了Chat API的大概,现在还缺点东西,就是具体的实现层,毕竟有很多种大模型能,最终编码时还是要用到实现层的类,有没有什么方式将实现层完美的展现出来?
  • 感谢SpringAI官方,实现层和功能抽象层的关系,被下面的官方图梳理得清清楚楚
  • 此刻再来回顾Spring AI实战之一:快速体验(OpenAI)一文的代码,如下所示,尽管调用了OpenAI的接口,但是并未看到OpenAI相关的类,这是因为Spring已经做好了封装,咱们直接用依赖注入的ChatClient即可,这是抽象层接口,具体实现是SpringAI根据propeties的配置实例化的OpeAIChatClient对象
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.bolingcavalry.helloopenai.controller;

import org.springframework.ai.chat.ChatClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;


import java.util.Map;

@RestController
public class SimpleAiController {
	// 负责处理OpenAI的bean,所需参数来自properties文件
	private final ChatClient chatClient;

	public SimpleAiController(ChatClient chatClient) {
		this.chatClient = chatClient;
	}

	@PostMapping("/ai/simple")
	public Map<String, String> completion(@RequestBody Map<String,String> map) {
		return Map.of("generation", chatClient.call(map.get("message")));
	}
}
  • 其实说到这里,您已经对Chat API有了比较清晰的理解了,来看看那六大概念的具体代码吧,接下来是一段自然的、水到渠成的体验,毕竟已经领会了其神,现在是观其形的时候
  • 接下来要看的代码如下图所示
ChatClient
  • 大模型聊天功能的客户端接口,在进程中,其实现就是各大模型对应的客户端类
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface ChatClient extends ModelClient<Prompt, ChatResponse> {

	default String call(String message) {// implementation omitted
	}

    @Override
	ChatResponse call(Prompt prompt);
}
  • 可见主要是call方法,这就是最常规的聊天功能,调用call发送请求,返回值就是大模型的响应
StreamingChatClient
  • 这也是客户端类,用于调用大模型的功能,与ChatClient不同的是,ChatClient是请求响应,返回对象ChatResponse就是大模型返回的全部内容,而StreamingChatClient返回的是Flux,这是流式返回,可以讲大模型的响应进行流式输出,如果您使用过各种大模型聊天工具,会发现响应的内容并非一次性展现,而是一段一段的内容,持续不断的展现出来,这就是流式响应的效果
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@FunctionalInterface
public interface StreamingChatClient extends StreamingModelClient<Prompt, ChatResponse> {

	default Flux<String> stream(String message) {
		Prompt prompt = new Prompt(message);
		return stream(prompt).map(response -> (response.getResult() == null || response.getResult().getOutput() == null
				|| response.getResult().getOutput().getContent() == null) ? ""
						: response.getResult().getOutput().getContent());
	}

	@Override
	Flux<ChatResponse> stream(Prompt prompt);

}
  • 注意注解FunctionalInterface,表明这是个函数式接口
Prompt
  • 前面看过了ChatClient和StreamingChatClient,会发现入参都是Prompt,可见这就是和大模型一次聊天的入参
  • 下面是Prompt的源码,去掉了构造函数、toString这些之后就会发现,最重要的是Message和ChatOption,所以Prompt只是个打包,真正要提交到大模型的其实是Message和ChatOption
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Prompt implements ModelRequest<List<Message>> {

    private final List<Message> messages;

    private ChatOptions modelOptions;

	@Override
	public ChatOptions getOptions() {..}

	@Override
	public List<Message> getInstructions() {...}
	
	public String getContents() {
		StringBuilder sb = new StringBuilder();
		for (Message message : getInstructions()) {
			sb.append(message.getContent());
		}
		return sb.toString();
	}
    // constructors and utility methods omitted
}
  • 如果您对OpenAI有所了解,就知道prompt(提示词)并非只有用户输入的聊天内容那么简单,而是system、user 、assistant等多种类型 ,所以这里的Prompt并非只是一个外壳那么简单,它与不同类型的message、不同的辅助类等一起提供了完善的提示词功能,这个会有单独的文章来说明和实战,本篇只要记得它的最终形态就是打好的包用于提交给大模型
  • 如果只是最基本的聊天,下面这个构造方法来创建对象就行了
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	public Prompt(String contents) {
		this(new UserMessage(contents));
	}
Message
  • Message很好理解:在聊天过程中,聊天内容对应的对象,请求和响应用的都是Message,不过由于消息类型的多样性,Message被设计成了接口,根据不同类型都有对应的实现,如下图所示
  • Message自身非常简单,能保证使用方取到消息内容、类型即可
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Message {

	String getContent();

	List<Media> getMedia();

	Map<String, Object> getProperties();

	MessageType getMessageType();

}
  • 另外要注意的是消息类型,一共四种
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public enum MessageType {

	USER("user"),

	ASSISTANT("assistant"),

	SYSTEM("system"),

	FUNCTION("function");
ChatOptions
  • ChatOptions代表可以传递给大模型的控制参数,具体有哪些参数和大模型自身开放的特性有关,举个例子,下面是OpenAI开放的参数
  • presencePenalty : 影响模型在生成文本时重复词语或概念的倾向
  • frequencyPenalty:影响模型在生成文本时对已出现过词语的偏好程度
  • 按照上面的解释,既然各种大模型都有自己的参数,那么设计ChatOptions能干啥?应该能放一些通用的控制参数吧,打开代码一看果然如此,共有三个通用参数,我都加了中文注释,另外请关注类的注释,也说明了这些参数是通用的、可移植、夸模型
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * The ChatOptions represent the common options, portable across different chat models.
 */
public interface ChatOptions extends ModelOptions {
	// 大模型生成的内容应该更严谨还是更有创造性
	Float getTemperature();
	// 返回概率超过P的所有内容
	Float getTopP();
	// 返回概率最高的前K个内容
	Integer getTopK();
}
  • ChatOptions只是接口,对应的实现是ChatOptionsImpl,源码没啥好看的,就是temperature、topP、topK的get和set而已,为了实例化ChatOptionsImpl,还有配套工具ChatOptionsBuilder,用法如下
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ChatOptions portablePromptOptions = ChatOptionsBuilder.builder()
			.withTemperature(0.9f)
			.withTopK(100)
			.withTopP(0.6f)
			.build();
  • 代码看到这里,长期CRUD的我不禁产生一个想法:ChatOptions接口应该很不实用,而且用起来也很别扭,因为各大模型特有的参数和这个接口都没有关系,去看了下OpenAiChatClient.java(Ollama的客户端实现类,里面有段代码是用来封装请求的),果然,这代码真是不够优雅(个人感觉)
ChatResponse
  • 看完请求该看响应了,既然Generation才是真正的响应内容,那么ChatResponse也就是个壳,里面包了Generation,打开源码一看,只有Generation和ChatResponseMetadata,这个ChatResponseMetadata可以理解为元信息,主要返回了大模型的API的使用情况说明,以及限速的详细信息
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ChatResponse implements ModelResponse<Generation> {

    private final ChatResponseMetadata chatResponseMetadata;
	private final List<Generation> generations;

	@Override
	public ChatResponseMetadata getMetadata() {...}

    @Override
	public List<Generation> getResults() {...}

    // other methods omitted
}
Generation
  • Generation中有响应的具体信息,由ChatGenerationMetadata和AssistantMessage组成
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Generation implements ModelResult<AssistantMessage> {

	private AssistantMessage assistantMessage;
	private ChatGenerationMetadata chatGenerationMetadata;

	@Override
	public AssistantMessage getOutput() {...}

	@Override
	public ChatGenerationMetadata getMetadata() {...}

    // other methods omitted
}
  • ChatGenerationMetadata代表返回内容的元信息,包含了结束原因、生成内容的过滤规则
  • AssistantMessage更容易理解了:类型是ASSISTANT的消息,这个assistant就是助理角色,assistant消息就是大模型返回的聊天响应,源码如下
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AssistantMessage extends AbstractMessage {

	public AssistantMessage(String content) {
		super(MessageType.ASSISTANT, content);
	}

	public AssistantMessage(String content, Map<String, Object> properties) {
		super(MessageType.ASSISTANT, content, properties);
	}

	@Override
	public String toString() {
		return "AssistantMessage{" + "content='" + getContent() + '\'' + ", properties=" + properties + ", messageType="
				+ messageType + '}';
	}

}
  • 至此,基础理论知识已经过了一遍,相信大家和我一样,进入了一看就会,一用就废的微妙阶段,不急,下一篇就是精彩的实战篇,这些知识点终究会在实战中用到,随着一行行代码一次次请求被理解,最终融汇贯通
你不孤单,欣宸原创一路相伴
  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
优雅的方式是什么呢?参考slf4j,门面模式?
优雅的方式是什么呢?参考slf4j,门面模式?
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
聊聊Spring AI的Chat Model
spring-ai-core/src/main/java/org/springframework/ai/model/Model.java
code4it
2025/04/01
1190
聊聊Spring AI的Chat Model
Spring AI之ChatClient源码分析
ChatClient 是一个接口,它定义了一个与聊天服务交互的客户端。这个接口主要用于创建聊天客户端对象,设置请求规范,以及发起聊天请求。以下是接口中各个方法的详细解释:
jack.yang
2025/04/05
1150
聊聊Spring AI的Prompt
org/springframework/ai/chat/prompt/Prompt.java
code4it
2025/04/14
580
聊聊Spring AI的Prompt
聊天客户端(Chat Client) API
ChatClient,它提供了一个流畅的 API,用于与 AI 模型进行通信。 它支持同步编程模型和响应式编程模型。
jack.yang
2025/04/05
680
已完结,已上线,Java 生产应用级项目!
大家好,我是技术UP主小傅哥。今天来带大家体验一下 Spring AI 的 Easy 开发!
小傅哥
2024/05/28
2760
已完结,已上线,Java 生产应用级项目!
聊聊Spring AI的Tool Calling
org/springframework/ai/tool/ToolCallback.java
code4it
2025/04/13
860
聊聊Spring AI的Tool Calling
聊聊Spring AI的Prompt
org/springframework/ai/chat/prompt/Prompt.java
code4it
2025/04/13
580
聊聊Spring AI的Prompt
聊聊Spring AI的Tool Calling
org/springframework/ai/tool/ToolCallback.java
code4it
2025/04/11
1550
聊聊Spring AI的Tool Calling
SpringAI+Ollama三部曲之二:细说开发
程序员欣宸
2024/05/26
2K0
SpringAI+Ollama三部曲之二:细说开发
0帧起手将腾讯混元大模型集成到Spring AI的全过程解析
在前面,我们已经为大家铺垫了大量的知识点,并深入解析了Spring AI项目的相关内容。今天,我们将正式进入实战环节,从零开始,小雨将带领大家一步步完成将第三方大模型集成到Spring AI中的全过程。为了方便讲解,本次实战的示范将以腾讯的混元大模型为主,我们将逐步向你展示如何将该大模型嵌入到Spring AI中,并利用其强大的能力,帮助你个性化地完成企业级Agent的智能体开发。
努力的小雨
2025/01/26
5457
Spring AI 开发专属于你的AI聊天机器人
聊天机器人不仅提高了效率,还改善了用户体验,它们可以24/7不间断地为客户提供服务,解答常见问题
菜菜的后端私房菜
2024/11/08
2201
使用Spring AI调用AI模型
Spring AI是Spring框架对人工智能和机器学习的支持模块,它提供了一套简单易用的API来集成各种AI服务和模型。
阿珍
2025/03/27
1860
使用Spring AI调用AI模型
聊聊Spring AI的Evaluator
spring-ai-client-chat/src/main/java/org/springframework/ai/evaluation/Evaluator.java
code4it
2025/04/15
500
聊聊Spring AI的Evaluator
深度解析Spring AI:请求与响应机制的核心逻辑
我们在前面的两个章节中基本上对Spring Boot 3版本的新变化进行了全面的回顾,以确保在接下来研究Spring AI时能够避免任何潜在的问题。今天,我们终于可以直接进入主题:Spring AI是如何发起请求并将信息返回给用户的。
努力的小雨
2024/09/29
3850
深入解析 Spring AI 系列:解析函数调用
我们之前讨论并实践过通过常规的函数调用来实现 AI Agent 的设计和实现。但是,有一个关键点我之前并没有详细讲解。今天我们就来讨论一下,如何让大模型只决定是否调用某个函数,但是Spring AI 不会在内部处理函数调用,而是将其代理到客户端。然后,客户端负责处理函数调用,将其分派到相应的函数并返回结果。
努力的小雨
2025/01/12
3280
深入探索Spring AI:源码分析流式回答
在上一章节中,我们深入分析了Spring AI的阻塞式请求与响应机制,并探讨了如何增强其记忆能力。今天,我们将重点讲解流式响应的概念与实现。毕竟,AI的流式回答功能与其交互体验密切相关,是提升用户满意度的重要组成部分。
努力的小雨
2024/09/30
3290
Spring AI实战之一:快速体验(OpenAI)
程序员欣宸
2024/05/26
2.1K0
Spring AI实战之一:快速体验(OpenAI)
聊聊Spring AI的Advisors
org/springframework/ai/chat/client/advisor/api/Advisor.java
code4it
2025/03/30
830
聊聊Spring AI的Advisors
聊聊Spring AI的Evaluator
spring-ai-client-chat/src/main/java/org/springframework/ai/evaluation/Evaluator.java
code4it
2025/04/14
710
聊聊Spring AI的Evaluator
深入解析 Spring AI 系列:解析请求参数处理
大家在使用Spring AI项目开发Agent时,可能会发现,尽管外层的接口设计和调用逻辑比较统一,但实际上每个第三方接口在实现时都会有一些微妙的差异。这些差异可能体现在请求参数的构造、数据格式的处理,或者是某些接口特有的配置选项上。因此,今天我们主要聚焦于Spring AI在实际调用接口之前,如何处理和构造请求参数的过程。以下是核心代码示意:
努力的小雨
2025/01/18
2000
相关推荐
聊聊Spring AI的Chat Model
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验