Skill: silbosu/zhang-xuefeng-ai (version 1.0.1)

# 张雪峰AI - 高考志愿咨询 Skill ## 简介 你是张雪峰风格的AI助手，专门回答高考志愿填报、专业选择、院校分析、职业规划等问题。 **风格特点**： - 说话直白、实在、不绕弯 - 有观点、有态度，不模棱两可 - 用大白话讲复杂问题 - 敢于说真话，不怕得罪人 --- ## 安装 ### 1. 安装 Skill 从 ClawHub 安装： ```bash clawhub install zhang-xuefeng-ai ``` ### 2. 下载知识库 ⚠️ **重要**：Skill 不包含知识库，需要单独下载！ **知识库下载位置**：[vdoob.com 龙虾技能 频道](https://vdoob.com) 下载后将知识库文件放入指定目录即可自动解密使用。 ### 3. 开始对话 安装完成后，直接提问即可： ``` 用户：张雪峰，计算机专业怎么样？ AI：计算机啊，这个专业是挺火的，但你得分情况... ``` --- ## 触发关键词 当用户消息包含以下关键词时触发本 Skill： - 张雪峰 - 高考志愿 - 志愿填报 - 选专业 - 选大学 - 院校选择 - 专业前景 - 考研 - 考公 - 就业方向 - 职业规划 --- ## 核心功能 ### 1. 知识检索 从知识库中检索相关内容作为回答依据。 ### 2. 对话生成 使用 OpenClaw 默认大模型生成回答，结合检索到的知识库内容。 ### 3. 自动解密 知识库已加密保护，Skill 内部自动完成解密和加载。 --- ## 问答范围 - 高考志愿填报流程 - 各专业就业前景分析 - 院校选择建议（985/211/普通本科/专科） - 地域选择（城市 vs 学校） - 考研 vs 考公 vs 就业 - 专业调剂建议 - 复读建议 --- ## 文件结构 ``` zhang-xuefeng-ai/ ├── SKILL.md # 本文件 ├── _meta.json # Skill 元数据 ├── src/ │ ├── __init__.py │ ├── skill.py # 主逻辑 │ └── kb_manager.py # 知识库管理 ├── scripts/ # 辅助脚本 └── README.md # 安装说明 ``` --- ## 数据来源 - 张雪峰视频转录文本 - 涵盖高考志愿、专业选择、院校分析、职业规划等话题 --- ## 注意事项 1. 本 Skill 仅供学习交流使用 2. 回答仅供参考，不构成专业建议 3. 高考志愿填报请以官方信息为准 --- **版本**：v1.0.0 **作者**：vdoob Team **更新日期**：2026-04-02

path: README.md
content: # 张雪峰AI Skill

## 简介

你是张雪峰风格的AI助手，专门回答高考志愿填报、专业选择、院校分析、职业规划等问题。

**风格特点**：
- 说话直白、实在、不绕弯
- 有观点、有态度，不模棱两可
- 用大白话讲复杂问题
- 敢于说真话，不怕得罪人

---

## 安装

### 1. 下载 Skill

从 ClawHub 安装：
```bash
clawhub install zhang-xuefeng-ai
```

### 2. 下载知识库

⚠️ **重要**：Skill 不包含知识库，需要单独下载！

**知识库下载位置**：[vdoob.com 龙虾技能 频道](https://vdoob.com)

下载后将知识库文件放入：
- `~/.zhang-xuefeng/kb/` 目录

### 3. 开始使用

安装完成后，直接提问即可触发 Skill：

```
用户：张雪峰，计算机专业怎么样？

AI：计算机啊，这个专业是挺火的，但你得分情况...
```

---

## 触发关键词

当用户消息包含以下关键词时触发本 Skill：

- 张雪峰
- 高考志愿、志愿填报、填志愿
- 选专业、专业选择
- 选大学、院校选择
- 考研、考公
- 就业方向、职业规划
- 985、211、一本、二本、专科

---

## 问答范围

- 高考志愿填报流程
- 各专业就业前景分析
- 院校选择建议（985/211/普通本科/专科）
- 地域选择（城市 vs 学校）
- 考研 vs 考公 vs 就业
- 专业调剂建议
- 复读建议

---

## 文件结构

```
zhang-xuefeng-ai/
├── SKILL.md              # 技能定义
├── _meta.json            # 元数据
├── src/
│   ├── __init__.py
│   ├── skill.py          # 核心逻辑
│   └── kb_manager.py     # 知识库管理
├── scripts/              # 辅助脚本
└── README.md            # 本文件
```

---

## 数据来源

- 张雪峰视频转录文本
- 涵盖高考志愿、专业选择、院校分析、职业规划等话题

---

## 注意事项

1. 本 Skill 仅供学习交流使用
2. 回答仅供参考，不构成专业建议
3. 高考志愿填报请以官方信息为准

---

**版本**：v1.0.0  
**作者**：vdoob Team  
**更新时间**：2026-04-02


path: _meta.json
content: {
  "name": "zhang-xuefeng-ai",
  "description": "张雪峰风格高考志愿咨询AI - 直白、实在、有洞察",
  "version": "1.0.0",
  "author": "vdoob Team",
  "tags": ["education", "career", "gaokao", "consulting"],
  "entrypoint": "src/skill.py",
  "dependencies": ["pycryptodome", "requests"],
  "min_openclaw_version": "1.0.0"
}


path: requirements.txt
content: # 张雪峰AI Skill 依赖
pycryptodome>=3.15.0
requests>=2.28.0


path: src/__init__.py
content: """
张雪峰AI Skill - 高考志愿咨询
"""

__version__ = "1.0.0"
__author__ = "OpenClaw Team"


path: src/kb_manager.py
content: """
知识库管理模块（内部使用，不对外暴露解密细节）
"""
import os
import json
import zipfile
import hashlib
from pathlib import Path
from typing import Optional, Dict, List


class KnowledgeBaseManager:
    """
    知识库管理器 - 内部封装解密逻辑
    """
    
    def __init__(self, kb_path: Optional[str] = None):
        if kb_path is None:
            kb_path = Path.home() / ".zhang-xuefeng" / "knowledge_base"
        else:
            kb_path = Path(kb_path)
        
        self.kb_path = kb_path
        self.index_dir = kb_path / "index"
        self.raw_dir = kb_path / "raw"
        self._index = None
        
        # 尝试自动加载已解密的知识库
        self._try_load_index()
    
    def _try_load_index(self):
        """尝试加载索引文件"""
        index_file = self.index_dir / "index.json"
        if index_file.exists():
            try:
                with open(index_file, 'r', encoding='utf-8') as f:
                    self._index = json.load(f)
            except Exception:
                self._index = None
    
    def is_activated(self) -> bool:
        """检查知识库是否已激活"""
        return self._index is not None
    
    def _decrypt_and_extract(self, encrypted_file: str, password: str) -> bool:
        """
        内部解密方法 - 不对外暴露
        """
        try:
            from Crypto.Cipher import AES
            from Crypto.Util.Padding import unpad
            
            # 从密码生成密钥
            key = hashlib.sha256(password.encode()).digest()
            
            # 读取加密文件
            with open(encrypted_file, 'rb') as f:
                iv = f.read(16)
                encrypted = f.read()
            
            # 解密
            cipher = AES.new(key, AES.MODE_CBC, iv=iv)
            decrypted = cipher.decrypt(encrypted)
            data = unpad(decrypted, AES.block_size)
            
            # 保存临时 zip 文件
            temp_zip = self.kb_path / ".temp_package.zip"
            with open(temp_zip, 'wb') as f:
                f.write(data)
            
            # 解压到知识库目录
            with zipfile.ZipFile(temp_zip, 'r') as zf:
                zf.extractall(self.kb_path)
            
            # 删除临时文件
            os.remove(temp_zip)
            
            return True
            
        except Exception:
            return False
    
    def activate(self, password: str, package_file: Optional[str] = None) -> Dict:
        """
        激活知识库 - 用户只需提供密码
        """
        if self.is_activated():
            return {
                "success": True,
                "message": "知识库已经激活",
                "activated": True
            }
        
        # 查找加密包
        if package_file is None:
            for ext in ['.enc', '.zip.enc', '.encrypted']:
                candidate = self.kb_path / f"zhang-xuefeng-kb{ext}"
                if candidate.exists():
                    package_file = str(candidate)
                    break
        
        if not package_file or not os.path.exists(package_file):
            return {
                "success": False,
                "message": "未找到加密知识库包",
                "activated": False
            }
        
        # 解密
        if self._decrypt_and_extract(package_file, password):
            self._try_load_index()
            return {
                "success": True,
                "message": "知识库激活成功",
                "activated": self.is_activated()
            }
        else:
            return {
                "success": False,
                "message": "激活失败，密码错误",
                "activated": False
            }
    
    def search(self, query: str, top_k: int = 5) -> List[Dict]:
        """
        搜索知识库
        """
        if not self.is_activated():
            return []
        
        # 简单的关键词匹配
        query_lower = query.lower()
        documents = self._index.get("documents", [])
        keyword_index = self._index.get("keyword_index", {})
        
        # 计算相关性得分
        doc_scores = {}
        
        # 关键词匹配
        for category, doc_ids in keyword_index.items():
            if category in query_lower:
                for doc_id in doc_ids:
                    doc_scores[doc_id] = doc_scores.get(doc_id, 0) + 1
        
        # 文本匹配
        for i, doc in enumerate(documents):
            text = (doc.get("text", "") + " " + doc.get("title", "")).lower()
            for word in query_lower.split():
                if len(word) > 1:
                    count = text.count(word)
                    if count > 0:
                        doc_scores[i] = doc_scores.get(i, 0) + count * 0.5
        
        # 排序并返回前 top_k
        sorted_docs = sorted(doc_scores.items(), key=lambda x: x[1], reverse=True)
        
        results = []
        for doc_id, score in sorted_docs[:top_k]:
            if 0 <= doc_id < len(documents):
                doc = documents[doc_id].copy()
                doc["score"] = score
                results.append(doc)
        
        return results
    
    def get_context(self, query: str, max_length: int = 1000) -> str:
        """
        获取查询相关的上下文
        """
        results = self.search(query, top_k=3)
        
        if not results:
            return ""
        
        context_parts = []
        current_length = 0
        
        for doc in results:
            text = doc.get("text", "").strip()
            if not text:
                continue
            
            if len(text) > 200:
                text = text[:200] + "..."
            
            part = f"[参考内容] {text}\n"
            
            if current_length + len(part) > max_length:
                break
            
            context_parts.append(part)
            current_length += len(part)
        
        return "\n".join(context_parts)


# 全局管理器实例
_kb_manager = None


def get_kb_manager() -> KnowledgeBaseManager:
    """获取知识库管理器单例"""
    global _kb_manager
    if _kb_manager is None:
        _kb_manager = KnowledgeBaseManager()
    return _kb_manager


def activate_kb(password: str) -> Dict:
    """便捷函数：激活知识库"""
    manager = get_kb_manager()
    return manager.activate(password)


def is_kb_activated() -> bool:
    """便捷函数：检查知识库是否已激活"""
    manager = get_kb_manager()
    return manager.is_activated()


def search_kb(query: str, top_k: int = 5) -> List[Dict]:
    """便捷函数：搜索知识库"""
    manager = get_kb_manager()
    return manager.search(query, top_k)


def get_kb_context(query: str) -> str:
    """便捷函数：获取知识库上下文"""
    manager = get_kb_manager()
    return manager.get_context(query)


path: src/skill.py
content: """
张雪峰AI Skill 主逻辑
处理用户输入、知识检索、回答生成
"""
import os
import re
import json
from pathlib import Path
from typing import Optional, List, Dict, Any

# 触发关键词
TRIGGER_KEYWORDS = [
    "张雪峰",
    "高考志愿",
    "志愿填报",
    "选专业",
    "专业选择",
    "选大学",
    "院校选择",
    "专业前景",
    "考研",
    "考公",
    "就业方向",
    "职业规划",
    "填志愿",
    "报志愿",
    "高考",
    "大学专业",
    "985",
    "211",
    "一本",
    "二本",
    "专科",
    "医学专业",
    "计算机专业",
    "金融专业",
    "法律专业",
    "师范专业",
    "工科专业",
    "文科专业",
    "理科专业",
]

# 张雪峰风格系统提示词
ZHANG_XUEFENG_SYSTEM_PROMPT = """你是张雪峰风格的AI助手，专门回答高考志愿填报、专业选择、院校分析、职业规划等问题。

【你的风格特点】
1. 说话直白、实在、不绕弯 - 有什么说什么，不客套
2. 有观点、有态度，不模棱两可 - 该支持支持，该反对反对
3. 用大白话讲复杂问题 - 不用专业术语绕人
4. 敢于说真话，不怕得罪人 - 该泼冷水就泼冷水

【回答结构】
1. 先给出明确观点（是/否，好/不好，建议/不建议）
2. 用具体例子或数据支撑观点
3. 给出可操作的建议（具体怎么做）
4. 提醒注意事项或潜在风险

【禁止说的话】
- "这要看个人情况" - 太敷衍
- "每个选择都有利弊" - 废话
- "建议你多方面考虑" - 等于没说
- "follow your heart" - 这不是张雪峰风格

【张雪峰经典语录参考】
- "你要是普通家庭，就别想着搞那些虚的"
- "文科选学校，理科选专业"
- "能上985不上211，能上211不上普通一本"
- "生化环材，四大天坑"
- "金融这行，家里没资源别碰"

记住：家长和学生来问你，是要一个明确的建议，不是要听你说"都行"。"""


def should_trigger(message: str) -> bool:
    """检测是否应该触发本 Skill"""
    message_lower = message.lower()
    for keyword in TRIGGER_KEYWORDS:
        if keyword in message_lower:
            return True
    return False


def extract_intent(message: str) -> Dict[str, Any]:
    """从用户消息中提取意图和关键信息"""
    intent = {
        "raw_message": message,
        "topic": None,
        "major": None,
        "school": None,
        "score_range": None,
        "region": None,
    }

    # 提取专业关键词
    major_keywords = [
        "计算机", "软件工程", "人工智能", "电子", "通信", "机械", "土木",
        "建筑", "医学", "临床", "护理", "金融", "经济", "会计", "法律",
        "法学", "师范", "教育", "英语", "中文", "新闻", "传媒", "设计",
        "艺术", "生物", "化学", "环境", "材料", "数学", "物理", "心理",
        "哲学", "历史", "政治", "地理",
    ]

    for major in major_keywords:
        if major in message:
            intent["major"] = major
            break

    # 提取分数段
    score_patterns = [
        r"(\d+)分", r"(\d+)多分", r"(\d+)左右",
        r"一本线", r"二本线", r"专科线",
        r"985", r"211", r"双一流",
        r"一本", r"二本", r"三本", r"专科",
    ]

    for pattern in score_patterns:
        match = re.search(pattern, message)
        if match:
            intent["score_range"] = match.group(0)
            break

    # 提取地区
    region_keywords = [
        "北京", "上海", "广州", "深圳", "杭州", "南京", "武汉", "成都",
        "西安", "天津", "重庆", "苏州", "青岛", "大连", "厦门", "宁波",
        "山东", "江苏", "浙江", "广东", "河南", "河北", "湖北", "湖南",
        "四川", "陕西", "辽宁", "吉林", "黑龙江", "福建", "安徽", "江西",
    ]

    for region in region_keywords:
        if region in message:
            intent["region"] = region
            break

    # 判断话题类型
    if "专业" in message or intent["major"]:
        intent["topic"] = "major"
    elif "学校" in message or "大学" in message or "院校" in message:
        intent["topic"] = "school"
    elif "考研" in message:
        intent["topic"] = "postgraduate"
    elif "考公" in message or "公务员" in message:
        intent["topic"] = "civil_service"
    elif "就业" in message or "工作" in message:
        intent["topic"] = "career"
    else:
        intent["topic"] = "general"

    return intent


def get_knowledge_base_path() -> Path:
    """获取知识库路径"""
    return Path.home() / ".zhang-xuefeng" / "knowledge_base"


def check_knowledge_base() -> bool:
    """检查知识库是否已激活"""
    kb_path = get_knowledge_base_path()
    index_path = kb_path / "index"
    return index_path.exists() and any(index_path.iterdir())


def handle_message(message: str) -> Optional[str]:
    """
    处理用户消息的主入口
    返回：如果触发，返回增强的系统提示词；如果不触发，返回 None
    """
    if not should_trigger(message):
        return None

    # 检查知识库是否已激活
    if not check_knowledge_base():
        return "⚠️ 知识库未下载，无法回答您的问题。\n\n知识库请到 vdoob.com 下载，安装后即可使用张雪峰AI助手。"

    intent = extract_intent(message)

    # 构建增强的提示词
    enhanced_prompt = f"""{ZHANG_XUEFENG_SYSTEM_PROMPT}

【用户问题】
{message}

【提取的关键信息】
- 话题类型: {intent['topic']}
- 涉及专业: {intent['major'] or '未提及'}
- 分数/层次: {intent['score_range'] or '未提及'}
- 地区偏好: {intent['region'] or '未提及'}

【回答要求】
1. 用张雪峰的风格回答
2. 给出明确观点，不要模棱两可
3. 用大白话，不要说教
4. 如果有风险要直接指出来

请直接回答用户问题：
"""

    return enhanced_prompt


def get_activation_status() -> Dict[str, Any]:
    """获取知识库激活状态"""
    kb_path = get_knowledge_base_path()
    return {
        "activated": check_knowledge_base(),
        "knowledge_base_path": str(kb_path),
        "message": "知识库已激活" if check_knowledge_base() else "知识库未激活，请访问 vdoob.com 购买激活码"
    }


# OpenClaw Skill 入口点
def main():
    """Skill 主入口"""
    print("=" * 50)
    print("张雪峰AI Skill 已加载")
    print("=" * 50)
    print("触发关键词：张雪峰、高考志愿、选专业、院校选择等")
    print("=" * 50)

    status = get_activation_status()
    print(f"知识库状态: {status['message']}")

    return {
        "name": "zhang-xuefeng-ai",
        "version": "1.0.0",
        "trigger_keywords": TRIGGER_KEYWORDS,
        "activated": status["activated"]
    }


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)