diff --git a/backend/common/pom.xml b/backend/common/pom.xml
index 6e19b5e..105eccc 100644
--- a/backend/common/pom.xml
+++ b/backend/common/pom.xml
@@ -49,5 +49,9 @@
com.fasterxml.jackson.core
jackson-databind
+
+ com.squareup.okhttp3
+ okhttp
+
diff --git a/backend/common/src/main/java/com/artedu/common/util/HttpUtils.java b/backend/common/src/main/java/com/artedu/common/util/HttpUtils.java
new file mode 100644
index 0000000..12dae29
--- /dev/null
+++ b/backend/common/src/main/java/com/artedu/common/util/HttpUtils.java
@@ -0,0 +1,139 @@
+package com.artedu.common.util;
+
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class HttpUtils {
+
+ private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS)
+ .writeTimeout(30, TimeUnit.SECONDS)
+ .build();
+
+ private static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json; charset=utf-8");
+ private static final MediaType FORM_MEDIA_TYPE = MediaType.get("application/x-www-form-urlencoded; charset=utf-8");
+
+ public static String get(String url) throws IOException {
+ return get(url, null);
+ }
+
+ public static String get(String url, Map headers) throws IOException {
+ Request.Builder requestBuilder = new Request.Builder().url(url).get();
+
+ if (headers != null) {
+ for (Map.Entry entry : headers.entrySet()) {
+ requestBuilder.addHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ Request request = requestBuilder.build();
+ return executeRequest(request);
+ }
+
+ public static String post(String url, String jsonBody) throws IOException {
+ return post(url, jsonBody, null);
+ }
+
+ public static String post(String url, String jsonBody, Map headers) throws IOException {
+ RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
+ Request.Builder requestBuilder = new Request.Builder().url(url).post(body);
+
+ if (headers != null) {
+ for (Map.Entry entry : headers.entrySet()) {
+ requestBuilder.addHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ Request request = requestBuilder.build();
+ return executeRequest(request);
+ }
+
+ public static String postForm(String url, Map formParams) throws IOException {
+ return postForm(url, formParams, null);
+ }
+
+ public static String postForm(String url, Map formParams, Map headers) throws IOException {
+ FormBody.Builder formBodyBuilder = new FormBody.Builder();
+ if (formParams != null) {
+ for (Map.Entry entry : formParams.entrySet()) {
+ String value = entry.getValue() != null ? String.valueOf(entry.getValue()) : "";
+ formBodyBuilder.add(entry.getKey(), value);
+ }
+ }
+
+ RequestBody body = formBodyBuilder.build();
+ Request.Builder requestBuilder = new Request.Builder().url(url).post(body);
+
+ if (headers != null) {
+ for (Map.Entry entry : headers.entrySet()) {
+ requestBuilder.addHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ Request request = requestBuilder.build();
+ return executeRequest(request);
+ }
+
+ public static String put(String url, String jsonBody) throws IOException {
+ return put(url, jsonBody, null);
+ }
+
+ public static String put(String url, String jsonBody, Map headers) throws IOException {
+ RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
+ Request.Builder requestBuilder = new Request.Builder().url(url).put(body);
+
+ if (headers != null) {
+ for (Map.Entry entry : headers.entrySet()) {
+ requestBuilder.addHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ Request request = requestBuilder.build();
+ return executeRequest(request);
+ }
+
+ public static String delete(String url) throws IOException {
+ return delete(url, null);
+ }
+
+ public static String delete(String url, Map headers) throws IOException {
+ Request.Builder requestBuilder = new Request.Builder().url(url).delete();
+
+ if (headers != null) {
+ for (Map.Entry entry : headers.entrySet()) {
+ requestBuilder.addHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ Request request = requestBuilder.build();
+ return executeRequest(request);
+ }
+
+ private static String executeRequest(Request request) throws IOException {
+ log.debug("HTTP request: {} {}", request.method(), request.url());
+
+ try (Response response = OK_HTTP_CLIENT.newCall(request).execute()) {
+ if (!response.isSuccessful()) {
+ String errorBody = response.body() != null ? response.body().string() : "";
+ log.error("HTTP request failed: {} {} - {} - {}",
+ request.method(), request.url(), response.code(), errorBody);
+ throw new IOException("HTTP request failed: " + response.code() + " " + errorBody);
+ }
+
+ ResponseBody body = response.body();
+ String result = body != null ? body.string() : "";
+ log.debug("HTTP response: {} {} - {}", request.method(), request.url(), result);
+ return result;
+ }
+ }
+
+ public static OkHttpClient getClient() {
+ return OK_HTTP_CLIENT;
+ }
+}
\ No newline at end of file
diff --git a/backend/generation-service/src/main/java/com/artedu/generation/controller/GenerationController.java b/backend/generation-service/src/main/java/com/artedu/generation/controller/GenerationController.java
index b23c15c..a165000 100644
--- a/backend/generation-service/src/main/java/com/artedu/generation/controller/GenerationController.java
+++ b/backend/generation-service/src/main/java/com/artedu/generation/controller/GenerationController.java
@@ -1,12 +1,15 @@
package com.artedu.generation.controller;
import com.artedu.common.result.Result;
+import com.artedu.common.util.HttpUtils;
import com.artedu.generation.client.LLMClient;
+import com.artedu.generation.config.QaConfig;
import com.artedu.generation.entity.ArchiveMessage;
import com.artedu.generation.mapper.ArchiveMessageMapper;
import com.artedu.generation.service.LlmModelService;
import com.artedu.generation.service.PromptEngine;
import com.artedu.generation.service.QianwenClient;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
@@ -16,12 +19,16 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
@Slf4j
@Validated
@@ -41,6 +48,9 @@ public class GenerationController {
@Autowired
private ArchiveMessageMapper archiveMessageMapper;
+ @Autowired
+ private QaConfig qaConfig;
+
private final ExecutorService sseExecutor = Executors.newCachedThreadPool();
private static final List