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