فهرست منبع

ai药典优化

liuchengsen 3 هفته پیش
والد
کامیت
dfc65b4e06

+ 3 - 1
backend-java/src/main/java/com/pharmacopoeia/controller/ChatController.java

@@ -171,7 +171,9 @@ public class ChatController {
 
         final String intent = retrieverService.classifyIntent(query);
         final long t0 = System.currentTimeMillis();
-        final String chatRequestId = servletRequest.getHeader("X-Request-Id");
+        // request_id:请求体优先(DTO 已带 requestId 字段),header 兜底
+        final String chatRequestId = request.getRequestId() != null && !request.getRequestId().isBlank()
+                ? request.getRequestId() : servletRequest.getHeader("X-Request-Id");
         final String chatIp = IpUtils.getClientIp(servletRequest);
         final String chatUa = servletRequest.getHeader("User-Agent");
         final java.util.Map<String, Long> timings = new java.util.concurrent.ConcurrentHashMap<>();

+ 4 - 0
backend-java/src/main/java/com/pharmacopoeia/dto/ChatRequest.java

@@ -1,5 +1,6 @@
 package com.pharmacopoeia.dto;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
@@ -12,4 +13,7 @@ import lombok.NoArgsConstructor;
 public class ChatRequest {
     private String message;
     private String conversationId;
+    /** 前端生成的请求追踪 id,用于前后端耗时埋点关联(非必填) */
+    @JsonProperty("request_id")
+    private String requestId;
 }

+ 18 - 7
backend-java/src/main/java/com/pharmacopoeia/service/LLMService.java

@@ -77,22 +77,33 @@ public class LLMService {
         log.info("[chatStream] POST /chat/completions, model={}, msgs={}, bodyBuilt={}ms",
                 props.getModel(), messages.size(), System.currentTimeMillis() - t0);
 
-        final long t1 = System.currentTimeMillis();
+        final long postAt = System.currentTimeMillis();
+        // 真实 TTFB = 首个非空内容 token 到达 - 发起 POST;doFirst 测的是订阅开销(~ms),不是首字
+        final java.util.concurrent.atomic.AtomicLong firstTokenAt = new java.util.concurrent.atomic.AtomicLong(0);
+        final java.util.concurrent.atomic.AtomicInteger tokenCount = new java.util.concurrent.atomic.AtomicInteger(0);
         return chatClient.post()
                 .uri("/chat/completions")
                 .contentType(MediaType.APPLICATION_JSON)
                 .bodyValue(body)
                 .retrieve()
                 .bodyToFlux(String.class)
-                .doFirst(() -> {
-                    long elapsed = System.currentTimeMillis() - t1;
-                    log.info("[chatStream] 百炼已响应, latency={}ms (从POST到收到第一个字节)", elapsed);
-                })
                 .filter(data -> !"[DONE]".equals(data.trim()))
                 .map(this::extractDeltaContent)
+                .doOnNext(s -> {
+                    if (s != null && !s.isEmpty()) {
+                        tokenCount.incrementAndGet();
+                        firstTokenAt.compareAndSet(0, System.currentTimeMillis());
+                    }
+                })
                 .doOnComplete(() -> {
-                    long total = System.currentTimeMillis() - t0;
-                    log.info("[chatStream] 流结束, total={}ms", total);
+                    long now = System.currentTimeMillis();
+                    long total = now - t0;
+                    long ttfb = firstTokenAt.get() > 0 ? firstTokenAt.get() - postAt : -1;
+                    long genMs = firstTokenAt.get() > 0 ? now - firstTokenAt.get() : total;
+                    int n = tokenCount.get();
+                    double tokPerSec = genMs > 0 ? (n * 1000.0 / genMs) : 0;
+                    log.info("[chatStream] done, model={}, total={}ms, ttfb={}ms, tokens={}, genMs={}, tok/s={}",
+                            props.getModel(), total, ttfb, n, genMs, String.format("%.1f", tokPerSec));
                 })
                 .doOnError(e -> {
                     long total = System.currentTimeMillis() - t0;

+ 1 - 1
backend-java/src/main/resources/application.yml

@@ -76,7 +76,7 @@ qwen:
   api-key: ${QWEN_API_KEY:}
   base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
   model: qwen3.7-flash
-  max-tokens: 4096
+  max-tokens: 2048
   temperature: 0.0
   # 视觉模型(图片分析+OCR)
   # 多模态模型(图片/视频分析,原生 API)

+ 1 - 1
static/index.html

@@ -450,7 +450,7 @@
       body=JSON.stringify({imageBase64:media.base64,mimeType:media.mime,message:query});
     }else{
       endpoint=API_BASE+'/api/v1/chat/stream';
-      body=JSON.stringify({message:query});
+      body=JSON.stringify({message:query,request_id:metrics.reqId});
     }
     try{
       var ctrl=streamAbort?streamAbort:new AbortController();