Initial commit: Fintec AI Framework with Agent, RAG, and MCP modules
This commit is contained in:
BIN
fintec-framework-ai-core/.DS_Store
vendored
Normal file
BIN
fintec-framework-ai-core/.DS_Store
vendored
Normal file
Binary file not shown.
23
fintec-framework-ai-core/pom.xml
Normal file
23
fintec-framework-ai-core/pom.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.ccb.fintec</groupId>
|
||||
<artifactId>fintec-framework-parent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>fintec-framework-ai-core</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- 只依赖 spring-ai 核心,不绑定具体模型 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-commons</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.ccb.fintec.core.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AI 统一响应对象 - 封装所有 AI 调用的返回结果
|
||||
*/
|
||||
public class AiResponse {
|
||||
|
||||
private String requestId;
|
||||
private Object content;
|
||||
private TokenUsage tokenUsage;
|
||||
private long duration;
|
||||
private LocalDateTime timestamp;
|
||||
private Map<String, Object> metadata;
|
||||
private ErrorInfo error;
|
||||
|
||||
public static class TokenUsage {
|
||||
private int promptTokens;
|
||||
private int completionTokens;
|
||||
private int totalTokens;
|
||||
|
||||
public TokenUsage() {}
|
||||
|
||||
public TokenUsage(int promptTokens, int completionTokens, int totalTokens) {
|
||||
this.promptTokens = promptTokens;
|
||||
this.completionTokens = completionTokens;
|
||||
this.totalTokens = totalTokens;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public int getPromptTokens() { return promptTokens; }
|
||||
public void setPromptTokens(int promptTokens) { this.promptTokens = promptTokens; }
|
||||
public int getCompletionTokens() { return completionTokens; }
|
||||
public void setCompletionTokens(int completionTokens) { this.completionTokens = completionTokens; }
|
||||
public int getTotalTokens() { return totalTokens; }
|
||||
public void setTotalTokens(int totalTokens) { this.totalTokens = totalTokens; }
|
||||
}
|
||||
|
||||
public static class ErrorInfo {
|
||||
private String code;
|
||||
private String message;
|
||||
private String detail;
|
||||
|
||||
public ErrorInfo() {}
|
||||
|
||||
public ErrorInfo(String code, String message, String detail) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getCode() { return code; }
|
||||
public void setCode(String code) { this.code = code; }
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
public String getDetail() { return detail; }
|
||||
public void setDetail(String detail) { this.detail = detail; }
|
||||
}
|
||||
|
||||
public AiResponse() {
|
||||
this.timestamp = LocalDateTime.now();
|
||||
this.metadata = new HashMap<>();
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getRequestId() { return requestId; }
|
||||
public void setRequestId(String requestId) { this.requestId = requestId; }
|
||||
public Object getContent() { return content; }
|
||||
public void setContent(Object content) { this.content = content; }
|
||||
public TokenUsage getTokenUsage() { return tokenUsage; }
|
||||
public void setTokenUsage(TokenUsage tokenUsage) { this.tokenUsage = tokenUsage; }
|
||||
public long getDuration() { return duration; }
|
||||
public void setDuration(long duration) { this.duration = duration; }
|
||||
public LocalDateTime getTimestamp() { return timestamp; }
|
||||
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
|
||||
public Map<String, Object> getMetadata() { return metadata; }
|
||||
public void setMetadata(Map<String, Object> metadata) { this.metadata = metadata; }
|
||||
public ErrorInfo getError() { return error; }
|
||||
public void setError(ErrorInfo error) { this.error = error; }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.ccb.fintec.core.exception;
|
||||
|
||||
/**
|
||||
* AI 框架统一异常
|
||||
*/
|
||||
public class AiException extends RuntimeException {
|
||||
|
||||
private final String errorCode;
|
||||
private final String requestId;
|
||||
|
||||
public AiException(String message) {
|
||||
super(message);
|
||||
this.errorCode = "AI_ERROR";
|
||||
this.requestId = null;
|
||||
}
|
||||
|
||||
public AiException(String errorCode, String message) {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
this.requestId = null;
|
||||
}
|
||||
|
||||
public AiException(String errorCode, String message, String requestId) {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
public AiException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.errorCode = "AI_ERROR";
|
||||
this.requestId = null;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.ccb.fintec.core.graph;
|
||||
|
||||
/**
|
||||
* 条件边 - 用于路由决策
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Condition {
|
||||
|
||||
/**
|
||||
* 判断条件是否满足
|
||||
*
|
||||
* @param context 上下文数据
|
||||
* @return 是否满足条件
|
||||
*/
|
||||
boolean evaluate(Object context);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.ccb.fintec.core.graph;
|
||||
|
||||
/**
|
||||
* 工作流节点 - 封装 AI 调用或业务逻辑
|
||||
*
|
||||
* @param <I> 输入类型
|
||||
* @param <O> 输出类型
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Node<I, O> {
|
||||
|
||||
/**
|
||||
* 执行节点逻辑
|
||||
*
|
||||
* @param input 输入数据
|
||||
* @return 输出结果
|
||||
*/
|
||||
O execute(I input);
|
||||
|
||||
/**
|
||||
* 获取节点名称(用于调试和日志)
|
||||
*/
|
||||
default String getName() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.ccb.fintec.core.metrics;
|
||||
|
||||
/**
|
||||
* AI 观测指标常量 - 统一定义所有模块的监控指标前缀和名称
|
||||
*/
|
||||
public final class MetricConstants {
|
||||
|
||||
// 指标前缀
|
||||
public static final String METRIC_PREFIX = "fintec.ai";
|
||||
|
||||
// Chat 相关指标
|
||||
public static final String CHAT_REQUEST_TOTAL = METRIC_PREFIX + ".chat.request.total";
|
||||
public static final String CHAT_REQUEST_DURATION = METRIC_PREFIX + ".chat.request.duration";
|
||||
public static final String CHAT_TOKEN_USAGE = METRIC_PREFIX + ".chat.token.usage";
|
||||
public static final String CHAT_ERROR_TOTAL = METRIC_PREFIX + ".chat.error.total";
|
||||
|
||||
// RAG 相关指标
|
||||
public static final String RAG_REQUEST_TOTAL = METRIC_PREFIX + ".rag.request.total";
|
||||
public static final String RAG_REQUEST_DURATION = METRIC_PREFIX + ".rag.request.duration";
|
||||
public static final String RAG_RETRIEVAL_COUNT = METRIC_PREFIX + ".rag.retrieval.count";
|
||||
public static final String RAG_EMBEDDING_DURATION = METRIC_PREFIX + ".rag.embedding.duration";
|
||||
|
||||
// MCP 相关指标
|
||||
public static final String MCP_TOOL_CALL_TOTAL = METRIC_PREFIX + ".mcp.tool.call.total";
|
||||
public static final String MCP_TOOL_CALL_DURATION = METRIC_PREFIX + ".mcp.tool.call.duration";
|
||||
public static final String MCP_TOOL_ERROR_TOTAL = METRIC_PREFIX + ".mcp.tool.error.total";
|
||||
|
||||
// Graph 工作流指标
|
||||
public static final String GRAPH_WORKFLOW_TOTAL = METRIC_PREFIX + ".graph.workflow.total";
|
||||
public static final String GRAPH_WORKFLOW_DURATION = METRIC_PREFIX + ".graph.workflow.duration";
|
||||
public static final String GRAPH_NODE_EXECUTION_TOTAL = METRIC_PREFIX + ".graph.node.execution.total";
|
||||
|
||||
// 安全相关指标
|
||||
public static final String SECURITY_BLOCK_TOTAL = METRIC_PREFIX + ".security.block.total";
|
||||
public static final String SECURITY_SCAN_DURATION = METRIC_PREFIX + ".security.scan.duration";
|
||||
|
||||
// 限流相关指标
|
||||
public static final String RATE_LIMIT_REJECT_TOTAL = METRIC_PREFIX + ".rate.limit.reject.total";
|
||||
|
||||
// 重试相关指标
|
||||
public static final String RETRY_TOTAL = METRIC_PREFIX + ".retry.total";
|
||||
public static final String RETRY_SUCCESS_TOTAL = METRIC_PREFIX + ".retry.success.total";
|
||||
|
||||
private MetricConstants() {
|
||||
// 防止实例化
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.ccb.fintec.core.properties;
|
||||
|
||||
/**
|
||||
* Agent 相关配置属性
|
||||
*/
|
||||
public class AgentProperties {
|
||||
/** 默认系统提示词,统一公司 AI 风格 */
|
||||
private String defaultSystemPrompt = "你是一个专业的 AI 助手,请用中文简洁准确地回答问题。";
|
||||
/** 对话记忆保留的最大消息条数 */
|
||||
private int memoryWindowSize = 20;
|
||||
/** 流式输出超时(秒) */
|
||||
private int streamTimeoutSeconds = 60;
|
||||
|
||||
public String getDefaultSystemPrompt() {
|
||||
return defaultSystemPrompt;
|
||||
}
|
||||
|
||||
public void setDefaultSystemPrompt(String defaultSystemPrompt) {
|
||||
this.defaultSystemPrompt = defaultSystemPrompt;
|
||||
}
|
||||
|
||||
public int getMemoryWindowSize() {
|
||||
return memoryWindowSize;
|
||||
}
|
||||
|
||||
public void setMemoryWindowSize(int memoryWindowSize) {
|
||||
this.memoryWindowSize = memoryWindowSize;
|
||||
}
|
||||
|
||||
public int getStreamTimeoutSeconds() {
|
||||
return streamTimeoutSeconds;
|
||||
}
|
||||
|
||||
public void setStreamTimeoutSeconds(int streamTimeoutSeconds) {
|
||||
this.streamTimeoutSeconds = streamTimeoutSeconds;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.ccb.fintec.core.properties;
|
||||
|
||||
/**
|
||||
* MCP 相关配置属性
|
||||
*/
|
||||
public class McpProperties {
|
||||
/** MCP Server 名称 */
|
||||
private String serverName = "fintec-mcp-server";
|
||||
/** MCP Server 版本 */
|
||||
private String serverVersion = "1.0.0";
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
public void setServerName(String serverName) {
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
public String getServerVersion() {
|
||||
return serverVersion;
|
||||
}
|
||||
|
||||
public void setServerVersion(String serverVersion) {
|
||||
this.serverVersion = serverVersion;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.ccb.fintec.core.properties;
|
||||
|
||||
/**
|
||||
* 观测配置属性
|
||||
*/
|
||||
public class ObservabilityProperties {
|
||||
private boolean logTokenUsage = true;
|
||||
private long slowRequestThresholdMs = 3000;
|
||||
|
||||
public boolean isLogTokenUsage() {
|
||||
return logTokenUsage;
|
||||
}
|
||||
|
||||
public void setLogTokenUsage(boolean logTokenUsage) {
|
||||
this.logTokenUsage = logTokenUsage;
|
||||
}
|
||||
|
||||
public long getSlowRequestThresholdMs() {
|
||||
return slowRequestThresholdMs;
|
||||
}
|
||||
|
||||
public void setSlowRequestThresholdMs(long slowRequestThresholdMs) {
|
||||
this.slowRequestThresholdMs = slowRequestThresholdMs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.ccb.fintec.core.properties;
|
||||
|
||||
/**
|
||||
* RAG 相关配置属性
|
||||
*/
|
||||
public class RagProperties {
|
||||
/** 文档分块大小(字符数) */
|
||||
private int chunkSize = 800;
|
||||
/** 分块重叠大小 */
|
||||
private int chunkOverlap = 100;
|
||||
/** RAG 检索返回的最相关文档数量 */
|
||||
private int topK = 5;
|
||||
/** RAG 相似度阈值,低于此值不使用 */
|
||||
private double similarityThreshold = 0.7;
|
||||
|
||||
public int getChunkSize() {
|
||||
return chunkSize;
|
||||
}
|
||||
|
||||
public void setChunkSize(int chunkSize) {
|
||||
this.chunkSize = chunkSize;
|
||||
}
|
||||
|
||||
public int getChunkOverlap() {
|
||||
return chunkOverlap;
|
||||
}
|
||||
|
||||
public void setChunkOverlap(int chunkOverlap) {
|
||||
this.chunkOverlap = chunkOverlap;
|
||||
}
|
||||
|
||||
public int getTopK() {
|
||||
return topK;
|
||||
}
|
||||
|
||||
public void setTopK(int topK) {
|
||||
this.topK = topK;
|
||||
}
|
||||
|
||||
public double getSimilarityThreshold() {
|
||||
return similarityThreshold;
|
||||
}
|
||||
|
||||
public void setSimilarityThreshold(double similarityThreshold) {
|
||||
this.similarityThreshold = similarityThreshold;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.ccb.fintec.core.properties;
|
||||
|
||||
/**
|
||||
* 限流配置属性
|
||||
*/
|
||||
public class RateLimitProperties {
|
||||
private int maxRequestsPerMinute = 60;
|
||||
private int maxTokensPerRequest = 4096;
|
||||
|
||||
public int getMaxRequestsPerMinute() {
|
||||
return maxRequestsPerMinute;
|
||||
}
|
||||
|
||||
public void setMaxRequestsPerMinute(int maxRequestsPerMinute) {
|
||||
this.maxRequestsPerMinute = maxRequestsPerMinute;
|
||||
}
|
||||
|
||||
public int getMaxTokensPerRequest() {
|
||||
return maxTokensPerRequest;
|
||||
}
|
||||
|
||||
public void setMaxTokensPerRequest(int maxTokensPerRequest) {
|
||||
this.maxTokensPerRequest = maxTokensPerRequest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.ccb.fintec.core.properties;
|
||||
|
||||
/**
|
||||
* 重试策略配置属性
|
||||
*/
|
||||
public class RetryProperties {
|
||||
private boolean enabled = true;
|
||||
private int maxAttempts = 3;
|
||||
private long backoffMs = 1000;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public int getMaxAttempts() {
|
||||
return maxAttempts;
|
||||
}
|
||||
|
||||
public void setMaxAttempts(int maxAttempts) {
|
||||
this.maxAttempts = maxAttempts;
|
||||
}
|
||||
|
||||
public long getBackoffMs() {
|
||||
return backoffMs;
|
||||
}
|
||||
|
||||
public void setBackoffMs(long backoffMs) {
|
||||
this.backoffMs = backoffMs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.ccb.fintec.core.properties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 安全防护配置属性
|
||||
*/
|
||||
public class SafetyProperties {
|
||||
private boolean enabled = true;
|
||||
private List<String> blockKeywords = new ArrayList<>();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public List<String> getBlockKeywords() {
|
||||
return blockKeywords;
|
||||
}
|
||||
|
||||
public void setBlockKeywords(List<String> blockKeywords) {
|
||||
this.blockKeywords = blockKeywords;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user