12下一页
返回列表 发布新帖

[用户教程] 绿联NAS:搭建WeKnora — 让文档活起来:RAG、Agent 推理与自动 Wiki 一体化的知识框

432 12
发表于 4 天前 | 查看全部 阅读模式 IP:四川省成都市温江区 公众宽带

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、项目介绍
WeKnora(维娜拉) 是一款开源的、基于大语言模型(LLM)的知识管理框架,专为企业级文档理解、语义检索与智能推理场景打造。

框架围绕三大核心能力构建:RAG 快速问答适合日常知识查询,ReAct Agent 智能推理自主编排知识检索、MCP 工具与网络搜索完成复杂多步任务,全新的 Wiki 模式则让 Agent 从原始文档中自治生成相互链接的 Markdown 知识库与可视化知识图谱。结合多源数据接入(飞书 / Notion / 语雀 / RSS,更多持续接入中)、网站嵌入 Widget 将智能体发布到外部站点、权限范围 API Key 与 Principal 模型面向程序化集成、每空间多实例存储后端灵活编排数据落地、二十余家主流模型厂商集成、Langfuse 全链路可观测性与运行时任务队列面板 + Worker 池治理、企业级多空间 RBAC(四级角色矩阵 + 资源归属 + 空间审计日志),以及完全可私有化部署的模块化架构,WeKnora 帮助团队把分散文档沉淀为可查询、可推理、可持续演进的专属知识资产。

框架支持从飞书、Notion 及语雀等外部平台自动同步知识(更多数据源持续接入中),覆盖 PDF、Word、图片、Excel 等十余种文档格式,并可通过企业微信、飞书、Slack、Telegram 等 IM 频道直接提供问答服务。模型层面兼容 OpenAI、DeepSeek、Qwen(阿里云)、智谱、混元、Gemini、MiniMax、NVIDIA、Ollama 等主流厂商。全流程模块化设计,大模型、向量数据库、存储等组件均可灵活替换,支持本地与私有云部署,数据完全自主可控。WeKnora 还无缝集成了 Langfuse,为 Agent 运行、Token 使用及任务流水线提供了全面的可观测性追踪。

二、搭建教程(型号DH4300PLUS,同样适用X86机型)
1、打开文件管理器-找到docker共享文件夹-创建一个文件夹weknora;
2、下载项目到电脑文件夹-解压-编辑.env.example文件-全选内容复制粘贴一下内容;
  1. # =================================================================
  2. # WeKnora 环境变量配置(绿联云 UGOS Pro 专用)
  3. # 生成日期:2026-07-17
  4. # 说明:
  5. #   1. 端口已调至 20000+ 避免与 NAS 系统服务冲突
  6. #   2. 所有密码/密钥均为强随机值,请妥善保管
  7. #   3. AES 密钥为 64 位十六进制(即 32 字节),符合 AES-256 要求
  8. #   4. 若无需 Langfuse 可观测性,请注释掉 LANGFUSE_PUBLIC_KEY 和 SECRET_KEY
  9. # =================================================================

  10. # ---------- 基础设置 ----------
  11. # 镜像版本:latest(稳定版)或 main(最新开发版)
  12. WEKNORA_VERSION=latest

  13. # Gin 运行模式:release(生产)或 debug(开发)
  14. GIN_MODE=release

  15. # 日志级别:debug / info / warn / error / fatal
  16. LOG_LEVEL=debug

  17. # 时区(影响日志时间戳和任务调度)
  18. TZ=Asia/Shanghai

  19. # 系统默认语言(BCP-47 格式)
  20. WEKNORA_LANGUAGE=zh-CN

  21. # ---------- 端口映射(宿主机端口,可安全修改) ----------
  22. # 前端 Web 端口(原 80 -> 28080,避免与 NAS 管理界面冲突)
  23. FRONTEND_PORT=28080

  24. # 后端 API 服务端口(原 8080 -> 28081)
  25. APP_PORT=28081

  26. # 说明:以下内部端口无需修改,保持默认即可
  27. # APP_BACKEND_PORT=8080   # 容器内后端监听端口(不要改)
  28. # DB_PORT=5432            # PostgreSQL 容器内端口(不要改)
  29. # REDIS_ADDR=redis:6379   # Redis 内部地址(不要改)

  30. # ---------- 数据库配置(PostgreSQL/ParadeDB) ----------
  31. # 数据库驱动(仅支持 postgres)
  32. DB_DRIVER=postgres

  33. # 数据库主机(内部服务名,不要改)
  34. DB_HOST=postgres

  35. # 数据库内部端口(容器内监听 5432,不要改)
  36. DB_PORT=5432

  37. # 数据库用户名
  38. DB_USER=postgres

  39. # 【必须修改】数据库密码(强随机,含特殊字符,已在 compose 中正确处理)
  40. DB_PASSWORD=Ug9#kL2$mNpQ5&xZvR7wY3@

  41. # 数据库名称
  42. DB_NAME=WeKnora

  43. # ---------- Redis 配置 ----------
  44. # Redis 主机地址(内部服务名)
  45. REDIS_ADDR=redis:6379

  46. # 【必须修改】Redis 密码(强随机)
  47. REDIS_PASSWORD=Fa8#sD4&hJkL9*PqW2@

  48. # Redis 数据库索引(0-15,WeKnora 使用 0)
  49. REDIS_DB=0

  50. # Redis key 前缀(用于命名空间隔离)
  51. REDIS_PREFIX=stream:

  52. # 流处理器类型(redis 或 memory)
  53. STREAM_MANAGER_TYPE=redis

  54. # ---------- 存储配置 ----------
  55. # 向量检索驱动(postgres / qdrant / milvus / weaviate / elasticsearch 等)
  56. RETRIEVE_DRIVER=postgres

  57. # 文件存储类型(local / minio / cos / tos / s3 / obs)
  58. STORAGE_TYPE=local

  59. # 本地存储基础目录(容器内路径,由卷持久化)
  60. LOCAL_STORAGE_BASE_DIR=/data/files

  61. # 是否自动恢复脏数据
  62. AUTO_RECOVER_DIRTY=true

  63. # ---------- AES 加密密钥(必须 32 字节) ----------
  64. # 说明:此处使用 64 位十六进制表示(每个字符 4 位,共 64 字符 = 32 字节)
  65. # 若需重新生成,可执行:openssl rand -hex 32

  66. # 租户 AES 密钥
  67. TENANT_AES_KEY=8f7e2d1a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e

  68. # 系统 AES 密钥
  69. SYSTEM_AES_KEY=1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2

  70. # ---------- 安全与认证 ----------
  71. # JWT 签名密钥(64 位十六进制,安全强度高)
  72. JWT_SECRET=4f8e2d1a7b3c9e5f0d6a8b4c2e7f1a3d5b8c0e2f4a6d8b1c3e5f7a9c0d2e4f6

  73. # 是否禁止新用户公开注册(生产环境建议 true)
  74. DISABLE_REGISTRATION=false

  75. # 注册后默认空间策略(create_personal / tenantless)
  76. # WEKNORA_AUTH_DEFAULT_TENANT_MODE=create_personal

  77. # 是否允许普通用户主动创建空间(默认 true)
  78. # WEKNORA_TENANT_SELF_SERVICE_CREATION_ENABLED=true

  79. # ---------- 外部服务地址 ----------
  80. # Ollama 服务地址(若在宿主机运行,保持 host.docker.internal)
  81. OLLAMA_BASE_URL=http://host.docker.internal:11434

  82. # Docreader 服务地址(内部服务名)
  83. DOCREADER_ADDR=docreader:50051
  84. DOCREADER_TRANSPORT=grpc

  85. # ---------- 并发与性能 ----------
  86. # 嵌入/模型并发数(遇 429 可调小)
  87. CONCURRENCY_POOL_SIZE=5

  88. # 异步任务并发(可根据机器性能调整)
  89. # WEKNORA_ASYNQ_CORE_CONCURRENCY=8
  90. # WEKNORA_ASYNQ_POSTPROCESS_CONCURRENCY=2
  91. # WEKNORA_ASYNQ_ENRICHMENT_CONCURRENCY=12
  92. # WEKNORA_ASYNQ_MAINTENANCE_CONCURRENCY=4
  93. # WEKNORA_ASYNQ_SHARED_CONCURRENCY=6
  94. # WEKNORA_WIKI_ASYNQ_CONCURRENCY=8
  95. # WEKNORA_MODEL_MAX_CONCURRENCY=32

  96. # ---------- 知识图谱(Neo4j) ----------
  97. # 是否启用图 RAG(需额外资源,默认关闭)
  98. ENABLE_GRAPH_RAG=false

  99. # Neo4j 连接参数(若启用请取消注释并配置)
  100. # NEO4J_ENABLE=false
  101. # NEO4J_URI=bolt://neo4j:7687
  102. # NEO4J_USERNAME=neo4j
  103. # NEO4J_PASSWORD=password

  104. # ---------- Agent 沙箱 ----------
  105. # 沙箱模式:docker / local / disabled
  106. WEKNORA_SANDBOX_MODE=docker

  107. # 脚本执行超时(秒)
  108. WEKNORA_SANDBOX_TIMEOUT=60

  109. # Agent LLM 调用超时(秒),复杂任务可调大
  110. # WEKNORA_AGENT_LLM_TIMEOUT=300

  111. # MCP 工具人工审核等待超时(秒)
  112. # WEKNORA_AGENT_TOOL_APPROVAL_TIMEOUT=600

  113. # ---------- 租户与 RBAC ----------
  114. # 启用空间级 RBAC(默认 true)
  115. # WEKNORA_TENANT_ENABLE_RBAC=true

  116. # 单个用户最大可创建空间数(0 使用默认,-1 关闭限制)
  117. # WEKNORA_TENANT_MAX_OWNED_PER_USER=

  118. # 创建空间时是否自动生成全量 API Key(默认 false)
  119. # WEKNORA_TENANT_AUTO_CREATE_API_KEY=false

  120. # 系统管理员引导邮箱(首次启动自动提权)
  121. # WEKNORA_BOOTSTRAP_SYSTEM_ADMIN_EMAIL=

  122. # ---------- 聊天附件与 OCR ----------
  123. # 附件保留时间(小时)
  124. # WEKNORA_CHAT_ATTACHMENT_TTL_HOURS=24

  125. # 附件解析等待超时(秒)
  126. # WEKNORA_CHAT_ATTACHMENT_WAIT_TIMEOUT_SEC=60

  127. # OCR 并发数
  128. # WEKNORA_CHAT_ATTACHMENT_OCR_CONCURRENCY=8

  129. # OCR 最大页数
  130. # WEKNORA_CHAT_ATTACHMENT_OCR_MAX_PAGES=8

  131. # ---------- SSRF 白名单 ----------
  132. # 默认已包含内置服务(searxng, qdrant, milvus, weaviate, doris-fe)
  133. # 若需添加自定义地址,请追加到 SSRF_WHITELIST_EXTRA
  134. SSRF_WHITELIST_EXTRA=searxng,qdrant,milvus,weaviate,doris-fe

  135. # ---------- Langfuse 可观测性(可选) ----------
  136. # 注意:若不使用,请将下面两行注释掉,否则应用启动会尝试连接 Langfuse
  137. # LANGFUSE_PUBLIC_KEY=pk-lf-xxxxxxxx
  138. # LANGFUSE_SECRET_KEY=sk-lf-xxxxxxxx

  139. # 若自建 Langfuse,取消注释并设置 HOST
  140. # LANGFUSE_HOST=http://langfuse-web:3000

  141. # 其他 Langfuse 参数(可选)
  142. # LANGFUSE_RELEASE=v0.4.2
  143. # LANGFUSE_ENVIRONMENT=production
  144. # LANGFUSE_FLUSH_AT=15
  145. # LANGFUSE_SAMPLE_RATE=1.0

  146. # ---------- APK 镜像源(加速 Alpine 构建) ----------
  147. APK_MIRROR_ARG=mirrors.tencent.com

  148. # ---------- 以下为高级存储配置(按需启用) ----------
  149. # 若需使用 MinIO,取消注释并配置,同时启用 profile minio
  150. # MINIO_ENDPOINT=minio:9000
  151. # MINIO_ACCESS_KEY_ID=minioadmin
  152. # MINIO_SECRET_ACCESS_KEY=minioadmin
  153. # MINIO_BUCKET_NAME=weknora

  154. # 腾讯云 COS
  155. # COS_SECRET_ID=xxx
  156. # COS_SECRET_KEY=xxx
  157. # COS_REGION=ap-guangzhou
  158. # COS_BUCKET_NAME=xxx
  159. # COS_APP_ID=xxx
  160. # COS_PATH_PREFIX=weknora/
  161. # COS_ENABLE_OLD_DOMAIN=true

  162. # 华为 OBS
  163. # OBS_ENDPOINT=obs.cn-north-4.myhuaweicloud.com
  164. # OBS_REGION=cn-north-4
  165. # OBS_ACCESS_KEY=xxx
  166. # OBS_SECRET_KEY=xxx
  167. # OBS_BUCKET_NAME=xxx
  168. # OBS_PATH_PREFIX=weknora/

  169. # AWS S3
  170. # S3_ENDPOINT=https://s3.amazonaws.com
  171. # S3_REGION=us-east-1
  172. # S3_ACCESS_KEY=xxx
  173. # S3_SECRET_KEY=xxx
  174. # S3_BUCKET_NAME=xxx
  175. # S3_PATH_PREFIX=weknora/

  176. # ---------- 其他向量数据库(按需启用) ----------
  177. # Qdrant
  178. # QDRANT_HOST=qdrant
  179. # QDRANT_PORT=6334
  180. # QDRANT_COLLECTION=weknora_embeddings

  181. # Milvus
  182. # MILVUS_ADDRESS=milvus:19530
  183. # MILVUS_COLLECTION=weknora_embeddings
  184. # MILVUS_METRIC_TYPE=IP

  185. # Weaviate
  186. # WEAVIATE_HOST=weaviate:8080
  187. # WEAVIATE_GRPC_ADDRESS=weaviate:50051
  188. # WEAVIATE_SCHEME=http
  189. # WEAVIATE_AUTH_ENABLED=false

  190. # Doris
  191. # DORIS_ADDR=doris-fe:9030
  192. # DORIS_HTTP_PORT=8030
  193. # DORIS_DATABASE=weknora
  194. # DORIS_USERNAME=root
  195. # DORIS_PASSWORD=
  196. # DORIS_TABLE_PREFIX=weknora_embeddings

  197. # ---------- 文件上传大小限制 ----------
  198. # MAX_FILE_SIZE_MB=50

  199. # ---------- 外部访问 URL(用于 IM 渠道) ----------
  200. # APP_EXTERNAL_URL=http://你的公网IP:28080
复制代码

3、保存后把文件名修改为.env,然后打开文件管理器,找到左小角设置-隐藏指定文件-取消以点开头-保存;

1

1

2

2


4、把解压的所有文件传到weknora文件夹,文件较多一定要等待所有文件传输完成;

3

3


5、打开docker-选择项目-创建-输入项目名weknora-自动带出存放路径;

4

4


6、把下方docker compose粘贴进去;
  1. # =============================================================================
  2. # WeKnora Docker Compose 配置(绿联云 UGOS Pro 专用)
  3. # 版本:最新稳定版
  4. # 说明:所有可变值均通过 .env 文件注入,请勿硬编码敏感信息
  5. # 使用前请确保 ./config/config.yaml 存在,且 Redis 密码不含易被 shell 截断的字符
  6. # =============================================================================

  7. # ---------- 网络定义 ----------
  8. # 所有服务共享此内部网络,通过服务名(如 app、postgres)互相访问
  9. networks:
  10.   WeKnora-network:
  11.     driver: bridge

  12. # ---------- 卷定义 ----------
  13. # 命名卷由 Docker 管理,数据保存在 Docker 数据目录(如 /var/lib/docker/volumes/)
  14. # 建议定期备份 postgres-data 和 data-files(核心业务数据)
  15. volumes:
  16.   postgres-data:            # PostgreSQL 数据库文件(最重要!)
  17.   data-files:               # 用户上传的文档、图片等(核心数据)
  18.   docreader-tmp:            # 文档解析临时文件(可随时清理)
  19.   minio_data:               # MinIO 对象存储数据(若启用 minio profile)
  20.   neo4j-data:               # Neo4j 图数据库数据(若启用 neo4j profile)
  21.   qdrant_data:              # Qdrant 向量库数据(若启用 qdrant profile)
  22.   milvus_data:              # Milvus 向量库数据(若启用 milvus profile)
  23.   weaviate_data:            # Weaviate 向量库数据(若启用 weaviate profile)
  24.   doris_fe_meta:            # Doris FE 元数据(若启用 doris profile)
  25.   doris_fe_log:             # Doris FE 日志
  26.   doris_be_storage:         # Doris BE 存储
  27.   doris_be_log:             # Doris BE 日志
  28.   langfuse_clickhouse_data: # Langfuse ClickHouse 数据(若启用 langfuse profile)
  29.   langfuse_clickhouse_logs: # Langfuse ClickHouse 日志
  30.   langfuse_minio_data:      # Langfuse 专用 MinIO 数据
  31.   searxng_config:           # SearXNG 配置文件卷(若启用 searxng profile)

  32. # ---------- 服务定义 ----------
  33. services:

  34.   # ============================================================
  35.   # 1. 前端服务 (frontend)
  36.   # 基于 Nginx 提供 Web 界面,并反向代理 API 请求到后端
  37.   # ============================================================
  38.   frontend:
  39.     image: wechatopenai/weknora-ui:${WEKNORA_VERSION:-latest}
  40.     # 若需本地构建,需先执行 ./scripts/build_frontend_dist.sh
  41.     build:
  42.       context: ./frontend
  43.     container_name: WeKnora-frontend
  44.     # 宿主机端口由 FRONTEND_PORT 控制(默认 80,现已改为 28080)
  45.     ports:
  46.       - "${FRONTEND_PORT:-80}:80"
  47.     environment:
  48.       - MAX_FILE_SIZE_MB=${MAX_FILE_SIZE_MB:-50}
  49.       - APP_HOST=${APP_HOST:-app}             # 后端服务名(容器内 DNS)
  50.       - APP_PORT=${APP_BACKEND_PORT:-8080}    # 后端容器监听端口
  51.       - APP_SCHEME=${APP_SCHEME:-http}        # 协议(http/https)
  52.     depends_on:
  53.       app:
  54.         condition: service_healthy   # 等待 app 健康后再启动
  55.     networks:
  56.       - WeKnora-network
  57.     restart: unless-stopped

  58.   # ============================================================
  59.   # 2. 后端应用服务 (app)
  60.   # 核心业务:知识库管理、对话、检索、Agent、文件处理等
  61.   # ============================================================
  62.   app:
  63.     image: wechatopenai/weknora-app:${WEKNORA_VERSION:-latest}
  64.     build:
  65.       context: .
  66.       dockerfile: docker/Dockerfile.app
  67.       args:
  68.         - APK_MIRROR_ARG=${APK_MIRROR_ARG:-}   # Alpine 镜像源加速(如 mirrors.tencent.com)
  69.     container_name: WeKnora-app
  70.     # 宿主机端口由 APP_PORT 控制(默认 8080,现已改为 28081)
  71.     ports:
  72.       - "${APP_PORT:-8080}:8080"
  73.     volumes:
  74.       # --- 命名卷(Docker 管理,推荐用于有状态数据) ---
  75.       - data-files:/data/files               # 上传文件持久化(务必定期备份)
  76.       - docreader-tmp:/tmp/docreader:ro      # 只读挂载 docreader 临时目录
  77.       # --- 绑定挂载(相对路径,便于直接编辑) ---
  78.       - ./config/config.yaml:/app/config/config.yaml   # 主配置文件(必须存在!)
  79.       - ./skills/preloaded:/app/skills/preloaded       # 自定义技能目录(可选)
  80.       # 若需内置模型声明,可复制 config/builtin_models.yaml.example 并取消注释下行
  81.       # - ./config/builtin_models.yaml:/app/config/builtin_models.yaml:ro
  82.     healthcheck:
  83.       test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
  84.       interval: 30s
  85.       timeout: 10s
  86.       retries: 3
  87.       start_period: 60s
  88.     # 从 .env 加载全部环境变量,供配置文件(如 builtin_models.yaml)使用 ${VAR} 引用
  89.     env_file:
  90.       - .env
  91.     environment:
  92.       # 以下所有变量均从 .env 读取,若未设置则使用默认值
  93.       - LOG_LEVEL=${LOG_LEVEL:-}
  94.       # --- 对象存储(腾讯云 COS) ---
  95.       - COS_SECRET_ID=${COS_SECRET_ID:-}
  96.       - COS_SECRET_KEY=${COS_SECRET_KEY:-}
  97.       - COS_REGION=${COS_REGION:-}
  98.       - COS_BUCKET_NAME=${COS_BUCKET_NAME:-}
  99.       - COS_APP_ID=${COS_APP_ID:-}
  100.       - COS_PATH_PREFIX=${COS_PATH_PREFIX:-}
  101.       - COS_ENABLE_OLD_DOMAIN=${COS_ENABLE_OLD_DOMAIN:-}
  102.       # --- 运行模式与安全 ---
  103.       - GIN_MODE=${GIN_MODE:-release}
  104.       - DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-false}
  105.       - WEKNORA_AUTH_DEFAULT_TENANT_MODE=${WEKNORA_AUTH_DEFAULT_TENANT_MODE:-}
  106.       - WEKNORA_TENANT_SELF_SERVICE_CREATION_ENABLED=${WEKNORA_TENANT_SELF_SERVICE_CREATION_ENABLED:-}
  107.       # --- 数据库(PostgreSQL) ---
  108.       - DB_DRIVER=${DB_DRIVER:-postgres}
  109.       - DB_HOST=${DB_HOST:-postgres}         # 内部服务名,不要改
  110.       - DB_PORT=${DB_PORT:-5432}             # 容器内部端口,不要改!
  111.       - DB_USER=${DB_USER:-}
  112.       - DB_PASSWORD=${DB_PASSWORD:-}
  113.       - DB_NAME=${DB_NAME:-}
  114.       - TZ=${TZ:-Asia/Shanghai}
  115.       - WEKNORA_LANGUAGE=${WEKNORA_LANGUAGE:-zh-CN}
  116.       # --- Langfuse 可观测性(可选) ---
  117.       # 同时设置 PUBLIC_KEY 和 SECRET_KEY 即自动启用
  118.       - LANGFUSE_ENABLED=${LANGFUSE_ENABLED:-}
  119.       - LANGFUSE_HOST=${LANGFUSE_HOST:-https://cloud.langfuse.com}
  120.       - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-}
  121.       - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-}
  122.       - LANGFUSE_RELEASE=${LANGFUSE_RELEASE:-}
  123.       - LANGFUSE_ENVIRONMENT=${LANGFUSE_ENVIRONMENT:-}
  124.       - LANGFUSE_FLUSH_AT=${LANGFUSE_FLUSH_AT:-}
  125.       - LANGFUSE_FLUSH_INTERVAL=${LANGFUSE_FLUSH_INTERVAL:-}
  126.       - LANGFUSE_QUEUE_SIZE=${LANGFUSE_QUEUE_SIZE:-}
  127.       - LANGFUSE_REQUEST_TIMEOUT=${LANGFUSE_REQUEST_TIMEOUT:-}
  128.       - LANGFUSE_SAMPLE_RATE=${LANGFUSE_SAMPLE_RATE:-}
  129.       - LANGFUSE_DEBUG=${LANGFUSE_DEBUG:-}
  130.       # --- 向量检索驱动 ---
  131.       - RETRIEVE_DRIVER=${RETRIEVE_DRIVER:-}
  132.       # Elasticsearch
  133.       - ELASTICSEARCH_ADDR=${ELASTICSEARCH_ADDR:-}
  134.       - ELASTICSEARCH_USERNAME=${ELASTICSEARCH_USERNAME:-}
  135.       - ELASTICSEARCH_PASSWORD=${ELASTICSEARCH_PASSWORD:-}
  136.       - ELASTICSEARCH_INDEX=${ELASTICSEARCH_INDEX:-}
  137.       # Qdrant
  138.       - QDRANT_HOST=${QDRANT_HOST:-qdrant}
  139.       - QDRANT_PORT=${QDRANT_PORT:-6334}
  140.       - QDRANT_COLLECTION=${QDRANT_COLLECTION:-weknora_embeddings}
  141.       - QDRANT_API_KEY=${QDRANT_API_KEY:-}
  142.       - QDRANT_USE_TLS=${QDRANT_USE_TLS:-false}
  143.       # Milvus
  144.       - MILVUS_ADDRESS=${MILVUS_ADDRESS:-milvus:19530}
  145.       - MILVUS_COLLECTION=${MILVUS_COLLECTION:-weknora_embeddings}
  146.       - MILVUS_METRIC_TYPE=${MILVUS_METRIC_TYPE:-IP}
  147.       # --- 文档解析服务 ---
  148.       - DOCREADER_ADDR=${DOCREADER_ADDR:-docreader:50051}
  149.       - DOCREADER_TRANSPORT=${DOCREADER_TRANSPORT:-grpc}
  150.       - GRPC_TLS_ENABLED=${GRPC_TLS_ENABLED:-false}
  151.       - GRPC_TLS_CERT=${GRPC_TLS_CERT:-}
  152.       - GRPC_TLS_KEY=${GRPC_TLS_KEY:-}
  153.       - GRPC_TLS_CA=${GRPC_TLS_CA:-}
  154.       - GRPC_TLS_SERVER_NAME=${GRPC_TLS_SERVER_NAME:-}
  155.       - GRPC_AUTH_TOKEN=${GRPC_AUTH_TOKEN:-}
  156.       # Weaviate
  157.       - WEAVIATE_HOST=${WEAVIATE_HOST:-weaviate:8080}
  158.       - WEAVIATE_GRPC_ADDRESS=${WEAVIATE_GRPC_ADDRESS:-weaviate:50051}
  159.       - WEAVIATE_SCHEME=${WEAVIATE_SCHEME:-http}
  160.       - WEAVIATE_AUTH_ENABLED=${WEAVIATE_AUTH_ENABLED:-false}
  161.       - WEAVIATE_API_KEY=${WEAVIATE_API_KEY:-}
  162.       # Apache Doris
  163.       - DORIS_ADDR=${DORIS_ADDR:-doris-fe:9030}
  164.       - DORIS_HTTP_PORT=${DORIS_HTTP_PORT:-8030}
  165.       - DORIS_DATABASE=${DORIS_DATABASE:-weknora}
  166.       - DORIS_USERNAME=${DORIS_USERNAME:-root}
  167.       - DORIS_PASSWORD=${DORIS_PASSWORD:-}
  168.       - DORIS_TABLE_PREFIX=${DORIS_TABLE_PREFIX:-weknora_embeddings}
  169.       - DORIS_COMPAT_MODE=${DORIS_COMPAT_MODE:-auto}
  170.       # --- 文件存储 ---
  171.       - STORAGE_TYPE=${STORAGE_TYPE:-}
  172.       - LOCAL_STORAGE_BASE_DIR=${LOCAL_STORAGE_BASE_DIR:-}
  173.       - AUTO_RECOVER_DIRTY=${AUTO_RECOVER_DIRTY:-true}
  174.       # MinIO
  175.       - MINIO_ENDPOINT=${MINIO_ENDPOINT:-minio:9000}
  176.       - MINIO_ACCESS_KEY_ID=${MINIO_ACCESS_KEY_ID:-minioadmin}
  177.       - MINIO_SECRET_ACCESS_KEY=${MINIO_SECRET_ACCESS_KEY:-minioadmin}
  178.       - MINIO_BUCKET_NAME=${MINIO_BUCKET_NAME:-}
  179.       # 华为 OBS
  180.       - OBS_ENDPOINT=${OBS_ENDPOINT:-}
  181.       - OBS_REGION=${OBS_REGION:-}
  182.       - OBS_ACCESS_KEY=${OBS_ACCESS_KEY:-}
  183.       - OBS_SECRET_KEY=${OBS_SECRET_KEY:-}
  184.       - OBS_BUCKET_NAME=${OBS_BUCKET_NAME:-}
  185.       - OBS_PATH_PREFIX=${OBS_PATH_PREFIX:-}
  186.       - OBS_PROXY_DOMAIN=${OBS_PROXY_DOMAIN:-}
  187.       # --- Ollama ---
  188.       - OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
  189.       # --- 流管理 ---
  190.       - STREAM_MANAGER_TYPE=${STREAM_MANAGER_TYPE:-}
  191.       # --- Redis ---
  192.       - REDIS_ADDR=${REDIS_ADDR:-redis:6379}
  193.       - REDIS_USERNAME=${REDIS_USERNAME:-}
  194.       - REDIS_PASSWORD=${REDIS_PASSWORD:-}
  195.       - REDIS_DB=${REDIS_DB:-}
  196.       - REDIS_PREFIX=${REDIS_PREFIX:-}
  197.       # --- 图 RAG(Neo4j) ---
  198.       - ENABLE_GRAPH_RAG=${ENABLE_GRAPH_RAG:-}
  199.       - NEO4J_ENABLE=${NEO4J_ENABLE:-}
  200.       - NEO4J_URI=${NEO4J_URI:-bolt://neo4j:7687}
  201.       - NEO4J_USERNAME=${NEO4J_USERNAME:-neo4j}
  202.       - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
  203.       # --- 加密密钥 ---
  204.       - TENANT_AES_KEY=${TENANT_AES_KEY:-}
  205.       - SYSTEM_AES_KEY=${SYSTEM_AES_KEY:-}
  206.       # --- SSRF 白名单 ---
  207.       - SSRF_WHITELIST=${SSRF_WHITELIST:-}
  208.       - IMAGE_HOST_KEEP_URL=${IMAGE_HOST_KEEP_URL:-}
  209.       - SSRF_WHITELIST_EXTRA=${SSRF_WHITELIST_EXTRA:-searxng,qdrant,milvus,weaviate,doris-fe}
  210.       # --- 并发与性能 ---
  211.       - CONCURRENCY_POOL_SIZE=${CONCURRENCY_POOL_SIZE:-5}
  212.       - JWT_SECRET=${JWT_SECRET:-}
  213.       - CRYPTO_MASTER_KEY=${CRYPTO_MASTER_KEY:-}
  214.       - CRYPTO_SALT=${CRYPTO_SALT:-}
  215.       - MAX_FILE_SIZE_MB=${MAX_FILE_SIZE_MB:-50}
  216.       # --- 聊天附件 ---
  217.       - WEKNORA_CHAT_ATTACHMENT_TTL_HOURS=${WEKNORA_CHAT_ATTACHMENT_TTL_HOURS:-24}
  218.       - WEKNORA_CHAT_ATTACHMENT_WAIT_TIMEOUT_SEC=${WEKNORA_CHAT_ATTACHMENT_WAIT_TIMEOUT_SEC:-60}
  219.       - WEKNORA_CHAT_ATTACHMENT_OCR_CONCURRENCY=${WEKNORA_CHAT_ATTACHMENT_OCR_CONCURRENCY:-8}
  220.       - WEKNORA_CHAT_ATTACHMENT_OCR_MAX_PAGES=${WEKNORA_CHAT_ATTACHMENT_OCR_MAX_PAGES:-8}
  221.       # --- Agent 沙箱 ---
  222.       - WEKNORA_SANDBOX_MODE=${WEKNORA_SANDBOX_MODE:-docker}
  223.       - WEKNORA_SANDBOX_TIMEOUT=${WEKNORA_SANDBOX_TIMEOUT:-60}
  224.       - WEKNORA_SANDBOX_DOCKER_IMAGE=${WEKNORA_SANDBOX_DOCKER_IMAGE:-wechatopenai/weknora-sandbox:${WEKNORA_VERSION:-latest}}
  225.       - WEKNORA_AGENT_LLM_TIMEOUT=${WEKNORA_AGENT_LLM_TIMEOUT:-}
  226.       - WEKNORA_AGENT_TOOL_APPROVAL_TIMEOUT=${WEKNORA_AGENT_TOOL_APPROVAL_TIMEOUT:-}
  227.       # --- 租户 RBAC ---
  228.       - WEKNORA_TENANT_ENABLE_RBAC=${WEKNORA_TENANT_ENABLE_RBAC:-}
  229.       - WEKNORA_TENANT_MAX_OWNED_PER_USER=${WEKNORA_TENANT_MAX_OWNED_PER_USER:-}
  230.       - WEKNORA_TENANT_AUTO_CREATE_API_KEY=${WEKNORA_TENANT_AUTO_CREATE_API_KEY:-}
  231.       # --- 异步任务并发控制 ---
  232.       - WEKNORA_ASYNQ_CORE_CONCURRENCY=${WEKNORA_ASYNQ_CORE_CONCURRENCY:-8}
  233.       - WEKNORA_ASYNQ_POSTPROCESS_CONCURRENCY=${WEKNORA_ASYNQ_POSTPROCESS_CONCURRENCY:-2}
  234.       - WEKNORA_ASYNQ_ENRICHMENT_CONCURRENCY=${WEKNORA_ASYNQ_ENRICHMENT_CONCURRENCY:-12}
  235.       - WEKNORA_ASYNQ_MAINTENANCE_CONCURRENCY=${WEKNORA_ASYNQ_MAINTENANCE_CONCURRENCY:-4}
  236.       - WEKNORA_ASYNQ_SHARED_CONCURRENCY=${WEKNORA_ASYNQ_SHARED_CONCURRENCY:-6}
  237.       - WEKNORA_WIKI_ASYNQ_CONCURRENCY=${WEKNORA_WIKI_ASYNQ_CONCURRENCY:-8}
  238.       - WEKNORA_MODEL_MAX_CONCURRENCY=${WEKNORA_MODEL_MAX_CONCURRENCY:-32}
  239.       - APK_MIRROR_ARG=${APK_MIRROR_ARG:-}
  240.       - WEKNORA_BOOTSTRAP_SYSTEM_ADMIN_EMAIL=${WEKNORA_BOOTSTRAP_SYSTEM_ADMIN_EMAIL:-}
  241.     depends_on:
  242.       redis:
  243.         condition: service_started
  244.       postgres:
  245.         condition: service_healthy
  246.       docreader:
  247.         condition: service_healthy
  248.     networks:
  249.       - WeKnora-network
  250.     restart: unless-stopped
  251.     extra_hosts:
  252.       - "host.docker.internal:host-gateway"   # 使容器能访问宿主机的 Ollama 等服务

  253.   # ============================================================
  254.   # 3. 沙箱服务 (sandbox)
  255.   # 仅用于构建/拉取沙箱镜像,实际 Skills 执行由 app 通过 Docker API 按需启动
  256.   # ============================================================
  257.   sandbox:
  258.     image: wechatopenai/weknora-sandbox:${WEKNORA_VERSION:-latest}
  259.     container_name: WeKnora-sandbox
  260.     build:
  261.       context: .
  262.       dockerfile: docker/Dockerfile.sandbox
  263.     profiles:
  264.       - full
  265.     command: ["true"]
  266.     restart: "no"

  267.   # ============================================================
  268.   # 4. 文档解析服务 (docreader)
  269.   # 提供 gRPC 接口,用于 PDF、Office、图片的解析、OCR 和版式识别
  270.   # ============================================================
  271.   docreader:
  272.     image: wechatopenai/weknora-docreader:${WEKNORA_VERSION:-latest}
  273.     build:
  274.       context: .
  275.       dockerfile: docker/Dockerfile.docreader
  276.       args:
  277.         - APT_MIRROR=${APT_MIRROR:-}
  278.     container_name: WeKnora-docreader
  279.     expose:
  280.       - "50051"           # 仅内部网络可访问,不映射到宿主机
  281.     volumes:
  282.       - docreader-tmp:/tmp/docreader
  283.     environment:
  284.       - TZ=${TZ:-Asia/Shanghai}
  285.       - DOCREADER_IMAGE_OUTPUT_DIR=/tmp/docreader
  286.       - DOCREADER_PDF_FORCE_SCANNED=${DOCREADER_PDF_FORCE_SCANNED:-false}
  287.       - MAX_FILE_SIZE_MB=${MAX_FILE_SIZE_MB:-}
  288.       - DOCREADER_ODL_MAX_WORKERS=${DOCREADER_ODL_MAX_WORKERS:-1}
  289.       - DOCREADER_ODL_HYBRID=${DOCREADER_ODL_HYBRID:-off}
  290.       - DOCREADER_ODL_HYBRID_URL=${DOCREADER_ODL_HYBRID_URL:-http://odl-hybrid:5002}
  291.       - DOCREADER_ODL_HYBRID_MODE=${DOCREADER_ODL_HYBRID_MODE:-auto}
  292.       - DOCREADER_ODL_HYBRID_FALLBACK=${DOCREADER_ODL_HYBRID_FALLBACK:-false}
  293.       - DOCREADER_ODL_MARKDOWN_WITH_HTML=${DOCREADER_ODL_MARKDOWN_WITH_HTML:-false}
  294.       - DOCREADER_MARKITDOWN_MAX_WORKERS=${DOCREADER_MARKITDOWN_MAX_WORKERS:-1}
  295.       - DOCREADER_PDF_RENDER_MAX_WORKERS=${DOCREADER_PDF_RENDER_MAX_WORKERS:-1}
  296.       - DOCREADER_PDF_RENDER_DPI=${DOCREADER_PDF_RENDER_DPI:-200}
  297.       - DOCREADER_PDF_JPEG_QUALITY=${DOCREADER_PDF_JPEG_QUALITY:-90}
  298.       - GRPC_TLS_ENABLED=${GRPC_TLS_ENABLED:-false}
  299.       - GRPC_TLS_CERT=${GRPC_TLS_CERT:-}
  300.       - GRPC_TLS_KEY=${GRPC_TLS_KEY:-}
  301.       - GRPC_TLS_CA=${GRPC_TLS_CA:-}
  302.       - GRPC_AUTH_TOKEN=${GRPC_AUTH_TOKEN:-}
  303.     healthcheck:
  304.       test: ["CMD", "grpc_health_probe", "-addr=localhost:50051"]
  305.       interval: 30s
  306.       timeout: 10s
  307.       retries: 3
  308.       start_period: 60s
  309.     networks:
  310.       - WeKnora-network
  311.     restart: unless-stopped
  312.     extra_hosts:
  313.       - "host.docker.internal:host-gateway"

  314.   # ============================================================
  315.   # 5. OpenDataLoader Hybrid(可选增强解析器)
  316.   # 启用 profile odl-hybrid 并本地构建(镜像 tag: local)
  317.   # ============================================================
  318.   odl-hybrid:
  319.     build:
  320.       context: .
  321.       dockerfile: docker/Dockerfile.odl-hybrid
  322.     image: weknora-odl-hybrid:local
  323.     container_name: WeKnora-odl-hybrid
  324.     profiles:
  325.       - odl-hybrid
  326.     expose:
  327.       - "5002"
  328.     environment:
  329.       - ODL_HYBRID_EXTRA_ARGS=${ODL_HYBRID_EXTRA_ARGS:---no-ocr}
  330.     networks:
  331.       - WeKnora-network
  332.     restart: unless-stopped

  333.   # ============================================================
  334.   # 6. PostgreSQL + ParadeDB(主数据库)
  335.   # 存储业务数据、向量嵌入、全文检索
  336.   # ============================================================
  337.   postgres:
  338.     image: paradedb/paradedb:v0.22.2-pg17
  339.     container_name: WeKnora-postgres
  340.     environment:
  341.       - POSTGRES_USER=${DB_USER}
  342.       - POSTGRES_PASSWORD=${DB_PASSWORD}
  343.       - POSTGRES_DB=${DB_NAME}
  344.     volumes:
  345.       - postgres-data:/var/lib/postgresql/data
  346.     networks:
  347.       - WeKnora-network
  348.     healthcheck:
  349.       test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
  350.       interval: 10s
  351.       timeout: 10s
  352.       retries: 3
  353.       start_period: 30s
  354.     restart: unless-stopped
  355.     stop_grace_period: 1m
  356.     # 若需从宿主机外部连接数据库(如 pgAdmin),可取消注释下行
  357.     # ports:
  358.     #   - "25432:5432"

  359.   # ============================================================
  360.   # 7. Redis(缓存 / 消息队列)
  361.   # 注意:command 使用数组格式,避免密码中的特殊字符被 shell 截断
  362.   # ============================================================
  363.   redis:
  364.     image: redis:7.0-alpine
  365.     container_name: WeKnora-redis
  366.     command:
  367.       - redis-server
  368.       - --appendonly
  369.       - yes
  370.       - --requirepass
  371.       - ${REDIS_PASSWORD}
  372.     restart: always
  373.     networks:
  374.       - WeKnora-network

  375.   # ============================================================
  376.   # 8. SearXNG 初始化器(一次性)
  377.   # 将模板 settings.yml 复制到配置卷
  378.   # ============================================================
  379.   searxng-init:
  380.     image: busybox:1.36
  381.     container_name: WeKnora-searxng-init
  382.     command: ["sh", "-c", "cp /template/settings.yml /etc/searxng/settings.yml && chmod 0644 /etc/searxng/settings.yml"]
  383.     volumes:
  384.       - ./docker/searxng/settings.yml:/template/settings.yml:ro
  385.       - searxng_config:/etc/searxng
  386.     restart: "no"
  387.     networks:
  388.       - WeKnora-network
  389.     profiles:
  390.       - searxng
  391.       - full

  392.   # ============================================================
  393.   # 9. SearXNG 搜索引擎(可选)
  394.   # 提供元搜索能力,默认仅绑定 127.0.0.1 确保安全
  395.   # ============================================================
  396.   searxng:
  397.     image: searxng/searxng:latest
  398.     container_name: WeKnora-searxng
  399.     ports:
  400.       - "${SEARXNG_BIND:-127.0.0.1}:${SEARXNG_PORT:-8888}:8080"
  401.     volumes:
  402.       - searxng_config:/etc/searxng
  403.     environment:
  404.       - SEARXNG_BASE_URL=http://localhost:${SEARXNG_PORT:-8888}/
  405.       - INSTANCE_NAME=weknora-searxng
  406.       - SEARXNG_SECRET=${SEARXNG_SECRET:-weknora-default-searxng-secret-rotate-before-exposing-publicly}
  407.     cap_drop:
  408.       - ALL
  409.     cap_add:
  410.       - CHOWN
  411.       - SETGID
  412.       - SETUID
  413.     restart: unless-stopped
  414.     depends_on:
  415.       searxng-init:
  416.         condition: service_completed_successfully
  417.     networks:
  418.       - WeKnora-network
  419.     profiles:
  420.       - searxng
  421.       - full

  422.   # ============================================================
  423.   # 10. MinIO(可选对象存储)
  424.   # 启用 profile minio 后使用,替代 local 存储
  425.   # ============================================================
  426.   minio:
  427.     image: minio/minio:RELEASE.2025-09-07T16-13-09Z
  428.     container_name: WeKnora-minio
  429.     ports:
  430.       - "${MINIO_PORT:-9000}:9000"
  431.       - "${MINIO_CONSOLE_PORT:-9001}:9001"
  432.     environment:
  433.       - MINIO_ROOT_USER=${MINIO_ACCESS_KEY_ID:-minioadmin}
  434.       - MINIO_ROOT_PASSWORD=${MINIO_SECRET_ACCESS_KEY:-minioadmin}
  435.     command: server --console-address ":9001" /data
  436.     volumes:
  437.       - minio_data:/data
  438.     healthcheck:
  439.       test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
  440.       interval: 30s
  441.       timeout: 20s
  442.       retries: 3
  443.     networks:
  444.       - WeKnora-network
  445.     profiles:
  446.       - minio
  447.       - full

  448.   # ============================================================
  449.   # 11. Neo4j(可选图数据库)
  450.   # 用于知识图谱构建,启用 profile neo4j
  451.   # ============================================================
  452.   neo4j:
  453.     image: neo4j:2025.10.1
  454.     container_name: WeKnora-neo4j
  455.     volumes:
  456.       - neo4j-data:/data
  457.     environment:
  458.       - NEO4J_AUTH=${NEO4J_USERNAME:-neo4j}/${NEO4J_PASSWORD:-password}
  459.       - NEO4J_apoc_export_file_enabled=true
  460.       - NEO4J_apoc_import_file_enabled=true
  461.       - NEO4J_apoc_import_file_use__neo4j__config=true
  462.       - NEO4JLABS_PLUGINS=["apoc"]
  463.     ports:
  464.       - "7474:7474"   # HTTP 控制台
  465.       - "7687:7687"   # Bolt 协议
  466.     restart: always
  467.     networks:
  468.       - WeKnora-network
  469.     profiles:
  470.       - neo4j
  471.       - full

  472.   # ============================================================
  473.   # 12. Qdrant(可选向量数据库)
  474.   # 高性能 ANN 检索,启用 profile qdrant
  475.   # ============================================================
  476.   qdrant:
  477.     image: qdrant/qdrant:v1.16.2
  478.     container_name: WeKnora-qdrant
  479.     ports:
  480.       - "${QDRANT_REST_PORT:-6333}:6333"
  481.       - "${QDRANT_PORT:-6334}:6334"
  482.     volumes:
  483.       - qdrant_data:/qdrant/storage
  484.     networks:
  485.       - WeKnora-network
  486.     restart: unless-stopped
  487.     profiles:
  488.       - qdrant
  489.       - full

  490.   # ============================================================
  491.   # 13. Milvus(可选向量数据库)
  492.   # 功能完整,启用 profile milvus
  493.   # ============================================================
  494.   milvus:
  495.     image: milvusdb/milvus:v2.6.11
  496.     container_name: WeKnora-milvus
  497.     security_opt:
  498.       - seccomp:unconfined
  499.     command: ["milvus", "run", "standalone"]
  500.     environment:
  501.       - ETCD_USE_EMBED=true
  502.       - ETCD_DATA_DIR=/var/lib/milvus/etcd
  503.       - COMMON_STORAGETYPE=local
  504.       - DEPLOY_MODE=STANDALONE
  505.     healthcheck:
  506.       test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
  507.       interval: 30s
  508.       start_period: 90s
  509.       timeout: 20s
  510.       retries: 3
  511.     ports:
  512.       - "19530:19530"
  513.       - "9091:9091"
  514.     volumes:
  515.       - milvus_data:/var/lib/milvus
  516.     networks:
  517.       - WeKnora-network
  518.     restart: unless-stopped
  519.     profiles:
  520.       - milvus

  521.   # ============================================================
  522.   # 14. Weaviate(可选向量数据库)
  523.   # 轻量级,支持 GraphQL,启用 profile weaviate
  524.   # ============================================================
  525.   weaviate:
  526.     image: semitechnologies/weaviate:1.28.4
  527.     container_name: WeKnora-weaviate
  528.     environment:
  529.       - PERSISTENCE_DATA_PATH=/var/lib/weaviate
  530.       - CLUSTER_HOSTNAME=node1
  531.       - DEFAULT_VECTORIZER_MODULE=none
  532.       - ENABLE_MODULES=none
  533.       - AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true
  534.       - CLUSTER_GOSSIP_BIND_PORT=7000
  535.       - CLUSTER_DATA_BIND_PORT=7001
  536.       - RAFT_BOOTSTRAP_EXPECT=1
  537.     ports:
  538.       - "9035:8080"
  539.       - "50052:50051"
  540.     volumes:
  541.       - weaviate_data:/var/lib/weaviate
  542.     networks:
  543.       - WeKnora-network
  544.     restart: unless-stopped
  545.     profiles:
  546.       - weaviate

  547.   # ============================================================
  548.   # 15. Apache Doris(可选 OLAP 向量库)
  549.   # FE + BE 单节点,启用 profile doris
  550.   # ============================================================
  551.   doris-fe:
  552.     image: apache/doris:fe-4.1.0
  553.     container_name: WeKnora-doris-fe
  554.     hostname: doris-fe
  555.     environment:
  556.       - FE_SERVERS=fe1:doris-fe:9010
  557.       - FE_ID=1
  558.     ports:
  559.       - "${DORIS_FE_HTTP_PORT:-8030}:8030"
  560.       - "${DORIS_FE_MYSQL_PORT:-9030}:9030"
  561.     volumes:
  562.       - doris_fe_meta:/opt/apache-doris/fe/doris-meta
  563.       - doris_fe_log:/opt/apache-doris/fe/log
  564.     networks:
  565.       - WeKnora-network
  566.     restart: unless-stopped
  567.     profiles:
  568.       - doris

  569.   doris-be:
  570.     image: apache/doris:be-4.1.0
  571.     container_name: WeKnora-doris-be
  572.     hostname: doris-be
  573.     environment:
  574.       - FE_SERVERS=fe1:doris-fe:9010
  575.       - BE_ADDR=doris-be:9050
  576.     depends_on:
  577.       - doris-fe
  578.     ports:
  579.       - "${DORIS_BE_HTTP_PORT:-8040}:8040"
  580.     volumes:
  581.       - doris_be_storage:/opt/apache-doris/be/storage
  582.       - doris_be_log:/opt/apache-doris/be/log
  583.     networks:
  584.       - WeKnora-network
  585.     restart: unless-stopped
  586.     profiles:
  587.       - doris

  588.   # ============================================================
  589.   # 16. Dex(可选 OIDC 认证服务)
  590.   # 需启用 profile dex 并准备 ./misc/dex-config.yaml
  591.   # ============================================================
  592.   dex:
  593.     image: dexidp/dex:latest
  594.     container_name: dex
  595.     ports:
  596.       - "5556:5556"
  597.     volumes:
  598.       - ./misc/dex-config.yaml:/etc/dex/config.yaml
  599.     command: ["dex", "serve", "/etc/dex/config.yaml"]
  600.     profiles:
  601.       - dex
  602.       - full

  603.   # ============================================================
  604.   # 17. Langfuse 自建可观测栈(可选)
  605.   # 启用 profile langfuse 后启动全套组件(Web + Worker + ClickHouse + MinIO)
  606.   # ============================================================
  607.   langfuse-db-init:
  608.     image: paradedb/paradedb:v0.22.2-pg17
  609.     container_name: WeKnora-langfuse-db-init
  610.     depends_on:
  611.       postgres:
  612.         condition: service_healthy
  613.     environment:
  614.       PGPASSWORD: ${DB_PASSWORD}
  615.     entrypoint: ["sh", "-c"]
  616.     command:
  617.       - |
  618.         set -e
  619.         echo "[langfuse-db-init] ensuring database '${LANGFUSE_DB_NAME:-langfuse}' exists..."
  620.         psql -h postgres -U ${DB_USER} -d postgres -v ON_ERROR_STOP=0 -c "ALTER DATABASE template1 REFRESH COLLATION VERSION;" >/dev/null 2>&1 || true
  621.         psql -h postgres -U ${DB_USER} -d postgres -v ON_ERROR_STOP=0 -c "ALTER DATABASE postgres REFRESH COLLATION VERSION;" >/dev/null 2>&1 || true
  622.         if psql -h postgres -U ${DB_USER} -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='${LANGFUSE_DB_NAME:-langfuse}'" | grep -q 1; then
  623.           echo "[langfuse-db-init] database '${LANGFUSE_DB_NAME:-langfuse}' already exists, skipping."
  624.         else
  625.           psql -h postgres -U ${DB_USER} -d postgres -v ON_ERROR_STOP=1 -c "CREATE DATABASE "${LANGFUSE_DB_NAME:-langfuse}" TEMPLATE template0;"
  626.           echo "[langfuse-db-init] database '${LANGFUSE_DB_NAME:-langfuse}' created."
  627.         fi
  628.         echo "[langfuse-db-init] done."
  629.     networks:
  630.       - WeKnora-network
  631.     restart: "no"
  632.     profiles:
  633.       - langfuse
  634.       - full

  635.   langfuse-clickhouse:
  636.     image: clickhouse/clickhouse-server:24.8
  637.     container_name: WeKnora-langfuse-clickhouse
  638.     restart: unless-stopped
  639.     user: "101:101"
  640.     environment:
  641.       CLICKHOUSE_DB: default
  642.       CLICKHOUSE_USER: ${LANGFUSE_CLICKHOUSE_USER:-clickhouse}
  643.       CLICKHOUSE_PASSWORD: ${LANGFUSE_CLICKHOUSE_PASSWORD:-clickhouse}
  644.     volumes:
  645.       - langfuse_clickhouse_data:/var/lib/clickhouse
  646.       - langfuse_clickhouse_logs:/var/log/clickhouse-server
  647.     healthcheck:
  648.       test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
  649.       interval: 5s
  650.       timeout: 5s
  651.       retries: 10
  652.       start_period: 10s
  653.     networks:
  654.       - WeKnora-network
  655.     profiles:
  656.       - langfuse
  657.       - full

  658.   langfuse-minio:
  659.     image: minio/minio:RELEASE.2025-09-07T16-13-09Z
  660.     container_name: WeKnora-langfuse-minio
  661.     restart: unless-stopped
  662.     entrypoint: sh
  663.     command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
  664.     environment:
  665.       MINIO_ROOT_USER: ${LANGFUSE_MINIO_USER:-langfuseminio}
  666.       MINIO_ROOT_PASSWORD: ${LANGFUSE_MINIO_PASSWORD:-langfuseminiosecret}
  667.     ports:
  668.       - "${LANGFUSE_MINIO_S3_PORT:-9100}:9000"
  669.       - "${LANGFUSE_MINIO_CONSOLE_PORT:-9101}:9001"
  670.     volumes:
  671.       - langfuse_minio_data:/data
  672.     healthcheck:
  673.       test: ["CMD", "mc", "ready", "local"]
  674.       interval: 5s
  675.       timeout: 10s
  676.       retries: 5
  677.     networks:
  678.       - WeKnora-network
  679.     profiles:
  680.       - langfuse
  681.       - full

  682.   langfuse-worker:
  683.     image: langfuse/langfuse-worker:3
  684.     container_name: WeKnora-langfuse-worker
  685.     restart: unless-stopped
  686.     depends_on: &langfuse-depends-on
  687.       langfuse-db-init:
  688.         condition: service_completed_successfully
  689.       redis:
  690.         condition: service_started
  691.       langfuse-clickhouse:
  692.         condition: service_healthy
  693.       langfuse-minio:
  694.         condition: service_healthy
  695.     entrypoint:
  696.       - /bin/sh
  697.       - -ec
  698.       - |
  699.         _enc() { node -e 'process.stdout.write(encodeURIComponent(process.argv[1]))' "$$1"; }
  700.         DU=$$(_enc "$$_LF_DB_USER")
  701.         DP=$$(_enc "$$_LF_DB_PASSWORD")
  702.         RP=$$(_enc "$$_LF_REDIS_PASSWORD")
  703.         export DATABASE_URL="postgresql://$$DU:$$DP@postgres:5432/$$_LF_DB_NAME"
  704.         export REDIS_CONNECTION_STRING="redis://:$$RP@redis:6379/$$_LF_REDIS_DB"
  705.         unset _LF_DB_USER _LF_DB_PASSWORD _LF_REDIS_PASSWORD
  706.         exec dumb-init -- ./worker/entrypoint.sh node worker/dist/index.js
  707.     environment: &langfuse-env
  708.       _LF_DB_USER: ${DB_USER}
  709.       _LF_DB_PASSWORD: ${DB_PASSWORD}
  710.       _LF_DB_NAME: ${LANGFUSE_DB_NAME:-langfuse}
  711.       _LF_REDIS_PASSWORD: ${REDIS_PASSWORD}
  712.       _LF_REDIS_DB: ${LANGFUSE_REDIS_DB:-1}
  713.       SALT: ${LANGFUSE_SALT:-weknora-langfuse-dev-salt-change-me}
  714.       ENCRYPTION_KEY: ${LANGFUSE_ENCRYPTION_KEY:-0000000000000000000000000000000000000000000000000000000000000000}
  715.       NEXTAUTH_URL: ${LANGFUSE_NEXTAUTH_URL:-http://localhost:3000}
  716.       NEXTAUTH_SECRET: ${LANGFUSE_NEXTAUTH_SECRET:-weknora-langfuse-dev-nextauth-secret-change-me}
  717.       TELEMETRY_ENABLED: ${LANGFUSE_TELEMETRY_ENABLED:-false}
  718.       LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES: "false"
  719.       CLICKHOUSE_URL: http://langfuse-clickhouse:8123
  720.       CLICKHOUSE_MIGRATION_URL: clickhouse://langfuse-clickhouse:9000
  721.       CLICKHOUSE_USER: ${LANGFUSE_CLICKHOUSE_USER:-clickhouse}
  722.       CLICKHOUSE_PASSWORD: ${LANGFUSE_CLICKHOUSE_PASSWORD:-clickhouse}
  723.       CLICKHOUSE_CLUSTER_ENABLED: "false"
  724.       LANGFUSE_S3_EVENT_UPLOAD_BUCKET: langfuse
  725.       LANGFUSE_S3_EVENT_UPLOAD_REGION: auto
  726.       LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_MINIO_USER:-langfuseminio}
  727.       LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_MINIO_PASSWORD:-langfuseminiosecret}
  728.       LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: http://langfuse-minio:9000
  729.       LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: "true"
  730.       LANGFUSE_S3_EVENT_UPLOAD_PREFIX: events/
  731.       LANGFUSE_S3_MEDIA_UPLOAD_BUCKET: langfuse
  732.       LANGFUSE_S3_MEDIA_UPLOAD_REGION: auto
  733.       LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_MINIO_USER:-langfuseminio}
  734.       LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_MINIO_PASSWORD:-langfuseminiosecret}
  735.       LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: ${LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT:-http://localhost:9100}
  736.       LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: "true"
  737.       LANGFUSE_S3_MEDIA_UPLOAD_PREFIX: media/
  738.     networks:
  739.       - WeKnora-network
  740.     profiles:
  741.       - langfuse
  742.       - full

  743.   langfuse-web:
  744.     image: langfuse/langfuse:3
  745.     container_name: WeKnora-langfuse-web
  746.     restart: unless-stopped
  747.     depends_on: *langfuse-depends-on
  748.     ports:
  749.       - "${LANGFUSE_WEB_PORT:-3000}:3000"
  750.     entrypoint:
  751.       - /bin/sh
  752.       - -ec
  753.       - |
  754.         _enc() { node -e 'process.stdout.write(encodeURIComponent(process.argv[1]))' "$$1"; }
  755.         DU=$$(_enc "$$_LF_DB_USER")
  756.         DP=$$(_enc "$$_LF_DB_PASSWORD")
  757.         RP=$$(_enc "$$_LF_REDIS_PASSWORD")
  758.         export DATABASE_URL="postgresql://$$DU:$$DP@postgres:5432/$$_LF_DB_NAME"
  759.         export REDIS_CONNECTION_STRING="redis://:$$RP@redis:6379/$$_LF_REDIS_DB"
  760.         unset _LF_DB_USER _LF_DB_PASSWORD _LF_REDIS_PASSWORD
  761.         if [ -n "$$NEXT_PUBLIC_LANGFUSE_CLOUD_REGION" ]; then
  762.           exec dumb-init -- ./web/entrypoint.sh node --import dd-trace/initialize.mjs ./web/server.js --keepAliveTimeout 110000
  763.         else
  764.           exec dumb-init -- ./web/entrypoint.sh node ./web/server.js --keepAliveTimeout 110000
  765.         fi
  766.     environment:
  767.       <<: *langfuse-env
  768.       LANGFUSE_INIT_ORG_ID: ${LANGFUSE_INIT_ORG_ID:-}
  769.       LANGFUSE_INIT_ORG_NAME: ${LANGFUSE_INIT_ORG_NAME:-}
  770.       LANGFUSE_INIT_PROJECT_ID: ${LANGFUSE_INIT_PROJECT_ID:-}
  771.       LANGFUSE_INIT_PROJECT_NAME: ${LANGFUSE_INIT_PROJECT_NAME:-}
  772.       LANGFUSE_INIT_PROJECT_PUBLIC_KEY: ${LANGFUSE_INIT_PROJECT_PUBLIC_KEY:-}
  773.       LANGFUSE_INIT_PROJECT_SECRET_KEY: ${LANGFUSE_INIT_PROJECT_SECRET_KEY:-}
  774.       LANGFUSE_INIT_USER_EMAIL: ${LANGFUSE_INIT_USER_EMAIL:-}
  775.       LANGFUSE_INIT_USER_NAME: ${LANGFUSE_INIT_USER_NAME:-}
  776.       LANGFUSE_INIT_USER_PASSWORD: ${LANGFUSE_INIT_USER_PASSWORD:-}
  777.     networks:
  778.       - WeKnora-network
  779.     profiles:
  780.       - langfuse
  781.       - full

  782.   # ============================================================
  783.   # 18. MCP Server(可选)
  784.   # 提供 Model Context Protocol 服务,用于外部工具调用
  785.   # ============================================================
  786.   mcp:
  787.     build:
  788.       context: ./mcp-server
  789.     container_name: WeKnora-mcp
  790.     ports:
  791.       - "${MCP_PORT:-8082}:8000"
  792.     environment:
  793.       - WEKNORA_BASE_URL=http://app:8080/api/v1
  794.       - WEKNORA_API_KEY=${WEKNORA_API_KEY:-}
  795.     depends_on:
  796.       app:
  797.         condition: service_healthy
  798.     networks:
  799.       - WeKnora-network
  800.     restart: unless-stopped
  801.     profiles:
  802.       - full
复制代码
7、点击立即部署;

7

7

8、接下来就是漫长的等待,等待完成。。。
9、访问http://你的NAS_IP:28080  ,选择创建账户进行初始化;

9

9

10、输入用户名、邮箱、密码、确认密码,点击注册;

10

10

11、此时,有成功的喜悦,也有身心的疲惫,项目就搭建好了!!!

11

11

三、注意事项:
安全加固:
注册完成后,将.env文件的 DISABLE_REGISTRATION 改回 true 并重启,以阻止后续公开注册。
  1. DISABLE_REGISTRATION=true
复制代码
四、使用方法和教程
请参考官网:https://weknora.weixin.qq.com/

评论12

playokLv.3 发表于 3 天前 | 查看全部 IP:上海市 公众宽带
gleecalmLv.1绿联NAS社区会员用户 发表于 3 天前 | 查看全部 IP:–河南–安阳
666厉害
蓝小白楼主Lv.4 发表于 3 天前 来自手机 | 查看全部 IP:四川省成都市温江区 公众宽带
playok 发表于 2026-7-18 11:36

😄哈哈
蓝小白楼主Lv.4 发表于 3 天前 来自手机 | 查看全部 IP:四川省成都市温江区 公众宽带
KsGoWL 发表于 2026-7-18 14:53
666厉害

搞起来搞起来
gleecalmLv.1绿联NAS社区会员用户 发表于 3 天前 | 查看全部 IP:河南省安阳市殷都区 公众宽带

最近在琢磨  手机上安装自己+Ai开发的行车录像app  录的视频怎么自动上传到NAS
微信图片_20260718133103_94_210.jpg
gleecalmLv.1绿联NAS社区会员用户 发表于 3 天前 | 查看全部 IP:河南省安阳市殷都区 公众宽带
本帖最后由 KsGoWL 于 2026-7-18 19:09 编辑

微信图片_20260718185836_103_210.jpg 微信图片_20260718133103_94_210.jpg 微信图片_20260718185727_102_210.jpg
蓝小白楼主Lv.4 发表于 3 天前 来自手机 | 查看全部 IP:四川省成都市温江区 公众宽带
KsGoWL 发表于 2026-7-18 19:00

这是啥🤔
gleecalmLv.1绿联NAS社区会员用户 发表于 3 天前 | 查看全部 IP:河南省安阳市殷都区 公众宽带

行车录像app  录的视频 自动上传到NAS
蓝小白楼主Lv.4 发表于 3 天前 来自手机 | 查看全部 IP:四川省成都市温江区 公众宽带
KsGoWL 发表于 2026-7-18 19:17
行车录像app  录的视频 自动上传到NAS

🐂🍺

评论

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright © 2026 绿联NAS私有云社区 版权所有 All Rights Reserved. 粤公网安备44030002002555号| 粤ICP备12028978号
关灯 在本版发帖
联系技术支持
返回顶部
快速回复 返回顶部 返回列表