Local Office Form Filler
环境依赖与安装
基础环境
- Python 3.9+(Windows)
- openpyxl(Excel 离线读写)
- python-docx(Word 离线读写)
- pywin32(桌面 COM 写入,可选但推荐)
pip install openpyxl python-docx pywin32
OpenVINO NER 增强(可选,强烈推荐)
启用本地 NER 模型后可显著提升叙事性文本中的人名、地址提取召回率。模型完全在本地运行,数据不出机。安装方式见下方 OpenVINO NER 增强提取 章节。
任务适用性判断
| 任务类型 | 是否使用本 skill | 推荐路径 |
|----------|-----------------|----------|
| 向已打开的 Excel 写数据 | 是 | fast-excel |
| 从文本/Excel 提取 PII 填入模板 | 是 | fill |
| 隐私脱敏 + 填报一体化 | 是 | fill(内置 masking) |
| 向已打开的 Word 替换/写表格 | 是 | fill-open-word |
| 批量记录写入(表头匹配) | 是 | fill / fast-excel |
| 复杂 Word 格式修改(修订/批注/分栏) | 否 | — |
| 从零新建 Word 文档 | 否 | — |
| 数据分析 / 统计计算 | 否 | — |
| 简单键值写入(≤3 个字段、无 PII) | 否 | — |
| PDF 表单填写 | 否 | — |
| 飞书电子表格 | 否 | — |
适用场景
只在下面场景调用这个 skill:
- 目标是本地 Excel / Word,尤其是”已经打开的 Office 文档”
- 需要通过桌面 COM / Office 进程完成写入
- 需要复用 inspect / fill / fill-open-excel / fill-open-word 能力
- 手工处理会更慢、更脆弱或根本做不到
如果只是普通文本理解、字段整理、简单映射判断,优先由 agent 自己完成。
核心原则
- 先判断这个 skill 是否真的能比 agent 自己做更快
- 默认不生成临时文件、不生成 request 样例、不依赖 outputs 目录
- 只保留”inspect 目标结构”和”执行难操作”这两个高价值环节给脚本
- 字段理解、记录整理、歧义判断优先由 agent 自己完成
命令选择决策树
目标文件状态?
├── 已在桌面 Excel/WPS 中打开 → fast-excel(最快路径)
├── 已在桌面 Word/WPS 中打开 → fill-open-word(需 request json)
├── 未打开 / 磁盘上的文件
│ ├── .xlsx → fill(template_type=xlsx)
│ └── .docx → fill(template_type=docx)
└── 不确定目标结构 → 先 inspect 查看,再选上述命令
源文件类型判断:
- 结构化源(Excel 表格、键值对文本):直接交给脚本提取
- 叙事性源文本(自然语言段落、故事描述):优先使用
--openvino-ner启用本地 NER 模型增强提取;如果 NER 模型不可用,agent 应自行解析出各条记录,构造 records 列表后通过records_override传入
最常用命令
看目标结构
python scripts/local_office_form_filler/cli.py inspect --path “<target.xlsx|target.docx>” --max-rows 12
写入已打开 Excel
当目标已经在桌面 Excel / WPS 中打开时使用。
python scripts/local_office_form_filler/cli.py fast-excel --source “<source>” --target-open-excel “<target.xlsx>” --worksheet “<actual worksheet name>”
这是最快桥接路径,默认只做必要写入与终端摘要输出。
写入已打开 Word
当目标已经在桌面 Word / WPS 中打开,需要替换占位符或按表头写表格时使用。
python scripts/local_office_form_filler/cli.py fill-open-word --request “<request.json>”
仅当 open Word 桌面写入无法直接用命令参数表达时,才组装 request json。
写入关闭的 Excel / Word
python scripts/local_office_form_filler/cli.py fill --request “<request.json>”
只在离线模板写入时使用。
request 使用原则
只有在 fill / fill-open-word / fill-open-excel 确实需要结构化参数时,才创建 request json。
最小原则:只写本次任务必需字段,用任务现场路径,不复用历史 demo json。
占位符格式
默认支持 {{字段名}} 格式。如果用户模板使用其他占位符风格,可在 request json 的 template 中指定 placeholder_pattern 参数:
| 预设名 | 匹配格式 | 示例 |
|--------|---------|------|
| {{}}(默认) | {{姓名}} | {{手机号}} |
| ${} | ${姓名} | ${手机号} |
| 【】 | 【姓名】 | 【手机号】 |
| <> | <姓名> | <手机号> |
也可以传入自定义正则(必须包含一个捕获组),如 \[\[(.+?)\]\] 匹配 [[姓名]]。
Word 模板设计指南
Word 模板支持两种写入模式,可同时使用:
段落占位符替换
在文档段落或表格单元格中放置 {{字段名}},脚本自动替换:
姓名:{{姓名}} 手机号:{{手机号}}
- 占位符可以在任意段落、表格单元格中
- 未匹配到值的占位符原样保留
- 跨 run 的占位符(Word 把
{{姓名}}拆成多个 run)能正确处理,但会合并到第一个 run(可能丢失部分格式)
表头匹配写入
在文档中插入表格,第一行写表头(如”姓名”、”手机号”),脚本自动识别表头并逐行写入记录:
- 表头行默认第 1 行,数据从第 2 行开始(可通过
header_row/value_row调整) - 只有能映射到源数据字段的列才会写入
- 行数不够时自动追加新行
OpenVINO NER 增强提取 (本地推理模型)
本 skill 集成了基于 OpenVINO 推理框架的本地 NER(命名实体识别)模型,用于增强叙事性/非结构化文本中的 PII 提取。模型完全在本地运行,数据不出机,充分利用 Intel AI PC 的 CPU / GPU / NPU 异构算力。
为什么需要 OpenVINO NER
纯正则提取对结构化文本(”姓名:张三”)效果很好,但面对叙事性文本(自然语言段落、故事描述)时,人名、地址等实体缺少固定标签前缀,召回率明显下降。NER 模型可以识别上下文中的命名实体,补上这块短板。
安装步骤
# 1. 安装 OpenVINO 推理框架
pip install “optimum-intel[openvino]” transformers openvino
# 2. 下载并转换 NER 模型(约 110MB,一次性操作)
python scripts/setup_openvino_model.py
setup_openvino_model.py 会从 HuggingFace 下载 ckiplab/bert-base-chinese-ner(~110M 参数),转换为 OpenVINO IR 格式后保存到 scripts/openvino_models/chinese-ner/。
可选参数:
# 使用自定义模型
python scripts/setup_openvino_model.py --model-id uer/roberta-base-finetuned-chinanews-chinese
# INT8 量化(减小体积、加速推理)
python scripts/setup_openvino_model.py --weight-format int8
使用方式
CLI 参数——在 fill 或 fast-excel 命令中添加 --openvino-ner:
python scripts/local_office_form_filler/cli.py fill --request “<request.json>” --openvino-ner
# 指定推理设备(默认 AUTO,自动选择 CPU/GPU/NPU 中最优设备)
python scripts/local_office_form_filler/cli.py fill --request “<request.json>” --openvino-ner --openvino-device GPU
Request JSON——在 request 中添加字段:
{
“profile_sources”: [{“path”: “narrative_source.txt”}],
“templates”: [],
“use_openvino_ner”: true,
“openvino_device”: “AUTO”
}
提取流程
- 正则提取先行:快速正则提取覆盖结构化文本(毫秒级)
- NER 补充:对正则未覆盖的字段,调用 OpenVINO NER 模型识别文本中的人名、地址等实体
- 结果合并:两条路径的结果合并,正则结果优先级更高
降级策略
如果 OpenVINO 未安装或模型未转换,--openvino-ner 不会报错,自动回退到纯正则提取。终端输出的 openvino.ner_used 字段指示本次是否实际使用了 NER 模型。
设备支持
| 设备 | 说明 |
|------|------|
| AUTO | 自动选择最优设备(默认) |
| CPU | Intel CPU,兼容所有 x86-64 平台 |
| GPU | Intel 集成显卡 / 独立显卡 |
| NPU | Intel AI PC 内置 NPU(需 Meteor Lake 及以上) |
dry-run 预览模式
fill 和 fast-excel 命令均支持 --dry-run。开启后只做字段提取与映射,不写入目标文件:
- 提取到的字段列表与映射关系
- 模板为 xlsx 时显示公式检测结果
- fast-excel 额外输出前 5 条脱敏记录预览
python scripts/local_office_form_filler/cli.py fill --request “<request.json>” --dry-run
适合在正式写入前确认字段映射是否正确。
公式处理策略
三阶段保护机制:
- 写入前:
inspect和fill --dry-run报告模板中公式单元格数量和示例 - 写入时:默认
protect_formulas: true,自动跳过公式单元格。被跳过的单元格记录在formula_protection.skipped_formula_cells中 - 写入后:自动扫描 7 种 Excel 错误标记(
#VALUE!、#DIV/0!、#REF!、#NAME?、#NULL!、#NUM!、#N/A),结果记录在error_scan中
openpyxl 离线写入后公式不会自动重算。首选方案:在 Excel 中打开文件按 Ctrl+Shift+F9;或使用 fast-excel(COM 模式)自动重算。
可识别字段范围
PII 提取器内置以下字段类型的正则识别:
| 字段名 | 别名示例 | 正则特征 | |--------|---------|---------| | 姓名 | 名字、申请人、联系人 | 中文 2-4 字 | | 身份证号 | 证件号码、居民身份证号 | 18位(含X校验) | | 手机号 | 联系电话、联系方式 | 1[3-9]开头11位 | | 邮箱 | Email、电子邮箱 | xxx@xxx.xxx | | 地址 | 住址、联系地址 | 标签后文本 | | 银行卡号 | 银行账号、收款账号 | 16-19位数字 | | 职业 | 工作、岗位、职务 | 标签后文本 | | 论文成果 | 论文、成果、发表论文 | 标签后文本 |
超出以上范围的字段(如血型、学历、爱好等)不会被自动提取。如需写入这类字段,agent 应自行解析并通过 records_override 或 field_overrides 传入。
输出质量标准
Excel 输出
- 公式保护:默认不覆盖模板中的公式单元格
- 数据格式:写入列统一使用文本格式(
@),防止长数字被截断 - 错误检测:写入后自动扫描公式错误标记
- 备份机制:输出路径与模板路径相同时,自动创建带时间戳的备份
Word 输出
- 占位符验证:写入后自动检查未替换的占位符,结果在
verification中报告 - 格式保持:段落替换优先在单个 run 内完成,保留原有字体和格式
- 表格行追加:记录数超过模板行数时自动追加
通用标准
- 隐私安全:所有终端输出自动脱敏(手机号、身份证、银行卡、邮箱)
- 写入验证:输出文件的
written_cells列出每个被写入的单元格地址和字段名 - 结构化报告:每次执行生成
agent_result.json(完整结果)和qa_report.json/qa_report.md(脱敏报告)
单元测试
python .\tests\run_tests.py
覆盖模块:PII 提取、字段映射、隐私脱敏、行偏移逻辑、占位符配置、公式保护与错误扫描、OpenVINO NER 集成。
常见问题排查
NO_CELLS_WRITTEN(写入了 0 个单元格)
最常见原因:Excel 模板表头文字与源数据字段无法匹配。用 inspect 检查表头名称,确认是否需要设置 field_aliases。
模板已有数据行时,脚本尝试”匹配更新”而非追加。新记录匹配不到已有行且 append_unmatched_records 为 false 时跳过写入。解决:清空模板数据行,或设置 append_unmatched_records: true。
占位符未被替换
检查占位符格式(默认 {{字段名}},不要写成 {字段名})。Word 中占位符有时会被拆成多个 run,脚本有两遍替换机制处理此情况。用 inspect 查看模板字段,用 dry-run 检查提取结果。
身份证号校验未通过
脚本内置身份证号校验位验证。测试数据会被标记为 validation_status: invalid,但仍会写入模板,这是 warning 而非错误。
已知限制
mask_text中手机号正则可能干扰身份证号:18 位身份证号中如果包含1[3-9]开头的 11 位子串,会被先当作手机号脱敏。mask_value(按字段名单独脱敏)不受影响。- 键值对文本提取的贪心问题:”邮箱:test@qq.com 请查收” 会把 “test@qq.com 请查收” 整体作为邮箱值。建议源文件中每个字段独占一行。
- Word 跨 run 占位符替换后格式合并:段落整体文本正确,但可能丢失部分格式。
- openpyxl 不重算公式:离线写入后需要在 Excel 中打开触发重算。
- COM 路径依赖 pywin32 和运行中的 Office 进程。不可用时,Excel 路径自动回退到 openpyxl,Word 路径尝试 PowerShell 回退。
Scan to join WeChat group