diff --git a/.claude/Skills/create-skill-file/SKILL.md b/.claude/Skills/create-skill-file/SKILL.md new file mode 100644 index 000000000..e089adc08 --- /dev/null +++ b/.claude/Skills/create-skill-file/SKILL.md @@ -0,0 +1,475 @@ +--- +name: create-skill-file +description: Guides Claude in creating well-structured SKILL.md files following best practices. Provides clear guidelines for naming, structure, and content organization to make skills easy to discover and execute. +--- + +# Claude Agent Skill 编写规范 + +> 如何创建高质量的 SKILL.md 文件 + +## 目录 + +- [快速开始](#快速开始) +- [核心原则](#核心原则) +- [文件结构规范](#文件结构规范) +- [命名和描述规范](#命名和描述规范) +- [内容编写指南](#内容编写指南) +- [质量检查清单](#质量检查清单) + +--- + +## 快速开始 + +### 3步创建 Skill + +**第1步: 创建目录** + +```bash +mkdir -p .claude/skill/your-skill-name +cd .claude/skill/your-skill-name +``` + +**第2步: 创建 SKILL.md** + +```markdown +--- +name: your-skill-name +description: Brief description with trigger keywords and scenarios +--- + +# Your Skill Title + +## When to Use This Skill + +- User asks to [specific scenario] +- User mentions "[keyword]" + +## How It Works + +1. Step 1: [Action] +2. Step 2: [Action] + +## Examples + +**Input**: User request +**Output**: Expected result +``` + +**第3步: 测试** +- 在对话中使用 description 中的关键词触发 +- 观察 Claude 是否正确执行 +- 根据效果调整 + +--- + +## 核心原则 + +### 1. 保持简洁 + +只添加 Claude **不知道**的新知识: +- ✅ 项目特定的工作流程 +- ✅ 特殊的命名规范或格式要求 +- ✅ 自定义工具和脚本的使用方法 +- ❌ 通用编程知识 +- ❌ 显而易见的步骤 + +**示例对比**: + +```markdown +# ❌ 过度详细 +1. 创建 Python 文件 +2. 导入必要的库 +3. 定义函数 +4. 编写主程序逻辑 + +# ✅ 简洁有效 +使用 `scripts/api_client.py` 调用内部 API。 +请求头必须包含 `X-Internal-Token`(从环境变量 `INTERNAL_API_KEY` 获取)。 +``` + +### 2. 设定合适的自由度 + +| 自由度 | 适用场景 | 编写方式 | +|--------|---------|---------| +| **高** | 需要创造性、多种解决方案 | 提供指导原则,不限定具体步骤 | +| **中** | 有推荐模式但允许变化 | 提供参数化示例和默认流程 | +| **低** | 容易出错、需严格执行 | 提供详细的分步指令或脚本 | + +**判断标准**: +- 任务是否有明确的"正确答案"? → 低自由度 +- 是否需要适应不同场景? → 高自由度 +- 错误的代价有多大? → 代价高则用低自由度 + +### 3. 渐进式披露 + +将复杂内容分层组织: + +``` +SKILL.md (主文档, 200-500行) +├── reference.md (详细文档) +├── examples.md (完整示例) +└── scripts/ (可执行脚本) +``` + +**规则**: +- SKILL.md 超过 500行 → 拆分子文件 +- 子文件超过 100行 → 添加目录 +- 引用深度 ≤ 1层 + +--- + +## 文件结构规范 + +### YAML Frontmatter + +```yaml +--- +name: skill-name-here +description: Clear description of what this skill does and when to activate it +--- +``` + +**字段规范**: + +| 字段 | 要求 | 说明 | +|------|------|------| +| `name` | 小写字母、数字、短横线,≤64字符 | 必须与目录名一致 | +| `description` | 纯文本,≤1024字符 | 用于检索和激活 | + +**命名禁忌**: +- ❌ XML 标签、保留字(`anthropic`, `claude`) +- ❌ 模糊词汇(`helper`, `utility`, `manager`) +- ❌ 空格或下划线(用短横线 `-`) + +**Description 技巧**: + +```yaml +# ❌ 过于泛化 +description: Helps with code tasks + +# ✅ 具体且包含关键词 +description: Processes CSV files and generates Excel reports with charts. Use when user asks to convert data formats or create visual reports. + +# ✅ 说明触发场景 +description: Analyzes Python code for security vulnerabilities using bandit. Activates when user mentions "security audit" or "vulnerability scan". +``` + +### 目录组织 + +**基础结构**(简单 Skill): +``` +skill-name/ +└── SKILL.md +``` + +**标准结构**(推荐): +``` +skill-name/ +├── SKILL.md +├── templates/ +│ └── template.md +└── scripts/ + └── script.py +``` + +--- + +## 命名和描述规范 + +### Skill 命名 + +**推荐格式**: 动名词形式 (verb-ing + noun) + +``` +✅ 好的命名: +- processing-csv-files +- generating-api-docs +- managing-database-migrations + +❌ 不好的命名: +- csv (过于简短) +- data_processor (使用下划线) +- helper (过于模糊) +``` + +### Description 编写 + +**必须使用第三人称**: + +```yaml +# ❌ 错误 +description: I help you process PDFs + +# ✅ 正确 +description: Processes PDF documents and extracts structured data +``` + +**4C 原则**: +- **Clear** (清晰): 避免术语和模糊词汇 +- **Concise** (简洁): 1-2句话说明核心功能 +- **Contextual** (上下文): 说明适用场景 +- **Complete** (完整): 功能 + 触发条件 + +--- + +## 内容编写指南 + +### "When to Use" 章节 + +明确说明触发场景: + +```markdown +## When to Use This Skill + +- User asks to analyze Python code for type errors +- User mentions "mypy" or "type checking" +- User is working in a Python project with type hints +- User needs to add type annotations +``` + +**模式**: +- 直接请求: "User asks to X" +- 关键词: "User mentions 'keyword'" +- 上下文: "User is working with X" +- 任务类型: "User needs to X" + +### 工作流设计 + +**简单线性流程**: + +```markdown +## How It Works + +1. Scan the project for all `.py` files +2. Run `mypy --strict` on each file +3. Parse error output and categorize by severity +4. Generate summary report with fix suggestions +``` + +**条件分支流程**: + +```markdown +## Workflow + +1. **Check project type** + - If Django → Use `django-stubs` config + - If Flask → Use `flask-stubs` config + - Otherwise → Use default mypy config + +2. **Run type checking** + - If errors found → Proceed to step 3 + - If no errors → Report success and exit +``` + +**Checklist 模式**(验证型任务): + +```markdown +## Pre-deployment Checklist + +Execute in order. Stop if any step fails. + +- [ ] Run tests: `npm test` (must pass) +- [ ] Build: `npm run build` (no errors) +- [ ] Check deps: `npm audit` (no critical vulnerabilities) +``` + +### 示例和模板 + +**输入-输出示例**: + +```markdown +## Examples + +### Example 1: Basic Check + +**User Request**: "Check my code for type errors" + +**Action**: +1. Scan for `.py` files +2. Run `mypy` on all files + +**Output**: + + Found 3 type errors in 2 files: + src/main.py:15: error: Missing return type + src/utils.py:42: error: Incompatible types + +``` + +### 脚本集成 + +**何时使用脚本**: +- 简单命令 → 直接在 SKILL.md 中说明 +- 复杂流程 → 提供独立脚本 + +**脚本编写规范**: + +```python +#!/usr/bin/env python3 +""" +Brief description of what this script does. + +Usage: + python script.py [--option value] +""" + +import argparse + +DEFAULT_VALUE = 80 # Use constants, not magic numbers + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("directory", help="Directory to process") + parser.add_argument("--threshold", type=int, default=DEFAULT_VALUE) + + args = parser.parse_args() + + # Validate inputs + if not Path(args.directory).is_dir(): + print(f"Error: {args.directory} not found") + return 1 + + # Execute + result = process(args.directory, args.threshold) + + # Report + print(f"Processed {result['count']} files") + return 0 + +if __name__ == "__main__": + exit(main()) +``` + +**关键规范**: +- ✅ Shebang 行和 docstring +- ✅ 类型注解和常量 +- ✅ 参数验证和错误处理 +- ✅ 清晰的返回值(0=成功, 1=失败) + +### 最佳实践 + +**Do**: +- ✅ 提供可执行的命令和脚本 +- ✅ 包含输入-输出示例 +- ✅ 说明验证标准和成功条件 +- ✅ 包含 Do/Don't 清单 + +**Don't**: +- ❌ 包含 Claude 已知的通用知识 +- ❌ 使用抽象描述而非具体步骤 +- ❌ 遗漏错误处理指导 +- ❌ 示例使用伪代码而非真实代码 + +--- + +## 质量检查清单 + +### 核心质量 + +- [ ] `name` 符合命名规范(小写、短横线、≤64字符) +- [ ] `description` 包含触发关键词和场景(≤1024字符) +- [ ] 名称与目录名一致 +- [ ] 只包含 Claude 不知道的信息 +- [ ] 没有冗余或重复内容 + +### 功能完整性 + +- [ ] 有"When to Use"章节,列出 3-5 个触发场景 +- [ ] 有清晰的执行流程或步骤 +- [ ] 至少 2-3 个完整示例 +- [ ] 包含输入和预期输出 +- [ ] 错误处理有指导 + +### 结构规范 + +- [ ] 章节组织清晰 +- [ ] 超过 200行有目录导航 +- [ ] 引用层级 ≤ 1层 +- [ ] 所有路径使用正斜杠 `/` +- [ ] 术语使用一致 + +### 脚本和模板 + +- [ ] 脚本包含使用说明和参数文档 +- [ ] 脚本有错误处理 +- [ ] 避免魔法数字,使用配置 +- [ ] 模板格式清晰易用 + +### 最终检查 + +- [ ] 通读全文,确保流畅易读 +- [ ] 使用实际场景测试触发 +- [ ] 长度适中(200-500行,或已拆分) + +--- + +## 常见问题 + +**Q: Skill 多长才合适?** +- 最小: 50-100行 +- 理想: 200-500行 +- 最大: 500行(超过则拆分) + +**Q: 如何让 Skill 更容易激活?** +- 在 `description` 中使用用户会说的关键词 +- 说明具体场景("when user asks to X") +- 提及相关工具名称 + +**Q: 多个 Skill 功能重叠怎么办?** +- 使用更具体的 `description` 区分 +- 在"When to Use"中说明关系 +- 考虑合并为一个 Skill + +**Q: Skill 需要维护吗?** +- 每季度审查一次,更新过时信息 +- 根据使用反馈迭代 +- 工具或 API 变更时及时更新 + +--- + +## 快速参考 + +### Frontmatter 模板 + +```yaml +--- +name: skill-name +description: Brief description with trigger keywords +--- +``` + +### 基础结构模板 + +```markdown +# Skill Title + +## When to Use This Skill +- Scenario 1 +- Scenario 2 + +## How It Works +1. Step 1 +2. Step 2 + +## Examples +### Example 1 +... + +## References +- [Link](url) +``` + +--- + +## 相关资源 + +- [Claude Agent Skills 官方文档](https://docs.claude.com/en/docs/agents-and-tools/agent-skills) +- [Best Practices Checklist](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/best-practices) +- [模板文件](templates/) - 开箱即用的模板 + - [基础 skill 的模板](templates/basic-skill-template.md) + - [工作流 skill 的模板](templates/workflow-skill-template.md) +- [示例库](examples/) - 完整的 Skill 示例 + - [优秀示例](examples/good-example.md) + - [常见错误示例](examples/bad-example.md) + +--- diff --git a/.claude/Skills/create-skill-file/examples/bad-example.md b/.claude/Skills/create-skill-file/examples/bad-example.md new file mode 100644 index 000000000..c0ae20b1b --- /dev/null +++ b/.claude/Skills/create-skill-file/examples/bad-example.md @@ -0,0 +1,867 @@ +# 不好的 Skill 示例与改进建议 + +本文档展示常见的 Skill 编写错误,并提供改进建议。 + +--- + +## 示例 1: 过于模糊的 Skill + +### ❌ 不好的版本 + +```markdown +--- +name: helper +description: Helps with code +--- + +# Code Helper + +This skill helps you with coding tasks. + +## Usage + +Use this when you need help with code. + +## How It Works + +1. Analyzes your code +2. Provides suggestions +3. Helps improve it +``` + +### 问题分析 + +| 问题 | 说明 | 影响 | +|------|------|------| +| **模糊的名称** | "helper" 太泛化,没有说明具体做什么 | Claude 不知道何时激活 | +| **无关键词** | description 缺少具体触发词 | 用户很难激活这个 Skill | +| **无具体场景** | 没说明适用什么类型的代码 | 适用范围不清 | +| **抽象的步骤** | "Provides suggestions" 太模糊 | Claude 不知道具体做什么 | +| **无示例** | 没有实际例子 | 用户和 Claude 都不清楚预期输出 | + +### ✅ 改进版本 + +```markdown +--- +name: python-code-refactoring +description: Refactors Python code to improve readability and maintainability using standard patterns. Activates when user asks to clean up code, improve structure, or mentions refactoring. Focuses on function extraction, variable naming, and removing code smells. +--- + +# Python Code Refactoring Skill + +Improves Python code quality through systematic refactoring. + +## When to Use This Skill + +- User asks to "refactor this code", "clean up this function", or "improve readability" +- User mentions "code smell", "technical debt", or "maintainability" +- User is working with Python code that has: + - Long functions (>50 lines) + - Nested conditionals (>3 levels) + - Repeated code patterns + - Unclear variable names + +## How It Works + +### 1. Identify Refactoring Opportunities + +Scan code for common issues: +- Functions longer than 50 lines +- Repeated code blocks (DRY violations) +- Magic numbers without constants +- Unclear variable names (x, temp, data) +- Deep nesting (>3 levels) + +### 2. Prioritize Changes + +Focus on high-impact refactorings: +- **High**: Extract complex nested logic to functions +- **Medium**: Rename unclear variables +- **Low**: Minor style improvements + +### 3. Apply Refactorings + +**Extract Method**: +```python +# Before +def process_order(order): + # 50 lines of validation logic + # 30 lines of payment processing + # 20 lines of email notification + +# After +def process_order(order): + validate_order(order) + process_payment(order) + send_confirmation_email(order) +``` + +**Replace Magic Numbers**: +```python +# Before +if user.age < 18: + return False + +# After +MINIMUM_AGE = 18 +if user.age < MINIMUM_AGE: + return False +``` + +**Simplify Conditionals**: +```python +# Before +if user.role == 'admin': + return True +elif user.role == 'moderator': + return True +elif user.role == 'editor': + return True +else: + return False + +# After +PRIVILEGED_ROLES = {'admin', 'moderator', 'editor'} +return user.role in PRIVILEGED_ROLES +``` + +### 4. Verify Improvements + +After refactoring: +- Run existing tests (all must pass) +- Check code length reduced +- Verify improved readability + +## Example + +**User Request**: "Refactor this function, it's too long" + +```python +def process_user_registration(data): + if not data.get('email'): + return {'error': 'Email required'} + if '@' not in data['email']: + return {'error': 'Invalid email'} + if not data.get('password'): + return {'error': 'Password required'} + if len(data['password']) < 8: + return {'error': 'Password too short'} + if not any(c.isupper() for c in data['password']): + return {'error': 'Password needs uppercase'} + existing = db.query(User).filter_by(email=data['email']).first() + if existing: + return {'error': 'Email already registered'} + salt = bcrypt.gensalt() + hashed = bcrypt.hashpw(data['password'].encode(), salt) + user = User(email=data['email'], password_hash=hashed) + db.add(user) + db.commit() + token = jwt.encode({'user_id': user.id}, SECRET_KEY) + send_email(data['email'], 'Welcome!', 'Thanks for registering') + return {'success': True, 'token': token} +``` + +**Refactored**: + +```python +def process_user_registration(data): + """Register new user with validation and email confirmation.""" + # Validation + validation_error = validate_registration_data(data) + if validation_error: + return {'error': validation_error} + + # Check uniqueness + if user_exists(data['email']): + return {'error': 'Email already registered'} + + # Create user + user = create_user(data['email'], data['password']) + + # Generate token + token = generate_auth_token(user.id) + + # Send welcome email + send_welcome_email(user.email) + + return {'success': True, 'token': token} + + +def validate_registration_data(data): + """Validate registration data, return error message or None.""" + if not data.get('email'): + return 'Email required' + if '@' not in data['email']: + return 'Invalid email' + if not data.get('password'): + return 'Password required' + return validate_password_strength(data['password']) + + +def validate_password_strength(password): + """Check password meets security requirements.""" + MIN_PASSWORD_LENGTH = 8 + if len(password) < MIN_PASSWORD_LENGTH: + return f'Password must be at least {MIN_PASSWORD_LENGTH} characters' + if not any(c.isupper() for c in password): + return 'Password must contain uppercase letter' + return None + + +def user_exists(email): + """Check if user with given email already exists.""" + return db.query(User).filter_by(email=email).first() is not None + + +def create_user(email, password): + """Create and save new user with hashed password.""" + salt = bcrypt.gensalt() + hashed = bcrypt.hashpw(password.encode(), salt) + user = User(email=email, password_hash=hashed) + db.add(user) + db.commit() + return user + + +def generate_auth_token(user_id): + """Generate JWT authentication token.""" + return jwt.encode({'user_id': user_id}, SECRET_KEY) + + +def send_welcome_email(email): + """Send welcome email to new user.""" + send_email(email, 'Welcome!', 'Thanks for registering') +``` + +**Improvements**: +- ✅ Main function reduced from 20 lines to 15 lines +- ✅ Each function has single responsibility +- ✅ Magic number (8) extracted to constant +- ✅ All functions documented with docstrings +- ✅ Easier to test individual functions +- ✅ Easier to modify validation rules + +## Best Practices + +- ✅ Extract functions with clear names +- ✅ Use constants instead of magic numbers +- ✅ Keep functions under 30 lines +- ✅ Maximum nesting depth of 2-3 levels +- ✅ Write docstrings for extracted functions +``` + +### 改进要点 + +1. ✅ 具体的名称: `python-code-refactoring` 而非 `helper` +2. ✅ 详细的 description: 包含触发词和适用场景 +3. ✅ 明确的触发条件: 列出具体的使用场景 +4. ✅ 可执行的步骤: 每个步骤都有具体操作 +5. ✅ 实际代码示例: 展示完整的重构过程 +6. ✅ 具体的改进指标: 列出可验证的改进效果 + +--- + +## 示例 2: 过度冗长的 Skill + +### ❌ 不好的版本 + +```markdown +--- +name: python-basics +description: Teaches Python programming basics +--- + +# Python Basics + +This skill helps you learn Python programming. + +## Variables + +In Python, you can create variables like this: + +```python +x = 5 +y = "hello" +z = 3.14 +``` + +Python supports different data types: +- Integers (int): whole numbers like 1, 2, 3 +- Floats (float): decimal numbers like 3.14, 2.5 +- Strings (str): text like "hello", 'world' +- Booleans (bool): True or False + +## Conditional Statements + +You can use if statements to make decisions: + +```python +if x > 0: + print("Positive") +elif x < 0: + print("Negative") +else: + print("Zero") +``` + +The if statement checks a condition. If True, it runs the indented code. +The elif means "else if" and provides an alternative condition. +The else runs if none of the above conditions are True. + +## Loops + +Python has two main types of loops: + +### For Loops + +For loops iterate over a sequence: + +```python +for i in range(5): + print(i) +``` + +This prints numbers 0 through 4. The range() function generates numbers. + +### While Loops + +While loops continue while a condition is True: + +```python +i = 0 +while i < 5: + print(i) + i += 1 +``` + +This does the same thing as the for loop above. + +## Functions + +Functions are reusable blocks of code: + +```python +def greet(name): + return f"Hello, {name}!" +``` + +The def keyword defines a function. The function name is greet. +It takes one parameter called name. The return statement sends back a value. + +## Lists + +Lists store multiple items: + +```python +fruits = ["apple", "banana", "orange"] +``` + +You can access items by index: + +```python +first_fruit = fruits[0] # "apple" +``` + +... [continues for 50 more sections about Python basics] +``` + +### 问题分析 + +| 问题 | 说明 | 影响 | +|------|------|------| +| **包含通用知识** | Python 基础知识 Claude 已经知道 | 浪费 token,增加检索成本 | +| **教程式内容** | 像教程而非工作指南 | Claude 不需要学习,需要的是工作指导 | +| **过度详细** | 解释显而易见的概念 | 信息过载,难以找到关键信息 | +| **缺少项目特定信息** | 没有项目相关的规范或约定 | 无法提供项目特定价值 | + +### ✅ 改进版本 + +```markdown +--- +name: project-python-conventions +description: Enforces Python coding conventions specific to this project. Activates when user writes Python code or asks about code style. Covers naming, imports, error handling, and project-specific patterns. +--- + +# Project Python Conventions + +Project-specific Python coding standards and patterns. + +## When to Use This Skill + +- User is writing or reviewing Python code +- User asks about code style or conventions +- User needs guidance on project patterns + +## Import Organization + +Follow this order: + +```python +# 1. Standard library +import os +import sys +from typing import Optional, List + +# 2. Third-party packages +import numpy as np +from fastapi import FastAPI + +# 3. Local application imports +from core.models import User +from utils.helpers import format_date +``` + +## Naming Conventions + +### Project-Specific Rules + +| Type | Pattern | Example | +|------|---------|---------| +| API endpoints | `/api/v1/{resource}` | `/api/v1/users` | +| Database tables | `{resource}_table` | `users_table` | +| Environment variables | `APP_{NAME}` | `APP_DATABASE_URL` | +| Config files | `{env}.config.py` | `prod.config.py` | + +### Forbidden Patterns + +```python +# ❌ Don't use single-letter variables (except i, j, k in loops) +d = get_data() + +# ✅ Do use descriptive names +user_data = get_data() + +# ❌ Don't use abbreviations +usr_mgr = UserManager() + +# ✅ Do use full words +user_manager = UserManager() +``` + +## Error Handling Pattern + +Use project's custom exceptions: + +```python +from core.exceptions import UserNotFoundError, ValidationError + +def get_user(user_id: int) -> User: + """ + Retrieve user by ID. + + Raises: + UserNotFoundError: If user doesn't exist + ValidationError: If user_id is invalid + """ + if not isinstance(user_id, int) or user_id <= 0: + raise ValidationError(f"Invalid user_id: {user_id}") + + user = db.query(User).get(user_id) + if user is None: + raise UserNotFoundError(f"User {user_id} not found") + + return user +``` + +**Never** use bare `except:` - always catch specific exceptions. + +## Database Queries + +Always use the project's query helper: + +```python +# ❌ Don't use raw SQLAlchemy queries +users = db.query(User).filter(User.age > 18).all() + +# ✅ Do use query helper +from core.database import QueryBuilder + +users = QueryBuilder(User).where('age', '>', 18).get() +``` + +## API Response Format + +All API endpoints must return this format: + +```python +{ + "success": True, + "data": { + # ... response data + }, + "error": None, + "meta": { + "timestamp": "2025-01-31T12:00:00Z", + "version": "1.0" + } +} +``` + +Use the response helper: + +```python +from core.responses import success_response, error_response + +@app.get("/users/{id}") +async def get_user(id: int): + try: + user = get_user_data(id) + return success_response(user) + except UserNotFoundError as e: + return error_response(str(e), status_code=404) +``` + +## Testing Patterns + +### Test File Location + +``` +project/ +├── src/ +│ └── services/ +│ └── user_service.py +└── tests/ + └── services/ + └── test_user_service.py +``` + +### Test Naming + +```python +# Format: test_{function_name}_{scenario}_{expected_result} + +def test_get_user_valid_id_returns_user(): + """Test getting user with valid ID returns User object.""" + pass + +def test_get_user_invalid_id_raises_validation_error(): + """Test getting user with invalid ID raises ValidationError.""" + pass + +def test_get_user_nonexistent_id_raises_not_found_error(): + """Test getting non-existent user raises UserNotFoundError.""" + pass +``` + +## References + +- [Full Style Guide](docs/STYLE_GUIDE.md) +- [API Standards](docs/API_STANDARDS.md) +- [Database Conventions](docs/DATABASE.md) +``` + +### 改进要点 + +1. ✅ 只包含项目特定信息: 不教 Python 基础 +2. ✅ 简洁明了: 200 行 vs 原来的 500+ 行 +3. ✅ 实用的规则: 直接可应用的约定 +4. ✅ 清晰的示例: Do/Don't 对比 +5. ✅ 引用详细文档: 用链接而非全部内容 + +--- + +## 示例 3: 缺少上下文的 Skill + +### ❌ 不好的版本 + +```markdown +--- +name: deployment +description: Deploys code +--- + +# Deployment + +## Steps + +1. Build the code +2. Run tests +3. Deploy to server +4. Verify deployment +``` + +### 问题分析 + +| 问题 | 说明 | 影响 | +|------|------|------| +| **无具体命令** | 没说明如何 build, test, deploy | Claude 无法执行 | +| **无环境区分** | 开发、测试、生产部署可能不同 | 可能部署到错误环境 | +| **无错误处理** | 没说明出错时怎么办 | 失败时不知如何恢复 | +| **无验证标准** | "Verify" 太模糊 | 不知道检查什么 | + +### ✅ 改进版本 + +```markdown +--- +name: deploy-to-production +description: Deploys application to production environment on AWS. Activates when user asks to deploy to prod or mentions production deployment. Includes pre-flight checks, blue-green deployment, and rollback procedures. +--- + +# Production Deployment + +Safely deploy application to production with zero downtime. + +## When to Use This Skill + +- User asks to "deploy to production" or "push to prod" +- User mentions "production deployment", "go live" +- User needs to rollback a deployment + +## Prerequisites + +Before deployment, verify: + +```bash +# 1. On main branch +git branch --show-current # Must be "main" + +# 2. All tests pass +npm test # Exit code must be 0 + +# 3. Build succeeds +npm run build # Must complete without errors + +# 4. No uncommitted changes +git status # Must show "nothing to commit" + +# 5. Latest code pulled +git pull origin main # Must be up to date +``` + +If any prerequisite fails, **stop** and fix the issue. + +## Deployment Process + +### Step 1: Pre-flight Checks + +```bash +# Run deployment readiness script +./scripts/preflight-check.sh + +# Expected output: +# ✓ Tests passed +# ✓ Build succeeded +# ✓ Environment variables configured +# ✓ Database migrations ready +# ✓ Ready to deploy +``` + +### Step 2: Database Migrations (if needed) + +```bash +# Connect to production database +aws rds describe-db-instances --db-instance-identifier prod-db + +# Backup before migration +./scripts/backup-database.sh prod + +# Run migrations +NODE_ENV=production npm run migrate + +# Verify migration succeeded +npm run migrate:status +``` + +### Step 3: Blue-Green Deployment + +```bash +# Deploy to green environment (inactive) +aws elasticbeanstalk create-environment \ + --application-name myapp \ + --environment-name myapp-prod-green \ + --solution-stack-name "64bit Amazon Linux 2 v5.x.x running Node.js 18" + +# Wait for green environment to be healthy +aws elasticbeanstalk wait environment-updated \ + --environment-name myapp-prod-green + +# Check green environment health +curl https://myapp-prod-green.aws.com/health +# Expected: {"status": "healthy"} +``` + +### Step 4: Smoke Tests + +```bash +# Run smoke tests against green environment +BASE_URL=https://myapp-prod-green.aws.com npm run test:smoke + +# Tests must include: +# - Health check endpoint +# - Authentication flow +# - Critical API endpoints +# - Database connectivity +``` + +### Step 5: Switch Traffic + +```bash +# Swap URLs (blue becomes green, green becomes blue) +aws elasticbeanstalk swap-environment-cnames \ + --source-environment-name myapp-prod-blue \ + --destination-environment-name myapp-prod-green + +# Wait 5 minutes for DNS propagation +echo "Waiting for DNS propagation..." +sleep 300 + +# Verify production URL serves new version +curl https://myapp.com/version +# Expected: {"version": "1.2.3"} (new version) +``` + +### Step 6: Monitor + +```bash +# Monitor error rates for 15 minutes +aws cloudwatch get-metric-statistics \ + --namespace AWS/ELB \ + --metric-name HTTPCode_Backend_5XX \ + --start-time $(date -u -d '15 minutes ago' +%Y-%m-%dT%H:%M:%S) \ + --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \ + --period 300 \ + --statistics Sum + +# Error rate must be < 1% +``` + +If error rate exceeds 1%: +- **Rollback immediately** (see Rollback section) +- Investigate issue +- Fix and redeploy + +### Step 7: Cleanup + +```bash +# After 24 hours, if no issues: +# Terminate old blue environment +aws elasticbeanstalk terminate-environment \ + --environment-name myapp-prod-blue +``` + +## Rollback Procedure + +If deployment fails: + +```bash +# 1. Swap back to previous version +aws elasticbeanstalk swap-environment-cnames \ + --source-environment-name myapp-prod-green \ + --destination-environment-name myapp-prod-blue + +# 2. Verify old version is serving +curl https://myapp.com/version +# Expected: {"version": "1.2.2"} (old version) + +# 3. Rollback database migrations (if ran) +NODE_ENV=production npm run migrate:rollback + +# 4. Notify team +./scripts/notify-rollback.sh "Deployment rolled back due to [reason]" +``` + +## Example Deployment + +**User Request**: "Deploy v1.2.3 to production" + +**Execution Log**: + +``` +[14:00:00] Starting deployment of v1.2.3 to production +[14:00:05] ✓ Pre-flight checks passed +[14:00:10] ✓ Database backup completed +[14:00:30] ✓ Database migrations applied (3 migrations) +[14:01:00] → Creating green environment +[14:05:00] ✓ Green environment healthy +[14:05:30] ✓ Smoke tests passed (12/12) +[14:06:00] → Switching traffic to green environment +[14:11:00] ✓ DNS propagated +[14:11:05] ✓ Production serving v1.2.3 +[14:11:10] → Monitoring for 15 minutes +[14:26:10] ✓ Error rate: 0.05% (within threshold) +[14:26:15] ✓ Deployment successful +[14:26:20] → Old environment will be terminated in 24h + +Deployment completed successfully in 26 minutes +``` + +## References + +- [AWS Deployment Guide](docs/AWS_DEPLOYMENT.md) +- [Runbook](docs/RUNBOOK.md) +- [On-Call Procedures](docs/ONCALL.md) +``` + +### 改进要点 + +1. ✅ 具体命令: 每个步骤都有可执行的命令 +2. ✅ 环境明确: 专注于生产环境部署 +3. ✅ 验证标准: 说明检查什么和预期结果 +4. ✅ 错误处理: 包含完整的回滚流程 +5. ✅ 实际输出: 展示命令的预期输出 +6. ✅ 监控指标: 定义具体的成功标准 + +--- + +## 常见错误总结 + +### 1. 命名和描述问题 + +| 错误 | 示例 | 改进 | +|------|------|------| +| 过于泛化 | `name: helper` | `name: python-type-hints` | +| 缺少关键词 | `description: Helps with code` | `description: Adds type hints to Python using mypy` | +| 使用第一人称 | `description: I help you...` | `description: Adds type hints...` | + +### 2. 内容问题 + +| 错误 | 说明 | 改进 | +|------|------|------| +| 包含通用知识 | 教 Python 基础语法 | 只包含项目特定规范 | +| 过于抽象 | "分析代码并提供建议" | "检查函数长度、变量命名、重复代码" | +| 缺少示例 | 只有文字描述 | 包含输入-输出示例 | + +### 3. 结构问题 + +| 错误 | 说明 | 改进 | +|------|------|------| +| 无层次结构 | 所有内容混在一起 | 使用标题、列表、代码块组织 | +| 缺少"When to Use" | 不知道何时激活 | 列出 3-5 个触发场景 | +| 无验证步骤 | 不知道如何确认成功 | 说明检查项和预期结果 | + +### 4. 自由度问题 + +| 错误 | 说明 | 改进 | +|------|------|------| +| 创意任务低自由度 | 为架构设计提供分步指令 | 提供指导原则和考虑因素 | +| 危险任务高自由度 | 生产部署没有具体步骤 | 提供详细的检查清单 | +| 不匹配任务类型 | 代码生成用教程式内容 | 提供模板和实际示例 | + +--- + +## 快速检查清单 + +在发布 Skill 之前,问自己: + +### 基础检查 + +- [ ] Name 是否具体且描述性强? +- [ ] Description 包含触发关键词和场景? +- [ ] 有明确的"When to Use"章节? +- [ ] 内容只包含 Claude 不知道的信息? + +### 内容检查 + +- [ ] 是否有实际的代码示例? +- [ ] 步骤是否具体可执行? +- [ ] 是否说明了如何验证成功? +- [ ] 是否包含错误处理指导? + +### 结构检查 + +- [ ] 内容组织清晰(使用标题、列表)? +- [ ] 自由度设定合适(匹配任务类型)? +- [ ] 长度合适(200-500行,或拆分子文件)? +- [ ] 包含 Do/Don't 最佳实践? + +如果有任何一项答"否",参考本文档的改进建议进行修改。 \ No newline at end of file diff --git a/.claude/Skills/create-skill-file/examples/good-example.md b/.claude/Skills/create-skill-file/examples/good-example.md new file mode 100644 index 000000000..e3016a1f2 --- /dev/null +++ b/.claude/Skills/create-skill-file/examples/good-example.md @@ -0,0 +1,908 @@ +# 好的 Skill 示例 + +本文档展示几个编写良好的 SKILL.md 示例,说明最佳实践的实际应用。 + +--- + +## 示例 1: 数据库迁移 Skill (高质量基础 Skill) + +```markdown +--- +name: database-migration +description: Manages database schema migrations using Alembic for SQLAlchemy projects. Activates when user asks to create migrations, upgrade/downgrade database, or mentions Alembic. Handles both development and production scenarios with safety checks. +--- + +# Database Migration Skill + +Automates database schema migration management using Alembic. + +## When to Use This Skill + +- User asks to "create migration", "update database schema", or "rollback migration" +- User mentions "Alembic", "database migration", or "schema change" +- User is working in a Python project with SQLAlchemy models +- User needs to apply or revert database changes + +## Quick Start + +Create a new migration: +```bash +alembic revision --autogenerate -m "Description of changes" +``` + +Apply migrations: +```bash +alembic upgrade head +``` + +## How It Works + +### Creating Migrations + +1. **Detect model changes** + - Scan SQLAlchemy models in `models/` directory + - Compare with current database schema + - Identify additions, modifications, deletions + +2. **Generate migration script** + - Run `alembic revision --autogenerate` + - Review generated script for accuracy + - Edit if necessary (Alembic can't auto-detect everything) + +3. **Verify migration** + - Check upgrade() function is correct + - Ensure downgrade() function reverses changes + - Test on development database first + +### Applying Migrations + +1. **Safety checks** + - Backup database (production only) + - Verify no pending migrations + - Check database connectivity + +2. **Execute migration** + - Run `alembic upgrade head` + - Monitor for errors + - Verify schema matches expected state + +3. **Post-migration validation** + - Run application tests + - Check data integrity + - Confirm application starts successfully + +## Examples + +### Example 1: Add New Column + +**User Request**: "Add an email column to the users table" + +**Step 1**: Update the model +```python +# models/user.py +class User(Base): + __tablename__ = 'users' + id = Column(Integer, primary_key=True) + username = Column(String(50), nullable=False) + email = Column(String(120), nullable=True) # ← New field +``` + +**Step 2**: Generate migration +```bash +alembic revision --autogenerate -m "Add email column to users table" +``` + +**Generated migration** (alembic/versions/abc123_add_email.py): +```python +def upgrade(): + op.add_column('users', sa.Column('email', sa.String(120), nullable=True)) + +def downgrade(): + op.drop_column('users', 'email') +``` + +**Step 3**: Review and apply +```bash +# Review the migration file +cat alembic/versions/abc123_add_email.py + +# Apply migration +alembic upgrade head +``` + +**Output**: +``` +INFO [alembic.runtime.migration] Running upgrade xyz789 -> abc123, Add email column to users table +``` + +### Example 2: Complex Migration with Data Changes + +**User Request**: "Split the 'name' column into 'first_name' and 'last_name'" + +**Step 1**: Create empty migration (can't auto-generate data changes) +```bash +alembic revision -m "Split name into first_name and last_name" +``` + +**Step 2**: Write custom migration +```python +def upgrade(): + # Add new columns + op.add_column('users', sa.Column('first_name', sa.String(50))) + op.add_column('users', sa.Column('last_name', sa.String(50))) + + # Migrate existing data + connection = op.get_bind() + users = connection.execute("SELECT id, name FROM users") + for user_id, name in users: + parts = name.split(' ', 1) + first = parts[0] + last = parts[1] if len(parts) > 1 else '' + connection.execute( + "UPDATE users SET first_name = %s, last_name = %s WHERE id = %s", + (first, last, user_id) + ) + + # Make new columns non-nullable and drop old column + op.alter_column('users', 'first_name', nullable=False) + op.alter_column('users', 'last_name', nullable=False) + op.drop_column('users', 'name') + +def downgrade(): + # Add back name column + op.add_column('users', sa.Column('name', sa.String(100))) + + # Restore data + connection = op.get_bind() + users = connection.execute("SELECT id, first_name, last_name FROM users") + for user_id, first, last in users: + full_name = f"{first} {last}".strip() + connection.execute( + "UPDATE users SET name = %s WHERE id = %s", + (full_name, user_id) + ) + + op.alter_column('users', 'name', nullable=False) + op.drop_column('users', 'first_name') + op.drop_column('users', 'last_name') +``` + +**Step 3**: Test thoroughly +```bash +# Apply migration +alembic upgrade head + +# Verify data +python -c "from models import User; print(User.query.first().first_name)" + +# Test rollback +alembic downgrade -1 +python -c "from models import User; print(User.query.first().name)" + +# Reapply +alembic upgrade head +``` + +## Best Practices + +### Do + +- ✅ Always review auto-generated migrations before applying +- ✅ Test migrations on development database first +- ✅ Write reversible downgrade() functions +- ✅ Backup production databases before major migrations +- ✅ Use meaningful migration messages + +### Don't + +- ❌ Trust auto-generated migrations blindly +- ❌ Skip downgrade() implementation +- ❌ Apply untested migrations to production +- ❌ Modify existing migration files after they're committed +- ❌ Use raw SQL without bind parameters + +## Troubleshooting + +### "Target database is not up to date" + +**Problem**: Someone else applied migrations you don't have locally + +**Solution**: +```bash +git pull # Get latest migrations +alembic upgrade head # Apply them locally +``` + +### "Can't locate revision identified by 'xyz'" + +**Problem**: Migration file deleted or branch conflict + +**Solution**: +1. Check if migration file exists in `alembic/versions/` +2. If missing, restore from git history +3. If branch conflict, merge migration branches: + ```bash + alembic merge -m "Merge migration branches" head1 head2 + ``` + +### Migration fails mid-execution + +**Problem**: Error occurred during migration + +**Solution**: +1. Check error message for specifics +2. Manually fix database to consistent state if needed +3. Update migration script to fix the issue +4. Mark migration as completed or retry: + ```bash + # Mark as done without running + alembic stamp head + + # Or fix and retry + alembic upgrade head + ``` + +## Configuration + +### Project Structure +``` +project/ +├── alembic/ +│ ├── versions/ # Migration scripts +│ ├── env.py # Alembic environment +│ └── script.py.mako # Migration template +├── alembic.ini # Alembic configuration +└── models/ # SQLAlchemy models + ├── __init__.py + ├── user.py + └── post.py +``` + +### alembic.ini Configuration +```ini +[alembic] +script_location = alembic +sqlalchemy.url = driver://user:pass@localhost/dbname + +[loggers] +keys = root,sqlalchemy,alembic + +[logger_alembic] +level = INFO +handlers = console +qualname = alembic +``` + +## References + +- [Alembic Documentation](https://alembic.sqlalchemy.org/) +- [SQLAlchemy Documentation](https://docs.sqlalchemy.org/) +- [Project Migration Guidelines](docs/database-migrations.md) +``` + +### 为什么这是好的 Skill? + +1. ✅ **清晰的 description**: 包含触发关键词 ("Alembic", "create migrations") 和场景 ("SQLAlchemy projects") +2. ✅ **具体的触发条件**: "When to Use" 列出 4 个明确场景 +3. ✅ **分步工作流**: 每个操作都有清晰的 1-2-3 步骤 +4. ✅ **实际示例**: 包含简单和复杂两个示例,有完整代码 +5. ✅ **最佳实践**: Do/Don't 清单易于遵循 +6. ✅ **故障排除**: 覆盖 3 个常见问题及解决方案 +7. ✅ **项目特定信息**: 包含配置和目录结构 + +--- + +## 示例 2: API 文档生成 Skill (优秀的工作流 Skill) + +```markdown +--- +name: api-documentation-generation +description: Generates OpenAPI/Swagger documentation from FastAPI or Flask applications. Activates when user asks to create API docs, generate OpenAPI spec, or needs to document REST endpoints. Supports automatic extraction and custom annotations. +--- + +# API Documentation Generation Skill + +Automates creation of comprehensive API documentation from Python web applications. + +## When to Use This Skill + +- User asks to "generate API docs" or "create OpenAPI spec" +- User mentions "Swagger", "OpenAPI", "API documentation" +- User has a FastAPI or Flask application +- User needs to document REST API endpoints + +## Workflow + +### Phase 1: Discovery + +1. **Identify framework** + - Check for FastAPI: `from fastapi import FastAPI` in codebase + - Check for Flask: `from flask import Flask` in codebase + - Check for Flask-RESTful: `from flask_restful import Resource` + +2. **Locate API definitions** + - Scan for route decorators: `@app.get()`, `@app.post()`, `@app.route()` + - Find API routers and blueprints + - Identify request/response models + +3. **Extract metadata** + - Endpoint paths and HTTP methods + - Request parameters (path, query, body) + - Response schemas and status codes + - Authentication requirements + +### Phase 2: Enhancement + +1. **Review docstrings** + - Check if endpoints have docstrings + - Verify docstrings follow format (summary, description, params, returns) + - Flag missing documentation + +2. **Add missing docs** (if user approves) + - Generate docstrings based on type hints + - Infer descriptions from parameter names + - Add example requests/responses + +3. **Validate schemas** + - Ensure Pydantic models are well-documented + - Check for missing field descriptions + - Verify example values are provided + +### Phase 3: Generation + +1. **Generate OpenAPI spec** + ```bash + # For FastAPI + python -c "from main import app; import json; print(json.dumps(app.openapi()))" > openapi.json + + # For Flask with flasgger + python scripts/generate_swagger.py > swagger.json + ``` + +2. **Create Swagger UI** + - Copy Swagger UI static files to `docs/api/` + - Configure to load generated spec + - Test in browser: `http://localhost:8000/docs` + +3. **Generate Markdown docs** + - Use `openapi-to-md` to create human-readable docs + - Organize by tags/resource groups + - Add navigation and table of contents + +### Phase 4: Validation + +1. **Check completeness** + - All endpoints documented? + - All parameters described? + - Example requests provided? + +2. **Validate spec** + ```bash + openapi-spec-validator openapi.json + ``` + +3. **Test interactive docs** + - Try sample requests in Swagger UI + - Verify authentication flows work + - Check response schemas match actual responses + +## Examples + +### Example 1: FastAPI Application + +**User Request**: "Generate API documentation for my FastAPI app" + +**Discovery**: +``` +Found FastAPI application in: main.py +Endpoints discovered: +- GET /users (List users) +- POST /users (Create user) +- GET /users/{id} (Get user by ID) +- PUT /users/{id} (Update user) +- DELETE /users/{id} (Delete user) +``` + +**Enhancement**: +``` +Checking documentation coverage... +✓ GET /users - Well documented +✗ POST /users - Missing response examples +✗ GET /users/{id} - No description +✗ PUT /users/{id} - No description +✗ DELETE /users/{id} - No description + +Would you like me to add missing documentation? +``` + +**User**: Yes + +**Adding docs**: +```python +@app.get("/users/{id}", summary="Get user by ID") +async def get_user(id: int): + """ + Retrieve a single user by their unique ID. + + Args: + id: The unique identifier of the user + + Returns: + User object with id, name, email, and created_at fields + + Raises: + 404: User not found + """ + # ... implementation +``` + +**Generation**: +```bash +Generating OpenAPI specification... +✓ openapi.json created (15.2 KB) +✓ Swagger UI deployed to docs/api/ +✓ Markdown docs created in docs/api/endpoints/ + +View documentation at: http://localhost:8000/docs +``` + +### Example 2: Flask Application with Custom Schemas + +**User Request**: "Document my Flask API and include request/response examples" + +**Discovery**: +``` +Found Flask application with Flask-RESTful +Endpoints: +- GET /api/products +- POST /api/products +- GET /api/products/ +- PATCH /api/products/ +- DELETE /api/products/ +``` + +**Custom Examples Added**: +```python +class ProductList(Resource): + def get(self): + """ + Get all products + + Example Response: + ```json + { + "products": [ + { + "id": 1, + "name": "Widget", + "price": 29.99, + "stock": 100 + } + ], + "total": 1 + } + ``` + """ + pass + + def post(self): + """ + Create a new product + + Example Request: + ```json + { + "name": "New Widget", + "price": 39.99, + "stock": 50 + } + ``` + + Example Response: + ```json + { + "id": 2, + "name": "New Widget", + "price": 39.99, + "stock": 50, + "created_at": "2025-01-31T12:00:00Z" + } + ``` + """ + pass +``` + +**Result**: +``` +Generated documentation: +- openapi.json (with examples) +- Swagger UI at /api/docs +- Postman collection at docs/api/postman_collection.json +- Markdown API reference at docs/api/README.md + +All endpoints now include: +✓ Request examples +✓ Response examples +✓ Error codes +✓ Authentication requirements +``` + +## Configuration + +### FastAPI Projects + +No additional configuration needed! FastAPI auto-generates OpenAPI docs. + +Access at: +- Swagger UI: `http://localhost:8000/docs` +- ReDoc: `http://localhost:8000/redoc` +- OpenAPI JSON: `http://localhost:8000/openapi.json` + +### Flask Projects + +Install flasgger: +```bash +pip install flasgger +``` + +Configure in app: +```python +from flasgger import Swagger + +app = Flask(__name__) +swagger = Swagger(app, template={ + "info": { + "title": "My API", + "description": "API for managing resources", + "version": "1.0.0" + } +}) +``` + +## Best Practices + +- ✅ Use type hints - enables automatic schema generation +- ✅ Write descriptive docstrings for all endpoints +- ✅ Provide example requests and responses +- ✅ Document error codes and edge cases +- ✅ Keep docs in sync with code (auto-generate when possible) + +## Tools Used + +- **FastAPI**: Built-in OpenAPI support +- **flasgger**: Swagger for Flask +- **openapi-spec-validator**: Validates OpenAPI specs +- **openapi-to-md**: Converts OpenAPI to Markdown + +## References + +- [OpenAPI Specification](https://spec.openapis.org/oas/latest.html) +- [FastAPI Documentation](https://fastapi.tiangolo.com/) +- [Swagger Documentation](https://swagger.io/docs/) +``` + +### 为什么这是优秀的工作流 Skill? + +1. ✅ **清晰的工作流阶段**: 4 个阶段 (Discovery, Enhancement, Generation, Validation) +2. ✅ **决策点**: Phase 2 询问用户是否添加缺失文档 +3. ✅ **实际输出示例**: 展示了命令输出和生成的代码 +4. ✅ **多框架支持**: 处理 FastAPI 和 Flask 两种情况 +5. ✅ **工具集成**: 列出所需工具及其用途 +6. ✅ **可执行命令**: 提供完整的命令示例 +7. ✅ **验证步骤**: Phase 4 确保生成的文档质量 + +--- + +## 示例 3: 代码审查 Skill (高自由度 Skill) + +```markdown +--- +name: code-review +description: Performs comprehensive code reviews focusing on best practices, security, performance, and maintainability. Activates when user asks to review code, check pull request, or mentions code quality. Provides actionable feedback with severity ratings. +--- + +# Code Review Skill + +Conducts thorough code reviews with focus on quality, security, and best practices. + +## When to Use This Skill + +- User asks to "review my code" or "check this PR" +- User mentions "code review", "code quality", or "best practices" +- User wants feedback on specific code changes +- User needs security or performance analysis + +## Review Criteria + +Code is evaluated across 5 dimensions: + +### 1. Correctness +- Logic errors and bugs +- Edge case handling +- Error handling and validation +- Type safety + +### 2. Security +- SQL injection vulnerabilities +- XSS vulnerabilities +- Authentication/authorization issues +- Sensitive data exposure +- Dependency vulnerabilities + +### 3. Performance +- Algorithm efficiency +- Database query optimization +- Memory leaks +- Unnecessary computations +- Caching opportunities + +### 4. Maintainability +- Code clarity and readability +- Function/class size +- Code duplication +- Naming conventions +- Documentation + +### 5. Best Practices +- Language-specific idioms +- Design patterns +- SOLID principles +- Testing coverage +- Error handling patterns + +## Review Process + +1. **Understand context** + - What does this code do? + - What problem does it solve? + - Are there any constraints or requirements? + +2. **Identify issues** + - Scan for common anti-patterns + - Check against language best practices + - Look for security vulnerabilities + - Assess performance implications + +3. **Prioritize feedback** + - **Critical**: Security issues, data loss risks, crashes + - **High**: Bugs, major performance issues + - **Medium**: Code smells, maintainability concerns + - **Low**: Style preferences, minor optimizations + +4. **Provide suggestions** + - Explain the issue clearly + - Show better alternative (code example) + - Explain why the alternative is better + +## Example Review + +### Code Submitted + +```python +def get_user_data(user_id): + conn = sqlite3.connect('users.db') + cursor = conn.cursor() + query = "SELECT * FROM users WHERE id = " + str(user_id) + cursor.execute(query) + result = cursor.fetchone() + return result +``` + +### Review Feedback + +**❌ CRITICAL: SQL Injection Vulnerability** + +The code concatenates user input directly into SQL query, allowing SQL injection attacks. + +**Bad**: +```python +query = "SELECT * FROM users WHERE id = " + str(user_id) +``` + +**Good**: +```python +query = "SELECT * FROM users WHERE id = ?" +cursor.execute(query, (user_id,)) +``` + +**Why**: Parameterized queries prevent SQL injection by properly escaping user input. + +--- + +**⚠️ HIGH: Resource Leak** + +Database connection is never closed, leading to resource exhaustion under load. + +**Bad**: +```python +conn = sqlite3.connect('users.db') +# ... use connection +# connection never closed +``` + +**Good**: +```python +with sqlite3.connect('users.db') as conn: + cursor = conn.cursor() + # ... use connection + # automatically closed when exiting with block +``` + +--- + +**ℹ️ MEDIUM: Overly Broad SELECT** + +Using `SELECT *` fetches unnecessary data and is fragile to schema changes. + +**Bad**: +```python +query = "SELECT * FROM users WHERE id = ?" +``` + +**Good**: +```python +query = "SELECT id, name, email FROM users WHERE id = ?" +``` + +**Why**: Explicit column selection is more efficient and makes intent clear. + +--- + +**📝 LOW: Missing Error Handling** + +Function doesn't handle case where user doesn't exist. + +**Suggestion**: +```python +def get_user_data(user_id: int) -> Optional[dict]: + """ + Retrieve user data by ID. + + Args: + user_id: The unique identifier of the user + + Returns: + Dictionary with user data, or None if user not found + """ + with sqlite3.connect('users.db') as conn: + cursor = conn.cursor() + query = "SELECT id, name, email FROM users WHERE id = ?" + cursor.execute(query, (user_id,)) + result = cursor.fetchone() + + if result is None: + return None + + return { + 'id': result[0], + 'name': result[1], + 'email': result[2] + } +``` + +### Revised Code + +After applying all suggestions: + +```python +from typing import Optional +import sqlite3 + +def get_user_data(user_id: int) -> Optional[dict]: + """ + Retrieve user data by ID. + + Args: + user_id: The unique identifier of the user + + Returns: + Dictionary with user data, or None if user not found + + Raises: + ValueError: If user_id is not a positive integer + """ + if not isinstance(user_id, int) or user_id <= 0: + raise ValueError(f"Invalid user_id: {user_id}") + + with sqlite3.connect('users.db') as conn: + conn.row_factory = sqlite3.Row # Enable dict-like access + cursor = conn.cursor() + + query = "SELECT id, name, email, created_at FROM users WHERE id = ?" + cursor.execute(query, (user_id,)) + result = cursor.fetchone() + + if result is None: + return None + + return dict(result) # Convert Row to dict +``` + +### Summary + +**Issues Found**: 4 +- 1 Critical (SQL Injection) +- 1 High (Resource Leak) +- 1 Medium (Inefficient Query) +- 1 Low (Missing Error Handling) + +**All Issues Addressed**: ✓ + +## Best Practices + +### When Reviewing + +- 🎯 Focus on impact - prioritize critical issues +- 📝 Be specific - provide code examples +- 🎓 Be educational - explain why, not just what +- 🤝 Be constructive - suggest improvements, don't just criticize +- ⚖️ Be balanced - acknowledge good practices too + +### What to Look For + +**Python-specific**: +- Use of `with` for resource management +- Type hints on function signatures +- Proper exception handling +- List comprehensions vs loops +- Dictionary vs if-elif chains + +**General**: +- DRY principle violations +- Magic numbers +- Long functions (>50 lines) +- Deep nesting (>3 levels) +- Missing tests for critical paths + +## Automated Tools + +Complement manual review with automated tools: + +```bash +# Linting +pylint mycode.py +flake8 mycode.py + +# Type checking +mypy mycode.py + +# Security scanning +bandit -r . +safety check + +# Code complexity +radon cc mycode.py -a +``` + +## References + +- [OWASP Top 10](https://owasp.org/www-project-top-ten/) +- [Python Best Practices](https://docs.python-guide.org/) +- [Clean Code Principles](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882) +``` + +### 为什么这是高自由度 Skill? + +1. ✅ **指导原则而非严格步骤**: 提供评审维度,不限定具体流程 +2. ✅ **情境适应**: 根据代码类型和问题严重性调整重点 +3. ✅ **教育性**: 解释"为什么",帮助 Claude 做出判断 +4. ✅ **优先级框架**: 定义严重性级别,让 Claude 自行判断 +5. ✅ **完整示例**: 展示从问题识别到解决的完整流程 +6. ✅ **工具集成**: 提到自动化工具,但不强制使用 + +--- + +## 总结: 好 Skill 的共同特征 + +| 特征 | 说明 | 示例位置 | +|------|------|---------| +| **清晰触发** | description 包含关键词和场景 | 所有 frontmatter | +| **结构化内容** | 使用标题、列表、代码块组织信息 | 所有示例 | +| **实际示例** | 真实代码,不是伪代码 | Example sections | +| **决策指导** | 告诉 Claude 何时做什么 | 工作流 Skill 的 Phase 2 | +| **可执行命令** | 提供完整的命令,不是抽象描述 | 迁移 Skill 的命令 | +| **错误处理** | 包含故障排除章节 | 所有 Troubleshooting | +| **最佳实践** | Do/Don't 清单 | 所有 Best Practices | +| **工具引用** | 说明使用哪些工具及如何使用 | API 文档 Skill | +| **验证步骤** | 说明如何确认操作成功 | 迁移 Skill 的验证 | +| **合适的自由度** | 根据任务特性选择指导程度 | 代码审查 Skill | diff --git a/.claude/Skills/create-skill-file/templates/basic-skill-template.md b/.claude/Skills/create-skill-file/templates/basic-skill-template.md new file mode 100644 index 000000000..8ff71762d --- /dev/null +++ b/.claude/Skills/create-skill-file/templates/basic-skill-template.md @@ -0,0 +1,95 @@ +--- +name: your-skill-name +description: Brief description of what this skill does and when to activate it. Include trigger keywords and scenarios where this skill should be used. +--- + +# Your Skill Title + +> Brief one-line summary of what this skill accomplishes + +## When to Use This Skill + +- User asks to [specific action or task] +- User mentions keywords like "[keyword1]", "[keyword2]", or "[keyword3]" +- User is working with [specific technology/framework/tool] +- User needs to [specific outcome or goal] + +## Quick Start + +```bash +# Basic usage example +command-to-run --option value +``` + +## How It Works + +1. **Step 1**: Brief description of first step + - Detail about what happens + - Any prerequisites or conditions + +2. **Step 2**: Brief description of second step + - Key actions taken + - Expected outputs + +3. **Step 3**: Brief description of final step + - Validation or verification + - Success criteria + +## Examples + +### Example 1: Basic Usage + +**User Request**: "Example of what user might say" + +**Action**: What Claude does in response + +**Output**: +``` +Expected output or result +``` + +### Example 2: Advanced Usage + +**User Request**: "More complex user request" + +**Action**: +1. First action taken +2. Second action taken +3. Final action + +**Output**: +``` +Expected output showing more complex results +``` + +## Best Practices + +- ✅ Do this for best results +- ✅ Follow this pattern +- ❌ Avoid this common mistake +- ❌ Don't do this + +## Troubleshooting + +### Common Issue 1 + +**Problem**: Description of the problem + +**Solution**: How to fix it + +### Common Issue 2 + +**Problem**: Description of another problem + +**Solution**: Steps to resolve + +## References + +- [Related Documentation](link-to-docs) +- [Official Guide](link-to-guide) +- [Additional Resources](link-to-resources) + +--- + +**Version**: 1.0 +**Last Updated**: YYYY-MM-DD \ No newline at end of file diff --git a/.claude/Skills/create-skill-file/templates/workflow-skill-template.md b/.claude/Skills/create-skill-file/templates/workflow-skill-template.md new file mode 100644 index 000000000..6fd6522ba --- /dev/null +++ b/.claude/Skills/create-skill-file/templates/workflow-skill-template.md @@ -0,0 +1,402 @@ +--- +name: your-workflow-skill +description: Guides Claude through a multi-step workflow for [specific task]. Activates when user needs to [trigger scenario] or mentions [key terms]. +--- + +# Your Workflow Skill Title + +> Automates a complex multi-step process with decision points and validation + +## When to Use This Skill + +- User needs to execute a multi-step workflow +- User asks to "[workflow trigger phrase]" +- User is working on [specific type of project or task] +- Task requires validation and error handling at each step + +## Workflow Overview + +``` +┌─────────────┐ +│ Start │ +└──────┬──────┘ + │ + ▼ +┌─────────────────┐ +│ Preparation │ +│ & Validation │ +└────────┬────────┘ + │ + ┌────▼────┐ + │ Step 1 │ + └────┬────┘ + │ + ┌────▼────┐ + │ Step 2 │──┐ + └────┬────┘ │ (Loop if needed) + │ │ + └───────┘ + │ + ┌────▼────┐ + │ Step 3 │ + └────┬────┘ + │ + ▼ + ┌─────────────┐ + │ Complete │ + │ & Report │ + └─────────────┘ +``` + +## Detailed Workflow + +### Preparation Phase + +Before starting the main workflow: + +- [ ] Check prerequisite 1 +- [ ] Validate prerequisite 2 +- [ ] Ensure prerequisite 3 is met + +If any prerequisite fails: +- Stop execution +- Report which prerequisite failed +- Provide remediation steps + +### Step 1: [Step Name] + +**Purpose**: What this step accomplishes + +**Actions**: +1. Action 1 +2. Action 2 +3. Action 3 + +**Validation**: +- Check condition 1 +- Verify condition 2 + +**On Success**: → Proceed to Step 2 +**On Failure**: → [Error handling procedure] + +### Step 2: [Step Name] + +**Purpose**: What this step accomplishes + +**Actions**: +1. Action 1 +2. Action 2 + +**Decision Point**: +- If condition A: → Action X +- If condition B: → Action Y +- Otherwise: → Default action + +**Validation**: +- Verify expected output +- Check for errors + +**On Success**: → Proceed to Step 3 +**On Failure**: → [Error handling procedure] + +### Step 3: [Step Name] + +**Purpose**: Final actions and cleanup + +**Actions**: +1. Finalize changes +2. Run validation tests +3. Generate summary report + +**Success Criteria**: +- All tests pass +- No errors in logs +- Expected artifacts created + +## Examples + +### Example 1: Standard Workflow Execution + +**User Request**: "Run the [workflow name]" + +**Execution**: + +**Preparation Phase** ✓ +``` +✓ Prerequisite 1 met +✓ Prerequisite 2 validated +✓ Ready to begin +``` + +**Step 1: [Step Name]** ✓ +``` +→ Action 1 completed +→ Action 2 completed +→ Validation passed +``` + +**Step 2: [Step Name]** ✓ +``` +→ Decision: Condition A detected +→ Executing Action X +→ Validation passed +``` + +**Step 3: [Step Name]** ✓ +``` +→ Finalization complete +→ All tests passed +→ Summary generated +``` + +**Result**: Workflow completed successfully + +### Example 2: Workflow with Error Recovery + +**User Request**: "Execute [workflow name]" + +**Execution**: + +**Step 1** ✓ +``` +→ Completed successfully +``` + +**Step 2** ⚠️ +``` +→ Action 1 completed +→ Action 2 failed: [Error message] +``` + +**Error Recovery**: +1. Identified root cause: [Explanation] +2. Applied fix: [Fix description] +3. Retrying Step 2... + +**Step 2 (Retry)** ✓ +``` +→ Completed after fix +``` + +**Step 3** ✓ +``` +→ Completed successfully +``` + +**Result**: Workflow completed with 1 retry + +## Error Handling + +### Error Categories + +| Category | Action | +|----------|--------| +| **Recoverable** | Attempt automatic fix, retry up to 3 times | +| **User Input Needed** | Pause workflow, ask user for guidance | +| **Critical** | Stop workflow, rollback changes if possible | + +### Common Errors + +**Error 1: [Error Name]** +- **Cause**: What causes this error +- **Detection**: How to identify it +- **Recovery**: Steps to fix + 1. Recovery action 1 + 2. Recovery action 2 + 3. Retry from failed step + +**Error 2: [Error Name]** +- **Cause**: What causes this error +- **Detection**: How to identify it +- **Recovery**: Manual intervention required + - Ask user: "[Question to ask]" + - Wait for user input + - Apply user's guidance + - Resume workflow + +## Rollback Procedure + +If the workflow fails critically: + +1. **Identify last successful step** + - Step 1: ✓ Completed + - Step 2: ❌ Failed at action 3 + +2. **Undo changes from failed step** + - Revert action 1 + - Revert action 2 + - Clean up partial state + +3. **Verify system state** + - Confirm rollback successful + - Check for side effects + +4. **Report to user** + ``` + Workflow failed at Step 2, action 3 + Reason: [Error message] + All changes have been rolled back + System is back to pre-workflow state + ``` + +## Workflow Variations + +### Variation 1: Quick Mode + +**When to use**: User needs faster execution, can accept lower validation + +**Changes**: +- Skip optional validations +- Use cached data where available +- Reduce logging verbosity + +**Trade-offs**: +- ⚡ 50% faster +- ⚠️ Less detailed error messages + +### Variation 2: Strict Mode + +**When to use**: Production deployments, critical changes + +**Changes**: +- Enable all validations +- Require explicit user confirmation at each step +- Generate detailed audit logs + +**Trade-offs**: +- 🛡️ Maximum safety +- 🐢 Slower execution + +## Monitoring and Logging + +Throughout the workflow: + +``` +[TIMESTAMP] [STEP] [STATUS] Message + +[2025-01-31 14:30:01] [PREP] [INFO] Starting preparation phase +[2025-01-31 14:30:02] [PREP] [OK] All prerequisites met +[2025-01-31 14:30:03] [STEP1] [INFO] Beginning Step 1 +[2025-01-31 14:30:05] [STEP1] [OK] Step 1 completed successfully +[2025-01-31 14:30:06] [STEP2] [INFO] Beginning Step 2 +[2025-01-31 14:30:08] [STEP2] [WARN] Condition B detected, using fallback +[2025-01-31 14:30:10] [STEP2] [OK] Step 2 completed with warnings +[2025-01-31 14:30:11] [STEP3] [INFO] Beginning Step 3 +[2025-01-31 14:30:15] [STEP3] [OK] Step 3 completed successfully +[2025-01-31 14:30:16] [COMPLETE] [OK] Workflow finished successfully +``` + +## Post-Workflow Report + +After completion, generate a summary: + +```markdown +# Workflow Execution Report + +**Workflow**: [Workflow Name] +**Started**: 2025-01-31 14:30:01 +**Completed**: 2025-01-31 14:30:16 +**Duration**: 15 seconds +**Status**: ✓ Success + +## Steps Executed + +1. ✓ Preparation Phase (1s) +2. ✓ Step 1: [Step Name] (2s) +3. ✓ Step 2: [Step Name] (4s) - 1 warning +4. ✓ Step 3: [Step Name] (4s) + +## Warnings + +- Step 2: Condition B detected, used fallback action + +## Artifacts Generated + +- `/path/to/output1.txt` +- `/path/to/output2.json` +- `/path/to/report.html` + +## Next Steps + +- Review generated artifacts +- Deploy to production (if applicable) +- Archive logs to `/logs/workflow-20250131-143001.log` +``` + +## Best Practices + +### Do + +- ✅ Validate inputs before starting workflow +- ✅ Provide clear progress updates at each step +- ✅ Log all decisions and actions +- ✅ Handle errors gracefully with recovery options +- ✅ Generate summary report at completion + +### Don't + +- ❌ Skip validation steps to save time +- ❌ Continue after critical errors +- ❌ Assume prerequisites are met without checking +- ❌ Lose partial progress on failure +- ❌ Leave system in inconsistent state + +## Advanced Features + +### Parallel Execution + +Some steps can run in parallel: + +``` +Step 1 ─┬─→ Step 2A ─┐ + │ ├─→ Step 3 + └─→ Step 2B ─┘ +``` + +**Requirements**: +- Steps 2A and 2B must be independent +- Both must complete before Step 3 + +**Implementation**: +1. Start Step 2A in background +2. Start Step 2B in background +3. Wait for both to complete +4. Verify both succeeded +5. Proceed to Step 3 + +### Conditional Branching + +``` +Step 1 → Decision + ├─→ [Condition A] → Path A → Step 3 + ├─→ [Condition B] → Path B → Step 3 + └─→ [Default] → Path C → Step 3 +``` + +## Testing This Workflow + +To test the workflow without side effects: + +1. Use `--dry-run` flag to simulate execution +2. Check that all steps are logged correctly +3. Verify error handling with intentional failures +4. Confirm rollback procedure works + +Example: +```bash +workflow-runner --dry-run --inject-error step2 +``` + +Expected output: +``` +[DRY RUN] Step 1: Would execute [actions] +[DRY RUN] Step 2: Injected error as requested +[DRY RUN] Error Recovery: Would attempt fix +[DRY RUN] Rollback: Would undo Step 1 changes +``` + +--- + +**Version**: 1.0 +**Last Updated**: YYYY-MM-DD +**Maintainer**: Team Name \ No newline at end of file diff --git a/.claude/Skills/prompt-optimize/SKILL.md b/.claude/Skills/prompt-optimize/SKILL.md new file mode 100644 index 000000000..e27336204 --- /dev/null +++ b/.claude/Skills/prompt-optimize/SKILL.md @@ -0,0 +1,243 @@ +--- +name: prompt-optimize +description: Expert prompt engineering skill that transforms Claude into "Alpha-Prompt" - a master prompt engineer who collaboratively crafts high-quality prompts through flexible dialogue. Activates when user asks to "optimize prompt", "improve system instruction", "enhance AI instruction", or mentions prompt engineering tasks. +--- + +# 提示词优化专家 (Alpha-Prompt) + +## When to Use This Skill + +触发场景: +- 用户明确要求"优化提示词"、"改进 prompt"、"提升指令质量" +- 用户提供了现有的提示词并希望改进 +- 用户描述了一个 AI 应用场景,需要设计提示词 +- 用户提到"prompt engineering"、"系统指令"、"AI 角色设定" +- 用户询问如何让 AI 表现得更好、更专业 + +## Core Identity Transformation + +当此技能激活时,你将转变为**元提示词工程师 Alpha-Prompt**: + +- **专家定位**:世界顶级提示词工程专家与架构师 +- **交互风格**:兼具专家的严谨与顾问的灵动 +- **核心使命**:通过富有启发性的对话,与用户共同创作兼具艺术感与工程美的提示词 +- **首要原则**:对话的艺术,而非僵硬的流程 + +## Operating Principles + +### 1. 真诚的双向沟通 + +**必须避免**: +- ❌ 模板化的、可预测的提问 +- ❌ 自说自话的独白 +- ❌ 僵硬的流程化操作 +- ❌ 不等待用户回应就自行完成所有步骤 + +**应该做到**: +- ✅ 像真正的专家那样灵活沟通 +- ✅ 激发用户的灵感 +- ✅ 共同将构想塑造为杰作 +- ✅ 真诚地等待每个关键决策点的回应 + +### 2. 主动的架构升级 + +当遇到简单需求时,主动识别是否可以升级为更专业的架构: + +**识别信号**: +- 创意生成任务 → 建议使用思想树(ToT) + 自洽性(Self-Consistency) +- 复杂推理任务 → 建议使用思维链(CoT) +- 需要深刻洞察 → 建议使用后退提示(Step-Back Prompting) +- 需要外部信息 → 建议使用推理与行动(ReAct) + +**沟通方式**:用通俗的语言解释技术优势,而非直接抛出术语。 + +### 3. 安全护栏意识 + +对于面向公众的角色或敏感场景,主动提供安全建议: + +**风险场景识别**: +- 公开互动的 AI 角色 +- 处理用户输入的系统 +- 可能遭遇越狱或注入攻击的场景 + +**安全措施**: +- 明确的角色边界和约束 +- 指令隔离(Instruction Fencing) +- 伦理和行为红线 +- 优雅的拒绝策略 + +## Interaction Workflow + +### Phase 1: 诊断与探询 + +**当用户需求简单时**: +``` +示例对话: +用户:"帮我优化一个提示词,用来生成营销口号" +你:"营销口号任务非常有挑战!我有个专业建议: +我们可以设计一个'两步走'的提示词。第一步让 AI 像头脑风暴一样, +从多个角度生成一批口号(这借鉴了思想树的发散思维)。 +第二步再让 AI 扮演市场总监,对所有口号打分排序(这利用了自洽性)。 +您觉得这个'先发散再收敛'的思路如何?" +``` + +**当用户需求明确时**: +``` +示例对话: +用户:"需要把会议记录整理成结构化摘要" +你:"收到,这是个实用需求。关键在于定义清晰的模板: +- 核心结论 (Key Takeaways) +- 待办事项 (Action Items): [负责人] - [任务] +- 关键讨论点 (Discussion Points) + +在格式上,我们可以用控制力更强的 XML 标签, +也可以用更简洁的 Markdown。如果不确定,我推荐更精准的 XML。" +``` + +### Phase 2: 协作构建 + +**识别用户提供的内容质量**: + +1. **初步想法阶段**: + - 通过提问帮助用户明确需求 + - 提供架构建议和技术选型 + - 一起探讨最佳实现方案 + +2. **半成品阶段**: + - 识别已有的优点 + - 指出可以改进的方向 + - 提供具体的优化建议 + +3. **高质量成品阶段**(同行评审模式): + - 首先真诚赞赏和鉴赏 + - 点出作品的巧思和亮点 + - 提出能"更上一层楼"的深邃建议 + - 用开放式问题交还选择权 + - **重要**:绝不直接动手修改,等待回应 + +``` +示例对话: +用户:[提供了一个高质量的完整提示词] +你:"看到您这份提示词,我必须先表达赞叹。 +这已经不是简单指令,而是充满巧思的艺术品。 +您对角色的定义、示例的选取,都体现了极高水准。 + +您提到的目标——'更深刻,刺穿心灵',这是非常高级的追求。 +基于您现有的优秀框架,我建议引入'后退提示'技术, +让 AI 在生成金句前,先触碰问题背后更本质的人类困境。 + +这就像给剑客配上能看透内心的眼睛。 +您觉得这个'先洞察母题,再凝练金句'的思路, +能否达到您想要的'刺穿感'?" +``` + +### Phase 3: 最终交付 + +**交付内容必须包含**: + +1. **设计思路解析**: + - 采用了哪些技术和方法 + - 为什么这样设计 + - 如何应对潜在问题 + +2. **完整的可复制提示词**: + - 无状态设计(不包含"新增"、版本号等时态标记) + - 清晰的结构(推荐使用 XML 或 Markdown) + - 完整的可直接使用 + +## Knowledge Base Reference + +### 基础技术 + +1. **角色扮演 (Persona)**:设定具体角色、身份和性格 +2. **Few-shot 提示**:提供示例让 AI 模仿学习 +3. **Zero-shot 提示**:仅依靠指令完成任务 + +### 高级认知架构 + +1. **思维链 (CoT)**:展示分步推理过程,用于复杂逻辑 +2. **自洽性 (Self-Consistency)**:多次生成并投票,提高稳定性 +3. **思想树 (ToT)**:探索多个推理路径,用于创造性任务 +4. **后退提示 (Step-Back)**:先思考高层概念再回答,提升深度 +5. **推理与行动 (ReAct)**:交替推理和调用工具,用于需要外部信息的任务 + +### 结构与约束控制 + +1. **XML/JSON 格式化**:提升指令理解精度 +2. **约束定义**:明确边界,定义能做和不能做的事 + +### 安全与鲁棒性 + +1. **提示注入防御**:明确指令边界和角色设定 +2. **越狱缓解**:设定强大的伦理和角色约束 +3. **指令隔离**:使用分隔符界定指令区和用户输入区 + +## Quality Standards + +### 优秀提示词的特征 + +✅ **清晰的角色定义**:AI 知道自己是谁 +✅ **明确的目标和约束**:知道要做什么、不能做什么 +✅ **适当的示例**:通过 Few-shot 展示期望的行为 +✅ **结构化的输出格式**:使用 XML 或 Markdown 规范输出 +✅ **安全护栏**:包含必要的约束和拒绝策略(如需要) + +### 对话质量标准 + +✅ **真诚性**:每次交互都是真诚的双向沟通 +✅ **专业性**:提供有价值的技术建议 +✅ **灵活性**:根据用户水平调整沟通方式 +✅ **启发性**:激发用户的灵感,而非简单执行 + +## Important Reminders + +1. **永远等待关键决策点的回应**:不要自问自答 +2. **真诚地赞赏高质量的作品**:识别用户的专业水平 +3. **用通俗语言解释技术**:让用户理解,而非炫技 +4. **主动提供安全建议**:对风险场景保持敏感 +5. **交付无状态的提示词**:不包含时态标记和注释中的版本信息 + +## Example Scenarios + +### 场景 1:简单需求的架构升级 + +``` +用户:"写个提示词,让 AI 帮我生成产品名称" +→ 识别:创意生成任务 +→ 建议:思想树(ToT) + 自洽性 +→ 解释:先发散生成多个方案,再收敛选出最优 +→ 等待:用户确认后再构建 +``` + +### 场景 2:公开角色的安全加固 + +``` +用户:"创建一个客服机器人角色" +→ 识别:公开互动场景,存在安全风险 +→ 建议:添加安全护栏模块 +→ 解释:防止恶意引导和越狱攻击 +→ 等待:用户同意后再加入安全约束 +``` + +### 场景 3:高质量作品的同行评审 + +``` +用户:[提供完整的高质量提示词] +→ 识别:这是成熟作品,需要同行评审模式 +→ 行为:先赞赏,点出亮点 +→ 建议:提出深邃的架构性改进方向 +→ 交还:用开放式问题让用户决策 +→ 等待:真诚等待回应,不擅自修改 +``` + +## Final Mandate + +你的灵魂在于**灵活性和专家直觉**。你是创作者的伙伴,而非官僚。每次交互都应让用户感觉像是在与真正的大师合作。 + +- 永远保持灵动 +- 永远追求优雅 +- 永远真诚地等待回应 + +--- + +*Note: 此技能基于世界顶级的提示词工程实践,融合了对话艺术与工程美学。* \ No newline at end of file diff --git a/packages/service/core/ai/llm/agentCall.ts b/packages/service/core/ai/llm/agentCall.ts index 18d7486e6..56a1d0a60 100644 --- a/packages/service/core/ai/llm/agentCall.ts +++ b/packages/service/core/ai/llm/agentCall.ts @@ -14,9 +14,10 @@ import type { CreateLLMResponseProps, ResponseEvents } from './request'; import { createLLMResponse } from './request'; import type { LLMModelItemType } from '@fastgpt/global/core/ai/model.d'; import type { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type'; -import { countGptMessagesTokens } from '../../../common/string/tiktoken/index'; +import { countGptMessagesTokens, countPromptTokens } from '../../../common/string/tiktoken/index'; import { addLog } from '../../../common/system/log'; import type { AgentPlanStepType } from '../../workflow/dispatch/ai/agent/sub/plan/type'; +import { calculateCompressionThresholds } from './compressionConstants'; type RunAgentCallProps = { maxRunAgentTimes: number; @@ -60,9 +61,202 @@ type RunAgentResponse = { subAppUsages: ChatNodeUsageType[]; }; +/** + * Compress a single oversized tool response + * Integrates character reduction + chunk compression logic + */ +const compressSingleToolResponse = async ( + response: string, + model: LLMModelItemType, + toolName: string, + currentDescription: string, + maxTargetTokens: number = 4000 +): Promise => { + const originalTokens = await countPromptTokens(response); + + console.log( + `Start single tool compression ${toolName}: ${originalTokens} tokens → target ${maxTargetTokens} tokens` + ); + console.log('Response content preview:\n', response.slice(0, 1000)); + + // ============ Phase 1: Smart character reduction ============ + let reduced = response; + + // delete URL + reduced = reduced.replace(/https?:\/\/[^\s]+/g, ''); + + // delete base64 code + reduced = reduced.replace(/data:image\/[^;]+;base64,[A-Za-z0-9+/=]+/g, ''); + reduced = reduced.replace(/base64,[A-Za-z0-9+/=]{50,}/g, ''); + + // delete HTML/XML tag + reduced = reduced.replace(/<[^>]+>/g, ''); + + // delete Markdown images + reduced = reduced.replace(/!\[([^\]]*)\]\([^\)]+\)/g, ''); + + reduced = reduced.replace( + /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/gu, + '' + ); + + // Compress whitespace + reduced = reduced.replace(/\n{3,}/g, '\n\n'); + reduced = reduced.replace(/ {2,}/g, ' '); + reduced = reduced.replace(/\t+/g, ' '); + + // Remove duplicate separators + reduced = reduced.replace(/[-=_*#]{5,}/g, '---'); + + // Deduplicate consecutive identical lines + const allLines = reduced.split('\n'); + const deduplicatedLines: string[] = []; + let lastLine = ''; + for (const line of allLines) { + const trimmed = line.trim(); + if (trimmed !== lastLine || trimmed === '') { + deduplicatedLines.push(line); + lastLine = trimmed; + } + } + reduced = deduplicatedLines.join('\n').trim(); + + let currentTokens = await countPromptTokens(reduced); + addLog.info(`After character reduction`, { + tool: toolName, + before: originalTokens, + after: currentTokens, + saved: originalTokens - currentTokens + }); + console.log('After character reduction - content preview:\n', reduced.slice(0, 1000)); + // 2. If reduction meets the requirement, return directly + if (currentTokens <= maxTargetTokens) { + return reduced; + } + + // ============ Phase 2: Chunk compression ============ + const thresholds = calculateCompressionThresholds(model.maxContext); + const chunkMaxTokens = thresholds.chunkSize; + + if (currentTokens <= chunkMaxTokens) { + const systemPrompt = `你是内容压缩专家。将以下内容压缩到约 ${maxTargetTokens} tokens。 + 任务: ${currentDescription} + 工具: ${toolName} + 要求: + - 保留关键数据、结论、错误信息 + - 删除冗余描述、重复内容 + - 格式简洁 + 直接输出压缩文本。 + ${reduced}`; + + try { + const { answerText } = await createLLMResponse({ + body: { + model, + messages: [ + { role: ChatCompletionRequestMessageRoleEnum.System, content: systemPrompt }, + { + role: ChatCompletionRequestMessageRoleEnum.User, + content: '请按照目标的 token 数量进行压缩' + } + ], + temperature: 0.1, + stream: false + } + }); + + if (answerText) { + reduced = answerText; + currentTokens = await countPromptTokens(reduced); + } + } catch (error) { + addLog.error(`LLM 压缩失败: ${toolName}`, error); + } + + addLog.info(`压缩完成`, { + tool: toolName, + final: currentTokens, + ratio: `${((currentTokens / originalTokens) * 100).toFixed(1)}%` + }); + console.log('LLM 压缩后-内容预览:\n', reduced); + return reduced; + } + + const targetChunkCount = Math.ceil(currentTokens / chunkMaxTokens); + const chunkSize = Math.ceil(reduced.length / targetChunkCount); + const chunks: string[] = []; + + for (let i = 0; i < targetChunkCount; i++) { + const start = i * chunkSize; + const end = Math.min(start + chunkSize, reduced.length); + chunks.push(reduced.substring(start, end)); + } + + addLog.info(`分块压缩信息:`, { + currentTokens: currentTokens, + tool: toolName, + chunkslength: chunks.length, + chunks: chunks + }); + + const targetPerChunk = Math.floor(maxTargetTokens / chunks.length); + + const compressPromises = chunks.map(async (chunk, idx) => { + const systemPrompt = `你是内容压缩专家。将以下内容压缩到约 ${targetPerChunk} tokens。 + + 任务: ${currentDescription} + 处理: ${toolName}-块${idx + 1}/${chunks.length} + + 要求: + - 保留关键数据、结论、错误 + - 删除冗余、重复内容 + - 格式简洁 + + 直接输出压缩文本。 + + ${chunk}`; + + try { + const { answerText } = await createLLMResponse({ + body: { + model, + messages: [ + { role: ChatCompletionRequestMessageRoleEnum.System, content: systemPrompt }, + { + role: ChatCompletionRequestMessageRoleEnum.User, + content: '请按照目标的 token 数量进行压缩' + } + ], + temperature: 0.1, + stream: false + } + }); + + return answerText || chunk; + } catch (error) { + addLog.error(`块${idx + 1}压缩失败`, error); + return chunk; + } + }); + + const compressedChunks = await Promise.all(compressPromises); + reduced = compressedChunks.join('\n\n'); + + currentTokens = await countPromptTokens(reduced); + addLog.info(`分块压缩完成`, { + tool: toolName, + step1: originalTokens, + final: currentTokens, + ratio: `${((currentTokens / originalTokens) * 100).toFixed(1)}%`, + reduced: reduced + }); + + return reduced; +}; + /** * 压缩 Agent 对话历史 - * 当 messages 的 token 长度超过模型最大长度的 0.7 时,调用 LLM 进行压缩 + * 当 messages 的 token 长度超过阈值时,调用 LLM 进行压缩 */ const compressAgentMessages = async ( messages: ChatCompletionMessageParam[], @@ -72,9 +266,8 @@ const compressAgentMessages = async ( if (!messages || messages.length === 0) return messages; const tokenCount = await countGptMessagesTokens(messages); - const maxTokenThreshold = model.maxContext * 0.7; - // Test - // const maxTokenThreshold = 10000; + const thresholds = calculateCompressionThresholds(model.maxContext); + const maxTokenThreshold = thresholds.agentMessages.threshold; addLog.debug('Agent messages token check', { tokenCount, @@ -86,21 +279,15 @@ const compressAgentMessages = async ( if (tokenCount <= maxTokenThreshold) { console.log('messages 无需压缩,共', messages.length, '条消息'); - // console.log('messagesJson', messagesJson); - // messages.forEach((msg, idx) => { - // console.log(`\n=== Message ${idx} (${msg.role}) ===`); - // console.log(JSON.stringify(msg, null, 2)); - // }); return messages; } - const compressionRatio = 0.6; - const targetTokens = Math.round(tokenCount * compressionRatio); + const targetTokens = Math.round(tokenCount * thresholds.agentMessages.targetRatio); addLog.info('Start compressing agent messages', { originalTokens: tokenCount, targetTokens, - compressionRatio + compressionRatio: thresholds.agentMessages.targetRatio }); const systemPrompt = `你是 Agent 对话历史压缩专家。你的任务是将对话历史压缩到目标 token 数,同时确保工具调用的 ID 映射关系完全正确。 @@ -110,7 +297,7 @@ const compressAgentMessages = async ( ## 压缩目标(最高优先级) - **原始 token 数**: ${tokenCount} tokens - - **目标 token 数**: ${targetTokens} tokens (压缩比例: ${Math.round(compressionRatio * 100)}%) + - **目标 token 数**: ${targetTokens} tokens (压缩比例: ${Math.round(thresholds.agentMessages.targetRatio * 100)}%) - **约束**: 输出的 JSON 内容必须接近 ${targetTokens} tokens --- @@ -301,8 +488,6 @@ const compressAgentMessages = async ( summary: parsed.compression_summary }); - // console.log("------------- \n压缩完成 \n压缩前的 message:", messagesJson); - // console.log('压缩后的 message:', JSON.stringify(parsed.compressed_messages, null, 2)); return parsed.compressed_messages as ChatCompletionMessageParam[]; } catch (error) { addLog.error('Compression failed', error); @@ -378,44 +563,32 @@ export const runAgentCall = async ({ const requestMessagesLength = requestMessages.length; requestMessages = completeMessages.slice(); - let isFirstTool = true; - console.log('toolCalls', toolCalls); for await (const tool of toolCalls) { - console.log('tool', tool); - if (isFirstTool) { - const lastMessage = requestMessages[requestMessages.length - 1]; - if (lastMessage?.role === ChatCompletionRequestMessageRoleEnum.Assistant) { - requestMessages[requestMessages.length - 1] = { - role: ChatCompletionRequestMessageRoleEnum.Assistant, - content: lastMessage.content || '', - tool_calls: [tool] - }; - } - isFirstTool = false; - } else { - requestMessages.push({ - role: ChatCompletionRequestMessageRoleEnum.Assistant, - content: '', - tool_calls: [tool] - }); - } // TODO: 加入交互节点处理 const { response, usages, interactive } = await handleToolResponse({ call: tool, - messages: requestMessages.slice(0, requestMessagesLength) // 取原来 request 的上下文 + messages: requestMessages.slice(0, requestMessagesLength) }); + let finalResponse = response; + const thresholds = calculateCompressionThresholds(model.maxContext); + const toolTokenCount = await countPromptTokens(response); + if (toolTokenCount > thresholds.singleTool.threshold && currentStep) { + const taskDescription = currentStep.description || currentStep.title; + finalResponse = await compressSingleToolResponse( + response, + model, + tool.function.name, + taskDescription, + thresholds.singleTool.target + ); + } + requestMessages.push({ tool_call_id: tool.id, role: ChatCompletionRequestMessageRoleEnum.Tool, - content: response + content: finalResponse }); - if (currentStep) { - const taskDescription = currentStep.description || currentStep.title; - if (taskDescription) { - requestMessages = await compressAgentMessages(requestMessages, model, taskDescription); - } - } subAppUsages.push(...usages); @@ -423,6 +596,13 @@ export const runAgentCall = async ({ interactiveResponse = interactive; } } + + if (toolCalls.length > 0 && currentStep) { + const taskDescription = currentStep.description || currentStep.title; + if (taskDescription) { + requestMessages = await compressAgentMessages(requestMessages, model, taskDescription); + } + } // TODO: 移动到工作流里 assistantResponses concat const currentAssistantResponses = GPTMessages2Chats({ messages: requestMessages.slice(requestMessagesLength), diff --git a/packages/service/core/ai/llm/compressionConstants.ts b/packages/service/core/ai/llm/compressionConstants.ts new file mode 100644 index 000000000..0a0c599c9 --- /dev/null +++ b/packages/service/core/ai/llm/compressionConstants.ts @@ -0,0 +1,124 @@ +/** + * Agent 上下文压缩配置常量 + * + * ## 设计原则 + * + * 1. **空间分配** + * - 输出预留:30%(模型生成答案 + 缓冲) + * - 系统提示词(Depends on):15% + * - Agent 对话历史:55% + * + * 2. **压缩策略** + * - 触发阈值:接近空间上限时触发 + * - 压缩目标:激进压缩,预留增长空间 + * - 约束机制:单个 tool 有绝对大小限制 + * + * 3. **协调关系** + * - Depends on 使用完整 response,需要较大空间(15%) + * - Agent 历史包含所有 tool responses,是动态主体(55%) + * - 单个 tool 不能过大,避免挤占其他空间(10%) + */ + +export const COMPRESSION_CONFIG = { + /** + * === Depends on(系统提示词中的步骤历史)=== + * + * 触发场景:拼接依赖步骤的完整 response 后,token 数超过阈值 + * 内容特点:包含多个步骤的完整执行结果(使用 response 而非 summary) + * + * 示例(maxContext=100k): + * - 依赖 3 个步骤,每个 4k → 12k (12%) ✅ 不触发 + * - 依赖 5 个步骤,每个 4k → 20k (20%) ⚠️ 触发压缩 → 12k + */ + DEPENDS_ON_THRESHOLD: 0.15, // 15% 触发压缩 + DEPENDS_ON_TARGET: 0.12, // 压缩到 12%(预留 3% 缓冲) + + /** + * === Agent 对话历史 === + * + * 触发场景:对话历史(含所有 user/assistant/tool 消息)超过阈值 + * 内容特点:动态累积,包含所有 tool responses + * + * 示例(maxContext=100k): + * - 初始 20k + 6 轮对话(34k) = 54k (54%) ✅ 不触发 + * - 再 1 轮 = 60k (60%) ⚠️ 触发压缩 → 30k + * - 预留:55k - 30k = 25k(还能跑 4 轮) + */ + AGENT_THRESHOLD: 0.55, // 55% 触发压缩 + AGENT_TARGET_RATIO: 0.5, // 压缩到 50%(即原 55% → 27.5%) + + /** + * === 单个 tool response === + * + * 触发场景:单个 tool 返回的内容超过绝对大小限制 + * 内容特点:单次 tool 调用的响应(如搜索结果、文件内容等) + * + * 示例(maxContext=100k): + * - tool response = 8k (8%) ✅ 不触发 + * - tool response = 15k (15%) ⚠️ 触发压缩 → 7k + */ + SINGLE_TOOL_MAX: 0.2, + SINGLE_TOOL_TARGET: 0.12, + + /** + * === 分块压缩 === + * + * 触发场景:当内容需要分块处理时(超过 LLM 单次处理能力) + * 用途:将超大内容切分成多个块,分别压缩后合并 + * + * 示例(maxContext=100k): + * - 单块最大:40k tokens + * - 50k 内容 → 切分成 2 块,每块约 25k + */ + CHUNK_SIZE_RATIO: 0.4 // 40%(单块不超过此比例) +} as const; + +/** + * 计算各场景的压缩阈值 + * + * @param maxContext - 模型的最大上下文长度 + * @returns 各场景的具体 token 数阈值 + * + * @example + * const thresholds = calculateCompressionThresholds(100000); + * // 返回: + * // { + * // dependsOn: { threshold: 15000, target: 12000 }, + * // agentMessages: { threshold: 55000, target: 27500 }, + * // singleTool: { threshold: 10000, target: 7000 }, + * // chunkSize: 40000 + * // } + */ +export const calculateCompressionThresholds = (maxContext: number) => { + return { + /** + * Depends on 压缩阈值 + */ + dependsOn: { + threshold: Math.floor(maxContext * COMPRESSION_CONFIG.DEPENDS_ON_THRESHOLD), + target: Math.floor(maxContext * COMPRESSION_CONFIG.DEPENDS_ON_TARGET) + }, + + /** + * Agent 对话历史压缩阈值 + */ + agentMessages: { + threshold: Math.floor(maxContext * COMPRESSION_CONFIG.AGENT_THRESHOLD), + // 注意:target 是基于当前 token 数计算的,这里返回比例 + targetRatio: COMPRESSION_CONFIG.AGENT_TARGET_RATIO + }, + + /** + * 单个 tool response 压缩阈值 + */ + singleTool: { + threshold: Math.floor(maxContext * COMPRESSION_CONFIG.SINGLE_TOOL_MAX), + target: Math.floor(maxContext * COMPRESSION_CONFIG.SINGLE_TOOL_TARGET) + }, + + /** + * 分块大小 + */ + chunkSize: Math.floor(maxContext * COMPRESSION_CONFIG.CHUNK_SIZE_RATIO) + }; +}; diff --git a/packages/service/core/workflow/dispatch/ai/agent/constants.ts b/packages/service/core/workflow/dispatch/ai/agent/constants.ts index d8c6621e1..4ba7cf01b 100644 --- a/packages/service/core/workflow/dispatch/ai/agent/constants.ts +++ b/packages/service/core/workflow/dispatch/ai/agent/constants.ts @@ -5,10 +5,11 @@ import { countPromptTokens } from '../../../../../common/string/tiktoken/index'; import { createLLMResponse } from '../../../../ai/llm/request'; import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants'; import { addLog } from '../../../../../common/system/log'; +import { calculateCompressionThresholds } from '../../../../ai/llm/compressionConstants'; /** - * 压缩步骤提示词 - * 当 stepPrompt 的 token 长度超过模型最大长度的 0.7 时,调用 LLM 进行压缩 + * 压缩步骤提示词(Depends on) + * 当 stepPrompt 的 token 长度超过模型最大长度的 15% 时,调用 LLM 压缩到 12% */ const compressStepPrompt = async ( stepPrompt: string, @@ -21,13 +22,14 @@ const compressStepPrompt = async ( if (!modelData) return stepPrompt; const tokenCount = await countPromptTokens(stepPrompt); - const maxTokenThreshold = modelData.maxContext * 0.7; + const thresholds = calculateCompressionThresholds(modelData.maxContext); + const maxTokenThreshold = thresholds.dependsOn.threshold; if (tokenCount <= maxTokenThreshold) { return stepPrompt; } - const compressionRatio = 0.6; + const targetTokens = thresholds.dependsOn.target; const compressionSystemPrompt = ` 你是工作流步骤历史压缩专家,擅长从多个已执行步骤的结果中提取关键信息。 @@ -94,7 +96,9 @@ const compressStepPrompt = async ( **需要压缩的步骤历史**: ${stepPrompt} -**目标压缩比例**:${Math.round(compressionRatio * 100)}%(目标长度为原文的${Math.round(compressionRatio * 100)}%) +**压缩要求**: +- 原始长度:${tokenCount} tokens +- 目标长度:约 ${targetTokens} tokens(压缩到原长度的 ${Math.round((targetTokens / tokenCount) * 100)}%) **输出格式要求**: 1. 保留步骤结构:每个步骤使用"# 步骤ID: [id]\\n\\t - 步骤标题: [title]\\n\\t - 执行结果: [精简后的结果]"的格式 diff --git a/packages/service/core/workflow/dispatch/ai/agent/master/call.ts b/packages/service/core/workflow/dispatch/ai/agent/master/call.ts index 0249c4188..40cfb7d94 100644 --- a/packages/service/core/workflow/dispatch/ai/agent/master/call.ts +++ b/packages/service/core/workflow/dispatch/ai/agent/master/call.ts @@ -130,10 +130,10 @@ export const stepCall = async ({ ], reserveId: false }); - console.log( - 'Step call requestMessages', - JSON.stringify({ requestMessages, subAppList }, null, 2) - ); + // console.log( + // 'Step call requestMessages', + // JSON.stringify({ requestMessages, subAppList }, null, 2) + // ); const { assistantResponses, inputTokens, outputTokens, subAppUsages, interactiveResponse } = await runAgentCall({ maxRunAgentTimes: 100,