半年以前,這需要一個後端開發者、一個 DevOps 工程師,以及兩週時間。現在,只需要一句話和 Claude 就能搞定。以下是完整的架構——以及為什麼大多數開發者還沒搞懂這件事。
大多數人對 AI 的認知模型是錯的。
他們認為:AI 助手 → 你問問題 → 它回答。
2026 年的現實是:AI Agent → 你描述一個系統 → 它構建、部署,並將該系統連接到你的環境。不是原型。不是程式碼片段。而是一個正在運行的應用程式。
這個轉變有個名字:生成式應用架構(Generative App Architecture)。而讓它變得實用的技術棧——Claude + Obsidian + MCP——現在任何人都可以使用。
1. 生成式應用架構到底是什麼意思
傳統軟體開發:
1想法 → 規格 → 設計 → 前端開發 → 後端開發2→ 資料庫設置 → API 整合 → 測試 → 部署3耗時:數週。成本:數千元。
生成式應用架構:
1想法 → 提示詞 → 運作中的系統2耗時:數分鐘。成本:API 代幣。
AI Agent 不只是寫程式碼。它在底層運行一個完整的 Agentic Loop:
步驟 1 - 任務分解
你抽象的請求(「為一間洗車場建立一個 CRM」)會被分解成數十個原子化的子任務:資料庫架構、UI 元件、通知邏輯、身份驗證流程、API 端點。
步驟 2 - 透過 MCP 進行環境對映
透過模型上下文協議(Model Context Protocol),Agent 能立即了解它有哪些工具可以使用——你的檔案系統、已安裝的套件、正在運行的服務、可用的 API。
步驟 3 - 迭代構建與測試
Agent 會自主地撰寫程式碼、執行它、捕捉編譯錯誤、修正錯誤,並重新測試,直到系統能正確運作為止。
步驟 4 - 情境化部署
輸出的不是一個包含程式碼的文字檔。而是一個即時的本地環境,或一個可部署的網頁應用程式。
這就是一個協助開發者的工具,與一個完全取代建構管線的系統之間的差異。
2. Claude 作為引擎——三種部署模式
模式 1 - Claude Artifacts
從提示詞到運行中應用程式的最快路徑。當你要求 Claude 建立某個東西時,它會開啟一個互動式的 Artifact 視窗,並即時組裝、編譯、運行一個完整的網頁應用程式——React、HTML、JavaScript——你可以親眼看著它發生。
你可以在 Artifact 內部與運行的應用程式互動,用自然語言對它進行迭代,並匯出完整的封存檔。
一個能產生可上線的財務追蹤工具的提示詞:
1建立一個個人財務追蹤應用程式,包含:23功能:4- 交易記錄(新增/編輯/刪除,附帶分類)5- 月度預算檢視,附進度條6- 加密貨幣投資組合追蹤器,從 CoinGecko API 拉取即時價格7- 即時更新的淨資產計算8- 深色模式切換910技術需求:11- 單一檔案 React 應用程式12- 僅使用 useState + useEffect(無外部狀態管理)13- 使用 Tailwind CSS 進行樣式設計14- 從公開 API 擷取資料(無需身份驗證)15- 行動裝置響應式設計1617資料:18- 在會話之間持久化儲存至 localStorage19- 將交易匯出為 CSV2021輸出:一個完整、自包含、可立即部署的應用程式。
Claude Artifacts 回傳的內容——一個完整的 React 應用程式:
1import { useState, useEffect } from "react";23const CATEGORIES = ["Housing","Food","Transport","Entertainment","Health","Savings","Income","Crypto","Other"];4const CRYPTO_IDS = { BTC: "bitcoin", ETH: "ethereum", SOL: "solana" };56export default function FinanceTracker() {7 const [transactions, setTransactions] = useState(() =>8 JSON.parse(localStorage.getItem("transactions") || "[]")9 );10 const [cryptoPrices, setCryptoPrices] = useState({});11 const [form, setForm] = useState({ description:"", amount:"", category:"Other", type:"expense", date:"" });12 const [darkMode, setDarkMode] = useState(false);1314 useEffect(() => {15 const ids = Object.values(CRYPTO_IDS).join(",");16 fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${ids}&vs_currencies=usd`)17 .then(r => r.json())18 .then(data => {19 const prices = {};20 Object.entries(CRYPTO_IDS).forEach(([sym, id]) => { prices[sym] = data[id]?.usd || 0; });21 setCryptoPrices(prices);22 });23 }, []);2425 useEffect(() => {26 localStorage.setItem("transactions", JSON.stringify(transactions));27 }, [transactions]);2829 const addTransaction = () => {30 if (!form.description || !form.amount) return;31 setTransactions(prev => [...prev, { ...form, id: Date.now(), amount: parseFloat(form.amount),32 date: form.date || new Date().toISOString().split("T")[0] }]);33 setForm({ description:"", amount:"", category:"Other", type:"expense", date:"" });34 };3536 const totalIncome = transactions.filter(t => t.type === "income").reduce((s,t) => s + t.amount, 0);37 const totalExpenses = transactions.filter(t => t.type === "expense").reduce((s,t) => s + t.amount, 0);38 const netWorth = totalIncome - totalExpenses;3940 const bg = darkMode ? "#0D0D0D" : "#F9F7F4";41 const card = darkMode ? "#1A1A1A" : "#FFF";42 const text = darkMode ? "#F0F0F0" : "#1A1A1A";43 const border = darkMode ? "#2A2A2A" : "#E8E8E8";4445 return (46 <div style={{ minHeight:"100vh", background:bg, color:text, fontFamily:"system-ui, sans-serif" }}>47 <div style={{ maxWidth:800, margin:"0 auto", padding:"24px 16px" }}>4849 <div style={{ display:"flex", justifyContent:"space-between", marginBottom:24 }}>50 <div>51 <h1 style={{ fontSize:22, fontWeight:500, margin:0 }}>Finance Tracker</h1>52 <p style={{ margin:"4px 0 0", fontSize:13, color: netWorth >= 0 ? "#22C55E" : "#EF4444" }}>53 Net worth: ${netWorth.toFixed(2)}54 </p>55 </div>56 <button onClick={() => setDarkMode(!darkMode)}57 style={{ padding:"8px 14px", borderRadius:8, border:`1px solid ${border}`,58 background:card, color:text, cursor:"pointer" }}>59 {darkMode ? "Light" : "Dark"}60 </button>61 </div>6263 <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10, marginBottom:20 }}>64 {[["Income","#22C55E",totalIncome],["Expenses","#EF4444",totalExpenses]].map(([label,color,val]) => (65 <div key={label} style={{ background:card, border:`1px solid ${border}`, borderRadius:10, padding:14 }}>66 <p style={{ margin:0, fontSize:12, color:"#999" }}>{label}</p>67 <p style={{ margin:"4px 0 0", fontSize:20, fontWeight:600, color }}>${val.toFixed(2)}</p>68 </div>69 ))}70 </div>7172 <div style={{ background:card, border:`1px solid ${border}`, borderRadius:10, padding:16, marginBottom:20 }}>73 <div style={{ display:"grid", gridTemplateColumns:"2fr 1fr 1fr", gap:8, marginBottom:8 }}>74 <input placeholder="Description" value={form.description}75 onChange={e => setForm(p => ({ ...p, description: e.target.value }))}76 style={{ padding:"9px 12px", borderRadius:8, border:`1px solid ${border}`, background:bg, color:text, fontSize:13 }} />77 <input type="number" placeholder="Amount" value={form.amount}78 onChange={e => setForm(p => ({ ...p, amount: e.target.value }))}79 style={{ padding:"9px 12px", borderRadius:8, border:`1px solid ${border}`, background:bg, color:text, fontSize:13 }} />80 <select value={form.type} onChange={e => setForm(p => ({ ...p, type: e.target.value }))}81 style={{ padding:"9px 12px", borderRadius:8, border:`1px solid ${border}`, background:bg, color:text, fontSize:13 }}>82 <option value="expense">Expense</option>83 <option value="income">Income</option>84 </select>85 </div>86 <div style={{ display:"grid", gridTemplateColumns:"2fr auto", gap:8 }}>87 <select value={form.category} onChange={e => setForm(p => ({ ...p, category: e.target.value }))}88 style={{ padding:"9px 12px", borderRadius:8, border:`1px solid ${border}`, background:bg, color:text, fontSize:13 }}>89 {CATEGORIES.map(c => <option key={c}>{c}</option>)}90 </select>91 <button onClick={addTransaction}92 style={{ padding:"9px 20px", borderRadius:8, background:"#E8692A",93 color:"#fff", border:"none", cursor:"pointer", fontSize:13, fontWeight:500 }}>94 Add95 </button>96 </div>97 </div>9899 <div style={{ background:card, border:`1px solid ${border}`, borderRadius:10, overflow:"hidden" }}>100 <p style={{ margin:0, padding:"12px 16px", borderBottom:`1px solid ${border}`, fontSize:13, fontWeight:500 }}>101 Transactions ({transactions.length})102 </p>103 {transactions.slice().reverse().map(t => (104 <div key={t.id} style={{ display:"flex", justifyContent:"space-between",105 alignItems:"center", padding:"11px 16px", borderBottom:`1px solid ${border}` }}>106 <div>107 <p style={{ margin:0, fontSize:13, fontWeight:500 }}>{t.description}</p>108 <p style={{ margin:"2px 0 0", fontSize:12, color:"#999" }}>{t.category} · {t.date}</p>109 </div>110 <span style={{ fontSize:14, fontWeight:600, color: t.type==="income" ? "#22C55E" : "#EF4444" }}>111 {t.type==="income" ? "+" : "-"}${t.amount.toFixed(2)}112 </span>113 </div>114 ))}115 </div>116 </div>117 </div>118 );119}
這就是完整的應用程式。一個提示詞。立即在 Claude Artifacts 內運行。
模式 2 - Claude + MCP(本地部署)
MCP(模型上下文協議)讓 Claude 能直接存取你的本地環境。一個提示詞不只產生程式碼——它會在你的硬碟上建立資料夾、透過終端機安裝套件、撰寫設定檔,並啟動一個本地伺服器。
將 Claude 連接到你檔案系統的 MCP 設定:
1{2 "mcpServers": {3 "filesystem": {4 "command": "npx",5 "args": [6 "-y",7 "@modelcontextprotocol/server-filesystem",8 "/Users/yourname/Projects"9 ]10 },11 "terminal": {12 "command": "npx",13 "args": ["-y", "@modelcontextprotocol/server-terminal"]14 },15 "sqlite": {16 "command": "npx",17 "args": [18 "-y",19 "@modelcontextprotocol/server-sqlite",20 "--db-path",21 "/Users/yourname/Projects/app.db"22 ]23 }24 }25}
當此設定啟用時,一個簡單的提示詞:
1為一間洗車場建立並部署一個本地 CRM 系統。23在 ~/Projects/carwash-crm/ 建立專案4自動安裝依賴項。5設定 SQLite 資料庫,包含以下表格:6- customers(姓名、電話、電子郵件、車輛、備註)7- visits(客戶 ID、日期、服務、價格、狀態)8- staff(姓名、角色、排班)910建立一個網頁介面,包含:11- 客戶搜尋與個人資料12- 每位客戶的到訪歷史13- 按月計算的營收儀表板14- 簡訊提醒系統(Twilio 整合,僅設定)1516完成後啟動開發伺服器。17準備就緒後回報 localhost 網址。
Claude 會透過 MCP 端到端地執行此任務——建立目錄結構、安裝 Node 套件、撰寫資料庫架構、建構 UI,並啟動伺服器。你將得到一個 localhost 網址。
模式 3 - 符合公司標準的 Claude Projects
將你的 UI 套件、設計 Token、API 文件和安全性需求一次上傳到 Claude Project。此後,Claude 產生的每個系統都會自動符合你的內部技術棧。
1[Claude Project 上下文包含:]2- design-system.md(顏色、排版、間距)3- api-standards.md(身份驗證模式、錯誤代碼)4- security-policy.md(輸入驗證規則、CORS 設定)5- stack.md(React 18、TypeScript、Tailwind、Prisma、PostgreSQL)67提示詞:8「建立一個帶有電子郵件驗證的客戶入職表單,9並在提交時自動建立 Notion 資料庫條目。」1011輸出:完全符合你技術棧的生產級程式碼——12無需任何清理工作。
3. Obsidian 作為 AI 指揮中心
2026 年的 Obsidian 不再只是一個筆記應用程式。它是一個個人 AI 指揮中心,你累積的知識庫會成為你建構之每個系統的上下文層。
架構上的轉變:你的知識庫不再是儲存空間。它是 RAG(檢索增強生成)——一個 AI Agent 在執行任何任務前都會查詢的動態知識庫。
實現此功能的插件技術棧:
Smart Connections - 索引你的整個知識庫,並在每次 AI 呼叫時將相關筆記作為上下文發送。
Obsidian Copilot - 將你的知識庫直接連接到 Claude API。設定一次即可:
12 "provider": "anthropic",3 "model": "claude-opus-4-8",4 "apiKey": "YOUR_ANTHROPIC_KEY",5 "systemPrompt": "你是一位系統架構師。你可以存取用戶完整的知識庫作為上下文。在建構系統時,請參考他們現有的筆記、過往的決策和既定的模式。輸出:可運行的程式碼 + Obsidian 文件結構。",6 "contextWindow": {7 "includeActiveFile": true,8 "includeLinkedFiles": true,9 "includeRecentFiles": 10,10 "includeFolders": ["Projects", "Systems", "Decisions"]11 }12}
Canvas 作為系統設計介面
一個提示詞就能建立一個互動式 Obsidian Canvas,Claude 會在裡面以連接的區塊形式呈現完整的系統架構。
1在 Obsidian Canvas 中的提示詞:2「為我的 Twitter 帳號設計一個內容生產管線。3我每週發布 3 篇文章,並管理 5 個贊助合作。4請參考我現有的內容日曆筆記。」56輸出:包含以下連接區塊的 Canvas:7→ 內容發想(從你的興趣筆記中提取)8→ 草稿 → 審閱 → 發布 工作流程9→ 附帶截止日期提醒的贊助商追蹤10→ 分析儀表板11→ 自動化跨平台發布邏輯12→ 每個區塊都連結到相關的 Obsidian 檔案
Claude 產生的 Canvas 輸出作為一個結構化檔案:
1{2 "nodes": [3 {4 "id": "ideation",5 "type": "file",6 "file": "Systems/ContentPipeline/Ideation.md",7 "x": 0, "y": 0, "width": 300, "height": 200,8 "color": "1"9 },10 {11 "id": "draft",12 "type": "file",13 "file": "Systems/ContentPipeline/Draft.md",14 "x": 400, "y": 0, "width": 300, "height": 200,15 "color": "3"16 },17 {18 "id": "sponsors",19 "type": "file",20 "file": "Systems/ContentPipeline/SponsorTracker.md",21 "x": 0, "y": 300, "width": 300, "height": 200,22 "color": "5"23 },24 {25 "id": "analytics",26 "type": "file",27 "file": "Systems/ContentPipeline/Analytics.md",28 "x": 400, "y": 300, "width": 300, "height": 200,29 "color": "6"30 }31 ],32 "edges": [33 {34 "id": "e1",35 "fromNode": "ideation", "fromSide": "right",36 "toNode": "draft", "toSide": "left",37 "label": "approved concepts"38 },39 {40 "id": "e2",41 "fromNode": "sponsors", "fromSide": "right",42 "toNode": "draft", "toSide": "bottom",43 "label": "brief integration"44 }45 ]46}
4. 完全隱私的本地 LLM
對於敏感資料——客戶系統、財務工具、內部工具——可以透過本地模型而非雲端 API 路由。零資料離開你的機器。
1# 安裝 Ollama2curl -fsSL https://ollama.com/install.sh | sh34# 拉取一個具備編碼能力的模型5ollama pull llama3.2:latest6# 或為了更強的程式碼生成:7ollama pull qwen2.5-coder:32b89# 啟動本地伺服器10ollama serve11# 運行於 localhost:11434
設定 Obsidian Copilot 以使用本地端點:
1{2 "provider": "ollama",3 "model": "qwen2.5-coder:32b",4 "baseUrl": "http://localhost:11434",5 "systemPrompt": "你是一個本地系統建構者,可以透過 MCP 存取用戶的檔案系統。建構完整可運行的系統。未經明確指示,絕不將資料發送到外部 API。"6}
本地模型 + MCP 橋接器:
1import requests2import json3from pathlib import Path4from watchdog.observers import Observer5from watchdog.events import FileSystemEventHandler67OBSIDIAN_INBOX = Path.home() / "Obsidian" / "AI-Inbox"8PROJECTS_DIR = Path.home() / "Projects"9OLLAMA_URL = "http://localhost:11434/api/generate"1011class InboxWatcher(FileSystemEventHandler):12 """13 監控 Obsidian AI-Inbox 資料夾。14 當一個新的 .md 檔案出現時,將其視為一個建構提示詞。15 傳遞給本地 LLM -> 透過 MCP 執行 -> 回報結果。16 """1718 def on_created(self, event):19 if not event.src_path.endswith(".md"):20 return2122 prompt_file = Path(event.src_path)23 prompt = prompt_file.read_text()2425 print(f"[Inbox] 新提示詞:{prompt_file.name}")26 self.execute_prompt(prompt, prompt_file.stem)2728 def execute_prompt(self, prompt: str, project_name: str):29 response = requests.post(OLLAMA_URL, json={30 "model": "qwen2.5-coder:32b",31 "prompt": f"""你是一個系統建構者。32 建構此系統:{prompt}3334 輸出一個 JSON 計劃,包含:35 {{36 "project_dir": "相對路徑",37 "files": [38 {{"path": "相對路徑", "content": "檔案內容"}}39 ],40 "commands": ["npm install", "等等"],41 "summary": "建構了什麼"42 }}""",43 "stream": False44 })4546 plan = json.loads(response.json()["response"])47 project_dir = PROJECTS_DIR / plan["project_dir"]48 project_dir.mkdir(parents=True, exist_ok=True)4950 for file_spec in plan["files"]:51 file_path = project_dir / file_spec["path"]52 file_path.parent.mkdir(parents=True, exist_ok=True)53 file_path.write_text(file_spec["content"])54 print(f"[Build] 已建立:{file_path}")5556 result_file = OBSIDIAN_INBOX / f"{project_name}-result.md"57 result_file.write_text(58 f"# 建構完成:{project_name}\n\n"59 f"**位置:** {project_dir}\n\n"60 f"**摘要:** {plan['summary']}\n\n"61 f"**已建立的檔案:** {len(plan['files'])}\n"62 )63 print(f"[Done] 結果已寫入 Obsidian")6465if __name__ == "__main__":66 OBSIDIAN_INBOX.mkdir(exist_ok=True)67 observer = Observer()68 observer.schedule(InboxWatcher(), str(OBSIDIAN_INBOX), recursive=False)69 observer.start()70 print(f"[Watching] {OBSIDIAN_INBOX}")7172 try:73 while True:74 import time; time.sleep(1)75 except KeyboardInterrupt:76 observer.stop()77 observer.join()
將一個帶有建構提示詞的 .md 檔案放入你的 Obsidian AI-Inbox。橋接器會拾取它,透過本地模型路由,在你的 Projects 資料夾中建構系統,然後將完成通知寫回 Obsidian。
5. 完整工作流程——從想法到部署系統
1步驟 1 - 輸入2在 Obsidian 的 AI 面板上,寫下:3「建立一個包含加密貨幣整合和月度預算追蹤的個人財務系統。」4按下「生成」。56步驟 2 - 上下文組裝7Smart Connections 插件掃描你的知識庫。8找到你過去 3 個月的財務筆記。9將它們作為上下文發送給 Claude API。1011步驟 3 - 架構設計12Claude(Opus 4.8)設計系統:13- 資料庫架構14- UI 元件15- API 整合16- 檔案結構1718步驟 4 - 建構19Claude(Sonnet 5)透過 MCP 實作:20- 建立 ~/Projects/finance-tracker/21- 安裝依賴項22- 撰寫所有檔案23- 在 localhost:3000 啟動開發伺服器2425步驟 5 - 結果26Obsidian 建立資料夾:Finance System/27內部包含:連結的儀表板、設定筆記,28以及一個指向運行中應用程式的直接連結。
從步驟 1 到運行中的應用程式總時間:4-12 分鐘。
這代表的轉變
這不是一種更快的寫程式碼方式。
這是想法與執行之間的一種不同關係。
過去,你能建構什麼的限制在於技術技能和時間。非開發者無法建構 CRM。單人開發者無法同時建構五個系統。一個團隊無法在數小時內而非數週內交付產品。
這三個限制現在都消失了。
新的限制是思維的清晰度——精確描述你所需內容的能力、理解什麼是良好輸出的能力,以及對其進行迭代的能力。這是一種思考技能,而非技術技能。
生成式應用架構不會讓開發者變得過時。它會讓系統性思考的能力——在你建構之前先釐清需求——變得比撰寫實作程式碼的能力更有價值。
技術棧已經到位。模型已經足夠強大。唯一剩下的變數是,你正在用它來建構,還是正在閱讀那些正在用它建構的人的故事。
本文描述了截至 2026 年 7 月 Claude、Obsidian 和 MCP 中可用的功能。特定插件版本和 API 配置可能會有所變動。在實作之前,請務必查閱最新的官方文件。
感謝您的閱讀。





