会议纪要自动提取待办:action items 按负责人分组、识别期限

2026-10-06 · 喵窝资源铺

开会开得热闹,纪要发到群里就沉底——真正要跟的是里面散落的 action items:- [ ] 张伟负责:输出引导流程初稿,10月10日前 这种行。人一多,没人记得谁欠什么。这篇给一个 60 行脚本,从 markdown 纪要里把 - [ ] / - [x] 行全部提出来,解析出负责人 + 事项 + 期限,输出一份 CSV 待办表和一份按人分组的 markdown 清单。代码实跑验证,真实输出贴在下面。

输入输出长什么样

输入一份典型周会纪要(含已完成项、四种期限写法、同一人两种署名),跑完:

提取完成:共 7 条 action items,待办 5 条,已完成 2 条
  张伟: 2 项待办,期限分布 ['10月10日', '明天']
  李娜: 1 项待办,期限分布 ['周五']
  王强: 1 项待办,期限分布 ['下周三']
  赵敏: 1 项待办,期限分布 ['月底']

markdown 输出按人分组:

# 待办清单(自动提取自会议纪要)

## 张伟(2 项待办)
- [ ] 输出新用户引导流程初稿,10月10日前(期限:10月10日)
- [ ] 和老刘对齐 API 字段口径,明天前(期限:明天)

## 李娜(1 项待办)
- [x] 完成竞品调研报告,已同步群内(期限:未定期限)
- [ ] 补齐竞品价格对比表,周五前(期限:周五)
……

7 条全部解析成功,四种期限写法(具体日期/周五/下周三/月底)都抓到了。

完整脚本

# -*- coding: utf-8 -*-
"""从会议纪要文本提取 action items:责任人+事项+期限 → 待办表(csv/markdown)。"""
import sys, re, csv

def parse(text):
    todos = []
    for line in text.splitlines():
        s = line.strip()
        if not s:
            continue
        # action 行:- [ ] 任务 | - [x] 任务
        m = re.match(r'-\s*\[( |x|X)\]\s*(.+)', s)
        if not m:
            continue
        done = m.group(1).lower() == 'x'
        body = m.group(2)
        owner = re.search(r'[@@]?([\u4e00-\u9fa5A-Za-z0-9]{1,6})(?:负责|:|:)', body)
        owner = owner.group(1).replace('负责', '') if owner else '未指派'
        # 期限:X月X日前 / 本周五前 / 周X / 底前 / 明天
        dl = re.search(r'(\d{1,2}月\d{1,2}日|下?周[一二三四五六日天]|明天|后天|月底)前?', body)
        due = dl.group(1) if dl else '未定期限'
        item = re.sub(r'[@@]?[\u4e00-\u9fa5A-Za-z0-9]{1,6}(?:负责|:|:)\s*', '', body).strip(' 。;;,')
        todos.append({'done': done, 'owner': owner, 'item': item, 'due': due})
    return todos

def main(src, dst_csv, dst_md):
    todos = parse(open(src, encoding='utf-8').read())
    with open(dst_csv, 'w', encoding='utf-8-sig', newline='') as f:
        w = csv.writer(f)
        w.writerow(['状态', '负责人', '待办事项', '期限'])
        for t in todos:
            w.writerow(['已完成' if t['done'] else '进行中', t['owner'], t['item'], t['due']])
    by_owner = {}
    for t in todos:
        by_owner.setdefault(t['owner'], []).append(t)
    with open(dst_md, 'w', encoding='utf-8') as f:
        f.write('# 待办清单(自动提取自会议纪要)\n\n')
        for owner, ts in sorted(by_owner.items()):
            f.write(f'## {owner}({sum(1 for t in ts if not t["done"])} 项待办)\n')
            for t in ts:
                mark = 'x' if t['done'] else ' '
                f.write(f'- [{mark}] {t["item"]}(期限:{t["due"]})\n')
            f.write('\n')
    open_cnt = sum(1 for t in todos if not t['done'])
    print(f'提取完成:共 {len(todos)} 条 action items,待办 {open_cnt} 条,已完成 {len(todos)-open_cnt} 条')
    for owner, ts in sorted(by_owner.items()):
        pend = sum(1 for t in ts if not t['done'])
        print(f'  {owner}: {pend} 项待办,期限分布 {sorted(set(t["due"] for t in ts if not t["done"]))}')

if __name__ == '__main__':
    main(sys.argv[1], sys.argv[2], sys.argv[3])

实跑里揪出来的三个真坑

扩展:纪要不是标准格式的怎么办

这份脚本吃的是 - [ ] 负责人:事项,期限 这种规整写法。如果纪要是自由文本(「会上说让王强去压测」),正则会漏——那一步得先靠 LLM 把纪要转成规整的 action item 列表,再做本脚本这种确定性解析。顺序别反:LLM 负责格式转换,代码负责解析和汇总,让 LLM 直接输出 CSV 容易在转义和编码上翻车。

不想自己跑?把活儿给我。纪要、聊天记录、周报里的待办混在一起没人跟,我可以替你写好脚本、用你的真实文件实测后交付(¥19.9 表格处理 / ¥29.9 脚本定制)。
→ 去下单页看看 | 虚拟物品交付后不退款;未收到或未达承诺免费补发/重做。

相关文章:手机号列清洗去重 · 邮箱列清洗去重 · Word 批量替换

← 更多实跑干货 | 喵窝资源铺

📖 相邻文章:聊天记录批量提取「待办+承诺日期」 · 两份流水账自动对账 · | 期限还跟日程表打架?看续篇 待办期限×日程表核对 · 博客目录