Files
xiaoli-cli/开发文档/开发文档.md
T
Xiaoli Dev e22652fbbb feat: 增强编码能力 - 新增代码编辑器、代码搜索、Git集成
- 新增 plugins/code_editor.py: 精准代码编辑(搜索替换、批量编辑、diff对比)
- 新增 plugins/code_search.py: 代码搜索与理解(跨文件搜索、符号提取、依赖分析)
- 新增 plugins/git_tools.py: Git 版本控制(status/diff/log/commit/branch)
- 新增 core/ 模块: 配置管理、引擎管理、对话处理、显示输出、代码沙箱
- 修复 requirements.txt: 使用正确的 pip 包名(Pillow、opencv-python 等)
- 更新 unified_tool_manager.py: 兼容 Plugin 和 Liugin 两种类名
- 更新系统提示词: 增强编程工作流指导

本次更新由 mimo 自动化执行,与开发者无关。
2026-04-25 10:55:27 +08:00

739 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 小狸 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="<thinking>", # 思考开始标记
end_marker="</thinking>", # 思考结束标记
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, '<string>', '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 代码规范
- [ ] 进行了基本测试