FeedForward

类 FeedForward 在 training/model.py: 前馈网络 | 方法: __init__, forward

class FeedForward:
    """前馈网络"""

    def __init__(self, d_model: int, d_ff: int, dropout: float = 0.1):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.GELU(),
            nn.Linear(d_ff, d_model),
            nn.Dropout(dropout),
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.net(x)


TransformerBlock

类 TransformerBlock 在 training/model.py: Transformer块 | 方法: __init__, forward

class TransformerBlock:
    """Transformer块"""

    def __init__(self, d_model: int, n_heads: int, d_ff: int, max_len: int = 512, dropout: float = 0.1):
        super().__init__()
        self.ln1 = nn.LayerNorm(d_model)
        self.attn = CausalSelfAttention(d_model, n_heads, max_len, dropout)
        self.ln2 = nn.LayerNorm(d_model)
        self.ff = FeedForward(d_model, d_ff, dropout)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = x + self.attn(self.ln1(x))
        x = x + self.ff(self.ln2(x))
        return x


SwarmModel

类 SwarmModel 在 training/model.py: 虫群小模型 — GPT风格Decoder-only Transformer

    配置:
    - SwarmTiny:   d=128, h=4, l=4, ff=512    → ~5M
    - SwarmSmall:  d=256, h=8, l=6, ff=1024   → ~15M
    - SwarmMedium: d=384, h=8, l=8, ff=1536   →  | 方法: __init__, _init_weights, _count_params, from_config, forward, generate, get_info

class SwarmModel:
    """
    虫群小模型 — GPT风格Decoder-only Transformer

    配置:
    - SwarmTiny:   d=128, h=4, l=4, ff=512    → ~5M
    - SwarmSmall:  d=256, h=8, l=6, ff=1024   → ~15M
    - SwarmMedium: d=384, h=8, l=8, ff=1536   → ~50M
    """

    # 预定义配置（vocab_size=8192时的参数量）
    CONFIGS = {
        "tiny":   {"d_model": 192, "n_heads": 6, "n_layers": 6, "d_ff": 768,  "dropout": 0.1},   # ~5M
        "small":  {"d_model": 320, "n_heads": 8, "n_layers": 8, "d_ff": 1280, "dropout": 0.1},   # ~15M
        "medium": {"d_model": 448, "n_heads": 8, "n_layers": 10, "d_ff": 1792, "dropout": 0.1},  # ~50M
        "large":  {"d_model": 768, "n_heads": 12, "n_layers": 12, "d_ff": 3072, "dropout": 0.1},  # ~100M
    }

    def __init__(
        self,
        vocab_size: int = 8192,
        d_model: int = 128,
        n_heads: int = 4,
        n_layers: int = 4,
        d_ff: int = 512,
        max_len: int = 512,
        dropout: float = 0.1,
    ):
        super().__init__()
        self.vocab_size = vocab_size
        self.d_model = d_model
        self.max_len = max_len

        # Token嵌入 + 位置嵌入
        self.tok_emb = nn.Embedding(vocab_size, d_model)
        self.pos_emb = nn.Embedding(max_len, d_model)
        self.drop = nn.Dropout(dropout)

        # Transformer层
        self.blocks = nn.ModuleList([
            TransformerBlock(d_model, n_heads, d_ff, max_len, dropout)
            for _ in range(n_layers)
        ])

        # 输出头
        self.ln_f = nn.LayerNorm(d_model)
        self.head = nn.Linear(d_model, vocab_size, bias=False)

        # 权重共享（embedding和输出头）
        self.head.weight = self.tok_emb.weight

        # 初始化
        self.apply(self._init_weights)
        self._param_count = self._count_params()

    def _init_weights(self, module):
        if isinstance(module, nn.Linear):
            nn.init.normal_(module.weight, mean=0.0, std=0.02)
            if module.bias is not None:
                nn.init.zeros_(module.bias)
        elif isinstance(module, nn.Embedding):


方法 SwarmModel.from_config():
        """从预定义配置创建模型"""
        if config_name not in cls.CONFIGS:
            raise ValueError(f"

def from_config(self):
        """从预定义配置创建模型"""
        if config_name not in cls.CONFIGS:
            raise ValueError(f"未知配置: {config_name}, 可选: {list(cls.CONFIGS.keys())}")
        cfg = cls.CONFIGS[config_name]
        return cls(
            vocab_size=vocab_size,
            d_model=cfg["d_model"],
            n_heads=cfg["n_heads"],
            n_layers=cfg["n_layers"],
            d_ff=cfg["d_ff"],
            max_len=max_len,
            dropout=cfg["dropout"],
        )


tokenizer.py

文件 training/tokenizer.py: 虫群分词器 — 基于BPE的轻量级中文分词器
专为小模型训练设计，词表4K-16K | 定义: class SwarmTokenizer, def __init__, def _init_base_vocab, def train, def _pre_tokenize, def encode, def decode, def pad_id, def unk_id, def bos_id

#!/usr/bin/env python3
"""
虫群分词器 — 基于BPE的轻量级中文分词器
专为小模型训练设计，词表4K-16K
"""

import os
import json
import re
from collections import Counter
from typing import Dict, List, Optional, Tuple

class SwarmTokenizer:
    """
    轻量级BPE分词器
    - 中文字符级 + 英文BPE
    - 特殊token: [PAD] [UNK] [BOS] [EOS] [CLS] [SEP]
    - 支持从语料训练合并规则
    """

    # 特殊token
    SPECIAL_TOKENS = ["[PAD]", "[UNK]", "[BOS]", "[EOS]", "[CLS]", "[SEP]"]

    def __init__(self, vocab_size: int = 8192):
        self.vocab_size = vocab_


SwarmTokenizer

类 SwarmTokenizer 在 training/tokenizer.py: 轻量级BPE分词器
    - 中文字符级 + 英文BPE
    - 特殊token: [PAD] [UNK] [BOS] [EOS] [CLS] [SEP]
    - 支持从语料训练合并规则 | 方法: __init__, _init_base_vocab, train, _pre_tokenize, encode, decode, pad_id, unk_id, bos_id, eos_id, vocab_size_actual, save, load

class SwarmTokenizer:
    """
    轻量级BPE分词器
    - 中文字符级 + 英文BPE
    - 特殊token: [PAD] [UNK] [BOS] [EOS] [CLS] [SEP]
    - 支持从语料训练合并规则
    """

    # 特殊token
    SPECIAL_TOKENS = ["[PAD]", "[UNK]", "[BOS]", "[EOS]", "[CLS]", "[SEP]"]

    def __init__(self, vocab_size: int = 8192):
        self.vocab_size = vocab_size
        self.token_to_id: Dict[str, int] = {}
        self.id_to_token: Dict[int, str] = {}
        self.merges: List[Tuple[str, str]] = []
        self._initialized = False

    def _init_base_vocab(self, chars: set):
        """初始化基础词表：特殊token + 字符"""
        vocab = {}
        # 特殊token
        for i, tok in enumerate(self.SPECIAL_TOKENS):
            vocab[tok] = i
        # 中文字符
        idx = len(self.SPECIAL_TOKENS)
        for ch in sorted(chars):
            if ch not in vocab:
                vocab[ch] = idx
                idx += 1
        return vocab

    def train(self, texts: List[str], min_freq: int = 2):
        """从语料训练BPE合并规则"""
        print(f"  分词器训练: 语料{len(texts)}条, 目标词表{self.vocab_size}")
        start_time = __import__('time').time()

        # 统计字符
        char_counter = Counter()
        word_splits: Dict[str, List[str]] = {}

        for text in texts:
            # 中文按字切，英文按空格切
            words = self._pre_tokenize(text)
            for word in words:
                if word not in word_splits:
                    word_splits[word] = list(word) + ["</w>"]
                char_counter.update(word)

        # 基础词表
        chars = set()
        for ch, cnt in char_counter.items():
            if cnt >= min_freq:
                chars.add(ch)
        # 确保常见标点和数字
        chars.update("，。！？、；：""''（）【】《》0123456789")

        self.token_to_id = self._init_base_vocab(chars)
        base_size = len(self.token_to_id)

        # BPE合并
        num_merges = self.vocab_size - base_size
        if num_merges < 0:
            num_merges = 0
        print(f"  基础词表: {base_size}, 需合并: {num_merges}")

        for i in range(num_merges):
            # 统计相邻pair频率


train

方法 SwarmTokenizer.train():
        """从语料训练BPE合并规则"""
        print(f"  分词器训练: 语料{len(texts)}条, 目标词表{self.vocab_size}")

def train(self):
        """从语料训练BPE合并规则"""
        print(f"  分词器训练: 语料{len(texts)}条, 目标词表{self.vocab_size}")
        start_time = __import__('time').time()

        # 统计字符
        char_counter = Counter()
        word_splits: Dict[str, List[str]] = {}

        for text in texts:
            # 中文按字切，英文按空格切
            words = self._pre_tokenize(text)
            for word in words:
                if word not in word_splits:
                    word_splits[word] = list(word) + ["</w>"]
                char_counter.update(word)

        # 基础词表
        chars = set()
        for ch, cnt in char_counter.items():
            if cnt >= min_freq:
                chars.add(ch)
        # 确保常见标点和数字
        chars.update("，。！？、；：""''（）【】《》0123456789")

        self.token_to_id = self._init_base_vocab(chars)
        base_size = len(self.token_to_id)

        # BPE合并
        num_merges = self.vocab_size - base_size
        if num_merges < 0:
            num_merges = 0
        print(f"  基础词表: {base_size}, 需合并: {num_m


save

方法 SwarmTokenizer.save():
        """保存分词器"""
        data = {
            "vocab_size": self.vocab_size,
            "token_

def save(self):
        """保存分词器"""
        data = {
            "vocab_size": self.vocab_size,
            "token_to_id": self.token_to_id,
            "merges": [list(m) for m in self.merges],
        }
        os.makedirs(os.path.dirname(path), exist_ok=True)
        with open(path, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        print(f"  分词器已保存: {path}")

    @classmethod


文件 training/export_mobile.py: 虫群模型移动端导出工具
支持: PyTorch Mobile (.ptl) / ONNX / TorchScript | 定义: def export_torchscript, class InferenceWrapper, def __init__, def forward, def export_onnx, def export_all

os sys time json torch training.model training.tokenizer

#!/usr/bin/env python3
"""
虫群模型移动端导出工具
支持: PyTorch Mobile (.ptl) / ONNX / TorchScript
"""

import os
import sys
import time
import json

sys.path.insert(0, "/home/admin/swarm")

import torch
from training.model import SwarmModel
from training.tokenizer import SwarmTokenizer

def export_torchscript(model_dir: str, output_dir: str = None):
    """导出TorchScript格式(.ptl) — PyTorch Mobile直接使用"""
    meta_path = os.path.join(model_dir, "meta.json")
    model_path = os.path.join(model_dir, "model.pt")


InferenceWrapper

类 InferenceWrapper 在 training/export_mobile.py:  | 方法: __init__, forward

class InferenceWrapper:
            def __init__(self, model):
                super().__init__()
                self.model = model
            def forward(self, x):
                out = self.model(x)
                return out[0] if isinstance(out, tuple) else out

        wrapper = InferenceWrapper(model)
        wrapper.eval()

        traced = torch.jit.trace(wrapper, example_input)

        # 优化为移动端
        from torch.utils.mobile_optimizer import optimize_for_mobile
        optimized = optimize_for_mobile(traced)

        output_path = os.path.join(output_dir, "model.ptl")
        optimized._save_for_lite_interpreter(output_path)

        size_mb = os.path.getsize(output_path) / 1024 / 1024
        print(f"  ✅ TorchScript导出: {output_path} ({size_mb:.1f}MB)")

        # 验证: 加载回来看推理结果
        loaded = torch.jit.load(output_path)
        with torch.no_grad():
            verify_logits = loaded(example_input)
        print(f"  验证: loaded output shape={verify_logits.shape}")

        return output_path

    except Exception as e:
        print(f"  ❌ TorchScript导出失败: {e}")
        # 回退: 保存完整state_dict
        print("  回退: 保存state_dict格式(需在手机端重建模型)")
        sd_path = os.path.join(output_dir, "model_state.pt")
        torch.save({
            "model_state_dict": sd,
            "vocab_size": vocab_size,
            "config": cfg,
            "max_len": max_len,
        }, sd_path)
        size_mb = os.path.getsize(sd_path) / 1024 / 1024
        print(f"  ✅ state_dict导出: {sd_path} ({size_mb:.1f}MB)")
        return sd_path


forward

方法 InferenceWrapper.forward():
                out = self.model(x)
                return out[0] if isinstance(out, tuple) else ou

def forward(self):
                out = self.model(x)
                return out[0] if isinstance(out, tuple) else out

        wrapper = InferenceWrapper(model)
        wrapper.eval()

        traced = torch.jit.trace(wrapper, example_input)

        # 优化为移动端
        from torch.utils.mobile_optimizer import optimize_for_mobile
        optimized = optimize_for_mobile(traced)

        output_path = os.path.join(output_dir, "model.ptl")
        optimized._save_for_lite_interpreter(output_path)

        size_mb = os.path.getsize(output_path) / 1024 / 1024
        print(f"  ✅ TorchScript导出: {output_path} ({size_mb:.1f}MB)")

        # 验证: 加载回来看推理结果
        loaded = torch.jit.load(output_path)
        with torch.no_grad():
            verify_logits = loaded(example_input)
        print(f"  验证: loaded output shape={verify_logits.shape}")

        return output_path

    except Exception as e:
        print(f"  ❌ TorchScript导出失败: {e}")
        #


函数 export_torchscript(model_dir: str, output_dir: str = None) 在 training/export_mobile.py: 导出TorchScript格式(.ptl) — PyTorch Mobile直接使用

def export_torchscript(model_dir: str, output_dir: str = None):
    """导出TorchScript格式(.ptl) — PyTorch Mobile直接使用"""
    meta_path = os.path.join(model_dir, "meta.json")
    model_path = os.path.join(model_dir, "model.pt")

    if not os.path.exists(model_path):
        print(f"  ❌ 模型不存在: {model_path}")
        return None

    output_dir = output_dir or os.path.join(model_dir, "mobile")
    os.makedirs(output_dir, exist_ok=True)

    # 加载模型
    checkpoint = torch.load(model_path, map_location="cpu", weights_only=False)
    vocab_size = checkpoint.get("vocab_size", 5526)
    cfg = checkpoint.get("config", {})
    max_len = checkpoint.get("max_len", 256)

    # 推断max_len
    sd = checkpoint.get("model_state_dict", {})
    if "pos_emb.weight" in sd:
        max_len = sd["pos_emb.weight"].shape[0]

    model = SwarmModel(
        vocab_size=vocab_size,
        d_model=cfg.get("d_model", 192),
        n_heads=cfg.get("n_heads", 6),
        n_layers=cfg.get("n_layers", 6),
        d_ff=cfg.get("d_model", 192) * 4,
        max_len=max_len,
    )
    model.load_state_dict(sd)
    model.eval()

    params = sum(p.numel() for p in model.parameters())
    print(f"  模型: vocab={vocab_size}, params={params/1e6:.2f}M, max_len={max_len}")

    # 创建示例输入 (batch=1, seq_len=16)
    example_input = torch.randint(0, vocab_size, (1, 16), dtype=torch.long)

    # TorchScript trace — 需要包装只返回logits
    print("  导出TorchScript...")
    try:
        # 先测试forward
        with torch.no_grad():
            output = model(example_input)
            # forward可能返回(logits, loss)或(logits,)
            if isinstance(output, tuple):
                logits = output[0]
            else:
                logits = output
            print(f"  forward测试: output shape={logits.shape}")

        # 包装: 只返回logits，TorchScript友好
        class InferenceWrapper(torch.nn.Module):
            def __init__(self, model):
                super().__init__()
                self.model = model
            def forward(self, x):
                out =


函数 export_onnx(model_dir: str, output_dir: str = None) 在 training/export_mobile.py: 导出ONNX格式 — ONNX Runtime Mobile / NCNN使用

def export_onnx(model_dir: str, output_dir: str = None):
    """导出ONNX格式 — ONNX Runtime Mobile / NCNN使用"""
    meta_path = os.path.join(model_dir, "meta.json")
    model_path = os.path.join(model_dir, "model.pt")

    if not os.path.exists(model_path):
        print(f"  ❌ 模型不存在: {model_path}")
        return None

    output_dir = output_dir or os.path.join(model_dir, "mobile")
    os.makedirs(output_dir, exist_ok=True)

    checkpoint = torch.load(model_path, map_location="cpu", weights_only=False)
    vocab_size = checkpoint.get("vocab_size", 5526)
    cfg = checkpoint.get("config", {})
    max_len = checkpoint.get("max_len", 256)

    sd = checkpoint.get("model_state_dict", {})
    if "pos_emb.weight" in sd:
        max_len = sd["pos_emb.weight"].shape[0]

    model = SwarmModel(
        vocab_size=vocab_size,
        d_model=cfg.get("d_model", 192),
        n_heads=cfg.get("n_heads", 6),
        n_layers=cfg.get("n_layers", 6),
        d_ff=cfg.get("d_model", 192) * 4,
        max_len=max_len,
    )
    model.load_state_dict(sd)
    model.eval()

    example_input = torch.randint(0, vocab_size, (1, 16), dtype=torch.long)

    output_path = os.path.join(output_dir, "model.onnx")

    try:
        print("  导出ONNX...")
        torch.onnx.export(
            model,
            example_input,
            output_path,
            input_names=["input_ids"],
            output_names=["logits"],
            dynamic_axes={
                "input_ids": {0: "batch", 1: "seq_len"},
                "logits": {0: "batch", 1: "seq_len"},
            },
            opset_version=14,
        )
        size_mb = os.path.getsize(output_path) / 1024 / 1024
        print(f"  ✅ ONNX导出: {output_path} ({size_mb:.1f}MB)")
        return output_path
    except Exception as e:
        print(f"  ❌ ONNX导出失败: {e}")
        return None


函数 export_all(model_name: str = "tiny_v6") 在 training/export_mobile.py: 导出所有格式

def export_all(model_name: str = "tiny_v6"):
    """导出所有格式"""
    models_dir = "/home/admin/swarm/training/models"
    model_dir = os.path.join(models_dir, model_name)

    if not os.path.exists(model_dir):
        print(f"❌ 模型目录不存在: {model_dir}")
        return

    print("=" * 50)
    print(f"  虫群模型移动端导出: {model_name}")
    print("=" * 50)

    results = {}

    # 1. TorchScript (PyTorch Mobile) — 用只返回logits的包装
    print(f"\n--- TorchScript导出 ---")
    ptl = export_torchscript(model_dir)
    if ptl:
        results["torchscript"] = ptl

    # 2. ONNX
    print(f"\n--- ONNX导出 ---")
    onnx = export_onnx(model_dir)
    if onnx:
        results["onnx"] = onnx

    # 3. 量化state_dict (最小体积)
    print(f"\n--- INT8量化导出 ---")
    checkpoint = torch.load(os.path.join(model_dir, "model.pt"), map_location="cpu", weights_only=False)
    sd = checkpoint.get("model_state_dict", {})

    # 动态量化
    vocab_size = checkpoint.get("vocab_size", 5526)
    cfg = checkpoint.get("config", {})
    max_len = checkpoint.get("max_len", 256)

    model = SwarmModel(
        vocab_size=vocab_size,
        d_model=cfg.get("d_model", 192),
        n_heads=cfg.get("n_heads", 6),
        n_layers=cfg.get("n_layers", 6),
        d_ff=cfg.get("d_model", 192) * 4,
        max_len=max_len,
    )
    model.load_state_dict(sd)
    model.eval()

    quantized = torch.quantization.quantize_dynamic(
        model, {torch.nn.Linear}, dtype=torch.qint8
    )

    output_dir = os.path.join(model_dir, "mobile")
    q_path = os.path.join(output_dir, "model_int8.pt")
    torch.save(quantized.state_dict(), q_path)
    size_mb = os.path.getsize(q_path) / 1024 / 1024
    print(f"  ✅ INT8量化: {q_path} ({size_mb:.1f}MB)")
    results["int8"] = q_path

    # 4. 导出模型信息
    info = {
        "model_name": model_name,
        "vocab_size": vocab_size,
        "params_M": sum(p.numel() for p in model.parameters()) / 1e6,
        "d_model": cfg.get("d_model", 192),
        "n_heads": cfg.get("n_heads", 6),
        "n_layers


文件 training/train_local_v6.py: 本地CPU训练v6 — 使用v2分词器(11838词表) + combined_v2数据 | 定义:

os sys json time training.tokenizer training.model torch numpy torch.optim os

#!/usr/bin/env python3
"""本地CPU训练v6 — 使用v2分词器(11838词表) + combined_v2数据"""
import os
import sys
import json
import time

# 强制输出无缓冲
os.environ["PYTHONUNBUFFERED"] = "1"

sys.path.insert(0, "/home/admin/swarm")
from training.tokenizer import SwarmTokenizer
from training.model import SwarmModel

import torch
import numpy as np
from torch.optim import Adam

print("=" * 60)
print("虫群本地CPU训练v6 — v2分词器(11838词表)")
print("=" * 60)

# 加载v2分词器
tokenizer = SwarmTokenizer.load("/home/admin/swarm/training/mode


文件 training/test_real_inference.py: 虫群v8 — 真实模型推理验证

验证：聚合协议 → 推理服务 → 参数化记忆模型 的完整链路
多个节点各自存储不同记忆 → 组网 → 分布式推理 → 聚合结果 | 定义:

#!/usr/bin/env python3
"""
虫群v8 — 真实模型推理验证

验证：聚合协议 → 推理服务 → 参数化记忆模型 的完整链路
多个节点各自存储不同记忆 → 组网 → 分布式推理 → 聚合结果
"""
import sys, os, time
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from core.swarm_node import SwarmNode, SwarmNetwork
from core.aggregation_protocol.types import PermissionLevel
from core.inference_service import DistributedInferenceBridge

print("=" * 60)
print("虫群v8 — 真实模型推理验证")
print("=" * 60)

# ===== [1] 创建3个节点 =====
print("\n[1] 创建3个虫后节点...")
n


文件 training/memory_training_daemon.py: 虫群记忆模型 — 24小时后台训练守护进程

部署在HF Spaces上持续运行：
1. 加载small基座+LoRA
2. 从训练数据集持续喂养记忆
3. 定期保存checkpoint
4. 支持断点续训

设计理念：
- 速度不重要，方法正确才重要
- 利用设备空闲碎片时间训练
- 长期积累让模型贴合个人习惯 | 定义: def load_checkpoint, def save_checkpoint, def run_training_loop

os sys time json glob torch datetime core.parametric_memory

#!/usr/bin/env python3
"""
虫群记忆模型 — 24小时后台训练守护进程

部署在HF Spaces上持续运行：
1. 加载small基座+LoRA
2. 从训练数据集持续喂养记忆
3. 定期保存checkpoint
4. 支持断点续训

设计理念：
- 速度不重要，方法正确才重要
- 利用设备空闲碎片时间训练
- 长期积累让模型贴合个人习惯
"""

import os
import sys
import time
import json
import glob
import torch
from datetime import datetime

# 添加项目路径
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, project_root)

from core.parametric_memory import ParametricMemoryModel

# 训练配置
CONFIG = {
    "model_conf


函数 load_checkpoint(pm: ParametricMemoryModel, checkpoint_dir: str) 在 training/memory_training_daemon.py: 加载最新checkpoint

def load_checkpoint(pm: ParametricMemoryModel, checkpoint_dir: str):
    """加载最新checkpoint"""
    os.makedirs(checkpoint_dir, exist_ok=True)
    checkpoints = sorted(glob.glob(os.path.join(checkpoint_dir, "ckpt_*")))
    if checkpoints:
        latest = checkpoints[-1]
        pm.load(latest)
        print(f"[训练守护] 加载checkpoint: {latest}")
        return True
    return False


函数 save_checkpoint(pm: ParametricMemoryModel, checkpoint_dir: str, iteration: int) 在 training/memory_training_daemon.py: 保存checkpoint

def save_checkpoint(pm: ParametricMemoryModel, checkpoint_dir: str, iteration: int):
    """保存checkpoint"""
    ckpt_path = os.path.join(checkpoint_dir, f"ckpt_{iteration:06d}")
    pm.save(ckpt_path)

    # 保存训练日志
    log = {
        "iteration": iteration,
        "timestamp": datetime.now().isoformat(),
        "status": pm.get_status(),
    }
    log_path = os.path.join(checkpoint_dir, "training_log.jsonl")
    with open(log_path, "a") as f:
        f.write(json.dumps(log, ensure_ascii=False) + "\n")

    # 只保留最近5个checkpoint
    checkpoints = sorted(glob.glob(os.path.join(checkpoint_dir, "ckpt_*")))
    while len(checkpoints) > 5:
        import shutil
        shutil.rmtree(checkpoints[0])
        checkpoints = checkpoints[1:]

    print(f"[训练守护] 保存checkpoint: {ckpt_path}")


函数 run_training_loop() 在 training/memory_training_daemon.py: 主训练循环

def run_training_loop():
    """主训练循环"""
    print("=" * 60)
    print("虫群记忆模型 — 24小时后台训练守护")
    print("=" * 60)
    print(f"基座: {CONFIG['model_config']}")
    print(f"写入模式: {CONFIG['write_mode']}")
    print(f"开始时间: {datetime.now().isoformat()}")
    print()

    # 1. 初始化记忆模型
    print("[1] 初始化记忆模型...")
    pm = ParametricMemoryModel(
        model_config=CONFIG["model_config"],
        lora_rank=CONFIG["lora_rank"],
        lora_alpha=CONFIG["lora_alpha"],
        write_mode=CONFIG["write_mode"],
        accumulate_steps=CONFIG["accumulate_steps"],
        micro_epochs=CONFIG["micro_epochs"],
    )

    # 2. 尝试加载checkpoint
    print("[2] 检查checkpoint...")
    loaded = load_checkpoint(pm, CONFIG["checkpoint_dir"])
    if loaded:
        print("  继续上次的训练")
    else:
        print("  全新开始训练")

    # 3. 准备训练数据
    all_memories = SAMPLE_MEMORIES + EXTENDED_MEMORIES
    print(f"[3] 训练数据: {len(all_memories)}条记忆")

    # 4. 训练循环
    iteration = 0
    last_checkpoint_time = time.time()
    total_memories_fed = 0

    print("[4] 开始训练循环...")
    print("-" * 60)

    try:
        while True:
            iteration += 1

            # 从训练数据中循环取记忆
            mem_idx = (iteration - 1) % len(all_memories)
            mem_type, *mem_data = all_memories[mem_idx]

            try:
                if mem_type == "chat":
                    user_input, ai_response, importance = mem_data
                    pm.store(user_input, ai_response, memory_type="chat", importance=importance)
                elif mem_type == "preference":
                    category, preference, importance = mem_data
                    pm.store_preference(category, preference)
                elif mem_type == "fact":
                    fact, source, importance = mem_data
                    pm.store_fact(fact, source)

                total_memories_fed += 1

                # 等待后台写入完成
                time.sleep(0.5)

                # 定


文件 training/train_tokenizer_v2.py: 虫群分词器v2 — 扩展词表训练脚本
从combined_v2.json训练32000词表的BPE分词器 | 定义: def main

#!/usr/bin/env python3
"""
虫群分词器v2 — 扩展词表训练脚本
从combined_v2.json训练32000词表的BPE分词器
"""

import os
import sys
import json
import time

sys.path.insert(0, "/home/admin/swarm")

from training.tokenizer import SwarmTokenizer

def main():
    print("=" * 50)
    print("  虫群分词器v2 — 词表扩展训练")
    print("=" * 50)

    # 加载合并数据
    data_path = "/home/admin/swarm/training/data/combined_v2.json"
    print(f"\n1. 加载数据: {data_path}")
    with open(data_path, 'r', encoding='utf-8') as f:
        data = json.load


main

函数 main() 在 training/train_tokenizer_v2.py:

def main():
    print("=" * 50)
    print("  虫群分词器v2 — 词表扩展训练")
    print("=" * 50)

    # 加载合并数据
    data_path = "/home/admin/swarm/training/data/combined_v2.json"
    print(f"\n1. 加载数据: {data_path}")
    with open(data_path, 'r', encoding='utf-8') as f:
        data = json.load(f)
    print(f"   数据量: {len(data)}条")

    # 提取所有文本
    texts = []
    for item in data:
        if 'input' in item:
            texts.append(item['input'])
        if 'output' in item:
            texts.append(item['output'])
    print(f"   文本段: {len(texts)}段")

    # 统计字符覆盖
    chars = set()
    for t in texts:
        chars.update(t)
    print(f"   唯一字符: {len(chars)}个")

    # 训练分词器
    print(f"\n2. 训练分词器 (目标词表: 12000)")
    start = time.time()
    tokenizer = SwarmTokenizer(vocab_size=12000)
    tokenizer.train(texts, min_freq=2)
    elapsed = time.time() - start
    print(f"   训练耗时: {elapsed:.1f}s")
    print(f"   实际词表: {len(tokenizer.token_to_id)}")

    # 测试编码
    print(f"\n3. 测试编码:")
    test_texts = [
        "你好，请问虫群智能体系统是什么？",
        "Help me write a Python function to calculate fibonacci numbers",
        "今天天气不错，适合出去散步。",
        "虫群的多模型聚合机制通过MOA实现",
    ]
    for text in test_texts:
        ids = tokenizer.encode(text)
        decoded = tokenizer.decode(ids)
        print(f"   原文: {text[:40]}...")
        print(f"   编码: {len(ids)} tokens (前10: {ids[:10]})")
        print(f"   解码: {decoded[:40]}...")
        print()

    # 保存分词器
    save_dir = "/home/admin/swarm/training/models"
    os.makedirs(save_dir, exist_ok=True)
    save_path = os.path.join(save_dir, "tokenizer_v2.json")
    tokenizer.save(save_path)
    print(f"4. 已保存分词器: {save_path}")

    # 对比旧分词器
    old_path = os.path.join(save_dir, "shared_tokenizer.json")
    if os.path.exists(old_path):
        with open(old_path, 'r') as f:
            old_data = json.load(f)
        old_vocab = len(old_data.get("token_to_id", old_data.get("vocab", {})))
        new_vocab = len(tokenizer.token_to_id)
        print(f"\n5. 词表对比:")
        p


文件 training/train_modal_v5.py: 虫群模型 — Modal GPU云端训练 v5
关键改进: 本地预处理分词，上传已编码的token ids到Modal
         避免在GPU容器里做慢速BPE分词
用法: modal run --detach training/train_modal_v5.py | 定义: def upload_tokenized, def train_model, def main, def upload_code_files

"""
虫群模型 — Modal GPU云端训练 v5
关键改进: 本地预处理分词，上传已编码的token ids到Modal
         避免在GPU容器里做慢速BPE分词
用法: modal run --detach training/train_modal_v5.py
"""
import modal
import json
import sys
import os

app = modal.App("swarm-gpu-train-v5")

# PyTorch + CUDA镜像
image = modal.Image.from_registry(
    "pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime"
).pip_install("numpy")

# 持久化存储
vol = modal.Volume.from_name("swarm-models", create_if_missing=True)

sys.path.insert(0, "/home/admin/swarm")
from training.tokeniz


上传预分词的数据到Volume

函数 upload_tokenized(samples_json: str, tokenizer_json: str) 在 training/train_modal_v5.py: 上传预分词的数据到Volume

def upload_tokenized(samples_json: str, tokenizer_json: str):
    """上传预分词的数据到Volume"""
    import os

    samples = json.loads(samples_json)
    tokenizer = json.loads(tokenizer_json)

    os.makedirs("/root/swarm-models/data", exist_ok=True)

    # 保存预分词数据
    with open("/root/swarm-models/data/tokenized_samples.json", "w") as f:
        json.dump(samples, f)

    # 保存分词器（推理时decode用）
    with open("/root/swarm-models/data/shared_tokenizer.json", "w") as f:
        json.dump(tokenizer, f, ensure_ascii=False)

    vol.commit()
    print(f"上传完成: {len(samples)}个模型的数据集, 词表{len(tokenizer.get('token_to_id', {}))}")

@app.function(
    image=image,
    gpu="T4",
    timeout=3600,
    volumes={"/root/swarm-models": vol},
)


在GPU上训练虫群模型 — v5预分词版

函数 train_model(model_name: str = "tiny") 在 training/train_modal_v5.py: 在GPU上训练虫群模型 — v5预分词版

def train_model(model_name: str = "tiny"):
    """在GPU上训练虫群模型 — v5预分词版"""
    import torch
    import torch.nn as nn
    from torch.optim import Adam
    import time
    import json
    import os
    import numpy as np

    print(f"=" * 60)
    print(f"虫群GPU训练v5 — {model_name}")
    print(f"CUDA: {torch.cuda.is_available()}, GPU: {torch.cuda.get_device_name(0)}")
    print(f"=" * 60)

    # v5配置: 3-4 epoch，早停loss=2.5
    configs = {
        "tiny":   {"d_model": 192, "n_heads": 6, "n_layers": 6, "epochs": 3,  "lr": 3e-4, "max_data": 5000,  "dropout": 0.15},
        "small":  {"d_model": 320, "n_heads": 8, "n_layers": 8, "epochs": 3,  "lr": 2e-4, "max_data": 10000, "dropout": 0.15},
        "medium": {"d_model": 448, "n_heads": 8, "n_layers": 10, "epochs": 4, "lr": 1e-4, "max_data": 14860, "dropout": 0.15},
    }
    cfg = configs[model_name]

    # 加载预分词数据
    with open("/root/swarm-models/data/tokenized_samples.json", "r") as f:
        all_samples = json.load(f)

    samples = all_samples[model_name][:cfg["max_data"]]
    print(f"预分词数据: {len(samples)} 条")

    # 加载分词器信息（用于vocab_size和生成测试）
    with open("/root/swarm-models/data/shared_tokenizer.json", "r") as f:
        tok_data = json.load(f)
    vocab_size = len(tok_data.get("token_to_id", {}))
    print(f"词表大小: {vocab_size}")

    # 导入SwarmTokenizer用于生成测试
    import sys
    sys.path.insert(0, "/root/swarm-models")
    # 需要上传tokenizer.py到Volume
    from tokenizer import SwarmTokenizer
    tokenizer = SwarmTokenizer.load("/root/swarm-models/data/shared_tokenizer.json")

    # 构建模型（与本地SwarmModel一致）
    from model import SwarmModel

    device = "cuda"
    model = SwarmModel(
        vocab_size=vocab_size,
        d_model=cfg["d_model"],
        n_heads=cfg["n_heads"],
        n_layers=cfg["n_layers"],
        d_ff=cfg["d_model"] * 4,
        dropout=cfg["dropout"],
    ).to(device)

    total_params = sum(p.numel() for p in model.parameters())
    print(f"模型参数: {total_params/1e6:.2f}M (vocab_size={vocab_size})")


函数 main() 在 training/train_modal_v5.py:

def main():
    # 1. 本地预处理分词
    print("本地预处理分词...")
    tokenizer = SwarmTokenizer.load("/home/admin/swarm/training/models/shared_tokenizer.json")
    print(f"分词器加载完成: vocab={tokenizer.vocab_size_actual}")

    with open("/home/admin/swarm/training/data/chinese_training_data.json", "r") as f:
        all_data = json.load(f)
    print(f"训练数据: {len(all_data)} 条")

    # 分词所有数据
    max_len = 128
    configs = {
        "tiny":   {"max_data": 5000},
        "small":  {"max_data": 10000},
        "medium": {"max_data": 14860},
    }

    tokenized = {}
    for model_name, mcfg in configs.items():
        samples = []
        data_subset = all_data[:mcfg["max_data"]]
        for i, item in enumerate(data_subset):
            inp = item.get("input", "")
            out = item.get("output", "")
            text = f"问：{inp} 答：{out}"
            ids = tokenizer.encode(text, add_special=True)
            if len(ids) > max_len:
                ids = ids[:max_len]
            if len(ids) > 5:
                samples.append(ids)
            if (i + 1) % 2000 == 0:
                print(f"  {model_name}: 已分词 {i+1}/{len(data_subset)}")
        tokenized[model_name] = samples
        print(f"  {model_name}: {len(samples)} 有效样本")

    # 2. 上传预分词数据 + 分词器 + tokenizer.py
    print("\n上传预分词数据到Modal...")
    with open("/home/admin/swarm/training/models/shared_tokenizer.json", "r") as f:
        tokenizer_json = f.read()

    # 同时上传tokenizer.py到Volume（生成测试时decode需要）
    import subprocess
    # 先上传tokenizer.py和model.py到Volume
    with open("/home/admin/swarm/training/tokenizer.py", "r") as f:
        tokenizer_py = f.read()
    with open("/home/admin/swarm/training/model.py", "r") as f:
        model_py = f.read()

    # 临时保存到文件用于上传
    os.makedirs("/tmp/swarm-upload", exist_ok=True)
    with open("/tmp/swarm-upload/tokenized_samples.json", "w") as f:
        json.dump(tokenized, f)
    with open("/tmp/swarm-upload/tokenizer.py", "w") as f:
        f.write(tokenizer_py)
    wi


上传代码文件到Volume

函数 upload_code_files(tokenizer_py: str, model_py: str) 在 training/train_modal_v5.py: 上传代码文件到Volume

def upload_code_files(tokenizer_py: str, model_py: str):
    """上传代码文件到Volume"""
    with open("/root/swarm-models/tokenizer.py", "w") as f:
        f.write(tokenizer_py)
    with open("/root/swarm-models/model.py", "w") as f:
        f.write(model_py)
    vol.commit()
    print("代码文件已上传: tokenizer.py, model.py")


文件 training/train_modal.py: 虫群模型 — Modal GPU云端训练 v2
修复: vocab_size用实际词表长度, 减epoch防过拟合, 加dropout
用法: modal run training/train_modal.py | 定义: def upload_data, def train_model, def main

"""
虫群模型 — Modal GPU云端训练 v2
修复: vocab_size用实际词表长度, 减epoch防过拟合, 加dropout
用法: modal run training/train_modal.py
"""
import modal
import json

app = modal.App("swarm-gpu-train-v2")

# PyTorch + CUDA镜像
image = modal.Image.from_registry(
    "pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime"
).pip_install("numpy")

# 持久化存储
vol = modal.Volume.from_name("swarm-models", create_if_missing=True)

@app.function(image=image, volumes={"/root/swarm-models": vol})
def upload_data(data_json: str, tokenizer_json:


上传训练数据、分词器和模型定义到Volume

函数 upload_data(data_json: str, tokenizer_json: str, model_py: str, tokenizer_py: str) 在 training/train_modal.py: 上传训练数据、分词器和模型定义到Volume

def upload_data(data_json: str, tokenizer_json: str, model_py: str, tokenizer_py: str):
    """上传训练数据、分词器和模型定义到Volume"""
    import os

    data = json.loads(data_json)
    tokenizer = json.loads(tokenizer_json)

    os.makedirs("/root/swarm-models/data", exist_ok=True)
    with open("/root/swarm-models/data/chinese_training_data.json", "w") as f:
        json.dump(data, f, ensure_ascii=False)

    with open("/root/swarm-models/data/shared_tokenizer.json", "w") as f:
        json.dump(tokenizer, f, ensure_ascii=False)

    # 上传模型定义（训练用）
    with open("/root/swarm-models/model.py", "w") as f:
        f.write(model_py)

    # 上传分词器定义（训练用，修复了</w>问题）
    with open("/root/swarm-models/tokenizer.py", "w") as f:
        f.write(tokenizer_py)

    vol.commit()
    actual_vocab = len(tokenizer.get("token_to_id", {}))
    print(f"数据上传完成: {len(data)}条, 实际词表{actual_vocab}, model.py+tokenizer.py已上传")

@app.function(
    image=image,
    gpu="T4",
    timeout=3600,
    volumes={"/root/swarm-models": vol},
)


在GPU上训练虫群模型 — v2防过拟合版

函数 train_model(model_name: str = "tiny") 在 training/train_modal.py: 在GPU上训练虫群模型 — v2防过拟合版

def train_model(model_name: str = "tiny"):
    """在GPU上训练虫群模型 — v2防过拟合版"""
    import torch
    import torch.nn as nn
    from torch.optim import Adam
    import time
    import json
    import os
    import numpy as np

    print(f"=" * 60)
    print(f"虫群GPU训练v2 — {model_name}")
    print(f"CUDA: {torch.cuda.is_available()}, GPU: {torch.cuda.get_device_name(0)}")
    print(f"=" * 60)

    # v3配置: 3-4 epoch，loss目标2.0-3.0
    configs = {
        "tiny":   {"d_model": 192, "n_heads": 6, "n_layers": 6, "epochs": 3,  "lr": 3e-4, "max_data": 5000,  "dropout": 0.15},
        "small":  {"d_model": 320, "n_heads": 8, "n_layers": 8, "epochs": 3,  "lr": 2e-4, "max_data": 10000, "dropout": 0.15},
        "medium": {"d_model": 448, "n_heads": 8, "n_layers": 10, "epochs": 4,  "lr": 1e-4, "max_data": 14860, "dropout": 0.15},
    }
    cfg = configs[model_name]

    # 加载分词器 — 用与推理一致的SwarmTokenizer
    import sys
    sys.path.insert(0, "/root/swarm-models")
    from tokenizer import SwarmTokenizer
    with open("/root/swarm-models/data/shared_tokenizer.json", "r") as f:
        tok_data = json.load(f)
    # 从token_to_id获取实际词表大小，不用vocab_size字段
    vocab_size = len(tok_data.get("token_to_id", {}))
    print(f"实际词表大小: {vocab_size} (文件字段: {tok_data.get('vocab_size', 'N/A')})")

    tokenizer = SwarmTokenizer.load("/root/swarm-models/data/shared_tokenizer.json")

    # 加载训练数据
    with open("/root/swarm-models/data/chinese_training_data.json", "r") as f:
        all_data = json.load(f)

    train_data = all_data[:cfg["max_data"]]
    print(f"训练数据: {len(train_data)} 条")

    max_len = 128
    samples = []
    for item in train_data:
        inp = item.get("input", "")
        out = item.get("output", "")
        text = f"问：{inp} 答：{out}"
        ids = tokenizer.encode(text, add_special=True)
        if len(ids) > max_len:
            ids = ids[:max_len]
        if len(ids) > 5:
            samples.append(ids)

    print(f"有效样本: {len(samples)} 条")

    # 防过拟合参数
    dropout_rate = cfg["dropout"]


函数 main() 在 training/train_modal.py:

def main():
    # 本地读取数据（用修正后的分词器）
    with open("/home/admin/swarm/training/data/chinese_training_data.json", "r") as f:
        data_json = f.read()
    with open("/home/admin/swarm/training/models/shared_tokenizer.json", "r") as f:
        tokenizer_json = f.read()
    with open("/home/admin/swarm/training/model.py", "r") as f:
        model_py = f.read()
    with open("/home/admin/swarm/training/tokenizer.py", "r") as f:
        tokenizer_py = f.read()

    # 上传数据+模型定义+分词器定义
    print("上传训练数据+模型定义+分词器定义（v4修复版）...")
    upload_data.remote(data_json, tokenizer_json, model_py, tokenizer_py)

    # GPU训练全部三个模型
    for name in ["tiny", "small", "medium"]:
        print(f"\n开始GPU训练v4: {name}")
        train_model.remote(name)


文件 training/quantize_model.py: 虫群模型量化模块
Phase 1: PyTorch动态量化 (INT8) | 定义: def quantize_dynamic, def benchmark_inference

os sys json time torch training.model training.tokenizer

#!/usr/bin/env python3
"""
虫群模型量化模块
Phase 1: PyTorch动态量化 (INT8)
"""

import os
import sys
import json
import time

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))

import torch
from training.model import SwarmModel
from training.tokenizer import SwarmTokenizer

def quantize_dynamic(model_path: str, output_dir: str = None):
    """动态量化模型 (FP32 → INT8)

    Args:
        model_path: 模型目录路径 (含model.pt和meta.json)
        output_dir: 输出目录，默认为模型目录下quantized_int8


函数 quantize_dynamic(model_path: str, output_dir: str = None) 在 training/quantize_model.py: 动态量化模型 (FP32 → INT8)

    Args:
        model_path: 模型目录路径 (含model.pt和meta.json)
        output_dir: 输出目录，默认为模型目录下quantized_int8/

    Returns:
        量化后模型和元信息

def quantize_dynamic(model_path: str, output_dir: str = None):
    """动态量化模型 (FP32 → INT8)

    Args:
        model_path: 模型目录路径 (含model.pt和meta.json)
        output_dir: 输出目录，默认为模型目录下quantized_int8/

    Returns:
        量化后模型和元信息
    """
    # 加载原始模型
    meta_path = os.path.join(model_path, "meta.json")
    ckpt_path = os.path.join(model_path, "model.pt")

    if not os.path.exists(meta_path) or not os.path.exists(ckpt_path):
        raise FileNotFoundError(f"模型文件不存在: {model_path}")

    with open(meta_path, 'r') as f:
        meta = json.load(f)

    print(f"加载模型: {meta.get('model_name', 'unknown')}")
    print(f"  参数量: {meta['params']/1e6:.2f}M")
    print(f"  词表: {meta['vocab_size']}")

    # 构建模型
    model = SwarmModel(
        vocab_size=meta['vocab_size'],
        d_model=meta['d_model'],
        n_heads=meta['n_heads'],
        n_layers=meta['n_layers'],
        d_ff=meta['d_model'] * 4,
        dropout=0.0,  # 推理模式无dropout
    )

    # 加载权重
    ckpt = torch.load(ckpt_path, map_location='cpu')
    model.load_state_dict(ckpt['model_state_dict'])
    model.eval()

    # 量化前大小
    original_size = os.path.getsize(ckpt_path)
    print(f"  原始模型大小: {original_size/1e6:.1f}MB")

    # 动态量化
    print("\n执行动态量化 (FP32 → INT8)...")
    t0 = time.time()
    quantized_model = torch.quantization.quantize_dynamic(
        model, {torch.nn.Linear}, dtype=torch.qint8
    )
    quantize_time = time.time() - t0
    print(f"  量化耗时: {quantize_time:.2f}s")

    # 保存量化模型
    if output_dir is None:
        output_dir = os.path.join(model_path, "quantized_int8")
    os.makedirs(output_dir, exist_ok=True)

    torch.save({
        "model_state_dict": quantized_model.state_dict(),
        "config": meta,
        "vocab_size": meta['vocab_size'],
        "quantization": "dynamic_int8",
    }, os.path.join(output_dir, "model.pt"))

    # 量化后大小
    quant_size = os.path.getsize(os.path.join(output_dir, "model.pt"))
    ratio = original_size / quant_size if quant_size > 0 else 0
    print(f"  量化后大小: {qua


对比原始模型和量化模型的推理速度

函数 benchmark_inference(model_path: str, tokenizer_path: str, n_runs: int = 5) 在 training/quantize_model.py: 对比原始模型和量化模型的推理速度

def benchmark_inference(model_path: str, tokenizer_path: str, n_runs: int = 5):
    """对比原始模型和量化模型的推理速度"""

    # 加载分词器
    tokenizer = SwarmTokenizer.load(tokenizer_path)

    with open(os.path.join(model_path, "meta.json"), 'r') as f:
        meta = json.load(f)

    # 构建原始模型
    model_fp32 = SwarmModel(
        vocab_size=meta['vocab_size'],
        d_model=meta['d_model'],
        n_heads=meta['n_heads'],
        n_layers=meta['n_layers'],
        d_ff=meta['d_model'] * 4,
        dropout=0.0,
    )
    ckpt = torch.load(os.path.join(model_path, "model.pt"), map_location='cpu')
    model_fp32.load_state_dict(ckpt['model_state_dict'])
    model_fp32.eval()

    # 量化模型
    model_int8 = torch.quantization.quantize_dynamic(
        model_fp32, {torch.nn.Linear}, dtype=torch.qint8
    )

    # 测试文本
    test_text = "问：什么是人工智能"
    test_ids = [tokenizer.bos_id] + tokenizer.encode(test_text, add_special=False)
    input_tensor = torch.tensor([test_ids], dtype=torch.long)

    # FP32推理
    times_fp32 = []
    with torch.no_grad():
        for _ in range(n_runs):
            t0 = time.time()
            model_fp32.generate(input_tensor, max_new_tokens=30, temperature=0.8, top_k=40,
                               eos_id=tokenizer.eos_id, repetition_penalty=1.3)
            times_fp32.append(time.time() - t0)

    # INT8推理
    times_int8 = []
    with torch.no_grad():
        for _ in range(n_runs):
            t0 = time.time()
            model_int8.generate(input_tensor, max_new_tokens=30, temperature=0.8, top_k=40,
                               eos_id=tokenizer.eos_id, repetition_penalty=1.3)
            times_int8.append(time.time() - t0)

    avg_fp32 = sum(times_fp32) / len(times_fp32)
    avg_int8 = sum(times_int8) / len(times_int8)
    speedup = avg_fp32 / avg_int8 if avg_int8 > 0 else 0

    print(f"\n推理性能对比 (n={n_runs}):")
    print(f"  FP32: {avg_fp32:.3f}s")
    print(f"  INT8: {avg_int8:.3f}s")
    print(f"  加速比: {speedup:.2f}x")

    return {"fp32_avg": avg_fp32, "int8_avg": avg_int8, "speedup": s


文件 training/train_modal_v4.py: 虫群模型 — Modal GPU云端训练 v4
修复: 并行训练3个模型, 修复分词器</w>问题, 早停+dropout防过拟合
用法: modal run training/train_modal_v4.py | 定义: def upload_data, def train_model, def main

"""
虫群模型 — Modal GPU云端训练 v4
修复: 并行训练3个模型, 修复分词器</w>问题, 早停+dropout防过拟合
用法: modal run training/train_modal_v4.py
"""
import modal
import json

app = modal.App("swarm-gpu-train-v4")

# PyTorch + CUDA镜像
image = modal.Image.from_registry(
    "pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime"
).pip_install("numpy")

# 持久化存储
vol = modal.Volume.from_name("swarm-models", create_if_missing=True)

@app.function(image=image, volumes={"/root/swarm-models": vol})
def upload_data(data_json: str, tokenizer_json:


上传训练数据、分词器和模型定义到Volume

函数 upload_data(data_json: str, tokenizer_json: str, model_py: str, tokenizer_py: str) 在 training/train_modal_v4.py: 上传训练数据、分词器和模型定义到Volume

def upload_data(data_json: str, tokenizer_json: str, model_py: str, tokenizer_py: str):
    """上传训练数据、分词器和模型定义到Volume"""
    import os

    data = json.loads(data_json)
    tokenizer = json.loads(tokenizer_json)

    os.makedirs("/root/swarm-models/data", exist_ok=True)
    with open("/root/swarm-models/data/chinese_training_data.json", "w") as f:
        json.dump(data, f, ensure_ascii=False)

    with open("/root/swarm-models/data/shared_tokenizer.json", "w") as f:
        json.dump(tokenizer, f, ensure_ascii=False)

    with open("/root/swarm-models/model.py", "w") as f:
        f.write(model_py)

    with open("/root/swarm-models/tokenizer.py", "w") as f:
        f.write(tokenizer_py)

    vol.commit()
    actual_vocab = len(tokenizer.get("token_to_id", {}))
    print(f"数据上传完成: {len(data)}条, 实际词表{actual_vocab}, model.py+tokenizer.py已上传")

@app.function(
    image=image,
    gpu="T4",
    timeout=3600,
    volumes={"/root/swarm-models": vol},
)


在GPU上训练虫群模型 — v4修复分词器版

函数 train_model(model_name: str = "tiny") 在 training/train_modal_v4.py: 在GPU上训练虫群模型 — v4修复分词器版

def train_model(model_name: str = "tiny"):
    """在GPU上训练虫群模型 — v4修复分词器版"""
    import torch
    import torch.nn as nn
    from torch.optim import Adam
    import time
    import json
    import os
    import numpy as np

    print(f"{'=' * 60}")
    print(f"虫群GPU训练v4 — {model_name}")
    print(f"CUDA: {torch.cuda.is_available()}, GPU: {torch.cuda.get_device_name(0)}")
    print(f"{'=' * 60}")

    # v4配置: 3-4 epoch，loss目标2.0-3.0，dropout=0.15
    configs = {
        "tiny":   {"d_model": 192, "n_heads": 6, "n_layers": 6, "epochs": 3,  "lr": 3e-4, "max_data": 5000,  "dropout": 0.15},
        "small":  {"d_model": 320, "n_heads": 8, "n_layers": 8, "epochs": 3,  "lr": 2e-4, "max_data": 10000, "dropout": 0.15},
        "medium": {"d_model": 448, "n_heads": 8, "n_layers": 10, "epochs": 4, "lr": 1e-4, "max_data": 14860, "dropout": 0.15},
    }
    cfg = configs[model_name]

    # 加载分词器 — 用修复了</w>问题的SwarmTokenizer
    import sys
    sys.path.insert(0, "/root/swarm-models")
    from tokenizer import SwarmTokenizer

    with open("/root/swarm-models/data/shared_tokenizer.json", "r") as f:
        tok_data = json.load(f)
    vocab_size = len(tok_data.get("token_to_id", {}))
    print(f"实际词表大小: {vocab_size}")

    tokenizer = SwarmTokenizer.load("/root/swarm-models/data/shared_tokenizer.json")

    # 验证分词器编码
    test_enc = tokenizer.encode("你好", add_special=True)
    print(f"分词器验证: encode('你好')={test_enc}")

    # 加载训练数据
    with open("/root/swarm-models/data/chinese_training_data.json", "r") as f:
        all_data = json.load(f)

    train_data = all_data[:cfg["max_data"]]
    print(f"训练数据: {len(train_data)} 条")

    max_len = 128
    samples = []
    for item in train_data:
        inp = item.get("input", "")
        out = item.get("output", "")
        text = f"问：{inp} 答：{out}"
        ids = tokenizer.encode(text, add_special=True)
        if len(ids) > max_len:
            ids = ids[:max_len]
        if len(ids) > 5:
            samples.append(ids)

    print(f"有效样本: {len(sa


函数 main() 在 training/train_modal_v4.py:

def main():
    # 本地读取数据
    with open("/home/admin/swarm/training/data/chinese_training_data.json", "r") as f:
        data_json = f.read()
    with open("/home/admin/swarm/training/models/shared_tokenizer.json", "r") as f:
        tokenizer_json = f.read()
    with open("/home/admin/swarm/training/model.py", "r") as f:
        model_py = f.read()
    with open("/home/admin/swarm/training/tokenizer.py", "r") as f:
        tokenizer_py = f.read()

    # 上传数据+模型定义+分词器定义
    print("上传训练数据+模型定义+分词器定义（v4修复版）...")
    upload_data.remote(data_json, tokenizer_json, model_py, tokenizer_py)

    # 并行训练3个模型！
    print("\n并行启动3个GPU训练...")
    results = list(train_model.map(["tiny", "small", "medium"]))

    print("\n全部训练完成!")
    for r in results:
        print(f"  {r['model']}: {r['params']/1e6:.2f}M参数, loss={r['loss']:.4f}, vocab={r['vocab']}")


文件 training/test_economy.py: 虫群经济系统 — 端到端验证 | 定义:

#!/usr/bin/env python3
"""虫群经济系统 — 端到端验证"""
import sys, os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from core.aggregation_protocol.economy import SwarmEconomy
from core.aggregation_protocol.economy_types import ResourceType, TransactionType

print("=" * 60)
print("虫群经济系统 — 端到端验证")
print("=" * 60)

eco = SwarmEconomy(overmind_id="overmind")

# 1. 注册节点
print("\n[1] 注册节点...")
eco.register_node("queen_zhangming")  # 张明
eco.register_node("queen_lisi")       # 李


文件 training/train_embedding.py: 虫群v13 — Embedding语义训练

目标：用训练语料训练有语义的embedding，替换随机初始化
方法：Skip-gram简化版（窗口内共现 → 相似向量）
约束：CPU友好，5分钟内完成 | 定义: def load_texts, def build_cooccurrence, def train_embedding, def verify_embedding, def main

json numpy collections sys core.neuro.text_encoder

#!/usr/bin/env python3
"""
虫群v13 — Embedding语义训练

目标：用训练语料训练有语义的embedding，替换随机初始化
方法：Skip-gram简化版（窗口内共现 → 相似向量）
约束：CPU友好，5分钟内完成
"""

import json
import numpy as np
from collections import Counter
import sys
sys.path.insert(0, '/home/admin/swarm')

from core.neuro.text_encoder import SimpleTokenizer, EmbeddingLayer

def load_texts(path, max_lines=5000):
    """从训练数据加载文本"""
    texts = []
    with open(path, 'r', encoding='utf-8') as f:
        for i, line in enumerate(f):
            if i >= max


函数 load_texts(path, max_lines=5000) 在 training/train_embedding.py: 从训练数据加载文本

def load_texts(path, max_lines=5000):
    """从训练数据加载文本"""
    texts = []
    with open(path, 'r', encoding='utf-8') as f:
        for i, line in enumerate(f):
            if i >= max_lines:
                break
            line = line.strip()
            if not line:
                continue
            try:
                obj = json.loads(line)
                # 尝试多种字段名
                for key in ['input', 'text', 'prompt', 'question', 'instruction']:
                    if key in obj and obj[key]:
                        texts.append(obj[key])
                for key in ['output', 'response', 'answer']:
                    if key in obj and obj[key]:
                        texts.append(obj[key])
            except json.JSONDecodeError:
                if len(line) > 5:
                    texts.append(line)
    return texts


函数 build_cooccurrence(tokenizer, texts, window=3) 在 training/train_embedding.py: 构建共现矩阵（稀疏）

def build_cooccurrence(tokenizer, texts, window=3):
    """构建共现矩阵（稀疏）"""
    # 共现计数: pair_count[(i,j)] = 次数
    pair_count = Counter()
    token_freq = Counter()

    for text in texts:
        ids = tokenizer.encode(text)
        # 过滤特殊token
        valid = [tid for tid in ids if tid >= 4]
        token_freq.update(valid)

        for pos, tid in enumerate(valid):
            left = max(0, pos - window)
            right = min(len(valid), pos + window + 1)
            for other_pos in range(left, right):
                if other_pos != pos:
                    pair_count[(tid, valid[other_pos])] += 1

    return pair_count, token_freq


函数 train_embedding(tokenizer, pair_count, token_freq, embed_dim=32, epochs=10, lr=0.05) 在 training/train_embedding.py: SGNS简化训练: 让共现token的embedding相近

def train_embedding(tokenizer, pair_count, token_freq, embed_dim=32, epochs=10, lr=0.05):
    """SGNS简化训练: 让共现token的embedding相近"""
    vocab_size = tokenizer.vocab_size
    embedding = EmbeddingLayer(vocab_size=vocab_size, embed_dim=embed_dim)

    # 只训练有共现的token
    active_tokens = set()
    for (i, j) in pair_count:
        active_tokens.add(i)
        active_tokens.add(j)
    active_tokens = sorted(active_tokens)

    print(f"活跃token数: {len(active_tokens)}")
    print(f"共现对数: {len(pair_count)}")

    # 构建负采样频率表
    freq_array = np.zeros(vocab_size, dtype=np.float32)
    for tid, cnt in token_freq.items():
        if tid < vocab_size:
            freq_array[tid] = cnt
    freq_array = np.power(freq_array + 1, 0.75)  # 平滑
    freq_sum = freq_array.sum()
    if freq_sum > 0:
        neg_prob = freq_array / freq_sum
    else:
        neg_prob = np.ones(vocab_size, dtype=np.float32) / vocab_size

    # 训练
    pair_list = list(pair_count.items())

    for epoch in range(epochs):
        np.random.shuffle(pair_list)
        total_loss = 0.0
        n_updates = 0

        # 采样mini-batch
        batch_size = min(2000, len(pair_list))
        indices = np.random.choice(len(pair_list), batch_size, replace=False)

        for idx in indices:
            (tid_i, tid_j), count = pair_list[idx]
            if tid_i >= vocab_size or tid_j >= vocab_size:
                continue

            # 正样本: 共现的pair应该相似
            vec_i = embedding.weight[tid_i]
            vec_j = embedding.weight[tid_j]
            sim = np.dot(vec_i, vec_j) / (np.linalg.norm(vec_i) * np.linalg.norm(vec_j) + 1e-8)

            #梯度: 推高相似度
            grad_scale = lr * (1.0 - sim)  # sim越低梯度越大
            diff = vec_j - vec_i
            embedding.weight[tid_i] += grad_scale * diff * 0.1
            embedding.weight[tid_j] -= grad_scale * diff * 0.1

            # 负采样: 不共现的pair应该不相似
            n_neg = 2
            neg_ids = np.random.choice(vocab_size, size=n_neg, p=neg_prob)
            for neg_id in neg_ids:


验证embedding质量: 相似词应有高余弦相似度

函数 verify_embedding(embedding, tokenizer, test_words) 在 training/train_embedding.py: 验证embedding质量: 相似词应有高余弦相似度

def verify_embedding(embedding, tokenizer, test_words):
    """验证embedding质量: 相似词应有高余弦相似度"""
    print("\n=== Embedding质量验证 ===")

    for word in test_words:
        if word not in tokenizer.token2id:
            print(f"  '{word}' 不在词表中")
            continue
        tid = tokenizer.token2id[word]
        vec = embedding.weight[tid]

        # 找最近邻
        valid_ids = [i for i in range(4, tokenizer.vocab_size)
                     if i in tokenizer.id2token and tokenizer.id2token[i] != '<UNK>' and i != tid]
        if not valid_ids:
            continue

        sims = embedding.weight[valid_ids] @ vec
        top_idx = np.argsort(sims)[-5:][::-1]
        neighbors = [(tokenizer.id2token.get(valid_ids[i], '?'), f"{sims[i]:.3f}") for i in top_idx]
        print(f"  '{word}' → {neighbors}")


函数 main() 在 training/train_embedding.py:

def main():
    print("=== 虫群v13 Embedding语义训练 ===\n")

    # 1. 加载语料
    data_path = '/home/admin/swarm/training/data/chinese_sharegpt.json'
    print(f"加载语料: {data_path}")
    texts = load_texts(data_path, max_lines=5000)
    print(f"加载文本数: {len(texts)}")

    # 2. 构建词表
    tokenizer = SimpleTokenizer(vocab_size=5000)
    tokenizer.build_vocab(texts, min_freq=2)
    print(f"词表大小: {tokenizer.actual_vocab_size}")

    # 3. 构建共现
    print("构建共现矩阵...")
    pair_count, token_freq = build_cooccurrence(tokenizer, texts, window=3)
    print(f"共现对: {len(pair_count)}")

    # 4. 训练embedding
    embedding = train_embedding(tokenizer, pair_count, token_freq,
                                embed_dim=32, epochs=15, lr=0.05)

    # 5. 验证
    test_words = ['你', '我', '是', '学', '虫', '好', 'ai', 'python', '模型', '训练']
    verify_embedding(embedding, tokenizer, test_words)

    # 6. 保存
    save_path = '/home/admin/swarm/models/brain_templates/embedding_trained.pkl'
    import pickle
    with open(save_path, 'wb') as f:
        pickle.dump({
            'embedding': embedding,
            'tokenizer': tokenizer,
        }, f)
    print(f"\n保存到: {save_path}")

    # 7. 对比随机embedding
    print("\n=== 对比: 训练 vs 随机 ===")
    random_emb = EmbeddingLayer(vocab_size=5000, embed_dim=32)
    for word in ['你', '好', 'ai']:
        if word not in tokenizer.token2id:
            continue
        tid = tokenizer.token2id[word]
        vec_trained = embedding.weight[tid]
        vec_random = random_emb.weight[tid]

        # 训练embedding找最近邻
        sims_t = embedding.weight[4:tokenizer.actual_vocab_size] @ vec_trained
        sims_r = random_emb.weight[4:tokenizer.actual_vocab_size] @ vec_random

        # 找最相似的非自身token
        sims_t[tid-4] = -999
        sims_r[tid-4] = -999
        best_t = tokenizer.id2token.get(np.argmax(sims_t)+4, '?')
        best_r = tokenizer.id2token.get(np.argmax(sims_r)+4, '?')

        print(f"  '{word}': 训练→'{best_t}' 随机→'{best_


文件 training/test_api_moa.py: 虫群v8 — 真实API推理 + MOA聚合 端到端验证
验证：本地记忆 + 智谱GLM + NIM → MOA聚合最优答案 | 定义: def main

"""
虫群v8 — 真实API推理 + MOA聚合 端到端验证
验证：本地记忆 + 智谱GLM + NIM → MOA聚合最优答案
"""
import sys
import os
import time
import logging

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

logging.basicConfig(level=logging.INFO, format='%(message)s')
logger = logging.getLogger(__name__)

def main():
    print("=" * 60)
    print("虫群v8 — API推理 + MOA聚合 端到端验证")
    print("=" * 60)

    passed = 0
    total = 0

    # ============================================================


函数 main() 在 training/test_api_moa.py:

def main():
    print("=" * 60)
    print("虫群v8 — API推理 + MOA聚合 端到端验证")
    print("=" * 60)

    passed = 0
    total = 0

    # ============================================================
    # [1] 验证API推理适配器
    # ============================================================
    print("\n[1] 验证API推理适配器...")
    from core.api_inference import APIInferenceManager
    mgr = APIInferenceManager.from_env()

    total += 1
    providers = list(mgr.adapters.keys())
    model_count = len(mgr.models)
    print(f"  提供商: {providers}")
    print(f"  可用模型: {model_count}")

    if model_count > 0:
        print("  ✅ API推理适配器初始化成功")
        passed += 1
    else:
        print("  ❌ 无可用API模型(检查GLM_API_KEY/NIM_API_KEY环境变量)")

    # ============================================================
    # [2] 验证智谱GLM单模型推理
    # ============================================================
    print("\n[2] 验证智谱GLM推理...")
    total += 1

    glm_key = os.environ.get("GLM_API_KEY", "")
    if glm_key:
        result = mgr.infer("什么是人工智能？请简要回答", model_name="glm-4-flash")
        if result.success:
            print(f"  模型: {result.model}")
            print(f"  延迟: {result.latency_ms:.0f}ms")
            print(f"  Token: {result.tokens_used}")
            print(f"  回答: {result.answer[:100]}...")
            print("  ✅ 智谱GLM推理成功")
            passed += 1
        else:
            print(f"  ❌ GLM推理失败: {result.error}")
    else:
        print("  ⚠ 无GLM_API_KEY，跳过")
        passed += 1  # 不计为失败

    # ============================================================
    # [3] 验证NIM推理
    # ============================================================
    print("\n[3] 验证NIM推理...")
    total += 1

    nim_key = os.environ.get("NIM_API_KEY", "")
    if nim_key:
        result = mgr.infer("What is machine learning? Answer briefly.")
        if result.success:
            print(f"  模型: {result.model}")
            print(f"  延迟: {result.latency_ms:.0f}ms")
            print(f"  回答: {resul


文件 training/data_generator.py: 虫群训练数据生成器
为小模型训练生成高质量中文对话数据 | 定义: class TrainingDataGenerator, def fibonacci, def is_palindrome, def binary_search, def timer, def wrapper, def __init__, def generate, def _augment, def _classify

#!/usr/bin/env python3
"""
虫群训练数据生成器
为小模型训练生成高质量中文对话数据
"""

import os
import json
import random
from typing import Dict, List, Optional

class TrainingDataGenerator:
    """
    生成多领域中文训练数据
    分类：对话、知识、代码、推理、写作
    """

    # 对话数据模板
    DIALOGUE_TEMPLATES = [
        # 问候类
        {"input": "你好", "output": "你好！很高兴见到你，有什么我可以帮助你的吗？"},
        {"input": "早上好", "output": "早上好！新的一天开始了，祝你今天一切顺利！"},
        {"input": "你好呀", "output": "你好！我是虫群智能体，随时准备为你提供帮助。"},
        {"input": "嗨", "output": "嗨！有什么问


TrainingDataGenerator

生成多领域中文训练数据
    分类：对话、知识、代码、推理、写作

类 TrainingDataGenerator 在 training/data_generator.py: 生成多领域中文训练数据
    分类：对话、知识、代码、推理、写作 | 方法: fibonacci, is_palindrome, binary_search, timer, wrapper, __init__, generate, _augment, _classify, save

class TrainingDataGenerator:
    """
    生成多领域中文训练数据
    分类：对话、知识、代码、推理、写作
    """

    # 对话数据模板
    DIALOGUE_TEMPLATES = [
        # 问候类
        {"input": "你好", "output": "你好！很高兴见到你，有什么我可以帮助你的吗？"},
        {"input": "早上好", "output": "早上好！新的一天开始了，祝你今天一切顺利！"},
        {"input": "你好呀", "output": "你好！我是虫群智能体，随时准备为你提供帮助。"},
        {"input": "嗨", "output": "嗨！有什么问题尽管问我，我会尽力帮你解答。"},

        # 知识问答
        {"input": "什么是深度学习", "output": "深度学习是机器学习的一个分支，使用多层神经网络来学习数据的层次化表示。它通过反向传播算法自动学习特征，在图像识别、自然语言处理等领域取得了突破性进展。"},
        {"input": "什么是人工智能", "output": "人工智能是计算机科学的一个分支，致力于创建能够模拟人类智能行为的系统。包括感知、推理、学习和决策等能力，广泛应用于语音识别、图像处理、自然语言理解等领域。"},
        {"input": "什么是机器学习", "output": "机器学习是人工智能的核心技术，通过数据驱动的方式让计算机自动学习和改进。主要分为监督学习、无监督学习和强化学习三大类。"},
        {"input": "什么是神经网络", "output": "神经网络是模拟生物神经系统的计算模型，由大量互连的神经元组成。每个神经元接收输入，进行加权求和后通过激活函数输出，多层神经元堆叠形成深度网络。"},
        {"input": "什么是自然语言处理", "output": "自然语言处理是人工智能和语言学的交叉领域，研究如何让计算机理解和生成人类语言。主要任务包括分词、命名实体识别、情感分析、机器翻译等。"},
        {"input": "什么是强化学习", "output": "强化学习是一种通过与环境交互来学习最优策略的方法。智能体通过试错获得奖励信号，逐步优化行为策略。AlphaGo就是强化学习的经典应用。"},
        {"input": "什么是卷积神经网络", "output": "卷积神经网络是一种专门处理网格状数据的深度学习模型，通过卷积层提取局部特征，池化层降低维度，广泛应用于图像识别和计算机视觉任务。"},
        {"input": "什么是Transformer", "output": "Transformer是基于自注意力机制的深度学习架构，由Google在2017年提出。它摒弃了循环结构，通过并行计算大大提升了训练效率，是GPT、BERT等模型的基础。"},
        {"input": "什么是知识图谱", "output": "知识图谱是一种结构化的知识表示方式，以实体为节点、关系为边构建语义网络。它将信息组织成机器可理解的图结构，支撑智能搜索和问答系统。"},
        {"input": "什么是联邦学习", "output": "联邦学习是一种分布式机器学习框架，允许多个参与方在不共享原始数据的情况下联合训练模型。数据保留在本地，只交换模型更新，保护数据隐私。"},

        # Python相关
        {"input": "Python是什么", "output": "Python是一种高级编程语言，以简洁优雅的语法著称。它支持面向对象、函数式和过程式编程，广泛应用于Web开发、数据分析、人工智能和自动化脚本等领域。"},
        {"input": "什么是列表推导式", "output": "列表推导式是Python中创建列表的简洁语法。例如 [x**2 for x in range(10)] 生成0到9的平方列表。它比传统的for循环更简洁高效。"},
        {"input": "什么是装饰器", "output": "装饰器是Python的一种高级特性，用于在不修改函数代码的情况下扩展函数功能。它本质上是一个接受函数并返回新函数的高阶函数，常用于日志记录、权限验证等。"},
        {"input": "什么是生成器", "output": "生成器是Python中一种特殊的迭代器，使用yield关键字实现。它按需生成值，而不是一次性生成所有值，节省内存。适合处理大


fibonacci

方法 TrainingDataGenerator.fibonacci(): \n    if n <= 1:\n        return n\n    a, b = 0, 1\n    for _ in range(2, n + 1):\n        a, b = b

def fibonacci(self):\n    if n <= 1:\n        return n\n    a, b = 0, 1\n    for _ in range(2, n + 1):\n        a, b = b, a + b\n    return b\n\n# 使用动态规划避免递归，时间复杂度O(n)"},
        {"input": "写一个Python函数检查回文", "output": "def is_palindrome(s):\n    s = s.lower().replace(' ', '')\n    return s == s[::-1]\n\n# 将字符串转小写去空格后，比较正序和逆序"},
        {"input": "写一个Python函数实现二分查找", "output": "def binary_search(arr, target):\n    left, right = 0, len(arr) - 1\n    while left <= right:\n        mid = (left + right) // 2\n        if arr[mid] == target:\n            return mid\n        elif arr[mid] < target:\n            left = mid + 1\n        else:\n            right = mid - 1\n    return -1"},
        {"input": "写一个Python装饰器计时函数", "output": "import time\n\ndef timer(func):\n    def wrapper(*args, **kwargs):\n        start = time.time()\n        result = func(*args, **kwargs)\n        elapsed = time.time() - start\n        print(f'{func.__name__} 耗时: {elapsed:.4f}秒')\n        return result\n    return wrapper"},
    ]


方法 TrainingDataGenerator.is_palindrome(): \n    s = s.lower().replace(' ', '')\n    return s == s[::-1]\n\n# 将字符串转小写去空格后，比较正序和逆序"},
        {"

def is_palindrome(self):\n    s = s.lower().replace(' ', '')\n    return s == s[::-1]\n\n# 将字符串转小写去空格后，比较正序和逆序"},
        {"input": "写一个Python函数实现二分查找", "output": "def binary_search(arr, target):\n    left, right = 0, len(arr) - 1\n    while left <= right:\n        mid = (left + right) // 2\n        if arr[mid] == target:\n            return mid\n        elif arr[mid] < target:\n            left = mid + 1\n        else:\n            right = mid - 1\n    return -1"},
        {"input": "写一个Python装饰器计时函数", "output": "import time\n\ndef timer(func):\n    def wrapper(*args, **kwargs):\n        start = time.time()\n        result = func(*args, **kwargs)\n        elapsed = time.time() - start\n        print(f'{func.__name__} 耗时: {elapsed:.4f}秒')\n        return result\n    return wrapper"},
    ]


方法 TrainingDataGenerator.binary_search(): \n    left, right = 0, len(arr) - 1\n    while left <= right:\n        mid = (left + right) // 2\n

def binary_search(self):\n    left, right = 0, len(arr) - 1\n    while left <= right:\n        mid = (left + right) // 2\n        if arr[mid] == target:\n            return mid\n        elif arr[mid] < target:\n            left = mid + 1\n        else:\n            right = mid - 1\n    return -1"},
        {"input": "写一个Python装饰器计时函数", "output": "import time\n\ndef timer(func):\n    def wrapper(*args, **kwargs):\n        start = time.time()\n        result = func(*args, **kwargs)\n        elapsed = time.time() - start\n        print(f'{func.__name__} 耗时: {elapsed:.4f}秒')\n        return result\n    return wrapper"},
    ]


timer

方法 TrainingDataGenerator.timer(): \n    def wrapper(*args, **kwargs):\n        start = time.time()\n        result = func(*args, **kwa

def timer(self):\n    def wrapper(*args, **kwargs):\n        start = time.time()\n        result = func(*args, **kwargs)\n        elapsed = time.time() - start\n        print(f'{func.__name__} 耗时: {elapsed:.4f}秒')\n        return result\n    return wrapper"},
    ]


wrapper

方法 TrainingDataGenerator.wrapper(): \n        start = time.time()\n        result = func(*args, **kwargs)\n        elapsed = time.time()

def wrapper(self):\n        start = time.time()\n        result = func(*args, **kwargs)\n        elapsed = time.time() - start\n        print(f'{func.__name__} 耗时: {elapsed:.4f}秒')\n        return result\n    return wrapper"},
    ]


save

方法 TrainingDataGenerator.save():
        """保存数据"""
        os.makedirs(os.path.dirname(path), exist_ok=True)
        with open(path

def save(self):
        """保存数据"""
        os.makedirs(os.path.dirname(path), exist_ok=True)
        with open(path, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)

        # 统计
        cats = {}
        total_input = 0
        total_output = 0
        for d in data:
            cat = d["category"]
            cats[cat] = cats.get(cat, 0) + 1
            total_input += len(d["input"])
            total_output += len(d["output"])

        print(f"  数据已保存: {path}")
        print(f"  类别分布: {cats}")
        print(f"  平均输入长度: {total_input / len(data):.1f}字")
        print(f"  平均输出长度: {total_output / len(data):.1f}字")

if __name__ == "__main__":
    gen = TrainingDataGenerator()
    data = gen.generate(5000)
    gen.save(data, "/home/admin/swarm/training/data/train.json")


fibonacci

函数 fibonacci(n) 在 training/data_generator.py: 生成训练数据集

def fibonacci(n):\n    if n <= 1:\n        return n\n    a, b = 0, 1\n    for _ in range(2, n + 1):\n        a, b = b, a + b\n    return b\n\n# 使用动态规划避免递归，时间复杂度O(n)"},
        {"input": "写一个Python函数检查回文", "output": "def is_palindrome(s):\n    s = s.lower().replace(' ', '')\n    return s == s[::-1]\n\n# 将字符串转小写去空格后，比较正序和逆序"},
        {"input": "写一个Python函数实现二分查找", "output": "def binary_search(arr, target):\n    left, right = 0, len(arr) - 1\n    while left <= right:\n        mid = (left + right) // 2\n        if arr[mid] == target:\n            return mid\n        elif arr[mid] < target:\n            left = mid + 1\n        else:\n            right = mid - 1\n    return -1"},
        {"input": "写一个Python装饰器计时函数", "output": "import time\n\ndef timer(func):\n    def wrapper(*args, **kwargs):\n        start = time.time()\n        result = func(*args, **kwargs)\n        elapsed = time.time() - start\n        print(f'{func.__name__} 耗时: {elapsed:.4f}秒')\n        return result\n    return wrapper"},
    ]

    def __init__(self, seed: int = 42):
        self.seed = seed
        random.seed(seed)

    def generate(self, num_samples: int = 5000) -> List[Dict]:
        """生成训练数据集"""
        print(f"  生成训练数据: 目标{num_samples}条")

        all_templates = (
            self.DIALOGUE_TEMPLATES +
            self.KNOWLEDGE_DATA +
            self.CODE_DATA
        )

        data = []
        for i in range(num_samples):
            template = random.choice(all_templates)

            # 数据增强：随机变换
            item = self._augment(template, i)
            data.append(item)

        # 打乱
        random.shuffle(data)
        print(f"  生成完成: {len(data)}条")
        return data

    def _augment(self, template: Dict, idx: int) -> Dict:
        """数据增强"""
        inp = template["input"]
        out = template["output"]

        # 随机添加前缀
        prefixes = ["请告诉我", "请问", "帮我解答", "解释一下", "", "", ""]
        if random.random() < 0.3:
            inp = random.choice(prefixes) + inp

        # 随机添加后缀
        su


文件 training/test_integration.py: 虫群v8 — 三大核心集成验证

验证：参数化记忆 + 聚合协议 + 经济系统 三者协同工作 | 定义:

#!/usr/bin/env python3
"""
虫群v8 — 三大核心集成验证

验证：参数化记忆 + 聚合协议 + 经济系统 三者协同工作
"""
import sys, os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from core.swarm_node import SwarmNode, SwarmNetwork
from core.aggregation_protocol.types import PermissionLevel

print("=" * 60)
print("虫群v8 — 三大核心集成验证")
print("=" * 60)

# ===== [1] 创建网络 =====
print("\n[1] 创建虫群网络(3个虫后+1个虫皇)...")
network = SwarmNetwork()

queen_a = network.create_node("queen_zhangming", "张明的虫后", PermissionLe


文件 training/test_instant_write.py: 即时写入模式快速验证 | 定义:

#!/usr/bin/env python3
"""即时写入模式快速验证"""
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from core.parametric_memory import ParametricMemoryModel
import time

print('=== 即时写入模式快速测试 ===', flush=True)
pm = ParametricMemoryModel(model_config='tiny', lora_rank=4, write_mode='instant', accumulate_steps=3, micro_epochs=3)
print(f'写入模式: {pm.write_mode}', flush=True)

# 存3条记忆触发即时写入
memories = [
    ('chat', '我叫什么', '你叫张明', 0.9),
    ('chat', '我喜欢什么编程语言', '你喜欢Python', 0.9)


文件 training/train_local_v5.py: 本地预处理分词 + CPU训练v5 | 定义:

json sys time numpy training.tokenizer training.model torch torch.optim os

#!/usr/bin/env python3
"""本地预处理分词 + CPU训练v5"""
import json
import sys
import time
import numpy as np

sys.path.insert(0, "/home/admin/swarm")
from training.tokenizer import SwarmTokenizer
from training.model import SwarmModel

import torch
from torch.optim import Adam

print("=" * 60)
print("虫群本地CPU训练v5 — 修复分词器版")
print("=" * 60)

# 加载分词器
tokenizer = SwarmTokenizer.load("/home/admin/swarm/training/models/shared_tokenizer.json")
print(f"分词器: vocab={tokenizer.vocab_size_actual}")
print(f"分词验证: enc


文件 training/test_perm.py:  | 定义:

#!/usr/bin/env python3
import sys; sys.path.insert(0, '.')
from core.aggregation_protocol.permission import PermissionManager
from core.aggregation_protocol.types import PermissionLevel

pm = PermissionManager(PermissionLevel.QUEEN)
g = pm.grant_permission('queen_lisi', 'queen_zhangming', scope='specific', max_nodes=5, models_allowed=['reasoning'])
print('Grants:', {k: v.to_dict() for k, v in pm._grants.items()})
print('has_grant:', pm._has_grant('queen_zhangming', 'queen_lisi'))
print('node_lev


文件 training/hf_memory_training.py: 虫群记忆模型 — HF Spaces 24小时后台训练守护

用法：在HF Spaces的app.py中启动，或在后台持续运行 | 定义: def run_training_loop

os sys time json signal datetime core.parametric_memory

#!/usr/bin/env python3
"""
虫群记忆模型 — HF Spaces 24小时后台训练守护

用法：在HF Spaces的app.py中启动，或在后台持续运行
"""

import os
import sys
import time
import json
import signal
from datetime import datetime

# 添加项目路径
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, project_root)

from core.parametric_memory import ParametricMemoryModel

# 训练记忆数据集
TRAINING_MEMORIES = [
    # 个人信息
    ("chat", "我叫什么", "你叫张明", 0.9),
    ("chat", "我的名字", "你的名字是张明", 0.9),
    ("preference", "编程


函数 run_training_loop(quick=False) 在 training/hf_memory_training.py: 训练主循环

def run_training_loop(quick=False):
    """训练主循环"""
    print("=" * 60)
    print("虫群记忆模型 — HF Spaces 24小时训练守护")
    print("=" * 60)

    model_size = "tiny" if quick else "small"
    print(f"基座: {model_size}")
    print(f"写入模式: instant")
    print(f"开始时间: {datetime.now().isoformat()}")

    # 初始化
    print("\n[1] 初始化记忆模型...")
    pm = ParametricMemoryModel(
        model_config=model_size,
        lora_rank=4,
        write_mode='instant',
        accumulate_steps=5,
        micro_epochs=3,
        save_dir="/tmp/swarm_memory_model",
    )

    # 写入基础记忆
    print(f"\n[2] 写入基础记忆({len(TRAINING_MEMORIES)}条)...")
    for mtype, user, ai, imp in TRAINING_MEMORIES:
        if mtype == "chat":
            pm.store(user, ai, memory_type="chat", importance=imp)
        elif mtype == "preference":
            pm.store_preference(user, ai)
        elif mtype == "fact":
            pm.store_fact(ai, source=user)
        elif mtype == "habit":
            pm.store(user, ai, memory_type="habit", importance=imp)
        print(f"  + {user[:20]}")

    # 等待写入完成
    time.sleep(3)

    # 循环强化
    print(f"\n[3] 强化训练(每轮写入扩展记忆)...")
    for round_num in range(1, 100):  # 持续100轮
        print(f"\n--- 第{round_num}轮强化 ---")

        # 每轮写入扩展记忆
        for mtype, user, ai, imp in EXTENDED_MEMORIES:
            if mtype == "chat":
                pm.store(user, ai, memory_type="chat", importance=imp)
            elif mtype == "fact":
                pm.store_fact(ai, source=user)

        time.sleep(2)

        # 每5轮验证
        if round_num % 5 == 0:
            print(f"\n  验证(第{round_num}轮):")
            for q in ["我叫什么", "我喜欢什么编程语言", "什么是LoRA", "什么是虫群"]:
                r = pm.recall(q, max_tokens=20, temperature=0.3)
                print(f"    Q: {q} → A: {r['response'][:30]}")

            # 保存
            pm.save()
            print(f"  已保存检查点")

        status = pm.get_status()
        print(f"  状态: {status['total_memories']}条记忆, {status['total_train_steps


文件 training/test_aggregation_protocol.py: 虫群聚合协议 — 端到端验证

测试场景：
1. 创建3个虫后节点（模拟3个用户）
2. 创建1个脑虫节点（区域路由）
3. 虫皇权限测试
4. 临时服务器组建与解散
5. 聚合任务全流程 | 定义: def test_basic

#!/usr/bin/env python3
"""
虫群聚合协议 — 端到端验证

测试场景：
1. 创建3个虫后节点（模拟3个用户）
2. 创建1个脑虫节点（区域路由）
3. 虫皇权限测试
4. 临时服务器组建与解散
5. 聚合任务全流程
"""

import sys
import os

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from core.aggregation_protocol import (
    AggregationProtocol, NodeRole, PermissionLevel,
    AggregationStrategy, NodeStatus,
)

def test_basic():
    """基础测试：3个节点 + 聚合任务"""
    print("=" * 60)
    print("虫群聚合协议 — 端到端验证")
    print("=" * 60)

    # 1. 创建虫后A（发起者）


基础测试：3个节点 + 聚合任务

函数 test_basic() 在 training/test_aggregation_protocol.py: 基础测试：3个节点 + 聚合任务

def test_basic():
    """基础测试：3个节点 + 聚合任务"""
    print("=" * 60)
    print("虫群聚合协议 — 端到端验证")
    print("=" * 60)

    # 1. 创建虫后A（发起者）
    print("\n[1] 创建节点...")
    queen_a = AggregationProtocol(
        node_id="queen_zhangming",
        role=NodeRole.QUEEN,
        name="张明的虫后",
        permission_level=PermissionLevel.QUEEN,
        capabilities=["coding", "python", "analysis"],
        compute_score=3.5,
    )
    queen_a.start()
    print(f"  虫后A: {queen_a.node_info.node_id} (权限={queen_a.node_info.permission_level.value})")

    # 2. 创建虫后B
    queen_b = AggregationProtocol(
        node_id="queen_lisi",
        role=NodeRole.QUEEN,
        name="李四的虫后",
        permission_level=PermissionLevel.QUEEN,
        capabilities=["reasoning", "math", "logic"],
        compute_score=4.0,
    )
    queen_b.start()
    print(f"  虫后B: {queen_b.node_info.node_id}")

    # 3. 创建虫后C
    queen_c = AggregationProtocol(
        node_id="queen_wangwu",
        role=NodeRole.QUEEN,
        name="王五的虫后",
        permission_level=PermissionLevel.QUEEN,
        capabilities=["translation", "creative", "writing"],
        compute_score=2.5,
    )
    queen_c.start()
    print(f"  虫后C: {queen_c.node_info.node_id}")

    # 4. 互相发现
    print("\n[2] 节点互相发现...")
    queen_a.add_local_node(queen_b)
    queen_a.add_local_node(queen_c)
    queen_b.add_local_node(queen_a)
    queen_b.add_local_node(queen_c)

    nodes = queen_a.discover_nodes()
    print(f"  虫后A发现 {len(nodes)} 个节点: {[n['node_id'] for n in nodes]}")

    # 5. 授权：虫后A授权调用虫后B和C
    print("\n[3] 权限管理...")
    queen_a.permission.grant_permission(
        granter_id="queen_lisi",
        grantee_id="queen_zhangming",
        scope="specific",
        max_nodes=5,
        models_allowed=["reasoning", "math"],
    )
    queen_a.permission.grant_permission(
        granter_id="queen_wangwu",
        grantee_id="queen_zhangming",
        scope="specific",
        max_nodes=3,
        models_allowed=["translation"],
    )
    print


train.py

文件 training/train.py: 虫群训练管线 — 端到端训练小模型
1. 准备数据 + 训练分词器
2. 构建模型
3. 训练循环
4. 评估 + 保存 | 定义: class ChatDataset, def __init__, def _prepare, def __len__, def __getitem__, class SwarmTrainer, def __init__, def train, def _save, def main

#!/usr/bin/env python3
"""
虫群训练管线 — 端到端训练小模型
1. 准备数据 + 训练分词器
2. 构建模型
3. 训练循环
4. 评估 + 保存
"""

import os
import sys
import json
import time
import math
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from typing import Dict, List, Optional

# 添加项目路径
sys.path.insert(0, "/home/admin/swarm")

from training.tokenizer import SwarmTokenizer
from training.model import SwarmModel
from training.data_generator import TrainingDataGenerator

class ChatDataset(Dataset):


ChatDataset

类 ChatDataset 在 training/train.py: 对话训练数据集 | 方法: __init__, _prepare, __len__, __getitem__

class ChatDataset:
    """对话训练数据集"""

    def __init__(self, data: List[Dict], tokenizer: SwarmTokenizer, max_len: int = 256):
        self.data = data
        self.tokenizer = tokenizer
        self.max_len = max_len
        self.samples = self._prepare()

    def _prepare(self) -> List[Dict]:
        """准备训练样本：input_ids + targets"""
        samples = []
        for item in self.data:
            # 格式: [BOS] input [SEP] output [EOS]
            input_ids = self.tokenizer.encode(item["input"], add_special=True)
            sep_id = self.tokenizer.token_to_id.get("[SEP]", 5)
            output_ids = self.tokenizer.encode(item["output"])
            eos_id = self.tokenizer.eos_id

            full_ids = input_ids + [sep_id] + output_ids + [eos_id]

            # 截断
            if len(full_ids) > self.max_len:
                full_ids = full_ids[:self.max_len]

            # padding
            pad_len = self.max_len - len(full_ids)
            pad_id = self.tokenizer.pad_id
            attention_mask = [1] * len(full_ids) + [0] * pad_len
            full_ids = full_ids + [pad_id] * pad_len

            # targets: 对input部分忽略(用-100)，只对output部分计算loss
            input_len = len(input_ids) + 1  # +1 for SEP
            targets = [-100] * input_len + full_ids[input_len:]

            samples.append({
                "input_ids": full_ids,
                "targets": targets,
                "attention_mask": attention_mask,
            })

        return samples

    def __len__(self):
        return len(self.samples)

    def __getitem__(self, idx):
        s = self.samples[idx]
        return (
            torch.tensor(s["input_ids"], dtype=torch.long),
            torch.tensor(s["targets"], dtype=torch.long),
            torch.tensor(s["attention_mask"], dtype=torch.long),
        )


SwarmTrainer

类 SwarmTrainer 在 training/train.py: 虫群模型训练器 | 方法: __init__, train, _save

class SwarmTrainer:
    """虫群模型训练器"""

    def __init__(
        self,
        model_config: str = "tiny",
        vocab_size: int = 8192,
        max_len: int = 256,
        batch_size: int = 16,
        learning_rate: float = 3e-4,
        num_epochs: int = 10,
        warmup_steps: int = 100,
        save_dir: str = "/home/admin/swarm/training/models",
        device: str = "auto",
    ):
        self.model_config = model_config
        self.vocab_size = vocab_size
        self.max_len = max_len
        self.batch_size = batch_size
        self.learning_rate = learning_rate
        self.num_epochs = num_epochs
        self.warmup_steps = warmup_steps
        self.save_dir = save_dir

        # 设备
        if device == "auto":
            self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        else:
            self.device = torch.device(device)

        print(f"  训练设备: {self.device}")

    def train(self, train_data: List[Dict], val_data: Optional[List[Dict]] = None) -> Dict:
        """完整训练流程"""
        start_time = time.time()
        metrics = {"train_loss": [], "val_loss": [], "epochs": 0}

        # 1. 训练分词器
        print("\n[1/4] 训练分词器...")
        all_texts = []
        for d in train_data:
            all_texts.append(d["input"])
            all_texts.append(d["output"])

        tokenizer = SwarmTokenizer(vocab_size=self.vocab_size)
        tokenizer.train(all_texts, min_freq=1)
        actual_vocab = tokenizer.vocab_size_actual
        print(f"  实际词表: {actual_vocab}")

        # 2. 构建模型
        print(f"\n[2/4] 构建{self.model_config}模型...")
        model = SwarmModel.from_config(
            self.model_config,
            vocab_size=actual_vocab,
            max_len=self.max_len,
        )
        model = model.to(self.device)
        info = model.get_info()
        print(f"  参数: {info['params_M']}M, 大小: {info['size_mb']}MB")

        # 3. 准备数据
        print(f"\n[3/4] 准备数据...")
        train_dataset = ChatDataset(train_data, tokenizer, self.max_len


main

函数 main() 在 training/train.py: 主训练入口

def main():
    """主训练入口"""
    import argparse
    parser = argparse.ArgumentParser(description="虫群模型训练")
    parser.add_argument("--config", type=str, default="tiny", choices=["tiny", "small", "medium"])
    parser.add_argument("--epochs", type=int, default=10)
    parser.add_argument("--batch-size", type=int, default=16)
    parser.add_argument("--lr", type=float, default=3e-4)
    parser.add_argument("--num-samples", type=int, default=5000)
    parser.add_argument("--max-len", type=int, default=256)
    args = parser.parse_args()

    print("=" * 50)
    print(f"  🐝 虫群模型训练: {args.config}")
    print("=" * 50)

    # 生成训练数据
    print("\n生成训练数据...")
    gen = TrainingDataGenerator()
    train_data = gen.generate(args.num_samples)

    # 保存原始数据
    data_path = f"/home/admin/swarm/training/data/train_{args.config}.json"
    gen.save(train_data, data_path)

    # 训练
    trainer = SwarmTrainer(
        model_config=args.config,
        vocab_size=8192,
        max_len=args.max_len,
        batch_size=args.batch_size,
        learning_rate=args.lr,
        num_epochs=args.epochs,
    )
    metrics = trainer.train(train_data)

    # 保存训练指标
    metrics_path = f"/home/admin/swarm/training/logs/metrics_{args.config}.json"
    os.makedirs(os.path.dirname(metrics_path), exist_ok=True)
    with open(metrics_path, "w") as f:
        json.dump(metrics, f, ensure_ascii=False, indent=2)

    print(f"\n训练指标已保存: {metrics_path}")

if __name__ == "__main__":
    main()


文件 skills/__init__.py: 技能模块
提供文本解析、任务分类、安全过滤、对话管理四大技能 | 定义: class SkillPipeline, def __init__, def add, def execute, def get_all_stats, def create_default_pipeline

#!/usr/bin/env python3
"""
技能模块
提供文本解析、任务分类、安全过滤、对话管理四大技能
"""

from skills.base_skill import (
    BaseSkill, SkillType, SkillStatus,
    SkillInput, SkillOutput,
)
from skills.text_parser import TextParserSkill, TextAnalysisResult, Sentiment, TextType
from skills.task_classifier import TaskClassifierSkill, TaskCategory, TaskPriority
from skills.safety_filter import SafetyFilterSkill, SafetyLevel, ContentType
from skills.dialogue_manager import DialogueManagerSkill, DialogueState, TopicCategory


SkillPipeline

技能管线
    将多个技能串联执行，前一个技能的输出可作为后一个的输入

类 SkillPipeline 在 skills/__init__.py: 技能管线
    将多个技能串联执行，前一个技能的输出可作为后一个的输入 | 方法: __init__, add, execute, get_all_stats

class SkillPipeline:
    """
    技能管线
    将多个技能串联执行，前一个技能的输出可作为后一个的输入
    """

    def __init__(self, skills: list = None):
        self.skills: list[BaseSkill] = skills or []

    def add(self, skill: BaseSkill):
        """添加技能"""
        self.skills.append(skill)

    def execute(self, text: str, context: dict = None,
                user_id: str = "default", session_id: str = "") -> dict:
        """
        执行管线中所有技能
        返回合并结果
        """
        skill_input = SkillInput(
            text=text,
            context=context or {},
            user_id=user_id,
            session_id=session_id,
        )

        results = {}
        enriched_context = dict(skill_input.context)

        for skill in self.skills:
            output = skill.execute(skill_input)
            results[skill.name] = output

            # 将前一个技能的结果注入上下文，供后续技能使用
            if output.success and output.result:
                enriched_context[f"prev_{skill.name}"] = output.result
                skill_input = SkillInput(
                    text=text,
                    context=enriched_context,
                    user_id=user_id,
                    session_id=session_id,
                )

        return results

    def get_all_stats(self) -> dict:
        """获取所有技能统计"""
        return {s.name: s.get_stats() for s in self.skills}


add

方法 SkillPipeline.add():
        """添加技能"""
        self.skills.append(skill)

def add(self):
        """添加技能"""
        self.skills.append(skill)


文件 skills/safety_filter.py: 安全过滤技能
检测和过滤敏感内容，包括违规检测、隐私保护、内容分级 | 定义: class SafetyLevel, class ContentType, class
class, def to_dict, class SafetyFilterSkill, def __init__, def process, def _detect_and_mask_pii, def _detect_sensitive_content, def _detect_spam

re enum typing dataclasses skills.base_skill

#!/usr/bin/env python3
"""
安全过滤技能
检测和过滤敏感内容，包括违规检测、隐私保护、内容分级
"""

import re
from enum import Enum
from typing import Dict, List, Tuple
from dataclasses import dataclass, field

from skills.base_skill import BaseSkill, SkillType, SkillInput, SkillOutput

class SafetyLevel(Enum):
    """安全等级"""
    SAFE = "safe"             # 安全
    CAUTION = "caution"       # 需注意
    DANGEROUS = "dangerous"   # 危险
    BLOCKED = "blocked"       # 已拦截

class ContentType(Enum):
    """内容类型标记"""
    NORMAL = "norma


SafetyLevel

类 SafetyLevel 在 skills/safety_filter.py: 安全等级 | 方法:

class SafetyLevel:
    """安全等级"""
    SAFE = "safe"             # 安全
    CAUTION = "caution"       # 需注意
    DANGEROUS = "dangerous"   # 危险
    BLOCKED = "blocked"       # 已拦截


ContentType

类 ContentType 在 skills/safety_filter.py: 内容类型标记 | 方法:

class ContentType:
    """内容类型标记"""
    NORMAL = "normal"
    PII = "pii"               # 个人隐私信息
    SENSITIVE = "sensitive"    # 敏感话题
    HARMFUL = "harmful"        # 有害内容
    SPAM = "spam"             # 垃圾信息

@dataclass


SafetyCheckResult

类 SafetyCheckResult 在 skills/safety_filter.py: 安全检查结果 | 方法: to_dict

class SafetyCheckResult:
    """安全检查结果"""
    is_safe: bool = True
    safety_level: SafetyLevel = SafetyLevel.SAFE
    detected_issues: List[Dict] = field(default_factory=list)
    filtered_text: str = ""
    content_types: List[ContentType] = field(default_factory=list)
    risk_score: float = 0.0  # 0-1，越高越危险

    def to_dict(self) -> Dict:
        return {
            "is_safe": self.is_safe,
            "safety_level": self.safety_level.value,
            "detected_issues": self.detected_issues,
            "filtered_text": self.filtered_text,
            "content_types": [ct.value for ct in self.content_types],
            "risk_score": self.risk_score,
        }


SafetyFilterSkill

安全过滤技能
    对输入文本进行安全检查和内容过滤

类 SafetyFilterSkill 在 skills/safety_filter.py: 安全过滤技能
    对输入文本进行安全检查和内容过滤 | 方法: __init__, process, _detect_and_mask_pii, _detect_sensitive_content, _detect_spam, _calculate_risk_score, _determine_safety_level

class SafetyFilterSkill:
    """
    安全过滤技能
    对输入文本进行安全检查和内容过滤
    """

    # 个人隐私信息(PII)模式
    PII_PATTERNS = {
        "phone": (r"1[3-9]\d{9}", "手机号"),
        "email": (r"[\w.-]+@[\w.-]+\.\w+", "邮箱"),
        "id_card": (r"\d{17}[\dXx]", "身份证号"),
        "bank_card": (r"\d{16,19}", "银行卡号"),
        "ip_address": (r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", "IP地址"),
    }

    # 敏感话题关键词
    SENSITIVE_KEYWORDS = {
        "violence": ["暴力", "杀人", "袭击", "炸弹", "武器"],
        "self_harm": ["自杀", "自残", "不想活"],
        "illegal": ["赌博", "洗钱", "诈骗", "毒品", "走私"],
        "hate": ["歧视", "仇恨", "侮辱"],
    }

    # 垃圾信息模式
    SPAM_PATTERNS = [
        r"免费.{0,10}领取",
        r"点击.{0,5}链接.{0,5}领取",
        r"限时.{0,5}优惠",
        r"(加|添).{0,3}(微信|QQ|群).{0,10}(领|获取|拿)",
    ]

    # 替换模板
    MASK_TEMPLATES = {
        "phone": lambda m: m.group()[:3] + "****" + m.group()[-4:],
        "email": lambda m: m.group()[0] + "***@" + m.group().split("@")[-1],
        "id_card": lambda m: m.group()[:6] + "********" + m.group()[-4:],
        "bank_card": lambda m: m.group()[:4] + "****" + m.group()[-4:],
        "ip_address": lambda m: m.group().split(".")[0] + ".*.*.*",
    }

    def __init__(self):
        super().__init__(
            skill_type=SkillType.SAFETY_FILTER,
            name="safety_filter",
            description="安全过滤：PII检测/敏感词/内容分级/脱敏",
        )

    def process(self, skill_input: SkillInput) -> SkillOutput:
        """处理安全过滤"""
        text = skill_input.text
        if not text or not text.strip():
            return SkillOutput(success=True, result={"is_safe": True}, confidence=1.0)

        result = SafetyCheckResult()
        result.filtered_text = text

        # 1. PII检测和脱敏
        pii_found = self._detect_and_mask_pii(result)

        # 2. 敏感话题检测
        sensitive_found = self._detect_sensitive_content(text, result)

        # 3. 垃圾信息检测
        spam_found = self._detect_spam(text, result)

        # 4. 综合风险评估
        result.risk_score = self._calculate_risk_score(pii_found, sensitive_


文件 skills/base_skill.py: 技能基类
所有技能的统一基类，定义标准接口和生命周期管理 | 定义: class SkillType, class SkillStatus, class
class, class
class, class BaseSkill, def __init__, def process, def execute, def get_stats, def reset

time logging abc enum typing dataclasses

#!/usr/bin/env python3
"""
技能基类
所有技能的统一基类，定义标准接口和生命周期管理
"""

import time
import logging
from abc import ABC, abstractmethod
from enum import Enum
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, field

class SkillType(Enum):
    """技能类型"""
    TEXT_PARSE = "text_parse"       # 文本解析
    TASK_CLASSIFY = "task_classify" # 任务分类
    SAFETY_FILTER = "safety_filter" # 安全过滤
    DIALOGUE = "dialogue"           # 对话管理
    INSTRUCTION = "instruction"     # 指令生成

class Skill


SkillType

类 SkillType 在 skills/base_skill.py: 技能类型 | 方法:

class SkillType:
    """技能类型"""
    TEXT_PARSE = "text_parse"       # 文本解析
    TASK_CLASSIFY = "task_classify" # 任务分类
    SAFETY_FILTER = "safety_filter" # 安全过滤
    DIALOGUE = "dialogue"           # 对话管理
    INSTRUCTION = "instruction"     # 指令生成


SkillStatus

类 SkillStatus 在 skills/base_skill.py: 技能状态 | 方法:

class SkillStatus:
    """技能状态"""
    IDLE = "idle"
    RUNNING = "running"
    ERROR = "error"
    DISABLED = "disabled"

@dataclass


SkillInput

类 SkillInput 在 skills/base_skill.py: 技能输入 | 方法:

class SkillInput:
    """技能输入"""
    text: str
    context: Dict = field(default_factory=dict)
    user_id: str = "default"
    session_id: str = ""

@dataclass


SkillOutput

类 SkillOutput 在 skills/base_skill.py: 技能输出 | 方法:

class SkillOutput:
    """技能输出"""
    success: bool
    result: Any = None
    skill_type: str = ""
    confidence: float = 0.0
    processing_time_ms: float = 0.0
    error: str = ""


BaseSkill

技能基类
    所有技能必须继承此类并实现 process() 方法

类 BaseSkill 在 skills/base_skill.py: 技能基类
    所有技能必须继承此类并实现 process() 方法 | 方法: __init__, process, execute, get_stats, reset, __repr__

class BaseSkill:
    """
    技能基类
    所有技能必须继承此类并实现 process() 方法
    """

    def __init__(self, skill_type: SkillType, name: str, description: str = ""):
        self.skill_type = skill_type
        self.name = name
        self.description = description
        self.status = SkillStatus.IDLE
        self.logger = logging.getLogger(f"skill.{name}")
        self._call_count = 0
        self._total_time_ms = 0.0
        self._error_count = 0

    @abstractmethod
    def process(self, skill_input: SkillInput) -> SkillOutput:
        """处理输入，子类必须实现"""
        pass

    def execute(self, skill_input: SkillInput) -> SkillOutput:
        """
        执行技能（带状态管理和性能统计）
        这是外部调用的入口方法
        """
        start = time.time()
        self.status = SkillStatus.RUNNING
        self._call_count += 1

        try:
            output = self.process(skill_input)
            elapsed_ms = (time.time() - start) * 1000
            output.processing_time_ms = elapsed_ms
            output.skill_type = self.skill_type.value

            self._total_time_ms += elapsed_ms
            self.status = SkillStatus.IDLE
            return output

        except Exception as e:
            elapsed_ms = (time.time() - start) * 1000
            self._error_count += 1
            self.status = SkillStatus.ERROR
            self.logger.error(f"技能 {self.name} 执行失败: {e}")

            return SkillOutput(
                success=False,
                error=str(e),
                skill_type=self.skill_type.value,
                processing_time_ms=elapsed_ms,
            )

    def get_stats(self) -> Dict:
        """获取技能统计信息"""
        avg_time = self._total_time_ms / max(self._call_count, 1)
        error_rate = self._error_count / max(self._call_count, 1)
        return {
            "name": self.name,
            "type": self.skill_type.value,
            "status": self.status.value,
            "call_count": self._call_count,
            "avg_time_ms": round(avg_time, 2),
            "error_count": self._error


reset

方法 BaseSkill.reset():
        """重置技能状态"""
        self.status = SkillStatus.IDLE
        self._call_count = 0
        se

def reset(self):
        """重置技能状态"""
        self.status = SkillStatus.IDLE
        self._call_count = 0
        self._total_time_ms = 0.0
        self._error_count = 0


文件 skills/text_parser.py: 文本解析技能
对输入文本进行多维度分析：情感、关键词、意图、实体、摘要 | 定义: class Sentiment, class TextType, class TextAnalysisResult, def __init__, def to_dict, class TextParserSkill, def __init__, def process, def _detect_language, def _classify_text_type

re math collections typing enum skills.base_skill

#!/usr/bin/env python3
"""
文本解析技能
对输入文本进行多维度分析：情感、关键词、意图、实体、摘要
"""

import re
import math
from collections import Counter
from typing import Dict, List, Optional, Tuple
from enum import Enum

from skills.base_skill import BaseSkill, SkillType, SkillInput, SkillOutput

class Sentiment(Enum):
    """情感类型"""
    POSITIVE = "positive"
    NEGATIVE = "negative"
    NEUTRAL = "neutral"

class TextType(Enum):
    """文本类型"""
    QUESTION = "question"     # 疑问
    STATEMENT = "statement"   # 陈述
    COM


Sentiment

类 Sentiment 在 skills/text_parser.py: 情感类型 | 方法:

class Sentiment:
    """情感类型"""
    POSITIVE = "positive"
    NEGATIVE = "negative"
    NEUTRAL = "neutral"


TextType

类 TextType 在 skills/text_parser.py: 文本类型 | 方法:

class TextType:
    """文本类型"""
    QUESTION = "question"     # 疑问
    STATEMENT = "statement"   # 陈述
    COMMAND = "command"       # 命令
    GREETING = "greeting"     # 问候


TextAnalysisResult

类 TextAnalysisResult 在 skills/text_parser.py: 文本分析结果 | 方法: __init__, to_dict

class TextAnalysisResult:
    """文本分析结果"""

    def __init__(self):
        self.text_type: TextType = TextType.STATEMENT
        self.sentiment: Sentiment = Sentiment.NEUTRAL
        self.sentiment_score: float = 0.0
        self.keywords: List[str] = []
        self.entities: List[Dict] = []
        self.intent: str = "unknown"
        self.summary: str = ""
        self.word_count: int = 0
        self.char_count: int = 0
        self.has_question: bool = False
        self.language_hint: str = "zh"  # zh/en/mixed

    def to_dict(self) -> Dict:
        return {
            "text_type": self.text_type.value,
            "sentiment": self.sentiment.value,
            "sentiment_score": self.sentiment_score,
            "keywords": self.keywords,
            "entities": self.entities,
            "intent": self.intent,
            "summary": self.summary,
            "word_count": self.word_count,
            "char_count": self.char_count,
            "has_question": self.has_question,
            "language_hint": self.language_hint,
        }


TextParserSkill

文本解析技能
    对用户输入进行轻量级多维分析

类 TextParserSkill 在 skills/text_parser.py: 文本解析技能
    对用户输入进行轻量级多维分析 | 方法: __init__, process, _detect_language, _classify_text_type, _analyze_sentiment, _extract_keywords, _extract_entities, _detect_intent, _generate_summary, _calculate_confidence

class TextParserSkill:
    """
    文本解析技能
    对用户输入进行轻量级多维分析
    """

    # 中文停用词
    STOP_WORDS = frozenset({
        "的", "了", "是", "在", "我", "你", "他", "她", "它",
        "这", "那", "和", "与", "或", "也", "都", "就", "要",
        "会", "能", "可以", "把", "被", "从", "到", "对", "给",
    })

    # 情感词典
    POSITIVE_WORDS = frozenset({
        "好", "棒", "优秀", "喜欢", "满意", "开心", "高兴", "感谢",
        "不错", "赞", "完美", "厉害", "牛", "强", "精彩",
    })
    NEGATIVE_WORDS = frozenset({
        "不好", "差", "糟糕", "讨厌", "不满", "生气", "难过", "失望",
        "错误", "失败", "问题", "麻烦", "困难", "烂", "弱",
    })

    # 问题指示词
    QUESTION_MARKERS = frozenset({
        "什么", "如何", "为什么", "怎么", "哪", "几", "多少",
        "是否", "能否", "可以", "吗", "呢", "？",
    })

    # 命令指示词
    COMMAND_MARKERS = frozenset({
        "请", "帮我", "帮我", "给我", "写", "创建", "生成", "制作",
        "删除", "修改", "更新", "执行", "运行", "安装",
    })

    # 问候词
    GREETING_MARKERS = frozenset({
        "你好", "hello", "hi", "早上好", "晚上好", "您好", "嗨",
    })

    # 实体模式（简单正则提取）
    ENTITY_PATTERNS = [
        ("phone", r"1[3-9]\d{9}"),
        ("email", r"[\w.-]+@[\w.-]+\.\w+"),
        ("url", r"https?://\S+"),
        ("date", r"\d{4}[-/年]\d{1,2}[-/月]\d{1,2}[日号]?"),
        ("money", r"\d+\.?\d*[万亿]?[元块钱]"),
        ("percent", r"\d+\.?\d*%"),
        ("number", r"\d+\.?\d*"),
    ]

    def __init__(self):
        super().__init__(
            skill_type=SkillType.TEXT_PARSE,
            name="text_parser",
            description="文本解析：情感/关键词/意图/实体/摘要",
        )

    def process(self, skill_input: SkillInput) -> SkillOutput:
        """处理文本分析"""
        text = skill_input.text
        if not text or not text.strip():
            return SkillOutput(success=False, error="空文本", confidence=0.0)

        result = TextAnalysisResult()
        result.char_count = len(text)

        # 1. 语言检测
        result.language_hint = self._detect_language(text)

        # 2. 文本类型
        result.text_type = self._classify_text_type(text)
        result.has_question = result.text_type == TextType.Q


文件 skills/task_classifier.py: 任务分类技能
将用户输入分类为不同的任务类型和优先级 | 定义: class

from, class TaskCategory, class TaskPriority, class
class, def __post_init__, def to_dict, class TaskClassifierSkill, def __init__, def process, def _classify_category

#!/usr/bin/env python3
"""
任务分类技能
将用户输入分类为不同的任务类型和优先级
"""

import re
from enum import Enum
from typing import Dict, List, Optional
from dataclasses import dataclass

from skills.base_skill import BaseSkill, SkillType, SkillInput, SkillOutput

class TaskCategory(Enum):
    """任务类别"""
    CHAT = "chat"                 # 闲聊
    QUERY = "query"               # 信息查询
    CODE = "code"                 # 编程开发
    WRITE = "write"               # 写作创作
    ANALYZE = "analyze"           # 分析研究
    PLAN = "


TaskCategory

类 TaskCategory 在 skills/task_classifier.py: 任务类别 | 方法:

class TaskCategory:
    """任务类别"""
    CHAT = "chat"                 # 闲聊
    QUERY = "query"               # 信息查询
    CODE = "code"                 # 编程开发
    WRITE = "write"               # 写作创作
    ANALYZE = "analyze"           # 分析研究
    PLAN = "plan"                 # 规划设计
    TRANSLATE = "translate"       # 翻译
    COMPUTE = "compute"           # 计算
    SAFETY = "safety"             # 安全相关
    UNKNOWN = "unknown"


TaskPriority

类 TaskPriority 在 skills/task_classifier.py: 任务优先级 | 方法:

class TaskPriority:
    """任务优先级"""
    LOW = 1       # 闲聊、简单查询
    MEDIUM = 2    # 信息查询、翻译
    HIGH = 3      # 编程、分析、写作
    CRITICAL = 4  # 安全、紧急

@dataclass