木曜日, 5月 8, 2025
No menu items!
ホームニューステックニュースMastra の workflow の書き方が新しくなるぞ!

Mastra の workflow の書き方が新しくなるぞ!


GWに Mastra を触ってみようと思っていたところ、Workflows の書き方が新しくなるという公式ブログを見かけたので、実際のコードも交えて変更点を確認してみました。

https://mastra.ai/blog/vNext-workflows

Mastra とは

Mastra は、AI機能を素早く、堅牢に、そして拡張可能に開発するための TypeScript 製フレームワークです。

個人的には、LLM アプリケーションといえば Python が主流という印象がある中で、TypeScript で書けるというだけで嬉しいです。

詳しくは以下のリンクも参考になります。

新しい Workflow: vNext Workflows

以下は、基本的に公式ブログからの要点の抜粋です。

背景

従来の Mastra Workflows は、シンプルで直感的な .then().step() 構文による構築が高く評価されていましたが、次の2点が課題とされていました。

  1. 複雑な制御フローの表現が困難
  2. 既存のワークフローエンジンとの統合が難しい

これらの課題を解決すべく登場したのが vNext Workflows です。

変更点

1. 制御フローの強化

複雑な分岐や繰り返し処理を直感的に記述できるように、以下の改善が加えられました。

  • .branch() による分岐記述
  • .parallel() の導入

    • 複数ステップを条件無しで並列実行可能に
  • .then() の1本化

    • .step() は廃止され、 .then()に統一
  • ループ構文の追加
    • whileuntil により、条件が成立するまでワークフローを繰り返せるように
  • after() の廃止

2. 型安全性の向上

vNext では、すべてのステップに対して入力スキーマと出力スキーマの定義が必要になります。

  • ステップの入力は前ステップの出力と自動的に接続
  • .branch().parallel() の結果は {[stepId]:output} 形式のユニオン型で返却
  • ステップの再開時に渡される値は resumeSchema として定義可能になった

これらの変更により、入出力の型が合わないときに型エラーの検出が可能になりました。

3. マルチエンジン対応(今後対応予定)

将来的に以下のような外部のワークフローエンジンでMastraの Workflow を扱えるようになります。

導入方法

ブログによると、2025年 5月 6日のリリースから vNext に切り替わる予定です。
従来のワークフローを利用している場合は、@mastra/core/workflows/legacy から import することで引き続き使用可能です。

ただし、執筆時点ではまだ vNext に切り替わっていませんでした。
今の段階で触りたい場合、 @mastra/core/workflows/vNext から import してくることで試すことができます。

https://github.com/mastra-ai/mastra/tree/8470550c94bce9970dae8e5e12553e7c57c43f30/packages/core/src/workflows/vNext

触ってみた

実際に vNext を試してみて、特に印象に残った点は以下の2つです。

型エラーがわかりやすくなった

以下のようなステップを組んだ際、入出力の型が一致していない場合に、エディタ上で即座に型エラーとして指摘されました。

import { createWorkflow, createStep } from '@mastra/core/workflows/vNext';
import { z } from 'zod';

export const firstStepInputSchema = z.object({
    inputValue: z.number(),
})
export const firstStepOutputSchema = z.object({
    doubledValue: z.number(),
})
const firstStep = createStep({
    id: 'first-step',
    inputSchema: firstStepInputSchema,
    outputSchema: firstStepOutputSchema,
    execute: async ({ inputData }) => {
        return { doubledValue: inputData.inputValue * 2 };
    },
})

export const plusOneStepInputSchema = z.object({
	
	
    doubledValue: z.number(),
})
export const plusOneStepOutputSchema = z.object({
    plusOneValue: z.number(),
})
const plusOneStep = createStep({
    id: 'plus-one-step',
    inputSchema: plusOneStepInputSchema,
    outputSchema: plusOneStepOutputSchema,
    execute: async ({ inputData }) => {
        return { plusOneValue: inputData.doubledValue + 1 };
    },
})
const mathWorkflow = createWorkflow({
    id: 'math-workflow',
    inputSchema: z.object({
        inputValue: z.number(),
    }),
    outputSchema: z.number(),
    steps: [firstStep, plusOneStep],
})
    .then(firstStep)
    
    .then(plusOneStep)
    .commit();

たとえば、plusOneStepInputSchema を以下のように変更した場合、画像のようにエラーがでます。

export const plusOneStepInputSchema = z.object({
    
    inputValue: z.number(),
})


即座にエラーがでるので、実装時も安心しながら開発ができます。

複雑なフローが書きやすくなった

次のような並列処理・分岐がある例を考えてみます。

このワークフローは、以下のコードで実現されています。(Stepなど、コード全体は付録に記載します)

const mathWorkflow = createWorkflow({
    id: 'math-workflow',
    inputSchema: z.object({
        inputValue: z.number(),
    }),
    outputSchema: z.number(),
    steps: [firstStep, plusOneStep, plusTwoStep, plusThreeStep, aggregateStep, resultStep],
})
    .then(firstStep)
    .parallel([plusOneStep, plusTwoStep, plusThreeStep])
    .then(aggregateStep)
    .branch([
        [async ({inputData}) => inputData.aggregatedValue >= 100, highValueStep],
        [async ({inputData}) => inputData.aggregatedValue  100, lowValueStep],
    ])
    .then(resultStep)
    .commit();

legacy で書く場合、次のようになりました。
(違う例で試していたので、Stepの名前等はことなります。フローの組み方もなにか間違えている気もするので、より良い書き方があれば教えて下さいmm)

const weatherWorkflowTwo = new Workflow({
    name: 'weather-workflow-two',
    triggerSchema,
})
    .step(fetchWeather)
    .after(fetchWeather)
    .step(clothingSuggestion)
    .step(ambrellaSuggestion)
    .step(washingSuggestion)
    .after([clothingSuggestion, ambrellaSuggestion, washingSuggestion])
    .step(highTempStep, {
        when: async ({context}) => {
            const forecast = context?.getStepResult(fetchWeather);
            return forecast?.some(item => item.maxTemp > 30);
        }
    })
    .then(mergeSteps)
    .step(lowTempStep, {
        when: async ({context}) => {
            const forecast = context?.getStepResult(fetchWeather);
            return forecast?.some(item => item.maxTemp  10);
        }
    })
    .then(mergeSteps)
    .commit();

おわりに

GWを機に Mastra を触ってみましたが、TypeScript の恩恵で型安全かつ開発体験の良い LLM アプリケーションが構築できそうだと感じました。
今後も引き続き試してみたいと思います。

付録

vNext を使ったコード全体はこちらです。https://gist.github.com/onsd/38ce6f833b93404a34e656716ed0b176

フラッグシティパートナーズ海外不動産投資セミナー 【DMM FX】入金

Source link

Views: 0

RELATED ARTICLES

返事を書く

あなたのコメントを入力してください。
ここにあなたの名前を入力してください

- Advertisment -

Most Popular

Recent Comments