# Crm Visit Sync

> 搬运式跟进记录同步工具。将 iWiki 文档 / 腾讯文档 / 企微文档 / 用户直接粘贴文本（结构化纪要/对话流/纯文本）/ 企微聊天合并转发 / 图片（拜访纪要截图、聊天记录截图、手写纪要照片等） 中已写好的或描述的跟进记录（拜访纪要、跟进进展）内容，搬运录入到腾讯云磐石 CRM 的跟进数据中。当用户提供 iWiki / 腾讯文档 / 企微文档 链接（或粘贴文本、直接描述、把与客户的聊天合并转发给企微号助手、发送跟进记录截图/照片）并要求「把跟进记录传到磐石」「同步到磐石跟进数据」「录入磐石跟进记录」「搬运拜访纪要到磐石」「把聊天记录/这段描述/这张截图整理成跟进记录」时，应使用本技能。本期仅支持销售（Sales）和售前架构师（Owner）两种角色，仅允许同步 15 天内的跟进记录。分支 A（文档类）字段值须来自源文档原文（原文摘取，禁 AI 加工）；分支 B（对话流/纯文本/图片）允许对沟通进展/下一步计划做忠于输入的总结提炼（图片先多模态识别再清洗），其余字段仍须取自输入，读不到即留空，严禁编造。写入时无法从输入确认的必填字段逐一向用户确认（必填优先，跟进人/创建时间自动生成）。全流程仅两次强制确认：① 跟进对象实体；② 拜访对象职位 + 关联打卡 + 全字段预览（一次性确认并提交）。

- Skill: `infometa/crm-visit-sync` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add infometa/crm-visit-sync`
- Raw SKILL.md: https://api.skillmd.com/api/skills/infometa/crm-visit-sync/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: infometa (https://skillmd.com/u/infometa)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/infometa/crm-visit-sync

---


# CRM 跟进记录搬运同步（crm-visit-sync）

## Overview（定位）

本技能把 **iWiki 文档 / 腾讯文档 / 企微文档 / 用户直接粘贴的文本（结构化纪要/对话流/纯文本）/ 企微聊天合并转发 / 图片（截图/照片）** 中已写好的或描述的跟进记录（拜访纪要、跟进进展），
搬运录入到腾讯云磐石 CRM 的跟进数据库（`customer_visit` 主表及其子表）。分支 A（文档类）字段值须来自源文档原文（原文摘取）；分支 B（对话流/纯文本/图片）允许对沟通进展/下一步计划做忠于输入的总结提炼（图片先多模态识别再清洗），其余字段仍须取自输入，读不到即留空，严禁编造。

**企微聊天合并转发（chat_forward）/ 纯文本（分支 B）场景**：用户把与客户的企微聊天**合并转发**给企微号助手，或**直接输入一段自由叙述的纯文本**（如"今天去 XX 客户聊了方案"），skill 从中识别/总结对象、时间、方式、拜访对象、沟通内容，生成跟进记录。此类输入无结构化字段，解析/总结规则见 `shared/STEPS.md` 1.3 分支 B（沟通内容/下一步计划在分支 B 允许总结提炼，区别于分支 A 的原文摘取）。

**保底机制（必填字段兜底）**：写入时，凡是无法仅从用户输入确认的字段，都在提交前逐一向用户确认、**优先确认表单必填字段**；跟进人（=当前用户）与创建时间（=系统时间）由系统自动生成、不询问。详见 `shared/STEPS.md`「必填字段保底确认」。

与「crm-create-visit-skill（AI 对话式创建）」的本质区别：

| 维度 | crm-create-visit-skill（对话式） | 本技能 crm-visit-sync（搬运式） |
|------|-------------------------------|------------------------------|
| 内容来源 | 用户口述、AI 提取润色 | iWiki/腾讯文档已有纪要，分支A原文摘取；分支B对话流/图片总结提炼 |
| AI 是否加工内容 | 会提取、归纳、润色 | 分支A**严禁**总结/生成/补写/改写；分支B仅对沟通进展/计划允许忠于输入的总结提炼 |
| 字段缺失处理 | AI 追问、引导补齐 | **留空**并如实提示，绝不编造 |
| 典型触发 | 「帮我记一条今天拜访 XX 的跟进」 | 「把这个 iWiki 链接里的跟进记录传到磐石」 |

底层接口、角色鉴权、字段矩阵、枚举口径 **复用** 磐石现网规则（见 shared/）。

## ⛔ 八条铁律（最高优先级，任何步骤不得违反）

1. **禁止幻觉**：所有写入磐石的字段值，必须能在源文档中逐字对应到出处。读不到就留空，**绝不凭印象、常识或上下文推测编造**任何人名、时间、地点、结论、进展、计划。
2. **分支加工限定**：分支 A（文档类）禁止 AI 加工，只做结构化抽取 + 原文摘取；分支 B（对话流/纯文本）仅允许对**沟通进展/下一步计划**做忠于输入的总结提炼，其余字段仍须取自输入、不得生成。
3. **角色限定**：本期只处理 **Sales（销售）** 和 **Owner（国内售前架构师）**。角色经 `get_user_info(showDetail=true)` 读 `detail.roles[]` 判定（销售族 `sales*`→Sales / 售前架构师族 `architect*`→Owner，一步直映射）。判定结果非 Sales/Owner 时按两种场景终止：**roles 非空但不含 `sales*`/`architect*`**（产研架构师、分包、POC、VP、海外角色等）→ 输出「本次版本仅支持销售和售前架构师，您的角色为 {finalRole}，暂不支持」；**roles 为空**（rare 兜底）→ 输出「当前用户为 {rtx}（{中文名}），但系统返回的角色标签为空（`roles: []`），无法判定您属于销售 (Sales) 还是售前架构师 (Owner)。本次版本仅支持销售和售前架构师使用。」并终止。
4. **15 天时间闸**：跟进时间（visit_time）距今 **超过 15 天** 的记录，一律拒绝同步，明确提示原因。无法从源文确定跟进时间时，必须让用户补充确认，不得默认当前时间。
5. **仅两次强制确认（其余全自动）**：全程用户只需确认**两次**——① **跟进对象实体**（类型 + 客户全称+CID / 商机全称+项目编号，含候选改选）；② **关联打卡 + 全字段预览**，在最后一步一次性确认并据此提交（**拜访(10000) 额外在此步补全拜访对象真实姓名 + 职位枚举；跟进进展(10002) 无拜访对象字段**）。时间、地点、跟进方式均**不单独确认**，由 AI 从源文提取/判定后在最后预览中整体展示供核对。
6. **对象名必须走磐石搜索**：源文里的对象名不一定等于磐石对象名。必须用源文对象名 **模糊搜索磐石**，把候选列给用户选，**严禁**直接把源文对象名当作磐石对象提交。
7. **对象必须在当前用户名下（权限一致性校验）**：识别并定位到的客户/商机，必须经过"是否在你名下"的校验——**客户**用 `GetCustomerListForVisitForMcp`，`type:[1]`（我相关）或 `type:[2]`（长尾）命中均可落定（方案B：长尾直接允许，不额外校验权限）；**商机**用 `ltc.project/list` 校验返回的 `businessManager`(主销售)/`architect`(架构师)/`projectMembers[].rtx`(项目成员)三处之一是你即算在名下。**校验不通过一律不提交**，先提示"该对象不在您名下"，再列出你名下相近对象让你重选。

8. **打卡只能关联、不能伪造**：跟进记录的签到打卡，只能通过 `csm/GetVisitCheckInsListForMcp` 查询用户名下已有打卡记录后关联；严禁调用 `AddCustomerVisitCheckIns` 创建打卡，严禁自行编造、推断或留空 `visit_check_ins_id` 冒充打卡。无可用打卡时，按 `shouldShowSignIn` 引导用户去磐石小程序补打卡或改判为「跟进进展」，绝不提交空值或假值打卡。

## ⛔ Anti-patterns（常见跑偏，必须避免）

- ❌ 跳过 Step 0 身份/权限自检直接拉数据（违反权限自检要求）
- ❌ 把正文「客户：西瓜」当跟进对象去搜索（应是拜访对象，公司名/项目名才是跟进对象）
- ❌ 直接把源文对象名当磐石对象提交（必须先搜 cid 校验名下，长尾 type:[2] 命中也可落定）
- ❌ 没拿到 cid 就把客户名当 cid 传给 `AddCustomerVisitForMcp`
- ❌ 调用 `AddCustomerVisitCheckIns` 伪造打卡（=幻觉，违反铁律 #8）
- ❌ 提交体传 `null` 或无关字段（触发伪权限错 2022；去 null 重试，仍报才走 ask_user_authority）
- ❌ Permission Denied 时只说"无权限"不给申请路径（违反友好引导，必须调 ask_user_authority）
- ❌ 在 SKILL.md / shared 写 panshi URL / token / api_key（安全约束）
- ❌ 把聊天里的群昵称/微信昵称直接当真实姓名落库（拜访方式下拜访对象强制真实姓名，禁占位；进展不收集拜访对象）
- ❌ 把对话里出现的"人名"当跟进对象实体（人名是拜访对象，公司名/项目名才是对象）
- ❌ 凭聊天相对时间（今天/昨天/上周/上午/下午）不二次确认就直接填 visit_time（模糊时间必须追问精确到天/时/分）
- ❌ 分支 A（文档类）对沟通内容/下一步计划做总结生成（分支 A 应原文摘取，禁 AI 加工）
- ❌ 分支 B（对话流/纯文本/图片）不敢总结、只摘单句导致沟通内容残缺（应基于输入归纳核心要点，但忠于事实、禁编造）
- ❌ 把"无法从输入确认的必填字段"留空提交或 AI 擅自填值（须走「必填字段保底确认」逐一问用户；自动字段仅跟进人/创建时间）
- ❌ 把职位菜单序号数字（如 `19`/`20`）直接写进 `contact_info[].position`（序号仅为交互，入库必须还原成枚举文字如「市场负责人」；实测后台已出现 position=「19」「20」）

## 门控流程总览（Gate 0 → Gate 5）

对用户只呈现 **2 次确认**（跟进对象实体 / 职位+打卡+预览），其余步骤静默自动完成。

```
Gate 0  静默加载规则          读取本 SKILL.md + shared，初始化 SYNC_STATE
Gate 1  静默读取来源          解析 iWiki/腾讯文档/企微文档链接、粘贴文本（结构化纪要/对话流/纯文本）、企微聊天合并转发（chat_forward）或图片（截图/照片，多模态识别）→ 抽取/总结每条原始字段（含标题供对象识别），回显识别结果但不阻塞
Gate 2  静默角色鉴权          get_user_info(showDetail=true) → 读 detail.roles[] 直映射 finalRole → 校验 Sales/Owner
Gate 3  静默抽取（核心）      对每条记录依次：
                              ① 15 天时间闸校验
                              ② 对象类型+实体名（**标题优先判定**客户/商机；正文"客户：XXX"是拜访对象不是跟进对象）不单独确认
                              ③ 对象定位 + 名下一致性校验（客户 type:[1] 或 type:[2] 命中均可落定 / 商机搜负责人），候选暂存不阻塞
                              ④ 时间提取（YYYY-MM-DD HH:mm:ss 单一时刻；**模糊时间须二次确认精确到天/时/分**）
                              ⑤ 地点提取
                              ⑥ 跟进方式（AI 按是否有线下会面信号自动判定 拜访10000/进展10002，不单独确认）
                              ⑦ 拜访对象提取 + 职位自动映射（**仅 type=10000 拜访执行；进展 10002 跳过不收集**；源文有职位直接映射；无则标记 pending 留待确认2给菜单；姓名禁占位）
                              ⑦-C 腾讯参与人/协同跟进人：从正文提取我方（腾讯）参与人，拆分为「当前用户=跟进人（不重复入协同）」与「其他腾讯人员→collaborators[]（协同跟进人）」；tx_participants 原文照搬全部腾讯参与人
                              3.5 静默查询可关联打卡（GetVisitCheckInsListForMcp，最近15天；⚠️后端不过滤已关联，skill 须客户端过滤 is_bind_visit=0；**拜访10000无论角色必填、进展10002无论角色显示但非必填**），候选暂存
=========== 确认 1（唯一组装前闸门）：跟进对象实体 ===========
        回显「类型 + 全称 + CID/项目编号」，并列出候选（文档名搜 + 用户名下模糊搜合并）供**回复序号**改选；用户回复选中后才继续
=========== 确认 2（最终预览+提交，职位与打卡一次确认）===========
        回显全字段预览 + 拜访对象职位（**仅 type=10000 拜访显示**；pending 项给编号菜单，回复序号选，🔴 序号选后须还原成枚举文字再入库、严禁写序号数字；姓名禁占位）+ 协同跟进人（其他腾讯人员，可核对/改 RTX）+ 关联打卡候选（或"无匹配"）；
        用户在此一步**回复**补全职位、选择打卡、确认无误 → 回复"提交"落库
```

> **概念约定**：本技能里「商机」即「项目」，二者同义；识别为商机时定位到的是「项目编号」（商机 id）。「线索」类跟进对象本期不支持。

## SYNC_STATE（执行状态对象，全程维护）

每条待搬运记录维护一个状态，多条时用数组。禁止跳步。

```json
{
  "user": { "rtx": "", "name": "" },
  "role": { "finalRole": "", "checked": false },
  "records": [
    {
      "source": { "type": "iwiki|tencent_doc|wecom_doc|text|chat_forward|image", "ref": "链接或原文位置", "title": "文件名/文档标题（用于对象类型识别；chat_forward/纯文本/图片无标题）", "raw": "抽取到的原始纪要文本或对话流或图片识别文字" },
      "extracted": { "对象名原文": "", "时间原文": "", "地点原文": "", "沟通内容": "", "进展": "", "计划": "", "拜访对象原始文本": "", "…": "" },
      "gate3": {
        "time_ok": false, "within_15d": null,

        "object_type": null, "object_type_basis": "", "object_type_confirmed": false,

        "object_located": false, "object_matched": false,
        "cid": "", "project_code": "", "customer_name": "", "opp_name": "",
        "from_type": null,
        "owner_check": { "in_scope": null, "hit_by": "", "owner_name": "", "sales_name": "", "architect_name": "" },
        "object_confirmed": false,

        "time_extracted": false, "visit_time": "",
        "location_extracted": false, "location": "",
        "type_basis": "", "type_confirmed": false,
        "contact_info_extracted": false, "contact_info": [],
        "participants": {
          "tx_participants_raw": "",
          "collaborators": [ { "name": "", "rtx": "", "rtx_role": "" } ]
        }
      },
      "type": null,
      "check_in": { "required": null, "linked": false, "visit_check_ins_id": null, "address": "", "create_time": "" },
      "field_preview_ok": false,
      "submitted": false, "base_info_visit_id": ""
    }
  ]
}
```

> `object_type` ∈ {`customer`(客户), `opportunity`(商机=项目)}；`from_type`：客户=1、商机=2。
> `owner_check.in_scope`：该对象是否在当前用户名下（一致性校验结果）；`hit_by`：命中依据（客户=list_hit / 商机=owner|sales|architect）。

## 关键接口（详见 shared/API_REFERENCE.md）

全部经 **omp-service** MCP 转发，`request_api` 的 `apiPath` + `data`：

| 用途 | apiPath |
|------|---------|
| 读取当前用户信息 + 拿角色（`showDetail=true` 读 `detail.roles[]`） | `get_user_info`（omp-service 通用工具，非 request_api） |
| 客户模糊搜索 + cid 名下校验（带权限过滤） | `csm/GetCustomerListForVisitForMcp` |
| 商机（项目）搜索(name模糊/code编号) + 负责人字段 | `ltc.project/list` |
| 查询签到打卡记录（仅查询） | `csm/GetVisitCheckInsListForMcp` |
| 提交跟进记录（MCP 专用） | `csm/AddCustomerVisitForMcp` |

> ⚠️ 严禁调用 `GetAssociationCustomerList`（无权限过滤，会选到无权限客户）。
> ⚠️ 严禁调用 `AddCustomerVisitCheckIns` 创建签到（PC 端只能关联已有打卡，凭空造打卡=幻觉，违反铁律 #8）。
> 💡 客户详情 `csm/GetCustomerInfoByFields` **拿不到架构师字段**（仅有主销售 business_manager），因此客户侧一致性校验走 `GetCustomerListForVisitForMcp` 命中判定，不依赖客户详情。

## 参考资料（shared/）

- **API_REFERENCE.md** — 三个核心接口的完整入参/出参、finalRole 计算规则、对象搜索策略、提交参数组装
- **FIELDS_MAPPING.md** — 【本技能核心】源文档字段 → 磐石新字段（重构后）的映射表，含 Sales / Owner 各自的必填字段矩阵
- **ENUMS.md** — type / source / summary_type / time_section / **position(拜访对象职位)** 等枚举值
- **STEPS.md** — Gate 0~5 的详细执行步骤与话术模板、异常处理、降级链路

## 执行入口

收到搬运请求后：
1. 读取 shared/STEPS.md，按 Gate 0 初始化。
2. 严格逐 Gate 推进，每条记录静默完成 Gate 0~3 的抽取；仅触发 **2 次确认**（跟进对象实体 / 职位+打卡+预览）。
3. 全过程遵守上方「八条铁律」。

