首页洞察 › 裁判文书 API 接入实战

裁判文书 API 接入实战:Python / Node.js 代码示例(2026 后端工程师指南)

2026-06-27 · 文书查 · 面向后端与法律 AI 工程师

如果你要在裁判文书数据上盖一个产品——类案检索、案件研判、合规尽调、法律 RAG 问答——最先要打通的,不是模型,而是把一份干净、可过滤、可回链的判决数据稳定地拉进你的服务。这篇是写给后端工程师的接入实战:鉴权怎么放、检索怎么调、分页和过滤怎么写、原文怎么回链、限流和重试怎么兜底,Python 与 Node.js 两种语言都给可直接改的骨架。文中的接口路径与字段名一律用占位,以你拿到的接口文档为准,本文教的是接入模式,不是某个固定端点。

一、接入前先想清楚三件事

动手写代码之前,先把这三个决定定下来,能省掉后面大半返工:

二、鉴权:API Key 怎么放才安全

裁判文书 API 通常用 API Key 鉴权(放在请求头里)。两条铁律:

下面所有示例里的 API_BASE 与具体路径(如 /search/judgments/{id})都是占位示意。实际的 base 地址、路径、请求头名称、字段命名,以接口文档 / 控制台为准,请勿照搬本文占位直接上线。

三、Python 接入示例(requests)

一个最小可用的检索 + 取详情 + 回链的骨架。生产里建议换成 httpx 并加连接池,这里用 requests 求清晰:

# pip install requests
import os, time, requests

API_BASE = "https://tob.wenshucha.com/api/v1"   # 占位,以接口文档为准
API_KEY  = os.environ["WENSHUCHA_API_KEY"]       # 放环境变量,别硬编码

session = requests.Session()
session.headers.update({"Authorization": f"Bearer {API_KEY}"})

def search_judgments(keyword, *, cause=None, court_level=None,
                     year_from=None, year_to=None, page=1, size=20):
    # 字段名以接口文档为准,这里示意常见的过滤维度
    params = {
        "q": keyword,
        "cause": cause,              # 案由
        "court_level": court_level,  # 法院层级
        "year_from": year_from,
        "year_to": year_to,
        "page": page,
        "page_size": size,
    }
    params = {k: v for k, v in params.items() if v is not None}
    resp = request_with_retry("GET", f"{API_BASE}/search", params=params)
    return resp.json()

def get_judgment(doc_id):
    resp = request_with_retry("GET", f"{API_BASE}/judgments/{doc_id}")
    return resp.json()

def request_with_retry(method, url, *, params=None, max_retry=4):
    # 对 429 / 5xx 做指数退避;对 4xx(鉴权/参数)直接抛
    for attempt in range(max_retry):
        r = session.request(method, url, params=params, timeout=15)
        if r.status_code == 429 or r.status_code >= 500:
            wait = min(2 ** attempt, 30)
            time.sleep(wait)
            continue
        r.raise_for_status()
        return r
    r.raise_for_status()
    return r

if __name__ == "__main__":
    data = search_judgments("民间借贷 利息", cause="民间借贷纠纷",
                            year_from=2022, year_to=2025, size=10)
    for hit in data.get("items", []):       # 列表字段名以文档为准
        print(hit.get("case_no"), hit.get("court"), hit.get("source_url"))
        # source_url = 回链原文,务必存下来供用户核对

四、Node.js 接入示例(fetch)

等价骨架,Node 18+ 自带 fetch。BFF / 实时检索服务这样写最顺:

// Node 18+ 自带 fetch;旧版本用 node-fetch / axios
const API_BASE = "https://tob.wenshucha.com/api/v1"; // 占位,以接口文档为准
const API_KEY  = process.env.WENSHUCHA_API_KEY;      // 放环境变量

async function requestWithRetry(path, { params = {}, maxRetry = 4 } = {}) {
  const qs = new URLSearchParams(
    Object.entries(params).filter(([, v]) => v != null)
  ).toString();
  const url = `${API_BASE}${path}${qs ? "?" + qs : ""}`;

  for (let attempt = 0; attempt < maxRetry; attempt++) {
    const r = await fetch(url, {
      headers: { Authorization: `Bearer ${API_KEY}` },
      signal: AbortSignal.timeout(15000),
    });
    if (r.status === 429 || r.status >= 500) {
      await new Promise(s => setTimeout(s, Math.min(2 ** attempt, 30) * 1000));
      continue;
    }
    if (!r.ok) throw new Error(`HTTP ${r.status}`);
    return r.json();
  }
  throw new Error("max retry exceeded");
}

async function searchJudgments(keyword, opts = {}) {
  return requestWithRetry("/search", {
    params: { q: keyword, cause: opts.cause, court_level: opts.courtLevel,
              year_from: opts.yearFrom, year_to: opts.yearTo,
              page: opts.page ?? 1, page_size: opts.size ?? 20 },
  });
}

const data = await searchJudgments("民间借贷 利息", {
  cause: "民间借贷纠纷", yearFrom: 2022, yearTo: 2025, size: 10,
});
for (const hit of data.items ?? []) {
  console.log(hit.case_no, hit.court, hit.source_url); // 字段名以文档为准
}

五、分页与批量:别一次性拉爆

检索结果上千上万条时,要用分页/游标逐页拉,别试图一把梭。两种常见模式:

模式怎么用适合
页码分页page + page_size 逐页递增,直到返回空结果量中等、要跳页的交互检索
游标分页每次带上一页返回的 cursor / next_token,顺序拉到底大批量顺序导出,深翻页更稳

批量拉取时务必控制并发 + 尊重限流:并发开 2-4 路足够,命中 429 就退避,别把自己 IP 打进限流黑名单。把已拉到的 doc_id 落库去重,断点续传靠它。

六、把结果接进你的产品:三种典型用法

1)接进检索 / 类案功能

最直接:用户输入 → 调 search → 渲染命中列表(带案由、法院、年份、回链)。要做"类案"而非"关键词匹配",检索侧的召回与重排是关键,展开见我们的 类案检索:语义向量 vs 关键词

2)接进法律 RAG / 问答

让大模型回答前先检索真实判决,把命中片段作为上下文喂给模型,并要求每个结论都回链到检索到的原文。绝不能让模型凭记忆生成判例——那会编造不存在的案号和裁判要旨。这是 grounding,不是 prompt 技巧。

3)接进批处理 / 实证统计

按案由+年份批量拉结构化字段做计量分析。这类场景对"覆盖可表征 + 可固定快照"要求高,展开见 法学实证研究数据接入指南

七、REST API 还是 MCP?一张表说清

同一份数据,两种接入形态,按谁来消费选:

维度REST APIMCP
消费方你自己的后端 / 批处理 / RAG 管线Claude、ChatGPT、Cursor 等大模型 Agent
谁决定何时检索你的代码显式调用模型自己判断、可链式多轮检索
控流控错你完全掌控(重试/限流/缓存)交给 MCP 客户端,集成成本低
典型节奏生产集成的主力先做原型快速验证价值

常见做法是先 MCP 跑原型、再 REST API 上生产。MCP 怎么接见 5 分钟接入文书查 MCP:Claude Desktop 实战

八、上生产前的检查清单

  1. Key 在服务端环境变量里,前端不直接持 Key,日志不打印 Key?
  2. 429 / 5xx 有指数退避,4xx 直接报错不空转?超时设了没?
  3. 分页拉全了没有漏页?doc_id 落库去重、能断点续传?
  4. 每条结果都存了回链原文,用户能核对到原始判决?
  5. 展示给用户的字段做了必要脱敏,符合合规要求?
  6. 字段名、过滤参数都对齐了接口文档,没照搬本文占位?

涉密 / 政企内网场景:如果你的产品要服务政府、国企或处理敏感案件,数据不能出域,可走私有化部署——把 1.7 亿+ 裁判文书与检索能力整套落到你的机房,内网调用同样的接口形态,详见 私有化方案

九、常见问题

Q:接口字段我能照着这篇文章写死吗?

A:不能。本文所有路径与字段名都是占位示意,目的是讲清接入模式。实际命名、过滤参数、分页机制以你拿到的接口文档 / 控制台为准,先用试用 Key 跑通真实返回结构再写映射。

Q:检索响应慢 / 偶发超时怎么办?

A:先确认是否命中了限流(429);其次给高频查询加一层结果缓存(同样的关键词+过滤短时间内别重复打);批量场景降并发、加退避。生产建议把检索服务和模型推理拆开,互不阻塞。

Q:能先小范围试再付费扩量吗?

A:可以。建议先申请试用 Key,用一个真实场景把"检索→回链→展示/grounding"全链路跑通,确认数据覆盖与字段满足产品需要,再谈正式额度与价格。

申请裁判文书 API 试用 Key

提供你的产品场景与大致调用量,我们给试用 key + 接口文档,1 个工作日内反馈。先跑通再谈扩量。

📞 联系商务 Jack · 131 6872 7779

或邮件 chenjiaxin@wenshucha.com · 查看 API / MCP 定价

相关阅读:5 分钟接入文书查 MCP · 类案检索:语义 vs 关键词 · 法律 AI 创业团队怎么选数据底座 · 私有化部署方案