Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
ask_data_ai_admin
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linyangyang
ask_data_ai_admin
Commits
aba26463
Commit
aba26463
authored
Jul 21, 2025
by
林洋洋
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
模型切换deepseek 使用deepseek的思考
parent
1c71562d
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
142 additions
and
32 deletions
+142
-32
pom.xml
ask-data-ai/ask-data-ai-biz/pom.xml
+4
-0
CommonConfiguration.java
...biz/src/main/java/com/ask/config/CommonConfiguration.java
+9
-1
ChatController.java
...-biz/src/main/java/com/ask/controller/ChatController.java
+38
-30
FluxUtils.java
...sk-data-ai-biz/src/main/java/com/ask/utils/FluxUtils.java
+83
-0
application.yml
...ta-ai/ask-data-ai-boot/src/main/resources/application.yml
+8
-1
No files found.
ask-data-ai/ask-data-ai-biz/pom.xml
View file @
aba26463
...
...
@@ -79,6 +79,10 @@
</dependency>
<!-- Spring AI -->
<dependency>
<groupId>
org.springframework.ai
</groupId>
<artifactId>
spring-ai-starter-model-deepseek
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.ai
</groupId>
<artifactId>
spring-ai-starter-model-openai
</artifactId>
...
...
ask-data-ai/ask-data-ai-biz/src/main/java/com/ask/config/CommonConfiguration.java
View file @
aba26463
...
...
@@ -9,6 +9,7 @@ import org.springframework.ai.chat.memory.ChatMemoryRepository;
import
org.springframework.ai.chat.memory.MessageWindowChatMemory
;
import
org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository
;
import
org.springframework.ai.chat.prompt.PromptTemplate
;
import
org.springframework.ai.deepseek.DeepSeekChatModel
;
import
org.springframework.ai.openai.OpenAiChatModel
;
import
org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor
;
import
org.springframework.ai.rag.generation.augmentation.ContextualQueryAugmenter
;
...
...
@@ -38,7 +39,14 @@ public class CommonConfiguration {
}
@Bean
public
ChatClient
chatClient
(
OpenAiChatModel
model
)
{
public
ChatClient
openAiChatClient
(
OpenAiChatModel
model
)
{
return
ChatClient
.
builder
(
model
)
.
defaultAdvisors
()
.
build
();
}
@Bean
public
ChatClient
deepseekChatClient
(
DeepSeekChatModel
model
)
{
return
ChatClient
.
builder
(
model
)
.
defaultAdvisors
()
.
build
();
...
...
ask-data-ai/ask-data-ai-biz/src/main/java/com/ask/controller/ChatController.java
View file @
aba26463
...
...
@@ -8,29 +8,37 @@ import com.ask.common.core.R;
import
com.ask.service.ChatConversationService
;
import
com.ask.service.impl.ChatService
;
import
com.ask.service.impl.RagPromptService
;
import
com.ask.utils.FluxUtils
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.Parameter
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.ai.chat.client.ChatClient
;
import
org.springframework.ai.chat.client.ChatClientResponse
;
import
org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor
;
import
org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor
;
import
org.springframework.ai.chat.memory.ChatMemory
;
import
org.springframework.ai.chat.messages.*
;
import
org.springframework.ai.chat.model.ChatResponse
;
import
org.springframework.ai.chat.prompt.Prompt
;
import
org.springframework.ai.deepseek.DeepSeekAssistantMessage
;
import
org.springframework.ai.document.Document
;
import
org.springframework.ai.openai.OpenAiChatModel
;
import
org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor
;
import
org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever
;
import
org.springframework.ai.vectorstore.SearchRequest
;
import
org.springframework.ai.vectorstore.VectorStore
;
import
org.springframework.ai.vectorstore.filter.Filter
;
import
org.springframework.ai.vectorstore.filter.FilterExpressionBuilder
;
import
org.springframework.http.MediaType
;
import
org.springframework.web.bind.annotation.*
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
java.util.*
;
import
java.util.concurrent.atomic.AtomicBoolean
;
@Slf4j
@RestController
...
...
@@ -39,7 +47,9 @@ import java.util.*;
@Tag
(
description
=
"ai"
,
name
=
"AI对话模块"
)
public
class
ChatController
{
private
final
ChatClient
chatClient
;
private
final
ChatClient
openAiChatClient
;
private
final
ChatClient
deepseekChatClient
;
private
final
ChatConversationService
chatConversationService
;
...
...
@@ -56,6 +66,7 @@ public class ChatController {
private
final
RagPromptService
ragPromptService
;
private
final
ChatMemory
chatMemory
;
private
final
OpenAiChatModel
openAiChatModel
;
/**
* 获取会话ID
...
...
@@ -84,21 +95,24 @@ public class ChatController {
*
* @return
*/
@Operation
(
summary
=
"普通对话"
,
description
=
"普通对话"
)
@GetMapping
(
value
=
"/chat"
,
produces
=
"text/html;charset=utf-8"
)
public
Flux
<
String
>
chat
(
@Parameter
(
description
=
"对话内容"
)
@RequestParam
String
message
,
@Parameter
(
description
=
"会话ID"
)
@RequestParam
String
conversationId
)
{
// 创建系统消息,告诉大模型只返回工具名和参数
Message
systemMessage
=
new
SystemMessage
(
"你是一个AI客服助手。请严格按照以下格式回答每个问题:"
);
// 用户消息
String
question
=
"请严格按以下格式回答:\n"
+
"<think>\n"
+
"[你的逐步推理过程]\n"
+
"</think>\n"
+
"<answer>\n"
+
"[最终答案]\n"
+
"</answer>\n"
+
"推理过程不要设计`<think>` 和 `<answer>` \n"
+
"问题:"
+
message
+
"\n"
;
Message
userMessage
=
new
UserMessage
(
question
);
// 创建提示,包含系统消息和用户消息
Prompt
prompt
=
new
Prompt
(
Arrays
.
asList
(
systemMessage
,
userMessage
));
// 使用修改后的提示获取响应
return
chatClient
.
prompt
(
prompt
).
advisors
(
messageChatMemoryAdvisor
).
advisors
(
a
->
a
.
param
(
ChatMemory
.
CONVERSATION_ID
,
conversationId
)).
stream
().
content
();
}
@GetMapping
(
value
=
"/chat"
,
produces
=
MediaType
.
TEXT_EVENT_STREAM_VALUE
)
public
Flux
<
String
>
chat
(
@RequestParam
String
message
,
@RequestParam
String
conversationId
)
{
Message
systemMessage
=
new
SystemMessage
(
"你是一个AI问答助手,请用回答用户问题"
);
Message
userMessage
=
new
UserMessage
(
"问题:"
+
message
+
"\n回答要求:请使用markdown格式输出"
);
Prompt
prompt
=
new
Prompt
(
List
.
of
(
systemMessage
,
userMessage
));
AtomicBoolean
reasoningStarted
=
new
AtomicBoolean
(
false
);
AtomicBoolean
answerStarted
=
new
AtomicBoolean
(
false
);
return
FluxUtils
.
wrapDeepSeekStream
(
deepseekChatClient
.
prompt
(
prompt
)
.
advisors
(
messageChatMemoryAdvisor
)
.
advisors
(
a
->
a
.
param
(
ChatMemory
.
CONVERSATION_ID
,
conversationId
))
.
stream
()
.
chatResponse
());
}
/**
* 知识库对话
* <p>
...
...
@@ -107,7 +121,7 @@ public class ChatController {
* @return
*/
@Operation
(
summary
=
"知识库对话"
,
description
=
"知识库对话"
)
@GetMapping
(
value
=
"/rag/chat"
,
produces
=
"text/html;charset=utf-8"
)
@GetMapping
(
value
=
"/rag/chat"
,
produces
=
MediaType
.
TEXT_EVENT_STREAM_VALUE
)
public
Flux
<
String
>
ragChat
(
@RequestParam
@Parameter
(
description
=
"对话内容"
)
String
message
,
@RequestParam
@Parameter
(
description
=
"会话ID"
)
String
conversationId
)
{
//获取对话历史
...
...
@@ -125,21 +139,15 @@ public class ChatController {
String
context
=
chatService
.
convertDocumentsToString
(
documents
);
//创建提示词
String
userPrompt
=
ragPromptService
.
createRagPrompt
(
message
,
context
,
historyMemory
);
StringBuilder
contentBuilder
=
new
StringBuilder
();
return
chatClient
.
prompt
()
.
user
(
userPrompt
)
.
system
(
"你是一个智能助手,基于以下上下文和历史对话回答问题,请用简洁的语言回答问题,并确保答案准确,要求"
+
"1.以 Markdown 格式输出"
+
"2.请务必将你的思考过程放在 <think></think> 标签内"
+
"3.请务必将生成最终答案放在 <answer></answer> 标签内"
)
.
stream
()
.
content
()
.
concatWith
(
Mono
.
just
(
reference
))
.
doOnNext
(
chunk
->
{
// 实时收集每个流片段
contentBuilder
.
append
(
chunk
);
})
StringBuilder
contentBuilder
=
new
StringBuilder
();
return
FluxUtils
.
wrapDeepSeekStream
(
deepseekChatClient
.
prompt
()
.
user
(
userPrompt
)
.
system
(
"你是一个智能助手,基于以下上下文和历史对话回答问题,请用简洁的语言回答问题,并确保答案准确,要求"
+
"1.以 Markdown 格式输出"
)
.
stream
()
.
chatResponse
(),
contentBuilder
)
.
concatWith
(
Flux
.
just
(
reference
))
.
doOnComplete
(()
->
{
// 流结束时获取完整内容
String
fullResponse
=
contentBuilder
.
toString
();
...
...
ask-data-ai/ask-data-ai-biz/src/main/java/com/ask/utils/FluxUtils.java
0 → 100644
View file @
aba26463
package
com
.
ask
.
utils
;
import
com.baomidou.mybatisplus.core.toolkit.StringUtils
;
import
org.springframework.ai.chat.model.ChatResponse
;
import
org.springframework.ai.deepseek.DeepSeekAssistantMessage
;
import
reactor.core.publisher.Flux
;
import
java.util.List
;
import
java.util.concurrent.atomic.AtomicBoolean
;
public
class
FluxUtils
{
/**
* 将 DeepSeek 的 Flux<ChatResponse> 转换成带 <think>/<answer> 的 Flux<String>
* @param upstream 原始 SSE 流
* @return 带标签的逐块流
*/
public
static
Flux
<
String
>
wrapDeepSeekStream
(
Flux
<
ChatResponse
>
upstream
)
{
AtomicBoolean
reasoningStarted
=
new
AtomicBoolean
(
false
);
AtomicBoolean
answerStarted
=
new
AtomicBoolean
(
false
);
return
upstream
.
flatMapIterable
(
resp
->
{
DeepSeekAssistantMessage
msg
=
(
DeepSeekAssistantMessage
)
resp
.
getResult
().
getOutput
();
StringBuilder
sb
=
new
StringBuilder
();
// 推理阶段:第一次出现推理内容时输出 <think>
if
(
StringUtils
.
isNotBlank
(
msg
.
getReasoningContent
()))
{
if
(
reasoningStarted
.
compareAndSet
(
false
,
true
))
{
sb
.
append
(
"<think>"
);
}
sb
.
append
(
msg
.
getReasoningContent
());
}
// 回答阶段:第一次出现答案时输出 </think><answer>
if
(
StringUtils
.
isNotBlank
(
msg
.
getText
()))
{
if
(
answerStarted
.
compareAndSet
(
false
,
true
))
{
sb
.
append
(
"</think><answer>"
);
}
sb
.
append
(
msg
.
getText
());
}
return
List
.
of
(
sb
.
toString
());
})
.
concatWith
(
Flux
.
just
(
"</answer>"
));
// 末尾补一次关闭标签
}
public
static
Flux
<
String
>
wrapDeepSeekStream
(
Flux
<
ChatResponse
>
upstream
,
StringBuilder
stringBuilder
)
{
AtomicBoolean
reasoningStarted
=
new
AtomicBoolean
(
false
);
AtomicBoolean
answerStarted
=
new
AtomicBoolean
(
false
);
return
upstream
.
flatMapIterable
(
resp
->
{
DeepSeekAssistantMessage
msg
=
(
DeepSeekAssistantMessage
)
resp
.
getResult
().
getOutput
();
StringBuilder
sb
=
new
StringBuilder
();
// 推理阶段:第一次出现推理内容时输出 <think>
if
(
StringUtils
.
isNotBlank
(
msg
.
getReasoningContent
()))
{
if
(
reasoningStarted
.
compareAndSet
(
false
,
true
))
{
sb
.
append
(
"<think>"
);
}
sb
.
append
(
msg
.
getReasoningContent
());
}
// 回答阶段:第一次出现答案时输出 </think><answer>
if
(
StringUtils
.
isNotBlank
(
msg
.
getText
()))
{
stringBuilder
.
append
(
msg
.
getText
());
if
(
answerStarted
.
compareAndSet
(
false
,
true
))
{
sb
.
append
(
"</think><answer>"
);
}
sb
.
append
(
msg
.
getText
());
}
return
List
.
of
(
sb
.
toString
());
})
.
concatWith
(
Flux
.
just
(
"</answer>"
));
// 末尾补一次关闭标签
}
}
ask-data-ai/ask-data-ai-boot/src/main/resources/application.yml
View file @
aba26463
...
...
@@ -37,12 +37,19 @@ spring:
api-key
:
sk-ae96ff281ff644c992843c64a711a950
chat
:
options
:
model
:
qwen-plus
model
:
deepseek-r1
embedding
:
base-url
:
https://dashscope.aliyuncs.com/compatible-mode
api-key
:
sk-ae96ff281ff644c992843c64a711a950
options
:
model
:
text-embedding-v4
deepseek
:
base-url
:
https://dashscope.aliyuncs.com/compatible-mode/v1
api-key
:
sk-ae96ff281ff644c992843c64a711a950
chat
:
enabled
:
true
options
:
model
:
deepseek-r1
mybatis-plus
:
mapper-locations
:
classpath*:/mapper/*Mapper.xml
# mapper文件位置
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment