Solon-AI聊天测试:对话功能测试案例
引言
在AI应用开发中,聊天对话功能是最核心且常用的能力之一。Solon-AI作为Java AI应用开发框架,提供了强大而灵活的聊天模型(ChatModel)接口,支持多种LLM提供商和丰富的功能特性。本文将深入探讨Solon-AI的聊天测试实践,通过具体案例展示如何构建和测试对话功能。
核心接口概览
Solon-AI的聊天功能基于ChatModel接口构建,支持同步调用和流式响应两种模式:
// 基础聊天模型构建
ChatModel chatModel = ChatModel.of("http://127.0.0.1:11434/api/chat")
.provider("ollama") // 指定供应商(方言)
.model("qwen2.5:1.5b")
.build();
// 同步调用
ChatResponse resp = chatModel.prompt("hello").call();
// 流式调用
chatModel.prompt("hello").stream(); // Publisher<ChatResponse>
测试架构设计
抽象测试基类
Solon-AI采用抽象测试基类AbsChatTest来统一管理各种LLM提供商的测试用例:
基础对话功能测试
同步调用测试
@Test
public void case1_call() throws IOException {
ChatModel chatModel = getChatModelBuilder().build();
// 一次性返回
ChatResponse resp = chatModel.prompt("hello").call();
// 打印消息
log.info("{}", resp.getMessage());
}
流式响应测试
@Test
public void case2_stream() throws Exception {
ChatModel chatModel = getChatModelBuilder().build();
// 流返回
CountDownLatch doneLatch = new CountDownLatch(1);
AtomicBoolean done = new AtomicBoolean(false);
chatModel.prompt("hello").stream()
.subscribe(new SimpleSubscriber<ChatResponse>()
.doOnNext(resp -> {
log.info("{} - {}", resp.isFinished(), resp.getMessage());
done.set(resp.isFinished());
}).doOnComplete(() -> {
log.debug("::完成!");
doneLatch.countDown();
}).doOnError(err -> {
doneLatch.countDown();
err.printStackTrace();
}));
doneLatch.await();
assert done.get();
}
工具调用功能测试
工具定义
Solon-AI支持Function Calling(工具调用)功能,可以定义各种工具函数:
@Component
public class Tools {
@ToolMapping(description = "获取指定城市的天气情况")
public String get_weather(@Param(name = "location", description = "根据用户提到的地点推测城市") String location) {
if (location == null) {
throw new IllegalStateException("arguments location is null (Assistant recognition failure)");
}
return "晴,24度";
}
@ToolMapping(description = "查询城市降雨量")
public String get_rainfall(@Param(name = "location", description = "城市位置") String location) {
if (location == null) {
throw new IllegalStateException("arguments location is null (Assistant recognition failure)");
}
return "555毫米";
}
@ToolMapping(description = "用关键词搜索网络")
public String search_www(@Param(name = "key", description = "根据用户内容提取关键词") String key) throws IOException {
if (key == null) {
throw new IllegalStateException("arguments key is null (Assistant recognition failure)");
}
return HttpUtils.http("https://solon.noear.org/article/about?format=md").get();
}
}
工具调用测试案例
单工具调用测试
@Test
public void case3_wather_call() throws IOException {
ChatModel chatModel = getChatModelBuilder()
.defaultToolsAdd(new Tools())
.build();
ChatResponse resp = chatModel
.prompt("今天杭州的天气情况?")
.call();
// 验证响应包含预期内容
assert resp.getMessage() != null;
assert resp.getMessage().getContent().contains("晴");
}
多工具组合调用测试
@Test
public void case3_wather_rainfall_call() throws IOException {
ChatModel chatModel = getChatModelBuilder()
.defaultToolsAdd(new Tools())
.build();
ChatResponse resp = chatModel
.prompt("杭州天气和北京降雨量如何?")
.call();
// 验证多个工具调用结果
assert resp.getMessage() != null;
assert resp.getMessage().getContent().contains("晴");
assert resp.getMessage().getContent().contains("555");
}
会话管理测试
聊天会话构建
@Test
public void case4_tool_stream() throws Throwable {
ChatModel chatModel = getChatModelBuilder().build();
// 创建聊天会话
ChatSession chatSession = InMemoryChatSession.builder().build();
chatSession.addMessage(ChatMessage.ofUser("今天杭州的天气情况?"));
// 流式调用
Publisher<ChatResponse> publisher = chatModel
.prompt(chatSession)
.options(o -> o.toolsAdd(new Tools()))
.stream();
// 订阅响应
AtomicReference<AssistantMessage> msgHolder = new AtomicReference<>();
CountDownLatch doneLatch = new CountDownLatch(1);
publisher.subscribe(new SimpleSubscriber<ChatResponse>()
.doOnNext(resp -> {
msgHolder.set(resp.getAggregationMessage());
}).doOnComplete(() -> {
log.debug("::完成!");
doneLatch.countDown();
}).doOnError(err -> {
err.printStackTrace();
msgHolder.set(null);
doneLatch.countDown();
}));
doneLatch.await();
// 验证会话状态
assert chatSession.getMessages().size() == 4;
System.out.println(chatSession.toNdjson());
}
多轮对话测试
@Test
public void case5_tool_stream() throws Throwable {
ChatModel chatModel = getChatModelBuilder().build();
ChatSession chatSession = InMemoryChatSession.builder().build();
// 第一轮对话
chatSession.addMessage(ChatMessage.ofUser("今天杭州的天气情况?"));
// ... 处理第一轮响应
// 第二轮对话
chatSession.addMessage(ChatMessage.ofUser("搜索网络:solon框架的作者是谁?"));
// ... 处理第二轮响应
// 验证多轮对话状态
assert chatSession.getMessages().size() == 8;
}
高级功能测试
返回值工具测试
@Test
public void case6_wather_return_call() throws IOException {
ChatModel chatModel = getChatModelBuilder()
.defaultToolsAdd(new ReturnTools())
.build();
ChatResponse resp = chatModel
.prompt("今天杭州的天气情况?")
.call();
// 验证精确返回值
assert "晴,24度".equals(resp.getMessage().getContent());
}
复杂工具调用测试
@Test
public void case8_tool_stream() throws Exception {
ChatModel chatModel = getChatModelBuilder()
.defaultToolsAdd(new Case8Tools())
.timeout(Duration.ofSeconds(600))
.build();
// 复杂查询场景
Publisher<ChatResponse> publisher = chatModel
.prompt(ChatMessage.ofUser("2025号3月20日,设备76-51的日用电量是多少"))
.stream();
// 处理复杂响应
// ...
}
测试最佳实践
1. 测试环境配置
@SolonTest
public class OllamaTest extends AbsChatTest{
private static final String apiUrl = "http://127.0.0.1:11434/api/chat";
private static final String provider = "ollama";
private static final String model = "qwen2.5:1.5b";
protected ChatModel.Builder getChatModelBuilder() {
return ChatModel.of(apiUrl)
.provider(provider)
.model(model);
}
}
2. 断言策略
| 测试类型 | 断言重点 | 示例 |
|---|---|---|
| 同步调用 | 响应内容完整性 | assert resp.getMessage() != null |
| 流式调用 | 完成状态验证 | assert done.get() |
| 工具调用 | 返回值验证 | assert resp.getMessage().getContent().contains("晴") |
| 会话管理 | 消息数量验证 | assert chatSession.getMessages().size() == 4 |
3. 异常处理
@Test
public void case3_wather_stream_finished() throws Exception {
// ... 测试代码
// 验证完成事件
Assertions.assertEquals(1, atomicInteger.get(), "完成事件");
}
性能优化建议
超时配置
@Test
public void case8_tool_stream() throws Exception {
ChatModel chatModel = getChatModelBuilder()
.defaultToolsAdd(new Case8Tools())
.timeout(Duration.ofSeconds(600)) // 设置超时时间
.build();
// ...
}
批量处理
// 在EmbeddingModel中支持批量处理
EmbeddingModel embeddingModel = EmbeddingModel.of(apiUrl)
.apiKey(apiKey)
.provider(provider)
.model(model)
.batchSize(10) // 批量大小
.build();
总结
Solon-AI的聊天测试框架提供了全面的测试覆盖,从基础对话到复杂的工具调用场景。通过抽象测试基类和具体的提供商实现,可以轻松扩展支持各种LLM服务。关键优势包括:
- 统一的测试接口:通过
AbsChatTest抽象基类实现测试标准化 - 全面的功能覆盖:支持同步/异步、工具调用、会话管理等
- 灵活的扩展性:易于添加新的LLM提供商测试
- 完善的断言机制:提供多种验证策略确保功能正确性
通过本文的测试案例,开发者可以快速掌握Solon-AI聊天功能的测试方法,构建稳定可靠的AI对话应用。
提示:在实际项目中,建议结合持续集成(CI)环境运行这些测试,确保AI功能的稳定性和可靠性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



