mcpField
C
cja-executive-briefing

cja-executive-briefing

github.com/adobe数据与数据库316330 次安装1 天前更新
代码仓库

关于 cja-executive-briefing

cja-executive-briefing 是一项 Customer Journey Analytics 技能,可将表现数据整理为面向管理层的叙述,并提供指标依据。它会选择 KPI、比较日历对齐的时段,并在可能时分析重大变化涉及的维度。

主要功能

  1. 01面向管理层的表现叙述
  2. 02确定性选择最多 6 个 KPI
  3. 03按日历规则对齐时段
  4. 04分析变化最大的两个指标的驱动因素
  5. 05列出指标 ID 以便审计

适用场景

  1. 01准备管理层表现简报
  2. 02比较当前结果与上一时段
  3. 03用维度数据解释 KPI 的重大变化

MCP 相关

使用 CJA MCP 工具读取数据视图上下文、识别指标、获取报告,并比较维度级别的驱动因素。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/adobe/skills --skill cja-executive-briefing

安装后在 Claude Code 中输入/cja-executive-briefing确认已加载。

附带文件evals/evals.json

详细介绍

高管简报(客户旅程分析)

生成一份精致、适合领导层阅读的绩效文档。高管不会阅读数据表——他们更关注能回答“我们在增长吗?”“发生了哪些变化?”以及“我们该怎么做?”的叙述。

此技能会将 CJA 数据转化为一份 VP 或 C-suite 领导者可在不到 3 分钟内读完的简报,并为希望深入了解的人提供支持数据。

语气:侧重业务影响,而非技术指标。应写“营收增长了 12%,这得益于付费搜索表现强劲的一周”,而不是“metrics/revenue 增加了 0.12 per metrics/sessions”。


使用的 CJA MCP 工具

  • describeCja(DATAVIEW_CONTEXT_GUIDE) — 了解数据视图的业务背景
  • listComponentUsage — 确定北极星指标和辅助 KPI
  • findMetrics — 查询用户指定或发现的指标 ID
  • findCalculatedMetrics — 纳入自定义业务 KPI
  • runReport — 提取当前周期和对比周期的 KPI 数值
  • searchDimensionItems — 确定维度值中的主要驱动因素

阶段 0 — 设置

  1. 调用 findDataViews 列出可用的数据视图。
  2. 如果用户尚未指定数据视图,请展示列表并询问要使用哪一个。
  3. 使用所选 ID 调用 setDefaultSessionDataViewId。
  4. 确认报告周期(默认:过去 7 天)和简报的受众(高管、董事会、团队负责人)。

阶段 1 — 确定背景

1.1 加载数据视图背景

调用 describeCja("DATAVIEW_CONTEXT_GUIDE") 以了解:

  • 数据视图代表的业务类型(电子商务、媒体、SaaS 等)
  • 主要转化事件和营收指标
  • 日历约定和时区。 记录这些值——它们是 1.2 中每次日期计算的输入:
    • WEEK_START_DOW — 每周开始的星期几(星期日、星期一,……)。 如果背景指南未指定,默认:星期一(ISO 8601)。
    • FISCAL_YEAR_START_MONTH — 财年开始的月份。如果背景指南未指定,默认: 一月(日历年)。
    • TIMEZONE — 例如,America/Los_Angeles。
    • CALENDAR_SOURCE — 以下选项之一:"context guide"(值来自 describeCja)、 "default fallback"(背景指南未提供这些值,因而使用了上述默认值),或 "user override"(用户明确指定了这些值)。

此背景决定了什么应被视为“北极星指标”,以及叙述中应使用什么措辞(例如,“订阅者”与“客户”或“用户”)。

1.2 确定报告周期

根据用户请求推断周期类型。不要停下来询问——立即继续。

原则

在相同的数据视图、周期类型和提示词下运行此技能两次,必须生成完全相同的 current 和 comparison 日期范围。确定性来自:(a) 读取 1.1 中的日历约定,而不是自行推测;(b) 对相应周期类型应用对齐规则,不凭主观判断。

周期类型 → 对齐规则

从用户请求中准确选择一种周期类型:

用户请求PERIOD_TYPE当前周期对比周期
“上周” / 未指定weekly截至今天之前最近一个完整周,按 WEEK_START_DOW 对齐(正好 7 天)紧邻的前一周,采用相同对齐方式
“本月” / “MTD”month-to-date当前月 1 日 → 今天上个月 1 日 → 与今天相同的日号
“上个月”monthly上一个完整日历月(1 日 → 最后一天)再往前一个月
“本季度” / “QTD”quarter-to-date当前财季开始日 → 今天;根据 FISCAL_YEAR_START_MONTH 推导财季上一财季中对应的相同天数
“上季度” / “Q[N]”quarterly上一个完整财季再往前一个财季
自定义日期范围custom按指定范围以 current.startDate 前一天为结束日的等长时间窗口
通用不变量(必须适用于每种周期类型)

调用 runReport 前,验证以下六项:

  1. current.startDate < current.endDate
  2. comparison.startDate < comparison.endDate
  3. comparison.endDate < current.startDate(无重叠)
  4. comparison.endDate 的次日等于 current.startDate(连续)
  5. current 和 comparison 的天数相同
  6. 满足 PERIOD_TYPE 的对齐规则:
    • weekly:两个 startDate 都落在 WEEK_START_DOW
    • monthly:两个 startDate 都落在每月 1 日
    • month-to-date:两个 startDate 都落在每月 1 日;两个 endDate 的日相同
    • quarterly:两个 startDate 都落在财务季度的第一天
    • quarter-to-date:两个 startDate 都落在财务季度的起始日;两个 endDate 距季度起始日的天数相同
    • custom:天数相同;日期连续

如果任一不变量不成立,请重新计算日期。切勿通过修改页脚来掩盖不匹配。

示例:今天是 2026 年 5 月 26 日,星期二

这些示例假设数据视图的上下文指南返回 WEEK_START_DOW = Sunday 和 FISCAL_YEAR_START_MONTH = January。使用其他日历时数字会有所不同——这正是重点。

用户请求PERIOD_TYPE当前周期对比周期
“上周”weekly5 月 17 日(周日)– 5 月 23 日(周六)5 月 10 日(周日)– 5 月 16 日(周六)
“本月”/“MTD”month-to-date5 月 1 日 – 5 月 26 日4 月 1 日 – 4 月 26 日
“上个月”monthly4 月 1 日 – 4 月 30 日3 月 1 日 – 3 月 31 日
“本季度”/“QTD”quarter-to-date4 月 1 日 – 5 月 26 日1 月 1 日 – 2 月 24 日
“上季度”quarterly1 月 1 日 – 3 月 31 日2025 年 10 月 1 日 – 12 月 31 日
自定义:“5 月 15–22 日”custom5 月 15 日 – 5 月 22 日(8 天)5 月 7 日 – 5 月 14 日(8 天)

如果 WEEK_START_DOW = Monday,则每周一行变为 May 18 (Mon) – May 24 (Sun) 与 May 11 (Mon) – May 17 (Sun)。其他行不变。

常见的 AI 失败模式

AI 可能会根据训练数据“知道”一周是周一至周日(ISO 8601),或者季度是 Q1=1 月至 3 月(日历季度)。擅自用这些默认值覆盖上下文指南,正是本节旨在避免的确定性错误。页脚的方法说明必须准确描述你计算出的日期——如果页脚写着“每周从周日开始”,但 current.startDate 是星期一,那就是日期计算有误,需要修正日期,而不是页脚。

1.3 受众假设

默认面向内部领导层(VP、总监、高级经理)。这意味着:

  • 在叙述中包含具体的维度值(例如渠道名称)
  • 同样直接地呈现正面和负面发现
  • 读者了解你的业务,无需解释基本术语

如果用户说“外部”“董事会”或“投资者”,则转而关注更高层级的业务成果,删除可能敏感的内部渠道名称,并优先介绍最积极的发现。


第二阶段 — 发现北极星指标

提取使用最频繁的指标,以识别组织实际用什么来衡量成功。 并行运行两个调用——速度快,也为后续所有 KPI 决策奠定基础:

listComponentUsage(componentType: "metric")
listComponentUsage(componentType: "calculatedMetric")
确定性选择——不要自行发挥

对于相同的数据视图,KPI 集合在不同运行中必须可复现。同一时期运行两次此技能,必须得到相同的指标值,这就要求每次都选择相同的指标 ID。请严格遵循以下算法:

  1. 将两个 listComponentUsage 结果合并为一个排名列表。
  2. 按 usageCount 降序排序。若相同,则按指标 ID 的字母顺序排序(稳定的次级排序)。
  3. 使用 describeMetric 或 describeCalculatedMetric 将指标 ID 解析为易读的显示名称。
  4. 从排序列表中取前 6 个指标 ID。这就是 KPI 集合。

不要按指标“类型”(流量、转化或收入)挑选,也不要因为某个替代指标的名称更适合叙述就换用它。不同运行分别选中 metrics/orders 和 metrics/orders_1_1,会导致数值大相径庭,并损害简报的可信度。

用户明确指定指标时

如果用户在请求中指定了指标(“给我一份关于收入、订单和转化率的简报”),请通过 findMetrics 将每个名称解析为一个具体的指标 ID。如果名称匹配到多个指标(例如,“Orders”同时匹配 metrics/orders 和一个名为“Orders”的计算指标),请选择 usageCount 最高的指标,并记录这一选择。

始终披露所用的指标 ID

在简报产物的页脚中加入一行简短的“包含的指标”,列出解析出的指标 ID(例如:metrics/orders_1_1、metrics/visits、metrics/page_views)。这样报告可供审计,用户也能确认重新运行时使用的是相同指标。

最多 6 个 KPI。更多只会带来噪声。


阶段 3 — 获取 KPI 数据

并行运行两份报告——当前时期和对比时期——并包含所有选定指标。使用日期维度(例如 variables/daterangeday),使报告返回整个时期的汇总总值。响应中的 summaryData.totals 数组包含所需的汇总值。

runReport(
  startDate: "<current period start>T00:00:00",
  endDate: "<current period end>T00:00:00",
  dimensionIds: "variables/daterangeday",
  metricIds: "metrics/visits,metrics/orders_1_1,metrics/revenue_1,...",
  page: 0,
  limit: 1
)
runReport(
  startDate: "<prior period start>T00:00:00",
  endDate: "<prior period end>T00:00:00",
  dimensionIds: "variables/daterangeday",
  metricIds: "metrics/visits,metrics/orders_1_1,metrics/revenue_1,...",
  page: 0,
  limit: 1
)

读取每个响应中的 summaryData.filteredTotals——这些值与 metricIds 中指定的指标顺序相对应。

针对每个 KPI 计算:

  • current 值
  • prior 值
  • delta = current − prior
  • pctChange = delta / prior × 100
  • direction:上升 / 下降 / 持平(采用 ±3% 阈值)
  • polarity:若数值越高越好则为正向,若越低越好则为负向
  • signal:绿色(有利)、红色(不利)、黄色(混合 / 持平)

阶段 4 — 找出变化的驱动因素

针对绝对百分比变化最大的 2 个 KPI,找出主要驱动因素:

并行运行当前时期和前一时期的细分报告:

runReport(
  startDate: "<current period start>",
  endDate: "<current period end>",
  dimensionIds: "variables/marketing_channel",
  metricIds: "<top-moved metric id>",
  limit: 5
)
runReport(
  startDate: "<prior period start>",
  endDate: "<prior period end>",
  dimensionIds: "variables/marketing_channel",
  metricIds: "<top-moved metric id>",
  limit: 5
)

比较各时期的渠道级数值,找出变化值最接近整体指标变化的维度值。这将成为叙述中的“驱动因素”表述。

仅针对变动最大的 2 个指标(按绝对百分比变化计算)运行维度细分。此限制的原因是:(a) 更多细分会增加延迟,却不会带来更多高管层面的价值;(b) 领导层首先会关注变动最大的两个指标。其余 KPI 通过叙述补充背景,无需归因。

如果 variables/marketing_channel 未返回有用的细分结果(例如,只有一个渠道有数据),请尝试使用 variables/page_type 或 variables/product_category 作为替代驱动维度。

第 5 阶段 — 撰写高管叙述

将叙述整理成 3–5 条要点。每条要点遵循以下结构:

[信号表情符号] [指标]:[值](较[上一时段][+/-百分比变化%])— [通俗易懂的背景说明]

指南:

  • 以最重要的发现开头(影响最大的指标,无论正面还是负面)
  • 使用业务语言:“收入”“客户”“转化”——不要写“指标/收入”
  • 已知驱动因素时应明确指出:“由付费搜索带动”“产品页面优化带动”
  • 如有必要,加入一条前瞻性说明:“应持续关注这一趋势……”
  • 对于负面趋势,应直截了当,但不要危言耸听。建议调查原因,而不是惊慌失措。

写得好的要点示例:

  • “上周收入达到 $1.24M,较前一周增长 8.2%——付费搜索带动了大部分增幅(+$82K)。”
  • “转化率降至 2.1%(−0.4pp),主要出现在移动端。桌面端转化率保持稳定,为 3.4%。”
  • “会话数持平于 540K(+1.1%)——自然流量和直接流量抵消了邮件营销活动发送量的减少。”
  • “跳出率小幅上升至 43%(+2pp)。尚未发现单一驱动因素;值得持续关注至月底。”

第 6 阶段 — 生成 HTML 简报文档

直接生成简报。写入 /tmp/cja_executive_briefing_<YYYY-MM-DD_HHMMSS>.html。 这份文档应经过精心设计,达到可分享给管理层的水准,而不是看起来像 开发者工具的输出。

渲染规则 — 每次运行时一致应用

在相同数据视图和时段上运行此技能两次,渲染结果必须完全一致 (生成时间戳除外)。以下规则用于固定格式选择,避免 AI 在这些方面出现偏差。

数字格式
  • KPI 值(每个卡片中的大号数字)——使用完整数字并添加 千位分隔符(8,160、77,584、1,250,000)。即使数值很大,也不得使用 K 或 M 等 SI 后缀。高管需要精确数字,而不是缩写。
  • 百分比变化(胶囊标签和叙述要点中)——始终保留一位小数, 按远离零方向舍入。例如,−23.55% 显示为 −23.6%,绝不显示为 −23.5%。基于完整精度的数值进行计算,只在 显示时舍入。
  • 百分点变化(适用于转化率或跳出率等本身已是百分比的指标)——舍入规则相同,后缀为 pp。例如:+0.40 pp。
  • 货币——以 $ 开头,使用千位分隔符;金额 ≥ $100 时不显示小数($1,240,000);金额 < $100 时显示美分($45.20)。
空值/缺失数据处理

KPI 卡片必须如实反映数据视图实际返回的内容。AI 不得悄悄替换为其他指标,也不得为了让简报更整洁而隐藏卡片。

  • 对于已解析指标集中的某个指标,如果两个时段都返回 0 或 NULL:渲染卡片,kpi-value = Data unavailable,胶囊标签类名为 flat,胶囊标签文本为 ⚠ N/A,prior 文本 = Both periods returned no data — validate instrumentation。卡片必须保留在网格中,不得省略。
  • 如果一个时段返回有效数据,另一个时段返回 0 / NULL:渲染卡片,kpi-value 使用有效值,胶囊标签类名为 flat,胶囊标签文本为 ⚠ N/A,prior 文本 = Prior {period_noun}: no data。
  • 绝不得替换为派生指标(例如,收入返回 $0 时擅自添加“转化率”)。可见的 KPI 集合必须与页脚中披露的已解析指标 ID 一致。
  • 如果收入/货币指标不可用,应在 KPI 网格上方显示 .callout.note,说明数据缺失情况。不得编造数值。
模板变量

按照以下规则填充下面 HTML 模板中的每个 {PLACEHOLDER}。 简报属于客户——绝不要在面向客户的字段中使用 Adobe、CJA 或任何供应商的措辞。

  • {ORG_NAME} — 客户的企业或品牌名称,根据第 1 阶段第 1.1 节中加载的数据视图上下文确定。移除 — Prod、 - Demo、 Stage、 Test、 MCP 等技术性/环境后缀。如果数据视图名称中没有清晰的品牌名称,则移除后缀后使用数据视图显示名称。不要编造名称,也不要替换为供应商名称。
  • {PERIOD_TYPE} — 从 Weekly、Monthly、Quarterly 或 Performance(默认)中选择,根据第 1 阶段第 1.2 节推断的周期确定。
  • {LEDE_SENTENCE} — 严格使用以下模式,不得包含供应商名称: Leadership readout for the {period type lowercase} of {PERIOD_LABEL} compared to {COMPARISON_LABEL}. 示例:Leadership readout for the week of May 12–18, 2026 compared to May 5–11, 2026.
  • {DATA_VIEW} — findDataViews 返回的数据视图显示名称。可以保留后缀——这一行是技术标识行,而非标题。
  • {PERIOD_LABEL} / {COMPARISON_LABEL} — 易读的日期范围,例如 May 12–18, 2026。
  • {GENERATED_DATE} — 今天的日期,使用相同的易读格式,例如 May 23, 2026。
  • {METRIC_LABEL} / {FORMATTED_VALUE} / {PCT_CHANGE} / {PRIOR_VALUE} — 第 3 阶段中每项 KPI 对应的值。使用面向客户的指标显示名称,不要使用内部 ID。
HTML 模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Performance Briefing &mdash; {ORG_NAME} &mdash; {PERIOD}</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;900&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  :root {
    --bg: #f5f4f1;
    --surface: #ffffff;
    --ink: #1a1a1a;
    --ink-muted: #6b6b6b;
    --border: #e5e2dc;
    --header-bg: #0e0e10;
    --header-warm: #3a1010;
    --accent-red: #c8312f;
    --accent-red-bright: #ff6b68;
    --accent-red-soft: #fdecea;
    --accent-green: #1f7a4d;
    --accent-yellow: #d4a017;
  }
  body { font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
         background: var(--bg); color: var(--ink); line-height: 1.5;
         -webkit-font-smoothing: antialiased; }

  /* === Header === */
  header { background: linear-gradient(120deg, var(--header-bg) 0%, #1a0d0d 55%, var(--header-warm) 100%);
           color: #fff; padding: 56px 56px 44px; position: relative; overflow: hidden; }
  header::after { content: ""; position: absolute; right: -140px; top: -140px;
                  width: 460px; height: 460px;
                  background: radial-gradient(circle, rgba(200,49,47,.35) 0%, transparent 70%);
                  pointer-events: none; }
  .header-inner { max-width: 1080px; margin: 0 auto; position: relative; z-index: 1; }
  .eyebrow { display: inline-flex; align-items: center; gap: 8px;
             padding: 6px 14px; border: 1px solid rgba(255,107,104,.55);
             border-radius: 999px; color: var(--accent-red-bright);
             font-size: 11px; font-weight: 600; letter-spacing: 1.2px;
             text-transform: uppercase; margin-bottom: 24px;
             background: rgba(200,49,47,.10); }
  .eyebrow::before { content: ""; width: 6px; height: 6px;
                     background: var(--accent-red-bright); border-radius: 50%; }
  header h1 { font-family: "Playfair Display", Georgia, serif;
              font-size: 56px; font-weight: 700; letter-spacing: -1.5px;
              line-height: 1.05; margin-bottom: 14px; }
  header .lede { font-size: 16px; max-width: 560px;
                 color: rgba(255,255,255,.80); margin-bottom: 24px;
                 line-height: 1.55; }
  header .meta { display: flex; flex-wrap: wrap; gap: 22px;
                 font-size: 13px; color: rgba(255,255,255,.60); }
  header .meta span { display: inline-flex; align-items: center; gap: 6px; }
  header .meta .icon { opacity: .8; }

  /* === Tabs === */
  nav { background: var(--surface); border-bottom: 1px solid var(--border);
        padding: 0 56px; display: flex; gap: 28px;
        position: sticky; top: 0; z-index: 50; }
  nav a { display: block; padding: 16px 0; font-size: 14px;
          color: var(--ink); text-decoration: none;
          border-bottom: 2px solid transparent;
          transition: border-color .15s ease; }
  nav a:hover { border-bottom-color: var(--accent-red); }

  /* === Container === */
  .container { max-width: 1080px; margin: 0 auto; padding: 36px 56px 60px; }

  /* === Callout === */
  .callout { background: var(--accent-red-soft);
             border-left: 4px solid var(--accent-red);
             border-radius: 6px;
             padding: 18px 22px; margin-bottom: 32px;
             display: flex; gap: 14px; align-items: flex-start; }
  .callout .warn-icon { font-size: 22px; line-height: 1; flex-shrink: 0;
                        color: var(--accent-yellow); }
  .callout-title { font-weight: 700; color: var(--accent-red);
                   margin-bottom: 4px; font-size: 15px; }
  .callout-body { font-size: 14px; color: #4a2222; line-height: 1.55; }
  .callout.note { background: #fdf6e7; border-left-color: var(--accent-yellow); }
  .callout.note .callout-title { color: #8a5a08; }
  .callout.note .callout-body { color: #5a4108; }

  /* === Section label === */
  .section-label { font-size: 11px; font-weight: 700;
                   text-transform: uppercase; letter-spacing: 1.4px;
                   color: var(--ink-muted); margin-bottom: 14px;
                   padding-bottom: 10px; border-bottom: 1px solid var(--border); }

  /* === KPI grid === */
  .kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
             gap: 14px; margin-bottom: 36px; }
  .kpi-tile { background: var(--surface); border-radius: 8px;
              padding: 22px 22px 20px;
              border-top: 3px solid #b9b6ae;
              box-shadow: 0 1px 3px rgba(0,0,0,.05); }
  .kpi-tile.down { border-top-color: var(--accent-red); }
  .kpi-tile.up   { border-top-color: var(--accent-green); }
  .kpi-tile.flat { border-top-color: #b9b6ae; }
  .kpi-head { display: flex; justify-content: space-between;
              align-items: center; margin-bottom: 10px; }
  .kpi-label { font-size: 11px; font-weight: 700;
               text-transform: uppercase;
               color: var(--ink-muted); letter-spacing: 1px; }
  .kpi-value { font-family: "Playfair Display", Georgia, serif;
               font-weight: 700; font-size: 38px;
               line-height: 1; color: var(--ink);
               margin-bottom: 12px; }
  .pill { display: inline-flex; align-items: center; gap: 4px;
          padding: 3px 9px; border-radius: 4px;
          font-size: 12px; font-weight: 600; line-height: 1.4; }
  .pill.down { background: var(--accent-red-soft); color: var(--accent-red); }
  .pill.up   { background: #ebf5ef; color: var(--accent-green); }
  .pill.flat { background: #f1efea; color: var(--ink-muted); }
  .prior { display: block; margin-top: 10px;
           font-size: 12px; color: var(--ink-muted); }

  /* === Narrative === */
  .narrative-card { background: var(--surface); border-radius: 8px;
                    padding: 32px 36px;
                    box-shadow: 0 1px 3px rgba(0,0,0,.04);
                    margin-bottom: 24px; }
  .narrative-card h2 { font-family: "Playfair Display", Georgia, serif;
                       font-size: 24px; font-weight: 700;
                       margin-bottom: 18px;
                       padding-bottom: 12px;
                       border-bottom: 1px solid var(--border); }
  .bullet-list { list-style: none; }
  .bullet-list li { padding: 14px 0; font-size: 15px; line-height: 1.65;
                    border-bottom: 1px solid #f1eeea; }
  .bullet-list li:last-child { border-bottom: none; }
  .bullet-list .signal { margin-right: 6px; }
  .bullet-list .metric-highlight { font-weight: 700; }
  .bullet-list .driver { color: var(--accent-red); font-style: italic; }

  /* === Sections (collapsible tables) === */
  .section { background: var(--surface); border-radius: 8px;
             box-shadow: 0 1px 3px rgba(0,0,0,.04);
             margin-bottom: 22px; overflow: hidden; }
  .section-header { padding: 18px 28px; border-bottom: 1px solid var(--border);
                    display: flex; justify-content: space-between;
                    align-items: center; cursor: pointer; }
  .section-header h2 { font-family: "Playfair Display", Georgia, serif;
                       font-size: 18px; font-weight: 700; }
  table { width: 100%; border-collapse: collapse; font-size: 13px; }
  thead th { background: #faf8f4; padding: 12px 22px;
             text-align: left; font-weight: 600;
             text-transform: uppercase; letter-spacing: .6px;
             font-size: 11px; color: var(--ink-muted);
             border-bottom: 1px solid var(--border); }
  tbody td { padding: 12px 22px; border-bottom: 1px solid #f4f1eb; }
  tbody tr:last-child td { border-bottom: none; }

  .badge { display: inline-block; padding: 3px 9px; border-radius: 4px;
           font-size: 11px; font-weight: 600; }
  .badge.green  { background: #ebf5ef; color: var(--accent-green); }
  .badge.red    { background: var(--accent-red-soft); color: var(--accent-red); }
  .badge.yellow { background: #fef6e3; color: #b67a08; }
  .badge.grey   { background: #f1efea; color: var(--ink-muted); }

  footer { text-align: center; padding: 32px 24px;
           font-size: 12px; color: var(--ink-muted); }

  /* === Print === */
  @media print {
    nav { display: none; position: static; }
    header { padding: 36px 32px 28px; }
    header h1 { font-size: 42px; }
    .section-header { cursor: default; }
    .kpi-row { page-break-inside: avoid; }
    .kpi-tile, .narrative-card, .section {
      box-shadow: none; border: 1px solid var(--border);
    }
  }
</style>
</head>
<body>

<header>
  <div class="header-inner">
    <div class="eyebrow">{PERIOD_TYPE} Performance Briefing</div>
    <h1>{ORG_NAME} Performance</h1>
    <p class="lede">{LEDE_SENTENCE}</p>
    <div class="meta">
      <span><span class="icon">&#128197;</span> {PERIOD_LABEL}</span>
      <span><span class="icon">&#128202;</span> {DATA_VIEW}</span>
      <span><span class="icon">&#128340;</span> Prepared {GENERATED_DATE}</span>
    </div>
  </div>
</header>

<nav>
  <a href="#highlights">Highlights</a>
  <a href="#narrative">Summary</a>
  <a href="#data">KPI Detail</a>
  <a href="#drivers">Drivers</a>
</nav>

<div class="container">

  
  

  
  <div class="section-label">Key Performance Indicators</div>
  <div id="highlights" class="kpi-row">
    
  </div>

  
  <div id="narrative" class="narrative-card">
    <h2>Executive Summary</h2>
    <ul class="bullet-list">
      
    </ul>
  </div>

  
  <div id="data" class="section">
    <div class="section-header" onclick="toggle('data-body')">
      <h2>Full KPI Detail</h2>
      <span id="data-body-icon">&#9662;</span>
    </div>
    <div id="data-body">
      <table>
        <thead><tr>
          <th>Metric</th>
          <th>{PERIOD_LABEL}</th>
          <th>{COMPARISON_LABEL}</th>
          <th>Change</th>
          <th>% Change</th>
          <th>Signal</th>
        </tr></thead>
        <tbody>
          
        </tbody>
      </table>
    </div>
  </div>

  
  <div id="drivers" class="section">
    <div class="section-header" onclick="toggle('drv-body')">
      <h2>What Drove the Movement</h2>
      <span id="drv-body-icon">&#9662;</span>
    </div>
    <div id="drv-body">
      <table>
        <thead><tr>
          <th>Metric</th>
          <th>Top Driver</th>
          <th>Value This Period</th>
          <th>Value Prior Period</th>
          <th>Contribution</th>
        </tr></thead>
        <tbody>
          
        </tbody>
      </table>
    </div>
  </div>

</div>

<footer>
  Performance Briefing &mdash; {ORG_NAME} &mdash; Generated {GENERATED_DATE}<br>
  <span style="opacity:.7">
    Methodology: {PERIOD_TYPE}
    &middot; current {CURRENT_START_ISO}&ndash;{CURRENT_END_ISO}
    &middot; comparison {COMPARISON_START_ISO}&ndash;{COMPARISON_END_ISO}
    &middot; week starts {WEEK_START_DOW}
    &middot; fiscal year starts {FISCAL_YEAR_START_MONTH}
    &middot; tz {TIMEZONE}
    &middot; calendar source: {CALENDAR_SOURCE}
    &middot; metrics: {METRIC_IDS_CSV}
  </span>
</footer>

<script>
function toggle(id) {
  var el = document.getElementById(id);
  var ic = document.getElementById(id + '-icon');
  if (el.style.display === 'none') { el.style.display=''; ic.textContent='\u25be'; }
  else { el.style.display='none'; ic.textContent='\u25b8'; }
}
</script>
</body></html>

第 7 阶段 — 交付简报

  1. 将 HTML 写入 /tmp/cja_executive_briefing_<YYYY-MM-DD_HHMMSS>.html
  2. 使用 open /tmp/cja_executive_briefing_<YYYY-MM-DD_HHMMSS>.html 打开
  3. 直接在聊天中输出叙述性要点,以便用户立即复制并粘贴到电子邮件或演示文稿中——HTML 是“附录”。

聊天中的格式:

Performance Briefing — Last Week vs Prior Week
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📈 Revenue: $1.24M (+8.2%) — Paid Search drove the majority of the gain.
📉 Conversion Rate: 2.1% (−0.4pp) — Mobile checkout declined; desktop stable.
➡  Sessions: 540K (+1.1%) — Essentially flat; organic offset email decline.
📈 Orders: 11,340 (+6.7%) — Product page improvements appear to be contributing.
⚠️  Bounce Rate: 43% (+2pp) — No clear driver identified; monitor next week.

Full briefing document: /tmp/cja_executive_briefing_<YYYY-MM-DD_HHMMSS>.html

语气和风格规则

  1. 写结果,不写活动。 写“收入增长了”,不要写“metrics/revenue 增加了”。
  2. 简洁地指出驱动因素。 写“付费搜索推动了增长”,不要写“Marketing Channel = Paid Search 在周期 A 的值高于周期 B”。
  3. 每条要点写一个句子。 最多两个句子。高管会快速浏览。
  4. 把最重要的发现放在开头。 不要层层铺垫才得出结论。
  5. 对坏消息直言不讳。 写“转化率下降了”,不要写“转化率出现了一些向下的变化”。
  6. 所有内容都要量化。 每条要点都必须包含数字。没有数据支撑的观点不属于高管沟通内容。
  7. 避免行话。 输出中不要出现“维度”“指标 ID”“数据视图上下文”或“MCP 工具调用”。

重要注意事项

  • 仅限只读报告。 切勿修改指标、细分或项目。
  • 使用业务语言,不要使用技术 ID。 将维度 ID(例如 variables/evar5)替换为其显示名称。叙述中绝不公开内部 ID。
  • 始终醒目地注明日期范围。 高管需要了解背景——“上周”含义模糊;请写成“2026 年 4 月 7 日至 13 日”。
  • 不要编造数据。 如果某项 KPI 不可用或报告未返回数据,请明确说明,而不是省略或估算。
  • 简报只聚焦最重要的发现。 最理想的是 3–5 个 KPI 卡片和 2–3 条驱动因素;KPI 超过 8 项会削弱信息传达效果。
  • 注明重要背景。 相关时,提及会影响指标的已知外部因素(营销活动、节假日、产品发布)。
  • 呈现前验证数据。 如果 KPI 数值看起来异常,请通过第二次 runReport 调用进行交叉核对。
  • 使用客户品牌,不使用供应商品牌。 简报是客户关于自身业务的文档。在面向客户的简报中(标题、导语、叙述、表格、页脚或聊天内容),绝不要使用 “Adobe”、“CJA”、“Customer Journey Analytics” 或任何供应商/产品名称。红黑配色的页眉是报告中唯一允许使用的 Adobe 品牌元素。

交互示例

“为我撰写一份上周业绩的执行简报。”

  1. 设置: 使用 findDataViews 确认数据视图。用户选择其主要数据视图。调用 setDefaultSessionDataViewId。
  2. 范围: 确认报告周期(过去 7 天,即 2026 年 4 月 7 日至 13 日)和关键 KPI(收入、转化率、会话数、AOV)。
  3. 提取数据: 针对每项 KPI 运行 runReport,比较本周与上周,以及与去年同一周的数据。
  4. 起草叙述: 使用业务语言撰写 3–4 条高管要点:“收入为 240 万美元,环比增长 8%,这主要得益于付费搜索带来的转化量增长 15%。转化率下降 2 个百分点至 3.1%,这与 4 月 9 日推出的产品页面改版一致。”
  5. HTML 报告: 生成可直接打印的 HTML 简报,包含 KPI 卡片、叙述部分和驱动因素表格。打开文件。向用户提供 2 句话的摘要,并询问是否需要调整语气或范围。

评论

支持 Markdown