筆記一直是程序員最重要的效率工具之一,幾乎每一代程序員都會試圖從自己的工作方式出發(fā),開發(fā)或改造一套屬于自己的筆記系統(tǒng),從最早的文本文件、Wiki,到 Word、印象筆記、Notion,本質(zhì)上都是在解決同一個問題:如何在高強度的信息處理環(huán)境中,保留可用的思考結(jié)果。但現(xiàn)實是,筆記系統(tǒng)始終是不夠好的,尤其是對每天需要處理大量文字、代碼和決策的人來說。
過去幾年我一直使用 Notion 作為主力筆記工具,常見的做法是開一個表格,每條記錄帶時間戳、鏈接和上下文說明,處理 bug 時在 icon ??上放一只小蟲子,把所有線索、想法、日志和代碼都塞進去,直到有一天我連續(xù)在電腦前工作了將近十二個小時,回過神來發(fā)現(xiàn)當天已經(jīng)產(chǎn)生了接近兩百條記錄。Notion 的每一條記錄本質(zhì)上都是一個可以無限展開的頁面,而不是 Excel 里的一個單元格,即便每一頁只有兩三千字,二百頁也已經(jīng)是四十萬字,這個規(guī)模早已遠遠超出人類在一天之內(nèi)能夠閱讀、理解和消化的極限,而且這并不是一次性的極端情況,而是逐漸變成了常態(tài)。
正是在這種背景下,我在最近幾周明顯進入了一種奇怪的狀態(tài):事情很多,但推進極慢,下意識回避工作,睡眠時間不斷拉長,再加上東岸連續(xù)的大雪,被困在家里幾天,又干脆出去玩了幾天雪,表面看像是怠工或逃避,但真實感受是一種深度的認知疲憊。與此同時,大語言模型變得異常強大,代碼、文檔、方案幾乎可以瞬間生成,但這種能力提升并沒有讓我成為一個更高效、更清醒的個體,反而帶來強烈的挫敗感,因為我發(fā)現(xiàn)這種狀態(tài)并不只發(fā)生在我身上,和一些朋友交流后,大家普遍都在經(jīng)歷類似的認知過載:個人能力被工具放大到一定程度之后,隨之而來的不是解放,而是更嚴重的反噬。
工業(yè)化語言生產(chǎn)機
回頭看,問題集中體現(xiàn)在三個方面:第一,信息和文本的生成規(guī)模已經(jīng)徹底超出人類的生理極限,這與個人能力強弱無關(guān);第二,生成速度過快,導致根本記不住自己看過什么,LLM 必須持續(xù)回答、持續(xù)發(fā)散、持續(xù)給路徑,卻從不提供“到此為止”的信號;第三,也是最致命的,是隱性漂移,狀態(tài)完全依賴窗口維持,窗口不斷疊加,幾天之后再回看幾天前的代碼,已經(jīng)無法理解當時的情境,同一個概念、腳本和索引在命名、路徑和 ID 上不斷漂移,vault_index、index_vault、inventory_index 之類的差異一路堆疊,幾周之后再看整個項目,只剩下一種徹底失控的感覺。
被雪困住的那幾天里,我反復思考這個問題,逐漸意識到這并不是個人管理能力的問題,而是機制層面的必然結(jié)果:LLM 本質(zhì)上是一個 zero-shot universe,幾乎零成本生成內(nèi)容,不會疲勞,不會猶豫,也不會做“是否值得繼續(xù)”的決策,prompt 只是軟約束,它沒有硬停機條件,它是一臺持續(xù)生產(chǎn)語言和符號的工業(yè)化機器,而人類的大腦并不具備相同的承載能力;漂移不是偶然,而是這種機制的必然產(chǎn)物,拉長上下文并不能解決問題,因為模型永遠只是在預測下一個 token,他要找不到最正確的答案他就給你猜一個;更重要的是,整個過程沒有責任主體,每天幾百上千次 prompt 強烈依賴當下環(huán)境,事后幾乎無法復現(xiàn),也無法追責。
這是一個治理Governance的問題
正是在這種情況下,我開始意識到,問題并不在于“記得不夠多”,而在于在這個時代,繼續(xù)沿用“多記一點總有用”的傳統(tǒng)筆記假設(shè),本身就是不可持續(xù)的。Notion 并不是沒有搜索功能,但當我真的需要解決一個具體問題、回溯自己過去的思考時,搜索出來的往往是成百上千條結(jié)果,其中大量內(nèi)容彼此沖突、語境缺失、時間錯位,幾乎無法直接使用,搜索本身并沒有降低認知負擔,反而把問題放大了。也正是在這個背景下,在這個 repo 連續(xù)開發(fā)了幾天之后,我又一次嘗試去重新搭建自己的記錄體系——這種嘗試其實已經(jīng)發(fā)生過很多次,絕大多數(shù)都以失敗告終,但這一次我明顯感覺到有些地方開始對路了,至少已經(jīng)值得寫出來和別人分享。關(guān)鍵并不在于我是否找到了一個“更好的工具”,而在于我發(fā)現(xiàn),這根本不是工具層面的問題,而是人在這個階段不可回避地遭遇了自身的生理與認知約束。一方面,我確實需要一個更貼合我個人工作方式的系統(tǒng),但另一方面,更重要的是必須把注意力放回真正的核心問題上:這個問題既不是筆記,也不是程序,更不是靠一個軟件、一個庫就能一次性解決的工程問題,它的核心只有一個——知識的治理。
這是個Governance的問題。
簡單說,“知識的治理”是什么意思?從更大的尺度看,人類社會中幾乎所有真正困難的問題,本質(zhì)上都是治理問題。政治是治理問題,國家如何被治理;法律是治理問題,立法、司法、執(zhí)法如何分工與約束;憲法本身也是治理問題,不只是寫下來,而是如何被解釋、如何被遵守、如何保證它真的被遵守。把尺度縮小,團隊管理、制度設(shè)計、流程約束,同樣是治理問題,而不是工具問題。治理的核心從來不在于“有沒有信息”“能不能訪問”,而在于哪些東西被承認為有效、哪些判斷具有權(quán)威、哪些狀態(tài)可以進入長期記憶、哪些必須被限制、凍結(jié)或廢棄。
回到個人層面,所謂“知識管理”的真正難點也在這里:不是信息不夠,不是搜索不強,而是缺乏一套能夠裁決、約束和負責的機制。正因為如此,這個問題其實已經(jīng)被無數(shù)程序員反復嘗試解決過,從早期的個人知識庫、標簽系統(tǒng)、到后來的雙鏈、圖譜、向量化檢索,再到 Obsidian、各種語義搜索和 AI 助手,它們解決的更多是“如何找到內(nèi)容”“如何關(guān)聯(lián)內(nèi)容”“如何生成內(nèi)容”,但幾乎都默認了一個前提:內(nèi)容一旦寫下,就天然具有價值,只要存得住、搜得到,就算成功。這個解決方案和各種開源項目到處都是,我自己也是借鑒了的。我現(xiàn)在也是把內(nèi)容全部存成 .md文檔,obsidian vault可讀。But this is not the point!
在信息和生成能力遠低于今天的年代,搜到就賺到。但在一個內(nèi)容可以零成本爆炸式生成的時代,這個前提本身已經(jīng)失效了。真正缺失的并不是更聰明的搜索算法,也不是更復雜的表示方式,而是一套能夠回答“什么可以被承認為知識”“什么只是過程噪聲”“什么需要被追責”“什么必須可復現(xiàn)”“什么不允許悄然漂移”的治理結(jié)構(gòu)。
所以,我說說我現(xiàn)在自己嘗試的這種方案,這個repo,雖然開始沒多久,但是我感覺這個方向很行。如果你有這個需求,也許我能啟發(fā)一些目前同樣困擾的人。
一個Sovereign Log, 簡單代碼,昂貴寫入,沒有接LLM,后期可以接,幫我定住我最核心的認知。
不是為了高頻記錄而設(shè)計的,恰恰相反,它刻意讓寫入變得昂貴、緩慢和需要思考;它的實現(xiàn)保持在盡可能簡單的代碼層面,不依賴復雜系統(tǒng),也不直接接入 LLM,因為一旦接入,零成本生成就會立刻侵蝕它作為“裁決記錄”的性質(zhì)。現(xiàn)階段都是硬編碼。我先簡單說說都包括啥,現(xiàn)在連UI都沒有,就已經(jīng)簡單的解決了我大量的問題。
├── _system
├── docs
├── inbox
├── requirements
├── sovereign_log
├── templates
└── tools
這里面有兩個.md組成的文本庫,一個是sovereign_log,另一個是doc。
Sovereign_log
當然,一切并不是從一個宏大的系統(tǒng)開始的。我最初建立的只是一個極小、極其克制的 vault,它的起點和任何一個普通的 Obsidian vault 并沒有本質(zhì)區(qū)別。如果你看到它的 graph,會發(fā)現(xiàn)幾乎沒有什么結(jié)構(gòu)特征:沒有刻意構(gòu)建的 backlink,沒有主題網(wǎng)絡(luò),也不追求連接密度。唯一真正不同的地方在于數(shù)量——極少。這是一個被我刻意維持的約束。在這個 vault 里,每一篇內(nèi)容都不是草稿,不是“先寫下來再說”,而是經(jīng)過反復推敲的結(jié)果。我會與 AI 多輪對話,壓縮表達、校正邊界、澄清含義。早期我主要使用英文寫作,同時輔以少量中文翻譯,是作為一種語義校驗手段,用來確認我是否真正理解了自己寫下的東西。隨著系統(tǒng)成熟,這個 vault 很可能會完全切換為英文。這個階段的 Sovereign_Log,本質(zhì)上是一個高度精煉、完全由個人主權(quán)控制的知識集合,其核心原則非常簡單:不要亂寫,不要當成草稿,數(shù)量不是越多越好,而是越精良越好。有時一整天的思考、推演和結(jié)構(gòu)對齊,最終只會留下 1–2 篇筆記,是一種有意為之的熵控制。你一定要維持這種紀律,否則又跟你其他筆記一樣,照搬過來一大堆東西。
![]()
Doc
Doc 在形式上依然是“筆記”,但它并不是 Sovereign_Log 的自然延伸,而是一次明確的躍遷。Doc 中的內(nèi)容并非寫得更正式,而是被提升過的文本,處于一種介于敘事語言與可執(zhí)行代碼之間的 IR 狀態(tài)。它們尚未成為代碼,但已經(jīng)不再允許自由敘述。在設(shè)計這個知識庫時,我刻意引入了“昂貴性”這一反直覺原則,用來對抗大語言模型生成文字與代碼過快、過多的問題。我認為,真正進入知識庫核心層的內(nèi)容,必須在制度上是昂貴的,而不是在情緒或表達上顯得復雜。這種昂貴性體現(xiàn)在三個層面。
首先是格式昂貴。Doc 不是自由文本,任何內(nèi)容想要進入這一層,必須滿足固定結(jié)構(gòu)并通過機器可執(zhí)行的格式檢查。確保這些文本在原則上是可解析、可索引、可審計、可約束的。一篇格式不合格的內(nèi)容是根本不具備進入該層的資格。
其次是流程昂貴。內(nèi)容不能一開始就進入 Doc,它必須先在 Sovereign_Log 中存在,經(jīng)過時間沉淀,在真實使用中反復被搜索、引用、轉(zhuǎn)化為代碼或決策,逐漸顯現(xiàn)出對系統(tǒng)行為的實際影響,才會成為候選項,并在明確授權(quán)后被提升進入 Doc。這一機制在未來引入團隊共享知識庫時尤為關(guān)鍵,因為它明確阻斷了任何人、任何模型、任何一時興起的想法對核心知識層的直接污染。Doc 被視為一種稀缺資源,而不是存放“整理后內(nèi)容”的地方。
第三,也是現(xiàn)階段最重要的一點,是語義昂貴。我對 Doc 的核心要求并不是表達清晰或邏輯自洽,而是語義必須達標。所謂語義達標,意味著條文之間不能互相矛盾,不允許隱含沖突,不允許模糊責任與邊界,每一條聲明都必須具備生成 binding 代碼的潛力。我觀察過許多文檔規(guī)模龐大的知識庫,它們的共同問題并不是信息不足,而是語義雜亂、定義漂移、條文沖突,最終無法轉(zhuǎn)化為真實可執(zhí)行的系統(tǒng)約束。這樣的知識庫看似厚重,實則不可執(zhí)行。而 Doc 的目標恰恰相反:每一條文本,都是潛在的系統(tǒng)約束;每一條語義,都是未來代碼的來源。因此,語義本身也必須進入可被機器介入和審計的范圍。
├── docs
│ ├── decisions
│ ├── governance
│ │ ├── CLAIM-AUTHORING-STYLE-V0-1.md
│ │ ├── EVIDENCE_SUGGEST_AUDIT.md
│ │ ├── RPT-2026-01-26-RUNTIME_ENV_GOVERNANCE.md
│ │ ├── SD-0007_RUNTIME_ENV_FREEZE.md
│ │ ├── SD-0008_INDEX_CONSOLIDATION.md
│ │ ├── SD-0009_DOC_IR_SPEC_v0.md
│ │ ├── SD-0010 — Normative Boundary & Semantic Consistency Rules
│ │ ├── SD-0011_ID_Taxonomy_and_Identity_Ledger.md
│ │ └── SD-0012 — Observability Causal Structure & Span Identity
│ ├── invariants
│ │ ├── INV_CATALOG_v0.md
│ │ ├── INV_DOC_IR_BOOTSTRAP_v0.md
│ │ └── INV_INDEX_ROOTS_0001.md
│ ├── Machine-Checkable Invariants.md
│ ├── runs
│ ├── SD-0001-System-Constitution.md
│ ├── SD-0002-Derived-Artifact-Path-Freeze.md
│ ├── Sovereign Log — Write Protocol v1.0.md
│ ├── stage_contracts
│ │ └── PRE_STAGE_5.md
│ └── taxonomy
│ ├── INDEX_TYPES.md
│ └── TDES.md
我現(xiàn)在的系統(tǒng)是完全沒有接入任何 LLM 的,至少在這一層沒有。這些約束、篩查和升級機制,全部是在代碼層面完成的。我一直相信,如果你是一個看到這里的程序員,并且你覺得這套方法對你有借鑒意義,那么它在技術(shù)上并不復雜,甚至可以說是非常直白的工程實現(xiàn)。這里我不展開具體代碼細節(jié),只用一個非常具體的例子來說明我所謂的“語義昂貴”到底是什么意思。
以語義篩查為例。我每次跑 audit,通常都會順手生成兩份報告:一份是給機器繼續(xù)消費的 JSON,一份是給人看的 Markdown。下面這段就是我某一次跑出來的語義審計報告摘要。
這次 audit 的標識是 AUDITDOCSEMANTIC — 20260130T205405Zdocsemantic_audit,整體結(jié)果是 ok: False,意味著這次檢查在制度上是不通過的。系統(tǒng)掃描了 docs 目錄下的文檔,共識別出 77 條 claims,使用的是基于 embedding 的相似性與語義模式匹配(這里用的是 all-MiniLM-L6-v2,閾值 0.92,top-k 為 8,最大配對 200)。需要特別說明的是,這里對 modality、target、predicate 的推斷仍然是啟發(fā)式的,屬于 v0.1 階段,這一點在 meta 里是明確寫出來的,后續(xù)會被提升為顯式的結(jié)構(gòu)化 claim tags。也正因為如此,重復或沖突在默認情況下只是 warning,但在這次配置里,我把沖突嚴重性提升為了 error,要求必須被解決。
真正關(guān)鍵的是下面這條 violation:SEM-CNF-001。它指向的是一個語義沖突,而且不是模糊沖突,而是非常具體的 modality 沖突。系統(tǒng)檢測到,在兩個不同的文檔中,針對同一個 (target, predicate) 組合——也就是 ('GLOBAL', 'evidence')——出現(xiàn)了相互矛盾的規(guī)范性斷言:一條是 must,另一條是 must_not。沖突來源被精確定位到了 SD-0011#C-0004 和 DOC-EVIDENCE-SUGGEST-AUDIT-V1#C-0003 這兩條具體的 claim 上。這意味著,在當前 Doc 層的語義空間中,系統(tǒng)同時被告知“這件事必須發(fā)生”和“這件事必須不能發(fā)生”,而且兩者作用域完全一致。
這類錯誤在我的系統(tǒng)里是不可接受的。一旦這樣的語義進入核心 Doc 層,任何試圖從中生成 binding 代碼、策略或運行時約束的行為,都會立刻失去確定性。因此 audit 是直接要求你做出選擇。hint 里給出的路徑也非常明確:要么通過既定的優(yōu)先級體系來裁決(例如 INV 高于 SD,高于 taxonomy),要么明確使用 supersede 機制,讓其中一條 claim 在制度上失效。這是哪一條規(guī)則在系統(tǒng)中繼續(xù)存活的問題。
對我來說,這正是“語義昂貴”的具體體現(xiàn)。不是靠人腦記住“這里好像有點矛盾”,而是讓系統(tǒng)在 Doc 層直接拒絕語義不閉合、不一致、不可執(zhí)行的狀態(tài)。也正因為有了這樣的機制,Doc 才不再是一個“寫得很嚴肅的文檔集合”,而是真正開始具備約束未來代碼與系統(tǒng)行為的資格。
AUDITDOCSEMANTIC — 20260130T205405Zdocsemantic_audit
ok: False
violations: 1
Meta
"docs_dir": "docs",
"claims_count": 77,
"dup_threshold": 0.92,
"topk": 8,
"max_pairs": 200,
"dup_severity": "warn",
"model": "sentence-transformers/all-MiniLM-L6-v2",
"notes": [
"v0.1 modality/target/predicate inference is heuristic; promote to structured claim tags later.",
"duplicates are warnings by default; set --dup_severity error to hard-enforce."
Violations
1. SEM-CNF-001 (error)
path: docs/governance/SD-0011_ID_Taxonomy_and_Identity_Ledger.md | docs/governance/EVIDENCE_SUGGEST_AUDIT.md
message: Modality conflict (must vs must_not) on (target,predicate)=('GLOBAL','evidence'): SD-0011#C-0004 vs DOC-EVIDENCE-SUGGEST-AUDIT-V1#C-0003
hint: Resolve via priority (INV > SD > TAXONOMY ...) or supersede one of the conflicting claims.
meta: 46502865b8712493e52dffd4a6b6871cd994c162f900ea8e6e7a8c3ebbcb5873
怎么實現(xiàn)的
從技術(shù)實現(xiàn)上講,這套機制并不依賴大語言模型,也不需要任何“智能理解”。它的核心思想是:把文檔的語義壓縮成一組可計算、可比較、可失敗的結(jié)構(gòu)化要素,然后用一套完全確定性的規(guī)則對這些要素做審計。整個系統(tǒng)可以拆解為幾個相對獨立的技術(shù)層,你可以按需要取用或替換其中任意一層,而不影響整體成立。
第一步是聲明式語義單元的引入。文檔不再被當作一整塊自然語言,而是被要求顯式標注最小治理單元——也就是穩(wěn)定編號的 claim。它們本質(zhì)上等價于“規(guī)范性斷言”,每一條都是一個潛在的系統(tǒng)約束。實現(xiàn)上不需要復雜解析器,只要用簡單、魯棒的文本模式(例如固定前綴或行結(jié)構(gòu))就可以穩(wěn)定抽取。這一步的關(guān)鍵不是解析能力,而是強迫作者在寫作階段就做出“這是我要被系統(tǒng)治理的句子”的選擇。
import re
from dataclasses import dataclass
CLAIM_RE = re.compile(r"(?m)^\\s*-\\s*(C-\\d{4})\\s*:\\s*(.+?)\\s*$")
@dataclass
class ClaimRaw:
claim_id: str
text: str
def extract_claims(md: str) -> list[ClaimRaw]:
out = []
for cid, txt in CLAIM_RE.findall(md):
out.append(ClaimRaw(claim_id=cid, text=txt.strip()))
return out
復現(xiàn)要點:你只需要一個穩(wěn)定、可被 grep 的寫作格式(比如 - C-0001:)。解析就能保持極簡。
第二步是規(guī)范性強度(modality)的離散化。系統(tǒng)并不嘗試理解句子的全部含義,而是只關(guān)心它在制度上的態(tài)度:是必須、禁止、允許,還是無法判定。這可以通過一組確定性的關(guān)鍵詞或規(guī)則完成,而不是統(tǒng)計模型。重要的是,這一步把“模糊的自然語言語氣”壓縮成一個有限集合,使得后續(xù)沖突判斷變成一個有限狀態(tài)問題,而不是語言理解問題。
import re
MODALITY_RULES = [
("must_not", re.compile(r"\\b(must not|shall not|forbidden|prohibited|not allowed)\\b", re.I)),
("must", re.compile(r"\\b(must|shall|required|mandatory)\\b", re.I)),
("forbid", re.compile(r"\\b(forbid|prohibit|disallow|deny)\\b", re.I)),
("allow", re.compile(r"\\b(allow|permit|allowed)\\b", re.I)),
def infer_modality(text: str) -> str:
for name, rx in MODALITY_RULES:
if rx.search(text):
return name
return "unknown"
復現(xiàn)要點:這不是 NLP,是可審計的規(guī)則表。你可以按你組織的寫作詞匯(MUST/SHALL/禁止/允許)擴展規(guī)則。
第三步是約束對象(target)的錨定。為了避免所有規(guī)則都在一個全局空間里相互干擾,系統(tǒng)需要一個機制,把每條 claim 映射到一個明確的約束對象上。實現(xiàn)方式可以非常簡單,例如通過顯式標注、路徑前綴、資源名或作用域標識符。只要這個 target 是穩(wěn)定、可比較的,就足夠用于治理。未能明確錨定的規(guī)則,可以被保守地歸入全局作用域,從而承擔更高的沖突風險,這本身就是一種設(shè)計激勵。
import re
BACKTICK_RE = re.compile(r"`([^`]+?)`")
def infer_target(text: str) -> str:
# Prefer explicit anchors like `docs/` `_system/` `sovereign_log/`
for m in BACKTICK_RE.finditer(text):
tok = m.group(1).strip()
if tok.startswith(("docs/", "_system/", "sovereign_log/")):
# collapse file path to a directory-ish prefix for stability
parts = tok.split("/")
if len(parts) >= 2:
return parts[0] + "/" + parts[1] + "/"
return parts[0] + "/"
return "GLOBAL"
復現(xiàn)要點:你要的不是“精準路徑”,而是穩(wěn)定可比對的 target key。寫作上用 backticks 做顯式錨點,工程上就能把 GLOBAL 降到最少。Global會給你很多的false positive, 沒完沒了的修。其實一般的claims都是針對特定域的,你不會動不動就寫一個“我這條整個系統(tǒng)都必須通用。”
第四步是謂詞維度的粗分類(predicate)。這是為了避免不相關(guān)的規(guī)則在同一 target 上產(chǎn)生誤報沖突。系統(tǒng)并不需要一個完整的本體論,只需要一個非常小、可擴展的謂詞集合,用來區(qū)分“這是關(guān)于存放位置的規(guī)則”“這是關(guān)于權(quán)限或權(quán)威性的規(guī)則”“這是關(guān)于證據(jù)或生成機制的規(guī)則”等。這一步同樣可以通過關(guān)鍵詞或標簽完成,其目標是縮小沖突比較的語義空間,而不是追求精細分類。
def infer_predicate(text: str) -> str:
t = text.lower()
if any(w in t for w in ["authoritative", "canonical", "binding", "truth layer"]):
return "authority"
if any(w in t for w in ["faiss", "semantic index", "vault_index", "index root", "index output"]):
return "index"
if any(w in t for w in ["write to", "stored under", "must exist only at", "reside at", "live under"]):
return "placement"
if any(w in t for w in ["admitted", "accepted", "effective", "governance-valid"]):
return "admission"
if any(w in t for w in ["evidence", "ingest", "payload", "manifest"]):
return "evidence"
return "general"
在完成上述四個要素之后,每一條文檔聲明在系統(tǒng)中都會被壓縮成一個結(jié)構(gòu)化記錄:(modality, target, predicate)。到這里,文檔已經(jīng)不再是自然語言集合,而是一個可以被機器枚舉、分組和比較的約束集合。
基于這個結(jié)構(gòu),語義沖突檢測就變成了一個純規(guī)則問題:在同一個 (target, predicate) 空間內(nèi),是否同時存在互斥的規(guī)范性態(tài)度(例如 must 與 must_not,allow 與 forbid)。一旦出現(xiàn)這種情況,系統(tǒng)可以直接判定為不可執(zhí)行狀態(tài),并給出精確到聲明級別的沖突定位。這里不涉及概率、不涉及模型判斷,也不需要人工解釋,沖突即失敗。
在此之上,可以疊加一個近似重復檢測層,用于發(fā)現(xiàn)語義上高度相似、但尚未構(gòu)成直接沖突的聲明。這一層可以使用任何向量化或相似度技術(shù)來實現(xiàn),其角色更接近于“治理衛(wèi)生檢查”,而不是硬約束。是否將其視為警告還是錯誤,完全取決于你對系統(tǒng)嚴格程度的要求。
整個審計流程的輸出應當是機器優(yōu)先的:結(jié)構(gòu)化結(jié)果用于后續(xù)自動化處理,人類可讀報告用于審查與決策。關(guān)鍵在于,審計必須能夠失敗,并且失敗應當通過明確的進程退出、狀態(tài)標志或流水線信號向外傳播,這樣文檔治理才能真正進入工程系統(tǒng),而不是停留在規(guī)范建議層。
如果你想在自己的系統(tǒng)中復現(xiàn)這一機制,并不需要復制具體實現(xiàn)。你只需要確認幾件事:你是否愿意引入顯式的聲明式語義單元;你是否愿意接受把自然語言壓縮為有限語義維度所帶來的約束;以及你是否愿意讓“文檔語義不一致”像代碼編譯錯誤一樣中斷流程。一旦這三個問題的答案都是“是”,那么無論你使用哪種語言、哪種工具、哪種存儲結(jié)構(gòu),這套“語義昂貴”的文檔治理模式都可以被復現(xiàn)出來。
為什么不引入大模型?當然我后期肯定會引入的。但是現(xiàn)在我需要搭建一個完全斷開大模型的基層。這個原因我覺得讀到這里的人應該都能大概理解。因為你想要的是歷史與治理必須由確定性機制承擔,模型只能作為建議者,而不能成為裁決者。失敗條件是穩(wěn)定的,系統(tǒng)邊界是清晰的。這件事情目前讓我感覺上就舒心很多。
硬編碼就萬能嗎?當然不是!它覆蓋不了復雜語義。關(guān)鍵詞、規(guī)則表、枚舉謂詞,本質(zhì)上都是低分辨率的認知壓縮。它無法理解隱喻、上下文、反諷,也無法自動適應新的表達方式。硬編碼會顯得笨、慢、保守。每加一個 predicate、每調(diào)一個規(guī)則,都需要人來做判斷。這在早期看起來效率很低。但我恰恰需要這種“慢”。它是一種摩擦機制,用來對抗“生成過快”的系統(tǒng)風險。在一個可以一秒鐘生成一百條規(guī)則的時代,慢本身就是一種安全設(shè)計。它迫使規(guī)則的作者為進入核心層付出認知成本。這也是我認為程序員容易陷入的一種精神陷阱,就是很容易把自己抽離。認為自己不是系統(tǒng)機制的一部分。我個人反而因為現(xiàn)在大量自己做項目,容易理解這種“自身必須帶入,自身必須收到約束”的想法。
核心當然是Vault Index and Query
好,我們先把系統(tǒng)總圖停在這里,剩下的那些“細枝末節(jié)”(derived 層怎么落盤、怎么隔離、各種 tools/templates、審計與報告的目錄法、生命周期與清理策略)確實規(guī)模很大,但它們本質(zhì)上都是工程衛(wèi)生問題:只要你的邊界清楚(Truth / Decision / Evidence / Derived),再加上寫入權(quán)限與路徑約束,技術(shù)實現(xiàn)不會難,更多是“制度一致性”和“長期可維護性”的問題。
我這里真正想展示的,是我的 vault_indexer:它不是一個“更好用的搜索”,而是一個把筆記系統(tǒng)變成證據(jù)底座(evidence substrate)的索引機制。現(xiàn)在幾乎所有筆記應用遲早都會走到“語義檢索 + chunk”這條路,但我在做的時候發(fā)現(xiàn),決定它最終價值的不是檢索本身,而是你如何組織證據(jù) chunk、如何讓它們具備可引用、可復現(xiàn)、可審計的屬性,以及最關(guān)鍵的:這個索引產(chǎn)物在你的系統(tǒng)里到底處于什么層級(Truth 還是 Derived)。
我的做法是把索引嚴格定位為 Derived:它永遠不擁有“真理權(quán)”。它只負責把 docs/、sovereign_log/ 這些文本資產(chǎn),編譯成一個面向檢索的中間產(chǎn)物:把文檔切成穩(wěn)定粒度的 chunks(通常是段落級或標題-段落組合級),為每個 chunk 生成穩(wěn)定標識(chunk_id)、保留來源路徑、heading/段落位置、以及內(nèi)容哈希(或可追溯的 digest)。然后對 chunk 文本做 embedding,構(gòu)建向量索引(FAISS 或同類),最終讓你可以用自然語言 query 去命中一組證據(jù) chunks。注意這里“證據(jù)”不是泛指相關(guān)文本,而是具備引用結(jié)構(gòu)的對象:每個 chunk 都能被精確地指向、被復制到 evidence pack、被后續(xù)工具鏈復用,甚至被審計系統(tǒng)要求“你生成的結(jié)論必須引用這些 chunk_id”。
這就直接解釋了為什么 LLM 在我這里不是“寫作機器”,而是“最佳 query 手”。LLM 的強項不是憑空生成,而是:把一個模糊問題拆解成可檢索的子問題、構(gòu)造有效 query、對返回的證據(jù)進行結(jié)構(gòu)化歸納,并把歸納結(jié)果映射回開發(fā)動作(改哪個文件、加哪個 invariant、補哪個 claim、寫哪個 diff)。當你已經(jīng)建立了信息底座——也就是把核心原則、邊界、約束、歷史責任都凍結(jié)在 Doc / Sovereign_Log 里——LLM 最合理的用法就是站在索引之上,做“證據(jù)驅(qū)動的開發(fā)協(xié)作”。你問一個問題,它先檢索,再給你一個帶引用的證據(jù)包(JSON/MD),你再用這個證據(jù)包去推進決策與代碼,而不是讓它用記憶和幻覺替你編故事。
也因此,我的方法和很多以“搜索”為核心的 Obsidian 插件有一個結(jié)構(gòu)性差異:大多數(shù)插件的目標是“更快找到筆記”,而我的目標是“讓檢索結(jié)果成為可治理的證據(jù)對象”。插件式搜索通常停留在 UI 體驗層:關(guān)鍵詞或語義匹配 → 打開筆記 → 人腦判斷;它們很少解決這些問題:檢索命中的內(nèi)容有沒有穩(wěn)定引用?是否能在 CI/審計里復現(xiàn)同一個結(jié)果?檢索產(chǎn)物是否會被錯誤地當成權(quán)威?能否形成“問題 → 證據(jù) → 決策 → 代碼 → 回寫證據(jù)”的閉環(huán)?而我的 vault_indexer 把檢索的輸出直接做成一種可落盤、可版本化、可再利用的中間態(tài)(pack / report / audit),并且明確把它放在 Derived 層:它可以被重建、可以被替換模型、可以被清理,但不能反向污染 Truth/Doc 的權(quán)威性。
換句話說:很多筆記插件把搜索當作“閱讀入口”,我把索引當作“開發(fā)輸入口”。前者優(yōu)化的是找筆記,后者優(yōu)化的是把筆記變成工程證據(jù),讓 LLM 以“證據(jù)分析器 + query 編譯器”的身份參與開發(fā)。這也是為什么當你的系統(tǒng)底座一旦穩(wěn)定(規(guī)則、邊界、歷史責任明確),索引檢索就不再是錦上添花,而會變成你推進長期工程的主引擎:你不是在“寫更多筆記”,你是在用檢索把過去的制度與證據(jù),持續(xù)地喂回現(xiàn)在的決策與代碼。
廢話不多說,直接給你看證據(jù)。
我們先從一份非常真實的 query_vault 結(jié)果說起。需要先說清楚一個前提:這個系統(tǒng)現(xiàn)在還在早期階段,它不是那種“裝完就立刻很神”的工具。它需要你在真實項目中長期使用、長期維護,并且真正把它當成核心系統(tǒng)來用,才會逐漸成長為你自己的“第二大腦”。在這個階段,檢索結(jié)果的 score 普遍不會特別高,這是正常現(xiàn)象。對我現(xiàn)在的庫來說,0.7 已經(jīng)算是相當不錯、可以認真閱讀的命中率了。
原因很簡單:語義索引的質(zhì)量,最終取決于你往里放了什么。你需要一邊做真實的開發(fā)、一邊寫真實的規(guī)則、一邊不斷用“已經(jīng)被你驗證過的優(yōu)質(zhì)內(nèi)容”去填充這個庫;同時還要持續(xù)升級、清理和維護。這個過程是累積性的:越用越好用,越用越省心,而不是一開始就給你“標準答案”。這才是第二大腦應有的成長方式。
從結(jié)構(gòu)上看,一次 query_vault 的 run,本質(zhì)上只是一個可復現(xiàn)的檢索結(jié)果對象。它并不試圖直接回答問題,而是把“當時系統(tǒng)認為可能相關(guān)的證據(jù)”列出來。這個對象里最重要的幾個字段是:
run_id:這次檢索的唯一標識。你可以把它當成一次“證據(jù)采樣”的編號,后續(xù)可以落盤、歸檔、甚至被審計。
query:你當時輸入的原始問題,用于回溯“當時你在想什么”。
model:用于向量化的 embedding 模型,它定義了“相似”的數(shù)學意義。
results[]:真正的核心內(nèi)容——chunk 級別的命中結(jié)果,而不是文件級搜索。
每一條 result,都不是“這篇文檔命中了”,而是“這一個具體段落(chunk)被認為相關(guān)”。因此,每條 result 都帶著一組對工程師來說非常關(guān)鍵的元信息:
chunk_id:這個段落的穩(wěn)定身份。后續(xù)引用證據(jù)時,你引用的是它,而不是“我記得哪篇文檔里有一句話”。
note_path / heading_path / paragraph_index:用于精確定位原文位置。
hash:該段落內(nèi)容的哈希,用來保證“你現(xiàn)在看到的證據(jù)”和“未來審計時看到的證據(jù)”是同一段文字。
mtime:最后修改時間,幫助你判斷新舊、是否存在語義漂移風險。
score:相似度分數(shù),只是排序信號,不是“正確性”或“權(quán)威性”的度量。
snippet:展示用的截斷文本,只能當預覽,不能當證據(jù)全文。
所以你要對這個結(jié)果有一個非常清醒的認識:
它是一份**“可引用的檢索命中清單”**,而不是“已經(jīng)回答你問題的證據(jù)”。
接下來才是關(guān)鍵:你問的是什么問題?你希望這份證據(jù)幫你解決什么?
在這次 query 里,問題是:
run session trace ordering
這并不是在問“Run、Session、Trace 分別是什么”,而是在做一次圍繞Run / Session / Trace 的存在順序與合法性(ordering & existence constraints)的證據(jù)檢索。
換句話說,這是一個非常“硬”的問題。你真正關(guān)心的不是定義,而是:
哪些推斷是被系統(tǒng)明確禁止的?
哪些順序關(guān)系必須顯式聲明,而不能從時間或結(jié)構(gòu)中“猜”出來?
這也是為什么這次命中的 chunk,即便 score 只有 0.6~0.7,依然是高價值證據(jù)。比如:
明確禁止從 trace 連續(xù)性推斷 session 存在
明確禁止用時間順序替代 run / session 的顯式聲明
明確要求 trace 必須綁定到合法 session,否則就是 non-legitimate
明確區(qū)分 Run / Session / Trace 各自回答的問題域
這些內(nèi)容并不是“百科式解釋”,而是制度級約束。它們的價值不在于“講清楚概念”,而在于防止你和 LLM 在開發(fā)過程中犯錯。
這也正好引出了 LLM 在這里的正確角色定位。
在這個系統(tǒng)里,LLM 不是用來腦補解釋的,而是一個“證據(jù)分析器”。它不應該看到 snippet 就開始編故事,也不應該試圖用時間順序、因果敘事去“合理化”缺失的結(jié)構(gòu)。相反,它應該被這些 chunk 錨定住行為邊界:
這些推斷是被明確禁止的 → 不要做
這些關(guān)系必須顯式聲明 → 如果缺失,就指出缺口
如果規(guī)則已經(jīng)存在但沒有被完美回答 → 就用已有證據(jù)做錨,而不是重新發(fā)明規(guī)則
即便這個問題在你的系統(tǒng)里還沒有一個“教科書式的最終答案”,0.7 分左右的證據(jù)依然有巨大價值:它為 LLM 提供了方向約束,防止概念漂移,防止在日常開發(fā)中慢慢把系統(tǒng)“想歪”。
這就是我做這套 vault_indexer + query 機制的初衷:
不是讓檢索直接給你答案,而是讓它在你和 LLM 之間,持續(xù)提供一個可以被引用、被校驗、被審計的證據(jù)錨點。只要這些錨點是穩(wěn)定的,你的系統(tǒng)就不會在長期使用中悄悄變形。
"run_id": "20260131T014112Z_query_vault_b52ba27830",
"query": "run session trace ordering",
"scope": {
"note_path_prefix": null
},
"topk": 12,
"per_note_cap": 2,
"exclude_temporal_note": false,
"model": "sentence-transformers/all-MiniLM-L6-v2",
"results": [
"chunk_id": "f91b794ab50cc20b12ee18d2a74a532ed5b0630d",
"note_path": "docs/governance/SD-0011_ID_Taxonomy_and_Identity_Ledger.md",
"heading_path": "",
"paragraph_index": 65,
"hash": "ed7cc7a84aa209ae63eb30ef531ab5cfd5cb0a649b8b98da78db3c9d3cf0f73c",
"mtime": 1769822404.9170113,
"score": 0.7674295067787171,
"snippet": "- Trace continuity MUST NOT be used to infer the existence of a session. - Session existence MUST NOT be inferred from trace structure. - Time ordering alone MUST NOT substitute for explicit run or session declaration.",
"boost": {
"prefix": "docs/",
"factor": 1.1
},
"chunk_id": "74abc9e9857e9ee0f805584d3b95dee8c0142f29",
"note_path": "sovereign_log/Session-Run-Trace-Formal Definitions.md",
"heading_path": "",
"paragraph_index": 29,
"hash": "f08025c0500946d913c04bbecbb5ee1ed106120b5d9ecc3f21d9a5254395578b",
"mtime": 1769737995.4226983,
"score": 0.6208187341690063,
"snippet": "- A Run **must exist** before any Session. - A Session **must exist** before Events are promoted. - A Trace **must exist** for any causal claim. - Time ordering **must never replace** trace structure."
},
"chunk_id": "8c355b0da6ce66924ec7fdb83adc71dc6a4e17d7",
"note_path": "docs/governance/SD-0011_ID_Taxonomy_and_Identity_Ledger.md",
"heading_path": "",
"paragraph_index": 60,
"hash": "c056ccfc21a6cd4e9352ed599b679a0018f95bbf828fd0f017fdb9ff6af51c90",
"mtime": 1769822404.9170113,
"score": 0.5683699011802674,
"snippet": "- A `trace_id` MUST be associated with a valid `session_id`. - Trace-level artifacts that lack an explicit session binding are non-legitimate.",
"boost": {
"prefix": "docs/",
"factor": 1.1
},
"chunk_id": "b8ecd51c38bb6cffceb35546af4f27176d67027d",
"note_path": "sovereign_log/Session-Run-Trace-Formal Definitions.md",
"heading_path": "",
"paragraph_index": 32,
"hash": "32a2b22ffaf1ffcabcb49924a30bdcbbf00c46b052403ca5ea32e9ad1739b0c6",
"mtime": 1769737995.4226983,
"score": 0.5365391969680786,
"snippet": "> **Run answers “which execution.” > Session answers “which lifecycle.” > Trace answers “why.”**"
},
我們現(xiàn)在已經(jīng)非常的操之過急的,習慣于,每次自己有什么問題,馬上寫prompt,馬上要得到答案。然而LLM又非常善于給你編織“完美答案”。這是非常危險的。這就是漂移的根源。
如果你考慮自己弄一個,那么可參考兩個核心腳本:index_vault.py; query_vault.py
代碼層面的復現(xiàn)其實并不難,真正的難點也不在代碼本身,而在于你是否愿意接受這樣一套知識治理制度。在現(xiàn)階段,我是刻意不把 LLM 接入系統(tǒng)執(zhí)行鏈路的。我只會把已經(jīng)生成好的證據(jù)(evidence packs)和審計報告,交給 LLM 去“解釋”和“建議”。無論你是在交互窗口里用 LLM,還是將來把它接入系統(tǒng)內(nèi)部,這一點在本質(zhì)上并不會改變:LLM 的強項是理解問題、組織合適的 query、并在你提供的證據(jù)約束下給出建議,而不是替你決定什么是真理。真正決定系統(tǒng)質(zhì)量的,是你如何看待證據(jù)、如何讓知識變得可治理。這是我目前非常明確的立場。
因此,這套東西并不是“一個搜索腳本”,而是一個最小可用的 Evidence Retrieval Substrate。它的目標非常克制:
把 vault(Markdown)編譯成 chunk 級的語義索引(Derived、可重建、沒有真理權(quán))
查詢時返回的是可引用的證據(jù)單元(chunk_id + 精確定位 + 內(nèi)容 hash + snippet)
把每一次查詢的結(jié)果落盤為 evidence pack(JSON + MD),供后續(xù) LLM 和人類在開發(fā)中反復引用
如果你要復現(xiàn),真正需要抓住的并不是 FAISS 或 embedding 模型,而是這三條不變量:
chunk 身份必須穩(wěn)定、引用必須可追溯、輸出必須可重放。
腳本 A:index_vault —— 構(gòu)建語義索引
技術(shù)選型與原理
輸入:docs/、sovereign_log/ 下的 Markdown
輸出:_system/artifacts/vault_index/(明確屬于 Derived 層)
它做的事情本質(zhì)上是一次“編譯”:
1、只在 vault 內(nèi)掃描 Markdown 文件
2、將每個文件切成段落級 chunks(paragraph chunks)
3、對每個 chunk:
丟棄過短內(nèi)容(min_chars)
生成一個穩(wěn)定的 chunk_id
記錄最小但關(guān)鍵的元數(shù)據(jù)(note_path、paragraph_index、hash、mtime)
4、使用 sentence-transformers 將 chunk 文本編碼成向量(并歸一化)
5、使用 FAISS 構(gòu)建向量索引(IndexFlatIP,等價 cosine)
6、將索引產(chǎn)物落盤:
meta.jsonl:每一行對應一個 chunk 的身份與來源
index.faiss:向量索引
config.json:索引配置與可復現(xiàn)參數(shù)
之所以選擇 IndexFlatIP,原因非常簡單:在歸一化 embedding 的前提下,內(nèi)積等價 cosine,這是最穩(wěn)定、最可解釋的基線方案。在你真正跑進性能瓶頸之前,沒有必要引入 IVF/HNSW 之類的復雜結(jié)構(gòu)。
必須保留的不變量
1、chunk 切分必須穩(wěn)定
split_to_paragraph_chunks() 的行為一旦改變,paragraph_index 就會漂移,歷史引用就會失效。
2、chunk_id 必須與內(nèi)容綁定
推薦的策略是:hash(path + paragraph_index + content_hash)
這樣可以確保:內(nèi)容一變,ID 必然變化,避免“引用幻覺”。
3、meta 與 index 順序必須嚴格對齊
FAISS 向量的順序,必須和 meta.jsonl 的行順序一一對應,否則整個索引就不可用。
腳本 B:query_vault —— 查詢并生成證據(jù)包
技術(shù)選型與原理
輸入:自然語言 query
讀取:_system/artifacts/vault_index/{meta.jsonl, index.faiss}
輸出:
_system/artifacts/packs/citations/.json
_system/artifacts/runs/.md
核心流程是:
1、載入 meta 與 FAISS index
2、用同一個模型、同一種歸一化方式對 query 編碼
3、先做一次寬松檢索(raw_k 通常是 topk 的 10 倍以上)
4、再進行后處理過濾:
scope_prefix:限制檢索空間
exclude_temporal_note:剔除不應參與治理的內(nèi)容
per_note_cap:避免單個文件刷屏
5、回到原文讀取 snippet(通過 paragraph_index 重切 chunk)
6、進行輕量排序調(diào)整(docs_boost / prefix boost)
7、生成 evidence pack(JSON)與 run note(MD),并統(tǒng)一寫入 Derived root
這里的關(guān)鍵價值在于:
檢索的輸出不是 UI 展示結(jié)果,而是一個可以被落盤、被引用、被審計的證據(jù)對象。
必須保留的不變量
索引模型與查詢模型必須一致
否則 embedding 空間不一致,分數(shù)沒有任何意義。
snippet 只能是展示層
證據(jù)的真實身份永遠來自 meta(chunk_id / hash),snippet 只是為了讓人讀得懂。
所有輸出必須寫入 Derived root
嚴格限制在 _system/artifacts/ 下,并綁定 run_id,這是保證可重放、不污染 Truth/Doc 層的關(guān)鍵。
最小復現(xiàn) Checklist(給工程師)
1、明確你的 Vault 輸入域(1–2 個目錄即可)
2、實現(xiàn)一個穩(wěn)定的 chunker(段落級是最優(yōu)起點)
3、定義清晰的 chunk_id 生成策略
4、構(gòu)建 index 與 meta,并保證順序一致
5、查詢時輸出的是“證據(jù)對象”,而不是路徑列表
6、加上最基本的治理過濾(per-note cap、scope)
普通搜索:找到筆記 → 人腦判斷
這套系統(tǒng):找到 chunk 證據(jù) → 生成 evidence pack → 支持審計 / 引用 / LLM 分析 → 反哺真實開發(fā)
索引只是入口,真正的產(chǎn)物是:
可引用的證據(jù)單位,以及可以被反復使用和復查的證據(jù)包。
寫個 wrapper:把 Vault 直接接入真實項目 Repo,邊開發(fā)邊用,邊開發(fā)邊反哺
你在寫代碼的時候,隨時可以 query 自己寫過的系統(tǒng)原則、治理規(guī)則、歷史約束、失敗邊界;同時你在開發(fā)過程中遇到的新問題、新決策、新證據(jù),也會被反向沉淀回 vault。兩邊一起增長,兩邊一起防止概念漂移——項目不會因為忙而忘記制度,制度也不會因為脫離實戰(zhàn)而空轉(zhuǎn)。
我目前是把 Vault 變成“項目的外置證據(jù)底座”
把 sovereign_knowledge 當成一個獨立、長期存在的知識/制度庫,然后在真實項目 repo 里寫兩個極薄的腳本:
skq:把“開發(fā)中遇到的問題”直接扔給 vault 的 query_vault.py
ski:在你更新了 vault 內(nèi)容后,重建語義索引(index_vault.py)
這兩個腳本的關(guān)鍵價值不是“省打字”,而是把查詢變成一種開發(fā)動作:
你在寫代碼時,隨時可以從自己的制度庫里抽取證據(jù) chunk,生成可落盤的 evidence pack,然后再把 pack 交給 LLM 或自己讀,防止概念漂移。
給屏幕前程序員的復現(xiàn)指南
1、把你的知識庫 repo clone 到任意路徑(例如 ~/sovereign_knowledge)
2、在你的項目 repo 里放兩個腳本:
scripts/skq(query)
scripts/ski(index)
3、給執(zhí)行權(quán)限:chmod +x scripts/skq scripts/ski
4、配置一次環(huán)境變量(可選):
export SK_VAULT=~/sovereign_knowledge
export PYTHON=python3(或 venv python)
5、日常開發(fā)用法:
更新了 vault 內(nèi)容:scripts/ski
寫代碼遇到問題:scripts/skq "run session trace ordering" --scope_prefix docs/
這就完成了“邊開發(fā)邊用”的閉環(huán):你不需要把 vault 代碼搬進項目,也不需要在項目里維護一套索引管線;你只需要把它當作外置制度底座,隨時 query。
一個很關(guān)鍵的點:我為什么認為這種“外置庫 + wrapper”比插件更像工程
因為它把檢索的輸出變成了穩(wěn)定產(chǎn)物(pack/run note)而不是 UI 瞬時結(jié)果;也因為它把“知識治理”從筆記工具里抽離出來,變成可以進入 CI、進入審計、進入代碼評審的工程對象。這就是“第二大腦”之所以能長期生長的地方:它不是靠你記得住,而是靠工具鏈持續(xù)生成可追溯證據(jù)。
一個多年工程經(jīng)驗的大哥曾經(jīng)說過,LLM時代,文本和代碼要一樣多。但是你總不能所有的項目全部塞一個文本庫吧。
最后,LLM強大的解構(gòu)問題能力,設(shè)計query能力,并且從證據(jù)段中讀取只字片語,生成建議的能力。這是現(xiàn)階段,這個辦法可以在你密集使用LLM的同時,減輕焦慮的一個辦法。
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.