Skip to content

[任务] 抽取接进一轮 #44

Closed

Description

@JunieXD

关联与状态

路线图 #2,一期。状态:进行中,@Xi1495 认领,PR #96 按审查意见修改中。认不出的日期按评论里提的 unresolved_dates 交接,已在 #96 确认。有问题直接在这里留言。

目标

把抽取接进一轮:通知有了新快照,网站会给出这所学校的学院和近期的项目做对照,抓取节点让 LLM 读通知,输出它涉及哪些项目、每个项目的各字段和证据(总体设计 §8.2)。这个任务写一轮里的 Steps.extract。

已经有的

  • 项目骨架:crawler/ 是 Python 3.14 + uv 的项目,装依赖 uv sync,跑全部检查 ./check.sh(格式、lint、Pyright 严格模式、测试)。命令见 AGENTS.md。
  • 一轮的流程:crawl/rounds.py 的 crawl_source 已经把一个来源的一轮串好:读列表 → 初筛 → 读正文和附件 → 抽取 → 交结果。四步作为 Steps 传进来,签名和交接的数据写在那里,测试的写法见 rounds_test.py。抓不成时抛 FetchError 或 StepError,流程会把原因记进抓取记录(开发约定 §2)。
  • 请求层:所有对来源网站的请求都经过 crawl/fetch.py 的 Fetcher,它管 UA、同一网站一次一个请求和间隔,不要自己用 httpx 发请求。
  • 和网站交接的类型:crawl/contract.py 由网站的接口定义生成,不手改(接口 §6)。
  • 输入:NoticePage(正文和附件的文字),以及网站给的 ExtractionContext:发布日期、学校的学院、近期的项目(编号、学院、届、类型、名称、报名时间)。
  • 要返回的:ExtractedProgram 的列表和用量。网站收到后检查证据能不能在快照里找到、置信度够不够、日期合不合理,拿不准的进审核页(§8.3、§8.4)。
  • 编号:[任务] 句子、日期和链接的编号 #43 的函数把句子、日期、链接编好号。

范围

  1. 按 [任务] 抽取的实验 #18 选定的 LLM 和提示词实现 Steps.extract:

    • 模型从学院清单里选学院、从近期的项目里认出是哪个项目(给编号,没有就新建),从编号里选日期和证据的句子;
    • 程序按编号取出原文、换算出时间值,拼成 ExtractedProgram。
    • 只给这条通知写了的部分:延期通知只写了新截止的,报名时间只给 end,不从近期项目里抄开始时间。网站按部分合并,没给的部分保持原样(§8.4)。
  2. 模型的输出按固定的结构解析,解析不了的当失败处理(开发约定 §2);通知里的文字只当要读的材料(AGENTS.md · 可靠与安全)。

  3. LLM 用 DeepSeek 官方接口的 V4.1 Flash(deepseek-flash)。[任务] 抽取的实验 #18 的比较是在硅基流动上做的,官方的 Chat Completions 不支持 json_schema,要用 Responses API(text.format 设成 json_schema),见总体设计 §8.5。key 从环境变量 LLM_API_KEY 读(补充基于编号的抽取评估和实验结果 #81 里定的);模型名、思考强度、温度和接口地址都写成常量,换模型要在标注集上重跑。

  4. 程序认不出的日期不能悄悄漏掉:模型看到原文写了截止这类时间,编号里却没有对应的日期时,照抄日期的原文、附上句子编号,这一项送审核页由人判断。这条规则写进 §8.2;怎么交给网站(契约里怎么表示),先在这里和维护者商定。

  5. 提示词按缓存命中组织:DeepSeek 的接口自动缓存请求开头相同的部分,命中的部分按缓存价计费,便宜得多(硅基流动上 V4.1 Flash 输入 2 元、命中 0.04 元每百万 token)。所以:

    • 固定不变的放最前面:规则和输出的结构;
    • 同一所学校共用的其次:院校清单里的学院、近期的项目;
    • 每条通知自己的放最后:标题、发布日期、编号后的正文;
    • 前面的部分每次都要一字不差:不放当天日期、请求编号这类每次都变的东西,结构化数据的字段顺序固定。

    这条规则写进总体设计 §8.6,以后所有调 LLM 的地方(比如试抓 [任务] 试抓:抓取节点这边 #46)都照着组织。

  6. 用固定的模型响应写测试;效果用 [任务] 抽取的实验 #18 的标注集和评估脚本重跑,结果贴在 PR 里,并写明缓存命中率(用量里的 prompt_cache_hit_tokens)和按实际命中算的费用。

建议的第一步

在本 Issue 留言认领。#18 的评估脚本在 crawler/src/crawler/extraction/,先读懂它怎么调模型、怎么还原编号。

验收标准

  • 一轮里要抽取的快照都交了抽取结果,网站那边证据找不到的比例和实验里一致
  • 标注集上的结果贴在 PR 里,报名截止的准确率不低于实验的结论,并写明缓存命中率
  • 测试用固定的响应,./check.sh 通过

Activity

  1. added
    task可以认领的具体工作
    crawler抓取节点:抓取、初筛、抽取
    on Oct 27, 2026
  2. JunieXD commented on Nov 9, 2026

    @JunieXD
    ContributorAuthor

    @Xi1495 #18 的实验和 #42 的初筛都是你做的,抽取接进一轮接着做最顺。有兴趣的话在这里留言认领,范围和第一步见正文;不方便也没关系,说一声就好。

  3. Xi1495 commented on Nov 9, 2026

    @Xi1495
    Contributor

    我来接着做 #44,按已合并的 #18 结论使用 DeepSeek 官方 deepseek-flash,通过 Responses API 的 text.format: json_schema 输出,密钥仍只从本地 LLM_API_KEY 读取,不沿用硅基流动接口。

    实现会复用现有编号与还原函数,按学院编号、近期项目编号交接,延期通知只提交原文新增的部分;提示词按固定规则与结构 → 同校学院和近期项目 → 单条通知编号正文排列,固定字段顺序。测试先使用固定响应,官方接口标注集重跑时保留失败分母、缓存命中 token 和实际用量,结果贴到 PR。

    范围第 4 项的契约想先确认:建议在每个 ExtractedProgram 上增加可选的 unresolved_dates,每项包含目标字段(如 apply.end)、模型照抄的日期文字 text 及由句子编号还原的 evidence。网站验证原文后将该项存入审核队列,原因用 unparsed_date;这一项不生成推测时间、不更新相应时间字段,原来已知的时间保持不变,其他可确定字段继续按现有规则处理。即使只是漏了活动时间或延期截止,也不能因为已有项目带着旧时间而忽略这项。

    请确认这种交接方式,或指定更合适的契约表示。我先做官方 Responses 调用与固定响应测试,契约及网站审核分支等这里商定后再实现,不会先手改生成类型。

  4. Xi1495 commented on Nov 9, 2026

    @Xi1495
    Contributor

    #96 已完成并处于待审状态。本轮按 CONTRIBUTING.md 的「自查」、PR 模板和 AGENTS.md 对照 #44 全部范围重新读了差异,补齐了数据表与审核文档,并将未识别日期结构集中到同模块 schemas,避免服务层反向依赖接口层。没有改动提示词和模型请求参数。

    • Steps.extract 已接通学院/已有项目编号选择、正文和附件编号还原、延期通知的部分更新;无效引用作为失败处理,不从项目对照里抄旧时间。
    • 未识别日期按前述 unresolved_dates 方案实现原文及证据交接,网站核对后入 unparsed_date 审核队列。旧时间保留,其他确定字段仍可更新;重复提交不重复入队,人工关闭不自动写入时间。契约及这项审核行为请在 将编号抽取接进一轮 #96 一并审查。
    • 官方 deepseek-flash 接入版的同一 50 条复验:截止正确 27/28,失败 0/50,证据未找到 0/826,输入加权缓存命中率 61.0457%,按实际命中估算 0.39222872 元,未核对账单。活动结束只有 17/24,已在 PR 明确列为限制,不能据截止指标认为全部字段可靠。
    • Python 全部检查及 211 项离线测试、Node 26 的完整检查及 99 项真实 PostgreSQL 测试通过,远端 crawler/web CI 均通过;桌面及手机审核截图为自编数据,已附在 PR。

    正文、原始响应、密钥、测试会话和临时材料均未提交。本轮自查未新增模型或高校网站请求。#45 的入口组装和部署不混入本 PR;本 Issue 待维护者确认契约并验收后关闭。

  5. added a commit that references this issue on Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

crawler抓取节点:抓取、初筛、抽取task可以认领的具体工作

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions