AI Recruiter を構築する
このガイドでは、Mastra がどのように LLM を用いたワークフローの構築を支援するかを学びます。
候補者の履歴書から情報を収集し、候補者のプロフィールに基づいて技術系の質問か行動特性に関する質問のいずれかに分岐するワークフローを作成します。その過程で、ワークフローのステップ設計、分岐の扱い方、LLM 呼び出しの組み込み方法を解説します。
前提条件
- Node.js
v20.0
以降がインストールされていること - 対応するモデルプロバイダーから取得した API キー
- 既存の Mastra プロジェクト(新規プロジェクトのセットアップはインストールガイドを参照)
ワークフローの構築
ワークフローを設定し、候補者データの抽出と分類の手順を定義し、適切なフォローアップ質問を行います。
ワークフローを定義する
新しいファイル src/mastra/workflows/candidate-workflow.ts
を作成し、次のようにワークフローを定義します:
import { createWorkflow, createStep } from "@mastra/core/workflows";
import { z } from "zod";
export const candidateWorkflow = createWorkflow({
id: "candidate-workflow",
inputSchema: z.object({
resumeText: z.string(),
}),
outputSchema: z.object({
askAboutSpecialty: z.object({
question: z.string(),
}),
askAboutRole: z.object({
question: z.string(),
}),
}),
}).commit();
ステップ: 候補者情報の収集
履歴書テキストから候補者の詳細を抽出し、その人物を「technical」または「non-technical」に分類します。このステップでは LLM を呼び出して履歴書を解析し、氏名、技術職か否か、専門分野、元の履歴書テキストを含む構造化 JSON を返します。inputSchema
で定義されているため、execute()
内で resumeText
にアクセスできます。これを使って LLM にプロンプトし、整理されたフィールドを返します。
既存の src/mastra/workflows/candidate-workflow.ts
ファイルに次を追加します:
import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
const recruiter = new Agent({
name: "Recruiter Agent",
instructions: `You are a recruiter.`,
model: openai("gpt-4o-mini"),
});
const gatherCandidateInfo = createStep({
id: "gatherCandidateInfo",
inputSchema: z.object({
resumeText: z.string(),
}),
outputSchema: z.object({
candidateName: z.string(),
isTechnical: z.boolean(),
specialty: z.string(),
resumeText: z.string(),
}),
execute: async ({ inputData }) => {
const resumeText = inputData?.resumeText;
const prompt = `Extract details from the resume text:
"${resumeText}"`;
const res = await recruiter.generate(prompt, {
output: z.object({
candidateName: z.string(),
isTechnical: z.boolean(),
specialty: z.string(),
resumeText: z.string(),
}),
});
return res.object;
},
});
execute()
内で Recruiter エージェントを使用するため、ステップより上で定義し、必要なインポートを追加してください。
ステップ: 技術的な質問
このステップでは、「technical」と判定された候補者に対し、その専門分野に入った経緯についての追加情報を尋ねます。LLM が関連性の高いフォローアップ質問を作成できるよう、履歴書テキスト全体を使用します。
既存の src/mastra/workflows/candidate-workflow.ts
ファイルに次を追加します:
const askAboutSpecialty = createStep({
id: "askAboutSpecialty",
inputSchema: z.object({
candidateName: z.string(),
isTechnical: z.boolean(),
specialty: z.string(),
resumeText: z.string(),
}),
outputSchema: z.object({
question: z.string(),
}),
execute: async ({ inputData: candidateInfo }) => {
const prompt = `You are a recruiter. Given the resume below, craft a short question
for ${candidateInfo?.candidateName} about how they got into "${candidateInfo?.specialty}".
Resume: ${candidateInfo?.resumeText}`;
const res = await recruiter.generate(prompt);
return { question: res?.text?.trim() || "" };
},
});
ステップ: 行動特性に関する質問
候補者が「non-technical」の場合は、別のフォローアップ質問が必要です。このステップでは、その役割について最も関心のある点を尋ねます。ここでも履歴書の全文を参照します。execute()
関数では、LLM に役割に焦点を当てた質問を生成させます。
既存の src/mastra/workflows/candidate-workflow.ts
ファイルに次を追加します:
const askAboutRole = createStep({
id: "askAboutRole",
inputSchema: z.object({
candidateName: z.string(),
isTechnical: z.boolean(),
specialty: z.string(),
resumeText: z.string(),
}),
outputSchema: z.object({
question: z.string(),
}),
execute: async ({ inputData: candidateInfo }) => {
const prompt = `You are a recruiter. Given the resume below, craft a short question
for ${candidateInfo?.candidateName} asking what interests them most about this role.
Resume: ${candidateInfo?.resumeText}`;
const res = await recruiter.generate(prompt);
return { question: res?.text?.trim() || "" };
},
});
ワークフローにステップを追加する
ここでは、候補者が技術職かどうかに応じて分岐ロジックを実装するため、ステップを組み合わせます。ワークフローは最初に候補者データを収集し、その後 isTechnical
に応じて、専門分野について質問するか、職務(ロール)について質問します。これは gatherCandidateInfo
を askAboutSpecialty
と askAboutRole
にチェーンすることで実現します。
既存の src/mastra/workflows/candidate-workflow.ts
ファイルで、candidateWorkflow
を次のように変更します:
export const candidateWorkflow = createWorkflow({
id: "candidate-workflow",
inputSchema: z.object({
resumeText: z.string(),
}),
outputSchema: z.object({
askAboutSpecialty: z.object({
question: z.string(),
}),
askAboutRole: z.object({
question: z.string(),
}),
}),
})
.then(gatherCandidateInfo)
.branch([
[async ({ inputData: { isTechnical } }) => isTechnical, askAboutSpecialty],
[async ({ inputData: { isTechnical } }) => !isTechnical, askAboutRole],
])
.commit();
ワークフローを Mastra に登録する
src/mastra/index.ts
ファイルで、ワークフローを登録します:
import { Mastra } from "@mastra/core";
import { candidateWorkflow } from "./workflows/candidate-workflow";
export const mastra = new Mastra({
workflows: { candidateWorkflow },
});
ワークフローのテスト
開発サーバーを起動し、Mastra のplayground内でワークフローをテストできます:
mastra dev
サイドバーで Workflows に移動し、candidate-workflow を選択します。中央にはワークフローのグラフビューが表示され、右サイドバーではデフォルトで Run タブが選択されています。このタブで、次のような職務経歴書のテキストを入力できます:
Knowledgeable Software Engineer with more than 10 years of experience in software development. Proven expertise in the design and development of software databases and optimization of user interfaces.
職務経歴書のテキストを入力したら、Run ボタンを押します。すると、ワークフロー各ステップの出力を含む 2 つのステータスボックス(GatherCandidateInfo
と AskAboutSpecialty
)が表示されるはずです。
.createRunAsync()
と .start()
を呼び出すことで、プログラムからワークフローをテストすることもできます。新しいファイル src/test-workflow.ts
を作成し、次を追加します:
import { mastra } from "./mastra";
const run = await mastra.getWorkflow("candidateWorkflow").createRunAsync();
const res = await run.start({
inputData: {
resumeText:
"Knowledgeable Software Engineer with more than 10 years of experience in software development. Proven expertise in the design and development of software databases and optimization of user interfaces.",
},
});
// Dump the complete workflow result (includes status, steps and result)
console.log(JSON.stringify(res, null, 2));
// Get the workflow output value
if (res.status === "success") {
const question = res.result.askAboutRole?.question ?? res.result.askAboutSpecialty?.question;
console.log(`Output value: ${question}`);
}
では、ワークフローを実行してターミナルで出力を確認しましょう:
npx tsx src/test-workflow.ts
これで、職務経歴書を解析し、候補者の技術力に基づいてどの質問をするかを判断するワークフローを構築できました。おめでとうございます、ハッキングを楽しんでください!