Java 接入降重降AI接口
Java 调用降重降AI API 完整示例:Java 11+ HttpClient 基础调用、Jackson 解析响应、Apache POI 提取脚注占位符、Maven 依赖与并发建议。
Java 接入降重降AI接口
Java 11+ 内置的 java.net.http.HttpClient 足够完成调用,无需额外 HTTP 依赖;JSON 处理推荐 Jackson。接口一次改写同时完成降重和降AI,单次请求处理一个正文自然段(不超过1000字),详细参数说明见接口文档。
Maven 依赖
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>
<!-- 如需处理 Word 文档脚注 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
</dependencies>
基础调用
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
public class ReduceClient {
private static final String API_URL = "https://api.llmapi.fit/completion/v2/reduce";
private static final String API_KEY = System.getenv().getOrDefault("LLMAPI_KEY", "YOUR_API_KEY");
private final HttpClient http = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
private final ObjectMapper mapper = new ObjectMapper();
/** 改写单个正文段落 */
public String reduceParagraph(String text) throws Exception {
String body = mapper.writeValueAsString(Map.of("text", text));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(API_URL))
.header("Authorization", "Bearer " + API_KEY)
.header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(180)) // 高峰期智能排队最长约2分钟
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> resp = http.send(request, HttpResponse.BodyHandlers.ofString());
JsonNode data = mapper.readTree(resp.body());
if (resp.statusCode() == 200 && "success".equals(data.path("code").asText())) {
return data.path("output_text").asText();
}
throw new RuntimeException("HTTP " + resp.statusCode()
+ " " + data.path("code").asText()
+ ": " + data.path("message").asText());
}
}
逐段落处理全文
接口按段落级别改写,循环处理论文的正文自然段,速率控制在 10 次/秒以内:
List<String> paragraphs = List.of(
"第一个正文自然段……",
"第二个正文自然段……"
);
List<String> rewritten = new ArrayList<>();
for (String p : paragraphs) {
rewritten.add(client.reduceParagraph(p));
Thread.sleep(500);
}
重试策略
429(请求过于频繁)与 503(GPU服务繁忙)是可重试错误,建议等待 3-5 秒后重试;400(参数/余额)与 401(密钥)不可重试:
public String reduceWithRetry(String text, int maxRetries) throws Exception {
for (int i = 1; i <= maxRetries; i++) {
try {
return reduceParagraph(text);
} catch (RuntimeException e) {
if (e.getMessage().contains("HTTP 429") || e.getMessage().contains("HTTP 503")) {
Thread.sleep(4000);
continue;
}
throw e;
}
}
throw new IllegalStateException("重试次数已用尽");
}
处理 Word 文档脚注(Apache POI)
论文段落常带脚注引用,直接发送会丢失。正确做法是把脚注引用替换为 [[FNn]] 占位符,改写后原样保留,写回时恢复(完整规范见接口文档第8节)。
POI(XWPF)提取段落文本与脚注占位符:
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
try (XWPFDocument doc = new XWPFDocument(new FileInputStream("论文.docx"))) {
for (XWPFParagraph paragraph : doc.getParagraphs()) {
StringBuilder sb = new StringBuilder();
int fnIndex = 0;
// 遍历段落内的 run,脚注引用处落占位符
paragraph.getRuns().forEach(run -> {
// 注意:脚注引用在 CTP 的子元素中,需按 w:footnoteReference 判断,
// 普通文本取 run.text(),占位符按段内顺序编号 [[FN0]]、[[FN1]]……
});
// 简化写法:遍历 CTP 子元素
org.apache.xmlbeans.XmlObject[] children = paragraph.getCTP().selectPath(
"declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' ./*");
for (org.apache.xmlbeans.XmlObject child : children) {
org.w3c.dom.Node node = child.getDomNode();
String localName = node.getLocalName();
if ("r".equals(localName)) {
for (int i = 0; i < node.getChildNodes().getLength(); i++) {
org.w3c.dom.Node inner = node.getChildNodes().item(i);
if ("t".equals(inner.getLocalName()) && inner.getTextContent() != null) {
sb.append(inner.getTextContent());
} else if ("footnoteReference".equals(inner.getLocalName())) {
sb.append(String.format("[[FN%d]]", fnIndex++));
}
}
}
}
String textWithPlaceholders = sb.toString();
// 调用接口改写后,按占位符切分写回,原脚注引用(原 id)插回原位
}
}
写回时段落对象保持不动,只替换文字内容,在 [[FNn]] 处插入原 CTRFtnMark/脚注引用节点;word/footnotes.xml 全程不需要修改。
并发建议
- 批量任务可用
ThreadPoolExecutor(固定 5 线程以内)或CompletableFuture,请求速率控制在 10 次/秒以内 HttpClient实例全局复用一个即可,Java 11+ 版本内部自带连接池
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
401 unauthorized | API Key 错误 | 检查请求头 Authorization: Bearer YOUR_API_KEY |
400 textTooLong | 单段超过1000字 | 按语义拆分成多个自然段分别调用 |
HttpTimeoutException | 高峰期排队 | 请求超时设 180 秒,重试 2-3 次 |
| 中文乱码 | 响应未按 UTF-8 解析 | HttpResponse.BodyHandlers.ofString(body, StandardCharsets.UTF_8) |