zhou zhou
8 小时以前 82624affb0251b75b62b35567d3eb260c06efe78
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package com.vincent.rsf.server.ai.service.impl.chat;
 
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.ai.entity.AiParam;
import com.vincent.rsf.server.ai.enums.AiErrorCategory;
import com.vincent.rsf.server.ai.exception.AiChatException;
import com.vincent.rsf.server.ai.service.impl.AiOpenAiApiSupport;
import io.micrometer.observation.ObservationRegistry;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.model.tool.DefaultToolCallingManager;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.execution.DefaultToolExecutionExceptionProcessor;
import org.springframework.ai.tool.resolution.SpringBeanToolCallbackResolver;
import org.springframework.ai.util.json.schema.SchemaType;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;
 
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
 
@Component
@RequiredArgsConstructor
public class AiOpenAiChatModelFactory {
 
    private final GenericApplicationContext applicationContext;
    private final ObservationRegistry observationRegistry;
 
    public OpenAiChatModel createChatModel(AiParam aiParam) {
        OpenAiApi openAiApi = AiOpenAiApiSupport.buildOpenAiApi(aiParam);
        ToolCallingManager toolCallingManager = DefaultToolCallingManager.builder()
                .observationRegistry(observationRegistry)
                .toolCallbackResolver(new SpringBeanToolCallbackResolver(applicationContext, SchemaType.OPEN_API_SCHEMA))
                .toolExecutionExceptionProcessor(new DefaultToolExecutionExceptionProcessor(false))
                .build();
        return new OpenAiChatModel(
                openAiApi,
                OpenAiChatOptions.builder()
                        .model(aiParam.getModel())
                        .temperature(aiParam.getTemperature())
                        .topP(aiParam.getTopP())
                        .maxTokens(aiParam.getMaxTokens())
                        .streamUsage(true)
                        .build(),
                toolCallingManager,
                org.springframework.retry.support.RetryTemplate.builder().maxAttempts(1).build(),
                observationRegistry
        );
    }
 
    public OpenAiChatOptions buildChatOptions(AiParam aiParam, ToolCallback[] toolCallbacks, Long userId, Long tenantId,
                                              String requestId, Long sessionId, Map<String, Object> metadata) {
        if (userId == null) {
            throw new AiChatException("AI_AUTH_USER_MISSING", AiErrorCategory.AUTH, "OPTIONS_BUILD", "当前登录用户不存在", null);
        }
        OpenAiChatOptions.Builder builder = OpenAiChatOptions.builder()
                .model(aiParam.getModel())
                .temperature(aiParam.getTemperature())
                .topP(aiParam.getTopP())
                .maxTokens(aiParam.getMaxTokens())
                .streamUsage(true)
                .user(String.valueOf(userId));
        if (toolCallbacks != null && toolCallbacks.length > 0) {
            builder.toolCallbacks(Arrays.stream(toolCallbacks).toList());
        }
        Map<String, Object> toolContext = new LinkedHashMap<>();
        toolContext.put("userId", userId);
        toolContext.put("tenantId", tenantId);
        toolContext.put("requestId", requestId);
        toolContext.put("sessionId", sessionId);
        Map<String, String> metadataMap = new LinkedHashMap<>();
        if (metadata != null) {
            metadata.forEach((key, value) -> {
                String normalized = value == null ? "" : String.valueOf(value);
                metadataMap.put(key, normalized);
                toolContext.put(key, normalized);
            });
        }
        builder.toolContext(toolContext);
        if (!metadataMap.isEmpty()) {
            builder.metadata(metadataMap);
        }
        return builder.build();
    }
}