手机派活,电脑交付:WorkBuddy 远程办公任务怎么写

从只读连通测试开始,把会前准备、拜访记录和方案修订写成可核对的远程任务。

1. 把远程任务写成一张可验收的工作单

人离开工位之后,最容易出错的指令往往很短:“把昨天的方案改一下。”电脑里可能有三份昨天的方案,数据又散在不同表格。用手机交给 WorkBuddy 的任务,最好带上文件定位、版本、修改范围和回报要求,让自己能在小屏幕上判断它处理得对不对。

本文用虚构的「青禾门店试点」串起三件事:准备会议、整理拜访记录、修订方案。示例提示词未在真实业务账号中执行,文件名与数据可按自己的项目替换。先用无敏感信息的副本练习,确认交付质量后再扩展到实际工作。

云端工作、连接电脑及交付审核的边界
图 1 手机是任务入口,执行位置仍需要明确

2. 接通手机之前,确认任务会在哪儿执行

官方小程序快速开始区分了云端工作和连接电脑:前者在云端沙箱执行,后者交由桌面端执行。处理本机方案时应选择对应电脑;把任务切到云端,并不会让那里的工作空间自动获得电脑硬盘中的文件。

按官方多端协同指南,桌面端侧边栏底部有「连接移动端」入口。开启设备连接许可后,小程序使用同一账号登录,再在设备入口选中电脑。两端需要联网,桌面端需保持运行;外出前检查保持唤醒相关设置。具体名称以当前客户端为准。

这些条件不支持“电脑关机后仍继续处理本地文件”的推断。对于公司电脑,还应遵守企业的设备与远程访问要求,不要为了少一次确认就随意扩大权限。若当前环境不允许远程接入,可以先在手机整理需求,回到电脑再执行。

3. 先完成一次只读连通测试

不要直接用一份正式报价单测试连接。先在允许访问的工作目录放入「远程测试.txt」,里面只写一个不敏感的校验词,例如“青禾演示 17”。手机上选择设备后,让 WorkBuddy 读这个文件并回报。

这是一项只读测试。
目标电脑:【设备名称】。工作空间:
【完整路径或已确认的工作空间名称】。
只读取 远程测试.txt,回复其中的校验词,
并说明实际读取的文件路径。
不要列举其他文件,不创建、修改、删除文件,也不调用外部服务。
如果文件不存在、设备离线或权限不足,回复具体阻塞,
不搜索其他目录代替。

收到的内容与文件一致,再回到桌面端检查这次会话。之后可以用一份副本测试“读取纪要并另存摘要”。分开验证连接和交付,出错时才知道该查哪一步。若只收到泛泛的“测试成功”,继续要求文件路径与校验词,不能据此认定文件读取已经完成。

远程任务需要目标材料、版本范围、输出边界以及回报停止条件
图 2 一条远程任务应包含足够的定位信息

4. 场景一 在路上准备项目例会

虚构项目下周准备试点上线,负责人需要知道上次会后哪些工作完成、今天要决定什么。输入只用三份文件:上一场纪要、最新任务表、本次议程。任务表的“进行中”不能直接被改写成“基本完成”,没有交付记录的事项应当保持待核实。

请为青禾门店试点准备一页会前材料,
只处理当前已选中的【设备名】和【工作空间】。
输入:
会议/2026-10-07纪要.md、台账/任务表-2026-10-09.xlsx、会议/2026-10-12议程.md。

先核对文件是否存在,报告读到的版本和表名。缺任何一份先告诉我,
不扫描整个硬盘。
确认材料齐全后,读取纪要中的待办,与任务表逐条匹配。输出四块:
上次待办及证据、本次应讨论的问题、需要我做的决定、信息缺口。
同一任务在两份材料中状态不一致时并列列出,不自行选一个。
保存到 输出/2026-10-12-会前材料-v1.md。只新增文件,
不修改原表,不创建会议,不发送给任何人。
手机回复不超过 250 字,包含最重要的两项决定、阻塞和文件名。
没有证据的内容标“待核实”。

手机回报可以这样组织:“需要确认:是否保留试点范围;培训是否可用录屏补充。待核实:任务表写培训完成,纪要仍要求补测。产物:会前材料-v1.md。”这是一份示例摘要,实际应能在文件里找到每项对应的记录。到会前再打开全文核对,避免只凭短消息主持会议。

5. 会前练习:三份可复制的完整输入

下面把场景一提到的三份材料全部展开。它们是作者编写的离线虚构练习,日期只服务于案例,不表示真实会议或实际执行记录;下文的答案也不是 WorkBuddy 测试结果。无需连接手机就能先对照材料核验答案。要做真实远程练习,先在自己允许访问的目录建立 qinghe-demo 工作空间,再完成前文的只读连通测试。

在该工作空间中建立“会议”“台账”“输出”三个目录。以下文件路径均相对于它;提示词中的设备名和工作空间要换成你实际验证过的信息。两份 Markdown 文件直接保存为 UTF-8 文本。任务表块使用制表符分列,可复制到电子表格软件的 A1;将唯一工作表命名为“任务”,另存为指定的 .xlsx 文件,不能仅把 .txt 改扩展名。表内没有隐藏行、公式或其他工作表。

会议/2026-10-07纪要.md:完整内容

# 青禾试点项目例会纪要
日期:2026-10-07;版本:v1
试点拟于 2026-10-19 启动,范围为东门店、西桥店;上线日尚未最终批准。

A01 门店范围确认|负责人:林岚|截止:2026-10-09
待办:取得两店的书面参加确认;任何一家未确认时,由项目负责人决定是否缩小范围。
A02 培训验收|负责人:周宁|截止:2026-10-09
待办:完成两店培训及补测。验收条件为两店均完成补测并留存结果,只有签到不算完成。
A03 导入演练|负责人:许澄|截止:2026-10-09
待办:使用脱敏样例完成两店导入,记录失败条数及处理结果。

下次会议需决定试点范围,以及未补测门店是否能用录屏学习加补测完成培训验收。

台账/任务表-2026-10-09.xlsx → 任务!A1:F4:全部单元格

任务ID	事项	负责人	状态	进展记录	记录日期
A01	门店范围确认	林岚	进行中	东门店书面确认已收到;西桥店口头同意,书面确认未收到	2026-10-09
A02	培训验收	周宁	已完成	两店均已签到;东门店补测通过;西桥店尚未补测	2026-10-09
A03	导入演练	许澄	已完成	两店各导入20条脱敏样例,失败0条;记录人许澄	2026-10-09

会议/2026-10-12议程.md:完整内容

# 青禾试点决策会
日期:2026-10-12;版本:v1;时长:20分钟
目标:形成试点范围及培训补测安排的决策草案。
议题1(8分钟):西桥店书面确认未到,是否仍保留两店试点范围?
议题2(8分钟):西桥店申请看录屏后补测。是否接受这种培训安排?通过条件仍为完成补测并留存结果。
议题3(4分钟):核对导入演练记录,确认仍缺哪些上线前证据。
本议程没有批准上线日,没有批准取消补测,也没有指定新增截止日期。

按场景一提示词运行时,再加一句:“任务表只读‘任务’工作表;证据位置写到任务 ID 或单元格。进展记录属于表内自报,不代表你打开过外部验收附件。”这样三份文件就是完整输入,无需寻找案例没有提供的隐含材料。

6. 会前练习:参考产物与错判纠正

先检查读取回报:应列出上述三个相对路径,纪要和议程各为 v1,任务表为“任务”工作表、3 条任务。以下是“输出/2026-10-12-会前材料-v1.md”的参考全文,允许表达方式变化,但不能丢掉状态冲突、证据来源或待决定事项。

# 青禾试点会前材料|2026-10-12
输入:2026-10-07纪要 v1;任务表-2026-10-09.xlsx / 任务;2026-10-12议程 v1。

## 上次待办及证据
- A01 门店范围确认:进行中。纪要要求两店书面确认;任务!D2:E2 记载东门店已收到、西桥店未收到。西桥店口头同意不满足书面条件。
- A02 培训验收:台账状态为“已完成”,但不满足纪要验收条件。任务!D3 写已完成,E3 写西桥店尚未补测;纪要 A02 要求两店均完成补测并留存结果。保留该差异,培训验收是否完成标为待核实。
- A03 导入演练:台账记为已完成。任务!E4 记载两店各20条、失败0条,共40条。这里只有表内记录,没有独立日志或附件,不能写“已核验导入日志”。

## 本次应讨论的问题
- 西桥店书面确认缺失对两店试点安排有什么影响?
- 西桥店用录屏学习后补测是否可行?如何留存补测结果?
- 导入演练需补充什么独立证据供上线前核对?

## 需要负责人做的决定
1. 是否保留两店试点范围;若书面确认仍不到,采用什么范围?当前输入未给出决定。
2. 是否接受西桥店“录屏学习+补测”的安排。不能把同意录屏等同于免除补测。

## 信息缺口
- 西桥店书面确认及获得时间:未提供。
- 西桥店补测结果及留存位置:未提供。
- 导入日志或独立验收附件:未提供。
- 上线日最终批准:未提供;10月19日只是纪要中的拟定日期。
- 本次会议的新决定、新负责人安排及新增截止日期:尚未产生。

手机上的短回报参考:“会前材料已整理。需决定:是否保留两店试点;是否接受西桥店录屏学习后补测。培训台账虽写已完成,西桥店仍缺补测;上线日未获批准。产物:输出/2026-10-12-会前材料-v1.md。”这是产物真正写入并读回后才可使用的回报;若仅完成文本推演,应写“参考稿已整理,未保存到目标电脑”。

出现错误时,直接按证据纠偏:若答案写“培训已全部完成,可以按期上线”,应判为未通过,因为它把状态列当成了完整证据。可在原会话发下面这条局部修正,而不是重做全部材料。

刚才会前材料中“培训已全部完成,可以按期上线”没有材料支持。
请重读 2026-10-07纪要.md 的 A02,以及任务表“任务”!D3:E3,
保留“台账写已完成”与“西桥店未补测”的差异,并将培训验收标为待核实。
议程没有批准上线日,删除“可以按期上线”的判断。
其他条目按原证据保留。只新增 输出/2026-10-12-会前材料-v2.md;
若 v2 已存在,先报告并停止。回报修正的两处及新文件路径,不改输入文件。

7. 场景二 拜访结束后整理三份材料

客户拜访后可以先用手机记录要点。若使用语音转写,先核对人名、金额、否定词和日期,再交给 WorkBuddy。记录中要写明“客户明确说过”与“我的理解”;口述里的停顿和语气不能可靠证明客户接受了某个条件。

以下是虚构输入:“客户希望先试点两家门店,提出费用最好控制在 8 万元以内。我答应整理范围,但没有承诺报价和交付日。我觉得对方担心培训时间,尚未问清。下次沟通日期未定。”

把下面的拜访记录整理为三个独立文件。它是我的会后回忆,
不是已核对的逐字记录。
【粘贴核对过的记录】
1. 内部纪要.md:
区分客户要求、我方明确承诺、我的判断、待澄清问题。
不要把回忆写成逐字引语。
2. 跟进邮件草稿.md:收件人暂写【待确认姓名与邮箱】。
复述“两家门店试点”的讨论方向,说明我们将整理范围供双方确认。
费用只写为客户提出的预算意向,不能写成成交价。不要承诺交付日,
也不要主动附上内部判断。
3. 行动清单.csv:事项|预期成果|负责人|截止时间|是否确认。
没有确定的人和日期写“待确认”,可在单独的建议栏提出建议。
保存到 输出/拜访记录-日期/。若已有同名文件,先报告,不覆盖。
只生成本地草稿,不发送邮件、不更新客户系统、不分派任务。
回报三个文件名,以及必须由我补充的信息。
拜访记录生成内部纪要、跟进邮件草稿和行动清单
图 3 用途不同,允许进入文档的信息也不同

8. 场景三 在出差途中修订方案副本

修改已有材料前,先说明输入版本。示例方案第 6 页写两家门店、每店 18,000 元培训费,总额 36,000 元;新确认表将单店培训费改为 16,000 元。这里只演示这笔费用的变化,不代表项目总报价已经确定。

请先检查修改计划,暂不写文件。
目标电脑与工作空间:【填入已验证的信息】。
输入方案:方案/青禾试点-v3.pptx;唯一更新依据:
数据/培训费用确认-2026-10-12.xlsx 的“已确认费用”工作表。
拟修改:第 6 页两家门店的培训费用,单位为元,
沿用输入表标明的含税或未税口径。先报告原值、新值与计算过程。
检索整份方案里其他引用这笔培训费的文字、图表和备注,列出位置;
不要顺带改其他费用或报价。
如果数据口径不清、工作表缺失、页码与内容不符,停止并问我。
输出计划:目标页|原值|拟修改值|依据|其他受影响位置。
等我确认后再执行。

确认计划后再补一条执行指令:“仅应用刚确认的修改,另存为青禾试点-v4-待审.pptx,保留 v3;交付逐项变更清单和未处理项,不发送。”示例中的新培训费用为 32,000 元,比原值减少 4,000 元。方案其他合计是否需要随之调整,必须看它的实际公式与费用范围,不能整篇替换数字。

远程修订需要原件、新版、变更记录和最终交付审核
图 4 先确认内容,再检查版式与交付范围

9. 方案练习:六页原稿和完整费用表

下面为场景三提供可从零搭建的最小方案。仍是离线虚构材料与人工推导的预期答案,不是某次远程控制、PPT 编辑或版式测试的日志。它用于检验修改计划是否完整;真实文件能否读写、备注能否提取,以及最终排版,需在实际环境另外验证。

在同一练习工作空间建立“方案”和“数据”目录。用演示文稿软件新建六页空白幻灯片,把下面各页的标题、正文、备注分别填入相应位置,保存为“方案/青禾试点-v3.pptx”。除列出的文本和备注外,不放图片、图表、隐藏对象或链接;这样检查范围就是这六页全部内容。手机练习前在大屏幕确认六页都可阅读。

第1页
标题:青禾门店试点方案
正文:内部讨论稿;上线日与项目总报价均待批准。
备注:本材料仅用于范围与培训费用讨论。

第2页
标题:拟定试点范围
正文:东门店、西桥店,共2家;目标启动日2026-10-19,待批准。
备注:西桥店书面确认尚未收到。

第3页
标题:单独列示的设备押金
正文:设备押金合计36,000元;不计入本方案的实施与培训费用小计。
备注:本次没有设备押金的更新依据,保持原值。

第4页
标题:培训安排
正文:两店分别培训,培训后补测;录屏学习安排待确认。
备注:讲解时引用培训费合计36,000元;含税。

第5页
标题:已列示费用小计
正文:实施服务费50,000元;培训费36,000元;两项小计86,000元,均为含税金额。
正文:设备押金另列;差旅费未确认。因此86,000元不是项目总报价。
备注:小计仅等于实施服务费加培训费,不含设备押金和差旅费。

第6页
标题:培训费用明细
正文:东门店18,000元;西桥店18,000元;2家合计36,000元,均含税。
备注:每店18,000元乘以2家等于36,000元。只讨论培训费用。

费用表也给出全部内容:将下列制表符分隔的文本粘贴到 A1,工作表命名为“已确认费用”,保存为“数据/培训费用确认-2026-10-12.xlsx”。范围为 A1:E3,无其他工作表与公式;每行就是一家门店的一次培训费用。

门店	培训费(元/店)	税费口径	确认状态	确认日期
东门店	16000	含税	已确认	2026-10-12
西桥店	16000	含税	已确认	2026-10-12

10. 方案练习:修改答案与断线续做

用场景三的“暂不写文件”指令检查计划,参考结果应包含以下五组位置。第 5 页两个 86,000 元都要识别,第 3 页虽然出现同样的 36,000,却不是本次培训费;这正是不能全篇替换数字的原因。

目标位置|原值|拟修改值|依据与范围
第6页正文|东门18,000;西桥18,000;合计36,000|东门16,000;西桥16,000;合计32,000|费用表B2+B3=32,000,C2:C3均含税,D2:D3均已确认
第6页备注|18,000×2=36,000|16,000×2=32,000|与明细一致
第4页备注|培训费合计36,000|培训费合计32,000|同一培训费引用
第5页正文第一行|培训费36,000;小计86,000|培训费32,000;小计82,000|原有小计范围为实施50,000+培训32,000
第5页正文第二行|因此86,000元不是项目总报价|因此82,000元不是项目总报价|与本页小计同步;总报价仍未确定

不改:第3页设备押金36,000;第5页实施服务费50,000;试点范围、目标日期及其他文字。
差额:培训费32,000-36,000=-4,000元;所列两项小计82,000-86,000=-4,000元。
待确认:是否批准同步修改第4页备注、第5页两项小计及说明;项目总报价不在本次范围内。

看过计划后,若同意这些连带修改,可发送下面这条明确执行范围的短消息。这里的“确认”是练习者要作出的选择,不是案例替真实用户作出的决定。

确认应用计划中全部五组改动,包括第4页备注、第5页小计及其说明。
第3页设备押金36,000元和第5页实施服务费50,000元保持不变。
另存到 输出/青禾试点-v4-待审.pptx,并新增 输出/青禾试点-v4-变更清单.md。
保留 v3,不发送文件。任一输出已存在就先报告,不覆盖。
写完重新读取这两个文件;如不能核对备注或不能完成版式检查,逐项说明,
不要把未做的检查报告为通过。

改后内容对照:第 1、2、3 页以及第 4 页正文不变;其余修改后的完整文本如下。比对这些文本能验收内容,不能替代实际 PPT 的大屏幕版式检查。

第4页备注:讲解时引用培训费合计32,000元;含税。
第5页正文第一行:实施服务费50,000元;培训费32,000元;两项小计82,000元,均为含税金额。
第5页正文第二行:设备押金另列;差旅费未确认。因此82,000元不是项目总报价。
第5页备注:小计仅等于实施服务费加培训费,不含设备押金和差旅费。
第6页正文:东门店16,000元;西桥店16,000元;2家合计32,000元,均含税。
第6页备注:每店16,000元乘以2家等于32,000元。只讨论培训费用。

变更清单应复用上面的五组前后值,注明依据“已确认费用!A1:E3”,并另列三项检查:v3 是否保持原样;第 3 页押金是否仍为 36,000 元;备注与版式是否实际核对。没有读回证据时,检查结果写“未核对”,不能预填“通过”。如果文字已核对但版式还没看,手机回报可写:“部分完成:已生成 v4-待审和变更清单;培训费 32,000 元,两项小计 82,000 元,押金未改。版式待在大屏幕复核。”仅在实际生成并核对过这些事实后使用这段回报。

断线或只交付了一半时:例如手机没收到回报,输出目录里可能已有 v4。恢复连接后先查同一个会话,只核对本次两个输出及指定原件,不立即再发整条写入指令。

继续刚才青禾方案修订任务,先只读核对,不创建新文件。
检查 输出/青禾试点-v4-待审.pptx、输出/青禾试点-v4-变更清单.md 是否存在;
不要仅依据“文件存在”判定完成。
若存在,逐项对照已确认的五组改动,读出第3页押金、第4页备注、
第5页两处小计、第6页正文与备注;另报告版式是否检查过。
若文件缺失、打不开或仍有旧培训费,列出具体缺项,等我决定后再修正。

如果核对发现“第 6 页已改,但第 4 页备注仍为 36,000 元”,说明是局部漏改。可继续:“仅将 v4 副本第 4 页备注中的培训费改为 32,000 元,另存 v5-待审并附本次补改清单;其余四组按已确认计划只核对、不重复改写。若 v5 同名已存在先停。”若是第 3 页押金被误改为 32,000 元,则依据原件将该处恢复为 36,000 元后另存;费用表从未授权改变押金。最终回到大屏幕检查页内溢出、备注、输出名称与版本,再决定是否交付。

11. 把手机回报做成固定格式

让每项远程任务以同一张回报单收尾,有助于快速发现未完成部分。回报单可直接要求以下字段:

字段应该写什么
结果已完成、部分完成或阻塞,三者选一
处理范围实际设备、输入文件版本、读取的表或页
产物文件名与可打开的位置
变更修改位置、前后值、依据;没有修改则明确写出
待确认缺失材料、未处理问题、建议的下一步

看到“部分完成”时,先验收已经产出的文件,再决定继续哪一项。任务失败也可能留下半成品,重发整段指令之前要检查原会话和输出目录,避免重复版本混在一起。涉及 PPT、表格公式或页眉页脚的修订,回到大屏幕做一次版式检查更稳妥。

12. 连接协作工具时,把读取和发送分别验证

官方连接器文档介绍了独立授权和任务内启用方式。可在「专家·技能·连接器」中管理连接器,或在任务输入框的加号菜单启用。先选当前确实需要的服务,完成授权后,用指定文档或邮件做一次只读查询。

消息能从某个平台发进来,不能据此认定 WorkBuddy 已获得该平台所有文档的读写权限。读到会议纪要,也不能推出一定能够创建云文档或发到任意群。让它报告当前能做的动作;遇到不支持的操作,保留本地文件和通知草稿,由负责人完成后续交付。

对外分享前核对最终文件、收件人或群、附带说明和访问权限。内部纪要与客户邮件分开存放,避免把内部判断一同传出。接入新服务出现的权限和协议应逐项阅读,密钥、口令与验证码不要放进普通任务提示词。

13. 常见问题与失败处理

手机显示离线,还能让它继续改文件吗?不能据此假定本地任务正在运行。检查电脑电源、网络、客户端和连接许可;恢复后先确认原任务状态,再决定继续或重试。

为什么没有收到完成提醒?先到对应会话查看产物与状态。通知渠道、订阅授权和任务状态都可能影响提醒;没有推送不等于没有产物。官方多端协同文档也说明小程序通知依赖订阅条件。

可以一直在后台等我补材料吗?不要把长期等待当成稳定保证。把缺项与当前产物保存清楚,待材料齐全后回到原会话继续,并重新确认文件版本。

能用企业微信或飞书吗?官方助理文档列有不同平台的接入指南。逐一按对应入口配置和验证,不要把小程序的设置步骤直接套用到其他平台。

14. 拜访练习:把一段手机记录拆成可核对的三份产物

前面的场景二只给出了提示词。这里补全它的输入、参考答案与导入检查,重点是“个人回忆怎样变成不同用途的文件”。两店、8万元及全部人物关系均为虚构教学材料;不涉及真实客户。本节没有调用 WorkBuddy、真实手机、邮箱或客户系统。

将下面五条保存为“拜访原始记录.txt”,逐条编号用于追溯。编号是本例编写的定位约定,不是 WorkBuddy 自动提供的证据功能。V01说明材料可信度,V02是客户意向,V03是已作出的承诺边界,V04是个人判断,V05是仍未确定的事项。每个产物都应保留这种区别。

先生成内部纪要、邮件草稿与行动清单的预览文本,人工检查语义后再导出。邮件仍是本地草稿,收件人占位符必须保留,不能从项目名猜一个联系人。完整练习只需本节材料,不需要搜索联系人、报价记录或其他目录。

拜访原始记录.txt

V01|记录性质:2026-10-12拜访后的个人回忆,已核对转写;不是录音逐字稿。
V02|客户希望先试点两家门店,提出费用最好控制在8万元以内;没有说明是否含税,也没有明确包含哪些费用。
V03|我答应整理试点范围供双方确认,没有承诺报价,也没有承诺交付日期。
V04|我觉得客户可能担心培训时间,但没有问过,这是我的判断。
V05|下次沟通日期未定;记录中没有其他人的任务分工。

15. 拜访练习:内部纪要和客户邮件的完整参考答案

内部纪要允许保留V04的判断,但必须明确是记录人的猜测。客户邮件不带这项内部猜测;可以提出预算口径与后续沟通的必要问题,不能虚构对方已经同意报价、日期或培训方案。下面的答案是人工编写的对照稿,不是一次模型运行结果。

“没有承诺”是需要保留的实质信息,而不是可删的赘词。把“8万元以内的意向”改为“8万元成交价”,把“整理范围”改为“下周交付”,都会改变业务事实。若录音转写把“没有”漏掉,先更正原始记录,不能让后续模板替原始证据做决定。

内部纪要.md

# 青禾拜访内部纪要(待核对)
记录性质:会后个人回忆,非逐字记录;日期2026-10-12。

客户提出的方向:希望先试点两家门店;费用最好在8万元以内。预算为客户意向,含税口径和费用范围未说明。(V02)
我方明确承诺:记录人答应整理试点范围供双方确认。记录人姓名待补;整理范围的截止日期未约定。(V03)
未承诺事项:报价、交付日期;不能从“整理范围”推出已接受8万元报价。(V03)
内部判断:记录人猜测客户可能担心培训时间,未向客户核实;不可写成客户已表达的事实。(V04)
待澄清:预算含税口径及费用范围;实际培训顾虑;下次沟通日期。(V02、V04、V05)
行动:整理范围为已承诺动作,其余三项为建议,尚未分派。详见行动清单。

跟进邮件草稿.md

收件人:【待确认姓名与邮箱】
主题:青禾两店试点范围的后续确认(草稿)

您好,

根据本次沟通,我们将整理两家门店的试点范围,供双方进一步确认。
我们记录到您提出的费用意向为尽量控制在8万元以内。为避免范围理解不一致,想请您确认这一意向是否包含税费,以及希望覆盖哪些费用项目。
本次记录尚未约定报价及交付日期,后续需结合范围另行确认。也请您告知方便继续沟通的日期。

【发件人姓名待补】

16. 拜访练习:四行行动清单的事实口径

行动清单只有第一行属于已承诺动作。其负责人可以写“记录人本人(姓名待确认)”,因为V03明确说“我答应”;这里不猜姓名。其他三行是从信息缺口提出的建议,负责人和截止时间均待确认。它们不代表已经在任务系统分派,也不能预填“销售”“本周五”。

下面是人工审阅后的结构化中间文件 actions.json。保留“是否确认”和“依据”两列,是为了在手机上也能看到承诺与建议的区别。本文的脚本只负责可靠导出这些已审阅字段,不会把自然语言自动理解为事实,更不会自动判断一段客户回忆是否真实。

这四行的独立人工验收口径为:总计4行;明确承诺1行、建议3行;所有截止日期均未知;只有整理范围能归到记录人本人;依据顺序分别为V02/V03、V02/V03、V04、V05。改变行文可以,不能改变这些事实。

actions.json:完整输入

[
  {"事项":"整理两店试点范围","预期成果":"范围草案供双方确认","负责人":"记录人本人(姓名待确认)","截止时间":"待确认","是否确认":"已承诺整理;范围未确认","依据":"V02、V03"},
  {"事项":"澄清预算口径","预期成果":"确认8万元意向是否含税及包含哪些费用","负责人":"待确认","截止时间":"待确认","是否确认":"建议动作,未分派","依据":"V02、V03"},
  {"事项":"确认培训顾虑","预期成果":"询问客户是否担心培训时间","负责人":"待确认","截止时间":"待确认","是否确认":"建议动作,未分派","依据":"V04"},
  {"事项":"约定下次沟通","预期成果":"确认双方可用日期","负责人":"待确认","截止时间":"待确认","是否确认":"建议动作,未分派","依据":"V05"}
]

17. 可复制工具:把已审阅行动项导出为保守的文本 CSV

CSV里的逗号、双引号和换行需要按CSV格式编码,不能手写“用逗号拼接”。Python官方csv文档说明了writer、reader和newline参数;下方使用标准库,全部字段加双引号,并以CRLF分隔记录。双引号会被加倍,字段内的换行仍属于同一条记录。

格式正确不等于表格打开时不会解释公式。OWASP的CSV Injection说明提醒,公式样式开头可能触发表格行为,而且不存在适合所有表格软件与下游系统的通用净化方案。这里采用本案例自己的保守拒绝策略,不尝试给危险字符串加一个字符后就宣称安全。

脚本拒绝每一行去掉前导空白后以 =、+、-、@ 或相应全角字符、单引号开头的字段;拒绝除LF以外的控制字符及Unicode格式字符。LF可保留在引号包围的字段内,但每个子行仍接受前缀检查。这会拒绝合法的负数、国际电话前缀和某些带符号文本,属于有意的适用范围限制:本工具只面向本例中文文字型行动清单,不能拿去导出金额流水。

所有字段先在内存里验证,任何一行不通过就不创建输出;不会静默删除或改写原文。检查通过后以独占创建模式写入,已有目标文件会报错。写入期间磁盘错误仍可能留下半份新文件,程序并非事务存储;发生错误应保留原JSON,在普通文本编辑器中检查输出,再另选新文件名,不把残留文件算成交付。

将代码保存为 visit_csv.py,与 actions.json 放在自己允许写入的练习目录。运行“python visit_csv.py actions.json actions.csv”。脚本不联网、不发送文件、不触碰其他文档。

visit_csv.py:完整源码

"""Reviewed action rows -> conservative text CSV, no files/network in exporter."""
import csv
import io
import unicodedata

FIELDS = ("事项", "预期成果", "负责人", "截止时间", "是否确认", "依据")
DANGEROUS = frozenset("=+-@=+-@")


def checked_text(value):
    if not isinstance(value, str) or not value.strip():
        raise ValueError("empty-or-nontext")
    # LF is allowed within quoted cells; every other control/format char is refused.
    if any(unicodedata.category(c) in {"Cc", "Cf"} and c != "\n" for c in value):
        raise ValueError("control-character")
    # Conservative export policy, not a claim about every spreadsheet parser.
    for line in value.split("\n"):
        probe = line.lstrip()
        if probe and (probe[0] in DANGEROUS or probe[0] == "'"):
            raise ValueError("formula-like-prefix")
    return value


def export_actions(rows):
    if not isinstance(rows, list) or not rows:
        raise ValueError("rows-required")
    cooked = []
    for row in rows:
        if not isinstance(row, dict) or set(row) != set(FIELDS):
            raise ValueError("field-set")
        cooked.append([checked_text(row[k]) for k in FIELDS])
    out = io.StringIO(newline="")
    writer = csv.writer(out, quoting=csv.QUOTE_ALL, lineterminator="\r\n")
    writer.writerow(FIELDS)
    writer.writerows(cooked)
    return out.getvalue()


def read_back(text):
    table = list(csv.reader(io.StringIO(text, newline=""), strict=True))
    if not table or table[0] != list(FIELDS):
        raise ValueError("header")
    if len(table) < 2 or any(len(r) != len(FIELDS) for r in table[1:]):
        raise ValueError("row-width")
    return [dict(zip(FIELDS, row)) for row in table[1:]]


def unique_object(pairs):
    result = {}
    for key, value in pairs:
        if key in result:
            raise ValueError("duplicate-json-key")
        result[key] = value
    return result


if __name__ == "__main__":
    import json
    import sys
    from pathlib import Path
    if len(sys.argv) != 3:
        raise SystemExit("usage: python visit_csv.py actions.json actions.csv")
    rows = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"), object_pairs_hook=unique_object)
    text = export_actions(rows)  # Validate the entire batch before opening output.
    if read_back(text) != rows:
        raise ValueError("roundtrip")
    with open(sys.argv[2], "x", encoding="utf-8", newline="") as f:
        f.write(text)
    print(f"exported {len(rows)} rows; UTF-8; comma; all quoted")

actions.csv:本次实际导出内容

"事项","预期成果","负责人","截止时间","是否确认","依据"
"整理两店试点范围","范围草案供双方确认","记录人本人(姓名待确认)","待确认","已承诺整理;范围未确认","V02、V03"
"澄清预算口径","确认8万元意向是否含税及包含哪些费用","待确认","待确认","建议动作,未分派","V02、V03"
"确认培训顾虑","询问客户是否担心培训时间","待确认","待确认","建议动作,未分派","V04"
"约定下次沟通","确认双方可用日期","待确认","待确认","建议动作,未分派","V05"

18. 独立检查:格式通过之外,还要检查语义和错误样本

下面检查程序使用手写的固定预期CSV文本核对字节形状,而不是让导出器自己生成“正确答案”。第二组检查在单个单元格中加入英文逗号、双引号和换行,读回后必须仍为一行六列;17个异常值覆盖公式样式、全角符号、隐藏格式字符、空值与非文本。额外检查拒绝缺列、多列、错误表头、错误列数与JSON重复键。检查使用显式抛错,python -O不会移除这些验收。

负对照把“=1+2”放进CSV双引号后再读回,得到的仍是“=1+2”。这仅证明CSV引用没有改变其内容,不是一次Excel公式执行测试。最后对四行案例做另外手写的业务断言,并确认导出没有修改输入对象。代码检查覆盖固定fixture;它不能证明任意模型输出都正确,更不能取代人工读V01至V05。

人工复核时可刻意尝试三种错误:把邮件改成“报价确定为8万元”,应因V02/V03不支持而失败;把内部判断放到客户邮件“您担心培训时间”,应因V04未经核实而失败;把所有截止时间改为“下周五”,应因材料未给出而失败。这三个语义错误不能靠CSV解析器发现。不要把“格式通过”写成“客户事实已核验”。

check_visit_csv.py:完整检查程序

import copy
import csv
import io
import json
from pathlib import Path
from visit_csv import FIELDS, export_actions, read_back, unique_object

BASE = dict(zip(FIELDS, ("整理范围", "两店草案", "待确认", "待确认", "未分派", "V02")))
# Literal oracle authored separately, not computed using the exporter.
EXPECTED = ('"事项","预期成果","负责人","截止时间","是否确认","依据"\r\n'
            '"整理范围","两店草案","待确认","待确认","未分派","V02"\r\n')
if not (export_actions([BASE]) == EXPECTED):
    raise AssertionError('check failed: export_actions([BASE]) == EXPECTED')
print("PASS literal byte-shape oracle")

complex_row = dict(BASE, 预期成果='范围含 A,B;名称为"青禾"\n另列不包含项')
encoded = export_actions([complex_row])
if not ('"范围含 A,B;名称为""青禾""\n另列不包含项"' in encoded):
    raise AssertionError('check failed: \'"范围含 A,B;名称为""青禾""\\n另列不包含项"\' in encoded')
if not (read_back(encoded) == [complex_row]):
    raise AssertionError('check failed: read_back(encoded) == [complex_row]')
if not (len(list(csv.reader(io.StringIO(encoded, newline="")))) == 2):
    raise AssertionError('check failed: len(list(csv.reader(io.StringIO(encoded, newline="")))) == 2')
print("PASS comma quote multiline roundtrip")

bad_values = ["=1+2", "+1", "-1", "@SUM(A1)", "=1+2", "+1", "-1", "@A1",
              "  =1", "\t=1", "\r=1", "\ufeff=1", "\u200b=1", "普通文字\n=1", "'=1", "", None]
for value in bad_values:
    try:
        export_actions([dict(BASE, 预期成果=value)])
    except ValueError:
        pass
    else:
        raise AssertionError(repr(value))
print(f"PASS {len(bad_values)} rejected cell probes")

for row in ({k: v for k, v in BASE.items() if k != "依据"}, dict(BASE, 多余列="x")):
    try:
        export_actions([row])
    except ValueError:
        pass
    else:
        raise AssertionError("bad schema accepted")
print("PASS missing and extra columns rejected")

# Negative control: quoting alone keeps a formula-like cell unchanged.
unsafe = '"=1+2","两店草案","待确认","待确认","未分派","V02"\r\n'
if not (next(csv.reader(io.StringIO(unsafe)))[0] == "=1+2"):
    raise AssertionError('check failed: next(csv.reader(io.StringIO(unsafe)))[0] == "=1+2"')
print("PASS negative control: CSV quotes do not neutralize formulas")

rows = json.loads(Path(__file__).with_name("actions.json").read_text(encoding="utf-8"))
frozen = copy.deepcopy(rows)
result = read_back(export_actions(rows))
if not (rows == frozen and result == rows and len(result) == 4):
    raise AssertionError('check failed: rows == frozen and result == rows and len(result) == 4')
# Separate authored business expectations; this checks this fixture, not arbitrary prose.
if not ([r["依据"] for r in result] == ["V02、V03", "V02、V03", "V04", "V05"]):
    raise AssertionError('check failed: [r["依据"] for r in result] == ["V02、V03", "V02、V03", "V04", "V05"]')
if not ([r["是否确认"] for r in result] == ["已承诺整理;范围未确认"] + ["建议动作,未分派"] * 3):
    raise AssertionError('check failed: [r["是否确认"] for r in result] == ["已承诺整理;范围未确认"] + ["建议动作,未分派"] * 3')
if not (all(r["截止时间"] == "待确认" for r in result)):
    raise AssertionError('check failed: all(r["截止时间"] == "待确认" for r in result)')
if not (sum(r["负责人"] != "待确认" for r in result) == 1):
    raise AssertionError('check failed: sum(r["负责人"] != "待确认" for r in result) == 1')
print("PASS four-row fixture and independently authored business expectations")
print("ALL CHECKS PASSED")

for invalid in ('"wrong"\r\n"value"\r\n', EXPECTED.split("\r\n")[0] + '\r\n"too","few"\r\n'):
    try:
        read_back(invalid)
    except ValueError:
        pass
    else:
        raise AssertionError("invalid header or width accepted")
try:
    json.loads('{"事项":"甲","事项":"乙"}', object_pairs_hook=unique_object)
except ValueError as exc:
    if str(exc) != "duplicate-json-key":
        raise
else:
    raise AssertionError("duplicate JSON key accepted")
print("PASS invalid header, row width and duplicate JSON keys rejected")

check_workflow.py:命令行与实际变异检查

"""Run CLI checks and five real exporter mutations in temporary directories."""
import json
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile

HERE = Path(__file__).resolve().parent


def require(ok, message):
    if not ok:
        raise AssertionError(message)


def run(folder, script, *args):
    flags = ["-O"] if sys.flags.optimize else []
    return subprocess.run([sys.executable, *flags, str(folder / script), *args],
                          cwd=folder, capture_output=True, text=True)


with tempfile.TemporaryDirectory() as tmp:
    folder = Path(tmp)
    for name in ("visit_csv.py", "check_visit_csv.py", "actions.json"):
        shutil.copyfile(HERE / name, folder / name)
    checks = run(folder, "check_visit_csv.py")
    require(checks.returncode == 0, checks.stderr)
    print(checks.stdout, end="")
    first = run(folder, "visit_csv.py", "actions.json", "actions.csv")
    require(first.returncode == 0, first.stderr)
    original = (folder / "actions.csv").read_bytes()
    repeat = run(folder, "visit_csv.py", "actions.json", "actions.csv")
    require(repeat.returncode != 0 and "FileExistsError" in repeat.stderr,
            "existing output was not refused")
    require((folder / "actions.csv").read_bytes() == original, "existing file changed")
    print("PASS existing output refused and byte-identical")
    rows = json.loads((folder / "actions.json").read_text(encoding="utf-8"))
    rows[-1]["预期成果"] = "=1+2"  # Inert text; never opened in a spreadsheet.
    (folder / "bad.json").write_text(json.dumps(rows, ensure_ascii=False), encoding="utf-8")
    bad = run(folder, "visit_csv.py", "bad.json", "bad.csv")
    require(bad.returncode != 0 and "formula-like-prefix" in bad.stderr,
            "invalid last row not rejected")
    require(not (folder / "bad.csv").exists(), "invalid batch created output")
    print("PASS invalid final row creates no output")
    # Explicit demonstration edit, not automatic sanitization or a real customer fact.
    rows[-1]["预期成果"] = "客户原文:=1+2"
    (folder / "reviewed.json").write_text(json.dumps(rows, ensure_ascii=False), encoding="utf-8")
    recovered = run(folder, "visit_csv.py", "reviewed.json", "reviewed.csv")
    require(recovered.returncode == 0, recovered.stderr)
    sys.path.insert(0, str(HERE))
    from visit_csv import read_back
    require(read_back((folder / "reviewed.csv").read_text(encoding="utf-8")) == rows,
            "recovery differs from explicit edit")
    print("PASS explicit review edit exports four rows")

source = (HERE / "visit_csv.py").read_text(encoding="utf-8")
mutations = [
    ("remove-prefix-check", "if probe and (probe[0] in DANGEROUS or probe[0] == \"'\"):", "if False:"),
    ("remove-leading-whitespace-check", "probe = line.lstrip()", "probe = line"),
    ("remove-unicode-control-check", "if any(unicodedata.category(c) in {\"Cc\", \"Cf\"} and c != \"\\n\" for c in value):", "if False:"),
    ("change-record-terminator", 'lineterminator="\\r\\n"', 'lineterminator="\\n"'),
    ("permit-extra-columns", "set(row) != set(FIELDS)", "not set(FIELDS).issubset(row)"),
]
for name, old, new in mutations:
    require(source.count(old) == 1, "mutation anchor ambiguous: " + name)
    with tempfile.TemporaryDirectory() as tmp:
        folder = Path(tmp)
        (folder / "visit_csv.py").write_text(source.replace(old, new), encoding="utf-8")
        for filename in ("check_visit_csv.py", "actions.json"):
            shutil.copyfile(HERE / filename, folder / filename)
        result = run(folder, "check_visit_csv.py")
        require(result.returncode != 0 and "AssertionError" in result.stderr,
                "mutation survived or failed for unrelated reason: " + name)
        print("KILLED " + name)
print("ALL WORKFLOW CHECKS PASSED")

19. 实测记录、失败修复与手机端接收

本补充于2026-10-14在隔离的本地练习目录使用Python 3.12.14运行,实际完成了标准库离线测试、四行CSV导出、末行异常时不创建输出、显式示范改写后的恢复导出,以及同名输出拒绝且原文件字节不变的测试。原始业务材料和参考文案均为合成案例;没有真实WorkBuddy运行、手机连接、语音识别、Excel/LibreOffice打开、邮件发送或生产数据验证。

复现顺序:先运行“python check_visit_csv.py”,再运行“python visit_csv.py actions.json actions.csv”。完整自动复现可运行“python check_workflow.py”和“python -O check_workflow.py”;它们在临时目录测试失败与恢复,并实际修改导出器的五处行为逐一确认被检测:前缀检查、前导空白检查、Unicode控制字符检查、CRLF记录结尾和多余列检查。此为五个指定变异,不代表测试覆盖全部可能错误。第二次运行同一导出命令,应返回FileExistsError;这属于预期保护,不是导出成功。若想保留另一次人工修订的结果,检查输入后使用新的目标文件名,不能为了通过检查覆盖旧结果。

若某条自由文本为“=1+2”,不要先用电子表格打开失败数据。留在JSON或普通文本视图中,确认它确实是要记录的原文后,可以经人工确认改写成“客户原文:=1+2”,在内部纪要记录人工改写依据,再导出新的文件。这样表达改变是显式的,不会把字符净化冒充成业务原文。需要完全保留原始字符时,保留JSON作为原始交换文件,另行验证目标软件的文本导入流程。

如果发现8万元被当成成交价,恢复办法是先按V02/V03纠正语义,再重新生成受影响的邮件和行动清单;只修CSV的引号没有用。若只是一行多列,回到writer导出而不是让手机用户凭视觉补逗号。若三份文件只生成了两份,先读已有内容与原始记录核对,再补缺项,不能因聊天里出现“三份已完成”就判定三份文件都存在。

WorkBuddy官方多端协同文档说明手机可以续聊桌面任务并查看回传产物。本例未实测该功能;实际接收时仍应在对应会话分别打开内部纪要、邮件草稿和CSV,确认文件名与内容。CSV在目标表格软件中应以UTF-8、逗号分列、各列按文本导入,核对4条记录和6列;目标软件真实打开与再次保存尚待测试,不能用这里的Python读回代替。

手机回报可保持短而具体:“已整理三份待审文件。范围整理为唯一已承诺动作;其余三项为建议,日期均待确认。预算是8万元以内的意向,未形成报价。CSV离线格式检查通过,目标表格导入待验证。未发送。”这段话仅在三份文件确实写入并核对后使用;只推演参考文案时应改为“参考稿已准备,未写入目标电脑”。

本次实际终端结果

Python 3.12.14
python check_workflow.py
PASS literal byte-shape oracle
PASS comma quote multiline roundtrip
PASS 17 rejected cell probes
PASS missing and extra columns rejected
PASS negative control: CSV quotes do not neutralize formulas
PASS four-row fixture and independently authored business expectations
ALL CHECKS PASSED
PASS invalid header, row width and duplicate JSON keys rejected
PASS existing output refused and byte-identical
PASS invalid final row creates no output
PASS explicit review edit exports four rows
KILLED remove-prefix-check
KILLED remove-leading-whitespace-check
KILLED remove-unicode-control-check
KILLED change-record-terminator
KILLED permit-extra-columns
ALL WORKFLOW CHECKS PASSED

python -O check_workflow.py
PASS literal byte-shape oracle
PASS comma quote multiline roundtrip
PASS 17 rejected cell probes
PASS missing and extra columns rejected
PASS negative control: CSV quotes do not neutralize formulas
PASS four-row fixture and independently authored business expectations
ALL CHECKS PASSED
PASS invalid header, row width and duplicate JSON keys rejected
PASS existing output refused and byte-identical
PASS invalid final row creates no output
PASS explicit review edit exports four rows
KILLED remove-prefix-check
KILLED remove-leading-whitespace-check
KILLED remove-unicode-control-check
KILLED change-record-terminator
KILLED permit-extra-columns
ALL WORKFLOW CHECKS PASSED