← Source Code
Source Code

Skill Library 的技術債:SkillOps 原始碼解析

2026-05-29 · — views

多數 Agent 系統在 skill library 上只解決一個問題:如何找到對的 skill。BM25、dense retrieval、top-k 調整——這些都有一個隱含假設:library 裡的 skill 本身是健康的。

但 skill library 會腐爛。

一個在 100 個 skill 時運作良好的 library,到了 1000 個 skill 開始出現問題——不是因為 retrieval 演算法不夠好,而是因為 library 本身累積了技術債:30% 的 skill 是近似重複、20% 缺少任何正確性驗證、15% 的 interface 已經和下游 skill 型別不匹配。retrieval 抓到什麼,就把什麼傳給 planner——library 的健康狀態直接決定了 agent 的天花板。

SkillOps(arXiv:2605.13716, GitHub: Hik289/SkillOps)把這個問題說清楚了:Skill Library 不是靜態的 retrieval pool,而是會累積技術債的軟體生態系統。 它引入 Typed Skill Contract、Hierarchical Skill Ecosystem Graph(HSEG),以及一個讓 library 自我維護的 Library-Time Loop——維護 2000 個 skill 的完整 pass 成本是 <1 秒 CPU、約 $0.0026。

讀完精華版(2 分鐘),你會理解:

  • Typed Skill Contract (P,O,A,V,F) 是什麼,以及為什麼它讓 planning-time type checking 變得可能
  • HSEG 的 4 種邊型別各自偵測哪種技術債,dep 和 comp 邊為什麼都需要
  • 雙迴圈架構如何分離「這次任務的修復」和「library 結構的修復」這兩件不同的事
  • 為什麼移除 add_adapter 讓任務成功率從 79.5% 掉到 13.2%

這篇是論文原始碼解析,不是使用教學。


精華版

設計維度SkillOps 的選擇核心 trade-off
Skill 表示Typed Contract (P,O,A,V,F):前置條件、操作、帶型別的產出物、驗證器、已知失敗模式planning-time type checking 可行,但需要 Skill Contract Miner 從執行 log 自動萃取 contract
跨 skill 關係HSEG 4 種有向邊(dep, comp, red, alt):dep 管資料流、comp 管型別、red 管重複、alt 管替換比只有 dep 邊(GoS)多偵測 interface mismatch,代價是維護更複雜的圖結構
計畫建構dep + comp 雙邊約束的 Dependency Stitching:只有型別相容的轉移才進計畫type mismatch 在 planning-time 攔截,消除 runtime 類型錯誤;候選路徑空間因此縮小
Library 維護Library-Time Loop:5 維健康診斷 + CGPD 風險傳播 + 6 種 rule-based 維護行動近乎零 LLM calls(N=2000 全 pass <1s CPU),但 rule-based 有語意盲區
系統整合Plug-in interface:cleaned_lib = run_maintenance(raw_lib)不需要改任何 downstream 邏輯;retrieval-heavy agent 受益大,LLM planner 受益相對小

Skill Contracts = (P, O, A, V, F) 把每個 skill 變成有型別的 API 合約——P 是呼叫條件(函數 precondition)、O 是可執行操作(函數本體)、A 是帶型別的產出物(return type)、V 是驗證器集合(單元測試)、F 是已知失敗模式(known bugs)。V = ∅ 表示 Validation Gap:skill 執行出錯時,錯誤會靜默向下游傳播。

HSEG:library 定義為 ℒ = (𝒮, ℛ),其中 4 種邊型別各有用途——dep 邊表示「A 的產出可以滿足 B 的前置條件」,comp 邊表示「A 的輸出型別與 B 的輸入型別相容」,兩者都有才允許計畫中的 s_i → s_j 轉移;red 邊偵測近似重複(body-hash collision);alt 邊記錄可替換實作(task-time local repair 的 fallback)。

Task-Time Loop:4 個階段——SkillMatch(BM25 + semantic + precondition filter)→ Dependency Stitching(dep + comp 雙邊約束遍歷)→ Validator/Adapter Insertion(補缺口、修型別)→ Local Repair(用 alt 邊替換失敗 skill)。Adapter 不是自由格式 patch,而是插入圖的型別轉換節點,型別約束必須被恢復。

Library-Time Loop:只在健康分數下降超過閾值 Θ_maint 時才觸發——先對每個 skill 做 5 維健康診斷(Utility / Redundancy / Compatibility / Failure-Risk / Validation-Gap),再用 CGPD 把風險沿 dep 邊傳播到下游,最後執行 6 種 rule-based 維護行動。整個 pass 近乎零 LLM calls,因為每種行動的觸發訊號都是可計算的(body-hash、utility log、Jaccard 型別相似度),不需要語意推理。


設計問題簡答

為什麼需要 comp 邊,dep 邊不夠嗎? dep 邊說的是「語意上夠用」——s_i 的產出可以滿足 s_j 的前置條件。但這不代表型別直接匹配。GoS 只用 dep 邊,結果是 interface mismatch 要到 runtime 才爆。SkillOps 在 dep 邊之外追蹤 comp 邊,planning-time 就能偵測「dep 有、comp 沒有」的 case,插入 adapter 節點而不是等 runtime 失敗。Ablation 顯示,移除 add_adapter 行動讓 SR 從 79.5% 掉到 13.2%——comp 邊體系是整個系統最關鍵的一環。

Task-Time Loop 和 Library-Time Loop 分開有什麼意義? Task-time self-repair(如 SkillWeaver 的 honing loop)只修當前 episode——下次遇到同一個 broken skill 還是會失敗,因為 library 本身的 defect 沒有被清除。Library-Time Loop 從根本清除 defect,代價是要等累積足夠的 ΔH 才觸發維護,不是即時修復。兩者不是競爭,是互補:task-time 處理「當次問題」,library-time 處理「系統性問題」。

CGPD 解決了什麼問題? 如果只獨立診斷每個 skill,會看到下游 skill 失敗,卻找不到上游的根因。ContractGraph-Propagated Diagnosis 把風險分數沿 dep 邊向下游傳播,讓上游 skill 的缺陷被「預防性」標記——在失敗發生前就對下游 skill 插入 validator 或 adapter。傳播公式是 α-contraction,Banach 不動點定理保證在 O(log(1/ε)) 次迭代內收斂。

Library scale 變大為什麼不影響 SkillOps 的精度? Retrieval baseline 需要指定 top-k:k 太小漏掉好 skill,k 太大引入噪音——library 越大、noise 越多,top-k 裡混入的問題 skill 比例越高。SkillOps 的 typed signature matching 不需要 top-k,直接返回型別相容的候選路徑,「排名問題」變成「過濾問題」。測試結果:lib=2000、noise=90% 時,SkillOps 80.5%,最強 baseline(LLM_SP)49.2%,差距 31pp。

什麼樣的 agent 接上 SkillOps 受益最大? Retrieval-heavy agent(BM25、dense retrieval)受益最大——library 清乾淨之後,candidate pool 品質直接提升,Plug-in 帶來 +1pp 到 +2.9pp。LLM planner 受益小,因為它有自己的過濾機制。ReAct 完全不受影響,因為它把整個 library 放進 prompt,根本不依賴 retrieval。


以下是完整版,按需取用。


Typed Skill Contract (P,O,A,V,F) 是什麼?

Typed Skill Contract 把每個 skill 定義為 (P, O, A, V, F) 五元組:前置條件、可執行操作、帶型別的產出物、驗證器集合、已知失敗模式。這個表示方式讓系統在 library-time 就能推理兩個 skill 的 interface 是否相容——不必等到 runtime 才發現型別不對。

傳統 skill library 把 skill 當成純文字——一段描述加上可執行腳本。這種表示方式的根本問題在於:系統在 library-time(不執行任何任務的時候)完全無法推理兩個 skill 之間的 interface 是否相容。只有執行之後,runtime error 才告訴你型別不對。

SkillOps 的解法是定義 Typed Skill Contract:

s = (P, O, A, V, F)
     │  │  │  │  └── F:Known Failure Modes(已知失敗模式)
     │  │  │  └───── V:Validators(驗證器集合;V = ∅ = Validation Gap)
     │  │  └──────── A:Typed Artifact(帶型別的產出物)
     │  └─────────── O:Executable Operation(可執行操作)
     └────────────── P:Precondition(呼叫前狀態條件)

軟體工程的類比:P 是 precondition/guard,O 是函數本體,A 是 return value + type signature,V 是 unit tests/assertions,F 是 known bugs/edge cases。

有了 contract,系統就能在 library-time 做以下推理:

  • P_{s_i} 是否被當前狀態滿足?→ precondition filter(不可執行的 skill 直接排除,不靠 retrieval 的幸運)
  • type(A_{s_i}) 是否與 type(P_{s_j}) 相容?→ comp 邊(interface mismatch 在 planning-time 偵測)
  • V_s = ∅?→ Validation Gap(缺乏本地驗證,錯誤會靜默向下游傳播)

Skill Contract 不是手動標注的——SkillOps 有一個 Skill Contract Miner,從 execution logs 中解析 execution traces,自動辨識 P、O、A、V、F 各欄位。這讓現有 skill library 不需要全面重寫就能建立 contracts。

Validation Gap 為什麼是系統性問題

V = ∅ 的問題不在 skill 本身,在下游。當 O 執行錯誤但沒有 validator 攔截,錯誤 artifact 會默默傳入下一個 skill 的 precondition——那個 skill 看到的是「合理輸入」但實際上是壞資料,產出另一個錯誤 artifact 繼續往下傳。skill library 裡有多少 V = ∅ 的節點,就有多少潛在的靜默錯誤路徑。

Library-Time Loop 的 add_validator 行動的邏輯是:先偵測 V = ∅ 的 skill,再從相同 body-hash 的「兄弟 skill」(已有 validator 的近似版本)繼承 checklist-style validators——不需要 LLM 生成,繼承的成本是 O(1) hash lookup。


HSEG 的四種邊各自偵測哪種技術債?

HSEG(Hierarchical Skill Ecosystem Graph)把 library 定義為有向圖 ℒ = (𝒮, ℛ),用四種邊型別追蹤不同的技術債——dep 偵測資料流斷裂、comp 偵測型別 drift、red 偵測近似重複、alt 記錄可替換實作供 local repair 用。四種邊缺一不可:只有 dep 邊的系統(如 GoS)在 planning-time 看不到型別不匹配。

HSEG 有兩層結構:

HSEG
├── Internal Skill Graph(每個 skill 的 contract 內部圖)
│   P → O → A → V
│            ↘ F
│   把 skill 的狀態流建模為節點圖

└── External Graph-of-Graphs(跨 skill 的生態圖)
    skill_i ─────── skill_j(4 種 relation 型別)

四種邊的語意

邊型別記法定義用途
depsi →dep sjA(si) ⊆ P(sj)資料流:si 的產出可滿足 sj 的前置條件
compsi →comp sjtype(A(si)) ⊆ type(P(sj))型別相容:si 輸出型別與 sj 輸入型別匹配
redsi →red sjP(si) ≡ P(sj) 且 A(si) ≡ A(sj)重複偵測:兩個 skill 暴露等價 interface
altsi →alt sjgoal(si) = goal(sj) 且 O(si) ≠ O(sj)替換備選:相同目標、不同實作

dep 和 comp 分開的關鍵場景

s_i ─dep─→ s_j(語意上:s_i 的資料夠用)
    但 s_i ─comp/→ s_j(型別不直接匹配)

→ 需要插入 adapter 節點:s_i → a_ij → s_j
   其中 type(A_a_ij) ⊆ type(P_s_j)

GoS-style 系統只有 dep 邊——結果是 interface mismatch 只能在 runtime 才暴露。SkillOps 同時追蹤 comp,planning-time 就能偵測「dep 有、comp 沒有」的 case,在計畫中插入型別轉換節點而不是讓執行失敗。

red 邊:為什麼重複的 skill 是問題

直覺上重複不嚴重——多幾個 skill 頂多選錯,重試一下就好。但 retrieval 的精度是全域的:有 30 個近似重複的 web_search 類 skill,它們會佔據 top-k 的大部分 slot,把真正需要的 skill 擠出 candidate pool。red 邊讓 Library-Time Loop 在維護時找到這些 cluster,執行 merge 只保留效用最高的那一個。

alt 邊:Local Repair 的基礎設施

當 task-time 執行到某個 skill 失敗,系統的第一反應是找 alt 邊的鄰居——相同目標但不同實作——替換並重試。這比重新呼叫 LLM 修復快得多(O(1) graph lookup vs. LLM API call),失敗資訊也直接進入 library 的診斷 buffer,供 Library-Time Loop 下次維護時分析。


Task-Time Loop 如何用型別約束保證計畫品質?

Task-Time Loop 用四個階段把任務 τ 轉為 execution trace:先用 BM25 + semantic + precondition filter 篩選候選 skill,再沿 dep + comp 雙邊約束建構計畫路徑,插入 adapter 和 validator 填補型別缺口,執行時失敗則用 alt 邊替換。關鍵約束是 dep 且 comp 都有才允許 s_i → s_j 轉移,把 type mismatch 攔在 planning-time,不讓它到 runtime 才爆。

四個階段按序執行:

Algorithm: Task-Time Loop
─────────────────────────────────────────────────────────
Input:  Library L=(S,R), task τ
Output: Execution trace

1. C ← SkillMatch(τ, L)               # BM25 + semantic + precondition filter
2. π ← Stitch(C, R)                   # dep + comp constrained traversal
3. π ← InsertValidatorsAdapters(π, R) # fill validation gaps, fix type mismatches
4. trace ← Execute(π, τ)
5. while trace has failure at step k do
6.   π ← LocalRepair(π, k, trace)     # alt edge substitution or repair
7.   trace ← Execute(π, τ)
8. end while
9. return trace

Stage 1:Skill Matching

候選篩選結合詞彙和語意兩個維度:

r(s, τ) = λ · r_BM25(s, τ) + (1-λ) · r_sem(s, τ)

初選 top-k=10(BM25),再用 Jaccard 語意打分過濾,最後做 precondition filter——只保留 P 被當前狀態滿足的 skill。這一步直接排除大量文字相關但不可執行的 skill,是 SkillOps token cost 遠低於 baseline 的原因之一(每 task 110 tokens vs. LLM_SP 的 867 tokens)。

Stage 2:Dependency Stitching

在候選集 𝒞 中沿 dep + comp 邊搜尋最優執行計畫:

π* = argmax over π=(s_1,...,s_T):  Σ r(s_t, τ)
     subject to: s_t →dep s_{t+1}  AND  s_t →comp s_{t+1}

「dep 且 comp 都有」才允許計畫轉移。複雜度是 O(k · d_max),k 是計畫長度,d_max 是最大 HSEG 出度——比 O(N²) pairwise comparison 快得多。

Stage 3:Validator & Adapter Insertion

計畫建好後,掃描每個非終端 skill:

  • Validation gapV_s = ∅ → 標記為 unverifiable,嘗試插入 validator 節點
  • Type mismatch:dep 邊有、comp 邊沒有 → 插入 adapter 節點 a_ij,且 type(A_{a_ij}) ⊆ type(P_{s_j})

adapter 不是自由格式的 shim——它是插入圖的型別轉換節點,型別約束必須被恢復。Ablation 中移除這個機制讓 SR 從 79.5% 降到 13.2%,比移除 Task-Time Loop 本身(→ 15.7%)的影響還大。

Stage 4:Local Repair

執行時若 s_k 失敗且計畫仍可恢復:

  1. 在 HSEG 找 s_k 的 alt 邊鄰居(相同目標、不同實作),替換並重試
  2. 若無 alt 鄰居,用觀察到的失敗 trace 呼叫 repair(s_k)
  3. 若兩者都失敗,把失敗記錄進 Library-Time 診斷 buffer

local repair 的上限是 2 次嘗試(MaxLocalRepairAttempts = 2),超過就記錄進 buffer 讓 library-time 處理——不讓 task-time 無限重試拖慢整體吞吐量。


Library-Time Loop 怎麼讓 Skill Library 自我維護?

Library-Time Loop 不在每次任務後執行,而是等 library 整體健康分數下降超過閾值 Θ_maint 才觸發。觸發後的流程是:對每個 skill 做 5 維健康診斷(Utility、Redundancy、Compatibility、Failure-Risk、Validation-Gap),用 CGPD 把風險沿 dep 邊向下游傳播,再執行 6 種 rule-based 維護行動。全部步驟近乎零 LLM calls,N=2000 的完整 pass <1 秒 CPU。

Algorithm: Library-Time Loop
─────────────────────────────────────────────────────────
Input:  L=(S,R), execution trace log
Output: Maintained library L'

1.  ΔH ← DiagnoseHealth(L, trace)
2.  if ΔH < Θ_maint: return L        # skip if library is still healthy
3.  for each s in S:
4.    H_loc(s) = (h_u, h_r, h_c, h_f, h_v)   # 5 dimensions
5.    R_loc(s) = LocalRisk(H_loc(s))
6.  R_cgpd ← CGPD(R_loc, R)          # propagate risk along dep edges
7.  L ← MergeRedundant(L)
8.  L ← RepairHighRisk(L, R_cgpd)
9.  L ← RetireLowUtility(L)
10. L ← AddValidators(L, R_cgpd)
11. L ← AddAdapters(L)
12. return L' ← L

五維健康診斷

Library health score 是所有 skill 的 5 維加權平均:

H(L) = (1/|S|) · Σ [ w_U·U(s) + w_R·(1-R(s)) + w_C·C(s) + w_F·(1-F(s)) + w_G·(1-G(s)) ]

每個維度偵測一種技術債:

維度計算方式偵測的問題觸發的維護
U(Utility)最近 task calls 中成功用到 s 的比例低價值 skill 膨脹 retrieval poolretire(s)(需同時有重複 skill 存在)
R(Redundancy)含 s 的最大 red cluster 的正規化大小近似重複降低 retrieval precisionmerge(s_i, s_j)
C(Compatibility)dep 邊中同時也是 comp 邊的比例interface drift(型別已不匹配)add_adapter
F(Failure-Risk)實際執行失敗率(從 execution log 統計)runtime 損壞的 skillrepair(s)
G(Validation-Gap)1[V_s = ∅](二元)缺乏本地驗證,錯誤靜默傳播add_validator(s)

重要的設計細節:低 Utility 不直接觸發 retire。U(s) < θ_u 只有在「同時有重複 skill 存在」的條件下才會觸發 retire,避免誤刪暫時沒被使用的有效 skill。

CGPD:風險沿依賴圖傳播

單獨診斷每個 skill 有一個盲點——失敗的不一定是有問題的那個。

upstream_skill(高失敗率)
    └── ─dep──→ downstream_skill(自身程式碼正確)
                    → s 收到壞 artifact 後失敗

獨立診斷只看到 downstream 失敗,upstream 被忽略。ContractGraph-Propagated Diagnosis(CGPD)把風險分數沿 dep 邊向下游傳播:

R(t+1)(s) = (1-α) · R_loc(s) + α · max{ R(t)(s') : s' ∈ Parents(s) }

這是 sup-norm 下的 α-contraction,Banach 不動點定理保證從任意初值在 O(log(1/ε)) 次迭代內收斂到唯一不動點。

CGPD 讓系統能在上游 bug 傳播之前就對下游 skill 插入 validator——預防性維護,不是事後補救。

六種維護行動

所有行動都是 rule-based,觸發訊號完全可計算:

行動觸發條件實作方式LLM 呼叫
merge(s_i, s_j)body-hash collision(SHA-256)保留 utility 較高者,移除其餘
repair(s)失敗率 > θ_f 或 R_cgpd > θ_risk從 body-hash sibling 繼承 scripts
retire(s)U(s) < θ_u 且有重複 skill 存在移除 s 及所有 incident edges
add_validator(s)V_s = ∅ 或 R_cgpd > θ_valid從 sibling 繼承 checklist validators
add_adapter(s_i, s_j)dep 有但 Jaccard(types) < 0.3插入標準型別轉換 shim
instantiate(s, arg)task-time 參數綁定(不是 library-time)把任務特定 argument 綁定到泛用 skill

設計選擇是刻意的:把能計算的訊號都算出來,LLM 只在真正需要語意推理的 compact contract-level edits 才介入(實際上極少發生)。N=2000 的完整 pass 耗時 <1 秒 CPU,成本約 $0.0026 per maintenance cycle——比 SkillWeaver 的 task-time honing(每 task 2.93 LLM calls)低幾個數量級。


Ablation:哪個組件拿掉影響最大

移除組件SR(%)下降幅度
無(Full)79.5
add_adapter13.2-66.3pp
Task-Time Loop15.7-63.8pp
add_validator38.0-41.5pp
repair55.9-23.6pp
External Graph(HSEG)64.6-14.9pp
Library-Time Loop71.9-7.6pp
Internal Graph(contracts)72.2-7.3pp
CGPD79.0-0.5pp

三個發現值得注意:

add_adapter 比 Task-Time Loop 本身還關鍵。 這表示 SkillOps 的核心競爭力不是規劃演算法,而是型別系統——comp 邊 + adapter insertion 讓 planning-time type checking 成真,移除之後系統退化為比 baseline 更差的狀態(13.2% vs ReAct 的 12.8%)。

Library-Time Loop 單獨拿掉只降 7.6pp,但它是系統長期穩定的基礎。 ALFWorld 是短期 benchmark,library-time 的效益在 library 持續增長的長期使用情境中才會完整顯現——技術債清除的邊際效益隨 library 規模增大而增加。

CGPD 目前效益有限(-0.5pp)。 作者在論文中承認:validator 欄位還沒被 plan-time skill selection 消費,CGPD 的預防性能量只發揮了一部分。這是最有改進空間的地方。


SkillOps vs HermesAgent:兩種「skill 自我維護」的不同抽象層次

兩個系統都圍繞 skill library 的自我維護,但操作的對象完全不同——這個差異比乍看之下重要得多。

維度SkillOpsHermesAgent
Skill 本體可執行程式碼模組,有正式合約 (P,O,A,V,F)Markdown 指令文件(SKILL.md),載入 context 供 agent 讀取
管理粒度Library 層級:1000+ skills 之間的關係網路Agent 個體層級:單一 agent 累積自己的技能 repertoire
維護驅動者系統主動:5 維 health 指標 + CGPD 風險傳播 → 觸發 6 種 maintenance actionAgent 主動:每 10 次 iteration 後 spawn background review agent
關係追蹤HSEG 圖:dep/comp/red/alt 4 種邊,cascading degradation 可沿圖傳播related_skills frontmatter 欄位,無圖結構

最直接的比喻:SkillOps 像 npm/cargo 在管一個大型 package ecosystem,解決的是「1000 個 skill 之間的相依、衝突、冗餘、健康度」。HermesAgent 像個人知識庫(Obsidian),解決的是「一個 agent 如何從自己的工作中學習並固化 SOP」。

兩者真正重疊的只有一個設計哲學:把失敗模式顯式記錄下來。SkillOps Skill Contract 的 F(known failure modes)和 Hermes SKILL.md 對 pitfalls 與邊界條件的描述,做的是同一件事——讓下次執行不從頭探路。這個邏輯也出現在 HeuristicLearning 的 EnvSpec.known_failure_modes 和 ledger 的 failure_analysis 欄位,是這個研究方向的一條共同線索。

兩個系統不是競爭關係——一個做 library-level architecture health,一個做 agent-level experiential learning,兩個問題在一個完整的 Agent 系統裡都存在,只是沒有系統同時解決了兩者。


SkillOps 的設計假設與適用邊界

SkillOps 的設計在三個地方有明確假設,套用到真實部署前值得先確認:是否有可供 Miner 解析的結構化 execution logs、是否能接受 rule-based 維護的語意盲區、以及 library-time maintenance 是否會和既有的 task-time repair 機制衝突。

需要結構化 Skill Contracts。 不是所有環境都有可供 Miner 解析的 execution logs,也不是所有 skill 都能自動萃取出 (P,O,A,V,F)。論文的評估在 ALFWorld(文字遊戲),gold PDDL-style arguments 是半合成的——真實部署中的 log 品質可能參差不齊。

Rule-based 維護有語意盲區。 body-hash collision 能抓到實作完全相同的重複 skill,但語意相似、實作稍有差異(例如兩個功能等價的不同 API wrapper)的重複仍然漏網。這是刻意的取捨——不用 LLM 換來效能,接受語意層面的不完整。

與 task-time self-repair 可能衝突。 SkillOps 的 Library-Time Loop 和 SkillWeaver 的 task-time honing loop 都想修同一個 skill——兩個系統同時運行時,誰的修復版本留下來?這個衝突在論文中被標記為 future work。

Plug-in 設計的哲學是正確的——cleaned_lib = run_maintenance(raw_lib) 讓 SkillOps 成為可以接在任何現有系統後面的一層,而不是要求重寫整個 Agent 架構。但把 Skill Library 真正當作一個需要維護的軟體生態系統,而不是只是一個 retrieval pool,這個觀點轉換才是 SkillOps 最值得帶走的東西。