search_resumes
Search and rank resumes by keywords, position, skills, experience, and education to find qualified candidates for specific job requirements.
Instructions
根据关键词、职位、技能、经验等条件搜索和排序简历。
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| keyword | No | 搜索关键词,会在姓名、职位、摘要、技能中搜索 | |
| position | No | 职位名称,例如:前端工程师、Java开发 | |
| skills | No | 所需技能列表,例如:["Java", "Spring", "MySQL"] | |
| minYearsOfExperience | No | 最低工作年限 | |
| maxYearsOfExperience | No | 最高工作年限 | |
| education | No | 教育背景,例如:本科、硕士 | |
| sortBy | No | 排序方式:relevance(相关性)、date(日期)、experience(经验)、name(姓名) | relevance |
| sortOrder | No | 排序顺序:asc(升序)、desc(降序) | desc |
| limit | No | 返回结果数量限制,默认50 | |
| offset | No | 分页偏移量,默认0 |
Implementation Reference
- src/mcp/mcp-server.service.ts:207-258 (handler)MCP tool handler for 'search_resumes': maps tool arguments to SearchResumeDto, calls resumeService.searchResumes, formats and returns JSON response.
case 'search_resumes': { const searchDto: SearchResumeDto = { keyword: args.keyword as string | undefined, position: args.position as string | undefined, skills: args.skills as string[] | undefined, minYearsOfExperience: args.minYearsOfExperience as number | undefined, maxYearsOfExperience: args.maxYearsOfExperience as number | undefined, education: args.education as string | undefined, sortBy: (args.sortBy as any) || 'relevance', sortOrder: (args.sortOrder as any) || 'desc', limit: args.limit as number | undefined, offset: args.offset as number | undefined, }; const result = await this.resumeService.searchResumes(searchDto); return { content: [ { type: 'text', text: JSON.stringify( { success: true, total: result.total, limit: result.limit, offset: result.offset, resumes: result.resumes.map((r) => ({ id: r.id, name: r.name, position: r.position, email: r.email, phone: r.phone, yearsOfExperience: r.yearsOfExperience, skills: r.skills, education: r.education, university: r.university, major: r.major, summary: r.summary, score: r.score, receivedDate: r.receivedDate?.toISOString(), // 添加下载相关字段 fileName: r.fileName, filePath: r.filePath, downloadUri: r.filePath ? `resume://download/${r.id}` : undefined, })), }, null, 2, ), }, ], }; } - src/mcp/mcp-server.service.ts:67-119 (schema)Input JSON schema for the 'search_resumes' tool defining all search parameters, sorting options, and pagination.
inputSchema: { type: 'object', properties: { keyword: { type: 'string', description: '搜索关键词,会在姓名、职位、摘要、技能中搜索', }, position: { type: 'string', description: '职位名称,例如:前端工程师、Java开发', }, skills: { type: 'array', items: { type: 'string' }, description: '所需技能列表,例如:["Java", "Spring", "MySQL"]', }, minYearsOfExperience: { type: 'number', description: '最低工作年限', }, maxYearsOfExperience: { type: 'number', description: '最高工作年限', }, education: { type: 'string', description: '教育背景,例如:本科、硕士', }, sortBy: { type: 'string', enum: ['relevance', 'date', 'experience', 'name'], description: '排序方式:relevance(相关性)、date(日期)、experience(经验)、name(姓名)', default: 'relevance', }, sortOrder: { type: 'string', enum: ['asc', 'desc'], description: '排序顺序:asc(升序)、desc(降序)', default: 'desc', }, limit: { type: 'number', description: '返回结果数量限制,默认50', default: 50, }, offset: { type: 'number', description: '分页偏移量,默认0', default: 0, }, }, }, - src/mcp/mcp-server.service.ts:64-120 (registration)Registration of 'search_resumes' tool in the ListToolsRequestSchema handler, including name, description, and input schema.
{ name: 'search_resumes', description: '根据关键词、职位、技能、经验等条件搜索和排序简历。', inputSchema: { type: 'object', properties: { keyword: { type: 'string', description: '搜索关键词,会在姓名、职位、摘要、技能中搜索', }, position: { type: 'string', description: '职位名称,例如:前端工程师、Java开发', }, skills: { type: 'array', items: { type: 'string' }, description: '所需技能列表,例如:["Java", "Spring", "MySQL"]', }, minYearsOfExperience: { type: 'number', description: '最低工作年限', }, maxYearsOfExperience: { type: 'number', description: '最高工作年限', }, education: { type: 'string', description: '教育背景,例如:本科、硕士', }, sortBy: { type: 'string', enum: ['relevance', 'date', 'experience', 'name'], description: '排序方式:relevance(相关性)、date(日期)、experience(经验)、name(姓名)', default: 'relevance', }, sortOrder: { type: 'string', enum: ['asc', 'desc'], description: '排序顺序:asc(升序)、desc(降序)', default: 'desc', }, limit: { type: 'number', description: '返回结果数量限制,默认50', default: 50, }, offset: { type: 'number', description: '分页偏移量,默认0', default: 0, }, }, }, }, - src/resume/resume.service.ts:186-201 (helper)ResumeService.searchResumes helper: retrieves all resumes and delegates search to searchService.search
async searchResumes(criteria: ISearchCriteria): Promise<ISearchResult> { try { const allResumes = Array.from(this.resumes.values()); const results = await this.searchService.search(allResumes, criteria); return { resumes: results.resumes, total: results.total, limit: criteria.limit || this.configService.get<number>('search.defaultLimit') || 50, offset: criteria.offset || 0, }; } catch (error) { this.logger.error(`搜索简历失败: ${error.message}`, error.stack, 'ResumeService'); throw error; } } - src/search/search.service.ts:22-51 (helper)Core searchService.search helper: calculates relevance scores, filters, sorts, and paginates resumes based on criteria.
async search(resumes: IResume[], criteria: ISearchCriteria): Promise<ISearchResult> { try { // 计算每个简历的评分 const scoredResumes: ScoredResume[] = resumes.map((resume) => ({ ...resume, score: this.calculateScore(resume, criteria), })); // 过滤掉评分为0的简历 const filteredResumes = scoredResumes.filter((resume) => resume.score > 0); // 排序 const sortedResumes = this.sortResumes(filteredResumes, criteria); // 分页 const limit = criteria.limit || 50; const offset = criteria.offset || 0; const paginatedResumes = sortedResumes.slice(offset, offset + limit); return { resumes: paginatedResumes, total: sortedResumes.length, limit, offset, }; } catch (error) { this.logger.error(`搜索失败: ${error.message}`, error.stack, 'SearchService'); throw error; } }