手机派活,电脑交付:WorkBuddy 远程办公任务怎么写
从只读连通测试开始,把会前准备、拜访记录和方案修订写成可核对的远程任务。
1. 把远程任务写成一张可验收的工作单
人离开工位之后,最容易出错的指令往往很短:“把昨天的方案改一下。”电脑里可能有三份昨天的方案,数据又散在不同表格。用手机交给 WorkBuddy 的任务,最好带上文件定位、版本、修改范围和回报要求,让自己能在小屏幕上判断它处理得对不对。
本文用虚构的「青禾门店试点」串起三件事:准备会议、整理拜访记录、修订方案。示例提示词未在真实业务账号中执行,文件名与数据可按自己的项目替换。先用无敏感信息的副本练习,确认交付质量后再扩展到实际工作。
2. 接通手机之前,确认任务会在哪儿执行
3. 先完成一次只读连通测试
不要直接用一份正式报价单测试连接。先在允许访问的工作目录放入「远程测试.txt」,里面只写一个不敏感的校验词,例如“青禾演示 17”。手机上选择设备后,让 WorkBuddy 读这个文件并回报。
这是一项只读测试。 目标电脑:【设备名称】。工作空间: 【完整路径或已确认的工作空间名称】。 只读取 远程测试.txt,回复其中的校验词, 并说明实际读取的文件路径。 不要列举其他文件,不创建、修改、删除文件,也不调用外部服务。 如果文件不存在、设备离线或权限不足,回复具体阻塞, 不搜索其他目录代替。
收到的内容与文件一致,再回到桌面端检查这次会话。之后可以用一份副本测试“读取纪要并另存摘要”。分开验证连接和交付,出错时才知道该查哪一步。若只收到泛泛的“测试成功”,继续要求文件路径与校验词,不能据此认定文件读取已经完成。
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:事项|预期成果|负责人|截止时间|是否确认。 没有确定的人和日期写“待确认”,可在单独的建议栏提出建议。 保存到 输出/拜访记录-日期/。若已有同名文件,先报告,不覆盖。 只生成本地草稿,不发送邮件、不更新客户系统、不分派任务。 回报三个文件名,以及必须由我补充的信息。
8. 场景三 在出差途中修订方案副本
修改已有材料前,先说明输入版本。示例方案第 6 页写两家门店、每店 18,000 元培训费,总额 36,000 元;新确认表将单店培训费改为 16,000 元。这里只演示这笔费用的变化,不代表项目总报价已经确定。
请先检查修改计划,暂不写文件。 目标电脑与工作空间:【填入已验证的信息】。 输入方案:方案/青禾试点-v3.pptx;唯一更新依据: 数据/培训费用确认-2026-10-12.xlsx 的“已确认费用”工作表。 拟修改:第 6 页两家门店的培训费用,单位为元, 沿用输入表标明的含税或未税口径。先报告原值、新值与计算过程。 检索整份方案里其他引用这笔培训费的文字、图表和备注,列出位置; 不要顺带改其他费用或报价。 如果数据口径不清、工作表缺失、页码与内容不符,停止并问我。 输出计划:目标页|原值|拟修改值|依据|其他受影响位置。 等我确认后再执行。
确认计划后再补一条执行指令:“仅应用刚确认的修改,另存为青禾试点-v4-待审.pptx,保留 v3;交付逐项变更清单和未处理项,不发送。”示例中的新培训费用为 32,000 元,比原值减少 4,000 元。方案其他合计是否需要随之调整,必须看它的实际公式与费用范围,不能整篇替换数字。
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