投研是典型的「長鏈條、多來源、要驗證」任務:一家公司要讀年報、翻公告、對市場數據、跑勾稽檢查、寫成報告;一個板塊要把這件事乘以二十。把整條鏈條塞給一個 Agent,它會在前半段還算聰明、後半段開始遺忘指令、遇到缺數時悄悄編一個補上——最後交出一份無法定位錯誤出處的長文。這不是模型不夠強,是任務結構與單 Agent 架構不匹配。
這篇文章把投研任務拆成收集、分析、報告三段流水線,給出每段的職責邊界與 input/output 契約、段間的結構化 JSON 傳遞格式、寫入範圍劃分、失敗隔離設計、驗證門控的擺放位置,以及成本與延遲的取捨框架。你會得到一張可以直接照抄的架構圖、三份 schema 範例、一份失敗模式清單。文中所有公司與數據均為虛構的教學示例。多 Agent 框架的具體操作可以配合 OMA 多 Agent 實戰教程,本篇處理的是設計層:為什麼這樣拆、段與段之間憑什麼互相信任。
一、為什麼單 Agent 做不完投研任務
四個結構性原因,每一個都無法靠「換更強的模型」解決:
1. 上下文容量與注意力稀釋。 一家公司的調研素材——年報關鍵章節、公告、行情數據、勾稽計算過程——動輒數十萬 token。即使塞得進超長窗口,實測經驗是:上下文越長,模型對中段資訊的檢索與遵守指令的能力越差。第 3 小時的「分析」早已忘記第 1 小時定下的口徑規則。
2. 職責混合導致錯誤不可定位。 單 Agent 邊收集邊推理邊寫作,輸出一段「應收帳款週轉天數異常拉長」時,你無法知道這個數字是抽取錯了、算錯了、還是編造的。三段拆分後,每段產出獨立落盤,錯誤可以精確定位到段與檔案。
3. 無法並行。 收集是 I/O 密集型工作(下載、抽取、比對),天然適合按標的並行;單 Agent 只能串行,板塊級任務的耗時不可接受。
4. 跨任務污染。 連續分析多家公司時,上一家的數據會滲進下一家的結論。這不是假想風險——本站記錄過一起真實事故:分析 A 公司時的基金減值數據,出現在隨後 B 公司的報告裡,而 B 公司根本沒有該業務(見 子代理隔離架構)。污染的根源是共享上下文,解藥是架構性的:每個標的獨立上下文、獨立寫入範圍。
反過來說,不是所有任務都該拆。單標的、單來源、一次性的快速問題(「這份公告說了什麼」),單 Agent 甚至單次提問就夠。拆分流水線的適用條件是:多標的或多來源、需要重跑、產出需要被驗證與追責。滿足兩條以上才值得付多 Agent 的複雜度成本。
二、三段分工:職責清單與「負面清單」
多 Agent 設計裡,定義每段不做什麼比定義做什麼更重要。職責清單決定產出,負面清單決定品質下限。
| 段 | 輸入 | 輸出 | 只做 | 絕不做 |
|---|---|---|---|---|
| 收集 Agent | 標的清單+資訊源白名單+字段清單 | facts JSON(值+來源指針+as-of) | 下載、抽取、欄位映射、metadata 規範化 | 分析、推理、評價;缺失值「合理估計」;白名單外的來源 |
| 分析 Agent | 收集段產物(只讀) | claims JSON(論斷+證據指針+信心等級) | 勾稽、指標計算、訊號判斷、交叉比對 | 訪問外部資料源;為缺數編造補丁;輸出無證據指針的論斷 |
| 報告 Agent | 分析段產物+報告模板 | 報告 Markdown+引用索引 | 組織敘事、渲染表格、生成引用索引 | 引入任何新事實;改動數字;對低信心論斷使用確定性語言 |
三個設計要點:
收集段禁止分析。 一旦收集 Agent 開始「順帶」總結,它就會為了敘事流暢而補全缺失——污染從源頭開始。收集段的產出應該是「無聊」的:一堆帶來源的三元組。
分析段禁止碰外部。 分析只允許在收集段的產物上工作。這條約束把「數據從哪來」的問題收斂到收集段一處,驗證只需要守住一個入口。分析發現缺數時的唯一合法動作是輸出 missing 標記與缺數影響說明,由編排層決定補採還是降級。
報告段禁止新事實。 報告裡的每個數字、每個論斷,都必須能在 claims JSON 中找到對應條目。這條規則讓「報告↔分析產物」的機械核對成為可能(第六節的 G3 門控)。
每段內部再按標的切片:收集段對每個標的起一個獨立子任務(獨立上下文),分析段同理。這就是三段流水線與按標的並行的組合:段間串行、段內並行。
三、段間資料契約:結構化 JSON 而非自由文字
段與段之間用自由文字傳遞(「收集 Agent 寫一段總結給分析 Agent 讀」)是多 Agent 系統最常見的偷工減料,代價是:來源指針丟失、無法機械驗證、下游把上游的推測當事實。契約必須是結構化的。
收集段輸出:facts(每個事實自帶完整 metadata):
{
"schema_version": "1.2",
"run_id": "run-20260930-001",
"target_id": "FAKE-001",
"target_name": "甲公司(虛構,教學用)",
"collected_at": "2026-09-30T10:00:00Z",
"facts": [
{
"id": "f-001",
"field": "revenue_fy2025",
"value": 1609.8,
"unit": "million",
"currency": "HKD",
"period": "FY2025",
"source": {"type": "filing", "doc": "annual-report-2025.pdf", "page": 88},
"extracted_by": {"agent": "collect-v3", "model": "model-a", "method": "ocr+rule"},
"status": "ok"
},
{
"id": "f-002",
"field": "trade_receivables_fy2025",
"value": null,
"unit": "million",
"period": "FY2025",
"source": {"type": "filing", "doc": "annual-report-2025.pdf", "page": 120},
"status": "missing",
"missing_reason": "附註表格跨頁,抽取失敗,需人工或二次抽取"
}
]
}
注意 f-002:缺失就是 null,絕不是估計值。missing_reason 讓編排層能決定重試策略。
分析段輸出:claims(每個論斷綁定證據與信心):
{
"schema_version": "1.2",
"run_id": "run-20260930-001",
"target_id": "FAKE-001",
"claims": [
{
"id": "c-001",
"type": "numeric",
"statement": "FY2025 現金轉換率為 0.29,連續四年下滑",
"value": 0.29,
"method": "ocf / net_profit,口徑見 analysis-policy v4",
"evidence_ids": ["f-010", "f-011", "f-021", "f-022"],
"confidence": "high",
"caveats": []
},
{
"id": "c-002",
"type": "qualitative",
"statement": "應收帳款增速持續高於收入增速,收入品質存疑",
"method": "rule CQ-002,參數 ar_gap_pp=15",
"evidence_ids": ["f-001", "f-003"],
"confidence": "medium",
"caveats": ["帳齡附註缺失,無法排除大客戶集中回款的替代解釋"]
}
]
}
報告段輸出:report(章節綁定 claim 引用):報告 Markdown 中每個數字與論斷帶 [c-001] 式引用標記,另附引用索引檔,列出每條 claim 到 fact 再到 source 的完整鏈路。
契約的執行靠 schema 校驗:每段收到輸入先跑 JSON Schema 驗證,schema_version 不匹配或缺必填欄位直接拒收並報錯,不嘗試「理解」不合規的輸入。契約升版時全鏈路一起升,禁止兩段之間用不同版本的 schema 對話。
四、寫入範圍劃分與衝突避免
多 Agent 並行時,檔案系統就是共享狀態,寫入範圍必須像資料庫權限一樣劃分:
runs/
└── run-20260930-001/
├── manifest.json # 編排層專屬:任務清單、狀態、run 級配置
├── collect/
│ ├── FAKE-001.facts.json # 收集 Agent-1 專屬寫入
│ ├── FAKE-002.facts.json # 收集 Agent-2 專屬寫入
│ └── ...
├── analysis/
│ ├── FAKE-001.claims.json # 分析 Agent 專屬寫入
│ └── ...
├── report/
│ ├── FAKE-001.md
│ └── citation-index.json
├── gates/ # 門控專屬:驗證結果只有門控進程可寫
│ ├── g1/FAKE-001.json
│ ├── g2/FAKE-001.json
│ └── g3/FAKE-001.json
└── logs/
規則四條:
1. 每個 Agent 只寫自己的輸出檔,檔名含 run_id 與 target_id;
任何 Agent 都不得寫別人的目錄,不得寫「全局匯總檔」
2. 匯總是最後一步的獨立產物:所有標的通過門控後,
由編排層(或獨立的匯總任務)一次性生成,生成過程唯讀所有輸入
3. 冪等重跑:同一 (run_id, target_id) 重跑即覆蓋自己的產物;
重跑不依賴上一次執行的記憶體狀態,只依賴落盤的輸入檔
4. 門控結果由門控進程獨佔寫入——被驗證者不能寫自己的驗證記錄,
這是防止「自己給自己蓋章」的架構手段
第 4 條背後有實證教訓:本站觀測過 LLM Agent 在連續執行中從「跳過驗證」惡化為「偽造驗證記錄」的行為(LLM Agent 自主繞過流程約束的實證分析)。只要驗證記錄的寫入權在被驗證者手裡,文字層面的「你必須如實記錄」就不可信。
五、失敗隔離:一個 Agent 出錯不污染全局
流水線的失敗哲學:預期每一段都會出錯,設計讓錯誤的影響範圍等於它的產生範圍。一個標的的收集失敗,影響範圍是那個標的;一個來源掛掉,影響範圍是使用該來源的字段。
隔離手段分四層:
| 層 | 手段 | 防的是什麼 |
|---|---|---|
| 上下文隔離 | 每標的獨立子任務、獨立會話,禁止跨標的共享工作記憶 | A 公司數據滲進 B 公司結論 |
| 檔案隔離 | 第四節的寫入範圍劃分 | 產物互相覆蓋、半成品被當成品 |
| 執行隔離 | 單標的失敗→標記 failed→其餘標的繼續;重試有上限與退避;來源連續失敗→熔斷該來源 | 一個標的拖死整個 run |
| 污染檢測 | 實體一致性校驗:每條 fact 的 target_id 必須與內容中出現的實體名一致;量級合理性斷言(單位、幣別、數量級);schema 校驗 | 抽取錯位、跨檔混入、單位事故 |
每個標的在編排層維護一個顯式的任務狀態機,狀態轉移只由門控結果觸發,不由 Agent 自報:
queued → collecting → g1_pass → analyzing → g2_pass → reporting → g3_pass → done
│ │ │
▼ ▼ ▼
collect_failed g1_reject g2_reject / g3_reject
(重試≤N次後) (退回重採, (退回上段重修,
記 missing 清單) 重修次數同樣有上限)
終態只有三種:done(全鏈路通過)、degraded(部分字段缺失但已標記,
人工裁決後放行)、failed(重試耗盡)。
不允許「無聲消失」:manifest 裡每個 target 必須落在某個終態。
狀態機的好處是把「部分成功」變成一等公民:一個標的的應收帳款附註抽不到,正確處理是標記 degraded、在報告裡明示缺數影響,而不是讓整個 run 卡死,更不是讓分析段悄悄補數。
失敗模式清單(設計評審時逐條過):
| 失敗模式 | 症狀 | 隔離/恢復設計 |
|---|---|---|
| 收集超時/來源改版 | facts 缺欄位、status=missing 激增 | 重試+退避;熔斷來源;缺欄位降級而非中斷 |
| OCR 錯位 | 數值量級異常、勾稽失敗 | G1 量級斷言+勾稽檢查攔截;回查原頁 |
| 跨標的污染 | B 檔出現 A 的實體名 | 實體一致性校驗(G1 硬性);上下文隔離 |
| 分析補數 | claims 的 evidence_ids 指向不存在或缺失的 fact | G2 證據存在性校驗:指針必須落到 status=ok 的 fact |
| 報告改數 | 報告數字與 claim 不一致(四捨五入、口徑偷換) | G3 機械核對:報告中每個數字與引用 claim 逐一 diff |
| 部分完成當全部完成 | 匯總表少了標的卻沒說明 | manifest 對帳:匯總產物必須解釋每個標的最終狀態(成功/失敗/剔除) |
| 成本失控 | token 消耗異常 | run 級預算+熔斷;單標的預算上限 |
| schema 漂移 | 下游解析錯誤或靜默丟欄位 | schema_version 嚴格校驗,不匹配即拒收 |
六、驗證門控放在哪裡:段間邊界+機械核對
門控的擺放原則:每個信任邊界一道門。段與段之間就是信任邊界——分析段不信任收集段的產出品質,報告段不信任分析段的輸出紀律,這種「不信任」要用代碼表達。
收集(每標的並行) ──▶ [G1] ──▶ 分析(每標的並行) ──▶ [G2] ──▶ 報告 ──▶ [G3] ──▶ 人工抽審 ──▶ 發布
│ │ │
schema+來源指針 證據存在性+重算斷言 數字機械核對
+實體一致性+勾稽 +信心標註率 +引用完整性+措辭掃描
│ │ │
fail→重採/標記missing fail→退回分析 fail→退回報告
三道門的具體內容:
- G1(收集後):schema 校驗;每個非 null 值必須有來源指針;實體一致性(fact 內容的實體=target);關鍵字段勾稽(三表勾稽公式,見 三表聯動與現金流品質檢查);按比例抽樣回原文檔重抽比對。
- G2(分析後):每條 claim 的 evidence_ids 必須存在且 status=ok;數值型 claim 用獨立代碼重算(不復用分析 Agent 自己的算式);信心等級必填;低信心 claim 自動進入人工複核佇列。
- G3(報告後):報告中每個數字與所引 claim 的機械 diff(容差內四捨五入要顯式登記);引用索引覆蓋率 100%;措辭掃描(對外部發布物檢查指令性、承諾性語言,見 投研 AI 的合規邊界)。
兩條架構級紀律。第一,門控必須是外部代碼,不是提示詞。在 prompt 裡寫「請仔細驗證」等於沒有驗證——被驗證者自己執行的「驗證」會被跳過甚至被偽造,這是實測結論(Agent 驗證架構的信任建築學)。第二,門控失敗的默認動作是攔截,不是警告後放行;放行需要人工在門控記錄上簽字。
七、成本與延遲的取捨
多 Agent 的成本結構與單 Agent 完全不同:多了編排開銷與重複校驗,省了長上下文的注意力浪費與重跑成本。優化槓桿按段分配:
| 段 | 成本特徵 | 優化槓桿 | 不能省的 |
|---|---|---|---|
| 收集 | I/O 密集、token 中等、可高度並行 | 小模型+規則優先(正則、模板抽取),大模型只處理非結構化殘段;來源快照快取 | 來源指針的完整性;抽樣回查 |
| 分析 | token 少、推理密度最高 | 用你可負擔的最強模型;一次只做一個標的(上下文小而乾淨,反而省 token) | 重算斷言;信心標註 |
| 報告 | token 中等、模板化程度高 | 中檔模型+嚴格模板;引用索引機械生成而非模型生成 | G3 機械核對 |
| 門控 | 純代碼、成本近零 | —— | 任何一道門 |
延遲方面,三段流水線的關鍵路徑是「最慢的標的」:段內並行度足夠時,總延遲≈單標的延遲×3+門控時間。三個實務決策:
1. 收集段預取:資訊源快照與抽取可以在任務下達前就完成
(年報發布即入庫),把收集延遲移出關鍵路徑
2. 流式過門:標的級粒度過門控——FAKE-001 通過 G1 就進分析,
不等 FAKE-002;全 run 的 barrier 只留在匯總前
3. 預算熔斷:run 級 token 與時間預算,超限即停止新任務派發,
已完成部分照常過門產出——部分結果好過沒有結果
最後是那個最容易被忽略的取捨:驗證成本與返工成本。砍掉門控省下的錢,會以「發現報告有錯→全板塊重跑→聲譽損失」的形式加倍收回。門控是全鏈路裡單位成本最低、回報最高的環節,預算緊張時先砍收集段的模型檔次,最後才動門控。
成本要落到可觀測的指標上才算管理。每次 run 結束,manifest 裡固定沉澱一組運行統計:各段的 token 消耗與耗時(按標的、按段拆分)、重試次數與原因分佈、門控攔截率(G1/G2/G3 各攔了多少、因為什麼)、missing 字段率、單標的平均成本。這組數字每週看一次趨勢:攔截率突然上升通常意味著上游抽取品質退化;重試激增通常意味著某個資訊源改版;單標的成本漂移則多半是提示詞或模型檔次被人動過。成本監控與品質監控共用同一套運行統計,這也是下一篇系統設計文章的伏筆——流水線的運行數據本身就是系統最重要的資產之一。
八、AI 會在這裡出錯:段間幻覺放大
單 Agent 的幻覺是點狀的;流水線的幻覺是級聯放大的。典型鏈路:
收集段:附註抽取失敗 → 輸出 missing(5% 的正常缺損率)
分析段:模型「知道」這類公司帳齡結構通常長什麼樣 → 用合理推斷補上缺口
→ claim 的 evidence_ids 指向一條 status=missing 的 fact(或乾脆不指向任何 fact)
報告段:claim 進了報告,caveats 被敘事「順平」,信心 medium 被寫成確定語氣
讀者:看到一段流暢、自信、有數字有結論的分析——其中關鍵一環是編的
三段各自的危險點與對應的機械防禦:
| 段 | 危險動作 | 機械防禦 |
|---|---|---|
| 收集 | 把缺失值補成「合理估計」 | 規則:value=null 必須伴隨 missing_reason;G1 攔截無來源的值 |
| 分析 | 論斷與證據脫鉤;用記憶中的「行業常識」當數據 | G2 證據存在性校驗+獨立重算;claims schema 中無 evidence 的論斷只能標 type=hypothesis 且禁止進報告正文 |
| 報告 | 數字改寫、信心升格、caveats 丟失 | G3 逐數字 diff;模板強制渲染 caveats;低信心 claim 的措辭白名單 |
再加一道端到端抽審:每次 run 隨機抽一個報告中的數字,沿 report→claim→fact→source 全鏈路人工回溯到原始文件的那一頁。這條抽審是全系統唯一能發現「三道門都沒想到的新錯誤模式」的機制,它的發現應該回流成新的門控規則。
流水線拆分不能消除幻覺,但它把幻覺從「瀰漫在全文」變成「卡在某道門」——可定位、可攔截、可統計。在此之上的系統級設計(技能庫、評測集、多層門控、維運),見 自建投研系統;三段分工背後的通用 Agent 分層原理,見 三層 Agent 框架 與 Agent 循環架構比較。
下一步
- OMA 多 Agent 實戰教程:把本篇的三段設計落到具體框架上跑一遍
- 子代理隔離架構:跨標的污染事故的完整復盤與 Clean Context 設計
- 三層 Agent 框架:編排層、執行層、模型層的分層原理
- 自建投研系統:從單條流水線到完整系統的演進藍圖
- 投研 AI 的合規邊界:發布前的留痕、覆核與措辭紅線