docs(project): 切换为AI工程化开发模式
This commit is contained in:
@@ -73,18 +73,18 @@ audit/ 日志、证据与版本追踪
|
||||
|
||||
详细边界参见 [架构设计](docs/architecture.md),Agent 的目标、工具和状态约定参见 [Agent 契约](docs/agent-contract.md),开发顺序参见 [实施路线图](docs/roadmap.md)。
|
||||
|
||||
## 学习与开发方式
|
||||
## AI开发方式
|
||||
|
||||
JobRadar 同时是实际项目和 Agent 学习项目,采用“逐阶段、逐课、手动实现”的协作方式:
|
||||
JobRadar采用“阶段目标驱动、AI直接实现”的开发方式:
|
||||
|
||||
1. 我先说明本课目标、核心原理以及它在完整系统中的位置。
|
||||
2. 对照 Java、Spring 和常见后端设计解释 Python、Django 与 Agents SDK 的差异。
|
||||
3. 我提供本课所需的完整参考代码、运行命令、预期结果和常见错误。
|
||||
4. 你根据讲解亲手把代码写入 JobRadar,不直接复制一个已完成项目。
|
||||
5. 你完成后,我检查正确性、可读性、Agent 设计和安全边界,并解释问题。
|
||||
6. 当前一课达到验收标准后,再开始下一课。
|
||||
1. 用户确认当前阶段目标、业务边界和验收重点。
|
||||
2. AI先检查仓库现状,给出修改方案和涉及文件。
|
||||
3. AI直接生成或修改代码、迁移、配置、测试与必要文档。
|
||||
4. AI执行静态检查、自动化测试和安全检查,并如实报告未覆盖项。
|
||||
5. 用户根据可运行结果和页面效果进行业务验收。
|
||||
6. 当前阶段稳定后,再进入下一阶段或扩展更多工具。
|
||||
|
||||
默认情况下,我不会直接替你写入业务代码,也不会一次性生成后续全部模块。只有你明确要求我落地某段代码时,我才修改项目文件。详细约定参见 [学习协作说明](docs/learning-guide.md)。
|
||||
实现应保持增量、小步、可验证。不会为了展示一次性生成所有未来模块,也不会将尚未运行验证的规划描述为已完成功能。详细约定参见 [AI开发约定](docs/development-guide.md)。
|
||||
|
||||
## 本地运行
|
||||
|
||||
@@ -212,4 +212,4 @@ JobRadar 仅用于个人岗位信息整理与求职辅助。使用前应确认
|
||||
|
||||
当前版本:`0.1.0-dev`
|
||||
|
||||
当前阶段:[阶段一第1课“Django项目配置与开发/生产环境拆分”](docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/README.md)已经创建,等待学习者手动完成项目配置拆分。
|
||||
当前阶段:架构与Agent契约已经确定,下一步由AI直接实现阶段一工程基线。
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# JobRadar AI开发约定
|
||||
|
||||
## 开发模式
|
||||
|
||||
JobRadar不再采用课程式手动编码。后续由AI根据阶段目标直接生成和修改代码,用户主要负责业务方向、关键选择和结果验收。
|
||||
|
||||
## 每次开发流程
|
||||
|
||||
1. 检查Git状态、现有实现、依赖和相关文档。
|
||||
2. 说明修改方案、涉及文件、风险和预期结果。
|
||||
3. 在授权范围内直接完成代码、配置、数据库迁移、测试和文档改动。
|
||||
4. 执行与改动匹配的验证,不以静态检查替代未执行的集成行为。
|
||||
5. 汇报实际完成内容、验证结果、剩余风险和建议下一步。
|
||||
6. 只有用户明确要求提交时才执行本地Git提交,默认不推送远程。
|
||||
|
||||
## 生成原则
|
||||
|
||||
- 以当前阶段的最小完整闭环为边界,不提前生成无法验证的未来模块。
|
||||
- 优先使用OpenAI Agents SDK、Django等选定技术的原生能力,不引入无明确需求的兼容层。
|
||||
- 所有Agent外部行为通过类型明确、权限受控、可审计的工具执行。
|
||||
- 确定性规则、评分和数据写入由代码工具完成,不让模型随意生成最终业务事实。
|
||||
- 新增代码遵循现有目录、命名、类型注解和中文注释风格。
|
||||
- 保留用户已有变更,不覆盖无关文件,不提交密钥、Cookie和本地配置。
|
||||
|
||||
## 验证要求
|
||||
|
||||
根据改动范围选择并执行:
|
||||
|
||||
- Python语法编译和代码质量检查。
|
||||
- Django系统检查与迁移检查。
|
||||
- 模型、Service、工具和视图测试。
|
||||
- Agent结构化输出、工具调用、失败路径和人工确认测试。
|
||||
- 公网部署配置与Django部署安全检查。
|
||||
- Git差异、敏感信息和提交范围检查。
|
||||
|
||||
无法运行的验证必须明确说明原因,不能仅凭代码阅读宣称通过。
|
||||
|
||||
## 交付要求
|
||||
|
||||
每次交付至少说明:
|
||||
|
||||
- 完成了什么功能。
|
||||
- 修改了哪些核心文件。
|
||||
- 执行了哪些验证及其结果。
|
||||
- 是否存在需要用户提供的域名、账号、API Key或网站授权。
|
||||
- 当前工作区是否已提交、是否推送。
|
||||
|
||||
## 用户确认边界
|
||||
|
||||
以下事项仍需用户明确决定:
|
||||
|
||||
- 目标招聘网站和允许的访问方式。
|
||||
- 外部付费服务、模型及调用预算。
|
||||
- 公网域名、服务器和部署平台。
|
||||
- 可能产生费用或对外副作用的操作。
|
||||
- 自动投递、自动联系、删除历史数据等高风险能力。
|
||||
@@ -1,82 +0,0 @@
|
||||
# JobRadar 学习协作说明
|
||||
|
||||
## 项目定位
|
||||
|
||||
JobRadar不只是需要交付的岗位系统,也是用于系统学习正规Agent开发的实战项目。学习目标包括Agents SDK运行循环、工具设计、状态管理、人工确认、可观测性、评测、公网Web应用和工程化部署。
|
||||
|
||||
## 默认协作方式
|
||||
|
||||
每次只推进一课,流程如下:
|
||||
|
||||
1. 回顾上一课成果和遗留问题。
|
||||
2. 说明本课完成后能够做什么。
|
||||
3. 解释新概念是什么、为什么需要以及在JobRadar中的位置。
|
||||
4. 使用Java、Spring或常见后端设计进行必要对照。
|
||||
5. 给出本课完整参考代码,并逐段解释执行顺序和设计原因。
|
||||
6. 明确代码应该写入哪个文件以及如何运行。
|
||||
7. 给出预期结果、常见错误、调试方法和验收标准。
|
||||
8. 学习者手动完成代码。
|
||||
9. 对学习者代码进行检查,不直接覆盖已有实现。
|
||||
10. 当前课通过后再继续下一课。
|
||||
|
||||
## 每课内容结构
|
||||
|
||||
每课原则上包含:
|
||||
|
||||
- 本课目标
|
||||
- 前置知识
|
||||
- 架构位置
|
||||
- 核心原理
|
||||
- Java或Spring对照
|
||||
- 完整参考代码
|
||||
- 关键代码解析
|
||||
- 手动实现步骤
|
||||
- 运行命令与预期结果
|
||||
- 常见错误与排查方法
|
||||
- 课堂练习
|
||||
- 自检清单
|
||||
- 验收标准
|
||||
- 本课小结
|
||||
|
||||
## 代码边界
|
||||
|
||||
- 默认由学习者手动编写业务代码。
|
||||
- 我提供参考代码、解释、提示、测试思路和审查反馈。
|
||||
- 未经明确要求,不直接向JobRadar写入本课业务实现。
|
||||
- 不一次性生成未来阶段代码,不提前制造空模块。
|
||||
- 不覆盖学习者已有实现;发现问题时先说明原因和修正方案。
|
||||
- 用户明确要求代为修改时,先说明方案、涉及文件和预期结果,再执行改动。
|
||||
|
||||
## 练习约定
|
||||
|
||||
如果后续为课程创建练习文件,练习文件只包含注释形式的题目、操作提示、预期结果、自检项和验收标准,不包含导入语句、函数骨架、`pass`、测试数据、答案或运行记录。
|
||||
|
||||
参考答案与练习文件分离。学习者完成代码后,优先基于学习者实现进行讲解,而不是用参考答案覆盖。
|
||||
|
||||
## 验收方式
|
||||
|
||||
每课至少验证:
|
||||
|
||||
- 代码能够在`JobRadar` Conda环境中运行。
|
||||
- Django系统检查或对应测试通过。
|
||||
- 行为与本课预期结果一致。
|
||||
- Agent工具真实执行,没有用自然语言伪造结果。
|
||||
- 数据写入具备用户归属、幂等和审计边界。
|
||||
- 密钥、Cookie和本地配置没有进入Git。
|
||||
- 学习者能够说明关键代码为什么这样设计。
|
||||
|
||||
涉及Agent的课程还需要检查工具调用、结构化输出、trace、失败路径和人工确认边界,不能只检查最终文本是否看起来正确。
|
||||
|
||||
## 教学深度
|
||||
|
||||
学习者已有Java和数据库基础,因此不重复教授变量、类、SQL、事务等通用概念。课程重点解释:
|
||||
|
||||
- Python与Java在语言和工程组织上的差异。
|
||||
- Django与Spring Boot在请求处理、ORM、配置和用户体系上的差异。
|
||||
- Agents SDK与普通Service编排、工作流引擎及传统定时任务的差异。
|
||||
- Agent何时自主决策,何时必须交给确定性工具或人工确认。
|
||||
- 如何通过trace和eval判断一个Agent是否真正可靠。
|
||||
|
||||
## 当前起点
|
||||
|
||||
第一课[Django项目配置与开发/生产环境拆分](lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/README.md)已经创建。当前应阅读讲义、参考完整示例,然后手动拆分项目配置;完成后执行课程验收命令并提交代码供检查。
|
||||
@@ -1,267 +0,0 @@
|
||||
# 第1课:Django项目配置与开发/生产环境拆分
|
||||
|
||||
## 本课目标
|
||||
|
||||
完成本课后,你将能够:
|
||||
|
||||
1. 解释Django设置模块(settings module)如何被加载。
|
||||
2. 将单一`settings.py`拆成公共、开发和生产三套配置。
|
||||
3. 使用`DJANGO_SETTINGS_MODULE`选择运行环境。
|
||||
4. 将生产密钥和域名移出Git仓库。
|
||||
5. 使用Django部署检查发现危险配置。
|
||||
|
||||
本课只学习配置拆分,不接入PostgreSQL、Celery或Agents SDK。
|
||||
|
||||
## 前置知识
|
||||
|
||||
- 能运行`python manage.py check`和`python manage.py runserver`。
|
||||
- 理解Python模块和`import`。
|
||||
- 了解Spring Boot的Profile和`application-{profile}.yml`。
|
||||
|
||||
## 在JobRadar架构中的位置
|
||||
|
||||
JobRadar最终部署到公网,并需要数据库密码、模型API Key、招聘网站凭据等敏感配置。如果开发与生产共用一个`settings.py`,很容易出现以下问题:
|
||||
|
||||
- 将开发环境的`DEBUG = True`带到公网。
|
||||
- 将生产密钥提交到Git。
|
||||
- 本地SQLite和生产PostgreSQL配置互相覆盖。
|
||||
- 本地地址、正式域名和HTTPS策略混在一起。
|
||||
- Agent运行时读取了错误的模型或密钥。
|
||||
|
||||
因此,安全配置是用户系统和Agent功能之前的工程基线。
|
||||
|
||||
## 核心原理
|
||||
|
||||
### 1. settings本质上是Python模块
|
||||
|
||||
Django设置不是特殊配置格式,而是包含模块级变量的Python模块。例如:
|
||||
|
||||
```python
|
||||
DEBUG = False
|
||||
ALLOWED_HOSTS = ["jobradar.example.com"]
|
||||
```
|
||||
|
||||
Django启动时读取`DJANGO_SETTINGS_MODULE`,然后导入该变量指定的Python模块:
|
||||
|
||||
```text
|
||||
JobRadar.settings.development
|
||||
JobRadar.settings.production
|
||||
```
|
||||
|
||||
点号是Python包路径,不是文件系统斜杠。
|
||||
|
||||
### 2. 公共配置与环境差异分离
|
||||
|
||||
本课采用三层结构:
|
||||
|
||||
```text
|
||||
JobRadar/
|
||||
└── settings/
|
||||
├── __init__.py
|
||||
├── base.py
|
||||
├── development.py
|
||||
└── production.py
|
||||
```
|
||||
|
||||
- `base.py`:应用、Middleware、模板、国际化等公共配置。
|
||||
- `development.py`:开发密钥、`DEBUG = True`和本地地址。
|
||||
- `production.py`:生产密钥、正式域名、HTTPS和安全Cookie。
|
||||
|
||||
`development.py`和`production.py`通过`from .base import *`继承公共配置。这种星号导入在普通业务代码中不推荐,但Django分层settings是一个边界明确的配置场景。
|
||||
|
||||
### 3. 与Spring Boot Profile对照
|
||||
|
||||
| Spring Boot | Django本课方案 |
|
||||
| --- | --- |
|
||||
| `application.yml` | `settings/base.py` |
|
||||
| `application-dev.yml` | `settings/development.py` |
|
||||
| `application-prod.yml` | `settings/production.py` |
|
||||
| `spring.profiles.active=dev` | `DJANGO_SETTINGS_MODULE=JobRadar.settings.development` |
|
||||
| `${DB_PASSWORD}` | `os.environ["DB_PASSWORD"]` |
|
||||
| `@Profile`控制Bean | Django通常在settings中切换组件配置 |
|
||||
|
||||
最大的区别是:Spring配置主要是YAML/Properties,Django settings本身就是Python代码。它更灵活,也意味着不能在里面随意写复杂业务逻辑。
|
||||
|
||||
## 完整参考代码
|
||||
|
||||
参考目录位于本课的`reference/`中:
|
||||
|
||||
```text
|
||||
reference/
|
||||
├── settings/
|
||||
│ ├── __init__.py
|
||||
│ ├── base.py
|
||||
│ ├── development.py
|
||||
│ └── production.py
|
||||
├── manage.py
|
||||
├── asgi.py
|
||||
└── wsgi.py
|
||||
```
|
||||
|
||||
这些文件用于阅读和手动输入,不能直接覆盖当前项目。你需要理解每一处路径变化后,再把对应结构写入项目。
|
||||
|
||||
## 关键代码解析
|
||||
|
||||
### `BASE_DIR`为什么多一个`parent`
|
||||
|
||||
原始`settings.py`位于:
|
||||
|
||||
```text
|
||||
JobRadar/settings.py
|
||||
```
|
||||
|
||||
拆分后的`base.py`位于:
|
||||
|
||||
```text
|
||||
JobRadar/settings/base.py
|
||||
```
|
||||
|
||||
文件多进入了一层`settings`目录,因此项目根目录改为:
|
||||
|
||||
```python
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||
```
|
||||
|
||||
如果仍使用两个`parent`,SQLite和模板目录都会指向错误位置。
|
||||
|
||||
### 为什么生产配置使用`os.environ[名称]`
|
||||
|
||||
```python
|
||||
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
|
||||
```
|
||||
|
||||
方括号读取在变量缺失时立即抛出`KeyError`,让生产进程启动失败。相比提供一个不安全默认值,这种“快速失败”(fail fast)更安全。
|
||||
|
||||
开发配置可以使用明确标记为仅限本地的默认密钥,但生产配置绝不能提供默认生产密钥。
|
||||
|
||||
### 为什么入口的默认环境不同
|
||||
|
||||
- `manage.py`默认开发配置,方便本地运行。
|
||||
- `asgi.py`和`wsgi.py`默认生产配置,降低部署时误启用开发设置的风险。
|
||||
- 命令行仍可通过`--settings`显式覆盖,便于检查两个环境。
|
||||
|
||||
## 手动实现步骤
|
||||
|
||||
1. 在`JobRadar`包内创建`settings`目录及`__init__.py`。
|
||||
2. 参考`base.py`移动原`settings.py`的公共配置,并修正`BASE_DIR`。
|
||||
3. 编写`development.py`和`production.py`。
|
||||
4. 修改项目根目录的`manage.py`,默认指向开发配置。
|
||||
5. 修改`JobRadar/asgi.py`和`JobRadar/wsgi.py`,默认指向生产配置。
|
||||
6. 删除旧`JobRadar/settings.py`前,逐项确认内容已经迁移。
|
||||
7. 分别运行开发和生产配置检查。
|
||||
|
||||
不要直接复制整个`reference`目录覆盖项目,因为参考文件的层级和真实文件位置并不完全相同。
|
||||
|
||||
## 运行方法
|
||||
|
||||
### 检查开发配置
|
||||
|
||||
```powershell
|
||||
conda activate JobRadar
|
||||
python manage.py check --settings=JobRadar.settings.development
|
||||
```
|
||||
|
||||
预期结果:
|
||||
|
||||
```text
|
||||
System check identified no issues (0 silenced).
|
||||
```
|
||||
|
||||
### 检查生产配置的缺失密钥保护
|
||||
|
||||
先确保当前PowerShell没有设置课程变量:
|
||||
|
||||
```powershell
|
||||
Remove-Item Env:DJANGO_SECRET_KEY -ErrorAction SilentlyContinue
|
||||
python manage.py check --settings=JobRadar.settings.production
|
||||
```
|
||||
|
||||
预期结果:命令失败,并明确提示缺少`DJANGO_SECRET_KEY`。这是安全保护生效,不是课程代码错误。
|
||||
|
||||
### 临时设置生产变量并检查
|
||||
|
||||
以下值只在当前PowerShell进程有效:
|
||||
|
||||
```powershell
|
||||
$env:DJANGO_SECRET_KEY = "仅用于本地检查的长随机字符串-请勿用于生产"
|
||||
$env:DJANGO_ALLOWED_HOSTS = "jobradar.example.com"
|
||||
$env:DJANGO_CSRF_TRUSTED_ORIGINS = "https://jobradar.example.com"
|
||||
python manage.py check --settings=JobRadar.settings.production
|
||||
python manage.py check --deploy --settings=JobRadar.settings.production
|
||||
```
|
||||
|
||||
普通`check`应通过。`check --deploy`可能继续提示HSTS时长等部署建议;本课重点是能区分错误和安全告警,不要求为了消除告警而盲目开启尚未理解的配置。
|
||||
|
||||
检查完成后清理临时变量:
|
||||
|
||||
```powershell
|
||||
Remove-Item Env:DJANGO_SECRET_KEY
|
||||
Remove-Item Env:DJANGO_ALLOWED_HOSTS
|
||||
Remove-Item Env:DJANGO_CSRF_TRUSTED_ORIGINS
|
||||
```
|
||||
|
||||
## 常见错误
|
||||
|
||||
### 错误1:`No module named 'JobRadar.settings.development'`
|
||||
|
||||
原因通常是:
|
||||
|
||||
- 没有创建`settings/__init__.py`。
|
||||
- 包或模块名称拼错。
|
||||
- 旧`settings.py`仍存在,导致目录结构未正确调整。
|
||||
|
||||
### 错误2:SQLite文件出现在`JobRadar/`包内
|
||||
|
||||
原因是拆分后没有为`BASE_DIR`增加一层`parent`。
|
||||
|
||||
### 错误3:生产检查仍然使用开发配置
|
||||
|
||||
先查看命令是否传入:
|
||||
|
||||
```text
|
||||
--settings=JobRadar.settings.production
|
||||
```
|
||||
|
||||
也可以运行:
|
||||
|
||||
```powershell
|
||||
python manage.py diffsettings --settings=JobRadar.settings.production
|
||||
```
|
||||
|
||||
### 错误4:把生产密钥写入`production.py`
|
||||
|
||||
生产密钥必须由服务器部署环境注入。Git中的示例只能写变量名和虚假示例,不能包含真实值。
|
||||
|
||||
### 错误5:`ALLOWED_HOSTS = ["*"]`
|
||||
|
||||
星号允许任意Host,失去了Django主机头校验的主要意义。公网项目应填写明确域名;本地开发单独允许`127.0.0.1`和`localhost`。
|
||||
|
||||
## 课堂练习
|
||||
|
||||
练习要求见[practice.py](practice.py)。该文件只有题目和验收标准,你的实际代码应写入JobRadar项目配置文件中。
|
||||
|
||||
## 自检清单
|
||||
|
||||
- [ ] 能解释`DJANGO_SETTINGS_MODULE`的作用。
|
||||
- [ ] 能说明`base.py`中为什么使用三个`parent`。
|
||||
- [ ] 开发环境默认开启`DEBUG`,生产环境固定关闭。
|
||||
- [ ] 生产环境缺少密钥时会快速失败。
|
||||
- [ ] 生产域名和CSRF可信来源来自外部配置。
|
||||
- [ ] ASGI/WSGI默认指向生产配置。
|
||||
- [ ] Git差异中没有真实密钥。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. `python manage.py check --settings=JobRadar.settings.development`通过。
|
||||
2. 缺少`DJANGO_SECRET_KEY`时,生产配置检查按预期失败。
|
||||
3. 临时提供生产变量后,普通生产配置检查通过。
|
||||
4. `python manage.py makemigrations --check --dry-run --settings=JobRadar.settings.development`显示无遗漏迁移。
|
||||
5. `git diff --check`通过。
|
||||
6. `git diff`中没有真实密钥、Cookie或密码。
|
||||
7. 学习者能解释开发和生产入口为何采用不同默认settings。
|
||||
|
||||
## 本课小结
|
||||
|
||||
本课没有增加业务功能,但建立了公网Agent项目的安全配置基础。Django通过`DJANGO_SETTINGS_MODULE`选择一个Python配置模块;公共设置放入`base.py`,开发和生产只覆盖差异。生产环境应关闭`DEBUG`、限制域名、启用HTTPS相关设置,并在缺少密钥时拒绝启动。
|
||||
|
||||
完成手动实现并通过验收后,下一课进入“Django用户系统与用户数据归属”。
|
||||
@@ -1,43 +0,0 @@
|
||||
# 第1课练习:Django项目配置与开发/生产环境拆分
|
||||
#
|
||||
# 练习目标:
|
||||
# 1. 将当前单文件settings.py拆分为base、development和production三个配置模块。
|
||||
# 2. 让本地管理命令默认使用开发配置,让ASGI和WSGI默认使用生产配置。
|
||||
# 3. 验证生产密钥缺失时快速失败,提供临时变量后能够通过普通系统检查。
|
||||
#
|
||||
# 操作要求:
|
||||
# 1. 在JobRadar包内创建settings目录和__init__.py。
|
||||
# 2. 把公共配置迁移到base.py,并根据新目录层级修正BASE_DIR。
|
||||
# 3. 在development.py中配置仅限本地使用的SECRET_KEY、DEBUG和ALLOWED_HOSTS。
|
||||
# 4. 在production.py中从外部读取DJANGO_SECRET_KEY、DJANGO_ALLOWED_HOSTS和
|
||||
# DJANGO_CSRF_TRUSTED_ORIGINS,固定关闭DEBUG并配置HTTPS安全项。
|
||||
# 5. 调整manage.py、asgi.py和wsgi.py使用正确的默认配置模块。
|
||||
# 6. 确认全部配置迁移后再删除旧settings.py。
|
||||
#
|
||||
# 预期结果:
|
||||
# 1. 开发配置执行Django系统检查时通过。
|
||||
# 2. 未设置DJANGO_SECRET_KEY时,生产配置检查明确失败。
|
||||
# 3. 设置三个临时生产变量后,生产配置普通检查通过。
|
||||
# 4. 项目根目录仍是BASE_DIR,SQLite和templates路径没有移动到JobRadar包中。
|
||||
# 5. Git变更中不存在真实密钥、密码或Cookie。
|
||||
#
|
||||
# 自检问题:
|
||||
# 1. DJANGO_SETTINGS_MODULE保存的是文件路径还是Python模块路径?
|
||||
# 2. 为什么生产配置不应该为SECRET_KEY提供默认值?
|
||||
# 3. 为什么DEBUG=False时必须正确设置ALLOWED_HOSTS?
|
||||
# 4. 为什么manage.py和ASGI/WSGI选择不同的默认配置?
|
||||
# 5. 为什么本课暂时不配置PostgreSQL和Agents SDK?
|
||||
#
|
||||
# 验收命令:
|
||||
# python manage.py check --settings=JobRadar.settings.development
|
||||
# python manage.py check --settings=JobRadar.settings.production
|
||||
# python manage.py check --deploy --settings=JobRadar.settings.production
|
||||
# python manage.py makemigrations --check --dry-run --settings=JobRadar.settings.development
|
||||
# git diff --check
|
||||
#
|
||||
# 验收标准:
|
||||
# 1. 能解释三个配置文件各自负责什么。
|
||||
# 2. 能解释BASE_DIR层级变化。
|
||||
# 3. 能复现生产密钥缺失时的失败,并确认这是预期安全行为。
|
||||
# 4. 能区分普通系统检查错误与部署安全告警。
|
||||
# 5. practice.py保持纯注释,不在此文件填写答案或运行记录。
|
||||
@@ -1,14 +0,0 @@
|
||||
"""JobRadar生产ASGI入口的参考实现。"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
|
||||
# 部署入口默认选择生产配置,避免遗漏环境选择时启用DEBUG。
|
||||
os.environ.setdefault(
|
||||
"DJANGO_SETTINGS_MODULE",
|
||||
"JobRadar.settings.production",
|
||||
)
|
||||
|
||||
application = get_asgi_application()
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""JobRadar本地管理命令入口的参考实现。"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""默认使用开发配置执行Django管理命令。"""
|
||||
os.environ.setdefault(
|
||||
"DJANGO_SETTINGS_MODULE",
|
||||
"JobRadar.settings.development",
|
||||
)
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"无法导入Django,请确认已经激活JobRadar Conda环境。"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1 +0,0 @@
|
||||
"""JobRadar分环境配置包的参考入口。"""
|
||||
@@ -1,77 +0,0 @@
|
||||
"""JobRadar所有运行环境共享的Django配置参考。"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
# base.py比原settings.py多位于一层settings目录中,因此需要向上三级到达项目根目录。
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "JobRadar.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [BASE_DIR / "templates"],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "JobRadar.wsgi.application"
|
||||
ASGI_APPLICATION = "JobRadar.asgi.application"
|
||||
|
||||
# 第一课保留SQLite,下一阶段学习PostgreSQL时再调整数据库配置。
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
}
|
||||
}
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
LANGUAGE_CODE = "zh-hans"
|
||||
TIME_ZONE = "Asia/Shanghai"
|
||||
USE_I18N = True
|
||||
USE_TZ = True
|
||||
|
||||
STATIC_URL = "static/"
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
@@ -1,16 +0,0 @@
|
||||
"""JobRadar本地开发环境的Django配置参考。"""
|
||||
|
||||
import os
|
||||
|
||||
from .base import * # noqa: F403
|
||||
|
||||
|
||||
# 默认值只能用于本机开发,生产环境不会导入本模块。
|
||||
SECRET_KEY = os.getenv(
|
||||
"DJANGO_SECRET_KEY",
|
||||
"django-insecure-jobradar-local-development-only",
|
||||
)
|
||||
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
|
||||
@@ -1,40 +0,0 @@
|
||||
"""JobRadar公网生产环境的Django配置参考。"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
from .base import * # noqa: F403
|
||||
|
||||
|
||||
def get_required_environment_value(name: str) -> str:
|
||||
"""读取必需的生产变量,缺失或空白时立即阻止应用启动。"""
|
||||
value = os.getenv(name, "").strip()
|
||||
if not value:
|
||||
raise ImproperlyConfigured(f"缺少必需的环境变量:{name}")
|
||||
return value
|
||||
|
||||
|
||||
def get_required_environment_list(name: str) -> list[str]:
|
||||
"""读取逗号分隔的必需列表,并去除每一项两侧的空白。"""
|
||||
raw_value = get_required_environment_value(name)
|
||||
values = [item.strip() for item in raw_value.split(",") if item.strip()]
|
||||
if not values:
|
||||
raise ImproperlyConfigured(f"环境变量没有有效配置项:{name}")
|
||||
return values
|
||||
|
||||
|
||||
SECRET_KEY = get_required_environment_value("DJANGO_SECRET_KEY")
|
||||
DEBUG = False
|
||||
ALLOWED_HOSTS = get_required_environment_list("DJANGO_ALLOWED_HOSTS")
|
||||
CSRF_TRUSTED_ORIGINS = get_required_environment_list(
|
||||
"DJANGO_CSRF_TRUSTED_ORIGINS"
|
||||
)
|
||||
|
||||
# HTTPS在反向代理终止时,Django通过该请求头识别原始请求协议。
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
SECURE_SSL_REDIRECT = True
|
||||
SESSION_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
X_FRAME_OPTIONS = "DENY"
|
||||
@@ -1,14 +0,0 @@
|
||||
"""JobRadar生产WSGI入口的参考实现。"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
|
||||
# 部署入口默认选择生产配置,避免遗漏环境选择时启用DEBUG。
|
||||
os.environ.setdefault(
|
||||
"DJANGO_SETTINGS_MODULE",
|
||||
"JobRadar.settings.production",
|
||||
)
|
||||
|
||||
application = get_wsgi_application()
|
||||
+29
-74
@@ -1,64 +1,41 @@
|
||||
# JobRadar 实施路线图
|
||||
|
||||
## 推进规则
|
||||
## 推进原则
|
||||
|
||||
本路线图用于确定学习顺序,不代表一次性生成所有代码。每个阶段继续拆成若干课,每次只开始当前一课:
|
||||
项目按可运行成果分阶段实施。每个阶段由AI直接生成代码、迁移、测试和必要文档,但只实现当前阶段所需内容;完成自动验证和用户验收后,再扩大范围。
|
||||
|
||||
- 开课时先讲解原理、Agent职责和本课代码边界。
|
||||
- 提供可运行的参考代码,但由学习者手动写入项目。
|
||||
- 学习者提交实现后进行代码检查和运行验证。
|
||||
- 当前课验收通过后,才准备下一课。
|
||||
- 不提前创建后续课程的业务代码或空目录。
|
||||
- 阶段结束时安排回顾、评测和一个可展示的阶段成果。
|
||||
## 阶段一:工程基线
|
||||
|
||||
## 阶段一:Agent 工程基线
|
||||
目标:建立适合公网运行和持续开发的Django基础。
|
||||
|
||||
建议课程:
|
||||
|
||||
1. Django项目配置与开发/生产环境拆分。
|
||||
2. Django用户系统与用户数据归属。
|
||||
3. PostgreSQL迁移与Agent运行数据模型。
|
||||
4. OpenAI Agents SDK最小Agent与Runner。
|
||||
5. Agent Run、运行事件与工具调用持久化。
|
||||
|
||||
- [x] 初始化 Django 项目、Conda 环境和 Git 仓库。
|
||||
- [x] 补充项目、架构、Agent 契约和路线图文档。
|
||||
- [ ] 拆分开发、测试和生产配置,将密钥移出版本库。
|
||||
- [ ] 拆分开发、测试和生产配置。
|
||||
- [ ] 将密钥及本地配置移出版本库。
|
||||
- [ ] 接入Django用户认证和用户资料模型。
|
||||
- [ ] 为用户私有业务数据建立统一归属边界。
|
||||
- [ ] 接入PostgreSQL并建立迁移基线。
|
||||
- [ ] 接入OpenAI Agents SDK。
|
||||
- [ ] 建立Agent Run、运行事件、工具调用和人工确认模型。
|
||||
- [ ] 增加统一日志、测试和代码质量工具。
|
||||
|
||||
验收条件:开发与生产配置隔离,用户可以安全登录,PostgreSQL迁移通过,最小Agent运行数据可持久化。
|
||||
|
||||
## 阶段二:最小Agent闭环
|
||||
|
||||
建议课程:
|
||||
目标:证明系统具备真实、可观察的Agent运行循环。
|
||||
|
||||
1. Function Tool原理及第一个只读工具。
|
||||
2. Pydantic结构化输入与输出。
|
||||
3. 多工具选择和Agent运行循环。
|
||||
4. 运行预算、超时、异常与人工确认。
|
||||
5. Agent轨迹页面和最小评测集。
|
||||
|
||||
- [ ] 定义岗位研究 Agent 的 instructions、输入、输出、工具、状态和人工确认点。
|
||||
- [ ] 使用 Agents SDK 实现一个 Agent 和 Runner 入口。
|
||||
- [ ] 定义岗位研究Agent的instructions、输入、输出、工具和状态。
|
||||
- [ ] 使用Agents SDK实现Agent和Runner入口。
|
||||
- [ ] 实现候选岗位查询、规则筛选和结果保存三个最小Function Tool。
|
||||
- [ ] 设置最大轮次、超时和工具调用预算。
|
||||
- [ ] 保存工具调用、结果摘要、最终输出和trace标识。
|
||||
- [ ] 在WebUI展示一次完整运行,而不只展示最终回答。
|
||||
- [ ] 建立最小评测集,覆盖正常结果、证据不足、工具失败和禁止操作。
|
||||
|
||||
验收条件:Agent 能自主选择并调用真实工具,输出结构化结果;页面可以查看工具轨迹,评测能识别没有调用必要工具的伪结果。
|
||||
验收条件:Agent能自主调用真实工具并输出结构化结果,页面能够展示运行轨迹,评测可以识别未调用必要工具的伪结果。
|
||||
|
||||
## 阶段三:单站采集与筛选
|
||||
|
||||
建议课程:
|
||||
|
||||
1. 招聘网站适配器与工具边界。
|
||||
2. HTTPX与Playwright采集。
|
||||
3. 原始数据、标准化与幂等入库。
|
||||
4. 硬性筛选工具和Agent调用。
|
||||
5. 单站采集阶段项目。
|
||||
目标:通过真实工具稳定处理一个明确授权范围内的招聘网站。
|
||||
|
||||
- [ ] 确认首个招聘网站的服务条款和访问边界。
|
||||
- [ ] 定义站点适配器协议和原始岗位结构。
|
||||
@@ -66,42 +43,31 @@
|
||||
- [ ] 增加限流、超时、重试和失败日志。
|
||||
- [ ] 定义岗位、企业和岗位来源模型。
|
||||
- [ ] 标准化岗位名、地点、薪资、经验和学历。
|
||||
- [ ] 完成来源岗位编号去重和内容变化识别。
|
||||
- [ ] 完成岗位去重和内容变化识别。
|
||||
- [ ] 建立排除词、黑名单和硬性筛选工具。
|
||||
- [ ] 实现岗位列表、详情和个人处理状态。
|
||||
|
||||
验收条件:Agent 通过真实工具采集一个网站,所有岗位均可追溯到原始来源,确定性规则能解释淘汰原因。
|
||||
验收条件:Agent通过真实工具采集一个网站,所有岗位可追溯到原始来源,确定性规则能够解释淘汰原因。
|
||||
|
||||
## 阶段四:企业联网研究
|
||||
|
||||
建议课程:
|
||||
|
||||
1. 企业研究任务拆解和证据模型。
|
||||
2. 联网搜索工具与来源可信度。
|
||||
3. 企业主体归一化和证据冲突。
|
||||
4. 人工复核与可恢复运行。
|
||||
目标:可靠判断企业主体和企业性质,并保留证据。
|
||||
|
||||
- [ ] 确定合法、稳定的企业信息来源。
|
||||
- [ ] 建立企业别名、标准主体和证据模型。
|
||||
- [ ] 实现企业研究工具,保存来源、时间和置信度。
|
||||
- [ ] 实现多来源冲突检测和人工复核队列。
|
||||
- [ ] 保留自动判断和人工确认历史。
|
||||
- [ ] 保留自动判断与人工确认历史。
|
||||
|
||||
验收条件:Agent不会在证据不足时强行分类,企业结论包含可访问来源和查询时间。
|
||||
|
||||
## 阶段五:评分、护栏与评测
|
||||
|
||||
建议课程:
|
||||
|
||||
1. 个人画像和匹配分析契约。
|
||||
2. 确定性评分工具。
|
||||
3. Guardrail与越权防护。
|
||||
4. Agent行为评测和回归用例。
|
||||
5. Trace分析和提示词迭代。
|
||||
目标:形成可解释、可测试的岗位推荐结果。
|
||||
|
||||
- [ ] 定义个人岗位画像和技能偏好。
|
||||
- [ ] 完善 Agent 结构化输出模型和运行状态。
|
||||
- [ ] 实现匹配分析工具与确定性评分工具。
|
||||
- [ ] 完善Agent结构化输出和运行状态。
|
||||
- [ ] 实现匹配分析工具和确定性评分工具。
|
||||
- [ ] 保存维度分数、风险扣分、理由和版本。
|
||||
- [ ] 增加输入/输出guardrail和人工确认节点。
|
||||
- [ ] 建立工具选择、证据引用、拒绝越权和故障恢复评测。
|
||||
@@ -111,33 +77,22 @@
|
||||
|
||||
## 阶段六:调度、公网部署与展示
|
||||
|
||||
建议课程:
|
||||
|
||||
1. Celery异步Agent Run。
|
||||
2. 定时任务、幂等和故障恢复。
|
||||
3. Agent工作台与执行过程展示。
|
||||
4. Docker Compose和生产配置。
|
||||
5. HTTPS公网部署与最终演示。
|
||||
目标:让系统能够在公网长期、安全运行。
|
||||
|
||||
- [ ] 接入Celery、Redis和Celery Beat。
|
||||
- [ ] 实现运行幂等、指数退避、暂停和恢复。
|
||||
- [ ] 完成 Agent 任务中心与实时运行状态展示。
|
||||
- [ ] 完成Agent任务中心和实时运行状态展示。
|
||||
- [ ] 增加高分新岗位通知。
|
||||
- [ ] 增加第二个站点工具,验证扩展边界。
|
||||
- [ ] 使用Nginx/Caddy、生产级应用服务器和HTTPS部署。
|
||||
- [ ] 增加安全响应头、登录限流和数据库备份。
|
||||
- [ ] 整理演示用Agent轨迹、评测结果和架构说明。
|
||||
|
||||
验收条件:系统可以在公网安全运行,用户能同时查看岗位结果与 Agent 执行过程,站点故障不会破坏其他运行。
|
||||
验收条件:系统可以在公网安全运行,用户能同时查看岗位结果与Agent执行过程,单个站点故障不会破坏其他运行。
|
||||
|
||||
## 第一轮开发前待确认
|
||||
## 第一阶段启动前待确认
|
||||
|
||||
1. 首个招聘网站及允许使用的访问方式。
|
||||
2. 岗位、城市、薪资、经验和学历范围。
|
||||
3. 必须包含和必须排除的关键词。
|
||||
4. 企业性质、行业和公司规模偏好。
|
||||
5. 评分维度及初始权重。
|
||||
6. 企业信息数据源。
|
||||
7. OpenAI 模型、调用预算及单次运行上限。
|
||||
8. 运行频率、单次岗位数量和通知渠道。
|
||||
9. 公网域名、服务器和 HTTPS 证书管理方式。
|
||||
1. PostgreSQL运行位置和连接方式。
|
||||
2. OpenAI模型、调用预算和API Key注入方式。
|
||||
3. 公网部署平台、域名和HTTPS证书管理方式。
|
||||
4. 首个目标招聘网站及允许使用的访问方式。
|
||||
|
||||
Reference in New Issue
Block a user