通过dify文件上传能力,解决较大文本与LLM实时交互问题

背景:

在调用大语言模型时,除了安全问题另外一个让用户很头疼的问题就是实时大文本交互,如果你的问题内容很多,经常遇到LLM返回内容很简单,甚至内容被截断的问题,因为达到了最大token数限制。注意这提到的是实时交互,如果不是实时交互,通过RAG技术也可以解决很多大文本交互问题。在一些官网,比如deepseek,如下图:

在网页中进行交互时,右下角会提供一个上传附件的功能,在这里你可以上传图片,文本等附件,而这些内容会被实时解读,而且可以上传较大文件内容(我上传过一个900Khtml文件,好像已经被告知有部分文件内容解析不了,600k大小是可以被完全解析的,600K纯文本内容基本可以满足我80%的需求了),但是问题又来了,我是想通过接口的形式进行调用,查了很多资料居然发现deepseek在发稿截止时官方并未提供可以上传附件的接口,只提供了普通对话接口。。。

经过多方查阅居然发现dify可以解决我的问题,dify平台的搭建和配置大家可以参考dify官方文档,在此基础上,我们进行问题的后续讨论。

一、技术栈:

  1. dify 服务

  2. 大语言模型:Gpt-4.1

  3. 编程语音:python

二、 创建工作流

我们需要在dify中创建一个Chatflow ,通过调用Chatflow接口实现大文本内容的交互,步骤如下:

  1. 创建空白应用
  1. 添加必要信息,因为我使用的是企业版,所以前面三项信息我这里都需要添加
  1. 创建工作流

我这边最终创建的工作流大致如下:

上面那条链路是处理图片分支,下面是处理文档分支

具体步骤如下:

【1】首先加入开始节点,使用系统默认配置

【2】加入条件节点,条件节点配置如下,如果文件类型是图片则走上面分支处理,其他情况都走下面路径处理:

【3】 增加列表操作节点,将其名称命名为IMAGE代表处理图片节点,配置如下图:

【4】IMAGE节点后面添加大语言模型节点,配置如下图:

注:此处需要说明较多

  • LLM我选择的是Gpt4.1 ,需要到模型配置==》管理凭据 ==》 编辑中将视觉支持修改为支持
  • 增加图片和文档上传能力
  • 打开视觉开关,如果上面视觉支持为不支持,这步视觉开关是被disable的,无法打开,这步的变量选择要和上下文中保存一致
  • 系统提示词中,输入 / 会自动弹出可选提示词,记得选择最下面的上下文,如下图我已经选择过了所以是灰色的

【5】添加模版转换节点配置如下:

【6】添加回复节点

【7】在条件节点else分支添加列表节点,名称修改为DOCS,用于开始处理文档

【8】添加文件提取器节点

【9】添加LLM节点,参数设置如下

【10】添加回复节点

按照上面流程配置起来的工作流是对图片和文档单独处理,如果想同时传递多个附件文件,同时处理图片和文档,可以将条件分支去掉后就可以进行并行处理。

三、 功能验证:

3.1 图片验证

点击预览,发送一张deepseek主页图片,让他解析,结果如下图:

3.2 文档验证

我们将图片解析内容保存到txt文件里面,然后再上传dify,让他实时读取一下文档中内容:

通过上面两张图可以看出,dify处理文件的工作流我们已经搭建好了,点击发布即可让外部应用进行接口调用了。

3.3 接口验证

3.3.1 dify接口文档

3.3.1.1 上传文件接口

注: 在接口请求时header中一般会有三个参数需要添加**,**ak 、 sid 和 appCode , sid就是下图中系统绑定管理中添加, appCode 是在创建Chatflow时填入的应用名称,ak 是秘钥,如果dify是你自己搭建的,自然知道如何获取,如果是公司搭建的,则需要找dify管理员申请,当然不同公司处理方式不同,只要和管理员沟通清楚,这些参数都可以获取到。

上传文件接口参数比较简单,post请求截图如下,用过post的应该都清楚如何填写,需要说明一下的是返回值中的id 字段就是接下来我们调用聊天接口需要传入的文件Id

python 请求代码如下:

python 复制代码
def dify_upload_file_direct(file_path, user_id):
    url = "https://******/api/v1/difyapi/files/upload"

    headers = {
        "ak": f"Bearer {os.getenv('API_KEY')}",
        "sid": "1111",
        "appCode": "*****"
    }

    with open(file_path, "rb") as file:
        if '.png' in file_path:
            my_file = {
                "file": (os.path.basename(file_path), file, 'image/png'),
            }
        else:
            my_file = {
                "file": (os.path.basename(file_path), file),
            }
        my_data = {
            "user": user_id
        }

        response = requests.post(url, data=my_data, headers=headers, files=my_file)

    if response.status_code == 200:
        file_data = response.json()
        MyLog.info(f"上传成功!文件ID: {file_data['id']}")
        return file_data['id']
    else:
        MyLog.info(f"上传失败: {response.status_code}, {response.text}")
        return None

说明:

我这里进行了偷懒处理,对于图片只处理了png图片,需要强调的是,文档上传问题不大,对于图片上传需要加上 'image/png' 这个参数,虽然这个参数在python requests请求中不是必填参数,但是对于有的dify服务器,需要带上这个参数,不然图片有可能被当做文档处理。

3.1.1.2 聊天接口

dify文档

postman请求:

type 如果是image 对于图片,document 对应文档, 如果选择本地上传 upload_file_id 为上面图片上传接口返回的id, 参数transfer_method 为 "local_file"

header参数和文件上传接口一致

python代码:

python 复制代码
def dify_chat_with_structured_file(text_message, user_id, file_ids=None, file_type=None):
    """
    使用结构化的消息格式包含文件ID

    Args:
        text_message: 文本消息
        file_ids: 文件ID或列表,可以是:
            - 字符串: 单个文件ID
            - 列表: 多个文件ID
            - 字典: {文件名: 文件ID}
    """
    url = "https://*******/api/v1/difyapi/chat-messages"

    headers = {
        "ak": f"Bearer {os.getenv('API_KEY')}",
        "sid": "1111",
        "appCode": "******"
    }

    # # 构建消息内容
    # content = []
    #
    # # 添加文本部分
    # content.append({
    #     "type": "text",
    #     "text": text_message
    # })
    #
    # # 添加文件引用部分
    # if isinstance(file_ids, dict):
    #     # 字典形式:{文件名: 文件ID}
    #     file_info = "我上传了以下文件,请参考:\n"
    #     for filename, file_id in file_ids.items():
    #         file_info += f"- {filename}: {file_id}\n"
    #     content.append({
    #         "type": "text",
    #         "text": file_info
    #     })
    # elif isinstance(file_ids, list):
    #     # 列表形式:多个文件ID
    #     file_info = f"我上传了 {len(file_ids)} 个文件,文件ID如下:\n"
    #     for i, file_id in enumerate(file_ids, 1):
    #         file_info += f"{i}. {file_id}\n"
    #     content.append({
    #         "type": "text",
    #         "text": file_info
    #     })
    # else:
    #     # 单个文件ID
    #     content.append({
    #         "type": "text",
    #         "text": f"我上传了一个文件,文件ID是:{file_ids}"
    #     })

    if file_ids:
        my_file_data = [
            {
                "type": file_type,
                "transfer_method": "local_file",
                "upload_file_id": file_ids
            }
        ]
    else:
        my_file_data = []
    data = {
        "auto_generate_name": "true",
        "conversation_id": "",
        "files": my_file_data,
        "inputs": {},
        "query": text_message,
        "response_mode": "blocking",
        "user": user_id
    }
    MyLog.info(f'发送给dfiy数据=================================\n{json.dumps(data, ensure_ascii=False)}')
    response = requests.post(url, headers=headers, json=data)
    if response.status_code == 200:
        res = json.dumps(response.json())
        # MyLog.info(f"dify 响应内容为:\n{res}")
        # 返回字典类型
        return response.json()
    else:
        MyLog.info(f"dify返回失败: {response.status_code}, {response.text}")
        return None

注:上面函数只处理了单文件上传,和上面讲的工作流是匹配的,如果需要同时上传多个文件,需要稍微修改一下dify 工作流,然后打开代码注释部分,稍微适配一下即可使用。

如果文档对你有帮助,请动动小手帮忙点个赞。

相关推荐
学习的周周啊2 小时前
ClawdBot(openclaw) + Cloudflare Tunnel + Zero-Trust 零基础保姆教程
网络·人工智能·python·clawdbot
电饭叔2 小时前
DataFrame和 Series 索引
android·python
穿过锁扣的风2 小时前
决策树:从入门到实战,解锁 AI 分类预测的核心利器
数据结构·python·决策树
爱学习的阿磊2 小时前
用Python实现自动化的Web测试(Selenium)
jvm·数据库·python
啊阿狸不会拉杆2 小时前
《机器学习导论》第 1 章 - 引言
人工智能·python·算法·机器学习·ai·numpy·matplotlib
fanstuck2 小时前
从 0 到 1 构建企业智能体平台:openJiuwen 架构解析与智能客服工作流实战
大数据·人工智能·算法·架构·aigc
阿钱真强道2 小时前
11 JetLinks MQTT 直连设备功能调用完整流程与 Python 实现
服务器·开发语言·网络·python·物联网·网络协议
2401_841495642 小时前
【LeetCode刷题】对称二叉树
数据结构·python·算法·leetcode·二叉树··递归
小饼干超人2 小时前
pytorch返回张量元素总数量的方法 x.numel()
人工智能·pytorch·python