lsagent
v0.1.3
Published
本机 AI 运行时——网页经 lsagent-sdk 连接用户电脑上的 AI:本机文件、邮件、带工具的 AI 任务,密钥与数据不出本机
Readme
lsagent — 本机 AI 运行时(Local AI Runtime)
跑在用户自己电脑上的 AI 常驻进程。任何网页通过 lsagent-sdk 连接它,就能让 AI 在用户本机 读文件、收发邮件、执行带工具的 AI 任务——模型密钥、文件、邮件数据全部留在用户电脑上, 不经过任何服务器。
解决什么问题
Web 应用想用 AI 处理"用户电脑上的东西"(一份提单 PDF、他的邮箱、一张截图),常规做法只能 把文件上传到自己的服务器再调云端模型:隐私没了、合规难了、存储算力都是成本。
lsagent 把方向反过来:AI 常驻在用户电脑上,网页只是遥控器。文件不离开用户机器, 模型密钥由用户自己保管,你的后端一行都不用改。
你的网页 ── lsagent-sdk(WebSocket · 免码确认 / 配对码)──> lsagent(用户电脑)──> 模型 API / 本机文件 / 邮箱
│
只监听 ws://127.0.0.1:37700/ws特性
- AI 任务运行时 —— 支持 OpenAI 兼容 / Anthropic 协议的主流模型(DeepSeek、GLM、Kimi、 Claude、OpenAI…),支持 Skills(操作手册)与 MCP 工具扩展
- 本机文件 —— 网页上传的文件落到用户电脑(≤20MB),AI 直接读取解析(图片 / 文档 / 文本)
- 邮件 —— IMAP 收件 + SMTP 发信 + 本地全文搜索
- 实时事件流 —— 流式输出、工具调用过程、任务状态与用量,全部实时推送给连接方
- 安全边界清晰 —— 只监听 127.0.0.1 回环;免码接入 = 系统弹窗一次确认(可随时撤销),或 6 位配对码
- 零依赖单包 ——
npm i -g即用,无需数据库等任何外部服务
快速开始
① 安装(Node.js ≥ 20)
npm i -g lsagent② 配置模型(一次性,编辑两个 JSON 文件)
~/.lsagent/pi/auth.json —— 放 API key:
{ "deepseek": { "type": "api_key", "key": "sk-你的密钥" } }~/.lsagent/pi/models.json —— 注册模型:
{
"providers": {
"deepseek": {
"name": "DeepSeek",
"baseUrl": "https://api.deepseek.com/v1",
"api": "openai-completions",
"models": [
{
"id": "deepseek-chat",
"name": "deepseek-chat",
"reasoning": false,
"input": ["text"],
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"contextWindow": 128000,
"maxTokens": 8192
}
]
}
}
}api:模型协议——OpenAI 兼容端点用openai-completions,Anthropic 兼容端点用anthropic-messages- 可选:
~/.lsagent/pi/settings.json设默认模型{ "defaultProvider": "deepseek", "defaultModel": "deepseek-chat" } - 也可以完全不碰文件——网页经
saveProvider()把模型配置直接推到用户本机(见下方 ④ 完整示例)
③ 启动
lsagent # 前台启动,首次自动生成并打印 6 位配对码
lsagent --show-code # 之后随时查看配对码④ 网页接入:配合 lsagent-sdk 使用
网页是本运行时的"遥控器"。lsagent-sdk (IIFE / ESM / 自带类型声明,零依赖)负责 WebSocket 连接、认证、断线重连、请求-响应关联 与事件订阅,你只写业务逻辑:
npm i lsagent-sdk(<script> 直引 https://unpkg.com/lsagent-sdk/dist/lsagent-sdk.js → 全局 window.LsagentSDK,无需构建工具)
接入推荐免码模式:SDK 不带配对码连接,首次连接在用户电脑弹一个系统确认框, 点一次"是"该网站即持久授权、之后无感直连。完整流程(连接 → 下发模型 → 建任务 → 流式进度 → 取结果):
import { LsagentClient } from "lsagent-sdk";
const client = new LsagentClient(); // 免码模式
client.onState(s => {
if (s === "pending") showTip("请在电脑弹出的确认框上点【是】"); // 首次连接的等待态
});
client.connect();
await client.waitForAuthed(120_000); // 首次要等用户点确认,超时给足
// ① 可选:把模型配置推到用户本机(写 models.json + auth.json,保存即生效)
// 页面上引导用户自己填 key;内网系统也可由服务端统一下发固定 key
await client.saveProvider({
name: "zhipu",
displayName: "智谱 GLM",
baseUrl: "https://open.bigmodel.cn/api/anthropic",
apiType: "anthropic-messages", // OpenAI 兼容端点用 openai-completions
apiKey: userTypedKey, // 省略 = 保留用户本机已有 key
models: [{ id: "glm-5.3", name: "GLM-5.3" }],
});
// ② 建任务并立即执行(firstMessage 非空则开始跑;systemPromptAppend 约定业务行为/输出格式)
const task = await client.createTask({
title: "解析提单",
provider: "zhipu",
modelId: "glm-5.3",
systemPromptAppend: "你是单证助手,只输出约定的 JSON。",
firstMessage: "读取本机文件 ~/.lsagent/workspace/uploads/bl.pdf 并抽取字段",
});
// ③ 实时进度(事件全量广播,按 taskId 过滤)
client.onEvent((event, p) => {
if (p.taskId !== task.id) return;
if (event === "task.delta") appendStream(String(p.text ?? "")); // 流式文本
if (event === "task.status" && p.status !== "running") finish(); // idle | error = 结束
});
// ④ 结束后取权威全文(流式丢包的兜底)
const msgs = await client.getMessages(task.id);
const answer = [...msgs].reverse().find(m => m.role === "assistant")?.text ?? "";
// 多轮 / 中止
await client.prompt(task.id, "把收货人改成 ACME"); // 任务空闲时追加执行
await client.steer(task.id, "先停一下,等我补充"); // 执行中转向(下一轮生效)
await client.abort(task.id); // 中止执行给 AI 的文件从哪来:网页 <input type="file"> 拿到 File 后经
client.request("fs.saveUpload", { name, bytesBase64 }) 落到用户电脑
(~/.lsagent/workspace/uploads/,≤20MB),把返回的本机路径写进 firstMessage 即可让 AI 读取。
其余能力(listModels / listProviders / listTasks,以及开放的全量 WS 接口
fs.readFile、email.*、flows.list 等)都经 client.request(type, payload) 直调,
清单见 SDK 文档。
用户侧的授权管理:
lsagent --list-origins # 查看白名单与确认授权
lsagent --allow-origin https://crm.example.com # 手动放行某网站(免弹窗)
lsagent --allow-origin chrome-extension://abc123 # 放行某个浏览器扩展
lsagent --disallow-origin https://crm.example.com # 撤销授权(下次连接重新弹窗确认)配对码模式仍然可用(页面来源须是 localhost 或已在白名单):
const client = new LsagentClient({ pairingCode: "123456" }); // lsagent --show-code 查看完整 API / 事件清单 / 安全模型 → lsagent-sdk README
命令与配置
| 项 | 值 |
| --- | --- |
| lsagent | 前台启动(首次自动生成配对码) |
| lsagent --show-code | 打印当前配对码 |
| lsagent --list-origins | 查看网页接入白名单与确认授权 |
| lsagent --allow-origin <url> | 手动放行某来源(网站或 chrome-extension:// 扩展,免弹窗确认) |
| lsagent --disallow-origin <url> | 撤销某网站的接入授权 |
| 监听地址 | ws://127.0.0.1:37700/ws(仅本机回环;端口用环境变量 COMPANION_PORT 覆盖) |
| 数据目录 | ~/.lsagent(环境变量 LSAGENT_DATA_DIR 覆盖) |
| 日志 | ~/.lsagent/logs/companion.log |
| 开机自启 | 自行加入系统启动项(Windows 任务计划 / systemd / launchd 等) |
数据目录结构:
~/.lsagent/
├── pi/ # AI 运行时:auth.json / models.json / settings.json / skills / mcp
├── workspace/ # 网页上传文件的落盘目录(uploads/)
├── web-origins.json # 外部网页 origin 白名单(配对码模式的来源门槛)
├── web-grants.json # 网页确认授权记录(免码模式:谁被允许/被拒几次)
├── tasks.json # 任务索引
└── logs/ # 运行日志外部网页接入
免码模式(推荐):网页用 SDK 不带配对码连接,首次连接弹系统确认框,
用户点一次"是"即持久授权(web-grants.json,可随时撤销);点"否"只拒当次,
同一网站连拒 3 次后静默拦截,lsagent --allow-origin 可解封。
浏览器扩展(chrome-extension:// 来源)同样走免码确认制,一次授权永久无感。
配对码模式:localhost 默认放行;生产网站的网页要配对码接入时,
用户在 ~/.lsagent/web-origins.json 添加来源(保存即生效,无需重启):
{ "origins": ["https://crm.example.com"] }安全模型
- 只监听 127.0.0.1:局域网 / 外网不可见
- 免码接入 = 系统弹窗确认制:授权绑定来源 origin(浏览器无法伪造),用户可见可撤销; 恶意网站反复请求会被"连拒 3 次静默 + 10 分钟最多 5 次弹窗"拦住,无法轰炸用户
- 6 位配对码 = 完全授权:拿到配对码的连接方可以驱动 AI、读写文件、收发邮件—— 请像对待密码一样对待它(同 IP 连续错 5 次锁 10 分钟;白名单外来源不认配对码,防钓鱼页骗码直连)
- origin 白名单:配对码模式的来源门槛,只挡来源不做细粒度权限
- 密钥与数据不出本机:模型 key、文件、邮件全部留在用户电脑
- 单实例:第二个实例检测到已在运行的实例会自动退出
FAQ
- 网页连不上? lsagent 没在运行——终端执行
lsagent;确认 37700 端口未被占用。 - 配对码在哪?
lsagent --show-code(也可以完全不用配对码,见「免码模式」)。 - 建任务报无可用模型? 先完成「② 配置模型」,或让网页用 SDK 的
saveProvider()引导配置。 - 网页被拒绝接入? 免码模式点"否"次数太多会被静默拦截:
lsagent --allow-origin <url>放行; 配对码模式需把 origin 加进~/.lsagent/web-origins.json。 - 想快速体验? 任意 localhost 页面引入 lsagent-sdk 即可连上(首次弹一次确认框)。
相关包
- lsagent-sdk —— 浏览器 JS SDK (IIFE / ESM / 类型声明),网页接入本运行时的官方方式
