跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaAIjava

Jimi:打造 Java 程序员专属的开源 AI 编程代理

Jimi 是基于纯 Java 技术栈构建的开源 AI 智能代理系统,旨在解决 Java 开发者在 AI 辅助编程中面临的技术栈割裂、企业级需求及私有化部署等痛点。项目采用 Spring Boot 3.2.5,支持响应式编程、MCP 协议集成、Skills 知识注入及多 LLM 模型抽象。通过分层架构设计,实现了 Agent 管理、工具注册、消息总线解耦等功能,并提供命令行交互界面。Jimi 强调模块化与可扩展性,适合企业级场景及教育用途,助力 Java 生态在 AI 时代的复兴。

指针猎手发布于 2026/3/22更新于 2026/7/542 浏览

图片

在 AI 辅助编程的浪潮中,Cursor、Claude Code 等工具为开发者带来了革命性的体验。但对于 Java 生态的开发者来说,我们面临着一些独特的挑战:

  • 🔧 技术栈割裂:主流 AI 工具多用 Python 或 ts 实现,与 Java 项目集成困难
  • 📚 企业级需求:需要支持 Spring Boot、Maven、微服务等企业级框架
  • 🔐 私有化部署:企业对代码安全有严格要求,需要可控的本地方案
  • 🎯 深度定制:希望能深入理解并定制 AI 代理的行为逻辑

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

▐ Jimi 的核心价值
  • 🎓 教育友好:清晰的代码架构,完整的中文注释,让每一行代码都能成为学习资源;
  • 🏢 企业级设计:基于 Spring Boot 3.2.5,支持响应式编程,生产级质量保证;
  • 🔌 开放生态:支持 MCP 协议,可集成各类外部工具和服务;
  • 🧩 极致模块化:像搭乐高一样组合功能,每个模块职责明确,易于扩展;
  • 💡 知识注入:灵活的 Skills 系统,让 AI 可以按需获取领域专业知识。

文章配图

架构之道——分层是银弹

▐ 从'积木'的角度理解 Jimi

如果要建造一座智能大厦,我们需要什么?首先是坚实的地基(基础设施),然后是稳定的骨架(核心引擎),再是灵活的功能模块(Agent 和工具),最后是友好的交互界面(UI)。Jimi 的架构设计正是遵循了这样的思路:

文章配图

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

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

▐ 核心模块一览

Jimi 共包含 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,彩色输出

文章配图

核心引擎——Agent 执行主逻辑

▐ 设计理念:委托与解耦

在早期版本中,JimiEngine 承担了过多的职责(执行循环、工具调用、上下文管理等),导致代码复杂度高、难以测试。经过重构,我们采用了委托模式:

  • JimiEngine:作为 Engine 接口的实现,专注于组件装配和协调
  • 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. 智能循环控制:支持最大步数限制、连续无工具调用检测

▐ 流式响应处理的设计

LLM 的流式响应(Streaming)是提升用户体验的关键。Jimi 采用了累加器模式来处理流式数据:

/**
* 流式累加器:用于组装完整的 Assistant 消息
*/
private static class StreamAccumulator {
    StringBuilder contentBuilder = new StringBuilder();
    List<ToolCall> toolCalls = new ArrayList<>();
    ChatCompletionResult.Usage usage;
    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 可能先发送 arguments、后发送 id 的异常情况
  • 临时 ID 策略:当收到参数但没有 ID 时,创建临时 ID 确保数据不丢失

文章配图

Agent 系统——SubAgent 的分工协作

▐ 多 Agent 协作架构

Jimi 支持多种专业化 Agent,每个 Agent 都有明确的职责边界:

文章配图

▐ Agent 的配置化设计

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

agent.yaml 示例:

name: "Code Agent"
description: "专业的代码实现 Agent"
model: null  # 继承默认模型
subagents:
  - review
  - test
tools:
  - read_file
  - write_to_file
  - str_replace_file
  - patch_file
  - bash
  - glob
  - grep
  - think
exclude_tools:
  - fetch_url
  - set_todo_list
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 进行代码审查

▐ Agent 加载与渲染机制

AgentRegistry 负责 Agent 的加载和管理:

@Service
public class AgentRegistry {
    @Autowired
    private AgentSpecLoader specLoader;

    /**
     * 加载 Agent 实例,支持模板渲染
     */
    public Mono<Agent> loadAgent(Path agentFile, Runtime runtime) {
        return loadAgentSpec(agentFile).flatMap(spec -> {
            // 渲染系统提示词模板
            String systemPrompt = renderSystemPrompt(
                spec.getSystemPromptPath(),
                spec.getSystemPromptArgs(),
                runtime.getBuiltinArgs()
            );

            // 构建 Agent 实例
            Agent agent = Agent.builder()
                .name(spec.getName())
                .systemPrompt(systemPrompt)
                .model(spec.getModel())
                .tools(processedTools)
                .build();

            return Mono.just(agent);
        });
    }

    /**
     * 渲染系统提示词(使用 Apache Commons Text)
     */
    private String renderSystemPrompt(Path promptPath, Map<String, String> args,
                                      BuiltinSystemPromptArgs builtinArgs) {
        String template = Files.readString(promptPath);
        // 准备替换参数(内置参数 + 自定义参数)
        Map<String, String> substitutionMap = new HashMap<>();
        substitutionMap.put("JIMI_NOW", builtinArgs.getJimiNow());
        substitutionMap.put("JIMI_WORK_DIR", builtinArgs.getJimiWorkDir().toString());
        if (args != null) {
            substitutionMap.putAll(args);
        }
        // 执行字符串替换
        StringSubstitutor substitutor = new StringSubstitutor(substitutionMap);
        return substitutor.replace(template);
    }
}

设计优势:

  • 配置与代码分离:修改 Agent 行为无需修改代码;
  • 模板化:支持参数替换,动态注入上下文信息;
  • 可扩展:新增 Agent 只需添加配置文件。

文章配图

工具系统——能力的扩展

文章配图

▐ 工具注册与执行架构

Jimi 的工具系统采用注册表模式,支持工具的动态注册和执行:

文章配图

▐ 工具的标准接口设计

所有工具都实现统一的 Tool 接口:

public interface Tool<P> {
    /**
     * 工具名称(对应 LLM function calling 的 name)
     */
    String getName();

    /**
     * 工具描述(告诉 LLM 这个工具的用途)
     */
    String getDescription();

    /**
     * 参数类型(用于 JSON Schema 生成)
     */
    Class<P> getParamsType();

    /**
     * 执行工具
     */
    Mono<ToolResult> execute(P params);
}

以 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("成功读取文件");
        });
    }
}

设计亮点:

  • Spring 集成:工具作为 Spring Bean,自动依赖注入;
  • 原型作用域:每次获取新实例,避免状态污染;
  • 审批机制:敏感工具(如文件写入、Shell 执行)需要审批;
  • 响应式设计:返回 Mono,支持异步执行。

文章配图

LLM 集成——多模型的统一抽象

▐ LLM 抽象层设计

Jimi 支持多种 LLM 提供商(OpenAI、Kimi、DeepSeek、Qwen、Ollama 等),通过统一的 ChatProvider 接口进行抽象:

public interface ChatProvider {
    /**
     * 流式生成聊天完成
     */
    Flux<ChatCompletionChunk> generateStream(
        String systemPrompt,
        List<Message> messages,
        List<Object> toolSchemas
    );

    /**
     * 获取模型名称
     */
    String getModelName();
}

▐ LLM 工厂与缓存机制

LLMFactory 使用Caffeine 高性能缓存来管理 LLM 实例:

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

    public LLMFactory(JimiConfig config, ObjectMapper objectMapper) {
        // 初始化 Caffeine 缓存
        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(优先使用环境变量)
     */
    private String resolveApiKey(LLMProviderConfig providerConfig) {
        // 构建环境变量名称:{PROVIDER_TYPE}_API_KEY
        String envVarName = providerConfig.getType().toString().toUpperCase() + "_API_KEY";
        String envApiKey = System.getenv(envVarName);

        return envApiKey != null ? envApiKey : providerConfig.getApiKey();
    }
}

设计优势:

  • 缓存复用:避免重复创建 LLM 实例,提升性能;
  • 环境变量覆盖:支持通过环境变量配置 API Key,提升安全性;
  • Fail-fast 验证:启动时验证配置,避免运行时错误。

文章配图

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

▐ Skills 系统的设计哲学

Skills(技能包)解决了一个关键问题:如何让 AI 在特定领域任务中表现得更专业?

传统方法是在系统提示词中硬编码所有知识,但这会导致:

  • 🚫 上下文过长:大量无关知识占用 Token
  • 🚫 维护困难:修改知识需要重新部署
  • 🚫 缺乏共享:团队间无法复用知识

Skills 系统的解决方案:

  • ✅ 按需激活:根据用户输入自动匹配相关知识
  • ✅ 模块化管理:每个 Skill 独立配置,易于维护
  • ✅ 团队共享:支持全局和项目级 Skill
  • ✅ 高性能:Caffeine 缓存提升匹配效率

文章配图

▐ Skill 配置格式

每个 Skill 由一个 skill.yaml 文件定义:

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

  ### 2. 设计原则
   - [ ] 遵循 SOLID 原则
   - [ ] 单一职责原则
   - [ ] 方法长度合理(建议<50 行)

  ### 3. 异常处理
   - [ ] 异常不被吞掉
   - [ ] 使用合适的异常类型
   - [ ] 资源正确关闭

▐ 智能匹配

SkillMatcher 实现了基于关键词的智能匹配:

@Service
public class SkillMatcher {
    private Cache<String, List<SkillSpec>> matchCache;

    /**
     * 匹配用户输入,返回相关的 Skills
     */
    public List<SkillSpec> matchFromInput(List<ContentPart> userInput) {
        String inputText = extractText(userInput);

        // 尝试从缓存获取
        String cacheKey = String.valueOf(inputText.hashCode());
        List<SkillSpec> cachedResult = matchCache.getIfPresent(cacheKey);
        if (cachedResult != null) {
            return cachedResult;
        }

        // 执行实际匹配
        List<SkillSpec> matchedSkills = performMatch(inputText);

        // 缓存结果
        matchCache.put(cacheKey, matchedSkills);
        return matchedSkills;
    }

    /**
     * 执行匹配逻辑
     */
    private List<SkillSpec> performMatch(String inputText) {
        // 1. 提取关键词
        Set<String> keywords = extractKeywords(inputText);

        // 2. 从注册表中查找候选 Skills
        List<SkillSpec> candidateSkills = skillRegistry.findByTriggers(keywords);

        // 3. 计算匹配得分并排序
        return candidateSkills.stream()
            .map(skill -> new ScoredSkill(skill, calculateScore(skill, keywords, inputText)))
            .filter(scored -> scored.score >= scoreThreshold)
            .sorted(Comparator.comparingInt(ScoredSkill::getScore).reversed())
            .limit(maxSkills)
            .map(ScoredSkill::getSkill)
            .collect(Collectors.toList());
    }

    /**
     * 计算匹配得分
     *
     * 计分策略:
     * - 触发词精确匹配:+50 分
     * - 触发词部分匹配:+30 分
     * - 名称匹配:+40 分
     * - 关键词在描述中出现:+10 分
     */
    private int calculateScore(SkillSpec skill, Set<String> keywords, String fullText) {
        int score = 0;

        // 检查触发词匹配
        for (String trigger : skill.getTriggers()) {
            if (keywords.contains(trigger.toLowerCase()) ||
                fullText.toLowerCase().contains(trigger.toLowerCase())) {
                score += 50;
            }
        }

        return Math.min(score, 100);
    }
}

▐ 知识注入

SkillProvider 负责将匹配的 Skills 注入到上下文:

@Service
public class SkillProvider {
    /**
     * 注入 Skills 到上下文
     */
    public Mono<Void> injectSkills(Context context, List<SkillSpec> skills) {
        // 过滤已激活的 Skills
        List<SkillSpec> newSkills = skills.stream()
            .filter(skill -> !context.getActiveSkills().contains(skill))
            .collect(Collectors.toList());

        if (newSkills.isEmpty()) {
            return Mono.empty();
        }

        // 格式化 Skills 为系统消息
        String skillsContent = formatSkills(newSkills);
        Message skillsMessage = Message.system(skillsContent);

        // 添加到上下文并记录激活的 Skills
        return context.appendMessage(skillsMessage)
            .then(context.addActiveSkills(newSkills));
    }

    /**
     * 格式化 Skills 为 Markdown 文本
     */
    private String formatSkills(List<SkillSpec> skills) {
        StringBuilder sb = new StringBuilder();
        sb.append("<system type=\"skills\">\n\n");
        sb.append("以下技能包已根据当前任务自动激活,请在执行任务时遵循这些专业指南:\n\n");

        for (int i = 0; i < skills.size(); i++) {
            SkillSpec skill = skills.get(i);
            sb.append("### ").append(i + 1).append(". ").append(skill.getName()).append("\n\n");
            sb.append(skill.getContent()).append("\n\n");
            if (i < skills.size() - 1) {
                sb.append("---\n\n");
            }
        }

        sb.append("</system>");
        return sb.toString();
    }
}

Skills 系统的优势:

  • 智能激活:无需手动选择,系统自动匹配最相关的知识;
  • 上下文优化:只注入必要的知识,节省 Token;
  • 团队协作:支持共享 Skills 库,团队经验沉淀;
  • 持续改进:可随时更新 Skills 内容,无需修改代码。

文章配图

MCP 协议集成——连接外部世界

▐ MCP 协议简介

MCP(Model Context Protocol)是一个标准化的 AI 工具调用协议,允许 AI 模型与外部服务进行结构化通信。Jimi 通过 MCP 集成,可以:

  • 🗄️ 访问数据库:执行 SQL 查询、数据分析
  • 📁 操作文件系统:跨平台文件管理
  • 🔗 调用 Git 服务:查看提交历史、分支管理
  • 🌐 集成 GitHub:创建 Issue、管理 PR

▐ MCP 客户端架构

文章配图

▐ MCP 客户端接口

/**
* JSON-RPC 客户端接口
*/
public interface JsonRpcClient extends AutoCloseable {
    /**
     * 初始化连接
     */
    MCPSchema.InitializeResult initialize() throws Exception;

    /**
     * 获取工具列表
     */
    MCPSchema.ListToolsResult listTools() throws Exception;

    /**
     * 调用工具
     */
    MCPSchema.CallToolResult callTool(String toolName, Map<String, Object> arguments)
        throws Exception;
}

HTTP 实现示例:

public class HttpJsonRpcClient implements JsonRpcClient {
    private final WebClient webClient;

    @Override
    public MCPSchema.CallToolResult callTool(String toolName, Map<String, Object> arguments)
            throws Exception {
        JsonRpcRequest request = JsonRpcRequest.builder()
            .method("tools/call")
            .params(Map.of(
                "name", toolName,
                "arguments", arguments
            ))
            .build();

        return sendRequest(request, MCPSchema.CallToolResult.class);
    }
}

▐ MCP 配置示例

{
  "name": "database-server",
  "description": "PostgreSQL 数据库查询服务",
  "type": "http",
  "config": {
    "url": "http://localhost:8080/mcp",
    "headers": {
      "Authorization": "Bearer ${DB_API_KEY}"
    }
  }
}

文章配图

消息总线 Wire——组件解耦

▐ Wire 的设计理念

Wire 消息总线通过发布 - 订阅模式实现组件解耦:

文章配图

▐ Wire 接口与实现

/**
* Wire 消息总线接口
*/
public interface Wire {
    void send(WireMessage message);
    Flux<WireMessage> asFlux();
    void complete();
}

/**
* Wire 实现(基于 Reactor 的 Sinks)
*/
public class WireImpl implements Wire {
    private final Sinks.Many<WireMessage> sink;

    public WireImpl() {
        // 使用 Multicast 支持多订阅者
        this.sink = Sinks.many().multicast().onBackpressureBuffer();
    }

    @Override
    public void send(WireMessage message) {
        sink.tryEmitNext(message);
    }

    @Override
    public Flux<WireMessage> asFlux() {
        return sink.asFlux();
    }
}

▐ 消息类型体系

// 步骤开始消息
public class StepBegin implements WireMessage {
    private int stepNumber;
    private boolean isSubagent;
    private String agentName;
}

// 内容部分消息(LLM 流式输出)
public class ContentPartMessage implements WireMessage {
    private ContentPart contentPart;
}

// 工具调用消息
public class ToolCallMessage implements WireMessage {
    private ToolCall toolCall;
}

// Skills 激活消息
public class SkillsActivated implements WireMessage {
    private List<String> skillNames;
    private int count;
}

▐ UI 层的消息处理

public class ShellUI {
    private void subscribeWire() {
        wireSubscription = wire.asFlux()
            .subscribe(this::handleWireMessage);
    }

    private void handleWireMessage(WireMessage message) {
        if (message instanceof StepBegin stepBegin) {
            printStatus("🤔 Step " + stepBegin.getStepNumber() + " - Thinking...");
        } else if (message instanceof ContentPartMessage contentMsg) {
            // 实时打印 LLM 输出
            printAssistantText(contentMsg.getContentPart().getText());
        } else if (message instanceof ToolCallMessage toolCallMsg) {
            // 显示工具调用
            toolVisualization.onToolCallStart(toolCallMsg.getToolCall());
        } else if (message instanceof SkillsActivated skillsMsg) {
            printInfo("💡 激活 Skills: " + String.join(", ", skillsMsg.getSkillNames()));
        }
    }
}

文章配图

使用示例与最佳实践

▐ 基本使用流程

# 1. 启动 Jimi
./scripts/start.sh
# 2. 查看帮助
/help
# 3. 开始对话
请帮我分析 src/main/java 目录下的代码结构
# 4. 使用专业 Agent
/agent code
请帮我实现一个用户注册功能

▐ 高级使用技巧

1. 配置 Skills 功能

编辑 application.yml:

jimi:
  skill:
    enabled: true
    auto-match: true
    matching:
      score-threshold: 30
      max-matched-skills: 5

2. 使用 YOLO 模式(自动批准)

./scripts/start.sh --yolo

3. 指定工作目录

./scripts/start.sh --work-dir /path/to/your/project

4. 会话恢复

# 恢复上次会话
./scripts/start.sh --resume
# 使用指定会话
./scripts/start.sh --session my-project

▐ 开发自定义 Agent

创建 agents/my-agent/agent.yaml:

name: "My Custom Agent"
description: "我的专属 Agent"
subagents:
  - code
  - review
tools:
  - read_file
  - write_to_file
  - bash
system_prompt_args:
  MY_CUSTOM_PARAM: "自定义参数值"

创建 agents/my-agent/system_prompt.md:

你是一位专业的${MY_CUSTOM_PARAM}助手。当前工作目录:${JIMI_WORK_DIR}
...

启动时使用:

./scripts/start.sh --agent my-agent

▐ 开发自定义工具

@Component
@Scope("prototype")
public class MyCustomTool extends AbstractTool<MyCustomTool.Params> {
    @Data
    public static class Params {
        @JsonProperty(required = true)
        @JsonPropertyDescription("参数描述")
        private String param1;
    }

    @Override
    public String getName() {
        return "my_custom_tool";
    }

    @Override
    public String getDescription() {
        return "我的自定义工具";
    }

    @Override
    protected Mono<ToolResult> executeInternal(Params params) {
        return Mono.fromCallable(() -> {
            // 工具逻辑实现
            return ToolResult.success()
                .withOutput("执行结果")
                .withMessage("执行成功");
        });
    }
}

在 ToolRegistryFactory 中注册:

public ToolRegistry createStandardRegistry(...) {
    // ... existing code
    registry.register(createMyCustomTool());
    return registry;
}

文章配图

技术架构总结与展望

▐ 核心设计模式总结

设计模式应用位置优势
委托模式JimiEngine → AgentExecutor职责分离,易于测试
工厂模式LLMFactory, ToolRegistryFactory对象创建与使用解耦
策略模式ChatProvider 多实现支持多种 LLM 提供商
注册表模式ToolRegistry, AgentRegistry动态注册和查找
观察者模式Wire 消息总线组件解耦通信
模板方法AbstractTool复用公共逻辑
原型模式Spring Prototype Bean避免状态污染

▐ 技术栈亮点

  • Spring Boot 3.2.5:现代企业级框架,依赖注入,配置管理;
  • Project Reactor:响应式编程,异步非阻塞,流式处理;
  • Caffeine:高性能缓存,LRU 淘汰,统计功能;
  • JLine 3:强大的终端交互库,自动补全,语法高亮;
  • Jackson:JSON 序列化/反序列化,支持注解;
  • Apache Commons Text:字符串替换,模板渲染。

▐ 性能优化策略

1. 多层缓存:

  • LLM 实例缓存(Caffeine)
  • Skills 匹配结果缓存
  • Agent 规范缓存

2. 并发执行:

  • 多个工具调用并发执行(Flux.merge)
  • 流式响应实时推送

3. 上下文压缩:

  • 自动检测 Token 超限
  • 智能压缩历史消息

4. 资源管理:

  • Spring Bean 作用域控制
  • AutoCloseable 资源自动释放

▐ 未来发展方向

短期计划
  • 🔥 增强 Skills 系统:
    • 支持模板变量和动态内容生成
    • 实现基于上下文的动态 Skills 匹配
    • 支持 Skills 间的依赖关系
  • 🚀 扩展工具生态:
    • 集成更多 MCP 服务(GitHub, Jira, Slack 等)
    • 开发代码分析工具(AST 解析、依赖分析)
    • 支持数据库 Schema 分析
  • 💡 优化用户体验:
    • Web UI 界面(可选)
    • IDE 插件(IntelliJ IDEA, VS Code)
    • 更丰富的可视化输出
中期计划
  • 🧠 智能化增强:
    • 引入 RAG(检索增强生成)
    • 支持项目知识库自动构建
    • 上下文智能摘要
  • 🌐 分布式支持:
    • 多 Agent 并行协作
    • 分布式工具执行
    • 云端 LLM 服务集成
  • 📊 可观测性:
    • 性能监控和指标采集
    • 执行过程可视化
    • 成本分析和优化建议
长期愿景
  • 🎯 企业级增强:
    • 多租户支持
    • 权限和审计系统
    • 企业知识库集成
  • 🔐 安全性强化:
    • 代码安全扫描
    • 敏感信息检测
    • 合规性检查
  • 🌟 生态建设:
    • 插件市场
    • Skills 共享平台
    • 社区贡献机制

文章配图

结语:开源的力量,Java 的未来

Jimi 项目不仅仅是一个 AI 代理工具,更是一次对'用 Java 做 AI'的深度探索。通过这个项目,我们证明了:

  • ✅ Java 完全可以胜任 AI 应用开发:响应式编程、流式处理、高性能缓存,一应俱全
  • ✅ 企业级设计可以与 AI 完美结合:Spring Boot 的依赖注入、配置管理、测试框架,为 AI 应用提供坚实基础
  • ✅ 模块化架构让 AI 系统更易维护:清晰的职责边界、可插拔的组件设计,降低了复杂度
  • ✅ 开源社区的力量无穷:通过分享代码、文档和经验,让更多开发者受益
给 Java 开发者的建议

如果你也对 AI 感兴趣,不妨从 Jimi 开始:

  1. Clone 代码,深入阅读:每个模块都有详细的注释
  2. 运行测试,理解流程:单元测试覆盖核心逻辑
  3. 尝试扩展,实践学习:自定义 Agent、工具、Skills
  4. 参与贡献,共同成长:提交 PR,分享经验
项目信息
  • GitHub 仓库:https://github.com/Leavesfly/Jimi
  • 文档中心:项目根目录 docs
  • 技术讨论:GitHub Discussions
  • 问题反馈:GitHub Issues
致谢

感谢以下开源项目为 Jimi 提供的灵感和支持:

  • Spring Boot - 企业级应用框架
  • Project Reactor - 响应式编程库
  • Caffeine - 高性能缓存
  • JLine - 终端交互库
  • Model Context Protocol - AI 工具标准协议

目录

  1. ▐ Jimi 的核心价值
  2. 架构之道——分层是银弹
  3. ▐ 从“积木”的角度理解 Jimi
  4. ▐ 核心模块一览
  5. 核心引擎——Agent 执行主逻辑
  6. ▐ 设计理念:委托与解耦
  7. ▐ 核心代码解析
  8. ▐ 流式响应处理的设计
  9. Agent 系统——SubAgent 的分工协作
  10. ▐ 多 Agent 协作架构
  11. ▐ Agent 的配置化设计
  12. 角色定位
  13. 工作环境
  14. 核心能力
  15. 工作流程
  16. ▐ Agent 加载与渲染机制
  17. 工具系统——能力的扩展
  18. ▐ 工具注册与执行架构
  19. ▐ 工具的标准接口设计
  20. LLM 集成——多模型的统一抽象
  21. ▐ LLM 抽象层设计
  22. ▐ LLM 工厂与缓存机制
  23. Skills 系统——领域知识的动态注入
  24. ▐ Skills 系统的设计哲学
  25. ▐ Skill 配置格式
  26. 触发词(用于智能匹配)
  27. 技能内容(Markdown 格式)
  28. Java 代码审查清单
  29. 1. 代码规范
  30. 2. 设计原则
  31. 3. 异常处理
  32. ▐ 智能匹配
  33. ▐ 知识注入
  34. MCP 协议集成——连接外部世界
  35. ▐ MCP 协议简介
  36. ▐ MCP 客户端架构
  37. ▐ MCP 客户端接口
  38. ▐ MCP 配置示例
  39. 消息总线 Wire——组件解耦
  40. ▐ Wire 的设计理念
  41. ▐ Wire 接口与实现
  42. ▐ 消息类型体系
  43. ▐ UI 层的消息处理
  44. 使用示例与最佳实践
  45. ▐ 基本使用流程
  46. 1. 启动 Jimi
  47. 2. 查看帮助
  48. 3. 开始对话
  49. 4. 使用专业 Agent
  50. ▐ 高级使用技巧
  51. 恢复上次会话
  52. 使用指定会话
  53. ▐ 开发自定义 Agent
  54. ▐ 开发自定义工具
  55. 技术架构总结与展望
  56. ▐ 核心设计模式总结
  57. ▐ 技术栈亮点
  58. ▐ 性能优化策略
  59. ▐ 未来发展方向
  60. 短期计划
  61. 中期计划
  62. 长期愿景
  63. 结语:开源的力量,Java 的未来
  64. 给 Java 开发者的建议
  65. 项目信息
  66. 致谢
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Cursor 配置网络代理:3 分钟搞定模型访问
  • C++ list 带头双向链表增删查改模拟实现
  • 腾讯云轻量应用服务器部署 OpenClaw 并接入 QQ 飞书机器人
  • Java 响应式编程 Mono 接口详解
  • Freqtrade 新手教程:macOS + Docker 环境配置与回测
  • MATLAB 实现基于天牛须搜索算法(BAS)的无人机三维路径规划
  • Python 异步编程与协程实战指南
  • CIC滤波器FPGA设计:位宽扩展与溢出控制实战
  • Java 集成高德开放平台 WebAPI 实现 POI 搜索
  • 全国计算机等级考试三级证书报考指南与科目解析
  • SpringBoot 联合 PostGIS 实现在线地图行政区划离线存储
  • 文本生成技术:原理、应用与国产工具实践
  • Neo4j 图数据库与 JDK 安装配置教程
  • Windows 10 系统性能优化指南:10 个实用技巧
  • 2024 年新能源大模型行业落地趋势与应用分析
  • Python 爬虫入门项目实战指南与学习路线
  • Android Studio 零基础入门指南:环境搭建与核心组件详解
  • .NET 开源分布式事务解决方案:CAP
  • 利用 Python 进行数据分析:核心流程与库详解
  • DES 加密算法原理详解、攻击手段及 3DES 原理

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online