實戰:從零寫一條每日摘要工作流程
跟著一個具體業務場景把所有核心概念串起來:拉資料 → 分類 → 總結 → 投遞。
這一篇把一個具體的業務場景從頭到尾走一遍,讓前面學過的所有概念(workflow / step / agent / variables / classifier / sub_workflow / credentials)在一條真實流程裡對號入座。15 分鐘之後,你會有"我可以獨立做一條工作流"的感覺。
- 已經註冊 Braidrun 賬號並登錄。不會的先看 註冊與登入。
- 有一把 OpenAI / Anthropic / DeepSeek 任一家的 API Key。完全沒有也能走前幾步,只是到真跑時會跳過 LLM step。
- (可選)一個 Slack Incoming Webhook URL —— 想體驗投遞環節時需要。
業務場景:每日科技新聞摘要
需求:
- 每天早上 8:00 自動跑;
- 從 Hacker News / 36Kr / The Verge RSS 抓 10 條最新科技新聞;
- 對每條做"AI / 硬件 / 其它"三類分類;
- 僅對分類為 AI 的那幾條生成 60 字中文摘要;
- 彙總成 Markdown,投遞到 Telegram 頻道;
- 發送前要求我點一下"確認"—— 避免投遞髒數據。
拆成 Braidrun 的步驟
fetch— code 步驟:用 Node 抓 RSS 解析成 JSON。classify— classifier 步驟:每條新聞打類別標籤。summarize— single 步驟:只對 AI 類生成中文摘要。compile— code 步驟:拼成一整份 Markdown。review— manual_approval:發送前暫停讓我看一眼。deliver— sub_workflow:複用內置 Slack 投遞模塊。
第 1 步 · 新建工作流
- 左側主導航點「工作流」→ 右上角「新建工作流」。
- 名稱:
daily-tech-digest,描述:每天早 8 点的科技新闻摘要。 - 點「創建」。立刻跳入編輯器。
編輯器打開後是兩欄:左邊是畫布(DAG 可視化),右邊是 YAML。任何一邊的改動會實時同步到另一邊。
第 2 步 · 聲明 Agent
切到 YAML 欄,在頂部(variables 之後)加一段 agents:
agents:
writer:
preset: writer
overrides:
max_iterations: 3
provider: openai_api_key # 引用凭据中心里的 Key說明:writer preset 專為中文寫作優化。overrides 把 max_iterations 限到 3,讓 Agent 不會在一條摘要上反覆思考太多(摘要本身很簡單)。
preset 詳解見 Agent 配置詳解。
第 3 步 · fetch:code 步驟抓 RSS
繼續在 YAML 裡,在 steps 下加 fetch:
steps:
- id: fetch
type: code
language: node
idempotent: true
code: |
const parser = new (await import('rss-parser')).default();
const feeds = [
'https://hnrss.org/frontpage',
'https://36kr.com/feed'
];
const articles = [];
for (const url of feeds) {
const feed = await parser.parseURL(url);
feed.items.slice(0, 5).forEach(item => {
articles.push({ title: item.title, url: item.link });
});
}
return { articles };
extract:
articles: $.articles幾個要點:
language: node— Node 20 是內置支持的運行時之一。extract— 從腳本 stdout JSON 裡挑出 articles 字段,下游用 steps.fetch.data.articles 引用。idempotent: true— "同一天拉新聞大概率是同樣的結果"—— 服務重啟續跑時可跳過。
你的腳本會在一次性隔離沙箱裡運行,預設有 512MB 記憶體、0.5 CPU 核、300 秒逾時。網路只允許出站請求。你可以放心 fetch 外部數據,但不能監聽連接埠;寫磁碟只有 /tmp 可用。
第 4 步 · classify:給每條新聞打標籤
- id: classify
type: classifier
agent: writer
task: |
给下面这条新闻标题分一个类别:
标题: {{steps.fetch.data.articles[0].title}}
categories:
- name: ai
description: AI / LLM / 机器学习相关
- name: hardware
description: 硬件 / 芯片 / 设备
- name: other
description: 其它科技话题
output_variable: categoryclassifier 的輸出可通過 {{classifier.category}} 引用 —— 就是上一條新聞的分類結果。我們會在下一步用它做條件分支。
變量引用的完整語法見 變數與表達式。
第 5 步 · summarize:只對 AI 類寫摘要
- id: summarize
type: single
agent: writer
idempotent: true
condition: "{{classifier.category}} == 'ai'"
task: |
用一段中文(不超过 60 字)概括下面这条 AI 新闻:
{{steps.fetch.data.articles[0].title}}說明:
condition讓這一步僅在分類結果是 ai 時執行,其它類別被跳過(狀態 SKIPPED,不算失敗)。idempotent: true—— 純摘要是冪等的,同樣的輸入 → 同樣的輸出。
第 6 步 · compile:拼成 Markdown 整份
- id: compile
type: code
language: node
depends_on: [summarize]
code: |
const summaries = JSON.parse(process.env.STEP_OUTPUT_SUMMARIZE || '[]');
const md = [
'# 📰 今日科技 AI 摘要',
'',
...summaries.map((s, i) => `${i + 1}. ${s}`)
].join('\n');
return { markdown: md };
extract:
markdown: $.markdown這一步把上游所有 summarize 結果聚合成一份可直接發送的 Markdown。extract 把它暴露為 steps.compile.data.markdown,下游引用更乾淨。
第 7 步 · review:發送前人工確認
- id: review
type: manual_approval
title: "请审阅今日 AI 摘要"
body: "{{steps.compile.data.markdown}}"
approvers: [] # 空 = 团队所有 Admin 都可审批
notify: [in_app] # 也可以 slack / email / feishu這是 manual_approval 的最簡形式 —— 流程會在這裡暫停,"審批管理"頁會出現一條待審批。你點"批准"工作流才往下走;點"拒絕"則 execution 狀態變成 FAILED,後續 step 全部取消。
更靈活的審批配置(approvers 指定、notify channels、expiration)見 人工審批。
第 8 步 · deliver:sub_workflow 調用平臺內置模塊
- id: deliver
type: sub_workflow
module: dingyue-module-slack-deliver
depends_on: [review]
inputs:
slack_webhook_url: "{{var:slack_webhook_url}}"
message_text: "{{steps.compile.data.markdown}}"說明:
dingyue-module-slack-deliver是平台內附的內建投遞模組之一,封裝了 "組裝 payload → 傳送訊息 → 重試 → 回寫狀態" 整個套路。slack_webhook_url引用變數裡配置的 Slack Incoming Webhook URL —— 我們會在第 10 步配。
第 9 步 · 畫布預覽
切回左邊畫布欄,你會看到 6 個節點按 fetch → classify → summarize → compile → review → deliver 連成一條線。雙擊任一節點可以展開它的 YAML 片段;拖動節點可調整位置 —— 佈局變化只是視覺,不影響 YAML。
第 10 步 · 補齊憑據
在跑這條工作流之前,憑據中心裡需要有:
openai_api_key(Agent 用的 LLM Key)- 類型選 api_key,值粘貼你從 OpenAI 拿的 sk-...。
slack_webhook_url(投遞用的 Slack Incoming Webhook URL)- 類型選 api_key 或 secret_text,值貼上 Slack Incoming Webhook URL。
保存後,工作流裡引用的憑據名字和這裡一一對應,就能被運行時解析了。
第 11 步 · 驗證 & dry-run
11.1 驗證
頂部點「驗證」。平臺用完整 agent 解析器做一次 round-trip;有語法 / 引用錯誤會給出具體行號 + 原因。搞定所有紅線再下一步。
11.2 試運行
點「執行」,對話框裡勾選 dry-run,點"開始執行"。這次:
- fetch 會真的跑 —— code 步驟的副作用判斷難,我們默認讓它真跑(但網絡沙箱受限);
- classify / summarize / compile —— 因為是 LLM,dry-run 時返回模擬值;
- review —— dry-run 下自動批准(不會真彈審批);
- deliver —— 模塊知道 dry-run 模式,不會真發 Telegram 消息。
成功的話,所有 step 都會是綠色 COMPLETED 或灰色 SKIPPED。去右下區檢視每步的"輸入 / 輸出 / 變量快照",確認變量都串對了。
第 12 步 · 真跑一次
- 點「執行」, 取消 勾選 dry-run,開始執行。
- 右側實時事件流開始刷。看 fetch 跑完後有沒有拉到 10 條;classify 每跑一條打一個標籤;summarize 只對 AI 那幾條執行。
- 跑到 review 時,整個執行會暫停,狀態變成 PENDING_APPROVAL。切到「審批管理」,你會看到一條待審批,點「查看」讀 Markdown 草稿。
- 滿意就點「批准」。工作流程自動繼續到 deliver,Slack 訊息就發出去了。
- 跑完回到工作流詳情頁看這次 execution 的 token / cost 統計。
大概耗時 1–3 分鐘(取決於網絡),token 消耗約 5000–15000(按 openai gpt-4.1-mini 約 $0.01–0.03)。低於這個範圍可能是拉新聞失敗了,高於這個範圍可能是 summarize 反覆思考。
第 13 步 · 掛 cron 讓它每天自動跑
- 左側「調度管理」→「新建調度」。
- 目標工作流:daily-tech-digest;類型:cron;表達式:
0 0 8 * * ?;時區:Asia/Shanghai。 - 「參數預設」可以空 —— 我們的 variables 都有合理默認值。
- 保存。「下次觸發時間」會顯示明天 8:00。
工作流 YAML 完整版
展開看完整 YAML
name: daily-tech-digest
version: "1.0.0"
description: 每天早 8 点的科技新闻摘要
recovery:
autoResumeOnRestart: true
policy: RESUME_FROM_LAST_INCOMPLETE
agents:
writer:
preset: writer
overrides:
max_iterations: 3
provider: openai_api_key
steps:
- id: fetch
type: code
language: node
idempotent: true
code: |
const parser = new (await import('rss-parser')).default();
const feeds = [
'https://hnrss.org/frontpage',
'https://36kr.com/feed'
];
const articles = [];
for (const url of feeds) {
const feed = await parser.parseURL(url);
feed.items.slice(0, 5).forEach(item => {
articles.push({ title: item.title, url: item.link });
});
}
return { articles };
extract:
articles: $.articles
- id: classify
type: classifier
agent: writer
task: |
给下面这条新闻标题分一个类别:
标题: {{steps.fetch.data.articles[0].title}}
categories:
- name: ai
- name: hardware
- name: other
output_variable: category
- id: summarize
type: single
agent: writer
idempotent: true
condition: "{{classifier.category}} == 'ai'"
task: |
用一段中文(不超过 60 字)概括下面这条 AI 新闻:
{{steps.fetch.data.articles[0].title}}
- id: compile
type: code
language: node
depends_on: [summarize]
code: |
const summaries = JSON.parse(process.env.STEP_OUTPUT_SUMMARIZE || '[]');
const md = [
'# 📰 今日科技 AI 摘要',
'',
...summaries.map((s, i) => `${i + 1}. ${s}`)
].join('\n');
return { markdown: md };
extract:
markdown: $.markdown
- id: review
type: manual_approval
title: "请审阅今日 AI 摘要"
body: "{{steps.compile.data.markdown}}"
notify: [in_app]
- id: deliver
type: sub_workflow
module: dingyue-module-slack-deliver
depends_on: [review]
inputs:
slack_webhook_url: "{{var:slack_webhook_url}}"
message_text: "{{steps.compile.data.markdown}}"做完之後你已經會的
- 用 YAML + 畫布雙欄編輯一條完整工作流
- 代碼步驟、classifier、single、manual_approval、sub_workflow 五種主模式的實際寫法
- 變量引用(var / steps / classifier / credentials)的不同用途
- validate / dry-run / 真跑 / 掛 cron 的完整上線循環
- 憑據中心與工作流 YAML 之間怎麼配合
接下來
- 讀完 8 種步驟類型 — 每種的用法、字段、組合約束
- 學會斷點調試 — 工作流變複雜時省 80% 的排錯時間
- 模組化與復用 — 有了第二條第三條工作流時,把公共邏輯抽成 sub_workflow