一个人的 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 文件。 这个坑的教训比坑本身值钱:「我手动能跑通」和「服务能跑通」是两个环境,别用前者证明后者。 ...