diff --git a/README.md b/README.md index 8bdbbe2..3180c89 100644 --- a/README.md +++ b/README.md @@ -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直接实现阶段一工程基线。 diff --git a/docs/development-guide.md b/docs/development-guide.md new file mode 100644 index 0000000..3e9c6a9 --- /dev/null +++ b/docs/development-guide.md @@ -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或网站授权。 +- 当前工作区是否已提交、是否推送。 + +## 用户确认边界 + +以下事项仍需用户明确决定: + +- 目标招聘网站和允许的访问方式。 +- 外部付费服务、模型及调用预算。 +- 公网域名、服务器和部署平台。 +- 可能产生费用或对外副作用的操作。 +- 自动投递、自动联系、删除历史数据等高风险能力。 diff --git a/docs/learning-guide.md b/docs/learning-guide.md deleted file mode 100644 index 21bcd21..0000000 --- a/docs/learning-guide.md +++ /dev/null @@ -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)已经创建。当前应阅读讲义、参考完整示例,然后手动拆分项目配置;完成后执行课程验收命令并提交代码供检查。 diff --git a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/README.md b/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/README.md deleted file mode 100644 index 4e57776..0000000 --- a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/README.md +++ /dev/null @@ -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用户系统与用户数据归属”。 diff --git a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/practice.py b/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/practice.py deleted file mode 100644 index 2fa0c73..0000000 --- a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/practice.py +++ /dev/null @@ -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保持纯注释,不在此文件填写答案或运行记录。 diff --git a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/asgi.py b/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/asgi.py deleted file mode 100644 index c8c2762..0000000 --- a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/asgi.py +++ /dev/null @@ -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() diff --git a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/manage.py b/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/manage.py deleted file mode 100644 index 7bc6743..0000000 --- a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/manage.py +++ /dev/null @@ -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() diff --git a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/__init__.py b/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/__init__.py deleted file mode 100644 index 61e4e1f..0000000 --- a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""JobRadar分环境配置包的参考入口。""" diff --git a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/base.py b/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/base.py deleted file mode 100644 index bfdb8a4..0000000 --- a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/base.py +++ /dev/null @@ -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" diff --git a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/development.py b/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/development.py deleted file mode 100644 index bb81c81..0000000 --- a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/development.py +++ /dev/null @@ -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"] diff --git a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/production.py b/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/production.py deleted file mode 100644 index 80c50b4..0000000 --- a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/settings/production.py +++ /dev/null @@ -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" diff --git a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/wsgi.py b/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/wsgi.py deleted file mode 100644 index bdd6664..0000000 --- a/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分/reference/wsgi.py +++ /dev/null @@ -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() diff --git a/docs/roadmap.md b/docs/roadmap.md index d31a860..d2d2f7e 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -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、运行事件、工具调用和人工确认模型。 +- [ ] 拆分开发、测试和生产配置。 +- [ ] 将密钥及本地配置移出版本库。 +- [ ] 接入Django用户认证和用户资料模型。 +- [ ] 为用户私有业务数据建立统一归属边界。 +- [ ] 接入PostgreSQL并建立迁移基线。 +- [ ] 接入OpenAI Agents SDK。 +- [ ] 建立Agent Run、运行事件、工具调用和人工确认模型。 - [ ] 增加统一日志、测试和代码质量工具。 -## 阶段二:最小 Agent 闭环 +验收条件:开发与生产配置隔离,用户可以安全登录,PostgreSQL迁移通过,最小Agent运行数据可持久化。 -建议课程: +## 阶段二:最小Agent闭环 -1. Function Tool原理及第一个只读工具。 -2. Pydantic结构化输入与输出。 -3. 多工具选择和Agent运行循环。 -4. 运行预算、超时、异常与人工确认。 -5. Agent轨迹页面和最小评测集。 +目标:证明系统具备真实、可观察的Agent运行循环。 -- [ ] 定义岗位研究 Agent 的 instructions、输入、输出、工具、状态和人工确认点。 -- [ ] 使用 Agents SDK 实现一个 Agent 和 Runner 入口。 -- [ ] 实现候选岗位查询、规则筛选和结果保存三个最小 Function Tool。 +- [ ] 定义岗位研究Agent的instructions、输入、输出、工具和状态。 +- [ ] 使用Agents SDK实现Agent和Runner入口。 +- [ ] 实现候选岗位查询、规则筛选和结果保存三个最小Function Tool。 - [ ] 设置最大轮次、超时和工具调用预算。 -- [ ] 保存工具调用、结果摘要、最终输出和 trace 标识。 -- [ ] 在 WebUI 展示一次完整运行,而不只展示最终回答。 +- [ ] 保存工具调用、结果摘要、最终输出和trace标识。 +- [ ] 在WebUI展示一次完整运行,而不只展示最终回答。 - [ ] 建立最小评测集,覆盖正常结果、证据不足、工具失败和禁止操作。 -验收条件:Agent 能自主选择并调用真实工具,输出结构化结果;页面可以查看工具轨迹,评测能识别没有调用必要工具的伪结果。 +验收条件:Agent能自主调用真实工具并输出结构化结果,页面能够展示运行轨迹,评测可以识别未调用必要工具的伪结果。 ## 阶段三:单站采集与筛选 -建议课程: - -1. 招聘网站适配器与工具边界。 -2. HTTPX与Playwright采集。 -3. 原始数据、标准化与幂等入库。 -4. 硬性筛选工具和Agent调用。 -5. 单站采集阶段项目。 +目标:通过真实工具稳定处理一个明确授权范围内的招聘网站。 - [ ] 确认首个招聘网站的服务条款和访问边界。 - [ ] 定义站点适配器协议和原始岗位结构。 @@ -66,78 +43,56 @@ - [ ] 增加限流、超时、重试和失败日志。 - [ ] 定义岗位、企业和岗位来源模型。 - [ ] 标准化岗位名、地点、薪资、经验和学历。 -- [ ] 完成来源岗位编号去重和内容变化识别。 +- [ ] 完成岗位去重和内容变化识别。 - [ ] 建立排除词、黑名单和硬性筛选工具。 - [ ] 实现岗位列表、详情和个人处理状态。 -验收条件:Agent 通过真实工具采集一个网站,所有岗位均可追溯到原始来源,确定性规则能解释淘汰原因。 +验收条件:Agent通过真实工具采集一个网站,所有岗位可追溯到原始来源,确定性规则能够解释淘汰原因。 ## 阶段四:企业联网研究 -建议课程: - -1. 企业研究任务拆解和证据模型。 -2. 联网搜索工具与来源可信度。 -3. 企业主体归一化和证据冲突。 -4. 人工复核与可恢复运行。 +目标:可靠判断企业主体和企业性质,并保留证据。 - [ ] 确定合法、稳定的企业信息来源。 - [ ] 建立企业别名、标准主体和证据模型。 - [ ] 实现企业研究工具,保存来源、时间和置信度。 - [ ] 实现多来源冲突检测和人工复核队列。 -- [ ] 保留自动判断和人工确认历史。 +- [ ] 保留自动判断与人工确认历史。 -验收条件:Agent 不会在证据不足时强行分类,企业结论包含可访问来源和查询时间。 +验收条件:Agent不会在证据不足时强行分类,企业结论包含可访问来源和查询时间。 ## 阶段五:评分、护栏与评测 -建议课程: - -1. 个人画像和匹配分析契约。 -2. 确定性评分工具。 -3. Guardrail与越权防护。 -4. Agent行为评测和回归用例。 -5. Trace分析和提示词迭代。 +目标:形成可解释、可测试的岗位推荐结果。 - [ ] 定义个人岗位画像和技能偏好。 -- [ ] 完善 Agent 结构化输出模型和运行状态。 -- [ ] 实现匹配分析工具与确定性评分工具。 +- [ ] 完善Agent结构化输出和运行状态。 +- [ ] 实现匹配分析工具和确定性评分工具。 - [ ] 保存维度分数、风险扣分、理由和版本。 -- [ ] 增加输入/输出 guardrail 和人工确认节点。 +- [ ] 增加输入/输出guardrail和人工确认节点。 - [ ] 建立工具选择、证据引用、拒绝越权和故障恢复评测。 -- [ ] 使用 trace 分析失败运行并形成回归用例。 +- [ ] 使用trace分析失败运行并形成回归用例。 -验收条件:每个总分都能分解到权重和证据;Agent 必须调用必要工具,不得编造外部事实或越过硬规则。 +验收条件:每个总分都能分解到权重和证据;Agent必须调用必要工具,不得编造外部事实或越过硬规则。 ## 阶段六:调度、公网部署与展示 -建议课程: +目标:让系统能够在公网长期、安全运行。 -1. Celery异步Agent Run。 -2. 定时任务、幂等和故障恢复。 -3. Agent工作台与执行过程展示。 -4. Docker Compose和生产配置。 -5. HTTPS公网部署与最终演示。 - -- [ ] 接入 Celery、Redis 和 Celery Beat。 +- [ ] 接入Celery、Redis和Celery Beat。 - [ ] 实现运行幂等、指数退避、暂停和恢复。 -- [ ] 完成 Agent 任务中心与实时运行状态展示。 +- [ ] 完成Agent任务中心和实时运行状态展示。 - [ ] 增加高分新岗位通知。 - [ ] 增加第二个站点工具,验证扩展边界。 -- [ ] 使用 Nginx/Caddy、生产级应用服务器和 HTTPS 部署。 +- [ ] 使用Nginx/Caddy、生产级应用服务器和HTTPS部署。 - [ ] 增加安全响应头、登录限流和数据库备份。 -- [ ] 整理演示用 Agent 轨迹、评测结果和架构说明。 +- [ ] 整理演示用Agent轨迹、评测结果和架构说明。 -验收条件:系统可以在公网安全运行,用户能同时查看岗位结果与 Agent 执行过程,站点故障不会破坏其他运行。 +验收条件:系统可以在公网安全运行,用户能同时查看岗位结果与Agent执行过程,单个站点故障不会破坏其他运行。 -## 第一轮开发前待确认 +## 第一阶段启动前待确认 -1. 首个招聘网站及允许使用的访问方式。 -2. 岗位、城市、薪资、经验和学历范围。 -3. 必须包含和必须排除的关键词。 -4. 企业性质、行业和公司规模偏好。 -5. 评分维度及初始权重。 -6. 企业信息数据源。 -7. OpenAI 模型、调用预算及单次运行上限。 -8. 运行频率、单次岗位数量和通知渠道。 -9. 公网域名、服务器和 HTTPS 证书管理方式。 +1. PostgreSQL运行位置和连接方式。 +2. OpenAI模型、调用预算和API Key注入方式。 +3. 公网部署平台、域名和HTTPS证书管理方式。 +4. 首个目标招聘网站及允许使用的访问方式。