Que fait 物业项目经理 · 月度经营分析 PPT ?
核心不是"把数据放上去",而是按听众的认知顺序,把经营底盘讲清楚,再把异常病灶定位到责任人和时限。
本技能的知识分两处存放
| 文件 | 给谁读 | 装什么 |
|---|---|---|
SKILL.md(本文件) | 人 / Agent | 为什么这样讲:叙事理由、归因方法、表达纪律 |
deck_spec.json | 工具 | 怎么落地:几页、顺序、结论句模板、配色 |
deck_spec.json 是本技能的机读知识。改它就能调整 PPT 的页数与讲法,
不需要改任何 Python 代码:
{
"page_rules": [ // ← 「ppt 要几页」在这里
{"max_minutes": 10, "sections": [7 个段落]},
{"max_minutes": 20, "sections": [11 个段落]},
{"max_minutes": 40, "sections": [16 个段落]}
],
"sections": [{
"key": "revenue", "label": "收入", "layout": "chart",
"data": {"value_column": "账单金额(元)", "group_column": "收费项"},
"narrative": [ // ← 结论句模板:从「念数字」到「给判断」
{"when": "top_share > 0.9",
"so_what": "{top_name} 占收入 {top_share_pct}%,结构单一、抗风险能力弱;"
"下月应把公共收益作为专项来抓。"},
{"when": "", "so_what": "…默认条款…"}
]
}],
"theme": {"colors": {...}, "palette": [...]} // ← 配色也是知识
}
结论句模板怎么工作
引擎按 when 条件从模板列表里挑出第一个命中的,用真实数字填充 {占位符}。
可用占位符(由数据自动算出):{total} {count} {top_name} {top_share}
{top_share_pct} {group_count} {bottom_name} {bottom_value} …
格式化后缀:{total:万}(÷10000){share:1%}(比值→百分数)
{count:,}(千分位){value:2}(小数位)
支持的条件:> >= < <= == !=、and/or/not、has(x)/empty(x)。
无法解析的条件视为不命中,不会报错。
数据缺失时诚实降级:页面标题标注"数据缺失,待补",绝不拿别的列冒充。 例如「成本」页声明了
成本科目,而数据里没有该列时,会明确说缺什么。
指标要从数据算,不能靠人工传
derived 段声明"怎么算",工具负责算:
"derived": {
"已收金额(元)": {"expr": "账单金额(元) - 未缴金额(元)"}, // 逐行,成为新列
"收缴率": {"expr": "已收金额(元) / 账单金额(元) * 100",
"scope": "total", "format": "{:.2f}%"} // 按合计算出**一个数**
}
⚠
scope默认row(逐行算,结果成为新列);比值类指标必须用scope: "total"—— 逐行算比值再求和会得到 1,476,800% 这种荒唐值。
算出来的值会自动并入叙事事实表,于是 {收缴率} 可以直接写进结论句模板。
实测验证(2、应收信息.xlsx):收缴率 = 92.48%,欠款率 = 7.52%。
用「缴费状态」分组独立核对完全吻合(已缴费行未缴合计 = 0)。
表达式只允许引用列名与数字常量,用 ast 白名单求值 —— 不用 eval。
__import__('os') 这类会被拒绝。
维度在主表里没有时,才需要跨表
datasets + join 声明"用哪张表、拿哪几列、按什么键":
"datasets": {
"properties": {"file": "1、房产客户信息.xlsx", "key_column": "房产编码",
"pick": {"实测收费面积(m²)": "实测收费面积"}}
},
"join": {"dataset": "properties", "left_on": "房产全称", "how": "left"}
顺序:先关联,再算派生 —— 否则派生表达式引用的维度列还不存在。
教训:先量再决定要不要 join。原以为"收缴率需要跨表", 量过才发现表 2 里同时有账单与未缴金额,单表就能算。 真正需要 join 的是"平均单价"(面积在表 1 里)。
必须交付三样东西
| 交付物 | 形式 | 作用 |
|---|---|---|
| ① 汇报 PPTX | 16:9 可编辑演示文稿 | 幻灯片,用来"看" |
| ② 校验报告 checks.json | JSON(由 pptx_check 工具产出) | 结构完整性证据 |
| ③ 汇报话术 | 聊天正文 / Markdown(模板见 references/03-汇报话术.md) | 逐字稿,用来"说" |
何时使用
- 物业项目月度/季度经营分析PPT
- 区域运营中心、总经理经营汇报
- 需要成本超支归因、收缴率分析、人均效能分析
- 关键词:"项目经理月度汇报""经营分析会材料""项目经营看板 PPT"
五阶段处理流水线
用户输入数据
|
v
+-------------------+
| 阶段 1: 数据理解 | 解析输入、补全缺省、校验口径
+-------------------+
|
v
+-------------------+
| 阶段 2: 数据分析 | 收入/成本/收缴/效能计算、偏差排序、异常归因
+-------------------+
|
v
+-------------------+
| 阶段 3: PPT结构规划 | 定页数、定图表类型、定每页结论标题
+-------------------+
|
v
+-------------------+
| 阶段 4: 内容生成 | 构造 DATA 字典、生成结论句、填充话术
+-------------------+
|
v
+-------------------+
| 阶段 5: 调用PPT Tool| 执行 build_deck.py → 校验 → 交付
+-------------------+
|
v
生成 .pptx + checks.json + 汇报话术
阶段 1: 数据理解
1.0 数据从哪来(三条路径,按优先级)
| 优先级 | 方式 | 说明 |
|---|---|---|
| 1 | 用户在对话里给了数据 | Agent 把数据填进 data 参数 |
| 2 | 用户给了文件名/线索 | 技能自动去常用目录找文件并抽数(见下) |
| 3 | 都没有 | 用默认模板生成,并给出数据不足警告 |
自动取数:当 data 为空时,技能会
- 从
request里解析文件名线索(例如"上个月的销售表") - 在
data/common与data/inbox里模糊匹配文件 - 用 pandas 读取,自动推断 日期列 / 金额列 / 分组列
- 转成契约结构(金额 ÷10000 成万元、比率用比值)
- 落盘成
input_data.json交给生成脚本
所以用户只需说「用上个月的销售表做个经营分析PPT」,不必提供路径 ——
前提是文件已放进 data/common。
覆盖搜索根:SKILL_COMMON_DIRS=D:\表格;E:\月报
关闭自动取数:auto_resolve_data=False
物业项目数据源(data/common 实测口径)
| 表 | 文件 | 用途 | 口径说明 |
|---|---|---|---|
| 表2 | 2、应收信息.xlsx | 主表(15,876 行) | 收入按「收费项」分组;「账单金额/未缴金额」派生收缴率(实测 92.48%) |
| 表1 | 1、房产客户信息.xlsx | 维表:实测收费面积 | 按「房产编码」=主表「房产全称」join → 派生平均单价(实测 0.30 元/m²·期) |
| 表4 | 4、欠款明细报表.xlsx | 维表:欠费原因(7 类) | 标题在第 2 行(header_row=1),表尾有合计行(自动丢弃);按「房产全称」join → 欠款归因页 |
| 表5 | 5、房产收缴率明细表.xlsx | 不用 | 三行复合表头、宽表口径,容易与表2派生口径打架,一律以表2派生为准 |
诚实降级声明:本项目数据里没有成本、预算、人数、工单数据。
成本页已替换为「欠款与催缴」页(数据真实可用),效能页只保留有数据支撑的
「平均单价」。账龄四分层数据不在表2里——需要时由主 agent 先调催费子 agent
(arrears_analysis)做账龄分析,再以 extra_facts 注入本技能。
1.1 解析用户输入 → 提取基本信息
| 要素 | 默认/示例 | 说明 |
|---|---|---|
| 项目名称 | XX 小区 | 必填,缺则标注"待补充" |
| 报告期间 | 本月 | 必填 |
| 金额单位 | 万元 | 全篇统一,不得混用;原始数据是"元"时必须 ÷10000 |
| 比率口径 | 比值 | 0.952 = 95.2%;传 95.2 会被渲染成 9520% |
| 对比基准 | 月度预算 + 上月 | 至少一个参照系 |
| 汇报时长 | 20 分钟 | 决定页数 |
1.2 数据完整性检查 —— 七组必填数据
检查用户是否提供了以下七组数据,缺哪组就在对应页标注"待补":
| # | 数据组 | 具体字段 |
|---|---|---|
| 1 | 收入分项 | 物业费、公共收益、多种经营、其他(实际值 + 预算值) |
| 2 | 成本分项 | 人力、公共能耗、外包、维保、物料、管理费(实际值 + 预算值) |
| 3 | 收缴数据 | 当月应收 / 当月实收 / 陈欠期初 / 陈欠回收 |
| 4 | 账龄分层 | 0-30 / 31-90 / 91-180 / 180+ 天欠费余额 |
| 5 | 效能数据 | 人数、在管面积、工单量、人力成本 |
| 6 | 异常科目 | 偏差额最大的 3~5 个科目及其可追溯事件 |
| 7 | 上月行动项 | 完成情况(必须回头报,形成闭环) |
1.3 数据口径校验
在进入分析前,必须对照以下红线检查数据口径:
- 公共收益依法属全体业主共有,必须单独列示,不得计入经营利润
- 当期收缴率分母 = 当月应收账单金额,不得混入陈欠回收
- 人力成本必须含社保公积金、加班费、外包折算人工
- 能耗必须区分"公共区域分摊"与"物业自用"
- 一次性支出(应急抢修、大修)单独列示,不进入月度可比口径
- 人均效能需与人工成本率合并判断,不能只看人数变化
阶段 2: 数据分析
2.1 分析顺序(必须按此顺序,不得打乱)
收入分析 → 成本分析 → 收缴率分析 → 人均效能分析 → 异常科目归因
顺序原因:收缴率是服务质量的果(投诉未闭环 → 业主拒缴),放收入/成本之后讲因果才成立;异常归因必须建立在四个经营底盘之上,否则讨论会失焦。
2.2 收入分析
- 计算每项收入的实际 vs 预算偏差
- 计算预算完成率 = 本月确认收入 / 本月预算收入
- 计算收入结构占比
- 公共收益单独列示,标注"属全体业主共有,不纳入经营利润"
2.3 欠款归因分析(原成本分析,本项目无成本数据)
本项目数据没有成本科目,本段改为欠款按欠费原因归因——物业经营里和成本同样吃现金流的一页:
- 用主表「未缴金额(元)」按 join 来的「欠费原因」分组聚合(实测合计 3.64 万元,与欠款明细报表逐户合计完全对账)
- ⚠ 不要用 join 来的「总欠款金额(元)」做聚合——它是每户合计,会被该户多条账单行复制导致重复计数
- 欠费原因四分层匹配催缴策略:服务争议(先整改后催缴)/ 客观困难(分期方案)/ 恶意拖欠(函件升级)/ 失联空置(上门核实)
- 成本数据到位后,把 deck_spec.json 的 arrears 段换回 cost 段即可,工具链不用动
2.4 收缴率分析 —— 三级指标拆解
| 指标 | 计算口径 |
|---|---|
| 当期收缴率 | 当月实收 / 当月应收(不含陈欠回收) |
| 累计收缴率 | 年初至今实收 / 年初至今应收 |
| 陈欠回收率 | 本期回收历史欠费 / 期初陈欠总额 |
配合账龄金字塔:0-30 / 31-90 / 91-180 / 180+ 天。账龄越长回收概率越低(180天以上仅 10%~20%)。
欠费原因分层:服务争议型 / 客观困难型 / 恶意拖欠型 / 失联空置型。前两类靠服务补救,后两类靠催收机制。
2.5 人均效能分析
| 指标 | 计算口径 |
|---|---|
| 人均管理面积 | 在管建筑面积 ÷(自有 + 外包折算人数) |
| 人均产值 | 营业收入 ÷ 项目总人数 |
| 人均工单量 | 完成工单数 ÷ 工程人员数 |
| 人工成本率 | 人力成本 ÷ 营业收入(反向指标,越低越好) |
⚠ 陷阱:外包替换自有员工会让分母变小、数字变好看,必须与人工成本率合并判断。
2.6 异常科目归因 —— 三层穿透法
这是整个分析最有价值的一步。
| 层级 | 要回答的问题 | 输出 |
|---|---|---|
| 第一层 量化偏差 | 是量差、价差还是口径差? | 偏差额 + 偏差率 |
| 第二层 驱动因素 | 拆到能追溯具体事件 | 一句可核查的事件描述 |
| 第三层 责任归属 | 可控/部分可控/不可控,主责是谁 | 责任部门 + 纠偏动作 + 时限 |
人力成本偏差拆解示例:
偏差 = 人数偏差 × 预算人均工资(量差)
+ 预算人数 × 人均工资偏差(价差)
+ 口径 / 一次性因素(口径差)
写法规范:
- ❌ "能耗上升" → ✅ "能耗超支 2.1 万元,地库照明改造延后导致全月沿用旧灯具(1.2 万元)+ 3 台电梯年检试运行延长(0.9 万元)"
- ❌ "维修费超支" → ✅ "维修费超支 1.3 万元,5# 楼污水管爆管应急抢修 1.3 万元(不可控)"
没有责任人和时限的归因等于没归因。
阶段 3: PPT 结构规划
3.1 汇报顺序(六段式,不可打乱)
① 一页纸结论(30 秒决策)
② 收入:钱从哪来 → 物业费 / 公共收益 / 多种经营 / 其他
③ 欠款与催缴:钱被谁欠着 → 欠费原因四分层:服务争议 / 困难 / 恶意 / 失联
④ 收缴率:钱收回了没 → 当期 / 累计 / 陈欠 / 账龄分层
⑤ 人均效能:人值不值 → 平均单价 / 人均面积 / 人工成本率 / 人均工单
⑥ 异常科目归因 → 三层穿透:量化偏差 → 驱动事件 → 责任与可控性
⑦ 总结与行动项 → 3~5 项,每项有责任人 + 时限 + 量化验收标准
3.2 页数规划
| 时长 | 建议页数 | 结构处理 |
|---|---|---|
| 10 分钟 | 6~8 页 | 一页纸结论 + 收入成本 + 异常 TOP3 + 行动项 |
| 20 分钟 | 12~16 页 | 完整六段式,异常归因选 TOP5 |
| 40 分钟 | 20~28 页 | 增加趋势对比(3~6 月)、同类对标、专项深挖 |
3.3 图表选择
| 分析内容 | 图表类型 |
|---|---|
| 收入实际 vs 预算 | 双系列柱状图 |
| 成本偏差排序 | 条形图(红/黄/绿语义色) |
| 收缴率 + 账龄 | 分层柱状图 + 三级指标卡片 |
| 人均效能趋势 | 柱+折线组合图(次轴显示成本率) |
| 异常归因 | 条形图 + 归因表格 |
| 行动项 | 行动卡片(责任人/时限/验收标准) |
3.4 每页结构模板
┌──────────────────────────────┐
│ 页眉:序号 + 结论型标题 + 阶段标签 │
├──────────────────────────────┤
│ │
│ 图表 / 数据可视化区域 │
│ │
├──────────────────────────────┤
│ 结论栏:so_what 结论句 │
├──────────────────────────────┤
│ 脚注:口径说明 │
└──────────────────────────────┘
阶段 4: 内容生成
4.1 构造 DATA 字典
根据阶段 2 的分析结果,将数据填入标准化的 DATA 字典。
DATA = {
"项目": "<项目名称>",
"期间": "<YYYY 年 M 月>",
"收入": {"物业费": 0, "公共收益": 0, "多种经营": 0, "其他": 0},
"收入预算": {...},
"成本": {"人力成本": 0, "公共能耗": 0, "外包服务费": 0, "维修维保": 0, "物料耗材": 0, "管理费及其他": 0},
"成本预算": {...},
"收缴": {"当月应收": 0, "当月实收": 0, "陈欠期初": 0, "陈欠回收": 0},
"账龄": {"0-30天": 0, "31-90天": 0, "91-180天": 0, "180天以上": 0},
"效能": {"人均管理面积": 0, "人均产值": 0, "人工成本率": 0, "人均工单量": 0},
"趋势月份": [...],
"趋势收入": [...],
"趋势成本": [...],
"预算完成率": 0,
"成本率": 0,
"预算成本率": 0,
"本月结论": "<三句话总结:经营结果 + 最大异常 + 下月第一动作>",
"最大异常": "<偏差最大的科目及金额>",
"第一动作": "<下月最高优先级行动>",
}
4.2 生成每页结论句(so_what)
每页必须生成一句结论句,不留白让听众猜。
| 页面 | 结论句式模式 |
|---|---|
| 一页纸结论 | "收入端基本达标,成本端是本月唯一失分项;先解决成本,收缴率自然回升。" |
| 收入 | "多种经营缺口 X 万元需在下月补回;公共收益不得计入经营利润美化业绩。" |
| 成本 | "前两项偏差均为部分可控,属本月必须纠偏的科目;后两项为不可控/口径因素。" |
| 收缴率 | "收缴率是服务质量的果:本月投诉闭环率 X%、报修及时率 Y%,是收缴率缺口的上游原因。" |
| 人均效能 | "人效未恶化,但成本率连续两月上行,需在下月排班与外包结算上做结构性调整。" |
| 异常归因 | "上月行动项(XXX)延期是能耗超支的直接原因,本月必须闭环,否则下月将重复发生。" |
| 总结行动 | "下月目标:收入 X 万、成本率降至 Y% 以内;风险预警:XXX 需提前申报。" |
4.3 内容表达纪律
这 6 条决定汇报是否专业,必须在内容生成阶段遵守:
- 标题写结论,不写栏目名。❌ "成本分析" → ✅ "成本超预算 3.9 万元,人力与能耗合计贡献 92% 偏差"
- 每页一句 so what。图表下方必须有结论行
- 数字必须带口径和期间。❌ "收缴率 92%" → ✅ "当期收缴率 92.0%(口径:当月实收/当月应收,不含陈欠回收)"
- 颜色语义全篇固定:达标=绿(#2EA06A)、预警=黄(#E8A31D)、未达标=红(#D9453D)
- 异常归因必须闭环:科目 / 偏差额 / 偏差率 / 主因 / 可控性 / 责任部门 / 时限
- 明细放附录,正文只放结论图
4.4 生成汇报话术
按照 references/03-汇报话术.md 的模板,为每页生成三段式话术:
| 段 | 内容 | 时长 |
|---|---|---|
| 结论先行 | 这页的结论是什么 | 10 秒 |
| 数据支撑 | 关键数字 + 口径 + 参照系 | 30 秒 |
| 主因与动作 | 为什么 + 谁的 + 什么时候 + 怎么验收 | 30 秒 |
话术红线:
- 先结论后过程
- 量词必须可执行:❌ "降本增效" → ✅ "加班费环比下降 30%,月底核账"
- 不报数字不开口:任何形容词都要有数字兜底
- 可核对:每个数字都要能答出"从哪查"
- 主动认领可控问题:先说"我的责任、我什么时候改完"
- 答不上来不硬编:标准接法"这个数我需要和财务复核,今天下班前书面回复"
阶段 5: 调用 PPT Tool
5.1 执行生成脚本
依赖 python-pptx 库,执行本技能的生成脚本:
pip install python-pptx
python <skill-dir>/scripts/build_deck.py
脚本读取 DATA 字典,输出 16:9(13.333 × 7.5 英寸)可编辑演示文稿。
build_pptx(data, output_path) 一次产出 4 个文件(同名不同后缀):
| 文件 | 内容 |
|---|---|
<name>.pptx | 演示文稿本体 |
<name>.speech.json | 逐页话术(交付物 ③ 的机器可读版) |
<name>.speech.md | 逐页话术(可直接贴进聊天正文) |
<name>.deck.json | 页 ↔ 章节元数据(供校验工具对齐检查) |
如需新增页面:照抄脚本里的页面函数模式:
add_slide() → header(s, idx, 结论型标题, 阶段标签) → 图形 → so_what(s, 结论句)
新增章节时,记得在 SECTION_KEYWORDS 里登记该章节的关键内容关键词,
否则校验工具无法逐页核对内容。
5.2 结构校验(必须执行)
调用能力中心里的 pptx_check 工具完成结构校验,产出 checks.json:
router.execute("pptx_check", {
"file_path": "<output>.pptx",
"expected_count": <页数>,
"must_contain": "异常科目归因,当期收缴率,人均,行动项",
"out": "<output>.checks.json",
})
它检查以下问题,并给出 pass / warn / fail 判定:
| 检查 | 说明 |
|---|---|
package / ooxml / open | 文件合法性、OOXML 包结构、能否打开 |
aspect | 是否 16:9 |
count | 页数是否符合预期 |
contains | 关键内容是否存在 |
section_content | 逐页核对「该章节该有的关键内容」 |
so_what | 每页底部是否有结论句(封面/路线图/附录豁免) |
overflow | 文字是否溢出形状(基于字体度量的估算) |
color_semantics | 是否只用了既定语义色 |
chart_data | 图表分类数/系列数是否与源一致 |
no_empty_slide | 是否有空白页 |
判定口径:任一 fail → 必须修完再交付;warn → 需人工确认(通常是估算误差)。
overflow是估算而非真实排版。报warn且条目很少时属正常; 条目很多或文本明显被裁切时,用 5.3 的视觉校验确认。若工具名不可用,退化为直接调用模块函数:
tool.common.pptx_check_tool.check_pptx(...)。
5.3 视觉校验(可选,视环境而定)
libreoffice --headless --convert-to png <file.pptx> --outdir preview
⚠ 环境可能未安装 LibreOffice。若不可用,退化为:
- 用
python-pptx读取每页形状与文字,人工核对关键页;或 - 用 PIL 按页面尺寸绘制近似缩略图(仅看版式分布,不等于真实渲染)。
逐页检查:文字有无被裁切、图表数字与数据源是否一致、颜色语义是否统一。
5.4 交付
同时交付三样:
- PPTX 文件 — 可编辑 16:9 演示文稿
- checks.json — 结构完整性校验报告(由
pptx_check产出,判定应为 pass) - 汇报话术 — 直接写在聊天正文中,格式见
references/03-汇报话术.md, 附时间分配表 + 领导追问预案(≥6 组)
陷阱与反模式
- ❌ 一上来就讲某个投诉纠纷 —— 没有经营底盘,听众抓不到轻重
- ❌ 通篇数字罗列 —— 只有"是多少",没有"为什么"和"所以呢"
- ❌ 只报偏差金额、不报责任人 —— 会上无法形成任务
- ❌ 用"客观因素"当解释 —— 必须落到具体事件
- ❌ 上月行动项不回头报 —— 汇报失去闭环
- ❌ 收缴率只报一个数 —— 必须拆当期 / 累计 / 陈欠 / 账龄
目录结构
ppt_skill/
├── SKILL.md # 本文件:五阶段流水线指令
├── references/
│ ├── 01-汇报逻辑.md # 六段式框架、页数控制、表达纪律
│ ├── 02-指标体系与归因.md # 指标口径表、三层归因、图表选择
│ └── 03-汇报话术.md # 逐页话术模板、时间分配、追问预案
├── assets/
│ └── 示例-物业项目月度经营分析.pptx
├── scripts/
│ └── build_deck.py # 生成脚本(改 DATA 即可复用)
└── checks.json # 历史校验报告样例(运行时由 pptx_check 重新生成)
依赖的能力工具
| 能力名 | 位置 | 用途 | 是否必须 |
|---|---|---|---|
pptx_check | tool/common/pptx_check_tool.py | 阶段 5.2 结构校验,产出 checks.json | 必须 |
| LibreOffice | 外部程序 | 阶段 5.3 视觉校验(转 PNG) | 可选,未装则退化 |
pptx_check 是独立于本技能的通用工具,通过能力中心提供:
from core.capability import CapabilityRouter
from tool.common.pptx_check_tool import PptxCheckTool
router = CapabilityRouter()
router.add_tool(PptxCheckTool()) # 技能与工具平级注册
技能不是 Tool,所以注册用
add_skill(build_capability_router会自动处理), 而pptx_check是工具,用add_tool。