Solon v3.9.5

示例: solon-web 集成参考

</> markdown
2026年3月11日 下午5:15:26

1、LLM 构建

@Configuration
public class ChatConfig {
    @Bean
    public ChatModel chatModel(CalculatorTools calculatorTools) throws Exception {
        return ChatModel.of(_Constants.chat_apiUrl)
                .provider(_Constants.chat_provider)
                .model(_Constants.chat_model)
                .defaultToolsAdd(new WeatherTools()) //添加默认工具
                .defaultToolsAdd(calculatorTools) //如果是托管组件,使用注入实例(不要手动 new)
                .build();
    }
}

2、Web 简单请求与响应

import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.annotation.*;

import java.io.IOException;

@Controller
public class DemoController {
    @Inject
    ChatModel chatModel;

    @Mapping("case1")
    public String case1(String prompt) throws IOException {
        return chatModel.prompt(prompt)
                .call()
                .getMessage()
                .getContent();
    }
}

3、Web 响应数据作为 sse 或 ndjson 输出

import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.annotation.*;
import org.noear.solon.core.util.MimeType;
import reactor.core.publisher.Flux;

import java.io.IOException;

@Controller
public class DemoController {
    @Inject
    ChatModel chatModel;

    //@Produces(MimeType.APPLICATION_X_NDJSON_VALUE)
    //自动转为 sse
    @Produces(MimeType.TEXT_EVENT_STREAM_UTF8_VALUE)
    @Mapping("case2")
    public Flux<ChatMessage> case2(String prompt) throws IOException {
        return chatModel.prompt(prompt)
                      .stream()
                      .filter(resp -> resp.hasContent())
                      .map(resp -> resp.getMessage());
    }
}

4、Web 聊天会话与记忆(即持久化)

import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.chat.ChatSession;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.ai.chat.session.InMemoryChatSession;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Header;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.web.sse.SseEvent;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Controller
public class DemoController {
    @Inject
    ChatModel chatModel;

    //会话记忆与持久化
    final Map<String, ChatSession> sessionMap = new ConcurrentHashMap<>();

    //手动转为 sse
    @Mapping("case3")
    public Flux<SseEvent> case3(@Header("sessionId") String sessionId, String prompt) throws IOException {
        ChatSession chatSession = sessionMap.computeIfAbsent(sessionId, 
                k -> InMemoryChatSession.builder().sessionId(k).build());

        return chatModel.prompt(prompt)
                        .session(chatSession)
                        .stream()
                        .filter(resp -> resp.hasContent())
                        .map(resp -> new SseEvent().data(resp.getContent()));
    }
}