# 自定义模块开发指南

欢迎使用 AgentSociety2 自定义模块功能！本指南将帮助您创建和使用自定义的 Agent 和环境模块。

## 目录结构

```
custom/
├── agents/              # 自定义 Agent
│   └── examples/        # 官方示例（参考用）
├── envs/                # 自定义环境模块
│   └── examples/        # 官方示例（参考用）
└── README.md            # 本文档
```

## 快速开始

### 1. 创建自定义 Agent

在 `custom/agents/` 目录下创建新的 `.py` 文件，例如 `my_agent.py`：

```python
from agentsociety2.agent.base import AgentBase
from datetime import datetime

class MyAgent(AgentBase):
    """我的自定义 Agent"""

    @classmethod
    def mcp_description(cls) -> str:
        return """MyAgent: 我的自定义 Agent

这是我的第一个自定义 Agent。
"""

    async def ask(self, message: str, readonly: bool = True) -> str:
        """回答问题"""
        prompt = f"问题：{message}\n请回答："
        response = await self.acompletion([{"role": "user", "content": prompt}])
        return response.choices[0].message.content or ""

    async def step(self, tick: int, t: datetime) -> str:
        """执行仿真步骤"""
        return f"Agent {self.id} 执行步骤"

    async def dump(self) -> dict:
        """序列化状态"""
        return {"id": self._id, "profile": self._profile}

    async def load(self, dump_data: dict):
        """加载状态"""
        self._id = dump_data.get("id", self._id)
        self._profile = dump_data.get("profile", self._profile)
```

### 2. 创建自定义环境模块

在 `custom/envs/` 目录下创建新的 `.py` 文件，例如 `my_env.py`：

```python
from agentsociety2.env import EnvBase, tool
from datetime import datetime

class MyEnv(EnvBase):
    """我的自定义环境"""

    def __init__(self, config=None):
        super().__init__()
        # 初始化你的环境状态

    @classmethod
    def mcp_description(cls) -> str:
        return """MyEnv: 我的自定义环境

这是我的第一个自定义环境。
"""

    @tool(readonly=True, kind="observe")
    async def get_state(self, agent_id: int) -> dict:
        """获取状态（观察工具）"""
        return {"agent_id": agent_id, "state": "正常"}

    @tool(readonly=False)
    async def do_action(self, agent_id: int, action: str) -> dict:
        """执行操作（修改工具）"""
        return {"agent_id": agent_id, "action": action, "result": "成功"}

    async def step(self, tick: int, t: datetime):
        """环境步骤"""
        self.t = t
```

### 3. 扫描和注册

创建代码后，在 VSCode 中运行命令：

```
AgentSociety: 扫描自定义模块
```

或调用 API：

```bash
curl -X POST http://localhost:8001/api/v1/custom/scan \
  -H "Content-Type: application/json" \
  -d '{"workspace_path": "/path/to/workspace"}'
```

### 4. 测试验证

在 VSCode 中运行命令：

```
AgentSociety: 测试自定义模块
```

或调用 API：

```bash
curl -X POST http://localhost:8001/api/v1/custom/test \
  -H "Content-Type: application/json" \
  -d '{"workspace_path": "/path/to/workspace"}'
```

系统会在内存中运行测试并返回结果。

## 详解

### Agent 必需方法

所有自定义 Agent 必须实现以下方法：

| 方法 | 说明 |
|------|------|
| `mcp_description()` | 返回模块描述（类方法） |
| `ask(message, readonly)` | 回答来自环境的问题 |
| `step(tick, t)` | 执行一个仿真步骤 |
| `dump()` | 序列化 Agent 状态 |
| `load(dump_data)` | 从字典加载状态 |

### 环境模块必需方法

所有自定义环境模块必须实现：

| 方法 | 说明 |
|------|------|
| `mcp_description()` | 返回模块描述（类方法） |
| `step(tick, t)` | 执行环境步骤 |
| 使用 `@tool` 装饰器注册至少一个工具方法 |

### @tool 装饰器参数

```python
@tool(
    readonly=True,           # 是否只读
    kind="observe",          # 工具类型: "observe", "statistics", 或 None
    name="custom_name",      # 自定义工具名（可选）
    description="描述"       # 工具描述（可选）
)
async def my_tool(self, agent_id: int) -> dict:
    """工具方法"""
    pass
```

**工具类型：**
- `kind="observe"`: 观察工具，只能有一个参数（agent_id），必须是 readonly=True
- `kind="statistics"`: 统计工具，只能有 self 参数，必须是 readonly=True
- `kind=None`: 普通工具，可以有多个参数，可以是 readonly=False

## API 端点

| 端点 | 方法 | 功能 |
|------|------|------|
| `/api/v1/custom/scan` | POST | 扫描并注册自定义模块 |
| `/api/v1/custom/test` | POST | 测试自定义模块 |
| `/api/v1/custom/clean` | POST | 清理自定义模块配置 |
| `/api/v1/custom/list` | GET | 列出已注册的自定义模块 |
| `/api/v1/custom/status` | GET | 获取模块状态概览 |

## VSCode 命令

| 命令 | 功能 |
|------|------|
| `agentsociety.scanCustomModules` | 扫描自定义模块 |
| `agentsociety.testCustomModules` | 测试自定义模块 |
| `agentsociety.cleanCustomModules` | 清理自定义模块配置 |

## 示例

查看 `custom/agents/examples/` 和 `custom/envs/examples/` 获取更多示例：

- `simple_agent.py` - 基础 Agent 示例
- `advanced_agent.py` - 带记忆和情绪的 Agent
- `simple_env.py` - 基础环境示例
- `advanced_env.py` - 资源管理环境

## 常见问题

### Q: 我的模块为什么没有被扫描到？

A: 检查以下几点：
1. 文件是否在 `custom/agents/` 或 `custom/envs/` 目录（不是 `examples/` 子目录）
2. 是否正确继承 `AgentBase` 或 `EnvBase`
3. 是否实现了所有必需方法
4. 文件名不要以 `__` 开头

### Q: 如何调试自定义模块？

A: 使用"测试自定义模块"命令，系统会在内存中：
1. 动态导入自定义模块
2. 运行测试验证
3. 显示详细的测试输出

### Q: 如何清理自定义模块？

A: 运行"清理自定义模块"命令，会删除所有 `is_custom=true` 的 JSON 配置。

### Q: 自定义模块可以和内置模块一起使用吗？

A: 可以！扫描后，自定义模块会与内置模块一起出现在可用列表中。

## 最佳实践

1. **命名规范**
   - Agent 类名以 `Agent` 结尾
   - 环境类名以 `Env` 结尾
   - 文件名使用小写和下划线

2. **错误处理**
   - 在 `ask()` 方法中捕获异常
   - 返回有意义的错误信息

3. **状态管理**
   - 使用 `dump()` 和 `load()` 正确保存/恢复状态
   - 记录重要的状态变化

4. **工具设计**
   - 观察工具用 `kind="observe"`
   - 统计工具用 `kind="statistics"`
   - 操作工具用 `kind=None` 和 `readonly=False`

## 技术支持

如有问题，请查看：
- 项目文档：`CLAUDE.md`
- 示例代码：`custom/*/examples/`
- API 文档：`http://localhost:8001/docs`
