Skip to content

Agent 和 Dify

AI Agent:感知环境、自主决策、使用工具完成任务的智能实体

Agent 和大模型的区别:大模型是聊天对象,Agent 可以聊还可以执行业务

那么 Agent = 大模型 + 工具

Dify 其实就是一个开源大语言模型的应用平台,低代码可以编排业务逻辑,可以接入 100+ 主流模型,并且支持本地化私有部署

Dify 可以支持多轮对话,支持 RAG 知识库接入企业私有文档,可以编排工作流,可以使用 Agent 智能体

Dify 安装

dify 安装按照官方文档启动测试版本

API 接入,可以通过阿里云的百炼平台进行使用

Prompt 提示词

提示词就是与 AI 沟通的交流书,提示词越清晰、越具体,AI 的表现就越好

提示词要素

  • 角色定位
  • 技能描述
  • 输出规范
  • 约束条件

dify 中应用提示词,有两种提示词

  • 用户提示词:用户直接提出具体的指令或者问题,指导模型回复
  • 系统提示词:定位大模型的角色和技能

RAG

RAG 其实就是从知识库检索文档然后生成答案,用于解决 AI 幻觉问题

知识库中的数据其实都是公司内部的数据,将问题经过知识库检索出来的上下文和原来的 query 进行拼接,然后送给大模型,让大模型给出最后的答案

  1. 文档切片

    RAG 知识构建,首先要进行相关文档的准备,然后进行一定的切片

    这个切片比较重要,因为大模型上下文长度不可能是无限的,所以要将文档进行切片

    切片的方式有很多,比如按照字符数量切分、按照符号切分、按照语义进行切分

    一般选择的方式是按照符号 + 字符长度一块切分,一般切分 200 - 500 字,长度太小上下文不完整,长度太多占用上下文

  2. 文档向量化

    知识库构建:文档向量化

    将切分后的文本进行向量数字化,以便于计算问题和文档的相似性

    进行向量化以便于计算问题和文档的相似性


RAG 创建知识库

  1. 进入 dify 选择知识库创建

    首先准备知识库文档

    指定分段的配置,然后可以进行预览

    Embedding 模型 这里默认是选了一个多模态模型,直接给他设置 text-embedding-v1 就行了

    检索设置 这里有三种方式:向量检索、全文检索、混合检索,向量检索就是通过词向量的方式检索匹配向量相似的值,全文检索是分词然后检索,混合检索两者都有,然后去重后进行检索

    推荐是使用混合检索,这里可以设置一个 topK 就是说根据向量检索出的内容有几个,这个可以设置,比如设置为 1 个

  2. 选择知识库使用

    默认情况下是可以看到训练时的数据的,但是不会看到训练后的数据

    选择导入知识库

一个 agent 可以设置多个知识库,并且还可以设置提示词规定先后顺序

Function Calling

Function Calling 简单来说就是能让大模型调用外部工具,也就是函数调用功能

如果大模型判断能够回答,则直接回答,如果大模型判断不能回答,则会调用工具获取数据后回答

在 Dify 视角中其实就看成了插件,插件是一个工具集,包含一个或者多个工具,模型通过插件的描述阅读插件的内容,所以必须要写的非常详细

插件可以自己定义也可以直接使用市场中的


时间插件的应用


自定义插件,目标是开发实时查询天气的助手

  1. 脚本开发

  2. 运行脚本

    这个脚本其实也就是后台服务,用啥写都行

    python main.py 运行脚本,然后调用内网穿透将当前端口映射到公网

    python
    from fastapi import FastAPI, Request, HTTPException
    from pydantic import BaseModel
    import requests
    
    app = FastAPI()
    
    # 身份验证令牌(个人使用,简单安全)
    VALID_TOKEN = "itcast"
    
    # 城市编码数据(直接硬编码,无需外部文件)
    CITY_CODES = {
        "北京": "101010100",
        "上海": "101020100",
        "广州": "101280101",
        "深圳": "101280601",
        "杭州": "101210101",
        "成都": "101270101",
        "武汉": "101200101",
        "西安": "101110101",
        "南京": "101190101",
        "重庆": "101040100",
        "天津": "101030100",
        "苏州": "101190401",
        "郑州": "101180101",
        "长沙": "101250101",
        "青岛": "101120201",
        "大连": "101070201",
        "宁波": "101210401",
        "厦门": "101230201",
        "福州": "101230101",
        "济南": "101120101",
        "合肥": "101220101",
        "南昌": "101240101",
        "昆明": "101290101",
        "南宁": "101300101",
        "贵阳": "101260101",
        "哈尔滨": "101050101",
        "长春": "101060101",
        "沈阳": "101070101",
        "石家庄": "101090101",
        "太原": "101100101",
        "呼和浩特": "101080101",
        "乌鲁木齐": "101130101",
        "拉萨": "101140101",
        "兰州": "101110501",
        "西宁": "101150101",
        "银川": "101170101",
        "海口": "101310101",
        "三亚": "101310201"
    }
    
    
    class WeatherRequest(BaseModel):
        location: str
    
    
    @app.post("/weather")
    def get_current_weather(request: Request, body: WeatherRequest):
        """
        天气查询接口
        - 需要Authorization头认证
        - 返回自然语言格式的天气信息
        """
        # 1. 验证身份
        auth_header = request.headers.get("Authorization")
        if auth_header != f"Bearer {VALID_TOKEN}":
            raise HTTPException(status_code=403, detail="Invalid Authorization header")
    
        location = body.location
    
        # 2. 查找城市编码
        city_code = CITY_CODES.get(location)
        if not city_code:
            return {
                "status": "error",
                "message": f"请提供{location}对应的编码方可查询,目前支持的城市:{','.join(CITY_CODES.keys())}"
            }
    
        # 3. 调用天气API
        url = f"http://t.weather.itboy.net/api/weather/city/{city_code}"
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()
            data = response.json()
        except Exception as e:
            return {"status": "error", "message": f"天气服务请求失败: {str(e)}"}
    
        # 4. 解析天气数据
        try:
            forecast = data["data"]["forecast"][0]
            weather_type = forecast["type"]
            high = forecast["high"].replace("高温 ", "")
            low = forecast["low"].replace("低温 ", "")
            temperature = f"{high}/{low}"
    
            # 5. 返回自然语言格式
            return f"{location}今天是{weather_type},温度{temperature}"
        except (KeyError, IndexError) as e:
            return {"status": "error", "message": f"天气数据解析失败: {str(e)}"}
    
    
    # 启动入口
    if __name__ == "__main__":
        import uvicorn
    
        uvicorn.run(app, host="0.0.0.0", port=1900)

    安装内网穿透

    bash
    npm install -g localtunnel
    lt --port 1900

    预期输出:https://xxx.loca.lt

    在 postman 中做测试

    • 使用 POST 请求

    • URL 为 https://xxx.loca.lt/weather

    • Headers: Authorization: Bearer itcast Content-Type: application/json

    • Body (raw, JSON):

      json
      {"location": "广州"}
  3. 在 dify 中选择工具创建自定义工具

  4. schema 操作

    ```json { "openapi": "3.1.0", "info": { "title": "天气查询API", "description": "查询中国城市当前天气信息", "version": "v1.0.0" }, "servers": [ { "url": "https://weather-api-abc123.loca.lt" } ], "paths": { "/weather": { "post": { "summary": "查询城市天气", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "location": { "type": "string", "description": "城市名称", "example": "北京" } }, "required": ["location"] } } } }, "responses": { "200": { "description": "成功获取天气信息" } } } } }, "components": { "schemas": {}, "securitySchemes": { "BearerAuth": { "type": "http", "scheme": "bearer" } } } } ```
  5. 测试,保存

工作流与 Agent

工作流 = 业务逻辑的可视化执行

Agent = 自主决策的 AI 助手

工作流是一种确定性的 Agent 实现方式,因为工作流是固定不变的,而智能体是自主决策、动态规划的

在运行成本来说,工作流消耗 token 可控,而智能体消耗大

在 dify 中,工作流体系分为工作流与对话流

  • workflow:工作流,适用于功能类的数据处理,比如报告生成、海报制作、数据分析。不支持对话历史,也没有会话的概念。发布在本地、API、嵌入网站。
  • chatflow:对话流,适用于对话类的交互式助手,比如智能客服、AI 助手。支持读取对话历史,必须传入会话名称。发布在本地、API、嵌入网站。

电商问答助手(workflow)

  1. 首先准备知识库,导入问答对

  2. 创建一个新的工作流

  3. 进行判断,若礼貌性用语则不需要使用大模型回复,直接返回,否则使用大模型返回

    python
    import random
    
    def main(query:str)->dict:
        """
        基于固定短语匹配的跨境电商问答处理器
        
        Args:
            query: 用户输入的问题
            
        Returns:
            Dict: 包含回复类型、回复内容等信息的字典
        """
        # 去除首尾空格
        query = query.strip()
    
        # 打招呼相关的固定短语
        greeting_phrases = {
            # 基本问候
            "你好", "您好", "hi", "hello", "嗨", "哈喽", "哈罗",
            "早上好", "下午好", "晚上好", "上午好", "中午好", "晚安",
            "早", "午安", "good morning", "good afternoon", "good evening",
            # 询问身份
            "你是谁", "你是什么", "你叫什么", "你的名字", "介绍一下自己", 
            "自我介绍", "你是什么东西", "你是哪个", "你是啥",
            # 询问状态
            "你好吗", "怎么样", "还好吗", "你还好吗", "最近怎么样",
            "你在吗", "在不在", "还在吗", "在线吗", "你在线吗",
            # 询问能力
            "你能干什么", "你会做什么", "你能做什么", "你的功能", 
            "你有什么用", "你的作用", "你的职责", "你的用途",
            "你能帮我什么", "你可以做什么", "你会什么", "你懂什么",
            "能力介绍", "功能介绍", "你的能力", "你有什么功能",
            # 开始对话
            "开始", "开始咨询", "开始对话", "开始聊天", "我想咨询",
            "我有问题", "我想问问题", "我想了解", "咨询一下",
            # 测试类
            "测试", "试试", "试一试", "test", "testing", "试试看",
            "测试一下", "看看", "检查一下"
        }
        
        # 固定回复
        greeting_response = "你好,很高兴为您服务!我是您的跨境电商学习小助手,专业为您答疑解惑。"
        # 礼貌用语
        thank_phrases = {
            "谢谢", "感谢", "多谢", "谢了", "thanks", "thank you", 
            "thx", "3q", "3x", "谢谢你", "感谢你", "多谢了",
            "非常感谢", "十分感谢", "万分感谢", "太感谢了"
        }
        
        goodbye_phrases = {
            "再见", "拜拜", "bye","byebye","goodbye", "88", "走了", "告辞",
            "先走了", "下次见", "回头见", "有空再聊", "改天聊",
            "see you", "拜", "溜了", "闪了", "slip away"
        }
        
            
        polite_responses = {
            "thank": [
                "不用客气,随时为您服务!", 
                "很高兴能帮助到您!", 
                "这是我应该做的,有问题随时找我哦!",
                "客气了,有什么问题尽管问!",
                "不客气,祝您跨境电商生意兴隆!"
            ],
            "goodbye": [
                "再见!期待下次为您服务!", 
                "祝您生活愉快,有问题随时来找我!", 
                "再见!祝您跨境电商生意兴隆!",
                "拜拜!有问题随时回来咨询!",
                "再见!祝您学习愉快!"
            ]
        }
        # 人工服务相关短语
        human_service_phrases = {
            # 直接要求人工服务
            "人工服务", "人工客服", "人工坐席", "人工咨询", "人工帮助",
            "人工支持", "人工答疑", "人工解答", "人工回复", "人工对话",
            # 转接相关
            "转人工", "找人工", "要人工", "转接人工", "转接客服",
            "切换人工", "接入人工", "联系人工","答疑入口",
            # 真人服务
            "真人服务", "真人客服", "真人咨询", "真人对话", "真人帮助",
            "活人", "真人", "人类", "人工", "真的人",
            # 客服相关
            "客服", "在线客服", "联系客服", "找客服", "客服电话",
            "客服微信", "客服qq", "官方客服",
            # 老师/导师
            "联系老师", "找老师", "咨询老师", "请教老师", "老师帮忙",
            "专业老师", "课程老师", "指导老师",
            # 专业服务
            "专人服务", "专人客服", "专业咨询", "专业服务", "专家咨询",
            "顾问咨询", "一对一服务", "专属服务",
            # 投诉和问题
            "投诉", "举报", "反馈问题", "意见反馈", "服务投诉",
            "质量问题", "服务问题", "系统问题",
            # 售后相关
            "退款", "退货", "售后", "售后服务", "退换货", "申请退款",
            "退费", "取消订单", "订单问题",
            # 不满意
            "不满意", "有问题", "出问题", "不行", "太差了", "服务差",
            "回答不对", "答非所问", "听不懂", "不准确"
        }
    
    
        
        human_service_response = "同学,点击 https://www.123.com 可进入人工答疑"
        
        def normalize_text(text: str) -> str:
            """标准化文本:去除标点符号,转换为小写"""
            import re
            # 保留中文、英文、数字,去除标点符号和空格
            cleaned = re.sub(r'[^\w\u4e00-\u9fff]', '', text.lower().strip())
            return cleaned
        
        def exact_match_check(query_text: str, phrase_set) -> bool:
            """精确匹配检查"""
            normalized_query = normalize_text(query_text)
            
            for phrase in phrase_set:
                normalized_phrase = normalize_text(phrase)
                if normalized_phrase == normalized_query:
                    return True
            return False
        
        def contains_match_check(query_text: str, phrase_set) -> bool:
            """包含匹配检查(用于短查询中包含关键短语的情况)"""
            normalized_query = normalize_text(query_text)
            
            # 只有当查询很短时才使用包含匹配(避免误匹配)
            if len(normalized_query) <= 10:
                for phrase in phrase_set:
                    normalized_phrase = normalize_text(phrase)
                    if normalized_phrase in normalized_query or normalized_query in normalized_phrase:
                        return True
            return False
        
        # 处理输入
        query = query.strip()
        if not query:
            return {
                "type": "error",
                "response": "请输入您的问题。",
                "need_rag": False,
                "original_query": query
            }
        
        print(f"处理查询: '{query}'")
        print(f"标准化后: '{normalize_text(query)}'")
        
        # 1. 检查感谢类礼貌用语(精确匹配)
        if exact_match_check(query, thank_phrases):
            return {
                "type": "greeting",
                "response": random.choice(polite_responses["thank"]),
                "need_rag": False,
                "original_query": query
            }
        
        # 2. 检查告别类礼貌用语(精确匹配)
        if exact_match_check(query, goodbye_phrases):
            return {
                "type": "greeting", 
                "response": random.choice(polite_responses["goodbye"]),
                "need_rag": False,
                "original_query": query
            }
        
        # 3. 检查打招呼(精确匹配 + 短语包含匹配)
        if exact_match_check(query, greeting_phrases) or contains_match_check(query, greeting_phrases):
            return {
                "type": "greeting",
                "response": greeting_response,
                "need_rag": False,
                "original_query": query
            }
        
        # 4. 检查人工服务请求(精确匹配 + 短语包含匹配)
        if exact_match_check(query, human_service_phrases) or contains_match_check(query, human_service_phrases):
            return {
                "type": "human_service",
                "response": human_service_response,
                "need_rag": False,
                "original_query": query
            }
        
        # 5. 其他情况需要RAG检索
        return {
            "type": "rag_needed",
            "response": "",
            "need_rag": True,
            "original_query": query
        }
  4. 条件判断为直接输出

  5. 条件判断为知识检索,即从知识库中进行检索知识

    markdown
    # 角色
    你是一位专业且高效的跨境电商答疑小助手,精通跨境电商领域的各类知识,能够依据相关信息准确回答用户关于跨境电商的问题。
    
    ## 重要参数
    - 上下文内容:{{#context#}}
    ## 技能
    ### 技能 1: 基于上下文解答问题
    1. 严格依据提供的上下文内容进行回答,不添加上下文中未出现的信息。
    2. 回答需精准、简洁、有条理,重点突出,逻辑严密,避免歧义,采用清晰的格式呈现内容,将复杂概念以通俗易懂的方式表达。
    
    ### 技能 2: 答案优化
    1. 若问题检索出来的上下文答案比较简单,需进行优化,但不能改变原来上下文中涉及到的答案核心内容。
    2. 示例:
        - 问题: 是不是不能在一个页面里面同时操作设置两个素材(A图案对应白T,B图案对应黑T)只能选一个通用于白黑T的图案?
        - 检索上下文答案: 是的
        - 优化后给出答案:  是的,不能在一个页面里面同时操作设置两个素材(A图案对应白T,B图案对应黑T),只能选一个通用于白黑T的图案。
    
    ### 技能 3: 上下文不足信息内容补齐
    1. 若问题经过数据库检索,给出的上下文信息非常少或没有,需结合自身专业知识回答。
    2. 示例:
        - 问题:如果我的产品标题中即有泰文和英文,算重复吗?
        - 上下文的信息:请不要在标题中出现叠词
        - 回答:本地知识库中未提供关于产品既有泰文和英文是否算重复的相关内容,结合专业知识,目前没有明确固定标准判定这种情况一定算重复,具体要根据不同平台规则和实际情况判断。以上信息仅供参考。
    
    ### 技能 4 敏感词过滤
    1. 当遇到不符合安全规范或者敏感的词汇时,优先利用插件check进行敏感词搜索,然后去除
    
    ## 限制:
    - 仅回答与跨境电商相关的问题,拒绝处理与跨境电商无关的话题。
    - 优先以检索的知识库内容为答案,除非内容不全在进行优化或者补全
    - 回答内容必须符合上述技能要求的格式和规范。
    - 若回答基于知识库已有信息,需遵循相应说明规范;若知识库中没有相关内容,应按技能 3 要求回答用户 。

    markdown
    # 角色
    你是一位专业且亲切的跨境电商答疑小助手,不仅拥有深厚的跨境电商专业知识,还具备广泛的通用知识储备。你能够根据用户需求,灵活切换角色,既能为用户解答跨境电商领域的复杂专业问题,也能与用户展开轻松愉快的日常闲聊。
    
    ## 技能
    ### 技能 1: 精准解答跨境电商问题
    1. 当用户提出跨境电商相关问题时,充分运用自身专业知识,结合丰富且贴合实际的案例,为用户提供准确、全面且详细的解答。
    2. 针对复杂的跨境电商概念,运用通俗易懂、生动形象的语言进行深入浅出的解释说明,确保用户能够轻松理解。
    3. 在回答的结尾处明确注明“以上答案仅供参考”。
    
    ### 技能 2: 耐心回应非跨境电商问题
    1. 当用户提及非跨境电商问题时,例如简单的数学运算“1 + 1 等于几”等,运用已有的知识储备,耐心、准确地对用户进行回答。
    2. 在回答此类问题的结尾同样注明“以上答案仅供参考”。
    
    ### 技能 3: 合理引导不明确问题
    1. 当用户输入的问题含义不明确时,不直接给出知识回答,而是友好地输出“我还在努力理解您的问题,请您详细描述后再来询问吧,这样我能更好地为您解答。”
    
    ## 限制:
    - 交流内容主要围绕跨境电商学习以及其他非电商知识相关范畴,对于与这两类内容无关的话题,需礼貌地拒绝回答,并告知用户“抱歉,我只能回答与跨境电商学习和其他非电商知识相关的问题哦”。
    - 所输出的内容必须严格符合上述回答要求,保证格式规范、条理清晰、逻辑连贯。 
    - 回答的答案中禁止提及:需要进行知识库检索

  6. 发布应用

数据库查询助手(chatflow)

接受自然语言提问,自动转化为 SQL 并查询数据库

  1. 准备 MySQL 数据库

    sql
    CREATE DATABASE dify_test;
    
    USE dify_test;
    
    CREATE TABLE student_grades (
        id INT AUTO_INCREMENT PRIMARY KEY,
        student_id VARCHAR(20) NOT NULL,
        student_name VARCHAR(50) NOT NULL,
        class_name VARCHAR(50) NOT NULL,
        subject VARCHAR(50) NOT NULL,
        score DECIMAL(5,2) NOT NULL,
        exam_date DATE NOT NULL,
        semester VARCHAR(50) NOT NULL,
        grade VARCHAR(50) NOT NULL,
        created_at DATETIME NOT NULL,
        updated_at DATETIME NOT NULL
    );
    
    INSERT INTO student_grades (student_id, student_name, class_name, subject, score, exam_date, semester, grade, created_at, updated_at) VALUES 
    ('2023001', '李一', '高一(1)班', '数学', 85.00, '2023-09-15', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023002', '王二', '高一(1)班', '英语', 92.50, '2023-09-20', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023003', '张三', '高一(2)班', '物理', 78.00, '2023-10-05', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023004', '赵四', '高一(2)班', '化学', 88.00, '2023-10-10', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023005', '孙五', '高一(3)班', '生物', 95.00, '2023-11-01', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023006', '周六', '高一(3)班', '历史', 82.00, '2023-11-05', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023007', '吴七', '高一(4)班', '地理', 90.00, '2023-12-01', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023008', '郑八', '高一(4)班', '政治', 87.00, '2023-12-05', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023009', '冯九', '高二(1)班', '数学', 76.00, '2024-01-10', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023010', '陈十', '高二(1)班', '英语', 94.00, '2024-01-15', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023011', '褚十一', '高二(2)班', '物理', 89.00, '2024-02-01', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023012', '卫十二', '高二(2)班', '化学', 81.00, '2024-02-05', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023013', '蒋十三', '高二(3)班', '生物', 93.00, '2024-03-01', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023014', '沈十四', '高二(3)班', '历史', 86.00, '2024-03-05', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023015', '韩十五', '高二(4)班', '地理', 91.00, '2024-04-01', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023016', '杨十六', '高二(4)班', '政治', 84.00, '2024-04-05', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023017', '朱十七', '高三(1)班', '数学', 79.00, '2024-05-10', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023018', '秦十八', '高三(1)班', '英语', 96.00, '2024-05-15', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023019', '尤十九', '高三(2)班', '物理', 88.00, '2024-06-01', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023020', '许二十', '高三(2)班', '化学', 83.00, '2024-06-05', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023021', '何二十一', '高三(3)班', '生物', 92.00, '2024-07-01', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023022', '吕二十二', '高三(3)班', '历史', 85.00, '2024-07-05', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023023', '施二十三', '高三(4)班', '地理', 90.00, '2024-08-01', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023024', '张二十四', '高三(4)班', '政治', 87.00, '2024-08-05', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023025', '孔二十五', '高一(1)班', '数学', 77.00, '2023-09-25', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023026', '曹二十六', '高一(1)班', '英语', 95.00, '2023-09-30', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023027', '严二十七', '高一(2)班', '物理', 89.00, '2023-10-15', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023028', '华二十八', '高一(2)班', '化学', 82.00, '2023-10-20', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023029', '金二十九', '高一(3)班', '生物', 94.00, '2023-11-10', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023030', '魏三十', '高一(3)班', '历史', 86.00, '2023-11-15', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023031', '陶三十一', '高一(4)班', '地理', 91.00, '2023-12-10', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023032', '姜三十二', '高一(4)班', '政治', 84.00, '2023-12-15', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023033', '戚三十三', '高二(1)班', '数学', 78.00, '2024-01-20', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023034', '谢三十四', '高二(1)班', '英语', 96.00, '2024-01-25', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023035', '邹三十五', '高二(2)班', '物理', 88.00, '2024-02-10', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023036', '喻三十六', '高二(2)班', '化学', 83.00, '2024-02-15', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023037', '吴三十七', '高二(3)班', '生物', 93.00, '2024-03-10', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023038', '柏三十八', '高二(3)班', '历史', 85.00, '2024-03-15', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023039', '水三十九', '高二(4)班', '地理', 90.00, '2024-04-10', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023040', '窦四十', '高二(4)班', '政治', 87.00, '2024-04-15', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023041', '章四十一', '高三(1)班', '数学', 79.00, '2024-05-20', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023042', '云四十二', '高三(1)班', '英语', 96.00, '2024-05-25', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023043', '苏四十三', '高三(2)班', '物理', 88.00, '2024-06-10', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023044', '潘四十四', '高三(2)班', '化学', 83.00, '2024-06-15', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023045', '葛四十五', '高三(3)班', '生物', 92.00, '2024-07-10', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023046', '奚四十六', '高三(3)班', '历史', 84.00, '2024-07-15', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023047', '范四十七', '高三(4)班', '地理', 90.00, '2024-08-10', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023048', '彭四十八', '高三(4)班', '政治', 87.00, '2024-08-15', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023049', '郎四十九', '高一(1)班', '数学', 77.00, '2023-10-01', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023050', '鲁五十', '高一(1)班', '英语', 95.00, '2023-10-05', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023051', '韦五十一', '高一(2)班', '物理', 88.00, '2023-10-25', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023052', '昌五十二', '高一(2)班', '化学', 82.00, '2023-10-30', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023053', '马五十三', '高一(3)班', '生物', 94.00, '2023-11-20', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023054', '苗五十四', '高一(3)班', '历史', 86.00, '2023-11-25', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023055', '凤五十五', '高一(4)班', '地理', 91.00, '2023-12-20', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023056', '花五十六', '高一(4)班', '政治', 83.00, '2023-12-25', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023057', '方五十七', '高二(1)班', '数学', 78.00, '2024-01-30', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023058', '俞五十八', '高二(1)班', '英语', 96.00, '2024-02-01', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023059', '任五十九', '高二(2)班', '物理', 88.00, '2024-02-20', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023060', '袁六十', '高二(2)班', '化学', 83.00, '2024-02-25', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023061', '柳六十一', '高二(3)班', '生物', 92.00, '2024-03-20', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023062', '酆六十二', '高二(3)班', '历史', 85.00, '2024-03-25', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023063', '鲍六十三', '高二(4)班', '地理', 90.00, '2024-04-20', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023064', '史六十四', '高二(4)班', '政治', 87.00, '2024-04-25', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023065', '唐六十五', '高三(1)班', '数学', 79.00, '2024-05-30', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023066', '费六十六', '高三(1)班', '英语', 95.00, '2024-06-01', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023067', '廉六十七', '高三(2)班', '物理', 88.00, '2024-06-20', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023068', '岑六十八', '高三(2)班', '化学', 82.00, '2024-06-25', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023069', '薛六十九', '高三(3)班', '生物', 94.00, '2024-07-20', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023070', '雷七十', '高三(3)班', '历史', 86.00, '2024-07-25', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023071', '贺七十一', '高三(4)班', '地理', 91.00, '2024-08-20', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023072', '倪七十二', '高三(4)班', '政治', 84.00, '2024-08-25', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023073', '汤七十三', '高一(1)班', '数学', 78.00, '2023-10-10', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023074', '滕七十四', '高一(1)班', '英语', 96.00, '2023-10-15', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023075', '殷七十五', '高一(2)班', '物理', 88.00, '2023-11-01', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023076', '罗七十六', '高一(2)班', '化学', 83.00, '2023-11-05', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023077', '毕七十七', '高一(3)班', '生物', 93.00, '2023-11-30', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023078', '郝七十八', '高一(3)班', '历史', 85.00, '2023-12-01', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023079', '邬七十九', '高一(4)班', '地理', 90.00, '2023-12-30', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023080', '安八十', '高一(4)班', '政治', 87.00, '2024-01-01', '2023-2024学年第二学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023081', '常八十一', '高二(1)班', '数学', 79.00, '2024-02-05', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023082', '乐八十二', '高二(1)班', '英语', 96.00, '2024-02-10', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023083', '于八十三', '高二(2)班', '物理', 88.00, '2024-03-01', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023084', '时八十四', '高二(2)班', '化学', 83.00, '2024-03-05', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023085', '傅八十五', '高二(3)班', '生物', 92.00, '2024-03-30', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023086', '皮八十六', '高二(3)班', '历史', 84.00, '2024-04-01', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023087', '卞八十七', '高二(4)班', '地理', 90.00, '2024-04-30', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023088', '齐八十八', '高二(4)班', '政治', 87.00, '2024-05-01', '2023-2024学年第二学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023089', '康八十九', '高三(1)班', '数学', 77.00, '2024-06-05', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023090', '伍九十', '高三(1)班', '英语', 95.00, '2024-06-10', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023091', '余九十一', '高三(2)班', '物理', 88.00, '2024-07-01', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023092', '元九十二', '高三(2)班', '化学', 82.00, '2024-07-05', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023093', '卜九十三', '高三(3)班', '生物', 94.00, '2024-07-30', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023094', '顾九十四', '高三(3)班', '历史', 86.00, '2024-08-01', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023095', '孟九十五', '高三(4)班', '地理', 91.00, '2024-08-30', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023096', '平九十六', '高三(4)班', '政治', 83.00, '2024-09-01', '2024-2025学年第一学期', '高三', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023097', '黄九十七', '高一(1)班', '数学', 78.00, '2023-10-20', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023098', '和九十八', '高一(1)班', '英语', 96.00, '2023-10-25', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023099', '穆九十九', '高一(2)班', '物理', 88.00, '2023-11-10', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023100', '萧一百', '高一(2)班', '化学', 83.00, '2023-11-15', '2023-2024学年第一学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023101', '李一', '高一(1)班', '数学', 90.00, '2024-03-15', '2023-2024学年第二学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023102', '王二', '高一(1)班', '英语', 88.00, '2024-03-20', '2023-2024学年第二学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023103', '张三', '高一(2)班', '物理', 85.00, '2024-04-05', '2023-2024学年第二学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023104', '赵四', '高一(2)班', '化学', 92.00, '2024-04-10', '2023-2024学年第二学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023105', '孙五', '高一(3)班', '生物', 55.00, '2024-05-01', '2023-2024学年第二学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023106', '周六', '高一(3)班', '历史', 70.00, '2024-05-05', '2023-2024学年第二学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023107', '吴七', '高一(4)班', '地理', 65.00, '2024-06-01', '2023-2024学年第二学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023108', '郑八', '高一(4)班', '政治', 95.00, '2024-06-05', '2023-2024学年第二学期', '高一', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023109', '冯九', '高二(1)班', '数学', 60.00, '2024-07-10', '2024-2025学年第一学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00'),
    ('2023110', '陈十', '高二(1)班', '英语', 75.00, '2024-07-15', '2024-2025学年第一学期', '高二', '2026-02-03 08:00:00', '2026-02-03 08:00:00');
  2. 安装 dify 工具: ECharts 图表生成、database

    database 插件需要链接到现有数据库

    mysql+pymysql://root:123456@host.docker.internal:3306/dify_test

    注意本机的话,host.docker.internal 可以直接指向 docker 外部的宿主机,如果是远程服务器那么就填写远程服务器地址

  3. 创建 chatflow

    系统提示词

    markdown
    ## 角色
    你是一个专业的SQL查询生成器,负责根据用户查询创建标准的MySQL数据库SQL语句。
    
    ## 任务
    根据以下问题,生成一个格式清晰、结构明确的JSON数组,其中每个元素是一条合法且性能优化的MySQL查询语句。
    
    ### 表信息
    表名:student_grades(学生成绩信息表)
    
    ### 字段说明
    - id: 主键
    - student_id: 学号
    - student_name: 学生姓名
    - class_name: 班级
    - subject: 科目
    - score: 分数
    - exam_date: 考试日期
    - semester: 学期
    - grade: 年级
    - created_at: 记录创建时间
    - updated_at: 记录更新时间
    
    ### 输出要求
    1. 根据用户的问题,生成最多10条直接关联问题的SQL查询语句。
    2. 每条SQL应从不同分析角度(如按科目、班级、学期、年级等维度)切入,确保覆盖多维统计需求。
    3. 所有SQL必须语法正确、可执行,并注重性能优化(如避免SELECT *,合理使用索引字段等)。
    4. 若问题涉及多维统计(例如“各班各科平均分”),请为每个统计维度单独生成子查询。
    5. 对于全量数据查询,必须按semester(学期)进行聚合或排序。
    6. 最终输出必须是纯JSON数组格式,以 ```json 开头,以 ``` 结尾,不包含任何额外解释或文本,其中每个元素必须是对象,且仅包含一个字段:`"sql"`**(字符串类型),格式示例:
    ```json
    [
        { "sql": "SELECT ...;" },
        { "sql": "SELECT ...;" }
    ]
    
    请严格按照上述格式和要求生成响应。

    用户提示词 查询全校各科目平均分情况

    助手提示词

    markdown
    - Few-shot示例
    
    ​```json
               [
        {
            "title": "统计全校各科目平均分",
            "sql": "SELECT subject, ROUND(AVG(score), 2) AS avg_score FROM student_scores GROUP BY subject ORDER BY avg_score DESC;"
        },
        {
            "title": "统计各科目及格率",
            "sql": "SELECT subject, ROUND(COUNT(CASE WHEN score >= 60 THEN 1 END) * 100.0 / COUNT(*), 2) as pass_rate FROM student_scores GROUP BY subject ORDER BY pass_rate DESC;"
        },
        {
            "title": "统计各科目成绩分布",
            "sql": "SELECT subject, COUNT(CASE WHEN score >= 90 THEN 1 END) as excellent, COUNT(CASE WHEN score >= 75 AND score < 90 THEN 1 END) as good, COUNT(CASE WHEN score >= 60 AND score < 75 THEN 1 END) as pass, COUNT(CASE WHEN score < 60 THEN 1 END) as fail FROM student_scores GROUP BY subject;"
        }
    ]
    ​```

    用户问题 用户问题:{x}query

  4. 代码执行

    格式转换,从大模型给到的 json 中提取出 SQL

    python
    # 导入正则表达式模块,用于字符串模式匹配
    import re  
    # 导入JSON模块,用于处理JSON数据
    import json 
    
    # 定义函数,用于从输入字符串中提取和解析JSON数据,返回字典
    def main(input_string: str) -> dict:  
        # 使用正则表达式查找并提取被 ```json 和 ``` 包裹的内容
        pattern_match = re.search(r'```json\s*([\s\S]*?)\s*```', input_string)
        # 如果没有找到匹配的内容
        if not pattern_match: 
            raise ValueError("输入字符串中未找到有效的 JSON 数据") 
        
        # 提取匹配到的JSON字符串,并去除前后空白
        json_content = pattern_match.group(1).strip()
        # 尝试解析JSON字符串
        try:  
            # 将提取的JSON字符串解析为Python字典
            parsed_json = json.loads(json_content)
        # 如果解析过程中发生JSON解码错误
        except json.JSONDecodeError as err:  
            raise ValueError(f"JSON 解析失败: {err}") 
        
        # 返回一个包含解析结果的字典
        return {
            "result": parsed_json, 
        }
  5. 循环迭代

Agent 发布

Agent 嵌入网站

Agent 封装 API