Files
zclaw_openfang/plans/polymorphic-orbiting-pinwheel.md
iven aa6a9cbd84
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
feat: 新增技能编排引擎和工作流构建器组件
refactor: 统一Hands系统常量到单个源文件
refactor: 更新Hands中文名称和描述

fix: 修复技能市场在连接状态变化时重新加载
fix: 修复身份变更提案的错误处理逻辑

docs: 更新多个功能文档的验证状态和实现位置
docs: 更新Hands系统文档

test: 添加测试文件验证工作区路径
2026-03-25 08:27:25 +08:00

3.6 KiB
Raw Permalink Blame History

ZCLAW Skill系统问题修复 - 完成报告

问题诊断

用户报告的问题

对话过程中agent无法正确调用skill去完成任务。

根因分析

经过代码分析,发现两个核心问题

问题1: Agent循环不完整

位置: crates/zclaw-runtime/src/loop_runner.rs

原始实现:

用户消息 → LLM → 工具调用 → 结果直接返回

正确实现应该是:

用户消息 → LLM → 工具调用 → 工具结果 → LLM(处理结果) → 最终响应

关键代码问题:

// 原始代码在工具执行后直接返回结果
full_response.push_str(&format!("\n[工具 {} 结果]: {}", name, ...));

问题2: 流式输出暴露内部细节

StreamChunk::ToolUseDelta事件被当作[工具参数]文本输出给用户,这是调试信息不应该暴露。


修复方案

1. 实现完整Agent循环

文件: crates/zclaw-runtime/src/loop_runner.rs

改动:

  • 添加循环结构, 最多10次迭代
  • 检查LLM响应中的工具调用
  • 如果没有工具调用, 返回最终响应
  • 如果有工具调用, 执行后添加结果到消息历史, 继续循环让LLM处理
loop {
    iterations += 1;
    if iterations > max_iterations { return error; }

    // 调用LLM
    let response = self.driver.complete(request).await?;

    // 提取工具调用
    let tool_calls = response.content.iter().filter_map(|b| match b {
        ContentBlock::ToolUse { id, name, input } => Some((id, name, input)),
        _ => None
    }).collect();

    // 没有工具调用 - 返回最终响应
    if tool_calls.is_empty() {
        return Ok(AgentLoopResult { response: text, ... });
    }

    // 添加工具调用到消息历史
    for (id, name, input) in &tool_calls {
        messages.push(Message::tool_use(id, ToolId::new(name), input));
    }

    // 执行工具
    for (id, name, input) in tool_calls {
        let result = self.execute_tool(&name, input, &context).await;
        messages.push(Message::tool_result(id, ToolId::new(&name), result));
    }

    // 继续循环 - LLM将处理工具结果
}

2. 简化LoopEvent

改动:

pub enum LoopEvent {
    Delta(String),
    ToolStart { name: String },
    ToolEnd { name: String, output: serde_json::Value },
    IterationStart { iteration: usize, max_iterations: usize },
    Complete(AgentLoopResult),
    Error(String),
}

隐藏的信息:

  • ToolUseDelta - 工具参数增量(内部处理)
  • 工具的详细input/output只记录到消息历史

3. 多轮流式支持

run_streaming方法:

  • 实现与run相同的循环逻辑
  • 支持流式输出
  • 发送IterationStart事件通知新迭代开始

验证

编译状态

编译通过,无错误

需要测试

  1. 单次工具调用 - "搜索腾讯财报"
  2. 多轮工具调用 - "搜索并分析数据"
  3. 无工具调用 - "你好"

后续步骤

  1. 手动测试 - 启动应用测试skill调用流程
  2. 前端适配 - 磁保前端正确处理新的事件类型
  3. 文档更新 - 更新skill系统文档

关键文件

文件 改动说明
crates/zclaw-runtime/src/loop_runner.rs 核心循环逻辑重写
crates/zclaw-types/src/message.rs 已有tool_result方法(无需修改)
crates/zclaw-kernel/src/kernel.rs System prompt构建已有skill注入

测试命令

# 编译
cargo build -p zclaw-runtime

# 启动开发环境
pnpm start:dev

# 测试对话
# 发送: "帮我分析一下腾讯的财报"
# 预期: LLM调用execute_skill工具返回分析结果