用友 DSP / ISP 平台登录与报错查询
零、一页速查(先读这一段,再按需下钻)
先认清三个脚本的分工(拿错参数是本技能最常见的空跑原因):
| 脚本 | 管什么 | 关键参数 |
|---|---|---|
run_query.sh |
唯一入口:门禁 + 采集 + (--finalize)渲染 |
--batch-content --version --years --out-dir --no-report --finalize --check --linkage-text --linkage-refs --linkage-note --steps-content --report-title --report-keyword --report-product --report-version --report-years |
digest_offers.py |
取数后的摘要与成图(run_query.sh 内部已自动调用,一般不需手工跑) |
--report <输出目录>(此参数属本脚本,不属 run_query.sh)-i <union.tsv> |
collect_offers.sh |
浏览器采集实现(run_query.sh 内部调用) |
— |
> 拿错参数/踩格式坑不必重跑:run_query.sh 已内置容错——① 误传 --report 会自动映射为 --out-dir 并告警;② 参数名拼错(如 --report-titel)会直接提示最接近的合法写法;③ run_query.sh --one-shot 会告警说明两步法不可合并;④ 裸单词关键词的报错自带可照抄的正确写法;⑤ --steps 的列表前缀(1. 第1步 1.1 -)会被自动剥离并告警,不必为编号格式回退;⑥ 暖机环境跑 --check 会提示「本轮预演属可省的一轮」。看到告警按提示改一次即可,无需回查文档或凭经验猜。
>
> 唯一需要自己拿捏的:--linkage-text 必须基于本轮真实 top-10 现写(§5.6 红线,脚本内不留任何主题结论)——这一段的推理时间无法由脚本代劳,是设计成本而非浪费。
暖机快捷路径(默认走这条)
> 适用条件(客观判定,不靠记忆):$HOME/.workbuddy/dsp_state/ 下 cli.runtime.json 与 _chrome_profile 同时存在。两文件皆在即为暖机。
> 暖机下,以下 2 条命令就是全部动作——不跑 setup_cli.sh --check、不 ls 探测目录、不读凭据文件、不为确认参数去 grep 脚本正文。参数不确定就直接跑,门禁会按提示告诉你正确写法(见上方容错清单),预读一律省略。
>
> ① 采集(前台 + 长 timeout;--no-report 跳过报告门禁,top-10 随输出打印)
> bash
> cd <技能目录>
> bash scripts/run_query.sh --no-report \
> --batch-content $'#术语:\n报销单/传结算\n#口语:\n报销单/没生成付款单' \
> --version <版本> --years <年,年> --out-dir <绝对输出目录>
>
> ② 渲染(读上一步打印的 top-10 后,与 present_files 放在同一条消息里发出)
> bash
> bash scripts/run_query.sh --finalize \
> --batch-content $'#术语:\n报销单/传结算\n#口语:\n报销单/没生成付款单' \
> --version <版本> --years <年,年> --out-dir <同一绝对输出目录> \
> --report-title "<主题>" --report-keyword "<词>" \
> --linkage-text "<据上一步 top-10 现写的结论>" \
> --linkage-refs "<单号1>" \
> --steps-content "标题|理由|单号
> 标题|理由|单号"
>
> 两处必须替换的占位:--version / --years(按本次查询填)与 --linkage-text(必须基于上一步真实 top-10 现写,不能提前编——编了会被 SR 一致性自检挡下)。其余照抄即可。
>
> --linkage-text 写作结构(只给结构、不给业务结论——业务结论必须来自本轮 top-10,技能内不留任何主题结论):
> 1. 先定位唯一 1 条主线工单(--linkage-refs 只填它),一句话点出系统规则 / 判定条件本身,而非"报错了"这类现象描述;
> 2. 再补「为什么这次会命中」——即该工单描述里给出的触发前提(如某个开关未启用、某个日期前后关系、某个字段为空),这是读者最需要的"判据";
> 3. 不写「其他可能原因」——其余根因一律写进 --steps-content 的排查顺序,两章职责不可混用(见 §5.6)。
>
> 冷机(上述两文件缺任一):先走 §三 三步安装 SOP,再回本路径。
>
> 为什么要固化这条:门禁只能拦住「参数写错」这类有判据的错误(机械门禁),管不住「跑之前多探测了几轮」这类行为(行为级门禁)。所以暖机下正确的做法不是"记得别多跑",而是照抄上面两条、不做其余动作——把选择成本降为零,才不会每轮重新推导。
| 我要做什么 | 怎么做 | 详见 |
|---|---|---|
| 查某个 BIP 报错的历史处理方案 | bash scripts/run_query.sh --batch <词表> --version <版本> --years <年,年> --out-dir <输出目录> --report-title <标题> --report-keyword <主题词> --linkage-text <本次结论> |
§五 / §六 |
| 第一次在新机器上用 / 收到分享包 | 前置四项 → 三步安装 | §三 |
| 登录被挡住 / 要人工介入 | 按 ①–⑤ 阶梯逐级下沉 | §四 |
| 跑出问题 | 按症状查速查表 | §七 |
| 报告要发给别人 | HTML 报告是默认交付物、不是附件 | §五.6 |
硬护栏 · 最小加载集(严禁超载读取):一次常规检索只加载 本文件 §一 / §四 / §五 / §六 + references/workflow.md §B.9(仅首次另需 §三)。禁止为「确认参数」去通读 workflow.md 全文(尤其 §C 深层理由)或 scripts/run_query.sh / collect_offers.sh 正文——参数契约已固化于 §B.9 与本文件,通读纯属把省下的时间全额付回去(实测一次多读约 650 行、拖累端到端约 150s)。确有疑义再按需下钻单条。
硬性禁读(省时的最大单项):scripts/dsp_flow.js 正文、references/manual-steps.md 的逐步命令、references/faq.md 全文、references/workflow.md 全文(仅读 §B.9)、scripts/run_query.sh 与 scripts/collect_offers.sh 正文——合计逾 10 万字符,通读等于把省下的时间全额付回去。workflow.md 的参数契约以 §B.9 为准;两脚本的参数契约以 §B.9 + 本文件为准,确有疑义再按需下钻单条。流程体由 scripts/make_flow.py 生成、控件定位细节留在脚本注释里;faq 按「症状 / 检索关键词」定位到单条再读。
一、技能维护边界(最高优先级)
本技能只沉淀通用的平台登录方法、凭据配置机制、查询策略与环境坑,绝不收录某一条具体报错的处理结论 / 某条工单的内容细节(处理方案是每次查询的运行产物,由用户自行归档);产出的报告同样只含通用结论、不写我方客户 / 项目专名。
禁止事项:不为登录写一次性 CAS 脚本(一律用 playwright-cli 标准命令序列)|不把账号密码硬编码进 SKILL.md / references / scripts|不猜测密码损坏(%% 可能是密码真字符,照原样填入)|不绕过 playwright-cli 裸开浏览器|不把真实 dsp_config.json 打进分享包 / 提交 git|不写客户具体信息(客户名、集团编码、业务单元 code、数据量)|不引用其它技能包。
铁律 · 先实查、后结论:任何根因 / 方案回报都必须先实际登录 ISP 完成真实查询取数,且回报须能引用实际查到的完整服务单号(机构前缀 + SR 串);未执行真实查询、或查完却无 SR 单号可引的回报一律视为无效。
回报前自检门禁(强制,违反即重做):交付任何根因 / 方案结论前,必须能回答三个问题——① 本次是否真的登录 ISP 跑了查询流程?② 登录是否取了当前实际可用的最高优先级通道(更高优先级可用时不得降至需人工参与的方式)?③ 回报里的服务单号是否来自本次运行、且未被截断为 SR 后缀?任一为「否」则不得输出结论,须先补完真实查询。
> 本规则优先级高于下方所有章节。红线只在此声明一次。
二、何时使用
- 触发:遇到 BIP 报错 / 异常的原因与方案问题时一律调用此技能(不待用户点名「查 ISP」——用户只问「某报错为什么」同样属本技能场景);另含「登 ISP / 开发者中心」「找历史工单处理案例」「DSP 报错库检索」等显式请求。
- 产出:① 可分享 HTML 报告——结果呈现的默认交付物、而非可选附件;② 对话内文字摘要(根因排序 + 关键证据单号 + 产物路径)。截图仅作运行留证存档,不作为回报内容。
三、首次安装自检与依赖安装 SOP
> 只在新机器 / 收到分享包后做一次。 技能包不携带浏览器 profile 与运行时缓存(二者都是纯本机态),须在本机重建。前置任一不满足都会在后续步骤碰壁,顺序勿颠倒。
3.1 前置四项(先过这一关)
| 项 | 判据 |
|---|---|
| Node.js ≥ 18 | node -v 有输出 |
| npm | npm -v 能打印版本号。只报 Cannot find module .../npm-prefix.js = 依赖残缺,先 command -v npm 看清 PATH 命中哪套 node,选含完整 npm 的那套 |
| Python | python / python3 / py 任一,或用 DSP_PYTHON 指定;collect_offers.sh 硬依赖它,无则 exit 2 |
| 磁盘空间 | 内核解包后占用不小,须预留 |
> 另:root / 容器环境须 --no-sandbox——由 setup_cli.sh 自动生成 .playwright/cli.config.json(--no-sandbox --disable-dev-shm-usage),无需手工维护。
3.2 三步安装(须在本技能目录下执行)
> .playwright/cli.config.json 落在调用者当前目录,换目录就落错地方。
- 就绪命令行驱动——
bash scripts/setup_cli.sh --check分档判读(标准 chromium 内核是采集的硬前提,不是可选项):
| 输出 | 判读 |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|[OK] playwright-cli 可用+[OK] 内核通道就绪| 完全就绪(可采集) |
|[OK] playwright-cli 可用+[WARN] 可用(未锁定内核通道)| 半就绪 = 不可采集:只够「打开 + 登录」,run-code采集会崩(中途报Target page, context or browser has been closed;巨量结果集下渲染崩溃更早出现)→ 必须装标准 chromium 内核后再用 |
|[FAIL](CLI 不在 PATH) | 阻断项(无 CLI 一切免谈) |
装内核=去掉--check跑bash scripts/setup_cli.sh,须同见「[OK] 内核已就绪」与「[OK] 就绪自检通过」两条(只看到「就绪完成」不算)。内核目录位置由本机登记、不在文档里写死——detect_env.sh把它落进cli.runtime.json的browsers_path(非惯例位置亦原样复用);分享包不带内核,受包方须自行装一次。
别只看「实开能不能起浏览器」——无内核时 CLI 会回退系统 Chrome / Edge、实开照样成功,据此判定会把「半就绪」误判成已就绪。系统浏览器通道只作登录兜底,永不作为采集通道。 - 落运行时缓存——
bash scripts/detect_env.sh(首次含实开校验,约 60 s)。退出码即处置依据:
| rc | 含义 | 处置 |
| --------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
|2| 无 CLI | 先跑bash scripts/setup_cli.sh|
|3| 无任何内核目录 | 跑bash scripts/setup_cli.sh装内核 |
|4| 全部无法实开 | 含is not installed/Expected executable者属版本失配(重装匹配内核、勿升级 CLI);其余为启动类失败(清残留浏览器进程后重试) |
| 其它非0码 | 未覆盖的异常——脚本未显式exit时以最末命令的退出码收场(如127) | 勿按上表硬套:连同 stdout / stderr 原样回报后再定处置 |
⚠️3/4有失败标记缓存(状态目录detect_fail.json,TTL 600 s):装完内核后在 TTL 内重跑仍复用旧失败结果、不重探 → 加--force(或删脚本报错时打印的那个detect_fail.json)即可立即重探。
无头 / 无显示环境下实开必然失败,可加--no-probe只做目录探测。 - 写入凭据 → 见 §4.1。
3.3 内核判据(一句话)
「内核就绪」不看 open 能否起浏览器(无内核时 CLI 回退系统 Chrome / Edge、照样成功),而看 detect_env.sh 是否把可用内核落进 cli.runtime.json(exit 0)。open 与 run-code 不等价——系统浏览器回退只够「打开 + 登录」,采集驱动必须真实 chromium 内核,否则 run-code 中途报 Target page, context or browser has been closed。采集路径探测到无内核时自动调 setup_cli.sh 装内核并继续(自愈幂等),仅安装失败才 exit 7。
为什么是「必须」而非「建议」:系统浏览器通道在巨量结果集下渲染易致浏览器中途关闭。「兜底只降低故障率」——run_query.sh 在无内核通道下会把页宽机械收敛为 30(防「宽词 + 高页宽 → 渲染崩溃 → 重跑」),采集路径探测到无内核也会自动装内核,但二者都不等于系统通道可用于采集。正解:首次就把标准内核装上(内核目录经 browsers_path 登记后长期复用,无需重复下载)。
3.4 耗时预期(受包方必读,避免误判卡死而中断)
装 CLI 约 1 分钟|内核下载约 3.5~5.5 分钟(体量不小、须预留磁盘)|detect_env.sh 首次探测约 60 s|首次跑到登录页约 3 分钟——均属正常、不要中断,此后复用缓存与 profile 会显著变快。
> 完整安装说明(换源提速 / 装对包 / 内核镜像 / 离线复用 / 版本纪律 / 非惯例位置登记 / 两脚本内核判据差异)见 references/install_quickstart.md。
> playwright-cli 路径 / 版本与可用内核目录一律由本机探测确定,不在文档 / 脚本里写死;CLI 版本与内核 revision 强绑定,盲目升级会报「(no browsers)」——需变更版本时先跑 detect_env.sh 重探校验。
四、登录网页 SOP
用友系站点共用用友统一认证 CAS(euc.* 域;主机由入口 302 决定、不得写死)。平台入口 https://isp.yonyou.com/——dsp.yonyou.com 是它的别名、会 302 跳过来,故技能内一律以 isp.yonyou.com 为准;开发者中心 https://developer.yonyou.com/ 登录方式同源。
4.1 凭据配置(登录前置;最高优先,分享与复用之本)
原则:账号密码一律进配置文件,绝不明文写进 SKILL.md / references / scripts。
config/dsp_config.example.json——占位模板(username/password用< >包裹);随包发布。config/dsp_config.json——真实配置;不随包发布(被.package_allowlist.txt排除)、被.gitignore忽略。
{
"isp_yonyou": {
"url": "https://isp.yonyou.com/",
"login_url": "https://euc.yonyoucloud.com/cas/login?sysid=sopportal&service=…",
"username": "<用户提供 ISP 账号(手机号)>",
"password": "<用户提供 ISP 密码>"
}
}
写入流程(必做):① 检查 config/dsp_config.json 是否存在且账密非占位符;② 缺失则询问用户 ISP 账号(手机号)与密码,明确告知凭据仅存本机、不随包外发;③ 写入并保持 schema;④ 后续登录直接读该文件、不再重复索要。也可用 scripts/init_config.py 引导(getpass 不回显),但首选由智能体直接询问并写文件——更可控、可顺带核对占位符未被误带。--check 预演会顺带校验该配置的存在性与占位符(仅 WARN、不阻断,且不回显任何值)——不必为此手工 ls / grep 预检。
> 用户不记得 / 不愿提供账密时:索要一次未果即止、不循环索要;不引导「重置密码」、不直接跳 ⑤ F12(二者都不在本技能通道清单内)。凭据要不回来 = ② 无启动条件、等同 ② 失效 → 按 §4.2 直接转 ③ 二维码;③ 成功后登录态照常固化进 profile,之后凭 ① 免登。
4.2 五种方式对照
> ① 复用已登录会话(免登录)> ② 账号密码自动填充 > ③ 二维码 > ④ 短信验证码 > ⑤ F12 取凭证。
| 编号·方式 | 谁操作 | 前提 | 说明 |
|---|---|---|---|
| ① 复用已登录会话 | 自动 | profile 内登录态仍有效(CAS 凭据为会话级:浏览器关闭即丢,跨天 / 长期闲置亦失效) | 登录一次后由 profile 持久化复用;过期则回退 ②/③/④ |
| ② 账号密码 | 我输入 | 用户提供账密 | 走 CAS「普通登录」;弹出图形 / 行为验证码则无法自动跳过 |
| ③ 二维码扫码 | 我出码、用户扫 | 手机装「友空间」App | 扫码授权不触发图形验证码、最稳;须把「出码 → 轮询等扫 → 校验落地 → 固化登录态」放进同一条命令 |
| ④ 短信验证码 | 我输入 | 用户提供手机号 + 验证码 | 人工动作是把验证码回填登录页、跨命令即丢会话,故一般不可行(除非改用命名会话 -s=<唯一名> 长驻承接) |
| ⑤ F12 取会话凭证 | 用户操作 | 用户自行网页登录后 F12 提供 | 广义是 Cookie 或 Authorization / 验签头,本质「把登录态借给我」;兜底,必成 |
查询页按 ① > ② > ③ > ⑤ 逐级下沉,走到成功即停。判据是「人工动作发生在浏览器之外还是之内」——③ 的人工动作在手机端、可整段闭环;④ 的在浏览器内、跨命令即失效。
连通即取最高、禁向下降级讨授权:① 成立时直接免登进入,不得向用户讨任何授权;只有当更高优先级方式确已失效,才允许降到 ③ / ⑤ 这类需用户动一次手的做法,并向用户说明是哪个 reason 导致。
4.3 ①② 已内置(免手工)
scripts/make_flow.py 默认把 config/dsp_config.json 的账密内联进流程体,流程体开头即按 ①→② 顺序自动完成——先复用已登录会话,失败则自动账密登录再继续跑。因此 ①/② 任一可达时,整件事在那一次 run-code 调用内就跑完了,不要再另写登录脚本、也不要向用户讨 ③/⑤。
仅当返回 need_login(附 reason:no_cred / badcred / captcha / controls_missing / bounced / not_advanced)才说明 ①② 确已失效,此时才按优先级降级。「无凭据」也是 ② 失效的一种——凭据缺失 / 占位符时脚本在凭据前置检查即退出(exit 2/3、浏览器未启),走不到「返回 need_login」那一步,不得据「没看到 need_login」判定降级条件未触发。
被挡 ≠ 账密错误——reason 已拆:badcred =账密错(核凭据)/captcha =确被风控(走人工通道)。分享后全新环境 ② 通常可直接通过(验证码由服务端风控按需下发,客户端指纹不是触发源);未验维度:出口 IP / 异地 / 账号。两类都不要反复重试——账密错时错试会诱发滑块,被挡时继续重试只会越试越难。
4.4 ⑤ F12 取凭证的落地(写入一次、之后凭 ① 免登)
由 scripts/cookie_to_state.py 把 Cookie 串转成 Playwright storageState,落进 <profile>/_auth_state.json,后续登录段用既有 state-load 分支复用,无需每次重做。四个要点:① 不要用控制台 document.cookie——它会漏 HttpOnly 会话 cookie,注入后 401;② 归属域默认 isp.yonyou.com,凭证含 CAS 票据域时追加 --domain euc.yonyoucloud.com --domain .yonyoucloud.com;③ 脚本只回显 cookie 名清单、不回显任何 cookie 值;④ 注入校验须整段同一条命令(open → state-load → goto → 回读 location.href,已离开 cas/login 即成功),复用期仍受服务端会话时效约束,跨天失效时重做一次即可。逐步命令见 references/manual-steps.md §B.1。
4.5 通用约束
- 控件
ref不仅跨会话会变,同一会话内每次交互 / 表单重渲染后也会重新分配——须现读快照,禁止写死 id、禁止跨轮复用;连续多关键词查询等循环操作时,每轮都要重新快照取 ref 并留取空重试。 - 此「已登录」指本技能独立 profile 的登录态(非你平时 Chrome);首次用需走 ②/③ 登录一次使其持久化,之后 ① 自动满足。
- 注意复用期受服务端会话时效约束(会话级凭据跨天 / 长期闲置即失效,届时需再做一次认证),并非「登一次即一劳永逸」。
> 逐步命令见 references/manual-steps.md(仅排错与定制时读)。登录失败的归因、验证码触发源、badcred 与 captcha 的区分、复用期为何会失效,见 references/faq.md 按症状定位。
五、执行查询工单过程 SOP
本技能只用 playwright-cli 一条驱动路径,不存在通道选择:常规检索一律走单入口脚本,排错与定制才用底层命令。
5.1 四步 SOP(照做;执行失败几乎都出在没走全这四步)
> 先判环境(客观条件,不靠记忆)——S1 是否要做,只取决于下面两个文件是否同时存在:
> bash
> # 暖机判定:两个都存在 = 暖机 → S1 跳过;缺任一 = 冷机 → 走 §三 安装 SOP
> ls "$HOME/.workbuddy/dsp_state/cli.runtime.json" "$HOME/.workbuddy/dsp_state/_chrome_profile" >/dev/null 2>&1 \
> && echo "暖机:跳过 S1" || echo "冷机:需走 §三"
>
> 两文件皆在 ⇒ 暖机:内核已登记、profile 已缓存,run_query.sh 运行期自会复用,S1 整个跳过(不要跑 setup_cli.sh --check、不要 ls 探测目录、不要读凭据文件——凭据存在性由 preflight 兜底且不回显)。
> 缺任一 ⇒ 冷机:执行 §三 三步安装 SOP。
> 本条判据不得凭印象替代:「我记得上次装过」不是判据;要么跑上面这行,要么直接跑 run_query.sh——它冷机时会因缺内核自动装并继续,不需要你预判。
| 步 | 动作 | 命令 / 要求 |
|---|---|---|
| S1 | 环境就绪(仅冷机:上述两文件缺任一) | 暖机则跳过;冷机见 §三 |
| S2 | 关键词清单一次性定稿 | 全部词写进同一个 --batch(#术语: / #口语: 两段) |
| S3 | 门禁预演(条件必跑:仅冷机、或本次参数未验证过时才跑) | bash scripts/run_query.sh --check <全部参数>;暖机且参数已验证 → 跳过本步,直接 S4(判据同 S1,见 §零 暖机快捷路径) |
| S4 | 真实检索 | bash scripts/run_query.sh <全部参数>;前台 + 显式长 timeout(600000 ms) |
> S3 耗时:关键词解析已合并为单遍内建解析(耗时几乎不随关键词数增长),剩余主要是固定启动开销(运行期自快照 + 解释器发现)。仍应一次把参数给全、一次跑完,不要分批改参数重跑(每重跑一次就重付一遍固定开销)。0 成功;1 门禁未通过(逐条 [FAIL] 随 stdout 给出,改参数、不要改脚本);2 未知参数;127 补 export PATH="/usr/bin:/bin:/c/Windows/System32:$PATH" 后重跑。脚本诊断一律双写 stdout 与 stderr,任一通道都能读到原因,不会出现「退出非 0 却零输出」。
> S4 若被转后台:前台运行超过执行侧默认超时会被自动转后台(不是失败、不丢结果)——读产物目录等它收敛即可,不要重跑(重跑=再付一次「清场 + 打开 + 恢复登录态」)。
> 输出目录:--out-dir <目录> 是本入口自有参数(非底层透传);不给时回落到调用者 CWD 下的 dsp_query_out(相对路径、换目录即散落)——每次显式给绝对路径。
> 无具体报错查询(需先检索、再基于真实结果现写 --linkage-text)一律走 §5.7 标准两步法:S4 直接带 --no-report 跑真实采集(--check 仅在「冷机或本次参数未验证」时才加;暖机且参数已验证则不加),先出 TSV、再单独 digest_offers.py --report 现写联动结论。这样跳过「检索前硬凑联动结论 → 被门禁挡下 → 再探参」的试错,门禁一次过。
5.2 后置打包(铁律 · 单消息合并为 1 轮)
> 铁律 · 后置必须单消息合并(唯一合规形态):本技能采集(--no-report)与渲染(--finalize)各只允许 1 次 Bash 调用,步骤用 --steps-content 内联、关键词用 --batch-content 内联,禁止先 Write 任何文件、禁止独立 --check 轮、禁止独立环境探测轮。S4 落盘 offers_union.tsv / offers_relevant.tsv 后,下列 4 步(内联 --steps-content → 现写 --linkage-text → run_query.sh --finalize --steps-content → present_files)必须在同一条消息内依次发出、算 1 轮,不得拆成多轮往返(拆轮只增加平台调度与决策延迟,不加快任何真实执行)。--no-report 已内嵌打印 top-10 全文,无需再单独 Read TSV 表头 / 跑勘察命令确认格式——直接用其写 --linkage-text 即可(见 §6.4 门禁 ⑧)。运行 run_query.sh --finalize 成功后会在输出尾部强制打印 §5.2 铁律提醒,须在同一条消息内紧接着执行 present_files,不得拆轮(详见 §6.4 ⑧ / Fix A)。
S4 落盘 offers_union.tsv / offers_relevant.tsv 后,所有后置动作合并进同一条消息、顺序执行,算 1 轮:
- 用
--steps-content内联排查步骤(排查顺序,每行步骤标题 | 理由说明 | 证据单号,单号用,分隔;不再单独 Write steps.txt 文件);关键词清单同理用--batch-content内联; - 现写
--linkage-text结论(基于 S4 内嵌的 top-10 全文,禁止提前硬编码); digest_offers.py --report(传入--steps-content与--linkage-text;脚本在渲染前强制执行 SR 一致性自检——把--linkage-refs与--steps里出现的每个证据单号,与本轮--input(=offers_union.tsv)逐行比对,缺失即[FAIL]并阻断出报告,rc=4);present_files呈现 HTML 报告。
合并与删除规则:
- 上述 4 步在同一条消息里依次发出,靠顺序依赖一次完成,不得拆成多轮往返(拆轮只增加平台调度与决策延迟,不加快任何真实执行)。
- 唯一合规调用形态:采集(--no-report)与渲染(--finalize)各只允许 1 次 Bash 调用,关键词/步骤一律内联;任何「先 Write 文件」「独立 --check」「独立 ls/探测」的拆轮都属违反门禁 ⑧⑨⑩,须重做。
- 删除独立的「抽 SR 号 / 读明细」轮:--no-report 的 digest 勘察输出已内嵌打印 top-10 的完整问题 / 方案正文,无需再 grep 一遍。
- 不可省的是 S2 关键词定稿 / S4 真实检索;S1 按环境判据(暖机跳过,见上表)、S3 同 S1(暖机且本次参数已验证时跳过)——判据与 §零 暖机快捷路径同口径,两处一致。
【为什么 S3 不是无条件必跑】真实运行的 preflight 会执行完全相同的门禁校验,故暖机下预演纯属多付一轮进程拉起(约 1.5–2 min,含 agent 往返);只有「冷机」或「本次参数还没验证过」两种情况下预演才有拦截价值。在暖机下跑 --check 属可省的一轮,不是必需步骤。
- 禁止独立环境核验轮(暖机):cli.runtime.json 已登记内核、_chrome_profile 已缓存时,严禁再发 ls 内核目录 / 读 config 大小 / 看 profile mtime 之类的独立轮次来「确认暖机」——凭据存在性由 preflight 兜底校验(不回显),内核/会话由运行期自理。这类多此一举的轮次会带坏节奏、诱发后续分步(本次已犯,列为此反例)。
5.3 唯一入口,禁止绕开
| 场景 | 怎么做 |
|---|---|
| 批量检索(多关键词 / 跨年 / 翻页取全)——主场景 | bash scripts/run_query.sh 单入口;禁止绕开它直接调 collect_offers.sh / make_flow.py / flow_result_to_tsv.py / digest_offers.py / tsv_to_report.py 做分段拼接 |
| 交互 / 单步查看、控件排错 | 用 playwright-cli 逐条命令,见 references/manual-steps.md(仅此场景才读) |
| 用户显式指定做法 | 以用户指定为准 |
为什么批量必须合并成一次调用:playwright-cli 每敲一条命令都要重拉进程并重连浏览器(单条固定开销约 3.5 s,量级有争议、跨机请按 3.5~17 s 区间取值),一次常规查询约 100 条命令,绝大部分时间花在冷启动上。故一律走「一次性驱动」——把整段流程合并进一次 run-code 调用,冷启动只付一次。逐命令循环是慢路径,批量化场景不得使用。
两条硬约束:
- 不在检索中途换做法——批量取数按单入口一路走到底;未中断时不得中途改用逐命令循环(等于重新付一次「清场 + 打开 + 恢复登录态」)。
- 选做法须先判登录可行性——复用已登录会话可达时登录不构成约束,失效时走 §4.2 阶梯。登录失败=整件事做不成,故效率偏好不得覆盖可行性约束。
5.4 一键采集与状态目录
scripts/collect_offers.sh(由 run_query.sh 内部调用)把「清场 → 打开 / 登录 → 固定筛选 → 逐关键词提交 → 采全 → 解码 TSV」全部浏览器动作合并为一次 run-code 调用,并自动抹掉流程体内的内联凭据。默认形态是一步到位(直接带 --batch),登录段与查询段共用同一次浏览器会话;仅当确实要预先落登录态供后续多条命令复用时才用 --login-only。
状态目录:运行时环境缓存与浏览器 profile 一律落在用户级状态目录 $HOME/.workbuddy/dsp_state/(可用 DSP_STATE_DIR 整体换目录,或用 DSP_RUNTIME_CONFIG / DSP_PROFILE 各自覆盖),与工作区解耦——换工作区不重付探测与登录成本。副作用:不要并行跑本技能(状态目录全机共用且每次运行开头都会清场,后开始的任务会把前一个的浏览器清掉);确需并行时用 DSP_PROFILE 为每个任务分目录。
5.5 取数后一次成型(禁止逐轮往返搬运)
拿到 offers_union.tsv 后先跑一次 scripts/digest_offers.py——输入须用 -i <union.tsv> 指定(该参数为必填,当位置参数传会直接报错中止),一次给出「领域·模块分布 + 根因簇命中计数 + 最相关 top-N 短摘」并落 offers_relevant.tsv;加 --report <输出目录> 则同一条命令直接渲染出可分享 HTML。不要用多轮脚本分别做筛选 / 聚类 / 取详情。
--must 支持前瞻断言正则表达「与」(如 --must "(?=.*预算组织体系)(?=.*(删除|引用))");--domains 直接取它打印的「领域·模块分布」结果,不必先跑勘察脚本;--symptom / --boost 分别给症状词 / 主题词加权(权重最高 / 次之)。
5.6 结果呈现(默认交付物)
- 可分享 HTML 报告是常规回报的默认交付物、而非可选附件:须 CSS 内联、不依赖外部资源;报告内「根因分类」为 AI 初判、已标注待人工复核。文件名固定格式——
--report传输出目录时自动命名为<主题>问题分析报告.html(主题取自--report-title,剥掉结尾「报告」二字与副标题、清理文件名非法字符);传.html完整路径则沿用原名。 - 报告章节编排(已固化于
tsv_to_report.py):根因概览 → 最贴合历史工单(必出)→ 建议排查顺序(可选)→ 方案明细表 → 处理建议;章节序号按实际渲染区块顺次累加、不得写死常数。「方案明细表」默认只渲染关联度前 30 条(--detail-limit,默认 30 / 0 = 不限),表尾注明「取前 N 条 / 相关集共 M 条」,完整相关集仍在offers_relevant.tsv。 - 方案明细表列序固定:① 适用版本边界 ② 来源服务单号 / 年度 / 产品线 ③ 问题摘要 ④ 命中 ⑤ 根因·方案摘要。④「命中」只标该条在报告中的角色——被「最贴合历史工单」或「建议排查顺序」引为证据的标「证据」、其余标「参考」;它不是与本问题的贴合度排序,真实贴合度须人工判断。
- 建议排查顺序须随报告交付(易漏项):依据本次命中工单归纳的排查先后顺序不能只留在对话里——须写入
--steps文件(每行步骤标题 | 理由说明 | 证据单号,单号用,分隔)并传给--report,报告即在明细表前插入该区块(后续章节序号自动顺延);缺失或无有效行时静默跳过、不报错。 - 两章职责切分(不得混用):「最贴合历史工单」只放唯一 1 条主线工单——须是本次检索中相关性最高的那一条(带上其机理与处置即可让读者拿到答案),
--linkage-refs最多 1 个单号(「最」字语义要求唯一,门禁已强制 ≤1);其余根因一律写进第三章「建议排查顺序」(每步一个根因 + 理由 + 其证据单号,可多单号)。判据:若某条既不承载主线结论、又有自己独立的排查动作与证据,它就属于第三章、不属于第二章。 - 工单号一致性铁律:服务单号须按 §一 口径带完整形态(含机构前缀与
SR串),禁止截断为SR后缀(否则用户在 DSP 搜不到)。 - 版本适配性:优先列与用户版本(2207/2305/2312/2505…)同版本的方案;其它版本在「适用版本边界」列标注差异并按可迁移性排序——高版本方案不等于可用于低版本,跨大版本只作思路参考。
- 收尾只报结论、且动作合批:回报给出「根因排序 + 关键证据单号 + 产物路径」即可,不逐条复述摘要里已有的正文;临时件清理与产物呈现尽量在一次内完成。收尾铁律:禁止用
python -c内联多行脚本(凡多行 Python 一律落成.py再执行);流程体路径只用make_flow.py --out回显的实际落盘路径,不要自己拼。
> 红线 · 联动结论区块必出且须每次现给(防跨主题串味):报告必出区块「最贴合历史工单」的内容一律由 --linkage-text / --linkage-refs / --linkage-note 传入,脚本内不保留任何主题结论。① --linkage-text 为必填——缺省 / 空值即报错退出,该章节每轮必定出现,逼着按本次检索结果现写联动结论与证据单号;② --linkage-refs / --linkage-note 可选。禁止把上一轮的主题结论留在源码里——一旦硬编码,下次换主题出报告会被原样带出,表现为报告里出现与本次问题无关、甚至本次数据中根本不存在的证据单号。交付前自检:报告里出现的每个证据单号,都必须能在本轮 offers_union.tsv 中 grep 到。 现已由 digest_offers.py --report 在渲染前脚本强制执行:证据单号未命中本轮输入 TSV 即 [FAIL] 阻断(rc=4),无需 AI 手工 grep。
>
> --report 还须与 --report-title / --report-keyword / --report-product / --report-version / --report-years 五个标题参数一并给全。完整参数与示例见 references/workflow.md §C 1.1 / 1.2。
> 「最」的含义 ·两章切分(已机械门禁):「最贴合历史工单」= 本次检索中相关性最高的唯一 1 条主线工单,不是"相关的一堆";其余根因归第三章「建议排查顺序」。run_query.sh 已加机械门禁——--linkage-refs 超 1 个即 [FAIL] 阻断,须改用 --steps 写入第三章。该约束的设计意图见 tsv_to_report.py 中该区块注释("集中给出与本问题关联性最高的唯一 1 条")。
5.7 无具体报错查询标准两步法(默认,强制纳入门禁)
为什么必须两步:run_query.sh 把「检索 + 渲染报告」合并为一次入口,而报告的 --linkage-text 必须基于本次真实结果现写(§5.6 红线)。检索前拿不到联动结论,一次性合并入口必然陷入「先硬凑联动结论 → 被门禁挡下 → 再探参」的试错。故无具体报错查询(即不设 --error-query 的多关键词组合场景)统一走两步法,把「检索」与「写联动结论 + 渲染」解耦:
| 步 | 动作 | 命令 |
|---|---|---|
| 1 检索 | run_query.sh --no-report 仅出 TSV(跳过报告参数门禁);top-10 已内嵌打印,禁止再单独跑 digest_offers.py 勘察态(纯增一轮) |
bash scripts/run_query.sh --no-report --batch <词表> --version <版本> --years <年,年> --out-dir <输出目录> --product <产品线> |
| 2 读结果 + 写 | 直接用步 1 内嵌打印的 top-10 现写 --linkage-text 与 --steps(不再单独跑勘察命令) |
Write(steps.txt) + 基于内嵌 top-10 写 --linkage-text 文本 |
| 3 出报告 | run_query.sh --finalize(等同 --render-report)跳过采集、直接基于已有 TSV 渲染(单次 Bash 调用,SR 一致性自检内置);成功后输出尾部强制打印 §5.2 铁律提醒,须在同消息内紧接着 present_files |
bash scripts/run_query.sh --finalize --batch <词表> --version <版本> --years <年,年> --out-dir <目录> --report-title "<主题>" --report-keyword "<词>" --linkage-text "…" [--linkage-refs "…"] --steps steps.txt |
> 后置合并(见 §5.2 铁律):步 1 已内嵌打印 top-10 全文、无需再单独跑勘察命令;步 2(读结果 + 写)与步 3(出报告)连同 present_files 按 §5.2 后置铁律合并为同一条消息内的 1 轮,不得拆散(即 Write(steps.txt) → Bash(--render-report) → present_files 一次性发出)。
>
> 合并后置 · 标准动作模板(同一条消息内依次发出,算 1 轮):
> > # 同一条消息内依次发出,不得插入「Write steps 文件 / 读 TSV / 查依赖 / 二次 --check / 独立环境探测」等独立轮次:
> Bash(run_query.sh --finalize --batch-content "<#术语:…#口语:…>" --version <版本> --years <年,年> \
> --out-dir <目录> --report-title "<主题>" --report-keyword "<词>" \
> --linkage-text "…" [--linkage-refs "…"] --steps-content "步骤标题|理由|单号
> 步骤标题|理由|单号")
> present_files(同一 html) # 呈现(HTML 路径由 --report-title 确定,可直接给)
>
> 关键变更(端到端单调用):① 关键词清单用 --batch-content 内联、排查步骤用 --steps-content 内联,不再单独 Write 任何文件;② 真实运行内置 preflight 已做门禁校验,无需独立 --check 轮;③ 暖机环境下禁止任何独立 ls/探测轮(内核登记与 profile 缓存由运行期自理,凭据存在性由 preflight 兜底校验且不回显)。
> 其中 --linkage-text 直接基于 --no-report 已打印的 top-10 现写;--finalize(等同 --render-report)会跳过采集、直接基于已有 offers_union.tsv 渲染报告,且成功后输出尾部强制打印 §5.2 铁律提醒(后置物理上成为 1 次 Bash 调用 + 同消息 present,从结构消灭拆分)。
门禁强制点:不带 --no-report 且未给齐 --report-title/--report-keyword/--linkage-text 时,门禁(run_query.sh 内)直接 FAIL 并提示本两步法——不靠 agent 自己试探。即:要么一次性给齐三项报告参数走合并入口,要么加 --no-report 走两步法,无第三种选择。
少犯错清单(门禁意图落地):
1. 报告标题一次给干净:直接给主题(如 贷款付息未推结算单),不要带「分析 / 报告」后缀——--report-title 会自动追「问题分析报告.html」,带后缀会冗余成「…分析问题分析报告.html」导致重渲染。
2. --no-report 从头带到尾:S3 门禁预演也带 --no-report,一次过;不要先不带、被 FAIL 后再补(多一轮冷启动 + 探参)。
3. --linkage-text 禁止占位符:必须步 2 读结果后现写,含真实证据单号(§5.6 红线)。
4. 出报告用 run_query.sh --render-report 直接吃已有 TSV(跳过采集、单次 Bash 调用),不要重跑采集版 run_query.sh(重跑=再付一次登录 + 清场),也不要裸调 digest_offers.py(绕开本入口的 SR 一致性自检与单入口约束)。
六、检索查询策略与门禁
6.1 过滤:先收窄,再放开
- 产品线:只输出用户所指产品线(高级版→
YonBIP高级版、NCC→NCCloud、NC65→NC),其它线不纳入。 - 产品版本:属版本强相关(报错文案 / 补丁归属与版本绑定)时先选定该版本;样本不足再放开并注明来源版本。
- 跨年覆盖近 5 年:当前 + 往前 4 年(年份按当前年动态取、不写死);【提交年度】为多选,一次勾选即覆盖多个年度。
- 【解决方案】字段可反查:已知补丁编码(
SUPPORT-...)或方案特征词时,用它反查同类工单(与【问题描述】走症状互补)。
6.2 关键词三层编排(清单必须一次定稿,两套词表交叉列)
> 权威算法·接近度优先、逐步放开、累计 100 即止:batch 文件中的关键词顺序即接近度顺序——最精准的「对象+动作/症状」组合词排最前,最宽泛的「超集词」排最后(门禁 ⑥-2 会拦截「宽泛词前置」倒置)。流程严格按该顺序逐词跑;累计去重 ≥ --total-limit(默认 100)时立即终止整个循环(门禁 ④),不跑后续词、不翻多页、不自愈追加。即:先吃最对症的样本,不够再逐步放开到宽泛词补量,一到上限就停。「逐步放开」指放宽到更宽泛的组合词,不是放开到裸单词(裸单词取数仅限具体报错场景,见 §6.5)。
| 层 | 内容 | 处理 |
|---|---|---|
| ① 系统术语精准组合词 | 平台页面标题 / 节点名 / 字段名上的说法(以截图与现场页面为准) | 必跑,排最前 |
| ② 用户口语词 / 原话词 | 客户 / 用户原话里的说法 | 值得跑。常是「低命中、高独家」,不要因为它是宽词就一律丢进末端兜底;但数量不必多,1~2 个高相关即可(见下方实证:否定式长组合词实测 0 命中) |
| ③ 通用症状宽词 / 模块名单词 | 产品名、模块名等 | 受门控兜底,通常直接跳过 |
> 口语词数量不必凑(与门禁的关系已放宽):#口语: 段缺失只告警、不阻断运行(原为硬门禁,与本节实证直接冲突——实证说否定式长组合词 0 命中白耗 78s,硬门禁却强制必须写口语段,agent 按实证精简必然被挡下、只能加回零命中词再重跑一整轮冷启)。故:按实证精简词表是正确方向,不必为凑段把零命中词加回来;口语词的价值在「独家」不在数量,仅当客户原话与术语词差异大时才补 1 个。
> ⚠ 排序硬约束(无报错查询):batch 的前 1~2 行必须是「对象 + 动作 / 症状」组合词;仅堆叠对象、无动作 / 症状限定的组合(如 报销单/付款结算单)虽含 / 但实为最宽泛的「超集词」,必须置底。理由:流程按 batch 顺序执行、遇「累计 100 停」即终止整个循环——宽泛词置顶会单独吃满上限、挡掉后续全部精准症状词,结果偏集且后续词根本不执行(实测:单条命中 347 的宽泛词置顶后,其余 5 个更对症症状词全部被跳过)。机械门禁 ⑥-2 只拦截「靠前长词字面子串包含靠后短词」的字面倒置、不识别语义广度——语义排序由操作者自行保证,勿依赖 ⑥-2 兜底;⑥-3 会对「各段均为对象名词(单 / 表 / 档案 / 类型)且不含动作/症状线索」的疑似超集词,在出现于 batch 首行或任一「对象+动作/症状」组合词之前时给出 [FAIL] 并阻断运行(已升级为硬门禁,非可忽略的误报)。
>
> 反面教材:曾把 报销单/付款结算单(最宽泛超集词)放首行、违背优先级——它单条命中 347 直接吃满上限,把更对症的症状词全部挡在门外,等于用最不精准的样本覆盖精准样本。正确做法只是按优先级重排(症状词前置、宽泛词置底):重排后流程按优先级顺序跑、到 100 即止,所得即是「高优先级样本优先」的合集,单轮即可,无需二次采集、也无需 --total-limit 0。注意:上限触发本身从来不是问题——无论在第 1 个还是第 4 个词触发,累计已 ≥100 条、足够分析;唯一要避免的是「低优先级宽泛词被排到前面抢跑」。
>
> 词型共现实证(2026-10-02,高级版 2207 费用/结算域实测,8 词采 101 条):无具体报错场景下,工单口语语料按词型的共现强度为——双对象名词对(源单据/目标单据,用单据全称)> 对象 + 正向动词短组合 > 否定式长组合。⚠ 此处的「>」表示「共现命中质量(价值)排序」,并非 batch 的「执行先后顺序」;实际执行顺序以下方「排序硬约束」为准——前 1~2 行必须是「对象+动作/症状」组合词,双对象名词对必须置于症状词之后、宽泛超集词之前。带完整宾语的否定动词串(如 报销单/未生成付款结算单、报销/没有生成付款单)在工单描述里几乎不连续出现:实测 6 条此类词合计 0 命中、白耗约 78 s,而唯一的「双对象名词对」报销单/付款结算单 单条命中 347。规则:① 否定式长组合词最多保留 1~2 个、且压成短式(如 报销单/未付款),不得作为主力词铺量;② 主力词优先用「双对象名词对 + 单据全称」(如 报销单/统一付款结算单)与「对象 + 正向动词」(如 报销单/传结算);③「双对象名词对」各段均为对象名词,属疑似超集词,受 ⑥-3 硬门禁约束——必须置于「对象+动作/症状」组合词之后、宽泛超集词之前;若出现在症状词之前(含 batch 首行),⑥-3 直接 [FAIL] 阻断运行,不是可忽略的误报。
四条判据:
- 「精确词」=「对象 + 动作 / 症状」的组合词,不是产品名 / 模块名单词——后者看似精确、实为领域通用宽词;清单必须以组合词打头。
- 组合词控制在 2~3 个:
/组合要求共现(是「与」非「或」),而 ISP 语料多为口语化、共现率低;其余覆盖面由更多角度的组合词承担,不得退化为裸单词(无报错场景禁用单词取数,见 §6.5)。 - 顺序 + 门槛必须一起给:提交顺序即执行顺序。
--fallback-from N把第 N 个及之后标成受门槛门控的兜底词,由--min-sample N(配--sample-pattern按症状计)决定是否还要跑;默认即为 2 =「够用即停」。注意:--fallback-from 0(强制全量并集)已从技能移除、不再可用——要按优先级跑齐全部组合词并逐词计量,改用--min-sample 0(关闭「样本达标即跳过后续」判据、让组合词按 batch 顺序跑完;仍受「累计 100 停」约束,计量由流程边跑边被动记录,见 §6.4④,无需放开上限、也绝不二次采集)。裸单词取数仅限具体报错,见 §6.5。 - 有效样本量按症状计,不按去重总数计:宽泛词会把去重总数推高、让后面的词被误判「样本已够」——清单里只要有宽词兜底,就应同时给
--sample-pattern。
6.3 采全口径
命中总数只认结果表分页器的「总计:N 条」。页宽档位 10 / 30 / 50 / 100,脚本默认切 100 条/页,切换必须在结果渲染之后。命中数 > 页宽时明示放弃翻页、接受 [WARN]——采满一页(默认 100 条)即已足够提炼,无需翻页(实测【下一页】点击不换页)。
6.4 门禁一览(跑之前会被什么卡住)
| # | 门禁 | 判据与处置 |
|---|---|---|
| ① | 清单先定稿 | 批量检索第一次运行前必须把本次全部关键词一次性列全(两套词表交叉列、按「精确 → 症状 → 兜底」排序)写进同一个 --batch 文件,清单定稿前不得启动任何一次运行。出现「先跑一批看看命中多少、再决定下一批查什么」的想法,即是本门禁的违规信号——它让计划天然分批,每批各付一次登录段固定成本(成因与实测见 faq.md Q1.24 / Q1.25)。 |
| ② | 关键词下限 | 非具体报错查询至少 2 个关键词;具体报错查询(--error-query)允许 ≥1 个精确报错词,且须同时传 --error-text <精确报错原文>、其值须等于 batch 首行关键词。低于下限即拒绝运行。 |
| ③ | 精确词置顶 | --error-query 时 batch 首行必须是精确报错原文;精确报错词被宽泛组合词垫后即 FAIL(既违反「精确 → 症状 → 兜底」,也浪费采集轮次——精确词本可一轮命中)。 |
| ④ | 累计 100 停 | --total-limit N(默认 100;显式给 0 = 不限)——落实「接近度优先、逐步放开、累计 100 即止」:流程按 batch 文件顺序(=接近度顺序)逐词跑,累计去重 ≥ N 时立即终止整个关键词循环,不再启动任何新词(含兜底词),任何参数都无法绕过(仅 --total-limit 0 可解除)。截断为关键词内+关键词后双重:① 单词采完一页后即判,达上限不再翻页;② 达上限后跳过漏采自愈、不追加样本;③ 该词采集结束立即 break。⚠️ 平台粒度:单页 = 实际页宽(通常 100 行)不可截断,故触发上限的词仍会一次性拉满至多一页,累计去重可能短暂达 100~(页宽) 区间——这非逻辑缺陷,循环会在该词后立刻终止、不再追加;如需更贴近 100,把宽泛超集词排在更后、或显式 --total-limit 0 取全集后本地截断。另:逐关键词计量(返回条数 / 查询时长)是『对本次实际执行的采集』做被动记录——只报真正跑过的词及其计量;命中 100 上限而中止时,未被执行的后续词如实标注「未执行(累计100停)」即可,无需为计量而 --total-limit 0 放开上限、也绝不因上限触发而二次采集。被跳过的词由统计段逐条列出并标「未执行(累计100停)」,无需从日志推断。 |
| ⑤ | 页宽 / 超限 | --oversize-limit N(实际门槛取 max(本项, 页宽))——超限即切页宽采满一页、不翻页、不做漏采自愈并接受 [WARN]。「采满一页」≠「只采首屏」,页宽仍须切。非合法页宽档位(10 / 30 / 50 / 100)的值会被门禁自动钳到最近档位并 [WARN]——非档位值在「切页宽采满 N 条」时物理上取不到,钳制后日志口径才与实际采集量一致。 |
| ⑥ | 样本门槛 | --min-sample / --fallback-from 联动,见 §6.2 判据 3。 |
| ⑦ | 组合词共现 | 非具体报错查询(--error-query 未设)时,每个关键词须含 / 共现算子(「对象/动作/症状」组合词),禁止把裸模块名/产品名单词(如 付款结算单)当主关键词提交(§6.2 ①/③)。非具体报错查询时一律禁止裸单词兜底(无报错场景只允许组合词,不得退化为单关键词取数)。由 bash run_query.sh --check 机械强制。 |
> 门禁 ⑧ 后置合并(行为级,须自证):取数完成后,下列动作必须在同一条消息内依次发出、算 1 轮:准备 --steps → 写 --linkage-text → digest_offers.py --report(或 run_query.sh --render-report / --finalize)→ present_files。下列轮次一律禁止单独立轮(脚本已成功时均为冗余、纯增延迟):① 单独 Read TSV 表头 / 格式确认;② 查 digest_offers.py 依赖(imports);③ 重排 batch 后二次 --check 门禁(首次已过、重排只改 WARN 严重度、不影响通过);④ 单独写记忆轮次。违反即重做(§5.2 铁律)。运行 run_query.sh --render-report / --finalize 成功后会在输出尾部强制打印 §5.2 铁律提醒(Fix A),须在同消息内紧接着 present_files;该提醒弥补本门禁「行为级、无机器兜底」的盲区。本门禁为行为级,靠 agent 出报告前自证,不靠 --check 机器拦截。
>
> 门禁 ⑨ 前置轮次合并(行为级,须自证):环境就绪(setup_cli.sh --check / detect_env.sh)/ 关键词写入 / 门禁预演 三件事合并编排——暖机环境(内核已登记 cli.runtime.json、profile 已缓存)可跳过环境重验,直接 Write(keywords) + bash run_query.sh --check 合并为 1 轮;参数契约已固化于 §五 / §六,禁止为「确认参数」去读 workflow.md §B.9 或脚本正文(--check 会在参数错时报错告知正确名字,无需预读);凭据预检不单独成轮(真实运行在凭据前置检查即 exit 2/3、浏览器未启,失败极快,无需提前 python 校验)。违反即重做。
>
> 门禁 ⑩ 落盘轮次合并(行为级,须自证):记忆 / 产物落盘:mkdir -p <目录> + Write(<文件>) 合并为 1 轮,禁止 ls → mkdir → Write 三拆轮(mkdir -p 幂等,无需先 ls 探存在)。与 ⑧④(单独写记忆轮次)一致。
>
> ①②③ 连同必填项(--version / --years;--batch 须含 #术语: / #口语: 两段)由 run_query.sh 的 preflight 机械强制(不启浏览器、不落盘)——--check 只是 preflight 的独立预演入口(同校验内容),暖机且参数已验证时无需单独跑,判据同 §5.1 S3;④⑤⑥ 在运行期由脚本自行门控;⑧⑨⑩ 为行为级门禁,由 agent 出报告前自证(不在机器校验范围)。其中 ⑧ 由 run_query.sh --render-report/--finalize 输出尾部的强制提醒做「决策点补强」(Fix A),⑨⑩ 仅靠 agent 自证。
6.5 查询口径二分(铁律)
检索一律按「有无具体报错」二分,二者取数口径互斥:
- 有具体报错 → 用报错原文匹配:
--error-query+--error-text <精确报错原文>(门禁 ②③ 已强制)。单关键词口径只在此场景适用;命中即形成结论出报告,不受 100 条门槛约束。 - 无具体报错 → 一律多关键词组合(含
/共现,见 §6.2 / §6.4⑦),按与主题的关联度从高到低排;累计 >100 条立即停(门禁 ④)。严禁退化为单关键词取数——即使多个组合词都未查满 100 条,也直接以已查到的组合词结果出报告,不借单词兜底补量。 - 对照词仅用于验证筛选是否生效(确认「暂无数据」是真的而非筛选没设上),属链路校验、不是取数口径,不改变上面「无报错禁用单关键词取数」的约束;应作为
--batch的末尾(最后 1 个)词与主题词同批跑——精确组合词置顶先拿到计量,对照词垫后,命中「累计 100 停」上限被门控跳过时如实标注「未执行(累计100停)」即可(它本身非取数口径,不影响结论)。禁止把对照词放首位:对照词是链路校验词、非取数口径,放首会抢先占满累计上限、挡掉后面真正需要对症计量的精确组合词(§6.2 / §6.4⑦ 已强制组合词形态)。
查询复核铁律:提交后必须确认结果真是本次的(该响应自身请求的 proDesc 与当前关键词配对),不是「结果表签名变了」;命中 0 或偏少时,用对照词验证链路并留「选完年度后的筛选回显快照」证明确实暂无数据,方可下「无命中」结论。
> 完整表述见 references/workflow.md §C 1.3.5。
七、问题清单速查检索项
> 排查入口:出问题再查。按症状定位到 references/faq.md 的单条再读(不要从头读)。本节速查表与题库互为等价入口,取一即可。
| 症状 | 一眼结论 | 详解 |
|---|---|---|
| 取数段单个关键词无故多花 30~60 s | 三处按序查:提交守卫是否只认「响应计数」(改「以本词自身响应放行」+ 条件复测)→ 结果区文本是否用会「自动等待」的定位器读(改直接查 DOM)→ 宽泛词是否把「页宽重查 + 漏采自愈重采」一并带出(加过泛门控与关键词门控) | faq.md Q1.16 / Q1.17 / Q1.18 |
| 多关键词里某词的「总计」恰等于上一个关键词 | 分页器「总计」渲染滞后于结果行,且上一词的响应迟到会改签名;总计应取响应体 totalElements 并与该响应自身请求的 proDesc 配对 |
faq.md Q1.27 |
| 长流程运行到一半看不到进度 | 登录态持久化在 profile 目录内、可跨命令复用 → 一步到位:带 --batch 一次运行即完成全流程。不要拆成「--login-only + 查询段」两步(重付一次「打开 + 恢复登录态」);也不要整条丢进后台 |
faq.md Q5.7 / Q1.20 |
手工执行报 command not found |
默认 shell 的 PATH 不含 coreutils → 先 export PATH="/usr/bin:/bin:/c/Windows/System32:$PATH"(一键采集脚本已内置) |
faq.md Q5.9 / Q5.10 |
| CAS 登录页点「登录」无效、停在登录页 | 登录页底部 cookie 同意浮层遮挡按钮 → 登录前先现读快照、点掉浮层再点「登录」,并按落地 URL 轮询校验(collect_offers.sh 已内置) |
manual-steps.md §B |
| 就绪脚本说「完成」、采集脚本却说未找到 CLI | 两个脚本互相指着对方(装包与内核两条通道的失败都被报成「就绪完成」)→ 判据是同时看到「[OK] 内核已就绪」与「[OK] 就绪自检通过」两条 | faq.md Q5.22 |
| 升级 CLI 后报「(no browsers)」 | playwright-cli 版本与内核 revision 强绑定 → 重装匹配内核,不要升级 CLI |
faq.md Q5.14 |
跑到末尾报 line N: unexpected EOF、采集成功却没有相关集/报告 |
运行期间脚本被外部改动(bash 惰性重读读到半写状态)→ run_query.sh 已内置启动自快照免疫;见此告警即改动落定后重跑 |
faq.md Q5.28 |
三条「省时默认动作」:① 批量检索直接走单入口 run_query.sh;② 校验本机文件是否存在,用 Read 工具直接探真实磁盘,勿凭 Glob / Bash 的 NOT_FOUND 判定缺失;③ 每条 bash 命令一律以 export PATH="/usr/bin:/bin:/c/Windows/System32:$PATH" 开头(漏加会报 command not found;一键脚本已内置)。
题库检索方式:faq.md 条目按「章 · 序」编号(Q<章>.<序>),每条的最后一栏固定是「检索关键词」——用症状词或那些关键词做全文检索即可定位到单条;命不中再换词。
文件清单
yonyou-js-djw-dsp/
├── SKILL.md 本文件:维护边界 / 何时使用 / 首次安装 SOP / 登录 SOP / 执行 SOP / 策略与门禁 / 问题速查
├── config/
│ ├── dsp_config.example.json 凭据占位模板(随包发布)
│ ├── dsp_config.json 真实配置(本机专用·不进包、不提交 git)
│ └── runtime.json 本机运行时登记(机器本地态·不进包、不提交 git)
├── scripts/
│ ├── run_query.sh 单入口(机械门禁):常规检索的唯一合规路径,内置参数与前置门禁校验
│ ├── detect_env.sh 运行时环境探测:定位 playwright-cli 路径 / 版本与可用内核目录
│ ├── _pw_browsers_root.js 内核路径派生辅助(供 detect_env.sh / setup_cli.sh 共用)
│ ├── setup_cli.sh CLI 一键就绪:装 playwright-cli + 装 chromium 内核 + 生成 no-sandbox 配置
│ ├── init_config.py 交互式引导写入真实配置(辅助;密码不回显)
│ ├── cookie_to_state.py ⑤ F12 取凭证的落地实现:Cookie 串转 storageState
│ ├── collect_offers.sh 一键采集(一次性驱动):清场 → 登录 → 逐关键词提交 → 采全
│ ├── dsp_flow.js 一次性驱动的流程体(由 run-code 加载)
│ ├── make_flow.py 流程体生成:把本次参数写进 dsp_flow.js,产出 flow_run.js
│ ├── flow_result_to_tsv.py 把 run-code 返回结果解码为 offers_union.tsv
│ ├── snapshot_to_tsv.py 把快照解析成 TSV 清单(供手工复用)
│ ├── digest_offers.py 取数后一次成型:压摘要 + 落相关集,可直出 HTML 报告
│ └── tsv_to_report.py 结果呈现:渲染自包含可分享 HTML 报告
├── references/
│ ├── workflow.md 必读层:一键采集脚本参数说明 / 取数与结果成型
│ ├── manual-steps.md 按需层(仅排错与定制时读):CLI 逐步命令与一次性驱动
│ ├── install_quickstart.md Playwright 快速安装说明
│ └── faq.md 技能问题题库(按症状 / 检索关键词定位单条)
├── .package_allowlist.txt 打包白名单(排除真实 config);本机治理产物,不进包
├── .gitignore 忽略真实 config 与运行时产物;本机治理产物,不进包
└── .playwright/
└── cli.config.json CLI 运行时配置(no-sandbox 等);本机专用·不进包