DeepSeeLite (DSL)

August 29, 2026 · View on GitHub

DeepSeeLite (DSL) 是面向轻量部署的视觉编排库和本地网关,为 DeepSeek API 增加图片 理解能力。它可以独立用于 Python/API 集成,也可以作为 DSH 的 DSV 网关;不需要安装 完整 DeepSee 才能使用 DSL。

DSL 通过独立的 PyPI 包名 deepseelite 发布,共享 deepsee import 包、 deepsee-server 命令和 ~/.config/deepsee 配置。完整 DeepSee 则通过 seedeep 发布;两个发行版不能安装在同一个 Python 环境中。

为 DeepSeek 官方 API 提供可插拔的视觉处理层,让 DeepSeek 获得多模态能力: 一次 ask_with_image() 调用,完成"视觉模型看图 → DeepSeek 推理回答"。

安装 DSL

pip install "deepseelite[server]"
deepsee-server

首次启动会显示 public key 和 admin key。普通 API/DSV 请求使用 public key;admin key 只用于管理端点,请勿交给客户端。

安装后可以直接调用 Python API:

from deepsee import ask_with_image

answer = ask_with_image("photo.jpg", "这张图里有什么?")
print(answer)

配置和启动

网关运行时的主事实来源是 ~/.config/deepsee/upstream.json 管理配置;也可以使用 deepsee.toml 或环境变量。最小的环境变量配置如下:

export DEEPSEEK_API_KEY='<DeepSeek API key>'
export VISION_API_KEY='<vision provider API key>'
export VISION_BASE_URL='https://dashscope.aliyuncs.com/compatible-mode/v1'
export VISION_MODEL='qwen-vl-max'
deepsee-server

完整配置格式、后端选择、鉴权和多协议端点见下方章节。

可选:接入 DSH

已经安装 DSH Web 的用户,可以按下面流程让 DSH 使用 DSL 的 DSV 网关;DSH 只保存 网关 public key,不接触 DeepSeek 或视觉 provider 的密钥。

1. 安装 DSH 适配层

在另一个终端运行:

curl -fsSL https://raw.githubusercontent.com/windyslime/DeepSeeLite/main/scripts/install-dsh-dsv.sh | bash

看到 Configure DeepSee connection automatically? [Y/n/c] 时:

  • 直接按回车或输入 Y:选择自动配置;需要时粘贴刚才复制的 public key。
  • 输入 n:只安装,暂时不配置连接。
  • 输入 c:取消,不改动 DSH。

2. 重启 DSH 并发一张图片

在运行 DSH Web 的终端按 Ctrl+C 停止它,再用原来的启动命令重新启动并刷新浏览器。 然后在聊天中上传一张图片并提问。看到可折叠的“识图”行即表示连接生效。

3. 检查连接

curl -fsSL https://raw.githubusercontent.com/windyslime/DeepSeeLite/main/scripts/install-dsh-dsv.sh \
  | bash -s -- --verify

看到 DeepSee gateway reachable 即表示 DSH 能找到 DSL 网关。若提示网关不可达,确认 安装 DSL 时启动的 deepsee-server 仍在运行后重试。

没有交互终端时,先设置 public key,再使用自动配置;只想安装时使用仅安装模式:

export DEEPSEE_DSV_API_KEY='<DSV public key>'
curl -fsSL https://raw.githubusercontent.com/windyslime/DeepSeeLite/main/scripts/install-dsh-dsv.sh \
  | bash -s -- --configure
curl -fsSL https://raw.githubusercontent.com/windyslime/DeepSeeLite/main/scripts/install-dsh-dsv.sh \
  | bash -s -- --no-configure

完整排错见 docs/DSH-DSV-INSTALL.zh.md。安装器的技术约束、 凭证处理和发布检查见 CONTRIBUTING.md

与完整 DeepSee 的关系

以下命令安装的是功能更完整的 DeepSee 正式发布包,不是 DSL:

pip install seedeep

PyPI 上的 deepsee 已被 2014 年的无关项目占用,本包发布名为 seedeep; import 包名仍是 deepsee。启动本地服务时用 pip install "seedeep[server]"

seedeepdeepseelite 提供相同的 deepsee import 包和 deepsee-server 命令, 不能安装在同一个 Python 环境中;切换版本时先卸载另一个。

配置

网关运行时的主事实来源是 ~/.config/deepsee/upstream.json 管理配置;浏览器管理端点 只写入这个文件,并且只返回脱敏状态。DSH 仅保存网关地址和 DSV public key,不接触 DeepSeek 或视觉 provider 的密钥。TOML 和环境变量仍然支持库调用、容器部署和启动时 覆盖,其中环境变量优先级最高,适合运维注入秘密。

配置文件 deepsee.toml(放在当前目录或 ~/.config/deepsee/),也可以只用环境变量 (DeepSee_DEEPSEEK_API_KEY 等)。${ENV} 可引用环境变量:

[deepseek]
api_key = "${DEEPSEEK_API_KEY}"

[vision]
backend = "openai_compatible"   # openai_compatible | anthropic | gemini
api_key = "${VISION_API_KEY}"
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
model = "qwen-vl-max"

# Optional per-mode models.  Omitted modes fall back to vision.model.
[vision.models]
auto = "qwen-vl-max"
ui = "qwen-vl-ui"
general = "qwen-vl-general"

vision.model 是旧配置格式保留的默认模型;vision.models.autovision.models.uivision.models.general 可以分别覆盖 autouigeneral 三种视觉模式。只配置其中一部分时,未配置的模式继续回落到 vision.model,因此旧配置无需迁移。auto 会判断图片是界面截图还是普通图片, ui 强制输出结构化界面分析,general 强制输出通用图片描述。

除 TOML 外,也可以使用环境变量覆盖每个模式。标准名称是 VISION_MODEL_AUTOVISION_MODEL_UIVISION_MODEL_GENERAL;带有 DeepSee_ 前缀的形式以及更短的 VISION_AUTO_MODELVISION_UI_MODELVISION_GENERAL_MODEL 别名也受支持。环境变量优先于 TOML,旧的 VISION_MODEL 仍然作为三个模式的共同回退。切换视觉后端时,必须显式提供新后端的 VISION_API_KEYVISION_MODEL,或同时提供三个模式变量。

用环境变量覆盖 VISION_BACKEND 切换后端时,TOML 中的 base_url / api_key / model 不会沿用(它们属于旧后端:base_url 指向旧主机,key 属于旧供应商, 会被发给错误的主机/供应商)。base_url 回落到新后端的官方默认主机 —— Anthropic 和 Gemini 有默认主机;OpenAI-compatible 没有默认值,必须显式设置 VISION_BASE_URLapi_keymodel 必须由环境变量显式提供,否则报错。 环境变量与 TOML 中字面量 backend 相同的 VISION_BACKEND 不算切换, TOML 配置原样保留(自定义代理 / 审计 / 数据驻留场景)。但 TOML backend 若写成 ${ENV} 插值(如 backend = "${VISION_BACKEND}"),一律视为切换: base_url 回落默认,且 api_key / model 必须使用标准环境变量 VISION_API_KEY / VISION_MODEL 显式提供 —— TOML 中的自定义 ${ENV} 占位符不会生效,旧变量可安全删除。

支持的后端

  • openai_compatible: Qwen-VL、GPT-4o、GLM-4V、Moonshot 等任意 OpenAI 兼容服务
  • anthropic: Claude 系列(原生 API)
  • gemini: Google Gemini(原生 API)

流式输出

for chunk in ask_with_image("photo.jpg", "讲个故事", stream=True):
    print(chunk, end="", flush=True)

异步 API

所有同步接口都有对应的 async 版本,签名一致:

import asyncio
from deepsee import ask_with_image_async

async def main():
    # 非流式
    answer = await ask_with_image_async("photo.jpg", "这张图里有什么?")
    print(answer)

    # 流式(async 迭代器)
    async for chunk in ask_with_image_async("photo.jpg", "讲个故事", stream=True):
        print(chunk, end="", flush=True)

asyncio.run(main())

另有 ask_async(纯文本)与 describe_image_async(仅视觉分析)。 错误语义与同步接口一致;图片处理(含 SSRF 防护)复用同一套同步管线。

本地网关

安装 server 依赖后启动网关:

pip install "deepseelite[server]"
deepsee-server

网关默认启用入站鉴权。首次启动会创建一组 public/admin key,明文只在该次 启动输出,磁盘中的 ~/.config/deepsee/api-keys.json 只保存 SHA-256 摘要。 普通推理和模型列表使用 public key:

curl http://127.0.0.1:8712/v1/models \
  -H "Authorization: Bearer <public-key>"

/admin/* 管理端点使用独立的 admin key,通过 X-DeepSee-Admin-Key: <admin-key> 传递。需要补发密钥时运行 deepsee-server --create-recovery-keys;旧 key 保持有效,可通过管理 API 撤销。

临时本机开发可以显式关闭鉴权,但仅允许 loopback 地址:

deepsee-server --no-auth --host 127.0.0.1

默认每个身份每 60 秒最多 60 个推理请求,全局最多 8 个并发推理请求,并发队列 最多等待 2 秒。可用 DeepSee_RATE_LIMIT_REQUESTSDeepSee_RATE_LIMIT_WINDOWDeepSee_MAX_CONCURRENT_REQUESTSDeepSee_REQUEST_QUEUE_TIMEOUT 覆盖。计数只在当前进程内共享;多 worker 或多 实例部署还需要在反向代理层配置共享限速。

多协议端点

DSV 公开编排端点

POST /v1/dsv 是 DeepSee 对外提供的视觉编排/输出协议。客户端只提交图片、消息、 DeepSeek 模型和工具 schema;DeepSee 在内部调用配置的 OpenAI-compatible 视觉 API, 再编排 DeepSeek 推理。视觉 provider 的 api_key 不属于 DSV 请求体,也不会返回给 客户端。DSV v1 当前要求 [vision].backend = "openai_compatible"

请求中的图片可以使用 DSV 原生 base64 形状,工具结果继续使用 OpenAI-compatible 的 role: "tool" 消息回传:

{
  "model": "deepseek-chat",
  "stream": true,
  "messages": [{
    "role": "user",
    "content": [
      {"type": "text", "text": "这张图里有什么?"},
      {"type": "image", "source": {
        "type": "base64",
        "media_type": "image/png",
        "data": "<BASE64>"
      }}
    ]
  }],
  "tools": [],
  "vision": {"mode": "auto", "include_analysis": true}
}

vision.mode 可选 autouigeneral,省略时使用 auto。网关会按所选模式 调用对应的 vision.models.<mode>;DSV 响应的 `vision.model$ 元数据会报告实际使用的 模型,便于 \text{DSH} 展开“识图”结果时显示来源。

视觉模式可以与手动切分独立组合。示例使用 \text{UI} 识别、4 \times 4 网格、120% 区域尺寸和允许重叠:

$``json "vision": { "mode": "ui", "include_analysis": true, "split": {"mode": "manual", "rows": 4, "columns": 4, "scale": 120, "overlap": true} }


DSV 的 `vision.tiles` 按行优先排列;失败项包含 `row`、`column` 和 `status: "error"`,
客户端可在对应网格中央显示红色“识别失败”。OpenAI 兼容接口使用
`X-DeepSee-Vision-Split-Mode`、`X-DeepSee-Vision-Split-Grid`、
`X-DeepSee-Vision-Split-Scale` 和 `X-DeepSee-Vision-Split-Overlap` 请求头,
并从 `X-DeepSee-Vision-Tiles` 响应头读取状态。

SSE 流首先发送 `response.created`、`vision.started` 和完整的
`vision.completed`,随后发送 `reasoning.delta`、`answer.delta` 或
`tool_call.delta`。工具调用结束时发送 `response.requires_action`;调用方执行自己
的工具后,把结果作为下一次 DSV 请求的 `role: "tool"` 消息提交。DeepSee 不执行
调用方的工具。非流式响应将 `vision`、`answer`、`reasoning`、`tool_calls` 和
`usage` 保持为独立字段。

服务同时暴露三种协议形状的聊天端点。视觉分析可以作为响应元数据返回,
供 GUI 像展开思考过程一样点击查看(字段语义 = "模型看到了什么"):

- `POST /v1/chat/completions` — OpenAI 兼容;仅当请求包含
  `X-DeepSee-Include-Vision: 1` 时,有图的非流式响应带
  `choices[0].message.vision_analysis`,流式响应以独立前置 chunk 发出
  `choices[0].delta.vision_analysis`(不含 `content`),随后是上游响应 chunk;
- `POST /v1/messages` — Anthropic messages 形状;非流式响应顶层
  `vision_analysis`;流式响应在 `message_start` 后发
  `{"type": "vision_analysis", "vision": ...}` 事件;
- `POST /v1beta/models/{model}:generateContent` — Gemini 形状;非流式
  响应 `parts` 首位是 `{"text": ..., "vision": true}`;流式响应以独立前置
  chunk 发出该 part。

三种端点都支持 `stream` 参数(流式/非流式),图片输入按各自协议形状
(data URL / base64 source / inline_data / http URL),统一受 SSRF 防护与
字节上限约束;`file://` 与本地路径一律拒绝。

OpenAI、Anthropic 和 Gemini 三种聊天协议都读取同一个
`X-DeepSee-Vision-Mode: auto|ui|general` 请求头;未提供时默认 `auto`。只想调用视觉
后端而不经过 DeepSeek 推理时,可使用 `POST /analyze`,请求体为
`{"image": "<data-url-or-http-url>", "question": "...", "mode": "general"}`;
该端点的 `mode` 默认是 `general`,响应返回 `{"kind": "description", "text": "..."}`。

**示例**(以 base64 图片 + 流式为例):

```bash
# OpenAI 兼容
curl -N http://127.0.0.1:8712/v1/chat/completions \
  -H "Authorization: Bearer <public-key>" \
  -H "X-DeepSee-Include-Vision: 1" \
  -H "Content-Type: application/json" -d '{
  "stream": true,
  "messages": [{"role": "user", "content": [
    {"type": "text", "text": "这张图里有什么?"},
    {"type": "image_url", "image_url": {"url": "data:image/png;base64,<BASE64>"}}
  ]}]
}'
# 响应:首个 chunk 为 {"choices":[{"delta":{"vision_analysis":"..."}}]},
#       之后 chunk 为 {"choices":[{"delta":{"content":"..."}}]},最后 data: [DONE]

# Anthropic messages
curl -N http://127.0.0.1:8712/v1/messages \
  -H "Authorization: Bearer <public-key>" \
  -H "Content-Type: application/json" -d '{
  "model": "claude-3-5-sonnet",
  "max_tokens": 1024,
  "stream": true,
  "messages": [{"role": "user", "content": [
    {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "<BASE64>"}},
    {"type": "text", "text": "这张图里有什么?"}
  ]}]
}'
# 响应:message_start → {"type":"vision_analysis","vision":"..."} → content_block_delta(text) → message_stop

# Gemini generateContent
curl -N http://127.0.0.1:8712/v1beta/models/gemini-2.0-flash:generateContent \
  -H "Authorization: Bearer <public-key>" \
  -H "Content-Type: application/json" -d '{
  "stream": true,
  "contents": [{"parts": [
    {"inline_data": {"mime_type": "image/png", "data": "<BASE64>"}},
    {"text": "这张图里有什么?"}
  ]}]
}'
# 响应:首个 chunk 的 parts 为 [{"text":"...","vision":true}],后续 chunk 只带回答文本 part

安全限制

网关对模型、推理和分析端点强制 public key,对 /admin/* 强制 admin key; 直接导入 ASGI app 但未配置鉴权时 fail closed,只有 /health 保持公开。速率和 并发保护覆盖完整流式响应生命周期,客户端取消或上游异常后会释放并发名额。

图片加载对所有服务化图片入口统一生效(/v1/dsvimage.source/image_url/v1/chat/completionsimage_url/v1/messagessource.url/base64、 /v1beta/models/{model}:generateContentfile_data.file_uri/inline_data/analyze):

  • SSRF 防护:http(s) URL 的主机(含每一跳重定向目标)解析到私网、loopback、 link-local、保留或特殊用途地址(如 127.0.0.1169.254.169.254)时拒绝下载。 校验通过后,TCP 连接固定到已校验的 IP(域名只解析一次),消除 DNS rebinding TOCTOU;TLS 仍按原始域名校验证书。下载不读环境代理(trust_env=False), 防止代理绕过本地校验。RFC 6052 NAT64 前缀(64:ff9b::/9664:ff9b:1::/48) 显式拒绝;部署网络若使用其他自定义 NAT64 前缀,需自行扩展 deepsee/pipeline/image.py_NAT64_NETWORKS;
  • 本地路径:服务端只接受 data: 与 http(s) URL,file:// 与本地路径一律拒绝 (CLI 本地调用不受影响);
  • 资源上限:原始图片字节上限 20 MiB、解码像素上限约 1670 万(4096x4096), 超限在下载/解码前拒绝;下载请求 Accept-Encoding: identity 并拒绝压缩响应, 字节上限按原始字节流式累计(扩容前检查),防止大响应与解压炸弹耗尽内存;
  • 请求体上限:服务端请求体超过 32 MiB 返回 413,请求体流式读取, 无 Content-Length 的 chunked 请求同样受限;
  • 推理成本上限:默认最多 100 条消息/内容、4 张图片、20 万文本字符; 未指定输出长度时使用 4096 tokens,单次最多 8192 tokens。可通过 DeepSee_MAX_MESSAGESDeepSee_MAX_IMAGESDeepSee_MAX_TEXT_CHARSDeepSee_DEFAULT_MAX_OUTPUT_TOKENSDeepSee_MAX_OUTPUT_TOKENS 覆盖;
  • 流式超时:DeepSeek 流式响应的 HTTP 帧间超时 120 秒(完全静默的上游 120 秒后报错),另有总时长上限 300 秒(deepsee/composer/deepseek.py_STREAM_TOTAL_TIMEOUT)—— 持续发送 SSE keepalive 却永不 [DONE] 的上游会触发总时长上限,超时抛 ComposeError(服务端以 error chunk 通知)。 注意同步接口是检查点软上限(每次读到数据后检查截止时间,完全静默时 可能再等待一次 120 秒帧间超时);异步接口是响应体迭代阶段的硬上限 (响应头返回后每帧等待剩余时间;连接、响应头等待与重试不计入 300 秒);
  • 流式资源释放:库的流式接口(stream=True)返回的迭代器需完整消费或 调用 close() / aclose()(建议 contextlib.closing / aclosing)以释放 底层连接;服务端流式端点已用 aclosing 保证取消/断开时释放;
  • 环境代理:库发起的上游请求不读环境代理(trust_env=False)。SOCKS 代理 (如 ALL_PROXY=socks5://)在未安装 socksio 时会直接 ImportError,且代理 会把含 API key 的请求转发到第三方。依赖代理访问公网 API 的环境需直连或 自行配置传输层。

已知限制与后续工作

以下问题已确认但不在当前版本修复,列为后续工作:

  • CI: 仓库尚无 CI(GitHub Actions)。建议配置 pytest 在 Python 3.10-3.12 矩阵上运行,并开启依赖安全扫描;
  • 分支保护: 主分支保护属 GitHub 仓库设置,需人工开启(建议要求 PR 评审 与 CI 通过后才能合并)。

许可证

MIT