# Dingtalk Workflow Personal Crm

> 个人 CRM — 从钉钉日程、群聊、通讯录中提取联系人并维护关系热度分，支持自然语言查询和超期提醒

- Skill: `liangdabiao/dingtalk-workflow-personal-crm` (Agent Skill)
- Install (CLI): `npx skillmds@latest add liangdabiao/dingtalk-workflow-personal-crm`
- Raw SKILL.md: https://api.skillmd.com/api/skills/liangdabiao/dingtalk-workflow-personal-crm/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: liangdabiao (https://skillmd.com/u/liangdabiao)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/liangdabiao/dingtalk-workflow-personal-crm

---


# 个人 CRM (dingtalk-workflow-personal-crm)

> 自动扫描钉钉日程、群聊和通讯录，提取联系人并维护关系热度分。
> 相比飞书版本，去掉邮件扫描（钉钉无邮箱），增加钉钉通讯录搜索作为联系人来源。

## 触发方式

```
"联系人管理"  "CRM"  "谁联系过我"  "多久没联系"  "联系人热度"  "关系管理"  "联系人"
```

## 热度分计算规则

| 维度 | 权重 | 计算方式 |
|------|------|---------|
| 频率分 | 40分 | 过去90天互动次数，0次=0分，20次+=40分，线性插值 |
| 近期分 | 40分 | 最后互动距今天数，7天内=40分，90天+=0分，线性递减 |
| 重要度分 | 20分 | 高=20分，中=12分，低=4分 |

总分 = 频率分 + 近期分 + 重要度分（0-100）

## 数据初始化

首次使用时，自动创建 aitable 数据表：

```bash
# 创建 Base
dws aitable base create --name "个人CRM" --yes -f json
# 返回 baseId，记为 <crm-base-id>

# 创建联系人主表
dws aitable table create --base-id <crm-base-id> --name "联系人" --yes -f json
# 返回 tableId，记为 <contacts-table-id>

# 创建互动记录表
dws aitable table create --base-id <crm-base-id> --name "互动记录" --yes -f json
# 返回 tableId，记为 <interactions-table-id>

# 添加业务字段（表创建后自动带一个"标题"primaryDoc字段，需额外添加业务字段）
dws aitable field create --base-id <crm-base-id> --table-id <contacts-table-id> --fields '[{"fieldName":"姓名","type":"text"},{"fieldName":"公司","type":"text"},{"fieldName":"职位","type":"text"},{"fieldName":"手机","type":"text"},{"fieldName":"userId","type":"text"},{"fieldName":"来源","type":"text"},{"fieldName":"关系类型","type":"text"},{"fieldName":"重要程度","type":"text"},{"fieldName":"热度分","type":"number"},{"fieldName":"最后联系时间","type":"date"},{"fieldName":"最后联系内容","type":"text"},{"fieldName":"备注","type":"text"}]' --yes -f json

dws aitable field create --base-id <crm-base-id> --table-id <interactions-table-id> --fields '[{"fieldName":"联系人姓名","type":"text"},{"fieldName":"联系人userId","type":"text"},{"fieldName":"互动时间","type":"date"},{"fieldName":"互动类型","type":"text"},{"fieldName":"互动摘要","type":"text"},{"fieldName":"涉及主题","type":"text"}]' --yes -f json
```

**表1: 联系人 (contacts)**

| 字段名 | 类型 | 说明 |
|--------|------|------|
| 姓名 | 文本 | 联系人姓名 |
| 公司 | 文本 | 所在公司 |
| 职位 | 文本 | 职位/角色 |
| 手机 | 文本 | 联系方式 |
| userId | 文本 | 钉钉 userId |
| 来源 | 文本 | 日程/群聊/通讯录/手动 |
| 关系类型 | 文本 | 客户/合作伙伴/同事/朋友/行业人脉/其他 |
| 重要程度 | 文本 | 高/中/低 |
| 热度分 | 数字 | 0-100 |
| 最后联系时间 | 日期 | 最近互动时间 |
| 最后联系内容 | 文本 | 互动摘要 |
| 备注 | 文本 | 自由备注 |

**表2: 互动记录 (interactions)**

| 字段名 | 类型 | 说明 |
|--------|------|------|
| 联系人姓名 | 文本 | 关联联系人姓名 |
| 联系人userId | 文本 | 关联联系人 userId |
| 互动时间 | 日期 | 互动发生时间 |
| 互动类型 | 文本 | 日程/群聊消息/DING/电话/其他 |
| 互动摘要 | 文本 | 内容简述 |
| 涉及主题 | 文本 | 讨论的话题 |

## 工作模式

### 模式 1: 联系人初始化 — 从日程和通讯录导入

**触发：** "帮我建立个人CRM系统" / "初始化联系人管理"

**工作流：**

```
Step 1: 获取当前用户信息
└── dws contact user get-self --yes -f json

Step 2: 扫描近期日程，提取参与者
├── dws calendar event list --yes -f json → 所有日程
├── 逐个获取日程参与者:
│   dws calendar participant list --event "eventId" --yes -f json
└── 批量获取参与者详细信息（注意：contact user search 仅返回 userId 列表，需二次查询）:
    dws contact user get --ids "id1,id2,id3" --yes -f json

Step 3: 搜索群聊，提取群成员
├── dws chat search --query "关键词" --yes -f json
└── dws chat group members list --id "openConversationId" --yes -f json

Step 4: 写入联系人表
└── dws aitable record create --base-id <crm-base-id> --table-id <contacts-table-id> --records '[...]' --yes

Step 5: 计算热度分并更新
└── dws aitable record update --base-id <crm-base-id> --table-id <contacts-table-id> --records '[...]' --yes
```

### 模式 2: 互动记录导入

**触发：** "从日程导入互动记录" / "记录最近的联系人互动"

**工作流：**

```
Step 1: 获取指定时间范围的日程
└── dws calendar event list --yes -f json → AI 过滤时间范围

Step 2: 逐个获取日程详情和参与者
├── dws calendar event get --id "eventId" --yes -f json
└── dws calendar participant list --event "eventId" --yes -f json

Step 3: AI 为每个参与者生成互动记录
├── 互动类型：日程
├── 互动摘要：日程标题 + 描述
├── 涉及主题：AI 从日程描述中提取
└── 更新联系人的最后联系时间和热度分

Step 4: 批量写入互动记录并更新联系人
├── dws aitable record create --base-id <crm-base-id> --table-id <interactions-table-id> --records '[...]' --yes
└── dws aitable record update --base-id <crm-base-id> --table-id <contacts-table-id> --records '[...]' --yes
```

### 模式 3: 联系人查询

**触发：** "上个月谁联系过我？" / "XX公司的人我最后一次和谁聊过？"

**工作流：**

```
Step 1: 解析用户查询意图（按时间/公司/热度等维度）

Step 2: 查询 aitable 联系人表
└── dws aitable record query --base-id <crm-base-id> --table-id <contacts-table-id> --limit 50 --yes -f json

Step 3: AI 过滤和排序，格式化输出
```

**查询示例：**

| 用户问题 | 查询方式 |
|----------|---------|
| "上个月谁联系过我？" | 按最后联系时间过滤最近30天 |
| "XX公司的人" | 按公司字段过滤 |
| "超过3个月没联系的重要关系" | 热度分 < 30 且重要程度=高 |
| "关系最密切的5个人" | 按热度分降序取前5 |
| "谁是客户？" | 按关系类型=客户过滤 |

### 模式 4: 超期提醒

**触发：** 自动执行 / "有没有需要跟进的联系人"

**工作流：**

```
Step 1: 查询所有重要程度=高或中且热度分 < 30 的联系人
└── dws aitable record query --base-id <crm-base-id> --table-id <contacts-table-id> --yes -f json

Step 2: 生成提醒列表

Step 3: 通过 DING 或群消息发送提醒
└── dws ding message send --robot-code "..." --users "manager6950" --content "N 个重要联系人需要跟进" --type "1" --yes
```

### 模式 5: 手动添加联系人

**触发：** "添加联系人 张三，XX公司，CTO"

**工作流：**

```
Step 1: 解析联系人信息（姓名、公司、职位等）

Step 2: 尝试在钉钉通讯录中匹配
├── dws contact user search --keyword "张三" --yes -f json
│   注意：返回格式为 {"userId":["id1","id2"]}，仅含 userId 列表，不含姓名等详细信息
│   或 dws contact user search-mobile --mobile "138..." --yes -f json
└── 如匹配到结果，用返回的 userId 获取完整信息:
    dws contact user get --ids "userId1,userId2" --yes -f json

Step 3: 如果匹配到，补充 userId 和详细信息；否则使用手动输入

Step 4: 写入联系人表
└── dws aitable record create --base-id <crm-base-id> --table-id <contacts-table-id> --records '[...]' --yes
```

### 模式 6: 热度分批量更新

**触发：** "更新所有联系人的热度分" / 自动定期执行

**工作流：**

```
Step 1: 查询所有联系人和互动记录
├── dws aitable record query --base-id <crm-base-id> --table-id <contacts-table-id> --limit 100 --yes -f json
└── dws aitable record query --base-id <crm-base-id> --table-id <interactions-table-id> --limit 500 --yes -f json

Step 2: AI 计算每个联系人的热度分（频率分 + 近期分 + 重要度分）

Step 3: 批量更新
└── dws aitable record update --base-id <crm-base-id> --table-id <contacts-table-id> --records '[...]' --yes
```

## dws CLI 命令参考

### 获取当前用户

```bash
dws contact user get-self --yes -f json
```

### 搜索联系人

```bash
dws contact user search --keyword "张三" --yes -f json
```

### 按手机号搜索

```bash
dws contact user search-mobile --mobile "13800000000" --yes -f json
```

### 批量获取用户信息

```bash
dws contact user get --ids "user1,user2,user3" --yes -f json
```

### 搜索部门

```bash
dws contact dept search --keyword "技术部" --yes -f json
```

### 获取日程列表

```bash
dws calendar event list --yes -f json
```

### 获取日程详情

```bash
dws calendar event get --id "eventId" --yes -f json
```

### 获取日程参与者

```bash
dws calendar participant list --event "eventId" --yes -f json
```

### 搜索群聊

```bash
dws chat search --query "关键词" --yes -f json
```

### 获取群成员

```bash
dws chat group members list --id "openConversationId" --yes -f json
```

### aitable 记录操作

```bash
# 创建联系人
dws aitable record create --base-id <crm-base-id> --table-id <contacts-table-id> --records '[{"cells":{"标题":"张三-XX科技","姓名":"张三","公司":"XX科技","重要程度":"高","热度分":65}}]' --yes -f json

# 查询联系人
dws aitable record query --base-id <crm-base-id> --table-id <contacts-table-id> --limit 50 --yes -f json

# 更新联系人
dws aitable record update --base-id <crm-base-id> --table-id <contacts-table-id> --records '[{"recordId":"rec_xxx","cells":{"热度分":75,"最后联系时间":"2026-04-06"}}]' --yes -f json
```

## 联动 Skill

| 联动 Skill | 数据交互 | 说明 |
|-----------|---------|------|
| morning-brief | 提供参会人背景 | 晨间简报展示会议参与者信息 |
| business-advisor | 提供联系人动态 | 商业顾问团分析人脉变化 |
| meeting-todo | 提供负责人信息 | 标识待办负责人身份 |

## 注意事项

1. 所有 `dws` 命令必须加 `--yes` 标志
2. 钉钉通讯录搜索仅返回当前用户有权限查看的成员，非全量
3. 热度分更新建议每周自动执行一次（可通过 CronCreate 配置）
4. `dws aitable record create/update` 的 `--records` 参数必须是 JSON 数组格式
5. 联系人姓名可能存在通讯录和 aitable 不一致的情况，以 userId 作为唯一标识
6. 联系人搜索 `contact user search` 仅返回 userId 列表，不含姓名等详细信息。如需详细信息，需将返回的 userId 传入 `contact user get --ids` 获取完整信息
7. `contact dept search` 对小组织（个体户等）可能返回空结果，属正常现象

## 已知问题

1. `contact user search` 返回格式为 `{"userId":["id1","id2"]}` 而非完整用户信息，需二次查询 `contact user get --ids` 获取姓名、公司等详细信息
2. `chat search` 对没有匹配群聊的关键词返回空结果，属正常行为

