diff --git a/easy-agents-core/src/main/java/com/easyagents/core/model/chat/ChatConfig.java b/easy-agents-core/src/main/java/com/easyagents/core/model/chat/ChatConfig.java
index 55b8445..4e4bea5 100644
--- a/easy-agents-core/src/main/java/com/easyagents/core/model/chat/ChatConfig.java
+++ b/easy-agents-core/src/main/java/com/easyagents/core/model/chat/ChatConfig.java
@@ -27,6 +27,9 @@ public class ChatConfig extends BaseModelConfig {
protected Boolean supportToolMessage;
protected Boolean supportThinking;
+ /** OpenAI-compatible 消息 content 的序列化格式。 */
+ protected ChatMessageContentFormat messageContentFormat = ChatMessageContentFormat.STANDARD;
+
// 在调用工具的时候,是否需要推理结果作为 reasoning_content 传给大模型, 比如 Deepseek
// 参考文档: https://api-docs.deepseek.com/zh-cn/guides/thinking_mode#%E5%B7%A5%E5%85%B7%E8%B0%83%E7%94%A8
protected Boolean needReasoningContentForToolMessage;
@@ -135,6 +138,35 @@ public class ChatConfig extends BaseModelConfig {
return supportThinking == null || supportThinking;
}
+ /**
+ * 获取消息 content 的序列化格式。
+ *
+ * @return 消息 content 格式
+ */
+ public ChatMessageContentFormat getMessageContentFormat() {
+ return messageContentFormat;
+ }
+
+ /**
+ * 设置消息 content 的序列化格式。
+ *
+ * @param messageContentFormat 消息 content 格式;null 时回退为标准格式
+ */
+ public void setMessageContentFormat(ChatMessageContentFormat messageContentFormat) {
+ this.messageContentFormat = messageContentFormat == null
+ ? ChatMessageContentFormat.STANDARD
+ : messageContentFormat;
+ }
+
+ /**
+ * 判断是否需要将纯文本 content 序列化为内容块数组。
+ *
+ * @return 配置为内容块数组时返回 true
+ */
+ public boolean isTextPartsMessageContent() {
+ return messageContentFormat == ChatMessageContentFormat.TEXT_PARTS;
+ }
+
public Boolean getNeedReasoningContentForToolMessage() {
return needReasoningContentForToolMessage;
}
diff --git a/easy-agents-core/src/main/java/com/easyagents/core/model/chat/ChatMessageContentFormat.java b/easy-agents-core/src/main/java/com/easyagents/core/model/chat/ChatMessageContentFormat.java
new file mode 100644
index 0000000..4a84c64
--- /dev/null
+++ b/easy-agents-core/src/main/java/com/easyagents/core/model/chat/ChatMessageContentFormat.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2023-2026, Easy-Agents (fuhai999@gmail.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.easyagents.core.model.chat;
+
+/**
+ * OpenAI-compatible 消息 content 的序列化格式。
+ */
+public enum ChatMessageContentFormat {
+
+ /** 保持供应商默认格式,纯文本 content 使用字符串。 */
+ STANDARD,
+
+ /** 将各角色的纯文本 content 统一序列化为文本内容块数组。 */
+ TEXT_PARTS
+}
diff --git a/easy-agents-core/src/main/java/com/easyagents/core/model/client/OpenAIChatMessageSerializer.java b/easy-agents-core/src/main/java/com/easyagents/core/model/client/OpenAIChatMessageSerializer.java
index 88fe800..82b4750 100644
--- a/easy-agents-core/src/main/java/com/easyagents/core/model/client/OpenAIChatMessageSerializer.java
+++ b/easy-agents-core/src/main/java/com/easyagents/core/model/client/OpenAIChatMessageSerializer.java
@@ -58,11 +58,39 @@ public class OpenAIChatMessageSerializer implements ChatMessageSerializer {
} else if (message instanceof ToolMessage) {
buildToolMessageObject(objectMap, (ToolMessage) message, config);
}
+ normalizeMessageContent(objectMap, config);
messageList.add(objectMap);
});
return messageList;
}
+ /**
+ * 根据模型配置将纯文本 content 规范为 OpenAI 文本内容块数组。
+ * 已经是多模态内容块数组的 content 保持不变。
+ *
+ * @param objectMap 已完成角色字段构建的消息
+ * @param config 模型配置
+ */
+ protected void normalizeMessageContent(Map objectMap, ChatConfig config) {
+ if (config == null
+ || !config.isTextPartsMessageContent()
+ || !objectMap.containsKey("content")) {
+ return;
+ }
+
+ Object content = objectMap.get("content");
+ if (content instanceof List>) {
+ return;
+ }
+ if (content == null || content instanceof String) {
+ String text = content == null ? "" : (String) content;
+ objectMap.put("content", List.of(Maps.of("type", "text").set("text", text)));
+ return;
+ }
+ throw new IllegalStateException(
+ "Unsupported OpenAI message content type: " + content.getClass().getName());
+ }
+
protected void buildToolMessageObject(Map objectMap, ToolMessage message, ChatConfig config) {
if (config.isSupportToolMessage()) {
objectMap.put("role", "tool");
@@ -289,4 +317,3 @@ public class OpenAIChatMessageSerializer implements ChatMessageSerializer {
}
}
}
-
diff --git a/easy-agents-core/src/test/java/com/easyagents/core/test/model/client/OpenAIChatMessageSerializerTest.java b/easy-agents-core/src/test/java/com/easyagents/core/test/model/client/OpenAIChatMessageSerializerTest.java
index 6fa0b24..0d93579 100644
--- a/easy-agents-core/src/test/java/com/easyagents/core/test/model/client/OpenAIChatMessageSerializerTest.java
+++ b/easy-agents-core/src/test/java/com/easyagents/core/test/model/client/OpenAIChatMessageSerializerTest.java
@@ -1,7 +1,12 @@
package com.easyagents.core.test.model.client;
+import com.easyagents.core.message.AiMessage;
+import com.easyagents.core.message.SystemMessage;
+import com.easyagents.core.message.ToolCall;
+import com.easyagents.core.message.ToolMessage;
import com.easyagents.core.message.UserMessage;
import com.easyagents.core.model.chat.ChatConfig;
+import com.easyagents.core.model.chat.ChatMessageContentFormat;
import com.easyagents.core.model.client.OpenAIChatMessageSerializer;
import org.junit.Assert;
import org.junit.Test;
@@ -14,6 +19,50 @@ import java.util.Map;
*/
public class OpenAIChatMessageSerializerTest {
+ /**
+ * 验证标准模式继续使用原有纯文本字符串格式。
+ */
+ @Test
+ public void shouldKeepStringContentInStandardMode() {
+ ToolMessage toolMessage = toolMessage("call-1", "工具结果");
+
+ List