13 KiB
LineUp Agents v1 — 设计方案
版本: v1.1(第二版) 最后更新: 2026-07-27
一、产品定位
LineUp Agents 是一个远程 Agent 操作交互端。用户通过手机或 Web App,与运行在本地或服务器上的 AI Agent 进行顺畅的交互。不是任务管理系统,Agent 的任务拆解、执行、管理属于 Agent 自己的工作范畴。
MVP 范围
| 做 | 不做 |
|---|---|
| App 直连 Agent(局域网 WebSocket) | 任务生命周期管理 |
| 通过 IM 中转连接 Agent(远程) | 自动化编排、调度 |
| App 收发消息、查看 Agent 状态 | 通知推送 |
| Agent 调 App 的工具(choice / 画板 / 计算器 等) | MCP 封装 |
| 工具发现与调用协议 | 多 Agent 工作流编排 |
| 用户 ↔ 用户基础通信(由 IM 平台提供) | 端到端加密(后续加) |
二、核心设计原则
LineUp 协议只定义工具交互,不定义基础消息。
这条原则是整个设计的关键。工具相关的内容(tool.call、tool.result、tool.list)由 LineUp 协议定义。文本、图片、语音、文件等基础消息,由下层传输平台(IM 服务或 WebSocket)原生处理,LineUp 不重复定义。
这让协议非常薄,换传输平台时工具协议不受影响。
三、架构总览
3.1 两种网络模式
LineUp 支持两种连接模式,插件根据配置自动切换。
直连模式(局域网)
Agent 插件 ── WebSocket 端口 :9527 ──→ App 端(Web)
Agent 插件在本地开 WebSocket Server,App 端手动输入 IP:端口连接。适合局域网内无公网 IP 的场景。
中转模式(广域网)
Agent 适配器 ──→ WuKongIM ←── 唐僧叨叨客户端 / LineUp App
▲
│ Webhook / HTTP API
唐僧叨叨业务服务
WuKongIM 负责客户端长连接、消息投递和消息存储;唐僧叨叨业务服务负责用户、好友、群组、文件等 IM 业务能力,并通过 Webhook 与 WuKongIM 协作。客户端以 WuKongIM 官方 SDK 建立长连接,以唐僧叨叨 API 处理业务操作。LineUp 的中转适配器需使用 WuKongIM 官方 SDK 或经验证的协议实现,不能复用其他 IM 平台的网关协议。
3.2 分层架构
┌──────────────────────────────────────────────┐
│ 工具协议层(LineUp 定义) │
│ 内容:工具定义、tool.call / tool.result │
│ App 渲染 choice / canvas / calculator 等工具 │
├──────────────────────────────────────────────┤
│ 消息传输层(IM 平台或直连 WebSocket) │
│ 内容:文本 / 图片 / 文件 / 语音的收发 │
│ 直连模式:WebSocket 原生传输 │
│ 中转模式:WuKongIM 消息通道传输 │
├──────────────────────────────────────────────┤
│ 连接层(IM 平台或 WebSocket Server) │
│ 内容:连接建立、心跳保活、断线重连 │
│ 直连模式:Agent 插件 WS Server │
│ 中转模式:WuKongIM 连接管理 │
└──────────────────────────────────────────────┘
LineUp 协议只关心最上面一层。下面两层由传输平台处理。
3.3 设计决策
| 决策 | 当期结论 | 后续扩展思路 |
|---|---|---|
| 网络模式 | 局域网直连 + WuKongIM 中转并存 | — |
| 中转服务 | 唐僧叨叨业务层 + WuKongIM 通讯层 | — |
| Agent 接入方式 | 直连模式用 LineUp 适配器;中转模式待基于 WuKongIM SDK 实现 | — |
| IM 平台选型 | WuKongIM;唐僧叨叨提供配套业务层和客户端 | — |
| App 端技术方向 | Vite + React(直连模式用 WebSocket;中转模式使用 WuKongIM JS SDK / 唐僧叨叨 API) | 原生移动端 App |
| 连接认证 | 直连:预共享 Token;中转:唐僧叨叨用户系统与 WuKongIM Token | 端到端加密 |
| 工具路由方式 | 字典路由 | 可引入框架级路由 |
四、工具协议定义(LineUp 协议的全部内容)
LineUp 协议只定义工具相关的三个消息类型。
4.1 工具定义结构
所有工具使用统一的结构模板,通过 type 区分行为差异。
| type | 含义 | 定义结构 |
|---|---|---|
app |
有状态应用,有生命周期 | { name, type, description, actions[] } |
toolset |
无状态工具集,多个动作 | { name, type, description, actions[] } |
action |
单指令工具,一个动作 | { name, type, description, inputSchema } |
4.2 三类工具的完整定义
type: app — 有状态应用
{
"name": "canvas",
"type": "app",
"description": "画板应用,支持绘制、撤销、清空等操作",
"actions": [
{
"name": "open",
"description": "创建画板实例,返回 instance_id",
"inputSchema": {
"type": "object",
"properties": {
"width": { "type": "integer", "description": "画板宽度" },
"height": { "type": "integer", "description": "画板高度" }
},
"required": ["width", "height"]
}
},
{
"name": "draw",
"description": "在画板上绘制路径",
"inputSchema": {
"type": "object",
"properties": {
"instance_id": { "type": "string", "description": "画板实例 ID" },
"path": { "type": "string", "description": "SVG 路径数据" },
"color": { "type": "string", "description": "线条颜色" },
"width": { "type": "integer", "description": "线条粗细" }
},
"required": ["instance_id", "path"]
}
},
{
"name": "undo",
"description": "撤销上一步操作",
"inputSchema": {
"type": "object",
"properties": {
"instance_id": { "type": "string", "description": "画板实例 ID" }
},
"required": ["instance_id"]
}
},
{
"name": "clear",
"description": "清空画板内容",
"inputSchema": {
"type": "object",
"properties": {
"instance_id": { "type": "string", "description": "画板实例 ID" }
},
"required": ["instance_id"]
}
},
{
"name": "close",
"description": "关闭画板释放资源",
"inputSchema": {
"type": "object",
"properties": {
"instance_id": { "type": "string", "description": "画板实例 ID" }
},
"required": ["instance_id"]
}
}
]
}
type: toolset — 无状态工具集
{
"name": "calculator",
"type": "toolset",
"description": "基础计算器,无状态,每次调用独立",
"actions": [
{
"name": "add",
"description": "两个数相加",
"inputSchema": {
"type": "object",
"properties": {
"a": { "type": "number" },
"b": { "type": "number" }
},
"required": ["a", "b"]
}
},
{
"name": "subtract",
"description": "两个数相减",
"inputSchema": {
"type": "object",
"properties": {
"a": { "type": "number" },
"b": { "type": "number" }
},
"required": ["a", "b"]
}
},
{
"name": "multiply",
"description": "两个数相乘",
"inputSchema": {
"type": "object",
"properties": {
"a": { "type": "number" },
"b": { "type": "number" }
},
"required": ["a", "b"]
}
},
{
"name": "divide",
"description": "两个数相除",
"inputSchema": {
"type": "object",
"properties": {
"a": { "type": "number" },
"b": { "type": "number" }
},
"required": ["a", "b"]
}
}
]
}
type: action — 单指令工具
{
"name": "choice",
"type": "action",
"description": "向用户提供一组选项让其选择",
"inputSchema": {
"type": "object",
"properties": {
"question": { "type": "string", "description": "问题描述" },
"options": { "type": "array", "items": { "type": "string" }, "description": "可选列表" }
},
"required": ["question", "options"]
}
}
4.3 三类工具对比
| app | toolset | action | |
|---|---|---|---|
| 定义结构 | name + type + description + actions[] | name + type + description + actions[] | name + type + description + inputSchema |
| 适用场景 | 需要维护内部状态的应用 | 多个独立功能可归类 | 单个独立功能 |
| 生命周期 | open → use → close | 无 | 无 |
| instance_id | 需要 | 不需要 | 不需要 |
| 每次调用需 action | 是 | 是 | 仍需 action 字段 |
| 示例 | canvas(画板) | calculator(计算器) | choice / confirm / input |
4.4 tool.call 消息格式
{
"call_id": "c1",
"name": "canvas",
"action": "open",
"arguments": { "width": 800, "height": 600 }
}
字段说明:
call_id— 调用方生成,唯一标识一次调用,用于 tool.result 配对name— 工具名action— 动作名(app 和 toolset 类型必填,action 类型可省略)arguments— 动作的参数,按 inputSchema 结构传入
4.5 tool.result 消息格式
{
"call_id": "c1",
"name": "canvas",
"action": "open",
"result": {
"message": "instance_id: inst_001"
}
}
字段说明:
call_id— 与 tool.call 中的 call_id 一致,用于配对name— 工具名action— 动作名result— 返回数据,约定统一放在 result.message,后续按工具定义扩展
4.6 tool.list 消息
{
"tools": [
{ "name": "choice", "type": "action", "description": "...", "inputSchema": {} },
{ "name": "calculator", "type": "toolset", "description": "...", "actions": [] },
{ "name": "canvas", "type": "app", "description": "...", "actions": [] }
]
}
设备注册和查询工具列表用统一的数据结构。直连模式下双向可查,中转模式下 App 端通过自定义消息类型注册工具。
五、完整交互流程
5.1 choice 工具调用
Agent 需要用户做选择
│
├── Agent 发 tool.call
│ { call_id: "c1", name: "choice", action: "select",
│ arguments: { question: "部署到哪个环境?", options: ["测试", "预发布", "生产"] } }
│
├── App 渲染选择界面,用户点击"预发布"
│
├── App 返回 tool.result
│ { call_id: "c1", name: "choice", action: "select",
│ result: { message: "预发布" } }
│
└── Agent 拿到结果,继续执行
5.2 canvas 完整生命周期
Agent 调 canvas 的 open 动作:
{ "call_id": "c1", "name": "canvas", "action": "open", "arguments": { "width": 800, "height": 600 } }
App 返回 instance_id:
{ "call_id": "c1", "name": "canvas", "action": "open", "result": { "message": "instance_id: inst_001" } }
Agent 绘制路径:
{ "call_id": "c2", "name": "canvas", "action": "draw", "arguments": { "instance_id": "inst_001", "path": "M10 10 L50 50", "color": "red" } }
Agent 关闭画板:
{ "call_id": "c3", "name": "canvas", "action": "close", "arguments": { "instance_id": "inst_001" } }
六、与 MCP 的关系
MCP LineUp
───────────────────────────────────────
MCP Server ──────────────── Tool(画板 / 计算器 / 选择框)
│ │
├─ MCP Tool A ├─ Action(open / draw / add / select)
├─ MCP Tool B ├─ Action
└─ MCP Tool C └─ Action
Tool = MCP Server 层,Action = MCP Tool 层。Action 才是实际可调用的最小能力单元。
工具定义格式复用 MCP 的 JSON Schema 标准。
七、后续可能的扩展
- 端到端加密,中转不可读消息内容
- 移动端原生 App(目前用响应式 Web)
- 直连模式切换到中转模式时的无缝过渡
- 更多 Agent 框架的插件支持(目前以 Hermes 为第一期)
- 框架级工具路由替代字典路由