User Analytics Toolkit — 系统级用户研究技能包
把多个开源库缝成「从数据到决策再到行动」的闭环系统,而非单一分析师工具箱。
七层架构,统一数据契约 (df, schema),互不耦合,可独立调用、可整链编排。
架构总览
数据源 → core(接入/质量/会话化/物化) → quant/qual/exp/ml 分析
↓
gov(合规/语义/血缘)
↓
activate(叙事/告警/导出)
↓
pipeline.py 编排 → app.py 多页看板
目录与层职责
| 层 | 目录 | 关键模块 / 函数 | 说明 |
|----|------|----------------|------|
| core 接入与生产化 | core/ | ingest(from_csv/from_sql/from_posthog/read_any)、quality(完整性/重复/bot/SRM)、sessionize、store(parquet 版本)、schema(统一契约)、events(re-export load_events) | 数据地基:多源接入 + 埋点质量门 + 物化 |
| quant 量化分析 | quant/ | run_funnel/run_transition_graph/run_step_matrix/run_clusters/run_stattests/run_ltv/run_cohorts(re-export 自 useranalytics) + rf(RFM)、churn(流失预警)、conversion_time、segment_diff(细分对比)、cohorts(滚动/无界留存) | 行为量化全谱 |
| qual 定性研究 | qual/ | survey(NPS/CSAT/CES+主题/情感)、interview(编码/JTBD)、close_loop(定性假设→定量验证)、recruit(被试招募闭环:althing 合成用户+Cookiy式真实预留)、knowledge_graph(跨访谈/工单主题知识图谱,社区检测+跨源桥接) | 现有 personas.py(合成焦点小组)仍保留在顶层 |
| exp 实验与因果 | exp/ | abtest(显著性/样本量/MDE/SRM)、causal(PSM / DiD——大面板自动切双向去均值 within 估计+聚类稳健SE,不奇异) | 从相关到归因 |
| gov 合规治理 | gov/ | privacy(PIPL/PII脱敏/同意/留存)、semantic(指标语义层)、lineage(审计血缘) | 国内上线硬门槛,默认开 |
| activate 输出与激活 | activate/ | report(自动洞察叙事)、alert(异常检测+告警,含 recommended_action/owner)、notify(Slack/BI webhook 路由到行动)、export(导出BI/看板) | 让洞察真正路由到行动 |
| report 专业长篇报告引擎 | report_engine/ | spec(章节骨架/样式/篇幅档位)、provenance(Artifact/TraceStep/Claim/ProvenanceLedger 溯源+留痕+交叉验证)、guardrails(CompletenessChecker 六类强制校验)、builder(ReportBuilder 分章生成+组装门禁+assign_refs 编号/TOC/交叉引用)、analysis(trend/comparison/correlation/anomaly 四维度,复用 core/quant)、render(to_html 自包含 / to_pdf PdfPages)、latex(to_latex/to_latex_pdf 真实 LaTeX PDF,ctex+latexmk -pdfxe)、fonts(ensure_cjk_font 中文注册) + useranalytics.make_report/make_full_report(latex_path 出 LaTeX) 入口 | 生成专业级、可审计、防捏造的长篇报告(HTML / PDF / LaTeX 三输出) |
| ml 高级建模 | ml/ | propensity(倾向性)、uplift_model(T/S-Learner + Qini/AUUC + 十分位表)、lookalike、lifecycle(阶段判定,阈值默认从事件间隔 P50/P75/P90 自动推导) | 预测与扩展 |
| discovery 发现阶段 | discovery/ | ost(build_ost 机会解法树 + opportunity_score(Importance×(1−Satisfaction)) + problem_interview_guide 问题访谈指南) | 把发现阶段数据化:机会按评分排序 |
| competitive 竞争研究 | competitive/ | analyze(competitive_matrix 对比矩阵 + differentiation_map 二维差异化地图) | 竞品/替代品对标 |
| qual 扩展(UX 研究) | qual/ | usability_test(任务成功率/时间/错误率/辅助 + plan_usability_test)、ia_research(卡片分类开/闭 + 树测试)、longitudinal(日记/情境 + 纵向聚合) | 传统 UXR 量化侧补齐 |
| gov 研究伦理 | gov/ | ethics(consent_form 知情同意书 / recording_release 录音授权 / irb_checklist 伦理审查清单) | 研究伦理与知情同意流程 |
| research_ops 研究运营 | research_ops/ | repository(本地研究存储库 JSON/CSV)、participant_panel(参与者面板 + 筛选→腾讯问卷)、calendar(研究日历 + ICS 导出) | Research Ops 底座,零外部依赖、可审计 |
| delivery 外部联动 | delivery/ | tencent_survey(build_dsl_scale/recruit_screener/usability_posttask 生成 DSL + push_survey/create_survey 投放 + pull_answers/list_answers 回收 + import_export_csv 导入;未连接降级返回 DSL) | 与腾讯问卷打通投放/回收(替代原腾讯文档方案) |
| NL 入口 / 审计 | 顶层 | nl.ask(自然语言→意图→七层洞察+出图,含可追溯 trace)、mcp_server.py(stdio MCP 工具,接入 Claude Code/Cursor)、audit(血缘日志→可追溯报告) | 问一句出图 + 每个结论可追到数据与代码 |
统一契约见 core/schema.py:所有函数接受 (df: pd.DataFrame, schema: dict),
schema 含 path_cols / event_cols / timestamp_col / segment_cols;重型依赖全部函数内懒加载。
编排与看板
python pipeline.py [CSV] [会话数] [输出目录] # 七层端到端跑通,产出报告+审计
streamlit run app.py # 10 个 Tab 覆盖七层 + 两个可选层
python example_run.py [CSV] [会话数] # 老核心 7 项 headless 验证
python -m nl "哪一步流失最严重?" [CSV] # 自然语言入口:问一句出图(可选 chart=True)
python mcp_server.py # 启动 stdio MCP server(接 Claude Code/Cursor)
python -m audit # 生成血缘/可追溯报告
pipeline.py 每层独立 try/except,单层失败不影响整体,并写 lineage.jsonl 审计日志。
何时用
- 用户要用户行为/点击流分析,且数据已落为 CSV / 数仓导出(GA4、ClickHouse、Snowflake…)。
- 用户要做用户研究系统:分群、留存、流失预警、RFM、A/B、合规脱敏、自动报告。
- 用户问 retentioneering 怎么用、为什么没 Cohorts/Stattests、怎么加 LTV / 实验 / 合规。
关键事实(避免踩坑)
- retentioneering v5 已砍掉 Cohorts 和 Stattests(旧文档是 v3 的)——用本包
run_cohorts/run_stattests,不要调内置类。 - 许可证不是 Apache 2.0:v5 是 Retentioneering Software Non-Exclusive License(专有),商用/客户项目前确认条款。
- 数据要求 3 列:
user_id/event_type/event_time(+可选price/user_session)。path_cols必须嵌套:user_id 包含 session。 - PostHog 是外部服务不塞进 skill;
collect.py只是客户端封装,dry_run不联网。 - synthpanel 的 CLI 已更名
althing:pip install synthpanel(依赖 althing),命令用althing panel run。 - retentioneering transition graph 行为:其 path 模型把
cart/purchase大量归到路径终点节点,cart→purchase边被系统性低估;完整 view→cart→purchase 链路用 Funnel 读更准。 - 合规默认开:
gov.privacy的 PII 脱敏/留存策略应在接入后立即应用(国内 PIPL 硬门槛)。
自然语言入口(NL 层 + 真实 LLM)
nl.ask(question, csv_path=..., use_llm=...) 把自然语言问题映射到七层函数并产出洞察+出图。
意图识别有两档:
- 规则(默认、零依赖):关键词打分,离线可用、零成本。
- 真实 LLM(更准):用 OpenAI 兼容端点做「意图分类 + 结构化参数抽取」,能理解同义/口语/复杂问句,
并抽取
segment_diff.dimension/funnel.events等参数让 handler 精准响应。
接入真实 LLM(配置一次、跨 agent 通用,不写死 key、不联网除非显式启用):
export UA_LLM_BASE_URL=https://api.openai.com/v1 # 或 https://api.longcat.chat/openai/v1
export UA_LLM_API_KEY=sk-xxx
export UA_LLM_MODEL=gpt-4o-mini
from nl import ask
ask("移动端和 PC 端购买率差多少", csv_path="events.csv", use_llm=True)
# → 规则无法识别维度,LLM 解析为 segment_diff + dimension=browser,按真实维度对比
use_llm=None(默认)= 自动(配了环境变量才走 LLM);True=强制;False=强制规则。
也可 llm_config={base_url,api_key,model} 临时覆盖。MCP 工具 user_analytics_ask 同样透传这两个参数。
未配置时不联网、自动回退规则,分析不中断。客户端见 llm_client.py(requests 懒加载、json 容错)。
可解释·可审计(差异化卖点)
业界两类方案都有盲区:定性 Skill 只给方法论脚手架、不跑真实数据、无统计检验; 定量平台(Amplitude/Mixpanel/PostHog/Heap)AI 层是闭源黑盒,且普遍不做因果、合规、激活闭环。
本包走第三条路——每个洞察都可追溯到「数据版本 + 代码函数 + 指标版本」:
gov.lineage.LineageLogger每次 run 写lineage.jsonl(数据版本、指标版本、产出路径)。audit.report_lineage()/trace_metric()把血缘日志汇总成可读追溯报告;nl.explain()返回单次分析的调用链。- 统计方法全白盒:BG/NBD + Gamma-Gamma(LTV)、Logistic/倾向性、uplift(T/S-Learner + Qini)、DiD(双向去均值 + 聚类稳健SE)。
- 对外以此作为卖点:别人黑盒,我们可解释、可复现、可审计,数据不出域。
环境
受管 venv 核心:
pip install retentioneering pandas pyarrow scipy lifetimes streamlit scikit-learn
可选(按需装,不装核心照跑):
pip install posthog # collect.py:PostHog 采集
pip install synthpanel # personas.py:合成焦点小组(CLI=althing)
pip install statsmodels jinja2 requests sqlalchemy # exp/gov/activate 部分能力
用法速查
from core import ingest as ci
import quant, exp.abtest as ea, gov.privacy as gp
df, schema = ci.from_csv("events.csv", n_sessions=8000)
quant.run_rfm(df, schema) # RFM 人群
quant.run_churn(df, schema) # 流失风险分(时间外推标签:cutoff 前特征、cutoff 后回访打标,AUC 真实可信)
ea.ab_test(group_a, group_b) # A/B 显著性
gp.mask_pii(df, ["email","phone"]) # PII 脱敏
专业长篇报告引擎(report_engine · 防捏造)
生成专业级、长篇、可审计的数据分析报告。核心铁律:正文里出现的任何数字都必须来自
ProvenanceLedger 中已登记的 Artifact;结论必须引用溯源 id 与可追溯的分析步骤。
组装阶段跑 CompletenessChecker,出现 BLOCKER 级违规(捏造数字 / 缺失强制章节 / 纯推测撑建议 /
关键统计量重算不一致)则报告进入 quarantined 不发布,绝不带病输出。
铁三角机制:
- 数据溯源:
Claim.artifact_ref必须 ∈ 账本;附录自动生成溯源账本供审计。 - 分析留痕:
TraceStepDAG 记录「输入→操作→输出」,结论回溯到source_data_ref。 - 交叉验证:关键统计量用独立路径重算,容差内不一致即 BLOCKER。
- 结论范围 + 完整性:每条结论标
EVIDENCE/SPECULATION+ 置信度 + scope; 强制章节(局限性/方法论/溯源账本)非空;分析密度(图+表/千字)下限防灌水。
from useranalytics import make_report
from report_engine import ProvenanceLedger, Artifact, Claim, TraceStep, ReportSpec
from report_engine.builder import (build_data, build_descriptive, build_interpretation,
build_limitations, build_summary, build_intro,
build_methodology, build_deep, build_cover, build_toc, build_appendix)
ledger = ProvenanceLedger()
ledger.register(Artifact("art.conv_rate", "stat", "整体转化率", 0.442,
"dataset:events_2026Q1_CAN", "mean(event='purchase')",
params={"filter": "country=CAN"}))
ledger.claim(Claim("claim.conv", "2026 Q1 加拿大区整体转化率为 44.2%", "art.conv_rate",
modality="EVIDENCE", confidence=0.95,
scope={"population": "CAN", "time_window": "2026Q1"}, backs_recommendation=True))
sections = {
"cover": build_cover(ReportSpec(title="转化分析报告")),
"summary": build_summary(ledger), "toc": build_toc(),
"intro": build_intro(), "data": build_data(ledger),
"methodology": build_methodology(), "descriptive": build_descriptive(ledger),
"deep": build_deep(ledger), "interpretation": build_interpretation(ledger),
"limitations": build_limitations(), "appendix": build_appendix(),
}
res = make_report(ledger, sections)
print(res["status"], "->", res["report"]) # "published" 或 "quarantined"(附违规清单)
回归测试:python report_engine/tests/test_guardrails.py(4 场景:A 发布 / B 捏造 / C 纯推测撑建议 / D 重算不一致);
python report_engine/tests/test_p1p2.py(端到端:四维度分析 + HTML/PDF 渲染 + 编号/交叉引用 + 护栏仍生效)。
一键出报告(make_full_report)
给定 (df, schema) 自动建账本、跑四维度分析、组装、渲染 HTML + PDF:
from useranalytics import make_full_report
from report_engine import ReportSpec
res = make_full_report(
df, schema,
spec=ReportSpec(title="用户行为分析报告", band="medium", version="1.0"),
analysis_cfg={"metric": "purchase", "freq": "M",
"by_col": "platform", "corr_cols": ["price", "dwell"]},
fig_dir="./figs", source_ref="dataset:events",
html_path="report.html", pdf_path="report.pdf",
)
print(res["status"]) # "published" 或 "quarantined"(附违规清单)
# HTML:内联样式 + base64 嵌入图,单文件自包含,可直接浏览器打开
# PDF :matplotlib PdfPages,自动中文(ensure_cjk_font 探测 msyh/simhei…),含 TOC/章节/图/表/溯源账本
要点:
- 图/表自动按「章-序号」编号(
图 5-1/表 2-3),正文用\ref{fig:trend}交叉引用,渲染层统一解析。 - 相关性结论一律标 相关≠因果(SPECULATION),不得单独支撑建议——护栏
SPEC_ONLY_RECO会拦截。 - 正文每个数字都来自
ProvenanceLedger的Artifact;缺失溯源 / 关键统计量重算不一致 →quarantined。
现状(v2.5.3):P0 规范层+护栏层+编排骨架,P1 四维度分析(trend/comparison/correlation/anomaly)接入 core/quant 填满 deep,P2 HTML(jinja2-free 内联)/PDF(matplotlib PdfPages) 渲染 + 自动编号/TOC/交叉引用 + 中文字体,均已落地并通过双测试套件。 与
activate/report.py(快速叙事)分工:长文专业报告走report_engine,短洞察填词走activate/report。 完整示例见pipeline.py与各层*_run*/ 顶层example_run.py。
模板化报告生成(v2.7.0+ · 严格防幻觉)
基于 templates/research_report_template.md(12 节:决策背景 BLUF / 目标范围 / 方法与伦理 /
Research Vitals / 关键发现四段式 / 主题 / 量化洞察 HEART / 机会评分 OST / 建议路线图 / 风险局限 /
附录 / 复用追踪),用真实数据填出可发布报告。铁律:任何数字/结论必须来自真实 data,缺失即哨兵,绝不编造。
from report_engine import generate_from_template, FactTable, enforce_no_fabrication
# data 的所有值必须来自真实计算(如 pipeline 的 quant 结果 / 各分析层返回值)
data = {
"meta_title": "新用户首周激活路径研究",
"exec_conclusion": f"流失模型 AUC={auc:.3f},高风险用户约 {high_risk} 人",
"findings_block": "- **F1 首周留存偏弱**:M1 约 {m1}。[src:quant.retention]",
# ... 其余字段见模板与 test_template_report.py
}
out = generate_from_template("research_report_template.md", data, "./report_out")
print(out["status"]) # "published" 或 "quarantined"(含 hallucination_issues)
# 防幻觉独立校验(可用于任何 LLM 生成文本的事后审查)
ft = FactTable({"a": 0.445, "b": 0.884})
ok, issues = enforce_no_fabrication("转化率提升 87.3%。", ft, strict=True)
# ok == False, issues 含 UNGROUNDED_NUMBER(87.3% 未溯源 → 拦截)
机制要点:
- 零编造(默认):纯数据填充,模板只接收 data 中的真实值,结构上不会生成任何数字或结论。
- 缺失即哨兵:
{{field}}无对应数据时渲染⚠ 无真实数据:…未生成任何结论或推测。,不编造占位。 - Layer 0 数字溯源:
FactTable汇总 data 中所有真实数字;verify_text(check_numbers=True)扫描报告文本,任何无法溯源的数字(如 AI 臆造的87.3%)判UNGROUNDED_NUMBER并quarantined。 - 占位符清零:残留
{{...}}/[...]一律视为不可发布。 - 复用既有发布门禁:传入
ProvenanceLedger时,CompletenessChecker的溯源/局限/密度校验继续生效。 llm_narrate=True为 opt-in:一旦启用真实 LLM,其叙述须通过数字溯源校验,未通过即拦截(当前_llm_narrate为占位接口,默认不接 LLM)。
全谱用户研究扩展(v2.7.0)
在原有七层「数据驱动分析」之上补齐了传统 UXR 的方法论与运营层,并把腾讯问卷作为 投放/回收联动层(替代原腾讯文档方案——腾讯问卷擅"建问卷→回收",研究存储库/面板/日历改为本地轻量)。
# 任务级可用性测试
from qual.usability_test import task_metrics, aggregate_usability
task_metrics(df_rows) # df 含 participant,task,success,time_sec,errors,assists
aggregate_usability(df_rows, sus_responses=[...], seq_responses=[...]) # 任务 + SUS + SEQ 聚合
# 信息架构:卡片分类 / 树测试
from qual.ia_research import card_sort_open, tree_test
card_sort_open(items, groupings) # 相似度矩阵 + 层次聚类 + 树状图
tree_test(tree_tasks) # 成功率/寻路/耗时
# 发现阶段:机会解法树
from discovery.ost import build_ost, opportunity_score
build_ost("提升售后自助效率", [{"name":"更快找订单","importance":9,"satisfaction":4}])
# 竞争研究
from competitive.analyze import competitive_matrix, differentiation_map
competitive_matrix(competitors) # competitors: [{name, 维度: 0-10}]
differentiation_map(competitors, "易用性", "价格优势")
# 研究伦理
from gov.ethics import consent_form, irb_checklist
consent_form("某研究"); irb_checklist("某研究")
# 研究运营(本地)
from research_ops.repository import add_study, search, export_markdown
from research_ops.calendar import add_event, to_ics
腾讯问卷联动(delivery.tencent_survey)
NPS/CSAT/CES/招募筛选/任务后 SUS·SEQ 由 toolkit 生成纯文本 DSL,经 tencent-survey MCP
(create_survey/list_answers)建问卷、回收答案,回灌 qual.survey 分析。
from delivery.tencent_survey import build_dsl_scale, push_survey, pull_answers, parse_answers_to_df
dsl = build_dsl_scale("nps") # 生成问卷 DSL
push = push_survey(dsl, scene=1) # 尝试建问卷 → {survey_id, hash, link}
# 未连接 tencent-survey 时 push.available=False,返回 dsl + 手建链接说明(不崩)
# 收集后:
raw = pull_answers(push["survey_id"]) # list_answers 游标分页
df, schema = parse_answers_to_df(raw["answers"]) # 转统一契约 → 喂 qual.survey.analyze_nps
# 离线可靠路径:导入腾讯问卷导出的 CSV
df2, s2 = import_export_csv("answers.csv")
接入前提:tencent-survey 连接器在 WorkBuddy 中已连接(或本机 mcporter 已注册 tencent-survey
且 Token 就绪)。未连接时所有函数降级返回 DSL/说明,分析链路不中断。
数据来源建议
- 练手:REES46 电子商城(
mkechinov/ecommerce-events-history-in-electronics-store)。 - 任意数据集只需 rename 成
user_id/event_type/timestamp(+session)三列即可接入。
微信扫一扫