20260910 會議記錄

:::info

上週待辦

[!Note] TODO MrOrz 把 DB mapping 送到 staging & production DB

Cofacts.ai

新訊息回報入口

@MrOrz:針對 8/18 讓 cofacts.ai 作為回報入口的設計(design doc: https://github.com/cofacts/kb/pull/16 )設計師子龍覺得讓回報者進 AI 容易分心,因此設計了獨立的訊息回報流程,基本上就是把 LINE bot 的流程做成網頁版這樣。我想了想,覺得如果做成 LINE bot 那種流程,確實會比靠 LLM 來弄穩定,而且 UI 上要做的東西其實差不多(就算做在 chat 也要刻展示搜尋列表、送出表單確認等 UI),所以我會重新 plan 回報入口的部分唷


有人在問「是誰在回報什麼訊息」,如 cofacts 舊網站的功能 [name=bil]

[!NOTE] TODO

  • 先撈過去的決策紀錄,看為啥當時新網站決定不要放 message author 與 profile page
  • 下周討論是否要做在 profile page

hint 不要放 placeholder,有 accessibility 問題 [name=nonumpa]

[!NOTE] TODO

  • Ask AI about accessibility advice
  • placeholder 寫太長的 example 會影響 lighthouse / accesibility 分數嗎

URL resolver in Cofacts

https://github.com/cofacts/ai/pull/118

目前狀態:仍在 agent code review + 我在和 AI 細修

User-level memory:Langfuse session 分析(cofacts/ai#125 後續)

Issue: https://github.com/cofacts/ai/issues/125

接 20260818 的兩件事:#125 的「觀察 session 裡使用者是不是會一直重複某些 prompt」,以及「用 AI + Langfuse skill 找找看使用者敘述的 session 是什麼」。翻了 Langfuse production 資料 + 讀了 ADK 1.26.0 原始碼與 Vertex 文件。

結論:值得做,但只值得做窄版的 —— per-user 的「編輯約束清單」,不是通用的對話式記憶。建議用 Vertex Memory Bank 當儲存層,V1 只用它的 CRUD、不用 LLM 自動萃取。成本實質上 $0。

資料範圍:environment=production,2026-07-29 ~ 09-09


發現 1:重複的 prompt 確實存在,集中在「佐證資料來源政策」

xPyH-IYBC7Q3lHuU6oTY(7 sessions / 22 turns,其中 9 個 turn 跟來源有關)把同一條媒體黑白名單講了四次:

08-07 佐證資料不要使用中時,NowNews,PCHome等媒體⋯⋯改用中央社與公視和報導者這類較為公允的媒體 08-14 佐證資料請不要引用聯合報及UDN來源⋯⋯UDN若是轉角國際的新聞來源則可以引用 08-30 佐證資料以中央社<公視新聞 08-30 (同一個 session 內,隔幾個 turn)佐證資料以中央社,公視新聞,央廣,報導者等資料為主,不要使用東森新聞

發現 2:四位重度使用者的工作風格完全不同(我認為這是最強的論據)

使用者 sessions turns/session 開場帶自己立場 特徵
sPyB-IYBC7Q3lHuU-YQl 23 2.1 0/23 貼 URL 就等成品;不滿意就整個重跑(「重新查核一次」6 次)
_1YnAG8BV0DITCqGm7go 20 5.7 0/20 逐條稽核型:15 個 turn 在查佐證資料連結能不能開、對不對題
AVriAlOoyrDaTqlmmqhC 15 1.7 13/15 「我先下判斷,你幫我寫」;7 個 turn 是語氣/切入角度
xPyH-IYBC7Q3lHuU6oTY 7 3.1 1/7 媒體可信度守門型(見發現 1)

發現 3:分類與訊息類型

發現 4:有相當比例的重複 prompt 是 bug,不是 memory 缺口

先修這些,再上 memory —— 否則 memory 會把「這個人總是要我重跑」記成偏好:

  1. 佐證資料 URL 失效/張冠李戴 —— _1YnAG8 有 15 個 turn 在做這件事(「此出處來源連結已失效」「報導者並沒有這篇文章」「請查明此連結是否可開啟」),還有一次是拿尚未被查證的 Cofacts 訊息當佐證資料。這該是 writer/verifier 自己 pre-flight 檢查
  2. 使用者裸打 draft_factcheck_response 當訊息送出 9 次以上,還有兩次直接送 [^draft_factcheck_response-call7886] –> UI/引導問題
  3. 「重新查核一次」6 次,某個 session 結尾使用者說「沒有 draft_factcheck_response 查核回應結論」–> 收尾不穩(對得上老鶴說的「查到一半停下來」)
  4. AVqVwjqQyrDaTqlmmp_a 在三個不同 session 開了同一篇文章(oqfr07on1plt)–> article-scoped 的「這篇之前查到哪」可能跟 user memory 一樣有價值,而且風險低得多

儲存層:user: state vs Memory Bank

#125 寫「ADK user-level session 可以記錄 memory,只要設計一個 tool 就行」—— 這個猜測成立,但要分清楚三件不同的東西:

  1. ADK user: session state — 存我們自己的 Postgres(StorageUserState),scope (app_name, user_id)
  2. ADK BaseMemoryService — 對話片段形狀,search_memory(query) 檢索
  3. Vertex Agent Engine Memory Bank — 真正的後端服務,有自己完整的 REST API

(2) 是 (3) 的一層薄且有損的 wrapper,評估 Memory Bank 不該用 ADK 的介面去評估它:

–> 結論:繞過 BaseMemoryService,直接用 vertexai client 打 Memory Bank。 用 Memory Bank,但不用 ADK 的 memory 整合。

錢:我們這個規模實質上是 $0(Memory Bank 2026-09-01 才開始計費,之前 preview 免費)

資源 免費額度/月/帳號 超出後 我們的用量
Agent Storage 1 GiB-month $0.30/GiB-month(含 revisions) 14 使用者 × 10 條 ≈ 30 KB
Agent Compute(讀) 50 vCPU-h = 1.5 億次讀 $0.085/vCPU-h(300 萬次讀 = 1 vCPU-h) 6 週 226 turns
Agent Compute(寫) 同上 = 5 千萬次寫 100 萬次寫 = 1 vCPU-h 6 週個位數

Region:asia-east1(台灣)支援,v1 GA —— 跟現有 Cloud Run + Cloud SQL 同區。Memory Bank 不支援的只有 Jakarta/Melbourne/Toronto。

Memory Bank 相對 user: state 的三個實質優勢

  1. user-scoped 資源自帶 CRUD –> 設定頁直接對它讀寫。user: state 只有 session-scoped 的 endpoint,設定頁得借一個 session id 或自己補一支 BFF endpoint
  2. 不汙染 session payload –> list_sessions() 會把 user state merge 進回傳清單裡的每一個 session(sPyB 有 45 個 session,1KB 的 memory 會被複製 45 次);Memory Bank 沒這問題
  3. scope 是任意 dict(上限 5 個 key) –> {"user_id": X} 放個人偏好、{"user_id": X, "category": "醫療保健"} 放分類 playbook,發現 3 用同一套機制就解決。另外 TTL 內建

缺點

  1. 新的 GCP 依賴:一個 reasoningEngine 資源 + IAM(client.agent_engines.create() 不帶參數就好,不用部署 agent,沒有 runtime 要維運)。prod/preview/staging 必須分開,否則 preview 會寫進正式使用者的記憶
  2. 繞過 ADK 抽象 = 自己維護一層薄 client,ADK 之後改進 memory 整合不會自動吃到
  3. 熱路徑多一次外部呼叫 –> 要 fallback:retrieve 失敗就當沒有偏好繼續跑,別讓查核卡住
  4. 資料放在 Google 而不是我們自己的 Postgres –> 見下方待拍板

可見性與隔離

可見性照 Claude 的作法(參考)—— 看得到、改得動、關得掉、有隔離:

隔離立場:memory 是私人的。session 分享出去只分享對話內容;別人接關時只載入對話內容 + 接關者自己的 memory。 跟 #124 一起看:


效益的誠實估計

建議的成功指標(都有現成 baseline)

指標 現況
turns/session 2.8(重度使用者 1.7–5.7)
帶來源/篇幅指正的 turn 比例 43/226 = 19%
drafts per session 3.2
單 turn 就結束的 session 比例 36/80 = 45%

建議的 V1 scope

  1. 一個 remember_editorial_preference(preference, kind) tool,writer 只在使用者給出跨訊息都適用的指示時呼叫。kind 二選一:sources/style。不做自動偵測
  2. memories.create(fact=..., scope={"user_id": X, "kind": ...});讀取用 memories.retrieve(scope={"user_id": X})。硬上限約 10 條、總長約 800 chars,超過要求使用者先刪。不呼叫 generate
  3. 注入用 before_model_callback(writer 已經有 inject_article_attachment 這個 pattern),接在既有 Step 2 constraint list 前面。比 instruction 的 {user:xxx} templating 安全 —— 後者 key 不存在時會炸
  4. 設定頁「我的查核偏好」:可看、可逐條刪、可整體關閉
  5. prod/preview/staging 用不同 Memory Bank 實例或不同 scope
  6. retrieve 失敗 fallback 成「沒有偏好」繼續跑

V1 不做


[!Warning] 待拍板 查核者的偏好資料要放我們自己的 Postgres,還是 Google 的 Memory Bank? 這是立場題不是技術題。技術上 Memory Bank 較優(獨立 CRUD 介面、不汙染 session payload、scope 多維、TTL、成本 $0、asia-east1 同區);但如果「使用者資料必須留在我們自己的資料庫」對 Cofacts 是原則,就用 user: state,代價是設定頁多一支 BFF endpoint + list_sessions payload 膨脹。

[!Note] TODO

  1. 發現 4 的四件事排在 memory 前面 —— 這四件都是使用者在重複講同一件事,但原因是產品有 bug,不是 AI 忘記偏好。先修這些,否則 memory 會把「這個人總是要我重跑」記成他的偏好:
    1. 佐證資料連結/對題 –> 推進 #118(已有解法,draft 狀態)。另外補兩個 #118 沒涵蓋的:不要拿未查證的 Cofacts 訊息當佐證資料
    2. 「查到一半停下來」有可偵測的訊號了(承 08-18「超難捕捉與修復」):turn 的 observation tree 裡 tool 回來之後沒有下一次 writer call_llm,且最後一個 generation output 為 null。08-30 那個 case 就是這個形狀,值得寫成一支查詢/alert
    3. 裸打 tool name 的 UI 問題:使用者把 draft_factcheck_response 當訊息送出 9 次以上,還有兩次直接送 [^draft_factcheck_response-call7886] 這種 citation marker
    4. article-scoped 的「這篇之前查到哪」:AVqVwjqQyrDaTqlmmp_a 在三個不同 session 開了同一篇文章。這比 user memory 風險低得多,可以先做
  2. 資料放哪拍板之後(見上方待拍板),V1 開 issue 到 cofacts/ai,接到 #125
  3. 實作前從本紀錄寫成 ADR(跨 src/ + adk/、新增資料存放位置)

[!Note] 只有選 user: state 才需要的 TODO 目前 code 完全沒有用 user: / app: 前綴的 state(只有 title、lastEventTime、lastOpenedAt 三個 session-scoped key),所以下面兩件事是「選了 user: state 才會新增的風險」。選 Memory Bank 就不需要做 —— memory 不在 session 物件裡,get_session 沒東西可以漏。

  1. #124 的唯讀路徑:BFF 要濾掉 session.state 裡所有 user: 前綴的 key,否則原作者的偏好會跟著唯讀頁面送到別人瀏覽器
  2. 不要有任何路徑呼叫 list_sessions(user_id=None) —— 那會撈出 app 底下所有使用者的 user state 並各自 merge 進回傳的 session

[!Note] 兩條路都要做的 #124 約束 #124 的「讓 agent 參考其他 public session 的內容」那個 tool,只回傳對話 content,不要去 retrieve 原作者的 memory。接關者用自己的 memory。

上週重點整理(2026-09-01 ~ 2026-09-09)

GitHub 活動

cofacts/ai

cofacts/rumors-api

cofacts/rumors-db

cofacts/rumors-site

cofacts/rumors-line-bot

cofacts/devops

cofacts/takedowns

cofacts/kb

Discord 重點討論

general

@mrorz:目前不需要 app-id 與 app-secret 可以直接接取唷!hackfoldr 已經修正,感謝指出問題

@bestian:我成功直接接取了,謝謝! 想請問沒有 app-id 與 app-secret 的情況下,同一 cloudflare worker 後端服務,接取 cofacts API 資料,目前有使用量上限嗎? 也附上開發中的專案 repo,供參考:https://github.com/g0v/fact-check-api

@bestian:或是有 X402 付費牆嗎? 想瞭解如果未來服務擴大,cofacts API 接口這邊的橋接規則(https://developers.cloudflare.com/agents/tools/payments/x402/ )

@mrorz:(使用量上限)目前沒有唷,但如果太頻繁導致我們的 Cloudflare 發現異常,可能會被判斷為是 DoS attack 然後擋下來⋯⋯ XD

@mrorz:其實我們有在規劃做 MCP 方便 coding agent 接取這樣

dev

@MrOrz:Global gathering 用的純英文 + submission 的版本,這個版本就是 for demo 方便使用者送訊息,不會 merge 進 master,到時候的送出流程以子龍版設計為準(demo: https://pr-137—cofacts-ai-sgnrxas52q-de.a.run.app/ )

@yutin:把 PR 拆一小部分出來 https://github.com/cofacts/rumors-api/pull/400

@MrOrz:https://github.com/cofacts/rumors-db/pull/80 這個也請看一下,沒問題的話可以給我個 approve,不然我沒辦法 deploy @yutin 的 hybrid search schema(rumors-db#78)

@MrOrz:@yutin 拆的兩個 PR 我都 review 囉,大感謝

Cofacts 正式環境狀態報告

報告期間:2026-09-01 ~ 2026-09-09(距上次會議 9 天) 比較基準:2026-08-25 ~ 2026-09-01(前一期間,取自歷史 metrics summary)

一、GCE 主機狀態(cofacts-prod)

現況快照(2026-09-09 15:52)

項目 數值
Uptime 125 天 21 小時(未重啟)
Load Average 0.69 / 0.51 / 0.61(1/5/15 分鐘)
記憶體(RAM) 21 GB used / 31 GB total(66–67%)
Swap 1.8 GB used / 4 GB total(~47%,穩定)
磁碟 59 GB / 67 GB(88% ⚠️,見下方調查)

GCE CPU / 記憶體 / Swap 逐日明細

格式:min | avg | p95 | max

日期 CPU(%) Mem(%) Swap(%)
09-01 11.8 | 21.4 | 29.9 | 32.9 64.7 | 66.8 | 68.4 | 73.7 43.1 | 45.3 | 48.2 | 49.6 ✅
09-02 10.0 | 19.3 | 28.4 | 38.4 63.9 | 66.4 | 68.1 | 68.8 45.5 | 47.1 | 49.4 | 50.4 ✅
09-03 8.7 | 17.5 | 25.3 | 45.7 64.2 | 66.2 | 68.0 | 68.6 45.3 | 47.4 | 49.7 | 50.4 ✅
09-04 9.8 | 16.5 | 23.5 | 38.9 63.9 | 66.4 | 68.1 | 68.9 45.0 | 46.7 | 49.1 | 49.8 ✅
09-05 7.5 | 15.6 | 21.4 | 38.8 64.8 | 66.6 | 68.7 | 69.3 44.9 | 46.5 | 49.5 | 51.4 ✅
09-06 8.9 | 15.7 | 22.6 | 39.6 64.1 | 65.9 | 67.7 | 68.8 47.1 | 48.8 | 50.8 | 52.2 ✅
09-07 8.6 | 16.5 | 26.1 | 39.9 65.0 | 67.3 | 69.6 | 71.1 45.0 | 46.6 | 48.1 | 49.8 ✅
09-08 8.9 | 16.6 | 30.1 | 36.4 64.3 | 66.4 | 68.8 | 70.1 46.0 | 47.5 | 49.2 | 57.5 ✅
09-09 11.0 | 16.2 | 20.9 | 28.5 64.0 | 66.3 | 68.6 | 69.7 45.2 | 47.4 | 49.7 | 49.8 ✅

觀察:CPU 平均使用率自 9/1 的 21.4% 逐日降至 9/9 的 16.2%,無異常尖峰。RAM 穩定在 66–67%,Swap 穩定在 45–49%(9/8 出現單一 max 57.5% 的短暫波動,之後隨即回落,不影響穩定度)。相較 4 月曾出現的 swap 滿載(98–100%)事件,目前狀態健康,memswap_limit 設定持續發揮效果。


二、GCE 程序層級資源(Top 消耗者,與前一期間 8/25–9/1 比較)

CPU(原始計數器單位,僅比較相對量級)

程序 前期 peak / avg 範圍 本期 peak / avg 範圍 觀察
java(Elasticsearch) 482,664 / 173,680–261,433 511,262 / 211,352–340,657 🟡 avg 上升約 20–30%
node server.js(rumors-api) 261,867 / 140,208–189,664 393,346 / 158,649–210,029 🟡 peak 明顯上升(+50%),avg 略升,建議留意流量來源
node build/index.js(rumors-site) 206,673 / 98,547–129,621 189,010 / 112,217–149,793 ➡️ 大致持平,avg 略升
cloudflared tunnel 35,496 / 15,691–22,291 41,505 / 17,474–26,934 ➡️ 略升,穩定
Chromium renderer(Puppeteer) 15,485 / 7,193–8,162 23,144 / 8,082–11,825 🟡 peak 上升,屬瞬間 spike(截圖/爬取任務)
python main.py(cofacts-ai) 18,292 / 3,484–5,876 (跌出本期 Top 15) ✅ 本期未進入 Top 15,CPU 占用下降
pm2-runtime start ecosystem 13,981 / 9,204–10,665 (跌出本期 Top 15) ✅ 同上

RSS 記憶體(MB)

程序 前期 peak / avg 範圍 本期 peak / avg 範圍 觀察
java(Elasticsearch) 19,694 / 19,144–19,289 19,563 / 19,155–19,265 ➡️ 持平,極穩定(std < 150)
node server.js(rumors-api) 1,450 / 269–314 1,450 / 289–322 ➡️ 持平
node build/index.js(rumors-site) 736 / 143–149 725 / 141–146 ➡️ 持平
pm2-runtime ecosystem.config.js 326 / 102–154 346 / 115–196 🟡 std 上升(103),波動略增
Chromium renderer(Puppeteer) 379 / 117–341 345 / 125–329 ➡️ 持平

結論:主機整體資源穩定,唯 node server.js(rumors-api)CPU peak 上升約 50%,建議下次確認是否對應特定流量事件(例如新聞熱點、爬蟲)。ES 記憶體/CPU 持續是最大單一消耗者但無異常波動。


三、Cloud Run 狀態

所有 11 個服務均正常運行(✔)。近期部署:


四、Cloud Run CPU 比較(p50 / p95 / p99,vCPU)

服務 前期 8/25–9/1 (p50 | p95 | p99) 本期 9/1–9/9 (p50 | p95 | p99) 觀察
site-tw(主力) 0.035–0.074 | 0.668–0.798 | 0.823–0.982 0.042–0.138 | 0.649–0.798 | 0.823–1.012 🟡 p50 上升(尤其 9/1 高峰),p99 觸頂 1.0,建議觀察
cofacts-ai 0.015–0.016 | 0.127–0.397 | 0.284–0.415 0.015–0.016 | 0.152–0.367 | 0.245–0.370 ✅ 穩定
line-bot-en 0.005–0.014 | 0.010–0.224 | 0.120–0.268 0.006–0.015 | 0.061–0.292 | 0.132–0.339 ➡️ 略升,仍在合理範圍
line-bot-ja 0.006–0.015 | 0.101–0.182 | 0.128–0.339 0.005–0.012 | 0.075–0.310 | 0.110–0.381 ➡️ 持平
site-staging-en/ja/tw 皆為低流量測試環境 皆為低流量測試環境 ➡️ 無異常

line-bot-tw、site-en、site-ja 本期與前期皆無回傳指標資料(Cloud Monitoring 查無時間序列),研判為該服務在查詢窗口內請求量趨近於 0(無活躍 instance)。


五、Cloud Run 記憶體比較(p50,GB)

服務 前期 p50 本期 p50 變化
site-tw 0.742–0.764 0.764–0.787 ➡️ 持平略升
site-staging-tw 0.787–0.913 0.586–0.811 🟢 下降(測試環境負載減少)
line-bot-en/ja 0.376–0.411 0.387–0.423 ➡️ 持平
cofacts-ai 0.056–0.065 0.056–0.065 ➡️ 持平

整體記憶體無異常增長。


六、Cloud Run 網路流出量(site-tw,每日 egress)

日期 Bytes 備註
09-01 6.85 GB 本期最高點
09-02 5.59 GB  
09-03~09-08 3.9–4.4 GB 穩定區間
09-09 2.75 GB 當日未滿(擷取當下)

前期(8/25–9/1)每日約 3.3–4.5 GB,本期 9/1 出現單日高點(6.85 GB),其餘天數回落至與前期相當的區間。無需立即處理,但可留意是否為特定事件流量。


七、磁碟使用調查

磁碟使用率從 4/28 的 62%(29 GB / 48 GB)上升至本期 88%(59 GB / 67 GB,注意:磁碟容量本身也從 48GB 擴增至 67GB,實際使用量仍成長約 2 倍)。上機查看佔用來源:

路徑 大小 佔比
/var(總計) 42 GB 佔根目錄 71%
└ /var/lib/docker 37 GB 主要成因
└ /var/lib/snapd 2.4 GB  
└ /var/log(含 journal) 1.5 GB  
/srv 11 GB 應用程式碼與資料
/usr 2.3 GB  

docker system df 明細:

類型 數量 總大小 可回收
Images 61(13 個使用中) 20.78 GB 7.58 GB(36%)
Containers 13(全數使用中) 6.44 GB 0 GB

根因:每次 docker-compose 重新 build/pull 後,舊版 image 未被清除,累積成 44 個 dangling(<none>)image,最舊可追溯到 16 個月前(cofacts/rumors-line-bot:latest-tw)。這是磁碟成長的主因。

已執行清理(2026-09-10,經確認後執行 docker image prune -f,只清 dangling image,未動有 tag 的 v6-backup/almir-webhook):

  清理前 清理後
磁碟使用率 88%(59GB/67GB) 68%(45GB/67GB)
可用空間 8.2GB 22GB
Dangling image 數量 44 0

實際回收約 14GB,優於原估 7.6GB。目前使用中的 13 個 container/image 未受影響。

後續建議:評估是否需要定期(如 cron)清理舊 image,避免再次累積到 88%。


八、整體健康評估

維度 狀態 說明
CPU 🟢 正常 avg 16–21%,逐日下降,無尖峰
RAM 🟢 正常 66–67%,穩定
Swap 🟢 正常 45–49%,遠低於 4 月曾出現的滿載風險
磁碟 🟢 已處理 原 88%,清除 44 個 dangling docker image 後降至 68%(回收 ~14GB),建議評估定期清理避免再次累積
Cloud Run 🟢 全部正常 11 服務皆 ✔
site-tw CPU 🟡 略高 p50/p99 較前期上升,p99 觸及 1.0 vCPU 上限,建議持續觀察
node server.js CPU 🟡 待觀察 peak 較前期上升約 50%

下次開會時間

一~四 bil 在國外,選項:

[!NOTE] 下次開會:9/14 (一) 20:00 線上