目标读者 :要做离线可用、隐私优先、自主可控 Agent 的移动/端侧工程师
预计阅读 :18~22 分钟
主线 :配合 <3B 端侧模型,在手机/PC 本地跑「规划 + 工具 + 记忆」多 Agent;以
onnxruntime-genai为推理底座,给出可运行骨架,并回应 2026-09-03 前沿模型连环宕机后的可靠性刚需关键词:端侧 Agent、Edge Multi-Agent、onnxruntime-genai、Phi-mini、离线推理、本地工具
开篇:云端挂了,你的 Agent 还在不在?
2026 年 9 月 3 日 早晨,ChatGPT、Claude、Grok 等在相近窗口相继出现故障(OpenAI 侧公开称路由错误;xAI 侧指向 Memphis 算力中心等)。争议焦点不是「谁背锅」,而是产品侧的冷事实:
只要决策链路绑死云端 API,一次厂商级中断就能让整条 Agent 产品停摆。
于是社区把目光重新压回端侧:配合 <3B 量级模型,在手机 / PC 本地跑「规划 + 工具 + 记忆」的小 Agent------离线可用、数据不出机、自主可控。这不是否定云端大模型,而是补上「可靠性底仓」。
日报卡片里那几行代码,点题很准:
python
# pip install onnxruntime-genai
import onnxruntime_genai as og
model = og.Model("phi-mini-onnx")
tok = og.Tokenizer(model)
out = model.generate(tok.encode("本地总结这段文本并调用日历"))
print(tok.decode(out)) # 端侧推理,无云端
本文把它展开成工程可落地的 端侧多 Agent 编排:真实 GenAI 循环、本地工具协议、Planner / Worker / Memory 分工,以及手机上的资源预算。
一、端侧多 Agent 长什么样?
On-device · offline-first · <3B models Planner 拆解 / 路由 Worker Agents 摘要 / 日历 / 检索 Local Tools 日历·文件·通知 Memory SQLite 推理底座:onnxruntime-genai(Phi-mini / Qwen2.5-1.5B / Llama-3.2-1B ONNX INT4) 加速:CPU / DirectML / CUDA / Snapdragon NPU · 数据:不出机 · 网络:可选云端升级
和云端多 Agent(如 OpenAI Agents SDK handoffs)对比:
| 维度 | 云端多 Agent | 端侧多 Agent |
|---|---|---|
| 模型 | 任意大 | 通常 ≤3B,INT4/INT8 |
| 网络 | 强依赖 | 离线可跑 |
| 工具 | HTTP / SaaS | 本机日历、通讯录、文件、传感器 |
| 记忆 | 服务端 Session | 本地 SQLite / 加密库 |
| 失败模式 | 厂商宕机 = 全挂 | 能力变弱,但产品仍在线 |
端侧「多 Agent」往往不是上十个 70B,而是:一个极薄 Planner + 两三个专精 Worker + 确定性工具层------小模型负责意图与槽位,副作用交给代码。
二、为什么卡在 <3B?手机的账要这么算
Rough RAM / UX budget on mid-high phones 0.5--1B 路由/分类 1.5--3B 主对话甜蜜点 3--8B 旗舰机/PC 边 >8B 手机难常驻
经验法则(INT4 ONNX,量级感):
- 0.5--1B:意图分类、是否调用工具、简单模板填槽
- 1.5--3B(Phi-mini / Qwen2.5-1.5B / Llama-3.2-1B~3B):端侧主对话 + 浅规划
- 更大:交给 PC / 云端升级路径,别强行塞进中端机后台
端侧 Agent 的正确姿势是 「小模型编排 + 大能力工具」,而不是「在手机里复刻一个云端 GPT」。
三、推理底座:onnxruntime-genai 实操
3.1 安装与拉模型
bash
pip install numpy
pip install --pre onnxruntime-genai # CPU;GPU/DML 选对应 wheel
# 示例:Phi-3/4 mini 的 CPU+Mobile INT4 包(路径以 HF 卡为准)
huggingface-cli download microsoft/Phi-3-mini-4k-instruct-onnx \
--include "cpu_and_mobile/cpu-int4-rtn-block-32-acc-level-4/*" \
--local-dir ./phi-mini-onnx
Windows GPU 可用 onnxruntime-genai-directml;骁龙机可参考 Snapdragon 教程。
3.2 日报「一行 generate」vs 官方循环
卡片里的 model.generate(...) 适合表达「无云端」;生产请用官方 Generator 循环(含 KV cache、采样、流式):
python
import onnxruntime_genai as og
MODEL_DIR = "phi-mini-onnx/cpu_and_mobile/cpu-int4-rtn-block-32-acc-level-4"
model = og.Model(MODEL_DIR)
tokenizer = og.Tokenizer(model)
stream = tokenizer.create_stream()
search_options = {"max_length": 1024, "batch_size": 1}
chat_template = "<|user|>\n{input} <|end|>\n<|assistant|>"
def generate(user_text: str) -> str:
prompt = chat_template.format(input=user_text)
tokens = tokenizer.encode(prompt)
params = og.GeneratorParams(model)
params.set_search_options(**search_options)
generator = og.Generator(model, params)
generator.append_tokens(tokens)
chunks: list[str] = []
while not generator.is_done():
generator.generate_next_token()
tid = generator.get_next_tokens()[0]
chunks.append(stream.decode(tid))
del generator # 释放捕获图,避免二次推理泄漏
return "".join(chunks)
print(generate("本地总结这段文本并调用日历"))
这才是「端侧推理,无云端」的可维护写法。
四、从单次生成到多 Agent:规划 + 工具 + 记忆
Deterministic loop · model decides, code executes ① Prompt ② Plan JSON ③ Tools ④ Memory 未完成则回 ①;步数上限 / 拒答策略必须写死 小模型输出严格 JSON schema,工具白名单,禁止自由 shell
核心原则:模型只产结构化计划,副作用只走白名单工具。 小模型胡写命令的风险,用代码兜住。
4.1 可运行骨架(PC 原型,可迁 Android/iOS)
python
"""edge_multi_agent.py --- 端侧 Planner + 本地工具 + 记忆(示意可运行)"""
from __future__ import annotations
import json
import re
import sqlite3
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Any, Callable
# --- 可选:有模型时接 onnxruntime_genai;无模型时用规则 stub ---
USE_OG = False
try:
import onnxruntime_genai as og # noqa: F401
USE_OG = Path("phi-mini-onnx").exists()
except ImportError:
pass
@dataclass
class EdgeMemory:
db: Path = Path("edge_memory.db")
def __post_init__(self) -> None:
with sqlite3.connect(self.db) as conn:
conn.execute(
"CREATE TABLE IF NOT EXISTS notes(ts TEXT, role TEXT, content TEXT)"
)
def add(self, role: str, content: str) -> None:
with sqlite3.connect(self.db) as conn:
conn.execute(
"INSERT INTO notes VALUES(?,?,?)",
(datetime.utcnow().isoformat(), role, content),
)
def recent(self, n: int = 6) -> list[str]:
with sqlite3.connect(self.db) as conn:
rows = conn.execute(
"SELECT role, content FROM notes ORDER BY ts DESC LIMIT ?", (n,)
).fetchall()
return [f"{r}: {c}" for r, c in reversed(rows)]
# ---------- 本地工具(手机上换成 CalendarContract / EventKit) ----------
def tool_summarize(text: str) -> str:
text = text.strip()
return text if len(text) <= 80 else text[:77] + "..."
def tool_add_calendar(title: str, when: str) -> str:
# 演示:写本地文件;真机写系统日历并申请权限
Path("local_calendar.log").write_text(
f"{when}\t{title}\n", encoding="utf-8"
)
return f"CAL_OK title={title} when={when}"
TOOLS: dict[str, Callable[..., str]] = {
"summarize": lambda **kw: tool_summarize(kw["text"]),
"add_calendar": lambda **kw: tool_add_calendar(kw["title"], kw["when"]),
}
PLANNER_SYS = """你是端侧 Planner。只输出一行 JSON,不要解释:
{"agent":"summarizer|calendar|chat","tool":"summarize|add_calendar|none","args":{...},"reply":"..."}
规则:需要写日历用 calendar+add_calendar;需要压缩文本用 summarizer+summarize;否则 chat+none。
"""
def llm_plan(user: str, memory_snip: str) -> dict[str, Any]:
"""有 OG 则调本地模型;否则用极简规则 stub,保证离线可演示。"""
if not USE_OG:
if "日历" in user or "提醒" in user:
return {
"agent": "calendar",
"tool": "add_calendar",
"args": {"title": "本地提醒", "when": "tonight-20:00"},
"reply": "已安排本地日历事项。",
}
if "总结" in user:
body = re.sub(r".*总结", "", user).strip() or user
return {
"agent": "summarizer",
"tool": "summarize",
"args": {"text": body},
"reply": "摘要如下。",
}
return {"agent": "chat", "tool": "none", "args": {}, "reply": "(离线 stub)收到。"}
# 真实路径:把 PLANNER_SYS + memory + user 喂给 generate()
from edge_infer import generate # 你可把上一节 generate 抽成模块
raw = generate(f"{PLANNER_SYS}\n记忆:{memory_snip}\n用户:{user}\nJSON:")
m = re.search(r"\{.*\}", raw, re.S)
return json.loads(m.group(0) if m else '{"agent":"chat","tool":"none","args":{},"reply":"解析失败"}')
def run_turn(user: str, mem: EdgeMemory) -> str:
mem.add("user", user)
plan = llm_plan(user, " | ".join(mem.recent()))
tool_name = plan.get("tool", "none")
tool_out = ""
if tool_name in TOOLS:
tool_out = TOOLS[tool_name](**plan.get("args", {}))
mem.add("tool", f"{tool_name}:{tool_out}")
final = plan.get("reply", "")
if tool_out:
final = f"{final}\n[{plan.get('agent')}] {tool_out}"
mem.add("assistant", final)
return final
if __name__ == "__main__":
memory = EdgeMemory()
print(run_turn("请总结:本周完成端侧 Agent POC,并调用日历提醒今晚复盘", memory))
一次运行的期望输出类似:
text
摘要如下。
[summarizer] 本周完成端侧 Agent POC,并调用日历提醒今晚复盘
[calendar] CAL_OK title=本地提醒 when=tonight-20:00
Planner 决定「谁上场」,Worker 通过工具名区分;记忆落 SQLite------这就是端侧多 Agent 的最小闭环。
五、手机落地:三条常见技术栈
A. ORT GenAI Phi ONNX · 跨平台 Python/C++/C# 适合 POC→嵌入 B. Android ADK Gemini Nano / 混合 Kotlin 多 Agent 敏感子任务留端 C. 本地 Runtime llama.cpp / EdgeChain GGUF + 工具总线 强离线定制
| 路线 | 代表 | 何时选 |
|---|---|---|
| A | onnxruntime-genai + Phi ONNX | 要官方 GenAI 循环、Windows/移动 CPU 友好 |
| B | ADK for Android + Gemini Nano | 原生 Kotlin、混合云端编排、系统级 on-device |
| C | llama.cpp / EdgeChain / MobAgent 类 | 任意 GGUF、自研工具沙箱、强离线 |
产品常见形态是 混合:日常敏感(摘要短信、写日历)走端侧;复杂推理征得用户同意后再上云------正好对冲 9/3 这类「全家桶云端同时抖」的风险。
六、可靠性设计:为宕机日准备的清单
| 能力 | 做法 |
|---|---|
| 离线路径 | 首启预下载 INT4 权重;无网仍可 Planner+Tools |
| 降级 | 无 NPU → CPU;无模型文件 → 规则 stub(仍可写日历) |
| 步数熔断 | max_steps=3,防小模型死循环烧电 |
| 工具白名单 | 只开放日历/通知/指定目录;禁止任意 shell |
| 记忆加密 | SQLCipher / Keystore;敏感字段不上云日志 |
| 观测 | 本地 trace 文件;可选同步,默认关 |
9/3 事件的产品翻译就一句话:
云端是加速器,端侧是底仓。 底仓不需要赢过 GPT,只需要「断网那天,核心动作还能做完」。
七、和浏览器本地推理怎么分工?
上一篇 WebLLM(浏览器 WebGPU)解决的是 标签页内隐私推理 ;端侧 Agent 解决的是 OS 级工具权限 + 后台 + 离线常驻。
| WebLLM | 端侧 ORT-GenAI / ADK | |
|---|---|---|
| 载体 | 浏览器 | App / 系统服务 |
| 工具 | 受限 Web API | 日历、通知、传感器 |
| 模型 | 可到 4B/8B(高配) | 手机常驻更偏 ≤3B |
| 典型 | 插件摘要 | 随身助理 / 车机 / 工牌 |
可以组合:PC 浏览器做重文档,手机端侧做轻行动。
八、踩坑
- 把
model.generate当生产 API → 用Generator+append_tokens循环,并del generator。 - 让小模型直接「执行自然语言命令」 → 只解析 JSON,工具层写死。
- 一个 3B 既当大脑又当百科 → 拆 Planner / Worker,百科交给本地 RAG 或云端。
- 忽略权限与电量 → 日历权限弹窗、推理放后台线程、限制
max_length。 - 以为离线=零下载 → 首次仍要拉 GB 级权重;做差分更新与完整性校验。
九、收束
端侧多 Agent = <3B 本地推理 + 结构化规划 + 白名单工具 + 本地记忆。
onnxruntime-genai把 Phi-mini 一类模型送进手机/PC;你要补的是编排与可靠性,而不是更大参数。9/3 的连环故障提醒我们:自主可控不是口号,是「云端抖动时产品是否还活着」。
下一步:
- 把本文骨架迁到 Android(ORT Mobile / ADK + 系统日历)
- 用 30 条真实口语评测「总结 / 建日程 / 闲聊」路由准确率
- 设计云端可选升级开关,默认关、用户显式开
参考链接
- microsoft/onnxruntime-genai
- ONNX Runtime GenAI · Snapdragon
- Phi ONNX 模型卡(HF)
- ADK for Android
- 事件背景:2026-09-03 多家长口模型服务中断相关公开报道(WIRED / Ars 等)