对话模型
在 快速入门 中,你已经跑通了最基本的模型调用。这页系统讲解 ChatModel 的配置项、两种调用模式的完整用法、多轮对话的实现方式,以及如何处理异常。
这里会详细介绍 ChatModel 的配置选项、两种调用方式的区别、多轮对话的实现,以及异常处理。如果你刚跑通第一个示例,想深入了解如何控制模型行为,从这里继续。
创建 ChatModel
Section titled “创建 ChatModel”FeatAI.chatModel(...) 接受一个 Consumer<ChatOptions>,所有配置都通过链式调用完成:
import tech.smartboot.feat.ai.FeatAI;import tech.smartboot.feat.ai.chat.ChatModel;
ChatModel chatModel = FeatAI.chatModel(opts -> opts .model("Qwen2.5-72B-Instruct") .system("你是一个专业的 Java 工程师。") .debug(false));| 配置项 | 说明 | 默认值 |
|---|---|---|
model(...) | 模型名称 | 必填 |
system(...) | 系统提示词,定义角色和输出风格 | null |
baseUrl(...) | 服务地址 | 从环境变量 FEAT_AI_BASE_URL 读取,或默认 Gitee AI |
apiKey(...) | API 密钥 | 从环境变量 FEAT_AI_API_KEY 读取 |
debug(...) | 是否打印请求/响应详情 | false |
extraBody(...) | 模型特有的额外参数 | null |
配置系统提示词
Section titled “配置系统提示词”system(...) 是最值得优先使用的配置。它定义了模型的整体角色和输出边界,往往比反复修改用户提示词更有效:
import tech.smartboot.feat.ai.FeatAI;import tech.smartboot.feat.ai.chat.ChatModel;
ChatModel chatModel = FeatAI.chatModel(opts -> opts .model("Qwen3-06B") .system("你是一个擅长生成藏头诗的诗人,只输出诗句,不解释。"));传递模型特有参数
Section titled “传递模型特有参数”某些模型或厂商支持标准参数之外的自定义字段,通过 extraBody(...) 传入:
import tech.smartboot.feat.ai.FeatAI;import tech.smartboot.feat.ai.chat.ChatModel;
ChatModel chatModel = FeatAI.chatModel(opts -> opts .model("qwen2.5:7b") .extraBody(body -> { body.put("seed", 42); body.put("temperature", 0.7); }));同步调用:chat(…)
Section titled “同步调用:chat(…)”chat(...) 系列方法返回 CompletableFuture<ChatResponse>,适合需要完整响应后再处理的场景。
最简单的单轮对话
Section titled “最简单的单轮对话”import tech.smartboot.feat.ai.FeatAI;import tech.smartboot.feat.ai.chat.ChatModel;
ChatModel chatModel = FeatAI.chatModel(opts -> opts.model("Qwen2.5-72B-Instruct"));
chatModel.chat("你好,请自我介绍一下。").thenAccept(rsp -> { System.out.println("内容: " + rsp.getContent()); System.out.println("Token 消耗: " + rsp.getUsage().getTotalTokens());});检查响应状态
Section titled “检查响应状态”ChatResponse 包含响应状态和错误信息:
chatModel.chat("你好").thenAccept(rsp -> { if (rsp.isSuccess()) { System.out.println(rsp.getContent()); } else { System.err.println("请求失败: " + rsp.getError()); }});流式调用:chatStream(…)
Section titled “流式调用:chatStream(…)”chatStream(...) 通过 ChatStreamListener 回调实时接收模型生成的片段,适合需要逐字展示的场景。
import tech.smartboot.feat.ai.FeatAI;import tech.smartboot.feat.ai.chat.ChatModel;import tech.smartboot.feat.ai.chat.ChatStreamListener;
ChatModel chatModel = FeatAI.chatModel(opts -> opts.model("Qwen2.5-72B-Instruct"));
chatModel.chatStream("根据以下关键词生成一首藏头诗:情,人,节,快,乐", new ChatStreamListener() { @Override public void onStreamResponse(String content) { System.out.print(content); }});完整回调:接收完成事件和推理内容
Section titled “完整回调:接收完成事件和推理内容”ChatStreamListener 提供四个回调方法,按需重写:
chatModel.chatStream("介绍一下 Feat 框架", new ChatStreamListener() { @Override public void onStreamResponse(String content) { // 每收到一个文本片段触发 System.out.print(content); }
@Override public void onReasoning(String content) { // 某些模型的推理过程(如 DeepSeek-R1 的思考链) System.err.print("[思考] " + content); }
@Override public void onCompletion(ChatResponse chatResponse) { // 流完全结束时触发,可获取完整 usage System.out.println("\n\n流结束,总 tokens: " + chatResponse.getUsage().getTotalTokens()); }
@Override public void onError(Throwable throwable) { // 网络异常或流式传输错误 System.err.println("出错了: " + throwable.getMessage()); }});多轮对话的本质是:把历史消息一并发送给模型。Feat AI 不替你维护对话状态,你需要自己管理消息列表。
使用消息列表
Section titled “使用消息列表”import tech.smartboot.feat.ai.FeatAI;import tech.smartboot.feat.ai.chat.ChatModel;import tech.smartboot.feat.ai.chat.entity.Message;
import java.util.ArrayList;import java.util.List;
ChatModel chatModel = FeatAI.chatModel(opts -> opts.model("Qwen2.5-72B-Instruct"));
List<Message> messages = new ArrayList<>();messages.add(Message.ofSystem("你是一个专业的 Java 工程师"));messages.add(Message.ofUser("什么是 Feat?"));
chatModel.chat(messages).thenAccept(rsp -> { System.out.println("AI: " + rsp.getContent()); // 把 AI 的回复也加入历史,供下一轮使用 messages.add(Message.ofAssistant(rsp.getContent()));});同步调用的错误
Section titled “同步调用的错误”chat(...) 返回 CompletableFuture,异常会封装在 Future 中:
chatModel.chat("你好").whenComplete((rsp, ex) -> { if (ex != null) { System.err.println("请求异常: " + ex.getMessage()); } else if (!rsp.isSuccess()) { System.err.println("业务错误: " + rsp.getError()); } else { System.out.println(rsp.getContent()); }});流式调用的错误
Section titled “流式调用的错误”流式错误通过 ChatStreamListener.onError(...) 回调处理。默认实现是 printStackTrace,生产环境务必重写:
chatModel.chatStream("你好", new ChatStreamListener() { @Override public void onStreamResponse(String content) { System.out.print(content); }
@Override public void onError(Throwable throwable) { // 自定义错误处理,如记录日志、通知用户 logger.error("流式调用失败", throwable); }});HTTP 状态码异常
Section titled “HTTP 状态码异常”Feat AI 底层复用 Feat Core 的 HTTP 错误处理机制,自动识别以下场景:
- 401/403:API Key 无效或权限不足
- 429:请求频率过高
- 5xx:服务端错误
这些错误会触发 onError 回调,或在同步调用中导致 CompletableFuture 异常完成。得益于 Feat Core 的完整 HTTP 协议实现,你能获得准确的错误信息和状态码。
流式输出为什么是碎片化的
Section titled “流式输出为什么是碎片化的”这是预期行为。大语言模型按 token 生成内容,流式传输每次推送一个或几个 token,不会等待完整句子。
为什么模型似乎”不记得”之前的对话
Section titled “为什么模型似乎”不记得”之前的对话”因为每个 chat(...) / chatStream(...) 调用都是独立的 HTTP 请求。模型本身是无状态的,上下文需要通过消息列表显式传递。
onReasoning 一直没有触发
Section titled “onReasoning 一直没有触发”并非所有模型都输出推理内容。目前 DeepSeek-R1、Qwen3 等部分模型支持,普通模型不会触发此回调。