Schema.org 不是「加幾個 tag」這麼簡單。沒有產業特化、沒有實體互連、沒有自動生成的結構化資料,對 AI 而言幾乎等於沒有。
Schema.org 誕生於 2011 年,是 Google、Bing、Yahoo、Yandex 聯合推動的結構化資料詞彙表1。它原本的主要用途是讓傳統搜尋引擎產出 Rich Results(評分星級、麵包屑、FAQ 展開等)。
2024 年之後,Schema.org 的角色出現兩個根本性轉變:
本書把 Schema.org 視為百原GEO 優化路徑的第一個槓桿。一個品牌若沒有完善的 Schema.org 結構,無論其他維度如何優化,AI 認知都難以穩定。
Schema.org 規範中有數百個 @type,許多特化程度極高(例:MedicalClinic、VeterinaryCare、CafeOrCoffeeShop)。對 AI 而言,選錯 @type 等於把自己塞到錯的抽屜——AI 以 @type 為關鍵維度在知識圖譜中定位實體。
百原平台將常見產業歸納為 25 類,每類對應一組 Schema.org @type:
| code | 中文名稱 | 對應 Schema.org @type |
|---|---|---|
medical_clinic |
醫美診所 | MedicalClinic, LocalBusiness |
dental_clinic |
牙科診所 | Dentist, LocalBusiness |
general_clinic |
一般診所 | MedicalOrganization, LocalBusiness |
beauty_salon |
美髮/美容 | BeautySalon, LocalBusiness |
fitness |
健身房/瑜珈 | HealthClub, SportsActivityLocation |
restaurant |
餐廳 | Restaurant, FoodEstablishment |
cafe |
咖啡店 | CafeOrCoffeeShop |
legal_service |
律師事務所 | LegalService, ProfessionalService |
accounting |
會計師事務所 | AccountingService, ProfessionalService |
real_estate |
不動產仲介 | RealEstateAgent, ProfessionalService |
auto_repair |
汽車維修 | AutoRepair, AutomotiveBusiness |
education_offline |
補習班/培訓 | EducationalOrganization, LocalBusiness |
veterinary |
寵物醫院 | VeterinaryCare, MedicalOrganization |
lodging |
旅館/民宿 | LodgingBusiness, Hotel |
retail_store |
零售店 | Store, LocalBusiness |
financial_service |
金融服務 | FinancialService, ProfessionalService |
saas_application |
SaaS 軟體 | SoftwareApplication, Organization |
web_application |
網頁工具 | WebApplication, Organization |
mobile_app |
手機 App | MobileApplication, Organization |
ecommerce |
純電商 | OnlineStore, Organization |
online_education |
線上課程平台 | EducationalOrganization |
news_media |
媒體/內容網站 | NewsMediaOrganization |
online_professional |
線上顧問 | ProfessionalService, Organization |
other_physical |
其他實體商家 | LocalBusiness |
other_online |
其他線上服務 | Organization |
Fig 7-1: 實體 16、線上 7、保底 2。每類同時指定兩個 @type(主 + 副),以符合 Schema.org 允許 @type 為陣列的規範。
Schema.org 規範中細分類型可達數百,但過細的分類反而降低 AI 的識別率。原因:
Restaurant 比 FastFoodRestaurant 更被識別)flowchart TB
subgraph L1["Layer 1: 主體"]
Org["Organization / LocalBusiness<br/>@id = #org<br/>name / description / url / logo /<br/>address / telephone / sameAs"]
end
subgraph L2["Layer 2: 服務"]
Svc1["Service<br/>@id = #svc-1"]
Svc2["Service<br/>@id = #svc-2"]
SvcN["..."]
end
subgraph L3["Layer 3: 人員"]
Emp1["Person / Physician<br/>@id = #emp-1"]
Emp2["Person / Attorney<br/>@id = #emp-2"]
end
Svc1 -->|provider| Org
Svc2 -->|provider| Org
Emp1 -->|worksFor| Org
Emp2 -->|worksFor| Org
Svc1 -->|performer| Emp1
Svc2 -->|performer| Emp2
Org -.->|sameAs| Wiki[Wikipedia]
Org -.->|sameAs| WD[Wikidata]
Org -.->|sameAs| LI[LinkedIn]
Org -.->|sameAs| GBP[Google Business Profile]
Fig 7-2: 三層用 @id 互相引用形成知識圖譜;外部權威平台透過 sameAs 建立跨知識庫連結。
實務上常見的錯誤是把所有資訊擠進一個 Organization 物件:
{
"@type": "Organization",
"name": "某醫美診所",
"employees": [
{ "name": "林醫師", "jobTitle": "院長" }
],
"services": [
"電波拉皮", "雙眼皮手術"
]
}
這種寫法的問題是:AI 無法把「林醫師」當成可被獨立引用的實體(Person entity);「電波拉皮」只是字串不是服務實體(Service entity)。結果是「關於林醫師的問題」無法對應到任何結構化資料。
三層 @id 的寫法則建立可定址的實體:
{
"@context": "https://schema.org",
"@graph": [
{
"@type": ["MedicalClinic", "LocalBusiness"],
"@id": "https://example.clinic/#org",
"name": "某醫美診所",
"sameAs": [
"https://www.wikidata.org/wiki/Q...",
"https://www.linkedin.com/company/..."
]
},
{
"@type": "Physician",
"@id": "https://example.clinic/#emp-1",
"name": "林醫師",
"jobTitle": "院長",
"worksFor": { "@id": "https://example.clinic/#org" }
},
{
"@type": "Service",
"@id": "https://example.clinic/#svc-thermage",
"name": "電波拉皮",
"provider": { "@id": "https://example.clinic/#org" },
"performer": { "@id": "https://example.clinic/#emp-1" }
}
]
}
當使用者問 AI「誰做電波拉皮」時,AI 的推理路徑有完整的實體鏈可走,而不是從模糊字串匹配。
is_physical 旗標決定了欄位完整度的權重表。兩者對 AI 引用率的影響維度完全不同:
flowchart LR
subgraph Physical["實體商家 (is_physical=true)"]
P1["地址 15%"]
P2["GBP Place ID 15%"]
P3["營業時段 10%"]
P4["電話 10%"]
P5["服務項目 10%"]
P6["員工名單 10%"]
P7["url / name / logo 30%"]
end
subgraph Online["線上服務 (is_physical=false)"]
O1["url 20%"]
O2["description 15%"]
O3["logo_url 10%"]
O4["服務/產品功能 20%"]
O5["sameAs 外部連結 15%"]
O6["FAQ 10%"]
O7["其他 10%"]
end
Fig 7-3: 實體商家的「地址 + GBP」佔 30%,線上服務的「url + description」佔 35%。同一套演算法兩套權重,以正確反映使用者查詢 AI 的主要意圖類型。
百原平台的 UI 依 is_physical 動態顯示/隱藏欄位:實體類客戶會看到「地址」「營業時段」卡片,線上類則不會;這是 Ch 2 提及的「Visibility Module」的具體體現。
每個欄位有一個權重(0–100),填寫即加分。總完整度是各欄位權重的加權平均。核心計算邏輯:
function computeCompletion(brand, industry) {
const weights = industry.is_physical ? PHYSICAL_WEIGHTS : ONLINE_WEIGHTS;
let score = 0;
let maxScore = 0;
for (const [field, weight] of Object.entries(weights)) {
maxScore += weight;
if (isFilledMeaningfully(brand, field)) {
score += weight;
}
}
return Math.round((score / maxScore) * 100);
}
// 不只看欄位是否非空,還檢查「是否有意義」
function isFilledMeaningfully(brand, field) {
const value = getField(brand, field);
if (!value) return false;
// 過濾佔位符
if (typeof value === 'string' && PLACEHOLDER_PATTERNS.test(value)) return false;
// 關聯表需至少一筆
if (Array.isArray(value) && value.length === 0) return false;
return true;
}
早期實作只判斷欄位是否非空,導致客戶把 url 填成 "https://"、description 填成 "公司" 等佔位符來刷分。isFilledMeaningfully 追加三個檢查:
^(https?:\/\/)?$、^[a-zA-Z ]{1,3}$、空白字元等這類「形式完整但實質無用」的案例很常見,尤其是客戶不熟悉 GEO 工具時。UI 不阻止填寫,但演算法不計入分數,避免誤導後續優化建議。
flowchart TD
Start{使用者類型} -->|新建品牌| Wiz[Wizard<br/>線性 7 步驟]
Start -->|既有品牌| Dash[Dashboard<br/>完整度 Banner]
Wiz --> W1[Step 1: 基本資訊]
W1 --> W2[Step 2: 產業與描述]
W2 --> W3[Step 3: 地址 位置<br/>僅 is_physical]
W3 --> W4[Step 4: 營業時段<br/>僅 is_physical]
W4 --> W5[Step 5: 服務項目]
W5 --> W6[Step 6: 員工名單]
W6 --> W7[Step 7: FAQ 社群]
W7 --> Done[完成]
Dash -->|<80%| Alert[紅/琥珀警示]
Dash --> Edit[/brands/id/entity<br/>自由跳轉任意 Card]
Alert --> Edit
Edit --> Save[儲存即時更新<br/>完整度 %]
Fig 7-4: 新品牌走 Wizard 保證首次覆蓋率;既有品牌走 Edit 自由更新。兩條路徑共用同一套 Card 元件(DRY 原則)。
設計上 Wizard 每一步都允許「暫時跳過」:
這是產品哲學的選擇:讓品牌先存在於 AI,再追求完美。
Google Business Profile(GBP)提供的地點識別有三種 ID 型別,客戶常常只拿到其中一種的 URL:
| ID 類型 | 範例 URL | 用途 |
|---|---|---|
place_id |
https://www.google.com/maps/place/?q=place_id:ChIJ... |
Place Details API 的 primary key |
FTID |
https://maps.google.com/maps?ftid=0x0:0xe6... |
Google Maps 內部識別 |
CID |
https://www.google.com/maps?cid=... |
Customer ID,短網址形式 |
flowchart TD
In[貼入任意 GMB URL] --> Split{URL 型別}
Split -->|含 place_id:| P[抽 place_id]
Split -->|含 ftid=| F[抽 FTID<br/>轉換為 place_id]
Split -->|含 cid=| C[抽 CID<br/>Places API 查詢 → place_id]
Split -->|短網址 goo.gl| R[resolve 301 → 重新進入 Split]
Split -->|其他| X[回傳 null<br/>要求使用者貼完整 URL]
P --> Done[回傳 Place ID]
F --> Done
C --> Done
Fig 7-5: parser 對四種 URL 格式各有分支;任何無法解析的 URL 回傳明確錯誤,不猜測。
CID 是 Google 內部流水號,無法直接轉換為 Place ID。parser 呼叫 Google Places API findPlaceFromText 用 CID 反查:
async function cidToPlaceId(cid) {
const res = await fetch(
`https://maps.googleapis.com/maps/api/place/findplacefromtext/json?` +
`input=cid:${cid}&inputtype=textquery&fields=place_id&key=${API_KEY}`
);
const data = await res.json();
return data.candidates?.[0]?.place_id ?? null;
}
這個呼叫會計入 Google API 配額;parser 對同一 URL 設 24 小時 cache,避免重複消耗。
function generateBrandEntitySchema(brand, industry) {
const base = `https://${brand.primary_domain}`;
const graph = [];
// Layer 1: Organization / LocalBusiness
graph.push({
'@type': industry.schema_types, // 陣列,如 ["MedicalClinic", "LocalBusiness"]
'@id': `${base}/#org`,
name: brand.name,
url: brand.url,
description: brand.description,
logo: brand.logo_url,
...(industry.is_physical && {
address: buildAddress(brand.location),
telephone: brand.location?.telephone,
openingHoursSpecification: buildHours(brand.hours),
geo: buildGeo(brand.location),
}),
sameAs: buildSameAs(brand), // Wikipedia / Wikidata / LinkedIn / GBP
});
// Layer 2: Services
for (const svc of brand.services ?? []) {
graph.push({
'@type': 'Service',
'@id': `${base}/#svc-${svc.slug}`,
name: svc.name,
description: svc.description,
provider: { '@id': `${base}/#org` },
});
}
// Layer 3: Employees
for (const emp of brand.employees ?? []) {
graph.push({
'@type': emp.specialized_type ?? 'Person', // Physician / Attorney / ...
'@id': `${base}/#emp-${emp.slug}`,
name: emp.name,
jobTitle: emp.job_title,
worksFor: { '@id': `${base}/#org` },
});
}
return {
'@context': 'https://schema.org',
'@graph': graph,
};
}
此函數是 AXP 生成流程(Ch 6)與 Closed-Loop 幻覺修復(Ch 9)的共同底層。
is_physical 旗標觸發兩套不同權重表;實體商家重「地址/GBP」、線上服務重「url/description」導覽:← Ch 6: AXP 影子文檔 · 📖 目次 · Ch 8: GBP API 整合 →
Schema.org. Schema.org Vocabulary Specification. https://schema.org/docs/schemas.html ↩