构建人工智能招聘系统
🌐 Building an AI Recruiter
在本指南中,你将学习 Mastra 如何帮助你使用大语言模型构建工作流程。
🌐 In this guide, you'll learn how Mastra helps you build workflows with LLMs.
你将创建一个工作流程,从候选人的简历中收集信息,然后根据候选人的资料分支到技术问题或行为问题。在此过程中,你将学习如何构建工作流程步骤、处理分支以及集成大型语言模型调用。
🌐 You'll create a workflow that gathers information from a candidate's resume, then branches to either a technical or behavioral question based on the candidate's profile. Along the way, you'll see how to structure workflow steps, handle branching, and integrate LLM calls.
先决条件Direct link to 先决条件
🌐 Prerequisites
构建工作流Direct link to 构建工作流
🌐 Building the Workflow
设置工作流程,定义提取和分类候选人数据的步骤,然后提出合适的后续问题。
🌐 Set up the Workflow, define steps to extract and classify candidate data, and then ask suitable follow-up questions.
创建一个新文件
src/mastra/workflows/candidate-workflow.ts并定义你的工作流程:🌐 Create a new file
src/mastra/workflows/candidate-workflow.tsand define your workflow:src/mastra/workflows/candidate-workflow.tsimport { 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();你想要从简历文本中提取候选人信息,并将其分类为“技术类”或“非技术类”。此步骤调用大型语言模型(LLM)来解析简历,并返回结构化的 JSON,包括名称、技术状态、专业特长以及原始简历文本。通过
inputSchema定义,可以在execute()中访问resumeText。使用它来提示 LLM 并返回已整理的字段。🌐 You want to extract candidate details from the resume text and classify the person as "technical" or "non-technical". This step calls an LLM to parse the resume and returns structured JSON, including the name, technical status, specialty, and the original resume text. Defined through the
inputSchemayou get access to theresumeTextinsideexecute(). Use it to prompt an LLM and return the organized fields.将以下内容添加到现有的
src/mastra/workflows/candidate-workflow.ts文件中:🌐 To the existing
src/mastra/workflows/candidate-workflow.tsfile add the following:src/mastra/workflows/candidate-workflow.tsimport { Agent } from "@mastra/core/agent";
const recruiter = new Agent({
id: "recruiter-agent",
name: "Recruiter Agent",
instructions: `You are a recruiter.`,
model: "openai/gpt-5.1",
});
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, {
structuredOutput: {
schema: z.object({
candidateName: z.string(),
isTechnical: z.boolean(),
specialty: z.string(),
resumeText: z.string(),
}),
},
});
return res.object;
},
});由于你在
execute()中使用了招聘代理,你需要在步骤上方定义它并添加必要的导入。🌐 Since you're using a Recruiter agent inside
execute()you need to define it above the step and add the necessary imports.这一步会要求被认定为“技术型”的候选人提供更多关于他们如何进入专业字段的信息。它使用整个简历文本,以便大型语言模型可以提出相关的后续问题。
🌐 This step prompts a candidate who is identified as "technical" for more information about how they got into their specialty. It uses the entire resume text so the LLM can craft a relevant follow-up question.
将以下内容添加到现有的
src/mastra/workflows/candidate-workflow.ts文件中:🌐 To the existing
src/mastra/workflows/candidate-workflow.tsfile add the following:src/mastra/workflows/candidate-workflow.tsconst 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() || "" };
},
});如果候选人是“非技术型”的,你需要提出不同的后续问题。这一步询问他们对该职位最感兴趣的地方,再次参考他们完整的简历内容。
execute()函数从大型语言模型中获取一个针对职位的查询。🌐 If the candidate is "non-technical", you want a different follow-up question. This step asks what interests them most about the role, again referencing their complete resume text. The
execute()function solicits a role-focused query from the LLM.将以下内容添加到现有的
src/mastra/workflows/candidate-workflow.ts文件中:🌐 To the existing
src/mastra/workflows/candidate-workflow.tsfile add the following:src/mastra/workflows/candidate-workflow.tsconst 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链接来完成的。🌐 You now combine the steps to implement branching logic based on the candidate's technical status. The workflow first gathers candidate data, then either asks about their specialty or about their role, depending on
isTechnical. This is done by chaininggatherCandidateInfowithaskAboutSpecialtyandaskAboutRole.将现有的
src/mastra/workflows/candidate-workflow.ts文件中的candidateWorkflow改成如下方式:🌐 To the existing
src/mastra/workflows/candidate-workflow.tsfile change thecandidateWorkflowlike so:src/mastra/workflows/candidate-workflow.tsexport 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();在你的
src/mastra/index.ts文件中,注册工作流:🌐 In your
src/mastra/index.tsfile, register the workflow:src/mastra/index.tsimport { Mastra } from "@mastra/core";
import { candidateWorkflow } from "./workflows/candidate-workflow";
export const mastra = new Mastra({
workflows: { candidateWorkflow },
});
测试工作流程Direct link to 测试工作流程
🌐 Testing the Workflow
你可以通过启动开发服务器在 Studio 中测试你的工作流程:
🌐 You can test your workflow inside Studio by starting the development server:
mastra dev
在侧边栏中,导航到 工作流 并选择 candidate-workflow。在中间你会看到你的工作流程的图表视图,右侧边栏默认选中 运行 标签。在此标签中,你可以输入简历文本,例如:
🌐 In the sidebar, navigate to Workflows and select candidate-workflow. In the middle you'll see a graph view of your workflow and on the right sidebar the Run tab is selected by default. Inside this tab you can enter a resume text, for example:
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.
输入简历文本后,按 运行 按钮。现在你应该可以看到两个状态框(GatherCandidateInfo 和 AskAboutSpecialty),其中包含工作流步骤的输出内容。
🌐 After entering the resume text, press the Run button. You should now see two status boxes (GatherCandidateInfo and AskAboutSpecialty) which contain the output of the workflow steps.
你也可以通过调用 .createRun() 和 .start() 来以编程方式测试工作流。创建一个新文件 src/test-workflow.ts 并添加以下内容:
🌐 You can also test the workflow programmatically by calling .createRun() and .start(). Create a new file src/test-workflow.ts and add the following:
import { mastra } from "./mastra";
const run = await mastra.getWorkflow("candidateWorkflow").createRun();
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}`);
}
现在,运行工作流程,并在终端中获取输出:
🌐 Now, run the workflow and get output in your terminal:
npx tsx src/test-workflow.ts
你刚刚建立了一个工作流程,用于解析简历并根据候选人的技术能力决定要问哪个问题。恭喜,祝你编程愉快!
🌐 You've just built a workflow to parse a resume and decide which question to ask based on the candidate's technical abilities. Congrats and happy hacking!