Files

17 KiB
Raw Permalink Blame History

reviewStatus, reviewedAt, replacedBy
reviewStatus reviewedAt replacedBy
pending null null

第一阶段工程基线后端落地设计

1. 文档定位

本文档定义 JobRadar 第一阶段工程基线的后端落地边界,供后续模型设计、编码、迁移、测试和验收使用。本文档是待审核设计,不代表相关代码已经实现。

设计依据:

当前技术基线为 Python 3.13、Django 6.0.8 和 OpenAI Agents SDK 0.22.0。项目没有已登记的 Django 公共 profile,实现时以当前项目规则和对应版本的官方契约为准。

2. 目标与范围

第一阶段将现有 Django 配置骨架扩展为一个可登录、可隔离、可审计、可记录 Agent 运行,但暂不执行真实岗位研究的模块化单体。

阶段完成后应具备:

  • Django 内置用户的登录、退出及基础资料维护能力。
  • 普通用户之间的数据归属隔离。
  • Agent Run、运行事件、工具调用和人工确认的持久化能力。
  • 合法的运行状态转换、事件顺序和幂等控制。
  • OpenAI Agents SDK 的稳定适配入口及无外部费用的测试替身。
  • 包含请求和运行关联标识的脱敏日志。
  • SQLite 完整测试及 PostgreSQL 核心兼容验证能力。

第一阶段明确不实现:

  • 招聘网站采集、企业调查、岗位标准化、筛选、评分和推荐报告。
  • 真实岗位研究 Agent 循环或付费模型调用。
  • Celery、Redis、定时调度和失败任务自动重试。
  • 公开注册、复杂 RBAC、前后端分离、REST API 和独立前端框架。
  • 自动投递简历、自动联系招聘人员或其他不可逆外部操作。

3. 总体调用关系

flowchart LR
    USER["普通用户"] --> AUTH["Django 登录与 Session"]
    AUTH --> PROFILE["用户资料"]
    AUTH --> RUN_VIEW["运行列表与详情"]
    ADMIN["管理员"] --> ADMIN_SITE["Django Admin"]
    ADMIN_SITE --> RUN_SERVICE["Agent Run 服务层"]
    RUN_SERVICE --> RUN["AgentRun"]
    RUN_SERVICE --> EVENT["AgentRunEvent"]
    RUN_SERVICE --> TOOL["ToolCall"]
    RUN_SERVICE --> APPROVAL["HumanApproval"]
    SDK_ADAPTER["SDK Gateway / 测试替身"] --> RUN_SERVICE

所有页面、Admin 扩展和 SDK 适配器通过服务层改变运行状态,不直接拼装跨模型写入。

4. 模块职责

4.1 common

common 只提供跨业务复用的基础能力:

  • 创建时间和更新时间抽象模型。
  • 用户归属抽象模型及用户范围查询入口。
  • 领域异常基类。
  • 请求关联标识中间件。
  • 日志上下文和敏感信息脱敏工具。

common 不包含账户、Agent 或未来岗位业务逻辑,也不依赖业务应用。

4.2 accounts

accounts 负责:

  • Django 内置 User 的一对一扩展资料。
  • 当前用户资料的读取和修改。
  • 登录、退出及资料页面组织。
  • 用户停用约定和资料管理后台。

第一阶段不自定义用户模型,不开放公开注册。用户由管理员创建,日常账户退出使用停用而非物理删除。

4.3 agent_runtime

agent_runtime 负责:

  • Agent Run 生命周期和状态转换。
  • 运行事件的有序追加。
  • 工具调用、幂等键及结果摘要记录。
  • 人工确认请求和处理结果。
  • SDK 运行结果到本地持久化模型的适配。
  • 运行列表、运行详情和管理后台。

该模块不拥有岗位、企业、筛选和评分数据。

4.4 依赖方向

JobRadar 配置与 URL
        ↓
accounts ──────→ common
        ↓
agent_runtime ─→ common
        ↓
OpenAI Agents SDK 适配层

禁止 common 反向依赖业务应用,禁止 accounts 依赖 agent_runtime。

5. 领域对象与数据所有权

5.1 用户归属抽象模型

建议提供抽象模型 UserOwnedModel:

  • owner:关联 Django 用户。
  • created_at:创建时间。
  • updated_at:更新时间。

规则:

  • 所有用户私有模型必须继承该模型或提供等价的 owner 字段。
  • 普通查询必须从 owner=request.user 的数据范围开始,不能先全表查询再在 Python 中校验。
  • 审计数据对用户删除采用保护策略;包含历史运行记录的用户不得直接物理删除。
  • 管理员跨用户查询仅允许出现在 Django Admin 或明确的管理服务中。

5.2 UserProfile

建议字段:

  • user:与 Django User 一对一关联。
  • display_name:可选显示名。
  • timezone:默认 Asia/Shanghai。
  • created_at、updated_at。

第一阶段不加入技能、薪资、地区和企业偏好。这些内容属于后续个人画像领域,应在需求明确后独立建模并支持版本化。

资料由账户服务显式 get_or_create,不依赖隐藏的 Signal 自动创建。

5.3 AgentRun

建议字段分组:

  • 归属:owner。
  • 标识与状态:主键、title、status、lock_version。
  • 输入输出:input_summary、output_summary。
  • 版本:agent_name、agent_version、instruction_version、toolset_version、model_name。
  • 追踪:trace_id、started_at、finished_at、duration_ms。
  • 用量:input_tokens、output_tokens、estimated_cost。
  • 失败:error_code、error_summary。
  • 审计:created_at、updated_at。

输入、输出和错误只保存经过脱敏、限制大小的摘要,不保存 API Key、密码、Cookie 或完整敏感工具参数。第一阶段不执行真实模型调用,因此 model_name、token 和费用字段允许为空。

5.4 AgentRunEvent

建议字段:

  • run、sequence、event_type。
  • summary、payload_summary。
  • occurred_at、created_at。

约束:

  • (run, sequence) 唯一。
  • 默认按 Run 和序号升序读取。
  • 事件作为审计记录追加,普通业务不得修改或删除。

事件类型至少包括:

  • run_created、run_started、run_paused、run_resumed。
  • run_succeeded、run_failed、run_cancelled。
  • tool_started、tool_completed、tool_failed。
  • approval_requested、approval_resolved。

5.5 ToolCall

建议字段分组:

  • 归属:run、call_id。
  • 工具:tool_name、tool_version、idempotency_key。
  • 状态:status、started_at、finished_at、duration_ms。
  • 摘要:arguments_summary、result_summary。
  • 失败:error_code、error_summary。
  • 审计:created_at、updated_at。

约束:

  • (run, call_id) 唯一。
  • 非空幂等键在明确的业务作用域内唯一。
  • 已成功的相同幂等调用不得重复产生副作用。
  • 第一阶段只验证记录能力,不实现真实采集工具。

5.6 HumanApproval

建议字段:

  • run、request_key、approval_type、status。
  • request_summary、decision_summary。
  • requested_at、resolved_at、resolved_by。
  • created_at、updated_at。

状态包括 pending、approved、rejected、expired 和 cancelled。

约束:

  • (run, request_key) 唯一。
  • 只有 pending 状态可以处理。
  • resolved_by 必须是 Run 所属用户或具备管理权限的管理员。
  • 第一阶段只在 Admin 中处理人工确认,不开发独立用户审批页面。

数据库字段类型、索引名和完整删除策略应在编码前通过数据库专项设计进一步确认。

6. Agent Run 状态机

运行状态:

  • pending
  • running
  • waiting_approval
  • succeeded
  • failed
  • cancelled

允许的转换:

当前状态 可转换状态
pending running、cancelled
running waiting_approval、succeeded、failed、cancelled
waiting_approval running、failed、cancelled
succeeded 无
failed 无
cancelled 无

状态规则:

  • 终态不可再次转换。
  • 成功和失败必须记录完成时间;失败还必须记录脱敏错误摘要。
  • 进入 waiting_approval 时必须在同一事务中创建待处理的 HumanApproval 和对应事件。
  • 确认通过后才能恢复运行;确认拒绝默认将 Run 置为 cancelled。
  • 状态转换和对应事件必须在同一事务中提交。
  • 第一阶段不支持失败 Run 原地重试;后续重试应创建新 Run 并关联原 Run。

7. 服务层设计

7.1 账户服务

建议职责:

  • 获取或显式创建当前用户资料。
  • 修改当前用户自己的资料。
  • 由管理员停用指定用户。

普通用户请求其他用户资料时按资源不存在处理,避免泄露目标用户是否存在。

7.2 Agent Run 服务

服务层应提供以下原子能力:

  • 创建 Run。
  • 开始、完成、失败或取消 Run。
  • 追加运行事件。
  • 开始、完成或失败一次工具调用。
  • 创建人工确认请求。
  • 处理人工确认结果。

每个状态写方法按统一顺序执行:

  1. 校验操作者身份、用户归属或管理权限。
  2. 锁定需要修改的记录。
  3. 校验当前状态和目标状态。
  4. 修改主记录。
  5. 追加不可变事件或更新关联记录。
  6. 提交事务后再触发任何外部操作。

8. 事务、并发与一致性

关键状态变更使用 transaction.atomic()。

同一 Run 的并发控制策略:

  • PostgreSQL 使用行锁串行化状态更新。
  • lock_version 提供乐观并发检测。
  • 事件序号在锁定 Run 后生成。
  • (run, sequence) 唯一约束作为最后一致性防线。
  • SQLite 测试只验证业务约束,不能代替 PostgreSQL 行锁与并发行为验证。

外部 SDK 或工具调用不得包裹在数据库长事务中:

事务 1:登记调用开始 → 提交
外部调用:不持有数据库事务
事务 2:登记成功或失败 → 更新 Run → 追加事件 → 提交

该边界避免网络或模型调用长期占用数据库连接和行锁。

9. SDK 适配边界

第一阶段只建立 SDK 适配协议和测试替身:

  • AgentExecutionRequest:本地运行编号、用户编号、版本和预算摘要。
  • AgentExecutionResult:状态、输出摘要、trace 标识、用量和错误摘要。
  • AgentRunnerGateway:运行入口协议。
  • StubAgentRunnerGateway:自动化测试替身。
  • OpenAIAgentRunnerGateway:真实 SDK 适配位置,岗位研究逻辑留到第二阶段。

约束:

  • 未配置 OpenAI API Key 时,登录、资料、Admin 和运行查询仍应正常工作。
  • 只有调用真实 SDK Gateway 时才检查 API Key。
  • API Key 不进入运行上下文、数据库或日志。
  • 第一阶段不接入 Celery,也不在 Web 请求内执行长时间 Agent Run。
  • 使用测试替身验证运行开始、事件记录、成功和失败链路。

Celery 是目标架构中的后续运行载体;第一阶段仅稳定持久化和适配边界,两者不冲突。

10. 页面、权限与错误语义

建议路由:

/accounts/login/
/accounts/logout/
/accounts/profile/
/runs/
/runs/<uuid>/

访问规则:

  • 未登录用户访问资料和 Run 页面时跳转到登录页。
  • 普通用户查询始终限定 owner=request.user。
  • 跨用户访问 Run 统一返回 404,避免暴露资源存在性。
  • 资料修改使用 POST 并启用 CSRF。
  • Run 列表分页并按创建时间倒序。
  • Run 详情按事件序号展示事件和工具调用摘要。
  • 第一阶段不提供公开注册、账户自助删除或 HTTP API。

Admin 规则:

  • 管理员可以维护用户资料并查看全部 Agent Run。
  • 运行事件和完成后的工具调用原则上只读。
  • Admin 中展示的参数和结果同样必须脱敏。

领域错误分类:

  • ResourceNotFound:资源不存在或无权访问,页面响应为 404。
  • ValidationError:输入不合法,显示表单错误或返回 400。
  • InvalidStateTransition:运行状态冲突,语义为 409。
  • DuplicateOperation:重复操作或幂等冲突,语义为 409。
  • AgentConfigurationError:SDK 配置缺失,明确提示该功能不可用。
  • ExternalServiceError:外部调用失败,保存脱敏错误并将 Run 置为失败。

用户响应不得包含堆栈、数据库信息、完整外部响应或敏感配置。

11. 日志与审计

增加请求关联标识中间件:

  • 接受格式合法的入站关联标识,否则生成新标识。
  • 将关联标识加入响应头和日志上下文。
  • Agent 日志同时携带 run_id、trace_id 和 tool_call_id。
  • 用户相关日志只记录内部用户编号。

必须记录:

  • 登录失败和账户停用。
  • Run 创建及每次状态转换。
  • 工具调用开始、完成和失败。
  • 人工确认请求及处理结果。
  • 非法状态转换和跨用户访问尝试。

禁止记录:

  • API Key、密码和 Session Cookie。
  • 招聘网站完整 Cookie。
  • 未脱敏的工具参数。
  • 模型返回的完整敏感内容。

12. 实施顺序

实现采用“功能闭环驱动、模块边界承载”的纵向切片,而不是依次把各技术模块全部做完:

  1. 用户登录、资料维护和跨用户隔离闭环。
  2. 管理员创建测试 Run 并审计状态、事件、工具调用和人工确认的闭环。
  3. 普通用户查看自己的运行列表和运行轨迹闭环。
  4. SDK 测试替身驱动一次成功或失败持久化运行的闭环。
  5. SQLite、页面、日志、质量工具和 PostgreSQL 的完整验收闭环。

每个切片内部仍按模型与迁移、服务与事务、入口与页面、测试与文档的依赖顺序实施。切片必须形成可运行结果并完成相应验证,才进入下一片;没有当前需求的未来模块和抽象不提前创建。

13. 测试与验收策略

自动化测试至少覆盖:

  • 用户资料首次创建和重复获取。
  • 未登录访问拒绝。
  • 用户只能读取和修改自己的资料。
  • 用户 A 查询用户 B 的 Run 返回 404。
  • 管理员能够查看全部运行记录。
  • 所有合法和非法状态转换。
  • 终态不可修改。
  • 并发状态更新只能有一个成功。
  • 事件序号连续且唯一。
  • 工具调用幂等键冲突。
  • 工具调用成功、失败和超时记录。
  • 人工确认只能处理一次且处理人权限正确。
  • 敏感字段不会写入日志和摘要。
  • 未配置 API Key 时非 Agent 页面正常。
  • SDK 测试替身的成功、失败和异常链路。
  • SQLite 迁移和全量测试。
  • PostgreSQL 空库迁移、唯一约束和并发验证。

阶段验收命令沿用开发计划:

python manage.py check
python manage.py check --deploy --settings=JobRadar.settings.production
python manage.py makemigrations --check --dry-run
python manage.py migrate
pytest
ruff check .

生产配置检查需要注入非秘密的验证用配置和隔离的数据库参数,不得连接生产库执行测试。

14. 兼容、迁移与回滚

  • 新应用按 common、accounts、agent_runtime 的依赖顺序生成迁移。
  • 模型和约束同时兼容 SQLite 与 PostgreSQL,不使用数据库方言专属 SQL。
  • 每组迁移先在空 SQLite 数据库验证,再在空 PostgreSQL 数据库验证。
  • 第一阶段没有既有业务数据迁移,不提供破坏性数据转换。
  • 单步实现失败时回滚对应代码和未发布迁移;不得通过修改已发布迁移掩盖问题。
  • 外部 SDK 未配置或不可用时关闭真实执行入口,不影响认证、资料和运行查询。

15. 风险与待确认项

以下事项不阻塞第一阶段编码,但必须在对应节点前确认:

事项 当前建议 最迟确认时间
PostgreSQL 实例位置 本地开发继续使用 SQLite PostgreSQL 集成验证前
OpenAI 模型与预算 第一阶段不固定付费模型 第二阶段启动前
API Key 注入 仅使用环境变量或部署平台密钥 真实调用前
用户物理删除 默认禁止,使用停用代替 开放账户管理能力前
摘要最大长度 编码前给出统一上限 模型详细设计时
日志和审计保留周期 暂不自动清理 公网部署前
人工确认超时 第一阶段仅支持手动取消 第二阶段运行设计时

16. 实现交接清单

编码前应进一步固化:

  • 使用数据库设计明确字段类型、索引、约束名和删除策略。
  • 如需 HTTP API,再使用 API 设计明确端点和响应契约;第一阶段默认只提供 Django 页面。
  • 确认 common、accounts、agent_runtime 的应用包名和 URL 命名空间。
  • 确认摘要长度、JSON 大小限制和日志脱敏词表。
  • 确认 PostgreSQL 集成验证环境。

推荐实现结论:

  • 使用 Django 内置用户和一对一 UserProfile。
  • 使用 common、accounts、agent_runtime 三个应用。
  • 由服务层统一权限检查、状态转换和审计写入。
  • 运行事件采用不可变追加模式。
  • 数据库事务与外部调用分离。
  • SDK 使用 Gateway 和测试替身建立稳定边界。
  • 第一阶段不引入 Celery、DRF、Vue 或真实模型调用。