Initial: multi-agent XMPP communication system with dashboard
- Platform-based architecture (Windows/Linux/Mac) - Agent instance registry (agents.yaml) - Management dashboard with cross-platform monitoring - xmpp_bot with HTTP bridge + health endpoints - wechat_agent with WeChat-Hermes bridging - Platform services: ProcessGuardian, HealthProbe, APIRouter, ChannelBridge - Deployment: systemd (Linux) + PowerShell (Windows) - Monitoring: SSH+ejabberdctl for cross-platform presence
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
# xxm(小小莫)稳定性与观察者模式
|
||||
|
||||
> 最后更新:2026-06-03
|
||||
|
||||
---
|
||||
|
||||
## 架构概要
|
||||
|
||||
xxm(`xxm@yoin.fun`)是一个 XMPP bot,通过 slixmpp 连接 ejabberd(`xmpp.yoin.fun:3021`),作为"小小莫"在群聊 `coregroup@conference.yoin.fun` 中观察和响应消息。
|
||||
|
||||
```
|
||||
XMPP 消息
|
||||
↓
|
||||
xmpp_bot.py ← on_message / on_group_message
|
||||
↓
|
||||
session_router.py → route() → 构建 prompt
|
||||
↓
|
||||
chat_bridge.py → send_raw() → HTTP API 调用
|
||||
↓
|
||||
volcengine API (deepseek-v4-flash)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-03 修复记录
|
||||
|
||||
### 一、HTTP 请求死锁(最严重的稳定性问题)
|
||||
|
||||
**问题**:`urllib.request.urlopen(req, timeout=timeout)` 在 Windows 特定网络条件下,timeout 参数不触发,请求永远挂在 socket 上。桥接线程卡死 → bot 不回消息。
|
||||
|
||||
**修复**:弃用 `urllib.request`,改用 `requests` 库。
|
||||
|
||||
```python
|
||||
# 旧(会挂死)
|
||||
req = urllib.request.Request(url, data=data, headers=headers)
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||
body = json.loads(resp.read())
|
||||
|
||||
# 新(Connect=10s, Read=60s,分别起效)
|
||||
resp = requests.post(url, json=payload, timeout=(10, timeout))
|
||||
resp.raise_for_status()
|
||||
body = resp.json()
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- Connect timeout 10s:DNS / 连接层挂死不再发生
|
||||
- Read timeout 60s:API 响应慢也能兜底
|
||||
- 异常精确分类:`Timeout` / `HTTPError` / `RequestException` 分别打不同日志
|
||||
|
||||
**涉及文件**:`chat_bridge.py`
|
||||
|
||||
---
|
||||
|
||||
### 二、工具循环截断
|
||||
|
||||
**问题**:`_MAX_TOOL_LOOPS = 5`,LLM 做多步排查(SSH 到服务器逐条查 nginx 配置)时很容易耗尽,耗尽后 `return None` → bot 告诉用户"模型无响应"。
|
||||
|
||||
**修复**:
|
||||
1. `_MAX_TOOL_LOOPS = 5 → 50`(足够做深度排查)
|
||||
2. 50 轮耗尽后,再调一次**不带 tools 参数**的 API,强制模型用文字总结
|
||||
|
||||
```python
|
||||
# 耗尽后的兜底
|
||||
final_resp = session.post(final_url, json={"model": model, "messages": messages}, ...)
|
||||
final_msg = final_resp.json()["choices"][0]["message"]["content"]
|
||||
if final_msg.strip():
|
||||
return final_msg.strip()
|
||||
```
|
||||
|
||||
**涉及文件**:`chat_bridge.py`
|
||||
|
||||
---
|
||||
|
||||
### 三、API Key 冷却与 retry-cache 绕过
|
||||
|
||||
**问题**:opencode-go / opencode-go-new 两个 key 都在 403 冷却期(`code 1010`)。同时 opencode 的 retry-cache 机制(`#25803/#24462`)按 `(provider, model)` 缓存 429 错误,导致切换到另一个 provider 后仍然被旧 cache 截断。
|
||||
|
||||
**修复**:
|
||||
1. 创建 `api_proxy.py` 本地 HTTP 代理(`:8787`)
|
||||
2. 模型名重映射:`deepseek-v4-flash-safe` → `deepseek-v4-flash`(不同的模型名绕开 retry-cache key 碰撞)
|
||||
3. 代理吞掉 429/5xx 错误码,自动重试最多 3 次(指数退避 1s/2s/4s)
|
||||
4. 代理配置为独立 provider:`volcengine-proxy/deepseek-v4-flash-safe`
|
||||
|
||||
```json
|
||||
{
|
||||
"volcengine-proxy": {
|
||||
"type": "openai",
|
||||
"options": {
|
||||
"baseURL": "http://localhost:8787",
|
||||
"apiKey": "...",
|
||||
"model": "deepseek-v4-flash-safe"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**涉及文件**:`api_proxy.py`、`start_proxy.bat`、`~/.config/opencode/config.json`
|
||||
|
||||
---
|
||||
|
||||
### 四、观察者模式与 `__SILENT__` 协议
|
||||
|
||||
**问题**:xxm 在群里应该只回应 @自己的消息,其他消息保持沉默。但 LLM 会说"我应该保持沉默"然后把这句话本身发出去(没有用 `__SILENT__` 前缀)。
|
||||
|
||||
**修复**(两层防护):
|
||||
|
||||
**第一层 — System Prompt 明确教学**(`chat_bridge.py`):
|
||||
```
|
||||
=== 群聊沉默协议 ===
|
||||
保持沉默的方法:在回复的最开头写 __SILENT__
|
||||
系统检测到 __SILENT__ 就不会把消息发出去。
|
||||
注意:不要直接把"我应该保持沉默"当回复发出去。
|
||||
```
|
||||
|
||||
**第二层 — 自然语言兜底**(`xmpp_bot.py`):
|
||||
```python
|
||||
_SILENCE_PATTERNS = [
|
||||
"保持沉默", "不应[该]?回复", "没有.*@.*我",
|
||||
"不是对[我我说]", "跟我无关", "我不用回复",
|
||||
]
|
||||
```
|
||||
如果回复第一行匹配任何静默模式(即便没有 `__SILENT__` 前缀),直接 suppress。只检查第一行,避免误杀多行正常回复。
|
||||
|
||||
**涉及文件**:`chat_bridge.py`、`xmpp_bot.py`
|
||||
|
||||
---
|
||||
|
||||
### 五、群消息合并与串行化
|
||||
|
||||
**问题**:同个群多条消息靠近到达时,每条都触发独立的 LLM 调用和工具循环,导致:
|
||||
- 并发工具调用互相干扰(同时 SSH 到同一台服务器)
|
||||
- 多条重复排查(浪费额度)
|
||||
- log 混乱
|
||||
|
||||
**修复**:3 秒 debounce + 房间级串行化
|
||||
|
||||
**三个状态 / 两个路径**:
|
||||
|
||||
```
|
||||
消息到达
|
||||
├─ @xxm → 立即处理(绕过 batch)
|
||||
└─ 其他 → 进入 batch 系统
|
||||
│
|
||||
[BATCHING] 3s 窗口内可合并
|
||||
│ Timer 到期
|
||||
▼
|
||||
[PROCESSING] LLM 调用中
|
||||
│ 新消息 → 进入 pending 队列
|
||||
│ LLM 结束
|
||||
▼
|
||||
[_batch_done] 检查 pending
|
||||
├─ 有 pending → 立即发起下一批
|
||||
└─ 无 pending → IDLE
|
||||
```
|
||||
|
||||
**保证**:同一房间同一时刻最多一个 LLM 调用在处理。
|
||||
|
||||
**涉及文件**:`xmpp_bot.py`
|
||||
|
||||
---
|
||||
|
||||
### 六、context log 保存(self-message)
|
||||
|
||||
**问题**:LLM 看不到自己在群里说过什么,因为 bot 的 self-message 被直接丢弃了。每次都是"失忆"状态。
|
||||
|
||||
**修复**:self-message 不走 LLM,但写入 bridge context log(`_append_to_log("assistant", body)`),这样下次 LLM 调用时通过 `_read_recent_context()` 能看到自己说过的话。
|
||||
|
||||
**涉及文件**:`xmpp_bot.py`(`on_group_message` 中 `nickname == bot_nick` 分支)
|
||||
|
||||
---
|
||||
|
||||
### 七、`part_` → `prt_` 前缀修复(2026-06-11)
|
||||
|
||||
**问题**:`chat_bridge.py` 的 `_append_to_session()` 生成 part ID 时用了 `part_` 前缀:
|
||||
```python
|
||||
part_id = "part_" + _uuid.uuid4().hex[:24] # BUG!
|
||||
```
|
||||
但 OpenCode 1.17+ 要求 part ID 必须用 `prt_` 前缀。这导致:
|
||||
- 每次 xxm 写入消息到 session → 产生 `part_` 数据
|
||||
- compaction 扫描到旧前缀 → schema 校验失败 → 死循环
|
||||
- session 崩掉 → xxm 也卡住
|
||||
|
||||
**修复**:`part_` → `prt_`(`chat_bridge.py:335`)
|
||||
|
||||
**连带发现**:`ses_xxm_xmpp` session 在代码里配了但 DB 里不存在,已手动创建。
|
||||
|
||||
### 八、`session_search` 工具说明
|
||||
|
||||
**用途**:让 xxm 能搜索其他 session 的历史对话。已内置为 function calling tool。
|
||||
|
||||
**定义位置**:`chat_bridge.py` 的 `_TOOLS` 列表
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `session_id` | 当前 session | 指定要搜索的 session ID,空字符串则查自己 |
|
||||
| `limit` | 20(最大100) | 返回最近多少条消息 |
|
||||
|
||||
**调用方式**:LLM 通过 function calling 调用 `session_search`,不需要 xxm 写代码。
|
||||
|
||||
**注意**:archived session 仍可搜索(`extract_session_context` 直接从 message 表读,不依赖 session 状态)。
|
||||
|
||||
---
|
||||
|
||||
## 关键配置
|
||||
|
||||
| 参数 | 值 | 说明 |
|
||||
|------|-----|------|
|
||||
| `_MAX_TOOL_LOOPS` | 30 | 工具循环上限(超限后 clean final force,不泄漏 XML) |
|
||||
| `DEFAULT_TIMEOUT` | 60s | 每次 API 调用 read timeout |
|
||||
| `LOCK_DURATION` | 300s | 锁定成功 provider(避免频繁切换) |
|
||||
| `FAILED_BACKOFF` | 1800s | 失败 provider 冷却 |
|
||||
| `_BATCH_WINDOW` | 3.0s | 群消息合并窗口 |
|
||||
| api_proxy 重试 | 3 次 | 指数退避 1s/2s/4s |
|
||||
|
||||
## Provider 优先级
|
||||
|
||||
```
|
||||
volcengine (deepseek-v4-flash) # 主用,火山免费额度
|
||||
→ opencode-go-new (deepseek-v4-flash) # 备用,有订阅但冷却中
|
||||
→ opencode-go (deepseek-v4-flash) # 备用,冷却中
|
||||
```
|
||||
|
||||
## 日志
|
||||
|
||||
| 日志文件 | 路径 | 用途 |
|
||||
|---------|------|------|
|
||||
| `logs/xmpp_bot.log` | `projects/.../logs/` | XMPP 连接、消息收发、batch 状态 |
|
||||
| `logs/bridge.log` | `projects/.../logs/` | LLM API 调用、耗时、工具调用 |
|
||||
| `logs/api_proxy.log` | `projects/.../logs/` | 代理请求、错误吞没、重试 |
|
||||
@@ -0,0 +1,153 @@
|
||||
# 老莫微信消息 → serve session 路由设计方案
|
||||
|
||||
> 2026-05-20
|
||||
> 目标:老莫给机器人号发微信,小小莫也能看到,不依赖莫荷转述
|
||||
|
||||
---
|
||||
|
||||
## 现状
|
||||
|
||||
```
|
||||
你微信 → wxhelper TCP (:19099) → wechat_agent.py
|
||||
↓
|
||||
Hermes API (:8642)
|
||||
↓
|
||||
莫荷回复你
|
||||
```
|
||||
|
||||
莫荷独占所有微信消息。小小莫只能被动等她转述。
|
||||
|
||||
---
|
||||
|
||||
## 目标
|
||||
|
||||
```
|
||||
你微信 → wxhelper TCP → wechat_agent.py ─┬→ Hermes API → 莫荷 (不变)
|
||||
└→ opencode serve (:4096) → 小小莫看到
|
||||
```
|
||||
|
||||
新增一条岔路:老莫的消息同时写入 serve session,小小莫可主动查看。
|
||||
|
||||
---
|
||||
|
||||
## 方案对比
|
||||
|
||||
### 方案 A:subprocess 调用 `opencode run --attach --message`
|
||||
|
||||
**做法**:wechat_agent.py 的 `process_msg()` 里加一段:
|
||||
|
||||
```python
|
||||
def fork_to_session(fu, ct):
|
||||
"""将消息写入 opencode serve session (非阻塞)"""
|
||||
if fu != "wxid_c0a6izmwd78y22":
|
||||
return # 只转发老莫
|
||||
try:
|
||||
import subprocess
|
||||
subprocess.run(
|
||||
["opencode", "run", "--attach", "http://localhost:4096",
|
||||
"--password", "hermes123",
|
||||
"--session", SESSION_ID,
|
||||
"--message", f"[老莫] {ct}"],
|
||||
capture_output=True, timeout=10,
|
||||
env={**os.environ, "PYTHONHOME": ""}
|
||||
)
|
||||
except Exception as e:
|
||||
log(f"FORK ERR (non-fatal): {e}")
|
||||
```
|
||||
|
||||
| 方面 | 评估 |
|
||||
|------|------|
|
||||
| 复杂度 | ⭐ 低,~10 行代码 |
|
||||
| 对现有链路影响 | ❌ **无**,fork 是独立线程,失败不影响 Hermes |
|
||||
| session ID 稳定性 | ⚠️ serve 重启后 ses_xxx 会变 → 需想办法拿到当前 ID |
|
||||
| 性能开销 | subprocess 每次约 1-2 秒,但独立线程不阻塞主流程 |
|
||||
| serve 密码硬编码 | ⚠️ 已经在代码库(hermes123),无新增风险 |
|
||||
| 可靠性 | subprocess 可能因 PATH/PYTHONHOME 问题失败 |
|
||||
|
||||
### 方案 B:直接 HTTP POST 调用 serve API
|
||||
|
||||
**做法**:抓包分析 `opencode run --attach` 的 HTTP 协议,直接用 `urllib.request` POST:
|
||||
|
||||
```python
|
||||
# 伪代码,serve API 协议未知,需逆向
|
||||
urllib.request.urlopen("http://localhost:4096/api/session/inject",
|
||||
data=json.dumps({"session": SID, "message": "[老莫] xxx"}))
|
||||
```
|
||||
|
||||
| 方面 | 评估 |
|
||||
|------|------|
|
||||
| 复杂度 | ⭐⭐⭐ 未知,需逆向 serve API |
|
||||
| 性能 | ✅ 纯 HTTP,无 subprocess 开销 |
|
||||
| 稳定性 | ⚠️ 非官方 API,版本更新可能不兼容 |
|
||||
|
||||
### 方案 C:写 inbox 文件 + 小小莫轮询
|
||||
|
||||
**做法**:wechat_agent 写文件,小小莫定期读取
|
||||
|
||||
| 方面 | 评估 |
|
||||
|------|------|
|
||||
| 复杂度 | ⭐ 最低 |
|
||||
| 即时性 | ❌ 需要轮询,无法实时 |
|
||||
|
||||
---
|
||||
|
||||
## 关键风险
|
||||
|
||||
### 1. session ID 稳定性(最核心)
|
||||
|
||||
`opencode run --attach` 需要 session ID。每次 serve 重启后,当前 TUI session 的 ID 可能变化:
|
||||
- 如果 serve 重启 → 老 session 消失 → 新 session 新 ID → 需要更新 wechat_agent 里的配置
|
||||
- **解决思路**:用 session 名称而不是 ID,或每次启动时自动获取
|
||||
|
||||
### 2. 不对莫荷通信造成任何影响
|
||||
|
||||
**铁律**:fork 到 session 的代码必须:
|
||||
- 在独立线程中运行
|
||||
- 捕获所有异常
|
||||
- 设置超时(≤10 秒)
|
||||
- 永远不阻塞 `call_hermes()` 和 `send_wx()`
|
||||
|
||||
### 3. 循环消息风暴
|
||||
|
||||
如果我不小心回了一条 `[老莫]` 到 session,wechat_agent 不能把它再 fork 一次。
|
||||
- 现有的 `is_self` 检查已经过滤自己发送的消息
|
||||
- 但如果 serve session 的消息被 serve 再推给 wechat_agent... 需要确认不会发生
|
||||
|
||||
### 4. `opencode` CLI 在 wechat_agent 环境中是否可用
|
||||
|
||||
wechat_agent 以 `$env:PYTHONHOME=''` 启动,`opencode.cmd` 可能也依赖 Python。
|
||||
- 需测试:从 Python subprocess 能否直接调用 `opencode run --attach --message`
|
||||
|
||||
---
|
||||
|
||||
## 推荐方案
|
||||
|
||||
**方案 A**(subprocess)最稳妥:
|
||||
1. 对现有链路零影响
|
||||
2. 改动最小
|
||||
3. 可以逐步优化(先 subprocess,后改 HTTP API)
|
||||
|
||||
### 待确认事项
|
||||
|
||||
1. **serve session ID 如何维护?**
|
||||
- 能否用固定名称?还是每次启动获取?
|
||||
- 如果 serve 重启导致 ID 变了,wechat_agent 如何感知?
|
||||
|
||||
2. **`opencode run --attach --message` 是否支持在 Python subprocess 中调用?**
|
||||
- 需要验证 CLI 安装路径和调用方式
|
||||
|
||||
3. **是否需要前缀路由?**
|
||||
- 是全部消息都 fork?
|
||||
- 还是只有特定前缀(如 `[小小莫]` 开头的消息)才 fork?
|
||||
|
||||
---
|
||||
|
||||
## 验证清单
|
||||
|
||||
实现后验证:
|
||||
- [ ] 老莫发微信 → 莫荷正常回复(链路不变)
|
||||
- [ ] 老莫发微信 → serve session 能看到消息(新增)
|
||||
- [ ] `opencode run --attach` 超时/失败 → 莫荷通信不受影响
|
||||
- [ ] 老莫连续发多条 → 都能看到
|
||||
- [ ] wechat_agent 重启后依然工作
|
||||
- [ ] serve 重启后 session ID 变化时能自动适配
|
||||
@@ -0,0 +1,155 @@
|
||||
# 莫小果(MacBook M5 Pro 64G)MLX vs Ollama 对比测试记录
|
||||
|
||||
> 日期:2026-06-03
|
||||
> 机器:MacBook M5 Pro 64G / macOS 26.4 / Apple M5 Pro / arm64
|
||||
|
||||
---
|
||||
|
||||
## 测试目标
|
||||
|
||||
评估莫小果(本地算力中心)是否该从 Ollama 切换到 MLX 栈(MLX-LM / Rapid-MLX / oMLX),以解决"日常操作很慢"的问题。
|
||||
|
||||
## 测试方法
|
||||
|
||||
同一组 3 个 prompt,覆盖日常(`daily_short`)、排查(`ops_reasoning`)、规划(`agent_style`)三种场景。max_tokens=256,非流式,temperature=0.2。
|
||||
|
||||
由于 27B MLX 模型因 HuggingFace 镜像链路不稳定未下载完整(进度 ~10GB/16GB),先用 `Qwen3.5-4B-MLX-4bit` 验证 MLX 栈可用性和端到端速度。27B 同规模交叉验证引用社区基准。
|
||||
|
||||
## 实测结果
|
||||
|
||||
### Ollama(现有栈)
|
||||
|
||||
**模型**: `qwen3.5:27b-q8_0` (GGUF Q8_0, 29GB, 27.8B params)
|
||||
**引擎**: Ollama 0.24 (llama.cpp)
|
||||
**服务**: `localhost:11434`
|
||||
|
||||
| prompt | tok/s | 总耗时 | prompt_tps | 加载内存 |
|
||||
|--------|-------|--------|-----------|---------|
|
||||
| daily_short | **8.12** | 39.6s | 82.78 | 54 GB RSS |
|
||||
| ops_reasoning | **8.17** | 32.1s | 74.04 | 54 GB |
|
||||
| agent_style | **8.14** | 32.2s | 72.23 | 54 GB |
|
||||
|
||||
### MLX-LM(原生 Apple Silicon)
|
||||
|
||||
**模型**: `mlx-community/Qwen3.5-4B-MLX-4bit` (MLX, 2.9GB, ~4B params)
|
||||
**引擎**: mlx-lm 0.31.3 / mlx 0.31.2
|
||||
**方式**: Python 脚本 `mlx_lm.generate`(本地加载,非 HTTP 服务)
|
||||
|
||||
| prompt | tok/s | 总耗时 | 加载内存 |
|
||||
|--------|-------|--------|---------|
|
||||
| daily_short | **92.76** | 2.76s | 2.8 GB |
|
||||
| ops_reasoning | **94.91** | 2.70s | — |
|
||||
| agent_style | **94.42** | 2.71s | — |
|
||||
|
||||
模型加载时间:0.70s
|
||||
|
||||
### Rapid-MLX(OpenAI-compatible HTTP 服务)
|
||||
|
||||
**模型**: 同上(本地文件路径加载)
|
||||
**引擎**: Rapid-MLX 0.6.80(封装 mlx-lm 0.31.3)
|
||||
**服务**: `localhost:18000` → OpenAI-compatible API
|
||||
|
||||
| prompt | tok/s | 总耗时 | 内存 |
|
||||
|--------|-------|--------|------|
|
||||
| daily_short | **82.53** | 3.10s | 2.8 GB RSS + 7GB cache |
|
||||
| ops_reasoning | **90.24** | 2.84s | — |
|
||||
| agent_style | **90.62** | 2.83s | — |
|
||||
|
||||
Rapid-MLX 比裸 MLX-LM 慢 ~6%(服务层开销)。
|
||||
|
||||
### oMLX(macOS-native 推理服务)
|
||||
|
||||
**模型**: 同上(文件系统路径 `~/llm-bench/models/`)
|
||||
**引擎**: oMLX 0.4.2rc1(封装 mlx-lm,EnginePool 多模型管理)
|
||||
**服务**: `localhost:18001` → OpenAI + Anthropic API
|
||||
**安装方式**: source(`git clone` + `pip install -e .`),网络正常时约 3 分钟完成
|
||||
|
||||
| prompt | tok/s | 总耗时 | 说明 |
|
||||
|--------|-------|--------|------|
|
||||
| daily_short | **56.04** | 4.57s | 冷启动(模型首次加载) |
|
||||
| ops_reasoning | **90.34** | 2.83s | 热起,MLX 全速 |
|
||||
| agent_style | **90.26** | 2.84s | 热起 |
|
||||
|
||||
oMLX 用 EnginePool 管理多模型,首次请求需要加载模型到内存(冷启动慢 30-50%)。热起后与裸 MLX-LM 速度一致。内置 5 个预设模型引擎(LLM/VLM/Embedding/Reranker/MarkItDown)。
|
||||
|
||||
## 27B 同规模交叉验证(社区基准)
|
||||
|
||||
| 引擎 | 模型 | tok/s | 来源 |
|
||||
|------|------|-------|------|
|
||||
| Ollama | qwen3:32b (Q4) | ~27 | Rapid-MLX README |
|
||||
| Ollama | **你的 qwen3.5:27b Q8** | **~8** | **实测** |
|
||||
| MLX-LM | Qwen3.5-27B-8bit | ~55 | mlx-lm benchmark |
|
||||
| Rapid-MLX | Qwen3.5-27B-8bit | ~66 | Rapid-MLX README |
|
||||
| MLX-LM | Qwen3.5-27B-4bit | ~80 | Rapid-MLX README |
|
||||
|
||||
对于你的 27B Q8(8 tok/s),MLX 同精度(8bit)预期 **30-55 tok/s**(3.5-7x 提升)。
|
||||
|
||||
## 结论:双栈并跑
|
||||
|
||||
### Ollama 保留
|
||||
|
||||
- 模型库最广,下载安装最方便
|
||||
- Hermes CLI 现有对接(`http://localhost:11434/v1`)
|
||||
- GGUF 生态兼容
|
||||
- 出问题时稳定 fallback
|
||||
|
||||
### 新增 Rapid-MLX 作为主力 MLX 服务
|
||||
|
||||
- **预期 3-7x 速度提升**(8 tok/s → 30-66 tok/s)
|
||||
- OpenAI-compatible API,`/v1/chat/completions`,Hermes/OpenCode 可直接对接
|
||||
- 连续批处理(continuous batching)支持多并发
|
||||
- 自动 tool_choice / reasoning parser(hermes / qwen3)
|
||||
- 莫小果 64G,跑 27B-4bit 约占用 14-18GB,绰绰有余
|
||||
- 易管理:`rapid-mlx serve <alias>` 一键启动
|
||||
|
||||
### oMLX 已装(可用,待网络恢复后再全面评估)
|
||||
|
||||
- 已通过 `git clone` + `pip install -e .` 安装,`~/.venv/bin/omlx` CLI 就绪
|
||||
- 性能持平 MLX-LM/Rapid-MLX(热起 ~90 tok/s),EnginePool 多模型管理有额外 5.6% 内存
|
||||
- 冷启动比 Rapid-MLX 慢(首次请求需要加载模型,约 4.5s vs 3.1s)
|
||||
- 优势:原生 tiered KV cache + macOS menubar app(通过 homebrew 安装时可用)
|
||||
- 劣势:安装流程比 Rapid-MLX 重(需 git clone + pyproject build)
|
||||
- **推荐使用顺序**:日常推理 → Rapid-MLX(最轻量);长上下文/agent 工作流 → oMLX(tiered cache 更好);备用/测试 → MLX-LM(最接近底层,无服务开销)
|
||||
|
||||
## 启动指南
|
||||
|
||||
```bash
|
||||
# 激活环境
|
||||
source ~/llm-bench/.venv/bin/activate
|
||||
|
||||
# 启动 Ollama(已有):localhost:11434
|
||||
ollama serve
|
||||
|
||||
# 启动 Rapid-MLX(新增):localhost:8001
|
||||
rapid-mlx serve qwen3.5-27b \
|
||||
--port 8001 \
|
||||
--gpu-memory-utilization 0.50 \
|
||||
--no-mllm \
|
||||
--served-model-name qwen35-27b-4bit
|
||||
|
||||
# 测试 API
|
||||
curl http://localhost:8001/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model":"qwen35-27b-4bit","messages":[{"role":"user","content":"你好"}],"max_tokens":256}'
|
||||
```
|
||||
|
||||
## 遗留项
|
||||
|
||||
- ⏳ MLX 27B 模型需续传(HF mirror 断连,约剩 6GB,需要 20-30 分钟)
|
||||
- ⏳ oMLX 待网络恢复后评估(brew install / 源码编译)
|
||||
- ⏳ Rapid-MLX 内置的 `rapid-mlx doctor` 集成评测待跑
|
||||
|
||||
## 环境
|
||||
|
||||
- **隔离路径**: `~/llm-bench/`(完整的 MLX 评估环境,不影响系统)
|
||||
- **Ollama**: 未动,App 0.24 仍在 `:11434`
|
||||
- **MLX 栈**: `mlx==0.31.2` / `mlx-lm==0.31.3` / `rapid-mlx==0.6.80`
|
||||
- **Python**: 3.12.13(Homebrew)
|
||||
- **磁盘**: 1.6TiB 可用(够用)
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `~/llm-bench/.venv/` — 隔离虚拟环境
|
||||
- `~/llm-bench/results/` — 测试原始 JSON 数据
|
||||
- `~/llm-bench/models/` — 下载的 MLX 模型
|
||||
- `~/llm-bench/rapid-local4b.log` — Rapid-MLX 4B 服务日志
|
||||
@@ -0,0 +1,120 @@
|
||||
# �𡁶鍂�嗆�嚗阳eChat �?opencode ���獢交𦻖
|
||||
|
||||
> 2026-05-20
|
||||
> �亦氖 Hermes AI 靘肽�嚗�遣蝡?opencode serve 銝𤾸凝靽∟揭�瑚��渡��𡁶鍂����𡁻�
|
||||
|
||||
---
|
||||
|
||||
## �詨���艙
|
||||
|
||||
敺桐縑�箏膥鈭箸𧋦韐冽糓銝�憟烾�𡁶鍂����航楝�梁頂蝏��
|
||||
|
||||
```
|
||||
敺桐縑 �鐥� wxhelper �鐥� 獢交𦻖隞�� �鐥� 隞颱� AI / 蝔见�
|
||||
```
|
||||
|
||||
**銝滚�霂交糓"�怨㭘銝枏�"**����齿沲��� Hermes API 蝖祉���銁獢交𦻖�餉�銝哨��𣂼�鈭��𡁶鍂�扼�?
|
||||
---
|
||||
|
||||
## �嗆�撖寞�
|
||||
|
||||
### 敶枏�嚗�緒�瑚��剁��峕㦤嚗?
|
||||
```
|
||||
雿惩凝靽?�?wxhelper TCP �?wechat_agent �?Hermes API (:8642, Linux) �?�怨㭘�𧼮�
|
||||
�? 瘨��頝舐眏蝖祉�����嫣�憭��閬�𢆡 agent
|
||||
```
|
||||
|
||||
### �格�嚗��𡁶鍂嚗𣬚滲 Windows嚗?
|
||||
```
|
||||
雿惩凝靽?�?wxhelper TCP �?Bridge Agent ���砂� opencode serve session (撠誩��怎��?
|
||||
�? �婙� HTTP API (:5801) 靘𥕢遙雿閧�摨𤩺�韐? �? serve �𣬚� AI / 憭㚚�蝔见� POST �𧼮�
|
||||
```
|
||||
|
||||
**�喲睸�睃�**嚗𡁏‘�乩誨����?�?AI �𡁜�摰?嚗諹�峕糓�䀹�**銝剔�����舫�𡁻�**嚗?
|
||||
| �蠘� | �啁𠶖 (wechat_agent.py) | �格� (Bridge Agent) |
|
||||
|------|----------------------|-------------------|
|
||||
| �嗅�敺桐縑瘨�� | �湔𦻖 POST Hermes API | **�坔� serve session + �𣂷� HTTP 瘨�晶�亙藁** |
|
||||
| 瘨��頝舐眏 | 蝖祉��?(call_hermes) | �牐��⊿�餉�嚗�蘨韐蠘提頧砍� |
|
||||
| AI �航� | �芾��航緒�?(Hermes) | �臭誑�?serve �𣬚�隞颱�鈭綽�Sisyphus��緒�?..嚗?|
|
||||
| 憭㚚�靚�鍂 | :5801 蝞��𧢲𤣰瘨�� | http API �嗆��?|
|
||||
|
||||
---
|
||||
|
||||
## �𡁶鍂�嗆��?
|
||||
```
|
||||
�𢞖����������������������������������������������������������������������������������������������������������������������������������?�? Windows 192.168.1.16 �?�? �?�? �𢞖��������������������������������������������? �?�? �?敺桐縑 3.9.10.19 �箏膥鈭?�? �?�? �?(wxid_xxxxxxxxx) �? �?�? �婙����������������砂��������������������������? �?�? �?wxhelper TCP (:19099) �?�嗆��? �?�? �?wxhelper HTTP (:19088) �?�烐��? �?�? �? �?�? �𢞖����������������������������������������������������������������������������������������? �?�? �? Bridge Agent (bridge.py v3) �? �?�? �? �? �?�? �? �𢞖������������������������������������������������������������������������? �? �?�? �? �?瘨���?(TCP thread) �? �? �?�? �? �?�嗅�敺桐縑瘨�� �?�坔� serve session �? �? opencode �?�? �? �? �?閫血� webhook(�舫�? ������潑����?serve :4096 �?�? �? �婙������������������������������������������������������������������������? �? �?�? �? �? �?�? �? �𢞖������������������������������������������������������������������������? �? �?�? �? �?HTTP API �滚𦛚 (:5801) �? �? �?�? �? �?POST /send �?�穃凝靽? �? �? �?�? �? �?POST /history �?�亙��? �? �? �?�? �? �?POST /inject �?�?serve 隡朞� �? �? �?�? �? �婙������������������������������������������������������������������������? �? �?�? �婙����������������������������������������������������������������������������������������? �?�? �? �? �?�? �? serve session �𣬚� AI �?HTTP POST /send �?�? �? �? �?�? �𢞖������������������������������������������������������������������������? �? �?�? �? opencode serve TUI �? �? �?�? �? (Sisyphus / 隞颱� Agent) ������? �?�? �? �? �?�? �? �諹��緒嚗帋�憭拙�鈭���𨧀� 隞?session �见� �? �?�? �? ���憭㵪�[xxm] ����𨧀� POST :5801 �? �?�? �婙������������������������������������������������������������������������? �?�婙����������������������������������������������������������������������������������������������������������������������������������?```
|
||||
|
||||
---
|
||||
|
||||
## �唳旿瘚?
|
||||
### 敺桐縑瘨�� �?AI嚗��銵䕘�
|
||||
|
||||
```
|
||||
1. ��緒�穃凝靽∠��箏膥鈭箏噡
|
||||
2. wxhelper DLL �朞� TCP (:19099) �券��� Bridge Agent
|
||||
3. Bridge Agent �嗅�瘨��嚗���?serve session:
|
||||
subprocess.run(["opencode", "run", "--attach",
|
||||
"--message", "[��緒] 瘨����捆"])
|
||||
4. �峕𧒄嚗峕��臬虾�朞� :5801 HTTP API 鋡思遙雿閗恥�����韐?5. serve session �𣬚� AI �?TUI �㚚�朞� session_search �见�
|
||||
```
|
||||
|
||||
### AI �𧼮� �?敺桐縑嚗��銵䕘�
|
||||
|
||||
```
|
||||
1. AI �喳��𧼮� �?POST http://localhost:5801/send
|
||||
{"to": "wxid_xxx", "message": "�𧼮���捆"}
|
||||
2. Bridge Agent �嗅� �?wxpost /api/sendTextMsg
|
||||
3. wxhelper DLL �煾�?�?��緒�𧢲㦤�嗅�
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bridge Agent �亙藁閫��
|
||||
|
||||
### HTTP API (:5801)
|
||||
|
||||
| �寞� | 頝臬� | �券�?| Body |
|
||||
|------|------|------|------|
|
||||
| POST | `/send` | �穃凝靽⊥��?| `{"to":"wxid","message":"text"}` |
|
||||
| POST | `/history` | �亥�憭抵扇敶?| `{"wxid":"...","count":20}` |
|
||||
| POST | `/recent` | ��餈𤏸�蝟颱犖 | �?|
|
||||
| POST | `/inject` | �?serve session | `{"message":"[xxm] ��捆"}` |
|
||||
| GET | `/health` | �亙熒璉��?| �?|
|
||||
|
||||
### 颲枏枂�?serve session ��聢撘?
|
||||
```
|
||||
[��緒] 瘨����捆 �?�亥䌊敺桐縑��芦�𡁏��?[��緒|�萇妍] 瘨����捆 �?撣行猐蝘?[蝟餌�] �啗�蝟颱犖 xxx �?蝟餌�鈭衤辣
|
||||
[session:<id>] �臬𢆡蝑曉� �?Agent 銝羓瑪�𡁶䰻
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 銝?Hermes AI ���蝟?
|
||||
Hermes 銝滚��舀沲����詨�蝏�辣嚗諹�峕糓�舫�厩�瘨��瘨�晶���銝�嚗?
|
||||
```
|
||||
�𢞖��?opencode serve session �?Sisyphus (撠誩��?
|
||||
��緒敺桐縑 �?Bridge �����? �婙��?瘨�晶 HTTP API ��遙�讐�摨? �? �𢞖����������氯����������? �? �? Hermes AI �嗡� AI
|
||||
(�怨㭘) (�芣䔉)
|
||||
```
|
||||
|
||||
**餈�停蝑𣇉裦**嚗?1. 蝚砌��嗆挾嚗鋳ridge Agent �峕𧒄�?serve session + POST Hermes API嚗�緵�嗡��辷�
|
||||
2. 蝚砌��嗆挾嚗鋳ridge Agent �芸� serve session嚗峵ermes �朞� serve session �亙�
|
||||
3. 蝚砌��嗆挾嚗𡁜��券�𡁶鍂�吔�Hermes �芣糓 serve session �𣬚�銝�銝?AI 閫坿𠧧
|
||||
|
||||
---
|
||||
|
||||
## 摰墧鴌�笔�
|
||||
|
||||
1. **銝滨聦�讐緵�厰曎頝?* �?Bridge Agent �寥�䭾��湛�Hermes 瘨��頝舐眏銝滚�
|
||||
2. **憓鮋�餈�宏** �?����啣��踝��漤�鞉郊�踵揢�折�餉�
|
||||
3. **session 銝箔蜓** �?���㗇��臭誑 serve session 銝箔葉敹��HTTP API 銝箄��?4. **��雿𦒘�韏?* �?蝥?Windows �航�銵䕘�銝漤�閬?Linux 蝡?Hermes
|
||||
|
||||
---
|
||||
|
||||
## 撘��暸䔮憸?
|
||||
1. **session ID 蝞∠�**嚗鋳ridge Agent 憒���仿�敶枏��㗇��?session ID嚗?2. **session write �孵�**嚗窃ubprocess (`opencode run --attach --message`) �臬炏�㗇凒頧駁���𤜯隞��
|
||||
3. **瘨���駁�**嚗𡁜� session + POST Hermes �航�撖潸稲�滚�憭��嚗?4. **serve �滚鍳�W�**嚗鋳ridge Agent 憒���?serve �滚鍳�舘䌊�券�餈痹�
|
||||
5. **��蟮瘨��**嚗鋫I 銝羓瑪�舘��行��?session 銝剖歇�厩�瘨����蟮嚗?
|
||||
---
|
||||
|
||||
*�����projects/wechat-hermes-gateway/docs/��緒瘨��頝舐眏霈曇恣.md*
|
||||
Reference in New Issue
Block a user