找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

983

积分

0

好友

139

主题
发表于 4 天前 | 查看: 11| 回复: 0

在AI辅助编程领域,Cursor、Claude Code等工具引领了开发体验的变革。然而,对于广大Java生态的开发者而言,在拥抱这股浪潮时却面临独特挑战:主流工具多基于Python/TS,与Java项目集成困难;企业级开发所需的Spring Boot、Maven、微服务等框架支持不足;以及出于代码安全考虑,对私有化、可深度定制的本地解决方案存在迫切需求。

Jimi项目正是为解决这些痛点而生——它是一个基于纯Java技术栈构建的功能完整、可扩展、面向企业级的AI智能代理系统。

核心设计理念与价值

Jimi致力于为Java开发者提供一个“原生友好”的AI编程伙伴,其核心价值体现在:

  • 🎓 教育友好:清晰的代码架构与完整的中文注释,使其本身成为优质的学习资源。
  • 🏢 企业级基石:基于Spring Boot 3.2.5构建,支持响应式编程,具备生产级质量。
  • 🔌 开放生态:支持MCP协议,可轻松集成各类外部工具与服务。
  • 🧩 极致模块化:组件职责明确,像搭乐高一样组合功能,易于扩展和维护。
  • 💡 智能知识注入:通过灵活的Skills系统,让AI能够按需获取领域专业知识。

架构之道:清晰的分层设计

Jimi的架构遵循了清晰的分层思想,如同建造智能大厦:基础设施层是坚实的地基,核心引擎层是稳定的骨架,功能模块层(Agent与工具)提供灵活的组件,交互层则是友好的界面。

这种分层带来了显著优势:

  • 🔒 底层稳定:消息总线和执行引擎为系统提供可靠基础。
  • 🎯 中层灵活:Agent、工具及Skills系统提供了丰富的可插拔功能组件。
  • 🚀 上层开放:支持多种大语言模型(LLM)、自定义Agent及外部工具集成。

项目包含8个核心功能域,各司其职:

功能域 核心模块 主要职责 设计亮点
核心引擎 JimiEngine, AgentExecutor 任务执行与调度 委托模式,单一职责
Agent系统 AgentRegistry, AgentSpecLoader Agent管理与加载 YAML配置化,模板渲染
工具系统 ToolRegistry, ToolRegistryFactory 工具注册与执行 Spring集成,插件化
LLM集成 LLMFactory, ChatProvider 多模型支持 Caffeine缓存,流式响应
Skills系统 SkillMatcher, SkillProvider 知识智能注入 关键词匹配,自动激活
消息总线 Wire, WireMessage 组件解耦通信 响应式流,事件驱动
会话管理 Session, Context 上下文持久化 检查点机制,智能压缩
UI交互 ShellUI, OutputFormatter 命令行界面 JLine3,彩色输出

核心引擎:AgentExecutor 的职责解耦

早期版本中,JimiEngine承担了过多职责。经过重构,采用委托模式进行了清晰的责任划分:

  • JimiEngine:作为总控入口,负责核心组件的装配与协调。
  • AgentExecutor:承担主循环调度和执行逻辑,是真正的“引擎心脏”。

让我们深入AgentExecutor的核心逻辑,观察其如何协调组件工作:

@Slf4j
public class AgentExecutor {
    private final Agent agent;
    private final Runtime runtime;
    private final Context context;
    private final Wire wire;
    private final ToolRegistry toolRegistry;
    private final Compaction compaction;
    private final SkillMatcher skillMatcher;
    private final SkillProvider skillProvider;

    /**
     * 执行 Agent 任务的入口方法
     */
    public Mono<Void> execute(List<ContentPart> userInput) {
        return Mono.defer(() -> {
            // 1. 创建检查点 0(初始状态)
            return context.checkpoint(false)
                    // 2. 添加用户消息到上下文
                    .flatMap(checkpointId -> context.appendMessage(Message.user(userInput)))
                    // 3. 启动Agent主循环
                    .then(agentLoop())
                    .doOnSuccess(v -> log.info("Agent execution completed"))
                    .doOnError(e -> log.error("Agent execution failed", e));
        });
    }

    /**
     * Agent 主循环的单步执行
     */
    private Mono<Void> agentLoopStep(int stepNo) {
        // 检查是否超过最大步数限制
        int maxSteps = runtime.getConfig().getLoopControl().getMaxStepsPerRun();
        if (stepNo > maxSteps) {
            return Mono.error(new MaxStepsReachedException(maxSteps));
        }
        // 发送步骤开始消息(通过Wire通知UI)
        wire.send(new StepBegin(stepNo, isSubagent, agentName));

        return Mono.defer(() -> {
            // 1. 检查上下文是否超限,必要时触发压缩
            return checkAndCompactContext()
                    // 2. 创建步骤检查点
                    .then(context.checkpoint(true))
                    // 3. 匹配并注入Skills(智能知识注入)
                    .then(matchAndInjectSkills(stepNo))
                    // 4. 执行单步:调用LLM并处理响应
                    .then(step())
                    .flatMap(finished -> {
                        if (finished) {
                            // LLM返回纯文本,没有工具调用,循环结束
                            log.info("Agent loop finished at step {}", stepNo);
                            return Mono.empty();
                        } else {
                            // 有工具调用,继续下一步
                            return agentLoopStep(stepNo + 1);
                        }
                    });
        });
    }
}

设计亮点

  1. 响应式编程:基于Reactor的Mono,原生支持异步非阻塞。
  2. 检查点机制:每个步骤创建检查点,支持错误恢复与状态回滚。
  3. 消息总线解耦:通过Wire发送事件,使UI层与核心逻辑解耦。
  4. 智能循环控制:内置最大步数限制、连续无工具调用检测等控制逻辑。

流式响应处理:累加器模式

为提升用户体验,Jimi采用累加器模式处理LLM的流式响应,实现实时反馈。

/**
 * 流式累加器:用于组装完整的Assistant消息
 */
private static class StreamAccumulator {
    StringBuilder contentBuilder = new StringBuilder();     // 累积文本内容
    List<ToolCall> toolCalls = new ArrayList<>();          // 累积工具调用
    ChatCompletionResult.Usage usage;                      // Token使用统计
    // 用于临时存储正在构建的工具调用
    String currentToolCallId;
    String currentFunctionName;
    StringBuilder currentArguments = new StringBuilder();
}

/**
 * 处理流式数据块
 */
private StreamAccumulator processStreamChunk(StreamAccumulator acc, ChatCompletionChunk chunk) {
    switch (chunk.getType()) {
        case CONTENT:
            // 文本内容:实时累加并通过Wire发送到UI
            String contentDelta = chunk.getContentDelta();
            acc.contentBuilder.append(contentDelta);
            wire.send(new ContentPartMessage(new TextPart(contentDelta)));
            break;
        case TOOL_CALL:
            // 工具调用:逐块累积参数JSON
            handleToolCallChunk(acc, chunk);
            break;
        case DONE:
            // 流结束:记录Token使用情况
            acc.usage = chunk.getUsage();
            break;
    }
    return acc;
}

技术亮点

  • 实时反馈:每个内容片段立即推送至UI,用户感知延迟极低。
  • 容错处理:能处理LLM可能先发送参数、后发送调用ID的异常情况。
  • 临时ID策略:当收到参数但缺少ID时,创建临时ID确保数据不丢失。

Agent系统:配置化与多Agent协作

Jimi支持多种专业化Agent协同工作,例如Code Agent负责实现,Review Agent负责审查,Test Agent负责生成测试用例。

配置化设计

Agent采用 YAML配置 + Markdown模板 的方式定义,极大提升了可定制性。

agent.yaml 示例

name: "Code Agent"
description: "专业的代码实现Agent"
model: null  # 继承默认模型
# 可以委托的子Agent
subagents:
  - review
  - test
# 可用工具列表
tools:
  - read_file
  - write_to_file
  - str_replace_file
  - patch_file
  - bash
  - glob
  - grep
  - think
# 系统提示词参数(用于模板渲染)
system_prompt_args:
  CODING_STYLE: "遵循阿里巴巴Java开发手册"
  JAVA_VERSION: "17"

system_prompt.md 模板

# 角色定位
你是一位经验丰富的Java高级工程师,专注于高质量代码实现。

# 工作环境
- 当前时间: ${JIMI_NOW}
- 工作目录: ${JIMI_WORK_DIR}
- Java版本: ${JAVA_VERSION}
- 编码规范: ${CODING_STYLE}

# 核心能力
1. 根据设计文档完成代码实现
2. 编写符合规范的注释和文档
3. 进行代码重构和优化
4. 处理异常情况和边界条件

# 工作流程
1. 仔细阅读需求和设计文档
2. 分析现有代码结构
3. 实现新功能或修复Bug
4. 编写必要的注释
5. 委托Review Agent进行代码审查

AgentRegistry负责加载和渲染这些配置,利用Apache Commons Text将参数动态注入模板,实现Agent行为的灵活定制。

工具系统:标准化与安全执行

所有工具都实现统一的Tool<P>接口,并通过ToolRegistry进行注册管理。工具作为Spring Bean,支持依赖注入,并以原型(Prototype)作用域避免状态污染。

ReadFile工具为例:

@Component
@Scope("prototype")
public class ReadFile extends AbstractTool<ReadFile.Params> {
    @Data
    public static class Params {
        @JsonProperty(required = true)
        @JsonPropertyDescription("要读取的文件路径(相对或绝对路径)")
        private String path;
        @JsonPropertyDescription("起始行号(从1开始)")
        private Integer startLine;
        @JsonPropertyDescription("结束行号")
        private Integer endLine;
    }

    @Override
    protected Mono<ToolResult> executeInternal(Params params) {
        return Mono.fromCallable(() -> {
            Path filePath = resolveWorkPath(params.getPath());
            // 验证文件存在且可读
            if (!Files.exists(filePath)) {
                return ToolResult.error("文件不存在: " + params.getPath());
            }
            // 读取文件内容
            List<String> lines = Files.readAllLines(filePath);
            // 处理行范围
            if (params.getStartLine() != null || params.getEndLine() != null) {
                int start = params.getStartLine() != null ? params.getStartLine() - 1 : 0;
                int end = params.getEndLine() != null ? params.getEndLine() : lines.size();
                lines = lines.subList(Math.max(0, start), Math.min(lines.size(), end));
            }
            return ToolResult.success()
                    .withOutput(String.join("\n", lines))
                    .withMessage("成功读取文件");
        });
    }
}

系统还为文件写入、Shell执行等敏感工具设计了审批机制,确保操作安全可控。

LLM集成:统一抽象与缓存优化

通过统一的ChatProvider接口,Jimi抽象了不同LLM提供商(如OpenAI、DeepSeek、Ollama等)的细节。LLMFactory利用Caffeine高性能缓存管理LLM实例,避免重复创建,提升性能。

@Service
public class LLMFactory {
    /**
     * LLM实例缓存(Caffeine)
     */
    private final Cache<String, LLM> llmCache;

    public LLMFactory(JimiConfig config, ObjectMapper objectMapper) {
        this.llmCache = Caffeine.newBuilder()
                .maximumSize(10)                        // 最多缓存10个模型
                .expireAfterAccess(30, TimeUnit.MINUTES) // 30分钟未使用则过期
                .recordStats()                          // 记录缓存统计
                .build();
    }

    /**
     * 获取或创建LLM实例
     */
    public LLM getOrCreateLLM(String modelName) {
        return llmCache.get(modelName, key -> createLLM(key));
    }
}

API Key支持通过环境变量配置(如OPENAI_API_KEY),优先级高于配置文件,提升了安全性。

Skills系统:领域知识的动态注入

Skills系统解决了如何让AI在特定任务中更专业的问题。它摒弃了在提示词中硬编码所有知识的传统做法,采用按需激活、模块化管理的策略。

每个Skill由一个skill.yaml文件定义,包含名称、描述、触发词和Markdown格式的知识内容。

name: "Java Code Review Checklist"
description: "Java代码审查的完整检查清单和最佳实践"
scope: global
# 触发词(用于智能匹配)
triggers:
  - code review
  - 代码审查
  - 代码质量
  - quality check
# 技能内容(Markdown格式)
content: |
  ## Java代码审查清单
  ### 1. 代码规范
   - [ ] 命名符合规范(驼峰、常量大写等)
   - [ ] 缩进和格式一致
   - [ ] 注释清晰且必要
  ### 2. 设计原则
   - [ ] 遵循SOLID原则
   - [ ] 单一职责原则
   - [ ] 方法长度合理(建议<50行)

SkillMatcher基于用户输入的关键词进行智能匹配,并使用缓存提升效率。匹配到的Skills由SkillProvider格式化为系统消息,动态注入到对话上下文中,确保AI只获取当前任务最相关的专业知识,节省Token的同时提升了专业性。

MCP协议集成:扩展外部能力

Jimi集成了MCP协议,使其能够以标准化的方式连接外部服务,如数据库、文件系统、Git服务等,极大地扩展了AI Agent的能力边界。通过实现JsonRpcClient接口,Jimi可以方便地与各种MCP服务器通信,调用其提供的工具。

消息总线(Wire):组件通信的枢纽

Wire消息总线基于发布-订阅模式,使用Reactor的Sinks实现,是系统内部解耦的关键。核心组件(如AgentExecutor)将执行步骤、流式内容、工具调用等事件发布到Wire,而UI层订阅这些事件并实时呈现,实现了业务逻辑与交互界面的彻底分离。

技术架构总结与展望

Jimi项目综合运用了多种经典设计模式,如委托模式、工厂模式、策略模式、观察者模式等,构建了一个高内聚、低耦合的系统。其技术栈精选了Spring Boot、Project Reactor、Caffeine、JLine等成熟框架,确保了系统的性能、可维护性和开发体验。

在性能优化上,Jimi采取了多层缓存、响应式并发、上下文智能压缩等策略。展望未来,项目计划在Skills系统智能化、工具生态扩展、Web/IDE集成、引入RAG以及企业级多租户与安全增强等方面持续演进。

结语

Jimi不仅仅是一个AI编程辅助工具,更是一次对“使用Java开发现代AI应用”的深度实践。它证明了Java技术栈完全能够胜任复杂AI系统的构建,并且能与Spring Boot等企业级框架完美融合,提供坚实、可维护的基础。通过开源该项目,作者希望吸引更多Java开发者共同探索AI工程化的可能性,为Java在智能时代的生态繁荣贡献力量。

项目开源地址:https://github.com/Leavesfly/Jimi




上一篇:FastAIE:本地轻量AI工具,让大模型直接执行命令与扫描端口
下一篇:Dyad开源AI应用构建引擎:零代码快速开发与本地化原型设计指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 20:35 , Processed in 0.123822 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表