Agent-study项目教程(02):智能简历结构化提取工具

📅 2026/8/14 12:13:11
Agent-study项目教程(02):智能简历结构化提取工具
一、理论部分1. 为什么要“结构化输出”从文本到可编排数据在 Agent 开发中模型输出如果只是自然语言文本往往难以被程序可靠消费而一旦把输出约束为结构化数据如 JSON就可以直接用于写入数据库/生成文件JSON、CSV作为下一步工具调用的参数函数调用、工作流编排做校验、做评估、做自动化测试因此“让模型稳定输出符合规范的数据结构”是从聊天走向可落地系统的关键一步。2. 用 Pydantic 定义“目标数据结构”让模型做填空题实现结构化输出的核心不是“让模型自己随便写 JSON”而是先明确你需要的数据结构然后让模型按这个结构填写。Pydantic 的价值在于用 Python 类型定义字段必填/可选、列表、嵌套对象自动生成 JSON Schema可作为约束条件写入提示词对模型输出进行校验不合格就直接报错便于定位问题在本项目中我们定义了Education、WorkExperience、Resume三个模型最终希望模型输出一个完整的ResumeJSON。3. “双重约束”保证稳定System Prompt JSON Mode 低温度仅靠提示词约束有时模型仍可能输出多余解释、Markdown 包裹或字段缺失。本项目采用三项组合策略来提高稳定性System Prompt 明确输出要求只输出纯 JSON不要 Markdown不要解释文本JSON Moderesponse_format让服务端强制返回 JSON 对象格式尽量减少跑偏temperature0.0信息抽取类任务追求稳定一致一般将温度设为 0此外得到模型输出后还会再用 Pydantic 做一次校验实现“生成—校验”的闭环。二、实战部分1. 项目目标实现一个“简历结构化提取工具”输入一份简历文本例如resume.txt输出一份结构化 JSON字段包括基本信息姓名、邮箱、电话技能技能列表教育经历学校/专业/学位/时间段工作经历公司/岗位/工作描述摘要2. 运行准备请确保本地已安装依赖并配置好环境变量不要把真实密钥写进代码或公开仓库依赖安装示例pipinstall-rrequirements.txt环境变量示例DEEPSEEK_API_KEYDEEPSEEK_BASE_URL输入文件将待解析简历放在项目目录下的resume.txt项目已提供示例文件。3. 项目代码完整实现下面给出项目的完整代码核心逻辑完整篇幅可控便于直接运行importosimportjsonfromopenaiimportOpenAIfromdotenvimportload_dotenvfrompydanticimportBaseModel,FieldfromtypingimportList,Optional# 加载环境变量# 假设 .env 文件在项目根目录project_rootos.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))load_dotenv(os.path.join(project_root,.env))clientOpenAI(api_keyos.getenv(DEEPSEEK_API_KEY),base_urlos.getenv(DEEPSEEK_BASE_URL),)# 1. 定义目标数据结构Pydantic ModelclassEducation(BaseModel):school:strField(...,description学校名称)major:strField(...,description专业)degree:strField(...,description学位如本科、硕士)year:strField(...,description毕业年份或就读时间段)classWorkExperience(BaseModel):company:strField(...,description公司名称)role:strField(...,description职位)description:strField(...,description工作描述摘要)classResume(BaseModel):name:strField(...,description候选人姓名)email:Optional[str]Field(None,description电子邮箱)phone:Optional[str]Field(None,description联系电话)skills:List[str]Field(...,description技能列表)education:List[Education]Field(...,description教育背景列表)work_experience:List[WorkExperience]Field(...,description工作经历列表)defextract_resume_info(file_path:str):# 2. 读取简历文本try:withopen(file_path,r,encodingutf-8)asf:resume_contentf.read()exceptFileNotFoundError:print(f错误: 找不到文件{file_path})returnNoneprint(f正在分析简历:{file_path}...)# 3. 构造 Prompt输出必须严格遵循 Schemasystem_promptf 你是一个专业的简历解析助手。请从用户的简历文本中提取关键信息。 请严格按照以下 JSON 格式输出不要包含任何 Markdown 格式标记如 json ... 只输出纯 JSON 字符串。 目标 JSON 结构定义如下:{json.dumps(Resume.model_json_schema(),indent2,ensure_asciiFalse)}.strip()messages[{role:system,content:system_prompt},{role:user,content:resume_content},]# 4. 调用 APIJSON Mode 低温度保证稳定try:responseclient.chat.completions.create(modeldeepseek-chat,messagesmessages,temperature0.0,response_format{type:json_object},)result_jsonresponse.choices[0].message.content# 5. 解析并验证不符合结构就会抛错便于调试与兜底resume_dataResume.model_validate_json(result_json)# 6. 输出结构化结果print(\n提取成功。结构化数据如下\n)print(json.dumps(resume_data.model_dump(),indent2,ensure_asciiFalse))returnresume_dataexceptExceptionase:print(f\n发生错误{e})ifresult_jsoninlocals():print(f原始返回内容:{result_json})returnNoneif__name____main__:current_diros.path.dirname(os.path.abspath(__file__))resume_pathos.path.join(current_dir,resume.txt)extract_resume_info(resume_path)4. 如何运行在项目根目录执行python stage_01_llm_basics/project_02_resume_extractor/extractor.py5. 运行结果示例如果输入的resume.txt类似“张三 / 电话 / 邮箱 / 教育背景 / 工作经历 / 技能清单”这种结构运行后你将得到类似如下的结构化输出示例{name:张三,email:zhangsanexample.com,phone:138-0013-8000,skills:[Java,Python,Golang,C,MySQL,Redis,MongoDB,Git,Docker,Kubernetes,英语,普通话],education:[{school:清华大学,major:计算机科学与技术,degree:本科,year:2018.09 - 2022.06}],work_experience:[{company:字节跳动,role:后端开发工程师,description:负责推荐系统后端开发优化接口响应时间参与高并发方案设计使用Golang重构部分服务提升吞吐。},{company:腾讯,role:后台开发实习生,description:参与微信支付营销活动后台开发编写自动化测试脚本提升测试效率。}]}6. 项目总结结构化输出是 Agent 工程化的前提让模型输出变成程序可直接消费的数据。Pydantic 提供了“先定义结构再生成约束再做校验”的完整闭环显著提升稳定性。System Prompt JSON Mode temperature0.0 的组合适用于“信息抽取/格式化”任务可作为后续工具调用参数生成的通用模板。