欢迎来到 Dan 的博客。
一个人的 Agent OS(二):造出第一个「应用」,然后差点把底座的定位想歪
本篇覆盖 P3a 用户端对话模块(A/B/C/D 四切片全上线) → 一次把整个项目定位重新想清楚的架构校正。 如果说 (一) 是「把一根线通到公网」,(二) 就是「往线上挂第一个真产品,并在挂之前先停下来问:这条线到底是给谁用的」。 P3a — 第一个「应用」:一个对话产品 P2 之后底座能跑了,但底座不是产品。P3a 是我在这套底座上造的第一个面向人的东西——一个对话应用。 刻意做薄:只做「对话」这一个模块,登录 + 多轮聊天 + 选 agent,不贪大。 前端栈定成 Vite SPA + Vue3 + shadcn-vue(Reka UI + Tailwind)+ PWA + Pinia, 审美北极星是 LobeChat;双主题(青碧 / 电光青,全走 CSS 变量)。登录后就是个 app,SSR 用不上。 后端沿用底座:网关加了白名单账号密码登录(argon2 + 防枚举等时校验 + 每 IP/账号限流), 会话是服务端 chat_sessions 多轮,上下文用滑动窗口(~3000 token 或 20 条,先到先停), session_id 是客户端生成的 UUID,家侧先写消息成功、网关再 lazy 登记会话(避免孤儿)。 这个模块我拆成四个切片依次上线,每个都留了坑给我长记性: A · 生产上线。把 web 构建进云端 Nginx、网关部署上云、库加列、种正式账号。 加了「真 per-IP 限流」(只在直连对端是回环、且显式开启信任时才采信 nginx 追加的 X-Forwarded-For 最右段, 否则用 RemoteAddr——默认关,不给伪造留缝)。 B · 内容审核真做。不接第三方,自建关键词/规则:规则进 DB 表,输入前置 + 输出分段两个切点真拦, 命中回 event:error{内容不合规} 且不泄露命中词,GATEWAY_MODERATION=off 是整体逃生开关, 有 DB 就默认开、加载失败直接 fatal(fail-closed)。词表不进 git。 C · 集成小修。修了几个只有真用才暴露的集成缺陷,最有代表性的是前端错误态串会话: 流式回调原来按「位置下标」写 messages[idx],而切换历史会话时整个数组被替换, 迟到的回调就写到别的会话去了——改成捕获消息对象的响应式引用再写,收尾再校验同会话。 D · 管理端 v1。只做「登录 + 只读服务健康看板」,但前端拉了一整套 naive-ui-admin 脚手架 (为后续管理模块留地方)。网关加 /v1/admin/health 并发探测各组件(网关 / 元数据库 / 家侧后端 / agent 计数), 单项失败不整体 500,总超时 3s。 坑 · systemd 不继承你的登录 shell 环境。 Gemini 走 generativelanguage.googleapis.com,在 systemd 跑的后端进程里直连被墙卡 60s 超时, 而我排障时在终端里 curl 每次都通——因为我的登录 shell 有 HTTPS_PROXY(Clash), 而 systemd 服务根本不继承登录 shell 的代理变量。用 httpx 的 trust_env 开关一对照实锤: 走代理 4.6s OK / 直连 ConnectTimeout。修法是把代理写进服务自己的 env 文件。 这个坑的教训比坑本身值钱:「我手动能跑通」和「服务能跑通」是两个环境,别用前者证明后者。 ...
一个人的 Agent OS(一):从一份草稿到公网上线
这是 agent-os-base 项目的系列进展复盘。每篇标一个序号、覆盖一段里程碑, 在 /tags/agent-os/ 下汇成一个系列,后续有新进展就出 (二)、(三)……。 本篇 (一) 覆盖 P0 需求定稿 → P2 公网接入上线。 缘起:我想要一个「自己的 Agent 底座」 作为独立开发者,我不想每做一个 AI 应用就从头搭一遍鉴权、用量、路由、SSE 流式。 我想要的是一层底座——把「谁在调用、调用什么、算多少钱、内容合不合规、请求发去哪个 agent」这些 横切关注点收口到一个地方,让每个具体的 agent 只管自己那点业务逻辑。 同时我有个私心:家里的机器算力和私有数据,不想全搬上云。于是最终的心智模型定成了 「混合云」——控制平面在云端收口,真正吃算力、碰私有数据的 agent 计算可以留在家里, 通过内网穿透被云端调用。本地能跑通的东西,配置一改就能平滑迁到云上。 这套东西,我给它起名 Agent OS。 架构 B:控制平面 / 数据平面 / 数据分层 定稿时对比了好几版草稿,最后拍板的是「架构 B」,三句话说清: 控制平面:云端一个 Go 薄网关。负责 JWT 鉴权、owner 授权、用量记账、(未来)内容审核、 限流,以及按 agent 路由,最后把各种后端的输出统一成一套 SSE 事件吐给客户端。 数据平面:可以分布式部署的 agent 后端。两种造法——自研的 FastAPI(Python), 或者 Dify app。对客户端而言两者长得一模一样。 数据分层:云端只放元数据(用户、agent 配置、用量流水);家侧放私有资产(向量库等)。 几个当时刻意做的减法,事后看都对: Dify 从「引擎」降级为「可选后端」。纯自研的 agent 可以完全不碰 Dify。 向量库只留 PGVector,砍掉 Chroma / Pinecone 的多套并存,用一个抽象接口兜住未来可能的切换。 不用 Nacos 这类注册中心,网关内部用一张路由表 + 内存热更新就够了。 否掉了「换皮上线」的念头,老老实实走飞书自建应用 / 内测。 技术栈落定:网关 = Go 标准库 net/http + pgx v5 + golang-jwt/v5; 自研后端 = Python 3.14 / FastAPI(httpx / asyncpg / pgvector); 数据层 = PostgreSQL 17 + pgvector。 ...
你好,世界
这是 Dan 博客的第一篇文章。Hugo + PaperMod 已经跑起来了。