用 Copilot 总结会议前,可先用本脚本从纪要里抽出「谁做什么」候选,再粘贴给助手润色。纯离线,不替代人工确认。
先看清成品
- 样例会议纪要抽出多条 action item JSON。
- 2 项 pytest 通过。
合规提醒:个人 Copilot 与 Microsoft 365 Copilot 是不同产品;企业场景用公司账号并遵守组织数据政策。不要把密钥、客户名单、未公开财报等粘贴进个人版聊天。Graph 连接器写入的外部内容受 ACL 约束;错误开放等于数据泄露。本文不编造价格。
运行说明:无 Microsoft 365 / Graph 租户密钥。三篇均为本地离线助手:A 从会议记录抽待办;B 粘贴前 DLP 启发式扫描;C 校验 externalItem 形状。未调用官方聊天 API(消费级 Copilot 无通用「随便调」的公开 chat API)。2026-10-23(Asia/Shanghai)pytest 通过。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
action_items.py |
待办抽取 |
sample_meeting.txt |
样例 |
test_102a.py |
测试 |
需要准备哪些环境?
| 项目 | 说明 |
|---|---|
| Python | 3.10+ |
关键事实
| 事实 | 来源 |
|---|---|
| 消费级 Copilot 侧重聊天/搜索;M365 Copilot 嵌入 Word/Excel 等 | 产品定位 |
| 本脚本是提示词前处理,不是 Graph 或 Copilot API | 重要 |
| 抽取结果可能漏检或误检,需人工确认负责人与截止日期 | 实践 |
文件结构
102-microsoft-copilot-A-src/
├── action_items.py
├── sample_meeting.txt
└── test_102a.py
第 1 步:抽取脚本
#!/usr/bin/env python3
"""Extract action-item candidates from a meeting transcript (offline helper for Copilot prompts)."""
from __future__ import annotations
import argparse
import json
import re
from pathlib import Path
PATTERNS = [
re.compile(r"(?P<who>[\w\u4e00-\u9fff]+)(负责|来|去)?(?P<verb>完成|跟进|提交|准备|更新|发送|安排)(?P<what>.+?)(,|。|$)", re.I),
re.compile(r"action\s*item[::]\s*(?P<what>.+)", re.I),
re.compile(r"(?P<who>[A-Z][a-z]+)\s+will\s+(?P<what>.+)", re.I),
re.compile(r"待办[::]\s*(?P<what>.+)"),
]
def extract(text: str) -> list[dict]:
items = []
for line in text.splitlines():
line = line.strip()
if not line:
continue
for pat in PATTERNS:
m = pat.search(line)
if m:
gd = m.groupdict()
items.append({
"raw": line,
"owner": (gd.get("who") or "").strip() or None,
"text": (gd.get("what") or line).strip(),
})
break
# dedupe by text
seen = set()
out = []
for it in items:
key = it["text"]
if key in seen:
continue
seen.add(key)
out.append(it)
return out
def main(argv=None) -> int:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("transcript")
ap.add_argument("-o", "--out", default="")
ap.add_argument("--prompt", action="store_true", help="also print a Copilot-ready prompt")
args = ap.parse_args(argv)
text = Path(args.transcript).read_text(encoding="utf-8")
items = extract(text)
payload = {"count": len(items), "items": items}
s = json.dumps(payload, ensure_ascii=False, indent=2)
if args.out:
Path(args.out).write_text(s + "\n", encoding="utf-8")
print(s)
if args.prompt:
print("\n--- Copilot prompt ---\n")
print("请把下列候选行动项整理成表格(负责人 / 事项 / 截止日期未知则标 TBD),不要编造会议中未出现的人名:")
for it in items:
print(f"- {it.get('owner') or 'TBD'}: {it['text']}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
第 2 步:测试
from pathlib import Path
import subprocess, sys
from action_items import extract
HERE = Path(__file__).resolve().parent
def test_extract():
items = extract((HERE/"sample_meeting.txt").read_text())
assert len(items) >= 3
def test_cli():
r = subprocess.run([sys.executable, str(HERE/"action_items.py"), str(HERE/"sample_meeting.txt"), "--prompt"], capture_output=True, text=True, check=True)
assert "Copilot prompt" in r.stdout
第 3 步:运行
$ python action_items.py sample_meeting.txt
{
"count": 3,
"items": [
{
"raw": "张三负责完成接口文档,周五前发给测试。",
"owner": "张三负责",
"text": "接口文档"
},
{
"raw": "待办:更新变更日志。",
"owner": null,
"text": "更新变更日志。"
},
{
"raw": "Action item: 通知客户维护窗口。",
"owner": null,
"text": "通知客户维护窗口。"
}
]
}
$ pytest -q
.. [100%]
2 passed in 0.03s
怎么检查结果?
- JSON 含 items 数组。
- 至少识别中文「负责/跟进」或英文 will / Action item。
调试示例
「大家尽快看一下」抽不出来。 没有明确动词+对象时规则会跳过。先在纪要里改成「Alice 负责更新报价单」。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 英文纪要 | 部分支持 | 可扩展正则 |
| 要截止日期 | 本篇未强抽 | 可后处理 |
| 能否直接调 Copilot | 无通用消费级 chat API | 用网页/应用或 M365 许可 |
模板规则
- 待办须人工确认再进任务系统。
- 勿把未脱敏纪要贴进个人版。
- 企业数据走公司租户。
项目资源
| 用途 | 地址 |
|---|---|
| Copilot 网页 | https://copilot.microsoft.com/ |
| Microsoft 365 Copilot(介绍) | https://www.microsoft.com/en-us/microsoft-365/copilot |
| Learn:Microsoft 365 Copilot | https://learn.microsoft.com/en-us/copilot/microsoft-365/ |
先抽出候选,再让助手润色——别把含糊句子当成承诺。