Skip to content

飞书 CLI Agent 工具链 ​

基于自研 lark-cli 搭的飞书 Agent(Daniel / MergeBot):在群聊里用自然语言发起 Git merge、推 Gerrit Review、跑 HCrash 崩溃分析,共 17 类指令。核心不是"远程执行 Git 命令",而是每一步都有权限、路由、状态机、日志和回滚边界。

指令覆盖17 类
权限模型三层
失败处理自动回滚
日报整理30min → 5min

背景 ​

日常研发里有两类高频重复劳动。一类是 merge:人工切分支、清理仓库、执行 merge、处理冲突、推 Gerrit、再挨个通知评审人,大仓合并前还必须把本地状态清干净,漏一步就是事故。另一类是崩溃分析:拿到日志包、解密、定位案发窗口、翻源码行号,全靠手工。

这个 Agent 的目标是把这两类流程收敛到飞书对话里。它同时还是个人知识生产的资料入口——群消息、文档、附件经审计脱敏后沉淀为日报草稿和案例素材,日报整理从 30 分钟级降到约 5 分钟。

问题 ​

问题表现后果
merge 步骤多切分支、clean、merge、解冲突、push、通知评审漏步骤直接污染远端
高风险操作无边界谁都能在群里喊机器人跑 Git权限和分支必须硬控
机器人串台多群多机器人,@错人就乱响应错误上下文里执行危险操作
失败留烂摊子merge 失败本地 target 已偏移下一次合并从脏状态开始
日志分析重解密、定位窗口、查符号全手工一次分析大半天

方案 ​

整体分六个域:飞书事件接入、消息路由、权限与策略、任务队列、Git merge 引擎、卡片回调。FastAPI 只绑定 loopback(127.0.0.1),事件入口快速返回,真正的合并在常驻任务队列里串行执行。

mermaid
flowchart TD
    A["飞书群聊 / 单聊"] --> B["lark-cli 事件消费者"]
    B --> C["FastAPI loopback 服务<br>仅绑定 127.0.0.1"]
    C --> D["消息路由<br>群聊必须 @机器人"]
    D --> E["意图三层安全路由"]
    E --> F["权限与分支策略校验"]
    F --> G["任务队列<br>merge 串行执行"]
    G --> H["MergeEngine<br>专用 clone 仓库"]
    H --> I["Gerrit refs/for/target"]
    E --> J["飞书交互卡片<br>状态 / 冲突 / 审批"]
    J --> C

关键实现 ​

消息路由:先解决串台 ​

单聊直接处理;群聊必须显式 @daniel 或 @MergeBot;消息以其他用户的 @ 开头直接静默忽略——防止机器人在多群里被 @别人 的消息误触发。未 @ 的普通消息不回复、不占用任何队列。

意图三层安全路由 ​

merge 是高风险动作,MVP 阶段的原则是高风险操作先用确定性模型兜住,LLM 只做意图归一:

  1. 第一层:确定性解析。正则和规则直接识别中英文 merge 语法、查询、取消、授权等指令,不经过任何模型。
  2. 第二层:模糊筛选 + LLM 归一。无法识别时,先从完整指令目录按关键词模糊筛选候选,再让模型只返回结构化意图(意图、命令表单、槽位、缺项、置信度)。模型不直接生成可执行命令——可执行命令由本地代码拼装,并必须重新通过确定性解析器。
  3. 第三层:用户确认。高置信度生成确认卡,用户点击或发确认码后才执行;中置信度只追问缺项;低置信度直接回能力导航。确认码绑定当前用户和会话,一次有效。

LLM 在任何一层都不能绕过权限、分支白名单和 Git 安全校验。

三层权限模型 ​

超级管理员 > merge owner > 普通 merge 用户。超级管理员管理 owner;owner 管理 merge 权限、分支策略和流程配置;普通用户只能发起授权范围内的合并。无权限用户发起 merge 时提示去申请,不会自动代申请、更不会轰炸 owner。一个细节:取消某人的普通 merge 权限不会取消其 owner 身份——两个维度独立。

Merge 引擎与失败自动回滚 ​

这是整条链路里最关键的部分。所有 Git 操作只在专用 clone 仓库进行,绝不碰开发工作区。每次 merge 前,source 和 target 都走同一套准备流程:checkout → clean → pull --rebase → reset 到远端 → 再 clean,保证从干净的远端状态开始。失败时的边界:

  • clean / pull / reset 失败:job 进 failed,记录失败命令摘要和日志路径。
  • merge 冲突:记录冲突文件和双方提交者,然后 merge --abort 回到干净状态;冲突卡片支持分页查看、逐文件选择 source/target,所有冲突都有选择才恢复执行,非文本冲突标记需人工处理,不提供危险自动选择。
  • verify 失败:不 push,把 target 重置回远端状态。
  • push Gerrit 失败:同样重置 target,不留本地偏移。

推送固定走 git push --no-thin origin HEAD:refs/for/target,即只进 Gerrit Review,不直接推目标分支。同一 repo + target 有活跃 job 时,新请求返回已有 job 状态,不创建并发合并。

HCrash 综合分析 ​

材料集齐(案发时间、主仓库分支、问题描述、ZIP 日志、Skill)后,固定各仓库到 40 位 commit SHA,进单槽 FIFO 队列。实测一次分析的扫描窗口覆盖 101,779 行日志。模型输入只含 Bug 信息、HCrash 确定性结论、Skill、选中日志的覆盖范围和有限原始证据——不整包投喂日志,也绝不读取源码。首轮结论一产出就释放重型槽位,每张分析单另有独立 5 分钟追问窗口,追问不占队列。

Gerrit 后续处理 ​

merge 成功拿到 Review 链接后,同一张卡片进入 +2 / submit 后续处理区。每个角色可配多个候选人,任一人点击即结算该角色,卡片显示完成者和时间;非候选人点击被拒绝或静默。关键设计:merge job 此时已是终态,Gerrit 后续流程不再占用 target 锁。

指标 ​

指标数据
指令覆盖17 类(HCrash 分析、merge、权限、分支策略、卡片风格、日志解密等)
单次分析扫描窗口101,779 行日志(案发前后对称扫描)
崩溃分析结论验证样例单经证据链复核输出"已证明",置信度 100%
日报整理30 分钟级 → 约 5 分钟
merge 推送方式只进 Gerrit Review(refs/for/),不直推目标分支

复盘 ​

  1. 这类 Agent 的工程难点不在"调 LLM",而在权限、状态机、回滚边界。自然语言只是入口,真正值钱的是每一条指令背后的确定性校验和失败兜底。
  2. LLM 的输出必须落成结构化意图,再过一遍确定性解析器。让模型直接生成 Git 命令等于把生产仓库交给概率。
  3. 串台和越权比"没功能"更可怕。静默忽略、权限提示、确认卡这些"不做的事",设计成本不低于功能本身。
  4. 一个 job 一张卡片。状态实时更新在同一张卡片上,冲突选择、取消、+2/submit 全在卡片里完成,聊天上下文就是操作界面,不需要另开系统。
  5. 资料入口侧的红线不变:飞书资料先过审计脱敏,再进公开站点,user 身份的灵活性必须配更严格的发布边界。

罗子初 · AI 座舱专家 · 8年端侧研发

Lv.1