Skip to content

Commit 9823906

Browse files
authored
feat: add agent calibration and content quality workflow
Add blinded calibration sampling, independent reviewer prompts, OpenAI-compatible review execution, consensus and disagreement analysis, resume identity validation, public copy linting, and cross-platform CI coverage.
1 parent d60b7c3 commit 9823906

34 files changed

Lines changed: 3957 additions & 128 deletions

.github/workflows/ci.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ jobs:
1010
test:
1111
name: Public release checks (${{ matrix.os }})
1212
runs-on: ${{ matrix.os }}
13+
env:
14+
PYTHONUTF8: "1"
1315
strategy:
1416
fail-fast: false
1517
matrix:
@@ -59,9 +61,43 @@ jobs:
5961
- name: Ruff - Tests
6062
run: ruff check tests
6163

64+
- name: Ruff - Full tree
65+
run: ruff check demo/src demo/tests pipeline tools tests
66+
67+
- name: Public copy P1 gate
68+
run: >-
69+
python tools/lint_public_copy.py --root . --quality-gate P1
70+
--format json --output "${{ runner.temp }}/public_copy_report.json"
71+
6272
- name: Test suite
6373
run: python -m pytest demo/tests tests -q
6474

75+
- name: Calibration pipeline smoke (mock, temp dir)
76+
shell: bash
77+
run: |
78+
python tools/calibration/build_calibration_sample.py --config config/calibration/calibration.yaml
79+
python tools/calibration/run_agent_reviews.py --provider mock \
80+
--input data/calibration/calibration_sample.csv --max-items 30 \
81+
--output "$RUNNER_TEMP/cal_reviews"
82+
python tools/calibration/build_agent_consensus.py \
83+
--input-dir "$RUNNER_TEMP/cal_reviews" --output-dir "$RUNNER_TEMP/cal_consensus"
84+
python tools/calibration/analyze_disagreements.py \
85+
--input "$RUNNER_TEMP/cal_consensus/consensus_reference.csv" \
86+
--output "$RUNNER_TEMP/cal_consensus/disagreement_report.md" \
87+
--codebook-output "$RUNNER_TEMP/cal_consensus/codebook_revision_proposals.md"
88+
89+
- name: Verify calibration outputs and public safety
90+
shell: bash
91+
env:
92+
RUN_REPORT: ${{ runner.temp }}/cal_reviews/run_report.json
93+
CONS_REPORT: ${{ runner.temp }}/cal_consensus/calibration_report.json
94+
run: |
95+
python tools/calibration/verify_mock_outputs.py \
96+
--run-report "$RUN_REPORT" \
97+
--consensus-report "$CONS_REPORT" \
98+
--public-sample data/calibration/calibration_sample.csv
99+
git diff --quiet -- data/public docs/files
100+
65101
- name: Normalize public data smoke
66102
run: python tools/normalize_public_dataset.py --source-dir data/public --output-dir artifacts/normalized_public
67103

.github/workflows/pages.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ jobs:
3333
run: |
3434
python -m compileall demo/src pipeline tools tests demo/tests
3535
ruff check demo/src demo/tests pipeline tools tests
36+
python tools/lint_public_copy.py --root . --quality-gate P1 --format json
3637
python -m pytest demo/tests tests -q
3738
python tools/normalize_public_dataset.py --source-dir data/public --output-dir artifacts/normalized_public
3839
python tools/summarize_public_analysis.py --public-dir data/public --output artifacts/public_analysis_summary.json

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,16 @@ __pycache__/
1111

1212
# 环境与凭据(严禁提交)
1313
.env
14+
.env*
1415
*.env
1516
*cookie*.txt
1617
*cookies*.txt
1718
*.key
19+
local_secrets/
20+
21+
# 自动校准私有映射与原始模型响应(严禁提交)
22+
artifacts/calibration/private_*
23+
artifacts/calibration/raw_model_responses/
1824

1925
# 编辑器 / 系统
2026
.DS_Store

README.md

Lines changed: 32 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,68 @@
11
# PsyLens
22

3-
PsyLens 是一套社区反馈分析与可靠性评测工作流。当前案例围绕《英雄联盟》海克斯大乱斗社区讨论展开,将多平台公开反馈整理为样本与证据单元,再从具体话题、体验机制和数据可靠性三个层面分析
3+
PsyLens 把分散的玩家反馈整理成可核查的产品线索,并对整条分析链路做可靠性评测。当前案例围绕《英雄联盟》海克斯大乱斗的社区讨论
44

55
- **在线页面**https://sherlock0717.github.io/PsyLens/
66
- **完整项目说明**[`docs/files/PsyLens_project_brief.docx`](docs/files/PsyLens_project_brief.docx)
77
- **公开数据**[`data/public/`](data/public/)
88
- **离线 Demo**[`demo/`](demo/)
99

10-
## 当前案例
10+
## 当前案例与主要结果
1111

12-
| 项目 | 结果 |
13-
| --- | --- |
14-
| 数据来源 | NGA、贴吧、B 站公开讨论 |
15-
| 样本设计 | 三个平台各 120 条,共 360 条 |
16-
| 证据单元 | 927 条,平均每条样本 2.575 条 |
17-
| 文本回溯 | 927 条证据均能在对应公开样本中定位 |
18-
| 结构问题 | 孤立证据 0,平台错配 0,重复文本组 0 |
19-
| 日期覆盖 | 120 条有日期,240 条日期为空 |
12+
案例整合 NGA、贴吧、B 站三个平台的公开讨论。每个平台等额保留 120 条样本,共 360 条。样本再切分为 927 条证据单元,平均每条样本约 2.58 条证据,全部能在对应公开样本中逐字定位。
2013

21-
## 主要分析结果
14+
**证据单元**:从一条完整反馈中切出的、可以单独判断问题类型的短片段。
2215

23-
### 具体话题
16+
主要分布以 441 条可明确分类的证据为分母:
2417

25-
排除 `other_uncertain` 后,共有 441 条证据能够分配具体话题:
18+
- 具体话题最集中在平衡与数值:270 条,占 61.2%;其次是匹配与对局分配:82 条,占 18.6%。
19+
- 体验机制最集中在胜任受挫:308 条,占 69.8%;其次是公平受损:88 条,占 20.0%。
20+
- 数量较高的交叉组合是平衡与数值 × 胜任受挫,共 138 条。
2621

27-
- 平衡与数值:270 条,占 61.2%;
28-
- 匹配与对局分配:82 条,占 18.6%;
29-
- 活动与玩法设计:24 条,占 5.4%;
30-
- 成长与养成:20 条,占 4.5%;
31-
- 社区冲突与氛围:18 条,占 4.1%。
22+
**体验机制**:玩家在表达中呈现的主要体验方向,例如觉得难以发挥、觉得规则不公平,或觉得官方说明不清楚。
3223

33-
### 体验机制
34-
35-
排除 `uncertain` 后,共有 441 条证据能够分配主要体验机制:
36-
37-
- 胜任受挫:308 条,占 69.8%;
38-
- 公平受损:88 条,占 20.0%;
39-
- 信任与沟通落差:24 条,占 5.4%;
40-
- 归属感下降:11 条,占 2.5%;
41-
- 规范与安全风险:10 条,占 2.3%。
42-
43-
### 话题与机制交叉
44-
45-
数量较高的具体组合包括:
24+
完整分布由 [`tools/summarize_public_analysis.py`](tools/summarize_public_analysis.py) 从公开数据计算,页面读取 [`docs/assets/data/analysis_summary.json`](docs/assets/data/analysis_summary.json) 展示。
4625

47-
- 平衡与数值 × 胜任受挫:138 条;
48-
- 平衡与数值 × 公平受损:35 条;
49-
- 匹配与对局分配 × 胜任受挫:22 条;
50-
- 匹配与对局分配 × 公平受损:16 条;
51-
- 沟通与透明度 × 信任与沟通落差:13 条。
26+
## 分析方法
5227

53-
完整分布由 [`tools/summarize_public_analysis.py`](tools/summarize_public_analysis.py) 从公开数据计算,页面读取 [`docs/assets/data/analysis_summary.json`](docs/assets/data/analysis_summary.json) 展示
28+
项目采用双层编码。表层话题记录反馈在谈什么,体验机制记录文本呈现的心理体验方向。两层分开记录,使产品问题、心理机制和证据来源可以分别核对
5429

55-
## 心理学分析框架
30+
编码顺序是先判断证据是否能独立成立,再分别标注话题与机制。当文本过短、依赖上下文或同时指向多个方向时,标签保留为 uncertain,避免牵强归类。
5631

57-
项目采用双层编码:
32+
## 心理学思路
5833

59-
1. **表层话题**记录反馈正在讨论的问题;
60-
2. **体验机制**记录文本呈现的心理体验方向。
34+
机制层参考胜任需要、公平判断、组织信任、社群归属与规范安全五个方向的研究,并把这些方向转化为可观察的文本判据。体验类型、操作性定义和参考文献见 [`docs/methodology/PSYCHOLOGY_FRAMEWORK.md`](docs/methodology/PSYCHOLOGY_FRAMEWORK.md)
6135

62-
机制层参考胜任需要、公平判断、组织信任、社群归属与规范安全研究,并通过固定纳入、排除和相邻标签区分规则转化为文本编码。详细构念、操作性定义和参考文献见 [`docs/methodology/PSYCHOLOGY_FRAMEWORK.md`](docs/methodology/PSYCHOLOGY_FRAMEWORK.md)
36+
交叉组合用于提出可验证的产品问题,再由问卷、访谈、行为日志或实验继续检验
6337

64-
## 数据处理流程
38+
## 数据处理
6539

66-
```text
67-
候选讨论登记
68-
→ 页面与回复采集
69-
→ 原始缓存
70-
→ 规则预清洗
71-
→ 内容筛选与字段规整
72-
→ 平台等额抽样
73-
→ 公开脱敏
74-
→ 证据单元切分
75-
→ 话题与机制编码
76-
→ 完整性与分布审计
77-
```
40+
处理流程从候选讨论登记开始,依次经过采集、规则预清洗、内容筛选、平台等额抽样、公开脱敏、证据切分与双层编码,最后做完整性与分布审计。
7841

79-
关键操作包括:删除回复头、引用残留、图片路径和多余空白;移除空文本与低信息噪声;删除来源链接和账号定位字段按标点切分证据;检查证据文本是否能在父样本中逐字定位;扫描重复、空值、URL 和非法标签
42+
关键操作包括删除回复头与引用残留、移除低信息文本、删除来源链接和账号定位字段按标点切分证据,并检查每条证据能否在父样本中逐字定位。字段、清洗规则和复现命令见 [`docs/methodology/DATA_CLEANING_AND_CODING.md`](docs/methodology/DATA_CLEANING_AND_CODING.md)
8043

81-
详细字段、清洗规则和复现命令见 [`docs/methodology/DATA_CLEANING_AND_CODING.md`](docs/methodology/DATA_CLEANING_AND_CODING.md)
44+
日期字段覆盖 120 / 360 条样本。当前版本聚焦当前样本的整体分布,时间维度在日期覆盖扩展后启用
8245

8346
## 可靠性评测
8447

85-
评测分为五组:
86-
87-
- **结构完整性**:ID、父样本、平台和文本定位;
88-
- **清洗与隐私**:字段白名单、URL、重复、空值和文件哈希;
89-
- **编码可用性**:合法标签、不确定比例、标签边界和编码来源;
90-
- **分析支撑**:结论是否带有证据、样本量、分母和平台范围;
91-
- **运行复现**:同输入输出一致、manifest 完整、跨平台 CI。
48+
评测把"结果看起来合理"拆成可检查的条件,分为五组:结构完整性、清洗与隐私、编码可用性、分析支撑、运行复现。当前结构完整性全部通过,公开数据 URL 命中为 0,重复文本组为 0。完整方法见 [`docs/evaluation/EVALUATION_METHOD.md`](docs/evaluation/EVALUATION_METHOD.md)
9249

93-
当前最明显的质量风险是机制不确定率较高:486 / 927,约 52.4%。这项结果提示短文本、上下文依赖和标签边界仍需要更细的编码设计。完整评测方法见 [`docs/evaluation/EVALUATION_METHOD.md`](docs/evaluation/EVALUATION_METHOD.md)
50+
编码可用性的校准重点是暂时保留为不确定的证据:486 条证据的体验机制标注为 uncertain,主要涉及短文本、上下文依赖和多种解释并存。这批样本是下一步标签边界校准的重点材料
9451

95-
## 两种不确定性
52+
## 自动校准计划
9653

97-
公开数据包含两个含义不同的字段:
54+
v1.1 通过三个互不查看彼此结果的代理,对分层样本做独立复检,输出一致结果、争议标签和重复运行稳定性。
9855

99-
- `mechanism_label=uncertain`:486 条,表示无法明确判断体验机制;
100-
- `analysis_inclusion_status=included_flagged_uncertain`:163 条,表示证据仍被保留,但纳入时存在上下文或解释风险。
56+
**自动校准参考集**:由多个互不查看彼此结果的代理独立判断后形成的参考标签,用于发现稳定结果和争议案例。它定位为自动校准参考,人工金标准另行建立。流程见 [`docs/evaluation/AGENT_CALIBRATION_WORKFLOW.md`](docs/evaluation/AGENT_CALIBRATION_WORKFLOW.md)
10157

102-
两者分别统计,不能合并为同一“不确定率”。
58+
## 运行与复现
10359

104-
## 离线 Demo
60+
离线 Demo 默认使用本地固定示例模式,不联网,也不调用外部模型:
10561

10662
```bash
10763
python tools/run_demo.py
10864
```
10965

110-
Demo 默认使用确定性 mock provider,不联网,也不调用外部模型。输出写入 `artifacts/`,包括 JSON、Markdown、HTML 和 manifest。
111-
11266
生成公开分析汇总:
11367

11468
```bash
@@ -117,31 +71,17 @@ python tools/summarize_public_analysis.py \
11771
--output artifacts/public_analysis_summary.json
11872
```
11973

120-
规范化公开数据到独立目录
74+
检查公开文案表达
12175

12276
```bash
123-
python tools/normalize_public_dataset.py \
124-
--source-dir data/public \
125-
--output-dir artifacts/normalized_public
77+
python tools/lint_public_copy.py --root . --format markdown
12678
```
12779

128-
## 仓库结构
129-
130-
```text
131-
data/public/ 公开脱敏样本、证据与字段说明
132-
demo/ 离线分析示例
133-
docs/index.html GitHub Pages 展示页
134-
docs/methodology/ 心理框架、编码与清洗方法
135-
docs/evaluation/ 评测方法
136-
evaluation/ 指标与失败类型配置
137-
pipeline/ 采集、配置和 Prompt 模板
138-
tools/ 公开数据规范化、统计与 Demo 入口
139-
tests/ 数据、页面与文档校验
140-
```
80+
## 结果使用说明
14181

142-
## 解释边界
82+
三个平台采用等额抽样,编码来源包含历史 AI 结果与离线规则提案。证据数量也会受文本长度和切分粒度影响。当前分布用于方法审计、探索性分析和研究设计。它为访谈、问卷、行为分析和实验提供问题线索。总体占比与因果结论由这些后续研究继续检验。
14383

144-
三个平台采用等额抽样,编码来源包含历史 AI 结果与离线规则提案,且证据数量会受到文本长度和切分粒度影响。因此当前分布用于方法审计、探索性分析和后续研究设计,不直接代表总体玩家意见占比,也不构成产品效果或心理状态的因果结论
84+
公开数据还包含两个含义不同的字段,各统计一次即可:`mechanism_label=uncertain` 有 486 条,表示机制暂时无法明确归类;`analysis_inclusion_status=included_flagged_uncertain` 有 163 条,表示证据仍被保留但纳入时需要提醒
14585

14686
## 权利与使用
14787

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# PsyLens 自动校准抽样配置(config/calibration/calibration.yaml)
2+
# 供 tools/calibration/build_calibration_sample.py 读取。
3+
# 校准结果为“自动校准参考”,不是人工金标准,也不覆盖公开数据的现有标签。
4+
5+
sample_size: 300
6+
retest_size: 30
7+
reviewer_count: 3
8+
random_seed: 20260720
9+
10+
# 分层维度:从公开证据的下列字段构造分层,保证覆盖。
11+
stratify_by:
12+
- platform_source
13+
- surface_topic
14+
- mechanism_label
15+
- label_source
16+
- analysis_inclusion_status
17+
18+
# 文本长度分桶(依据公开证据文本字符数)。
19+
length_buckets:
20+
- short
21+
- medium
22+
- long
23+
24+
# 长度阈值(字符数):short <= short_max;medium <= medium_max;其余为 long。
25+
length_short_max: 15
26+
length_medium_max: 40
27+
28+
# 每个分层值至少保证的样本数(保证稀有标签也被覆盖)。
29+
min_per_stratum_value: 2
30+
31+
# 输入公开数据(只读,不覆盖)。
32+
input_evidence: data/public/evidence_public.csv
33+
input_samples: data/public/samples_public.csv
34+
35+
# 输出目录:公开校准样本写入 data/calibration,私有映射与运行产物写入 artifacts/calibration。
36+
public_output: data/calibration/calibration_sample.csv
37+
artifact_dir: artifacts/calibration
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Reviewer A · 严格编码手册优先
2+
3+
prompt_version: a-1.0
4+
5+
你是一名独立的证据复检代理。你依据一条脱敏证据文本和可选的父样本上下文独立判断。
6+
你不会获得平台字段、来源编号、当前标签、编码来源或重测关系,也看不到其他代理的判断。公开脱敏文本按原貌保留。
7+
8+
## 任务
9+
10+
严格依据编码手册对证据分类。当证据不足以明确归入某一体验机制时,保留 uncertain,
11+
不要为了提高覆盖率而牵强归类。
12+
13+
## 体验机制标签(固定六项)
14+
15+
- competence_frustration:玩家觉得难以发挥、投入难以见效。
16+
- fairness_threat:玩家觉得规则、匹配或分配本身不合理。
17+
- trust_communication_gap:玩家觉得官方说明、回应或承诺执行不足。
18+
- belonging_drop:玩家表达疏离、退出或与社区的距离感。
19+
- norm_safety_risk:涉及外挂、辱骂、骚扰、误封等秩序与安全问题。
20+
- uncertain:文本过短、依赖上下文或同时指向多个机制。
21+
22+
## 边界判断
23+
24+
先判断 boundary_status:complete、needs_parent_context、over_segmented、under_segmented、not_evidence。
25+
若边界不完整,倾向保留 uncertain 并说明 abstain_reason。
26+
27+
## 模型输出契约
28+
29+
只输出一个 JSON 对象,字段见下。不要输出 run_id、model_name、prompt_version、prompt_sha256、created_at、evidence_text,这些由程序补充。不要输出多余文字或注释。
30+
31+
字段与允许值:
32+
33+
- surface_topic:balance、matchmaking、event_design、progression、community_conflict、communication_transparency、rewards、new_player_onboarding、other_uncertain。
34+
- mechanism_label:competence_frustration、fairness_threat、trust_communication_gap、belonging_drop、norm_safety_risk、uncertain。
35+
- boundary_status:complete、needs_parent_context、over_segmented、under_segmented、not_evidence。
36+
- confidence_band:high、medium、low。
37+
- abstain_reason:none、insufficient_context、multiple_mechanisms、unclear_topic、unclear_boundary、other。
38+
- evidence_phrase:从证据文本中原样摘取的短语,必须是原文子串;无法摘取时留空。
39+
- decision_basis:用普通中文说明依据。
40+
41+
约束:
42+
43+
- mechanism_label 为 uncertain 时,abstain_reason 不能为 none。
44+
- evidence_phrase 非空时必须是证据文本的子串。
45+
46+
JSON 示例(模型实际需要填写的内容):
47+
48+
```json
49+
{
50+
"surface_topic": "matchmaking",
51+
"mechanism_label": "fairness_threat",
52+
"boundary_status": "complete",
53+
"confidence_band": "high",
54+
"abstain_reason": "none",
55+
"evidence_phrase": "连胜连败",
56+
"decision_basis": "文本强调匹配结果不公平,偏向公平受损。"
57+
}
58+
```

0 commit comments

Comments
 (0)