你問 Agent:「為什麼要先遷移 Checkout?」它若只回「因為文件看起來相關」,你仍不知道引用哪一份文件、哪個依賴會受影響,也無法把推理材料交給同事覆核。Semantica Context Graph 想解的正是這個缺口:把來源、事實、服務、決策與因果關係,變成可查詢的圖,而不是只留一段答案。
2026 年 8 月 20 日查核時,Semantica 位於 GitHub 官方 weekly Trending 頁面。這是值得研究的採用代理訊號,不是品質、部署規模或教學需求的證明。這篇專為第一次接觸知識圖譜的開發者寫:用一個完全虛構的 API 遷移案,從零建立 bounded audit trail,最後輸出 JSON 與 W3C PROV-O Turtle。
先說清楚驗證範圍:本文依 Semantica 0.6.5 的固定 tag、原始碼與測試撰寫,範例檔已通過 Python 語法編譯;AlphaLab 這次環境沒有安裝 Semantica 的完整依賴,因此沒有把下文包裝成效能實測或執行結果。所有人物、服務、文件、日期與決策都是教學 fixture,終端輸出採「你執行後應看到的格式」呈現。
先說結論
- 圖不會自動讓答案變真。它把你已記錄的來源、關係與處理步驟變得可追;來源本身錯了,圖仍會忠實保留錯誤。
- 向量檢索與 Context Graph 是互補層。前者擅長找語意相近內容;後者把依賴、所有權、precedent 與 lineage 寫成明確關係。
- 先輸出、再執行。本 lab 故意放入一個日期衝突;assertion 必須抓到它,輸出標成
review_required,不可讓 Agent 靜默採用其中一個日期。
Semantica Context Graph 的一句話定位
可稽核 Agent = 決策節點 + 證據邊 + 來源譜系
少一項,你最多只有「看起來合理」的答案,還沒有可覆核的決策紀錄。
ContextGraph 是知識與決策的結構層:節點可代表文件、事實、服務、團隊與 Decision;邊則明寫 SUPPORTED_BY、DEPENDS_ON、OWNED_BY、PRECEDENT_FOR。ProvenanceManager 是來源譜系層,記錄某個實體從哪裡來、使用哪些上游實體、由哪個 activity/agent 產生,以及 checksum 是否仍一致。

這和向量 RAG不是二選一。向量層可以先把候選段落找回來;圖層再回答「Checkout 依賴誰」「誰負責」「這個決策沿用哪個 precedent」。若你還沒建立 Agent 的資訊邊界,可先讀Context Engineering;Context Graph 是其中一個可結構化、可查詢的零件。
這個 lab 要回答哪四個問題?
- Precedent:以前有沒有相似的 API 遷移決策?當時怎麼做?
- Impact:若先遷移 Checkout,會沿著哪些依賴碰到 Billing 與 Payments Team?
- Conflict:ADR 寫 9 月 30 日停用,Slack 卻寫 12 月 31 日,系統能否把歧異留給人處理?
- Lineage:Agent 的 proposal 使用哪些 fact?fact 又來自哪份來源?checksum 與 hash chain 是否完整?
這裡的目標不是把整家公司建成萬能圖譜,而是先做一個有入口、有出口、有失敗條件的小型稽核情境。當它能穩定回答四題,再把 schema 擴到真實資料。這也符合Agent Harness的做法:先釘死控制邊界,再增加能力。
步驟一:固定 Semantica 0.6.5,不跟 main 混用
截至 2026 年 8 月 20 日,PyPI 最新穩定版是 0.6.5,tag 對應 commit 5b319560fb0b8403644b70bc592864418cdcc740。官方 main 雖仍顯示 0.6.5,實際已有 release 後的變更;因此教學只使用 stable tag 具備的方法,不從 main 複製新 API。
請先確認 python3 --version 為 3.10 以上;Semantica 自身 metadata 雖標示 >=3.8,但 0.6.5 的必要依賴目前實際把安裝下限推到 3.10。
mkdir semantica-audit-lab
cd semantica-audit-lab
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install "semantica==0.6.5"
Semantica 0.6.5 的 wheel 宣告數十個必要依賴,包含 NumPy、PyTorch、Transformers、spaCy、NetworkX 與 RDFLib;安裝容量與時間都不像一個極小型 graph package。請用獨立 virtual environment,不要直接灌進既有 production 專案。0.6.5 的 release note 也把它標為安全性版本;若要開啟 Explorer、MCP 或遠端 endpoint,先讀官方 v0.6.5 release,不要沿用更舊的網路部署範例。
步驟二:把來源、事實、服務與決策建成圖
建立 audit_lab.py。第一段關閉自動抽取與進階分析,因為這個 lab 的重點是明確 schema,不是讓 LLM 猜關係。三份來源分別是 ADR、事故報告與 Slack note;三個 fact 都保留來源 ID、原句與 confidence。
import json
from dataclasses import asdict
from pathlib import Path
from semantica.conflicts import ConflictDetector
from semantica.context import ContextGraph
from semantica.provenance import ProvenanceManager
OUT = Path("audit_output")
OUT.mkdir(exist_ok=True)
graph = ContextGraph(
advanced_analytics=False,
extract_entities=False,
extract_relationships=False,
)
prov = ProvenanceManager(storage_path=str(OUT / "provenance.db"))
sources = {
"src_adr_017": ("ADR-017", "repo://architecture/ADR-017.md"),
"src_postmortem": ("Payment incident", "repo://incidents/payment-2026-07.md"),
"src_slack": ("Migration note", "slack://payments/1738"),
}
for source_id, (label, uri) in sources.items():
graph.add_node(source_id, "Source", label, uri=uri)
prov.track_entity(source_id, source=uri, metadata={"label": label})
for node_id, node_type, label in [
("svc_checkout", "Service", "Checkout Service"),
("svc_billing", "Service", "Billing Service"),
("team_payments", "Team", "Payments Team"),
]:
graph.add_node(node_id, node_type, label)
facts = [
("fact_deadline", "API v1 sunset is 2026-09-30", "src_adr_017", 0.95),
("fact_dependency", "Checkout calls Billing API v1", "src_postmortem", 0.90),
("fact_owner", "Payments Team owns the migration", "src_slack", 0.70),
]
for fact_id, text, source_id, confidence in facts:
graph.add_node(fact_id, "Fact", text, confidence=confidence)
graph.add_edge(fact_id, source_id, "SUPPORTED_BY")
prov.track_entity(
fact_id,
source=source_id,
parent_entity_id=source_id,
source_quote=text,
confidence=confidence,
metadata={"assertion": text},
)
graph.add_edge("svc_checkout", "svc_billing", "DEPENDS_ON")
graph.add_edge("svc_checkout", "team_payments", "OWNED_BY")
confidence 是你輸入的 belief,不是真實性證書。若 ADR 本身過期,把它寫成 0.95 只會精確記錄一個過度自信的錯誤。Production 應把 source credibility 的來源、調整者與時間也列入 provenance。
步驟三:新增 precedent 與帶證據的 decision record
record_decision() 會建立 first-class Decision node,保存 category、scenario、reasoning、outcome、confidence、entities 與 decision maker。先放一筆舊版 API 遷移,再放今天的 proposal,最後以 PRECEDENT_FOR 明寫兩者關係。
precedent_id = graph.record_decision(
category="api_migration",
scenario="Migrate Checkout away from legacy Payments API v0",
reasoning="A dated ADR and incident record show the old API blocks recovery",
outcome="Use a staged migration with a rollback window",
confidence=0.82,
entities=["svc_checkout", "svc_billing"],
decision_maker="platform-council",
)
decision_id = graph.record_decision(
category="api_migration",
scenario="Migrate Checkout away from legacy Payments API v1",
reasoning="ADR-017 sets a deadline; the incident shows a live dependency",
outcome="Propose Checkout first with a seven-day rollback window",
confidence=0.86,
entities=["svc_checkout", "svc_billing", "team_payments"],
decision_maker="migration-agent",
)
graph.add_causal_relationship(precedent_id, decision_id, "PRECEDENT_FOR")
graph.add_edge(decision_id, "fact_deadline", "SUPPORTED_BY")
graph.add_edge(decision_id, "fact_dependency", "SUPPORTED_BY")
graph.add_edge(decision_id, "svc_checkout", "IMPACTS")
prov.track_entity(
decision_id,
source="agent://migration-agent",
used_entities=["fact_deadline", "fact_dependency", "fact_owner"],
activity_id="activity_plan_api_migration",
agent_id="migration-agent",
agent_type="software_agent",
confidence=0.86,
metadata={"outcome": "propose_checkout_first"},
)
本文所說的「可重跑 assertion」,是我們對 ContextGraph、conflict 與 provenance 輸出寫 Python assert;範例不假設或呼叫額外的框架 Assertion API。這個界線很重要,因為讀者複製的每一行都應能在固定的 0.6.5 surface 找到對應。
步驟四:同時查 precedent、impact、conflict、lineage
下面四個查詢各自對準一個失敗模式。穩定版 find_similar_decisions() 的這條路徑主要做文字集合重疊,不應宣傳成向量語意搜尋;它適合當候選 precedent helper。Impact 則沿我們親自寫入的 IMPACTS → DEPENDS_ON/OWNED_BY 邊走三 hops。
precedents = [
item for item in graph.find_similar_decisions(
"Migrate Checkout away from legacy Payments API",
category="api_migration",
min_similarity=0.05,
)
if item["decision"]["id"] != decision_id
]
impact = graph.get_neighbors(
decision_id,
hops=3,
relationship_types=["IMPACTS", "DEPENDS_ON", "OWNED_BY"],
include_distance_metadata=True,
)
conflicts = ConflictDetector().detect_value_conflicts(
[
{"id": "payments_api_v1", "source": "ADR-017",
"sunset": "2026-09-30", "confidence": 0.95},
{"id": "payments_api_v1", "source": "Slack note",
"sunset": "2026-12-31", "confidence": 0.60},
],
property_name="sunset",
)
lineage = prov.get_lineage(decision_id)
integrity = prov.check(strict=True)
chain = prov.verify_chain()

ConflictDetector 只負責把同一 canonical entity 的 sunset 歧異浮出來。即使之後使用 resolver,它也不代表 winner 已自動寫回 graph;你仍要建立人工覆核、persist 與新 provenance entry。這正是AI Evals要驗的地方:不是答案看起來順,而是衝突能否穩定觸發阻擋。
步驟五:用 assertion 擋住缺證據與靜默衝突
把驗收條件直接寫成程式。這個 fixture 的正確狀態不是「沒有衝突」,而是「精確抓到一個衝突並要求 review」。若 Billing 沒出現在 impact、precedent 消失、lineage checksum 失敗,程式立即停止,不產生可供下游執行的 clean verdict。
assert precedents, "No prior migration precedent found"
assert any(row["id"] == "svc_billing" for row in impact), \
"Billing impact is missing"
assert len(conflicts) == 1, \
"Expected one unresolved sunset-date conflict"
assert lineage["integrity_verified"], \
"A lineage checksum failed"
assert integrity["valid"] and chain["valid"], \
"Provenance integrity failed"
bundle = {
"review_state": "review_required",
"decision_id": decision_id,
"graph": graph.to_dict(),
"precedents": precedents,
"impact": impact,
"conflicts": [asdict(item) for item in conflicts],
"lineage": lineage,
"integrity": integrity,
"hash_chain": chain,
"audit_log": prov.audit_log(format="json"),
}
(OUT / "audit_bundle.json").write_text(
json.dumps(bundle, ensure_ascii=False, indent=2, default=str),
encoding="utf-8",
)
(OUT / "audit_bundle.ttl").write_text(
prov.export_prov(
format="turtle",
base_uri="https://example.com/audit/",
),
encoding="utf-8",
)
print(f"AUDIT_READY_REVIEW_REQUIRED: {decision_id}")
print(f"JSON: {OUT / 'audit_bundle.json'}")
print(f"PROV-O: {OUT / 'audit_bundle.ttl'}")
執行 python audit_lab.py 後,終端應出現一個隨機 UUID,以及兩個檔案路徑。audit_bundle.json 保存 graph、四種查詢結果與完整 audit log;audit_bundle.ttl 則把 provenance entries 序列化為 RDF。兩者是互補輸出:普通 graph JSON 不會因為「可匯出」就自動包含所有 provenance history。
PROV-O 到底證明什麼?
W3C PROV-O 提供 Entity、Activity、Agent,以及 derivation、usage、attribution 等關係的 RDF vocabulary。Semantica 0.6.5 的 export_prov(format="turtle") 會把追蹤資料轉成這種結構,所以其他 RDF 工具能讀懂「誰在什麼活動使用了哪些上游實體」。
它證明的是你所記錄的來源與處理鏈仍可追,不是證明 ADR 的內容真實,也不是揭露底層模型的隱藏 chain-of-thought。稽核者仍要檢查來源是否可信、entity resolution 是否正確、是否漏記邊,以及 schema 更新後舊資料是否仍符合語意。

向量 RAG、Context Graph、Workflow Graph 怎麼分工?
- 向量 RAG:問題是「哪些內容語意相近?」也可以保存 metadata、citation 與 filter,不能把它說成天生沒有 provenance。
- Context Graph:問題是「哪些實體以什麼關係相連?」價值來自 typed nodes/edges、decision records 與 lineage;前提是資料真的被正確寫入。
- Workflow Graph:問題是「程式下一步執行哪個節點?」它描述控制流程、checkpoint 與重播,並不等於公司知識圖;可與 Context Graph 疊在同一個 Agent 系統。
實務上的接法是:Harness 收到問題 → 向量層找候選文件 → Context Graph 補依賴與 precedent → policy/assertion 驗收 → Agent 產生 proposal → observability 記錄執行 trace。若要追 runtime latency、tool call 與錯誤,仍要加上Agent Observability;provenance 不取代 operational trace。
Semantica Context Graph 最常踩的 6 個坑
1. main 與 PyPI 都寫 0.6.5,就當成同一份程式
修法:production pin package 版本與 wheel hash;研究 main 時另外記 commit。不要把 main 才有的 to_kg_dict() 寫成 stable 0.6.5 教學。
2. 在 0.6.5 用 trace_decision_chain 驗 explicit causal edge
修法:穩定版這條 high-level path 沒有可靠納入顯式 causal edges;修正於 2026 年 8 月 14 日才進 main。本文將 PRECEDENT_FOR 寫進 graph,但用 graph export 與獨立 precedent 查詢驗收,不把 release 後修正倒灌進穩定版。
3. 把 find_similar_decisions 當向量 benchmark
修法:0.6.5 這條 ContextGraph 路徑以文字集合重疊為主;把它當候選召回,再用自己的 embedding retriever 與 eval 比較 precision/recall。
4. ConflictDetector 找到 winner,就以為 graph 已更新
修法:detector 只識別歧異;resolver 的結果也要由你的應用明確 persist,並留下 reviewer、策略、舊值、新值與新 provenance。
5. 有 checksum 就等於來源可信
修法:checksum 驗完整性,不驗事實。Source authority、freshness、owner 與撤回流程都要另建欄位與 policy。
6. 一開始就把全公司資料塞進圖
修法:先限定一個 decision type、三種 source、四個 query 與五個 assertions。fixture 穩定後,再加入 ACL、retention、PII redaction、schema migration、備份與 backend conformance test。
什麼情況值得用 Semantica?
- 值得評估:你有跨文件的依賴、所有權、決策 precedent 與 audit export 需求,而且願意明確維護 schema。
- 先用簡單方案:只有少量 FAQ、單一權威來源,或只需要 citation;向量檢索加 metadata 可能已足夠。
- 不要直接當合規閘門:你還沒建立 source authority、人工覆核、存取控制、衝突 persist 與版本回歸測試。
Semantica 的 repo 確實活躍,0.6.5 也提供 ContextGraph、決策、conflict 與 PROV-O 元件;但它仍是快速變動的 0.x 專案,star 與 publisher 自填的「Production/Stable」classifier 不能取代你自己的回歸 eval與安全檢查。
Semantica Context Graph FAQ
1. Semantica 會取代向量資料庫嗎?
不必取代。向量檢索負責語意候選,Context Graph 負責明確關係與多 hop traversal;同一套 Agent 可以同時使用兩者。
2. PROV-O 匯出能證明 Agent 的答案正確嗎?
不能。它標準化你記錄的 entity、activity、agent 與 derivation;來源錯誤、漏記或 entity 對錯人,仍會產生看似完整的圖。
3. 一定要使用 Neo4j 嗎?
這個 lab 不需要。ContextGraph 在記憶體執行,provenance 使用 SQLite;若換外部 backend,要另驗 adapter 的功能一致性與部署權限。
4. confidence 0.95 代表 95% 正確嗎?
不代表。除非你用有校準的評估定義它,否則只是系統輸入的 belief。務必連同評分者、方法與日期保存。
5. 為什麼不直接呼叫 trace_decision_chain?
因為本文固定在 PyPI 0.6.5。explicit causal edge 的 high-level tracing 修正晚於該 release;先驗 graph edge 與 lineage,等新 release 後再加 regression fixture。
6. ConflictDetector 會自動選可信來源嗎?
detector 不會。它先找歧異;resolver 可套投票、時效或 credibility 等策略,但 credibility 是你提供的規則,仍要保存與覆核。
7. audit_bundle.json 與 TTL 要保存多久?
依決策風險與資料政策決定。至少綁定 code version、schema version、source snapshot 與 decision ID;含個資或機密時,retention 與 access control 必須先於長期保存。
8. 下一個 production 步驟是什麼?
先把 fixture 接進 CI。每次升級 Semantica、修改 schema 或更換 backend,都重跑同一個 conflict、impact、lineage 與 export test;通過後才接真實 Agent。
給新手的 5 個重點
- 先記住 anchor:決策節點、證據邊、來源譜系缺一不可。
- 把 graph 與 vector 當互補,而不是互相取代。
- Stable 版本、commit、schema 與輸出格式都要固定。
- Conflict 被抓到是成功,不是失敗;靜默吞掉衝突才是失敗。
- 稽核輸出回答「資料怎麼來」,不自動回答「資料是不是真的」。
接著閱讀
左右滑動查看更多推薦
下一步:先讓一個 proposal 說得清楚
今天不要先做「全公司的腦」。先把這個 fixture 跑通,再換成你的一份 ADR、一個服務依賴與一筆真實但低風險的 proposal;只要 reviewer 能從 decision 一路追回 fact、source、conflict 與 export,你就已經跨過「Agent 說了算」與「Agent 提供可覆核建議」之間最重要的一步。想把它接進完整開發流程,可繼續逛AlphaLab AI 專區與AI 實戰課程。






