一個指令。一個按鈕。一套完整部署的系統。這就是 2026 年的 AI 工程樣貌

@0xWast3
英語2 天前 · 2026年7月15日
129K
111
15
20
263

TL;DR

一份關於生成式應用架構的完整指南,詳細介紹 AI Agents 如何利用 Claude 和 Obsidian 建構、部署並管理完整的軟體系統。

半年以前,這需要一個後端開發者、一個 DevOps 工程師,以及兩週時間。現在,只需要一句話和 Claude 就能搞定。以下是完整的架構——以及為什麼大多數開發者還沒搞懂這件事。

大多數人對 AI 的認知模型是錯的。

他們認為:AI 助手 → 你問問題 → 它回答。

2026 年的現實是:AI Agent → 你描述一個系統 → 它構建、部署,並將該系統連接到你的環境。不是原型。不是程式碼片段。而是一個正在運行的應用程式。

這個轉變有個名字:生成式應用架構(Generative App Architecture)。而讓它變得實用的技術棧——Claude + Obsidian + MCP——現在任何人都可以使用。

1. 生成式應用架構到底是什麼意思

傳統軟體開發:

text
1想法 → 規格 → 設計 → 前端開發 → 後端開發
2→ 資料庫設置 → API 整合 → 測試 → 部署
3耗時:數週。成本:數千元。

生成式應用架構:

text
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 內部與運行的應用程式互動,用自然語言對它進行迭代,並匯出完整的封存檔。

一個能產生可上線的財務追蹤工具的提示詞:

text
1建立一個個人財務追蹤應用程式,包含:
2
3功能:
4- 交易記錄(新增/編輯/刪除,附帶分類)
5- 月度預算檢視,附進度條
6- 加密貨幣投資組合追蹤器,從 CoinGecko API 拉取即時價格
7- 即時更新的淨資產計算
8- 深色模式切換
9
10技術需求:
11- 單一檔案 React 應用程式
12- 僅使用 useState + useEffect(無外部狀態管理)
13- 使用 Tailwind CSS 進行樣式設計
14- 從公開 API 擷取資料(無需身份驗證)
15- 行動裝置響應式設計
16
17資料:
18- 在會話之間持久化儲存至 localStorage
19- 將交易匯出為 CSV
20
21輸出:一個完整、自包含、可立即部署的應用程式。

Claude Artifacts 回傳的內容——一個完整的 React 應用程式:

javascript
1import { useState, useEffect } from "react";
2
3const CATEGORIES = ["Housing","Food","Transport","Entertainment","Health","Savings","Income","Crypto","Other"];
4const CRYPTO_IDS = { BTC: "bitcoin", ETH: "ethereum", SOL: "solana" };
5
6export 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);
13
14 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 }, []);
24
25 useEffect(() => {
26 localStorage.setItem("transactions", JSON.stringify(transactions));
27 }, [transactions]);
28
29 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 };
35
36 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;
39
40 const bg = darkMode ? "#0D0D0D" : "#F9F7F4";
41 const card = darkMode ? "#1A1A1A" : "#FFF";
42 const text = darkMode ? "#F0F0F0" : "#1A1A1A";
43 const border = darkMode ? "#2A2A2A" : "#E8E8E8";
44
45 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" }}>
48
49 <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>
62
63 <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>
71
72 <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 Add
95 </button>
96 </div>
97 </div>
98
99 <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 設定:

json
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}

當此設定啟用時,一個簡單的提示詞:

text
1為一間洗車場建立並部署一個本地 CRM 系統。
2
3在 ~/Projects/carwash-crm/ 建立專案
4自動安裝依賴項。
5設定 SQLite 資料庫,包含以下表格:
6- customers(姓名、電話、電子郵件、車輛、備註)
7- visits(客戶 ID、日期、服務、價格、狀態)
8- staff(姓名、角色、排班)
9
10建立一個網頁介面,包含:
11- 客戶搜尋與個人資料
12- 每位客戶的到訪歷史
13- 按月計算的營收儀表板
14- 簡訊提醒系統(Twilio 整合,僅設定)
15
16完成後啟動開發伺服器。
17準備就緒後回報 localhost 網址。

Claude 會透過 MCP 端到端地執行此任務——建立目錄結構、安裝 Node 套件、撰寫資料庫架構、建構 UI,並啟動伺服器。你將得到一個 localhost 網址。

模式 3 - 符合公司標準的 Claude Projects

將你的 UI 套件、設計 Token、API 文件和安全性需求一次上傳到 Claude Project。此後,Claude 產生的每個系統都會自動符合你的內部技術棧。

text
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)
6
7提示詞:
8「建立一個帶有電子郵件驗證的客戶入職表單,
9並在提交時自動建立 Notion 資料庫條目。」
10
11輸出:完全符合你技術棧的生產級程式碼——
12無需任何清理工作。

3. Obsidian 作為 AI 指揮中心

2026 年的 Obsidian 不再只是一個筆記應用程式。它是一個個人 AI 指揮中心,你累積的知識庫會成為你建構之每個系統的上下文層。

架構上的轉變:你的知識庫不再是儲存空間。它是 RAG(檢索增強生成)——一個 AI Agent 在執行任何任務前都會查詢的動態知識庫。

實現此功能的插件技術棧:

Smart Connections - 索引你的整個知識庫,並在每次 AI 呼叫時將相關筆記作為上下文發送。

Obsidian Copilot - 將你的知識庫直接連接到 Claude API。設定一次即可:

javascript
1
2 "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 會在裡面以連接的區塊形式呈現完整的系統架構。

text
1在 Obsidian Canvas 中的提示詞:
2「為我的 Twitter 帳號設計一個內容生產管線。
3我每週發布 3 篇文章,並管理 5 個贊助合作。
4請參考我現有的內容日曆筆記。」
5
6輸出:包含以下連接區塊的 Canvas:
7→ 內容發想(從你的興趣筆記中提取)
8→ 草稿 → 審閱 → 發布 工作流程
9→ 附帶截止日期提醒的贊助商追蹤
10→ 分析儀表板
11→ 自動化跨平台發布邏輯
12→ 每個區塊都連結到相關的 Obsidian 檔案

Claude 產生的 Canvas 輸出作為一個結構化檔案:

json
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 路由。零資料離開你的機器。

bash
1# 安裝 Ollama
2curl -fsSL https://ollama.com/install.sh | sh
3
4# 拉取一個具備編碼能力的模型
5ollama pull llama3.2:latest
6# 或為了更強的程式碼生成:
7ollama pull qwen2.5-coder:32b
8
9# 啟動本地伺服器
10ollama serve
11# 運行於 localhost:11434

設定 Obsidian Copilot 以使用本地端點:

javascript
1{
2 "provider": "ollama",
3 "model": "qwen2.5-coder:32b",
4 "baseUrl": "http://localhost:11434",
5 "systemPrompt": "你是一個本地系統建構者,可以透過 MCP 存取用戶的檔案系統。建構完整可運行的系統。未經明確指示,絕不將資料發送到外部 API。"
6}

本地模型 + MCP 橋接器:

python
1import requests
2import json
3from pathlib import Path
4from watchdog.observers import Observer
5from watchdog.events import FileSystemEventHandler
6
7OBSIDIAN_INBOX = Path.home() / "Obsidian" / "AI-Inbox"
8PROJECTS_DIR = Path.home() / "Projects"
9OLLAMA_URL = "http://localhost:11434/api/generate"
10
11class InboxWatcher(FileSystemEventHandler):
12 """
13 監控 Obsidian AI-Inbox 資料夾。
14 當一個新的 .md 檔案出現時,將其視為一個建構提示詞。
15 傳遞給本地 LLM -> 透過 MCP 執行 -> 回報結果。
16 """
17
18 def on_created(self, event):
19 if not event.src_path.endswith(".md"):
20 return
21
22 prompt_file = Path(event.src_path)
23 prompt = prompt_file.read_text()
24
25 print(f"[Inbox] 新提示詞:{prompt_file.name}")
26 self.execute_prompt(prompt, prompt_file.stem)
27
28 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}
33
34 輸出一個 JSON 計劃,包含:
35 {{
36 "project_dir": "相對路徑",
37 "files": [
38 {{"path": "相對路徑", "content": "檔案內容"}}
39 ],
40 "commands": ["npm install", "等等"],
41 "summary": "建構了什麼"
42 }}""",
43 "stream": False
44 })
45
46 plan = json.loads(response.json()["response"])
47 project_dir = PROJECTS_DIR / plan["project_dir"]
48 project_dir.mkdir(parents=True, exist_ok=True)
49
50 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}")
55
56 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")
64
65if __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}")
71
72 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. 完整工作流程——從想法到部署系統

text
1步驟 1 - 輸入
2在 Obsidian 的 AI 面板上,寫下:
3「建立一個包含加密貨幣整合和月度預算追蹤的個人財務系統。」
4按下「生成」。
5
6步驟 2 - 上下文組裝
7Smart Connections 插件掃描你的知識庫。
8找到你過去 3 個月的財務筆記。
9將它們作為上下文發送給 Claude API。
10
11步驟 3 - 架構設計
12Claude(Opus 4.8)設計系統:
13- 資料庫架構
14- UI 元件
15- API 整合
16- 檔案結構
17
18步驟 4 - 建構
19Claude(Sonnet 5)透過 MCP 實作:
20- 建立 ~/Projects/finance-tracker/
21- 安裝依賴項
22- 撰寫所有檔案
23- 在 localhost:3000 啟動開發伺服器
24
25步驟 5 - 結果
26Obsidian 建立資料夾:Finance System/
27內部包含:連結的儀表板、設定筆記,
28以及一個指向運行中應用程式的直接連結。

從步驟 1 到運行中的應用程式總時間:4-12 分鐘。

這代表的轉變

這不是一種更快的寫程式碼方式。

這是想法與執行之間的一種不同關係。

過去,你能建構什麼的限制在於技術技能和時間。非開發者無法建構 CRM。單人開發者無法同時建構五個系統。一個團隊無法在數小時內而非數週內交付產品。

這三個限制現在都消失了。

新的限制是思維的清晰度——精確描述你所需內容的能力、理解什麼是良好輸出的能力,以及對其進行迭代的能力。這是一種思考技能,而非技術技能。

生成式應用架構不會讓開發者變得過時。它會讓系統性思考的能力——在你建構之前先釐清需求——變得比撰寫實作程式碼的能力更有價值。

技術棧已經到位。模型已經足夠強大。唯一剩下的變數是,你正在用它來建構,還是正在閱讀那些正在用它建構的人的故事。

本文描述了截至 2026 年 7 月 Claude、Obsidian 和 MCP 中可用的功能。特定插件版本和 API 配置可能會有所變動。在實作之前,請務必查閱最新的官方文件。

感謝您的閱讀。

二次創作

使用 YouMind 創作爆款文章

收集素材、拆解爆點、生成視覺資產、撰寫內容,並在一個 AI 工作空間裡完成分發。

了解 YouMind
寫給創作者

把你的 Markdown 變成乾淨的 𝕏 文章

圖片上傳、表格、程式碼區塊,往 𝕏 上手動重排太痛苦。YouMind 把整篇 Markdown 一鍵轉成乾淨、可直接發佈的 𝕏 文章草稿。

試試 Markdown 轉 𝕏

更多可拆解樣本

近期爆款文章

探索更多爆款文章