从 0 到 1:我的第一个 AI Agent 自动化工作流(附完整代码)

3 阅读11分钟

写在前面:为什么做这个?

每个周一早上,我都要花 20-30 分钟 做同一件事——打开 Git 仓库,翻提交记录,回忆上周干了啥,然后拼凑成周报发给领导。

不是周报多难写,是这件事太机械、太重复、太浪费脑力了。

作为一个 8 年经验的程序员,我决定用自己最擅长的方式解决它:写一个 Agent,让它自动帮我搞定。

这不是什么高大上的项目,它就是一个 Go 程序,不到 400 行代码。但它是我的第一个真正"跑起来"的 AI Agent 工作流——从数据采集到 AI 生成再到自动推送,全程无人值守。

今天我把整个过程开源出来,包括完整的代码和部署步骤。如果你也想用 AI 自动化一些重复劳动,这篇文章就是一份可以照抄的作业。


一、整体架构:三步走

先看全局,不迷路:

┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│  CNB API    │ ──→  │  DeepSeek   │ ──→  │  企业微信   │
│  采集提交记录 │      │  AI 生成周报 │      │  推送消息   │
└─────────────┘      └─────────────┘      └─────────────┘
     Step 1               Step 2               Step 3

三步,就这么简单:

步骤做什么技术
Step 1从代码仓库拉取本周所有 commit 记录CNB(类似 GitHub)REST API
Step 2把原始提交记录丢给 AI,让它整理成专业周报DeepSeek Chat API
Step 3把生成的周报推送到企业微信群企业微信 Webhook

整个流程跑下来大概 3 秒。比我自己写快了 10 倍,而且不会漏。


二、技术选型:为什么是 Go?

说实话,这个项目用 Python 也行,用 Node.js 也行。但我选 Go 的原因很务实:

  • 单文件部署go build 出来一个二进制,扔服务器上就能跑,不用装 Python 环境、不用管依赖
  • 定时任务内置:Go 的 cron 库一行代码搞定定时执行,不用额外配 crontab 或 Windows 计划任务
  • 并发友好:以后要扩展多仓库、多团队,goroutine 天然支持

核心依赖就两个:

import (
    "github.com/robfig/cron/v3"    // 定时任务
)

对,你没看错,HTTP 请求用的标准库 net/http,JSON 处理用的标准库 encoding/json零第三方依赖(除了 cron)。


三、Step 1:数据采集——从仓库拉取 Commit

3.1 配置设计

程序通过环境变量配置,.env 文件长这样:

# DeepSeek API(AI 生成周报用)
DEEPSEEK_API_KEY=sk-xxxxx
DEEPSEEK_MODEL=deepseek-chat

# CNB Token(代码托管平台 API 认证)
CNB_TOKEN=your-token

# 要监控的仓库列表(支持多个)
CNB_REPOS=org/repo1,org/repo2

# 企业微信机器人 Webhook
WECHATWORK_WEBHOOK=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx

# 定时任务:每周一早上 7:00 执行
CRON_SPEC=0 7 * * 1

加载配置的代码很简单:

type Config struct {
    DeepSeekAPIKey    string
    DeepSeekModel     string
    CNBToken          string
    CNBRepos          []string
    WeChatWorkWebhook string
    CronSpec          string
}

func loadConfig() *Config {
    return &Config{
        DeepSeekAPIKey:    getEnv("DEEPSEEK_API_KEY", ""),
        // ... 其他字段同理
    }
}

3.2 调用 CNB 获取提交记录

核心逻辑:遍历配置的每个仓库,按日期范围逐天调用 API 拉取 PushEvent:

func fetchEventsFromCNB(cfg *Config, repo string, date string) ([]Commit, error) {
    url := fmt.Sprintf("https://api.cnb.cool/events/%s/-/%s", repo, date)

    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Set("Authorization", "Bearer "+cfg.CNBToken)

    resp, err := http.DefaultClient.Do(req)
    // ... 错误处理

    // CNB 返回 JSONL 格式(每行一个 JSON 对象)
    scanner := bufio.NewScanner(resp.Body)
    for scanner.Scan() {
        var evt CNBEvent
        json.Unmarshal([]byte(scanner.Text()), &evt)

        // 只处理 PushEvent(包含代码提交)
        if evt.Type != "PushEvent" { continue }

        for _, c := range evt.Payload.Commits {
            commits = append(commits, Commit{
                SHA:     c.SHA,
                Author:  c.Author.Name,
                Message: c.Message,
            })
        }
    }
    return commits, nil
}

几个关键点:

  1. 日期范围计算:默认取"上周一到上周五"(工作日)。周一早上跑,刚好覆盖上一周的完整工作日。
  2. 只取 PushEvent:CNB 的 Events API 会返回各种事件类型(创建分支、合并 PR 等),我们只关心 PushEvent,因为那才是真正的代码提交。
  3. 404 不算错:某一天没有提交时,CNB 返回 404 而非空数组。这是正常行为,跳过即可。

3.3 日期范围的坑

这里有个容易踩的坑——本周一的计算

now := time.Now()
weekday := int(now.Weekday())
if weekday == 0 { weekday = 7 }  // Go 里周日是 0,我们要转成 7
thisMonday := now.AddDate(0, 0, -(weekday-1)).Truncate(24 * time.Hour)
lastMonday := thisMonday.AddDate(0, 0, -7)
lastSunday := thisMonday.AddDate(0, 0, -1)

Go 的 time.Weekday() 返回周日=0、周一=1...周六=6。但我们的业务逻辑里一周应该从周一开始,所以需要做个转换。这个坑我调试了两次才对,记下来免得你踩。


四、Step 2:AI 生成周报——Prompt 是核心

原始的 commit 数据是这样的:

- init. (a1b2c3d)
- 总纲.md (e4f5g6h)
- 01.md (i7j8k9l)
- W1-个人故事开场.md (m0n1o2p)
- Update cover-w1-juejin.png (q3r4s5t)

直接发给领导肯定不行。我们需要 AI 做几件事:

  1. 合并同类项:同一个功能的多次提交合并成一条
  2. 去噪音:"init."、"fix"、"Update xxx" 这种无意义提交直接忽略
  3. 归类整理:按项目/模块分组
  4. 专业语气:像人写的周报,不像机器吐的日志

Prompt 设计

systemPrompt := `你是一个周报整理助手。把原始代码提交记录整理成简洁、专业的工作周报。

【核心原则】
1. 只基于原始数据归纳,绝对不能编造、推测、猜测
2. 合并同类项:同一功能的多轮调试提交,合并为一条
3. 去噪音:"1"、"fix"、"Update xxx.vue" 直接忽略
4. 删掉所有 Merge 相关的信息

【格式要求】
📊 周报(日期范围)

### 姓名
**项目名**(简要描述)
- 工作项 1
- 工作项 2

💡 建议
- 建议 1(针对本周数据的建设性意见)`

Prompt 设计的几点经验:

  • 强调"不能编造":LLM 很容易"发挥",明明没有的功能它能给你编出来。必须明确约束
  • 给示例:在 Prompt 里给出输入→输出的示例,比纯文字描述有效得多
  • 加建议部分:让 AI 不仅整理周报,还给出改进建议(比如 commit message 太模糊),这样领导看了觉得"还有附加值"

调用 DeepSeek API

func generateReport(cfg *Config, rawData string) (string, error) {
    reqBody := ChatRequest{
        Model: cfg.DeepSeekModel,
        Messages: []ChatMessage{
            {Role: "system", Content: systemPrompt},
            {Role: "user", Content: "以下是本周的代码仓库动态:\n" + rawData},
        },
    }

    jsonBody, _ := json.Marshal(reqBody)
    req, _ := http.NewRequest("POST",
        "https://api.deepseek.com/v1/chat/completions",
        bytes.NewReader(jsonBody))
    req.Header.Set("Authorization", "Bearer "+cfg.DeepSeekAPIKey)
    req.Header.Set("Content-Type", "application/json")

    resp, _ := http.DefaultClient.Do(req)
    // ... 解析返回结果
    return chatResp.Choices[0].Message.Content, nil
}

为什么选 DeepSeek?便宜。同样的任务,DeepSeek 的价格大概是 GPT-4 的 1/10。对于这种每天/每周跑一次的任务,成本几乎可以忽略不计。我这边的实际花费:生成一次周报约 0.01 元


五、Step 3:推送到企业微信

企业微信的群机器人支持 Webhook 方式推送消息,非常简单:

func sendWeChatWorkMarkdown(webhook, markdown string) error {
    msg := WeChatWorkMarkdownMsg{
        MsgType: "markdown",
    }
    msg.Markdown.Content = markdown

    jsonBody, _ := json.Marshal(msg)
    resp, _ := http.Post(webhook, "application/json", bytes.NewReader(jsonBody))
    // ... 检查返回的 errcode
    return nil
}

企业微信支持 Markdown 格式,所以 AI 生成的周报可以直接渲染成带格式的消息:标题加粗、列表缩进、emoji 显示。

💡 如果你用飞书或钉钉,逻辑完全一样,只是 Webhook URL 和消息格式稍有不同。


六、定时执行:每周一自动跑

robfig/cron 库实现定时任务:

func main() {
    loadDotEnv()
    cfg := loadConfig()

    // 支持立即执行模式:daily-report-agent now
    if len(os.Args) > 1 && os.Args[1] == "now" {
        runReport(cfg)
        return
    }

    c := cron.New()
    c.AddFunc(cfg.CronSpec, func() {
        runReport(cfg)
    })
    c.Start()

    log.Printf("🌱 周报 Agent 已启动,定时: %s", cfg.CronSpec)
    select {}  // 阻塞主 goroutine,保持程序运行
}

CRON_SPEC=0 7 * * 1 表示每周一早上 7:00 执行。上班路上,周报已经自己跑到群里了。

💡 如果你习惯周五写周报,可以改成 0 18 * * 5(每周五下午 6:00),但需要注意:当前代码的日期范围是固定取"上周一上周五",周五跑的话只到周四的数据。想覆盖到周五,需要改一下日期计算逻辑,取"本周一本周五"。这是一个简单的改造,欢迎 PR。

另外加了 now 参数支持手动触发,方便调试:

./daily-report-agent now    # 立即执行一次
./daily-report-agent         # 定时模式(阻塞运行)

七、实际效果

说了这么多,看看真实效果。这是企业微信群里收到的周报:

e28c299f7ea062cf7525cc68bac30312.jpg 可以看到:

  • ✅ 日期范围正确
  • ✅ 按人名归类
  • ✅ 提交记录经过 AI 整理,不再是原始的 commit message
  • ✅ 末尾有💡建议部分,指出 commit message 可以更规范

从杂乱的 commit 列表 → 可读的专业周报,全靠中间这层 AI。


八、部署指南:5 分钟上手

前置准备

  1. 一个代码托管平台的账号和 API Token(CNB / GitHub / GitLab 都行)
  2. 一个 DeepSeek API Key(注册就送额度)
  3. 一个企业微信群机器人(群里添加机器人,复制 Webhook URL)

部署步骤

# 1. 克隆项目
git clone https://github.com/lobster-bujiaban/daily-report-agent.git
cd daily-report-agent

# 2. 配置 .env 文件
cp .env.example .env
# 编辑 .env,填入你的 API Key 和 Webhook

# 3. 编译(需要 Go 1.21+)
go build -o daily-report-agent .

测试运行

./daily-report-agent now

看到企业微信群里收到周报,说明一切正常。

长期运行

根据你的服务器系统选择部署方式:

Linux(推荐)

方式一:systemd 服务(最稳定)

创建 /etc/systemd/system/daily-report-agent.service

[Unit]
Description=Daily Report Agent
After=network.target

[Service]
Type=simple
WorkingDirectory=/opt/daily-report-agent
ExecStart=/opt/daily-report-agent/daily-report-agent
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

启动并设置开机自启:

sudo systemctl daemon-reload
sudo systemctl enable daily-report-agent
sudo systemctl start daily-report-agent

# 查看运行状态
sudo systemctl status daily-report-agent

# 查看日志
sudo journalctl -u daily-report-agent -f

方式二:nohup(快速但不推荐生产环境)

nohup ./daily-report-agent > report.log 2>&1 &

方式三:crontab(如果不想用程序内置定时)

不启动程序的 cron 模式,直接用系统 crontab 调用 now 模式:

# 编辑 crontab
crontab -e

# 每周五下午 6 点执行
0 18 * * 5 cd /opt/daily-report-agent && ./daily-report-agent now >> /var/log/report-agent.log 2>&1

Windows

方式一:NSSM 注册为系统服务

# 下载 NSSM: https://nssm.cc/download
nssm install DailyReportAgent "C:\path\to\daily-report-agent.exe"
nssm set DailyReportAgent AppDirectory "C:\path\to"
nssm start DailyReportAgent

方式二:Windows 计划任务

schtasks /create /tn "DailyReportAgent" /tr "C:\path\to\daily-report-agent.exe now" /sc weekly /d FRI /st 18:00

Docker(跨平台通用)

FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o daily-report-agent .

FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/daily-report-agent .
COPY .env .
CMD ["./daily-report-agent"]
docker build -t daily-report-agent .
docker run -d --name report-agent --restart=always daily-report-agent

改造成你自己的

这个项目的架构是通用的,你可以轻松改造:

你想做的改哪里
换代码平台fetchEventsFromCNB 函数,适配 GitHub/GitLab API
换 AI 模型generateReport 的 API 地址和 Key,支持 OpenAI 兼容接口
换推送渠道sendWeChatWorkMarkdown,对接飞书/钉钉/Slack
加更多仓库.envCNB_REPOS 逗号分隔添加即可

九、踩过的坑

写的过程中遇到几个问题,分享给你:

坑 1:CNB API 的 404 问题

某天没有提交记录时,CNB 返回 HTTP 404 而不是空数组。一开始我当错误处理了,导致日志里一堆 WARN。后来发现这是正常行为,改成静默跳过就好。

坑 2:Commit Message 的噪音

真实的 commit message 并不都像教科书一样规范。你会看到 "1"、"fix"、"12"、"update" 这种毫无意义的 message。如果不过滤,AI 生成的周报会很丑。所以在 Prompt 里加了明确的去噪规则。

坑 3:AI 编造内容

第一次跑的时候,AI 居然给我"编"了一个我没做的功能进去。后来在 Prompt 开头加了铁律:「绝对不能编造、推测、猜测」,并要求只基于传入的原始数据。之后就没再出过这个问题。

坑 4:时间计算的边界情况

当前代码默认取"上周一上周五",适合周一早上跑。但如果你改成周五跑,想取"本周一本周五"的数据,日期范围的计算逻辑就需要调整。这是不同执行时间带来的边界差异,改起来不难,但要意识到这个坑。


十、总结与源码

这个项目从想法到跑通,花了大约 一个周末。代码量不大,但它是我副业产线上的第一个"产品"。

它的意义不在于周报本身,而在于验证了一个流程:

数据采集 → AI 处理 → 自动推送

这个流程可以复用到很多场景:监控告警、日报汇总、竞品追踪……周报只是第一个。

📦 源码地址

GitHub - lobster-bujiaban/daily-report-agent

欢迎 Star、提 Issue、Fork 改造。如果你做了有趣的改造,欢迎 PR 或者给我发邮件交流。


写在最后

我是龙虾,一个 8 年程序员,正在用 AI Agent 搭建副业产线。

这不是一篇"教你赚大钱"的文章,这是一个普通程序员从 0 到 1 的实践记录。如果你觉得有用,点个「在看」就是最大的支持。

下周我会写一篇踩坑实录,详细记录做这个 Agent 过程中遇到的 5 个坑和解决方案。关注不迷路 👇


🦞 一只用 AI Agent 搭副业产线的程序员

公众号:虾哥不加班 | B站:龙虾不加班 | 掘金:龙虾不加班