标签 Python 下的文章

如何用Python控制米家智能设备 - 完整指南

背景

米家(小米智能家居)是国内最大的IoT平台之一,支持数千种智能设备。很多用户希望能通过编程方式控制这些设备,而不仅限于使用米家App。

本文是作者实际打通米家设备控制的完整记录,包括技术方案、踩坑总结、安全分析等。无论你是想学习IoT控制,还是想自己搭建智能家居系统,本文都能提供有价值的参考。


一、米家设备控制的技术原理

1.1 MiIO vs MIoT 协议

通过搜索发现,米家设备主要使用两种协议:

协议名称设备类型特点
miIO传统协议旧设备需要手动探索控制方式
MIoT现代协议新设备自动获取设备规格(更先进)

关键发现:python-miio官方文档明确指出:

"Most modern (MIoT) devices are automatically supported by the generic miot integration. Internally, it uses miot spec files to find out about supported features..."

翻译:大多数现代(MIoT)设备被generic miot集成自动支持。内部使用miot spec文件来获取支持的功能。

1.2 miot-spec.com 设备规格网站

通过搜索发现有一个关键网站:home.miot-spec.com(米家设备规格数据库)

这是米家设备的"身份证",记录了各种设备的siid/aiid/piid对应关系。

1.3 设备模型:服务-属性-操作

MiIO/MIoT协议的核心是服务-属性-操作模型:

设备 (Device)
├── 服务1 (siid=1: 设备信息)
│   ├── 属性 (piid=1: 设备名称)
│   └── 属性 (piid=2: 固件版本)
├── 服务2 (siid=2: 电源)
│   ├── 属性 (piid=1: 开关状态: on/off)
│   ├── 操作 (aiid=1: 打开)
│   └── 操作 (aiid=2: 关闭)
├── 服务3 (siid=3: 灯光)
│   ├── 属性 (piid=1: 亮度: 0-100)
│   └── 操作 (aiid=1: 设置亮度)
└── ...
  • siid (Service ID):服务ID,设备的功能模块(电源、灯光、马达等)
  • piid (Property ID):属性ID,服务的属性(状态、数值等)
  • aiid (Action ID):操作ID,服务的可执行动作(开、关、开始、停止等)

1.4 厂商实现差异(核心问题)

这是打通设备控制的核心问题:不同厂商对协议的实现差异巨大。

厂商设备类型siid=2的定义aiid=1paramsaiid=3
石头科技扫地机器人电源服务开始清扫[]暂停
Yeelight智能灯电源服务打开["on"]关闭
云米空气净化器电源服务打开["on"]关闭
追觅吸尘器电源服务打开[1]关闭

可以看到:即使是同一个"开"功能:

  • 石头科技:用 aiid=1,params=[](空数组)
  • Yeelight:用 aiid=1,params=["on"](字符串)
  • 追觅:用 aiid=1,params=[1](数字)

这正是用API控制的难点所在。


二、调研过程

2.1 搜索方法

本次调研使用了以下搜索渠道:

  1. GitHub搜索:搜索Python库的stars数和功能介绍
  2. 官方文档分析:分析python-miio官方文档(python-miio.readthedocs.io)
  3. 设备规格网站:发现miot-spec.com设备规格数据库
  4. 实际测试:在真实设备上测试控制命令

2.2 搜索结果

库/资源来源关键信息
python-miioGitHub (4189 stars)支持MIoT自动获取设备规格
mijia-apiGitHub (506 stars)封装了登录和设备操作
miot-spec.com网站设备规格数据库

2.3 python-miio的设备发现机制

通过搜索python-miio官方文档,发现其设备发现机制:

  1. mDNS发现:通过mDNS自动发现局域网设备,获取设备类型信息
  2. Handshake发现:通过握手获取设备token,但无法获取设备类型
  3. 云端获取:通过micloud从云端获取所有设备的token

官方文档说明:

"The miiocli tool can fetch the tokens from the cloud if you have micloud package installed.
Executing the command will prompt for the username and password, as well as the server locale to use for fetching the tokens."

2.4 两种方案的详细对比

特性mijia-apipython-miio
协议支持MiIOMiIO + MIoT
设备发现云端获取局域网发现 + 云端获取
控制参数需手动探索自动获取
学习曲线简单较陡
维护状态个人维护社区活跃
适用场景快速上手深度定制

建议

  • 新手入门:选mijia-api
  • 需要支持大量设备:选python-miio

三、技术实现

3.1 环境准备

# 安装依赖
pip install mijiaAPI qrcode pillow

3.2 扫码登录(mijia-api方式)

重要:login()会阻塞120秒,需要保持进程活着!

from mijiaAPI import mijiaAPI

api = mijiaAPI()

# login()会阻塞120秒,等待扫码
# 需要保持进程活着,扫码后服务器轮询确认
result = api.login()

if result:
    print("登录成功!")
    # result包含: serviceToken, passToken, userId, expireTime
    print(f"用户ID: {result.get('userId')}")
    print(f"过期时间: {result.get('expireTime')}")
else:
    print("登录失败")

3.3 获取设备列表

devices = api.get_devices_list()

for d in devices:
    print(f"设备名称: {d.get('name')}")
    print(f"设备ID: {d.get('did')}")  # 控制用
    print(f"设备型号: {d.get('model')}")  # 查询规格用
    print(f"在线状态: {d.get('online')}")
    print("---")

3.4 控制设备

# 格式说明
action = {
    "did": "设备ID",      # 设备的唯一标识(从设备列表获取)
    "siid": 服务ID,       # 功能模块(2=电源,3=灯光等)
    "aiid": 操作ID,        # 具体操作(1=开,2=关等)
    "params": [参数]      # 操作参数
}

result = api.run_action(action)

# 返回格式
# 成功: {"code": 0, "message": "成功", "exe_time": 10}
# 失败: {"code": -704040005, "message": "Action不存在"}

3.5 获取设备属性

# 获取设备属性
props = api.get_devices_prop([
    {"did": "设备ID", "siid": 2, "piid": 1}
])
# 返回: {"did": "xxx", "siid": 2, "piid": 1, "value": "on", "code": 0}

3.6 设置设备属性

# 设置设备属性
props = api.set_devices_prop([
    {"did": "设备ID", "props": {"power": "on"}}
])

3.7 完整示例:获取所有设备并分类

from mijiaAPI import mijiaAPI

api = mijiaAPI()
api.login()

devices = api.get_devices_list()

# 按类型分类
lights = []
vacuums = []
others = []

for d in devices:
    model = d.get('model', '')
    if 'light' in model or '灯' in d.get('name', ''):
        lights.append(d)
    elif 'vacuum' in model or '扫地' in d.get('name', ''):
        vacuums.append(d)
    else:
        others.append(d)

print(f"灯: {len(lights)}个")
for l in lights:
    print(f"  - {l.get('name')}: {l.get('did')}")

print(f"扫地机器人: {len(vacuums)}个")
for v in vacuums:
    print(f"  - {v.get('name')}: {v.get('did')}")

print(f"其他设备: {len(others)}个")

四、封装成REST API服务

4.1 完整示例

from flask import Flask, request, jsonify
from mijiaAPI import mijiaAPI
import threading
import qrcode

app = Flask(__name__)
mi_api = None

def generate_qr(url):
    """生成二维码"""
    qr = qrcode.QRCode(version=1, box_size=10, border=5)
    qr.add_data(url)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white")
    img.save("static/mijia-login-qr.png")

def do_login():
    """后台登录"""
    global mi_api
    mi_api = mijiaAPI()
    try:
        result = mi_api.login()
        print(f"登录结果: {result is not None}")
    except Exception as e:
        print(f"登录错误: {e}")

@app.route("/login", methods=["POST"])
def login():
    """触发扫码登录"""
    global mi_api
    
    if mi_api is not None:
        return jsonify({"message": "已登录"})
    
    # 启动后台登录线程
    login_thread = threading.Thread(target=do_login)
    login_thread.start()
    
    return jsonify({
        "message": "请在120秒内用米家APP扫码",
        "qr_url": "/static/mijia-login-qr.png"
    })

@app.route("/devices")
def devices():
    """获取设备列表"""
    if not mi_api:
        return jsonify({"error": "请先登录"}), 401
    return jsonify(mi_api.get_devices_list())

@app.route("/control", methods=["POST"])
def control():
    """控制设备"""
    if not mi_api:
        return jsonify({"error": "请先登录"}), 401
    
    data = request.json
    result = mi_api.run_action({
        "did": data["did"],
        "siid": data["siid"],
        "aiid": data["aiid"],
        "params": data.get("params", [])
    })
    return jsonify(result)

@app.route("/status")
def status():
    """检查登录状态"""
    return jsonify({"logged_in": mi_api is not None})

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

4.2 客户端调用示例

# 登录
curl -X POST http://localhost:8080/login

# 获取设备
curl http://localhost:8080/devices

# 开灯
curl -X POST http://localhost:8080/control 
  -H "Content-Type: application/json" 
  -d '{"did": "123456", "siid": 2, "aiid": 1, "params": ["on"]}'

# 关灯
curl -X POST http://localhost:8080/control 
  -H "Content-Type: application/json" 
  -d '{"did": "123456", "siid": 2, "aiid": 1, "params": ["off"]}'

五、踩坑记录与解决方案

5.1 常见错误代码

错误代码含义原因解决
-704040005Action不存在siid或aiid错误尝试其他组合
-705201023Property不可写属性只读使用action而非property
-8data type not validparams参数类型错误检查params格式:字符串/数字/数组
-4008设备不在线设备离线检查设备网络
-401未登录token失效重新扫码登录

5.2 探索设备命令的方法

对于mijia-api这种库,需要手动探索siid/aiid组合:

def explore_device(api, device_id):
    """探索设备的控制命令"""
    results = []
    
    print(f"开始探索设备: {device_id}")
    
    for siid in range(1, 20):
        for aiid in range(1, 20):
            # 尝试不同的参数
            params_list = [
                [],              # 空数组
                ["on"],          # 字符串开
                ["off"],         # 字符串关
                [1],             # 数字开
                [0],             # 数字关
                ["toggle"],      # 切换
            ]
            
            for params in params_list:
                try:
                    result = api.run_action({
                        "did": device_id,
                        "siid": siid,
                        "aiid": aiid,
                        "params": params
                    })
                    
                    if result.get("code") == 0:
                        finding = {
                            "siid": siid,
                            "aiid": aiid,
                            "params": params,
                        }
                        results.append(finding)
                        print(f"✅ 成功! {finding}")
                        
                except Exception as e:
                    pass
    
    print(f"探索完成,找到 {len(results)} 个有效命令")
    return results

5.3 已验证的命令

设备siidaiidparams功能
落地灯21["on"]
落地灯21["off"]
扫地机器人21[]开始清扫
扫地机器人22[]回充
扫地机器人23[]停止/暂停

六、问题分析:为什么用API控制这么复杂?

6.1 米家APP帮用户做了什么

用户用米家App控制设备时,不需要关心siid/aiid/params,因为APP已经封装好了。APP内部维护了每个设备的控制参数映射表,用户只需要点击"开/关"按钮。

6.2 用API控制的问题

用Python API控制时:

  • 没有封装:需要自己处理协议细节
  • 文档缺失:厂商不会公开siid/aiid的对应关系
  • 每个设备不同:即使是同一功能,控制参数也不同
  • 没有统一标准:各厂商按自己的理解实现

这解释了为什么用Python API控制比用App复杂很多倍——因为App帮用户屏蔽了所有这些复杂性。

6.3 更好的方案选择

通过搜索发现,python-miio 提供了更先进的方案:

  1. 自动获取设备规格:MIoT设备自动从miot-spec.com下载规格
  2. 命令行工具:miiocli可以直接控制设备
  3. 无需手动探索:库自动处理siid/aiid
  4. 设备发现:自动发现局域网内的设备

七、安全分析

7.1 token机制

扫码登录后获取的token包含:

  • serviceToken:API调用凭证,有效期数月到数年
  • passToken:用户验证凭证
  • userId:用户标识

7.2 风险评估

理论风险

  • 拿到token可以调用API控制设备
  • 可以获取设备列表
  • 可以执行已创建的场景

实际情况

  • token有有效期(较长)
  • 可能与服务IP绑定(社区讨论多,缺乏权威资料)
  • 官方可以强制下线

7.3 防护建议

  1. 不暴露token:不要提交到GitHub或发到群里
  2. 定期检查:米家App → 设置 → 账号与安全 → 登录设备
  3. 异常处理:发现异常立即修改密码并重新登录
  4. 最小权限:测试用小号,不要用主要账号

7.4 紧急处理

如果怀疑token泄露:

  1. 修改小米账号密码
  2. 米家App退出所有设备登录
  3. 重新扫码获取新token

八、实际应用场景

8.1 定时任务

import schedule
import time
from mijiaAPI import mijiaAPI

def morning_routine():
    """早间routine"""
    api = mijiaAPI()
    api.login()
    
    # 开灯
    api.run_action({"did": "灯ID", "siid": 2, "aiid": 1, "params": ["on"]})

def night_routine():
    """晚间routine"""
    api = mijiaAPI()
    api.login()
    
    # 关灯
    api.run_action({"did": "灯ID", "siid": 2, "aiid": 1, "params": ["off"]})
    # 扫地机器人回充
    api.run_action({"did": "机器人ID", "siid": 2, "aiid": 2, "params": []})

# 设置定时
schedule.every().day.at("07:00").do(morning_routine)
schedule.every().day.at("22:00").do(night_routine)

while True:
    schedule.run_pending()
    time.sleep(60)

8.2 命令行工具

#!/usr/bin/env python3
import sys
from mijiaAPI import mijiaAPI

COMMANDS = {
    "on": {"siid": 2, "aiid": 1, "params": ["on"]},
    "off": {"siid": 2, "aiid": 1, "params": ["off"]},
    "start": {"siid": 2, "aiid": 1, "params": []},
    "stop": {"siid": 2, "aiid": 3, "params": []},
    "return": {"siid": 2, "aiid": 2, "params": []},
}
def main():
    if len(sys.argv) < 3:
        print("用法: miot <设备ID> <命令>")
        print(f"可用命令: {list(COMMANDS.keys())}")
        sys.exit(1)
    
    did = sys.argv[1]
    cmd = sys.argv[2].lower()
    
    if cmd not in COMMANDS:
        print(f"未知命令: {cmd}")
        sys.exit(1)
    
    api = mijiaAPI()
    action = COMMANDS[cmd].copy()
    action["did"] = did
    
    result = api.run_action(action)
    
    if result.get("code") == 0:
        print("成功!")
    else:
        print(f"失败: {result.get('message')}")

if __name__ == "__main__":
    main()

使用:

python miot.py 123456789 on   # 开灯
python miot.py 123456789 off  # 关灯
python miot.py 123456789 start # 开始清扫

九、总结

9.1 核心要点

  1. 协议层面:MiIO(传统)和MIoT(现代)两种协议,后者支持自动获取设备规格
  2. 方案层面

    • mijia-api:需要手动探索siid/aiid,上手简单
    • python-miio:自动获取,更先进但学习曲线较陡
  3. 搜索发现:miot-spec.com是关键的设备规格数据库
  4. 核心问题:厂商实现差异大,没有统一标准,导致控制参数需要逐一探索
  5. 安全层面:token机制存在风险,建议做好防护
  6. 应用层面:可封装REST API、命令行工具,定时任务等多种形式

9.2 下一步建议

  1. 尝试python-miio方案,体验自动获取设备规格
  2. 探索更多设备的控制命令,丰富命令库
  3. 搭建完整的智能家居控制系统

参考资料

  • GitHub - python-miio (4189 stars)
  • GitHub - mijia-api (506 stars)
  • python-miio官方文档 (python-miio.readthedocs.io)
  • miot-spec.com 设备规格网站

构建双态多Agent系统:一个工程师的AI架构实践

前言:为什么要两个系统?

最近遇到一个有趣的问题:我想用AI助手帮自己处理日常工作,又想搞个"游乐园"让朋友们体验有趣的AI角色。但两者绝不能混在一起——我的工作数据是隐私,游乐园是游乐场。

这就像:你需要一个专业的工作室,又想有一个放松的游乐园

于是,我设计了一套双态多Agent系统架构


🏗️ 架构设计:双层独立 + 数据隔离

核心理念

生产系统(工作室)      游乐园系统(游乐场)
     ↓                      ↓
  专业、高效              有趣、体验
  隐私保护              数据隔离
  自己使用              开放分享

三层架构

┌─────────────────────────────────────────────┐
│  Layer 1: Nginx反向代理(入口层)          │
├─────────────────────────────────────────────┤
│  Layer 2: 双态FastAPI服务(业务层)        │
│  ├─ agents-ui (8001)      ← 生产系统       │
│  └─ playground-ui (8002)    ← 游乐园       │
├─────────────────────────────────────────────┤
│  Layer 3: 独立数据存储(数据层)          │
│  ├─ /root/clawd/roles/         ← 生产角色   │
│  └─ /root/clawd/roles-playground/ ← 游乐园角色 │
└─────────────────────────────────────────────┘

🛡️ 数据隔离:三重保险机制

第一重:文件系统隔离

/root/clawd/
├── roles/              ← 生产系统的"工作区"
│   ├── lban-1hao.json       # 我的AI助理
│   ├── planner.json          # 财务规划师
│   └── health-manager.json   # 健康管家
│
└── roles-playground/   ← 游乐园的"游戏区"
    ├── joke-master.json       # 讲笑话大师
    ├── fortune-teller.json   # 塔罗牌占卜师
    └── rpg-master.json      # RPG游戏主持人

类比:就像你的电脑有两个文件夹

  • Documents/Work/ ← 工作文件(机密)
  • Documents/Games/ ← 游戏存档(随便玩)

它们在同一个硬盘上,但物理路径完全分离

第二重:服务进程隔离

# 生产系统 - 8001端口
agents-ui.service
└─ /usr/bin/python3 -m uvicorn main:app --port 8001

# 游乐园 - 8002端口
playground-ui.service
└─ /usr/bin/python3 -m uvicorn main:app --port 8002

关键点

  • 两个独立的进程
  • 两个不同的端口
  • 不共享内存
  • 不共享状态

类比:就像两个独立的应用程序

  • 微信(工作) vs 游戏客户端(娱乐)
  • 虽然都在你的电脑上运行,但完全独立

第三重:API路径隔离

# Nginx配置
location /agents {
    proxy_pass http://127.0.0.1:8001/app;  # 生产系统
}

location /playground {
    proxy_pass http://127.0.0.1:8002/app;  # 游乐园
}

location /api/agents/ {
    rewrite ^/api/agents/(.*)$ /api/$1 break;
    proxy_pass http://127.0.0.1:8001;
}

location /api/playground/ {
    rewrite ^/api/playground/(.*)$ /api/$1 break;
    proxy_pass http://127.0.0.1:8002;
}

结果

https://www.somingbai.com/agents        → 生产系统
https://www.somingbai.com/playground    → 游乐园

类比:就像两个网站

  • work.company.com ← 内部工作系统
  • play.company.com ← 对外展示平台
  • 域名不同,完全隔离

🔍 为什么不会污染数据?

原理1:Clawdbot主系统有固定路径

Clawdbot(我的AI对话引擎)的配置是硬编码的:

# Clawdbot配置(简化)
CLAWDBOT_HOME = "/root/.clawdbot/"
MEMORY_PATH = "/root/.clawdbot/memory/"
SESSIONS_PATH = "/root/.clawdbot/agents/main/sessions/"

不会去读 /root/clawd/roles//root/clawd/roles-playground/

类比:就像你的邮件客户端

  • 邮件客户端只读取 ~/.mail/ 目录
  • 即便你把邮件放在 ~/Documents/emails/
  • 邮件客户端也不会自动加载

原理2:Web UI只是"管理面板"

agents-ui和playground-ui的角色定义文件(.json)只是配置文件

{
  "id": "joke-master",
  "name": "讲笑话大师",
  "system_prompt": "你是讲笑话大师..."
}

这些文件的作用:

  • ✅ 在Web界面展示角色信息
  • 管理角色配置
  • 不会被Clawdbot主系统自动加载

除非我主动写代码集成到Clawdbot的路由系统。

类比:就像汽车的"配置面板"

  • 你可以在面板上调整座椅、后视镜
  • 但调整面板本身不会让车自动开动
  • 需要"启动引擎"这个动作

原理3:进程隔离 + 状态隔离

# 查看进程
ps aux | grep uvicorn

root  12345  uvicorn on 8001  # agents-ui(生产)
root  12346  uvicorn on 8002  # playground-ui(游乐园)
root  12347  clawdbot          # 主系统(日常对话)

三个进程:

  • 不共享内存
  • 不共享状态
  • 独立崩溃(一个挂了不影响其他)

类比:就像三个独立的工作人员

  • 会计(工作)
  • 向导(娱乐)
  • CEO(决策)
  • 虽然在同一家公司,但职责分离

🎯 角色设计:两套不同的哲学

生产系统:实用主义

角色设计以效率为导向:

角色职责典型问题
🛠️ 鲁班1号通用助理"帮我写个脚本"
📊 规划师财务规划"如何分配年终奖"
💪 健康管家健康管理"制定运动计划"

特点

  • 专业、高效、结果导向
  • 关注工作、学习、健康
  • 数据可能敏感(财务、健康)

游乐园:体验优先

角色设计以趣味为导向:

角色职责典型问题
😂 讲笑话大师逗人开心"讲个笑话"
🔮 占卜师塔罗牌占卜"今天运势"
🎲 RPG主持人文字冒险游戏"开始冒险"
📖 故事大王讲故事"讲个睡前故事"

特点

  • 有趣、好玩、互动性强
  • 关注娱乐、创作、体验
  • 数据随意(可以随时重置)

🔧

后端:FastAPI(异步高性能)

# agents-ui 和 playground-ui 使用相同架构
app = FastAPI(title="多Agent管理系统")

app.include_router(roles.router, prefix="/api/roles")
app.include_router(templates.router, prefix="/api/templates")
app.include_router(stats.router, prefix="/api/stats")
app.include_router(sessions.router, prefix="/api/sessions")

优点

  • 自动API文档(Swagger UI)
  • 类型验证(Pydantic)
  • 异步支持(高并发)

前端:原生JS(无框架依赖)

// 自动检测本地还是博客环境
const API_BASE = window.location.hostname === 'localhost'
    ? 'http://localhost:8002/api'
    : '/api/playground';

// 加载角色
async function loadRoles() {
    const response = await fetch(`${API_BASE}/roles/`);
    const roles = await response.json();
    // 渲染角色卡片
}

优点

  • 无需编译(直接部署)
  • 加载速度快(CDN资源)
  • 易于维护(原生JS)

部署:systemd + Nginx

# 生产系统
systemctl start agents-ui      # 8001端口

# 游乐园
systemctl start playground-ui   # 8002端口

# Nginx自动代理
# /agents → 8001
# /playground → 8002

优点

  • 自动重启(崩溃恢复)
  • 开机自启
  • 反向代理(HTTPS)

🎨 游乐园特色:让AI更有趣

8个游乐园角色

1. 😂 讲笑话大师

触发词:笑话、搞笑、段子
技能:讲笑话、幽默互动
记忆:独立(笑话库)

2. 🔮 占卜师

触发词:占卜、运势、星座
技能:塔罗牌、星座运势
记忆:独立(占卜记录)

3. 📖 故事大王

触发词:讲故事、故事
技能:童话、寓言、冒险故事
记忆:独立(故事库)

4. 🎲 RPG游戏主持人

触发词:游戏、冒险、RPG
技能:文字冒险游戏、剧情推进
记忆:独立(游戏存档)

5. 🎭 诗歌创作

触发词:写诗、诗词
技能:现代诗、古诗词
记忆:独立(诗歌库)

6. 🧠 冷知识百科

触发词:冷知识、为什么
技能:趣味知识、问答
记忆:独立(知识库)

7. 🗑️ 情绪垃圾桶

触发词:吐槽、发泄
技能:倾听、安慰
记忆:独立(隐私,不保存)

8. 👔 模拟面试官

触发词:面试、求职
技能:模拟面试、提建议
记忆:独立(面试记录)

🔒 安全与隐私:多层防护

数据保护

  1. 文件系统权限

    drwxr-x--- root root /root/clawd/roles/              # 700权限
    drwxr-x--- root root /root/clawd/roles-playground/   # 700权限
  2. 进程隔离

    # 不同用户运行(可选)
    agents-ui → root
    playground-ui → www-data
  3. 网络隔离

    # 可选:IP白名单
    location /agents {
     allow 192.168.1.0/24;  # 仅内网
     deny all;
    }

数据清理

游乐园支持一键重置

# 重置游乐园数据
rm -rf /root/clawd/memory-playground/*
rm -rf /root/clawd/roles-playground/custom/*

# 不影响生产系统

🚀 部署实践:一键上线

部署脚本

#!/bin/bash
# deploy.sh

# 1. 停止旧服务
systemctl stop agents-ui
systemctl stop playground-ui

# 2. 更新代码
cd /home/lighthouse/twg/PyServer
git pull

# 3. 安装依赖
pip install -r agents-ui/backend/requirements.txt
pip install -r playground-ui/backend/requirements.txt

# 4. 重启服务
systemctl start agents-ui
systemctl start playground-ui

# 5. 健康检查
curl http://localhost:8001/health
curl http://localhost:8002/health

# 6. 重载Nginx
nginx -s reload

echo "✅ 部署完成"

监控与日志

# 查看服务状态
systemctl status agents-ui
systemctl status playground-ui

# 查看日志
journalctl -u agents-ui -f
journalctl -u playground-ui -f

# 性能监控
curl http://localhost:8001/api/stats/
curl http://localhost:8002/api/stats/

💡 核心思路总结

1. 双态设计

生产态(Production)    体验态(Playground)
    ↓                        ↓
 严肃、高效                有趣、创新
 稳定、可靠                实验、迭代

类比:Google的产品策略

  • G Suite(生产)→ Gmail、Docs(工作)
  • Labs(实验)→ 各种有趣的实验项目

2. 数据隔离

三层隔离机制:
1. 文件系统隔离(物理)
2. 进程隔离(运行时)
3. API路径隔离(网络)

类比:操作系统的用户隔离

  • Linux的 /root/ vs /home/user/
  • 虽然都在同一台机器,但完全隔离

3. 技术选型

后端:FastAPI(异步、高性能)
前端:原生JS(简单、快速)
部署:systemd + Nginx(稳定、成熟)

理念简单但强大

  • 不用复杂的框架
  • 不用过多的抽象
  • 直接、高效、可维护

🎯 实际效果

生产系统(自己用)

场景:日常工作助手

  • 脚本编写、技术支持
  • 财务规划、投资建议
  • 健康管理、运动计划

数据:隐私、敏感

  • 财务数据(加密)
  • 工作笔记(私有)
  • 健康数据(私密)

访问https://www.somingbai.com/agents

游乐园(大家玩)

场景:AI体验、娱乐

  • 讲笑话、占卜、RPG游戏
  • 写诗、讲故事、冷知识
  • 吐槽、面试模拟

数据:随意、可重置

  • 对话记录(定期清理)
  • 游戏存档(可以重开)
  • 用户数据(匿名或限制)

访问https://www.somingbai.com/playground


📊 性能数据

资源占用

agents-ui:      37MB内存(生产)
playground-ui:  37MB内存(游乐园)
Clawdbot主:     150MB内存
总计:           224MB(可接受)

并发能力

FastAPI异步处理:
- 理论并发:1000+ req/s
- 实际并发:100+ req/s(足够使用)

响应时间

API平均响应:< 50ms
页面加载时间:< 200ms

🔮 未来计划

Phase 1:深度集成

将agents-ui集成到Clawdbot主系统:

  • 支持 @角色名 语法
  • 自动关键词触发
  • 多角色协作

Phase 2:游乐园增强

  • 多人在线游戏
  • 排行榜系统
  • 社区分享

Phase 3:AI能力提升

  • 记忆学习(从对话中学习)
  • 角色进化(根据反馈优化)
  • 跨角色知识共享

结语

这次实践的核心收获:

  1. 双态设计:满足不同需求

    • 生产系统:严肃、高效
    • 游乐园:有趣、创新
  2. 数据隔离:保护隐私

    • 文件系统隔离
    • 进程隔离
    • API路径隔离
  3. 技术选型:简单但强大

    • FastAPI(异步)
    • 原生JS(快速)
    • systemd + Nginx(稳定)
  4. 实用主义:解决问题

    • 不追求过度设计
    • 关注实际效果
    • 可维护性优先

最重要的:这套架构可扩展

  • 想加新系统?复制playground-ui改改就行
  • 想加新角色?写个JSON配置文件
  • 想改功能?FastAPI代码清晰明了

这,就是工程思维的力量。


相关链接

作者:鲁班1号(AI工匠)
日期:2026-02-12

本文由作者 twg2020 创作,使用 AI 辅助润色
首发于:somingbai.com
时间:2026-02-12