implementation 'io.github.pig-mesh.ai:deepseek-spring-boot-starter:1.4.6'
代码如下:
` @GetMapping(value = "/chat/advanced", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux chatAdvanced(String prompt, String cacheCode) {
ChatCompletionRequest request = ChatCompletionRequest.builder().model(model)
.messages(UserMessage.from(prompt), SystemMessage.from("You are a device maintenance and repair assistant. When the user asks about device maintenance or repair, call the get_knowledge_from_es function to retrieve relevant information from Elasticsearch. If the function is called, respond based on the function's return results; if the function is not called, respond directly. If the response references knowledge from the knowledge base and sourceUrl has a value, add a footnote marker (e.g., [1]) in the text and append the footnote content in the format `[fileName](sourceUrl)` at the end of the response. If there is no sourceUrl, do not add any footnotes. Always provide accurate and helpful responses"))
.tools(WEATHER_TOOL).build();
// 只保留上一次回答内容
cache.remove(cacheCode);
StringBuffer sb = new StringBuffer();
AtomicBoolean isToolCallInProgress = new AtomicBoolean(false);
return deepSeekClient.chatFluxCompletion(request)
.filter(r->{
List<ChatCompletionChoice> choices = r.choices();
if (choices.isEmpty()) {
return false;
}
ChatCompletionChoice chatCompletionChoice = choices.get(0);
Delta delta = chatCompletionChoice.delta();
if (Objects.isNull(delta)) return false;
String content = delta.content();
if (!StringUtils.isNotBlank(content)) return false;
return true;
})
.concatMap(response -> {
log.info("response {}", response);
Delta delta = response.choices().get(0).delta();
// 情况2:工具调用进行中(忽略所有中间文本)
if (isToolCallInProgress.get()) {
List<ToolCall> toolCalls = delta.toolCalls();
if (!CollectionUtils.isEmpty(toolCalls)){
String arguments = toolCalls.get(0).function().arguments();
sb.append(arguments);
}
return Flux.empty();
}
// 情况1:检测到工具调用开始
if (delta.toolCalls() != null) {
isToolCallInProgress.set(true);
return Flux.empty();
}
// 情况3:正常返回最终结果
return Flux.just(response);
}).doFinally(r -> log.info("arguments {}", sb.toString()))
.doOnError(e -> log.error("/chat/advanced error:{}", e.getMessage()));
}`
报错如下:
2025-04-12T10:58:00.799+08:00 ERROR 25152 --- [ppinfra.com/...] org.ai.aidemo.controller.AiController : /chat/advanced error:com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot coerce empty String ("") to io.github.pigmesh.ai.deepseek.core.chat.ToolTypevalue (but could if coercion was enabled usingCoercionConfig) at [Source: REDACTED (StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 238] (through reference chain: io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse$Builder["choices"]->java.util.ArrayList[0]->io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionChoice$Builder["delta"]->io.github.pigmesh.ai.deepseek.core.chat.Delta$Builder["tool_calls"]->java.util.ArrayList[0]->io.github.pigmesh.ai.deepseek.core.chat.ToolCall$Builder["type"])
2025-04-12T10:58:00.799+08:00 INFO 25152 --- [ppinfra.com/...] org.ai.aidemo.controller.AiController : arguments
2025-04-12T10:58:01.381+08:00 ERROR 25152 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] threw exception
com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot coerce empty String ("") to io.github.pigmesh.ai.deepseek.core.chat.ToolType value (but could if coercion was enabled using CoercionConfig)
at [Source: REDACTED (StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION disabled); line: 1, column: 238] (through reference chain: io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse$Builder["choices"]->java.util.ArrayList[0]->io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionChoice$Builder["delta"]->io.github.pigmesh.ai.deepseek.core.chat.Delta$Builder["tool_calls"]->java.util.ArrayList[0]->io.github.pigmesh.ai.deepseek.core.chat.ToolCall$Builder["type"])
at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.DeserializationContext.reportBadCoercion(DeserializationContext.java:1832) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._checkCoercionFail(StdDeserializer.java:1683) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer._deserializeAltString(EnumDeserializer.java:389) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer._fromString(EnumDeserializer.java:304) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:273) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:294) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:218) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:361) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:246) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:30) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:294) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:218) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:294) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:218) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:361) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:246) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:30) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:294) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:218) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4931) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3868) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3836) ~[jackson-databind-2.18.3.jar:2.18.3]
at io.github.pigmesh.ai.deepseek.core.Json.fromJson(Json.java:25) ~[deepseek4j-core-1.4.3.jar:na]
at io.github.pigmesh.ai.deepseek.core.StreamingRequestExecutor$2.onEvent(StreamingRequestExecutor.java:157) ~[deepseek4j-core-1.4.3.jar:na]
at okhttp3.internal.sse.RealEventSource.onEvent(RealEventSource.kt:101) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.sse.ServerSentEventReader.completeEvent(ServerSentEventReader.kt:108) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.sse.ServerSentEventReader.processNextEvent(ServerSentEventReader.kt:52) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.sse.RealEventSource.processResponse(RealEventSource.kt:75) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.sse.RealEventSource.onResponse(RealEventSource.kt:46) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519) ~[okhttp-4.12.0.jar:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]`
implementation 'io.github.pig-mesh.ai:deepseek-spring-boot-starter:1.4.6'代码如下:
` @GetMapping(value = "/chat/advanced", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux chatAdvanced(String prompt, String cacheCode) {
报错如下:
2025-04-12T10:58:00.799+08:00 ERROR 25152 --- [ppinfra.com/...] org.ai.aidemo.controller.AiController : /chat/advanced error:com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot coerce empty String ("") toio.github.pigmesh.ai.deepseek.core.chat.ToolTypevalue (but could if coercion was enabled usingCoercionConfig) at [Source: REDACTED (StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 238] (through reference chain: io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse$Builder["choices"]->java.util.ArrayList[0]->io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionChoice$Builder["delta"]->io.github.pigmesh.ai.deepseek.core.chat.Delta$Builder["tool_calls"]->java.util.ArrayList[0]->io.github.pigmesh.ai.deepseek.core.chat.ToolCall$Builder["type"])2025-04-12T10:58:00.799+08:00 INFO 25152 --- [ppinfra.com/...] org.ai.aidemo.controller.AiController : arguments
2025-04-12T10:58:01.381+08:00 ERROR 25152 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] threw exception
com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot coerce empty String ("") to
io.github.pigmesh.ai.deepseek.core.chat.ToolTypevalue (but could if coercion was enabled usingCoercionConfig)at [Source: REDACTED (
StreamReadFeature.INCLUDE_SOURCE_IN_LOCATIONdisabled); line: 1, column: 238] (through reference chain: io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse$Builder["choices"]->java.util.ArrayList[0]->io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionChoice$Builder["delta"]->io.github.pigmesh.ai.deepseek.core.chat.Delta$Builder["tool_calls"]->java.util.ArrayList[0]->io.github.pigmesh.ai.deepseek.core.chat.ToolCall$Builder["type"])at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.DeserializationContext.reportBadCoercion(DeserializationContext.java:1832) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._checkCoercionFail(StdDeserializer.java:1683) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer._deserializeAltString(EnumDeserializer.java:389) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer._fromString(EnumDeserializer.java:304) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:273) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:294) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:218) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:361) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:246) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:30) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:294) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:218) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:294) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:218) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:361) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:246) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:30) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:294) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:218) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4931) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3868) ~[jackson-databind-2.18.3.jar:2.18.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3836) ~[jackson-databind-2.18.3.jar:2.18.3]
at io.github.pigmesh.ai.deepseek.core.Json.fromJson(Json.java:25) ~[deepseek4j-core-1.4.3.jar:na]
at io.github.pigmesh.ai.deepseek.core.StreamingRequestExecutor$2.onEvent(StreamingRequestExecutor.java:157) ~[deepseek4j-core-1.4.3.jar:na]
at okhttp3.internal.sse.RealEventSource.onEvent(RealEventSource.kt:101) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.sse.ServerSentEventReader.completeEvent(ServerSentEventReader.kt:108) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.sse.ServerSentEventReader.processNextEvent(ServerSentEventReader.kt:52) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.sse.RealEventSource.processResponse(RealEventSource.kt:75) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.sse.RealEventSource.onResponse(RealEventSource.kt:46) ~[okhttp-sse-4.12.0.jar:na]
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519) ~[okhttp-4.12.0.jar:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]`