从 0 到 1 搭建企业级 AI 智能体:Java+Spring AI+Skill 金融架构全解析
动力节点
2026年04月16日 15:34
收录于文集
共9篇
AI Agent 智能体

导读

在大模型爆发的今天,90% 的开发者还停留在 “调用 API 聊天” 的阶段。真正能进入金融、医疗、政企生产环境的 AI 系统,必须满足:可计算、可审计、可扩展、可管控。

本文将带你从头到尾,完整实现一套 AI 智能体 + Skill 双层架构 + Java/Python 混合计算 + 金融级审计 的生产可用系统。全文包含完整架构图、接口定义、核心代码、启动流程、对话流程、工具封装,可直接作为你的项目 / 毕设 / 面试作品。

一、项目定位:为什么我们需要 Agent+Skill 架构?

1.1 传统大模型应用的致命缺陷

在金融场景里,单纯调用大模型接口有四大死穴:

  1. 计算不准:DCF、VaR、波动率等必须精确,大模型经常幻觉。

  2. 不可管控:技能不可插拔、不可覆盖、不可审计。

  3. 性能差:全量加载 Prompt,Token 爆炸、启动慢。

  4. 不合规:没有日志、没有评估、没有风险校验。

这些问题,直接导致大模型无法进入金融核心业务。

1.2 我们的解决方案:AI 智能体 + Skill 工具链

本项目的设计哲学非常清晰:

  • LLM = 大脑:只负责理解、推理、决策。

  • Skill = 专业能力包:领域知识、执行流程、指令规范。

  • Tool = 执行手脚:精确计算、脚本调用、接口访问。

  • Agent = 指挥官:管理 Skill、调度 Tool、会话、日志。

一句话:

LLM 负责想,Skill 负责专业,Tool 负责干,Agent 负责管。

1.3 项目核心亮点

  1. 双层 Skill 存储架构:内置只读 + 外部可写,安全合规。

  2. Skill 三阶段加载:发现→激活→执行,省 Token、启动快。

  3. Agent 可插拔:动态挂载技能,一键切换金融顾问。

  4. Java+Python 混合计算:Java 稳、Python 计算强。

  5. 全链路审计:对话日志 + AI 自动质检,满足金融监管。

  6. SSE 流式输出:像 ChatGPT 一样丝滑体验。

  7. 多模态支持:图片、音频、文本统一处理。

  8. DDD 领域驱动架构:可维护、可扩展、可替换。

二、整体架构设计(图文)

2.1 项目模块结构图(Maven 多模块)

代码块
PlainText
自动换行
复制代码
sk-agent(父工程)
├─ sk-agent-domain         领域模型层(实体:Skill、AuditLog)
├─ sk-agent-framework      框架层(Agent、SkillPackage接口)
├─ sk-agent-infrastructure 基础设施层(Skill加载、Python执行、仓储)
├─ sk-agent-agents         智能体层(金融顾问Agent、子Agent)
└─ sk-agent-api            接口层(HTTP、流式、多模态、健康检查)
复制成功

依赖方向:api → agents → infrastructure → framework → domain

2.2 运行流程图

启动流程

  1. 启动 SpringBoot

  2. 扫描 @Component、@Service

  3. 并行加载双层 Skill

  4. 创建 Agent 并注入 Skill

  5. 注册到 AgentRegistry

  6. 启动 Web 服务,等待请求

对话流程

  1. HTTP 请求 → /api/chat/stream

  2. 匹配 Agent

  3. 准备上下文(会话 ID、Tool)

  4. Agent 调用 LLM 思考

  5. LLM 选择 Skill/Tool

  6. 执行 Python 计算

  7. 流式返回结果

  8. 记录审计日志

三、领域层设计(Domain)—— 架构的灵魂

3.1 Skill 实体类

代码块
Java
自动换行
复制代码
@Data
@Builder
public class Skill {
    private String name;          // 技能唯一标识
    private String description;   // 技能描述
    private String instructions;  // 执行指令
    private String fullContent;   // 完整SKILL.md内容
}
复制成功

3.2 审计日志实体

代码块
Java
自动换行
复制代码
@Data
@Builder
public class AuditLog {
    private String sessionId;       // 会话ID
    private String skillName;       // 调用技能
    private String userMessage;     // 用户问题
    private String agentResponse;   // AI回答
    private String evaluation;      // AI质检结果
    private LocalDateTime timestamp;// 时间
    private long durationMs;        // 耗时
}
复制成功

设计意义:纯业务、无框架、无技术侵入,是整个系统最稳定的部分。

四、框架层设计(Framework)—— 系统骨架

4.1 SkillPackage 接口(技能包标准)

代码块
Java
自动换行
复制代码
public interface SkillPackage {
    String getName();
    String getDescription();
    String getContent();
    boolean isAvailable();
    Map<String, Object> getProperties();
}
复制成功

4.2 SkillPackage 实现类

代码块
Java
自动换行
复制代码
@Data
@Builder
public class SkillPackageImpl implements SkillPackage {
    private String name;
    private String description;
    private String content;
    private boolean available;
    private Map<String, Object> properties;
}
复制成功

4.3 Agent 核心接口

代码块
Java
自动换行
复制代码
public interface Agent {
    String getId();
    String getName();
    List<SkillPackage> getSkillPackages();
    void addSkillPackage(SkillPackage skillPackage);
    Flux<String> processStream(String message, Map<String, Object> context);
    boolean isAvailable();
}
复制成功

4.4 BaseAgent 模板类(最核心代码)

代码块
Java
自动换行
复制代码
@Slf4j
@Getter
@Setter
public abstract class BaseAgent implements Agent {
    protected String id;
    protected String name;
    protected String description;
    protected List<SkillPackage> skillPackages = new ArrayList<>();
    protected ChatClient chatClientWithSkills;
    protected File skillsDirectory;

    public BaseAgent(String name, String desc, ChatClient chatClient, ChatClient.Builder builder) {
        this.id = UUID.randomUUID().toString();
        this.name = name;
        this.description = desc;
        if (builder != null) {
            this.chatClientWithSkills = builder.defaultSystem(desc).build();
        } else {
            this.chatClientWithSkills = chatClient;
        }
    }

    public void setSkillsDirectory(File skillsDirectory) {
        this.skillsDirectory = skillsDirectory;
        try {
            var skillsTool = SkillsTool.builder()
                .addSkillsDirectory(skillsDirectory.getAbsolutePath())
                .build();
            this.chatClientWithSkills = chatClientBuilder
                .defaultSystem(description)
                .defaultToolCallbacks(skillsTool)
                .build();
        } catch (Exception e) {
            log.error("初始化SkillsTool失败", e);
        }
    }

    @Override
    public Flux<String> processStream(String message, Map<String, Object> context) {
        if (!isAvailable()) {
            return Flux.just("当前智能体不可用");
        }
        String sessionId = (String) context.get("sessionId");
        Object tools = context.get("tools");

        var prompt = chatClientWithSkills.prompt().user(message);
        if (tools != null) prompt.tools(tools);
        if (sessionId != null) {
            prompt.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, sessionId));
        }
        return prompt.stream().content();
    }
}
复制成功

五、基础设施层(Infrastructure)—— 技能加载 + Python 执行 + 审计

5.1 Skill 解析器(SKILL.md → Java 对象)

代码块
Java
自动换行
复制代码
@Slf4j
public class SkillParser {
    private static final Pattern PATTERN = Pattern.compile(
        "^---\\s*[\\r\\n]+name:\\s*(.+?)\\s*[\\r\\n]+description:\\s*(.+?)\\s*[\\r\\n]+---\\s*[\\r\\n]+(.*)$",
        Pattern.DOTALL
    );

    public static Skill parse(String content) {
        if (content == null || content.isBlank()) return null;
        Matcher matcher = PATTERN.matcher(content);
        if (matcher.find()) {
            return Skill.builder()
                .name(matcher.group(1).trim())
                .description(matcher.group(2).trim())
                .instructions(matcher.group(3).trim())
                .fullContent(content)
                .build();
        }
        log.warn("技能解析失败");
        return null;
    }
}
复制成功

5.2 双层 Skill 加载器(核心)

代码块
Java
自动换行
复制代码
@Service
@Slf4j
public class SkillLoaderService {
    private final FileSystemSkillRepository repository;

    @PostConstruct
    public void loadAllSkills() {
        int classpathCount = repository.loadFromPath("classpath:skills/**/SKILL.md");
        File dynamicDir = new File("data/skills");
        int fileCount = 0;
        if (dynamicDir.exists()) {
            fileCount = repository.loadFromPath("file:data/skills/**/SKILL.md");
        }
        log.info("技能加载完成:内置{}个,外部{}个", classpathCount, fileCount);
    }
}
复制成功

5.3 Python 脚本执行器(Java 调 Python)

代码块
Java
自动换行
复制代码
@Component
@Slf4j
public class PythonScriptExecutor {
    private final String pythonCommand;

    public PythonScriptExecutor() {
        this.pythonCommand = detectPython();
    }

    private String detectPython() {
        if (testCommand("python3")) return "python3";
        if (testCommand("python")) return "python";
        log.warn("未检测到Python环境");
        return null;
    }

    public ScriptResult execute(String skillPath, String scriptName, String... args) {
        Path script = Paths.get("skills", skillPath, "scripts", scriptName);
        List<String> command = new ArrayList<>();
        command.add(pythonCommand);
        command.add("-u");
        command.add(script.toString());
        Collections.addAll(command, args);

        try {
            Process process = new ProcessBuilder(command)
                .redirectErrorStream(true)
                .start();
            String output = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
            int exitCode = process.waitFor();
            return exitCode == 0 ? ScriptResult.success(output) : ScriptResult.error(output);
        } catch (Exception e) {
            log.error("执行Python失败", e);
            return ScriptResult.error(e.getMessage());
        }
    }
}
复制成功

5.4 审计日志服务(AI 自动质检)

代码块
Java
自动换行
复制代码
@Service
@Slf4j
public class AuditLogService {
    private final EvaluationRepository repository;
    private final ChatClient.Builder chatClientBuilder;
    private final SkillLoaderService skillLoaderService;

    public void logAndEvaluate(AuditLog log) {
        Skill critic = skillLoaderService.findByName("critic-agent").orElse(null);
        if (critic != null) {
            String eval = chatClientBuilder.build()
                .prompt()
                .system(critic.getFullContent())
                .user(String.format("用户:%s\nAI:%s", log.getUserMessage(), log.getAgentResponse()))
                .call()
                .content();
            log.setEvaluation(eval);
        }
        repository.save(log);
    }
}
复制成功

六、智能体层(Agents)—— 金融顾问实现

代码块
Java
自动换行
复制代码
@Component
@Slf4j
public class SuperFinancialAdvisorAgent extends BaseAgent {
    public SuperFinancialAdvisorAgent(
            ChatClient.Builder chatClientBuilder,
            ResourceLoader resourceLoader) {
        super(
            "全能金融顾问大师",
            "我提供投资分析、风控计算、组合优化、技术指标分析",
            chatClientBuilder.build(),
            chatClientBuilder
        );
        try {
            Resource resource = resourceLoader.getResource("classpath:skills/super-financial-advisor");
            setSkillsDirectory(resource.getFile());
        } catch (Exception e) {
            log.error("技能目录加载失败", e);
        }
    }
}
复制成功

七、接口层(API)—— 流式对话接口

代码块
Java
自动换行
复制代码
@RestController
@RequestMapping("/api/chat")
@Slf4j
public class ChatController {
    private final AgentRegistry agentRegistry;
    private final FinancialTools financialTools;
    private final AuditLogService auditLogService;

    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter stream(
            @RequestParam String agentName,
            @RequestParam String message,
            @RequestParam(defaultValue = "default-session") String sessionId) {
        SseEmitter emitter = new SseEmitter(180000L);
        Agent agent = agentRegistry.getAgentByName(agentName).orElse(null);

        Map<String, Object> context = new HashMap<>();
        context.put("sessionId", sessionId);
        context.put("tools", financialTools);

        agent.processStream(message, context).subscribe(
            chunk -> {
                try {
                    emitter.send(SseEmitter.event().name("content").data(Map.of("chunk", chunk)));
                } catch (IOException e) { }
            },
            error -> emitter.completeWithError(error),
            () -> {
                emitter.send(SseEmitter.event().name("done"));
                emitter.complete();
            }
        );
        return emitter;
    }
}
复制成功

八、四大金融 Tool 封装(DCF、VaR、技术指标、组合优化)

代码块
Java
自动换行
复制代码
@Component
@Slf4j
public class FinancialTools {
    private final PythonScriptExecutor executor;

    @Tool(description = "DCF现金流折现估值,参数:cashFlows、discountRate、terminalGrowth、sharesOutstanding")
    public String calculateDcf(double[] cashFlows, double discountRate, double terminalGrowth, double sharesOutstanding) {
        return executor.executeDcfCalculator(cashFlows, discountRate, terminalGrowth, sharesOutstanding).getOutput();
    }

    @Tool(description = "计算技术指标 MA、RSI、MACD")
    public String calculateTechnicalIndicators(double[] prices) {
        return executor.executeTechnicalIndicators(prices).getOutput();
    }

    @Tool(description = "计算投资组合VaR风险价值")
    public String calculateVar(double portfolioValue, double meanReturn, double stdDev, double confidenceLevel) {
        return executor.executeVarCalculator(portfolioValue, meanReturn, stdDev, confidenceLevel).getOutput();
    }

    @Tool(description = "马科维茨投资组合优化")
    public String optimizePortfolio(String[] assets, double[] expectedReturns, double riskFreeRate) {
        return executor.executePortfolioOptimizer(assets, expectedReturns, riskFreeRate).getOutput();
    }
}
复制成功

九、项目启动与测试

  1. 配置 application.yml:OpenAI/Azure/ 通义千问

  2. 放入 skills 目录:SKILL.md + scripts

  3. 启动 SkAgentApiApplication

  4. 访问接口:

代码块
PlainText
自动换行
复制代码
http://localhost:8080/api/chat/stream?agentName=全能金融顾问大师&message=分析贵州茅台DCF估值
复制成功

十、总结

本文完整实现了一套可直接上生产的 AI 智能体金融项目。

从 DDD 架构→Skill 标准化→Agent 调度→Python 混合计算→审计日志→流式接口,全部打通。

这套架构解决了大模型落地的所有痛点:

  • 可计算:精确金融计算,不幻觉

  • 可管控:Skill 可插拔、可覆盖、可审计

  • 可扩展:模块解耦,支持多 Agent、多 Skill

  • 合规安全:双层技能、全链路日志、风险质检

  • 体验流畅:SSE 流式输出、多模态支持