Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
R
recruit-sys
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
李文光
recruit-sys
Commits
6248f275
Commit
6248f275
authored
Sep 02, 2026
by
李文光
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: 简历解析真正改为大模型优先提取,失败才回退正则
parent
07310dd8
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
219 additions
and
100 deletions
+219
-100
llm.py
backend/app/services/llm.py
+4
-4
resume_parser.py
backend/app/services/resume_parser.py
+70
-23
resume_parser_core.py
backend/app/services/resume_parser_core.py
+33
-18
test_resume_parser_llm.py
backend/tests/test_resume_parser_llm.py
+112
-55
No files found.
backend/app/services/llm.py
View file @
6248f275
...
@@ -218,8 +218,8 @@ def sanitize_candidate_for_llm(candidate: dict[str, Any]) -> dict[str, Any]:
...
@@ -218,8 +218,8 @@ def sanitize_candidate_for_llm(candidate: dict[str, Any]) -> dict[str, Any]:
# 简历结构化提取:LLM 返回的字段集合(与 llm_resume_fields 的 prompt 保持一致)。
# 简历结构化提取:LLM 返回的字段集合(与 llm_resume_fields 的 prompt 保持一致)。
# 其中姓名/手机/邮箱/出生年月/年龄等 PII 会被本地脱敏,LLM 无法看到真实值,
# 其中姓名/手机/邮箱/出生年月/年龄
/城市
等 PII 会被本地脱敏,LLM 无法看到真实值,
# 这些字段
最终以正则解析结果为准(见 resume_parser._merge_parse_result
)。
# 这些字段
始终以正则预扫描结果为准(见 resume_parser_core.extract_pii_fields
)。
LLM_RESUME_FIELDS
=
(
LLM_RESUME_FIELDS
=
(
"name"
,
"name"
,
"jobTitle"
,
"jobTitle"
,
...
@@ -239,8 +239,8 @@ LLM_RESUME_FIELDS = (
...
@@ -239,8 +239,8 @@ LLM_RESUME_FIELDS = (
async
def
llm_resume_fields
(
text
:
str
,
hints
:
dict
[
str
,
Any
]
|
None
=
None
)
->
dict
[
str
,
Any
]
|
None
:
async
def
llm_resume_fields
(
text
:
str
,
hints
:
dict
[
str
,
Any
]
|
None
=
None
)
->
dict
[
str
,
Any
]
|
None
:
"""用大模型从简历文本中提取结构化字段;未配置 Key 或调用失败时返回 None(调用方回退正则)。
"""用大模型从简历文本中提取结构化字段;未配置 Key 或调用失败时返回 None(调用方回退正则)。
发送前用正则
解析
结果对姓名/手机/邮箱/城市/出生年月/年龄做本地脱敏,
发送前用正则
预扫描
结果对姓名/手机/邮箱/城市/出生年月/年龄做本地脱敏,
被脱敏的字段 LLM 一律返回空值,最终以正则结果为准。
被脱敏的字段 LLM 一律返回空值,最终以正则
预扫描
结果为准。
"""
"""
settings
=
get_settings
()
settings
=
get_settings
()
if
not
settings
.
effective_llm_api_key
:
if
not
settings
.
effective_llm_api_key
:
...
...
backend/app/services/resume_parser.py
View file @
6248f275
...
@@ -3,7 +3,19 @@ from tempfile import TemporaryDirectory
...
@@ -3,7 +3,19 @@ from tempfile import TemporaryDirectory
from
backend.app.services.file_storage
import
sanitize_filename
from
backend.app.services.file_storage
import
sanitize_filename
from
backend.app.services.llm
import
LLM_RESUME_FIELDS
,
llm_resume_fields
from
backend.app.services.llm
import
LLM_RESUME_FIELDS
,
llm_resume_fields
from
backend.app.services.resume_parser_core
import
parse_resume
,
school_tags
from
backend.app.services.resume_parser_core
import
(
extract_pii_fields
,
infer_source
,
parse_resume
,
parse_resume_text
,
read_resume_text
,
school_tags
,
)
# LLM 看不到真实值的 PII 字段:发送前已本地脱敏,始终以正则预扫描结果为准。
_PII_KEYS
=
{
"name"
,
"phone"
,
"email"
,
"birthDate"
,
"age"
,
"city"
,
"resumeName"
}
# 交给大模型提取的内容字段(大模型非空值优先采用,正则仅作整体兜底)。
_LLM_CONTENT_KEYS
=
tuple
(
key
for
key
in
LLM_RESUME_FIELDS
if
key
not
in
_PII_KEYS
)
def
parse_resume_path
(
path
:
Path
)
->
dict
:
def
parse_resume_path
(
path
:
Path
)
->
dict
:
...
@@ -19,10 +31,21 @@ def parse_uploaded_bytes(content: bytes, original_name: str = "resume.bin") -> d
...
@@ -19,10 +31,21 @@ def parse_uploaded_bytes(content: bytes, original_name: str = "resume.bin") -> d
async
def
parse_resume_path_async
(
path
:
Path
)
->
dict
:
async
def
parse_resume_path_async
(
path
:
Path
)
->
dict
:
"""LLM 优先、正则兜底的简历解析入口(API/CLI 均走这里)。"""
"""LLM 优先、正则兜底的简历解析入口(API/CLI 均走这里)。
rule_result
=
parse_resume
(
path
)
llm_result
=
await
llm_resume_fields
(
rule_result
.
get
(
"resumeText"
)
or
""
,
rule_result
)
读取简历文本后,先把内容交给大模型理解并提取结构化字段;只有大模型不可用
return
_merge_parse_result
(
rule_result
,
llm_result
)
或提取失败时才整体回退到纯正则解析(parse_resume_text)。姓名/手机/邮箱/
出生年月/年龄/城市等 PII 发往大模型前必须先本地脱敏(见
llm.sanitize_resume_for_llm),因此这类字段始终以 extract_pii_fields 的
正则预扫描结果为准,不采用大模型返回值。
"""
text
=
read_resume_text
(
path
)
filename
=
path
.
name
pii
=
extract_pii_fields
(
text
,
filename
)
llm_result
=
await
llm_resume_fields
(
text
,
pii
)
if
not
_has_llm_content
(
llm_result
):
return
parse_resume_text
(
text
,
filename
)
return
_compose_llm_result
(
text
,
filename
,
pii
,
llm_result
)
async
def
parse_uploaded_bytes_async
(
content
:
bytes
,
original_name
:
str
=
"resume.bin"
)
->
dict
:
async
def
parse_uploaded_bytes_async
(
content
:
bytes
,
original_name
:
str
=
"resume.bin"
)
->
dict
:
...
@@ -32,22 +55,46 @@ async def parse_uploaded_bytes_async(content: bytes, original_name: str = "resum
...
@@ -32,22 +55,46 @@ async def parse_uploaded_bytes_async(content: bytes, original_name: str = "resum
return
await
parse_resume_path_async
(
path
)
return
await
parse_resume_path_async
(
path
)
def
_merge_parse_result
(
rule_result
:
dict
,
llm_result
:
dict
|
None
)
->
dict
:
def
_has_llm_content
(
result
:
dict
|
None
)
->
bool
:
"""LLM 结果优先、正则结果兜底:LLM 字段非空则覆盖,否则保留正则值。
"""大模型是否提取到可用内容字段;返回空字典/全空时视为提取失败,回退正则。"""
if
not
isinstance
(
result
,
dict
):
return
False
for
key
in
_LLM_CONTENT_KEYS
:
value
=
result
.
get
(
key
)
if
isinstance
(
value
,
list
):
if
any
(
str
(
item
)
.
strip
()
for
item
in
value
):
return
True
elif
value
not
in
(
None
,
""
,
[],
{}):
return
True
return
False
技能取并集去重(LLM 优先);schoolTags 依据最终 school 重新推导。
"""
def
_clean_text_value
(
value
:
object
)
->
str
:
result
=
dict
(
rule_result
)
if
isinstance
(
value
,
str
):
if
not
isinstance
(
llm_result
,
dict
):
return
value
.
strip
()
return
result
if
value
is
None
:
for
key
in
LLM_RESUME_FIELDS
:
return
""
value
=
llm_result
.
get
(
key
)
return
str
(
value
)
.
strip
()
if
isinstance
(
value
,
str
):
value
=
value
.
strip
()
if
value
not
in
(
None
,
""
,
[],
{}):
def
_compose_llm_result
(
text
:
str
,
filename
:
str
,
pii
:
dict
,
llm_result
:
dict
)
->
dict
:
result
[
key
]
=
value
"""大模型提取成功时的结果组装:PII 取正则预扫描值,其余内容字段取大模型值。"""
llm_skills
=
[
str
(
item
)
.
strip
()
for
item
in
llm_result
.
get
(
"skills"
)
or
[]
if
str
(
item
)
.
strip
()]
school
=
_clean_text_value
(
llm_result
.
get
(
"school"
))
if
llm_skills
:
skills
=
[
result
[
"skills"
]
=
list
(
dict
.
fromkeys
([
*
llm_skills
,
*
(
rule_result
.
get
(
"skills"
)
or
[])]))
str
(
item
)
.
strip
()
result
[
"schoolTags"
]
=
school_tags
(
result
.
get
(
"school"
)
or
""
)
for
item
in
(
llm_result
.
get
(
"skills"
)
or
[])
return
result
if
str
(
item
)
.
strip
()
]
return
{
**
pii
,
"jobTitle"
:
_clean_text_value
(
llm_result
.
get
(
"jobTitle"
)),
"years"
:
_clean_text_value
(
llm_result
.
get
(
"years"
)),
"education"
:
_clean_text_value
(
llm_result
.
get
(
"education"
)),
"school"
:
school
,
"major"
:
_clean_text_value
(
llm_result
.
get
(
"major"
)),
"schoolTags"
:
school_tags
(
school
),
"skills"
:
list
(
dict
.
fromkeys
(
skills
)),
"source"
:
infer_source
(
text
,
filename
),
"resumeText"
:
text
,
"textLength"
:
len
(
text
),
}
backend/app/services/resume_parser_core.py
View file @
6248f275
...
@@ -431,7 +431,8 @@ def school_tags(school: str):
...
@@ -431,7 +431,8 @@ def school_tags(school: str):
return
tags
return
tags
def
parse_resume
(
path
:
Path
):
def
read_resume_text
(
path
:
Path
)
->
str
:
"""读取 PDF/DOCX/TXT 简历文本并做统一规范化,供 LLM 优先解析与正则解析共用。"""
suffix
=
path
.
suffix
.
lower
()
suffix
=
path
.
suffix
.
lower
()
if
suffix
==
".pdf"
:
if
suffix
==
".pdf"
:
text
=
read_pdf
(
path
)
text
=
read_pdf
(
path
)
...
@@ -439,42 +440,56 @@ def parse_resume(path: Path):
...
@@ -439,42 +440,56 @@ def parse_resume(path: Path):
text
=
read_docx
(
path
)
text
=
read_docx
(
path
)
else
:
else
:
text
=
read_text
(
path
)
text
=
read_text
(
path
)
text
=
normalize
(
text
)
return
normalize
(
text
)
filename
=
path
.
name
# 电话:支持多种格式 13812345678 / 138 1234 5678 / 138-1234-5678 / +86 13812345678
def
extract_pii_fields
(
text
:
str
,
filename
:
str
)
->
dict
:
"""正则预扫描候选人 PII 字段(脱敏依据,不随正文发往大模型)。
姓名/手机/邮箱/出生年月/年龄/城市 等敏感字段在解析链路中始终以本地正则
结果为准:发送给大模型前必须先把它们替换为占位符(见
llm.sanitize_resume_for_llm),大模型看不到真实值,最终取值也以这里的
正则结果为准。
"""
phone
=
first_match
([
phone
=
first_match
([
r"((?:\+?86[-\s]?)?1[3-9]\d[-\s]?\d{4}[-\s]?\d{4})"
,
r"((?:\+?86[-\s]?)?1[3-9]\d[-\s]?\d{4}[-\s]?\d{4})"
,
r"电话[::\s]*((?:\+?86[-\s]?)?1[3-9]\d{9})"
,
r"电话[::\s]*((?:\+?86[-\s]?)?1[3-9]\d{9})"
,
],
text
)
],
text
)
email
=
first_match
([
r"([A-Z0-9._
%+-
]+@[A-Z0-9.-]+\.[A-Z]{2,})"
],
text
)
email
=
first_match
([
r"([A-Z0-9._
%+-
]+@[A-Z0-9.-]+\.[A-Z]{2,})"
],
text
)
years
=
infer_work_years
(
f
"{text}
\n
{filename}"
)
birth_date
=
infer_birth_date
(
text
)
birth_date
=
infer_birth_date
(
text
)
education
=
infer_education
(
text
)
return
{
school
=
infer_school
(
text
)
major
=
infer_major
(
text
)
city
=
first_match
([
r"(?:现居|所在地|城市|地点)[::\s]+([一-龥]{2,12})"
],
text
)
result
=
{
"name"
:
infer_name
(
text
,
filename
),
"name"
:
infer_name
(
text
,
filename
),
"jobTitle"
:
infer_job
(
text
),
"phone"
:
phone
,
"phone"
:
phone
,
"email"
:
email
,
"email"
:
email
,
"birthDate"
:
birth_date
,
"birthDate"
:
birth_date
,
"age"
:
infer_explicit_age
(
text
)
or
age_from_birth_date
(
birth_date
),
"age"
:
infer_explicit_age
(
text
)
or
age_from_birth_date
(
birth_date
),
"years"
:
years
,
"city"
:
first_match
([
r"(?:现居|所在地|城市|地点)[::\s]+([一-龥]{2,12})"
],
text
),
"education"
:
education
,
"resumeName"
:
filename
,
}
def
parse_resume_text
(
text
:
str
,
filename
:
str
)
->
dict
:
"""对已读取的简历文本做纯正则结构化提取(无大模型时的兜底/调试路径)。"""
pii
=
extract_pii_fields
(
text
,
filename
)
school
=
infer_school
(
text
)
return
{
**
pii
,
"jobTitle"
:
infer_job
(
text
),
"years"
:
infer_work_years
(
f
"{text}
\n
{filename}"
),
"education"
:
infer_education
(
text
),
"school"
:
school
,
"school"
:
school
,
"major"
:
major
,
"major"
:
infer_major
(
text
)
,
"schoolTags"
:
school_tags
(
school
),
"schoolTags"
:
school_tags
(
school
),
"city"
:
city
,
"source"
:
infer_source
(
text
,
filename
),
"source"
:
infer_source
(
text
,
filename
),
"skills"
:
extract_skills
(
text
),
"skills"
:
extract_skills
(
text
),
"resumeText"
:
text
,
"resumeText"
:
text
,
"resumeName"
:
filename
,
"textLength"
:
len
(
text
),
"textLength"
:
len
(
text
),
}
}
return
result
def
parse_resume
(
path
:
Path
)
->
dict
:
"""纯正则解析入口(无大模型时的兜底/调试路径):读取文件并提取字段。"""
return
parse_resume_text
(
read_resume_text
(
path
),
path
.
name
)
def
infer_education
(
text
:
str
)
->
str
:
def
infer_education
(
text
:
str
)
->
str
:
...
...
backend/tests/test_resume_parser_llm.py
View file @
6248f275
...
@@ -2,7 +2,7 @@ import asyncio
...
@@ -2,7 +2,7 @@ import asyncio
import
pytest
import
pytest
from
backend.app.services.llm
import
llm_resume_fields
from
backend.app.services.llm
import
llm_resume_fields
from
backend.app.services.resume_parser
import
_
merge_parse
_result
,
parse_resume_path_async
from
backend.app.services.resume_parser
import
_
compose_llm
_result
,
parse_resume_path_async
@
pytest
.
fixture
()
@
pytest
.
fixture
()
...
@@ -18,73 +18,130 @@ def llm_disabled(monkeypatch):
...
@@ -18,73 +18,130 @@ def llm_disabled(monkeypatch):
config
.
get_settings
.
cache_clear
()
config
.
get_settings
.
cache_clear
()
def
test_merge_parse_result_prefers_llm_values
():
@
pytest
.
fixture
()
rule
=
{
def
stub_llm
(
monkeypatch
):
"""把 parse_resume_path_async 引用的 llm_resume_fields 替换为固定返回的异步桩。"""
def
install
(
result
):
async
def
fake_llm
(
text
,
hints
=
None
):
return
result
monkeypatch
.
setattr
(
"backend.app.services.resume_parser.llm_resume_fields"
,
fake_llm
)
return
install
def
_write_resume
(
tmp_path
,
name
:
str
=
"张晓燕.txt"
)
->
str
:
resume
=
tmp_path
/
name
resume
.
write_text
(
"张晓燕
\n
性别:女年龄:28
\n
电话:18734915261 邮箱:1822742034@qq.com
\n
销售支持专员
\n
教育经历
\n
"
"2017.09—2021.07 甘肃农业大学
\n
农林经济管理
\n
"
"主修课程:市场营销、管理学原理、人力资源管理、企业经营战略、财务管理、会计学原理、区域经济学"
,
encoding
=
"utf-8"
,
)
return
str
(
resume
)
def
test_compose_llm_result_keeps_regex_pii_and_uses_llm_content
():
pii
=
{
"name"
:
"张晓燕"
,
"name"
:
"张晓燕"
,
"jobTitle"
:
""
,
"phone"
:
"18734915261"
,
"school"
:
"甘肃农业大学"
,
"email"
:
"1822742034@qq.com"
,
"major"
:
"人力资源管理"
,
"skills"
:
[
"市场营销"
],
"schoolTags"
:
[
"非985/211"
],
}
llm
=
{
"name"
:
""
,
"jobTitle"
:
"销售支持专员"
,
"phone"
:
""
,
"email"
:
""
,
"birthDate"
:
""
,
"birthDate"
:
""
,
"age"
:
""
,
"age"
:
"28"
,
"years"
:
""
,
"education"
:
""
,
"school"
:
""
,
"major"
:
"农林经济管理"
,
"city"
:
""
,
"city"
:
""
,
"
skills"
:
[
"销售支持"
,
"客户管理"
]
,
"
resumeName"
:
"张晓燕.txt"
,
}
}
merged
=
_merge_parse_result
(
rule
,
llm
)
llm
=
{
assert
merged
[
"jobTitle"
]
==
"销售支持专员"
"name"
:
"大模型幻觉姓名"
,
assert
merged
[
"major"
]
==
"农林经济管理"
"phone"
:
"13900000000"
,
assert
merged
[
"name"
]
==
"张晓燕"
"email"
:
"fake@llm.com"
,
assert
merged
[
"skills"
]
==
[
"销售支持"
,
"客户管理"
,
"市场营销"
]
"birthDate"
:
"1990-01-01"
,
"age"
:
"35"
,
"city"
:
"太原"
,
def
test_merge_parse_result_keeps_rule_when_llm_empty
():
rule
=
{
"name"
:
"张三"
,
"jobTitle"
:
"销售支持专员"
,
"jobTitle"
:
"销售支持专员"
,
"years"
:
"2年"
,
"education"
:
"本科"
,
"school"
:
"甘肃农业大学"
,
"school"
:
"甘肃农业大学"
,
"major"
:
"农林经济管理"
,
"major"
:
"农林经济管理"
,
"skills"
:
[],
"skills"
:
[
"客户管理"
,
"客户管理"
],
"schoolTags"
:
[
"非985/211"
],
}
llm
=
{
"name"
:
""
,
"jobTitle"
:
""
,
"phone"
:
""
,
"email"
:
""
,
"birthDate"
:
""
,
"age"
:
""
,
"years"
:
""
,
"education"
:
""
,
"school"
:
""
,
"major"
:
""
,
"city"
:
""
,
"skills"
:
[],
}
}
merged
=
_merge_parse_result
(
rule
,
llm
)
text
=
"简历正文"
assert
merged
[
"name"
]
==
"张三"
merged
=
_compose_llm_result
(
text
,
"张晓燕.txt"
,
pii
,
llm
)
# PII 字段不采用大模型幻觉值,始终以正则预扫描结果为准
assert
merged
[
"name"
]
==
"张晓燕"
assert
merged
[
"phone"
]
==
"18734915261"
assert
merged
[
"email"
]
==
"1822742034@qq.com"
assert
merged
[
"birthDate"
]
==
""
assert
merged
[
"age"
]
==
"28"
assert
merged
[
"city"
]
==
""
# 内容字段采用大模型值,schoolTags 依据最终 school 重新推导
assert
merged
[
"jobTitle"
]
==
"销售支持专员"
assert
merged
[
"jobTitle"
]
==
"销售支持专员"
assert
merged
[
"years"
]
==
"2年"
assert
merged
[
"education"
]
==
"本科"
assert
merged
[
"school"
]
==
"甘肃农业大学"
assert
merged
[
"major"
]
==
"农林经济管理"
assert
merged
[
"major"
]
==
"农林经济管理"
assert
merged
[
"skills"
]
==
[]
assert
merged
[
"skills"
]
==
[
"客户管理"
]
assert
merged
[
"schoolTags"
]
==
[
"非985/211"
]
assert
merged
[
"resumeText"
]
==
text
def
test_merge_parse_result_recomputes_school_tags
():
def
test_async_parse_prefers_llm_content_and_keeps_regex_pii
(
tmp_path
,
stub_llm
):
merged
=
_merge_parse_result
(
_write_resume
(
tmp_path
)
{
"school"
:
"甘肃农业大学"
,
"schoolTags"
:
[
"非985/211"
]},
stub_llm
(
{
"school"
:
"清华大学"
},
{
"name"
:
"大模型幻觉姓名"
,
"jobTitle"
:
"销售支持专员"
,
"phone"
:
"13900000000"
,
"email"
:
""
,
"birthDate"
:
""
,
"age"
:
""
,
"years"
:
"2年"
,
"education"
:
"本科"
,
"school"
:
"甘肃农业大学"
,
"major"
:
"农林经济管理"
,
"city"
:
"太原"
,
"skills"
:
[
"客户管理"
],
}
)
)
assert
merged
[
"school"
]
==
"清华大学"
parsed
=
asyncio
.
run
(
parse_resume_path_async
(
tmp_path
/
"张晓燕.txt"
))
assert
merged
[
"schoolTags"
]
==
[
"985"
,
"211"
]
assert
parsed
[
"name"
]
==
"张晓燕"
assert
parsed
[
"phone"
]
==
"18734915261"
assert
parsed
[
"jobTitle"
]
==
"销售支持专员"
assert
parsed
[
"major"
]
==
"农林经济管理"
assert
parsed
[
"years"
]
==
"2年"
assert
parsed
[
"education"
]
==
"本科"
assert
parsed
[
"city"
]
==
""
assert
parsed
[
"skills"
]
==
[
"客户管理"
]
assert
parsed
[
"resumeName"
]
==
"张晓燕.txt"
assert
parsed
[
"textLength"
]
>
0
def
test_async_parse_skips_regex_when_llm_usable
(
tmp_path
,
stub_llm
,
monkeypatch
):
"""LLM 提取到内容时不应再跑正则兜底(正则仅在大模型不可用/失败时执行)。"""
def
boom
(
*
args
,
**
kwargs
):
raise
AssertionError
(
"LLM 可用且提取到内容时不应调用正则兜底 parse_resume_text"
)
monkeypatch
.
setattr
(
"backend.app.services.resume_parser.parse_resume_text"
,
boom
)
_write_resume
(
tmp_path
)
stub_llm
({
"jobTitle"
:
"销售支持专员"
,
"school"
:
"甘肃农业大学"
,
"major"
:
"农林经济管理"
})
parsed
=
asyncio
.
run
(
parse_resume_path_async
(
tmp_path
/
"张晓燕.txt"
))
assert
parsed
[
"name"
]
==
"张晓燕"
assert
parsed
[
"major"
]
==
"农林经济管理"
def
test_async_parse_falls_back_to_regex_when_llm_returns_empty
(
tmp_path
,
stub_llm
):
"""大模型返回空内容视为提取失败,回退纯正则解析。"""
_write_resume
(
tmp_path
)
stub_llm
({})
parsed
=
asyncio
.
run
(
parse_resume_path_async
(
tmp_path
/
"张晓燕.txt"
))
assert
parsed
[
"name"
]
==
"张晓燕"
assert
parsed
[
"phone"
]
==
"18734915261"
assert
parsed
[
"school"
]
==
"甘肃农业大学"
assert
parsed
[
"major"
]
==
"农林经济管理"
assert
parsed
[
"jobTitle"
]
==
"销售支持专员"
assert
parsed
[
"resumeText"
]
def
test_llm_resume_fields_returns_none_without_key
(
llm_disabled
):
def
test_llm_resume_fields_returns_none_without_key
(
llm_disabled
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment