Skip to content

[WIP] Improve code coverage for oxo-call to 95% - #159

Closed
ShixiangWang with Copilot wants to merge 1 commit into
mainfrom
copilot/increase-code-coverage-to-95
Closed

[WIP] Improve code coverage for oxo-call to 95%#159
ShixiangWang with Copilot wants to merge 1 commit into
mainfrom
copilot/increase-code-coverage-to-95

Conversation

Copilot AI commented May 1, 2026

Copy link
Copy Markdown
Contributor

Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.


This section details on the original issue you should resolve

<issue_title>test</issue_title>
<issue_description>oxo-call全部代码的覆盖度代码覆盖度请提升到95%(以模块化测试为核心)

检查和是否全面完成和达到重构计划目标。全面检查和清理oxo-call冗余代码。

# oxo-call v0.13 融合式架构重构计划

> 版本: 2026-04-29
> 基于: 20260429.md 用户设计思想 + hidden-jumping-globe.md HDA架构 + 全面代码分析

---

## 一、重构目标与原则

### 1.1 核心目标

将 oxo-call 从"串行管道"架构重构为"融合式Agent流水线"架构,实现:

1. **泛化准确度高**: doc模式≥0.8, full模式≥0.95
2. **3B模型稳定可靠**: 结构化输出 + Schema白名单约束,消除幻觉
3. **最少LLM调用**: 确定性代码优先,LLM仅在代码无法解决时介入
4. **最少token消耗**: 极简prompt + 结构化JSON输出
5. **最快响应速度**: Rust性能最大化,并行获取文档
6. **最通用设计**: 覆盖任何CLI工具(含路径依赖命令、无文档工具等)

### 1.2 设计原则

- **代码为主,LLM为辅**: 每个阶段都是 `if deterministic_solution { use_it } else { call_llm() }`
- **Schema即约束**: LLM只能从Schema白名单中选择flag,消除extra_flag幻觉
- **结构化输出**: LLM填充JSON而非自由生成命令字符串,代码负责组装
- **融合而非拼接**: Doc+Skill融合为ToolDoc,Prompt+Doc融合,不再独立存在

### 1.3 Breaking Changes

| 变更 | 旧 | 新 | 原因 |
|------|-----|-----|------|
| `--scenario` | bare/prompt/doc/skill/full | bare/doc/full | prompt与doc融合,skill与full融合 |
| `--no-prompt` | 存在 | 删除 | prompt已融入doc,无独立存在意义 |
| `--no-skill` | 存在 | 删除 | skill已融入full,用--scenario doc替代 |
| `--no-doc` | 存在 | 删除 | 用--scenario bare替代 |
| `ChatScenario` | 5值枚举 | 3值枚举 | 同run scenario |
| `WorkflowScenario` | 5值枚举 | 3值枚举 | 同上 |
| `TOOL_SUBCOMMAND_MAP` | 硬编码 | 删除 | 由Schema动态生成 |
| `KNOWN_SUBCOMMANDS` | 3处重复定义 | 删除 | 由Schema.subcommands动态提供 |
| `subcommand_detector.rs` | 独立模块 | 删除 | 功能由Schema解析覆盖 |
| `doc_summarizer.rs` | 独立模块 | 融入ToolDoc | 不再需要独立摘要 |
| `reflection_engine.rs` | 独立模块 | 删除 | 未使用 |
| `auto_fixer.rs` | 独立模块 | 融入Validation | 不再独立 |
| `rag/` | 独立模块 | 删除 | 未有效使用 |
| `orchestrator/` | 独立模块 | 删除 | 过度设计,由融合流水线替代 |
| `knowledge/` | 独立模块 | 融入Skill/ToolDoc | 不再独立 |
| `validation_loop.rs` | 独立模块 | 融入Stage 5 | 不再独立 |
| `llm_workflow.rs` | 独立模块 | 重写为Pipeline | 架构变更 |
| `workflow_graph.rs` | 独立模块 | 重写为Pipeline | 架构变更 |
| `engine.rs` | 独立模块 | 删除 | 功能融入Runner |
| `context.rs` | 独立模块 | 融入IntentMapper | 不再独立 |
| `command_validator.rs` | 独立模块 | 融入Stage 5 | 不再独立 |
| `generator.rs` | 独立模块 | 融入CommandAssembler | 不再独立 |
| `validate_tool_name()` | 拒绝`/`和`\` | 支持路径依赖命令 | 核心需求 |

---

## 二、融合式五阶段流水线

┌─────────────────────────────────────────────────────────────────────────┐
│ oxo-call v0.13 融合式架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Stage 1: Tool Resolution (纯代码, 0次LLM) │
│ 输入: │
│ 输出: ToolRecord │
│ │
│ Stage 2: Doc Exploration (代码为主, 0-1次LLM) │
│ 输入: ToolRecord │
│ 输出: ToolDoc (融合Schema+Doc+Skill) │
│ │
│ Stage 3: Intent Mapping (代码为主, 1次LLM) │
│ 输入: ToolDoc + TASK │
│ 输出: LlmCommandFill (结构化JSON) │
│ │
│ Stage 4: Command Assembly (纯代码, 0次LLM) │
│ 输入: ToolRecord + LlmCommandFill + ToolDoc │
│ 输出: 完整命令字符串 │
│ │
│ Stage 5: Validation (代码为主, 0-1次LLM) │
│ 输入: 命令 + ToolDoc │
│ 输出: ValidationResult │
│ │
│ 总LLM调用: 最少0次(bare), 最多3次(低置信度full) │
│ 总token消耗: 最少0, 最多约2000 │
└─────────────────────────────────────────────────────────────────────────┘


---

## 三、核心数据模型

### 3.1 ToolRecord (Stage 1 产出)

```rust
struct ToolRecord {
    name: String,                       // 用户输入的原始名称
    resolved_path: PathBuf,             // 解析后的绝对路径
    interpreter: Option<Interpreter>,   // python/Rscript/perl/bash/none
    is_path_dependent: bool,            // 是否路径依赖命令
    global_path: Option<PathBuf>,       // which查找到的全局路径(非路径依赖时)
    version: Option<String>,            // tool --version 输出
    companion_tools: Vec<String>,       // 伴生命令 (如bowtie2-build, hisat2-build)
}

enum Interpreter {
    Python { path: PathBuf },
    Rscript { path: PathBuf },
    Perl { path: PathBuf },
    Bash { path: PathBuf },
    None,
}

伴生命令定义修正: 伴生命令是随主工具一起安装的辅助二进制文件,而非不同工具的替代版本。

主工具 伴生命令 说明
bowtie2 bowtie2-build, bowtie2-inspect 索引构建和检查
hisat2 hisat2-build, hisat2-inspect 索引构建和检查
bismark bismark_genome_preparation, bismark2genome, deduplicate_bismark 甲基化辅助工具
manta configureManta.py 配置脚本
strelka2 configureStrelka2.py 配置脚本

注意: bwa和bwa-mem2是完全不同的工具,不是伴生关系。bwa-mem2是bwa-mem算法的独立重新实现,有自己的二进制和子命令。

3.2 ToolDoc (Stage 2 产出, 融合Schema+Doc+Skill)

struct ToolDoc {
    // 来自Stage 1
    record: ToolRecord,

    // CLI元信息
    cli_style: CliStyle,
    description: String,
    schema_source: String,              // "argparse"|"clap"|"cobra"|"click"|"generic"|"llm-enhanced"
    doc_quality: f32,                   // 0.0-1.0

    // 命令结构
    subcommands: Vec<SubcommandDoc>,
    global_flags: Vec<FlagDoc>,
    flags: Vec<FlagDoc>,                // 非子命令工具的flags
    positionals: Vec<PositionalDoc>,
    usage_patterns: Vec<String>,        // 从USAGE行提取
    constraints: Vec<ConstraintRule>,

    // 增强信息 (来自文档解析+Skill融合)
    examples: Vec<CommandExample>,      // 文档示例 + Skill示例
    concepts: Vec<String>,              // 来自Skill的领域概念
    pitfalls: Vec<String>,              // 来自Skill的常见错误

    // 原始文档 (用于LLM上下文)
    raw_help: Option<String>,           // 原始help输出
    subcommand_helps: HashMap<String, String>, // 子命令help输出
}

struct SubcommandDoc {
    name: String,
    description: String,
    usage_pattern: String,
    flags: Vec<FlagDoc>,
    positionals: Vec<PositionalDoc>,
    constraints: Vec<ConstraintRule>,
    task_keywords: Vec<String>,         // 从DOMAIN_SUBCMD_MAP + 文档提取
}

struct FlagDoc {
    name: String,                       // 主名 (如 "-o", "--output")
    aliases: Vec<String>,               // 别名 (如 ["-o", "--out"])
    param_type: ParamType,
    description: String,
    default: Option<String>,
    required: bool,
    category: FlagCategory,             // 参数分类
}

enum FlagCategory {
    Input,                              // -i, --input, --read1
    Output,                             // -o, --output, --out
    Performance,                        // -@, --threads, --memory
    Quality,                            // -q, --min-quality, --min-mapq
    Format,                             // --format, --bam, --sam
    Algorithm,                          // -a, --algorithm, --strategy
    General,                            // -h, --help, --version, --verbose
}

struct PositionalDoc {
    position: usize,
    name: String,                       // 占位名 (如 "INPUT", "K", "OUTPUT")
    param_type: ParamType,
    description: String,
    required: bool,
    default: Option<String>,
}

struct CommandExample {
    args: String,                       // 命令参数部分
    explanation: String,
    source: ExampleSource,              // 来源标记
}

enum ExampleSource {
    HelpText,                           // 从help输出提取
    SkillFile,                          // 从Skill文件提取
    LlmGenerated,                       // LLM清洗时生成
}

3.3 LlmCommandFill (Stage 3 产出, 结构化LLM输出)

struct LlmCommandFill {
    subcommand: Option<String>,
    flags: BTreeMap<String, String>,    // flag_name → value (有序,保证输出稳定)
    positionals: Vec<String>,
}

四、各阶段详细设计

Stage 1: Tool Resolution (纯代码, 0次LLM)

1.1 路径依赖命令识别

输入: 用户输入的tool字符串
输出: ToolRecord

路径依赖判定规则:
  - 包含 '/' 或 '\' → 路径依赖命令
  - 不含路径分隔符 → 非路径依赖命令

路径依赖命令处理:
  1. 解析路径: 相对路径→绝对路径
  2. 检测解释器:
     a. 读取文件shebang行 (#!/usr/bin/env python3, #!/usr/bin/Rscript)
     b. 根据扩展名: .py→Python, .R→Rscript, .pl→Perl, .sh→Bash
     c. 无扩展名+无shebang→尝试file命令检测
  3. 记录: name=原始输入, resolved_path=绝对路径, interpreter=检测到的解释器

非路径依赖命令处理:
  1. which/whereis查找全局路径
  2. 检测版本: tool --version 或 tool -v
  3. 发现伴生命令: 遍历PATH中{tool}-*和{tool}_*模式的可执行文件
  4. 记录: name=工具名, global_path=which结果, companion_tools=发现的伴生命令

1.2 伴生命令发现算法

fn discover_companions(tool: &str) -> Vec<String> {
    // 1. 前缀模式: {tool}-xxx (如 bowtie2-build)
    // 2. 前缀模式: {tool}_xxx (如 bismark_genome_preparation)
    // 3. 脚本模式: {tool}*.py, {tool}*.sh (如 configureManta.py)
    // 4. 后缀模式: xxx_{tool} (如 deduplicate_bismark)
    // 验证: 发现的候选必须在PATH中可执行
}

1.3 validate_tool_name 重写

fn validate_tool_name(tool: &str) -> Result<()> {
    if tool.is_empty() {
        return Err(...);
    }
    // 不再拒绝 / 和 \
    // 只拒绝 .. 和明显危险的路径
    if tool.contains("..") {
        return Err(...);
    }
    Ok(())
}

Stage 2: Doc Exploration (代码为主, 0-1次LLM)

2.1 递归Help获取 (全面策略)

根命令Help获取策略 (按优先级):

序号 命令 适用场景
1 tool --help 最常见
2 tool -h 常见简写
3 tool -H 部分工具
4 tool help Git风格工具
5 tool --usage GNU工具
6 tool --help-all 部分工具(扩展帮助)
7 tool (无参数) 很多生信工具无参数时输出usage
8 tool -help 部分旧工具
9 tool --h 少见
10 tool -? Windows风格(少见)
11 bash -c "help -- tool" Shell内置命令

子命令Help获取策略:

序号 命令 适用场景
1 tool subcmd --help 标准子命令
2 tool subcmd -h 简写
3 tool help subcmd Git风格 (如 git help commit)
4 tool subcmd (无参数) 很多生信子命令无参数时输出usage
5 tool --help subcmd 少见
6 tool subcmd --help-all 扩展帮助

子命令发现方法:

序号 方法 说明
1 解析根help中的 "Commands:"/"Subcommands:" 段 最常见
2 解析USAGE行中的 {cmd1,cmd2,...} 模式 Python argparse
3 解析 "Available Commands:" 段 Go Cobra
4 尝试 tool help 子命令 部分工具有help子命令
5 DOMAIN_SUBCMD_MAP 语义映射 已有,保留
6 尝试已知子命令名并验证 补充发现

递归深度: 最大3层

Level 0: tool --help (根命令)
Level 1: tool subcmd1 --help (一级子命令, 如 samtools sort --help)
Level 2: tool subcmd1 subcmd2 --help (二级子命令, 如 git remote add --help)
Level 3: tool subcmd1 subcmd2 subcmd3 --help (三级子命令, 极少见)

大部分生信工具只需要Level 0-1,Level 2-3主要针对git等复杂工具。

2.2 Help文本有效性判断

fn is_valid_help(output: &str) -> bool {
    let lower = output.to_lowercase();
    // 必须包含帮助信息关键词
    let has_help_section = lower.contains("usage")
        || lower.contains("option")
        || lower.contains("flag")
        || lower.contains("command")
        || lower.contains("argument")
        || lower.contains("syntax");
    // 排除纯错误输出
    let is_pure_error = (lower.contains("error:") || lower.contains("fatal:"))
        && !has_help_section;
    // 最小长度
    let long_enough = output.trim().len() >= 80;
    has_help_section && !is_pure_error && long_enough
}

2.3 多框架解析器

框架 检测特征 解析器 状态
Python argparse "optional arguments:", "positional arguments:", "show this help message" PythonArgparseParser 已有
Python Click 类似argparse但格式不同 ClickParser 需新增
Rust clap "Options:" 标题, 表格对齐, 无"optional arguments" ClapParser 需新增
Go Cobra "Available Commands:", 缩进子命令列表 CobraParser 需新增
Go flag 简单flag列表, tab分隔 GoFlagParser 需新增
通用 其他 GenericParser 已有, 需增强

2.4 LLM清洗Agent (仅当doc_quality < 0.5时触发)

触发条件: Schema解析后doc_quality < 0.5
输入: raw_help前500字符 + 已解析的Schema摘要
输出: CliSchemaPatch (JSON格式补丁)

Prompt设计 (极少token):
  "Given this CLI help excerpt and partial schema, identify:
   1. Missing flag descriptions
   2. Incorrect parameter types
   3. Missing required flags
   Output JSON: {\"patches\": [{\"flag\": \"-o\", \"type\": \"File\", \"desc\": \"...\"}]}"

关键: LLM只做"补丁",不做"重写" → 极少token

2.5 ToolDoc生成 (融合Schema+Doc+Skill)

输入: ToolRecord + RawDocCollection + CliSchema + Option<Skill>
输出: ToolDoc

融合规则:
1. Schema提供: cli_style, flags, subcommands, positionals, constraints, usage_patterns
2. Doc提供: description, raw_help, examples(从文档提取), doc_quality
3. Skill提供: concepts, pitfalls, examples(从Skill提取), task_keywords增强
4. 融合时Skill的examples优先于Doc的examples (人工校验 > 自动提取)
5. 融合时Skill的task_keywords补充到SubcommandDoc.task_keywords

Stage 3: Intent Mapping (代码为主, 1次LLM)

3.1 命令前缀匹配 (确定性优先)

确定性路径 (按优先级):
  1. task中直接包含子命令名 → 精确匹配
     "sort bam by coordinate" → subcommand="sort"
  2. SubcommandDoc.task_keywords语义匹配
     "align reads to ref" → bwa.mem (task_keyword="align")
  3. DOMAIN_SUBCMD_MAP映射 (保留,从docs.rs移入)
  4. 伴生命令匹配
     "build index for bowtie2" → companion="bowtie2-build"

LLM辅助 (仅当确定性路径无匹配时):
  输入: task + 子命令列表(名称+描述, 每个一行)
  输出: 子命令名 (1个token)
  token消耗: ~50-100

3.2 参数意图映射 (LLM为主, Schema约束)

这是最关键的重构: LLM从"自由生成命令"改为"填充结构化JSON"

当前方式 (问题多):
  LLM自由生成 → "sort -@ 4 -o sorted.bam input.bam"
  问题: 可能产生不存在的flag、格式错误、参数顺序错误

新方式 (可靠):
  LLM填充JSON → {"subcommand":"sort","flags":{"-@":"4","-o":"sorted.bam"},"positionals":["input.bam"]}
  代码组装 → "samtools sort -@ 4 -o sorted.bam input.bam"
  优势: flag白名单约束、格式保证、顺序可控

Prompt设计 (极简+约束):

System: You are a CLI parameter filler. Output ONLY valid JSON.

User:
Tool: samtools
Task: sort input.bam by coordinate with 4 threads and output to sorted.bam

Available subcommands: sort, view, index, merge, flagstat, depth, mpileup, stats, markdup
Selected subcommand: sort

Available flags for 'sort':
  -@ INT      - Number of additional threads [0]
  -o FILE     - Output file [stdout]
  -m INT      - Approximate maximum memory per thread [768M]
  -n          - Sort by read name
  -l INT      - Compression level [1]
  --no-PG     - Do not add PG line

Positional parameters:
  INPUT.bam   - Input BAM file

Output JSON:
{"subcommand":"sort","flags":{"-@":"4","-o":"sorted.bam"},"positionals":["input.bam"]}

关键约束:

  • LLM只能从"Available flags"列表中选择 → 消除extra_flag幻觉
  • flags值必须匹配ParamType → 类型校验
  • positionals按位置填充 → 顺序保证

Stage 4: Command Assembly (纯代码, 0次LLM)

fn assemble_command(
    record: &ToolRecord,
    fill: &LlmCommandFill,
    doc: &ToolDoc,
) -> String {
    let mut parts = Vec::new();

    // 1. 工具名/路径
    parts.push(record.effective_name());

    // 2. 子命令
    if let Some(subcmd) = &fill.subcommand {
        parts.push(subcmd.clone());
    }

    // 3. 按CliStyle排序flags和positionals
    match doc.cli_style {
        CliStyle::Subcommand | CliStyle::FlagsFirst => {
            // flags first, then positionals
            for (flag, value) in &fill.flags {
                parts.push(flag.clone());
                if !value.is_empty() {
                    parts.push(value.clone());
                }
            }
            parts.extend(fill.positionals.iter().cloned());
        }
        CliStyle::Positional => {
            // positionals first, then flags
            parts.extend(fill.positionals.iter().cloned());
            for (flag, value) in &fill.flags {
                parts.push(flag.clone());
                if !value.is_empty() {
                    parts.push(value.clone());
                }
            }
        }
        CliStyle::Hybrid => {
            // 按usage_pattern的顺序排列
            // 简化: positionals → flags → trailing_positionals
        }
    }

    parts.join(" ")
}

Stage 5: Validation (代码为主, 0-1次LLM)

5.1 Schema验证 (纯代码):
    - flag存在性: flag ∈ ToolDoc.all_flag_names()
    - 值类型: value matches ParamType
    - 必选flag: required flags 全部存在
    - 互斥flag: 无冲突组合
    - ConstraintRule: 所有约束满足

5.2 Skill校验 (如有Skill数据, 纯代码):
    - 比对生成命令与Skill examples的相似度
    - 检查是否违反Skill pitfalls

5.3 LLM最终审查 (仅低置信度, 1次调用):
    输入: 生成命令 + ToolDoc + task
    输出: "CORRECT" 或 "ISSUE: <description>"
    token消耗: ~50-100

五、CLI接口变更

5.1 Scenario枚举简化

// 旧: 5个值
enum RunScenario { Bare, Prompt, Doc, Skill, Full }
enum ChatScenario { Bare, Prompt, Doc, Skill, Full }
enum WorkflowScenario { Bare, Prompt, Doc, Skill, Full }

// 新: 3个值
enum RunScenario { Bare, Doc, Full }
enum ChatScenario { Bare, Doc, Full }
enum WorkflowScenario { Bare, Doc, Full }

Scenario含义:

Scenario 含义 LLM上下文 预期准确度
bare 仅Tool+Task 无文档、无Skill 低(~0.3)
doc Tool+Task+ToolDoc 自动解析的文档+Schema ≥0.8
full Tool+Task+ToolDoc(含Skill) 文档+Schema+Skill融合 ≥0.95

5.2 删除的CLI选项

选项 原因 替代
--scenario prompt prompt已融入doc --scenario doc
--scenario skill skill已融入full --scenario full
--no-prompt prompt不再独立 无需替代
--no-skill skill不再独立 --scenario doc
--no-doc doc不再独立 --scenario bare

5.3 保留的CLI选项

所有其他选项保留: --ask, --model, --no-cache, --json, --verify, --var, --input-list, --input-items, --jobs, --stop-on-error, --auto-retry, --no-stream

5.4 Chat命令更新

Chat的scenario同样简化为bare/doc/full:

  • bare: 纯聊天
  • doc: 加载工具文档上下文
  • full: 加载工具文档+Skill上下文

六、模块重构映射

6.1 删除的模块

模块 行数(估) 原因 功能去向
subcommand_detector.rs ~550 功能由Schema解析覆盖 Stage 2
reflection_engine.rs ~300 未使用 删除
auto_fixer.rs ~400 功能融入Validation Stage 5
rag/ ~1500 未有效使用 删除
orchestrator/ ~2000 过度设计 Stage 3/5
knowledge/ ~800 功能融入Skill/ToolDoc Stage 2
validation_loop.rs ~500 功能融入Stage 5 Stage 5
workflow_graph.rs ~700 由Pipeline替代 重写
llm_workflow.rs ~300 由Pipeline替代 重写
engine.rs ~600 功能融入Runner Runner
context.rs ~300 功能融入IntentMapper Stage 3
command_validator.rs ~400 功能融入Stage 5 Stage 5
generator.rs ~500 功能融入CommandAssembler Stage 4
doc_summarizer.rs ~800 功能融入ToolDoc Stage 2

6.2 保留的模块 (微调)

模块 保留原因 微调内容
confidence/mod.rs 置信度评估逻辑合理 微调权重,移除skill_availability(已融入doc_quality)
schema/types.rs CliSchema/FlagSchema类型定义合理 扩展为ToolDoc
schema/parser/python.rs Python argparse解析器 保留
schema/parser/generic.rs 通用解析器 增强
skill.rs Skill文件加载/解析 保留加载,融合到ToolDoc
config.rs 配置管理 保留
llm/provider.rs LLM客户端 保留
llm/types.rs LLM类型定义 新增LlmCommandFill
llm/response.rs LLM响应解析 重写为JSON解析
llm/streaming.rs SSE流式输出 保留
history.rs 历史记录 保留,更新Provenance
cache.rs 缓存 保留,缓存ToolDoc
docs.rs 文档获取 重写validate_tool_name,增强递归获取
doc_processor.rs 文档处理 融入ToolDoc生成
runner/core.rs 核心运行器 重写prepare()为五阶段流水线
runner/utils.rs 工具函数 保留companion检测,重构其他
runner/batch.rs 批量执行 保留
runner/retry.rs 重试逻辑 保留
runner/validation.rs 验证逻辑 增强,融入Stage 5
chat.rs 聊天模式 更新scenario枚举
cli.rs CLI定义 更新scenario枚举,删除ablation选项
main.rs 入口 更新scenario映射
format.rs 格式校验 保留
sanitize.rs 命令清洗 保留
license.rs 许可证 保留
server.rs SSH执行 保留
job.rs Job管理 保留
mcp.rs MCP集成 保留
handlers.rs 命令处理 更新
index.rs 索引管理 保留
markdown.rs Markdown渲染 保留
streaming_display.rs 流式显示 保留
copilot_auth.rs Copilot认证 保留
error.rs 错误类型 保留,新增ToolRecordError等

6.3 新增的模块

模块 职责
tool_resolver.rs Stage 1: Tool Resolution
doc_explorer.rs Stage 2: Doc Exploration (递归Help获取)
tool_doc.rs ToolDoc数据模型 + 生成逻辑
intent_mapper.rs Stage 3: Intent Mapping (前缀匹配+参数映射)
command_assembler.rs Stage 4: Command Assembly
validator.rs Stage 5: Validation (Schema+Skill+LLM)
pipeline.rs 五阶段流水线编排
schema/parser/clap.rs Rust clap解析器
schema/parser/cobra.rs Go Cobra解析器
schema/parser/click.rs Python Click解析器
schema/parser/goflag.rs Go flag解析器

七、Prompt设计重构

7.1 当前问题

  1. system_prompt() 有15+条规则 → 3B模型难以全部遵循
  2. TOOL_SUBCOMMAND_MAP 硬编码15个工具 → 应由Schema动态生成
  3. KNOWN_SUBCOMMANDS 在3个文件中重复定义 → 应统一
  4. LLM自由生成命令字符串 → 格式错误、flag幻觉

7.2 新Prompt架构

System Prompt (极简, ~50 tokens):

You are a CLI parameter filler. Output ONLY valid JSON matching this schema:
{"subcommand":"<name|null>","flags":{"<flag>":"<value>"},"positionals":["<value>"]}
Rules: Use ONLY flags from the provided list. Omit flags not needed. No explanation.

User Prompt (Schema约束, ~200-500 tokens):

Tool: {tool_name}
Task: {task}

Available subcommands: {subcommand_list}
Selected subcommand: {selected_subcommand}

Available flags for '{subcommand}':
{flag_list_with_types_and_descriptions}

Positional parameters:
{positional_list}

Output JSON:

7.3 Prompt分层策略

模型大小 System User 总计 策略
≤3B 50 tokens 200 tokens ~250 极简+强约束
7B 50 tokens 400 tokens ~450 标准+约束
≥16B 100 tokens 600 tokens ~700 扩展+约束

八、缓存与性能优化

8.1 ToolDoc缓存

缓存路径: ~/.cache/oxo-call/tooldoc/{tool}.json
缓存内容: ToolDoc的JSON序列化
缓存键: tool_name + version
失效策略: version变更时自动刷新

8.2 并行获取

Stage 2中:
  - 根命令help获取与Skill加载并行
  - 多个子命令help获取并行 (tokio::join!)
  - 伴生命令发现并行

8.3 增量更新

如果ToolDoc缓存存在且version未变:
  - 跳过Stage 2的大部分工作
  - 直接从缓存加载ToolDoc
  - 仅重新执行Stage 3-5

九、Benchmark与验证

9.1 准确度目标

Scenario 目标准确度 当前(估) 差距
bare ≥0.3 ~0.3
doc ≥0.8 ~0.5 +0.3
full ≥0.95 ~0.7 +0.25

9.2 Benchmark配置

测试脚本: oxo-call-test/bench/run_parallel_bench.sh
配置文件: oxo-call-test/bench/test-bench/bench_config.toml
参考命令: oxo-call-test/bench/test-bench/reference_commands.csv
工作目录: oxo-call-test/bench/test-bench

9.3 验证命令

make ci  # 必须通过

十、实施里程碑

Milestone 1: 核心数据模型 + CLI接口变更

目标: 建立新数据模型,更新CLI接口

  1. 新增 ToolRecord 结构体
  2. 新增 ToolDoc 结构体
  3. 新增 LlmCommandFill 结构体
  4. 更新 RunScenario → 3值枚举
  5. 更新 ChatScenario → 3值枚举
  6. 更新 WorkflowScenario → 3值枚举
  7. 删除 --no-prompt, --no-skill, --no-doc 选项
  8. 更新 main.rs 中的scenario映射
  9. 更新 chat.rs 中的scenario处理
  10. 重写 validate_tool_name() 支持路径依赖命令

验证: cargo build 通过, cargo test 通过

Milestone 2: Stage 1 - Tool Resolution

目标: 实现路径依赖命令识别和伴生命令发现

  1. 新增 tool_resolver.rs
  2. 实现路径依赖命令识别
  3. 实现解释器检测 (shebang + 扩展名)
  4. 实现伴生命令发现
  5. 实现ToolRecord生成
  6. 更新 docs.rs 使用新的validate_tool_name

验证: oxo-call dry-run ./path/bwa "align reads to ref" 可正确识别

Milestone 3: Stage 2 - Doc Exploration

目标: 实现递归Help获取和ToolDoc生成

  1. 新增 doc_explorer.rs
  2. 实现递归Help获取 (最大深度3)
  3. 实现Help文本有效性判断
  4. 实现子命令发现 (6种方法)
  5. 新增 schema/parser/clap.rs
  6. 新增 schema/parser/cobra.rs
  7. 新增 schema/parser/click.rs
  8. 新增 schema/parser/goflag.rs
  9. 增强 schema/parser/generic.rs
  10. 新增 tool_doc.rs (ToolDoc生成 + Schema+Doc+Skill融合)
  11. 实现LLM清洗Agent
  12. 实现ToolDoc缓存

验证: `samt...</issue_description>

Comments on the Issue (you are @copilot in this section)

Copilot AI linked an issue May 1, 2026 that may be closed by this pull request
Copilot AI requested a review from ShixiangWang May 1, 2026 06:26
Copilot stopped work on behalf of ShixiangWang due to an error May 1, 2026 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test

2 participants