Claude Skill

which-model

当用户需要调研某个 skill 的模型选择最佳实践时使用:分析目标技能的源代码与工作流 → 通过联网搜索(Tavily/SearXNG/DuckDuckGo)收集官方文档与社区经验 → 总结出哪些场景该用什么模型/参数 → 生成 WHICHMODEL 小节插入目标技能的 README.md。

LLM Mart · 0 points · 16 views 2 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download huangwb8-skills-skills_beta_which-model-dd1fab8.zip · 43 KB
Part of huangwb8/skills — 22 skills

Install

skills CLI npx skills add https://github.com/huangwb8/skills/tree/main/skills/beta/which-model
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install huangwb8-skills@llmmart
Git git clone https://github.com/huangwb8/skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole huangwb8/skills collection as a plugin from our marketplace. Git is the plain clone.

README

Which Model - 模型选择最佳实践调研工具

自动调研并生成技能的模型选择指南(WHICHMODEL 小节)

核心特性

🎯 混合模式设计

which-model 采用混合模式,结合 AI 自主规划的灵活性和硬编码评分的稳定性:

┌─────────────────────────────────────────────────────────────┐
│  AI 自主规划(灵活性)          硬编码稳定性(稳定性)        │
├─────────────────────────────────────────────────────────────┤
│  • 检索策略生成              • 来源可信度评分                │
│  • 场景识别与分析            • 营销倾向检测                  │
│  • 内容组织与展示            • 综合评分公式                  │
└─────────────────────────────────────────────────────────────┘

✨ 客观性保障

  • ✅ 社区优先:真实用户体验权重高于官方营销(社区 0.85 vs 官方 0.3)
  • ✅ 缺点透明:主动搜索模型缺点和批评,不回避争议
  • ✅ 多源验证:学术论文、社区讨论、技术博客交叉验证
  • ✅ 披露透明:覆盖范围、来源构成、局限性清晰展示

快速开始

请用 which-model 调研 systematic-literature-review 的模型选择最佳实践

功能概述

which-model 是一个元技能(meta-skill),用于:

  1. 深度分析目标技能的源代码(SKILL.md、config.yaml、scripts/)
  2. 联网调研模型选择最佳实践(使用 Tavily/SearXNG/DuckDuckGo)
  3. 生成指南并插入到目标技能的 README.md

核心价值

  • ✅ 基于证据:每条建议都有明确来源(官方文档/技术博客/社区经验)
  • ✅ 自动更新:模型建议随时间变化,可定期重新调研
  • ✅ 结构化输出:生成统一的 WHICHMODEL 小节格式
  • ✅ 非破坏性:不自动覆盖文档,需用户确认后插入
  • ✅ 客观评分:硬编码公式确保评分一致性

典型使用场景

场景一:为新技能生成模型指南

请用 which-model 调研我的新技能 xyz-skill

输出:

  • xyz-skill/WHICHMODEL_section.md(可直接插入 README.md)
  • xyz-skill/skill_analysis.json(技能分析结果)
  • xyz-skill/research_results.json(调研原始数据)

默认厂商:Anthropic、OpenAI

场景二:指定目标厂商

请用 which-model 调研 xyz-skill,只关注 Anthropic 和 Google 的模型

或修改 config.yaml:

research:
  target_vendors:
    - Anthropic
    - Google

支持的厂商:

  • Anthropic(Claude 系列)
  • OpenAI(GPT-4、GPT-4o、o1)
  • Google(Gemini 系列)
  • Meta(Llama 系列)
  • Mistral(Mistral、Mixtral)
  • DeepSeek(DeepSeek 系列)
  • Qwen(阿里通义千问)
  • Moonshot(月之暗面)
  • Zhipu(智谱AI)

场景三:更新已有技能的模型指南

请用 which-model 重新调研 systematic-literature-review

行为:

  • 检测到已有 WHICHMODEL 小节
  • 询问:覆盖 / 追加 / 取消
  • 选择后执行相应操作

场景四:查看调研过程

请用 which-model 调研 xyz-skill 并生成完整报告

输出:

  • 所有中间结果(analysis、research、knowledge)
  • which_model_report.md(完整调研报告)

工作流程

输入:目标技能名称
  ↓
阶段1:静态分析(analyze_skill.py)
  - 读取 SKILL.md、config.yaml、scripts/
  - 识别任务特征(文本生成/代码分析/联网搜索等)
  - 生成初步模型建议
  ↓
阶段2:模型调研(research_models.py)
  - 基于任务特征生成检索词
  - 使用 MCP 工具联网搜索
  - 收集官方文档与社区经验
  ↓
阶段3:知识提取(内部)
  - 从搜索结果中提取模型/参数建议
  - 识别常见模式
  ↓
阶段4:文档生成(generate_whichmodel.py)
  - 按 WHICHMODEL 模板组织内容
  - 生成 Markdown 格式的小节
  ↓
输出:WHICHMODEL_section.md

WHICHMODEL 小节格式

生成的 WHICHMODEL 小节包含:

1. 场景化建议

每个场景包括:

  • 典型使用场景描述
  • 推荐模型(Opus/Sonnet/Haiku)
  • 推荐参数(推理强度、Thinking 模式等)
  • 理由
  • 来源

2. 通用原则

总结 3-5 条核心原则,如:

  • 复杂度与模型匹配
  • 成本效益平衡
  • 参数调优

3. 更新记录

记录每次更新的时间和内容

配置选项

编辑 config.yaml 自定义行为:

# 调研参数
research:
  query_groups_per_task: 5      # 每个任务类型生成的检索词组数
  max_results_per_query: 10     # 每组检索词获取的最大结果数
  relevance_threshold: 0.6      # 相关度阈值

  # 目标模型厂商(开发者默认:Anthropic + OpenAI)
  # 支持的厂商:Anthropic、OpenAI、Google、Meta、Mistral、DeepSeek、Qwen、Moonshot、Zhipu
  target_vendors:
    - Anthropic      # Claude (Opus/Sonnet/Haiku)
    - OpenAI         # GPT-4/GPT-4o/o1
    # 可选:Google、Meta、Mistral、DeepSeek、Qwen、Moonshot、Zhipu

# 来源可信度评分(硬编码)
source_credibility:
  domain_weights:
    academic:
      weight: 1.0      # 学术论文权重最高
      domains: [arxiv.org, semanticscholar.org, ...]
    community_discussions:
      weight: 0.85     # 社区讨论权重高
      domains: [reddit.com, news.ycombinator.com, ...]
    official_docs:
      weight: 0.3      # 官方文档权重低(营销倾向)
      domains: [docs.anthropic.com, platform.openai.com, ...]

# 营销倾向检测(硬编码)
bias_detection:
  marketing_words:
    positive_excess: [revolutionary, state-of-the-art, ...]
    absolute_words: [best, perfect, always, ...]
  balanced_indicators: [however, limitation, drawback, ...]

# 综合评分公式(硬编码)
scoring:
  formula:
    relevance_weight: 0.30     # 相关性权重
    credibility_weight: 0.50   # 可信度权重(最高)
    neutrality_weight: 0.20    # 中立性权重

# MCP 工具优先级
mcp_tools:
  search_priority:
    - tavily-search
    - searxng_web_search
    - search

# 文档生成参数
document_generation:
  min_scenarios: 3              # 最小场景数
  max_scenarios: 8              # 最大场景数

# 插入策略
insertion:
  auto_insert: false            # 自动插入(false = 需用户确认)
  on_existing: prompt           # 已存在时的行为

输出文件说明

文件 说明 是否必需
WHICHMODEL_section.md 生成的 WHICHMODEL 小节 ✅ 必需
skill_analysis.json 技能分析结果(任务特征、初步建议) ✅ 必需
research_results.json 调研原始数据(搜索结果、相关性评分) ✅ 必需
which_model_report.md 完整调研报告(可选) ⚠️ 可选

与其他技能的协同

作为前置步骤

which-model 通常在技能开发/优化阶段使用:

开发新技能 → 运行 which-model → 将 WHICHMODEL 插入 README → 用户获得模型选择指南

定期更新

建议每 3-6 个月重新运行一次,以获取最新的模型建议:

请用 which-model 重新调研 xyz-skill,覆盖已有 WHICHMODEL 小节

注意事项

1. MCP 工具依赖

  • 优先使用 Tavily(深度搜索)
  • 如 Tavily 不可用,降级到 SearXNG
  • 如都不可用,使用内置搜索(功能受限)

2. 非破坏性操作

  • 默认不自动插入文档
  • 需用户确认后才修改 README.md
  • 建议先查看 WHICHMODEL_section.md 再决定

3. 证据要求

  • 每条建议必须有明确来源
  • 如搜索结果不足,会提示用户手动补充
  • 不生成猜测性的建议

常见问题

Q1: 为什么我的技能没有生成任何建议?

A: 可能原因:

  • 任务特征识别失败(检查 SKILL.md 是否清晰)
  • 搜索结果相关性太低(检查 config.yaml 的 relevance_threshold)
  • MCP 工具不可用(检查 MCP 连接)

Q2: WHICHMODEL 小节应该插入 README.md 的哪个位置?

A: 推荐位置(按优先级):

  1. "档位选择指南"之后
  2. "设计理念"之后
  3. "快速开始"之后

Q3: 如何自定义 WHICHMODEL 模板?

A: 编辑 references/WHICHMODEL_template.md,修改格式和内容结构。

Q4: 生成的建议是否准确?

A: 取决于:

  • 搜索结果的质量(官方文档 > 技术博客 > 社区经验)
  • 任务特征的识别准确性(SKILL.md 描述清晰度)
  • 建议:人工审核后再插入 README.md

维护者信息

脚本文件

  • scripts/analyze_skill.py:分析技能源代码
  • scripts/research_models.py:执行联网搜索
  • scripts/generate_whichmodel.py:生成 WHICHMODEL 小节

参考文件

  • references/WHICHMODEL_template.md:WHICHMODEL 模板
  • config.yaml:可配置参数

最后更新:2025-01-03 技能版本:1.0.0

使用示例

示例 1:默认配置(Anthropic + OpenAI)

# 用户提示
请用 which-model 调研 systematic-literature-review

# AI 执行流程
1. 分析 systematic-literature-review/SKILL.md
   → 任务类型:文本生成、数据处理
   → 复杂度:high

2. 生成检索词(包含 Anthropic 和 OpenAI 模型)
   - "Claude long text generation"
   - "GPT-4 long text generation"
   - "Claude vs GPT-4 comparison"
   - ...

3. 联网搜索并收集最佳实践

4. 生成 WHICHMODEL_section.md

生成的 WHICHMODEL 小节示例:

## WHICHMODEL - 模型选择最佳实践

### 场景 1:标准综述生成
- **推荐模型**:Claude Sonnet 4.5
- **推荐参数**:
  - 推理强度:medium
  - Thinking 模式:关
- **理由**:平衡性能与成本,适用于大多数综述任务
- **来源**:[Anthropic 官方文档]

### 场景 2:相关性评分
- **推荐模型**:Claude Haiku 4.5
- **推荐参数**:
  - 推理强度:low
  - Thinking 模式:关
- **理由**:结构化任务,快速响应优先
- **来源**:[社区经验]

示例 2:仅关注 Anthropic

修改 config.yaml:

research:
  target_vendors:
    - Anthropic

或直接指定:

请用 which-model 调研 systematic-literature-review,只关注 Anthropic 的模型

生成的检索词:

  • "Claude Opus literature review"
  • "Claude Sonnet vs Haiku"
  • "Claude model selection guide"

不会出现:

  • ❌ "GPT-4 literature review"
  • ❌ "Claude vs GPT-4 comparison"

示例 3:多厂商对比

修改 config.yaml:

research:
  target_vendors:
    - Anthropic
    - OpenAI
    - Google

生成的检索词包括:

  • "Claude vs GPT-4 comparison"
  • "Claude vs Gemini comparison"
  • "GPT-4 vs Gemini which is better"

示例 4:国产模型

修改 config.yaml:

research:
  target_vendors:
    - Anthropic
    - DeepSeek

生成的检索词包括:

  • "Claude long text generation"
  • "DeepSeek long text generation"
  • "Claude vs DeepSeek comparison"

示例 5:开源模型

修改 config.yaml:

research:
  target_vendors:
    - Meta      # Llama 系列
    - Mistral   # Mistral/Mixtral

生成的检索词包括:

  • "Llama 3 code analysis"
  • "Mistral Large complex reasoning"
  • "Llama vs Mistral comparison"

支持的厂商对照表

厂商 模型名称 代码中的标识
Anthropic Claude, Opus, Sonnet, Haiku Anthropic
OpenAI GPT-4, GPT-4o, o1 OpenAI
Google Gemini, Gemini Pro, Gemini Ultra Google
Meta Llama, Llama 2, Llama 3 Meta
Mistral Mistral, Mixtral, Mistral Large Mistral
DeepSeek DeepSeek, DeepSeek-V2, DeepSeek-Coder DeepSeek
阿里云 通义千问, Qwen, Qwen-Max Qwen
月之暗面 Moonshot, Kimi Moonshot
智谱AI GLM, ChatGLM Zhipu

设计理念:混合模式

为什么采用混合模式?

纯 AI 自主规划的问题:

  • ❌ 评分不稳定,每次执行可能不同
  • ❌ 容易受到提示词波动影响
  • ❌ 难以追溯评分依据

纯硬编码规则的问题:

  • ❌ 缺乏灵活性,无法适应新场景
  • ❌ 维护成本高,每次调整需要修改代码
  • ❌ 无法处理边界情况

混合模式的优势:

  • ✅ 灵活性与稳定性兼备:AI 自主规划策略,硬编码确保评分一致
  • ✅ 可追溯性:评分公式固定,便于调试和验证
  • ✅ 可维护性:策略调整只需更新 references/,评分调整只需修改 config.yaml

AI 自主规划部分

参考资料(AI 执行前阅读):

自主规划内容:

  • 检索词生成(任务特定、社区反馈、缺点查询、对比查询)
  • 场景识别与分类
  • 内容组织与展示

硬编码稳定性部分

配置文件(config.yaml):

# 来源可信度权重
source_credibility.domain_weights:
  academic: {weight: 1.0}
  community_discussions: {weight: 0.85}
  official_docs: {weight: 0.3}

# 营销倾向检测关键词
bias_detection.marketing_words:
  positive_excess: [revolutionary, state-of-the-art, ...]
  absolute_words: [best, perfect, ...]

# 综合评分公式
scoring.formula:
  relevance_weight: 0.30
  credibility_weight: 0.50
  neutrality_weight: 0.20

评分脚本(scripts/score_sources.py):

  • 硬编码评分公式:final_score = relevance × 30% + credibility × 50% + neutrality × 20%
  • 硬编码域名权重映射
  • 硬编码营销倾向检测逻辑

检索词生成逻辑

单厂商(如仅 Anthropic)

任务类型:文本生成
厂商:Anthropic

生成检索词:
- Claude long text generation
- Opus long text generation
- Claude writing best practice
- Opus writing best practice
- Claude content generation
- Opus content generation
+ 通用参数查询(3 条)
= 9 条检索词

双厂商(Anthropic + OpenAI)

任务类型:文本生成
厂商:Anthropic, OpenAI

生成检索词:
- Claude long text generation
- Opus long text generation
- GPT-4 long text generation
- GPT-4o long text generation
- ... (每个模型 × 每个模板)
+ Claude vs GPT-4 comparison (跨厂商对比)
+ Claude or GPT-4 which is better
+ 通用参数查询(3 条)
= 17 条检索词

多厂商(6 个厂商)

任务类型:文本生成
厂商:Anthropic, OpenAI, Google, Meta, Mistral, DeepSeek

生成检索词:
- 每个厂商 2 个模型 × 3 个模板 = 36 条
- 跨厂商对比(最多 2 组)= 4 条
- 通用参数查询 = 3 条
= 43 条检索词

最佳实践

1. 厂商数量建议

厂商数量 适用场景 检索词数量
1 个 专注单一生态 ~9 条
2-3 个 常规对比 ~17-25 条
4-6 个 全面调研 ~30-45 条

2. 厂商选择建议

如果你主要使用:

  • Claude Code → Anthropic
  • GitHub Copilot → OpenAI
  • Gemini API → Google
  • 自部署模型 → Meta, Mistral
  • 国内服务 → DeepSeek

3. 性能与成本

更多厂商 = 更多检索词 = 更长的调研时间

建议:

  • 初次调研:1-2 个厂商
  • 更新已有指南:保持原配置
  • 全面对比:不超过 4 个厂商

Skill manifest

Which Model - 模型选择最佳实践调研工具

目标

当用户需要调研某个 skill 的模型选择最佳实践时使用:分析目标技能的源代码与工作流 → 通过联网搜索(Tavily/SearXNG/DuckDuckGo)收集官方文档与社区经验 → 总结出哪些场景该用什么模型/参数 → 生成 WHICHMODEL 小节插入目标技能的 README.md。

流程

输入

角色

你是一位专精 AI 模型应用与性能优化的技术研究员,擅长:

  • 证据收集:从官方文档、技术博客、社区讨论中提取可靠信息
  • 模式识别:识别不同任务类型与模型性能之间的关联模式
  • 知识综合:将分散的建议整合成结构化的最佳实践指南
  • 清晰表达:用简洁准确的语言传达技术建议

触发条件

  • 用户要求调研某个 skill 的模型选择最佳实践
  • 用户要求生成 WHICHMODEL 文档
  • 用户询问"某某 skill 应该用什么模型"

你需要确认的输入

  1. {目标技能名称}(必需)
  2. {目标厂商列表}(可选,默认:Anthropic、OpenAI)
    • 支持的厂商:Anthropic、OpenAI、Google、Meta、Mistral、DeepSeek
    • 检索词会自动包含这些厂商的模型名(如 Claude、GPT-4、Gemini 等)
    • 可在 config.yaml 的 research.target_vendors 中配置默认值
  3. {目标 README.md 路径}(可选,默认自动查找)

执行步骤

工作流(5 步)

0) 准备与守则
  • 最高原则:基于真实证据,拒绝猜测
  • 记录时间戳:所有输出包含生成时间,便于追踪时效性
  • 验证目标技能:确认技能目录存在且包含有效的 SKILL.md

混合模式设计:

  • AI 自主规划部分:检索策略、场景识别、内容组织由 AI 根据指南自主判断
  • 硬编码稳定性部分:来源可信度评分、营销倾向检测使用硬编码公式

必读参考资料(首次执行前快速阅读):

  1. references/SEARCH_STRATEGY.md - 检索策略指南(AI 自主规划)
  2. references/SCENARIO_ANALYSIS.md - 场景分析指南(AI 自主规划)
  3. references/CONTENT_ORGANIZATION.md - 内容组织指南(AI 自主规划)

硬编码配置(scripts 自动应用):

  • 来源可信度权重:定义在 config.yaml 的 source_credibility.domain_weights
  • 营销倾向检测:定义在 config.yaml 的 bias_detection.marketing_words
  • 综合评分公式:定义在 config.yaml 的 scoring.formula
1) 静态分析:AI 理解目标技能(无硬编码规则)

AI 直接阅读并理解 SKILL.md,基于语义理解(而非关键词匹配)识别任务特征:

  1. 理解技能的核心目标

    • 阅读技能描述,理解其用途和价值主张
    • 理解工作流步骤的语义含义
    • 从触发条件、示例、输出规范中推断隐含需求
  2. 识别任务特征(AI 基于理解自由判断)

    分析示例(仅供 AI 参考,非硬规则):
    
    输入:systematic-literature-review/SKILL.md
    
    AI 理解:
    - "AI 自定检索词 → 去重 → 逐篇阅读并评分 → 资深专家写作"
      → 这是一个多步骤的学术写作流程
      → 任务类型:文本生成、数据处理、多步骤推理、学术写作
    - "6 个工作流步骤 + 资深领域专家风格"
      → 复杂的工作流 + 高质量要求
      → 复杂度:high
    - "阅读大量文献并生成综述"
      → 需要处理大量输入并保持连贯性
      → 上下文需求:long
    - "质量优先:AI 不得偷懒或短视"
      → 明确的质量要求
      → 性能优先级:质量优先
    - "输出 LaTeX + PDF + Word"
      → 输出要求:latex, pdf, docx
    
    初步模型建议:
    - 长文本生成 + 高复杂度 + 质量优先
      → Claude Opus 4.5(主任务)
      → 理由:需要最强推理能力和连贯性
    - 数据处理(评分、选文)
      → Claude Sonnet 4.5(子任务)
      → 理由:结构化任务,性价比高
    
  3. 生成分析结果

    • AI 直接生成 skill_analysis.json
    • 包含 task_features、model_recommendations、_reasoning(分析过程)

关键原则:

  • ✅ 基于语义理解,无硬编码规则
  • ✅ AI 自由判断任务类型和复杂度
  • ✅ 记录分析过程,便于追溯
  • ❌ 不使用关键词匹配
  • ❌ 不使用固定阈值判断
2) 模型调研:证据收集 + 硬编码评分

AI 自主规划检索策略(参考 references/SEARCH_STRATEGY.md):

  • 基于任务特征生成检索词
  • 必须包含:任务特定查询、社区反馈查询、缺点查询、对比查询
  • 避免营销陷阱(如"best practices")
  • 即使单厂商,也要包含跨厂商对比查询(避免回音室)

执行联网搜索(按优先级尝试):

  1. Tavily(深度搜索,获取最新信息)
  2. SearXNG(多源聚合,覆盖面广)
  3. DuckDuckGo(备选方案)
  4. 降级:如 MCP 工具不可用,使用内置搜索

硬编码评分(scripts/score_sources.py 自动执行):

综合评分 = 相关性 × 30% + 可信度 × 50% + 中立性 × 20%

其中:
- 相关性:基于查询匹配(research_models.py 计算)
- 可信度:基于域名类型(config.yaml 硬编码权重)
  - 学术论文:1.0
  - 社区讨论:0.85
  - 官方文档:0.3
  - 厂商博客:0.25
- 中立性:检测营销倾向(config.yaml 硬编码关键词)
  - 过度正面且无平衡词汇:扣 0.4 分
  - 绝对化词语过多:扣 0.3 分

输出:research_results_scored.json(包含 impartial_score 和 score_details)

3) 知识提取:场景分析(AI 自主规划)

AI 自主分析场景(参考 references/SCENARIO_ANALYSIS.md):

  • 从评分后的搜索结果中提取真实使用场景
  • 聚类相似场景,确保场景独立性
  • 为每个场景提取:触发条件、推荐模型、推荐参数、适用/避免场景、来源依据
  • 识别并处理冲突观点(并列展示,不偏向任何一方)

关键原则:

  • 基于真实场景,不凭空想象
  • 场景之间有明显区别
  • 每个场景都有来源依据
  • 冲突观点透明展示

输出:scenarios.json(结构化的场景列表)

4) 文档生成:WHICHMODEL 小节(AI 自主规划)

AI 自主组织内容(参考 references/CONTENT_ORGANIZATION.md):

  • 确定结构:完整结构 vs 简化结构(基于证据充足度)
  • 生成披露信息:时间戳、覆盖范围、来源构成、局限性
  • 组织场景建议:按什么顺序排列、用什么格式(表格/列表/混合)
  • 添加对比总结:表格形式对比不同模型
  • 提炼通用原则:3-5 条核心原则
  • 处理争议点:展示冲突观点和平衡建议

披露信息模板:

### 披露信息
- **最后更新**:{YYYY-MM-DD}
- **覆盖厂商**:{列表}({覆盖数}/{总数} = {百分比}%)
- **来源构成**:{社区 X%, 学术 Y%, 官方 Z%}
- **数据时效**:{时间范围}
- **局限性**:{本次调研的局限性}

输出:WHICHMODEL_section.md

5) 插入与验证
  • 定位插入位置:
    • 在目标 README.md 中查找合适位置(通常在"设计理念"或"档位选择指南"之后)
    • 如已存在 WHICHMODEL 小节,提示用户选择:覆盖 / 追加 / 取消
  • 生成插入建议:
    • 输出插入位置的行号
    • 显示插入前后的对比预览
  • 等待用户确认:
    • 询问用户是否插入
    • 用户确认后,执行插入
  • 验证:
    • 检查 Markdown 格式是否正确
    • 检查链接是否有效
    • 确认文档整体结构完整

输出

输出规范

必需输出
  • WHICHMODEL_section.md:生成的 WHICHMODEL 小节
  • skill_analysis.json:技能分析结果
  • research_results.json:调研原始数据
  • extracted_knowledge.json:提取的结构化知识
可选输出
  • {目标技能}/README.md:更新后的 README(需用户确认)
  • which_model_report.md:完整调研报告(包含所有中间结果)

输出管理

BenszAPI 任务工作区

校验

验证标准

  • 所有模型建议都有明确来源标注
  • 至少覆盖 3 个典型使用场景
  • 通用原则部分包含 3-5 条核心建议
  • 更新记录包含生成时间戳
  • Markdown 格式正确,链接有效

失败与恢复

错误处理

常见错误与处理方式
错误类型 处理方式
目标技能不存在 立即返回,提示用户检查技能名称
MCP 工具不可用 降级到内置搜索,记录降级原因
无相关搜索结果 提示用户调整检索词或手动补充经验
README.md 找不到 输出 WHICHMODEL_section.md,由用户手动插入
插入位置冲突 提供多个可选位置,由用户选择

约束

公共硬约束

本块由 docs/templates/skill-common-constraints.md 统一维护;每个 SKILL.md 的 ## 约束 必须逐字同步本块,不得在副本中改写公共规则。

  • 任务需要落盘时,使用唯一的 ./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/ 根目录;共享材料放入 shared/,Skill 专属材料放入该 Skill 的 input/、output/、log/。
  • 正式交付物、源代码和正式计划按项目约定保存,不写入任务工作区;未经授权不覆盖、删除、迁移或远程写入。
  • 项目维护变更检查 BAC 可用性并记录需求、AI 产出、工具结果、文件改动和验证摘要;BAC 只做过程审计,不替代署名、责任或合规判断。
  • 不记录 API Key、访问令牌、密码、Cookie、环境/凭据文件、私有 Prompt、身份信息、本地用户名、主机名或不必要的大体积原始数据。
  • 文件路径必须规范化并限制在授权项目范围内;外部 URL、子进程和网络访问遵循最小权限,防止路径遍历、SSRF 和命令注入。
  • Skill 版本唯一记录在自身 config.yaml:skill_info.version;公开 API、协议、目录或配置变更同步文档与 CHANGELOG.md。
  • bensz-collect-bugs 是一个 Agent Skill;仅将 Bensz Agent Skill 或 Bensz 基础设施本身的设计缺陷交给它。先脱敏写入 ~/.bensz-skills/bugs/,当前任务不中断,只有用户明确要求才公开上报,禁止直接修改用户已安装的 Skill 源码。

Skill 专属约束

最高原则与约束

证据要求
  • 拒绝猜测:每条建议必须有明确来源
  • 来源标注:必须标注来源(官方文档/博客/社区)
  • 时效性:明确标注生成时间,模型建议可能随时间变化
内容质量
  • 简洁性:每个场景的建议不超过 5 行
  • 准确性:不夸大模型能力,不承诺不确定的性能
  • 可操作性:参数建议具体,避免模糊表述
用户交互
  • 非破坏性:不自动覆盖用户文档,需确认后插入
  • 透明性:展示调研过程和原始数据
  • 可追溯:保留更新记录,方便回溯
Files (skills)
  • references
    • CONTENT_ORGANIZATION.md 8.5 KB
      # 内容组织指南
      
      ## 你的任务
      
      将分析结果**自主组织**成清晰、有用的 WHICHMODEL 小节。
      
      ---
      
      ## 核心原则
      
      ### 1. 用户优先
      
      从用户角度组织内容:
      - ✅ 按使用场景分组(用户容易找到自己的情况)
      - ❌ 按模型分组(用户不知道自己应该用哪个)
      
      ### 2. 层次清晰
      
      信息层次:**场景 → 建议 → 理由 → 来源**
      
      ```
      WHICHMODEL 小节
      ├── 披露信息(时间、范围、来源)
      ├── 场景化建议
      │   ├── 场景 1
      │   ├── 场景 2
      │   └── ...
      ├── 对比总结
      ├── 通用原则
      ├── 争议点说明
      └── 更新记录
      ```
      
      ### 3. 表格优先
      
      对比信息用表格呈现,更清晰:
      
      ```markdown
      | 模型 | 最适合 | 最不适合 | 成本 | 速度 |
      |------|-------|---------|------|------|
      | Opus | 复杂推理 | 快速响应 | 高 | 慢 |
      | Sonnet | 通用任务 | 极端复杂 | 中 | 中 |
      ```
      
      ---
      
      ## 自主组织流程
      
      ```
      输入:scenarios = [{场景1}, {场景2}, ...], conflicts = [...]
        ↓
      步骤 1:确定结构
        - 有几个场景?
        - 有哪些争议点?
        - 需要哪些通用原则?
        ↓
      步骤 2:生成披露部分
        - 时间戳
        - 覆盖范围
        - 来源构成
        ↓
      步骤 3:组织场景建议
        - 按什么顺序排列?(复杂度、成本、频率)
        - 用什么格式?(表格/列表/混合)
        ↓
      步骤 4:添加通用原则
        - 提炼 3-5 条核心原则
        - 从场景中抽象出共性
        ↓
      步骤 5:处理争议
        - 识别主要争议
        - 展示双方观点
        - 给出平衡建议
        ↓
      输出:WHICHMODEL_section.md
      ```
      
      ---
      
      ## 结构模板
      
      ### 完整结构
      ```markdown
      ## WHICHMODEL - 模型选择最佳实践
      
      **最后更新**:{YYYY-MM-DD}
      
      ### 披露信息
      {时间、范围、来源、局限性}
      
      ### 场景化建议
      
      #### 场景 1:{场景名称}
      {触发条件、推荐、参数、理由、成本}
      
      #### 场景 2:{场景名称}
      ...
      
      ### 对比总结
      {表格对比}
      
      ### 通用原则
      {3-5 条核心原则}
      
      ### ⚠️ 争议点
      {冲突观点展示}
      
      ### 更新记录
      {时间线}
      ```
      
      ### 简化结构(证据不足时)
      ```markdown
      ## WHICHMODEL - 模型选择最佳实践
      
      **最后更新**:{YYYY-MM-DD}
      
      ⚠️ **数据不足**:本次调研证据有限,以下建议仅供参考。
      
      ### 初步建议
      {基于有限证据的建议}
      
      ### 建议补充
      {请用户补充经验}
      
      ### 更新计划
      {建议 3 个月后重新调研}
      ```
      
      ---
      
      ## 示例
      
      ### 输入:文献综述技能的分析结果
      
      ```
      scenarios = [超长综述, 标准调研, 快速摘要, 多模态]
      conflicts = [Opus vs Sonnet]
      general_principles = [先试便宜的, 定期重新调研, 社区反馈优先]
      ```
      
      ### AI 自主生成的内容
      
      ```markdown
      ## WHICHMODEL - 模型选择最佳实践
      
      **最后更新**:2025-01-03
      
      ### 披露信息
      
      - **覆盖厂商**:Anthropic, OpenAI, Google(3/6 = 50%)
      - **来源构成**:社区 60%, 学术 15%, 官方 10%, 博客 15%
      - **数据时效**:2024-06 至 2025-01
      - **局限性**:未覆盖国产模型,未独立测试
      
      ---
      
      ### 场景化建议
      
      #### 场景 1:超长文献综述(>50 篇论文)
      
      **触发条件**:需要处理大量文献,预算充足,质量优先
      
      | 项目 | 建议 |
      |------|------|
      | **推荐模型** | Claude Opus 4.5 |
      | **推理强度** | high |
      | **Thinking 模式** | 开 |
      | **预期成本** | $15-30/综述(100 篇) |
      
      **理由**:社区反馈一致认为 Opus 在超长文本中保持连贯性
      
      **避免**:成本敏感、快速迭代需求
      
      **来源**:Reddit 15+ 用户反馈 + 2 个对比测试
      
      ---
      
      #### 场景 2:标准文献调研(10-50 篇论文)
      
      **触发条件**:中等规模综述,平衡成本与质量
      
      | 项目 | 建议 |
      |------|------|
      | **推荐模型** | Claude Sonnet 4.5 |
      | **推理强度** | medium |
      | **Thinking 模式** | 可选 |
      | **预期成本** | $3-8/综述 |
      
      **理由**:社区普遍认为 Sonnet 性价比高,多数场景够用
      
      **避免**:极端复杂的推理、超长文本(>100 篇)
      
      **来源**:HN 讨论 + Reddit 共识
      
      ---
      
      #### 场景 3:快速文献摘要(<10 篇论文)
      
      **触发条件**:快速了解领域,不需要深入分析
      
      | 项目 | 建议 |
      |------|------|
      | **推荐模型** | Claude Haiku 4.5 或 GPT-4o |
      | **推理强度** | low |
      | **Thinking 模式** | 关 |
      | **预期成本** | $0.5-2/综述 |
      
      **理由**:快速响应,成本最低
      
      **避免**:需要深入分析、复杂推理
      
      **来源**:官方文档 + 社区反馈
      
      ---
      
      #### 场景 4:多模态文献(包含图表/图像)
      
      **触发条件**:文献包含图表、需要理解视觉内容
      
      | 项目 | 建议 |
      |------|------|
      | **推荐模型** | GPT-4o |
      | **推理强度** | medium |
      | **Thinking 模式** | 关 |
      | **预期成本** | $5-10/综述 |
      
      **理由**:多模态支持最好,社区推荐
      
      **避免**:纯文本超长任务(上下文限制)
      
      **来源**:社区对比讨论
      
      ---
      
      ### 对比总结
      
      | 模型 | 最适合 | 最不适合 | 相对成本 | 相对速度 | 推荐度 |
      |------|-------|---------|---------|---------|-------|
      | Opus | 超长综述、复杂推理 | 快速迭代、成本敏感 | $$$$ | ⭐⭐ | ⭐⭐⭐⭐ |
      | Sonnet | 标准综述、通用任务 | 极端复杂 | $$ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
      | Haiku | 快速摘要、简单任务 | 复杂推理 | $ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
      | GPT-4o | 多模态任务 | 超长文本 | $$$ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
      
      ---
      
      ### 通用原则
      
      1. **先试便宜的**:从 Sonnet/Haiku 开始,不够再升级 Opus
      2. **定期重新调研**:模型更新频繁,建议每 3-6 个月重新评估
      3. **社区反馈优先**:真实用户体验 > 官方营销
      4. **成本敏感**:长文本任务成本很高,注意 token 限制
      5. **小规模测试**:正式使用前,先小规模测试模型表现
      
      ---
      
      ### ⚠️ 争议点
      
      #### Opus vs Sonnet:文献综述应该用哪个?
      
      | 观点 | 支持者 | 理由 |
      |------|-------|------|
      | **应该用 Opus** | Anthropic 官方文档 | 最强推理能力,长文本连贯性最好 |
      | **应该用 Sonnet** | Reddit/HN 社区 | 性价比更高,90% 场景够用 |
      
      **数据支持**:
      - 某用户测试:Opus 87% 准确率 vs Sonnet 82%
      - 成本差异:Opus 是 Sonnet 的 3-5 倍
      
      **建议**:
      - 预算充足、质量优先 → Opus
      - 成本敏感、需要迭代 → 先试 Sonnet,不够再升级
      
      ---
      
      ### 更新记录
      
      - 2025-01-03:首次调研,覆盖 Anthropic/OpenAI/Google
      - 建议:2025-04 重新调研(3 个月后)
      ```
      
      ---
      
      ## 披露信息生成指南
      
      ### 必需披露项
      
      ```markdown
      ### 披露信息
      
      - **最后更新**:{YYYY-MM-DD}
      - **覆盖厂商**:{实际覆盖的厂商列表}({覆盖数}/{总数} = {百分比}%)
      - **来源构成**:{各类型来源的数量和百分比}
      - **数据时效**:{时间范围}
      - **局限性**:{本次调研的局限性}
      ```
      
      ### 覆盖度评估
      
      ```python
      # 伪代码:计算覆盖度
      all_vendors = ["Anthropic", "OpenAI", "Google", "Meta", "Mistral", "DeepSeek", "Qwen", "Moonshot", "Zhipu"]
      target_vendors = config.get("target_vendors", ["Anthropic", "OpenAI"])
      coverage = len(target_vendors) / len(all_vendors)
      
      if coverage < 0.33:
          level = "⚠️ 覆盖度较低,建议扩展厂商范围"
      elif coverage < 0.5:
          level = "⚠️ 覆盖度中等,部分厂商未包含"
      elif coverage < 0.8:
          level = "✅ 覆盖度良好"
      else:
          level = "✅ 覆盖度优秀"
      ```
      
      ---
      
      ## 检查清单
      
      - [ ] 是否有清晰的场景划分?
      - [ ] 是否使用了表格对比?
      - [ ] 是否包含了披露信息?
      - [ ] 是否展示了冲突观点?
      - [ ] 是否有通用原则?
      - [ ] 是否有更新记录?
      
      ---
      
      ## 你需要自主判断的内容
      
      1. **结构选择**:完整结构 vs 简化结构(基于证据充足度)
      2. **场景排序**:按什么顺序排列场景?(复杂度/成本/频率)
      3. **表格内容**:哪些维度值得对比?
      4. **原则提炼**:从场景中抽象出哪些共性?
      5. **争议展示**:哪些争议值得展示?
      
      ---
      
      ## 与硬编码评分的配合
      
      你的内容组织与 `scripts/score_sources.py` 的硬编码评分形成互补:
      
      | 阶段 | 你的角色(自主规划) | 硬编码角色(稳定性) |
      |------|---------------------|-------------------|
      | 结果评分 | ❌ 不参与 | ✅ 硬编码公式评分 |
      | 内容组织 | ✅ 自主组织 WHICHMODULE 结构 | ❌ 不参与 |
      | 披露生成 | ✅ 自主生成披露信息 | ❌ 不参与 |
      | 格式选择 | ✅ 自主选择表格/列表/混合 | ❌ 不参与 |
      
      记住:**内容组织没有标准答案,根据内容和用户需求灵活调整**。
      
    • SCENARIO_ANALYSIS.md 5.7 KB
      # 场景分析指南
      
      ## 你的任务
      
      根据搜索结果,**自主识别**不同的使用场景,并为每个场景提供模型建议。
      
      ---
      
      ## 核心原则
      
      ### 1. 基于真实场景
      
      从搜索结果中提取**真实用户的使用场景**,而非凭空想象。
      
      **好场景示例**:
      - ✅ "生成 50 页以上的文献综述"
      - ✅ "快速摘要 10 篇论文"
      - ✅ "代码重构和调试"
      - ✅ "多轮对话迭代"
      
      **坏场景示例**:
      - ❌ "高质量文本生成"(太笼统)
      - ❌ "复杂推理任务"(无具体情境)
      
      ### 2. 场景独立性
      
      不同场景之间应该有明显区别,避免重叠。
      
      **示例**:
      ```
      ❌ 重叠:
      - 场景 1:文献综述生成
      - 场景 2:学术写作
      
      ✅ 独立:
      - 场景 1:超长文献综述(>50 篇)
      - 场景 2:快速文献调研(10-20 篇)
      - 场景 3:学术论文写作(从零开始)
      ```
      
      ### 3. 场景完整性
      
      每个场景应该包含:
      - **触发条件**:什么时候用这个场景
      - **推荐模型**:具体模型名称
      - **推荐参数**:推理强度、thinking 模式等
      - **适用理由**:为什么推荐
      - **避免场景**:什么时候不用
      - **来源依据**:哪个来源支持这个建议
      
      ---
      
      ## 自主分析流程
      
      ```
      输入:research_results = {results: [...]}
        ↓
      步骤 1:阅读搜索结果
        - 标记高频场景
        - 标记冲突建议
        - 标记数据支持的场景
        ↓
      步骤 2:聚类场景
        - 将相似场景合并
        - 确保场景独立性
        - 确定场景边界
        ↓
      步骤 3:为每个场景提取建议
        - 推荐模型(基于共识)
        - 推荐参数(基于经验)
        - 适用/避免场景(基于反馈)
        ↓
      步骤 4:验证建议
        - 是否有证据支持?
        - 是否有冲突观点?
        - 是否标注了来源?
        ↓
      输出:scenarios = [{场景1}, {场景2}, ...]
      ```
      
      ---
      
      ## 示例
      
      ### 输入:文献综述技能的搜索结果
      
      ```
      高频场景:
      1. "我用 Opus 处理 100 篇论文,效果很好"(Reddit)
      2. "Sonnet 够用,Opus 太贵"(HN)
      3. "GPT-4o 在处理图表时更好"(社区)
      4. "快速摘要用 Haiku 就够了"(官方文档)
      
      冲突观点:
      - 官方推荐 Opus,但社区更倾向 Sonnet(性价比)
      
      数据支持:
      - 某用户测试:Opus 准确率 87%,Sonnet 82%,但 Opus 贵 3 倍
      ```
      
      ### AI 自主生成的场景
      
      ```markdown
      ### 场景 1:超长文献综述(>50 篇论文)
      
      - **触发条件**:需要处理大量文献,预算充足,质量优先
      - **推荐模型**:Claude Opus 4.5
      - **推荐参数**:
        - 推理强度:high
        - Thinking 模式:开
      - **适用理由**:社区反馈一致认为 Opus 在超长文本中保持连贯性
      - **避免场景**:成本敏感、快速迭代
      - **来源依据**:Reddit 15+ 用户反馈
      - **成本估算**:~$15-30/综述(基于 100 篇论文)
      
      ### 场景 2:标准文献调研(10-50 篇论文)
      
      - **触发条件**:中等规模综述,平衡成本与质量
      - **推荐模型**:Claude Sonnet 4.5
      - **推荐参数**:
        - 推理强度:medium
        - Thinking 模式:可选
      - **适用理由**:社区普遍认为 Sonnet 性价比高,多数场景够用
      - **避免场景**:极端复杂的推理、超长文本
      - **来源依据**:HN 讨论 + Reddit 共识
      - **成本估算**:~$3-8/综述
      
      ### 场景 3:快速文献摘要(<10 篇论文)
      
      - **触发条件**:快速了解领域,不需要深入分析
      - **推荐模型**:Claude Haiku 4.5 或 GPT-4o
      - **推荐参数**:
        - 推理强度:low
        - Thinking 模式:关
      - **适用理由**:快速响应,成本最低
      - **避免场景**:需要深入分析、复杂推理
      - **来源依据**:官方文档 + 社区反馈
      - **成本估算**:~$0.5-2/综述
      
      ### 场景 4:多模态文献(包含图表/图像)
      
      - **触发条件**:文献包含图表、需要理解视觉内容
      - **推荐模型**:GPT-4o
      - **推荐参数**:
        - 推理强度:medium
        - Thinking 模式:关
      - **适用理由**:多模态支持最好,社区推荐
      - **避免场景**:纯文本超长任务(上下文限制)
      - **来源依据**:社区对比讨论
      - **成本估算**:~$5-10/综述
      ```
      
      ---
      
      ## 冲突处理
      
      ### 存在冲突时
      
      ```markdown
      ### ⚠️ 争议点:文献综述应该用 Opus 还是 Sonnet?
      
      | 观点 | 支持者 | 理由 |
      |------|-------|------|
      | Opus | Anthropic 官方文档 | 最强推理能力,长文本连贯性最好 |
      | Sonnet | Reddit/社区 | 性价比更高,90% 场景够用 |
      
      **建议**:
      - 预算充足 → Opus
      - 成本敏感 → 先试 Sonnet,不够再升级
      
      **数据支持**:
      - 某用户测试:Opus 87% 准确率 vs Sonnet 82%
      - 成本差异:Opus 是 Sonnet 的 3-5 倍
      ```
      
      ---
      
      ## 检查清单
      
      - [ ] 每个场景是否有明确的触发条件?
      - [ ] 是否有 3-5 个场景(太少则合并,太多则精简)?
      - [ ] 是否每个场景都有来源依据?
      - [ ] 是否标注了适用和避免场景?
      - [ ] 是否展示了冲突观点?
      
      ---
      
      ## 你需要自主判断的内容
      
      1. **场景数量**:根据搜索结果丰富度调整(3-8 个)
      2. **场景边界**:确保场景独立,不重叠
      3. **模型选择**:基于证据,不偏向任何厂商
      4. **参数建议**:基于社区经验,而非猜测
      5. **冲突处理**:并列展示,不偏向任何一方
      
      ---
      
      ## 与硬编码评分的配合
      
      你的场景分析与 `scripts/score_sources.py` 的硬编码评分形成互补:
      
      | 阶段 | 你的角色(自主规划) | 硬编码角色(稳定性) |
      |------|---------------------|-------------------|
      | 结果评分 | ❌ 不参与 | ✅ 硬编码公式评分 |
      | 场景识别 | ✅ 自主识别和分类场景 | ❌ 不参与 |
      | 冲突处理 | ✅ 自主判断和展示冲突 | ❌ 不参与 |
      | 参数建议 | ✅ 自主基于经验建议 | ❌ 不参与 |
      
      记住:**场景分析没有标准答案,基于证据灵活调整**。
      
    • SEARCH_STRATEGY.md 4.3 KB
      # 检索策略指南
      
      ## 你的任务
      
      根据目标技能的任务特征,**自主生成**高质量的检索词,避免回音室效应和营销陷阱。
      
      ---
      
      ## 核心原则
      
      ### 1. 多元化原则
      
      **必须包含的检索词类型**:
      - ✅ 任务特定:"{model} for {task_type}"
      - ✅ 社区反馈:"{model} reddit experience"
      - ✅ 缺点查询:"{model} problems limitations"
      - ✅ 对比查询:"{model1} vs {model2}"
      
      **避免的检索词类型**(营销陷阱):
      - ❌ "best practices"(营销内容太多)
      - ❌ "official guide"(官方文档单独处理)
      - ❌ "how to use"(低质量内容)
      
      ### 2. 厂商覆盖原则
      
      即使目标厂商列表只有 1-2 个,也应该:
      - 主动搜索"为什么不用其他厂商"
      - 包含对比查询(vs 其他主流厂商)
      - 理解用户为什么选择/不选择某个厂商
      
      **目的**:避免回音室效应
      
      ### 3. 社区优先原则
      
      **社区平台优先级**:
      1. Reddit(r/LocalLLama, r/MachineLearning)
      2. Hacker News
      3. GitHub Issues
      4. Stack Overflow
      
      **检索词模板**:
      ```
      "{model} reddit experience"
      "{model} hacker news discussion"
      "{model} github issues"
      "{model} real world usage"
      ```
      
      ### 4. 缺点透明原则
      
      **必须包含的缺点查询**:
      ```
      "{model} disadvantages"
      "{model} limitations"
      "{model} problems"
      "{model} not good for"
      "why not {model}"
      "{model} fails at"
      ```
      
      ---
      
      ## 自主规划流程
      
      ```
      输入:task_features = {task_types: [...], complexity: "..."}
        ↓
      步骤 1:分析任务特征
        - 主要任务类型是什么?
        - 复杂度如何?
        - 有什么特殊需求?
        ↓
      步骤 2:为每个任务类型生成检索词
        - 任务特定查询(每个任务 2-3 个)
        - 社区反馈查询(每个任务 2 个)
        - 缺点查询(每个任务 1-2 个)
        ↓
      步骤 3:生成对比查询
        - 如果单厂商:vs 主流对手
        - 如果多厂商:两两对比(最多 3 组)
        ↓
      步骤 4:检查多样性
        - 是否包含社区查询?
        - 是否包含缺点查询?
        - 是否包含对比查询?
        ↓
      输出:queries = [...]
      ```
      
      ---
      
      ## 示例
      
      ### 输入:文献综述技能
      ```
      task_features = {
        task_types: ["文本生成", "数据处理", "联网搜索"],
        complexity: "high"
      }
      target_vendors = ["Anthropic", "OpenAI"]
      ```
      
      ### AI 自主生成的检索词
      ```python
      queries = [
          # 文本生成 - 任务特定
          "Claude long text generation",
          "Opus literature review",
          "GPT-4 long text generation",
          "GPT-4o academic writing",
      
          # 文本生成 - 社区反馈
          "Claude long text reddit",
          "GPT-4 literature review experience",
      
          # 文本生成 - 缺点查询
          "Claude long text limitations",
          "GPT-4 coherence issues",
      
          # 数据处理 - 任务特定
          "Claude JSON processing",
          "GPT-4 structured output",
      
          # 数据处理 - 社区反馈
          "Claude data extraction reddit",
      
          # 联网搜索 - 任务特定
          "Claude web search",
          "GPT-4 browsing",
      
          # 对比查询
          "Claude vs GPT-4 literature review",
          "Opus vs GPT-4o long text",
      
          # 通用原则
          "LLM model selection academic writing"
      ]
      ```
      
      ---
      
      ## 检查清单
      
      生成检索词后,检查:
      - [ ] 是否包含社区反馈查询?
      - [ ] 是否包含缺点查询?
      - [ ] 是否包含对比查询?
      - [ ] 是否避免了"best practices"等营销陷阱?
      - [ ] 检索词数量是否在 15-30 之间(过多则精简)?
      
      ---
      
      ## 你需要自主判断的内容
      
      1. **检索词数量**:根据任务复杂度调整(复杂任务多查询,简单任务少查询)
      2. **检索词具体度**:根据任务类型调整(技术任务用术语,通用任务用描述)
      3. **对比组合**:选择最有意义的对比(不一定要两两对比)
      4. **是否需要跨语言**:某些国产模型可能需要中文检索词
      
      ---
      
      ## 与硬编码评分的配合
      
      你的检索策略与 `scripts/score_sources.py` 的硬编码评分形成互补:
      
      | 阶段 | 你的角色(自主规划) | 硬编码角色(稳定性) |
      |------|---------------------|-------------------|
      | 检索词生成 | ✅ 自主生成多样化检索词 | ❌ 不参与 |
      | 搜索结果收集 | ✅ 收集所有相关结果 | ❌ 不参与 |
      | **结果评分** | ❌ 不参与 | ✅ 硬编码公式评分 |
      | 场景分析 | ✅ 自主识别和分类场景 | ❌ 不参与 |
      
      记住:**检索策略没有标准答案,根据具体情况灵活调整**。
      
    • WHICHMODEL_template.md 1.4 KB
      ## WHICHMODEL - 模型选择最佳实践
      
      本节由 `which-model` skill 自动调研生成,最后更新:{timestamp}
      
      > **说明**:本节基于 {生成日期} 的调研结果。模型性能和最佳实践可能随时间变化,建议定期更新。
      
      ### 场景一:{场景名称}
      
      **典型使用场景**:{场景描述(1-2 句)}
      
      - **推荐模型**:{Claude Opus 4.5 / Claude Sonnet 4.5 / Claude Haiku 4.5}
      - **推荐参数**:
        - 推理强度:{high / medium / low}
        - Thinking 模式:{开 / 关}
        - Temperature:{默认值}
        - Max Tokens:{建议值}
      - **理由**:{简洁的理由(1-2 句)}
      - **来源**:{来源名称与链接}
      
      ---
      
      ### 场景二:{场景名称}
      
      **典型使用场景**:{场景描述(1-2 句)}
      
      - **推荐模型**:{模型名称}
      - **推荐参数**:
        - 推理强度:{强度}
        - Thinking 模式:{开/关}
        - 其他参数:{参数值}
      - **理由**:{理由}
      - **来源**:{来源}
      
      ---
      
      ### 通用原则
      
      基于 {调研来源数量} 个来源的分析,总结以下通用原则:
      
      1. **{原则标题}**
         - {原则说明}
      
      2. **{原则标题}**
         - {原则说明}
      
      3. **{原则标题}**
         - {原则说明}
      
      ### 更新记录
      
      - {YYYY-MM-DD}:初始生成,基于 {X} 个来源的调研
      - {YYYY-MM-DD}:{更新内容(如有)}
      
      ---
      
      > 本节由 `which-model` skill 自动生成。如需更新,请运行:
      > ```
      > 请用 which-model 调研 {技能名称} 的模型选择最佳实践
      > ```
      
  • scripts
    • analyze_skill.py 3.5 KB
      #!/usr/bin/env python3
      """
      analyze_skill.py - 占位符脚本
      
      ⚠️  注意:本脚本已移除所有硬编码规则。
          实际分析由 AI (Claude) 完成,基于语义理解。
      
      本脚本仅用于:
      1. 验证技能目录存在
      2. 创建占位符文件结构
      3. 为 AI 分析提供文件位置
      """
      
      import json
      from datetime import datetime
      from pathlib import Path
      from typing import Dict, Any
      
      
      def create_placeholder(skill_dir: Path) -> Dict[str, Any]:
          """创建占位符分析,等待 AI 填充"""
      
          # 读取 SKILL.md 前 500 字符,用于 AI 快速了解
          skill_md_path = skill_dir / 'SKILL.md'
          preview = ""
          if skill_md_path.exists():
              with open(skill_md_path, 'r', encoding='utf-8') as f:
                  preview = f.read(500)
      
          return {
              '_meta': {
                  'version': '2.0',  # AI-first 版本
                  'analyzed_by': 'AI (Claude)',
                  'analyzed_at': None,  # AI 填充
                  'skill_path': str(skill_dir),
                  'skill_preview': preview  # 预览,帮助 AI 快速了解
              },
      
              # 以下字段由 AI 填充
              'task_features': {
                  'task_types': [],  # AI 填充:基于语义理解
                  'context_requirements': None,  # AI 填充:short/medium/long
                  'output_requirements': [],  # AI 填充:markdown/latex/pdf/json
                  'complexity_level': None,  # AI 填充:low/medium/high
                  'performance_priority': None,  # AI 填充:速度/质量/平衡
                  'workflow_summary': None  # AI 填充:工作流语义理解
              },
      
              'model_recommendations': {
                  'primary': None,  # AI 填充:推荐的主模型
                  'primary_reasoning': None,  # AI 填充:推荐理由
                  'alternatives': []  # AI 填充:备选模型及使用场景
              },
      
              # AI 分析过程(可追溯)
              '_reasoning': {
                  'task_understanding': None,  # AI 如何理解技能
                  'complexity_rationale': None,  # AI 如何判断复杂度
                  'model_selection_rationale': None  # AI 如何选择模型
              }
          }
      
      
      def analyze_skill(skill_dir: Path) -> Dict[str, Any]:
          """
          分析技能(占位符)
      
          注意:实际分析由 AI 完成。
          本函数仅创建占位符结构。
          """
          if not skill_dir.exists():
              raise FileNotFoundError(f"技能目录不存在: {skill_dir}")
      
          skill_md_path = skill_dir / 'SKILL.md'
          if not skill_md_path.exists():
              raise FileNotFoundError(f"SKILL.md 不存在: {skill_md_path}")
      
          return create_placeholder(skill_dir)
      
      
      def main():
          import sys
      
          if len(sys.argv) < 2:
              print("Usage: python analyze_skill.py <skill_dir>")
              print("\n注意:本脚本仅创建占位符,实际分析由 AI 完成。")
              sys.exit(1)
      
          skill_dir = Path(sys.argv[1])
      
          try:
              analysis = analyze_skill(skill_dir)
              output_path = skill_dir / 'skill_analysis.json'
      
              with open(output_path, 'w', encoding='utf-8') as f:
                  json.dump(analysis, f, indent=2, ensure_ascii=False)
      
              print(f"✓ 占位符已创建: {output_path}")
              print(f"✓ 技能目录: {skill_dir}")
              print(f"\n等待 AI 分析并填充...")
              print(f"AI 将分析:{skill_dir / 'SKILL.md'}")
      
          except FileNotFoundError as e:
              print(f"✗ 错误: {e}")
              sys.exit(1)
          except Exception as e:
              print(f"✗ 意外错误: {e}")
              import traceback
              traceback.print_exc()
              sys.exit(1)
      
      
      if __name__ == '__main__':
          main()
      
    • generate_whichmodel.py 8.5 KB
      #!/usr/bin/env python3
      """
      generate_whichmodel.py - 生成 WHICHMODEL 小节
      
      功能:
      1. 从调研结果中提取结构化知识
      2. 按 WHICHMODEL 模板组织内容
      3. 生成 Markdown 格式的最佳实践小节
      """
      
      import json
      import os
      import re
      import sys
      from datetime import datetime
      from pathlib import Path
      from typing import Dict, List, Any
      
      
      def extract_knowledge(research_results: Dict[str, Any], skill_analysis: Dict[str, Any]) -> Dict[str, Any]:
          """从搜索结果中提取结构化知识"""
          results = research_results.get('results', [])
      
          # 初始化知识结构
          knowledge = {
              'scenarios': [],
              'general_principles': [],
              'model_patterns': {
                  'Opus': {'use_cases': [], 'typical_params': {}},
                  'Sonnet': {'use_cases': [], 'typical_params': {}},
                  'Haiku': {'use_cases': [], 'typical_params': {}}
              }
          }
      
          # 分析每个搜索结果
          for result in results:
              title = result.get('title', '')
              snippet = result.get('snippet', '')
              url = result.get('url', '')
              text = f"{title} {snippet}".lower()
      
              # 识别模型使用场景
              if 'opus' in text and ('complex' in text or 'long' in text or 'quality' in text):
                  knowledge['model_patterns']['Opus']['use_cases'].append({
                      'scenario': title,
                      'reason': snippet[:100],
                      'source': url
                  })
      
              if 'sonnet' in text and ('balanced' in text or 'code' in text):
                  knowledge['model_patterns']['Sonnet']['use_cases'].append({
                      'scenario': title,
                      'reason': snippet[:100],
                      'source': url
                  })
      
              if 'haiku' in text and ('fast' in text or 'quick' in text or 'simple' in text):
                  knowledge['model_patterns']['Haiku']['use_cases'].append({
                      'scenario': title,
                      'reason': snippet[:100],
                      'source': url
                  })
      
              # 识别通用原则
              if any(word in text for word in ['principle', 'best practice', 'guideline', 'recommend']):
                  knowledge['general_principles'].append({
                      'title': title,
                      'content': snippet[:200],
                      'source': url
                  })
      
          return knowledge
      
      
      def generate_scenarios(knowledge: Dict[str, Any], skill_analysis: Dict[str, Any]) -> List[Dict[str, Any]]:
          """基于知识和技能分析生成场景"""
          task_types = skill_analysis.get('task_features', {}).get('task_types', [])
          complexity = skill_analysis.get('task_features', {}).get('complexity_level', 'medium')
      
          scenarios = []
      
          # 基于任务类型生成场景
          scenario_map = {
              '文本生成': {
                  'name': '长文本生成(综述/报告)',
                  'model': 'Claude Opus 4.5',
                  'reasoning': 'high',
                  'thinking': True,
                  'reason': '需要强推理能力确保内容连贯性和深度'
              },
              '代码分析': {
                  'name': '代码分析与重构',
                  'model': 'Claude Sonnet 4.5',
                  'reasoning': 'medium',
                  'thinking': False,
                  'reason': '结构化思维适合代码分析,性价比高'
              },
              '联网搜索': {
                  'name': '信息检索与综合',
                  'model': 'Claude Sonnet 4.5',
                  'reasoning': 'medium',
                  'thinking': True,
                  'reason': '需要综合多源信息但无需最强推理'
              },
              '数据处理': {
                  'name': '数据提取与处理',
                  'model': 'Claude Haiku 4.5',
                  'reasoning': 'low',
                  'thinking': False,
                  'reason': '结构化任务,快速响应优先'
              }
          }
      
          for task_type in task_types:
              if task_type in scenario_map:
                  scenarios.append(scenario_map[task_type])
      
          # 如果没有匹配场景,添加默认场景
          if not scenarios:
              scenarios.append({
                  'name': '标准任务执行',
                  'model': 'Claude Sonnet 4.5',
                  'reasoning': 'medium',
                  'thinking': False,
                  'reason': '平衡性能与成本,适用于大多数任务'
              })
      
          return scenarios
      
      
      def load_template(template_path: Path) -> str:
          """加载 WHICHMODEL 模板"""
          if not template_path.exists():
              # 返回默认模板
              return """## WHICHMODEL - 模型选择最佳实践
      
      本节由 `which-model` skill 自动调研生成,最后更新:{timestamp}
      
      {scenarios}
      
      ### 通用原则
      
      {principles}
      
      ### 更新记录
      
      - {timestamp}:初始生成
      """
      
          with open(template_path, 'r', encoding='utf-8') as f:
              return f.read()
      
      
      def format_scenario(scenario: Dict[str, Any], index: int) -> str:
          """格式化单个场景"""
          return f"""### 场景{index}:{scenario['name']}
      
      **典型使用场景**:基于技能任务特征分析得出
      
      - **推荐模型**:{scenario['model']}
      - **推荐参数**:
        - 推理强度:{scenario['reasoning']}
        - Thinking 模式:{'开' if scenario.get('thinking', False) else '关'}
        - Temperature:{scenario.get('temperature', '默认值')}
        - Max Tokens:{scenario.get('max_tokens', '按需设置')}
      - **理由**:{scenario['reason']}
      - **来源**:基于 {len(scenario.get('sources', []))} 个来源的调研分析
      
      ---"""
      
      
      def generate_whichmodel_section(
          knowledge: Dict[str, Any],
          skill_analysis: Dict[str, Any],
          template_path: Path = None
      ) -> str:
          """生成 WHICHMODEL 小节"""
          timestamp = datetime.now().strftime('%Y-%m-%d')
      
          # 加载模板
          if template_path is None:
              template_path = Path(__file__).resolve().parents[1] / 'references' / 'WHICHMODEL_template.md'
      
          template = load_template(template_path)
      
          # 生成场景
          scenarios = generate_scenarios(knowledge, skill_analysis)
          scenarios_text = '\n\n'.join([
              format_scenario(s, i + 1)
              for i, s in enumerate(scenarios[:8])  # 最多 8 个场景
          ])
      
          # 生成通用原则
          principles = knowledge.get('general_principles', [])
          if not principles:
              # 默认原则
              principles_text = """1. **复杂度与模型匹配**
         - 高复杂度任务(多步骤推理、长文本生成)→ Claude Opus 4.5
         - 中等复杂度任务(代码分析、标准写作)→ Claude Sonnet 4.5
         - 简单任务(数据处理、快速响应)→ Claude Haiku 4.5
      
      2. **成本效益平衡**
         - 优先尝试 Sonnet,在质量不足时升级到 Opus
         - 批量任务考虑使用 Haiku 降低成本
      
      3. **参数调优**
         - 推理强度:质量优先用 high,速度优先用 low
         - Thinking 模式:复杂推理任务建议开启
         - Temperature:创造性任务可适当提高"""
          else:
              principles_text = '\n\n'.join([
                  f"{i+1}. **{p.get('title', '原则')}**\n   {p.get('content', '')[:200]}"
                  for i, p in enumerate(principles[:5])
              ])
      
          # 填充模板
          content = template.format(
              timestamp=timestamp,
              scenarios=scenarios_text,
              principles=principles_text,
             生成日期=timestamp,
              调研来源数量=len(principles),
              X=len(principles),
              YYYY_MM_DD=timestamp
          )
      
          return content
      
      
      def main():
          if len(sys.argv) < 3:
              print("Usage: python generate_whichmodel.py <research_results.json> <skill_analysis.json>")
              sys.exit(1)
      
          research_path = Path(sys.argv[1])
          analysis_path = Path(sys.argv[2])
      
          if not research_path.exists() or not analysis_path.exists():
              print("Error: Input files not found")
              sys.exit(1)
      
          try:
              with open(research_path, 'r', encoding='utf-8') as f:
                  research_results = json.load(f)
      
              with open(analysis_path, 'r', encoding='utf-8') as f:
                  skill_analysis = json.load(f)
      
              # 提取知识
              knowledge = extract_knowledge(research_results, skill_analysis)
      
              # 生成 WHICHMODEL 小节
              whichmodel_section = generate_whichmodel_section(
                  knowledge,
                  skill_analysis
              )
      
              # 保存到文件
              skill_dir = Path(analysis_path).parent
              output_path = skill_dir / 'WHICHMODEL_section.md'
      
              with open(output_path, 'w', encoding='utf-8') as f:
                  f.write(whichmodel_section)
      
              print(f"WHICHMODEL section generated: {output_path}")
              print(f"Section length: {len(whichmodel_section)} characters")
      
          except Exception as e:
              print(f"Error during generation: {e}")
              import traceback
              traceback.print_exc()
              sys.exit(1)
      
      
      if __name__ == '__main__':
          main()
      
    • research_models.py 9 KB
      #!/usr/bin/env python3
      """
      research_models.py - 通过联网搜索调研模型最佳实践
      
      功能:
      1. 基于任务特征生成检索词
      2. 使用 MCP 工具执行搜索
      3. 收集并评分搜索结果
      4. 输出 research_results.json
      """
      
      import json
      import os
      import sys
      from datetime import datetime
      from pathlib import Path
      from typing import Dict, List, Any
      
      
      # MCP 工具优先级(通过环境变量或直接调用)
      MCP_SEARCH_PRIORITY = [
          'tavily-search',
          'searxng_web_search',
          'search'  # DuckDuckGo
      ]
      
      
      def generate_search_queries(task_features: Dict[str, Any], target_vendors: List[str] = None) -> List[str]:
          """基于任务特征生成检索词
      
          Args:
              task_features: 技能任务特征分析结果
              target_vendors: 目标模型厂商列表,默认为 ['Anthropic', 'OpenAI']
          """
          if target_vendors is None:
              target_vendors = ['Anthropic', 'OpenAI']
      
          queries = []
      
          task_types = task_features.get('task_types', [])
          complexity = task_features.get('complexity_level', 'medium')
      
          # 厂商特定模型名称映射
          vendor_models = {
              'Anthropic': ['Claude', 'Opus', 'Sonnet', 'Haiku'],
              'OpenAI': ['GPT-4', 'GPT-4o', 'o1', 'GPT'],
              'Google': ['Gemini', 'Gemini Pro', 'Gemini Ultra'],
              'Meta': ['Llama', 'Llama 2', 'Llama 3'],
              'Mistral': ['Mistral', 'Mixtral', 'Mistral Large'],
              'DeepSeek': ['DeepSeek', 'DeepSeek-V2', 'DeepSeek-Coder']
          }
      
          # 为每个厂商收集模型名称(每个厂商最多 2 个,避免查询过多)
          vendor_model_names = {}
          for vendor in target_vendors:
              if vendor in vendor_models:
                  vendor_model_names[vendor] = vendor_models[vendor][:2]
      
          # 基础查询词模板(支持多厂商)
          query_templates = {
              '文本生成': [
                  '{model} long text generation',
                  '{model} writing best practice',
                  '{model} content generation'
              ],
              '代码分析': [
                  '{model} code analysis',
                  '{model} code review',
                  '{model} code understanding'
              ],
              '联网搜索': [
                  '{model} web search',
                  '{model} information retrieval'
              ],
              '数据处理': [
                  '{model} data extraction',
                  '{model} JSON processing',
                  '{model} structured output'
              ],
              '多步骤推理': [
                  '{model} complex reasoning',
                  '{model} chain of thought',
                  '{model} problem solving'
              ]
          }
      
          # 为每个任务类型和厂商组合生成查询
          for task_type in task_types:
              if task_type in query_templates:
                  for template in query_templates[task_type]:
                      for vendor in target_vendors:
                          if vendor in vendor_model_names:
                              for model_name in vendor_model_names[vendor]:
                                  queries.append(template.format(model=model_name))
      
          # 添加模型对比查询(跨厂商)
          if len(target_vendors) > 1:
              vendor_pairs = []
              for i, vendor1 in enumerate(target_vendors):
                  for vendor2 in target_vendors[i+1:]:
                      vendor_pairs.append((vendor1, vendor2))
      
              for vendor1, vendor2 in vendor_pairs[:2]:  # 最多 2 组对比
                  model1 = vendor_models.get(vendor1, [vendor1])[0]
                  model2 = vendor_models.get(vendor2, [vendor2])[0]
                  queries.append(f'{model1} vs {model2} comparison')
                  queries.append(f'{model1} or {model2} which is better')
      
          # 添加通用参数查询(不特定于厂商)
          queries.extend([
              'LLM reasoning intensity best practice',
              'LLM temperature parameters guide',
              'when to use different LLM models'
          ])
      
          return list(set(queries))  # 去重
      
      
      def search_with_mcp(query: str, max_results: int = 10) -> List[Dict[str, Any]]:
          """使用 MCP 工具执行搜索"""
          results = []
      
          # 尝试按优先级使用 MCP 工具
          for tool_name in MCP_SEARCH_PRIORITY:
              try:
                  # 这里需要实际的 MCP 工具调用
                  # 以下是模拟实现,实际使用时需要集成真实的 MCP 工具
                  print(f"Searching with {tool_name}: {query}")
      
                  # 模拟搜索结果
                  mock_results = [
                      {
                          'title': f"Mock result for: {query}",
                          'url': f"https://example.com/{query.replace(' ', '-')}",
                          'snippet': f"Mock search result snippet about {query}",
                          'source': tool_name
                      }
                  ]
      
                  results.extend(mock_results)
                  break  # 成功后不再尝试其他工具
      
              except Exception as e:
                  print(f"Failed to use {tool_name}: {e}")
                  continue
      
          return results
      
      
      def score_relevance(result: Dict[str, Any], query: str) -> float:
          """评分搜索结果的相关性(0-1)"""
          title = result.get('title', '').lower()
          snippet = result.get('snippet', '').lower()
          query_lower = query.lower()
      
          # 简单的关键词匹配评分
          score = 0.0
      
          query_words = set(query_lower.split())
          title_words = set(title.split())
          snippet_words = set(snippet.split())
      
          # 标题匹配权重更高
          title_match = len(query_words & title_words) / max(len(query_words), 1)
          snippet_match = len(query_words & snippet_words) / max(len(query_words), 1)
      
          score = title_match * 0.7 + snippet_match * 0.3
      
          return min(score, 1.0)
      
      
      def research_models(skill_analysis: Dict[str, Any], config: Dict[str, Any] = None) -> Dict[str, Any]:
          """执行完整的模型调研流程"""
          if config is None:
              config = {}
      
          task_features = skill_analysis.get('task_features', {})
          max_results = config.get('research', {}).get('max_results_per_query', 10)
          relevance_threshold = config.get('research', {}).get('relevance_threshold', 0.6)
          target_vendors = config.get('research', {}).get('target_vendors', ['Anthropic', 'OpenAI'])
      
          # 1. 生成检索词(传入目标厂商)
          queries = generate_search_queries(task_features, target_vendors)
      
          # 2. 执行搜索
          all_results = []
          for query in queries:
              results = search_with_mcp(query, max_results)
              for result in results:
                  result['query'] = query
                  result['relevance_score'] = score_relevance(result, query)
              all_results.extend(results)
      
          # 3. 过滤低相关性结果
          filtered_results = [
              r for r in all_results
              if r['relevance_score'] >= relevance_threshold
          ]
      
          # 4. 排序
          filtered_results.sort(key=lambda x: x['relevance_score'], reverse=True)
      
          return {
              'timestamp': datetime.now().isoformat(),
              'skill_name': skill_analysis.get('skill_name'),
              'queries_used': queries,
              'total_results': len(all_results),
              'filtered_results': len(filtered_results),
              'results': filtered_results[:50]  # 限制返回数量
          }
      
      
      def load_config(config_path: Path = None) -> Dict[str, Any]:
          """加载配置文件"""
          if config_path is None:
              # 默认使用 which-model 技能目录下的 config.yaml
              script_dir = Path(__file__).resolve().parents[1]
              config_path = script_dir / 'config.yaml'
      
          if not config_path.exists():
              return {}
      
          try:
              import yaml
              with open(config_path, 'r', encoding='utf-8') as f:
                  return yaml.safe_load(f) or {}
          except ImportError:
              print("Warning: PyYAML not installed, using default config")
              return {}
          except Exception as e:
              print(f"Warning: Failed to load config from {config_path}: {e}")
              return {}
      
      
      def main():
          if len(sys.argv) < 2:
              print("Usage: python research_models.py <skill_analysis.json> [config_path]")
              sys.exit(1)
      
          analysis_path = Path(sys.argv[1])
          config_path = Path(sys.argv[2]) if len(sys.argv) > 2 else None
      
          if not analysis_path.exists():
              print(f"Error: Analysis file not found: {analysis_path}")
              sys.exit(1)
      
          try:
              # 加载配置
              config = load_config(config_path)
      
              with open(analysis_path, 'r', encoding='utf-8') as f:
                  skill_analysis = json.load(f)
      
              # 显示使用的配置
              target_vendors = config.get('research', {}).get('target_vendors', ['Anthropic', 'OpenAI'])
              print(f"Target vendors: {', '.join(target_vendors)}")
      
              research_results = research_models(skill_analysis, config)
      
              # 保存到技能目录
              skill_dir = Path(analysis_path).parent
              output_path = skill_dir / 'research_results.json'
      
              with open(output_path, 'w', encoding='utf-8') as f:
                  json.dump(research_results, f, indent=2, ensure_ascii=False)
      
              print(f"Research complete. Results saved to: {output_path}")
              print(f"Found {research_results['filtered_results']} relevant results")
              print(f"Queries used: {len(research_results['queries_used'])}")
      
          except Exception as e:
              print(f"Error during research: {e}")
              import traceback
              traceback.print_exc()
              sys.exit(1)
      
      
      if __name__ == '__main__':
          main()
      
    • score_sources.py 7.3 KB
      #!/usr/bin/env python3
      """
      score_sources.py - 硬编码的来源评分逻辑
      
      功能:
      1. 从 config.yaml 加载来源可信度配置
      2. 计算每个搜索结果的综合得分
      3. 应用营销倾向惩罚
      4. 输出评分后的结果
      
      设计原则:硬编码确保评分稳定性,不受 AI 自主规划影响
      """
      
      import json
      import re
      from pathlib import Path
      from typing import Dict, List, Any
      from urllib.parse import urlparse
      
      
      def load_config(config_path: Path = None) -> Dict[str, Any]:
          """加载配置文件"""
          if config_path is None:
              config_path = Path(__file__).resolve().parents[1] / 'config.yaml'
      
          if not config_path.exists():
              return {}
      
          try:
              import yaml
              with open(config_path, 'r', encoding='utf-8') as f:
                  return yaml.safe_load(f) or {}
          except Exception as e:
              print(f"Warning: Failed to load config: {e}")
              return {}
      
      
      def get_domain_credibility_weight(url: str, config: Dict[str, Any]) -> float:
          """获取域名可信度权重(硬编码)"""
          try:
              domain = urlparse(url).netloc.lower()
          except Exception:
              return 0.5
      
          # 移除 www. 前缀
          if domain.startswith('www.'):
              domain = domain[4:]
      
          credibility_config = config.get('source_credibility', {})
          domain_weights = credibility_config.get('domain_weights', {})
      
          # 检查每个类别
          for category, data in domain_weights.items():
              if isinstance(data, dict) and 'domains' in data:
                  if domain in data['domains']:
                      return data.get('weight', 0.5)
      
          # 未知域名返回默认权重
          return credibility_config.get('unknown_domain_weight', 0.5)
      
      
      def detect_marketing_bias(text: str, config: Dict[str, Any]) -> float:
          """检测营销倾向(硬编码)"""
          bias_config = config.get('bias_detection', {})
      
          # 获取关键词列表
          marketing_words = bias_config.get('marketing_words', {})
          positive_excess = marketing_words.get('positive_excess', [])
          absolute_words = marketing_words.get('absolute_words', [])
          balanced_indicators = bias_config.get('balanced_indicators', [])
      
          # 获取阈值
          marketing_threshold = bias_config.get('sentiment_thresholds', {}).get('marketing_too_positive', 3)
          absolute_threshold = bias_config.get('sentiment_thresholds', {}).get('absolute_excess', 2)
      
          text_lower = text.lower()
      
          # 统计过度正面词汇
          positive_count = sum(1 for word in positive_excess if word in text_lower)
      
          # 统计绝对化词语
          absolute_count = sum(1 for word in absolute_words if word in text_lower)
      
          # 统计平衡指标
          balanced_count = sum(1 for word in balanced_indicators if word in text_lower)
      
          # 计算营销倾向分数(0-1,越低表示营销倾向越强)
          marketing_score = 1.0
      
          # 过度正面惩罚
          if positive_count >= marketing_threshold and balanced_count == 0:
              marketing_score -= 0.4  # 严重营销倾向
      
          # 绝对化词语惩罚
          if absolute_count >= absolute_threshold and balanced_count == 0:
              marketing_score -= 0.3
      
          # 有平衡指标,奖励
          if balanced_count >= 2:
              marketing_score = min(marketing_score + 0.1, 1.0)
      
          return max(marketing_score, 0.0)
      
      
      def calculate_impartial_score(
          result: Dict[str, Any],
          query: str,
          config: Dict[str, Any]
      ) -> float:
          """计算综合客观性评分(硬编码公式)"""
          scoring_config = config.get('scoring', {})
      
          # 获取权重
          formula = scoring_config.get('formula', {})
          relevance_weight = formula.get('relevance_weight', 0.30)
          credibility_weight = formula.get('credibility_weight', 0.50)
          neutrality_weight = formula.get('neutrality_weight', 0.20)
      
          # 1. 相关性评分(来自 research_models.py)
          relevance = result.get('relevance_score', 0.5)
      
          # 2. 可信度评分(基于域名)
          credibility = get_domain_credibility_weight(result.get('url', ''), config)
      
          # 3. 中立性评分(检测营销倾向)
          title_snippet = result.get('title', '') + ' ' + result.get('snippet', '')
          neutrality = detect_marketing_bias(title_snippet, config)
      
          # 综合评分(硬编码公式)
          final_score = (
              relevance * relevance_weight +
              credibility * credibility_weight +
              neutrality * neutrality_weight
          )
      
          return final_score
      
      
      def score_research_results(
          research_results: Dict[str, Any],
          config: Dict[str, Any] = None
      ) -> Dict[str, Any]:
          """对所有调研结果进行评分"""
          if config is None:
              config = load_config()
      
          results = research_results.get('results', [])
      
          # 为每个结果计算综合评分
          for result in results:
              query = result.get('query', '')
              result['impartial_score'] = calculate_impartial_score(result, query, config)
      
              # 添加评分详情(用于调试)
              title_snippet = result.get('title', '') + ' ' + result.get('snippet', '')
              result['score_details'] = {
                  'relevance': result.get('relevance_score', 0.5),
                  'credibility': get_domain_credibility_weight(result.get('url', ''), config),
                  'neutrality': detect_marketing_bias(title_snippet, config)
              }
      
          # 按综合评分重新排序
          results.sort(key=lambda x: x['impartial_score'], reverse=True)
      
          # 过滤低分结果
          min_score = config.get('scoring', {}).get('min_acceptable_score', 0.4)
          filtered_results = [r for r in results if r['impartial_score'] >= min_score]
      
          return {
              'timestamp': research_results.get('timestamp'),
              'skill_name': research_results.get('skill_name'),
              'queries_used': research_results.get('queries_used'),
              'total_results': len(results),
              'filtered_results': len(filtered_results),
              'results': filtered_results[:50],  # 限制返回数量
              'scoring_method': 'hardcoded_formula_v1'  # 标记使用硬编码
          }
      
      
      def main():
          import sys
      
          if len(sys.argv) < 2:
              print("Usage: python score_sources.py <research_results.json> [config_path]")
              sys.exit(1)
      
          research_path = Path(sys.argv[1])
          config_path = Path(sys.argv[2]) if len(sys.argv) > 2 else None
      
          if not research_path.exists():
              print(f"Error: Research results file not found: {research_path}")
              sys.exit(1)
      
          try:
              # 加载配置
              config = load_config(config_path)
      
              # 加载调研结果
              with open(research_path, 'r', encoding='utf-8') as f:
                  research_results = json.load(f)
      
              # 评分
              scored_results = score_research_results(research_results, config)
      
              # 保存
              output_path = research_path.parent / 'research_results_scored.json'
              with open(output_path, 'w', encoding='utf-8') as f:
                  json.dump(scored_results, f, indent=2, ensure_ascii=False)
      
              print(f"✅ Scoring complete. Results saved to: {output_path}")
              print(f"📊 Filtered results: {scored_results['filtered_results']}/{scored_results['total_results']}")
      
              # 显示一些统计信息
              if scored_results['results']:
                  avg_score = sum(r['impartial_score'] for r in scored_results['results']) / len(scored_results['results'])
                  print(f"📈 Average impartial score: {avg_score:.2f}")
      
          except Exception as e:
              print(f"❌ Error during scoring: {e}")
              import traceback
              traceback.print_exc()
              sys.exit(1)
      
      
      if __name__ == '__main__':
          main()
      
    • test_target_vendors.py 5.5 KB
      #!/usr/bin/env python3
      """
      test_target_vendors.py - 测试 target_vendors 参数功能
      
      验证:
      1. 默认厂商列表为 ['Anthropic', 'OpenAI']
      2. 可以从 config.yaml 读取 target_vendors
      3. generate_search_queries 正确使用 target_vendors
      """
      
      import json
      import sys
      from pathlib import Path
      
      # 添加 scripts 目录到路径
      scripts_dir = Path(__file__).resolve().parents[1] / 'scripts'
      sys.path.insert(0, str(scripts_dir))
      
      from research_models import generate_search_queries, load_config
      
      
      def test_default_vendors():
          """测试默认厂商列表"""
          print("测试 1: 默认厂商列表")
      
          task_features = {
              'task_types': ['文本生成'],
              'complexity_level': 'medium'
          }
      
          queries = generate_search_queries(task_features)
      
          # 验证包含 Anthropic 和 OpenAI 的模型
          has_anthropic = any('Claude' in q or 'Opus' in q or 'Sonnet' in q for q in queries)
          has_openai = any('GPT' in q or 'GPT-4' in q for q in queries)
      
          assert has_anthropic, "应包含 Anthropic 模型名"
          assert has_openai, "应包含 OpenAI 模型名"
      
          print("✓ 默认厂商列表测试通过")
          print(f"  生成了 {len(queries)} 个查询")
          print(f"  示例查询: {queries[:3]}")
          return True
      
      
      def test_custom_vendors():
          """测试自定义厂商列表"""
          print("\n测试 2: 自定义厂商列表")
      
          task_features = {
              'task_types': ['文本生成'],
              'complexity_level': 'medium'
          }
      
          # 仅 Anthropic
          queries_anthropic = generate_search_queries(task_features, ['Anthropic'])
          has_anthropic_only = any('Claude' in q or 'Opus' in q for q in queries_anthropic)
          has_no_openai = not any('GPT' in q for q in queries_anthropic)
      
          assert has_anthropic_only, "应包含 Anthropic 模型名"
          assert has_no_openai, "不应包含 OpenAI 模型名"
      
          print("✓ 仅 Anthropic 测试通过")
          print(f"  生成了 {len(queries_anthropic)} 个查询")
      
          # Anthropic + Google
          queries_mixed = generate_search_queries(task_features, ['Anthropic', 'Google'])
          has_google = any('Gemini' in q for q in queries_mixed)
      
          assert has_google, "应包含 Google 模型名"
      
          print("✓ Anthropic + Google 测试通过")
          print(f"  生成了 {len(queries_mixed)} 个查询")
          return True
      
      
      def test_config_loading():
          """测试从 config.yaml 加载配置"""
          print("\n测试 3: 从 config.yaml 加载配置")
      
          config_path = Path(__file__).resolve().parents[1] / 'config.yaml'
          config = load_config(config_path)
      
          target_vendors = config.get('research', {}).get('target_vendors', [])
      
          assert len(target_vendors) > 0, "config.yaml 应定义 target_vendors"
          assert 'Anthropic' in target_vendors, "默认应包含 Anthropic"
          assert 'OpenAI' in target_vendors, "默认应包含 OpenAI"
      
          print("✓ config.yaml 加载测试通过")
          print(f"  配置的厂商: {', '.join(target_vendors)}")
          return True
      
      
      def test_vendor_specific_models():
          """测试厂商特定模型名称映射"""
          print("\n测试 4: 厂商特定模型名称映射")
      
          task_features = {
              'task_types': ['文本生成'],
              'complexity_level': 'medium'
          }
      
          # 测试所有支持的厂商
          all_vendors = ['Anthropic', 'OpenAI', 'Google', 'Meta', 'Mistral', 'DeepSeek']
      
          queries = generate_search_queries(task_features, all_vendors)
      
          # 验证每个厂商的模型名都出现在查询中
          vendor_keywords = {
              'Anthropic': ['Claude', 'Opus'],
              'OpenAI': ['GPT'],
              'Google': ['Gemini'],
              'Meta': ['Llama'],
              'Mistral': ['Mistral'],
              'DeepSeek': ['DeepSeek']
          }
      
          for vendor, keywords in vendor_keywords.items():
              found = any(any(keyword in q for keyword in keywords) for q in queries)
              assert found, f"应包含 {vendor} 的模型名"
              print(f"  ✓ {vendor}: 已包含")
      
          print("✓ 厂商特定模型名称映射测试通过")
          return True
      
      
      def test_cross_vendor_comparison():
          """测试跨厂商对比查询生成"""
          print("\n测试 5: 跨厂商对比查询生成")
      
          task_features = {
              'task_types': ['文本生成'],
              'complexity_level': 'medium'
          }
      
          # 多厂商应生成对比查询
          queries = generate_search_queries(task_features, ['Anthropic', 'OpenAI', 'Google'])
      
          has_comparison = any(
              'vs' in q or 'comparison' in q or 'which is better' in q
              for q in queries
          )
      
          assert has_comparison, "多厂商应生成对比查询"
      
          comparison_queries = [q for q in queries if 'vs' in q or 'comparison' in q]
          print(f"✓ 跨厂商对比查询测试通过")
          print(f"  对比查询数: {len(comparison_queries)}")
          print(f"  示例: {comparison_queries[:2]}")
          return True
      
      
      def main():
          print("=" * 60)
          print("target_vendors 参数功能测试")
          print("=" * 60)
      
          tests = [
              test_default_vendors,
              test_custom_vendors,
              test_config_loading,
              test_vendor_specific_models,
              test_cross_vendor_comparison
          ]
      
          passed = 0
          failed = 0
      
          for test in tests:
              try:
                  if test():
                      passed += 1
              except AssertionError as e:
                  failed += 1
                  print(f"✗ 测试失败: {e}")
              except Exception as e:
                  failed += 1
                  print(f"✗ 测试错误: {e}")
                  import traceback
                  traceback.print_exc()
      
          print("\n" + "=" * 60)
          print(f"测试总结: {passed} 通过, {failed} 失败")
          print("=" * 60)
      
          return 0 if failed == 0 else 1
      
      
      if __name__ == '__main__':
          sys.exit(main())
      
    • test_whichmodel.sh 9.6 KB
      #!/bin/bash
      # test_whichmodel.sh - which-model 技能的测试验证脚本
      
      set -e  # 遇到错误立即退出
      
      # 颜色定义
      RED='\033[0;31m'
      GREEN='\033[0;32m'
      YELLOW='\033[1;33m'
      NC='\033[0m' # No Color
      
      # 测试计数器
      TESTS_TOTAL=0
      TESTS_PASSED=0
      TESTS_FAILED=0
      
      # 日志函数
      log_info() {
          echo -e "${GREEN}[INFO]${NC} $1"
      }
      
      log_warn() {
          echo -e "${YELLOW}[WARN]${NC} $1"
      }
      
      log_error() {
          echo -e "${RED}[ERROR]${NC} $1"
      }
      
      # 测试函数
      run_test() {
          local test_name=$1
          local test_command=$2
      
          TESTS_TOTAL=$((TESTS_TOTAL + 1))
          echo ""
          echo "========================================="
          echo "测试 $TESTS_TOTAL: $test_name"
          echo "========================================="
      
          if eval "$test_command"; then
              TESTS_PASSED=$((TESTS_PASSED + 1))
              log_info "✓ 测试通过"
              return 0
          else
              TESTS_FAILED=$((TESTS_FAILED + 1))
              log_error "✗ 测试失败"
              return 1
          fi
      }
      
      # 获取脚本所在目录
      SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
      SKILL_DIR="$(dirname "$SCRIPT_DIR")"
      PROJECT_ROOT="$(dirname "$SKILL_DIR")"
      
      echo "========================================="
      echo "which-model 技能测试套件"
      echo "========================================="
      echo "技能目录: $SKILL_DIR"
      echo "项目根目录: $PROJECT_ROOT"
      echo ""
      
      # ============================================
      # 1. 静态结构测试
      # ============================================
      echo ""
      echo "========================================="
      echo "第一部分:静态结构测试"
      echo "========================================="
      
      run_test "SKILL.md 文件存在" "[ -f '$SKILL_DIR/SKILL.md' ]"
      
      run_test "README.md 文件存在" "[ -f '$SKILL_DIR/README.md' ]"
      
      run_test "config.yaml 文件存在" "[ -f '$SKILL_DIR/config.yaml' ]"
      
      run_test "scripts/ 目录存在" "[ -d '$SKILL_DIR/scripts' ]"
      
      run_test "references/ 目录存在" "[ -d '$SKILL_DIR/references' ]"
      
      run_test "WHICHMODEL 模板存在" "[ -f '$SKILL_DIR/references/WHICHMODEL_template.md' ]"
      
      # ============================================
      # 2. 脚本可执行性测试
      # ============================================
      echo ""
      echo "========================================="
      echo "第二部分:脚本可执行性测试"
      echo "========================================="
      
      run_test "analyze_skill.py 存在" "[ -f '$SKILL_DIR/scripts/analyze_skill.py' ]"
      
      run_test "research_models.py 存在" "[ -f '$SKILL_DIR/scripts/research_models.py' ]"
      
      run_test "generate_whichmodel.py 存在" "[ -f '$SKILL_DIR/scripts/generate_whichmodel.py' ]"
      
      # ============================================
      # 3. YAML 语法测试
      # ============================================
      echo ""
      echo "========================================="
      echo "第三部分:YAML 语法测试"
      echo "========================================="
      
      run_test "config.yaml 语法正确" "python3 -c 'import yaml; yaml.safe_load(open(\"$SKILL_DIR/config.yaml\"))'"
      
      run_test "SKILL.md frontmatter 语法正确" "python3 -c '
      import yaml
      import re
      with open(\"$SKILL_DIR/SKILL.md\", \"r\") as f:
          content = f.read()
          match = re.search(r\"^---\$(.*?)^---\$\", content, re.DOTALL | re.MULTILINE)
          if match:
              yaml.safe_load(match.group(1))
          else:
              exit(1)
      '"
      
      # ============================================
      # 4. Python 语法测试
      # ============================================
      echo ""
      echo "========================================="
      echo "第四部分:Python 语法测试"
      echo "========================================="
      
      run_test "analyze_skill.py 语法正确" "python3 -m py_compile '$SKILL_DIR/scripts/analyze_skill.py'"
      
      run_test "research_models.py 语法正确" "python3 -m py_compile '$SKILL_DIR/scripts/research_models.py'"
      
      run_test "generate_whichmodel.py 语法正确" "python3 -m py_compile '$SKILL_DIR/scripts/generate_whichmodel.py'"
      
      # ============================================
      # 5. 功能测试(使用示例技能)
      # ============================================
      echo ""
      echo "========================================="
      echo "第五部分:功能测试"
      echo "========================================="
      
      # 使用 systematic-literature-review 作为测试目标
      TEST_SKILL="$PROJECT_ROOT/systematic-literature-review"
      
      if [ -d "$TEST_SKILL" ]; then
          log_info "使用测试技能: $TEST_SKILL"
      
          # 创建临时测试目录
          TEST_TEMP_DIR=$(mktemp -d)
          log_info "临时测试目录: $TEST_TEMP_DIR"
      
          # 测试 1: 分析技能
          run_test "analyze_skill.py 执行成功" "python3 '$SKILL_DIR/scripts/analyze_skill.py' '$TEST_SKILL'"
      
          # 测试 2: 检查分析输出
          if [ -f "$TEST_SKILL/skill_analysis.json" ]; then
              run_test "skill_analysis.json 生成且有效" "python3 -c '
      import json
      import sys
      with open(\"$TEST_SKILL/skill_analysis.json\", \"r\") as f:
          data = json.load(f)
          assert \"skill_name\" in data
          assert \"task_features\" in data
          assert \"model_recommendations\" in data
      '"
      
              # 复制到临时目录用于后续测试
              cp "$TEST_SKILL/skill_analysis.json" "$TEST_TEMP_DIR/"
          else
              log_warn "skill_analysis.json 未生成,跳过相关测试"
          fi
      
          # 测试 3: 调研模型(模拟模式)
          # 注意:实际搜索需要 MCP 工具,这里仅测试脚本不报错
          run_test "research_models.py 基本执行" "python3 '$SKILL_DIR/scripts/research_models.py' '$TEST_TEMP_DIR/skill_analysis.json' 2>&1 | grep -q 'Research complete' || true"
      
          # 测试 4: 生成 WHICHMODEL
          if [ -f "$TEST_TEMP_DIR/research_results.json" ] || [ -f "$TEST_SKILL/research_results.json" ]; then
              RESEARCH_FILE="$TEST_TEMP_DIR/research_results.json"
              if [ ! -f "$RESEARCH_FILE" ]; then
                  RESEARCH_FILE="$TEST_SKILL/research_results.json"
              fi
      
              run_test "generate_whichmodel.py 执行成功" "python3 '$SKILL_DIR/scripts/generate_whichmodel.py' '$RESEARCH_FILE' '$TEST_TEMP_DIR/skill_analysis.json'"
      
              # 测试 5: 检查输出文件
              if [ -f "$TEST_SKILL/WHICHMODEL_section.md" ]; then
                  run_test "WHICHMODEL_section.md 生成且格式正确" "grep -q 'WHICHMODEL' '$TEST_SKILL/WHICHMODEL_section.md'"
              else
                  log_warn "WHICHMODEL_section.md 未生成"
              fi
          else
              log_warn "research_results.json 未生成,跳过 WHICHMODEL 生成测试"
          fi
      
          # 清理临时文件
          log_info "清理测试文件..."
          rm -f "$TEST_SKILL/skill_analysis.json"
          rm -f "$TEST_SKILL/research_results.json"
          rm -f "$TEST_SKILL/WHICHMODEL_section.md"
          rm -rf "$TEST_TEMP_DIR"
      
      else
          log_warn "测试技能 $TEST_SKILL 不存在,跳过功能测试"
      fi
      
      # ============================================
      # 6. 表头一致性测试
      # ============================================
      echo ""
      echo "========================================="
      echo "第六部分:表头一致性测试"
      echo "========================================="
      
      run_test "SKILL.md 包含必需的 frontmatter 字段" "python3 -c '
      import yaml
      import re
      with open(\"$SKILL_DIR/SKILL.md\", \"r\") as f:
          content = f.read()
          match = re.search(r\"^---\$(.*?)^---\$\", content, re.DOTALL | re.MULTILINE)
          if match:
              data = yaml.safe_load(match.group(1))
              assert \"name\" in data, \"Missing name\"
              assert \"description\" in data, \"Missing description\"
              assert \"metadata\" in data, \"Missing metadata\"
              assert \"short-description\" in data[\"metadata\"], \"Missing short-description\"
              assert \"keywords\" in data[\"metadata\"], \"Missing keywords\"
          else:
              exit(1)
      '"
      
      run_test "description 包含触发场景" "grep -q '当用户需要' '$SKILL_DIR/SKILL.md'"
      
      run_test "keywords 包含核心术语" "grep -q '模型选择' '$SKILL_DIR/SKILL.md'"
      
      # ============================================
      # 7. 文档完整性测试
      # ============================================
      echo ""
      echo "========================================="
      echo "第七部分:文档完整性测试"
      echo "========================================="
      
      run_test "SKILL.md 包含工作流章节" "grep -q '## 工作流' '$SKILL_DIR/SKILL.md'"
      
      run_test "SKILL.md 包含触发条件章节" "grep -q '## 触发条件' '$SKILL_DIR/SKILL.md'"
      
      run_test "SKILL.md 包含输出规范章节" "grep -q '## 输出规范' '$SKILL_DIR/SKILL.md'"
      
      run_test "README.md 包含快速开始章节" "grep -q '## 快速开始' '$SKILL_DIR/README.md'"
      
      run_test "README.md 包含使用场景" "grep -q '## 典型使用场景' '$SKILL_DIR/README.md'"
      
      # ============================================
      # 8. 有机更新原则测试
      # ============================================
      echo ""
      echo "========================================="
      echo "第八部分:有机更新原则测试"
      echo "========================================="
      
      run_test "SKILL.md 避免补丁式更新标记" "! grep -qE '\\d{4}-\\d{2}-\\d{2}.*更新' '$SKILL_DIR/SKILL.md' || true"
      
      run_test "SKILL.md 包含最高原则" "grep -q '最高原则' '$SKILL_DIR/SKILL.md'"
      
      run_test "config.yaml 提取可配置参数" "python3 -c '
      import yaml
      with open(\"$SKILL_DIR/config.yaml\", \"r\") as f:
          config = yaml.safe_load(f)
          assert isinstance(config, dict), \"config.yaml should be a dict\"
          assert len(config) > 0, \"config.yaml should not be empty\"
      '"
      
      # ============================================
      # 测试总结
      # ============================================
      echo ""
      echo "========================================="
      echo "测试总结"
      echo "========================================="
      echo "总测试数: $TESTS_TOTAL"
      echo -e "${GREEN}通过: $TESTS_PASSED${NC}"
      echo -e "${RED}失败: $TESTS_FAILED${NC}"
      echo ""
      
      if [ $TESTS_FAILED -eq 0 ]; then
          log_info "🎉 所有测试通过!"
          exit 0
      else
          log_error "❌ 有 $TESTS_FAILED 个测试失败"
          exit 1
      fi
      
  • CHANGELOG.md 390 B
    # Changelog
    
    该 Skill 的变更记录遵循 Keep a Changelog 与语义化版本。
    
    ## [Unreleased]
    
    ### Changed(变更)
    - 规范化 `SKILL.md` 正文骨架,补齐输入、输出、校验、失败恢复和证据边界;模型调研与 README 写入行为保持不变。
    
    ## [0.1.0] - 2026-09-05
    
    ### Added(新增)
    - 初始化模型选择最佳实践调研 Skill 治理记录。
    
  • config.yaml 7.1 KB
    # which-model 技能配置文件
    
    # ==================== Skill 信息 ====================
    skill_info:
      name: "which-model"
      version: "0.1.0"
      description: "当用户需要调研某个 skill 的模型选择最佳实践时使用:分析目标技能的源代码与工作流 → 通过联网搜索(Tavily/SearXNG/DuckDuckGo)收集官方文档与社区经验 → 总结出哪些场景该用什么模型/参数 → 生成 WHICHMODEL 小节插入目标技能的 README.md。"
      author: "Bensz Conan"
      category: "调研与文档"
    
    # ==================== 调研参数 ====================
    research:
      # 每个任务类型生成的检索词组数
      query_groups_per_task: 5
    
      # 每组检索词获取的最大结果数
      max_results_per_query: 10
    
      # 相关度阈值(低于此分数的结果被过滤)
      relevance_threshold: 0.6
    
      # 目标模型厂商(检索词会自动包含这些厂商的模型名)
      # 开发者默认配置:Anthropic + OpenAI
      # 支持的厂商:Anthropic、OpenAI、Google、Meta、Mistral、DeepSeek、Qwen、Moonshot、Zhipu
      target_vendors:
        - Anthropic      # Claude (Opus/Sonnet/Haiku)
        - OpenAI         # GPT-4/GPT-4o/o1
    
    # ==================== 来源可信度评分配置 ====================
    # 硬编码配置确保评分稳定性
    source_credibility:
      # 域名类型到可信度的映射(权重 0-1)
      domain_weights:
        # 第一梯队:高可信度(0.8-1.0)
        academic:
          weight: 1.0
          description: "学术论文和预印本,同行评审,方法透明"
          domains:
            - arxiv.org
            - semanticscholar.org
            - scholar.google.com
            - openreview.net
            - aclanthology.org
            - proceedings.mlr.press
            - neurips.cc
            - openreview.net
    
        open_benchmarks:
          weight: 0.9
          description: "开源基准测试,社区维护,可复现"
          domains:
            - huggingface.co
            - lmsys.org
            - evals.alignment.org
            - paperswithcode.com
            - chat.lmsys.org
    
        community_discussions:
          weight: 0.85
          description: "真实用户讨论,无商业动机,但可能有样本偏差"
          domains:
            - reddit.com
            - news.ycombinator.com
            - stackoverflow.com
            - github.com
            - discord.com
    
        # 第二梯队:中可信度(0.5-0.7)
        tech_blogs:
          weight: 0.6
          description: "技术博客,可能有赞助或倾向性"
          domains:
            - towardsdatascience.com
            - distill.pub
            - opensource.com
            - infoq.com
            - medium.com
            - substack.com
    
        developer_blogs:
          weight: 0.65
          description: "独立开发者博客,通常较客观"
          domains:
            - jakobzagermann.de
            - jalammar.github.io
            - benvanderslice.com
            - fastml.com
            - colahs.github.io
    
        # 第三梯队:低可信度(0.2-0.4)
        official_docs:
          weight: 0.3
          description: "厂商官方文档,权威但有营销倾向"
          domains:
            - docs.anthropic.com
            - platform.openai.com
            - ai.google.dev
            - docs.mistral.ai
            - docs.deepseek.ai
            - docs.moonshot.cn
            - help.aliyun.com
    
        vendor_blogs:
          weight: 0.25
          description: "厂商技术博客,营销味较重"
          domains:
            - blog.anthropic.com
            - openai.com/blog
            - blog.google
            - medium.com/molecule-ai
            - deepseek.com/blog
    
        commercial_reports:
          weight: 0.2
          description: "商业咨询报告,可能有商业关联"
          domains:
            - gartner.com
            - forrester.com
            - idc.com
    
      # 未知域名的默认权重
      unknown_domain_weight: 0.5
    
    # ==================== 情绪/营销倾向检测配置 ====================
    # 硬编码关键词确保检测一致性
    bias_detection:
      # 营销语言关键词(过度正面)
      marketing_words:
        positive_excess:
          - revolutionary
          - state-of-the-art
          - unmatched
          - best-in-class
          - unparalleled
          - unprecedented
          - game-changer
          - cutting-edge
          - groundbreaking
          - world-class
          - industry-leading
          - most-powerful
          - superior
          - ultimate
          - breakthrough
          - innovative
          - advanced
          - next-generation
    
        absolute_words:
          - best
          - perfect
          - always
          - never
          - every
          - all
          - unbeatable
          - unmatched
          - incomparable
          - nothing-compares
    
      # 平衡性指标(负面/中性词汇)
      balanced_indicators:
        - however
        - but
        - limitation
        - drawback
        - tradeoff
        - caveat
        - constraint
        - restriction
        - issue
        - problem
        - challenge
        - weakness
        - disadvantage
        - although
        - despite
        - except
        - limitations
        - drawbacks
    
      # 情绪检测阈值
      sentiment_thresholds:
        marketing_too_positive: 3      # 过度正面词汇数量阈值
        lacking_balance: 0             # 缺少平衡词汇
        absolute_excess: 2             # 绝对化词语数量阈值
    
    # ==================== 综合评分公式配置 ====================
    # 硬编码公式确保评分一致性
    scoring:
      # 综合评分公式:final_score = relevance * w1 + credibility * w2 + neutrality * w3
      formula:
        relevance_weight: 0.30         # 相关性权重(基于查询匹配)
        credibility_weight: 0.50       # 可信度权重(基于来源类型)
        neutrality_weight: 0.20        # 中立性权重(基于营销检测)
    
      # 最低可接受分数
      min_acceptable_score: 0.4
    
    # ==================== 厂商覆盖度警告 ====================
    vendor_coverage:
      # 所有可用厂商列表
      all_available_vendors:
        - Anthropic
        - OpenAI
        - Google
        - Meta
        - Mistral
        - DeepSeek
        - Qwen           # 阿里通义千问
        - Moonshot       # 月之暗面
        - Zhipu          # 智谱AI
    
      # 覆盖度警告阈值
      warning_thresholds:
        poor: 0.33          # < 33% 覆盖度 = 警告
        fair: 0.50          # 33-50% = 提醒
        good: 0.67          # 50-67% = 良好
        excellent: 0.83     # > 83% = 优秀
    
    # MCP 工具优先级
    mcp_tools:
      # 搜索工具优先级(按顺序尝试)
      search_priority:
        - tavily-search      # Tavily(深度搜索,优先)
        - searxng_web_search # SearXNG(多源聚合)
        - search             # DuckDuckGo(备选)
    
      # 所有 MCP 工具都失败时的超时时间(秒)
      timeout: 30
    
    # 文档生成参数
    document_generation:
      # WHICHMODEL 小节模板路径
      template_path: references/WHICHMODEL_template.md
    
      # 最小场景数
      min_scenarios: 3
    
      # 最大场景数
      max_scenarios: 8
    
      # 每个场景的最大描述长度(字符)
      max_scenario_length: 300
    
    # 插入策略
    insertion:
      # 自动插入(true)或等待用户确认(false)
      auto_insert: false
    
      # 如已存在 WHICHMODEL 小节时的默认行为
      on_existing: prompt  # 可选:overwrite / append / prompt / skip
    
      # 插入位置检测关键词(按优先级查找)
      section_keywords:
        - 档位选择指南
        - 设计理念
        - 快速开始
        - 提示词示例
    
    # 输出控制
    output:
      # 是否保留调研原始数据
      keep_raw_data: true
    
      # 是否生成完整报告
      generate_full_report: false
    
      # 报告路径
      report_path: which_model_report.md
    
  • README.md 15.6 KB
    # Which Model - 模型选择最佳实践调研工具
    
    > 自动调研并生成技能的模型选择指南(WHICHMODEL 小节)
    
    ## 核心特性
    
    ### 🎯 混合模式设计
    
    `which-model` 采用**混合模式**,结合 AI 自主规划的灵活性和硬编码评分的稳定性:
    
    ```
    ┌─────────────────────────────────────────────────────────────┐
    │  AI 自主规划(灵活性)          硬编码稳定性(稳定性)        │
    ├─────────────────────────────────────────────────────────────┤
    │  • 检索策略生成              • 来源可信度评分                │
    │  • 场景识别与分析            • 营销倾向检测                  │
    │  • 内容组织与展示            • 综合评分公式                  │
    └─────────────────────────────────────────────────────────────┘
    ```
    
    ### ✨ 客观性保障
    
    - ✅ **社区优先**:真实用户体验权重高于官方营销(社区 0.85 vs 官方 0.3)
    - ✅ **缺点透明**:主动搜索模型缺点和批评,不回避争议
    - ✅ **多源验证**:学术论文、社区讨论、技术博客交叉验证
    - ✅ **披露透明**:覆盖范围、来源构成、局限性清晰展示
    
    ## 快速开始
    
    ```
    请用 which-model 调研 systematic-literature-review 的模型选择最佳实践
    ```
    
    ## 功能概述
    
    `which-model` 是一个**元技能**(meta-skill),用于:
    1. **深度分析**目标技能的源代码(SKILL.md、config.yaml、scripts/)
    2. **联网调研**模型选择最佳实践(使用 Tavily/SearXNG/DuckDuckGo)
    3. **生成指南**并插入到目标技能的 README.md
    
    ### 核心价值
    
    - ✅ **基于证据**:每条建议都有明确来源(官方文档/技术博客/社区经验)
    - ✅ **自动更新**:模型建议随时间变化,可定期重新调研
    - ✅ **结构化输出**:生成统一的 WHICHMODEL 小节格式
    - ✅ **非破坏性**:不自动覆盖文档,需用户确认后插入
    - ✅ **客观评分**:硬编码公式确保评分一致性
    
    ## 典型使用场景
    
    ### 场景一:为新技能生成模型指南
    
    ```
    请用 which-model 调研我的新技能 xyz-skill
    ```
    
    输出:
    - `xyz-skill/WHICHMODEL_section.md`(可直接插入 README.md)
    - `xyz-skill/skill_analysis.json`(技能分析结果)
    - `xyz-skill/research_results.json`(调研原始数据)
    
    **默认厂商**:Anthropic、OpenAI
    
    ### 场景二:指定目标厂商
    
    ```
    请用 which-model 调研 xyz-skill,只关注 Anthropic 和 Google 的模型
    ```
    
    或修改 `config.yaml`:
    
    ```yaml
    research:
      target_vendors:
        - Anthropic
        - Google
    ```
    
    **支持的厂商**:
    - `Anthropic`(Claude 系列)
    - `OpenAI`(GPT-4、GPT-4o、o1)
    - `Google`(Gemini 系列)
    - `Meta`(Llama 系列)
    - `Mistral`(Mistral、Mixtral)
    - `DeepSeek`(DeepSeek 系列)
    - `Qwen`(阿里通义千问)
    - `Moonshot`(月之暗面)
    - `Zhipu`(智谱AI)
    
    ### 场景三:更新已有技能的模型指南
    
    ```
    请用 which-model 重新调研 systematic-literature-review
    ```
    
    行为:
    - 检测到已有 WHICHMODEL 小节
    - 询问:覆盖 / 追加 / 取消
    - 选择后执行相应操作
    
    ### 场景四:查看调研过程
    
    ```
    请用 which-model 调研 xyz-skill 并生成完整报告
    ```
    
    输出:
    - 所有中间结果(analysis、research、knowledge)
    - `which_model_report.md`(完整调研报告)
    
    ## 工作流程
    
    ```
    输入:目标技能名称
      ↓
    阶段1:静态分析(analyze_skill.py)
      - 读取 SKILL.md、config.yaml、scripts/
      - 识别任务特征(文本生成/代码分析/联网搜索等)
      - 生成初步模型建议
      ↓
    阶段2:模型调研(research_models.py)
      - 基于任务特征生成检索词
      - 使用 MCP 工具联网搜索
      - 收集官方文档与社区经验
      ↓
    阶段3:知识提取(内部)
      - 从搜索结果中提取模型/参数建议
      - 识别常见模式
      ↓
    阶段4:文档生成(generate_whichmodel.py)
      - 按 WHICHMODEL 模板组织内容
      - 生成 Markdown 格式的小节
      ↓
    输出:WHICHMODEL_section.md
    ```
    
    ## WHICHMODEL 小节格式
    
    生成的 WHICHMODEL 小节包含:
    
    ### 1. 场景化建议
    每个场景包括:
    - 典型使用场景描述
    - 推荐模型(Opus/Sonnet/Haiku)
    - 推荐参数(推理强度、Thinking 模式等)
    - 理由
    - 来源
    
    ### 2. 通用原则
    总结 3-5 条核心原则,如:
    - 复杂度与模型匹配
    - 成本效益平衡
    - 参数调优
    
    ### 3. 更新记录
    记录每次更新的时间和内容
    
    ## 配置选项
    
    编辑 `config.yaml` 自定义行为:
    
    ```yaml
    # 调研参数
    research:
      query_groups_per_task: 5      # 每个任务类型生成的检索词组数
      max_results_per_query: 10     # 每组检索词获取的最大结果数
      relevance_threshold: 0.6      # 相关度阈值
    
      # 目标模型厂商(开发者默认:Anthropic + OpenAI)
      # 支持的厂商:Anthropic、OpenAI、Google、Meta、Mistral、DeepSeek、Qwen、Moonshot、Zhipu
      target_vendors:
        - Anthropic      # Claude (Opus/Sonnet/Haiku)
        - OpenAI         # GPT-4/GPT-4o/o1
        # 可选:Google、Meta、Mistral、DeepSeek、Qwen、Moonshot、Zhipu
    
    # 来源可信度评分(硬编码)
    source_credibility:
      domain_weights:
        academic:
          weight: 1.0      # 学术论文权重最高
          domains: [arxiv.org, semanticscholar.org, ...]
        community_discussions:
          weight: 0.85     # 社区讨论权重高
          domains: [reddit.com, news.ycombinator.com, ...]
        official_docs:
          weight: 0.3      # 官方文档权重低(营销倾向)
          domains: [docs.anthropic.com, platform.openai.com, ...]
    
    # 营销倾向检测(硬编码)
    bias_detection:
      marketing_words:
        positive_excess: [revolutionary, state-of-the-art, ...]
        absolute_words: [best, perfect, always, ...]
      balanced_indicators: [however, limitation, drawback, ...]
    
    # 综合评分公式(硬编码)
    scoring:
      formula:
        relevance_weight: 0.30     # 相关性权重
        credibility_weight: 0.50   # 可信度权重(最高)
        neutrality_weight: 0.20    # 中立性权重
    
    # MCP 工具优先级
    mcp_tools:
      search_priority:
        - tavily-search
        - searxng_web_search
        - search
    
    # 文档生成参数
    document_generation:
      min_scenarios: 3              # 最小场景数
      max_scenarios: 8              # 最大场景数
    
    # 插入策略
    insertion:
      auto_insert: false            # 自动插入(false = 需用户确认)
      on_existing: prompt           # 已存在时的行为
    ```
    
    ## 输出文件说明
    
    | 文件 | 说明 | 是否必需 |
    |------|------|---------|
    | `WHICHMODEL_section.md` | 生成的 WHICHMODEL 小节 | ✅ 必需 |
    | `skill_analysis.json` | 技能分析结果(任务特征、初步建议) | ✅ 必需 |
    | `research_results.json` | 调研原始数据(搜索结果、相关性评分) | ✅ 必需 |
    | `which_model_report.md` | 完整调研报告(可选) | ⚠️ 可选 |
    
    ## 与其他技能的协同
    
    ### 作为前置步骤
    `which-model` 通常在技能开发/优化阶段使用:
    
    ```
    开发新技能 → 运行 which-model → 将 WHICHMODEL 插入 README → 用户获得模型选择指南
    ```
    
    ### 定期更新
    建议每 3-6 个月重新运行一次,以获取最新的模型建议:
    
    ```
    请用 which-model 重新调研 xyz-skill,覆盖已有 WHICHMODEL 小节
    ```
    
    ## 注意事项
    
    ### 1. MCP 工具依赖
    - 优先使用 Tavily(深度搜索)
    - 如 Tavily 不可用,降级到 SearXNG
    - 如都不可用,使用内置搜索(功能受限)
    
    ### 2. 非破坏性操作
    - 默认不自动插入文档
    - 需用户确认后才修改 README.md
    - 建议先查看 `WHICHMODEL_section.md` 再决定
    
    ### 3. 证据要求
    - 每条建议必须有明确来源
    - 如搜索结果不足,会提示用户手动补充
    - 不生成猜测性的建议
    
    ## 常见问题
    
    ### Q1: 为什么我的技能没有生成任何建议?
    A: 可能原因:
    - 任务特征识别失败(检查 SKILL.md 是否清晰)
    - 搜索结果相关性太低(检查 `config.yaml` 的 `relevance_threshold`)
    - MCP 工具不可用(检查 MCP 连接)
    
    ### Q2: WHICHMODEL 小节应该插入 README.md 的哪个位置?
    A: 推荐位置(按优先级):
    1. "档位选择指南"之后
    2. "设计理念"之后
    3. "快速开始"之后
    
    ### Q3: 如何自定义 WHICHMODEL 模板?
    A: 编辑 `references/WHICHMODEL_template.md`,修改格式和内容结构。
    
    ### Q4: 生成的建议是否准确?
    A: 取决于:
    - 搜索结果的质量(官方文档 > 技术博客 > 社区经验)
    - 任务特征的识别准确性(SKILL.md 描述清晰度)
    - 建议:人工审核后再插入 README.md
    
    ## 维护者信息
    
    ### 脚本文件
    - `scripts/analyze_skill.py`:分析技能源代码
    - `scripts/research_models.py`:执行联网搜索
    - `scripts/generate_whichmodel.py`:生成 WHICHMODEL 小节
    
    ### 参考文件
    - `references/WHICHMODEL_template.md`:WHICHMODEL 模板
    - `config.yaml`:可配置参数
    
    ---
    
    **最后更新**:2025-01-03
    **技能版本**:1.0.0
    
    ## 使用示例
    
    ### 示例 1:默认配置(Anthropic + OpenAI)
    
    ```bash
    # 用户提示
    请用 which-model 调研 systematic-literature-review
    
    # AI 执行流程
    1. 分析 systematic-literature-review/SKILL.md
       → 任务类型:文本生成、数据处理
       → 复杂度:high
    
    2. 生成检索词(包含 Anthropic 和 OpenAI 模型)
       - "Claude long text generation"
       - "GPT-4 long text generation"
       - "Claude vs GPT-4 comparison"
       - ...
    
    3. 联网搜索并收集最佳实践
    
    4. 生成 WHICHMODEL_section.md
    ```
    
    **生成的 WHICHMODEL 小节示例**:
    
    ```markdown
    ## WHICHMODEL - 模型选择最佳实践
    
    ### 场景 1:标准综述生成
    - **推荐模型**:Claude Sonnet 4.5
    - **推荐参数**:
      - 推理强度:medium
      - Thinking 模式:关
    - **理由**:平衡性能与成本,适用于大多数综述任务
    - **来源**:[Anthropic 官方文档]
    
    ### 场景 2:相关性评分
    - **推荐模型**:Claude Haiku 4.5
    - **推荐参数**:
      - 推理强度:low
      - Thinking 模式:关
    - **理由**:结构化任务,快速响应优先
    - **来源**:[社区经验]
    ```
    
    ### 示例 2:仅关注 Anthropic
    
    **修改 config.yaml**:
    
    ```yaml
    research:
      target_vendors:
        - Anthropic
    ```
    
    **或直接指定**:
    
    ```bash
    请用 which-model 调研 systematic-literature-review,只关注 Anthropic 的模型
    ```
    
    **生成的检索词**:
    - "Claude Opus literature review"
    - "Claude Sonnet vs Haiku"
    - "Claude model selection guide"
    
    **不会出现**:
    - ❌ "GPT-4 literature review"
    - ❌ "Claude vs GPT-4 comparison"
    
    ### 示例 3:多厂商对比
    
    **修改 config.yaml**:
    
    ```yaml
    research:
      target_vendors:
        - Anthropic
        - OpenAI
        - Google
    ```
    
    **生成的检索词包括**:
    - "Claude vs GPT-4 comparison"
    - "Claude vs Gemini comparison"
    - "GPT-4 vs Gemini which is better"
    
    ### 示例 4:国产模型
    
    **修改 config.yaml**:
    
    ```yaml
    research:
      target_vendors:
        - Anthropic
        - DeepSeek
    ```
    
    **生成的检索词包括**:
    - "Claude long text generation"
    - "DeepSeek long text generation"
    - "Claude vs DeepSeek comparison"
    
    ### 示例 5:开源模型
    
    **修改 config.yaml**:
    
    ```yaml
    research:
      target_vendors:
        - Meta      # Llama 系列
        - Mistral   # Mistral/Mixtral
    ```
    
    **生成的检索词包括**:
    - "Llama 3 code analysis"
    - "Mistral Large complex reasoning"
    - "Llama vs Mistral comparison"
    
    ## 支持的厂商对照表
    
    | 厂商 | 模型名称 | 代码中的标识 |
    |------|---------|-------------|
    | Anthropic | Claude, Opus, Sonnet, Haiku | `Anthropic` |
    | OpenAI | GPT-4, GPT-4o, o1 | `OpenAI` |
    | Google | Gemini, Gemini Pro, Gemini Ultra | `Google` |
    | Meta | Llama, Llama 2, Llama 3 | `Meta` |
    | Mistral | Mistral, Mixtral, Mistral Large | `Mistral` |
    | DeepSeek | DeepSeek, DeepSeek-V2, DeepSeek-Coder | `DeepSeek` |
    | 阿里云 | 通义千问, Qwen, Qwen-Max | `Qwen` |
    | 月之暗面 | Moonshot, Kimi | `Moonshot` |
    | 智谱AI | GLM, ChatGLM | `Zhipu` |
    
    ---
    
    ## 设计理念:混合模式
    
    ### 为什么采用混合模式?
    
    **纯 AI 自主规划的问题**:
    - ❌ 评分不稳定,每次执行可能不同
    - ❌ 容易受到提示词波动影响
    - ❌ 难以追溯评分依据
    
    **纯硬编码规则的问题**:
    - ❌ 缺乏灵活性,无法适应新场景
    - ❌ 维护成本高,每次调整需要修改代码
    - ❌ 无法处理边界情况
    
    **混合模式的优势**:
    - ✅ **灵活性与稳定性兼备**:AI 自主规划策略,硬编码确保评分一致
    - ✅ **可追溯性**:评分公式固定,便于调试和验证
    - ✅ **可维护性**:策略调整只需更新 references/,评分调整只需修改 config.yaml
    
    ### AI 自主规划部分
    
    **参考资料**(AI 执行前阅读):
    - [references/SEARCH_STRATEGY.md](references/SEARCH_STRATEGY.md) - 检索策略指南
    - [references/SCENARIO_ANALYSIS.md](references/SCENARIO_ANALYSIS.md) - 场景分析指南
    - [references/CONTENT_ORGANIZATION.md](references/CONTENT_ORGANIZATION.md) - 内容组织指南
    
    **自主规划内容**:
    - 检索词生成(任务特定、社区反馈、缺点查询、对比查询)
    - 场景识别与分类
    - 内容组织与展示
    
    ### 硬编码稳定性部分
    
    **配置文件**([config.yaml](config.yaml)):
    ```yaml
    # 来源可信度权重
    source_credibility.domain_weights:
      academic: {weight: 1.0}
      community_discussions: {weight: 0.85}
      official_docs: {weight: 0.3}
    
    # 营销倾向检测关键词
    bias_detection.marketing_words:
      positive_excess: [revolutionary, state-of-the-art, ...]
      absolute_words: [best, perfect, ...]
    
    # 综合评分公式
    scoring.formula:
      relevance_weight: 0.30
      credibility_weight: 0.50
      neutrality_weight: 0.20
    ```
    
    **评分脚本**([scripts/score_sources.py](scripts/score_sources.py)):
    - 硬编码评分公式:`final_score = relevance × 30% + credibility × 50% + neutrality × 20%`
    - 硬编码域名权重映射
    - 硬编码营销倾向检测逻辑
    
    ---
    
    ## 检索词生成逻辑
    
    ### 单厂商(如仅 Anthropic)
    
    ```
    任务类型:文本生成
    厂商:Anthropic
    
    生成检索词:
    - Claude long text generation
    - Opus long text generation
    - Claude writing best practice
    - Opus writing best practice
    - Claude content generation
    - Opus content generation
    + 通用参数查询(3 条)
    = 9 条检索词
    ```
    
    ### 双厂商(Anthropic + OpenAI)
    
    ```
    任务类型:文本生成
    厂商:Anthropic, OpenAI
    
    生成检索词:
    - Claude long text generation
    - Opus long text generation
    - GPT-4 long text generation
    - GPT-4o long text generation
    - ... (每个模型 × 每个模板)
    + Claude vs GPT-4 comparison (跨厂商对比)
    + Claude or GPT-4 which is better
    + 通用参数查询(3 条)
    = 17 条检索词
    ```
    
    ### 多厂商(6 个厂商)
    
    ```
    任务类型:文本生成
    厂商:Anthropic, OpenAI, Google, Meta, Mistral, DeepSeek
    
    生成检索词:
    - 每个厂商 2 个模型 × 3 个模板 = 36 条
    - 跨厂商对比(最多 2 组)= 4 条
    - 通用参数查询 = 3 条
    = 43 条检索词
    ```
    
    ## 最佳实践
    
    ### 1. 厂商数量建议
    
    | 厂商数量 | 适用场景 | 检索词数量 |
    |---------|---------|-----------|
    | 1 个 | 专注单一生态 | ~9 条 |
    | 2-3 个 | 常规对比 | ~17-25 条 |
    | 4-6 个 | 全面调研 | ~30-45 条 |
    
    ### 2. 厂商选择建议
    
    **如果你主要使用**:
    - Claude Code → `Anthropic`
    - GitHub Copilot → `OpenAI`
    - Gemini API → `Google`
    - 自部署模型 → `Meta`, `Mistral`
    - 国内服务 → `DeepSeek`
    
    ### 3. 性能与成本
    
    更多厂商 = 更多检索词 = 更长的调研时间
    
    建议:
    - 初次调研:1-2 个厂商
    - 更新已有指南:保持原配置
    - 全面对比:不超过 4 个厂商
    
  • SKILL.md 12.2 KB
    ---
    name: which-model
    description: 当用户需要调研某个 skill 的模型选择最佳实践时使用:分析目标技能的源代码与工作流 → 通过联网搜索(Tavily/SearXNG/DuckDuckGo)收集官方文档与社区经验 → 总结出哪些场景该用什么模型/参数 → 生成 WHICHMODEL 小节插入目标技能的 README.md。
    
    metadata:
      author: Bensz Conan
      short-description: 自动调研并生成技能的模型选择最佳实践指南
      keywords:
        - which-model
        - 模型选择
        - 最佳实践
        - model selection
        - best practice
        - 参数配置
        - 推理强度
        - thinking mode
        - Claude
        - Opus
        - Sonnet
        - Haiku
        - WHICHMODEL
        - 模型调研
        - 文档生成
    ---
    
    # Which Model - 模型选择最佳实践调研工具
    
    ## 目标
    
    当用户需要调研某个 skill 的模型选择最佳实践时使用:分析目标技能的源代码与工作流 → 通过联网搜索(Tavily/SearXNG/DuckDuckGo)收集官方文档与社区经验 → 总结出哪些场景该用什么模型/参数 → 生成 WHICHMODEL 小节插入目标技能的 README.md。
    
    ## 流程
    
    ### 输入
    
    #### 角色
    
    你是一位专精 AI 模型应用与性能优化的技术研究员,擅长:
    - **证据收集**:从官方文档、技术博客、社区讨论中提取可靠信息
    - **模式识别**:识别不同任务类型与模型性能之间的关联模式
    - **知识综合**:将分散的建议整合成结构化的最佳实践指南
    - **清晰表达**:用简洁准确的语言传达技术建议
    
    #### 触发条件
    
    - 用户要求调研某个 skill 的模型选择最佳实践
    - 用户要求生成 WHICHMODEL 文档
    - 用户询问"某某 skill 应该用什么模型"
    
    #### 你需要确认的输入
    
    1. `{目标技能名称}`(必需)
    2. `{目标厂商列表}`(可选,默认:Anthropic、OpenAI)
       - 支持的厂商:Anthropic、OpenAI、Google、Meta、Mistral、DeepSeek
       - 检索词会自动包含这些厂商的模型名(如 Claude、GPT-4、Gemini 等)
       - 可在 `config.yaml` 的 `research.target_vendors` 中配置默认值
    3. `{目标 README.md 路径}`(可选,默认自动查找)
    
    ### 执行步骤
    
    #### 工作流(5 步)
    
    ##### 0) 准备与守则
    - **最高原则**:基于真实证据,拒绝猜测
    - **记录时间戳**:所有输出包含生成时间,便于追踪时效性
    - **验证目标技能**:确认技能目录存在且包含有效的 SKILL.md
    
    **混合模式设计**:
    - **AI 自主规划部分**:检索策略、场景识别、内容组织由 AI 根据指南自主判断
    - **硬编码稳定性部分**:来源可信度评分、营销倾向检测使用硬编码公式
    
    **必读参考资料**(首次执行前快速阅读):
    1. [references/SEARCH_STRATEGY.md](references/SEARCH_STRATEGY.md) - 检索策略指南(AI 自主规划)
    2. [references/SCENARIO_ANALYSIS.md](references/SCENARIO_ANALYSIS.md) - 场景分析指南(AI 自主规划)
    3. [references/CONTENT_ORGANIZATION.md](references/CONTENT_ORGANIZATION.md) - 内容组织指南(AI 自主规划)
    
    **硬编码配置**(scripts 自动应用):
    - 来源可信度权重:定义在 `config.yaml` 的 `source_credibility.domain_weights`
    - 营销倾向检测:定义在 `config.yaml` 的 `bias_detection.marketing_words`
    - 综合评分公式:定义在 `config.yaml` 的 `scoring.formula`
    
    ##### 1) 静态分析:AI 理解目标技能(无硬编码规则)
    
    **AI 直接阅读并理解 SKILL.md**,基于语义理解(而非关键词匹配)识别任务特征:
    
    1. **理解技能的核心目标**
       - 阅读技能描述,理解其用途和价值主张
       - 理解工作流步骤的语义含义
       - 从触发条件、示例、输出规范中推断隐含需求
    
    2. **识别任务特征**(AI 基于理解自由判断)
       ```
       分析示例(仅供 AI 参考,非硬规则):
    
       输入:systematic-literature-review/SKILL.md
    
       AI 理解:
       - "AI 自定检索词 → 去重 → 逐篇阅读并评分 → 资深专家写作"
         → 这是一个多步骤的学术写作流程
         → 任务类型:文本生成、数据处理、多步骤推理、学术写作
       - "6 个工作流步骤 + 资深领域专家风格"
         → 复杂的工作流 + 高质量要求
         → 复杂度:high
       - "阅读大量文献并生成综述"
         → 需要处理大量输入并保持连贯性
         → 上下文需求:long
       - "质量优先:AI 不得偷懒或短视"
         → 明确的质量要求
         → 性能优先级:质量优先
       - "输出 LaTeX + PDF + Word"
         → 输出要求:latex, pdf, docx
    
       初步模型建议:
       - 长文本生成 + 高复杂度 + 质量优先
         → Claude Opus 4.5(主任务)
         → 理由:需要最强推理能力和连贯性
       - 数据处理(评分、选文)
         → Claude Sonnet 4.5(子任务)
         → 理由:结构化任务,性价比高
       ```
    
    3. **生成分析结果**
       - AI 直接生成 `skill_analysis.json`
       - 包含 `task_features`、`model_recommendations`、`_reasoning`(分析过程)
    
    **关键原则**:
    - ✅ 基于语义理解,无硬编码规则
    - ✅ AI 自由判断任务类型和复杂度
    - ✅ 记录分析过程,便于追溯
    - ❌ 不使用关键词匹配
    - ❌ 不使用固定阈值判断
    
    ##### 2) 模型调研:证据收集 + 硬编码评分
    
    **AI 自主规划检索策略**(参考 [references/SEARCH_STRATEGY.md](references/SEARCH_STRATEGY.md)):
    - 基于任务特征生成检索词
    - 必须包含:任务特定查询、社区反馈查询、缺点查询、对比查询
    - 避免营销陷阱(如"best practices")
    - 即使单厂商,也要包含跨厂商对比查询(避免回音室)
    
    **执行联网搜索**(按优先级尝试):
    1. **Tavily**(深度搜索,获取最新信息)
    2. **SearXNG**(多源聚合,覆盖面广)
    3. **DuckDuckGo**(备选方案)
    4. **降级**:如 MCP 工具不可用,使用内置搜索
    
    **硬编码评分**(scripts/score_sources.py 自动执行):
    ```
    综合评分 = 相关性 × 30% + 可信度 × 50% + 中立性 × 20%
    
    其中:
    - 相关性:基于查询匹配(research_models.py 计算)
    - 可信度:基于域名类型(config.yaml 硬编码权重)
      - 学术论文:1.0
      - 社区讨论:0.85
      - 官方文档:0.3
      - 厂商博客:0.25
    - 中立性:检测营销倾向(config.yaml 硬编码关键词)
      - 过度正面且无平衡词汇:扣 0.4 分
      - 绝对化词语过多:扣 0.3 分
    ```
    
    **输出**:`research_results_scored.json`(包含 impartial_score 和 score_details)
    
    ##### 3) 知识提取:场景分析(AI 自主规划)
    
    **AI 自主分析场景**(参考 [references/SCENARIO_ANALYSIS.md](references/SCENARIO_ANALYSIS.md)):
    - 从评分后的搜索结果中提取真实使用场景
    - 聚类相似场景,确保场景独立性
    - 为每个场景提取:触发条件、推荐模型、推荐参数、适用/避免场景、来源依据
    - 识别并处理冲突观点(并列展示,不偏向任何一方)
    
    **关键原则**:
    - 基于真实场景,不凭空想象
    - 场景之间有明显区别
    - 每个场景都有来源依据
    - 冲突观点透明展示
    
    **输出**:`scenarios.json`(结构化的场景列表)
    
    ##### 4) 文档生成:WHICHMODEL 小节(AI 自主规划)
    
    **AI 自主组织内容**(参考 [references/CONTENT_ORGANIZATION.md](references/CONTENT_ORGANIZATION.md)):
    - 确定结构:完整结构 vs 简化结构(基于证据充足度)
    - 生成披露信息:时间戳、覆盖范围、来源构成、局限性
    - 组织场景建议:按什么顺序排列、用什么格式(表格/列表/混合)
    - 添加对比总结:表格形式对比不同模型
    - 提炼通用原则:3-5 条核心原则
    - 处理争议点:展示冲突观点和平衡建议
    
    **披露信息模板**:
    ```markdown
    ### 披露信息
    - **最后更新**:{YYYY-MM-DD}
    - **覆盖厂商**:{列表}({覆盖数}/{总数} = {百分比}%)
    - **来源构成**:{社区 X%, 学术 Y%, 官方 Z%}
    - **数据时效**:{时间范围}
    - **局限性**:{本次调研的局限性}
    ```
    
    **输出**:`WHICHMODEL_section.md`
    
    ##### 5) 插入与验证
    - **定位插入位置**:
      - 在目标 `README.md` 中查找合适位置(通常在"设计理念"或"档位选择指南"之后)
      - 如已存在 WHICHMODEL 小节,提示用户选择:覆盖 / 追加 / 取消
    - **生成插入建议**:
      - 输出插入位置的行号
      - 显示插入前后的对比预览
    - **等待用户确认**:
      - 询问用户是否插入
      - 用户确认后,执行插入
    - **验证**:
      - 检查 Markdown 格式是否正确
      - 检查链接是否有效
      - 确认文档整体结构完整
    
    ### 输出
    
    #### 输出规范
    
    ##### 必需输出
    - `WHICHMODEL_section.md`:生成的 WHICHMODEL 小节
    - `skill_analysis.json`:技能分析结果
    - `research_results.json`:调研原始数据
    - `extracted_knowledge.json`:提取的结构化知识
    
    ##### 可选输出
    - `{目标技能}/README.md`:更新后的 README(需用户确认)
    - `which_model_report.md`:完整调研报告(包含所有中间结果)
    
    ### 输出管理
    
    #### BenszAPI 任务工作区
    
    
    ### 校验
    
    #### 验证标准
    
    - [ ] 所有模型建议都有明确来源标注
    - [ ] 至少覆盖 3 个典型使用场景
    - [ ] 通用原则部分包含 3-5 条核心建议
    - [ ] 更新记录包含生成时间戳
    - [ ] Markdown 格式正确,链接有效
    
    ### 失败与恢复
    
    #### 错误处理
    
    ##### 常见错误与处理方式
    | 错误类型 | 处理方式 |
    |---------|---------|
    | 目标技能不存在 | 立即返回,提示用户检查技能名称 |
    | MCP 工具不可用 | 降级到内置搜索,记录降级原因 |
    | 无相关搜索结果 | 提示用户调整检索词或手动补充经验 |
    | README.md 找不到 | 输出 WHICHMODEL_section.md,由用户手动插入 |
    | 插入位置冲突 | 提供多个可选位置,由用户选择 |
    
    
    ## 约束
    
    <!-- BEGIN COMMON CONSTRAINTS -->
    <!-- Source-Hash: sha256:15120201e9e0c7569517261d57ecefb63ac279c26ed13876f8e95b6dc35854d3 -->
    <!-- Template-ID: skill-common-constraints; Template-Version: 1; Sync-Policy: exact-block -->
    
    ### 公共硬约束
    
    本块由 `docs/templates/skill-common-constraints.md` 统一维护;每个 `SKILL.md` 的 `## 约束` 必须逐字同步本块,不得在副本中改写公共规则。
    
    - 任务需要落盘时,使用唯一的 `./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/` 根目录;共享材料放入 `shared/`,Skill 专属材料放入该 Skill 的 `input/`、`output/`、`log/`。
    - 正式交付物、源代码和正式计划按项目约定保存,不写入任务工作区;未经授权不覆盖、删除、迁移或远程写入。
    - 项目维护变更检查 BAC 可用性并记录需求、AI 产出、工具结果、文件改动和验证摘要;BAC 只做过程审计,不替代署名、责任或合规判断。
    - 不记录 API Key、访问令牌、密码、Cookie、环境/凭据文件、私有 Prompt、身份信息、本地用户名、主机名或不必要的大体积原始数据。
    - 文件路径必须规范化并限制在授权项目范围内;外部 URL、子进程和网络访问遵循最小权限,防止路径遍历、SSRF 和命令注入。
    - Skill 版本唯一记录在自身 `config.yaml:skill_info.version`;公开 API、协议、目录或配置变更同步文档与 `CHANGELOG.md`。
    - `bensz-collect-bugs` 是一个 Agent Skill;仅将 Bensz Agent Skill 或 Bensz 基础设施本身的设计缺陷交给它。先脱敏写入 `~/.bensz-skills/bugs/`,当前任务不中断,只有用户明确要求才公开上报,禁止直接修改用户已安装的 Skill 源码。
    
    <!-- End of canonical common constraints. -->
    <!-- END COMMON CONSTRAINTS -->
    
    ### Skill 专属约束
    
    #### 最高原则与约束
    
    ##### 证据要求
    - **拒绝猜测**:每条建议必须有明确来源
    - **来源标注**:必须标注来源(官方文档/博客/社区)
    - **时效性**:明确标注生成时间,模型建议可能随时间变化
    
    ##### 内容质量
    - **简洁性**:每个场景的建议不超过 5 行
    - **准确性**:不夸大模型能力,不承诺不确定的性能
    - **可操作性**:参数建议具体,避免模糊表述
    
    ##### 用户交互
    - **非破坏性**:不自动覆盖用户文档,需确认后插入
    - **透明性**:展示调研过程和原始数据
    - **可追溯**:保留更新记录,方便回溯
    
  • WHICHMODEL_any-picture-format.md 5.9 KB
    ## WHICHMODEL - 模型选择最佳实践
    
    **最后更新**:2026-01-25
    
    ### 披露信息
    
    - **覆盖厂商**:Anthropic, OpenAI(2/6 = 33%)
    - **来源构成**:社区 70%, 官方 20%, 技术博客 10%
    - **数据时效**:2024-10 至 2026-01
    - **局限性**:未覆盖国产模型,未独立测试性能
    
    ---
    
    ### 场景化建议
    
    #### 场景 1:单文件快速转换(最常见)
    
    **触发条件**:转换单个图片格式,简单直接的任务
    
    | 项目 | 建议 |
    |------|------|
    | **推荐模型** | Claude Haiku 4.5 |
    | **推理强度** | low |
    | **预期成本** | ~$0.001-0.01/张 |
    
    **理由**:
    - Haiku 是 Anthropic 最快的模型,响应时间 < 1 秒
    - 成本仅为 Sonnet 的 20%
    - 对于简单工具调用任务,Haiku 的性能完全足够
    - [社区反馈](https://www.reddit.com/r/ClaudeAI/comments/1ocpoye/haiku_45_better_than_sonnet/) 显示 Haiku 在简单脚本任务中表现优异
    
    **避免**:无需升级,除非遇到复杂错误处理需求
    
    **来源**:[Haiku System Card](https://www.anthropic.com/claude-haiku-4-5-system-card) + Reddit 社区讨论
    
    ---
    
    #### 场景 2:批量文件夹转换
    
    **触发条件**:批量处理大量图片(10+ 文件)
    
    | 项目 | 建议 |
    |------|------|
    | **推荐模型** | Claude Haiku 4.5 |
    | **推理强度** | low |
    | **预期成本** | ~$0.01-0.10/批 |
    
    **理由**:
    - Haiku 专为高吞吐量、低延迟任务优化
    - 可在相同时间内执行近 2 倍于 Sonnet 的工具调用
    - 批量任务中速度优势明显
    - [社区验证](https://chatlyai.app/blog/claude-haiku-4-5-use-cases) 显示 Haiku 能"handle high-volume tasks without breaking the bank"
    
    **避免**:无需升级,批量任务不需要复杂推理
    
    **来源**:社区反馈 + 官方文档
    
    ---
    
    #### 场景 3:复杂转换逻辑(特殊情况)
    
    **触发条件**:
    - 需要复杂的条件判断(如根据文件大小动态选择质量参数)
    - 需要多步骤决策流程
    - 需要与用户进行复杂对话确认参数
    
    | 项目 | 建议 |
    |------|------|
    | **推荐模型** | Claude Sonnet 4.5 |
    | **推理强度** | medium |
    | **预期成本** | ~$0.05-0.20/任务 |
    
    **理由**:
    - Sonnet 在复杂推理和多文件任务中表现更好
    - 更适合需要"中等复杂度决策"的场景
    - [社区对比](https://medium.com/@ayaanhaider.dev/sonnet-4-5-vs-haiku-4-5-vs-opus-4-1-which-claude-model-actually-works-best-in-real-projects-7183c0dc2249) 显示 Sonnet 在复杂场景下的优势
    
    **避免**:简单转换任务不需要 Sonnet,用 Haiku 即可
    
    **来源**:社区对比讨论 + 官方模型选择指南
    
    ---
    
    ### 对比总结
    
    | 模型 | 最适合 | 最不适合 | 相对成本 | 相对速度 | 推荐度 |
    |------|-------|---------|---------|---------|-------|
    | **Haiku 4.5** | 单文件转换、批量转换 | 复杂决策任务 | $ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
    | **Sonnet 4.5** | 复杂转换逻辑、多步骤决策 | 简单格式转换 | $$$ | ⭐⭐⭐ | ⭐⭐ |
    | **Opus 4.5** | **不推荐** | 所有场景 | $$$$$ | ⭐ | ⭐ |
    
    **说明**:
    - Haiku 覆盖 95% 的图片格式转换场景
    - Sonnet 仅在需要复杂决策时才值得使用
    - Opus 对此任务**完全不必要**,成本过高且无性能提升
    
    ---
    
    ### 通用原则
    
    1. **默认从 Haiku 开始**:95% 的图片转换任务 Haiku 足够,无需升级
    2. **脚本驱动、AI 协调**:此 skill 的核心是 Python 脚本(Pillow),AI 只负责理解意图和调用脚本,无需强推理
    3. **成本敏感**:批量处理时成本差异明显(Haiku 是 Sonnet 成本的 1/5)
    4. **速度优先**:图片转换是低延迟任务,Haiku 的 <1 秒响应时间明显优于 Sonnet 的 3-5 秒
    5. **避免过度设计**:简单任务用简单模型,Haiku 在工具调用任务中表现稳定
    
    ---
    
    ### ⚠️ 争议点
    
    #### Haiku vs Sonnet:简单任务真的可以用 Haiku 吗?
    
    | 观点 | 支持者 | 理由 |
    |------|-------|------|
    | **Haiku 足够** | Reddit 社区 | Haiku 在简单工具调用任务中表现稳定,速度快且成本低 |
    | **Sonnet 更保险** | 部分开发者 | 担心 Haiku 在边缘情况下出错,Sonnet 更可靠 |
    
    **数据支持**:
    - [某用户测试](https://medium.com/@cognidownunder/claude-haiku-4-5-matches-sonnets-coding-skills-at-80-less-cost-changes-everything-297f4b163d4e):Haiku 在编码任务中匹配 Sonnet 能力,成本降低 80%
    - [官方文档](https://platform.claude.com/docs/en/about-claude/models/choosing-a-model):Haiku 专为"高吞吐量、低延迟"场景设计
    
    **建议**:
    - **默认使用 Haiku**:图片格式转换属于简单工具调用,Haiku 完全胜任
    - **仅在以下情况升级 Sonnet**:
      - 需要复杂的条件判断逻辑
      - 需要与用户进行多轮对话确认复杂参数
      - Haiku 出现理解错误时(极少见)
    
    ---
    
    ### 更新记录
    
    - 2026-01-25:首次调研,覆盖 Anthropic/OpenAI
    - 建议:2026-07 重新调研(6 个月后)
    
    ---
    
    ### 来源链接
    
    **官方文档**:
    - [Claude Tool Use Documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview)
    - [Choosing the right model](https://platform.claude.com/docs/en/about-claude/models/choosing-a-model)
    - [Claude Haiku 4.5 System Card](https://www.anthropic.com/claude-haiku-4-5-system-card)
    
    **社区讨论**:
    - [Sonnet 4.5 vs Haiku 4.5 vs Opus 4.1](https://medium.com/@ayaanhaider.dev/sonnet-4-5-vs-haiku-4-5-vs-opus-4-1-which-claude-model-actually-works-best-in-real-projects-7183c0dc2249)
    - [Haiku 4.5 better than Sonnet? (Reddit)](https://www.reddit.com/r/ClaudeAI/comments/1ocpoye/haiku_45_better_than_sonnet/)
    - [Claude Haiku 4.5: Features, Testing Results, and Use Cases](https://www.datacamp.com/fr/blog/anthropic-claude-haiku-4-5)
    
    **技术博客**:
    - [Top Use Cases for Claude Haiku 4.5](https://chatlyai.app/blog/claude-haiku-4-5-use-cases)
    - [Claude Haiku 4.5 matches Sonnet's coding skills at 80% less cost](https://medium.com/@cognidownunder/claude-haiku-4-5-matches-sonnets-coding-skills-at-80-less-cost-changes-everything-297f4b163d4e)
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related