Skip to content

建议支持多轮对话 Assistant 历史思考 (reasoning_content) 正文注入回放,避免上游静默丢弃 #123

Description

@pinewhite

背景与问题描述 (Background & Problem)

在将 codebuddy2api 作为各类支持推理思考链的客户端(如 DeepSeek Harness, OpenCode/OMP, Claude Code, Cherry Studio 等)的上游反代时,发现多轮对话中存在**“上轮 Assistant 的思考过程被丢弃,下轮模型无法感知前序思考”**的问题:

  1. 下行流式正常:流式 SSE 能正确产出思考过程,并在客户端渲染折叠块。
  2. 上行回放丢失:下一轮对话中,客户端回传上一轮 assistant 消息中的 reasoning_content。但由于直接原样将 JSON 转发给腾讯 CodeBuddy 上游接口,腾讯网关在反序列化强类型消息体时,只读取 rolecontenttool_calls 等白名单字段,客户端附带的非标扩展字段 reasoning_content 被服务端静默丢弃
  3. 模型层结果:上游组装给底层模型(如 DeepSeek-v4-flash、混元等)的上下文里完全缺失思考部分,底层模型的自注意力机制(Self-Attention)无法看到上一轮推导的中间逻辑,Prompt Tokens 增加量也为 0,导致长上下文或需要延续上轮思路的多步代码重构中频繁出现“思维断层”。

根本原因 (Root Cause)

  1. 上游服务严格白名单反序列化:腾讯私有网关不接收非标字段 reasoning_content
  2. 大模型注意力机制依赖正文:现代推理大模型底层对历史思考的自注意力捕捉,严重依赖其作为正文文本存在(如 <thought>...</thought><think>...</think>)。

建议解决方案 (Suggested Fix)

在网关将客户端请求转发给腾讯 CodeBuddy 上游前,针对 messages 数组做一层快速拦截:

  • 遍历所有 role === "assistant" 的历史记录;
  • 若消息包含 reasoning_content,且尚未包含 <thought> 标签,将其提取并包装为 <thought>\n${reasoning_content}\n</thought> 前置拼入 content 首部;
  • 这样上游网关只看到完全合规的标准 content 正文字符串,底层模型也能够实打实地读取历史思考。

参考伪代码 (Node.js / TypeScript):

function injectAssistantReasoning(messages: any[]) {
  if (!Array.isArray(messages)) return;
  for (const msg of messages) {
    if (msg.role !== 'assistant') continue;
    
    const reasoning = msg.reasoning_content || msg.reasoning;
    if (!reasoning || typeof reasoning !== 'string' || !reasoning.trim()) continue;

    const thoughtBlock = `<thought>\n${reasoning.trim()}\n</thought>`;
    if (typeof msg.content === 'string') {
      if (!msg.content.trim().startsWith('<thought>')) {
        msg.content = msg.content.trim() 
          ? `${thoughtBlock}\n\n${msg.content}` 
          : thoughtBlock;
      }
    } else if (Array.isArray(msg.content)) {
      const firstTextPart = msg.content.find((p: any) => p.type === 'text');
      if (firstTextPart && typeof firstTextPart.text === 'string' && !firstTextPart.text.trim().startsWith('<thought>')) {
        firstTextPart.text = `${thoughtBlock}\n\n${firstTextPart.text}`;
      }
    }
  }
}

实测验证与收益

经实测:

  • 加上该正文注入后,无论模型是 DeepSeek 还是混元,均能在多轮对话中精准回忆上轮思考细节;
  • 同时保持了与上游网关的完全兼容,不会触发 400 格式错误或 WAF 拦截。
  • 建议作为可选开关(默认推荐启用)加入到请求转换管道中。

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions