删除的对话接口

This commit is contained in:
zk
2026-06-24 17:54:09 +08:00
parent 11c6bf6ba7
commit dc02969f3a
9 changed files with 20 additions and 319 deletions
-118
View File
@@ -1,118 +0,0 @@
# 求职助手 Agent 对话接口设计方案
## 1. 接口概述
`POST /job-agent/chat` — 求职助手对话接口,Python 端实现。
用户通过对话与求职助手交互,AI 根据用户简历和求职意向提供求职建议,识别用户意图后触发前端工具调用(岗位推荐 / 调整偏好)。
## 2. 入参 Schema
```python
class ChatMessage(BaseModel):
role: Literal["user", "assistant"]
content: str
class JobAgentChatParam(BaseModel):
message: str = Field(..., description="用户输入的消息")
resume_id: int = Field(..., alias="resumeId", description="简历ID")
history: list[ChatMessage] = Field(default_factory=list, description="对话历史")
job_categories: list[str] = Field(default_factory=list, alias="jobCategories", description="意向岗位类型名称")
regions: list[str] = Field(default_factory=list, alias="regions", description="意向城市名称")
industries: list[str] = Field(default_factory=list, alias="industries", description="意向行业名称")
```
## 3. 出参 Schema
```python
class ToolParams(BaseModel):
preference: str = Field(default="", description="用户岗位偏好描述,仅tool=recommend时有值")
class JobAgentChatDto(BaseModel):
message: str = Field(..., description="AI回复文本,不超过200字")
tool: str | None = Field(default=None, description="前端需执行的工具:recommend / editPreference / null")
tool_params: ToolParams | None = Field(default=None, alias="toolParams", description="工具参数")
```
## 4. AI 上下文构造
每次对话请求,后端自动查询以下数据拼入 system prompt
1. **简历信息**:根据 resumeId 查 bg_user_resume 主表 + 5张子表(教育/工作/实习/项目/竞赛),序列化为文本
2. **求职意向**:直接使用前端传入的 jobCategories / regions / industries(中文名称)
## 5. System Prompt 设计
```
你是 OfferPie 求职助手,帮助用户找到合适的工作。
【用户简历】
{resume_text}
【求职意向】
意向岗位:{job_categories}
意向城市:{regions}
意向行业:{industries}
【你的能力】
1. 回答求职相关问题(面试技巧、简历建议、行业分析等),回复不超过200字
2. 当用户想看岗位推荐时,提取用户的偏好描述,调用岗位推荐工具
3. 当用户想修改求职偏好/设置时,调用偏好设置工具
【输出格式】
严格返回 JSON,不要其他内容:
{"message":"回复内容","tool":null,"toolParams":null}
tool 可选值:
- null:普通对话,不触发工具
- "recommend":岗位推荐,toolParams 必须包含 {"preference":"用户偏好描述"}
- "editPreference":调整偏好,toolParams 为 null
【规则】
1. 只聊求职相关话题,其他话题礼貌拒绝
2. 回复简洁,不超过200字
3. 用户表达想看岗位、推荐岗位、帮我找工作等意图时,从对话中提取偏好描述,返回 recommend
4. 用户表达想改设置、调整偏好、修改意向等意图时,返回 editPreference
5. 偏好描述要准确概括用户的岗位偏好,如"更偏技术方向的产品岗"、"大厂优先"
```
## 6. 处理流程
1. 校验登录态,获取 user_id
2. 根据 resume_id 查简历主表 + 5张子表,序列化为文本
3. 构造 system prompt(简历 + 求职意向 + 规则)
4. 构造 messages 列表:system prompt + history + 当前 message
5. 调用 LLM(使用 LLM.DEEPSEEK_V3 或配置的模型)
6. 用 parse_llm_json 解析 AI 返回的 JSON
7. 构造 JobAgentChatDto 返回
## 7. 前端交互流程
1. 前端发消息 → 调 `POST /job-agent/chat`
2. 拿到返回后判断 tool 字段:
- `tool=null` → 直接展示 message
- `tool="recommend"` → 展示 message + 用 toolParams.preference 调 Java 端 `POST /job/agent/recommend` 拿岗位列表展示
- `tool="editPreference"` → 展示 message + 打开偏好设置页面
## 8. 涉及文件
| 文件 | 位置 | 说明 |
|------|------|------|
| `job_agent_chat.py` | app/schemas/ | Pydantic 请求/响应 Schema |
| `job_agent_chat.py` | app/api/ | 路由定义 |
| `job_agent_chat_service.py` | app/services/ | Service:查简历 + 构造 prompt + 调 LLM |
| `prompts.py` | app/ai/job_agent/ | System Prompt 模板 |
| `main.py` | app/ | 注册新路由 |
## 9. 依赖的现有模块
- `app/models/user_resume.py` + 5张子表 ORM — 查简历数据
- `app/ai/models.py` — LLM 枚举,创建模型实例
- `app/tool/json_helper.py` — parse_llm_json 解析 AI 输出
- `app/core/context.py` — RequestContext 获取 user_id
- `app/core/database.py` — get_db 获取数据库会话
## 10. 不需要新增的 ORM 模型
- 求职意向由前端传入中文名称,不查 bg_user_job_intention 表
- 简历相关 ORM 模型已全部存在
+2 -2
View File
@@ -143,7 +143,7 @@ inclusion: manual
### 模型引用示例 ### 模型引用示例
```python ```python
from app.ai.model_config import SkillGapModel from app.ai.model_config import SkillGapModel, NovaChatModel
# chain 中直接使用配置类属性(已经是 ChatOpenAI 实例) # chain 中直接使用配置类属性(已经是 ChatOpenAI 实例)
_plan_chain = ( _plan_chain = (
@@ -153,7 +153,7 @@ _plan_chain = (
) )
# 非 chain 场景直接 await 调用 # 非 chain 场景直接 await 调用
result = await JobAgentModel.CHAT.ainvoke(messages) result = await NovaChatModel.CHAT.ainvoke(messages)
``` ```
### 新增 AI 场景步骤 ### 新增 AI 场景步骤
+9 -10
View File
@@ -45,9 +45,8 @@ offerpie_python_ai/
│ ├─ skill_gap_analyzer/ # 技能差距分析 + 定制简历 AI 模块 │ ├─ skill_gap_analyzer/ # 技能差距分析 + 定制简历 AI 模块
│ │ ├─ prompts.py # 差距分析 + 简历优化 + Agent 规划(原子化操作)/ 单条记录修改 / 新增记录 Prompt 模板 + MODULE_SCHEMAS │ │ ├─ prompts.py # 差距分析 + 简历优化 + Agent 规划(原子化操作)/ 单条记录修改 / 新增记录 Prompt 模板 + MODULE_SCHEMAS
│ │ └─ analyzer.py # AI 调用逻辑(差距分析 + summary优化 + 经历优化 + Agent规划 + 单条记录修改 + 新增记录) │ │ └─ analyzer.py # AI 调用逻辑(差距分析 + summary优化 + 经历优化 + Agent规划 + 单条记录修改 + 新增记录)
│ ├─ job_agent/ # 求职助手 Agent AI 模块 │ ├─ job_agent/ # 求职助手 Agent AI 模块(岗位简历优化)
│ │ ├─ prompts.py # 对话 System Prompt + 岗位简历优化 Prompt 模板 │ │ ├─ prompts.py # 岗位简历优化 Prompt 模板
│ │ ├─ chat.py # AI 对话引擎(构造 prompt + 拼 messages + 调 LLM + 解析返回)
│ │ └─ resume_optimizer.py # 岗位简历优化 AI 引擎(summary优化 + 经历优化,独立 chain) │ │ └─ resume_optimizer.py # 岗位简历优化 AI 引擎(summary优化 + 经历优化,独立 chain)
│ └─ nova_chat/ # Nova 对话助手 AI 模块 │ └─ nova_chat/ # Nova 对话助手 AI 模块
│ ├─ prompts.py # Nova 对话 System Prompt(岗位匹配评估 + 简历优化建议 + 通用求职对话) │ ├─ prompts.py # Nova 对话 System Prompt(岗位匹配评估 + 简历优化建议 + 通用求职对话)
@@ -59,7 +58,7 @@ offerpie_python_ai/
│ ├─ resume_diagnose.py # 简历诊断接口(POST 触发诊断 / GET 查询报告 / PUT 标记处理+用户评价 / POST 润色优化) │ ├─ resume_diagnose.py # 简历诊断接口(POST 触发诊断 / GET 查询报告 / PUT 标记处理+用户评价 / POST 润色优化)
│ ├─ skill_gap.py # 技能差距分析接口(差距分析 / 生成定制简历 / AI对话编辑) │ ├─ skill_gap.py # 技能差距分析接口(差距分析 / 生成定制简历 / AI对话编辑)
│ ├─ customize_resume.py # 定制简历接口(查询 / 修改 / 回滚) │ ├─ customize_resume.py # 定制简历接口(查询 / 修改 / 回滚)
│ ├─ job_agent_chat.py # 求职助手接口(POST /job-agent/chat 对话、POST /job-agent/optimize-resume 岗位简历优化) │ ├─ job_agent_chat.py # 求职助手接口(POST /job-agent/optimize-resume 岗位简历优化)
│ └─ nova_chat.py # Nova 对话助手接口(POST /nova-chat/chat 纯对话,支持可选岗位上下文) │ └─ nova_chat.py # Nova 对话助手接口(POST /nova-chat/chat 纯对话,支持可选岗位上下文)
├─ models/ # **ORM 模型层**SQLAlchemy 声明式映射) ├─ models/ # **ORM 模型层**SQLAlchemy 声明式映射)
@@ -86,7 +85,7 @@ offerpie_python_ai/
├─ schemas/ # **Schema 层**Pydantic 请求/响应/缓存模型) ├─ schemas/ # **Schema 层**Pydantic 请求/响应/缓存模型)
│ ├─ skill_gap.py # 技能差距分析 SchemaSkillGapParam、CustomizeResumeParam、AiEditParam │ ├─ skill_gap.py # 技能差距分析 SchemaSkillGapParam、CustomizeResumeParam、AiEditParam
│ ├─ customize_resume.py # 定制简历 SchemaCustomizeResume、ResumeProfile、Education、Work、Internship、Project、Competition、Paragraph │ ├─ customize_resume.py # 定制简历 SchemaCustomizeResume、ResumeProfile、Education、Work、Internship、Project、Competition、Paragraph
│ ├─ job_agent_chat.py # 求职助手对话 SchemaJobAgentChatParam、JobAgentChatDto、ToolParams │ ├─ job_agent_chat.py # 求职助手岗位简历优化 SchemaOptimizeResumeParam
│ └─ nova_chat.py # Nova 对话助手 SchemaNovaChatParam、NovaChatDto │ └─ nova_chat.py # Nova 对话助手 SchemaNovaChatParam、NovaChatDto
└─ services/ # **业务逻辑层** └─ services/ # **业务逻辑层**
@@ -96,7 +95,7 @@ offerpie_python_ai/
├─ skill_gap_service.py # 技能差距分析服务(差距分析→定制简历生成→AI对话编辑) ├─ skill_gap_service.py # 技能差距分析服务(差距分析→定制简历生成→AI对话编辑)
├─ resume_loader.py # 简历统一查询模块(按ID查/自动选默认+5张子表,返回 ResumeDetail dataclass ├─ resume_loader.py # 简历统一查询模块(按ID查/自动选默认+5张子表,返回 ResumeDetail dataclass
├─ customize_resume_store.py # 定制简历存取模块(数据库持久化 + Redis回滚备份、按用户+岗位维度存取) ├─ customize_resume_store.py # 定制简历存取模块(数据库持久化 + Redis回滚备份、按用户+岗位维度存取)
├─ job_agent_chat_service.py # 求职助手对话服务(查简历→序列化→调AI模块完成对话 ├─ job_agent_chat_service.py # 求职助手服务(查简历+岗位→并发AI优化简历→存库
└─ nova_chat_service.py # Nova 对话助手服务(查简历+查岗位(可选)→调AI,纯对话不持久化) └─ nova_chat_service.py # Nova 对话助手服务(查简历+查岗位(可选)→调AI,纯对话不持久化)
``` ```
@@ -105,11 +104,11 @@ offerpie_python_ai/
|------|----------|-------------| |------|----------|-------------|
| **config** | 统一配置管理,基于 Pydantic Settings,支持 .env 文件加载 | `Settings`(数据库、Redis、LLM供应商、JWT、CORS、日志等全部配置项) | | **config** | 统一配置管理,基于 Pydantic Settings,支持 .env 文件加载 | `Settings`(数据库、Redis、LLM供应商、JWT、CORS、日志等全部配置项) |
| **core** | 核心基础设施:数据库连接、Redis连接、鉴权、日志、中间件、异常处理、统一响应 | `database.py``redis.py``auth.py``middleware.py``exceptions.py``logger.py``StandardResponse` | | **core** | 核心基础设施:数据库连接、Redis连接、鉴权、日志、中间件、异常处理、统一响应 | `database.py``redis.py``auth.py``middleware.py``exceptions.py``logger.py``StandardResponse` |
| **ai** | AI 模型管理 + 业务 AI 能力 | `LLM` 枚举(models.py)、`model_config.py`(场景模型配置)、`resume_extractor/`(简历并行提取)、`resume_polisher/`(简历段落润色)、`resume_diagnoser/`(简历诊断)、`skill_gap_analyzer/`(技能差距分析 + 定制简历优化 + Agent 原子化规划 + 单条记录修改/新增)、`job_agent/`(求职助手对话 + 岗位简历优化)、`nova_chat/`Nova 对话助手,纯对话) | | **ai** | AI 模型管理 + 业务 AI 能力 | `LLM` 枚举(models.py)、`model_config.py`(场景模型配置)、`resume_extractor/`(简历并行提取)、`resume_polisher/`(简历段落润色)、`resume_diagnoser/`(简历诊断)、`skill_gap_analyzer/`(技能差距分析 + 定制简历优化 + Agent 原子化规划 + 单条记录修改/新增)、`job_agent/`(求职助手岗位简历优化)、`nova_chat/`Nova 对话助手,纯对话) |
| **api** | REST API 路由定义 | `health.py`(健康检查)、`resume.py`(简历上传解析 + 段落润色)、`resume_diagnose.py`(简历诊断)、`skill_gap.py`(技能差距分析 + 生成定制简历 + AI对话编辑)、`customize_resume.py`(定制简历查询/修改/回滚)、`job_agent_chat.py`(求职助手对话 + 岗位简历优化)、`nova_chat.py`Nova 对话助手) | | **api** | REST API 路由定义 | `health.py`(健康检查)、`resume.py`(简历上传解析 + 段落润色)、`resume_diagnose.py`(简历诊断)、`skill_gap.py`(技能差距分析 + 生成定制简历 + AI对话编辑)、`customize_resume.py`(定制简历查询/修改/回滚)、`job_agent_chat.py`(求职助手岗位简历优化)、`nova_chat.py`Nova 对话助手) |
| **models** | SQLAlchemy ORM 模型,与 Java 端共享同一数据库 | `FuncPermission``UserFuncPermissionStock``UserFuncUsageLog``UserResume``UserResumeEducation`/`Work`/`Internship`/`Project`/`Competition``ResumeDiagnosisReport``ResumeDiagnosisIssue``Job`(只读)、`JobAgentConfig``UserJobCustomizeResume` | | **models** | SQLAlchemy ORM 模型,与 Java 端共享同一数据库 | `FuncPermission``UserFuncPermissionStock``UserFuncUsageLog``UserResume``UserResumeEducation`/`Work`/`Internship`/`Project`/`Competition``ResumeDiagnosisReport``ResumeDiagnosisIssue``Job`(只读)、`JobAgentConfig``UserJobCustomizeResume` |
| **tool** | 无状态通用工具,不依赖数据库/Redis/用户上下文 | `file_parser.py`PDF/Word(.docx)/TXT/Markdown 文件解析为文本单元数组)、`json_helper.py`AI 输出 JSON 解析,去 markdown 代码块 + json_repair 容错)、`snowflake.py`(雪花ID生成) | | **tool** | 无状态通用工具,不依赖数据库/Redis/用户上下文 | `file_parser.py`PDF/Word(.docx)/TXT/Markdown 文件解析为文本单元数组)、`json_helper.py`AI 输出 JSON 解析,去 markdown 代码块 + json_repair 容错)、`snowflake.py`(雪花ID生成) |
| **services** | 业务逻辑实现 | `FuncPermissionService`(功能权限校验、扣减、回退)、`ResumeService`(简历文件解析→AI结构化→入库 + 段落润色)、`ResumeDiagnoseService`(简历诊断→AI并行分析→评级→入库)、`SkillGapService`(技能差距分析→定制简历生成→AI对话编辑)、`resume_loader`(简历统一查询,返回ResumeDetail)、`customize_resume_store`(定制简历数据库存取+数据构建,按用户+岗位维度,Redis回滚备份)、`JobAgentChatService`(求职助手对话+岗位简历优化)、`NovaChatService`(Nova对话助手,查简历+查岗位→调AI) | | **services** | 业务逻辑实现 | `FuncPermissionService`(功能权限校验、扣减、回退)、`ResumeService`(简历文件解析→AI结构化→入库 + 段落润色)、`ResumeDiagnoseService`(简历诊断→AI并行分析→评级→入库)、`SkillGapService`(技能差距分析→定制简历生成→AI对话编辑)、`resume_loader`(简历统一查询,返回ResumeDetail)、`customize_resume_store`(定制简历数据库存取+数据构建,按用户+岗位维度,Redis回滚备份)、`JobAgentChatService`(求职助手岗位简历优化)、`NovaChatService`(Nova对话助手,查简历+查岗位→调AI) |
## 3️⃣ 技术栈 ## 3️⃣ 技术栈
| 类别 | 技术选型 | 说明 | | 类别 | 技术选型 | 说明 |
@@ -179,7 +178,7 @@ offerpie_python_ai/
| 配置类 | 场景 | 说明 | | 配置类 | 场景 | 说明 |
|--------|------|------| |--------|------|------|
| `SkillGapModel` | ANALYSIS / SUMMARY / EXPERIENCE / AGENT_PLAN / AGENT_EDIT / AGENT_ADD | 技能差距分析模块 | | `SkillGapModel` | ANALYSIS / SUMMARY / EXPERIENCE / AGENT_PLAN / AGENT_EDIT / AGENT_ADD | 技能差距分析模块 |
| `JobAgentModel` | CHAT / SUMMARY / EXPERIENCE | 求职助手Agent模块 | | `JobAgentModel` | SUMMARY / EXPERIENCE | 求职助手Agent模块 |
| `NovaChatModel` | CHAT | Nova智能聊天模块 | | `NovaChatModel` | CHAT | Nova智能聊天模块 |
| `ResumeExtractorModel` | PARSE | 简历解析模块 | | `ResumeExtractorModel` | PARSE | 简历解析模块 |
| `DiagnoserModel` | MODULE / SUMMARY / POLISH | 简历诊断模块 | | `DiagnoserModel` | MODULE / SUMMARY / POLISH | 简历诊断模块 |
-51
View File
@@ -1,51 +0,0 @@
"""求职助手 Agent 对话 AI 引擎
构造 prompt + 调 LLM + 解析返回。
依赖:LLM 枚举、job_agent/prompts、parse_llm_json
"""
from app.ai.job_agent.prompts import SYSTEM_PROMPT
from app.ai.model_config import JobAgentModel
from app.core.logger import log
from app.tool.json_helper import parse_llm_json
async def agent_chat(resume_text: str, message: str, history: list[dict],
job_categories: list[str], regions: list[str],
industries: list[str]) -> dict:
"""求职助手对话
1. 构造 system prompt 2. 拼 messages 3. 调 LLM 4. 解析返回
"""
# 1. 构造 system prompt
system_content = SYSTEM_PROMPT.format(
resume_text=resume_text,
job_categories="".join(job_categories) if job_categories else "未设置",
regions="".join(regions) if regions else "未设置",
industries="".join(industries) if industries else "未设置",
)
# 2. 拼 messages
messages = [("system", system_content)]
for msg in history:
messages.append((msg["role"], msg["content"]))
messages.append(("human", message))
# 3. 调 LLM
try:
result = await JobAgentModel.CHAT.ainvoke(messages)
raw = result.content
except Exception as e:
log.error(f"求职助手AI调用失败: {e}")
return {"message": "抱歉,我暂时无法回复,请稍后再试。", "tool": None, "toolParams": None}
# 4. 解析返回
try:
parsed = parse_llm_json(raw)
return {
"message": parsed.get("message", ""),
"tool": parsed.get("tool"),
"toolParams": parsed.get("toolParams"),
}
except Exception as e:
log.warning(f"求职助手AI返回解析失败, raw={raw}, error={e}")
return {"message": raw.strip() if raw else "抱歉,我暂时无法回复。", "tool": None, "toolParams": None}
+1 -38
View File
@@ -1,41 +1,4 @@
"""求职助手 Agent 对话 Prompt 模板 + 岗位简历优化 Prompt""" """求职助手 Agent 岗位简历优化 Prompt"""
SYSTEM_PROMPT = """你是 OfferPie 求职助手,帮助用户找到合适的工作。
【用户简历】
{resume_text}
【求职意向】
意向岗位:{job_categories}
意向城市:{regions}
意向行业:{industries}
【你的能力】
1. 回答求职相关问题(面试技巧、简历建议、行业分析等),回复不超过200字
2. 当用户想看岗位推荐时,提取用户的偏好描述,调用岗位推荐工具
3. 当用户想修改求职偏好/设置时,调用偏好设置工具
【输出格式】
严格返回 JSON,不要其他内容:
{{"message":"回复内容","tool":null,"toolParams":null}}
tool 可选值:
- null:普通对话,不触发工具
- "recommend":岗位推荐,toolParams 必须包含 {{"preference":"用户偏好描述"}}
- "editPreference":调整偏好,toolParams 为 null
【规则】
1. 只聊求职相关话题,其他话题礼貌拒绝
2. 回复简洁,不超过200字
3. 用户表达想看岗位、推荐岗位、帮我找工作等意图时,从对话中提取偏好描述,返回 recommend
4. 用户表达想改设置、调整偏好、修改意向等意图时,返回 editPreference
5. 偏好描述要准确概括用户的岗位偏好,如"更偏技术方向的产品岗""大厂优先"
6. 如果用户没有明确偏好,preference 填"无特殊偏好"
7. 触发工具时(tool 非 null),前端会在消息展示后再打开对应面板/列表,message 只做一句简短的"即将..."提示,不要追问"想怎么调整""有什么偏好"等引导用户在对话里继续输入的话
- 注意工具调用是置后的:message 先展示给用户,面板/列表随后打开,所以用将来时态,不要用"已为你..."这种完成时
- recommend 示例:"好的,正在为你匹配合适的岗位"
- editPreference 示例:"好的,为你打开偏好设置"
"""
# ===== 岗位简历优化 Prompt ===== # ===== 岗位简历优化 Prompt =====
-2
View File
@@ -24,8 +24,6 @@ class SkillGapModel:
class JobAgentModel: class JobAgentModel:
"""求职助手Agent模块""" """求职助手Agent模块"""
# 多轮对话:理解用户求职意图,返回结构化回复(message+tool调用)
CHAT = LLM.DOUBAO_PRO_32K.create(temperature=0.7)
# 岗位简历-summary优化:针对具体岗位JD优化个人概述 # 岗位简历-summary优化:针对具体岗位JD优化个人概述
SUMMARY = LLM.DEEPSEEK_V4_FLASH.create(temperature=0.3) SUMMARY = LLM.DEEPSEEK_V4_FLASH.create(temperature=0.3)
# 岗位简历-经历优化:针对具体岗位JD优化单条经历描述 # 岗位简历-经历优化:针对具体岗位JD优化单条经历描述
+2 -16
View File
@@ -1,30 +1,16 @@
"""求职助手 Agent 对话接口""" """求职助手 Agent 岗位简历优化接口"""
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends
from app.core.auth import func_permission from app.core.auth import func_permission
from app.core.context import RequestContext from app.core.context import RequestContext
from app.core.database import get_db from app.core.database import get_db
from app.schemas.job_agent_chat import JobAgentChatParam, OptimizeResumeParam from app.schemas.job_agent_chat import OptimizeResumeParam
from app.services.job_agent_chat_service import JobAgentChatService from app.services.job_agent_chat_service import JobAgentChatService
router = APIRouter(prefix="/job-agent", tags=["求职助手agent"]) router = APIRouter(prefix="/job-agent", tags=["求职助手agent"])
@router.post("/chat", summary="求职助手对话")
async def chat(param: JobAgentChatParam):
"""求职助手对话,根据用户简历和意向提供求职建议、触发岗位推荐或偏好调整"""
user_id = RequestContext.user_id.get()
async for session in get_db():
service = JobAgentChatService(session)
result = await service.chat(
user_id, param.resume_id, param.message,
[msg.model_dump() for msg in param.history],
param.job_categories, param.regions, param.industries,
)
return result
@router.post("/optimize-resume", summary="针对岗位优化简历") @router.post("/optimize-resume", summary="针对岗位优化简历")
async def optimize_resume(param: OptimizeResumeParam, _: None = Depends(func_permission("resume_custom"))): async def optimize_resume(param: OptimizeResumeParam, _: None = Depends(func_permission("resume_custom"))):
"""根据目标岗位,AI并发优化简历(summary + 5张子表经历),存Redis并返回""" """根据目标岗位,AI并发优化简历(summary + 5张子表经历),存Redis并返回"""
+2 -32
View File
@@ -1,41 +1,11 @@
"""求职助手 Agent 对话 Schema """求职助手 Agent 岗位简历优化 Schema
请求参数 Param、响应 Dto 请求参数 Param。
字段命名使用 camelCase alias,与前端 JSON 对齐。 字段命名使用 camelCase alias,与前端 JSON 对齐。
""" """
from typing import Literal
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
ChatRole = Literal["user", "assistant"]
class ChatMessage(BaseModel):
role: ChatRole
content: str
class JobAgentChatParam(BaseModel):
message: str = Field(..., description="用户输入的消息")
resume_id: int = Field(..., alias="resumeId", description="简历ID")
history: list[ChatMessage] = Field(default_factory=list, description="对话历史")
job_categories: list[str] = Field(default_factory=list, alias="jobCategories", description="意向岗位类型名称")
regions: list[str] = Field(default_factory=list, alias="regions", description="意向城市名称")
industries: list[str] = Field(default_factory=list, alias="industries", description="意向行业名称")
class ToolParams(BaseModel):
preference: str = Field(default="", description="用户岗位偏好描述")
class JobAgentChatDto(BaseModel):
message: str = Field(..., description="AI回复文本,不超过200字")
tool: str | None = Field(default=None, description="前端需执行的工具:recommend / editPreference / null")
tool_params: ToolParams | None = Field(default=None, alias="toolParams", description="工具参数")
model_config = {"populate_by_name": True}
class OptimizeResumeParam(BaseModel): class OptimizeResumeParam(BaseModel):
resume_id: int = Field(..., alias="resumeId", description="简历ID") resume_id: int = Field(..., alias="resumeId", description="简历ID")
+4 -50
View File
@@ -1,7 +1,7 @@
"""求职助手 Agent 对话 + 岗位简历优化 Service """求职助手 Agent 岗位简历优化 Service
主要功能:查询简历数据,调用 AI 模块完成对话;针对岗位并发优化简历。 主要功能:针对岗位并发优化简历。
依赖:resume_loader(简历统一查询)、customize_resume_store(定制简历存取+构建)、job_agent.chat AI 模块、job_agent.resume_optimizer(岗位简历优化) 依赖:resume_loader(简历统一查询)、customize_resume_store(定制简历存取+构建)、job_agent.resume_optimizer(岗位简历优化)
使用表:bg_user_resume + 5张子表(通过 resume_loader 查询)、bg_job(查岗位) 使用表:bg_user_resume + 5张子表(通过 resume_loader 查询)、bg_job(查岗位)
""" """
@@ -12,12 +12,11 @@ import time
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.ai.job_agent.chat import agent_chat
from app.ai.job_agent.resume_optimizer import optimize_summary, optimize_experience_record from app.ai.job_agent.resume_optimizer import optimize_summary, optimize_experience_record
from app.core.logger import log from app.core.logger import log
from app.models.job import Job from app.models.job import Job
from app.schemas.customize_resume import CustomizeResume, Education, Work, Internship, Project, Competition from app.schemas.customize_resume import CustomizeResume, Education, Work, Internship, Project, Competition
from app.services.resume_loader import ResumeDetail, load_resume_detail from app.services.resume_loader import load_resume_detail
from app.services import customize_resume_store from app.services import customize_resume_store
@@ -26,51 +25,6 @@ class JobAgentChatService:
def __init__(self, session: AsyncSession): def __init__(self, session: AsyncSession):
self.session = session self.session = session
async def chat(self, user_id: int, resume_id: int, message: str,
history: list[dict], job_categories: list[str],
regions: list[str], industries: list[str]) -> dict:
"""求职助手对话:查简历 → 序列化 → 调 AI 模块"""
detail = await load_resume_detail(self.session, resume_id, user_id)
resume_text = self._build_resume_text(detail)
return await agent_chat(resume_text, message, history, job_categories, regions, industries)
@staticmethod
def _build_resume_text(detail: ResumeDetail) -> str:
"""将简历数据序列化为文本供 AI 使用"""
resume = detail.resume
parts = []
if resume.name:
parts.append(f"姓名:{resume.name}")
if resume.target_position:
parts.append(f"目标岗位:{resume.target_position}")
if resume.skills:
parts.append(f"技能:{''.join(resume.skills)}")
if resume.certificates:
parts.append(f"证书:{''.join(resume.certificates)}")
if resume.summary:
parts.append(f"个人概述:{resume.summary}")
if detail.education:
parts.append("教育经历:")
for r in detail.education:
parts.append(f" - {r.school or ''} {r.major or ''} {r.degree or ''}")
if detail.work:
parts.append("工作经历:")
for r in detail.work:
parts.append(f" - {r.company_name or ''} {r.position or ''}")
if detail.internship:
parts.append("实习经历:")
for r in detail.internship:
parts.append(f" - {r.company_name or ''} {r.position or ''}")
if detail.project:
parts.append("项目经历:")
for r in detail.project:
parts.append(f" - {r.project_name or ''} {r.role or ''}")
if detail.competition:
parts.append("竞赛经历:")
for r in detail.competition:
parts.append(f" - {r.competition_name or ''} {r.award or ''}")
return "\n".join(parts) if parts else "暂无简历信息"
async def optimize_resume(self, user_id: int, resume_id: int, job_id: int) -> dict: async def optimize_resume(self, user_id: int, resume_id: int, job_id: int) -> dict:
"""针对岗位优化简历:查简历+岗位 → 构建定制简历 → 按单条记录并发AI优化 → 存数据库 → 返回""" """针对岗位优化简历:查简历+岗位 → 构建定制简历 → 按单条记录并发AI优化 → 存数据库 → 返回"""
# 1. 查简历 + 岗位 # 1. 查简历 + 岗位