generated from kgod/ai-review-template
716 lines
22 KiB
Markdown
716 lines
22 KiB
Markdown
# 零资料新用户 AI 简历创建 Agent PRD
|
||
|
||
## 1. 文档信息
|
||
|
||
| 项目 | 内容 |
|
||
| --- | --- |
|
||
| 产品名称 | AI 创建第一份简历 |
|
||
| 文档版本 | MVP v1.0 |
|
||
| 适用用户 | 没有现成个人资料或简历的新用户 |
|
||
| 前端 | Vue |
|
||
| 后端 | Python + FastAPI |
|
||
| 核心编排 | Python 显式有限状态机(FSM) |
|
||
| 模型接入 | OpenAI Python SDK 兼容网关 |
|
||
| 当前实现目录 | \`resume-agent-mvp/\` |
|
||
|
||
本文档描述产品目标、交互规则、内容门禁、模型边界、技术方案和验收标准。它以“零资料新用户”为前提,不从已有个人资料或历史简历开始。
|
||
|
||
## 2. 产品定义
|
||
|
||
用户进入“AI 创建第一份简历”后,在一个连续的对话时间线中完成:隐私授权、简历手机号、姓名、求职阶段、第一段必要经历采集和确认。结构化信息使用对话消息中的可操作组件,自由描述使用聊天输入框。
|
||
|
||
产品的核心不是让模型自由规划流程,而是让模型处理事实,让确定性的状态机持续约束流程和内容门禁。
|
||
|
||
### 2.1 MVP 目标
|
||
|
||
1. 新用户可以从 0 资料开始创建一份业务简历。
|
||
2. 结构化步骤不依赖用户自由输入,全部以对话组件呈现。
|
||
3. Agent 能从自然语言中抽取经历事实,并只追问当前最高优先级缺口。
|
||
4. 模型不能自行决定阶段、组件、门禁或数据库写入。
|
||
5. 业务简历创建不被可选字段阻塞;创建后继续丰富。
|
||
6. AI 改写必须经过用户确认后才写入正式简历内容。
|
||
|
||
### 2.2 非目标
|
||
|
||
- V1 不加载或合并用户已有个人资料、旧简历或历史会话。
|
||
- V1 不做简历投递、职位匹配、JD 定制和人工审核。
|
||
- V1 不引入 RAG、向量数据库、多 Agent 或长期语义记忆。
|
||
- V1 不让模型直接操作业务数据库。
|
||
|
||
## 3. 已有业务字段
|
||
|
||
业务库已有字段如下。姓名、手机号为必填;其余字段按门禁规则分为首段必要字段和创建后的可选字段。
|
||
|
||
### 3.1 个人信息
|
||
|
||
- 姓名
|
||
- 手机号
|
||
- 微信
|
||
- 邮箱
|
||
- 所在城市
|
||
- 个人作品集链接
|
||
|
||
### 3.2 经历和标签
|
||
|
||
- 教育经历(多段):学校名、专业、学历、是否全日制、就读开始时间、就读结束时间、学习经历描述
|
||
- 工作经历(多段):公司名、职位、工作开始时间、工作结束时间、工作经历描述
|
||
- 实习经历(多段):公司名、职位、实习开始时间、实习结束时间、实习经历描述
|
||
- 项目经历(多段):项目名、项目角色、项目开始时间、项目结束时间、项目经历描述
|
||
- 竞赛(多段):竞赛名、获奖名称、获奖时间、竞赛经历描述
|
||
- 证书(多标签):正式名
|
||
- 技能(多标签):技能名
|
||
|
||
## 4. 用户流程
|
||
|
||
### 4.1 首次创建路径
|
||
|
||
~~~text
|
||
进入“AI 创建第一份简历”
|
||
→ 隐私授权组件
|
||
→ 手机号来源组件
|
||
→ (选择其他号码时)手动手机号组件
|
||
→ 姓名输入组件
|
||
→ 求职类型组件
|
||
→ (其他类型时)首段经历类型组件
|
||
→ 开放式首段经历问题
|
||
→ LLM 抽取 + 缺口追问
|
||
→ 首段经历确认组件
|
||
→ 最低门禁达成
|
||
→ 用户点击创建简历
|
||
→ 创建后丰富
|
||
~~~
|
||
|
||
### 4.2 对话时间线原则
|
||
|
||
所有消息都保留在同一条时间线中,不跳转独立表单页面。已提交组件变为只读,用户可以回顾之前的选择。
|
||
|
||
示例:
|
||
|
||
~~~text
|
||
Agent 隐私授权卡
|
||
→ 用户点击同意
|
||
→ Agent 手机号选择卡
|
||
→ 用户选择使用其他号码
|
||
→ Agent 手机号输入卡
|
||
→ 用户提交号码
|
||
→ Agent 姓名输入卡
|
||
→ 用户提交姓名
|
||
→ Agent 求职类型卡
|
||
→ 用户选择校招
|
||
→ Agent 开放式经历问题
|
||
→ 用户自然语言描述
|
||
→ Agent 日期补充卡
|
||
→ 用户选择日期
|
||
→ Agent 经历确认卡
|
||
→ 用户确认
|
||
→ Agent 创建简历卡
|
||
~~~
|
||
|
||
### 4.3 语气定义
|
||
|
||
Agent 使用“温和、明确、正式但不僵硬”的中文语气:
|
||
|
||
- 先确认已理解的事实,再说明还缺什么。
|
||
- 每轮只追问一个最高优先级缺口。
|
||
- 不责备用户信息不完整,不使用压迫表达。
|
||
- 对未知事实明确说“暂时不知道”,不替用户猜测。
|
||
- 正式化时使用职业化表达,但保留用户原始事实和数字。
|
||
- 结构化组件前用一句短说明解释用途,避免连续输出长段落。
|
||
|
||
推荐表达:
|
||
|
||
> 我已经记录了公司和职位。为了确认这段经历,还需要补充开始和结束时间。
|
||
|
||
不推荐表达:
|
||
|
||
> 你的信息不完整,请重新输入全部内容。
|
||
|
||
## 5. 结构化对话协议
|
||
|
||
### 5.1 Agent 消息模式
|
||
|
||
| 模式 | 自由输入框 | 适用场景 |
|
||
| --- | --- | --- |
|
||
| \`ui_only\` | 关闭 | 隐私、手机号、姓名、求职类型、确认、创建 |
|
||
| \`chat\` | 开启 | 开放式经历描述、事实补充 |
|
||
| \`hybrid\` | 按组件配置 | 日期补充、创建后丰富、确认后的继续对话 |
|
||
|
||
### 5.2 ConversationTurn
|
||
|
||
~~~text
|
||
ConversationTurn
|
||
- message_id
|
||
- sender: assistant | user | system
|
||
- stage
|
||
- input_mode: ui_only | chat | hybrid
|
||
- blocks[]
|
||
- composer
|
||
- created_at
|
||
~~~
|
||
|
||
\`blocks\` 支持:
|
||
|
||
~~~text
|
||
TextBlock
|
||
ComponentBlock
|
||
ResumePatchBlock
|
||
StatusBlock
|
||
ErrorBlock
|
||
~~~
|
||
|
||
组件块:
|
||
|
||
~~~text
|
||
ComponentBlock
|
||
- component_id
|
||
- component_name
|
||
- component_version
|
||
- props
|
||
- status: active | submitted | expired | replaced | confirmed
|
||
- allowed_actions
|
||
- validation_schema
|
||
~~~
|
||
|
||
输入框:
|
||
|
||
~~~text
|
||
composer:
|
||
enabled
|
||
placeholder
|
||
accepted_input: text | none
|
||
max_length
|
||
~~~
|
||
|
||
### 5.3 组件生命周期
|
||
|
||
1. Python 状态机返回当前阶段。
|
||
2. 渲染层根据阶段输出唯一主要活动组件。
|
||
3. 用户提交组件事件。
|
||
4. 服务端校验组件 ID、事件、会话版本和 payload。
|
||
5. 原组件变为 \`submitted\` 或 \`confirmed\`,不可重复生效。
|
||
6. 时间线追加结构化用户回复摘要和下一条 Agent 消息。
|
||
7. 修改关键字段时,依赖它的确认状态失效并重新计算门禁。
|
||
|
||
同一时间只能有一个主要 \`active\` 组件。点击过期组件返回 \`COMPONENT_EXPIRED\`,并引导用户回到当前有效组件。
|
||
|
||
## 6. 阶段与组件映射
|
||
|
||
阶段由 Python FSM 生成,LLM 不得输出阶段或组件名称。
|
||
|
||
| Stage | 主要组件 | 输入模式 |
|
||
| --- | --- | --- |
|
||
| \`PRIVACY_CONSENT\` | \`PrivacyConsentCard\` | \`ui_only\` |
|
||
| \`PHONE_SELECTION\` | \`ResumePhoneSelector\` | \`ui_only\` |
|
||
| \`MANUAL_PHONE_INPUT\` | \`ResumePhoneInput\` | \`ui_only\` |
|
||
| \`NAME_CAPTURE\` | \`ResumeNameInput\` | \`ui_only\` |
|
||
| \`JOB_TYPE_SELECT\` | \`JobTypeCards\` | \`ui_only\` |
|
||
| \`ANCHOR_TYPE_SELECT\` | \`AnchorTypeCards\` | \`ui_only\` |
|
||
| \`ANCHOR_COLLECTING\` | 文本问题、短文本、学历、日期组件 | \`chat\` / \`hybrid\` |
|
||
| \`CONTENT_DISAMBIGUATION\` | \`ChoiceChips\` 或补充提示 | \`ui_only\` / \`chat\` |
|
||
| \`ANCHOR_CONFIRM\` | \`ExperienceConfirmCard\` | \`ui_only\` |
|
||
| \`MINIMUM_READY\` | \`CreateResumeCard\` | \`ui_only\` |
|
||
| \`RESUME_CREATING\` | \`CreatingStatusCard\` | \`ui_only\` |
|
||
| \`RESUME_ENRICHING\` | 文本、进度卡、字段组件 | \`chat\` / \`hybrid\` |
|
||
| \`CONTENT_READY\` | \`ExperienceConfirmCard\`、\`ContentReadyCard\` | \`ui_only\` / \`hybrid\` |
|
||
| \`CREATE_FAILED\` | \`CreateRetryCard\` | \`ui_only\` |
|
||
|
||
### 6.1 隐私卡
|
||
|
||
隐私文案由产品预设,不由模型生成,至少包含:
|
||
|
||
- 数据处理目的。
|
||
- 将收集的信息类型。
|
||
- AI 如何处理用户输入。
|
||
- 不会自动公开、投递或发送给第三方。
|
||
- 用户可以退出并删除草稿。
|
||
- 完整隐私政策链接和版本号。
|
||
- “同意并继续”和“暂不使用”按钮。
|
||
|
||
### 6.2 手机号
|
||
|
||
登录手机号存在时,展示脱敏号码和两个选项:
|
||
|
||
- 使用此号码。
|
||
- 使用其他号码。
|
||
|
||
手动号码使用前端和后端双重格式校验:
|
||
|
||
~~~text
|
||
^1[3-9]\d{9}$
|
||
~~~
|
||
|
||
不发送验证码,不验证号码归属,只提示“仅完成格式校验”。完整手机号不得进入 LLM prompt、模型上下文或 trace。
|
||
|
||
### 6.3 姓名和求职类型
|
||
|
||
姓名使用短文本组件,过滤纯空格和明显非法内容。求职类型提供:
|
||
|
||
- 校招
|
||
- 社招
|
||
- 其他
|
||
|
||
求职类型用于选择首段经历路径和创建后丰富优先级,不写入已有简历字段。
|
||
|
||
## 7. 内容门禁
|
||
|
||
### 7.1 两级门禁
|
||
|
||
| 门禁 | 作用 | 条件 |
|
||
| --- | --- | --- |
|
||
| 业务创建门禁 | 允许创建业务简历实体 | 核心资料、求职类型、首段必要经历已确认 |
|
||
| 正式内容门禁 | 判断已有正式可用内容 | 业务简历已创建,至少一段 AI 改写已被用户确认,无冲突 |
|
||
|
||
正式内容门禁不能反向删除或隐藏已经创建的业务简历。
|
||
|
||
### 7.2 首段必要经历映射
|
||
|
||
| 求职类型 | 默认锚点 | 创建所需字段 |
|
||
| --- | --- | --- |
|
||
| 校招 | 教育经历 | 学校、专业、学历、开始时间、结束时间或至今 |
|
||
| 社招 | 工作经历 | 公司、职位、开始时间、结束时间或至今 |
|
||
| 其他 | 用户选择教育、工作、实习或项目 | 对应记录的核心字段 |
|
||
|
||
实习核心字段为公司、职位、开始时间、结束时间或至今;项目核心字段为项目名、角色、开始时间、结束时间或至今。
|
||
|
||
以下信息不阻塞业务简历创建:
|
||
|
||
- 经历描述和成果。
|
||
- 是否全日制。
|
||
- 第二段经历。
|
||
- 微信、邮箱、城市、作品集。
|
||
- 技能、证书和竞赛。
|
||
|
||
社招用户没有正式工作经历时,提供:使用实习、使用项目、修改求职类型、保存草稿并退出。
|
||
|
||
### 7.3 门禁公式
|
||
|
||
~~~text
|
||
can_create_resume =
|
||
privacy_accepted
|
||
AND resume_phone_format_valid
|
||
AND name_confirmed
|
||
AND job_type_confirmed
|
||
AND anchor_type_allowed
|
||
AND anchor_required_fields_complete
|
||
AND anchor_dates_valid
|
||
AND anchor_confirmed
|
||
AND unresolved_conflicts == 0
|
||
~~~
|
||
|
||
达到门禁后才展示 \`CreateResumeCard\`。用户点击主按钮后,服务端才写入业务简历。
|
||
|
||
### 7.4 AI 改写确认门禁
|
||
|
||
创建后的经历先生成提议内容:
|
||
|
||
~~~text
|
||
用户事实
|
||
→ LLM 抽取
|
||
→ LLM 正式化
|
||
→ ExperienceConfirmCard 展示提议
|
||
→ 用户确认
|
||
→ 更新正式简历 revision
|
||
~~~
|
||
|
||
用户选择“需要调整”时,提议内容不得写入正式简历,回到 \`RESUME_ENRICHING\` 继续对话。
|
||
|
||
## 8. 首段经历采集 Loop
|
||
|
||
### 8.1 开放式首问
|
||
|
||
校招:
|
||
|
||
> 请介绍当前或最高的一段教育经历,包括学校、专业、学历和就读时间。你可以像平时聊天一样描述。
|
||
|
||
社招:
|
||
|
||
> 请介绍一段最近或最有代表性的工作,包括公司、职位和大致任职时间。
|
||
|
||
实习:
|
||
|
||
> 请介绍一段实习经历,包括公司、职位和实习时间。
|
||
|
||
项目:
|
||
|
||
> 请介绍一个代表性项目,包括项目名、你的角色和项目时间。
|
||
|
||
### 8.2 处理链路
|
||
|
||
~~~text
|
||
自然语言输入
|
||
→ LLM 抽取候选字段
|
||
→ Pydantic Schema 校验
|
||
→ 确定性格式与时间校验
|
||
→ 更新临时经历
|
||
→ 计算缺失字段
|
||
→ 输出一个最高优先级问题或组件
|
||
→ 字段齐全后输出确认卡
|
||
→ 用户确认
|
||
→ MINIMUM_READY
|
||
~~~
|
||
|
||
LLM 输出可以包含 \`field_updates\`、\`evidence_spans\`、\`ambiguities\` 和 \`extra_records\`,但不能输出当前 Stage、Vue 组件、门禁结果或写库指令。
|
||
|
||
### 8.3 缺口优先级
|
||
|
||
工作和实习:
|
||
|
||
1. 公司与职位。
|
||
2. 开始和结束时间。
|
||
3. 工作/实习归属歧义。
|
||
4. 经历确认。
|
||
5. 创建后追问职责、行动、方法和成果。
|
||
|
||
教育:
|
||
|
||
1. 学校。
|
||
2. 专业与学历。
|
||
3. 开始和结束时间。
|
||
4. 经历确认。
|
||
5. 创建后追问全日制和学习亮点。
|
||
|
||
项目:
|
||
|
||
1. 项目名与角色。
|
||
2. 开始和结束时间。
|
||
3. 经历确认。
|
||
4. 创建后追问行动、方法和成果。
|
||
|
||
一轮只处理一个最高优先级缺口,但同一条消息可以抽取多个字段。
|
||
|
||
### 8.4 缺口组件策略
|
||
|
||
| 缺失内容 | 组件或交互 |
|
||
| --- | --- |
|
||
| 公司、职位、学校、专业、项目名 | 短文本组件或针对性追问 |
|
||
| 学历 | \`DegreeSelector\` |
|
||
| 开始和结束时间 | \`DateRangeSelector\` |
|
||
| 工作、实习、项目归属 | \`ChoiceChips\` |
|
||
| 职责、行动、方法、成果 | 自然语言问题 |
|
||
| 整段经历确认 | \`ExperienceConfirmCard\` |
|
||
|
||
结构化事实优先使用组件;需要回忆、组织和解释的内容优先使用自然语言。
|
||
|
||
## 9. 复杂交互规则
|
||
|
||
### 9.1 一次提供多段经历
|
||
|
||
- 拆分成多个临时记录。
|
||
- 选择符合求职类型的一段完成业务创建门禁。
|
||
- 其他记录保留到创建后的丰富阶段。
|
||
- 未确认的其他记录不得阻止业务简历创建。
|
||
|
||
### 9.2 内容归属不明确
|
||
|
||
显示:
|
||
|
||
> 这段内容更接近哪种经历?
|
||
|
||
选项:工作、实习、项目。选择前不得写入具体业务模块。
|
||
|
||
### 9.3 时间处理
|
||
|
||
- “至今”是合法结束状态。
|
||
- 结束时间早于开始时间必须要求修正。
|
||
- 模型不能自行推断“至今”。
|
||
- 未知月份不能自动填成一月。
|
||
- 年月统一使用 \`YYYY-MM\`。
|
||
|
||
### 9.4 修改和幂等
|
||
|
||
- 修改姓名会同步更新简历名称。
|
||
- 修改首段关键字段会使确认状态失效。
|
||
- 修改求职类型会重新计算必要锚点,但保留已采集事实。
|
||
- 已提交组件重复提交不能产生第二次状态变更。
|
||
- 创建简历按 session 幂等,重试不能产生重复业务简历。
|
||
|
||
### 9.5 解析失败
|
||
|
||
1. Structured Output 校验失败自动重试一次。
|
||
2. 再失败时不推进阶段。
|
||
3. 保留原始用户消息,输出针对性的组件或追问。
|
||
4. 网关不可用时按配置选择规则降级或安全报错。
|
||
|
||
## 10. 创建后丰富
|
||
|
||
### 10.1 创建成功消息
|
||
|
||
包含:
|
||
|
||
- 创建成功状态。
|
||
- 简历 ID 或名称。
|
||
- 当前完成度。
|
||
- “继续完善”和“稍后再说”。
|
||
- 下一条高价值问题。
|
||
|
||
“稍后再说”是正常结束,不计为技术失败。
|
||
|
||
### 10.2 丰富优先级
|
||
|
||
社招:首段工作职责 → 行动/方法/成果 → 更多工作经历 → 项目 → 教育/技能/证书 → 可选联系方式。
|
||
|
||
校招:实习或项目 → 竞赛 → 教育亮点 → 技能和证书 → 可选联系方式。
|
||
|
||
其他:当前锚点描述和成果 → 下一段核心经历 → 技能、证书和可选信息。
|
||
|
||
## 11. Agent 与 LLM 边界
|
||
|
||
### 11.1 Python FSM 负责
|
||
|
||
- 当前阶段和合法转移。
|
||
- 活动组件和输入模式。
|
||
- 门禁计算。
|
||
- 字段格式和时间校验。
|
||
- 组件生命周期和幂等。
|
||
- 草稿、业务简历写入。
|
||
- 错误码和恢复策略。
|
||
|
||
### 11.2 LLM 负责
|
||
|
||
- 从用户自然语言抽取明确事实。
|
||
- 标注证据片段和歧义。
|
||
- 将已确认事实改写为正式简历表达。
|
||
|
||
### 11.3 LLM 禁止负责
|
||
|
||
- 决定 Stage。
|
||
- 决定使用哪个 Vue 组件。
|
||
- 宣布门禁通过。
|
||
- 自行补全缺失事实。
|
||
- 覆盖用户已确认字段。
|
||
- 直接写数据库。
|
||
- 处理完整手机号、登录标识或会话元数据。
|
||
|
||
## 12. 技术架构
|
||
|
||
### 12.1 V1 选型
|
||
|
||
- Vue 对话组件系统。
|
||
- Python FastAPI。
|
||
- Python 显式 FSM。
|
||
- Pydantic 状态、事件和模型输出 Schema。
|
||
- SQLite 会话、时间线和 MVP 业务简历存储。
|
||
- OpenAI Python SDK 兼容网关。
|
||
- 前端开发代理和 JSON API。
|
||
|
||
V1 暂不使用 LangChain、LangGraph、AgentExecutor、多 Agent、RAG 或向量数据库。当前流程是明确枚举的单主线状态机,显式实现更容易测试非法事件、回退、幂等和门禁。
|
||
|
||
当出现上传简历解析、旧简历合并、JD 定制、并行模型节点或人工审核时,再评估迁移 LangGraph。
|
||
|
||
### 12.2 服务接口
|
||
|
||
~~~python
|
||
transition(
|
||
state: ResumeDraftState,
|
||
event: ResumeEvent,
|
||
) -> TransitionResult
|
||
~~~
|
||
|
||
模型接口:
|
||
|
||
~~~text
|
||
ExperienceExtractor
|
||
ResumeRewriter
|
||
~~~
|
||
|
||
渲染层根据 \`TransitionResult\` 生成 \`ConversationTurn\`。
|
||
|
||
### 12.3 OpenAI SDK 配置
|
||
|
||
~~~dotenv
|
||
RESUME_AGENT_LLM_PROVIDER=openai
|
||
OPENAI_API_KEY=<server-side-secret>
|
||
OPENAI_BASE_URL=https://re.94xy.cn
|
||
OPENAI_MODEL=gpt-5.5
|
||
OPENAI_STRUCTURED_OUTPUT_MODE=json_schema
|
||
OPENAI_TIMEOUT_SECONDS=30
|
||
OPENAI_MAX_RETRIES=2
|
||
OPENAI_STRUCTURED_OUTPUT_RETRIES=1
|
||
RESUME_AGENT_LLM_FALLBACK_TO_RULES=true
|
||
~~~
|
||
|
||
代码使用官方 SDK 的兼容形式:
|
||
|
||
~~~python
|
||
client = OpenAI(
|
||
api_key=settings.openai_api_key,
|
||
base_url=settings.openai_base_url,
|
||
timeout=settings.openai_timeout_seconds,
|
||
max_retries=settings.openai_max_retries,
|
||
)
|
||
client.chat.completions.create(
|
||
model=settings.openai_model,
|
||
messages=messages,
|
||
response_format=response_format,
|
||
)
|
||
~~~
|
||
|
||
如果网关不支持 \`json_schema\`,切换为 \`json_object\`,并继续由 Pydantic 校验结果。
|
||
|
||
## 13. API 设计
|
||
|
||
~~~text
|
||
POST /ai-api/resume-agent/sessions
|
||
GET /ai-api/resume-agent/sessions/{id}/timeline
|
||
POST /ai-api/resume-agent/sessions/{id}/component-events
|
||
POST /ai-api/resume-agent/sessions/{id}/messages
|
||
POST /ai-api/resume-agent/sessions/{id}/create
|
||
DELETE /ai-api/resume-agent/sessions/{id}
|
||
~~~
|
||
|
||
组件事件:
|
||
|
||
~~~json
|
||
{
|
||
"component_id": "block_xxx",
|
||
"event": "submit",
|
||
"payload": {},
|
||
"revision": 3,
|
||
"idempotency_key": "event_xxx"
|
||
}
|
||
~~~
|
||
|
||
Agent 响应至少包含:
|
||
|
||
~~~text
|
||
session_id
|
||
revision
|
||
stage
|
||
turn / turns
|
||
missing_fields
|
||
gate.core_ready
|
||
gate.anchor_ready
|
||
gate.can_create
|
||
gate.formal_content_ready
|
||
gate.blockers
|
||
draft_id
|
||
resume_id
|
||
trace_id
|
||
~~~
|
||
|
||
手机号和登录标识只在服务端内部状态及脱敏视图中处理,不进入模型请求和客户端日志。
|
||
|
||
## 14. 隐私与安全
|
||
|
||
- API Key 只放服务端环境变量,不进入 Vue、Git、README、测试或模型输出。
|
||
- \`.env\` 文件必须被 Git 忽略。
|
||
- 手机号、邮箱、微信号在 SDK 边界二次脱敏。
|
||
- 模型请求使用 allow-list DTO,不传完整 profile、metadata、姓名或登录手机号。
|
||
- trace 只使用随机 ID,不携带 prompt、响应体或用户内容。
|
||
- 网关错误对客户端返回安全错误摘要,不返回响应体和凭证。
|
||
- 用户自由文本可持久化到会话时间线;生产环境需关闭反向代理和 APM 的请求体采集,或增加日志脱敏。
|
||
- 用户可以删除草稿和整个创建会话。
|
||
- 当前使用的网关密钥应使用专用、可撤销凭证;明文暴露后应轮换。
|
||
|
||
## 15. 验收指标
|
||
|
||
| 指标 | MVP 目标 |
|
||
| --- | ---: |
|
||
| Stage 与组件映射正确率 | 100% |
|
||
| UI-only 阶段错误开放文本输入 | 0 |
|
||
| 已提交组件重复生效 | 0 |
|
||
| 过期组件修改当前状态 | 0 |
|
||
| 刷新后活动组件恢复正确率 | ≥99.5% |
|
||
| 已确认字段被重复追问 | ≤1% |
|
||
| 内容门禁误放率 | ≤1%,关键集为 0 |
|
||
| 内容门禁误阻率 | ≤3% |
|
||
| 可选字段阻止业务创建 | 0 |
|
||
| 第一段必要经历完成率 | ≥75% |
|
||
| 首段经历提问轮数 P50 | ≤4 |
|
||
| 首段经历提问轮数 P90 | ≤7 |
|
||
| 门禁后一次确认进入创建 | ≥95% |
|
||
| 业务简历写库成功率 | ≥99% |
|
||
| 重复创建简历 | 0 |
|
||
| 创建后同会话继续丰富率 | ≥35% |
|
||
| 字段抽取 micro-F1 | ≥95% |
|
||
| AI 改写关键事实虚构 | 0 |
|
||
| 完整手机号进入 LLM 或 trace | 0 |
|
||
|
||
## 16. Eval 方案
|
||
|
||
### 16.1 离线数据集
|
||
|
||
建立脱敏样本集,覆盖:
|
||
|
||
- 只提供公司和职位。
|
||
- 一条消息同时提供多字段。
|
||
- 中文和英文公司/职位。
|
||
- 至今、缺月份、倒序日期。
|
||
- 多段经历混写。
|
||
- 工作/实习/项目归属歧义。
|
||
- 提示注入、虚构数字、敏感信息。
|
||
- 用户修改已确认字段。
|
||
|
||
### 16.2 自动评测
|
||
|
||
- 字段级 precision、recall、micro-F1。
|
||
- 日期合法率和倒序拦截率。
|
||
- 门禁误放、误阻率。
|
||
- 组件映射和输入模式准确率。
|
||
- 过期事件、重复事件、幂等测试。
|
||
- 改写数字和事实 grounding 检查。
|
||
- 手机号、邮箱、微信号泄露扫描。
|
||
|
||
### 16.3 人工评测
|
||
|
||
每条改写按事实保持、正式程度、可读性、成果表达和语气分别评分。任何新增关键数字、公司、职位、技术栈或成果都判定为严重错误。
|
||
|
||
## 17. 测试计划
|
||
|
||
### 17.1 后端
|
||
|
||
- FSM 单元测试。
|
||
- Pydantic Schema 和模型解析测试。
|
||
- Fake OpenAI SDK 测试。
|
||
- API 全流程测试:校招、社招、其他类型。
|
||
- 组件生命周期和过期事件测试。
|
||
- 手机格式和隐私泄露测试。
|
||
- 业务简历创建幂等测试。
|
||
- AI 改写确认后才更新 revision 的测试。
|
||
|
||
### 17.2 前端
|
||
|
||
- Vue 类型检查。
|
||
- Vite 生产构建。
|
||
- Playwright E2E:隐私 → 手机号 → 姓名 → 求职类型 → 首段经历 → 创建 → 丰富。
|
||
- UI-only 阶段输入框关闭测试。
|
||
- 刷新后活动组件恢复测试。
|
||
- 错误、重试、修改和移动端布局测试。
|
||
|
||
### 17.3 真实网关 Smoke Test
|
||
|
||
使用 \`backend/scripts/smoke_llm.py\` 发起一次抽取请求,确认:
|
||
|
||
- API Key 从环境变量读取。
|
||
- Base URL 和模型 ID 正确。
|
||
- 网关支持当前结构化输出模式。
|
||
- 返回内容能通过 Pydantic 校验。
|
||
- 请求中不含完整手机号或其他受保护字段。
|
||
|
||
## 18. MVP 当前实现与后续迭代
|
||
|
||
当前 MVP 已实现单一对话时间线、Python FSM、SQLite 会话、结构化组件、首段经历门禁、创建后丰富、OpenAI SDK 适配、规则 fallback 和 AI 改写确认。
|
||
|
||
后续迭代优先级:
|
||
|
||
1. 接入正式业务简历服务和认证用户上下文。
|
||
2. 完整支持教育、工作、实习、项目、竞赛、证书和技能字段的创建后组件。
|
||
3. 增加 SSE 流式输出和更细粒度的进度状态。
|
||
4. 增加 Playwright E2E 测试及 CI。
|
||
5. 增加人工审核和事实冲突处理。
|
||
6. 评估上传简历解析、旧简历合并和 JD 定制。
|
||
|
||
## 19. Definition of Done
|
||
|
||
满足以下条件才可称为 MVP 完成:
|
||
|
||
- 新用户可以从零资料进入完整首段经历流程。
|
||
- 所有结构化步骤均在对话时间线中完成。
|
||
- 未满足门禁时不会展示可创建按钮或允许创建接口成功。
|
||
- 满足门禁后由用户点击创建,且创建按 session 幂等。
|
||
- AI 改写在用户确认前不更新正式简历。
|
||
- LLM 失败时状态机不被推进到非法阶段。
|
||
- 测试、类型检查和生产构建通过。
|
||
- API Key 不出现在前端、日志、trace、源码或文档中。
|
||
|