三、Spring AI Alibaba · Messages

发布时间:2026/10/11 7:50:06
三、Spring AI Alibaba · Messages Spring AI Alibaba · Messages 消息整理时间2026-10-09适用版本Spring AI 1.1.0 / Spring AI Alibaba 1.1.2.x一、什么是 MessageMessage 是模型交互的基本单元代表模型的输入与输出承载对话状态所需的内容和元数据。Spring AI Alibaba 提供跨厂商一致的标准消息类型系统。一个 Message 由三部分组成组成说明Role角色标识消息类型system / user / assistant / toolContent内容实际内容文本、图像、音频、文档等Metadata元数据可选响应信息、消息 ID、token 使用情况注意并非所有厂商都对三者一视同仁尤其 metadata 的行为因提供商而异有的用于用户识别有的直接忽略使用前需查对应厂商文档。二、两种调用方式文本提示 vs 消息提示文本提示StringStringresponsechatModel.call(写一首关于春天的俳句);适用场景单个独立请求不需要对话历史追求最小代码复杂度本质是单个 UserMessage 的快捷方式拿不到 metadata / token 用量。消息提示ListMessageListMessagemessagesList.of(newSystemMessage(你是一个诗歌专家),newUserMessage(写一首关于春天的俳句),newAssistantMessage(樱花盛开时...));PromptpromptnewPrompt(messages);ChatResponseresponsechatModel.call(prompt);适用场景管理多轮对话处理多模态内容图像 / 音频 / 文件需要携带系统指令三、四种消息类型3.1 SystemMessage —— 定规则、设人设用于设定语气、定义角色、建立响应指南。// 基础指令SystemMessagesystemMsgnewSystemMessage(你是一个有帮助的编程助手。);// 详细角色设定推荐用文本块SystemMessagesystemMsgnewSystemMessage( 你是一位资深的 Java 开发者擅长 Web 框架。 始终提供代码示例并解释你的推理。 在解释中要简洁但透彻。 );本项目MockInterviewService就是这一模式的典型SystemMessage(prompt资源)UserMessage(简历/问答)。3.2 UserMessage —— 用户输入与多模态载体纯文本ChatResponseresponsechatModel.call(newPrompt(List.of(newUserMessage(什么是机器学习))));StringshortcutchatModel.call(什么是机器学习);// 等价快捷方式带元数据UserMessageuserMsgUserMessage.builder().text(你好).metadata(Map.of(user_id,alice,// 用户标识session_id,sess_123// 会话标识)).build();多模态MediaUserMessageuserMsgUserMessage.builder().text(描述这张图片的内容。).media(Media.builder().mimeType(MimeTypeUtils.IMAGE_JPEG).data(newURL(https://example.com/image.jpg))// 也支持 ClassPathResource.build()).build();3.3 AssistantMessage —— 模型输出模型调用返回的结果包含文本内容、工具调用、媒体内容与厂商元数据。ChatResponseresponsechatModel.call(newPrompt(解释 AI));AssistantMessageaiMessageresponse.getResult().getOutput();System.out.println(aiMessage.getText());四要素属性说明text消息文本内容metadata元数据映射含厂商特有信息如 reasoningContenttoolCalls模型发起的工具调用列表media媒体内容列表若有手动构造回填历史对话编排/纠偏常用AssistantMessageaiMsgnewAssistantMessage(我很乐意帮助你回答这个问题);ListMessagemessagesList.of(newSystemMessage(你是一个有帮助的助手),newUserMessage(你能帮我吗),aiMsg,// 插入就像它来自模型一样newUserMessage(太好了22 等于多少));ChatResponseresponsechatModel.call(newPrompt(messages));不同厂商对消息权重的处理方式不同手动插入 AssistantMessage 是控制对话走向的实用技巧。工具调用读取AssistantMessageaiMessageresponse.getResult().getOutput();if(aiMessage.hasToolCalls()){for(AssistantMessage.ToolCalltoolCall:aiMessage.getToolCalls()){System.out.println(Tool: toolCall.name());System.out.println(Args: toolCall.arguments());System.out.println(ID: toolCall.id());}}3.4 ToolResponseMessage —— 工具执行结果回传用于把单个工具执行的结果回传给模型让 LLM 接着推理。// 1) 模型发出工具调用AssistantMessageaiMessageAssistantMessage.builder().content().toolCalls(List.of(newAssistantMessage.ToolCall(call_123,tool,get_weather,{\location\: \San Francisco\}))).build();// 2) 执行工具构造结果消息ToolResponseMessagetoolMessageToolResponseMessage.builder().responses(List.of(newToolResponse(call_123,get_weather,晴朗22°C))).build();// 3) 继续对话ListMessagemessagesList.of(newUserMessage(旧金山的天气怎么样),aiMessage,// 模型的工具调用toolMessage// 工具执行结果);ChatResponseresponsechatModel.call(newPrompt(messages));ToolResponse 三要素字段说明id工具调用 ID必须与 AssistantMessage 中的 toolCall.id 匹配name调用的工具名称responseData工具输出的字符串化结果这就是 ReactAgent「推理 → 行动 → 观察」中Observation环节的底层形式。四、Token 使用统计ChatResponse的 metadata 中保存 token 计数与使用信息ChatResponseresponsechatModel.call(newPrompt(你好));ChatResponseMetadatametadataresponse.getMetadata();if(metadata!nullmetadata.getUsage()!null){System.out.println(Input tokens: metadata.getUsage().getPromptTokens());System.out.println(Output tokens: metadata.getUsage().getCompletionTokens());System.out.println(Total tokens: metadata.getUsage().getTotalTokens());}成本治理的第一步别把ChatResponse丢掉。写getResult().getOutput().getText()的链式调用会让中间的 metadata 无从获取。五、流式与块Chunk流式期间收到的每个ChatResponse是消息的片段需要自己拼接FluxChatResponseresponseStreamchatModel.stream(newPrompt(你好));StringBuilderfullResponsenewStringBuilder();responseStream.subscribe(chunk-{Stringcontentchunk.getResult().getOutput().getText();fullResponse.append(content);System.out.print(content);});流式下的消息类型场景怎么取内容模型普通响应AssistantMessage.getText()且metadata.reasoningContent为空模型 Thinkingmetadata.reasoningContent非空如 DeepSeek / qwen 深度思考工具调用请求AssistantMessage.hasToolCalls() true工具执行结果ToolResponseMessage.getResponses()→responseData()六、多模态输入统一通过Mediaorg.springframework.ai.content.Media MIME 类型承载。// 图片 - URL.media(Media.builder().mimeType(MimeTypeUtils.IMAGE_JPEG).data(newURL(https://example.com/image.jpg)).build())// 图片 - 本地/类路径资源.media(newMedia(MimeTypeUtils.IMAGE_JPEG,newClassPathResource(images/photo.jpg)))// 音频.media(newMedia(MimeTypeUtils.parseMimeType(audio/wav),newClassPathResource(audio/recording.wav)))// 视频.media(Media.builder().mimeType(MimeTypeUtils.parseMimeType(video/mp4)).data(newURL(https://example.com/path/to/video.mp4)).build())警告并非所有模型支持所有文件类型需查厂商文档确认格式与大小限制。对照前表通义千问 DashScope 在官方能力矩阵中未标注多模态支持OpenAI / Gemini / Ollama 支持。七、实用 APIBuilder / copy / mutate// UserMessage builderUserMessageuserMsgUserMessage.builder().text(你好我想学习 Spring AI Alibaba).metadata(Map.of(user_id,user_123)).build();// SystemMessage builderSystemMessagesystemMsgSystemMessage.builder().text(你是一个 Spring 框架专家).metadata(Map.of(version,1.0)).build();// AssistantMessage builderAssistantMessageassistantMsgAssistantMessage.builder().content(我很乐意帮助你学习 Spring AI Alibaba).build();// 复制UserMessagecopyoriginal.copy();// 基于副本修改原对象不变UserMessagemodifiedoriginal.mutate().text(修改后的消息).metadata(Map.of(modified,true)).build();mutate()是不可变风格的改造入口适合在拦截器/钩子中改写消息而不污染原列表。八、多轮对话ChatModel 是无状态的ChatModel 交互天然无状态简单对话循环 不断变长的消息列表ListMessageconversationHistorynewArrayList();conversationHistory.add(newUserMessage(你好));ChatResponseresponse1chatModel.call(newPrompt(conversationHistory));conversationHistory.add(response1.getResult().getOutput());// 把 AI 回复回填conversationHistory.add(newUserMessage(你能帮我学习 Java 吗));ChatResponseresponse2chatModel.call(newPrompt(conversationHistory));conversationHistory.add(response2.getResult().getOutput());conversationHistory.add(newUserMessage(从哪里开始));ChatResponseresponse3chatModel.call(newPrompt(conversationHistory));三个必须注意的点每轮都要把AssistantMessage回填否则模型失忆。列表会不断膨胀 → 需要窗口裁剪/摘要ReactAgent 里对应MessagesModelHook。生产环境请交给ChatMemory或 Agent 的SaverMemorySaver / RedisSaver托管。九、在 ReactAgent 中使用 MessageReactAgent自动管理消息历史但也接受直接传消息ReactAgentagentReactAgent.builder().name(my_agent).model(chatModel).systemPrompt(你是一个有帮助的助手).build();AssistantMessager1agent.call(你好);// 字符串AssistantMessager2agent.call(newUserMessage(帮我写一首诗));// 单条 UserMessageListMessagemessagesList.of(newUserMessage(我喜欢春天),newUserMessage(写一首关于春天的诗));AssistantMessager3agent.call(messages);// 消息列表十、速查表类型谁产生关键 APISystemMessage开发者.text()多写角色规则输出格式UserMessage用户/系统.text().media().metadata()AssistantMessage模型.getText().hasToolCalls().getToolCalls().getMetadata()ToolResponseMessage工具执行侧.builder().responses(List.of(new ToolResponse(id, name, data)))// 取值链路ChatResponse→getMetadata()// token 用量→getResult()// Generation→getOutput()// AssistantMessage→getText()/hasToolCalls()/getMetadata()四条铁律chatModel.call(String)≡ 单个 UserMessage别指望拿到元数据。多轮上下文靠自己拼ListMessageChatModel 无状态。ToolResponse.id必须和ToolCall.id对齐否则模型无法关联结果。多模态/元数据能力因厂商而异换模型前务必查适配文档。十一、对照本项目MockInterviewService的三次调用都是标准的「System User → Assistant」结构messages.add(newSystemMessage(resumeAnalysisSystemPromptResource));// 资源注入的系统提示messages.add(newUserMessage(promptTemplate.render(Map.of(resumeText,resumeText))));PromptpromptnewPrompt(messages,DashScopeChatOptions.builder().temperature(0.7).build());StringresponsechatModel.call(prompt).getResult().getOutput().getText();可优化点接住 metadata 做成本核算简历全文 长 JSON 输出 token 不低应记录getUsage().getTotalTokens()并做预算告警。回填历史实现追问result.html若要做针对评估报告追问正好用第八节的conversationHistory累加模式以resumeId为 key 存起来。多模态扩展面试官上传项目截图让 AI 点评用UserMessage.media(ClassPathResource/MultipartFile 转 Resource)即可无需改模型层。mutate 改写 SystemMessage想做Java / 前端 / 算法多套面试模式时用systemMsg.mutate().text(...)生成变体避免重复写模板。