“写笔记”支持四种格式——Word 文档、Excel 表格、Markdown、纯文本,起稿或二次编辑时都能随时切换,同一篇笔记想用哪种形态来记,都由你说了算。
md、txt、csv、json 这类纯文本则原样载入,不做多余加工。拿一张现成的表倒进来、改几笔、再导出去,等于白用一台免费的格式转换器。
要带走就在右上角点“下载”,可导出 PDF、Word、Markdown、Excel、TXT 等格式;列表卡片“⋯”菜单里,也有同样的下载入口。
在“工具”页点“+ 上传工具”即可发布:填好名称与链接,再用 Markdown 把使用方法写清楚——能解决什么问题、怎么装、怎么用,比堆介绍实在。
要分发安装包就一并上传压缩包(ZIP、RAR、7Z、TAR.GZ,最大 35MB),别人在详情页一键下载;只放链接不带附件也可以。
工具按大家的收藏热度排序,好用的自然会被顶上来。发布后可在详情页或卡片菜单里编辑、下架。
写笔记时勾上“隐藏”,这篇就只存在于你自己的账号里:不进列表、不进搜索、不上首页精选,也不会出现在任何公开的页面,链接发给别人同样打不开。
适合放密码、草稿、日记这类只给自己看的内容;想公开,去“发布”打开它,把“隐藏”的勾去掉再保存,之后编辑会默认保持原状态,不会悄悄变回公开。
你的内容会同时保存在多个副本上,系统定期做备份与完整性校验,再配合异地容灾机制:就算某台机器出问题,数据也不会丢,可以长期放心存放;特别重要的资料,仍建议你另外再留一份备份。
全站跑在容器化、模块化的现代架构上,更新、部署、回滚都很快,扩展性和稳定性都按长期运营的标准来设计(Built for reliability, designed to scale)。
这个网站最早只是一个人的笔记仓库,后来慢慢长成现在的知识中枢。设计上很克制——没有广告、没有追踪、没有推荐算法,只是干干净净地存放一些东西;既然做好了,就公开出来,万一有人用得上呢。
不做大而全,不做平台梦,保持简单、保持克制、保持好奇。所有内容都由用户贡献、由用户维护:不会突然冒出付费墙,不会在角落塞广告位,也不会把你的数据卖给第三方。
产品会持续迭代,站内日志页记录着每一次改动,改了什么都有迹可循;想了解这个站是怎么一步步走到今天的,翻翻日志就能看到来龙去脉。
如果在这里看到涉嫌违规的内容,点对应卡片右侧的“举报”按钮就能提交,我们会尽快核实处理;也谢谢你花一点时间,一起把这里维护干净。
LLM负责叙述,代码负责决策
最近看了不少“AI 用于可观测性”的方案,发现一个共同点:大家都把判断权交给了语言模型。给 LLM 喂告警、喂指标,问它“怎么了”、“怎么办”,然后让它下结论。这跟我实际用 LLM 的经验正好相反——我试过之后发现,把流程倒过来效果要好得多。
简单说就是:在我的告警处理流水线里,所有允许的分类都写死在 Python 代码里,模型只能从这些分类里选。LLM 的唯一工作就是把结构化的判定结果转化成一句人话。它从来不需要判断“这事是不是有问题”、“问题有多严重”,或者“这是哪类问题”。它只是在代码已经划好的决策空间里做翻译。
一句话总结:不让 LLM 判断告警出了什么问题,而是用确定性 Python 代码来做所有操作层面的决策,模型只负责用大白话解释结果。代码负责分类、验证、聚合;LLM 只负责叙述。这样数据一致性有保障,不会出现幻觉分类,就算模型挂了,监控流水线照样跑。
问题背景
我运营着一个托管监控服务。Alertmanager 一触发,webhook 就发过来,以前这 webhook 只会生成一条类似 HighMemoryUsage on host web-vm, severity warning 的记录。准确是准确,但没什么卵用。看告警的人还得自己琢磨:HighMemoryUsage 到底意味着什么?这台机器是不是一直跑得热?我到底要不要管?
我想给告警加上大白话的上下文解释,但又不想改动告警投递流程本身。最直接的想法当然是把整个告警扔给 LLM,让它解释。第一版实验我就是这么干的,心里预期是“可能不太准但凑合用”,结果还真没让我“失望”——模型表现得自信满满,但每次说的都不一样。
同样的告警,触发了三次,给出了三种不同的“根因分类”。第一次说“配置或设置问题”,第二次说“配置/测试”,第三次又变成了别的。如果你像我一样想把输出存下来做聚合分析(我想知道一周内是不是有三个不同客户遇到了同一类问题),这种自由格式的输出就是一团噪声。按一个模型随机变化的字段来做分组,根本行不通。
其实一开始我就隐约觉得这方法不太对劲,肯定比看起来要难。于是我去做了些研究,决定把设计翻过来。脑子里那个小声音一直是对的:别让模型做决策。
核心设计:硬分界线
我搞了个流水线,中间划了一条硬分界线。
确定性一侧:Python 负责分类。输出被限制在一个8值枚举里:
from enum import Enum
class AlertCategory(Enum):
MEMORY_PRESSURE = "memory_pressure"
CPU_SATURATION = "cpu_saturation"
DISK_PRESSURE = "disk_pressure"
SERVICE_UNAVAILABILITY = "service_unavailability"
NETWORK_ISSUE = "network_issue"
CONFIGURATION_ERROR = "configuration_error"
EXTERNAL_DEPENDENCY = "external_dependency"
UNKNOWN = "unknown"
我按这个字段做聚合,因为它永远只有这8个字符串之一。如果哪个都不匹配,就归为 unknown——这本身就是一个有用的信号,比模型瞎猜出来的变体强多了。
叙述一侧:LLM(我用的是 llama3:8b,跑在我自己局域网的一台机器上,数据/网络都安全)必须从那个固定的8值集合里选分类,同时写两个短字段:告警是什么(大白话),以及操作层面意味着什么。代码定义了答案的格式,模型只是填一个已经存在的槽位。我明确要求它不要提修复建议,不要编造原因——它做的是翻译,不是分析。
prompt 返回严格 JSON,受语法约束,所以我每次都能拿到 {what, means, likely_cause_class},并且枚举值在输出时会被校验是否在允许集合内。如果模型返回了列表之外的值,我就当 bug 捕获,而不是存一条记录。
上下文注入:别让模型瞎说
就算只是叙述这一步,naive 的做法也会产生危言耸听的文案。调系统的时候我收到一个 DiskFillPredicted 告警,光看表面确实值得查一查。但我去查了那台主机的指标,发现它的磁盘利用率几个月来一直是一条平线。这个“预测”其实是个四舍五入的假象——“你的磁盘快满了”这种说法极具误导性。模型光看告警本身根本不知道这个背景,所以就随便写了一句。
我的解决办法是:给模型提供人类在做出反应之前会看的上下文。在调用 LLM 之前,Python 会快速查询这台主机的指标后端,获取近期基线数据。prompt 里有一条明确规则:如果提供了历史上下文,优先考虑它而不是告警的字面文本。对于一个磁盘预测告警,如果主机基线几个月都没变,那就是信息性通知,不是紧急事件。
这个查询的延迟预算只有5秒。而 LLM 调用本身大约需要80秒——因为我故意跑在只有 CPU 的廉价硬件上:一台第四代 Intel i7,16GB 内存,没有 GPU。这是有意为之,不是没办法:整个服务的姿态就是数据不能离开我的局域网,所以慢的本地模型比快的远程模型更合适。
而且这80秒永远不会让被告警的人感知到。因为注释器是沿着现有路径“搭便车”的(下面会细说),原始告警会立刻出现在 Slack 和邮件里;带注释的版本大约一分钟之后作为单独的注释出现。没有任何东西在等模型。
相比80秒的 LLM 调用,5秒的预取开销不到7%,完全不可见。更重要的是:如果指标后端响应慢或不可达,系统会立即失败,回退到无上下文注入的路径——富化步骤永远不会阻塞结果投递。
故障关闭:注释器是锦上添花
这个回退思路贯穿整个流程:注释器是附加的,是“有更好,没有也行”的东西。Alertmanager 用 continue: true 路由到它,所以它跟现有的 Slack 和邮件投递流程是并行的,永远不会阻塞它们。webhook 永远返回 200,即使 LLM 机器挂了,或者 JSON 格式错误,也会用静态的 fallback 注释替代。
最坏的情况就是最终用户收到的告警文案没那么花哨,但绝不会漏掉任何一条告警。叙述功能是搭建在完全不依赖它的投递路径之上的一个附加服务。
经验教训(如果算的话)
“让模型叙述,别让模型分析”——这句话说起来容易,但真正难的是执行:把输出限制在一个可验证的固定集合里,让模型远离关键路径,这样模型挂了只会影响文案质量,不会导致丢告警。
模型的价值在于流畅性,而不是判断力。而流畅性恰恰是整个技术栈里最可替换的部分。把所有实际决策推到你可以测试的代码里,把任何将来要做聚合的字段都限制成枚举,把模型当作流水线里最后一个、也是最可替换的环节。如果你明天就能把模型换掉,而你的数据依然干净,那说明你把分界线画在了正确的位置。
我的这套系统已经在真实基础设施上跑了几周了。文案写得还不错——我确信等硬件升级、换上更强的模型之后会更好——但之所以我(暂时)信任它,是因为文案本身并不是那个做决策的东西。