pom 依赖
1
2
3
4
5
|
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M6.1</version>
</dependency>
|
核心 yml
1
2
3
4
5
6
7
|
spring:
ai:
dashscope:
api-key:
chat:
options:
model: qwen-plus
|
Controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
@RestController
@RequestMapping("/ai")
public class AiController {
@Resource
private AiService aiService;
/**
* 发送问题
* @param msg
* @return
*/
@GetMapping(value = "/chat/sse",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter chatSse(String msg) {
return aiService.chatSse(msg);
}
/**
* 发送问题
* @param msg
* @return
*/
@GetMapping(value = "/chat/flux",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chatWebFlux(String msg) {
return aiService.chatWebFlux(msg);
}
@GetMapping(value = "/chat/flux/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> chatFluxSse(String msg) {
return aiService.chatWebFlux(msg)
.map(data -> ServerSentEvent.builder(data).build());
}
}
|
ServiceImpl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
@Slf4j
@Service
public class AiServiceImpl implements AiService {
@Resource
BeanFactory beanFactory;
@Resource
LoginUserChatStrategyFactory loginUserChatStrategyFactory;
@Override
public Flux<String> chatWebFlux(String msg) {
Long userId = UserContext.getUser();
ChatStrategy chatStrategy;
if(userId!=null){
chatStrategy = loginUserChatStrategyFactory.create(userId);
}else {
chatStrategy = beanFactory.getBean(AnonymousUserChatStrategy.class);
}
return chatStrategy.processMessage(msg);
}
@Override
public SseEmitter chatSse(String msg) {
Long userId = UserContext.getUser();
ChatStrategy chatStrategy;
if(userId!=null){
chatStrategy = loginUserChatStrategyFactory.create(userId);
}else {
chatStrategy = beanFactory.getBean(AnonymousUserChatStrategy.class);
}
// 创建一个超时时间较长的 SseEmitter 3 分钟超时
SseEmitter sseEmitter = new SseEmitter(180000L);
Flux<String> ccontentFlux = chatStrategy.processMessage(msg);
ccontentFlux.subscribe(chunk -> {
try {
sseEmitter.send(chunk);
// Thread.sleep(1000);
} catch (Exception e) {
sseEmitter.completeWithError(e);
}
}, sseEmitter::completeWithError, sseEmitter::complete);
return sseEmitter;
}
}
|
ChatStrategy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class LoginUserChatStrategy implements ChatStrategy{
private Long userId;
@Resource
private ChatClient chatClient;
public LoginUserChatStrategy(Long userId,ChatClient chatClient) {
this.chatClient = chatClient;
this.userId = userId;
}
/**
* 登录用户消息持久化最大100条
* @param msg
* @return
*/
@Override
public Flux<String> processMessage(String msg) {
return chatClient.prompt().user(msg)
.advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, userId)
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
.stream()
.content();
}
}
|
自定义日志 Advisor
打印 info 级别日志、只输出单次用户提示词和 AI 回复的文本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
@Slf4j
public class MyLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
/**
* 每个advisor的名字
* @return
*/
@Override
public String getName() {
return this.getClass().getSimpleName();
}
/**
* advisor的优先级
* @return
*/
@Override
public int getOrder() {
return 0;
}
@Override
public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
advisedRequest = before(advisedRequest);
AdvisedResponse advisedResponse = chain.nextAroundCall(advisedRequest);
observeAfter(advisedResponse);
return advisedResponse;
}
@Override
public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
advisedRequest = before(advisedRequest);
Flux<AdvisedResponse> advisedResponses = chain.nextAroundStream(advisedRequest);
return new MessageAggregator().aggregateAdvisedResponse(advisedResponses, this::observeAfter);
}
private void observeAfter(AdvisedResponse advisedResponse) {
log.info("AI Response: {}", advisedResponse.response().getResult().getOutput().getText());
}
private AdvisedRequest before(AdvisedRequest request) {
log.info("AI Request: {}", request.userText());
return request;
}
}
|
自定义 Re2 Advisor
可提高大型语言模型的推理能力
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
public class ReReadingAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
/**
* 执行请求前,改写 Prompt
* @param advisedRequest
* @return
*/
private AdvisedRequest before(AdvisedRequest advisedRequest) {
Map<String, Object> advisedUserParams = new HashMap<>(advisedRequest.userParams());
advisedUserParams.put("re2_input_query", advisedRequest.userText());
return AdvisedRequest.from(advisedRequest)
.userText("""
{re2_input_query}
Read the question again: {re2_input_query}
""")
.userParams(advisedUserParams)
.build();
}
@Override
public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
return chain.nextAroundCall(this.before(advisedRequest));
}
@Override
public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
return chain.nextAroundStream(this.before(advisedRequest));
}
@Override
public int getOrder() {
return 1;
}
@Override
public String getName() {
return this.getClass().getSimpleName();
}
}
|