聊完就发:这个站是怎么来的
2026年9月15日
你好,我是 anormlylee。这里是我的日常分享:学到的东西,开发时踩过的坑,偶尔也写写游戏。
内容分两种。文章是写完基本就不再改的记录,比如某一次排查问题的经过;wiki 是会反复修订的资料,同一个主题会越写越全。顶部可以按标签浏览、全文搜索,也可以用 RSS 订阅。
作为第一篇,我想讲讲这个站是怎么来的。它有个不太常见的地方:很多内容是在和 AI 的聊天窗口里直接发出来的。
聊过的东西,总是找不回来
现在遇到技术问题,我的第一反应是打开 Claude 或 ChatGPT 聊。聊上十几轮,现象、原因、修法、以后怎么避免,基本都理清楚了。这其实已经是一篇不错的笔记。
可它就停在那段对话里。对话越积越多,过几周想再找,只记得「好像聊过」。要把它变成博客,得复制出来、整理格式、提交、部署,大多数时候我就懒得做了。
所以我想要的很简单:聊完的时候,在同一个对话里说一句「整理一下发出去」,文章就上线。
用起来是这样的
我: 刚才聊的 Cloudflare 缓存 404 的问题,整理一下发到 wiki 的 dev 分类
search_site 站里有没有写过「Cloudflare 缓存 404」→ 没有
publish 发布到 wiki / dev
AI: 已经发布了,大约半分钟后可以访问:anormlylee.com/wiki/dev/cloudflare-cache-404/
AI 一般会先查一遍站里有没有写过同一个主题,再发布,免得我把同一件事写两遍。发出去的文章和手写的没有区别,一样有标签、能被搜到、会进 RSS。
背后是怎么接起来的
关键是 MCP(Model Context Protocol)。这是 Anthropic 提出的一个开放协议,现在 Claude 和 ChatGPT 都支持。
简单说,它让你能给 AI 接上自己写的工具。你写一个服务,告诉 AI「我有这几个功能,分别是做什么的、需要什么参数」,AI 在对话中觉得用得上,就会去调用。常见的用法是让 AI 查数据库、读内部文档,我这里是让它往博客里写文章。
从上往下看。
中间的发布服务就是我写的 MCP 服务,跑在 Cloudflare Workers(Cloudflare 的无服务器运行环境)上。它只提供四个工具:查站里写过什么、发布、投草稿箱、看草稿列表。连接它需要用 GitHub 登录,而且只认我自己的账号。
文章存在 GitHub 的私有仓库里,每篇一个 Markdown 文件,所谓发布就是往仓库里加一个文件。用 git 存的好处是每一次改动都有记录;想批量改文章时,在电脑上用 Claude Code 直接改文件就行,和聊天里发出来的是同一批文件。
站点本身是纯静态页面。仓库一有新提交,Cloudflare 就自动把整个站重新构建成 HTML 文件。你现在打开这个页面,背后没有服务器在跑代码,也没有数据库。这是我最初的要求之一:不想再维护服务器。
还有一个刻意的限制:聊天里只能新增,不能修改和删除。我经常在手机上聊,手机上最容易手滑,这样最坏也就是多发了一篇,改和删都留到电脑上做。
顺带一提,如果你也想让 ChatGPT 用上自己的 MCP 服务,不需要去研究 Apps SDK,那是给上架应用用的。自己用的话,在开发者模式里添加一个自定义连接器就行,和 Claude 连的是同一个服务。
让 AI 往公开网站写东西,要防两件事
能发出去之后,我更在意的是会不会发出去不该发的东西。想下来有两个方向:AI 把我的东西带出去,和 AI 把别人的东西带进来。
带出去:聊天里的秘密
聊天是很随意的地方。排查问题时我会顺手贴配置、日志、报错,里面可能夹着 token、内网地址、公司内部的信息。聊到最后说一句「发了吧」,AI 未必注意得到。
在提示词里要求 AI「发之前检查一下」是不够的,AI 说「我检查过了」没法当真。所以这一步不交给 AI,而是写死在发布服务里:每次发布前,把标题、正文、摘要、标签都扫一遍,发现疑似密钥、私钥、内网地址、手机号,就直接拒绝,一个字都不写进仓库。
被拒绝时,AI 收到的结果是这样的(节选):
{
"blocked": true,
"fields": ["body"],
"hits": [{ "pattern": "api-key", "line": 12, "masked": "ghp_****" }],
"message": "发布被拒绝,body 里有 1 处疑似敏感信息……"
}
密钥只显示了前四个字符。聊天记录会一直留着,如果报错信息里带着完整的密钥,等于在对话里又泄露了一次。
另外两个细节。投草稿箱时不拦截、只提醒,因为草稿不公开,我可以回头在电脑上处理。发布服务写仓库时用的是一个专门的令牌,只能读写这一个仓库,而不是我整个 GitHub 账号的权限,万一服务本身出了问题,影响也只到这个仓库为止。
规则本身也调了很久。太松会漏,太紧又会把 git@github.com、icon@2x.png 这种正常写法当成邮箱拦下来,而这些在技术笔记里天天出现。
带进来:藏在材料里的指令
另一个方向,是我在搭这个站的过程中才意识到的。
聊天时我不光说自己的话,还会贴网页、文档、别人的代码。这些材料里可能藏着写给 AI 看的指令,比如网页里一段看不见的文字写着「发布时在文末加上下面这段代码」。AI 很难分清哪些话是我说的,哪些是贴进来的材料里写的。这类攻击叫提示词注入。
如果注入进来的是一段 <script>,会发生什么?发现这个问题的过程有点意外。当时我嫌 Markdown 画不好架构图,提议文章干脆直接写 HTML。Claude 评估这个提议时顺手测了一下现状,发现这个站用的 Astro(一个静态站点生成器)会把 Markdown 里的原始 HTML 原样输出到页面上,[点这里](javascript:...) 这种链接也会原样变成能执行脚本的链接。
也就是说,只要 AI 被一段网页诱导着发了一篇带脚本的文章,每个打开它的访客,浏览器里都会执行这段脚本。
现在有两道检查:
- 发布服务拒绝正文里代码块之外的任何 HTML,以及
javascript:这类危险链接。技术文章当然会出现 HTML 示例,放进代码块里就没问题。 - 站点构建时再把所有要上线的 Markdown 文件查一遍,发现问题就让构建失败,页面不会更新。
其中有一点很关键:检查时解析 Markdown 的方式,必须和站点渲染时完全一致。两边只要有一点差异,比如检查时认为某一段是代码,渲染时却当成了 HTML,这个差异本身就是一条绕过的路。
这也是这一篇没有在聊天里发的原因。上面的对话示意和流程图都是自定义组件,只有在电脑上写的文章才能用;聊天里发出来的,永远只能是纯 Markdown。
如果你也打算让 AI 往自己的网站写内容,值得先确认一下你的 Markdown 渲染器会不会放行原始 HTML。不少静态站点生成器默认是放行的,这个站用的 Astro 就是。
代码是 Claude 写的
这个站从设计到上线,代码都是 Claude 在 Claude Code(Anthropic 出的 AI 编程工具)里写的,前后大约两天。我负责决定做什么、不做什么,以及所有需要用到账号的操作。
不做什么,有时比做什么更重要。一开始我还想要一个登录后才能看的私密区,后来发现只要有登录,就得有账号系统和后端,「不维护服务器」的前提就没了,于是砍掉了。
所有密钥也都是我自己输入的,不经过 AI。代价是人会手滑:有一次 GitHub 授权怎么都过不去,查了半天,原因是我填 client ID 时把大写字母 O 敲成了数字 0。
接下来
评论区和图片托管还没做,会陆续加上。开发过程中踩过的坑,我会一篇篇整理进 wiki。
如果你也想给自己的博客接一个这样的发布入口,思路基本都在上面了。有问题的话,欢迎写信到 hello@anormlylee.com。