本文最后更新于 2026-05-17,文章内容可能已经过时。

我们用 API 流水线自动化了团队周报,踩了三个月的坑才摸出这套打法

周五下午三点,我们的产品经理小陈在飞书群里翻了将近 40 分钟。

她只是想找到上周三那个需求变更是谁说的、改了什么——就这么一件事。群里有 237 条消息,夹杂着"今天谁请客""会议室订好了吗""这个 bug 先不管"……最后她放弃了,在周报里写了一行"需求细节待确认"。

这个场景在我们团队每周都在上演。

---

一、这件事到底有多痛

我们是一个 10 人的产研团队,每周五下午固定有一个"写周报"的非正式惯例。说是惯例,其实是全员停工两小时,各自翻聊天记录、整理任务进度、拼凑一份给主管看的汇报文档。

算一笔账:

| 指标 | 数字 | | 团队人数 | 10 人 | | 每人每周花在周报上的时间 | 约 2 小时 | | 全年累计消耗 | 10 × 2 × 52 = 1040 小时 | | 折算成工作日 | 约 130 个工作日 |

130 个工作日,相当于半个人力,全用来整理信息、复述已经发生的事情。

更让人崩溃的是:这份周报的质量还不稳定。有人写得很详细,有人就贴几个任务标题。主管每次还得逐条核对,问"这个进度是指完成了还是进行中"。

我们决定动手做自动化,但没想到这件事比想象中难得多。

---

二、先看整体架构,再聊哪里卡壳

在讲踩坑之前,先给你一张全局地图,不然后面的细节会让人迷失。

整个流水线分五个节点:

graph LR

A[飞书消息采集] --> B[数据清洗过滤]

B --> C[结构化分类]

C --> D[LLM 润色生成]

D --> E[自动推送飞书/邮件]

每个节点用了什么:

  • 飞书消息采集:飞书开放平台 Webhook + Bot API,定时拉取指定群聊的消息记录
  • 数据清洗过滤:Python 脚本 + LLM Prompt,过滤噪音消息
  • 结构化分类:LLM 按项目/优先级/负责人三个维度打标签,输出 JSON
  • LLM 润色生成:把结构化数据转化为自然语言周报段落
  • 自动推送:通过飞书 Bot 发送到指定群,同时抄送邮件

这套流水线的设计原则是每个节点都可以独立替换。你用钉钉不用飞书?换掉第一个节点就行。不想用 LLM 生成?第四步改成模板填充也能跑。这不是一个黑盒系统,而是一条可拆卸的流水线。

调度用的是 GitHub Actions,每周五下午两点自动触发,全程无人值守。

---

三、哪个节点卡了最久

这是全文最重要的部分。我们在三个节点上踩了坑,每个都让我们停下来重新设计。

节点 1:飞书消息拉取——权限比你想的复杂

失败方案: 最开始我们以为,在飞书开放平台申请一个 Bot,给它加进群,就能直接读消息了。

现实是:飞书的消息读取权限分得很细。im:message:readonly 这个权限需要企业管理员审批,而且只能读取 Bot 被 @ 的消息,不能主动拉取历史消息。我们第一版代码跑起来之后,每次只能拿到几条被 @ 的记录,完全没法覆盖全周的讨论。

最终方案: 绕了一个弯——我们在飞书群里设置了一个"周报收集"的固定机器人入口。每天下班前,Bot 会在群里发一条消息:"今天有什么值得记录的进展?直接回复这条消息。" 成员只需要把关键信息 reply 给 Bot,Bot 就能收到(这走的是消息事件推送,不需要历史消息读取权限)。

这个方案有一个副作用:它把"信息采集"从被动变成了主动——团队成员需要有意识地把关键信息喂给系统。一开始有人不适应,后来发现这反而让大家养成了"随手记录"的习惯,周报质量反而更高了。

节点 2:噪音过滤——Prompt 工程的真实战场

失败方案: 第一版 Prompt 是这样写的:
请从以下消息中,过滤掉与工作无关的内容,只保留项目进展、决策记录和问题反馈。

结果 LLM 把"下午三点开会讨论了首页改版方案"也过滤掉了,因为它判断"开会"本身不是进展。同时,"今天的 bug 修了,感觉还不错"这种模糊表达也被保留了下来,没有任何有效信息。

最终方案: 加入 few-shot 示例,明确定义"有效信息"的边界:
你的任务是判断一条飞书消息是否包含"有效工作信息"。

【有效信息的定义】

  • 包含具体任务的完成、推进或阻塞状态
  • 包含明确的决策或需求变更
  • 包含需要跟进的问题或风险

【示例 - 保留】

输入:"首页改版的设计稿已经确认,开发可以开始切图了"

输出:{"keep": true, "reason": "包含任务状态变更"}

【示例 - 过滤】

输入:"今天谁订外卖?"

输出:{"keep": false, "reason": "与工作无关"}

【示例 - 过滤】

输入:"感觉这周压力有点大"

输出:{"keep": false, "reason": "情绪表达,无具体信息"}

现在请判断以下消息:

{message}

加了 few-shot 之后,过滤准确率明显提升,误报率(把有效信息过滤掉)从体感上的两三成降到了偶发个例。

节点 3:LLM 输出格式不稳定——JSON 崩溃是真实的痛

这是让我们最头疼的问题,也是最值得展开说的部分。

失败现象: 我们要求 LLM 输出结构化 JSON,用于后续的分类和渲染。大多数时候没问题,但每隔几次就会出现这样的输出:
好的,以下是整理后的结果:

json

{

"project": "首页改版",

"status": "进行中",

"owner": "小陈"


注意到问题了吗?JSON 没有闭合,而且前面多了一段自然语言解释。这种输出直接让 json.loads() 抛出异常,整条流水线中断。

更诡异的是:这种崩溃不是必现的,有时候跑三十次都没问题,然后突然在第三十一次炸掉。

最终方案: 三层兜底机制:

1. Prompt 层:明确要求"只输出 JSON,不要任何解释文字,不要 markdown 代码块标记"

2. 解析层:用正则表达式从输出中提取第一个合法 JSON 块,即使前后有噪音也能解析

3. 重试层:解析失败时自动重试最多 3 次,第 3 次失败后降级为纯文本输出并告警

这套机制上线后,格式崩溃的情况基本消失了。偶发的解析失败也能被重试机制兜住,不会中断流水线。

---

四、关键代码片段,可以直接复用

代码片段①:飞书消息接收(Python)

python

from flask import Flask, request, jsonify

import json

app = Flask(__name__)

存储收到的消息

message_buffer = []

@app.route('/webhook', methods=['POST'])

def receive_message():

data = request.json

# 飞书的验证握手

if data.get('type') == 'url_verification':

return jsonify({'challenge': data['challenge']})

# 提取消息内容

event = data.get('event', {})

if event.get('type') == 'message':

msg = {

'sender': event['sender']['sender_id']['user_id'],

'content': event['message']['content'],

'timestamp': event['message']['create_time'],

'msg_type': event['message']['msg_type']

}

message_buffer.append(msg)

print(f"收到消息: {msg['content'][:50]}...")

return jsonify({'code': 0})

if __name__ == '__main__':

app.run(port=8080)


注意:这段代码需要你在飞书开放平台配置 Webhook 回调地址,并开启"接收消息"事件订阅。

代码片段②:清洗用 Prompt 模板(含 few-shot)

python

FILTER_PROMPT = """

你的任务是判断一条飞书消息是否包含"有效工作信息"。

【有效信息的定义】

  • 包含具体任务的完成、推进或阻塞状态
  • 包含明确的决策或需求变更
  • 包含需要跟进的问题或风险

【输出格式】

只输出 JSON,不要任何解释:

{{"keep": true/false, "category": "进展/决策/风险/其他", "summary": "一句话摘要"}}

【示例】

输入:首页改版设计稿已确认,开发可以开始切图了

输出:{{"keep": true, "category": "进展", "summary": "首页改版设计稿确认,进入开发阶段"}}

输入:今天谁订外卖

输出:{{"keep": false, "category": "其他", "summary": ""}}

输入:登录接口有个性能问题,高并发下响应超过3秒,需要排查

输出:{{"keep": true, "category": "风险", "summary": "登录接口高并发性能问题,需排查"}}

【待判断的消息】

{message}

"""

你可以直接复制这段 Prompt,

把 [项目名] 相关的上下文加在【有效信息的定义】部分,改掉就能用


代码片段③:JSON 格式校验 + 重试逻辑

python

import json

import re

from openai import OpenAI

文中的 LLM 调用部分,我们用的是 api.884819.xyz 提供的 API 接口

它兼容 OpenAI 格式,不需要改代码结构,直接换 base_url 就能接入

这对我们快速验证流水线帮助很大

client = OpenAI(

api_key="your_api_key",

base_url="https://api.884819.xyz/v1"

)

def extract_json(text: str) -> dict | None:

"""从可能包含噪音的文本中提取第一个合法 JSON"""

# 先尝试直接解析

try:

return json.loads(text.strip())

except json.JSONDecodeError:

pass

# 用正则提取 JSON 块

pattern = r'\{[^{}]*\}'

matches = re.findall(pattern, text, re.DOTALL)

for match in matches:

try:

return json.loads(match)

except json.JSONDecodeError:

continue

return None # 解析彻底失败

def call_llm_with_retry(prompt: str, max_retries: int = 3) -> dict:

"""带重试机制的 LLM 调用"""

for attempt in range(max_retries):

response = client.chat.completions.create(

model="deepseek-r1", # 或其他模型

messages=[{"role": "user", "content": prompt}],

temperature=0.1 # 低温度,输出更稳定

)

result = extract_json(response.choices[0].message.content)

if result:

return result

print(f"第 {attempt + 1} 次解析失败,重试中...")

# 三次失败后降级处理

print("⚠️ JSON 解析失败,降级为纯文本输出")

return {"keep": True, "raw_text": response.choices[0].message.content}

```

---

五、跑了 8 周之后,真实数据和没解决的问题

效果数据

| 指标 | 改造前 | 改造后(第 8 周) | | 出稿时间 | 全员停工约 2 小时 | 自动生成约 5 分钟 | | 主管核对时间 | 约 30 分钟 | 约 10 分钟(只看摘要) | | 周报覆盖率 | 依赖个人记忆,易遗漏 | 基本覆盖群内所有有效信息 | | 格式一致性 | 每人风格不同 | 统一结构,可对比历史 |

出稿时间从 2 小时压缩到 5 分钟,这个数字是真实的。但需要说明的是:这 5 分钟是机器跑的时间,人工审核还需要 10 分钟左右——我们没有去掉人工审核这一步,因为 LLM 偶尔还是会把某条消息的归属搞错。

还没解决的问题(诚实说)

1. 跨项目消息归因仍靠人工

当一条消息同时涉及两个项目时(比如"A 项目的接口改动会影响 B 项目"),LLM 只会归到一个项目下,另一个项目的负责人看不到。这个问题我们目前还是靠人工审核时手动调整。

2. 突发性故障偶发

飞书 Webhook 偶尔会有延迟,导致某些消息在采集窗口结束后才到达,被漏掉。我们加了一个 30 分钟的缓冲窗口,但还不是完美方案。

3. 历史对比功能缺失

主管有时候想看"这个问题上周提过,这周有没有推进",但我们的系统目前没有做跨周关联,每周的周报是独立的。这是下一步想做的功能。

---

自动化不是终点,它只是把你从重复劳动里解放出来,去做真正需要判断力的事。

周报自动化跑起来之后,我们节省了时间,但也发现了一个更深的问题:生成的内容"读起来没问题,用起来没用"——数据准确,格式规整,但主管看完还是不知道下周该重点关注什么。

这让我们开始思考一个新问题:怎么让 LLM 不只是"整理信息",而是真正"提炼判断"?

下一篇,我们会拆解在 Prompt 层做的三次迭代,以及一个让我们挺意外的反直觉结论。如果你也在做类似的事,或者对这个方向感兴趣,关注我们,不定期更新。

---

附:本文流水线用到的工具清单
  • LLM 调用:[api.884819.xyz](https://api.884819.xyz)(兼容 OpenAI SDK,国内可直连,新用户注册即送体验 token)
  • 消息拉取:飞书开放平台 Webhook + Bot API
  • 调度:GitHub Actions(免费额度对这个场景完全够用)
  • 格式校验:Pydantic(比手写正则更健壮)
  • 部署:任意能跑 Python 的服务器,或者直接用 Serverless

---

本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。

#AI自动化 #飞书 #周报自动化 #LLM应用 #Python #Prompt工程 #8848AI #效率工具