跳到正文
终章 · AI 与科研

实测 · 三个学术 Skill 跑一遍真科研

CPS1985 工资回归,端到端走完,看 Skill 到底靠不靠谱

终章说过一句最重要的话:评价 AI 的科研能力,不能只看 idea 多漂亮,要看执行。这一章就把终章介绍的那套学术 Skill 包拉出来,真刀真枪跑一遍——下载真实数据、做真实回归、出图、生成 Word 和 PPT,全程不许 AI"自己写段代码假装是 skill 在干活"。跑完你就知道,这些 Skill 到底是"按一下出论文"的魔法,还是"一位严谨导师的工作清单 + 一箱趁手的脚本"。

一、想让模型干什么#

任务定得很具体:用这三个 Skill 协作,独立完成一个完整的小型实证研究。题目选了劳动经济学里最经典的 Mincer 工资方程——说人话就是回答一个问题:

多读一年书,时薪到底涨百分之几?

围绕这个问题,要求模型走完一条真实科研的全链路:找一个公开的小数据集 → 估计受教育回报 → 出版级配图 → 生成一份可交付的 Word 报告和一套答辩 PPT。三个 Skill 各管一段:

Skill这次负责什么实际触发的子模块
scientific-toolkit-skill跑数据:EDA、回归、出图、机器学习、查文献eda · statistical-analysis · scientific-visualization · scikit-learn · citation-management
research-writing-skill写正文:中文优先、证据分级、不编造Writing Principles · Section Guides
office-academic-skill出交付物:可编辑 Word / PPT + 交付前质检report-structure · slide-quality · Quality Gate

为了避免"自己重写一遍代码、假装是 skill 干的",这次定了三条硬规矩:

项目长这样

所有产物都写进一个独立的 skill-eval/ 子目录,不碰仓库里其它东西:

skill-eval/
├── data/         # 原始数据集(CPS1985.csv)
├── analysis/     # 分析脚本 + 中间结果(回归、分类、质检)
├── figures/      # 出版级配图(png + svg,300 DPI)
├── deliverables/ # 最终 Word / PPT 交付物
├── papers/       # 文献与 BibTeX
└── logs/         # 检索原始返回

一句话:左边是输入(数据、文献),中间是脚本(调用 skill),右边是产物(图、Word、PPT)。

二、运行了什么、喂了哪些提示词#

环境先探一遍,确认依赖齐全:Python 3.13.11,科学栈 pandas 2.3.3 / numpy 2.2.6 / matplotlib 3.9.2 / scikit-learn 1.8.0 / statsmodels 0.14.6,Office 栈 python-docx 1.2.0 / python-pptx 1.0.2。三个 skill 要用的运行环境都满足。

数据靠 Tavily 选、靠 curl 下(遵守本机全局规则:不用原生 WebSearch,搜索统一走 Tavily)。喂给 Tavily 的提示词:

open source small economics labor wage dataset CSV download CPS1985 Rdatasets

Tavily 确认 CPS 1985(Determinants of Wages,AER/Rdatasets)是公认的小型开源劳动经济学数据集,于是下载:

curl -sSL --retry 2 -o CPS1985.csv \
  "https://raw.githubusercontent.com/vincentarelbundock/Rdatasets/master/csv/AER/CPS1985.csv"

拿到 534 行 × 12 列(wage、education、experience、age、gender、union、married、ethnicity、occupation、sector、region)。体量小,正合适。

这里要澄清一个关键点:真正"喂给模型"的提示词,其实就是这几个 Skill 的 description 和规则文件本身——它们既决定 Skill 何时出场,也决定它干活的纪律。下面是这次实际生效的几段核心提示词:

【A · office-academic 的报告结构提示词,驱动 DOCX 标题与证据标签】
文献信息 / 一页式摘要 / 研究背景与问题 / 方法与模型 /
实验·仿真·数据设置 / 结果与图表解读 / 创新点与贡献 /
局限性与边界条件 / 可复现要点 / 汇报讲稿要点 / 原文依据索引表
证据标签:来源: / 推断: / 建议:

【B · office-academic 的幻灯片质量提示词,驱动 PPT 标题写法】
每页一个核心观点;用"行动标题"陈述结论而非话题标签;
图表承载技术论证;保持坐标轴/单位/图例科学准确;
避免文字溢出 / 图片拉伸 / 中文乱码 / 残留占位符。

【C · research-writing 的写作原则提示词,驱动正文风格】
默认中文;保留英文标题/公式/变量/方法名/软件命令/参考文献;
不编造数据/DOI/期刊/实验值;
区分 原文·已有数据 / 用户确认 / 推断 / 建议;
用可测量条件替换"显著/先进/有效"等模糊词。

注意 B 和 C 的味道:它们不是"写得漂亮点"这种空话,而是一串可执行的约束——这正是终章说的"用提示词做纪律"。

三、触发了哪些 Skill、结果如何#

九项测试逐个跑下来,全部端到端通过(过程中暴露 4 处真实摩擦,留到第四节如实交代):

#Skill / 子模块测了什么结果
T1exploratory-data-analysiseda_analyzer.py 跑 EDA 报告✅ 零改动跑通
T2statistical-analysis + statsmodelsMincer OLS + VIF + 残差正态检验✅ 通过(1 处签名修正)
T3scientific-visualizationstyle_presets 出 3 张出版级图✅ 通过
T4scikit-learn用内置 classification_pipeline 做分类✅ 通过
T5citation-managementDOI→BibTeX(CrossRef)✅ 通过(1 DOI 失效有报错 + 1 编码 bug)
T6–T8office-academic生成 DOCX / PPTX + 质量门禁回读✅ 通过(门禁抓出真实溢出)
T9research-writing中文优先、证据分级的报告正文✅ 通过

下面挑最硬的几项,把代码、命令、运行结果原样摆出来。

核心:Mincer 工资回归

这是整个分析的心脏,回答开头那个问题。脚本 analysis/mincer_regression.py 直接 import 了 skill 自带的两个模块(出图样式 + 假设检验),再用 statsmodels 跑一个带稳健标准误的 OLS:

import statsmodels.formula.api as smf
from statsmodels.stats.outliers_influence import variance_inflation_factor

# 关键一步:把 skill 自己的脚本目录加进路径,import 它本身(而不是重写)
sys.path.insert(0, str(SK / "scientific-visualization" / "scripts"))
sys.path.insert(0, str(SK / "statistical-analysis" / "scripts"))
import style_presets          # 来自 scientific-visualization
import assumption_checks      # 来自 statistical-analysis

# 数据准备:Mincer 方程用 log 工资 + 工龄二次项
df["lwage"]  = np.log(df["wage"])
df["exper2"] = df["experience"] ** 2 / 100

# Mincer OLS,HC3 异方差稳健标准误
formula = ("lwage ~ education + experience + exper2 + C(gender) "
           "+ C(union) + C(married) + C(ethnicity)")
model = smf.ols(formula, data=df).fit(cov_type="HC3")
print(model.summary())

# 多重共线性(VIF)
Xnum = df[["education", "experience", "exper2"]].assign(const=1.0)
vif = {c: round(float(variance_inflation_factor(Xnum.values, i)), 2)
       for i, c in enumerate(Xnum.columns) if c != "const"}

# 残差正态性——调用 skill 自己的模块来检验
resid = model.resid
norm = assumption_checks.check_normality(
    resid.values, name="OLS residuals", alpha=0.05, plot=False)

运行命令(MPLBACKEND=Agg 是为了无界面环境不弹窗卡住):

MPLBACKEND=Agg python analysis/mincer_regression.py

真实运行输出(statsmodels 的回归摘要,原样粘贴):

                            OLS Regression Results
==============================================================================
Dep. Variable:                  lwage   R-squared:                       0.325
Model:                            OLS   Adj. R-squared:                  0.315
Method:                 Least Squares   F-statistic:                     29.34
No. Observations:                 534   Prob (F-statistic):           6.93e-38
Df Residuals:                     525   Covariance Type:                  HC3
============================================================================================
                               coef    std err          z      P>|z|      [0.025      0.975]
--------------------------------------------------------------------------------------------
Intercept                    0.3851      0.130      2.957      0.003       0.130       0.640
C(gender)[T.male]            0.2316      0.040      5.860      0.000       0.154       0.309
C(union)[T.yes]              0.2091      0.047      4.470      0.000       0.117       0.301
C(married)[T.yes]            0.0362      0.042      0.864      0.387      -0.046       0.118
C(ethnicity)[T.hispanic]    -0.0800      0.090     -0.884      0.376      -0.257       0.097
C(ethnicity)[T.other]       -0.1224      0.055     -2.234      0.025      -0.230      -0.015
education                    0.0887      0.008     10.505      0.000       0.072       0.105
experience                   0.0331      0.006      5.356      0.000       0.021       0.045
exper2                      -0.0504      0.013     -3.754      0.000      -0.077      -0.024
==============================================================================

把关键数字翻成人话:

指标怎么读
样本量 n534
R² / 调整 R²0.325 / 0.315这些变量解释了约 32% 的工资差异
受教育回报8.87 %/年(p ≈ 8e-26)每多读一年书,时薪平均高约 8.9%
男性工资溢价+0.232 对数点(≈26%)同等条件下男性更高
工会工资溢价+0.209 对数点入会者更高
工龄二次项−0.050(显著)工龄收益先升后降,呈凹形
残差正态(Shapiro,skill 模块)W=0.986, p≈5e-5残差非正态,已如实写进局限

最关键的一行:受教育回报 8.87%/年,正落在权威文献(Card、Heckman 等)给出的 5–10%/年经验区间内——结果可信,不是瞎算。

三张出版级配图

出图脚本 analysis/make_figures.py 直接套用 skill 的出版样式和色盲安全调色板

import style_presets
style_presets.apply_publication_style("default")
style_presets.set_color_palette("okabe_ito")   # 8 色,色盲友好

跑出三张图(每张同时存 png + svg,300 DPI),分别对应回归里三个最重要的结论:

工资随教育年限上升,性别差距持续存在:按性别分组的散点与拟合线

图 1 把"受教育回报"画了出来:两条拟合线都向上,且男性(蓝)整体高于女性(黄)——对应回归里的 education 系数和 gender 溢价。

工龄-收入凹形剖面:log 工资对潜在工龄的二次拟合

图 2 是 Mincer 方程的招牌形状——凹形:工龄早期收益快,后期变平甚至下降,对应回归里显著为负的 exper2 二次项。

工会工资溢价:入会与非入会者时薪的箱线图对比

图 3 把工会溢价可视化:入会一组(右)的中位数和均值都更高,对应回归里 +0.209 的 union 系数。

顺手做了个分类(scikit-learn)

为了测 scikit-learn 子技能,又让它的内置管线做了个二分类:预测某人时薪是否高于中位数。脚本只是把数据喂给 skill 的 train_and_evaluate_model,预处理、三模型五折交叉验证、网格调参、评估全由管线自动完成:

import classification_pipeline as cp   # skill 自己的管线
y = (df["wage"] > df["wage"].median()).astype(int)   # 1 = 高于中位数
res = cp.train_and_evaluate_model(
    X, y, numeric_features=numeric, categorical_features=categorical,
    test_size=0.25, random_state=42)

运行结果(管线自动选出最优模型为逻辑回归):

Random Forest       : 0.7025 (+/- 0.0843)
Gradient Boosting   : 0.7175 (+/- 0.1091)
Best model: Logistic Regression  (Best CV score: 0.7350)
Best parameters: {'classifier__C': 0.1, 'classifier__penalty': 'l2'}
Test: Accuracy=0.627  F1=0.626  ROC AUC=0.699

整套管线零改动跑通。准确率 0.627 不算高——这恰恰诚实:单看人口学特征预测个体工资本就难,结果没被粉饰。

把结果变成 Word 和 PPT,再回读质检

最后由 office-academic-skill 把分析变成交付物:一份 DOCX 报告(401 KB,内嵌 3 张图、2 张表、7 处 来源: 证据标签,中文微软雅黑 + 英文 Times New Roman)和一套 8 页 16:9 答辩 PPT(每页一个观点、行动标题陈述结论、配演讲者备注)。

真正体现工程严谨的是最后一步——Quality Gate(质量门禁):它把生成好的文件重新解包回读,不信任生成过程,专查缺文、乱码、图片溢出、残留占位符。第一次跑就抓出真问题:

slides overflowing bounds : [3, 4]

第 3、4 页的图按 8.5 英寸插入后高度超出了画布下边界——这正是 skill 文档里点名要防的"图片溢出"。把这两页图宽改窄后重新生成,复检全绿

slide count               : 8
slides overflowing bounds : none
slides missing notes      : none
embedded media (images)   : 3
stale 'Click to add' text : False
'{{' template leftover    : False

DOCX 复检同样干净:31 段正文、2 表、3 图、CJK 正常、mojibake 嫌疑 0 处、关键数字 8.87 确实出现在正文里。

四、四处真实摩擦(实测,不是宣传)#

跑通不等于完美。如实记下过程中撞到的 4 个坑:

  1. 网络会抽风。 下载数据第一次 curlRecv failure: Connection was reset,重试第 2 次才成功。检索和下载都遇到过连接 reset,得靠 --retry
  2. 脚本有真实小 bug。 引文工具 doi_to_bibtex.py 把 CrossRef 返回的 en-dash 写成了乱码 1801–1863(响应未显式设编码导致双重编码)。生产前需要清洗。
  3. reference 文档不给函数签名。 调用 check_normality 时按直觉传 test= 参数直接报 TypeError,读源码才知道真实签名是 check_normality(data, name=, alpha=, plot=),而且 plot 默认 True,无界面环境会 plt.show() 卡住,必须显式 plot=False
  4. PPT 图片溢出(见上一节)——好在被 Quality Gate 自己逮住了。

还有一处值得表扬的"优雅失败":验证 DOI 时 10.1257/jep.20.4.69 失效,脚本明确报 Error: DOI not found 并给出 Converted 1/2 DOIs (50.0%)不静默吞错

五、结论:魔法,还是工作清单?#

把九项测试、四处摩擦放一起,结论很清楚:

站得住的地方 ✅

  • 三技能协作链路真能端到端跑通:分析 → 写正文 → 出 Word/PPT 完整走了一遍,交付 1 份 DOCX + 1 份 PPT。
  • 内置脚本是真资产不是摆设:EDA、假设检验、出版样式、ML 管线、DOI→BibTeX 五个模块全部被实际调用并产出正确结果,多数零改动。
  • "证据分级 + 不编造"落地有效:受教育回报 8.87%/年与权威文献吻合,所有定量主张都挂了 来源: 标签。
  • Quality Gate 名副其实:它真的抓出了一个 PPT 溢出缺陷并驱动修复。

打折扣的地方 ⚠️

  • reference 是"概念性指南"不是"API 文档",调内置脚本前最好先 Read 一眼源码确认签名。
  • 脚本存在真实小 bug(en-dash 编码),headless 默认值也不友好。
  • Office 产物本质是标准 python-docx/pptx 生成,价值在"结构模板 + 证据标签 + 质量门禁"这套方法论,而非独家引擎。

这恰好回应了终章那盆冷水——"理念惊艳、执行褪色"。这次执行之所以没有褪色,是因为全程都有终章强调的那几样东西兜底:真实数据、可溯源的证据分级、以及交付前那道把关的 Quality Gate。说到底,让 AI 科研靠谱的从来不是某段惊艳的提示词,而是有没有验证机制