跳轉到主要內容
文件入門實戰:第一條工作流程
實戰 · 15 分鐘

實戰:從零寫一條每日摘要工作流程

跟著一個具體業務場景把所有核心概念串起來:拉資料 → 分類 → 總結 → 投遞。

這一篇把一個具體的業務場景從頭到尾走一遍,讓前面學過的所有概念(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 的步驟

  1. fetchcode 步驟:用 Node 抓 RSS 解析成 JSON。
  2. classifyclassifier 步驟:每條新聞打類別標籤。
  3. summarizesingle 步驟:只對 AI 類生成中文摘要。
  4. compilecode 步驟:拼成一整份 Markdown。
  5. reviewmanual_approval:發送前暫停讓我看一眼。
  6. deliversub_workflow:複用內置 Slack 投遞模塊。

第 1 步 · 新建工作流

  1. 左側主導航點「工作流」→ 右上角「新建工作流」。
  2. 名稱: daily-tech-digest,描述: 每天早 8 点的科技新闻摘要
  3. 點「創建」。立刻跳入編輯器。

編輯器打開後是兩欄:左邊是畫布(DAG 可視化),右邊是 YAML。任何一邊的改動會實時同步到另一邊。

第 2 步 · 聲明 Agent

切到 YAML 欄,在頂部(variables 之後)加一段 agents:

yaml
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:

yaml
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 — "同一天拉新聞大概率是同樣的結果"—— 服務重啟續跑時可跳過。
code 步驟的沙箱

你的腳本會在一次性隔離沙箱裡運行,預設有 512MB 記憶體、0.5 CPU 核、300 秒逾時。網路只允許出站請求。你可以放心 fetch 外部數據,但不能監聽連接埠;寫磁碟只有 /tmp 可用。

第 4 步 · classify:給每條新聞打標籤

yaml
  - 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: category

classifier 的輸出可通過 {{classifier.category}} 引用 —— 就是上一條新聞的分類結果。我們會在下一步用它做條件分支。

變量引用的完整語法見 變數與表達式

第 5 步 · summarize:只對 AI 類寫摘要

yaml
  - 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 整份

yaml
  - 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:發送前人工確認

yaml
  - 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 調用平臺內置模塊

yaml
  - 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 步 · 補齊憑據

在跑這條工作流之前,憑據中心裡需要有:

  1. openai_api_key (Agent 用的 LLM Key)
    • 類型選 api_key,值粘貼你從 OpenAI 拿的 sk-...。
  2. 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 步 · 真跑一次

  1. 點「執行」, 取消 勾選 dry-run,開始執行。
  2. 右側實時事件流開始刷。看 fetch 跑完後有沒有拉到 10 條;classify 每跑一條打一個標籤;summarize 只對 AI 那幾條執行。
  3. 跑到 review 時,整個執行會暫停,狀態變成 PENDING_APPROVAL。切到「審批管理」,你會看到一條待審批,點「查看」讀 Markdown 草稿。
  4. 滿意就點「批准」。工作流程自動繼續到 deliver,Slack 訊息就發出去了。
  5. 跑完回到工作流詳情頁看這次 execution 的 token / cost 統計。
第一次真跑的期望

大概耗時 1–3 分鐘(取決於網絡),token 消耗約 5000–15000(按 openai gpt-4.1-mini 約 $0.01–0.03)。低於這個範圍可能是拉新聞失敗了,高於這個範圍可能是 summarize 反覆思考。

第 13 步 · 掛 cron 讓它每天自動跑

  1. 左側「調度管理」→「新建調度」。
  2. 目標工作流:daily-tech-digest;類型:cron;表達式: 0 0 8 * * ?;時區:Asia/Shanghai。
  3. 「參數預設」可以空 —— 我們的 variables 都有合理默認值。
  4. 保存。「下次觸發時間」會顯示明天 8:00。

工作流 YAML 完整版

展開看完整 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 之間怎麼配合

接下來