整条链全在云上,不碰任何人的本机。每台无影只要:① 抖音登录对应账号 ② .env 配好 ③ 账号 channel_pref=cloud_pc,就三条通道一起自动跑。
pnpm tsx … / Claude Code / claim 拉单。就是你现在看这份文档的这台。py …)、装抖音 PC、真正发私信/评论的地方。pnpm/tsx 的在本机 Mac 跑;带 py / Invoke-WebRequest / Get-Content 的在无影跑。同一台机上三条通道不是三个程序同时跑 —— 是一个 agent 进程、一个循环、三条 lane 严格串行(DM > RC > 二触)。
抖音 PC 是 GUI 自动化(模拟鼠标点屏幕坐标、抢窗口焦点)。同一时刻只能有一个程序操作抖音窗口 —— 两个一起点必然抢焦点、点错位、双双崩溃。所以 agent 用阻塞式调用,DM 那批发完才轮到 RC、RC 完才轮到二触,时间上完全错开。
wuying_poll_agent.py # 全机唯一进程,start.bat 只拉它一个 while True: # 路线 A —— DM 私信 claim_dispatch(≤3) → douyin_dm_grounded.py # 阻塞到这批发完 # 路线 B —— RC 反向评论(开关开了才跑,优先于二触) claim_rc_dispatch(≤3) → douyin_rc_reply_grounded.py # A 完了才开始,阻塞 # 路线 C —— 二次触达评论(开关开了才跑,最后) claim_second_touch(≤3) → douyin_comment_grounded.py # B 完了才开始,阻塞 sleep(60) # 三条都跑完 → 歇 60s → 下一轮
给高/中意向新评论的人发开场白私信(LLM 现起文案)。本版(镜像 43953460)私信前先进主页关注 → 点赞最新作品 → 再私信(best-effort,关注/点赞失败不阻断私信;无作品用户只跳点赞、照常关注+私信)。
dispatch_queueAKKE_CLAIM_LIMIT)min_send_interval_seconds(默认 60s,抖动后约 1–2 分钟/条)accounts.daily_limitCLOUD_PC_HOURLY_CAP(默认 10)对高/中意向用户,在源账号视频评论区公开回复 ta 那条意向评论本身(楼中回复)。话术由服务端 /rc/gen 现起,趁新鲜(6h 命中≈100%)。
rc_dispatch_queue(服务端 1h cron reverse-comment-dispatch 派单)AKKE_REVERSE_COMMENT_CLAIM_LIMIT,默认 3)AKKE_RC_DAILY_LIMIT(15)—— RC 独立计,不并入 DM/二触 合并门sendable = DM/RC 都没碰过)+ outreach_events对发过 DM、≥3 天没回的高/中意向用户,去 ta 视频下发一条评论唤回(复用最后一条 DM 原文)。
second_touch_dispatch_queueAKKE_SECOND_TOUCH_CLAIM_LIMIT)SECOND_TOUCH_MIN_DAYS(3 天)SECOND_TOUCH_DAILY_CAP(20)SECOND_TOUCH_COMBINED_HOURLY_CAP(6)已有一台配好的(野荞这台)→ 烤成自定义镜像 → 新机克隆。零重装、零装依赖、同分辨率零校准,每台只改几处。
镜像里已含 Python + 依赖 + 全部脚本(DM + 二触 + RC)+ 模板 + 开机自启。新机克隆出来只改账号 + 开开关。
无镜像时:装 Python → 传脚本 → 装依赖 → 配 .env → 设自启 →(分辨率不同才)校准。见 wuying-selfdrive-deploy.html 方式 B。
C:\akke-wuying\wuying-dm\(脚本 wuying_poll_agent.py / douyin_dm_grounded.py / douyin_comment_grounded.py / douyin_rc_reply_grounded.py + templates/)、开机自启 akke_wuying_agent.bat。43953460(PM 已烤好,克隆新机时填它,见下一步)。务必确认源机已装 douyin_comment_grounded.py(二触)+ douyin_rc_reply_grounded.py(RC)且坐标校准过,否则克隆机只能发 DM。43953460 → 克隆出来零重装、零装依赖。douyin_dm_grounded.py --capture +(本版新增)measure_nav.py 补采 关注 / 点赞 / 私信(已关注态)/ 返回 坐标(AKKE_C_FOLLOW / C_LIKE / C_DM / C_BACK)、二触走 _measure-comment.py,各重采一次。建议在无影客户端锁死分辨率。.env:把 AKKE_ACCOUNT_ID 换成这台账号的 id(PM 下发);要开二触就加 AKKE_SECOND_TOUCH_ENABLED=1(见下方 .env 模板)。accounts.channel_pref=cloud_pc + 设节奏/上限。
SECOND_TOUCH_AUTOSEND_ENABLED=true。两个开关都开才真发二触:Vercel 的 SECOND_TOUCH_AUTOSEND_ENABLED(派单侧)+ 无影 .env 的 AKKE_SECOND_TOUCH_ENABLED(执行侧)。AKKE_RC_DISPATCH_LIVE=1。执行侧 AKKE_REVERSE_COMMENT_ENABLED=1 已烤进镜像(rc=on),克隆机不用另加,所以 RC 只差 Vercel 这一个开关。⚠️ 一翻就会对真实用户公开回评,定好时机再开。Get-Content C:\akke-wuying\wuying-dm\agent.log -Tail 8,看到 === wuying_poll_agent account=… every 60s second_touch=on rc=on … 即三条通道都在。源机的 .env 跟着镜像一起克隆过来了,不用整份重配。只改两处:
① AKKE_ACCOUNT_ID 换成这台绑的账号(不同抖音号,见下表怎么拿);
② 这台要发二触就确认有 AKKE_SECOND_TOUCH_ENABLED=1。
其余(URL/key 等)全队一样、照搬不动 → 下面整份照抄可跳过。
没有镜像、新机上没有 .env 时,才需要照下面 3 步整份配。值几乎全在你本机 Mac 的 .env.local 里,照抄即可、不必等谁下发。
cd C:\akke-wuying\wuying-dm → notepad .env → 把 AKKE_ACCOUNT_ID= 那行换成你的账号 id → 存盘 → 重启 agent。改完不重启 agent 不读新值。↓ 以下是「从零整份配」(方式 B)用的;镜像克隆只看上面那 1 行就行。
# 本机 Mac,在 Akke 仓库目录里跑
cat .env.local
NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEY / SUPABASE_SERVICE_ROLE_KEY / OPENROUTER_API_KEY / AKKE_ACCOUNT_ID —— 正好就是无影 .env 要的那几个。# 无影 PowerShell / cmd
cd C:\akke-wuying\wuying-dm
notepad .env
.env 必须重启 agent 才生效:关掉 agent 黑窗口 → 双击 start.bat 重开(见第 3 章)。每个值从哪拿 ↓
| 无影 .env 变量 | 从哪拿 |
|---|---|
SUPABASE_URL + NEXT_PUBLIC_SUPABASE_URL | 本机 .env.local 的 NEXT_PUBLIC_SUPABASE_URL,两行填同一个值 |
NEXT_PUBLIC_SUPABASE_ANON_KEY | 本机 .env.local 同名,直接抄 |
SUPABASE_SERVICE_ROLE_KEY | 本机 .env.local 同名,直接抄(连库鉴权,自助最省事的路) |
OPENROUTER_API_KEY | 本机 .env.local 同名,务必是后台设了额度封顶的 key |
AKKE_ACCOUNT_ID | 本机 .env.local 的 AKKE_ACCOUNT_ID = 你这台绑的账号。一机一号,别和别人填重(没配过 → 这是一人一号的绑定,找 PM 要一次) |
AKKE_POLL_INTERVAL / AKKE_CLAIM_LIMIT / AKKE_SECOND_TOUCH_* | 固定值,照下面模板填即可 |
# —— Supabase(本机 .env.local 照抄)—— SUPABASE_URL=https://<项目>.supabase.co NEXT_PUBLIC_SUPABASE_URL=https://<项目>.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon key> SUPABASE_SERVICE_ROLE_KEY=<service_role key> # 连库鉴权(自助最省事) # 这台绑的账号(本机 .env.local 的 AKKE_ACCOUNT_ID,一机一号) AKKE_ACCOUNT_ID=<accounts.id> # 视觉定位 —— 务必用设了额度封顶的 key OPENROUTER_API_KEY=<sk-or-... 封顶 key> # 固定值,照填即可 AKKE_POLL_INTERVAL=60 AKKE_CLAIM_LIMIT=3 # ↓ 开二次触达评论通道(不加=只发 DM) AKKE_SECOND_TOUCH_ENABLED=1 AKKE_SECOND_TOUCH_CLAIM_LIMIT=3
service_role 权限很大。更稳的做法是用受控 JWT(role=wuying_worker,只能领单/回写)替代它 —— .env 里删掉 SUPABASE_SERVICE_ROLE_KEY、改填 SUPABASE_SCOPED_JWT(配合 anon key),agent 自动识别。这把 JWT 要用 JWT 密钥签出来、cat 不出来,问 PM 要一次(全队共用一把)。OpenRouter key 也务必后台设 Credit limit($30 等),烧超即停、不碰生产额度。只有分辨率跟源镜像(2560×1600)不一致时才要做这步。一致的话坐标随镜像 .env 来了,啥都不用采。
douyin_dm_grounded.py --capture 采发私信 5 个基础坐标(搜索框 / 用户tab / 私信 / 发送↑ / 输入框);② 本节的 measure_nav.py 才采关注·点赞那一套(7 项)。只跑了 --capture = 缺关注/点赞/返回,那段会自动跳过(只发私信不报错),整套「关注→点赞→私信」不生效。两个都要跑。无影上打开抖音 PC 客户端登录好号;先想好一个有作品的用户(等下进 ta 主页);切英文输入法。
cd C:\akke-wuying\wuying-dm python measure_nav.py
它先打印分辨率(确认是你这台真实值),然后逐条提示。
在搜索结果页(先搜个人、点「用户」结果页):
AKKE_C_USERTABAKKE_C_FIRST换界面 → 进一个【有作品】用户的个人主页:
AKKE_C_FOLLOWAKKE_C_DMAKKE_C_WORK_FIRST手动点进那个作品 → 打开视频播放页:
AKKE_C_LIKEAKKE_C_BACK(可选,不采走 VL 实时定位;采上更稳)notepad .env,按下面格式填(用脚本打印的「归一化 x,y」,逗号分隔、千分比整数、不要括号不要空格;值是举例,填你自己量的):
AKKE_C_USERTAB=287,45 AKKE_C_FIRST=...,... AKKE_C_FOLLOW=...,... AKKE_C_DM=...,... AKKE_C_WORK_FIRST=...,... AKKE_C_LIKE=...,... AKKE_C_BACK=...,...
.env 必须重启 agent,不重启不读新值。重启后 Get-Content C:\akke-wuying\wuying-dm\agent.log -Tail 8 看是否在拉单。measure_nav.py → 悬停+回车量 7 个点(第④步先手动点关注再量私信)→ 归一化值写 .env → 重启 agent。
agent 停 → cron 顶多在队列留 1 条 pending(背压门挡着,不会堆)→ 不丢单、不重发。发到一半被关的那条会被 15 分钟死锁回收、下次重领。不挑关机时机,下班随手关。
开机后队列里攒着的单会自动续发。你只要确认抖音和输入法状态对,agent 是开机自启的,不用手动开。
akke_wuying_agent.bat 会延迟 30s 自动拉起 agent(等抖音先起来)。它在后台一个黑窗口里跑,但日志被写进了 agent.log、窗口里看着是空的(正常),所以光看桌面判断不了,得按下一步读日志。Win 键)→ 输 powershell → 回车,打开蓝底的 Windows PowerShell 窗口,把下面这条粘进去回车(只有 PowerShell 认这个命令):Get-Content C:\akke-wuying\wuying-dm\agent.log -Tail 8
# 输出里看到这行 = 三条通道都在(second_touch=on rc=on):
=== wuying_poll_agent account=81cc9678… every 60s claim=3 second_touch=on rc=on ===
start.bat —— 文件管理器进 C:\akke-wuying\wuying-dm 文件夹,双击 start.bat。会弹出一个能实时看到日志滚动的黑窗口,出现 account=… 那行就成了。cd C:\akke-wuying\wuying-dm py wuying_poll_agent.py
Ctrl+C。scripts/cloudpc-status.ts),不用进无影看。自动通道有节奏门(DM 约 1–2 分钟/条、二触每小时派一轮)。要现在就推一批出去,不等 cron,有两条路。
本机 PM 跑 CLI 直接入队,无影 agent ≤60 秒内领走开发。绕开 cron 的等待,但仍走 GUI 自动发。
完全不靠 cron/agent:本机 claim+出文案+投递,无影下载 CSV 直接 py douyin_dm_grounded.py contacts.csv 一把发完。适合临时冲量。
# 给指定账号立刻派 N 条进 dispatch_queue(不带 --pace = 不等 1-2min 节奏门) pnpm tsx scripts/dispatch-leads.ts --account=<accounts.id> --per-account=10 # 无影那台的 agent 每 60s 轮询,会在 1 分钟内自动领走开发
# DM 派单 curl -s -H "Authorization: Bearer $CRON_SECRET" https://<生产域名>/api/cron/cloud-pc-dispatch # 二触派单(需已开 SECOND_TOUCH_AUTOSEND_ENABLED=true) curl -s -H "Authorization: Bearer $CRON_SECRET" https://<生产域名>/api/cron/second-touch-dispatch
send-cloudpc-dm skill(claim→出文案→+v→投递)。手动版:# 本机(有 Akke 仓库) pnpm tsx scripts/export-leads-csv.ts --limit=N --out=data/contacts.csv pnpm tsx scripts/release-surplus-claims.ts --csv=data/contacts.csv # 释放多锁 sed -i '' 's/微信/+v/g' data/contacts.csv # 避关键词风控 curl -s --data-binary @data/contacts.csv https://paste.rs # 返回 URL 给无影
# 无影(确认抖音登录+最大化+前台+输入法英文)
Invoke-WebRequest -Uri <本机给的URL> -OutFile C:\akke-wuying\wuying-dm\contacts.csv -UseBasicParsing
del C:\akke-wuying\wuying-dm\sent_log_*.csv
py douyin_dm_grounded.py contacts.csv
second-touch-dispatch 端点即可。AKKE_SECOND_TOUCH_ENABLED=1。accounts.daily_limit + min_send_interval_seconds;二触:SECOND_TOUCH_DAILY_CAP / MIN_DAYS / COMBINED_HOURLY_CAP(Vercel env)。由 PM 改。channel_pref=cloud_pc;关:改回 manual。单关二触:无影 .env 去掉 AKKE_SECOND_TOUCH_ENABLED 重启。| 现象 | 原因 / 处理 |
|---|---|
| agent 起来但不发 | 多半当日上限满(含人工通道)→ 等滚动窗口腾槽自动续;或该账号没 channel_pref=cloud_pc |
| 只发 DM、不发二触 | .env 没加 AKKE_SECOND_TOUCH_ENABLED=1;或 Vercel 没开 SECOND_TOUCH_AUTOSEND_ENABLED=true(还在干跑);或没满足 ≥3 天没回的候选 |
启动行显示 second_touch=off | 开关没生效 → 改 .env 后重启 agent(改了不重启不读新值) |
| 搜错人 / 身份门跳过 | 输入法不是英文(抢搜索词首字);或同名撞大号(身份门跳过 = 安全兜底) |
| 文字没进输入框 → 不发 | 分辨率变了坐标偏 → DM 重跑 --capture、二触重跑 _measure-comment.py |
agent.log 空 | 自启缺 -u(缓冲);或还在 30s 倒计时 |
| 连库报错 401 | 把角色 JWT 当 apikey 了;确认 SUPABASE_SCOPED_JWT + NEXT_PUBLIC_SUPABASE_ANON_KEY 都配了 |
| 手动跑 CSV 时界面乱跳 | 自动 agent 没关、两程序抢抖音窗口 → 关掉 agent 黑窗口再跑手动 |
每个新部署的人都会问这两条 —— 都已对照代码核实,放心起 agent。
有 cron 自动喂,不用手动灌。上游 /api/cron/cloud-pc-dispatch(每 5 分钟)→ claim_leads_batch claim 高意向 + 现起 opener + 写 dispatch_queue;无影 wuying_poll_agent.py 每 60s 拉走发。
channel_pref=cloud_pc + status=active + type=messaging(部署第 4 步「让 PM 开后台」)。没 flip 成 cloud_pc,cron 找不到账号 → 一条不派 → agent 空转。这一步是开关,不是要你手动灌队列。二触队列由 /api/cron/second-touch-dispatch(每 2 分钟)喂,需两个开关都开。同一套,全局共享,不会重发。dispatch_queue 只是 agent 的传送带、不是去重点。两个真正的去重点,手动链和 agent 链写的是同一处:
| 去重点 | 手动链 | agent 链 |
|---|---|---|
4h claim 锁lead_claims | claim-leads.ts → claim_leads_batch | cron → 同一个 claim_leads_batch |
永久去重comments.contacted | mark-contacted.ts → mark_lead_contacted | complete_dispatch(sent) → 同一个 mark_lead_contacted |
claim_leads_batch 候选过滤含 contacted_by_account IS NULL(已触达的人直接排除)+ UPSERT lead_claims 的 ON CONFLICT (org_id, douyin_user_id) 仅在锁过期才重抢。你手动锁过/发过的人,4h 内 agent claim 不到、已 contacted 的永久跳过 —— 不会重发。去重按 (org_id, douyin_user_id) 生效,跨账号 / 跨机器 / 跨手动·自动全互通。镜像克隆 → 抖音登对号 → .env 改账号(RC 已默认开)→ DB 开 cloud_pc → 重启 → 三条通道自己跑。