跳到主要內容

【2026 最新】Information Support Graph 是什麼?用三份 CSV 查出 Agent 任務缺資料

最後更新: ·
Information Support Graph 教學:先查 Agent 任務缺資料,再評成果

你請 Agent 比較三家供應商,它交出漂亮的推薦,卻把空白運費當成零。換一個更大的模型之前,先問:題目給的資料,真的足以做出決定嗎?Information Support Graph(資訊支援圖)就是把「答案需要哪些前提、前提在哪裡」攤開檢查的方法。

這篇寫給第一次設計 Agent 任務、也願意照著複製小段程式的新手。概念從零解釋;操作需要電腦已有 Python 3。你會用三份 CSV(逗號分隔的純文字資料檔)做一個虛構採購題,親手注入缺值、矛盾與不可讀來源,再檢查修補有沒有把答案一起塞給解題者。

方法背景來自 2026 年 10 月 27 日的 WorkFactory 論文;下方程式與採購數字是 AlphaLab 自製練習,採單次採購總成本,與論文的多年期成本案例分開。2026 年 11 月 2 日,我們執行了這份規則檢查程式與算術核對,範圍是資料診斷,沒有呼叫模型或重跑訓練。

先說結論:可解任務=前提齊全+來源可達+推導留給解題者

可解任務=前提齊全+來源可達+推導留給解題者。把它想成一道料理考題:食材、份量、限制要交代清楚,烹調與調味則留給考生。缺了一袋食材,不能只用成品不好吃來判定廚藝;把成品也放進材料包,又失去考試的意義。

  • 先倒推:每項交付需要什麼資料,再問檔案是否存在。
  • 分開檢查:欄位有值、跨檔一致、實際讀得到,各是一關。
  • 修補前提:補運費、對齊同一份報價;總成本和推薦仍讓解題者完成。

一、Information Support Graph 是什麼?先分清「事實」與「工作」

在 WorkFactory 中,圖包含資訊單位、承載它的資料位置,以及資訊之間的支援關係;一項結果也可能同時需要多個前提。資訊會區分已提供、需外取、待解題者推導,以及建題內部使用的內容。原論文的 附錄 B說明了這個邊界:任務需要的事實要能取得,待算的結果仍由解題者產生。

套進本篇的練習,「訂購一百個」是輸入,「總成本」是待算結果;quotes.csv 是載體,supplier=C 那一列則是具體位置。若只寫「看附件」,卻沒指出哪一欄,你還要再問一次:讀者能從同一份材料找到相同的數值嗎?

這張圖關心「憑什麼得出答案」。Graph Engineering 工作圖關心誰先做、誰等誰;Agent Harness則安排工具與執行迴圈。畫出一條執行箭頭,仍要另外核對箭頭所需的資料是否存在。

二、先倒推交付物:三份 CSV 各自負責什麼?

我們的題目是:買一百個 BOX,等級至少二、交期最多八天;在合格供應商裡選總成本最低者,同價按代號排序。全部金額採美元,運費按件,設定費只收一次;這個虛構題排除稅、折扣與其他費用。這些規則先寫清楚,解題者才不必猜。

①「採購清單」:數量和限制

痛點是「最便宜」沒有範圍。解法是把需求固定在 requirements.csv:quantity 是數量,min_grade 是最低等級,max_days 是最長交期,currency 是幣別。驗收時,每一項合格判斷都應回指這一列。

②「報價單」:原料數值

痛點是單價低,結帳卻未必低。quotes.csv 分開列 unit_price、freight_per_unit 和 setup_fee。本題的計算關係是 quantity × (unit_price + freight_per_unit) + setup_fee。這是計算規則,並未替任何供應商填好總成本。

③「同一張身分證」:對齊對象與範圍

痛點是兩份資料看似相近,實際指向不同規格。profiles.csv 以 supplier + sku 對齊等級與交期。本題明定兩檔描述同一個當期報價,因此同欄應一致;真實採購若有不同日期、數量區間或運送條款,先把這些範圍加進識別條件,別急著判資料互相打架。

Information Support Graph:需求、報價和供應商資料共同支援資格、成本與推薦
AlphaLab 自製練習的支援關係:多個前提要一起成立,資料位置也要能追到。這是教學簡圖,未展示解題結果。

三、Information Support Graph 實作:先建立材料包

先在新空資料夾,將下列程式存成 make_lab.py,再執行 python3 make_lab.py;Windows 若以 Python Launcher 啟動,可用 py -3 make_lab.py。程式會建立 isg-lab,已存在就停止,避免蓋掉上一輪練習。CSV 用純文字編輯器保存;手動編輯時保留欄名、半形逗號與小數點。

from pathlib import Path
root = Path('isg-lab')
root.mkdir()  # Stop if it already exists; do not overwrite a prior run.
files = {
'requirements.csv': '''sku,quantity,min_grade,max_days,currency
BOX,100,2,8,USD
''',
'quotes.csv': '''supplier,sku,unit_price,freight_per_unit,setup_fee,grade,lead_days,currency,source
A,BOX,9,1,100,2,7,USD,profiles.csv
B,BOX,8,1,0,2,10,USD,profiles.csv
C,BOX,10,0.5,0,3,5,USD,profiles.csv
''',
'profiles.csv': '''supplier,sku,grade,lead_days
A,BOX,2,7
B,BOX,2,10
C,BOX,3,5
''',
'TASK.txt': '''Use only TASK.txt and the three CSV files in this directory.
Choose one supplier for 100 BOX units. Minimum grade is 2 and maximum
lead time is 8 days. All quotes are for the same current offer and in USD.
Use requirements.csv as the requirement record. Each quote must agree
with its profile on grade and lead_days, and its source must be readable.
Total = quantity * (unit_price + freight_per_unit) + setup_fee.
No tax, discount, or other charges apply in this fictional exercise.
Choose the lowest total among eligible suppliers; break equal totals
by supplier ID ascending. Do not treat a blank price as zero.
If required evidence is missing or contradictory, report the blocker
and do not finalize a ranking. Write RESULT.md with the eligibility,
cost calculation and source row for each supplier, then your decision.
'''
}
for name, body in files.items():
    (root / name).write_text(body, encoding='utf-8')
print('Created isg-lab: TASK.txt + 3 CSV files')

這時先別加 total_cost 或 winner 欄。給解題者的範圍是 TASK.txt 和三份 CSV;出題者可另畫支援圖、保存答案本,放在工作目錄之外。若 Agent 同時能讀上層目錄,單靠文字說「不要看」不構成隔離;試跑時要用工具或執行環境限制讀取範圍。

四、用一個小檢查器,找出三種阻塞

把下面程式存成材料包外的 check_inputs.py。在同一個父資料夾執行 python3 check_inputs.py isg-lab。程式以 Python 的 DictReader按欄名讀資料,並用 Decimal從字串檢查數值;newline="" 遵循 CSV 官方文件的開檔方式。

import csv
import sys
from decimal import Decimal
from pathlib import Path

root = Path(sys.argv[1]).resolve()

def require(ok, message):
    if not ok:
        raise ValueError(message)

def read(name, fields):
    with (root / name).open(encoding='utf-8-sig', newline='') as f:
        reader = csv.DictReader(f)
        require(reader.fieldnames == fields.split(), name + ': schema')
        rows = list(reader)
    require(bool(rows), name + ': empty file')
    for row in rows:
        require(None not in row and all(v is not None and v.strip()
                for v in row.values()), name + ': missing value')
    return rows

def number(text, integer=False, positive=False):
    n = Decimal(text)
    require(n.is_finite() and n >= 0, 'invalid number: ' + text)
    require(not integer or n == n.to_integral_value(), 'not an integer')
    require(not positive or n > 0, 'must be positive')
    return n

try:
    reqs = read('requirements.csv',
                'sku quantity min_grade max_days currency')
    require(len(reqs) == 1, 'expected one requirement')
    req = reqs[0]
    number(req['quantity'], integer=True, positive=True)
    number(req['min_grade'], integer=True)
    number(req['max_days'], integer=True)
    profiles = read('profiles.csv', 'supplier sku grade lead_days')
    quotes = read('quotes.csv', 'supplier sku unit_price freight_per_unit '
                  'setup_fee grade lead_days currency source')
    keys = lambda rows: [(r['supplier'], r['sku']) for r in rows]
    require(len(set(keys(profiles))) == len(profiles), 'duplicate profile')
    require(len(set(keys(quotes))) == len(quotes), 'duplicate quote')
    require(set(keys(quotes)) == set(keys(profiles)), 'unmatched supplier')
    require(len(quotes) == 3, 'expected three suppliers')
    profile_map = dict(zip(keys(profiles), profiles))
    for q in quotes:
        label = q['supplier'] + ': '
        require(q['sku'] == req['sku'], label + 'SKU mismatch')
        require(q['currency'] == req['currency'], label + 'currency mismatch')
        for field in ['unit_price', 'freight_per_unit', 'setup_fee']:
            number(q[field])
        p = profile_map[(q['supplier'], q['sku'])]
        for field in ['grade', 'lead_days']:
            require(number(q[field], integer=True) ==
                    number(p[field], integer=True), label + field + ' conflict')
        source = (root / q['source']).resolve()
        require(source.parent == root, label + 'source outside workspace')
        with source.open(encoding='utf-8-sig') as f:
            f.read()
        require(source == root / 'profiles.csv', label + 'unexpected source')
    print('PASS: declared inputs are filled, consistent and readable')
except (ValueError, OSError, csv.Error, ArithmeticError) as exc:
    print('BLOCKED:', exc)
    sys.exit(1)

原始材料應出現 PASS: declared inputs are filled, consistent and readable。這句話刻意限縮在已宣告的檢查:欄位、識別鍵、數字、同一報價的一致性與本機來源可讀。它不會判斷真實供應商說的是不是真話,也不會讀懂任意新題目的自然語言,更未評分最終推薦。

①「漏一塊拼圖」:把 C 的運費清空

痛點是空格被默認成零。在 quotes.csv 的 C 列,把 freight_per_unit 的 0.5 刪掉,保留左右逗號。再跑檢查器,應得到 BLOCKED: quotes.csv: missing value。這表示當前題目要求的成本前提缺失;先補回可信數值,再談誰更便宜。

②「同一張單據說兩種話」:改 A 的交期

先還原 C 的運費,再把報價檔 A 的 lead_days 從 7 改為 9,供應商檔保留七天。預期是 BLOCKED: A: lead_days conflict。這裡故意讓矛盾跨過八天門檻:若直接挑比較有利的數值,就可能改變資格。確認原始報價後,只修正有依據的那一份。

③「有地址,門卻打不開」:改來源檔名

還原 A 的七天,再將 C 的 source 改成 missing-evidence.csv。重跑應收到 BLOCKED 與找不到檔案的訊息。錯誤路徑依你的電腦而異。本次用本機缺檔模擬取證失敗;它沒有測量網站、登入限制或網路狀態。實際外部來源則須保存網址、時間、工具錯誤與存取條件。

來源檢查還用 Path.resolve()展開實際路徑,再限制在材料包內,避免把 ../ 指到別處。這是本練習的路徑檢查;真正隔離 Agent 的檔案權限,仍由你使用的執行環境設定。

五、修好資料後再解題:把三張成績單分開

AlphaLab 本次跑過原始材料、三種單獨注入的缺陷,以及各自還原後的版本:原始與還原版通過,缺值、交期矛盾、缺檔各被阻擋。這七次是同一個確定性程式的檢查紀錄;它們支持「這些規則抓得到這三種缺陷」,不構成 Agent 成功率或一般任務完整性的估計。

真正的解題試跑,要開全新工作階段,只掛載目前的 TASK.txt 和三份 CSV,要求交出 RESULT.md。別附上舊診斷、答案本或前次輸出。若工具無法限制可見範圍,就先把這一輪標為未完成隔離驗收,別把它混入乾淨試跑。

WorkFactory 的修補流程也保留解題工作:修正阻塞資料後,重新執行探查,而非直接交出完成的推薦。沿用這個原則,本題只補原始欄位;不要因為 C 難算,就把它從候選者刪除,或新增「選 C」提示。

  • 環境單:哪些必需資訊已提供、是否一致、是否能讀取?缺陷指向哪個檔案、列與欄?
  • 工具單:記成功呼叫數與總呼叫數,例如成功讀檔次數/全部讀檔嘗試;保留每次失敗的類型。尚未執行就記「未測」,不要填零或滿分。
  • 成果單:打開 RESULT.md,核對資格、算式、引用列與最後選擇。另記是否杜撰缺值;工具回合較少只是一項過程觀察。

這個拆法也符合 Anthropic 的 Agent 評估說明對執行紀錄與最終環境成果的區分。聊天說「完成」是一段文字,檔案確實存在且內容合格,才是這一題的交付證據。想設計多題回歸,可接著讀 AI Evals 七步教學。

完成自己的解答後再核對:A 的成本是 100 × (9 + 1) + 100 = 1,100 美元;B 是九百美元,但十天超過限制;C 是 100 × (10 + 0.5) = 1,050 美元,等級與交期合格,所以本題選 C。這份答案放在文章供讀者自查,請別把本段或整篇文章交進解題工作區。

六、三個常見誤判:別把題目修成送分題

第一個是把合理分歧當缺陷。本題要求同一份當期報價一致,交期衝突才會阻塞;若題目本來就是「調查兩份報價為何不同」,矛盾可能正是工作材料。先問衝突是否妨礙最低交付,或只是需要解釋的證據。

第二個是把檢查通過當萬用保證。這支檢查器固定對應一個 SKU、三家供應商與本機來源。換成多幣別、分批交貨、階梯價格,就要新增範圍、公式與驗收條件;先讓新規則在刻意做錯的樣本上失敗,再相信通過結果。

第三個是把修補後變好全算給模型。比較模型時,固定材料版本、工具權限、提示與預算;比較修補時,固定解題配置。先把資料改動與模型改動拆成兩組對照,才說得清楚改善來自哪裡。需要判斷既有示範是否偷看答案,可接著讀 Trajectory2Gym 的可見證據練習。

常見問題:八個先講答案的判斷

1. 一定要安裝 WorkFactory 才能畫圖嗎?

本篇練習直接用紙筆與 Python 標準函式庫。WorkFactory 倉儲提供研究脈絡;這裡的三份 CSV 與檢查器由 AlphaLab 自行設計,請分開看待。

2. 它和知識圖譜有什麼差別?

先看用途。這裡從一項交付倒推必要前提與位置,目的是檢查任務支援;不用先替整間公司的所有知識建模。

3. 有空白欄,就一定整題不可解嗎?

看它是否必要。備註空白與必要運費空白,後果不同;本題刻意把宣告的欄位都設為必填,換題要重新定義。

4. 缺運費時,Agent 可以合理估算嗎?

要先看題目是否允許。本題要求可比較的確定成本,應回報缺口;若另設估算任務,需提供估算規則並把估計值標清楚。

5. 所有跨檔差異都要改成一樣嗎?

先對齊對象與範圍。不同日期、規格或交貨條件可以有不同數值;本例才明定兩檔屬於同一報價。

6. 來源檔讀得到,就證明資料正確嗎?

還要驗內容。程式可驗路徑與欄位,真實取證還須確認來源身分、適用期間與那一列究竟支持什麼。

7. 程式出現 PASS,表示 Agent 已經合格嗎?

尚未評到這一層。接著收 RESULT.md,按資格、算術與證據評分;把未跑的模型測試留為未測。

8. 可以把支援圖和答案都放進工作區嗎?

要配合測試目的。若要測從原始資料自行解題,答案與舊診斷放在外部;若任務是審查既有分析,已算出的結果可以成為待審材料,但那是另一張考卷。

給新手的三個重點

  • 先畫「交付物需要什麼」,再整理「我有什麼檔案」。
  • 每次只注入一種缺陷,保存修補前後的 CSV 與檢查輸出。
  • 環境、工具、成果各留一張單;修好前提後,重新讓解題者做自己的工作。

接著閱讀

左右滑動查看更多推薦

下一步:今天先刪掉一個必需數值

建立材料包、清空 C 的運費、確認檢查器真的阻擋,再補回原數值重跑。記住前提齊全+來源可達+推導留給解題者:當你能說清楚缺的是哪一項證據,下一次 Agent 卡住,就有一個具體的修正起點。更多練習可從 AlphaLab AI 專區挑選,或到 AlphaLab 課程建立完整的學習路線。

ALPHALAB 社群

有問題?來 Telegram 聊

和 Terry、編輯、其他網友一起討論這篇文章。提問、分享觀點,回覆更即時。

加入 Telegram 討論

📩 訂閱 AlphaLab 電子報

週日 Weekly 週報+週二、週四 Alpha Signal,每週最多三封。

我們不會 spam,隨時可退訂。已訂閱?管理訂閱偏好(會寄登入連結到你的信箱)

主題篩選與退訂說明

寄送日期以台灣時間為準。主題偏好會篩選每期精選,並非每篇新文章的即時通知;當期符合主題的文章不足時會略過寄送。

未勾選任何主題會收到所有主題的精選,並不會停止寄信。

取消勾選 Alpha Signal 可停止週二、週四短報,仍保留週日週報。若要停止所有電子報,請使用信件底部的「取消訂閱」。