Docling 托管服务实战:用 Docling for IBM watsonx 将文档转换能力以 HTTP 服务方式接入应用
本篇基于 managed.md 展开,讲解 Docling 托管服务的定位与选型逻辑:它相对自建 docling-serve 省去了哪些运维工作、如何通过服务 URL + API Key 的极简方式接入现有应用与 AI Agent,并给出从 REST 原始调用到 Python 客户端、CLI 命令的完整接入路径,以及客户端在超时、重试、用量限额等场景下的真实行为(均有源码佐证)。
为什么选择托管服务
自行部署 docling-serve 意味着你要自己经营整套基础设施:服务器、GPU、扩缩容、模型升级、运行监控。managed.md 明确列出托管服务消除的正是这些工作,具体拆解为三点:
1. 无需运行任何基础设施(No infrastructure to run)
没有服务器、没有 GPU、没有扩容、没有升级、没有运维监控——服务由提供方托管维护。对照 deployment.md 中自托管需要处理的内容(进程编排、计算引擎、Redis 队列、API Key 配置),托管服务把这些全部收敛到服务提供方一侧。对读者而言,这意味着可以把精力从"怎么把服务跑起来"转移到"怎么用好文档理解能力"。
2. 集成方式简单(Simple integration)
托管服务暴露与自托管服务器完全相同的 REST API。把它接入应用或 AI Agent 只需一次 HTTP 调用——把客户端指向托管端点即可。客户端代码保持可移植性:从自托管切换到托管服务,通常只需要更换 base URL 并补一个 API Key。这一"可移植性"在仓库源码中有一致的体现:
- Python 客户端
DoclingServiceClient的构造函数签名就是url+api_key两个核心输入,见 client.py; - CLI 的
convert-remote命令凭据解析优先级同样是"flag > 环境变量 > .env 文件",与自托管服务共用同一套客户端实现,见 remote.py。
3. 与开源版本相同的 Docling 转换(Same Docling conversion)
托管服务执行与开源库、开源服务器相同的文档理解流程和输出格式——Markdown、JSON(DoclingDocument)、HTML、doctags 等格式、OCR、表格结构、增强(代码/公式/图片/图表)能力保持一致。换句话说,托管不是"缩水版 API",而是同一引擎的托管实例,你在本地用 DocumentConverter 验证过的转换行为,在托管端点上是可预期的。
当前可用的托管服务:Docling for IBM watsonx
managed.md 目前列出的托管服务是 Docling for IBM watsonx:一个完全托管、由 IBM 托管运行的 Docling 服务实例,暴露与这些文档页面描述的同一套 REST API。使用方式就是提供两个东西——服务 URL 和 API Key——然后像调用任何其他端点一样调用它。产品页面可在 IBM 官方渠道("Docling for IBM watsonx" 产品页)获取,本文不输出外部链接。
从仓库代码结构看,客户端对托管服务的处理是通用化的:代码中没有任何针对特定云厂商的特判,url 参数可以是任意实现了 docling-serve REST 契约的端点。这正是"同一 REST API"这一承诺在工程上的含义——接入新托管服务不需要改客户端代码,只需换 URL 和 Key。
接入方式一:直接调用 REST API
托管服务与自托管服务的端点完全一致,参考 rest_api.md:
| 端点 | 方法 | 用途 |
|---|---|---|
/v1/convert/source |
POST | 从 URL / base64 源转换(同步) |
/v1/convert/file |
POST | 上传文件转换,multipart(同步) |
/v1/convert/source/async、/v1/convert/file/async |
POST | 提交异步任务 |
/v1/status/poll/{task_id} |
GET | 轮询任务状态 |
/v1/status/ws/{task_id} |
WebSocket | 订阅任务状态 |
/v1/result/{task_id} |
GET | 获取已完成的结果 |
认证:服务端要求 API Key 时(自托管侧由 DOCLING_SERVE_API_KEY 开启),每个请求都要携带:
-H "X-Api-Key: <YOUR_KEY>"
对托管服务,把 rest_api.md 示例中的 http://localhost:5001 替换为你的托管服务 base URL 即可,例如提交一次异步转换:
curl -X POST "https://<your-managed-service-host>/v1/convert/source/async" \
-H "Content-Type: application/json" \
-H "X-Api-Key: <YOUR_KEY>" \
-d '{"http_sources": [{"url": "https://arxiv.org/pdf/2501.17887"}]}'
响应体中 task_id 用于后续 GET /v1/status/poll/{task_id} 轮询与 GET /v1/result/{task_id} 取回结果;任务状态机为 pending | started | success | failure。完整的请求/响应 schema 在任何运行中的服务上都可通过 /docs(OpenAPI / Swagger)在线查看,这在评估托管服务时是权威参照——文档可能滞后,/docs 不会。
接入方式二:Python 客户端 SDK
仓库自带 Python 客户端 docling.service_client,返回与本地 DocumentConverter 相同的 ConversionResult,无需手搓 HTTP 调用:
from docling.service_client import DoclingServiceClient
from docling.datamodel.service.options import ConvertDocumentsOptions
with DoclingServiceClient(
url="https://<your-managed-service-host>",
api_key="YOUR_API_KEY", # 服务未启用鉴权时省略
) as client:
result = client.convert(
source="https://arxiv.org/pdf/2501.17887", # 也支持 Path / DocumentStream
options=ConvertDocumentsOptions(to_formats=["md"]),
)
print(result.document.export_to_markdown())
source 接受 HTTP/HTTPS URL 字符串、本地 pathlib.Path 或 DocumentStream;多文档用 convert_all(source=[...], max_concurrency=4) 并发转换,返回迭代器逐个产出 ConversionResult。可运行的完整示例见 convert.py 与 README。
从源码看,这个客户端为"托管场景"做了几个值得注意的设计(均位于 client.py):
- URL 校验:
_normalize_base_url要求传入绝对 http(s) base URL,且不允许把/v1拼进 base URL(端点前缀由客户端自动补全),传错会在构造期立即报ValueError(client.py)。 - 鉴权头:设置
api_key后,所有 HTTP 请求自动附加X-Api-Key头,WebSocket 状态订阅则在 URL 查询参数中携带api_key(client.py)。 - 版本协商:客户端自动附加
Accept-Docling-Document-Version头,告知服务端其安装的 docling-core 能读取的 DoclingDocument 版本,必要时服务端会向下投影(client.py)——这对跨版本使用托管服务的兼容性有实际意义。 - 批量语义:
convert()默认在状态非success/partial_success时抛出ConversionError(raises_on_error=True);convert_all()内部会强制附加 JSON 输出格式以便重建DoclingDocument(client.py)。
安装方式:托管场景通常只需 pip install "docling-slim[service-client]",不必安装完整模型栈(见 README)。
接入方式三:docling convert-remote 命令行
CLI 提供了 convert-remote 子命令,内部就是驱动上面这个同步客户端,并复用与本地 convert 相同的导出器,因此写入本地的输出与 docling convert 完全一致(remote.py)。它同时适用于自托管服务与托管服务:
# 凭据来自环境变量或工作目录 .env
docling convert-remote report.pdf
# 显式端点 + Key,输出 Markdown 和 JSON 到 ./out
docling convert-remote --service-url https://<your-managed-service-host> \
--api-key "$KEY" --to md --to json --output ./out report.pdf
# 整个目录,只处理 PDF 和 DOCX,禁用 OCR
docling convert-remote --from pdf --from docx --no-ocr ./inbox
凭据解析(优先级:flag > 环境变量 > .env 文件):
| 参数 | 环境变量 | 说明 |
|---|---|---|
--service-url |
DOCLING_SERVICE_URL |
服务 base URL,必填 |
--api-key |
DOCLING_SERVICE_API_KEY |
API Key,服务未启用鉴权时可省略 |
工作目录存在 .env 文件时会自动加载(override=False,即真实环境变量优先于 .env),见 remote.py。
常用参数(完整列表见 docling convert-remote --help):
| 参数 | 默认值 | 说明 |
|---|---|---|
--from |
全部支持格式 | 输入格式白名单,同时用于目录过滤 |
--to |
md |
本地写出格式,可重复 |
--no-ocr / --force-ocr |
OCR 开 / 不强制 | 位图内容是否走 OCR |
--ocr-lang |
— | 逗号分隔的 OCR 语言 |
--pipeline |
standard |
服务端处理 PDF/图像所用管线 |
--enrich-code 等 |
关 | 服务端增强开关(code / formula / picture 分类 / picture 描述 / chart) |
--page-range |
— | 仅转换页码范围,如 1-4(从 1 开始) |
--document-timeout |
— | 服务端处理单文档超时(秒) |
--max-concurrency |
8 | 并发文档数上限(客户端侧) |
--timeout |
300.0 | 客户端等待每个任务的超时(秒) |
--watcher |
websocket |
任务状态跟踪方式:websocket 或 polling |
--output |
. |
结果输出目录 |
源码上可以看到几个与托管场景直接相关的行为:
- 先做健康检查再干活:命令执行时先调用
client.health(),服务不可达会立即以退出码 1 失败并打印Cannot reach service at <url>(remote.py),避免大批量提交后才发现端点写错。 - 只暴露服务端认可的可选项:
option_kwargs只映射ConvertDocumentsOptions中服务会处理的字段;本地执行类参数(device、线程、PDF 后端内部参数、调试可视化器)被刻意排除(remote.py)。这提示一个事实边界:CLI 的选项集是服务端契约的投影,托管服务如果未开启某些增强模型,对应请求会被服务端拒绝或忽略,以该服务的/docs为准。 - 退出码约定:0 成功;1 运行时/连接失败(服务不可达、转换错误);2 用法/配置错误(三个来源都解析不到 service URL)(remote.py),便于在脚本和 Agent 工作流中做分支处理。
- URL 源不会被本地下载:http(s) URL 直接作为 HTTP 源请求发给服务端,由服务端抓取(remote.py)——对托管服务来说这通常更高效,也避免大文件过客户端。
客户端的可靠性行为:超时、重试与用量限额
托管服务通常有网关、限流与配额,客户端在 client.py 中对此有明确处理,了解这些行为有助于排错:
- 服务端 500/502:指数退避重试(基数 1 秒),默认
http_retries=3,耗尽后抛ServiceUnavailableError(client.py)。 - 429/503 限流:优先读取响应头
Retry-After(支持秒数与 HTTP-date 两种格式)作为等待时间,同样受重试次数约束(client.py)。 - 402 支付要求:被解释为用量超限——客户端解析
UsageLimitExceededResponse并抛出携带currentUsage与limit的UsageLimitExceededError(client.py)。这是托管服务特有的信号:请求本身合法,但账户配额/计费被触发,属于业务错误而非瞬时故障,不应盲目重试。异常类定义见 exceptions.py。 - 任务级超时:
job_timeout默认 300 秒,由 WebSocket 状态观察者(默认)或轮询观察者执行,WebSocket 失败可回落到轮询(ws_fallback_to_poll=True),见 client.py。 - 并发上限:
max_concurrency默认 8、硬上限 512,越界在构造期报错(client.py)。 - 产物下载防护:对预签名产物 URL 做 SSRF 防护(只允许全局可路由地址,拒绝内网/回环/链路本地地址),防止被恶意或错误配置的服务指向客户端内网(client.py)。
这些行为对自托管服务同样生效,因此把它们理解为"客户端对任何 docling-serve 端点的通用契约"即可。
接入自检清单
把托管服务(如 Docling for IBM watsonx)接入生产前的核对项:
- 连通性:先
GET /health(或client.health())确认端点与 Key 有效;再打开/docs核对可用端点与 schema 版本。 - 鉴权:确认 Key 通过
X-Api-Key头传递,并避免把它写进代码仓库;CLI 场景可用环境变量或.env。 - 选项裁剪:只发送该服务
/docs中声明的转换选项;增强类开关(公式、图表、图片描述)以服务端实际部署的模型为准。 - 异步优先:长文档建议走
/async端点 + 轮询/WebSocket,避免同步长请求被网关断开;客户端 SDK 的convert/convert_all已内置该生命周期。 - 错误分类:区分瞬时错误(5xx/429,可重试)、业务错误(402 用量超限,应停并发并检查配额)与任务失败(
TaskExecutionError,看failure详情)。
小结与延伸阅读
managed.md 的核心主张可以浓缩为一句话:托管服务用"同一个 REST API + 一个 base URL + 一个 API Key"换取了全部基础设施运维。当前可用的托管服务为 Docling for IBM watsonx;接入侧有原始 REST、Python 客户端(docling/service_client)、docling convert-remote CLI 三种等价路径,且客户端在重试、限额、超时方面有明确的、源码可查的行为。继续深入可阅读 API server 总览、REST API 参考、部署文档 以及 客户端示例目录。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00