Skip to content

[bug] Claude Code adapter inject模式实现Bug报告 #14

Description

@YYangZiXin

What happened?

Claude Code adapter inject模式实现Bug报告

问题概述

类型: Bug - 设计缺陷
组件: src/adapters/claude-code.ts
影响: inject模式不是真正的skill注入,而是文本追加
严重程度: 高 - inject模式本质设计错误


Bug描述

当前inject实现

// src/adapters/claude-code.ts:576-580
if (skillMode === "inject") {
  appendSystemPrompt = injectedSystemPrompt(task.skillContent)
}
// 实际命令: claude --append-system-prompt "<skvm-skill-injected/>\n\n{skillContent}"

问题本质

inject模式使用--append-system-prompt参数追加文本到system prompt,这不是Claude Code的skill系统

关键问题

  • --append-system-prompt只是追加一段文本,不是skill机制
  • skill不会出现在init事件的skills列表中
  • 无法通过/skill命令调用
  • Claude Code不将其识别为skill
  • 模型只是一段额外instruction,不知道这是skill

Bug后果

1. skillLoaded检测失败

由于inject模式使用--append-system-prompt而非skill系统:

  • skill不会出现在init事件的skills列表中
  • detectSkillInject依赖模型回显sentinel(thinking mode不回显)
  • 最终skillLoaded=false
// src/adapters/claude-code.ts:649-656
if (task.skillContent && skillLoaded === false) {
  if (skillMode === "inject") {
    skillLoaded = detectSkillInject(events, snippet)  // 返回false
  }
}

2. Evidence记录skill未加载

// src/adapters/claude-code.ts:659-661
if (skillLoaded !== undefined) {
  result.skillLoaded = skillLoaded  // false
}

Evidence的runMeta.skillLoaded=false被写入agent logs。

3. Optimizer生成WARNING警告

// src/jit-optimize/workspace.ts:536
if (ev.runMeta.skillLoaded === false) {
  parts.push(`- WARNING: skill was not loaded`)
}

Optimizer在生成evidence摘要时,看到"WARNING: skill was not loaded"。

4. Optimizer误判放弃优化

Optimizer认为"无法基于skill分析问题",因为skill"未加载":

Round 1: optimizer abstained (infraBlocked).
Reason: Run with Evidence Index 0 (runStatus=ok) shows
'WARNING: skill was not loaded', meaning the agent operated
without the skvm-general skill's guidance. No skill-level
diagnosis is possible from this evidence.

5. jit-optimize流程中断

=== Round 0 (baseline): train=0.700  test=0.613 ===
=== Round 1/3 ===
optimizer abstained (infraBlocked)
Proposal finalized as infra-blocked
  • Round 0 baseline评估完成(有分数)
  • Round 1 optimizer启动但立即放弃
  • 后续round全部跳过
  • 无法进入skill修改流程

6. 最终结果:无法完成skill迭代

status: infra-blocked
best round: 0
total rounds: 2 (但实际只有round-0有效)

关键后果

  • 没有产生skill修改建议
  • 没有优化后的skill版本(round-1/round-2)
  • 没有验证skill提升效果
  • jit-optimize核心功能完全失效

7. 受影响范围

受影响的模型

  • GLM系列(DashScope,thinking mode)
  • DeepSeek thinking mode
  • 其他不会回显system prompt内容的模型

不受影响的模型

  • 可能某些Anthropic模型会回显(但行为不确定)

8. 实际测试证据

# 测试日志 ~/.skvm/proposals/.../run.log
[10:38:52.381] Round 0 (baseline): train=0.700  test=0.613
[10:38:52.387] === Round 1/3 ===
[10:44:40.716] optimizer abstained (infraBlocked)
Reason: WARNING: skill was not loaded

# proposal状态
status: infra-blocked
bestRoundReason: infra-blocked at round-1: skill was not loaded

对比分析

inject模式(当前实现)

claude --append-system-prompt "<skvm-skill-injected/>\n\n{skill内容}"
  • 追加文本到system prompt末尾
  • Claude Code视为普通文本
  • 不在skill系统中
  • 检测依赖模型回显(不可靠)

discover模式(正确实现)

# skill文件: .claude/skills/skvm-general/SKILL.md
claude -p "prompt"
  • 使用官方skill目录
  • Claude Code自动加载识别
  • 在init事件skills列表中
  • 模型可通过/skill调用
  • 检测基于init事件(可靠)

应该如何实现inject模式

建议方案:skill文件 + prompt触发

inject模式应该写入skill文件并在prompt中触发调用

if (skillMode === "inject") {
  // 1. 写入skill文件(同discover)
  const skillDir = path.join(task.workDir, ".claude", "skills", skillName)
  await mkdir(skillDir, { recursive: true })
  const frontmatter = `---\nname: ${skillName}\ndescription: ${skillDesc}\n---\n\n`
  await Bun.write(path.join(skillDir, "SKILL.md"), frontmatter + task.skillContent)
  
  // 2. 在prompt中触发skill调用
  prompt = `/skill ${skillName}\n\n${task.prompt}`
}

效果

  • skill通过官方机制加载
  • 模型主动响应/skill命令加载skill
  • skill出现在init事件skills列表中
  • 检测可以基于Skill tool调用或init事件

模式语义重新定义

模式 行为 含义
discover 写入skill文件 skill静默存在,模型可能自动发现
inject 写入skill文件 + prompt触发 /skill skill存在 + 主动调用,模型必加载

核心区别

  • discover:skill存在,等待模型自动识别(基于description触发)
  • inject:skill存在 + 强制调用,模型一定会加载使用

当前inject模式的额外问题

检测逻辑依赖模型回显

// src/adapters/claude-code.ts:430
if (text.includes(SKILL_INJECT_SENTINEL)) return true

假设模型会在输出中回显<skvm-skill-injected/>sentinel:

  • thinking mode模型不回显system prompt内容
  • 导致误判skill未加载
  • 即使修复检测,inject本身仍是错误设计

建议修复方案

步骤1:重新实现inject模式

// src/adapters/claude-code.ts:576-589
if (task.skillContent) {
  skillLoaded = false
  
  // 无论inject还是discover,都写入skill文件
  const skillDir = path.join(task.workDir, ".claude", "skills", skillName)
  await mkdir(skillDir, { recursive: true })
  const frontmatter = `---\nname: ${skillName}\ndescription: ${skillDesc}\n---\n\n`
  await Bun.write(path.join(skillDir, "SKILL.md"), frontmatter + task.skillContent)
  
  if (skillMode === "inject") {
    // inject模式:在prompt中触发skill调用
    prompt = `/skill ${skillName}\n\n${task.prompt}`
  }
}

步骤2:更新检测逻辑

// inject模式检测:模型是否执行了Skill tool调用
if (skillMode === "inject") {
  skillLoaded = detectSkillInvoke(events, skillName)  // 检测Skill tool调用
} else {
  skillLoaded = detectSkillDiscover(events, skillName)  // 检测init事件skills列表
}

新增检测函数

function detectSkillInvoke(events: ClaudeCodeEvent[], skillName: string): boolean {
  const matchesName = (s: unknown): boolean =>
    typeof s === "string" && (s === skillName || s.endsWith(`:${skillName}`))
  
  for (const ev of events) {
    if (ev.type !== "assistant" || !ev.message) continue
    const content = Array.isArray(ev.message.content) ? ev.message.content : []
    for (const c of content) {
      if (!c || (c as { type?: string }).type !== "tool_use") continue
      const tu = c as ClaudeCodeContentToolUse
      if (tu.name === "Skill" || tu.name === "skill") {
        const inputName = (tu.input as { name?: string; skill?: string })?.name
          ?? (tu.input as { name?: string; skill?: string })?.skill
        if (matchesName(inputName)) return true
      }
    }
  }
  return false
}

相关文件

文件 位置 问题
src/adapters/claude-code.ts:576-580 inject模式实现 使用--append-system-prompt而非skill系统
src/adapters/claude-code.ts:417-435 detectSkillInject 检测依赖模型回显

测试验证

验证修复后inject模式

预期行为:

  1. skill文件写入.claude/skills/<name>/SKILL.md
  2. prompt以/skill <name>开头
  3. 模型执行Skill tool调用
  4. init事件显示skill已加载
  5. 检测返回skillLoaded=true

报告人: yang_zixin
日期: 2026-05-13
状态: 待修复
建议优先级: 高 - 需要重新实现inject模式逻辑

Reproduction

.

Logs / output

SkVM version / commit

.

Runtime

.

Additional context

No response

Checks

  • I searched existing issues and this is not a duplicate.
  • I read CONTRIBUTING.md.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions