- package com.jinhei;
-
- import com.alibaba.fastjson2.JSONObject;
- import com.openai.client.OpenAIClient;
- import com.openai.client.okhttp.OpenAIOkHttpClient;
- import com.openai.models.chat.completions.ChatCompletion;
- import com.openai.models.chat.completions.ChatCompletionCreateParams;
-
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.HashMap;
- import java.util.List;
-
- /**
- * 调用模型对话
- */
- public class AiChat {
-
- private static final String TEMPLATE = """
- 你是一位能力强大的 AI 助手,擅长通过逻辑推理与调用工具来解决问题。
-
- 你可以使用的工具如下:
- {tools}
-
- **重要:你必须严格按照以下 JSON 格式返回工具调用请求:**
- ```json
- {
- "toolName": "工具名称",
- "params": "{参数 JSON 字符串}"
- }
- ```
-
- 注意:
- 1. 只能返回上述 JSON 格式,不要添加任何解释文字
- 2. params 字段必须是字符串格式的 JSON
- 3. 不要使用代码块标记
-
- 对话历史:
- {memory}
-
- 当前用户的问题是:
- {input}
- """;
-
- public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
-
- // 第0步:准备工作 - 注册可用的工具
- // 创建一个工具注册表(就像一个工具箱),记录每个工具的名称和对应的方法
- // key: 工具名称(AI调用时使用)
- // value: 实际执行的Java方法(反射调用)
- // 通俗理解:建立一张"工具对照表"
- // 当AI说"我要用putFile工具"时,程序就知道要调用AgentTools类的putFile方法
- HashMap<String, Method> tools = new HashMap<>();
- tools.put("putFile", AgentTools.class.getMethod("putFile", String.class));
- tools.put("getFile", AgentTools.class.getMethod("getFile", String.class));
- tools.put("batchPutFile", AgentTools.class.getMethod("batchPutFile", String.class));
-
- // 第 0.5 步:创建记忆管理器 - 加载长期记忆
- MemoryManager memoryManager = new MemoryManager();
- System.out.println(memoryManager.getMemoryStats());
-
- //第1步:创建AI客户端 - 建立与AI服务的连接通道
- OpenAIClient aiClient = OpenAIOkHttpClient.builder()
- .apiKey(AiConfig.API_KEY) // 设置身份证(API密钥)
- .baseUrl(AiConfig.BASE_URL) // 设置对方地址(服务地址)
- .build(); // 建造完成,电话接通
-
- //第 2 步:准备要问的问题 - 编写聊天内容
- // 2.1 用户的实际问题(原始输入)
- // String promptString = "批量创建 3 个文件到 D:\\ 中,分别是 a.txt 内容为 Hello A, b.txt 内容为 Hello B, c.txt 内容为 Hello C";
- // String promptString = "读取 D:\\a.txt 文件的内容"; // 这个问题 AI 会直接回答,不需要调用工具
- // String promptString = "我之前都让你干了哪些事情"; // 这个问题 AI 会直接回答,不需要调用工具
- String promptString = "请帮我写一个完整的飞机大战 Java 游戏,包含以下功能:\n" +
- "1. 玩家飞机可以用方向键或 WASD 移动\n" +
- "2. 空格键发射子弹\n" +
- "3. 敌机会从屏幕上方随机出现并向下移动\n" +
- "4. 子弹击中敌机会产生爆炸效果并加分\n" +
- "5. 敌机撞到玩家则游戏结束\n" +
- "6. 显示分数和等级\n" +
- "7. 飞机形状,敌机下落速度均匀,不要出现一快慢\n" +
- "\n" +
- "请将所有代码保存到一个文件中。";
- // 2.1.5 记录用户消息到记忆中
- memoryManager.addUserMessage(promptString);
-
- // 2.2 替换模板中的工具占位符
- // ToolUtil.getToolDescription(AgentTools.class) 会返回 AgentTools 类中所有工具的说明
- // 就像把“工具箱清单”填写到工作流程说明书中
- // 告诉 AI:你能用的工具有“写文件”、“读文件”等等...
- String prompt = TEMPLATE.replace("{tools}", ToolUtil.getToolDescription(AgentTools.class));
-
- // 2.2.5 获取最近的记忆并替换到模板中
- // 这样 AI 就能记住之前的对话内容
- String memoryContext = buildMemoryContext(memoryManager.getRecentMemories(10));
- prompt = prompt.replace("{memory}", memoryContext);
-
- // 2.3 替换模板中的用户问题占位符
- // 把用户的具体问题填进去
- // 就像告诉AI:"这是你要完成的具体任务"
- prompt = prompt.replace("{input}", promptString);
-
- //第3步:构建请求参数 - 把问题打包成AI能理解的格式
- ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
- .addUserMessage(prompt) // 添加用户消息:你说的话
- .model(AiConfig.LLM_NAME) // 指定用哪个AI大脑来处理
- .build(); // 打包完成,准备发送
-
- //第4步:发送请求并获取回复 - 把信寄出去,等待回信
- ChatCompletion chatCompletion = aiClient.chat() // 打开聊天功能
- .completions() // 开启补全模式(AI回复)
- .create(params); // 发送请求并等待响应
-
- // 第5步:提取AI的回答 - 拆开回信,取出内容
- // 5.1 获取AI返回的原始消息
- String message = chatCompletion.choices().get(0).message().content().get();
-
- // 5.2 清理消息格式 - 移除 markdown 代码块标记和多余文字
- // AI 可能把工具调用放在代码块中,我们需要提取出纯 JSON
- // 例如:将 ```tool_code {...} ``` 转换成 {...}
- message = message.replace("```tool_code", "");
- message = message.replace("```json", "");
- message = message.replace("```", "");
-
- // 尝试提取第一个 { 到最后一个 } 之间的内容(处理 AI 添加解释文字的情况)
- int firstBrace = message.indexOf('{');
- int lastBrace = message.lastIndexOf('}');
- if (firstBrace != -1 && lastBrace != -1 && lastBrace > firstBrace) {
- message = message.substring(firstBrace, lastBrace + 1);
- }
-
- // 5.3 解析 JSON - 理解 AI 想要调用哪个工具
- // 将清理后的字符串解析成 JSON 对象,提取工具名称和参数
- // 就像读懂 AI 写的"工具使用申请单"
- JSONObject jsonObject = null;
- try {
- jsonObject = JSONObject.parseObject(message);
-
- // 检查是否是有效的工具调用格式(必须包含 toolName 和 params)
- String toolName = jsonObject.getString("toolName");
- String toolParams = jsonObject.getString("params");
-
- if (toolName == null || toolParams == null) {
- // 格式不对,说明不是工具调用
- jsonObject = null;
- }
- } catch (Exception e) {
- // 解析失败,说明 AI 返回的不是 JSON,而是直接回答
- System.out.println("\n[AI 直接回复]\n" + message);
-
- // 记录 AI 的回复到记忆中(没有工具调用)
- memoryManager.addAssistantMessage(message, null, null);
- memoryManager.saveMemories();
- System.out.println(memoryManager.getMemoryStats());
- return; // 直接结束,不执行工具调用
- }
-
- // 能到这里说明是有效的工具调用
- String toolName = jsonObject.getString("toolName");
- String toolParams = jsonObject.getString("params");
-
- // 第 6 步:执行工具调用 - 根据 AI 的指令实际操作
- // 6.1 从工具注册表中找到对应的方法
- // 就像根据工具名称从工具箱里取出对应的工具
- Method toolMethod = tools.get(toolName);
-
- // 6.2 创建工具实例并执行方法
- // 通过反射调用工具方法,就像启动机器开始干活
- // new AgentTools():创建工具对象(准备干活)
- // toolMethod.invoke():执行具体方法(开始干活)
- // toolParams:传入参数(告诉工具要怎么做)
- Object result = toolMethod.invoke(new AgentTools(), toolParams);
-
- // 第 7 步:显示结果 - 把工具执行的结果打印出来
- System.out.println(result);
-
- // 第 8 步:保存记忆 - 将本次对话记录保存到长期记忆中
- // 重要:记录自然语言总结,而不是工具调用 JSON
- String assistantSummary = buildAssistantSummary(toolName, result.toString());
- memoryManager.addAssistantMessage(assistantSummary, toolName, result.toString());
- memoryManager.saveMemories();
- System.out.println(memoryManager.getMemoryStats());
- }
-
- /**
- * 构建 AI 回复的自然语言总结
- * @param toolName 工具名称
- * @param toolResult 工具执行结果
- * @return 自然语言总结
- */
- private static String buildAssistantSummary(String toolName, String toolResult) {
- if ("putFile".equals(toolName)) {
- return "使用写文件工具创建了文件";
- } else if ("getFile".equals(toolName)) {
- return "使用读文件工具读取了文件内容";
- } else if ("batchPutFile".equals(toolName)) {
- // 从结果中提取文件信息
- StringBuilder summary = new StringBuilder("批量创建了以下文件:");
- String[] lines = toolResult.split("\\n");
- for (String line : lines) {
- if (line.contains("成功写入")) {
- // 提取文件名
- int start = line.indexOf("D:");
- if (start != -1) {
- String filePath = line.substring(start).trim();
- summary.append(filePath).append("、");
- }
- }
- }
- // 移除最后一个顿号
- if (summary.length() > 0 && summary.charAt(summary.length() - 1) == '、') {
- summary.setLength(summary.length() - 1);
- }
- return summary.toString();
- }
- return "调用了工具:" + toolName;
- }
-
- /**
- * 构建记忆上下文字符串
- * @param memories 记忆列表
- * @return 格式化的记忆文本
- */
- private static String buildMemoryContext(List<MemoryManager.MemoryEntry> memories) {
- if (memories.isEmpty()) {
- return "(暂无历史对话)";
- }
-
- StringBuilder context = new StringBuilder();
- for (MemoryManager.MemoryEntry entry : memories) {
- String roleText = "user".equals(entry.getRole()) ? "用户" : "AI";
- context.append(String.format("[%s] %s: %s\n",
- entry.getTimestamp(), roleText, entry.getContent()));
-
- // 如果有工具调用信息,也加上
- if (entry.getToolName() != null) {
- context.append(String.format(" → 使用工具:%s\n", entry.getToolName()));
- }
- if (entry.getToolResult() != null) {
- context.append(String.format(" → 工具结果:%s\n", entry.getToolResult()));
- }
- }
- return context.toString();
- }
-
- }
复制代码
aiagent.zip
(22.01 KB, 下载次数: 0, 售价: 50 金豆)
|