# 小狸 Pro-CLI 开发文档 > 版本:2.0 | 更新日期:2026年3月 --- ## 目录 1. [系统架构概述](#1-系统架构概述) 2. [AI引擎开发规范](#2-ai引擎开发规范) 3. [Plugin协议开发](#3-plugin协议开发) 4. [Skill协议开发](#4-skill协议开发) 5. [MCP协议支持](#5-mcp协议支持) 6. [WebSocket API](#6-websocket-api) 7. [已加载模块列表](#7-已加载模块列表) 8. [最佳实践](#8-最佳实践) 9. [调试与测试](#9-调试与测试) 10. [常见问题](#10-常见问题) --- ## 1. 系统架构概述 ### 1.1 三大协议支持 小狸 Pro-CLI 的工具系统支持三种协议: | 协议 | 目录 | 说明 | |------|------|------| | **Plugin 协议** | `plugins/` | 小狸自有协议,简单易用 | | **Skill 协议** | `skills/` | Agent Skills 开源协议,支持 Markdown 和 Python 格式 | | **MCP 协议** | - | Model Context Protocol,Anthropic/OpenAI 标准 | ### 1.2 统一工具管理器 `unified_tool_manager.py` 协调三种协议,提供统一的工具调用接口: ```python from unified_tool_manager import UnifiedToolManager manager = UnifiedToolManager(cli_instance) manager.initialize("plugins", "skills") # Plugin 格式调用 result = manager.execute("file_manager", "read test.txt") # MCP 格式调用 result = manager.mcp_call("file_manager", {"operation": "read", "path": "test.txt"}) ``` ### 1.3 路由策略 - 优先使用 Skill 协议(如果存在同名技能) - 回退到 Plugin 协议 - 支持强制指定协议 - MCP 格式调用统一入口 --- ## 2. AI引擎开发规范 ### 2.1 文件与类命名规范 | 规范 | 说明 | |------|------| | 文件命名 | 必须以 `_engine.py` 结尾 | | 类命名 | 使用驼峰命名,如 `Qwen3CoderPlusAI` | **示例:** - 文件:`qwen3-coder-plus_engine.py` - 类名:`Qwen3CoderPlusAI` ### 2.2 引擎配置声明 ```python class MyEngineAI: # 配置属性 requires_api_key = True # 是否需要API密钥 default_base_url = "https://api.example.com/v1" default_model = "my-model" def __init__(self): self.name = "my_engine" # 初始化代码... ``` ### 2.3 核心接口 ```python def generate_response(self, user_input, tool_results=None, system_prompt=None): """ 生成AI响应 参数: user_input: 用户输入文本 tool_results: 工具执行结果(可选) system_prompt: 系统提示词(可选,由主程序生成) 返回: AI响应字符串 """ pass def get_help_info(self): """返回引擎帮助信息""" return "引擎帮助信息..." ``` ### 2.4 禁止设置超时 ```python # ✅ 正确 response = requests.post(url, json=body, headers=headers, timeout=None) # ❌ 错误 response = requests.post(url, json=body, headers=headers, timeout=30) ``` ### 2.5 SDK快速开发 使用 SDK,只需几行代码就能完成引擎开发: ```python from SDK_openAI import * class MyAIAI: def __init__(self): engine_Online("on") # 云模式 ai_name("my_ai") ai_api_url("https://api.example.com/v1") ai_api_key("your_api_key") ai_model_id("gpt-3.5-turbo") self.name = "my_ai" self.cli = None self.shared_conversation_history = None def set_cli(self, cli): set_cli(cli) self.cli = cli def generate_response(self, user_input, tool_results=None, system_prompt=None): set_shared_history(self.shared_conversation_history) return generate_response(user_input, tool_results, system_prompt) ``` ### 2.6 SDK方法说明 | 方法 | 说明 | |------|------| | `engine_Online("on"/"off")` | 云模式/本地模式 | | `ai_name(name)` | 设置引擎名称 | | `ai_api_url(url)` | 设置API地址 | | `ai_api_key(key)` | 设置API密钥 | | `ai_model_id(model)` | 设置模型名称 | | `ai_thinking_engine(...)` | 深度思考引擎配置 | ### 2.7 深度思考引擎配置 适用于 QwQ、DeepSeek-R1 等会输出思考过程的模型: ```python ai_thinking_engine( enable=True, # 启用深度思考 start_marker="", # 思考开始标记 end_marker="", # 思考结束标记 show_thinking=True # 显示思考过程 ) ``` --- ## 3. Plugin协议开发 ### 3.1 基本结构 ```python class Plugin: """插件描述""" def __init__(self): self.usage = "使用方法说明" self.cli = None def set_cli(self, cli): """设置CLI引用(可选)""" self.cli = cli def get_tool_info(self): """返回工具信息(必需)""" return { "name": "tool_name", "description": "工具描述", "keywords": ["关键词1", "关键词2"], "usage": self.usage } def get_mcp_definition(self): """返回MCP格式定义(可选)""" return { "name": "tool_name", "description": "工具描述", "inputSchema": { "type": "object", "properties": { "operation": {"type": "string"}, "path": {"type": "string"} }, "required": ["operation"] } } def convert_mcp_args(self, arguments): """转换MCP参数(可选)""" return f"{arguments.get('operation', '')} {arguments.get('path', '')}" def handle(self, args: str) -> str: """处理工具调用(必需)""" try: # 实现逻辑 return "处理结果" except Exception as e: return f"错误: {str(e)}" ``` ### 3.2 完整示例:文件管理器 ```python import os from typing import Dict, Any, List class Plugin: """文件管理器插件""" def __init__(self): self.usage = """文件管理器使用方法: file_manager <操作> <参数> 操作类型: - list <路径> - 列出目录内容 - read <文件路径> - 读取文件内容 - write <文件路径> -c "内容" - 写入文件 - delete <路径> - 删除文件或目录 """ self.cli = None def set_cli(self, cli): self.cli = cli def get_tool_info(self): return { "name": "file_manager", "description": "文件和目录管理工具", "keywords": ["文件", "目录", "管理", "file"], "usage": self.usage } def get_mcp_definition(self) -> Dict[str, Any]: return { "name": "file_manager", "description": "文件和目录管理工具", "inputSchema": { "type": "object", "properties": { "operation": { "type": "string", "enum": ["list", "read", "write", "delete"], "description": "操作类型" }, "path": {"type": "string", "description": "路径"}, "content": {"type": "string", "description": "内容"} }, "required": ["operation"] } } def convert_mcp_args(self, arguments: Dict[str, Any]) -> str: op = arguments.get("operation", "") path = arguments.get("path", "") content = arguments.get("content", "") if content: return f'{op} {path} -c "{content}"' return f"{op} {path}" def handle(self, args: str) -> str: parts = args.strip().split(maxsplit=2) if not parts: return "错误:请提供操作类型" operation = parts[0].lower() if operation == "list": return self._op_list(parts[1:] if len(parts) > 1 else ["."]) elif operation == "read": return self._op_read(parts[1:] if len(parts) > 1 else []) elif operation == "write": return self._op_write(parts[1:]) elif operation == "delete": return self._op_delete(parts[1:]) return f"错误:不支持的操作 '{operation}'" def _op_list(self, args: List[str]) -> str: path = args[0] if args else "." if not os.path.exists(path): return f"错误:路径不存在: {path}" # 实现列出目录逻辑... return f"目录内容: {path}" def _op_read(self, args: List[str]) -> str: if not args: return "错误:请提供文件路径" # 实现读取文件逻辑... return "文件内容..." def _op_write(self, args: List[str]) -> str: if len(args) < 2: return "错误:请提供文件路径和内容" # 实现写入文件逻辑... return "写入成功" def _op_delete(self, args: List[str]) -> str: if not args: return "错误:请提供路径" # 实现删除逻辑... return "删除成功" ``` ### 3.3 参数格式规范 **多操作插件格式:** ``` <操作类型> <目标对象> [可选内容] ``` 示例:`read file.txt`、`write file.txt 内容` **单参数插件格式:** ``` <待处理内容> ``` 示例:`2+3`、`hello world` --- ## 4. Skill协议开发 ### 4.1 Python格式技能 ```python # skills/my_skill/__init__.py from skills.base import Skill, SkillResult class MySkill(Skill): """我的技能""" name = "my_skill" description = "技能描述" tags = ["标签1", "标签2"] def get_tool_definition(self): return { "type": "function", "function": { "name": self.name, "description": self.description, "parameters": { "type": "object", "properties": { "operation": {"type": "string"} } } } } def run(self, **kwargs) -> SkillResult: try: operation = kwargs.get("operation", "") # 实现逻辑 return SkillResult( success=True, message="执行成功", data={"result": "..."} ) except Exception as e: return SkillResult( success=False, error=str(e) ) ``` ### 4.2 Markdown格式技能 ```markdown # skills/my_skill/SKILL.md --- name: my_skill description: 技能描述 tags: [标签1, 标签2] --- # 技能说明 这是技能的详细使用说明... ## 使用方法 1. 步骤一 2. 步骤二 ``` --- ## 5. MCP协议支持 ### 5.1 MCP工具定义格式 ```python { "name": "tool_name", "description": "工具描述", "inputSchema": { "type": "object", "properties": { "param1": {"type": "string", "description": "参数说明"}, "param2": {"type": "integer", "description": "参数说明"} }, "required": ["param1"] } } ``` ### 5.2 MCP调用格式 **请求:** ```json { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "file_manager", "arguments": { "operation": "read", "path": "test.txt" } } } ``` **响应:** ```json { "jsonrpc": "2.0", "id": 1, "result": { "content": [ {"type": "text", "text": "文件内容..."} ], "isError": false } } ``` ### 5.3 统一工具管理器MCP接口 ```python # 获取MCP工具列表 tools = manager.get_mcp_tools() # MCP格式调用 result = manager.mcp_call("file_manager", {"operation": "read", "path": "test.txt"}) # 处理MCP请求 response = manager.handle_mcp_request({ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {...} }) ``` --- ## 6. WebSocket API ### 6.1 消息类型 | 类型 | 方向 | 说明 | |------|------|------| | `heartbeat` | 双向 | 心跳检测 | | `auth` | 客户端→服务端 | 认证请求 | | `auth_success` / `auth_failed` | 服务端→客户端 | 认证结果 | | `message` | 双向 | 文本消息 | | `file` | 客户端→服务端 | 文件上传 | | `image` | 服务端→客户端 | 图片发送 | | `tool_status` | 服务端→客户端 | 工具状态 | ### 6.2 消息格式示例 **认证请求:** ```json {"type": "auth", "password": "your_password"} ``` **发送消息:** ```json {"type": "message", "content": "你好"} ``` **上传文件:** ```json { "type": "file", "file": "base64_encoded_data", "filename": "example.txt", "text": "附加说明" } ``` ### 6.3 启动远程服务 ```bash # 本地模式 /remote start 9079 your_password # 代理模式 /remote proxy relay.example.com:9079 server_pwd 12345 pc_pwd ``` --- ## 7. 已加载模块列表 ### 7.1 AI引擎 | 引擎名 | 类型 | 说明 | |--------|------|------| | ollama | 本地 | Ollama本地模型,无需API密钥 | | glm | 云端 | 智谱GLM | | spark | 云端 | 讯飞星火 | | qwq | 云端 | QwQ深度思考引擎 | | qwen | 云端 | 通义千问 | ### 7.2 插件 | 插件名 | 功能 | |--------|------| | file_manager | 文件管理(14种操作) | | ai_search | AI搜索 | | audio_player | 音频播放 | | cmd_executor | 命令执行 | | frontend_tester | 前端测试 | | glados_tts_plugin | GLaDOS语音合成 | | napcat_qq | QQ机器人 | | network_tools | 网络工具 | | ollama_image | Ollama图像 | | send_image | 发送图片 | | speech_recognition | 语音识别 | | task_manager | 任务管理 | | tool_search | 工具搜索 | --- ## 8. 最佳实践 ### 8.1 安全性 ```python # ❌ 避免使用危险函数 result = eval(user_input) # 危险! # ✅ 安全的替代方案 import ast try: tree = ast.parse(user_input, mode='eval') result = eval(compile(tree, '', 'eval')) except: return "无效表达式" ``` ### 8.2 输入验证 ```python def handle(self, args: str) -> str: # 参数验证 if not args: return "错误:参数不能为空" # 长度限制 if len(args) > 10000: return "错误:输入过长" # 格式验证 if not re.match(r'^[\w\s\-\.]+$', args): return "错误:包含非法字符" # 继续处理... ``` ### 8.3 错误处理 ```python def handle(self, args: str) -> str: try: # 业务逻辑 return "结果" except FileNotFoundError: return "错误:文件不存在" except PermissionError: return "错误:权限不足" except Exception as e: return f"错误: {str(e)}" ``` ### 8.4 资源管理 ```python # 使用上下文管理器 with open(file_path, 'r', encoding='utf-8') as f: content = f.read() # 或确保资源释放 try: f = open(file_path, 'r') content = f.read() finally: f.close() ``` --- ## 9. 调试与测试 ### 9.1 日志记录 ```python def handle(self, args: str) -> str: if self.cli: print(f"[DEBUG] 插件被调用: {args}") # 处理逻辑 return "结果" ``` ### 9.2 单元测试 ```python import unittest from plugins.file_manager import Plugin class TestFileManager(unittest.TestCase): def setUp(self): self.plugin = Plugin() def test_get_tool_info(self): info = self.plugin.get_tool_info() self.assertIn("name", info) self.assertEqual(info["name"], "file_manager") def test_handle_list(self): result = self.plugin.handle("list .") self.assertIsInstance(result, str) if __name__ == "__main__": unittest.main() ``` ### 9.3 集成测试 ```python # integration_test.py import sys import os sys.path.insert(0, os.path.dirname(__file__)) from ai_cli import AICLI def test_integration(): cli = AICLI() # 测试插件调用... ``` --- ## 10. 常见问题 ### Q1: 插件不加载? 检查以下几点: - 文件是否放在 `plugins/` 目录 - 类名是否为 `Plugin` - 是否实现了 `get_tool_info()` 和 `handle()` 方法 - 文件名是否为 `.py` 结尾 ### Q2: 插件不被调用? 检查: - 关键词是否匹配用户输入 - `keywords` 列表是否正确设置 - 插件是否成功加载(查看启动日志) ### Q3: MCP格式调用失败? 确保: - 实现了 `get_mcp_definition()` 方法 - 实现了 `convert_mcp_args()` 方法(如果需要) - `inputSchema` 格式正确 ### Q4: 如何调试? - 在 `handle()` 方法中添加 `print()` 语句 - 检查返回值是否为字符串 - 查看主程序日志 ### Q5: 如何处理大文件? ```python # 限制输出长度 MAX_LENGTH = 10000 if len(content) > MAX_LENGTH: content = content[:MAX_LENGTH] + "\n... (内容已截断)" ``` --- ## 附录:插件开发检查清单 - [ ] 插件类名是 `Plugin` - [ ] 实现了 `get_tool_info()` 方法 - [ ] 实现了 `handle(args)` 方法 - [ ] 返回字符串结果 - [ ] 包含 `usage` 属性 - [ ] 可选:实现 `get_mcp_definition()` 支持 MCP - [ ] 可选:实现 `convert_mcp_args()` 转换参数 - [ ] 所有异常都被捕获 - [ ] 遵循参数格式规范 - [ ] 遵循 PEP 8 代码规范 - [ ] 进行了基本测试