java 透传ollama请求工具
·
实现功能
- 透传ollama请求
- 支持关闭think标签
- 支持流式返回
具体实现
controller
@Slf4j
@RestController
@RequestMapping("/ollama")
@RequiredArgsConstructor
public class OllamaAgentController {
private final OllamaAgentService agentService;
/**
* 流式智能体问答
* @param ollamaDTO agentChatReqDTO
* @return
*/
@PostMapping(value = "/generate", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<OllamResponse> streamChat(@RequestBody OllamaDTO ollamaDTO) {
return agentService.streamChat(ollamaDTO);
}
}
service
public interface OllamaAgentService {
/**
* 流式智能体问答
* @param ollamaDTO agentChatReqDTO
* @return
*/
Flux<OllamResponse> streamChat(OllamaDTO ollamaDTO);
}
serviceImpl
@Slf4j
@Service
@RequiredArgsConstructor
public class OllamaAgentServiceImpl implements OllamaAgentService {
private final OllamaChatModel ollamaChatModel;
private final OllamaDialogueLogService agentDialogueLogService;
@Override
public Flux<OllamResponse> streamChat(OllamaDTO ollamaDTO) {
UserDetail userDetail = UserUtil.currentUser();
OllamaDialogueLogDTO dialogueLogDTO = new OllamaDialogueLogDTO(ollamaDTO);
dialogueLogDTO.setUserId(userDetail.getUserId());
StringBuilder aiResponseBuilder = new StringBuilder();
Flux<OllamResponse> responseFlux = ollamaChatModel.stream(ollamaDTO.toPrompt())
.scan(new ThinkTagState(ollamaDTO.isFilterThink()), (state, response) -> {
String chunk = response.getResult().getOutput().getText();
state.setChatResponse(response);
return state.process(chunk);
})
.filter(state -> StrUtil.isNotBlank(state.getFilteredText()))
.map(response -> {
OllamResponse responseDTO = new OllamResponse(response.getChatResponse());
aiResponseBuilder.append(response.getChatResponse().getResult().getOutput().getText());
return responseDTO;
}).doOnComplete(() -> {
dialogueLogDTO.setSystemOut(aiResponseBuilder.toString());
agentDialogueLogService.save(dialogueLogDTO.toDialogueLog());
}).doOnError(e -> {
log.error("Error during AI chat stream: {}", e.getMessage());
dialogueLogDTO.setSystemOut(aiResponseBuilder.toString());
dialogueLogDTO.setAnswerType(1);
agentDialogueLogService.save(dialogueLogDTO.toDialogueLog());
});
if (ollamaDTO.isStream()){
return responseFlux;
}
return mergeResponses(responseFlux);
}
/**
* 合并响应
* @param responseFlux 响应流
* @return
*/
private Flux<OllamResponse> mergeResponses(Flux<OllamResponse> responseFlux) {
return responseFlux
.collectList()
.flatMapMany(list -> {
if (list.isEmpty()) {
return Flux.empty();
}
OllamResponse last = CollUtil.getLast(list);
String combinedText = list.stream()
.map(r -> r.getMessage().getContent())
.collect(Collectors.joining());
last.getMessage().setContent(combinedText);
return Flux.just(last);
});
}
}
think标签状态机
import org.springframework.ai.chat.model.ChatResponse;
public class ThinkTagState {
private boolean inThink = false;
private final StringBuilder buffer = new StringBuilder();
private ChatResponse chatResponse;
private boolean filerThink = false;
public ThinkTagState(boolean filerThink) {
this.filerThink = filerThink;
}
public ThinkTagState process(String chunk) {
StringBuilder output = new StringBuilder();
String remaining = chunk;
if (!filerThink) {
buffer.append(remaining);
return this;
}
while (!remaining.isEmpty()) {
if (!inThink) {
int startIdx = remaining.indexOf("<think>");
if (startIdx == -1) {
output.append(remaining);
break;
}
output.append(remaining.substring(0, startIdx));
inThink = true;
remaining = remaining.substring(startIdx + "<think>".length());
} else {
int endIdx = remaining.indexOf("</think>");
if (endIdx == -1) {
break; // 等待后续分块
}
inThink = false;
remaining = remaining.substring(endIdx + "</think>".length());
}
}
buffer.append(output);
return this;
}
public String getFilteredText() {
return buffer.toString();
}
public ChatResponse getChatResponse() {
return chatResponse;
}
public void setChatResponse(ChatResponse chatResponse) {
this.chatResponse = chatResponse;
}
}
请求类OllamaDTO
@Data
public class OllamaDTO {
private String model;
private boolean stream;
private boolean filterThink;
private List<MessageDTO> messages;
public Prompt toPrompt() {
List<Message> list = messages.stream().map(messageDTO -> {
String role = messageDTO.getRole();
if ("user".equals(role)) {
return (Message)new UserMessage(messageDTO.getContent());
} else if ("assistant".equals(role)) {
return new AssistantMessage(messageDTO.getContent());
} else if ("system".equals(role)) {
return new SystemMessage(messageDTO.getContent());
} else {
throw new IllegalArgumentException("Unknown role: " + role);
}
}).toList();
OllamaOptions.Builder optionsBuilder = OllamaOptions.builder();
optionsBuilder.model(model);
return new Prompt(list,optionsBuilder.build());
}
}
请求示例
{
"model": "qwen3:30b-a3b",
"messages": [
{
"role": "user",
"content": "qwen3:30b-a3b是什么/no_think"
}
],
"options": {
"temperature": 0.5
},
"stream": false,
"filterThink":true
}
更多推荐



所有评论(0)