"""技能差距分析 AI 引擎 差距分析 + 定制简历优化 + Agent 规划/执行。 依赖:LLM 枚举、skill_gap_analyzer/prompts """ import asyncio import re from json_repair import repair_json from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate from app.ai.models import LLM from app.ai.skill_gap_analyzer.prompts import ( SKILL_GAP_PROMPT, SUMMARY_OPTIMIZE_PROMPT, EXPERIENCE_OPTIMIZE_PROMPT, AGENT_PLAN_PROMPT, AGENT_MODULE_EDIT_PROMPT, MODULE_SCHEMAS, ) from app.core.logger import log def _parse_json(text: str): """解析 AI 输出的 JSON,自动去除 markdown 代码块包裹,容错处理""" cleaned = re.sub(r"^```(?:json)?\s*\n?", "", text.strip()) cleaned = re.sub(r"\n?```\s*$", "", cleaned) return repair_json(cleaned, return_objects=True) # ===== 差距分析 ===== _skill_gap_chain = ( ChatPromptTemplate.from_messages([("system", SKILL_GAP_PROMPT), ("human", "请开始分析。")]) | LLM.DOUBAO_PRO_32K.create(temperature=0) | StrOutputParser() ) async def analyze_skill_gap(skill_tags: list[str], resume_json: str) -> list[str]: """分析技能差距,返回缺失技能列表""" try: raw = await _skill_gap_chain.ainvoke({"skill_tags": str(skill_tags), "resume_json": resume_json}) result = _parse_json(raw) if isinstance(result, list): return [s for s in result if isinstance(s, str) and s in skill_tags] return skill_tags # 解析异常降级:全部标记缺失 except Exception as e: log.warning(f"AI技能差距分析失败: {e}") return skill_tags # 降级:全部标记缺失 # ===== 定制简历 - summary 优化 ===== _summary_optimize_chain = ( ChatPromptTemplate.from_messages([("system", SUMMARY_OPTIMIZE_PROMPT), ("human", "请开始优化。")]) | LLM.CLAUDE_SONNET_4.create(temperature=0.3) | StrOutputParser() ) async def optimize_summary(job_title: str, add_skills: list[str], original_summary: str) -> str: """优化个人概述,融入技能关键词""" try: return await _summary_optimize_chain.ainvoke({ "job_title": job_title, "add_skills": "、".join(add_skills) if add_skills else "无", "original_summary": original_summary or "暂无", }) except Exception as e: log.warning(f"AI优化summary失败: {e}") return original_summary # ===== 定制简历 - experience 优化 ===== _experience_optimize_chain = ( ChatPromptTemplate.from_messages([("system", EXPERIENCE_OPTIMIZE_PROMPT), ("human", "请开始优化。")]) | LLM.CLAUDE_SONNET_4.create(temperature=0.3) | StrOutputParser() ) async def optimize_module(job_title: str, job_description: str, module_data: str) -> list | dict | None: """优化子表模块经历描述,返回修改后的完整模块数据""" try: raw = await _experience_optimize_chain.ainvoke({ "job_title": job_title, "job_description": job_description or "", "original_module_data": module_data, }) return _parse_json(raw) except Exception as e: log.warning(f"AI优化经历模块失败: {e}") return None # ===== Agent - 规划 ===== _plan_chain = ( ChatPromptTemplate.from_messages([("system", AGENT_PLAN_PROMPT), ("human", "请分析用户指令。")]) | LLM.DOUBAO_PRO_32K.create(temperature=0) | StrOutputParser() ) async def plan_edit(job_title: str, resume_json: str, chat_history: str, instruction: str) -> dict | None: """Agent 规划:分析用户指令,返回修改计划或对话回复""" try: raw = await _plan_chain.ainvoke({ "job_title": job_title, "resume_json": resume_json, "chat_history": chat_history, "instruction": instruction, }) result = _parse_json(raw) return result if isinstance(result, dict) else None except Exception as e: log.warning(f"AI规划失败: {e}") return None # ===== Agent - 模块修改 ===== _module_edit_chain = ( ChatPromptTemplate.from_messages([("system", AGENT_MODULE_EDIT_PROMPT), ("human", "请执行修改。")]) | LLM.GPT_4O.create(temperature=0.3) | StrOutputParser() ) async def execute_module_edit(job_title: str, module_instruction: str, module_schema: str, module_data: str) -> dict | list | None: """Agent 模块修改:根据指令修改指定模块数据""" try: raw = await _module_edit_chain.ainvoke({ "job_title": job_title, "module_instruction": module_instruction, "module_schema": module_schema, "module_data": module_data, }) return _parse_json(raw) except Exception as e: log.warning(f"AI模块修改失败: {e}") return None