Docker和Dify学习笔记

文章目录

  • [1 docker学习](#1 docker学习)
    • [1.1 基本命令使用](#1.1 基本命令使用)
      • [1.1.1 docker ps查看当前正在运行的镜像](#1.1.1 docker ps查看当前正在运行的镜像)
      • [1.1.2 docker stop停止容器](#1.1.2 docker stop停止容器)
      • [1.1.3 docker compose容器编排](#1.1.3 docker compose容器编排)
      • [1.1.4 docker网络](#1.1.4 docker网络)
        • [[1] 进入到容器里面敲命令](#[1] 进入到容器里面敲命令)
        • [[2] docker network ls](#[2] docker network ls)
        • [[3] brige网络模式下容器访问宿主机的方式](#[3] brige网络模式下容器访问宿主机的方式)
  • [2 Dify的安装和基础使用](#2 Dify的安装和基础使用)
    • [2.1 下载dify的工程仓库](#2.1 下载dify的工程仓库)
    • [2.2 创建.env配置文件](#2.2 创建.env配置文件)
    • [2.3 修改Nginx的端口](#2.3 修改Nginx的端口)
    • [2.4 启动Dify](#2.4 启动Dify)
    • [2.5 添加一个本地模型](#2.5 添加一个本地模型)
      • [2.5.1 添加一个大语言模型](#2.5.1 添加一个大语言模型)
      • [2.5.2 添加一个Embedding模型](#2.5.2 添加一个Embedding模型)
  • [3 基于Dify开发功能场景](#3 基于Dify开发功能场景)
    • [3.1 Echarts绘图](#3.1 Echarts绘图)
    • [3.2 让大模型能够解析Json](#3.2 让大模型能够解析Json)
  • [4 大模型或者Dify中常见的参数](#4 大模型或者Dify中常见的参数)
    • [4.1 Temperature](#4.1 Temperature)
  • [4 Dify使用过程中常见问题](#4 Dify使用过程中常见问题)
    • [4.1 json超长了,超过80000个字符了](#4.1 json超长了,超过80000个字符了)
  • 参考资料

1 docker学习

1.1 基本命令使用

1.1.1 docker ps查看当前正在运行的镜像

复制代码
PS E:\LargeModel\dify\docker> docker ps
CONTAINER ID   IMAGE                                       COMMAND                   CREATED          STATUS                    PORTS                                         NAMES
5b2b8c1636e7   langgenius/dify-web:1.0.0                   "/bin/sh ./entrypoin..."   6 minutes ago    Up 6 minutes              3000/tcp                                      thirsty_diffie
99740eb3c659   langgenius/dify-web:1.0.0                   "/bin/sh ./entrypoin..."   6 minutes ago    Up 6 minutes              3000/tcp                                      upbeat_euclid
f8108bddcff7   nginx:latest                                "sh -c 'cp /docker-e..."   11 minutes ago   Up 11 minutes             0.0.0.0:8001->80/tcp, 0.0.0.0:8443->443/tcp   docker-nginx-1
2794a7f88a69   langgenius/dify-api:1.0.0                   "/bin/bash /entrypoi..."   11 minutes ago   Up 11 minutes             5001/tcp                                      docker-api-1
d51ee39beb2c   langgenius/dify-api:1.0.0                   "/bin/bash /entrypoi..."   11 minutes ago   Up 11 minutes             5001/tcp                                      docker-worker-1
e008dc5e6386   ubuntu/squid:latest                         "sh -c 'cp /docker-e..."   11 minutes ago   Up 11 minutes             3128/tcp                                      docker-ssrf_proxy-1
8c966517876b   langgenius/dify-sandbox:0.2.10              "/main"                   11 minutes ago   Up 11 minutes (healthy)                                                 docker-sandbox-1
a2d137e0f516   langgenius/dify-plugin-daemon:0.0.3-local   "/bin/bash -c /app/e..."   11 minutes ago   Up 11 minutes             0.0.0.0:5003->5003/tcp                        docker-plugin_daemon-1
56f97d78ab4c   langgenius/dify-web:1.0.0                   "/bin/sh ./entrypoin..."   11 minutes ago   Up 11 minutes             3000/tcp                                      docker-web-1
cfe29ccee8df   postgres:15-alpine                          "docker-entrypoint.s..."   11 minutes ago   Up 11 minutes (healthy)   0.0.0.0:5432->5432/tcp                        docker-db-1
edd0a6879ba7   semitechnologies/weaviate:1.19.0            "/bin/weaviate --hos..."   11 minutes ago   Up 11 minutes                                                           docker-weaviate-1
191a080293e4   redis:6-alpine                              "docker-entrypoint.s..."   11 minutes ago   Up 11 minutes (healthy)   6379/tcp                                      docker-redis-1
PS E:\LargeModel\dify\docker>

1.1.2 docker stop停止容器

【停止指定名称的容器】

复制代码
PS E:\LargeModel\dify\docker> docker stop thirsty_diffie
thirsty_diffie

【停止所有当前在运行的容器】

复制代码
PS E:\LargeModel\dify\docker> docker stop $(docker ps -aq)
5b2b8c1636e7
99740eb3c659
f8108bddcff7
2794a7f88a69
d51ee39beb2c
e008dc5e6386
8c966517876b
a2d137e0f516
56f97d78ab4c
cfe29ccee8df
edd0a6879ba7
191a080293e4
fe75be867cd5

1.1.3 docker compose容器编排

1.1.4 docker网络

[1] 进入到容器里面敲命令
shell 复制代码
docker exec -it docker-api-1 /bin/bash

案例:安装ping命令和telnet命令

shell 复制代码
root@cb7f80d95b40:/app/api# apt-get update
Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB]
Get:2 http://deb.debian.org/debian bookworm-updates InRelease [55.4 kB]
Get:3 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]
Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8792 kB]
Get:5 http://deb.debian.org/debian bookworm-updates/main amd64 Packages [13.5 kB]
Get:6 http://deb.debian.org/debian-security bookworm-security/main amd64 Packages [246 kB]
Fetched 9306 kB in 8min 19s (18.6 kB/s)
Reading package lists... Done
root@cb7f80d95b40:/app/api# apt-get install -y iputils-ping
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libcap2-bin libpam-cap
The following NEW packages will be installed:
[2] docker network ls
shell 复制代码
PS D:\LargeModel> docker network ls
NETWORK ID     NAME                        DRIVER    SCOPE
35353aad5d22   bridge                      bridge    local
6e02ea3b25c6   docker_default              bridge    local
5973270d4a91   docker_ssrf_proxy_network   bridge    local
503869a64910   host                        host      local
a0056c2c396d   none                        null      local
[3] brige网络模式下容器访问宿主机的方式

容器内可以使用host.docker.internal来代替主机的ip

2 Dify的安装和基础使用

2.1 下载dify的工程仓库

复制代码
git clone https://github.com/langgenius/dify.git
# 国内镜像站
https://gitee.com/dify_ai/dify

2.2 创建.env配置文件

我们进入dify目录下的docker目录中,

复制代码
# 以示例创建一个.env的文件,执行下面命令
cp .\.env.example .env

2.3 修改Nginx的端口

默认占用的是80和443端口,如果你本机已经部署了其他的应用,占了该端口,修改.env文件中的下面两个变量

复制代码
EXPOSE_NGINX_PORT=8001
EXPOSE_NGINX_SSL_PORT=8443

2.4 启动Dify

复制代码
docker compose up -d

2.5 添加一个本地模型

2.5.1 添加一个大语言模型



这里需要注意, 我的ollama是直接安装在宿主机的。 但是Dify是通过docker启动起来的,这里涉及到docker和宿主机之间的通信。 如果docker访问宿主机,可以使用host.docker.internal域名,Docker的DNS可以解析这个域名。

2.5.2 添加一个Embedding模型

(1)安装bge-m3模型

复制代码
ollama pull bge-m3

(2)Dify中配置embedding模型

3 基于Dify开发功能场景

3.1 Echarts绘图

思路就是利用Dify的echarts渲染的能力(即使是Dify自带的Echarts图表生成工具也是输出了一串echarts的配置字符串,甚至还没有直接写python代码生成来的直接)。 但是只能在工作流和chatflow里面使用。如果将绘图的工作流集成到Agent里面的话,会导致大模型解析不了json,输出不了内容了。

python 复制代码
import json
import requests
from datetime import datetime, timedelta
import statistics

"""
    这是一个try参数的机制
"""
def getValidResponse(url, headers, params):
    response = None
    for resourceFlag in ['sw', 'lk', 'wlw']:
        params["resource_flag"] = resourceFlag

        response = requests.get(url= url, headers= headers, params= params, timeout= 10)
        # 检查请求是否成功
        if response.status_code == 200:
            try:
                json_data = response.json()
                print(json_data)
                if (not "data" in json_data) or json_data["data"] is None or len(json_data["data"]) <= 0:
                    continue
                else:
                    return response
            except ValueError:
                continue        
        else:
            continue        

"""
    获取某一个水库某一段时间内的的水情数据。(主要是水位)
    参数:
        startDate: start_dt=2025-03-16+10:00:00
        endDate: end_dt=2025-03-17+11:00:00
"""
def getWaterStatus(guid: str, stcd: str, startDate: str, endDate: str) -> dict:
    url = "https://sk.hubeishuiyi.cn/services/1234567890ABCDEFGHIJKLMN/res_z_detail/param"
    headers = {
        "Apikey": "F1DBECD719108635189480CF60E6553ADB3109616426BD537F25A430DFC613B491A025C4A51E77FD08C6E5B7CBE05917A461286E7B6D69F1AB1B14F946149D2065B0C675F8FEDF4B9B05C1496881BC5A"
    }
    params = {
        "is_tb": "n",
        "pageNo": 1,
        "pageSize":10000,
        "st_cd": stcd,
        "resource_flag":"sw",
        "flag": 1,
        "start_dt": startDate,
        "end_dt": endDate,
        "res_cd": guid
    }

    response = getValidResponse(url, headers, params)
    # 检查请求是否成功
    if response is not None and response.status_code == 200:
        try:
            json_data = response.json()
            # # 转为双引号的标准json字符串
            # json_data = json.dumps(json_data)
            # json_data = json.loads(json_data)
            print(json_data)
            if (not "data" in json_data) or json_data["data"] is None or len(json_data["data"]) <= 0:
                return {"result" : []} 
            
            # 以时间作为横坐标
            timeList = []
            # 水位数据
            waterLevelList = []
            # 蓄水量
            waterStorageList = []
            for dataObject in json_data["data"]:
                timeStr = dataObject["tm"]
                timeList.append(timeStr)
                waterLevel = dataObject["rz"]
                waterLevelList.append(waterLevel)
                waterStorage = dataObject["w"]
                waterStorageList.append(waterStorage)

            statisticData = {
                "time": timeList,
                "waterLevel": waterLevelList,
                "waterStorage": waterStorageList
            }

            return {"result": statisticData}
        except ValueError:
            return {"result" : "Failed to parse JSON response"}
    else:
        statisticData = {
            "failMsg": f"Request failed. url = {url}, params = {params}"
        }
        return {"result" : statisticData}

def calcYAxisMinMax(nums: list):
    minValue = min(nums) - 8
    if minValue < 0:
        minValue = 0
    maxValue = max(nums) + 8

    return minValue, maxValue

"""
    参数:
        data: tuple的列表。
"""
def create_dynamic_table_str(headers: list, data):
    table = "|"
    for header in headers:
        table += f" {header} |"
    table += "\n|"
    for _ in headers:
        table += " ------- |"
    for row in data:
        table += "\n|"
        for item in row:
            table += f" {item} |"
    return table

def constructTableString(timeList: list, waterLevelList: list) -> str:
    timeList = timeList[-10:]
    waterLevelList = waterLevelList[-10:]

    headers = ['时间', '水位(m)']
    data = list(zip(timeList, waterLevelList))
    return create_dynamic_table_str(headers, data)

def constructStatisticString(waterLevelList: list) -> str:
    headers = ['统计项', '统计值']
    data = []

    minValue = min(waterLevelList)
    data.append(("最小值", f"{minValue:.2f}"))
    maxValue = max(waterLevelList)
    data.append(("最大值", f"{maxValue:.2f}"))
    meanValue = sum(waterLevelList) / len(waterLevelList)
    data.append(("平均值", f"{meanValue:.2f}"))
    # 计算列表的中位数
    medianValue = statistics.median(waterLevelList)
    data.append(("中位数", f"{medianValue:.2f}"))
    # 标准差
    devValue = statistics.stdev(waterLevelList)
    data.append(("标准差", f"{devValue:.2f}"))

    return create_dynamic_table_str(headers, data=data)

def drawEcharts(data: dict) -> dict:
    if data is None or len(data) <= 0:
        return {"result": ""}
    if "time" not in data or "waterLevel" not in data or "waterStorage" not in data:
        return {"result": ""}
    
    waterStatusData = data
    
    # 提取时间和对应的数据
    timeList = list(reversed(waterStatusData["time"]))
    waterLevelList = waterStatusData["waterLevel"]
    waterStorageList = waterStatusData["waterStorage"]

    if timeList is None or len(timeList) < 2:
        return {"result": ""}

    # 绘图准备工作
    UTC_FORMAT = "%Y-%m-%d %H:%M:%S"
    startTime = datetime.strptime(timeList[0], UTC_FORMAT)
    endTime = datetime.strptime(timeList[-1], UTC_FORMAT)

    walterLevelMin, walterLevelMax = calcYAxisMinMax(waterLevelList)

    # 生成echarts配置
    echarts_config = {
        "color": ['#eb6877', '#0f91c4', '#46cbd4'],
        "title": {
            "subtext": f"{startTime.strftime('%m')}月{startTime.strftime('%d')}日-{endTime.strftime('%m')}月{endTime.strftime('%d')}日水位情况",
            "left": 20
        },
        "tooltip": {
            "trigger": "axis",
            "axisPointer": {
                "type": "cross"
            }
        },
        "legend": {
            # "data": ["水位", "最低气温", "降水"],
            "data": ["水位"],
            "right": 20
        },
        "xAxis": {
            "data": timeList,
            "axisLine": {
                "onZero": False
            }
        },
        "yAxis": [
            {
                "type": "value",
                "name": "水位",
                "position": "left",
                "min": walterLevelMin,
                "max": walterLevelMax,
                "axisLabel": {
                    "formatter": "{value} m"
                }
            },
            # {
            #     "type": "value",
            #     "name": "蓄水量",
            #     "position": "right",
            #     "axisLabel": {
            #         "formatter": "{value} m"
            #     }
            # }
        ],
        "series": [
            {
                "name": "水位",
                "type": "line",
                "data": waterLevelList,
                "yAxisIndex": 0,
                "itemStyle": {
                    "color": "#eae213"
                },
                "markPoint": {
                    "data": [
                        {
                            "type": 'max'
                        },
                        {
                            "type": 'min'
                        },
                    ],
                    # 设置为点
                    "symbol": 'circle', 
                    # 调整点的大小
                    "symbolSize": 8, 
                    "label": {
                        "position": 'right',
                        # 标签字体加粗
                        "fontWeight": 'bold', 
                        # 标签字体大小
                        "fontSize": 12 
                    }
                },
            },
            # {
            #     "name": "蓄水量",
            #     "type": "bar",
            #     "smooth": True,
            #     "data": waterStorageList,
            #     "yAxisIndex": 0,
            #     "itemStyle": {
            #         "color": "#4bb2fa"
            #     }
            # },
            # {
            #     "name": "降水",
            #     "type": "bar",
            #     "smooth": True,
            #     "data": rainfall,
            #     "yAxisIndex": 1,
            #     "itemStyle": {
            #         "color": "#31e84f"
            #     }
            # }
        ]
    }

    echartString = "```echarts\n" + json.dumps(echarts_config, indent=2, ensure_ascii=False) + "\n```"
    tableString = constructTableString(timeList, waterLevelList)
    statisticString = constructStatisticString(waterLevelList)

    # 生成输出文件
    output = echartString + "\n\n"  \
        + "最近十条数据展示:\n" + tableString + "\n\n" \
        + "常用统计数据展示:\n" + statisticString

    return {"result":output}

def main(guid: str, stcdList: list) -> dict:
    if guid is None or stcdList is None or len(guid) <= 0 or len(stcdList) <= 0:
        return {"result" : ""}
    
    endDate = datetime.now()
    endDateStr = endDate.strftime("%Y-%m-%d %H:%M:%S")
    startDate = endDate - timedelta(days=15)
    startDateStr = startDate.strftime("%Y-%m-%d %H:%M:%S")
    result = getWaterStatus(guid=guid, stcd=stcdList[0], startDate=startDateStr, endDate=endDateStr)
    print(f"main.result = {result['result']}")
    markdownScript = drawEcharts(result["result"])
    print(markdownScript)
    return markdownScript

if __name__ == "__main__":
    # print(main('42022220001', ['61608180']))
    # print(main('42130330004', ["61608180"]))
    # print(main('42122350024', ['90021804']))
    print(main('42058340006', [ "90006379"]))

3.2 让大模型能够解析Json

4 大模型或者Dify中常见的参数

4.1 Temperature

LLM 生成是具有随机性的,在模型的顶层通过选取不同预测概率的预测结果来生成最后的结果。我们一般可以通过控制 temperature 参数来控制 LLM 生成结果的随机性与创造性。

Temperature 一般取值在 0~1 之间,当取值较低接近 0 时,预测的随机性会较低,产生更保守、可预测的文本,不太可能生成意想不到或不寻常的词。当取值较高接近 1 时,预测的随机性会较高,所有词被选择的可能性更大,会产生更有创意、多样化的文本,更有可能生成不寻常或意想不到的词。

4 Dify使用过程中常见问题

4.1 json超长了,超过80000个字符了

这是因为Dify限制了默认的长度。本地部署的情况下可以修改.env配置文件中的相关变量数值。 修改之后重启整个服务。

常见的参数和含义入下图所示:

重启服务所需要使用的命令:

shell 复制代码
docker compose down
docker compose up -d

参考资料

1\] https://mp.weixin.qq.com/s/n5GrGZ9hZmdhzt4avs1XSw \[2\] https://wiki.eryajf.net/pages/674f53/ \[3\] https://zhuanlan.zhihu.com/p/20939683190 \[4\] https://dify.flowus.cn/haojixing/share/943044ea-005e-4e57-9e74-450700df71c2 \[5\] https://blog.csdn.net/luckcxy/article/details/144900399

相关推荐
zybishe2 分钟前
免费送源码:Java+springboot+MySQL 房屋租赁系统小程序的设计与实现 计算机毕业设计原创定制
android·java·spring boot·mysql·docker·zookeeper·小程序
霸王蟹37 分钟前
Vue3自定义指令实现前端权限控制 - 按钮权限
前端·javascript·vue.js·笔记·学习·html
Logintern0943 分钟前
嵌入式基础知识学习:UART是什么?
学习·嵌入式·通信
郭涤生1 小时前
第十四章:模板实例化_《C++ Templates》notes
开发语言·c++·笔记
Lojarro1 小时前
MyBatis-Plus(SpringBoot版)学习第一讲:简介&入门案例
spring boot·学习·mybatis
Sean_summer1 小时前
压缩壳学习
学习·re
咯拉咯啦1 小时前
Docker 安装 Mysql
mysql·docker
霸王蟹1 小时前
Vue的性能优化方案和打包分析工具。
前端·javascript·vue.js·笔记·学习·性能优化
霸王蟹1 小时前
Pinia-构建用户仓库和持久化插件
前端·vue.js·笔记·ts·pinia·js
FakeOccupational2 小时前
生物化学笔记:医学免疫学原理02 抗原概念+免疫应答+抗原的分类
笔记