会员身份匹配

SKILL商业运营
商业运营 未标注权限 许可证不明确
安装这个技能

外部渠道会员身份识别:匹配渠道ID、问姓名兜底、回写绑定。当会员在微信/飞书/企微联系时使用。

累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_f329779e/member-identity-matching

技能档案

商业运营
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_f329779e仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791623269
正文体量5.6 KBSKILL.md 原文大小,越大说明说明书写得越细

SKILL.md 全文

5.6 KB
模型实际读到的说明书原文,来自技能仓库

会员身份识别与渠道绑定

触发场景

会员通过微信/飞书/企微等外部渠道联系教练,会话开头需要先确认身份("您好/嗨"之后报名字或直接问事)。

匹配顺序(2026-08-28 微信渠道验证通过)

  1. 先按渠道ID匹配(不先问名字):
    - 微信渠道:c.find_member_by_weixin_id(weixin_id)
    - 飞书渠道:c.find_member_by_openid(openid)
    - 返回统一结构:{"found": bool, "name": ..., "record_id": ...}
  2. 匹配不上 → 问姓名 → c.find_member_by_name("姓名")(返回同结构,found: True 时拿到 record_id)
  3. 匹配成功 → 回写渠道ID到会员表,下次同渠道联系自动识别,不用再问名字

绑定签名(🔴 两个坑)

import sys; sys.path.insert(0, "/root/.hermes/profiles/coach/knowledge")
import coach_feishu as cf

c = cf.CoachFeishu()
r = c.save_member_weixin_id("recvo7Lrmhofc7", "[email protected]")  # (record_id, weixin_id)
# 成功 → {"status": "ok"}
  • 🔴 save_member_weixin_id(record_id, weixin_id) 需要两个位置参数,record_id 在前。只传 weixin_id 一个参数报 TypeError: missing 1 required positional argument: 'weixin_id'。record_id 来自 find_member_by_name / find_member_by_weixin_id 的返回值
  • 🔴 所有查询/绑定方法都是实例方法 — 必须先 c = cf.CoachFeishu()。模块级调用 cf.find_member_by_name(...) 报 AttributeError: module 'coach_feishu' has no attribute 'find_member_by_name'(用 terminal heredoc 跑,勿用 execute_code)

已确认方法清单(2026-08-28 模块内核对)

方法 参数 用途
find_member_by_name(name) name 按姓名查(兜底)
find_member_by_openid(openid) openid 飞书渠道识别
find_member_by_weixin_id(weixin_id) weixin_id 微信渠道识别
save_member_openid(record_id, openid) 两个位置参数 回写飞书ID
save_member_weixin_id(record_id, weixin_id) 两个位置参数 回写微信ID

陌生 openid 主动发消息:先定人,再定「会员 or admin」

  • 新 chat_id ≠ 新的人:飞书里每个人(含会员)与 bot 各有自己的 DM chat_id,马可的私聊 chat_id 只是其中一个。先 find_member_by_openid(openid) 定人,再谈别的。
  • admin 名单看 config:grep -n -A5 "admins:" /root/.hermes/profiles/coach/config.yaml(马可 = ou_e23c26d0b63227efa9ac80a179c602c3)。
  • openid 在名单 → admin 模式,可查所有会员
  • openid 不在名单 → 会员自助模式:只服务他本人的数据,不要透露他人信息
  • 会员档案 飞书OpenID 字段有值 = 该会员本人已接入渠道,直接服务,不要再问姓名;匹配成功即 cf.bind_member(姓名, "external") 后开始干活(绑定后查询方法都是无参的,见下)。

文字说"发了图片"、但这条消息 media=0 → 先别回"没收到图"

飞书图片是独立消息,通常滞后几秒到几十秒到达。正确顺序:

  1. grep "Inbound dm message received" /root/.hermes/profiles/coach/logs/gateway.log | tail -20 —— 看同一 chat_id 后面有没有 type=photo … media=1 的消息;有就等这批到齐再处理。
  2. 落盘路径 /root/.hermes/profiles/coach/cache/images/img_*.jpg。目录里会留历史旧图,必须按 mtime 取最新的几张(ls -lt 或 find -newermt),不要按文件名猜、也不要把昨天的图当今天的。
  3. 确实一张都没到,再回会员"图片没收到,麻烦重发"。

绑定之后怎么查:getter 全部无参,返回的是飞书原始结构

cf.bind_member(r["name"], "external")   # 先绑定(姓名 + 来源),外部会员传 "external"
c = cf.CoachFeishu()                    # 再实例化
c.get_member_info()                     # 无参!传姓名 → TypeError: takes 1 positional argument but 2 were given
  • get_my_body_tests() / get_my_training_logs() / get_my_diet_records() / get_my_training_plans() / get_my_evaluations() 同样无参,取的都是当前绑定的那个会员的数据——换人必须重新 bind_member(忘记重绑会把前一个人的数据当成本人的)。
  • 返回的是飞书原始字段结构:键是中文(训练日期 毫秒时间戳、动作名称 是 [{"text": …}] 富文本数组、关联会员 是 {"link_record_ids": [...]})。按自己猜的字段名取值只会得到一串 {} → 先 print(json.dumps(rec, ensure_ascii=False)) 看键名再解析。
  • 会员自助(external 绑定)只能查本人数据;admin 查询用白名单里的飞书 OpenID。
  • 每次答复后留痕:c.log_qa(question="…", category="饮食营养/动作疑问/…", result="🟢已自动解答", level="🟢常规", ai_answer="…"),成功返回 {"status": "ok", "record_id": …}。

判断会员是否已接入渠道

看会员档案(get_member_info())里两个字段的区别:
- 飞书OpenID:会员本人的 open_id → 已接入飞书,方案可直推
- 飞书用户:可能绑的是马可 → 会员未接入飞书,方案需输出给马可转发
回写新渠道ID前先看这两个字段,避免重复绑定或误判。

验证

绑定后同会话内再调 find_member_by_weixin_id(weixin_id) 应返回 found: True。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。