# IntelliW 算法服务集成开发指南

本文档介绍如何基于 `intelliw` 脚手架和 OpenSpec 规范驱动开发范式，快速构建算法服务项目。

## 概述

通过 `intelliw init` 初始化项目后，开发者可以：

1. **使用 AICoding 范式** - AI 辅助代码生成与审查
2. **遵循 OpenSpec 规范** - 规范先行，实现在后
3. **复用 IntelliW 能力** - 模型加载、推理、测试、压测等

## 快速开始

### 1. 环境准备

```bash
# 安装 intelliw 脚手架
pip install intelliw

# 验证安装
intelliw --version
```

### 2. 初始化项目

```bash
# 初始化算法项目
intelliw init --name my_algorithm --output_path=/path/to/project
```

生成的项目结构：

```
my_algorithm/
├── algorithm.py              # 算法入口文件
├── algorithm.yaml            # 算法描述文件
├── README.md                 # 项目描述文件
├── debug_controller.py       # 本地开发测试文件
├── requirements.txt          # Python 依赖包
└── docs/
    ├── README.md             # 框架使用说明
    └── instructions.md       # 算法文件说明
```

### 3. 配置 OpenSpec 规范

项目初始化后，按照 OpenSpec 规范驱动开发：

```bash
# 查看现有规范
openspec list --specs

# 创建变更提案（如需新增功能）
/openspec:proposal
```

## 核心能力复用

### 1. 模型加载

在 `algorithm.py` 中通过 `load` 方法实现模型加载：

```python
import pickle

class Algorithm:
    def __init__(self, parameters):
        self.parameters = parameters
        self.logger = self.parameters['framework_log']
        self.model = None

    def load(self, path):
        """
        加载模型
        平台会在推理或 checkpoint 训练时自动调用此方法
        """
        # 根据模型类型选择加载方式
        # 示例：pickle 加载
        with open(path, 'rb') as f:
            self.model = pickle.load(f)

        # 或使用模型管理器（高级功能）
        # 需先在 __init__ 中设置 self.model_manager_mode = True
        # 并实现 load_with_manager 方法
```

使用模型管理器模式：

```python
class Algorithm:
    def __init__(self, parameters):
        self.parameters = parameters
        self.logger = self.parameters['framework_log']
        self.model_manager_mode = True  # 启用模型管理器
        self.model_manager = None

    def load_with_manager(self, path):
        """
        使用模型管理器加载模型
        适用于需要热更新、版本管理的场景
        """
        # 加载模型并返回实例
        model = None
        # ... 加载逻辑
        return model
```

### 2. 模型推理

通过 `infer` 方法实现推理逻辑：

```python
class Algorithm:
    async def infer(self, infer_data):
        """
        推理方法
        平台会根据 algorithm.yaml 中的路由配置调用此方法
        """
        # 直接使用 self.model 进行推理
        # 注意：model 是在 load 方法中加载的

        # 示例：简单预测
        result = self.model.predict(infer_data)

        return {
            "status": "success",
            "predictions": result.tolist() if hasattr(result, 'tolist') else result
        }
```

自定义路由的推理方法：

```python
from intelliw.feature import Application

class Algorithm:
    def __init__(self, parameters):
        self.parameters = parameters
        self.logger = self.parameters['framework_log']

    @Application.route("/custom-infer", method='post', need_feature=True)
    async def custom_infer(self, infer_data):
        """自定义推理路由"""
        # 实现推理逻辑
        return {"result": "custom inference result"}
```

### 3. 单元测试

使用 Python 标准 `unittest` 框架：

```python
# tests/test_algorithm.py
import unittest
import sys
import os

# 添加项目路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from algorithm import Algorithm


class TestAlgorithm(unittest.TestCase):
    """算法单元测试"""

    def setUp(self):
        """测试前初始化"""
        parameters = {
            'framework_log': None,  # 实际使用时传入 logger
            'param1': 'value1'
        }
        self.algo = Algorithm(parameters)

    def test_init(self):
        """测试初始化"""
        self.assertIsNotNone(self.algo)
        self.assertEqual(self.algo.parameters['param1'], 'value1')

    def test_load(self):
        """测试模型加载"""
        # 创建临时模型文件
        import tempfile
        import pickle

        with tempfile.NamedTemporaryFile(delete=False, suffix='.pkl') as f:
            model = {'type': 'test', 'weights': [1, 2, 3]}
            pickle.dump(model, f)
            model_path = f.name

        try:
            self.algo.load(model_path)
            self.assertIsNotNone(self.algo.model)
            self.assertEqual(self.algo.model['type'], 'test')
        finally:
            os.unlink(model_path)


if __name__ == '__main__':
    unittest.main()
```

使用 `pytest` 进行测试（需安装）：

```bash
# 安装 pytest
pip install pytest pytest-asyncio

# 运行测试
pytest tests/test_algorithm.py -v

# 运行所有测试
pytest tests/ -v --cov=.
```

### 4. 服务启动与压测

启动推理服务：

```bash
# 基本启动命令
intelliw infer --path ${algo_path} --port 8888

# 完整示例
intelliw infer \
    --path /path/to/my_algorithm \
    --port 8080 \
    --host 0.0.0.0
```

使用 `debug_controller.py` 进行本地调试：

```bash
# 调试推理服务
python debug_controller.py -j infer_http_server

# 调试训练流程
python debug_controller.py -j train

# 调试批量任务
python debug_controller.py -j batch_infer
```

性能压测：

```bash
# 使用 ab (Apache Bench) 进行压测
ab -n 1000 -c 100 -T 'application/json' \
    -d '{"data": [1.0, 2.0, 3.0]}' \
    http://localhost:8888/predict

# 使用 wrk 进行压测
wrk -t12 -c400 -d30s \
    -s script.lua \
    http://localhost:8888/predict
```

Python 压测脚本示例：

```python
# benchmark.py
import asyncio
import aiohttp
import time
import statistics


async def send_request(session, url, data):
    """发送单个请求"""
    start = time.time()
    try:
        async with session.post(url, json=data) as resp:
            await resp.json()
            latency = time.time() - start
            return {'success': True, 'latency': latency}
    except Exception as e:
        return {'success': False, 'error': str(e)}


async def run_benchmark(url, data, concurrency=100, total_requests=1000):
    """运行压测"""
    results = []
    semaphore = asyncio.Semaphore(concurrency)

    async def bounded_request(session, url, data):
        async with semaphore:
            return await send_request(session, url, data)

    async with aiohttp.ClientSession() as session:
        tasks = [
            bounded_request(session, url, data)
            for _ in range(total_requests)
        ]
        results = await asyncio.gather(*tasks)

    # 统计分析
    success_results = [r for r in results if r['success']]
    latencies = [r['latency'] for r in success_results]

    print(f"总请求数: {total_requests}")
    print(f"成功请求: {len(success_results)}")
    print(f"失败请求: {total_requests - len(success_results)}")
    print(f"平均延迟: {statistics.mean(latencies):.3f}s")
    print(f"中位数延迟: {statistics.median(latencies):.3f}s")
    print(f"95分位延迟: {sorted(latencies)[int(len(latencies)*0.95)]:.3f}s")


if __name__ == '__main__':
    url = 'http://localhost:8888/predict'
    data = {'data': [1.0, 2.0, 3.0, 4.0]}
    asyncio.run(run_benchmark(url, data, concurrency=100, total_requests=1000))
```