执行摘要
本 PR 修复了 Rust 前端 DeepSeek V4 渲染器中历史开发者消息处理的 bug,使其与 Python tokenizer 行为对齐。当启用 thinking 且 drop_thinking 为 true 时,现在会正确删除最后一个用户类轮次之前的开发者消息,确保多轮对话提示的一致性。
功能与动机
Rust DeepSeek V4 渲染器在 thinking=true 且有效 drop_thinking=true 时,错误地保留了出现在最后一个用户类轮次之前的开发者消息,而 Python tokenizer 和官方 DeepSeek 编码会删除这些历史开发者消息。本 PR 旨在对齐 Rust 实现,消除这一不一致行为。
实现拆解
- 核心渲染逻辑调整:在
encoding.rs 的 render_request 函数中,新增 drop_historical_developers 条件和 last_user_like_message_index,用于判断是否删除历史开发者消息。在主循环中,当条件满足时跳过历史开发者消息。
- 新增辅助函数:添加
is_historical_developer 函数,定义历史开发者消息为 Developer 类型且索引小于最后一个用户类消息索引的消息。
- 调整消息跳过逻辑:修改
next_rendered_entry_is_assistant_or_end 函数,增加参数以支持跳过历史开发者消息,确保正确写入助手过渡。
- 测试覆盖增强:在
tests.rs 中新增辅助函数 thinking_request 和多个测试用例,覆盖各种消息序列场景,如开发者消息在用户消息前后、工具调用等。
rust/src/chat/src/renderer/deepseek_v4/encoding.rs
核心渲染逻辑修改,添加历史开发者消息处理条件和函数,确保与 Python tokenizer 行为对齐。
// encoding.rs 中 render_request 函数的关键变更:添加历史开发者消息处理逻辑
let drop_historical_developers = thinking_mode == ThinkingMode::Thinking && drop_thinking;
let last_user_like_message_index = request.messages.iter().rposition(is_user_like_entry);
// ... 主循环中 ...
if drop_historical_developers
&& is_historical_developer(message, message_index, last_user_like_message_index)
{
continue; // 跳过历史开发者消息
}
// ... 后续逻辑 ...
if (is_user_like_entry(message) || matches!(message, ChatMessage::System { .. }))
&& next_rendered_entry_is_assistant_or_end(
request.messages.as_slice(),
message_index,
drop_historical_developers,
last_user_like_message_index,
)
{
write_assistant_transition(
&mut out,
thinking_mode,
drop_thinking,
current_render_index >= last_user_render_index,
);
}
// 新增函数:判断是否为历史开发者消息
fn is_historical_developer(
message: &ChatMessage,
message_index: usize,
last_user_like_message_index: Option<usize>,
) -> bool {
matches!(message, ChatMessage::Developer { .. })
&& last_user_like_message_index.is_some_and(|last_index| message_index < last_index)
}
// 修改函数:调整以支持跳过历史开发者消息
fn next_rendered_entry_is_assistant_or_end(
messages: &[ChatMessage],
message_index: usize,
drop_historical_developers: bool,
last_user_like_message_index: Option<usize>,
) -> bool {
let mut next_index = message_index + 1;
while next_index < messages.len()
&& (is_following_user_content(messages, next_index)
|| (drop_historical_developers
&& is_historical_developer(
&messages[next_index],
next_index,
last_user_like_message_index,
)))
{
next_index += 1;
}
messages
.get(next_index)
.map(|message| matches!(message, ChatMessage::Assistant { .. }))
.unwrap_or(true)
}
rust/src/chat/src/renderer/deepseek_v4/tests.rs
新增多个测试用例,验证历史开发者消息处理的各种场景,确保变更正确性和回归防护。
// tests.rs 中新增的辅助函数和测试用例
fn thinking_request(messages: Vec<ChatMessage>) -> ChatRequest {
let mut request = ChatRequest {
messages,
..ChatRequest::for_test()
};
request
.chat_options
.template_kwargs
.insert("thinking".to_string(), Value::Bool(true));
request.chat_options.reasoning_effort = Some(ReasoningEffort::Low);
request
}
#[test]
fn drop_thinking_removes_developer_before_last_user() {
let request = thinking_request(vec![
ChatMessage::developer("old instruction", None),
ChatMessage::assistant_blocks(vec![
AssistantContentBlock::Reasoning {
text: "old reasoning".to_string(),
},
AssistantContentBlock::Text {
text: "old answer".to_string(),
},
]),
ChatMessage::user("next question"),
]);
let rendered = render_request(&request);
expect![
"<|begin▁of▁sentence|>old answer<|end▁of▁sentence|><|User|>next question<|Assistant|>"
]
.assert_eq(&rendered);
}
#[test]
fn tools_keep_historical_developer() {
let tool = ChatTool {
name: "lookup".to_string(),
description: None,
parameters: Value::Object(Default::default()),
strict: None,
};
let request = thinking_request(vec![
ChatMessage::developer("old instruction", Some(vec![tool])),
ChatMessage::assistant_text("old answer"),
ChatMessage::user("next question"),
]);
let rendered = render_request(&request);
assert!(rendered.contains("<|User|>old instruction"));
}
评论区精华
无深入技术讨论。自动审查和手动批准过程顺利,主要关注点在于 CI 触发和审查状态。
风险与影响
- 风险:核心渲染逻辑变更可能引入回归,但测试覆盖良好,新增的多个测试用例验证了关键场景。影响限于 Rust DeepSeek V4 渲染器,处理多轮对话时。
- 影响:确保了 Rust 和 Python 实现的行为一致性,可能间接提升推理提示的质量。对用户无直接功能变更,但提高了代码可靠性。
关联脉络
本 PR 与 PR #54566(添加 DeepSeek-V4-Flash-Vision-Exp 多模态支持)同属 DeepSeek V4 模型支持系列,后者扩展模型能力,而本 PR 修复基础渲染行为,共同完善 DeepSeek V4 的推理支持。
参与讨论