# 在企业内网复制一个数据分析 Agent：从上下文层到离线评估

> 本文整理自 GitHub Blog《How we built an internal data analytics agent》。原文讲的是 GitHub 内部的 Qubot：员工可以在 Slack、VS Code 或 Copilot CLI 中用自然语言查询数据仓库。本文改写为企业内网可复制的实施教程。
>
> Source URL: https://github.blog/ai-and-ml/github-copilot/how-we-built-an-internal-data-analytics-agent/

## 适用场景

这套方法适合已经有数据仓库、BI/数据团队、内部协作工具，并且希望降低业务团队“问数”门槛的企业。

优先适用：

- 产品、运营、业务团队经常问“哪个用户群体留存更高”“上周哪个产品拉动了指标”。
- 数据团队被大量重复性查询打断，复杂分析反而排不上队。
- 数据仓库里有大量可用数据，但业务口径、表粒度、过滤条件分散在文档和人员经验里。
- 企业已有内网 IM、代码平台、文档仓库、权限系统和数据查询引擎。

不建议一开始就做成“全自动决策系统”。更稳妥的目标是：先做一个内部探索式数据助手，帮助员工更快找到表、生成查询、解释结果，并保留人工复核边界。

## 最小可复制架构

把系统拆成三层：

1. **用户入口**：内网 IM、IDE 插件、CLI 或企业门户。
2. **上下文层**：指标定义、表说明、业务口径、数据血缘、常见过滤条件。
3. **查询引擎层**：连接数据仓库或查询服务，执行 SQL/KQL 等查询。

推荐先画出这样的边界：

```text
员工问题
  ↓
内网入口（IM / IDE / CLI / 企业门户）
  ↓
Agent 编排层
  ├─ 读取上下文层：指标、表、口径、权限、示例查询
  ├─ 选择查询引擎：近期事件 / 历史分析 / 复杂 Join
  ├─ 生成并执行查询
  └─ 生成 Markdown 分析报告
  ↓
结果返回：会话回复 + 可追溯报告链接
```

企业内网复制时，先不要追求多入口。建议从 **IM 群聊入口 + Markdown 报告归档** 开始，因为它最容易形成团队协作和复核记录。

## 第 1 步：先定义 Agent 不做什么

这是最容易被忽略的一步。原文明确说 Qubot 不是报表工具或仪表盘替代品，而是用于探索性问题。

企业内网版本也应先写清边界：

```markdown
# 数据分析 Agent 使用边界

## 适合的问题
- 这个指标最近一周为什么波动？
- 哪个用户 cohort 的留存更高？
- 某个功能上线后相关行为有没有变化？
- 我应该查哪张表、用哪个口径？

## 不适合的问题
- 需要正式财务披露或审计口径的问题
- 会直接触发业务动作的问题
- 涉及敏感个人数据但用户无权限的问题
- 跨多个系统且没有明确定义口径的问题

## 输出要求
- 必须展示使用的数据集、时间窗口、过滤条件
- 必须提供生成的查询语句或报告链接
- 对低置信度答案必须标注“需要数据分析师复核”
```

验收标准：业务用户知道它适合“探索”，数据团队知道哪些问题必须人工接管。

## 第 2 步：整理数据分层，而不是让 Agent 猜表

GitHub 文中把数据仓库分为三类：

- bronze：原始事件数据；
- silver：标准化事实表和维度表；
- gold：面向具体业务场景的精选数据集。

企业可以用自己的命名，但要保留这三类含义。

可复制模板：

```markdown
# 数据集分层说明

## 原始层
- 用途：事件回放、低层排查、近期行为探索
- 风险：字段含义可能不稳定，业务用户不应直接使用
- Agent 策略：仅在问题需要近期事件明细时使用

## 标准层
- 用途：稳定事实表、维度表、常规分析
- 风险：需要理解粒度、主键、时间字段
- Agent 策略：默认优先使用

## 业务层
- 用途：核心业务指标、管理看板、对外口径
- 风险：口径变更需要审批
- Agent 策略：涉及正式指标时优先使用，并展示口径说明
```

落地建议：先覆盖 5–10 个最高频数据集，不要一开始接入全仓库。

## 第 3 步：建立上下文层，把文档变成一等资产

原文最重要的经验是：结构化、维护良好的上下文会显著提升 Agent 的准确性和响应速度。GitHub 称实验中获取正确答案的速度提升了 3 倍，但这个数字只代表其内部环境，不应直接当作通用承诺。

企业内网可先用 Markdown 管理上下文，因为它容易进入代码评审、版本管理和变更审计。

### 数据集上下文模板

```markdown
# 数据集：product_feature_events

## 业务含义
记录用户在产品功能中的关键行为事件，用于分析功能使用、转化和留存。

## 推荐使用场景
- 分析某功能上线后的使用趋势
- 按用户 cohort 比较留存
- 排查某个事件是否采集异常

## 不推荐使用场景
- 财务收入分析
- 正式月度经营报表
- 需要跨产品线统一口径的指标

## 粒度
一行代表一次用户行为事件。

## 关键字段
- user_id：用户 ID；需要遵守权限策略
- event_name：事件名称
- event_time：事件发生时间，UTC
- feature_name：功能名称
- plan_type：用户套餐类型

## 常用过滤条件
- 排除内部测试账号
- event_time 使用业务分析窗口
- feature_name 必须匹配标准枚举

## 示例问题
- 最近 7 天哪个套餐用户使用 feature_x 最多？
- feature_x 上线后，新用户 7 日留存是否变化？

## 示例查询
```sql
SELECT
  plan_type,
  COUNT(DISTINCT user_id) AS users
FROM product_feature_events
WHERE event_name = 'feature_used'
  AND feature_name = 'feature_x'
  AND event_time >= CURRENT_DATE - INTERVAL '7' DAY
GROUP BY plan_type
ORDER BY users DESC;
```

## 负责人
数据 Owner：数据平台组  
业务 Owner：产品分析组
```

注意：模板里的 SQL 是示例，不是原文提供的代码。正式落地时应替换成企业自己的表名、字段和权限规则。

## 第 4 步：设计上下文贡献流程

GitHub 的做法是让团队通过标准模板或关联文档仓库贡献上下文，并由 Context Agent 进行整理和规范化。

企业可复制成一条 PR 流程：

```text
业务/数据团队提交上下文 PR
  ↓
自动检查模板字段是否完整
  ↓
Context Agent 规范化：字段、口径、示例问题、示例查询
  ↓
离线评估：准确率、延迟、回归
  ↓
数据 Owner 审核
  ↓
合并进入上下文层
```

建议的 PR 检查清单：

```markdown
# 上下文贡献 PR 检查

- [ ] 数据集业务含义已写清
- [ ] 粒度、主键、时间字段已写清
- [ ] 常用过滤条件已写清
- [ ] 至少包含 2 个示例问题
- [ ] 至少包含 1 个示例查询
- [ ] 标明数据 Owner 和业务 Owner
- [ ] 涉及敏感字段时写明权限限制
- [ ] 已通过离线评估集
```

验收标准：上下文更新不靠私聊和口头经验，而是可以审查、回滚、比较。

## 第 5 步：连接查询引擎，并显式写出路由规则

原文中 Qubot 连接 Kusto 和 Trino：Kusto 更适合近期事件探索，Trino 更适合复杂 Join 和历史分析。企业内网可以替换成自己的查询系统，例如 ClickHouse、Trino、Presto、Hive、Doris、DuckDB、PostgreSQL 或内部查询服务。

关键不是具体用哪个引擎，而是让 Agent 知道何时选择哪个引擎。

```yaml
query_engines:
  fast_event_engine:
    suitable_for:
      - 最近事件探索
      - 简单聚合
      - 低延迟互动查询
    avoid_for:
      - 复杂跨域 Join
      - 长历史窗口
      - 正式经营口径

  warehouse_engine:
    suitable_for:
      - 多表 Join
      - 历史趋势分析
      - 业务层 gold 数据集
    avoid_for:
      - 秒级互动探索
      - 未建模的原始事件排查
```

最低要求：每次回答都展示使用了哪个引擎、为什么使用它、查询语句是什么。

## 第 6 步：先做报告归档，再做漂亮界面

GitHub 的 Slack 入口会把结果保存成 Markdown 报告，用户可以引用它微调查询或放入 dashboard。

企业内网也建议先保存报告，原因很简单：可追溯比界面好看更重要。

报告模板：

```markdown
# 数据分析 Agent 报告

## 用户问题
{原始问题}

## 问题解释
{Agent 对问题的理解}

## 使用数据
- 数据集：{dataset}
- 数据层级：{bronze/silver/gold 或企业等价分层}
- 查询引擎：{engine}
- 时间窗口：{time_window}
- 过滤条件：{filters}

## 查询语句
```sql
{sql}
```

## 结果摘要
{核心结果，避免过度解释}

## 置信度
- 高：上下文明确，字段和口径稳定
- 中：存在轻微口径歧义，但不影响方向判断
- 低：需要数据分析师复核

## 后续建议
{可选：下一步追问或人工复核建议}
```

验收标准：任何重要回答都能回到报告，看到原始问题、查询、口径和结果。

## 第 7 步：用离线评估保护上下文层

原文中，每次上下文层或 Agent 配置变更都会进入离线评估，评估准确率、找到正确答案的延迟，并捕捉回归。

企业复制时，不需要一开始做复杂评测平台。先维护一个黄金测试集即可。

### 评估集模板

```json
{
  "id": "retention_feature_x_by_plan",
  "question": "feature_x 上线后，不同套餐用户的 7 日留存有什么变化？",
  "expected_datasets": ["product_feature_events", "user_retention_daily"],
  "expected_filters": ["exclude_internal_users", "feature_name = feature_x"],
  "expected_time_window": "launch_date +/- 28 days",
  "expected_output_contains": ["plan_type", "7_day_retention", "pre_launch", "post_launch"],
  "manual_review_required": true
}
```

### 评估流程

```text
准备 20–50 个高频问题
  ↓
每个问题运行 Agent N 次
  ↓
记录使用的数据集、查询引擎、SQL、结果摘要、耗时
  ↓
与期望数据集、过滤条件、输出字段比较
  ↓
生成评估报告
  ↓
阻止明显回归的上下文/配置变更合并
```

建议指标：

- 数据集选择正确率；
- 必要过滤条件覆盖率；
- 查询可执行率；
- 平均响应时间；
- 低置信度标注召回率；
- 与上一版本相比是否回归。

验收标准：上下文变更前后能比较，而不是靠“感觉更聪明”。

## 第 8 步：权限和安全边界必须前置

原文没有展开权限实现细节，因此这一节是企业落地时的必要补充，不应理解为 GitHub 原文已给出的完整方案。

最小安全要求：

- Agent 只能使用调用者已有的数据权限；
- 敏感字段默认不可直接返回明细；
- 对包含个人信息、财务、合同、客户敏感数据的问题强制人工复核；
- 查询语句、调用人、数据集、时间窗口必须记录审计日志；
- 禁止 Agent 绕过数据平台直接访问生产库。

权限检查清单：

```markdown
# 数据分析 Agent 安全检查

- [ ] 调用身份来自企业 SSO
- [ ] 数据权限按用户身份下推，而不是使用共享超级账号
- [ ] 敏感字段有脱敏或聚合规则
- [ ] 查询结果有行数和成本限制
- [ ] 所有查询有审计日志
- [ ] 高风险问题进入人工复核队列
```

## 第 9 步：分阶段上线

不要一次性把全公司数据仓库暴露给 Agent。推荐四阶段：

### 阶段 1：只读 PoC

范围：1 个业务域、5 个数据集、20 个评估问题。  
目标：验证上下文层是否能让 Agent 稳定选对表、生成可执行查询。

通过标准：

- 高频问题中大部分能选对数据集；
- 查询失败原因可归类；
- 所有回答都有报告和审计记录。

### 阶段 2：内测群

范围：数据团队 + 1–2 个业务团队。  
目标：验证真实追问、报告归档、人工复核流程。

通过标准：

- 业务用户能独立完成探索性问数；
- 数据团队重复性问答减少；
- 高风险问题没有绕过人工复核。

### 阶段 3：上下文贡献开放

范围：允许各团队提交上下文 PR。  
目标：让领域知识进入统一上下文层，而不是散落在个人文档里。

通过标准：

- PR 模板完整；
- 每次上下文更新都跑离线评估；
- 回归能阻止合并。

### 阶段 4：多入口扩展

范围：从 IM 扩展到 IDE、CLI、企业门户。  
目标：让不同角色在自己的工作流中使用同一个能力。

通过标准：

- 多入口共享同一上下文层；
- 权限策略一致；
- 报告归档和审计日志一致。

## 常见失败模式

### 失败 1：只接模型，不建上下文层

表现：Agent 会写 SQL，但经常选错表、错口径、漏过滤条件。  
处理：暂停扩入口，先补数据集上下文和黄金测试集。

### 失败 2：上下文谁都能改，但没有评估

表现：一次“补文档”让原本稳定的问题开始退化。  
处理：所有上下文 PR 必须跑离线评估；失败不能合并。

### 失败 3：把探索性助手当正式报表

表现：业务直接拿 Agent 输出做正式汇报或决策。  
处理：区分探索问题和正式指标；正式指标必须链接到 gold 数据集和人工审批口径。

### 失败 4：权限用共享账号绕过

表现：Agent 看得到用户本来不该看的数据。  
处理：权限按调用者身份下推；共享账号只能用于无敏感的系统元数据，不得用于业务数据查询。

### 失败 5：只看准确率，不看延迟和可解释性

表现：答案偶尔对，但用户等太久，或者无法复核查询过程。  
处理：评估报告必须包含延迟、查询语句、数据集选择和失败原因。

## 企业内网落地清单

```markdown
# 企业内网数据分析 Agent 落地清单

## 范围
- [ ] 明确首个业务域
- [ ] 选定 5–10 个高频数据集
- [ ] 明确不支持的问题类型

## 上下文层
- [ ] 每个数据集有 Markdown 上下文
- [ ] 有负责人、粒度、关键字段、过滤条件、示例查询
- [ ] 上下文通过 PR 管理

## 查询层
- [ ] 查询引擎路由规则已写清
- [ ] 每次回答展示数据集、引擎、时间窗口、过滤条件
- [ ] 查询有超时、成本和行数限制

## 评估
- [ ] 至少 20 个黄金问题
- [ ] 每次上下文/配置变更自动评估
- [ ] 评估包含准确率、延迟、回归

## 安全
- [ ] 使用企业身份认证
- [ ] 权限按调用者下推
- [ ] 敏感字段有脱敏/聚合限制
- [ ] 所有查询有审计日志

## 运营
- [ ] 有人工复核入口
- [ ] 有失败样例收集机制
- [ ] 有上下文贡献指南
- [ ] 有版本回滚方案
```

## 最小成功标准

第一版不要用“像不像人”衡量，而用这 6 个标准：

1. 用户能在内网入口提出自然语言问题。
2. Agent 能说明自己使用了哪个数据集、哪个查询引擎、哪个时间窗口。
3. Agent 能生成可复核的查询语句和 Markdown 报告。
4. 高频问题有黄金评估集。
5. 上下文更新会触发离线评估。
6. 权限、审计、人工复核边界清楚。

如果这 6 条没满足，多接几个模型或入口意义不大。GitHub Qubot 的可迁移价值，不在于某个具体工具，而在于把分散的数据知识、自然语言入口和评估回归流程合成了一个可治理的内部系统。
