Skip to content

修复:过滤空助手消息,以防止在严格API上出现400错误(fix: filter empty assistant messages to prevent 400 error on strict APIs)#7202

Open
kaixinyujue wants to merge 1 commit intoAstrBotDevs:masterfrom
kaixinyujue:fix/filter-empty-assistant-messages
Open

修复:过滤空助手消息,以防止在严格API上出现400错误(fix: filter empty assistant messages to prevent 400 error on strict APIs)#7202
kaixinyujue wants to merge 1 commit intoAstrBotDevs:masterfrom
kaixinyujue:fix/filter-empty-assistant-messages

Conversation

@kaixinyujue
Copy link
Copy Markdown

@kaixinyujue kaixinyujue commented Mar 30, 2026

描述

修复调用 Moonshot (Kimi K2.5) API 时,因对话历史中存在空 assistant 消息而导致的 400 错误。

错误信息:

[2026-03-30 21:32:10.426] [Core] [WARN] [v4.22.2] [runners.tool_loop_agent_runner:350]: Chat Model moonshot/kimi-k2.5 request error: Error code: 400 - {'error': {'message': "Invalid request: the message at position 8 with role 'assistant' must not be empty", 'type': 'invalid_request_error'}}

问题根源: 部分严格遵守 OpenAI 规范的 API(如 Moonshot)会校验 assistant 消息的 content 字段,当内容为空且没有 tool_calls 时直接拒绝请求。而 DeepSeek 等 API 对此较为宽松,导致同样的消息历史在 Moonshot 上失败,在 DeepSeek 上却能正常工作。

解决方案

OpenAIAPIProviderBase._query() 方法中,发送请求前对消息数组进行清理:

  • 过滤:删除 content 为 None 或空字符串且没有 tool_calls 的 assistant 消息
  • 规范化:当存在 tool_calls 时,将空字符串转为 None(符合 OpenAI 官方规范)

将修复放在 Provider 层而非 Agent 层,确保所有继承 OpenAIAPIProviderBase 的 Provider(Moonshot、GPT、DeepSeek 等)都能受益,无需逐个适配。

变更文件

  • astrbot/core/provider/sources/openai_source.py:在调用 API 前添加消息清洗逻辑

关联 Issue

Closes #7200 - [Feature] AstrBot 在调用 Moonshot (Kimi K2.5) API 时的空消息报错解决建议

检查清单

  • 已使用 ruff format 格式化代码
  • 已在本地测试 Moonshot API,不再出现 400 错误
  • 已在本地测试 DeepSeek API,保持向后兼容

Summary by Sourcery

Filter and normalize assistant messages before invoking OpenAI-compatible chat APIs to avoid invalid empty-message requests on strict providers.

Bug Fixes:

  • Remove empty assistant messages without tool calls from outgoing payloads to prevent 400 errors on strict OpenAI-compatible APIs.
  • Normalize assistant messages that have tool calls by converting empty string content to null to comply with OpenAI message schema.

Some OpenAI-compatible APIs (e.g., Moonshot) reject requests with
empty content in assistant messages when no tool_calls are present.
This fix cleans up the messages payload before sending to avoid
'message at position X must not be empty' errors.

Closes related issue with fallback provider behavior.
@auto-assign auto-assign bot requested review from Fridemn and Raven95676 March 30, 2026 14:46
@dosubot dosubot bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Mar 30, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The message cleanup currently only treats content == "" and content is None as empty; consider also handling whitespace-only strings or other non-string/complex content types (e.g. list/array content) to avoid leaving structurally empty assistant messages that strict providers might still reject.
  • For tool_calls you only check truthiness (if not tool_calls); if the field can be present but empty (e.g. []), it might be clearer and safer to normalize or explicitly treat that as "no tool calls" to avoid subtle differences between None, missing, and empty values.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The message cleanup currently only treats `content == ""` and `content is None` as empty; consider also handling whitespace-only strings or other non-string/complex `content` types (e.g. list/array content) to avoid leaving structurally empty assistant messages that strict providers might still reject.
- For `tool_calls` you only check truthiness (`if not tool_calls`); if the field can be present but empty (e.g. `[]`), it might be clearer and safer to normalize or explicitly treat that as "no tool calls" to avoid subtle differences between `None`, missing, and empty values.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@dosubot dosubot bot added the area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. label Mar 30, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a message cleaning mechanism in the OpenAI provider to handle assistant messages with empty or null content. It filters out invalid messages and ensures compliance with OpenAI specifications by converting empty content to null when tool calls are present. A review comment suggests simplifying the filtering logic by merging the checks for empty and null content into a single conditional block.

Comment on lines +468 to +478
# 情况1: content 为空字符串且没有工具调用 -> 删除
if content == "" and not tool_calls:
logger.warning(f"过滤第 {idx} 条空 assistant 消息 (无工具调用)")
continue

# 情况2: content 为 None 但没有工具调用 -> 删除或赋予空字符串
if content is None and not tool_calls:
logger.warning(
f"过滤第 {idx} 条 null content 的 assistant 消息"
)
continue
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

为了提高代码的简洁性和可读性,可以将处理空字符串 content 和 None content 且没有 tool_calls 的 assistant 消息的逻辑合并为一个条件判断。这两种情况都导致消息被过滤掉,合并后可以减少重复代码。

建议:

Suggested change
# 情况1: content 为空字符串且没有工具调用 -> 删除
if content == "" and not tool_calls:
logger.warning(f"过滤第 {idx} 条空 assistant 消息 (无工具调用)")
continue
# 情况2: content 为 None 但没有工具调用 -> 删除或赋予空字符串
if content is None and not tool_calls:
logger.warning(
f"过滤第 {idx} 条 null content 的 assistant 消息"
)
continue
# 情况1: content 为空字符串或 None 且没有工具调用 -> 删除
if (content == "" or content is None) and not tool_calls:
logger.warning(f"过滤第 {idx} 条空或 null content 的 assistant 消息 (无工具调用)")
continue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] AstrBot 在调用 Moonshot (Kimi K2.5) API 时的空消息报错解决建议

1 participant