飞书 CIL-AI 智能助手

飞书 AI 智能助手制作流程文档

飞书 AI 智能助手 — 制作流程文档

基于 Python + Anthropic LLM + lark-cli 构建的全功能飞书 Bot,支持文档操作、消息发送、日历管理、多维表格查询、天气查询等。


一、项目概述

本项目实现了一个飞书 AI 智能助手 Bot,通过飞书消息接收用户指令,调用大语言模型(sc-qwen-modes)进行智能理解,并自动执行飞书相关操作。

核心能力:

  • 创建/阅读/编辑飞书云文档

  • 发送消息(Bot 身份或用户身份)

  • 搜索飞书通讯录用户

  • 查看/创建/搜索日历日程

  • 查询/添加多维表格记录

  • 查询城市实时天气

技术特点:

  • LLM 多轮工具调用循环(最多 5 轮)

  • Bot 身份回复,避免身份混乱

  • 消息去重机制,防止递归回复

  • 多策略容错(SDK + lark-cli 双路径)


二、项目文件说明

项目目录:feishu-bot/

文件说明
bot.py核心文件,包含 Bot 全部逻辑(约 830 行)
start.batWindows 启动脚本
server.py备用 Webhook 服务端(可选)
server.log服务日志

bot.py 代码结构:

代码区域行数说明
导入与配置1-21导入依赖、配置 App ID/Secret、LLM 客户端
工具定义(TOOLS)24-177定义 13 个 Function Calling 工具 Schema
系统提示词(SYSTEM_PROMPT)180-225LLM 行为准则和身份策略
记忆与去重230-235会话记忆管理、防递归机制
run_lark()238-246lark-cli 命令封装(支持 stdin)
execute_tool()249-283工具调度分发
create_doc()286-345创建文档(lark-cli 主路径 + SDK 回退)
read_doc()348-360读取文档内容
update_doc()363-372追加/覆盖文档
search_docs()375-390搜索文档
send_msg()393-456发送消息(Bot/用户双身份)
search_users()459-470搜索用户
get_self()473-479获取当前用户信息
calendar_agenda()482-505查看日程
calendar_create()508-517创建日程
calendar_search()520-540搜索日程
base_query()543-587查询多维表格
base_add_record()590-610添加多维表格记录
query_weather()613-650查询天气(wttr.in API)
extract_token()653-657从 URL 提取文档 token
send_reply()660-681发送回复(SDK Bot 身份)
ai_reply()684-760LLM 多轮对话 + 工具调用核心
process_event()763-791事件处理(过滤去重)
main()794-830主循环(启动 lark-cli event consume)

三、依赖说明

3.1 Python 环境

  • Python 版本:3.7+(推荐 3.13)

  • 操作系统:Windows 11 / macOS / Linux

3.2 Python 包

pip install anthropic lark_oapi
包名用途
anthropicAnthropic SDK,用于调用 LiteLLM 代理的模型
lark_oapi飞书开放平台 Python SDK,用于 Bot 身份发送消息和创建文档

3.3 外部工具 — lark-cli

npm install -g lark-cli

安装后需要授权登录:

lark-cli auth login

lark-cli 负责:

  • 接收飞书消息事件(event consume

  • 文档操作(创建/读取/编辑/搜索)

  • 用户搜索

  • 日历管理

  • 多维表格操作

3.4 飞书开放平台

需要在飞书开放平台创建一个企业自建应用,获取:

  • App ID

  • App Secret

  • 配置权限:

    • im:message — 接收和发送消息

    • im:message:send_as_bot — Bot 身份发消息

    • docx:document — 文档读写

    • calendar:calendar — 日历读写

    • contact:user:readonly — 通讯录只读

    • drive:file — 云空间文件操作

3.5 LLM 服务

  • 模型

  • 代理地址

  • API Key

3.6 天气 API

  • APIwttr.in(免费,无需注册)

  • 方式:Python 标准库 urllib,无额外依赖


四、创建流程

步骤 1:环境准备

cmd

# 1. 安装 Python 3.7+
# 2. 安装 Node.js 及 npm
# 3. 安装 Python 依赖
pip install anthropic lark_oapi
​
# 4. 安装并登录 lark-cli
npm install -g lark-cli
lark-cli auth login

步骤 2:创建飞书应用

  1. 打开 飞书开放平台

  2. 创建企业自建应用

  3. 获取 App ID 和 App Secret

  4. 配置应用权限(见上文权限列表)

  5. 发布应用并获取审批

  6. 将 Bot 添加到需要使用的群聊中

步骤 3:拉取代码

bot.py 放入 feishu-bot/ 目录,修改其中的配置项:

# ============ 配置 ============
APP_ID = "你的 App ID"
APP_SECRET = "你的 App Secret"
LARK_CLI = r"lark-cli 的安装路径"
LLM = Anthropic(base_url="你的 LLM 代理地址", api_key="你的 API Key")
MODEL = "你的模型名"

步骤 4:启动 Bot

cd feishu-bot
python bot.py

启动后输出:

飞书 AI Bot 
工具: 创建/阅读/编辑文档、搜索、发消息、搜用户
按 Ctrl+C 停止
​
[daemon] [event] listening for events (key=im.message.receive_v1)

此时在飞书中向 Bot 发消息即可与之对话。

步骤 5:验证功能

在飞书中向 Bot 发送以下测试指令:

测试指令预期结果
"你好"Bot 回复自我介绍
"帮我创建一个测试文档,标题叫 Hello,内容写你好世界"创建云文档并返回链接
"搜索文档 Hello"返回搜索结果
"今天有什么日程"返回今日日程列表
"帮我查一下北京天气"返回北京实时天气和未来预报
"搜索用户 张三"返回用户信息和 open_id

五、核心架构

飞书用户 → 飞书服务器 → lark-cli event consume → bot.py
                                                        ↓
                                                  process_event()
                                                  (过滤去重)
                                                        ↓
                                                  ai_reply()
                                                  (LLM 多轮循环)
                                                        ↓
                                              ┌─ 文本回复 ─→ send_reply()
                                              │                 ↓
                                              │           飞书 SDK API
                                              │                 ↓
                                              └─ 工具调用 ─→ execute_tool()
                                                              ↓
                                                     run_lark() / SDK
                                                              ↓
                                                         飞书服务器

LLM 工具调用流程:

  1. 用户消息发送到 LLM,附带 13 个工具定义

  2. LLM 判断是否需要调用工具

  3. 如需调用,返回 tool_use 块,bot 执行对应 Python 函数

  4. 工具结果返回给 LLM,LLM 判断是否继续调用(最多 5 轮)

  5. 最终 LLM 生成文本回复,返回给用户

防递归机制(三层过滤):

  1. sender_id 匹配 — 跳过 Bot 自己的消息

  2. message_id 匹配 — 跳过刚发送的消息 ID

  3. content 匹配 — 内容去重兜底

身份策略:

  • 回复消息:SDK app_id + app_secrettenant_access_token → Bot 身份

  • 文档操作:lark-cli --as user → 使用用户 OAuth token(权限更全)

  • 发送消息:默认 Bot 身份(SDK),用户明确要求时用 --as user


六、踩坑记录

问题原因解决方案
文档创建失败lark-cli --content 要求相对路径,tempfile 生成的是绝对路径改用 stdin 传入内容:--content -
SDK 创建文档权限不足Bot 应用无 docx:document:create 权限主路径改用 lark-cli --as user,SDK 作为回退
Bot 回复显示为用户身份lark-cli --as bot 子进程与 daemon 冲突改用 SDK 直接发消息
同时收到两条回复多个 bot.py 进程同时运行确保只运行一个实例,旧进程 kill 掉
AI 无回复或空回复ThinkingBlock 类型混入文本块过滤非 text 类型的 content block

七、扩展指南

要添加新的能力(如天气查询),只需三步:

  1. TOOLS 数组中添加工具定义 Schema

  2. 编写对应的 Python 函数

  3. execute_tool() 中添加 elif 分支

天气查询扩展示例

# 1. 工具定义
{
    "name": "feishu_query_weather",
    "description": "查询指定城市的实时天气和未来几天预报。",
    "input_schema": {
        "type": "object",
        "properties": {
            "city": {"type": "string", "description": "城市名称,支持中文或英文"},
        },
        "required": ["city"],
    },
},
​
# 2. Python 函数
def query_weather(city: str) -> str:
    encoded = urllib.parse.quote(city)
    url = f"https://wttr.in/{encoded}?format=j1"
    # ... HTTP 请求与解析 ...
​
# 3. 调度分发
elif name == "feishu_query_weather":
    return query_weather(args["city"])

八、代码优化分析

8.1 bot.py 优化建议

序号位置问题建议
1第 4 行import textwrap 未使用可移除
2第 4 行import tempfile 未使用(已改用 stdin 方案)可移除
3第 4 行import os 未使用可移除
4第 653 行extract_token() 内重复 import re(顶部第 4 行已导入)移除内部 import
5第 14-17 行App Secret 和 API Key 硬编码在代码中改为 os.environ.get() 读取环境变量,避免将密钥提交到 git
6第 482-505 行calendar_agenda 返回数据可能是 listdict,用 isinstance 判断逻辑正确但可统一为 dict 处理
7全局单一文件 833 行,随着功能增多会越来越难以维护后续可将工具函数拆分到独立模块(如 tools.py

8.2 server.py 分析

项目说明
定位备用的 Flask Webhook 方案,通过飞书开放平台事件订阅接收消息
依赖lark_oapi 外还需 flaskpycryptodomepyngrok
启动方式python server.py --port 5000 --ngrok 或双击 start.bat
与 bot.py 的区别bot.py 通过 lark-cli event consume 长连接接收消息,无需公网 URL;server.py 需要公网 URL(ngrok)接收飞书回调
当前状态简易 echo 回复,无 LLM 集成,功能远弱于 bot.py
建议如主用 bot.py,server.py 可保留作为备份方案;如需使用需补充 pip install flask pycryptodome pyngrok

8.3 start.bat 分析

项目说明
定位Windows 启动脚本,仅用于启动 server.py
问题Encrypt Key 和 Verification Token 为空,需手动填写
建议如需启动 bot.py,应使用以下命令:python bot.py(无需 ngrok)

九、完整代码文件

9.1 bot.py — 核心智能体

此文件约 833 行,包含以下完整代码:

"""
飞书 AI Bot — 支持飞书文档、消息等全功能控制
"""
import sys, json, subprocess, threading, textwrap, re, os, tempfile, urllib.request, urllib.parse
from collections import deque
from anthropic import Anthropic
import lark_oapi as lark
from lark_oapi.api.im.v1 import CreateMessageRequest, CreateMessageRequestBody
from lark_oapi.api.docx.v1 import CreateDocumentRequest, CreateDocumentRequestBody
​
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
​
# ============ 配置 ============
APP_ID = ""
APP_SECRET = ""
LARK_CLI = r""
LLM = Anthropic(base_url="", api_key="")
MODEL = ""
​
# SDK 客户端
sdk_client = lark.Client.builder().app_id(APP_ID).app_secret(APP_SECRET).build()

工具定义 (TOOLS) — 13 个 Function Calling 工具:

  • feishu_create_doc — 创建云文档

  • feishu_read_doc — 读取文档

  • feishu_update_doc — 追加/覆盖文档

  • feishu_search_docs — 搜索文档

  • feishu_send_message — 发送消息

  • feishu_search_users — 搜索用户

  • feishu_calendar_agenda — 查看日程

  • feishu_calendar_create — 创建日程

  • feishu_calendar_search — 搜索日程

  • feishu_base_query — 查询多维表格

  • feishu_base_add_record — 添加多维表格记录

  • feishu_get_current_user — 获取当前用户

  • feishu_query_weather — 查询天气

核心函数列表:

  • run_lark() — lark-cli 命令封装(支持 stdin)

  • execute_tool() — 工具调度分发

  • create_doc() / read_doc() / update_doc() / search_docs() — 文档操作

  • send_msg() / search_users() / get_self() — 消息和用户

  • calendar_agenda() / calendar_create() / calendar_search() — 日历管理

  • base_query() / base_add_record() — 多维表格

  • query_weather() — 天气查询

  • send_reply() — Bot 身份回复

  • ai_reply() — LLM 多轮工具调用核心(最多 5 轮)

  • process_event() — 事件处理与防递归过滤

  • main() — 主循环

完整代码请参见实际项目文件 feishu-bot/bot.py


9.2 server.py — 备用 Webhook 服务端

"""
飞书 Bot 服务端 — 接收并回复飞书消息
​
需要配置:
  1. 飞书开放平台 → 应用 → 事件订阅 → 配置回调地址
  2. 设置 Encrypt Key(加密密钥)
  3. 订阅 im.message.receive_v1 事件
  4. 启动 ngrok 获取公网 URL
​
启动方式:
  python server.py --port 5000
"""
import sys
import os
import json
import hashlib
import base64
import argparse
from flask import Flask, request, jsonify
from lark_oapi.api.im.v1 import CreateMessageRequest, CreateMessageRequestBody
import lark_oapi as lark
​
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
​
app = Flask(__name__)
​
# ============ 飞书应用凭据 ============
APP_ID = os.environ.get("FEISHU_APP_ID", "")
APP_SECRET = os.environ.get("FEISHU_APP_SECRET", "")
VERIFICATION_TOKEN = os.environ.get("FEISHU_VERIFICATION_TOKEN", "")
ENCRYPT_KEY = os.environ.get("FEISHU_ENCRYPT_KEY", "")
​
# ============ 飞书客户端 ============
client = lark.Client.builder() \
    .app_id(APP_ID) \
    .app_secret(APP_SECRET) \
    .build()
​
​
def decrypt_event(encrypt_key: str, encrypted: str) -> dict:
    """解密飞书事件推送 — 需要 pip install pycryptodome"""
    from Crypto.Cipher import AES
​
    key = hashlib.sha256(encrypt_key.encode()).digest()
    raw = base64.b64decode(encrypted)
    iv = raw[:16]
    ciphertext = raw[16:]
​
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    plaintext = cipher.decrypt(ciphertext)
​
    pad_len = plaintext[-1]
    plaintext = plaintext[:-pad_len]
​
    return json.loads(plaintext.decode("utf-8"))
​
​
def send_text_reply(open_id: str, text: str):
    """发送文本回复 — 使用 SDK Bot 身份"""
    req = CreateMessageRequest.builder() \
        .receive_id_type("open_id") \
        .request_body(CreateMessageRequestBody.builder()
            .receive_id(open_id)
            .msg_type("text")
            .content(json.dumps({"text": text}))
            .build()) \
        .build()
    return client.im.v1.message.create(req)
​
​
def handle_message(event: dict):
    """处理收到的消息 — echo 示例"""
    msg_type = event.get("message", {}).get("message_type", "")
    sender = event.get("sender", {}).get("sender_id", {})
    sender_id = sender.get("open_id", "")
​
    if msg_type != "text":
        return
​
    content_str = event.get("message", {}).get("content", "{}")
    try:
        content = json.loads(content_str)
        text = content.get("text", "")
    except json.JSONDecodeError:
        print(f"[忽略] 无法解析消息内容: {content_str}", flush=True)
        return
​
    print(f"[收到] {sender_id}: {text}", flush=True)
​
    # ----------------- 回复逻辑 -----------------
    if text.strip().lower() in ("你好", "hello", "hi"):
        reply = f"你好!我是你的飞书 CLI 助手,有什么可以帮你的?"
    elif text.strip().lower() in ("帮助", "help"):
        reply = "我能帮你:\n- 处理飞书文档\n- 发送消息\n- 查询信息\n\n直接跟我说你的需求即可!"
    else:
        reply = f"收到你的消息:「{text}」\n\n这是一个自动回复。"
​
    result = send_text_reply(sender_id, reply)
    if result.success():
        print(f"[回复] -> {sender_id}: {reply}", flush=True)
    else:
        print(f"[回复失败] {result.code}: {result.msg}", flush=True)
​
​
@app.route("/", methods=["GET"])
def health():
    """健康检查"""
    return "Feishu Bot Server is running"
​
​
@app.route("/webhook", methods=["POST"])
def webhook():
    """飞书事件回调入口"""
    body = request.get_json(force=True, silent=True) or {}
​
    # 1. URL 验证
    if "challenge" in body and "token" in body:
        token = body["token"]
        challenge = body["challenge"]
        encrypt_type = body.get("type", "")
​
        if encrypt_type and ENCRYPT_KEY:
            try:
                decrypted = decrypt_event(ENCRYPT_KEY, challenge)
                challenge = decrypted.get("challenge", challenge)
            except Exception as e:
                print(f"[验证失败] 解密错误: {e}", flush=True)
                return jsonify({"code": 1, "msg": "decrypt failed"}), 400
​
        if VERIFICATION_TOKEN and token != VERIFICATION_TOKEN:
            return jsonify({"code": 1, "msg": "token mismatch"}), 400
​
        return jsonify({"challenge": challenge})
​
    # 2. 加密事件
    if "encrypt" in body:
        if not ENCRYPT_KEY:
            print("[错误] 收到加密事件但 ENCRYPT_KEY 未配置", flush=True)
            return jsonify({"code": 1, "msg": "encrypt key not configured"}), 500
        try:
            event_data = decrypt_event(ENCRYPT_KEY, body["encrypt"])
        except Exception as e:
            print(f"[错误] 解密事件失败: {e}", flush=True)
            return jsonify({"code": 1, "msg": "decrypt failed"}), 400
        body = event_data
​
    # 3. 处理事件
    event_type = body.get("header", {}).get("event_type", "")
    event = body.get("event", {})
​
    if event_type == "im.message.receive_v1":
        handle_message(event)
​
    return jsonify({"code": 0})
​
​
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--port", type=int, default=5000, help="服务端口 (默认 5000)")
    parser.add_argument("--ngrok", action="store_true", help="自动启动 ngrok 隧道")
    args = parser.parse_args()
​
    port = args.port
    public_url = None
​
    if args.ngrok:
        try:
            from pyngrok import ngrok
            tunnel = ngrok.connect(port, "http")
            public_url = tunnel.public_url
            print(f"[ngrok] 公网地址: {public_url}/webhook")
        except Exception as e:
            print(f"[ngrok] 启动失败: {e}")
​
    if not public_url and not args.ngrok:
        print("提示: 使用 --ngrok 自动获取公网 URL,或手动配置反向代理")
        print(f"本地地址: http://localhost:{port}/webhook")
​
    print(f"\n启动服务: http://0.0.0.0:{port}")
    print("按 Ctrl+C 停止\n")
​
    app.run(host="0.0.0.0", port=port, debug=True)

9.3 start.bat — Windows 启动脚本

@echo off
chcp 65001 >nul
cd /d "%~dp0"
​
:: ============ 配置区域 ============
:: 从飞书开放平台复制: 应用 → 事件订阅 → Encrypt Key
set FEISHU_ENCRYPT_KEY=
​
:: 从飞书开放平台复制: 应用 → 事件订阅 → Verification Token
set FEISHU_VERIFICATION_TOKEN=
:: =================================
​
if "%FEISHU_ENCRYPT_KEY%"=="" (
    echo [警告] 未设置 FEISHU_ENCRYPT_KEY,事件解密将失败
    echo 请编辑 start.bat,设置正确的 Encrypt Key
)
​
echo ========================================
echo   飞书 Bot 服务端启动
echo ========================================
echo.
​
python server.py --port 5000 --ngrok
​
pause

注意: 此脚本仅启动 server.py(Webhook 模式)。如需启动 bot.py(lark-cli 长连接模式),直接在终端运行 python bot.py 即可。


十、两种运行方案对比

特性bot.py(主方案)server.py(备用方案)
消息接收方式lark-cli event consume 长连接飞书开放平台 HTTP 回调
是否需要公网 URL是(需 ngrok 或反向代理)
LLM 智能回复是()否(规则匹配 echo)
工具调用13 个飞书操作工具
依赖数量anthropic + lark_oapiflask + pycryptodome + pyngrok + lark_oapi
启动命令python bot.pypython server.py --port 5000 --ngrok
推荐场景日常使用备份 / 需自定义 Webhook 时
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值