AI 自动整理周报并生成 Word:自研周报总结 skill 拆解
背景与目标
每周写周报是很多团队的固定动作,但它非常机械:收集每个人/每个项目做了什么(常是零散的几条),把它们整理成简洁客观的条目,再按规格排好序、附上总结,最后导成一份带格式的 Word 文档。重复劳动,枯燥,还容易因为格式不一致被退回。
我把它做成了一个 skill(可复用的能力封装,见 GLOSSARY.md),让 AI 完成"整理→排序→总结→排版→出文档"的整条流水线。阅读本文后你会得到:
一套从零搭一个"整理类" skill 的通用套路:输入怎么定、规则怎么列、脚本怎么接、踩过哪些坑。
一个可以复制改造成任意"条目整理成文档"场景的方法论骨架(会议纪要、日报、需求清单、验收记录……换汤不换药)。
这不是一个"开箱即用"的成品 skill,而是"如何设计一个这样的 skill"的思路拆解。核心价值在方法论,不在某一份具体配置。
步骤
一个整理类 skill 通常由四块组成,按这个顺序设计基本不会漏:
1. 定输入结构:让"人"的活最轻松
最重要的是输入格式要贴近人怎么说话,而不是贴近程序怎么解析。我用的输入长这样:
项目名-姓名
1. 完成事项描述
2. 完成事项描述
工作总结:(可选)一段话汇总核心成果三条约定保证了机器可解析、人易书写:
每条以
项目名-姓名开头作为块标题。块是一个最小组织单元。标题下是数字列表,至少一条。数字列表让 AI 容易识别"这是条目而不是废话"。
末尾可选一段
工作总结:。人是可以偷懒不写的,缺了让 AI 自动补。
注意一个关键决策:同一人可出现在多个项目下,每个 项目名-姓名 视为独立块,不合并。这跟"按人汇总"的直觉相反,但它更接近真实输入——人本来就是按"在哪个项目里做了什么"来打字的,中途改回按人合并反而逼用户多做事。
2. 列处理规则:把"隐性规则"讲明白
AI 的难点不在生成,而在你不知道它有没有遵守你的隐性要求。所以规则要一条条写明。以周报为例,最要命的是两类规则:
语言规则(所有条目通用):
以动词开头,简洁客观(
上线XX功能、修复XX的Bug)。每条 1-2 句,突出"做了什么→结果如何"。
去除冗余、重复,按重要性排序。
结构规则(本场景特有,也是最容易踩坑的一类):
块按固定的板块顺序排列(如:主产品 → 子产品 → 其他 → 运维支持)。这个顺序写在规则里,AI 才可能遵守。
"禁止主动添加":分类标题(如
【功能开发】)只在用户输入里明确给了才保留,用户没给就纯数字列表。规则里专门加了一句"禁止主动归类捏造标题"——没有这句,AI 会自作主张给空白条目编分类,这是实际踩出来的教训,详见踩坑第 3 条。特例板块(如
【运维支持】)要合并、每条约负责人、且不要工作总结——凡是"特殊处理",都要显式写清楚范围。
3. 总结生成:三分靠模板,七分靠"不编造"
工作总结是周报里最需要"AI 味"的地方,但要防止它编造没做过的事。所以规则分两种情况:
用户给了
工作总结:→ 保留并优化语言,突出核心价值。用户没给 → AI 根据该块条目自动生成,且规则要求"概括准确、不编造内容",只能从已有条目归纳,不能凭空加成果。
给 AI 一条生成句式参考(如 完成X,对接Y,实现Z 的动宾结构)能显著稳定输出质量。"可参考例子"是让 AI 稳定的一等公民手段——一个正确的例子比十句话都管用。
4. 生成 Word:把排版交给脚本,而不是让 AI 手写
不要让 AI 直接吐 docx,它做不到稳定格式。正确分工是:
AI 负责内容:把输入整理成一段结构化 JSON(
blocks数组:标题、分类、条目、总结)。脚本负责排版:用一个
python-docx脚本读这份 JSON,产出格式统一的.docx。
这就是"AI 纠内容、脚本管格式"的边界,也是整套系统可持续的关键——改格式只改脚本,改规则只改 prompt,互不污染。
于是流程闭合为:用户给草稿 → AI 整理成 JSON → 脚本转 Word。人只需要在最开始打字,最末尾核对。
附:完整 skill 内容
下面给出我实际用的 skill 完整内容,便于你把方法论落到自己的版本。公司内部的项目名、板块名、团队署名已用占位符替换。
A. SKILL.md(规则主体)
---
name: weekly-summary
description: 团队周报工作总结 - 调整优化已有周报内容,或根据输入生成周报总结,按项目维度汇总,最终生成 Word 文档。
---
# 周报工作总结 Skill
## 功能概述
- **内容整理**:用户提供按人/项目整理的周报草稿,自动优化语言、统一格式、生成工作总结
- **输出 Word 文档**:自动生成格式规范的 `.docx` 文件
## 工作流程
### 1. 收集输入
用户自行整理本周团队工作内容,输入格式如下:
项目名-姓名
1. 完成事项描述
工作总结:(可选)一段话汇总核心成果
- 每条以 `项目名-姓名`(无括号)开头作为标题
- 标题下列数字列表条目(至少 1 条)
- 末尾可选 `工作总结:` 段落
- **同一人可出现在多个项目下**,每个 `项目名-姓名` 视为独立块
### 2. 处理内容
#### 2.1 保留块结构
保持每个 `项目名-姓名` 为独立块,**不合并同人不同项目**的条目。
**例外:`【运维支持】` 板块** — 将所有涉及运维支持的条目合并为一个板块,标题为 `【运维支持】`,且**不需要工作总结**。每条条目末尾标注负责人及状态,格式如 `(XX-已完成)`、`(XX-进行中)`。
#### 2.2 整理条目
- 检查语言表达是否简洁明了
- 统一句式:以动词开头,简洁客观
- 去除冗余、重复内容
- 保持每条 1-2 句话,突出成果
- 按重要性排序
- **分类标题(如 `【功能开发】`)仅在用户输入中已明确提供时原样保留,禁止主动添加**。用户未提供分类标题时,直接使用数字列表列出条目,不得自行归类捏造标题
#### 2.3 处理工作总结
- **用户已提供** `工作总结:` → 保留并优化语言表达,使其精炼、突出核心价值
- **用户未提供** → AI 根据该块条目自动生成一段工作总结,以 `工作总结:` 开头
### 3. 输出格式
参考示例 docx,将输入转换为以下结构:
YYYYMMDD工作情况
【项目名】-姓名
【分类标题】(可选:仅当用户输入中已提供时保留,不主动添加)
1. 完成事项描述(以动词开头,简洁客观)
...
工作总结:用一段话汇总该人本周核心成果,突出价值
- **板块排序**:按固定顺序排列,`【运维支持】` 固定在最后(具体项目名已打码):
1. 【主产品 A】 2. 【主产品 B】 3. 【子产品 C】 4. 【子产品 D】 5. 【智能体 E】 6. 【应用服务 F】 7. 其他未在上述列表中的板块(按原顺序) 8. 【运维支持】(始终最后)
- **条目语言风格**:简洁客观,以「动词 + 事项 + 结果/状态」结构为主
- **不含「下周计划」板块**
### 4. 生成 Word 文档
运行 `script/generate_weekly_report.py` 使用 `python-docx` 生成 `.docx` 文件,保存到项目 `output/` 文件夹下,文件命名格式:`周报_YYYY-MM-DD.docx`。
## 输出规则
1. 每条条目控制在 1-2 句话,以动词开头,突出做了什么、结果如何
2. 按人/项目维度组织(`【项目名】-姓名`),项目内按重要性排序
3. 语言简洁、客观,避免主观评价
4. 每人板块内先列详细条目(数字列表),再附一段工作总结
5. **工作总结处理规则**:用户已提供 → 保留并优化;用户未提供 → AI 自动生成,确保概括准确、不编造内容。**例外:`【运维支持】` 板块不需要工作总结**
6. **`【运维支持】` 板块合并规则**:所有涉及运维支持的条目合并为一个板块,标题为 `【运维支持】`,不需要工作总结。每条条目末尾标注负责人及状态B. generate_weekly_report.py(Word 生成脚本)
"""Generate a weekly summary Word document matching SKILL.md format."""
import sys
import json
from pathlib import Path
from docx import Document
from docx.shared import Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
def generate_report(data: dict, output_path: str):
doc = Document()
for section in doc.sections:
section.top_margin = Cm(2.5)
section.bottom_margin = Cm(2.5)
section.left_margin = Cm(2.5)
section.right_margin = Cm(2.5)
# Title: YYYYMMDD工作情况
date_str = data.get('date', '').replace('-', '')
title_text = f'{date_str}工作情况'
title = doc.add_heading(title_text, level=0)
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
doc.add_paragraph()
blocks = data.get('blocks', [])
for block in blocks:
# 【项目名】-姓名
heading = doc.add_heading(block['heading'], level=2)
# Multiple category groups if present
groups = block.get('groups')
if groups:
for group in groups:
cat = group.get('category')
if cat:
cat_para = doc.add_paragraph()
run = cat_para.add_run(cat)
run.bold = True
run.font.size = Pt(11)
g_items = group.get('items', [])
for i, item in enumerate(g_items, 1):
p = doc.add_paragraph()
p.paragraph_format.left_indent = Cm(0.75)
p.paragraph_format.first_line_indent = Cm(-0.75)
run = p.add_run(f'{i}. {item}')
run.font.size = Pt(11)
else:
# Single category if present
category = block.get('category')
if category:
cat_para = doc.add_paragraph()
run = cat_para.add_run(category)
run.bold = True
run.font.size = Pt(11)
# Items (numbered list)
items = block.get('items', [])
for i, item in enumerate(items, 1):
p = doc.add_paragraph()
p.paragraph_format.left_indent = Cm(0.75)
p.paragraph_format.first_line_indent = Cm(-0.75)
run = p.add_run(f'{i}. {item}')
run.font.size = Pt(11)
# Summary
summary = block.get('summary', '')
if summary:
p = doc.add_paragraph()
run = p.add_run(f'工作总结:{summary}')
run.font.size = Pt(11)
run.italic = True
doc.add_paragraph()
# Footer
footer_para = doc.add_paragraph()
footer_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT
run = footer_para.add_run('— 【某研发团队】 —')
run.font.size = Pt(9)
run.font.color.rgb = RGBColor(0x99, 0x99, 0x99)
doc.save(output_path)
return output_path
def main():
if len(sys.argv) < 2:
print('Usage: generate_weekly_report.py <json_data_or_file> [output_path]')
sys.exit(1)
input_data = sys.argv[1]
data_path = Path(input_data)
if data_path.exists():
raw = data_path.read_bytes()
if raw.startswith(b'\xef\xbb\xbf'):
raw = raw[3:]
data = json.loads(raw.decode('utf-8'))
else:
data = json.loads(input_data)
if len(sys.argv) >= 3:
output_path = sys.argv[2]
else:
output_dir = Path(__file__).resolve().parent.parent / 'output'
output_dir.mkdir(parents=True, exist_ok=True)
import datetime
today = datetime.date.today().strftime('%Y-%m-%d')
output_path = str(output_dir / f'周报_{today}.docx')
result = generate_report(data, output_path)
print(f'Word 文档已生成:{result}')
if __name__ == '__main__':
main()脚本接收参数:python generate_weekly_report.py <json数据或文件> [输出路径]。不传输出路径时,默认生成到项目 output/周报_YYYY-MM-DD.docx。AI 端把整理好的 blocks(含 heading、category/groups、items、summary 字段)序列化成这份 JSON 喂给脚本即可。
踩坑与解决
1. AI 自作主张给条目编分类标题
问题:输出里凭空出现
【功能开发】、【线上运维】这类用户没给的分类标题。复现:用户输入只有
项目-姓名\n1. 上线XX功能,不写任何分类,输出却自动分了类。根因:规则没说明白"分类标题默认不加"。AI 看到示例文档里有分类标题,就学样添油加醋。
解决:规则里显式写死"分类标题仅在用户输入中已明确提供时原样保留,禁止主动添加;用户未提供时直接用数字列表,不得自行归类捏造标题"。把"禁止项"写进规则。
验证:不提供分类的输入跑一遍,输出里不再有多余标题。给 AI 立边界,防它发挥。
2. 运维板块的性质从一开始就没说清
问题:
【运维支持】板块时而被合并、时而没合并,有时还带工作总结。复现:多次生成同一份周报,运维板块的处理不稳定。
根因:这类"特例板块"的特殊性(要合并、每条约负责人、不要总结)散落在规则各处,没有集中表述,AI 记不全。
解决:把特例板块的所有特殊处理集中成一条规则(
所有涉及运维支持的条目合并为一个板块,标题固定为X,不写工作总结,每条末尾标注负责人及状态),并放到"输出规则"小节里单独列一条,不再分散。验证:特例板块的处理在多次生成中保持一致。规则要内聚,一条规则管一件事。
3. 同人在多个项目,被 AI 自作主张"按人并块"
问题:同一个人在不同项目下的条目被 AI 合并成一个板块。
复现:输入按
项目-人分了四块,输出却按"人"归并成两块。根因:AI 默认"按人汇总"更合理,但项目方的需求恰恰是"按项目块";没有成文约定,AI 按自己的直觉来。
解决:明写"每个
项目名-姓名视为独立块,不合并同人不同项目的条目"。验证:确认输出块数 = 输入块数。你的排序逻辑要写进规则,AI 才不会自作聪明。
4. 格式稳定但内容漂移:只靠 prompt 不够
问题:AI 每次生成的措辞差异大,交付要求严格的场景(如对外周报)难以接受。
复现:同一份输入连跑三次,条目句式、详略不一致。
根因:prompt 只约束了"结构",没有约束"语言模板";且没有给足"参考例句"。
解决:在规则里给出明确的语言模板(
动词 + 事项 + 结果/状态),并放 1-2 条示例条目供对照;同时用示例 Word 文档作为"目标产物"让 AI 对齐。验证:多次生成的句式、结构趋于一致。稳定输出靠两样:语言模板 + 目标样例。
5. Word 生成脚本跟内容"两层皮"
问题:AI 改规则后,脚本读不懂新结构,或脚本字段变了 AI 不认。
复现:给 block 增加了一个
category分组字段,脚本没跟上,分类标题打印不出来。根因:AI 端(prompt 里的 JSON 约定)和脚本端(字段解析)没有统一契约,两边各自演进。
解决:把 JSON 结构定义成 AI 和脚本共同遵守的契约,脚本对这契约做宽容解析(
block.get('groups')、block.get('category')这类"缺省即空"的写法),并给脚本留默认输出路径。验证:新增可选字段后,旧输入仍能正常出文档。接口层做宽容,缺字段不崩,是两边解耦的关键。
小结与参考
一个"整理类" skill 的四件套:输入结构(贴近人)→ 处理规则(显式化)→ 总结模板(不编造)→ 脚本排版(管格式)。
三个最容易踩的坑,本质都是同一条:AI 有它自己的"合理直觉",你不显式下边界,它就会自作主张。所以规则里要写"禁止项"、把特例集中、用语言模板和参考样例给它稳定输出。
AI 与脚本的分工边界:AI 管内容成结构,脚本管格式成文档。两边用一份 JSON 契约沟通,缺字段宽容处理。
这套骨架可以迁移到任何"零散条目 → 规范文档"的场景:日报、会议纪要、需求验收清单、实验记录。换掉输入字段和规则,换掉目标文档模板,方法不变。
参考:
需求管理方法:先把"输入/规则/模板/脚本"四个格子填满,再动手写 prompt
本文拆解的 skill 为团队内部定制。上面的 rules 与脚本已按"原文贴入 + 敏感信息打码"处理:具体项目名、板块名、姓名与团队署名均已替换为占位符;骨架与实现细节保留。请结合你自己的业务约束改造。

