1. 项目缘起:一个“外行”的痛点与野心

去年年底,我接手了一个听起来有点“跨界”的任务:为一家拥有几十个末端网点的快递公司,搭建一套能主动预警安全风险的管理系统。我不是程序员,我的背景是物流运营和流程优化。过去,我们依赖的是人工巡检、纸质记录和零散的微信群汇报。问题显而易见:信息滞后、标准不一、隐患发现全靠运气。一个网点的灭火器过期了,可能要到总部季度检查时才会被发现;监控摄像头离线了,可能几天都没人知道。

传统的解决方案是找软件公司定制开发,但动辄几十万的报价和漫长的开发周期,让我们这种注重实效的中小企业望而却步。更重要的是,定制系统往往僵化,业务规则一变,系统就得改,沟通成本和金钱成本都太高。就在我为此头疼时,“AI Agent”这个概念频繁地出现在我的视野里。它被描述为能理解目标、自主调用工具去完成任务的智能体。这让我灵光一现:我需要的,不正是一个不知疲倦、能7x24小时按我设定的规则,去主动“巡检”各个网点数据、发现异常并通知我的“智能助理”吗?

我的野心很简单:不写一行复杂的业务代码,用现成的、低门槛的工具,拼装出一个能实际跑起来的AI驱动安全管理系统。核心目标有三个:第一, 自动监控 ,将分散在各网点的设备状态、安检记录数字化并集中监控;第二, 智能预警 ,不是简单罗列数据,而是能像经验丰富的安全员一样,判断哪些情况组合在一起构成风险,并主动告警;第三, 低成本与可进化 ,整套系统的构建和维护成本要低,并且当业务规则变化时,我能自己快速调整,而不必求助于开发人员。

这条路,一个非程序员能走通吗?我用三个月的时间,从零开始,搭起了一套覆盖几十个网点的系统。下面,我就把这趟“踩坑”与“惊喜”并存的落地实录,毫无保留地分享出来。

2. 技术选型:为什么是“WorkBuddy + Dify + Flask + SQLite”这套组合拳?

面对琳琅满目的技术名词,我的首要原则是: “非程序员友好” 。这意味着工具必须有图形化界面、文档清晰、社区活跃,并且能让我用“配置”和“拼接”代替“编码”。经过大量对比和试错,我锁定了最终的技术栈: WorkBuddy作为AI智能体核心,Dify作为工作流与知识库平台,Flask搭建轻量级数据接口,SQLite作为嵌入式数据库

2.1 核心大脑:WorkBuddy——开箱即用的AI智能体框架

在众多AI Agent框架中,我选择WorkBuddy,主要基于以下几点考量:

第一,理念契合“非程序员” 。WorkBuddy的宣传语就是“为每个人打造的AI伙伴”。它提供了一个清晰的“技能(Skill)”市场。我不需要理解背后大语言模型(LLM)复杂的微调或提示工程,只需要像在应用商店下载APP一样,找到我需要的“安全检查”、“报表分析”、“数据查询”等技能,安装并授权即可。这极大地降低了使用门槛。

第二,核心功能解耦清晰 。WorkBuddy的架构分为“大脑”(推理决策)和“手脚”(技能执行)。我的工作重点是告诉“大脑”目标(例如:“每日上午10点检查所有网点的消防设备状态”),并为它配备好“手脚”(即连接到我数据库的查询技能、发送邮件的通知技能)。这种分工让我只需关注业务逻辑的组装,而非底层实现。

第三,本地化部署与数据安全 。快递网点的数据,如监控地址、负责人联系方式、安检记录,都属于敏感信息。WorkBuddy支持本地部署,所有数据在自己的服务器上闭环,避免了第三方SaaS服务的数据隐私风险。这对于企业级应用是底线要求。

注意 :WorkBuddy和另一个常被提及的CodeBuddy有本质区别。CodeBuddy更偏向于辅助程序员写代码,而WorkBuddy是面向最终业务场景的智能体构建平台。对于我这个不写代码的运营人员来说,WorkBuddy是唯一正确的选择。

2.2 流程编排与知识库:Dify——可视化的工作流引擎

仅有智能体还不够,复杂的业务逻辑需要被编排成可重复、可调试的流程。这就是Dify的用武之地。

Dify的核心价值在于“可视化工作流” 。我可以在画布上通过拖拽节点的方式,构建一个完整的处理链路。例如,一个“安全风险巡检”工作流可以这样设计:

  1. 开始节点 :由定时器或API调用触发。
  2. 知识库检索节点 :从Dify关联的知识库中,获取最新的“安全风险判定规则”(如:灭火器压力低于X、监控离线超过Y小时、同一周内发生Z起包裹破损等)。
  3. LLM推理节点 :将规则和从Flask接口获取的实时网点数据,一起提交给LLM(如GPT-4或本地部署的模型),让LLM判断是否存在风险及风险等级。
  4. 条件判断节点 :根据风险等级,决定流程分支。
  5. 工具调用节点 :高风险则调用WorkBuddy的“钉钉群预警”技能;中风险则调用“邮件通知负责人”技能;低风险则生成日志存入数据库。

整个过程无需编写任何流程控制代码,通过图形化界面就能完成,并且可以随时回看执行日志,排查问题。此外,Dify的 知识库功能 让我能把厚厚的安全手册、应急预案文档上传,转化为智能体可以理解和引用的知识,让预警判断更有依据。

2.3 数据桥梁:Flask——极简的Python Web框架

我的数据源在哪里?一部分在总部旧的MySQL数据库里,更多的是各个网点通过Excel表格每周上报的数据。我需要一个中间层,将这些异构数据源统一成标准的API接口,供Dify工作流和WorkBuddy技能调用。

选择Flask的原因只有一个: 简单、快速 。作为一个微型框架,它学习曲线平缓。我通过一些在线教程,学会了用Flask创建几个关键接口:

  • GET /api/sites :获取所有网点基本信息。
  • GET /api/equipment_status?site_id=xxx :获取指定网点的设备实时状态(通过对接设备厂商的API或轮询数据库获得)。
  • POST /api/inspection_record :接收网点上传的每日安检记录。
  • GET /api/risk_indicators :提供用于风险判定的综合指标数据。

我不需要开发复杂的前端页面,Flask只负责提供纯净的JSON数据。它的轻量特性使得这个数据桥梁服务可以轻松地运行在低配置的服务器上,非常稳定。

2.4 数据存储:SQLite——轻量且自包含的数据库

对于这个项目,我没有选择MySQL或PostgreSQL这类需要独立服务管理的数据库,而是选择了SQLite。

SQLite的优势完美匹配项目初期需求

  1. 零配置 :无需安装数据库服务器,一个 .db 文件就是整个数据库。部署时直接拷贝文件即可,极度简化。
  2. 单机性能足够 :我们几十个网点的数据量,每天万级别的记录,SQLite的性能完全绰绰有余,读写速度非常快。
  3. 开发调试便捷 :配合 DB Browser for SQLite 这个图形化工具,我可以像操作Excel一样查看、修改表结构和数据,对于非程序员来说直观友好。需要执行复杂查询或数据恢复时(比如误删除),也能通过这个工具方便地操作。
  4. 成本为零 :完全免费,没有授权费用。

我使用SQLite存储了网点档案、设备清单、每日巡检记录、系统告警日志等核心数据。它的简洁性让整个系统的数据层变得非常可控。

这套“WorkBuddy(大脑与手脚) + Dify(流程与知识) + Flask(数据桥梁) + SQLite(数据仓库)”的组合,就像一套高乐积木,每个部件都简单、专注,通过清晰的接口拼装在一起,最终形成了一个功能完整的有机体。

3. 实战搭建:从零到一的详细步骤与核心配置

理论说再多,不如动手做一遍。接下来,我详细拆解从环境准备到第一个智能预警生效的全过程。请跟随我的步骤,你可以完全复现。

3.1 基础环境准备:Python与依赖管理

我的服务器是一台普通的CentOS 7云主机。第一步是搭建Python环境。

# 1. 安装Python 3.8+ 和 pip
yum install python3 python3-pip -y

# 2. 创建虚拟环境,隔离项目依赖
python3 -m venv /opt/venv
source /opt/venv/bin/activate

# 3. 安装核心Python包
pip install flask flask-cors  # Flask及跨域支持
pip install requests          # 用于调用外部API
pip install schedule          # 简易定时任务库(用于一些简单的后台轮询)

对于SQLite,系统通常已内置,无需额外安装。重点在于安装 DB Browser for SQLite 中文版 到你的办公电脑上,用于管理数据库。你可以从其官网下载安装包,图形化界面非常容易上手,创建表、导入导出CSV数据、执行SQL语句都能轻松完成。

3.2 构建数据层:设计SQLite数据库与Flask接口

数据库设计是整个系统的基石。我的核心表结构如下:

-- 网点信息表
CREATE TABLE delivery_sites (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    site_code TEXT UNIQUE NOT NULL, -- 网点编码
    site_name TEXT NOT NULL,        -- 网点名称
    manager_phone TEXT,             -- 负责人电话
    manager_email TEXT,             -- 负责人邮箱
    region TEXT                     -- 所属区域
);

-- 安全设备表
CREATE TABLE safety_equipment (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    site_id INTEGER NOT NULL,
    equipment_type TEXT NOT NULL, -- 如:灭火器、监控摄像头、烟感器
    equipment_id TEXT NOT NULL,   -- 设备唯一标识
    status TEXT DEFAULT 'normal', -- normal, warning, offline
    last_check_time DATETIME,
    FOREIGN KEY (site_id) REFERENCES delivery_sites(id)
);

-- 每日巡检记录表
CREATE TABLE daily_inspections (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    site_id INTEGER NOT NULL,
    inspection_date DATE NOT NULL,
    inspector_name TEXT,
    fire_extinguisher_ok BOOLEAN, -- 灭火器状态
    monitor_ok BOOLEAN,           -- 监控状态
    electric_ok BOOLEAN,          -- 用电安全
    notes TEXT,                   -- 备注
    FOREIGN KEY (site_id) REFERENCES delivery_sites(id)
);

-- 系统告警日志表
CREATE TABLE alert_logs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    alert_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    site_id INTEGER NOT NULL,
    alert_level TEXT, -- critical, warning, info
    alert_content TEXT,
    handled BOOLEAN DEFAULT 0,
    handled_notes TEXT,
    FOREIGN KEY (site_id) REFERENCES delivery_sites(id)
);

使用DB Browser for SQLite创建好数据库文件 safety.db 后,开始编写Flask应用 app.py

from flask import Flask, request, jsonify, g
import sqlite3
import os

app = Flask(__name__)
DATABASE = '/path/to/your/safety.db'

def get_db():
    """获取数据库连接"""
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)
        # 设置返回字典格式的行
        db.row_factory = sqlite3.Row
    return db

@app.teardown_appcontext
def close_connection(exception):
    """请求结束后关闭数据库连接"""
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

@app.route('/api/sites', methods=['GET'])
def get_all_sites():
    """获取所有网点信息"""
    db = get_db()
    cursor = db.execute('SELECT * FROM delivery_sites')
    sites = cursor.fetchall()
    return jsonify([dict(site) for site in sites])

@app.route('/api/equipment_status', methods=['GET'])
def get_equipment_status():
    """根据网点ID查询设备状态"""
    site_id = request.args.get('site_id')
    if not site_id:
        return jsonify({'error': 'Missing site_id parameter'}), 400

    db = get_db()
    cursor = db.execute('''
        SELECT equipment_type, equipment_id, status, last_check_time 
        FROM safety_equipment 
        WHERE site_id = ? AND status != 'normal'
    ''', (site_id,))
    abnormal_equipments = cursor.fetchall()
    return jsonify([dict(eq) for eq in abnormal_equipments])

@app.route('/api/risk_indicators', methods=['GET'])
def get_risk_indicators():
    """获取综合风险指标:过去3天有设备异常的网点,且当日无合格巡检记录"""
    db = get_db()
    # 这是一个稍复杂的查询,展示了SQLite的能力
    cursor = db.execute('''
        SELECT 
            ds.id as site_id,
            ds.site_name,
            COUNT(DISTINCT CASE WHEN se.status != 'normal' THEN se.id END) as abnormal_equipment_count,
            MAX(CASE WHEN di.inspection_date = DATE('now') AND di.fire_extinguisher_ok = 1 AND di.monitor_ok = 1 THEN 1 ELSE 0 END) as today_inspection_ok
        FROM delivery_sites ds
        LEFT JOIN safety_equipment se ON ds.id = se.site_id AND se.last_check_time >= DATETIME('now', '-3 days')
        LEFT JOIN daily_inspections di ON ds.id = di.site_id AND di.inspection_date = DATE('now')
        GROUP BY ds.id, ds.site_name
        HAVING abnormal_equipment_count > 0 AND today_inspection_ok = 0
    ''')
    risks = cursor.fetchall()
    return jsonify([dict(risk) for risk in risks])

if __name__ == '__main__':
    # 生产环境请使用Gunicorn等WSGI服务器
    app.run(host='0.0.0.0', port=5000, debug=True)

这个Flask应用提供了最关键的几个数据接口。运行后,通过 http://你的服务器IP:5000/api/risk_indicators 就能获取到初步的风险网点列表。

3.3 部署与配置Dify:构建智能工作流

我选择了Dify的Docker-Compose方式进行本地部署,这是官方推荐的最简单方式。

# 1. 克隆Dify代码
git clone https://github.com/langgenius/dify.git
cd dify

# 2. 复制环境变量配置文件并修改
cp .env.example .env
# 使用编辑器修改 .env 文件,关键配置如下:
# OPENAI_API_KEY=sk-xxx # 如果你使用OpenAI的模型
# 或者配置本地模型,如Ollama
# MODE=local
# LOCAL_MODEL_PROVIDER=ollama
# OLLAMA_BASE_URL=http://host.docker.internal:11434
# 设置数据库密码等

# 3. 启动Dify
docker-compose up -d

访问 http://你的服务器IP:3000 即可进入Dify控制台。接下来是关键的工作流创建:

  1. 创建知识库 :在“知识库”模块,上传公司《安全生产管理规范》、《应急预案》等PDF和Word文档。Dify会自动进行切片、向量化处理。我将这个知识库命名为“安全规则库”。
  2. 创建工作流
    • 从“工作流”模块点击“创建”。
    • 拖入一个**“HTTP请求”节点**,配置它调用我们刚写好的Flask接口 GET /api/risk_indicators ,获取原始风险数据。
    • 拖入一个**“知识库检索”节点**,关联“安全规则库”,并设置检索query为“如何判定网点风险等级?”。
    • 拖入一个**“LLM”节点**(我配置为GPT-4)。将前两个节点的输出作为其输入,并编写提示词(Prompt):
      你是一个快递安全专家。请根据以下知识库中的规则,分析提供的网点数据,判断其风险等级(critical-严重, warning-警告, info-提示),并给出简要原因。
      知识库规则:{{knowledge}}。
      网点数据:{{risk_data}}。
      请以JSON格式输出,包含字段:site_id, site_name, risk_level, reason。
      
    • 拖入**“条件判断”节点**,根据LLM输出的 risk_level 字段进行分支。
    • 在每个分支后,拖入**“HTTP请求”节点**,用于触发后续动作(如调用WorkBuddy的Webhook技能)。例如,critical分支可以调用一个发送钉钉群高危告警的接口。

这个工作流实现了“获取数据 -> 结合规则库分析 -> 智能判断 -> 分级触发”的完整逻辑。在Dify中,你还可以方便地设置定时触发器,让这个工作流每天自动执行多次。

3.4 集成WorkBuddy:让智能体拥有“手脚”

WorkBuddy的部署同样推荐使用Docker。部署成功后,其管理界面通常运行在 http://你的服务器IP:7860

  1. 安装核心技能 :在WorkBuddy的技能市场,我安装了“HTTP请求器”技能(用于调用外部API)和“邮件发送器”技能。对于更复杂的通知,我额外部署了一个简单的“钉钉机器人Webhook”自定义技能。
  2. 配置技能参数 :在“HTTP请求器”技能中,我配置了我们的Flask API地址和认证信息(如果需要)。在“邮件发送器”中,配置了公司的SMTP服务器和发件邮箱。
  3. 创建智能体与任务
    • 创建一个名为“安全巡检官”的智能体。
    • 为其添加“HTTP请求器”和“邮件发送器”技能。
    • 创建一个定时任务,内容为:“调用HTTP请求器,访问Dify工作流的触发Webhook URL”。这样,WorkBuddy就成为了一个准时的“发令员”,定期去启动Dify的复杂分析流程。
    • 同时,创建另一个由Dify调用的任务:“当收到高风险告警时,调用邮件发送器技能,将告警详情发送给对应区域经理和总部安全负责人”。

至此,整个链路就打通了: WorkBuddy定时触发 -> Dify工作流执行复杂分析与决策 -> Dify根据决策结果,回调WorkBuddy执行具体的通知动作 。Flask和SQLite作为可靠的数据支撑层,贯穿始终。

4. 核心挑战与解决方案:非程序员视角下的“坑”与“桥”

搭建过程并非一帆风顺,以下几个问题是我遇到的核心挑战,相信也是很多非技术背景的尝试者会遇到的。

4.1 数据格式的“鸡同鸭讲”:API对接的标准化

最初,我的Flask接口返回的数据格式比较随意,而Dify的HTTP节点和WorkBuddy的技能对输入输出有特定要求。经常出现“调不通”的情况。

解决方案 :建立严格的接口契约。

  1. 统一响应格式 :所有Flask API统一返回 {“code”: 200, “msg”: “success”, “data”: {}} 的格式。错误时返回相应的code和msg。
  2. 使用JSON Schema进行校验 :虽然我没写复杂的代码,但我用在线JSON Schema生成工具,为每个主要API的响应生成了一个Schema描述文档。在Dify和WorkBuddy配置HTTP节点时,参考这个文档来解析数据路径。例如,在Dify中配置从响应中提取数据时,路径明确写为 {{#context.data.risk_indicators}}
  3. 善用“调试”功能 :Dify和WorkBuddy都提供了工作流或任务执行的详细日志。每次对接新接口,我都先单独测试HTTP节点,查看原始返回数据,再一步步配置后续节点的变量引用。这个过程虽然繁琐,但能从根本上理解数据流。

4.2 智能体“犯傻”:LLM判断的稳定性与幻觉

在初期测试中,LLM节点有时会“胡言乱语”,比如把明显的低风险判为高风险,或者给出的原因与规则库完全不符。

解决方案 :优化提示词与引入“校验层”。

  1. 结构化输出与严格指令 :在给LLM的提示词中,我强制要求它必须以指定JSON格式输出,并明确每个字段的含义和可选值。例如: risk_level 必须是 [‘critical‘, ‘warning‘, ‘info‘] 中的一个。这大大减少了自由发挥导致的格式错误。
  2. 提供少量示例(Few-Shot) :在提示词中,我会加入1-2个判断示例。
    示例1:
    数据:{网点A, 有1个监控离线超过24小时, 今日已巡检且合格}
    规则:单一非关键设备短时离线,且当日巡检合格,为info级。
    输出:{“risk_level”: “info“, “reason”: “监控短时离线,但当日巡检合格,风险可控。“}
    
  3. 在Dify工作流中增加“规则校验”节点 :在LLM节点之后,我增加了一个“代码执行”节点(Dify支持运行少量Python代码)。这个节点的作用是:用硬编码的逻辑对LLM的输出进行二次校验。例如,如果数据中显示所有设备正常且巡检合格,但LLM却输出了 critical ,那么校验节点会自动将结果修正为 info 并记录一条异常日志。这样就用“规则引擎+AI”的双重保险,提升了稳定性。

4.3 系统监控与维护:如何知道它还在正常工作?

系统跑起来后,最怕的就是它“静默失败”。定时任务没执行、接口挂掉了、数据库磁盘满了,我都需要及时知道。

解决方案 :搭建最简易的监控看板。

  1. 健康检查接口 :在Flask应用中,我增加了一个 /api/health 接口,返回数据库连接状态、关键表的数据量、服务启动时间等。
  2. 利用WorkBuddy自监控 :我创建了一个独立的WorkBuddy智能体,它的唯一任务就是每天早晚各一次,去调用健康检查接口和Dify的API状态接口。如果任何一项检查失败,或者当天告警日志数为0(这可能意味着巡检流程中断),它就自动发送告警邮件给我。
  3. 关键日志可视化 :我并没有用复杂的ELK栈,而是将关键的告警日志、工作流执行成功/失败记录,都写入SQLite的 alert_logs 表。然后用一个非常简单的单HTML页面,配合Chart.js库,从Flask接口获取数据,绘制出“每日告警趋势图”、“高频问题网点排名”等图表。这个页面就作为我们安全小组的每日晨会看板。

5. 项目复盘:成本、效益与未来展望

这套系统从构思到稳定运行,耗时约3个月,其中前两个月主要是在学习、选型和踩坑,最后一个月是迭代优化。总成本极低:一台中等配置的云服务器(约200元/月),以及GPT-4 API的调用费用(由于主要用本地模型和规则判断,用量很少,每月约数十元)。人力成本就是我自己的时间投入。

带来的效益是显著的

  1. 效率提升 :安全巡检从“人工抽查”变为“自动全量覆盖”,每日自动生成风险报告,管理人员从繁杂的信息筛选中解放出来。
  2. 风险前置 :系统运行第一个月,就提前发现了3起灭火器即将过期、5起监控设备长期离线却未上报的隐患,均在酿成事故前得以处理。
  3. 标准统一 :通过知识库和LLM的判断,所有网点的风险判定尺度变得一致,避免了因不同安全员理解偏差导致的误判或漏判。
  4. 可进化性 :当公司新增“防疫安全检查”项时,我只需在数据库加个字段,在Dify知识库上传新规定,并微调一下工作流和提示词,半天内新功能就能上线。这是传统定制软件无法比拟的灵活性。

对于也想尝试的非技术同仁,我的最后几点心得是

  • 心态上要“敢拼敢试” :不要被“AI”、“开发”这些词吓到。现在的工具已经足够友好,你要做的是“产品经理”和“组装工程师”,而不是“科学家”或“码农”。
  • 路径上要“小步快跑” :不要想着一口吃成胖子。我的第一步,只是用Flask+SQLite把Excel数据变成了一个能查询的网页。第二步,才是接入Dify做一个简单的自动判断。每一步都先做出一个可用的最小版本,获得正反馈后再迭代。
  • 核心是“数据闭环” :无论AI多智能,它的基础是准确、及时的数据。花大力气把数据源头(网点上报、设备接口)理顺,比后期调优AI提示词重要十倍。
  • 拥抱“不完美” :AI判断会有误差,系统偶尔会出bug。接受这一点,但建立监控和人工复核机制作为兜底。我们的系统现在依然要求安全员每天查看自动报告并进行确认,人机协同才是最优解。

未来,我计划将更多物联网设备(如智能烟感、温湿度传感器)直接接入系统,让数据源更实时。同时,探索利用AI对监控视频流进行简单的异常行为识别(如堆积物堵塞消防通道)。这条路还很长,但起点,或许就从你决定动手解决手头那个具体问题开始。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐