java ragflow api

接入与开发

给 Java 后端讲清 RAGFlow 接口的请求封装:HTTP 客户端选型、超时并发、流式解析、日志与降级怎么落地。

Java 项目里调 RAGFlow,多数人不是卡在「不知道接口」,而是卡在封装上:用 RestTemplate 还是 OkHttp、流式响应怎么读、超时设多少、线程池怎么配、失败了要不要重试。这篇按工程落地的顺序讲一遍,给出可直接套用的封装结构和排查顺序,具体接口字段与参数以站内页面当时的口径为准。

Java 项目里调 RAGFlow,卡人的往往不是「不知道有哪个接口」,而是封装那一层没想清楚:用 RestTemplate 还是 OkHttp、流式响应怎么读、超时设多少、线程池配多大、失败了要不要重试。这些问题在写第一行代码前不定下来,后面就是一边改调用一边改架构。

这篇按工程落地的顺序走一遍:先选客户端,再定模型层,然后处理超时并发和流式解析,最后落到日志降级和上线验收。具体的接口路径、字段含义和参数取值,以站内资料库当时的口径为准,别拿这篇当接口文档用。

先定 HTTP 客户端:RestTemplate、WebClient 还是 OkHttp

选型先看团队现有栈,别为了调一个接口引入一套新范式。三种方式的核心差别在阻塞模型、流式支持和连接池调优成本上,下面这张表可以当快速对照用。

方案适合场景主要代价
RestTemplate已有 Spring 阻塞式项目,调用量不大默认连接池需手动调优,流式读取要自己处理
WebClient需要大量并发或天然要流式响应式心智负担,调试链路变长
OkHttp想要结构直白、流式读取省心需自己管序列化和重试逻辑
  • 团队已有栈优先:已经在用 WebClient 就别退回 OkHttp,混用两套客户端会带来两套超时和两套连接池
  • 连接池必须显式配:最大连接数、单路由连接数、空闲回收时间,默认值在高并发下会排队
  • 统一封装一个 RagflowClient 类,把 baseUrl、鉴权头、序列化器、超时收在构造里,业务层只传参数
  • 什么情况下不适用:只在启动脚本里跑一两次的批处理任务,直接静态方法拼请求就够,套 Client 反而增加维护面

请求与响应的模型层:别让 Map 满天飞

接口能调通之后,维护成本主要来自模型层。用 Map 传参省时间,但字段一多就会出现「这个 key 到底叫什么」的反复确认,编译期一点忙都帮不上。用 record 或不可变类定义请求体和响应体,字段命名跟接口文档对齐,字段增减时改一处。

  1. 抽参数对象把会话 ID、知识库 ID、文档 ID 这类标识单独抽成一个参数对象,避免长参数列表里传错位置——这是这类接口最常见的低级错误
  2. 包一层结果对象响应统一包一层:业务数据、原始 JSON、HTTP 状态、耗时。出问题时不用再加日志复现,直接看这层日志就行
  3. 流式与非流式分开流式接口和非流式接口的返回类型要分开,别用同一个方法签名靠布尔开关切换,调用方读起来很痛苦

一个容易忽略的点:响应体里带引用来源或分片信息时,不要只保留拼好的字符串就丢掉原始结构。后面要做引用高亮、前端回链时,原始结构才是可用的,字符串只能用来展示。

超时、重试与并发:按接口性质分档

超时不能全项目一个值。短查询类接口和上传文档、触发解析这类长任务,性质完全不同,混用一个超时值要么误杀正常请求,要么让真正的卡死长时间占着连接。分档设置之前,先到站内的速度测试工具量一下自己的延迟基线,别拍脑袋定秒数。

接口性质连接超时读取超时重试策略
短查询可以紧一些可以紧一些幂等 GET 可重试
上传文档常规值给得宽不开自动重试,靠幂等键
触发解析常规值给得宽不开自动重试
流式问答常规值单独配或加心跳不重试,重试会丢上下文
  • 重试只对幂等且失败原因明确的操作开:文档上传和入库触发重复提交会造脏数据,靠业务层幂等键挡
  • 线程池跟下游限流对齐:池子开得比对方额度还大,只会把请求堆在队列里等到超时,参考站内关于限流与并发的口径
  • 流式读取时连接不能被普通超时掐断,要单独配置读超时或心跳,否则长回答会断在半句话上
  • 并发突刺时先看队列长度再看错误率,队列先满说明是池子配置问题,不是网络问题

流式解析与错误处理:把失败变成可读信息

流式响应按行或按 SSE 事件边界切,不要按字节读。缓冲区里的残包要留到下一轮拼接,否则中文会被截断成乱码,这种问题在本地测试时经常看不出来,一上生产就变成偶发脏数据。

# Java 侧伪代码结构,不是可直接运行脚本\n// 缓冲残包,按行边界切分\nStringBuilder buf = new StringBuilder();\nwhile ((line = reader.readLine()) != null) {\n  if (!line.endsWith(delimiter)) { buf.append(line); continue; }\n  buffer = buf.append(line).toString(); buf.setLength(0);\n  handle(buffer);\n}

错误要分三类处理:连不上(网络、DNS、证书)、连上被拒(鉴权、权限、额度)、连上但返回业务错误(参数不对、资源不存在)。三类的动作完全不同,统一 catch 成一句日志等于把排查线索全丢了。

  • 错误对象至少留:HTTP 状态、请求 ID、接口路径、关键入参摘要、耗时
  • 排查顺序先看状态码,再看响应体,最后才回头查自己的参数拼装
  • 遇到限流要做退避而不是立刻重投,退避梯度和排队思路见站内限流处理指南
  • 不要把所有非 2xx 都当「服务挂了」,很多其实是自己的参数或权限问题

日志、降级与验收:上线前要跑的几条

日志字段固定成几个:traceId、接口名、耗时、状态、重试次数、Token 或文档量级。字段不固定,后面做慢查询和成本复盘时就没法聚合。这部分和站内关于中转站调用成本追踪的思路是一致的:先有可量化的记录,才谈得上优化。

  • 降级路径提前想好:不可用时是返回空结果、走缓存、还是降级到纯模型直答,取决于业务能不能接受「没有引用来源」的答案
  • 上线前跑一轮小验收:正常查询、空结果、超长文档、并发突刺、断网恢复各一条
  • 封装层的单测用本地桩服务,把流式分片和错误响应做成固定样本,回归才有意义
  • 降级要能被观测:走到降级分支时打一条明确日志,别让降级悄悄发生

验收跑完再放量。这五条里最容易被跳过的是「断网恢复」——它检验的是连接池和重试逻辑在异常后能不能自己恢复,而不是功能对不对。

下一步封装结构定下来之后,顺手核对一下你实际调用的接口在哪家服务上跑、延迟基线是多少,这两个数会直接影响你的超时和线程池取值。

常见问题

Java 调 RAGFlow 用 RestTemplate 够不够?

单机低并发、只做查询类调用,够用。但默认的 SimpleClientHttpRequestFactory 没有连接池,并发一上来就退化成串行等待,而且读取流式响应不方便。要接流式或并发稍高,换成带连接池的 OkHttp 或 Apache HttpClient,或者直接用 WebClient,省掉后面改封装的返工。

流式输出在 Java 里怎么读才不会乱码?

关键是按行或按事件边界读,不要按固定字节数读。用 BufferedReader 的 readLine 或 OkHttp 的 source 逐行取,遇到不完整的一行先缓存在 StringBuilder 里,等下一批数据拼上再解析;解析时统一按 UTF-8 处理。如果没按边界切,多字节中文就会断在中间,表现出来就是偶尔冒出乱码。

接口偶尔超时,是该加重试还是加超时时间?

先分清是「对方慢」还是「到不了」。到不了通常是网络或网关问题,加超时没用,加重试也大概率还是失败,先查连通性和代理配置。对方慢的话,先到 /tools/speed-test 量一遍基线,再看是不是自己的连接池或线程池排队造成的等待。只有确认是偶发抖动,才对幂等的查询操作加有限次退避重试。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。