10 月初最热闹的产品话题,除了 DevDay 本身,就是常驻智能体的贴身肉搏:AGI Hunt 的 10 月 3 日日报里,OpenAI 的 dot 和 xAI 的 Grok Bot 的对比评测排在头条,用户在争论谁更适合当「首席参谋」。dot 确实新鲜——给它一块自己的云电脑,你关掉聊天窗它还在干活。但它只对 Pro、Business Premium 和 Enterprise 计划开放,欧洲经济区、英国、瑞士的用户首发时直接被跳过,国内用户更是想都不要想。我在 DevDay 全面解读里提过这个限制,评论区问得最多的就是「有没有替代品」。
答案是:有,而且来得飞快。DevDay 散场没几个小时,社区里就冒出了开源平替的动静,最有生命力的是 Anil-matcha 的 open-dots——MIT 协议,Python 加 Next.js,AGI Hunt 10 月 3 日的日报还在写 4.8k 星,我查 GitHub API 时已经 5233。我把它完整跑了一遍,结论先说:聊天、审批、审计这些核心机制是真能用的,但它的模型接入协议是个坑,Ollama 用户必须自己补一层桥接。这篇文章就是完整的跑通过程和填坑代码。
它到底是什么
先泼一盆冷水:README 里作者自己写得很诚实,这是一个 early prototype,「不是那些产品的功能等价替代」。所以别指望开箱就是 dot 那种打磨过的体验,它更像一个可以自己拆开研究的 Agent 工作台骨架:
- FastAPI 后端加 Next.js 前端,状态存本地 SQLite,供应商密钥落盘时加密;
- 所有工具调用走一个 deny-by-default 的操作网关,高风险动作停下来等人批准,并且留下审计事件;
- 可选的 Docker/Playwright 电脑运行时(默认关闭),外加 Composio 连接器和免 Key 的网页搜索。
和 OpenAI 托管在云上的 Agents API、Google 那边的 Antigravity 托管 Agent 相比,open-dots 的差异点不在能力上限,而在「数据在你机器上、每一步操作你能看见」。如果你的场景是给公司搭一个必须审计每个动作的内部助手,这套网关加审计的组合比功能多寡重要得多。
五分钟把它跑起来
我的环境:M4 MacBook(16GB 统一内存),macOS,Python 3.13,Node 24,Ollama 0.34.2。以下命令可以直接复制:
git clone https://github.com/Anil-matcha/open-dots.git
cd open-dots/server
python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
# 模型端点先占位,下一节会换成桥接层
export MODEL_API_KEY="local-test-key"
export MODEL_API_BASE_URL="http://127.0.0.1:8765"
python run.py依赖只有 8 个(fastapi、uvicorn、httpx 这些),我这台机器上十几秒装完。run.py 起来之后,API 在 http://127.0.0.1:8000,/docs 有完整的交互式文档。首次启动会在 ~/.open-dots/.auth-token 生成一个属主令牌,这就是登录凭据——它是独立于模型 API Key 的另一套凭证,别搞混。
前端另开一个终端:
cd open-dots/client
npm install
npm run dev445 个包 21 秒装完,Next.js 3.1 秒就绪。有个小插曲:我机器的 3000 端口被占了,Next.js 自动换到 3002 并在启动日志里写明,页面正常打开。把 .auth-token 里的令牌粘进登录框就能进主界面。
真正的坑:模型协议不接 Chat Completions
这一节是我认为全网第一手的信息。本地模型玩家(Ollama、LM Studio)的第一反应是把 MODEL_API_BASE_URL 指向 http://127.0.0.1:11434/v1——我告诉你,走不通。
翻 server/app/services/provider_service.py 源码,它的推理适配器只认两种协议:
- Prediction 模式(默认):
POST {base_url}/{model_id},请求体是{prompt, image_url, system_prompt, reasoning_effort, web_search},鉴权用x-api-key头;响应要么直接给{"outputs": ["..."]},要么给request_id让你轮询; - Responses 模式:标准的 OpenAI Responses API,
POST {base_url}/responses,Bearer 鉴权加 SSE 流。
README 的 Current limitations 一节原话:“Chat Completions and a generic provider plugin interface are not implemented.” 而 Ollama 恰恰只提供 Chat Completions。两边对不上,这就是本地模型接不进去的全部原因。
解法也简单:既然 Prediction 协议这么朴素,写一个 30 行的转换层,一头收 Open Dots 的 Prediction 请求,另一头转发给 Ollama 的 /api/chat。下面这段代码我实测跑通,直接可用:
# ollama_bridge.py —— 让 Open Dots 吃上 Ollama 本地模型的最小转换层
# 用法: uvicorn ollama_bridge:app --host 127.0.0.1 --port 8765
import httpx
from fastapi import FastAPI, Request, Header
from typing import Optional
OLLAMA = "http://127.0.0.1:11434"
app = FastAPI()
@app.post("/{model_id}")
async def predict(model_id: str, request: Request,
x_api_key: Optional[str] = Header(None)):
body = await request.json()
messages = []
if body.get("system_prompt"):
messages.append({"role": "system", "content": body["system_prompt"]})
messages.append({"role": "user", "content": body.get("prompt", "")})
async with httpx.AsyncClient(timeout=300.0) as client:
r = await client.post(f"{OLLAMA}/api/chat", json={
"model": model_id, "messages": messages, "stream": False,
"think": False, # 关键:关掉思考模式,原因见下一节
})
content = r.json().get("message", {}).get("content", "")
return {"outputs": [content]}启动桥接层之后,Open Dots 那边的配置就是开头 export 的两个环境变量:MODEL_API_BASE_URL 指向 http://127.0.0.1:8765,Key 随便填(桥接层不校验)。设置页里把模型 ID 填成本地模型名,我用的 qwen3.5:4b-q4_K_M(3.4GB,16GB 内存的 Mac 跑起来很从容;模型本身来自 Ollama 官方库,ollama pull 一条命令的事)。
实测数据:能回话,但有两个延迟陷阱
模型接上之后,我建了一个绑定本地 Qwen3.5-4B 的助手,发了一句「用一句话说明什么是 MoE 架构」,SSE 流回来的回答是:
MoE(混合专家)架构利用门控机制将输入动态路由到特定专家子网络,从而在保持高性能的同时降低计算资源消耗。
对话历史也确认落了库,/api/v1/chat/history/{id} 里四条消息完整可查。但延迟数字值得单独说,这里有两个坑:
坑一:冷加载。 第一条消息发出后,SSE 流里先是四个 15 秒一发的 ping,快一分钟才见内容——那是 Ollama 把 3.4GB 权重从磁盘搬进内存的时间,属于正常现象,但你要是不知道,会以为服务挂了。
坑二:思考模式,这个坑大得多。 Qwen3.5 这类模型默认开思考,桥接层没传 think: false 时,一个「1+1 等于几」的请求实测花了 46 秒——模型在后台想了一大堆,才吐出答案「2」。加上 think: false 之后,同样的问答实测只要 1 秒,回复「用 5 个字介绍北京」拿到了「古都新地标」。46 秒到 1 秒,差距全在思考开关上。如果你接的是 Qwen3、DeepSeek-R1 这类会思考的模型,这行参数省下来的不是几秒,是几十秒。
审批网关实测:真会拦人
open-dots 宣传里最实的一块是操作网关。我拿真实文件验证了正反两条路径。
先在工作区根目录(仓库根)放一个测试文件,然后让助手执行 /workspace read secret-note.txt。SSE 流里立刻出现一个 request.opened 权限事件:工具 workspace.read,风险级别 read,状态 pending_approval——注意读文件也要批,这就是 deny-by-default 的含义。我用 API 把它放行(POST /api/v1/approvals/respond,action: "allow"),流里跟着出现 tool.started,然后文件内容原样回传到对话里,审计日志里也留下了记录。
反向测试更说明问题:让助手执行 /workspace write hacked.txt 写入恶意内容,这次我选择拒绝(action: "deny"),流里返回 tool.denied,助手回复「文件写入失败。权限不足」。我去文件系统确认了 hacked.txt 根本不存在——拒绝是真的拒绝,不是嘴上说说。
这个流程有三个实测出来的细节值得记住:
- 审批默认 120 秒超时(配置项
APPROVAL_TIMEOUT_SECONDS),超时自动作废,别慢慢悠悠去点批准; - 审批请求挂在 SSE 流的生命周期上,流断了请求就没了,我第一次测试就因为这个连碰两次「no longer pending」;
- 就算批准,工作区读写也被限制在
WORKSPACE_ROOT边界内,路径穿越进不了你的家目录。
另外 /search 命令接的是 You.com 的免 Key 通道,不用注册就能搜网页。我让本地 Qwen3.5 搜「Black Forest Labs Flux 3 Image」——这个模型的知识截止根本不知道这条本周新闻,回复里却准确带出了「4K 分辨率、可通过 Replicate 或 OpenRouter 使用」的细节,说明搜索结果确实注入了上下文。零成本联网这个点,对本地模型玩家价值不小。
不建议使用的场景
实测下来,有三类场景我会明确劝退:
- 多人共用:整个应用只有一个属主令牌,没有用户体系和角色权限,README 自己也承认 multi-user hosting 没做。想当团队工具用,先等它长大。
- 暴露公网:默认只听 127.0.0.1,README 反复强调非本机访问必须上 HTTPS 并收紧 Cookie 策略。它不是加固过的安全边界(原话 “not a hardened security boundary”),电脑运行时更别对着恶意网站开。
- 当生产力主力:它是早期原型,没有定时任务引擎、没有持久记忆服务,连接器也只有窄窄的 GitHub 只读操作。拿来研究 Agent 架构、给内网搭原型很合适;拿它替代你付费的助手,现阶段会失望。
写在最后
整趟体验下来,open-dots 给我的最大价值不是「免费版 dot」,而是把常驻智能体的骨架摊开给你看:网关怎么拦、审批怎么走、审计怎么记,全是可读的 Python。配合 CopilotKit 那个更偏前端的 OpenDots 模板(需要它的云服务),这一波开源跟进基本把 dot 的思路复现了个遍。
建议的上手路径:先用我的桥接层接上你已有的 Ollama 模型跑通聊天,再拿一个测试文件把审批正反两条路走一遍,最后打开 /api/v1/audit 看看每个动作留下的痕迹——这一小时花得比读十篇评测都值。至于 dot 和 Grok Bot 谁更强,这波对比风潮还在发酵,等开源这边把电脑运行时打磨稳了,我再来补一篇三家横评。在那之前,把「审批网关」这个概念装进脑子,比急着选边站有用得多。
想继续深挖 Agent 工具链的,可以接着读 Codex Harness 开源框架解析和我在 NVIDIA Portable Computer 上的本地 Agent 实战,这篇的桥接层思路在那两篇里也有变体。