Skip to content

Repository files navigation

Hance

跨设备智能体系统,类似钢铁侠的贾维斯 — 一个大脑,多个躯体。

核心理念

  • 一个大脑:所有设备共享统一的记忆和推理能力,大脑运行在云端服务器
  • 多个躯体:智能体可在手机、电脑、嵌入式设备等同时运行,每个设备是一个交互入口
  • 无处不在:用户可以在任意设备上用自然语言与大脑对话,大脑可以感知用户状态并调用任意设备的能力

架构概览

                    ┌──────────────────────────────┐
                    │        云端大脑 (Brain)        │
                    │                              │
                    │  对话引擎     LLM推理层        │
                    │  工具路由     记忆系统          │
                    │  会话管理     Context组装      │
                    └──────────────┬───────────────┘
                                   │ WebSocket (WSS)
         ┌──────────────┬─────────────────┼─────────────────┬──────────────┐
         │              │                 │                 │              │
┌────────▼─────┐ ┌──────▼──────┐ ┌────────▼────────┐ ┌──────▼─────────┐ ┌──▼───────────┐
│ 桌面端躯体    │ │ 微信网关躯体 │ │ Android 躯体    │ │ 嵌入式躯体      │ │ 外部服务      │
│ (body-pc)    │ │(body-wechat)│ │ (body-android)  │ │ (body-embedded)│ │ HA / Photos  │
│ Electron     │ │ Node.js     │ │ Kotlin 原生     │ │ Python          │ │ (第二版)      │
│ +React+Vite  │ │ iLink Bot   │ │ (第二版)        │ │ (第二版)        │ │              │
└──────────────┘ └─────────────┘ └─────────────────┘ └────────────────┘ └──────────────┘

每个设备同时承担两个角色:

  • Chat Client:用户交互入口,WebSocket 与大脑对话
  • Tool Provider:暴露本地能力(截图、文件、shell 等),通过同一 WebSocket 通道被大脑调用

核心机制:Artifact

所有跨设备传递的文件和图片(无论来自用户上传还是工具返回)均通过 Artifact 机制统一管理,不直接在 LLM 上下文中传递原始字节。

用户上传图片
     │
     ▼
brain 拦截,并发写入 ArtifactStore(PostgreSQL 元数据 + 文件系统字节)
同时并行执行 build_system_prompt(embedding 检索)
     │
     ▼
生成 artifact_id(格式:art_xxxxxxxxxxxxxxxx)
     │
     ▼
LLM 上下文中只出现 JSON 引用:
  {"artifact_id": "art_xxxx", "kind": "image/jpeg", "name": "user_image.jpg",
   "size": 3129964, "note": "...", "source": "user_upload"}
     │
     ├─► 用户要分析图片 → LLM 调用 load_artifact(artifact_id=...)
     │        └─► brain 读取字节,在线程池压缩(最大 1024px / JPEG q75),注入 LLM 上下文
     │
     └─► 用户要保存到设备 → LLM 调用 save_file(file_path=..., artifact_id=...)
              └─► brain 从 store 读取字节并展开,通过 WebSocket 发给目标设备执行

为什么这样设计:

  • 避免大文件/高分辨率图片直接塞满 LLM 上下文窗口
  • 大脑统一持久化所有文件,支持跨设备引用(手机拍的照片可以直接保存到 PC 桌面)
  • LLM 只在真正需要时才加载文件内容,其余情况只需传递轻量 ID

关键文件:

  • brain/artifacts/store.py — ArtifactStore,持久化存储
  • brain/chat/engine.py_store_user_images(),用户上传图片的拦截入口
  • brain/main.py_load_artifact_handler(),加载时自动压缩图片
  • brain/mcp_client/router.py_expand_artifact_refs(),工具调用时自动展开字节

核心机制:Skills

Skills 是可插拔的行为指令模块(Markdown 文件),在对话时动态注入 system prompt,让 LLM 在特定场景下具备更精准的上下文和行为约束。

三层来源:

  • Brain 内置brain/skills/builtin/*.md,随代码部署
  • 用户自定义:存数据库,运行时动态增删
  • 设备注册:body 连接时通过 register 消息携带,设备下线自动失效

触发方式:

  • 关键词自动匹配(当轮):消息命中 skill 的 triggers 词时自动注入 system prompt
  • /skill <name>(会话级):用户显式激活,存 Redis,新建会话自动清除
  • LLM 主动加载:LLM 可调用 list_skills / load_skill 工具查看和加载 skill

Skill 文件格式(YAML front matter + Markdown body):

---
name: travel-planner
description: 旅行规划助手:当用户询问旅行路线、景点推荐时使用
triggers:
  - 旅行
  - 出行
  - 景点
---

# 旅行规划模式
你现在是用户的专属旅行规划师...

关键文件:

  • brain/skills/loader.pySkill dataclass + 解析 .md 文件
  • brain/skills/manager.pySkillManager,匹配/激活/设备 skill 管理
  • brain/skills/store.py — 数据库 CRUD(用户自定义 skill)
  • brain/skills/builtin/ — 内置 skill 文件目录
  • body-pc/electron/skills/ — 桌面端设备 skill,注册时携带

技术栈

层级 技术 说明
服务端 Python 3.12+, FastAPI 异步高性能,WebSocket 原生支持
LLM litellm 统一 OpenAI/Anthropic 等多种模型格式
数据库 PostgreSQL + pgvector 结构化数据 + 知识记忆向量检索
缓存 Redis 对话记忆(会话级)、活跃会话管理
向量数据库 Qdrant RAG 文档检索(第二版)
ORM SQLAlchemy (async) + Alembic 数据库迁移
桌面端 Electron + React + Vite 原生桌面应用,多模态交互(文本+图片)
Android Kotlin + Ktor + OkHttp 原生实现(第二版)
部署 Docker Compose 一键启动大脑及依赖服务

项目结构

hance/
├── brain/                      # 云端大脑(服务器运行)
│   ├── main.py                 # FastAPI 入口,生命周期管理
│   ├── config.py               # 配置(环境变量)
│   ├── models.py               # SQLAlchemy ORM 模型
│   ├── db.py                   # 数据库连接
│   ├── chat/
│   │   ├── engine.py           # 对话引擎(LLM + 工具 + 记忆编排)
│   │   ├── context.py          # Context 组装(设备状态/记忆/工具/skill 注入)
│   │   └── session.py          # 会话管理(创建/归档/切换)
│   ├── llm/
│   │   ├── provider.py         # litellm 封装,可切换模型
│   │   └── prompts.py          # System prompt 模板
│   ├── artifacts/
│   │   └── store.py            # ArtifactStore:元数据→PostgreSQL,字节→文件系统
│   ├── mcp_client/
│   │   └── router.py           # 工具路由,通过 WebSocket 转发调用
│   ├── memory/
│   │   ├── conversation.py     # 对话记忆(Redis 滑动窗口)
│   │   ├── knowledge.py        # 知识记忆(pgvector 语义检索)
│   │   └── manager.py          # 会话归档时累积摘要 + 知识抽取
│   ├── skills/
│   │   ├── loader.py           # Skill dataclass + 解析 .md 文件
│   │   ├── store.py            # 数据库 CRUD(用户自定义 skill)
│   │   ├── manager.py          # SkillManager:匹配/激活/设备 skill 管理
│   │   └── builtin/            # 内置 skill 文件(.md)
│   └── ws/
│       ├── protocol.py         # WebSocket 消息协议(Pydantic)
│       ├── device_registry.py  # 设备注册表(在线状态/工具列表)
│       └── server.py           # WebSocket 服务端,消息分发
├── body-pc/                    # 桌面端躯体(Linux/Mac/Windows,Electron)
│   ├── electron/               # Electron 主进程
│   │   ├── main.js             # 入口,窗口管理、系统托盘
│   │   ├── preload.js          # 渲染进程安全桥接
│   │   ├── ws-client.js        # WebSocket 客户端(对话+工具调用)
│   │   ├── tool-executor.js    # 工具执行器(本地调用)
│   │   ├── config.json         # 躯体配置(Brain URL、设备 ID 等)
│   │   ├── skills/             # 设备专属 skill 文件(.md),注册时携带
│   │   └── tools/
│   │       ├── desktop.js      # 截图、列出窗口、鼠标点击、应用启动
│   │       ├── filesystem.js   # 文件读写搜索
│   │       ├── accessibility.js # AT-SPI 无障碍树(LLM 驱动的 UI 检查)
│   │       └── shell.js        # Shell 命令执行
│   ├── src/                    # React 渲染进程(Vite)
│   │   ├── App.jsx             # 根组件
│   │   ├── components/
│   │   │   ├── Titlebar.jsx    # 自定义无边框标题栏(最小化/关闭)
│   │   │   ├── Sidebar.jsx     # 会话列表(新建/切换会话)
│   │   │   ├── ChatArea.jsx    # 对话消息流
│   │   │   ├── InputBar.jsx    # 输入框(支持拖拽/粘贴图片)
│   │   │   └── StatusDot.jsx   # WebSocket 连接状态指示
│   │   └── store/
│   │       └── chat.js         # Zustand 全局状态
│   └── resources/              # 应用图标 + 托盘图标
├── body-wechat/                # 微信躯体(Node.js 网关,无 UI)
│   ├── main.js                 # 入口:加载账号,启 WSClient/bridge,长轮询 iLink getUpdates
│   ├── login-cli.js            # 一次性扫码登录脚本(npm run login)
│   ├── config.js / config.json # 配置加载(环境变量 + 默认值)
│   ├── ws-client.js            # WebSocket 客户端,连接 brain
│   ├── bridge.js               # 双向桥接:微信↔brain,含 artifact 自动转发
│   ├── tool-executor.js        # 暴露 send_wechat_media 工具
│   ├── session-map.js          # from_user_id ↔ session_id + context_token 持久化
│   ├── weixin/                 # iLink 协议封装层
│   │   ├── api.js              # HTTP 调用(认证头/长轮询/发送)
│   │   ├── login.js            # 扫码登录
│   │   ├── send.js             # 文本/图片/视频/文件发送
│   │   ├── media.js            # 接收媒体下载解密 + SILK→WAV
│   │   └── cdn.js              # AES-128-ECB + CDN 上传/下载
│   └── state/                  # 运行时状态(账号、sessions、临时媒体)
├── body-android/               # Android 躯体(第二版,Kotlin)
│   ├── app/                    # 主应用(前台服务 + WebSocket + 工具执行)
│   │   └── src/main/
│   │       ├── aidl/           # IShellService.aidl(与 shell-server 共享接口)
│   │       ├── assets/         # shell-server.dex + start-shell.sh(随 APK 打包)
│   │       └── java/com/hance/body/
│   │           ├── shell/      # ShellConnector(Binder 轮询)+ ShellToolRegistry(动态注册工具)
│   │           ├── service/    # HanceService(前台服务入口)
│   │           ├── tools/      # 普通工具:相机、文件、定位、通知等
│   │           └── ws/         # WSClient(WebSocket)+ ToolExecutor
│   └── shell-server/           # 特权扩展进程(以 shell UID 运行)
│       └── src/main/java/com/hance/shell/
│           ├── ShellMain.kt    # app_process 入口,向 ServiceManager 注册 Binder
│           ├── ShellServiceImpl.kt  # IShellService.Stub 实现,分发工具调用
│           └── tools/          # InputTool / ScreenCaptureTool / PackageTool / SystemInfoTool
├── body-embedded/              # 嵌入式躯体(第二版,Python)
├── services/                   # 外部服务 MCP(第二版)
│   ├── homeassistant/
│   └── google_photos/
├── alembic/                    # 数据库迁移
├── docs/
│   └── superpowers/
│       ├── specs/              # 设计文档
│       └── plans/              # 实现计划
├── docker-compose.yml
├── pyproject.toml
└── .env.example

快速开始

1. 配置环境

cp .env.example .env

编辑 .env,至少填写:

HANCE_LLM_API_KEY=sk-xxx          # LLM API Key
HANCE_LLM_MODEL=gpt-4o            # 模型名(litellm 格式)
HANCE_DEVICE_TOKENS=["token-desktop-1"]  # 设备认证 Token 列表

2. 启动大脑

# 启动 PostgreSQL + Redis + Brain
docker compose up -d

# 初始化数据库
docker compose exec brain uv run alembic upgrade head

# 查看日志
docker compose logs -f brain

3. 启动桌面端躯体

cd body-pc

# 安装依赖
npm install

# 开发模式启动,通过环境变量传入配置
HANCE_DEVICE_ID=desktop-home \
HANCE_DEVICE_NAME="Home Desktop" \
HANCE_DEVICE_TOKEN=token-desktop-1 \
HANCE_BRAIN_WS_URL=ws://your-server:18731/ws \
  npm run dev

# 多实例时指定不同端口(避免 Vite 冲突)
PORT=5174 \
HANCE_DEVICE_ID=desktop-office \
HANCE_DEVICE_NAME="Office Desktop" \
HANCE_DEVICE_TOKEN=token-desktop-2 \
  npm run dev

# 未设置的环境变量从 electron/config.json 读取默认值
# 打包为可执行文件
npm run build

4. 启动 Android 躯体

用 Android Studio 构建并安装 APK(body-android/)。

应用启动后,在配置页填入 Brain WS URL 和 Device Token,然后通过 ADB 启动特权扩展进程(需一次性执行,之后自动后台运行):

adb shell sh /sdcard/Android/data/com.hance.body/files/start-shell.sh

脚本会自动终止旧进程并在后台启动新进程。日志通过 adb logcat -s HanceShell 查看。

shell-server 启动后,brain 将自动收到以 shell_ 为前缀的额外工具(截图、输入注入、dumpsys 等)。shell-server 停止时这些工具自动从 brain 注销。

MVP 验证场景

  1. 文字对话,上下文跨轮连贯
  2. /image <path> 发图片让 Hance 分析
  3. 「帮我截个屏看看屏幕上有什么」
  4. 「帮我执行 df -h 看看磁盘」
  5. 「在 ~/Documents 下找所有 .py 文件」
  6. /new 新建会话,知识记忆保留但对话历史清空
  7. 两台电脑同时连接,在 A 上说「截取 desktop-b 的屏幕」

路线图

  • v1(已完成):大脑 + 桌面端躯体 + 微信躯体,对话/工具/记忆/会话管理
  • v1.5(已完成):Android 躯体,含 shell-server 特权扩展(截图/输入注入/系统调试工具)
  • v2(进行中):嵌入式躯体、RAG 知识库、事件驱动、定时任务、Home Assistant
  • v3:语音交互、Google Photos 等云服务接入

许可证

TODO

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages