# 5. 功能扩展

Jarvis 的强大之处在于其高度的可扩展性。通过创建自己的工具和平台，您可以让 Jarvis 与您的私有API、内部数据库、专有系统或任何您需要的服务进行交互。

本章将指导您完成创建、测试和部署自定义功能的全过程。Jarvis 支持三种主要的功能扩展方式：

1. **标准工具开发**：通过创建符合规范的 Python 类来定义新工具。
2. **MCP 工具集成**：通过配置文件连接到外部的“模型上下文协议”(Model Context Protocol)，快速集成用任何语言编写的现有工具集。
3. **平台扩展**：通过创建 Python 类来集成新的大语言模型平台。

---

## 5.1 标准工具开发 (Python 类)

这是最常用、最直接的工具开发方式。

### 工具加载位置

Jarvis 启动时会从以下位置自动扫描并加载工具文件 (`.py`):

1. **内置工具**: `src/jarvis/jarvis_tools/` (Jarvis 源码内部)
2. **用户自定义工具**: `~/.jarvis/tools/` (推荐存放您个人工具的地方)
3. **额外工具目录**: 由 `tool_load_dirs` 配置指定的目录列表。

#### 通过 Git 共享和同步工具

与方法论类似，`tool_load_dirs` 的设计也考虑到了团队协作和版本控制。您可以将一个或多个包含Jarvis工具的Git仓库作为共享的工具库。

1. **创建工具仓库**: 创建一个 Git 仓库，用于存放团队共享的工具 (`.py` 文件)。
2. **克隆仓库**: 团队成员将此仓库克隆到本地。
3. **设置配置**: 设置 `tool_load_dirs` 指向该仓库的本地路径。可以指定多个路径，使用列表格式。

```bash
# 例如，将团队的工具仓库克隆到 ~/git/team-tools
git clone https://github.com/your-org/team-tools.git ~/git/team-tools

# 在 ~/.jarvis/config.yaml 中设置
tool_load_dirs:
  - ~/git/team-tools
```

设置完成后，Jarvis不仅会从该目录加载工具，还会**每日自动执行 `git pull`**，拉取最新的工具代码，确保团队成员的工具集保持同步。

#### 中心工具库

Jarvis 支持中心工具库功能，允许团队建立一个集中管理的工具仓库，所有成员可以共享和使用统一的工具集。

##### 配置中心工具库

通过设置 `central_tool_repo` 配置来指定中心工具库的 Git 仓库地址：

```yaml
# 在 ~/.jarvis/config.yaml 中设置
central_tool_repo: "https://github.com/your-org/central-tools.git"
```

配置后，Jarvis 会：

1. 自动克隆中心工具库到 `~/.jarvis/central_tool_repo`
2. 每日自动更新中心工具库（执行 `git pull`）
3. 从中心工具库加载所有工具

##### 工具加载优先级

当存在同名工具时，加载优先级从低到高为：

1. 内置工具（最低优先级）
2. 本地工具（`~/.jarvis/tools/`）
3. 外部目录工具（`tool_load_dirs`）
4. 中心工具库（最高优先级）

如果发现同名工具，系统会显示警告信息，后加载的工具会覆盖先加载的。

##### 分享工具到中心库

您可以将本地开发的优秀工具分享到中心工具库，供团队其他成员使用：

```bash
# 分享本地工具到中心工具库
jarvis --share-tool
```

执行此命令后：

1. 显示本地 `~/.jarvis/tools/` 目录中可分享的工具列表（排除已存在的）
2. 支持选择单个或多个工具（格式：1,2,3 或 4-9 或 all）
3. **注意**：工具文件会被**移动**到中心库，而不是复制，原文件将被删除
4. 自动提交并推送到中心工具库

##### 使用示例

```bash
# 1. 配置中心工具库（在 ~/.jarvis/config.yaml 中设置）
# central_tool_repo: "https://github.com/team/jarvis-tools.git"

# 2. 启动 Jarvis（会自动加载中心工具库）
jarvis

# 3. 开发新工具并测试
echo 'class my_awesome_tool: ...' > ~/.jarvis/tools/my_awesome_tool.py

# 4. 分享到中心库
jarvis --share-tool
# 选择 my_awesome_tool 并确认
# 工具会被移动到中心库，团队成员下次启动时会自动获得这个工具
```

### 工具类的核心规范

一个标准的工具类必须遵循以下规范：

1. **文件名与工具名匹配 (关键)**: 工具文件名 (不含 `.py` 后缀) **必须**与工具类内部的 `name` 属性完全一致。这是Jarvis能够找到并注册工具的硬性约定。
   - **正确**: 文件 `my_tool.py` -> 类属性 `name = "my_tool"`
   - **错误**: 文件 `my_tool.py` -> 类属性 `name = "MyTool"` 或 `name = "some_other_name"`

2. **类属性**:
   - `name`: (字符串) 工具的唯一名称，与文件名匹配。
   - `description`: (字符串) 工具功能的清晰描述。AI会根据这个描述来判断何时使用该工具。
   - `parameters`: (字典) 定义工具所需参数的 JSON Schema。

3. **类方法**:
   - `execute(self, args)`: (方法) 工具的实际执行逻辑。
   - `check()`: (可选的 `@staticmethod`) 一个静态方法，用于在加载工具前进行前置检查。如果 `check()` 方法存在并且返回 `False`，该工具将被跳过，不会加载。这可以用于检查依赖项是否存在、API密钥是否配置等。

### 开发步骤

让我们创建一个新工具，它能读取 `.ini` 配置文件。

#### 第1步：创建工具文件

根据命名约定，我们想创建一个名为 `read_ini_section` 的工具，所以文件名必须是 `read_ini_section.py`。

在 `~/.jarvis/tools/` 目录下创建 `read_ini_section.py` 文件。

#### 第2步：编写工具类

在 `read_ini_section.py` 文件中，写入以下代码：

```python
import configparser
from typing import Dict, Any

class ReadIniSectionTool:
    # 1. 工具名称 (必须与文件名 "read_ini_section" 匹配)
    name = "read_ini_section"

    # 2. 工具描述 (给AI看，必须清晰)
    description = "读取 .ini 格式的配置文件中指定 section 的所有内容。"

    # 3. 参数定义 (使用JSON Schema)
    parameters = {
        "type": "object",
        "properties": {
            "file_path": {
                "type": "string",
                "description": "要读取的 .ini 文件的完整路径。"
            },
            "section_name": {
                "type": "string",
                "description": "要读取的配置项所在的 section 名称。"
            }
        },
        "required": ["file_path", "section_name"]
    }

    # 4. (可选) 前置检查
    @staticmethod
    def check() -> bool:
        # 这里的依赖 'configparser' 是标准库，所以我们直接返回 True。
        # 如果你的工具依赖第三方库，可以在这里检查。
        # try:
        #     import some_dependency
        # except ImportError:
        #     print("警告: 'some_dependency' 未安装，'read_ini_section' 工具已禁用。")
        #     return False
        return True

    # 5. 执行逻辑
    def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
        file_path = args.get("file_path")
        section_name = args.get("section_name")

        try:
            if not file_path or not section_name:
                raise ValueError("错误：必须同时提供 file_path 和 section_name。")

            config = configparser.ConfigParser()
            if not config.read(file_path):
                raise FileNotFoundError(f"错误：配置文件 '{file_path}' 不存在或无法读取。")

            if not config.has_section(section_name):
                raise ValueError(f"错误：在配置文件中未找到名为 '{section_name}' 的 section。")

            section_content = dict(config.items(section_name))
            return {
                "success": True,
                "stdout": str(section_content),
                "stderr": ""
            }
        except Exception as e:
            return {
                "success": False,
                "stdout": "",
                "stderr": f"执行工具时发生错误: {str(e)}"
            }
```

#### 第3步：测试工具

无需额外注册，只需重新启动 `jarvis` (`jvs`)，新工具就会被自动加载。

1. **检查加载**: 输入 `'ToolUsage'` 查看工具列表，确认 `read_ini_section` 已在其中。
2. **自然语言测试**: 给 Jarvis 一个任务，例如：`请帮我读取 /path/to/my/app.ini 文件中 [database] section 的内容。`

---

## 5.2 MCP 工具集成

MCP (Model Context Protocol) 是一种强大的机制，允许 Jarvis 通过标准输入/输出 (stdio) 或 HTTP 等方式与外部工具集进行通信。这意味着您可以用任何语言（如 Go, Rust, Node.js）编写工具，并将它们作为一个整体接入 Jarvis。

### 配置方法

MCP 工具通过 `config.yaml` 文件中的 `mcp` 列表进行配置。每个列表项都定义了一个MCP客户端。

Jarvis 支持以下三种类型的 MCP 客户端：

#### 1. `stdio` (标准输入输出)

用于集成在本地运行的、通过标准输入输出进行通信的命令行程序。

- **工作流程**: Jarvis 启动时会执行您指定的 `command`，然后通过 `stdin` 发送 JSON-RPC 请求，并通过 `stdout` 接收响应。
- **适用场景**: 将现有的、独立的命令行工具快速封装为 Jarvis 可用的工具集。

**配置参数**:

- `type`: `"stdio"` (必须)
- `name`: 为此工具集指定的唯一名称 (可选)
- `command`: 启动工具程序的完整命令 (必须)
- `args`: 命令参数列表 (可选，数组格式)
- `env`: 环境变量 (可选，对象格式)
- `enable`: 是否启用此配置 (可选, 默认为 `true`)

**示例**:

```yaml
mcp:
  - type: "stdio"
    name: "my_cli_tools"
    command: "/path/to/your/tool_program"
    args: ["--json-rpc", "--verbose"]
    env:
      CUSTOM_VAR: "value"
    enable: true
```

#### 2. `sse` (Server-Sent Events)

用于连接支持 Server-Sent Events 的远程 HTTP 服务器。SSE 允许服务器向客户端推送事件流。

- **工作流程**: Jarvis 会向 `base_url` 发起一个持久的 HTTP 连接，并通过这个连接接收来自服务器的事件流。
- **适用场景**: 需要与远程服务进行实时、长连接通信的场景。

**配置参数**:

- `type`: `"sse"` (必须)
- `name`: 唯一的名称 (可选)
- `base_url`: 远程 MCP 服务器的基础 URL (必须)
- `auth_token`: 用于认证的令牌 (可选)
- `headers`: 额外的 HTTP 请求头 (可选，对象格式)
- `enable`: 是否启用 (可选, 默认为 `true`)

**示例**:

```yaml
mcp:
  - type: "sse"
    name: "realtime_data_service"
    base_url: "https://api.example.com/mcp"
    auth_token: "your-secret-token"
    headers:
      X-Custom-Header: "value"
    enable: true
```

#### 3. `streamable` (流式HTTP)

用于连接支持标准流式 HTTP 响应的远程服务器。

- **工作流程**: Jarvis 发送一个标准的 HTTP POST 请求，服务器以流的形式返回响应体。这比 SSE 更简单，但只能单向（服务器到客户端）流式传输。
- **适用场景**: 调用返回大量数据、适合分块读取的远程 API。

**配置参数**:

- `type`: `"streamable"` (必须)
- `name`: 唯一的名称 (可选)
- `base_url`: 远程 MCP 服务器的基础 URL (必须)
- `auth_token`: 用于认证的令牌 (可选)
- `headers`: 额外的 HTTP 请求头 (可选，对象格式)
- `endpoint_path`: MCP 服务器端点路径 (可选，默认为 `"mcp"`)。如果 `base_url` 已包含端点路径，可设置为空字符串
- `timeout`: 请求超时时间数组 `[连接超时, 读取超时]` (可选，默认 `[10, 300]`，单位：秒)
- `enable`: 是否启用 (可选, 默认为 `true`)

**示例**:

```yaml
mcp:
  - type: "streamable"
    name: "large_file_processor"
    base_url: "https://stream.example.com/api"
    auth_token: "your-secret-token"
    endpoint_path: "mcp" # 可选，默认为 "mcp"
    timeout: [10, 300] # 可选，[连接超时, 读取超时] 秒
    enable: true
```

---

## 5.3 平台扩展 (Python 类)

除了工具和MCP，Jarvis还允许您集成新的大语言模型平台。这使您可以连接到专有模型、内部部署的LLM服务或任何未被官方支持的API。

### 平台加载位置

Jarvis会从以下位置自动加载平台适配器 (`.py`):

1. **内置平台**: `src/jarvis/jarvis_platform/` (Jarvis源码内部)
2. **用户自定义平台**: `~/.jarvis/models/` (推荐存放您个人平台适配器的地方; 首次运行会自动创建目录与 `__init__.py`)

注意：

- 加载顺序为“用户目录 -> 内置目录”。如存在同名平台，后加载的实现将覆盖先加载的实现（当前实现表现为“内置覆盖用户定义”）。

### 平台类的核心规范

一个标准的平台类必须遵循以下规范：

1. **继承基类**: 必须继承自 `jarvis.jarvis_platform.base.BasePlatform`。
2. **实现抽象方法**: 必须实现基类中所有的抽象方法。`PlatformRegistry` 在加载时会进行严格检查。

根据 `src/jarvis/jarvis_platform/registry.py` 的 `REQUIRED_METHODS` 和 `base.py` 的定义，一个平台类必须实现以下方法：

- `chat(self, message: str) -> Generator[str, None, None]`: 核心对话方法，以流式生成器方式返回模型的响应。
- `name(self) -> str`: 返回当前平台的名称。
- `platform_name(cls) -> str` (类方法): 返回平台的唯一标识符，用于在配置中指定平台。
- `set_model_name(self, model_name: str)`: 设置当前对话使用的具体模型名称。
- `get_model_list(self) -> List[Tuple[str, str]]`: 返回平台支持的模型列表，格式为 `(模型ID, 模型描述)`。
- `delete_chat(self) -> bool`: 清除当前对话上下文。
- `set_system_prompt(self, message: str)`: 设置系统级提示词。
- `upload_files(self, file_list: List[str]) -> bool`: (如果支持) 实现文件上传逻辑。
- `support_upload_files(self) -> bool`: 返回平台是否支持文件上传。
- `save(self, file_path: str) -> bool`: (可选) 保存对话状态。
- `restore(self, file_path: str) -> bool`: (可选) 恢复对话状态。

### 开发步骤

假设我们要集成一个名为 `MyLLM` 的新平台。

#### 第1步：创建平台文件

在 `~/.jarvis/models/` 目录下创建 `my_llm.py` 文件。

#### 第2步：编写平台类

在 `my_llm.py` 文件中，写入以下代码骨架：

```python
import os
from typing import Generator, List, Tuple
from jarvis.jarvis_platform.base import BasePlatform

class MyLLMPlatform(BasePlatform):

    def __init__(self):
        super().__init__()
        # 在这里初始化API客户端、会话等
        self.api_key = os.getenv("MYLLM_API_KEY")
        if not self.api_key:
            raise ValueError("环境变量 MYLLM_API_KEY 未设置")
        self._current_model = "default-model"
        self._conversation_history = []

    @classmethod
    def platform_name(cls) -> str:
        # 这个名称将用于 config.yaml 中的 platform
        return "my_llm"

    def name(self) -> str:
        return f"MyLLMPlatform ({self._current_model})"

    def set_model_name(self, model_name: str):
        self._current_model = model_name

    def get_model_list(self) -> List[Tuple[str, str]]:
        # 返回你的平台支持的模型列表
        return [("default-model", "默认模型"), ("pro-model", "专业模型")]

    def chat(self, message: str) -> Generator[str, None, None]:
        # 在这里实现与你的LLM API的交互逻辑
        # ... 调用API ...
        # 假设API返回一个完整的字符串
        # for char in api_response:
        #     yield char
        self._conversation_history.append({"role": "user", "content": message})

        # 模拟流式响应
        response_text = f"模拟回复 {message}"
        self._conversation_history.append({"role": "assistant", "content": response_text})
        yield response_text

    def set_system_prompt(self, message: str):
        # 实现设置系统提示词的逻辑
        self._conversation_history.insert(0, {"role": "system", "content": message})

    def delete_chat(self) -> bool:
        # 清空对话历史
        self._conversation_history = []
        return True

    def upload_files(self, file_list: List[str]) -> bool:
        # 如果不支持，直接返回False
        print("MyLLM 平台不支持文件上传。")
        return False

    def support_upload_files(self) -> bool:
        return False

    def save(self, file_path: str) -> bool:
        # 可选实现
        return False

    def restore(self, file_path: str) -> bool:
        # 可选实现
        return False
```

#### 第3步：配置并使用

1. **设置配置**:

```yaml
# 在 ~/.jarvis/config.yaml 中设置
platform: my_llm
model: pro-model # 可选，根据你的实现
ENV:
  MYLLM_API_KEY: "YOUR_API_KEY"
```

2. **启动Jarvis**: 重新启动 `jarvis`，它会自动加载并使用你的新平台。

---

## 5.4 方法论共享配置

Jarvis 支持团队级别的方法论共享，通过配置中心方法论仓库，团队成员可以：

- 共享和复用经过验证的解决方案
- 自动同步最新的方法论更新
- 避免重复工作，提高团队效率

### 配置中心方法论仓库

在 `~/.jarvis/config.yaml` 中添加以下配置：

```yaml
# 中心方法论Git仓库地址
central_methodology_repo: https://github.com/your-org/jarvis-methodologies.git

# 额外的方法论加载目录（可选）
methodology_dirs:
  - ~/git/team-methodologies
  - /shared/methodologies
```

### 工作原理

1. **自动克隆和更新**：
   - 首次使用时，Jarvis 会自动克隆中心仓库到 `~/.jarvis/central_methodology_repo`
   - 每日启动时自动执行 `git pull` 更新最新方法论

2. **方法论加载优先级**：
   - 本地方法论目录：`~/.jarvis/methodologies`
   - 中心方法论仓库：`~/.jarvis/central_methodology_repo`
   - 额外配置目录：`methodology_dirs` 指定的目录

3. **重复检测**：
   - 当存在同名方法论时，优先使用先加载的版本
   - 分享功能会自动检测并排除已存在的方法论

### 分享方法论到中心仓库

使用以下命令将本地方法论分享到团队：

```bash
jarvis --share-methodology
```

分享流程：

1. 自动更新中心仓库到最新版本
2. 检测并显示可分享的方法论（排除重复）
3. 支持批量选择要分享的方法论
4. 自动复制文件并提交到远程仓库

### 最佳实践

- **规范命名**：使用清晰、描述性的问题类型名称
- **定期更新**：定期拉取中心仓库的更新
- **质量控制**：分享前确保方法论经过充分验证
- **文档说明**：在方法论中包含使用说明和注意事项

---

## 5.5 规则系统扩展

Jarvis 的规则系统允许您创建和管理自定义规则，用于指导 AI 的行为和代码生成。规则可以以多种方式组织和共享，支持团队协作和知识复用。

### 规则类型

Jarvis 支持两种规则格式：

1. **纯文本规则文件**：简单的文本文件，包含规则内容
   - 全局规则：`~/.jarvis/rule` 或 `~/.jarvis/rules/<规则名>`
   - 项目规则：`.jarvis/rule` 或 `.jarvis/rules/<规则名>`

2. **命名规则文件（YAML）**：结构化的 YAML 文件，可以定义多个命名规则
   - 全局规则：`~/.jarvis/rules.yaml`
   - 项目规则：`.jarvis/rules.yaml`

### 规则加载位置和优先级

Jarvis 会从以下位置按优先级加载规则（从高到低）：

1. **中心规则仓库**（最高优先级）
   - 配置项：`central_rules_repo`
   - 存储位置：`~/.jarvis/central_rules_repo`
   - 支持自动克隆和每日更新

2. **项目规则目录**
   - 位置：`.jarvis/rules/` 目录
   - 每个文件一个规则，文件名即为规则名

3. **项目规则 YAML 文件**
   - 位置：`.jarvis/rules.yaml`
   - 可以定义多个命名规则

4. **配置的规则目录**
   - 配置项：`rules_load_dirs`（列表格式）
   - 支持多个目录，按配置顺序加载

5. **全局规则 YAML 文件**
   - 位置：`~/.jarvis/rules.yaml`

6. **全局规则目录**
   - 位置：`~/.jarvis/rules/` 目录

7. **内置规则**（最低优先级）
   - Jarvis 系统内置的规则，作为后备

### 配置中心规则仓库

在 `~/.jarvis/config.yaml` 中添加以下配置：

```yaml
# 中心规则仓库 Git 地址
central_rules_repo: https://github.com/your-org/jarvis-rules.git

# 额外的规则加载目录（可选，列表格式）
rules_load_dirs:
  - ~/git/team-rules
  - /shared/rules
```

配置后，Jarvis 会：

1. 自动克隆中心规则仓库到 `~/.jarvis/central_rules_repo`
2. 每日自动更新中心规则仓库（执行 `git pull`）
3. 从中心规则仓库加载所有规则

### 创建规则

#### 方式一：创建独立规则文件

在项目 `.jarvis/rules/` 目录或全局 `~/.jarvis/rules/` 目录下创建规则文件：

```bash
# 创建项目规则
mkdir -p .jarvis/rules
echo "# TDD 规则
- 所有新功能必须先写测试
- 测试必须覆盖主要功能路径和边界情况
- 禁止使用 todo!() 宏" > .jarvis/rules/tdd

# 创建全局规则
mkdir -p ~/.jarvis/rules
echo "# 代码风格规则
- Python 代码必须遵循 PEP 8 规范
- 所有函数必须包含类型注解和 docstring" > ~/.jarvis/rules/python_style
```

#### 方式二：在 YAML 文件中定义命名规则

创建或编辑 `rules.yaml` 文件：

**项目规则**（`.jarvis/rules.yaml`）：

```yaml
# 项目特定的规则
project_style: |
  - 本项目使用 TypeScript
  - 所有接口必须定义类型
  - 使用 ESLint 进行代码检查

security: |
  - 禁止使用 eval() 和 exec()
  - 所有用户输入必须进行验证和转义
  - 敏感信息不得硬编码在代码中
```

**全局规则**（`~/.jarvis/rules.yaml`）：

```yaml
# 全局通用规则
python_best_practices: |
  - Python 代码必须遵循 PEP 8 规范
  - 所有函数必须包含类型注解和 docstring
  - 使用 Black 进行代码格式化
  - 使用 isort 进行导入排序

clean_code: |
  - 函数应该保持简短，单一职责
  - 避免深层嵌套，最多 3 层
  - 使用有意义的变量名
```

### 使用规则

#### 在 CodeAgent 中使用规则

```bash
# 使用多个规则（逗号分隔）
jca --rule-names tdd,clean_code -r "实现用户登录功能"

# 使用项目特定的规则
jca --rule-names project_style -r "添加新的 API 端点"
```

#### 在交互式输入中动态注入规则

在用户输入中使用 `'<rule:rule_name>'` 标记动态注入规则：

```bash
jca
# 然后输入：'<rule:tdd>' 实现用户登录功能
```

系统会自动查找并注入对应的规则内容。

### 分享规则到中心仓库

您可以将本地开发的优秀规则分享到中心规则仓库，供团队其他成员使用。规则分享功能通过 `RuleShareManager` 实现，可以通过编程方式调用，或等待未来版本添加 CLI 命令支持。

**注意**：只能分享默认规则目录（`~/.jarvis/rules/`）中的规则，不能分享配置的规则目录和项目规则目录中的规则。

规则分享流程：

1. 更新中心仓库到最新版本
2. 检测并显示可分享的规则列表（排除已存在的）
3. 支持选择单个或多个规则（格式：`1,2,3` 或 `4-9` 或 `all`）
4. **注意**：规则文件会被**移动**到中心库，而不是复制，原文件将被删除
5. 自动提交并推送到中心规则仓库

### 规则加载优先级示例

假设您有以下规则配置：

```
中心规则仓库: tdd, clean_code
项目 .jarvis/rules/: tdd, project_style
项目 .jarvis/rules.yaml: tdd, security
全局 ~/.jarvis/rules.yaml: python_style, clean_code
```

当使用 `--rule-names tdd,clean_code` 时：

- `tdd` 规则：从中心规则仓库加载（最高优先级）
- `clean_code` 规则：从中心规则仓库加载（如果存在），否则从全局 `rules.yaml` 加载

### 规则最佳实践

1. **命名规范**：使用清晰、描述性的规则名称，使用下划线分隔（如 `python_style`、`tdd_rules`）

2. **内容组织**：
   - 保持规则简洁明了，使用条目式清单
   - 每个规则聚焦一个主题（代码风格、测试、安全等）
   - 避免冗长的背景描述

3. **优先级管理**：
   - 通用规则放在全局规则目录
   - 项目特定规则放在项目规则目录
   - 团队共享规则放在中心规则仓库

4. **版本控制**：
   - 项目规则应该提交到 Git 仓库
   - 中心规则仓库使用 Git 进行版本管理
   - 定期更新中心规则仓库以获取最新规则

5. **规则复用**：
   - 在多个规则中引用通用规则
   - 使用 YAML 格式便于管理和维护
   - 定期审查和更新规则内容

---

## 5.6 最佳实践

- **命名约定是关键**: 务必遵守**文件名与 `name` 属性匹配**的规则，这是最常见的工具加载失败原因。
- **保持原子性**: 每个工具应该只做一件事，并把它做好。复杂的逻辑应该拆分为多个工具。
- **描述要清晰**: `description` 是写给 AI 看的，是决定工具能否被正确使用的最关键因素。
- **健壮的错误处理**: `execute` 方法必须能妥善处理错误，并通过 `stderr` 返回有意义的错误信息。
- **精确的参数定义**: `parameters` 定义要尽可能精确。使用 `description` 字段详细解释每个参数。
- **返回值为字符串**: `stdout` 和 `stderr` 字段应该是字符串。如果结果是复杂数据结构，请将其序列化为字符串（如 `json.dumps()`）。

---

## 5.7 开发环境设置

为了进行 Jarvis 的开发和扩展，建议从源码安装：

### 克隆和安装

```bash
# GitHub（推荐）
git clone https://github.com/skyfireitdiy/Jarvis.git

# 或者使用 Gitee 镜像（国内访问更快）
git clone https://gitee.com/skyfireitdiy/Jarvis.git

cd Jarvis
pip3 install -e .
```

使用 `-e`（可编辑模式）安装的好处是，您对代码的任何修改都会立即生效，无需重新安装。

### 目录结构说明

```
Jarvis/
├── src/jarvis/
│   ├── jarvis_agent/        # Agent 核心实现
│   ├── jarvis_tools/        # 内置工具集
│   ├── jarvis_platform/     # 平台适配器
│   └── jarvis_utils/        # 通用工具函数
├── docs/                    # 文档
├── tests/                   # 测试用例
└── pyproject.toml          # 项目配置文件
```

### 开发工作流

1. **创建功能分支**：

   ```bash
   git checkout -b feature/my-new-tool
   ```

2. **开发和测试**：
   - 在相应目录下创建您的代码文件
   - 编写单元测试（如果适用）
   - 本地测试您的功能

3. **代码风格**：
   - 使用 Python 3.8+ 的特性
   - 遵循 PEP 8 代码风格指南
   - 使用类型注解提高代码可读性

4. **提交规范**：
   使用语义化的提交信息格式：

   ```bash
   git commit -m "feat(tools): 添加数据库查询工具"
   git commit -m "fix(platform): 修复 OpenAI 平台的流式响应问题"
   git commit -m "docs: 更新工具开发指南"
   ```

---

## 5.8 贡献代码

我们欢迎社区的贡献！如果您开发了有用的工具或平台适配器，可以通过以下方式贡献给 Jarvis 项目：

### 贡献流程

1. **Fork 项目**：
   在 GitHub 上 Fork Jarvis 主仓库到您的账号下。

2. **创建特性分支**：

   ```bash
   git checkout -b feature/AmazingFeature
   ```

3. **提交更改**：

   ```bash
   git commit -m 'feat(scope): Add some AmazingFeature'
   ```

4. **推送分支**：

   ```bash
   git push origin feature/AmazingFeature
   ```

5. **创建 Pull Request**：
   在 GitHub 上创建 Pull Request，详细描述您的更改。

### 贡献指南

- **代码质量**：确保代码经过充分测试，没有明显的 bug
- **文档完善**：为新功能添加必要的文档说明
- **向后兼容**：尽量保持 API 的向后兼容性
- **提交信息**：使用清晰、规范的提交信息
- **单一职责**：每个 PR 应该只解决一个问题或添加一个功能

### 代码审查

提交 PR 后，维护者会进行代码审查。请耐心等待并积极响应审查意见。常见的审查要点包括：

- 代码风格是否符合项目规范
- 是否有充分的错误处理
- 是否有潜在的性能问题
- 文档是否完整清晰
