在Dify中访问Gemini等模型代理设置指南

ops/2025/3/10 20:21:14/
aidu_pl">

问题背景

Google Gemini模型可纯免费使用,且性能也相当不错,一般个人使用或研究足够。但在在国内访问,需设置代理。在Docker部署Dify时,虽然按官方文档介绍设置代理环境变量,但实测发现并不生效。我们通过研究试验解决了这个问题,并探索了可配置化的按需走代理的方法。

说明:本文主要内容不是介绍dify本地部署的内容,可参见Dify官方部署指南。如看官有兴趣,小子可以写一个专门文章。

根因分析

先说结论

Dify中访问Gemini模型使用了Google的generativeai Python SDK,底层通过gRPC进行通信,它要求代理相关的环境变量必须使用小写形式,大写形式不生效

详细分析过程

  1. Dify官方文档说明
    Dify的官方文档中提到可以通过设置环境变量(在.env.example和.env文件中)来配置代理,但没有特别说明大小写问题。文档中通常使用的是大写形式的环境变量,如HTTP_PROXYHTTPS_PROXY

     HTTP_PROXYHTTP 代理地址,用于解决国内无法访问 OpenAI、HuggingFace 的问题。注意,若代理部署在宿主机 (例如 http://127.0.0.1:7890),此处代理地址应当和接入本地模型时一样,使用 Docker 容器内部的宿主机地址(例如 http://192.168.1.100:7890 或 http://172.17.0.1:7890)。HTTPS_PROXYHTTPS 代理地址,用于解决国内无法访问 OpenAI、HuggingFace 的问题。同上。
    
  2. Gemini模型插件实现
    Dify的Gemini模型插件使用了Google的generativeai Python SDK。

  3. 底层通信机制
    Google的generativeai SDK底层使用gRPC进行通信。根据gRPC官方文档,它支持以下几个代理相关的环境变量:

    grpc_proxy, https_proxy, http_proxy The URI of the proxy to use for HTTP CONNECT support. These variables are checked in order, and the first one that has a value is used.
    no_grpc_proxy, no_proxy A comma separated list of hostnames to connect to without using a proxy even if a proxy is set. These variables are checked in order, and the first one that has a value is used.
    
  4. 问题确认
    对比Dify文档中说明的变量是大写形式(如HTTP_PROXY),而gRPC文档中是小写形式(如http_proxy)。通过实验确认,只有小写形式的环境变量对Gemini模型生效

  5. 版本差异
    对于Dify 0.15.x版本(尚未引入插件概念的版本),Gemini模型的源代码位于主仓库中,但代理环境变量的要求相同。

解决方案

同时设置大小写环境变量

最直接的解决方法是同时设置大小写两套环境变量,确保各种组件都能正确识别代理设置。

如果在Docker容器中设置了全局代理环境变量,所有HTTP请求都会走代理,这可能会导致不必要的性能开销。

虽然可能通过no_proxy(NO_PROXY)配置,但黑名单域名多起来就比较麻烦。
也可以让http proxy server那边配置,也不是所有的proxy server都能进行配置。

我们看到,dify本身是有一个ssrf_proxy的容器服务,是使用squid支持的。至于为何dify添加了这个组件,一句话:为了安全,参见官方介绍。
我们借用这个服务,更优雅地实现按需代理。因为squid是一个非常经典的代理服务器,它支持代理链(proxy chain)和域名白名单配置。

实现步骤

确保已有可用的HTTP代理服务器(相信看官都会有,如果没有小子也提供不了)

  1. 在dify/docker/.env中配置环境变量
    变量名没有使用官方指定,因为原来处理逻辑比较绕,可以简化,另外域名变量是为了使用白名单,而不是黑名单。为何分开主机和端口配置?这个是为了适配squid(ssrf_proxy),后续说明。

    
    # public http proxy server used in ssrf_proxy service(squid), change for your ip/port
    HTTP_PROXY_SERVER_HOST = 192.168.0.1
    HTTP_PROXY_SERVER_PORT = 3128
    # domains through public http proxy, space separate(if include subdomains, domain wildcard must be begin with comma)
    DOMAINS_BY_PROXY = ".googleapis.com .google.com google.dev .openai.com .anthropic.com .github.com .githubusercontent.com .githubassets.com .youtube.com .duckduckgo.com .huggingface.co .dify.ai"
  2. 修改dify/docker/ssrf_proxy/squid.conf.template
    找到以下行(40多行的位置):

    # cache_dir ufs /var/spool/squid 100 16 256
    # upstream proxy, set to your own upstream proxy IP to avoid SSRF attacks
    # cache_peer 172.1.1.1 parent 3128 0 no-query no-digest no-netdb-exchange default 

    替换为(必须要替换在原来的这个位置,因为squid有一序列的规则,有兴趣可参见官方文档):

    # 使用squid的机制实现对指定域名及其子域名走上游代理,
    cache_peer ${HTTP_PROXY_SERVER_HOST} parent ${HTTP_PROXY_SERVER_PORT} 0 no-query no-digest no-netdb-exchange default
    acl external_domains dstdomain ${DOMAINS_BY_PROXY}
    never_direct allow external_domains
    cache_peer_access ${HTTP_PROXY_SERVER_HOST} allow external_domains
    cache_peer_access ${HTTP_PROXY_SERVER_HOST} deny all
  3. 修改dify/docker/docker-compose-template.yaml
    尽量不直接修改docker-compose.yaml,但也是可行的,看官自己选择。在api、plugin_daemon、sandbox几个服务的"environment:" 节中增加如下配置

    environment:...# setting http proxy using ssrf_proxy serviceHTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}# lowercase set again for google grpc and othershttp_proxy: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}https_proxy: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
  4. 使用工具重新生成docker-compose.yaml

    cd dify/docker
    ./generate_docker_compose
    
  5. 重建container并重启

    cd dify/docker
    docker compose down
    docker compose up -d
    
  6. 验证配置
    在Dify控制台中添加Gemini模型,测试连接是否成功。如果配置正确,应该能够成功连接到Google的Gemini API服务。可以docker logs docker-ssrf_proxy-1查看日志,出现以下日志(FIRSTUP_PARENT/)说明已经走了上游代理。

    1741518209.044 260965 172.19.0.8 TCP_TUNNEL/200 13177 CONNECT generativelanguage.googleapis.com:443 - FIRSTUP_PARENT/192.168.0.1 -

Dify的Docker网络架构简要说明

这个图表主要展示了Dify系统中的网络连接情况(可能不完全准确供参考),重点突出了以下几个方面:

  1. 用户访问流程:用户通过nginx访问系统,nginx将请求分发给api和web服务

  2. 核心服务组件

    • api:核心API服务
    • web:前端Web应用
    • worker:后台工作进程
    • plugin_daemon:插件管理服务
    • sandbox:安全的代码执行环境
  3. 代理服务

    • ssrf_proxy:基于Squid的代理服务器,
aid"> aid-svg-X1zF4vHuV7U181s9" width="519.3624877929688" xmlns="http://www.w3.org/2000/svg" height="642" viewbox="0 0 519.3624877929688 642" class="mermaid-svg"> aid-svg-X1zF4vHuV7U181s9Text">
默认网络
aid-svg-X1zF4vHuV7U181s9Text">
安全代理网络
ainer">
nginx
ainer">
web
ainer">
plugin_daemon
ainer">
api
ainer">
sandbox
ainer">
worker
ainer">
ssrf_proxy
ainer">
用户
ainer">
外部网络

注意事项

  1. 本方案已在Dify 1.0.0版本上验证通过,对0.15.x系列版本也适用
  2. 如果使用SSRF代理方式,确保ssrf_proxy容器能够正常访问您的代理服务器
  3. 对于不同的模型提供商,可能需要不同的代理配置,请根据实际情况调整(国内的供应供应商一般不用配置)
  4. 另外发现dify官方域名dify.ai主机也是在国外,有时访问不畅,尤其是添加工具或插件,查看插件市场时,访问缓慢,所以可以让它也走代理,配置方案参见第3点。

总结

通过正确配置代理环境变量,特别是注意使用小写形式的环境变量,可以解决在国内环境下Dify使用Gemini模型的网络连接问题。利用Dify内置的SSRF代理组件,可以实现更灵活的按需代理配置,提高系统整体性能。

参考资料

  • Dify官方文档
  • gRPC环境变量文档
  • Google Generative AI Python SDK

http://www.ppmy.cn/ops/164744.html

相关文章

【Git】linux搭建Gitea配置mysql数据库

WindowsServer搭建内网Gitea【中文更方便使用】 1. 安装Gitea # 下载 wget https://dl.gitea.io/gitea/1.23.5/gitea-1.23.5-linux-amd642. 创建用户 # 创建 gitea 用户:这个命令的作用是创建一个名为 git 的系统用户,该用户使用 /bin/bash 作为默认 …

课题推荐——无人机在UWB环境下基于TOA/TDOA/AOA的室内定位与精度对比

随着无人机在工业检测、仓储物流、应急救援等室内场景的广泛应用,高精度室内定位技术成为关键支撑。超宽带(UWB)技术凭借其高时间分辨率、强抗多径能力等优势,成为室内定位的主流方案。然而,不同的定位方法&#xff08…

可狱可囚的爬虫系列课程 19:静态页面和动态页面之分

在爬虫开发中,静态页面和动态页面的核心区别在于数据的生成和加载方式,理解两者的差异直接影响爬虫技术选型和数据抓取策略;掌握静态/动态页面的区别,可显著提升爬虫效率和成功率。 一、静态页面(Static Page&#xf…

五子棋对弈

1.五子棋对弈 - 蓝桥云课 问题描述 “在五子棋的对弈中,友谊的小船说翻就翻?”不!对小蓝和小桥来说,五子棋不仅是棋盘上的较量,更是心与心之间的沟通。这两位挚友秉承着“友谊第一,比赛第二”的宗旨&…

Halcon:HObject与opencv:Mat互转

Halcon:HObject与opencv:Mat互转 1. Mat转HObject2. HObject转Mat 1. Mat转HObject void MatToHObject(Mat mat, out HObject hObj){int width mat.Width;int height mat.Height;HTuple type, pointer, widthTuple, heightTuple;if (mat.Channels() 1){// 单通道图像&#x…

分布式锁—4.Redisson的联锁和红锁一

大纲 1.Redisson联锁MultiLock概述 2.Redisson联锁MultiLock的加锁与释放锁 3.Redisson红锁RedLock的算法原理 4.Redisson红锁RedLock的源码分析 1.Redisson联锁MultiLock概述 (1)MultiLock的简介 (2)MultiLock的使用 (3)MultiLock的初始化 (1)MultiLock的简介 一.一次…

解析 SQL,就用 sqlparse!

文章目录 解析 SQL,就用 sqlparse!一、背景:为什么你需要 sqlparse?二、什么是 sqlparse?三、如何安装 sqlparse?四、简单易用的库函数1\. parse(sql)2\. format(sql, **options)3\. split(sql)4\. get_typ…

Android笔记:android 6.0 TextView对state_selected失效

在 Android 6.0 系统中,TextView 的 state_selected 状态失效可能由多种原因导致,下面为你详细分析原因并提供相应的解决办法。 原因分析 系统兼容性问题 Android 6.0 系统在处理视图状态和样式方面可能存在一些兼容性问题,导致 state_selec…