public class AgentWithTools { // 配置 private static final Path WORKDIR Paths.get(System.getProperty(user.dir)); // --- 核心工具定义与分发 --- // 1. 定义工具枚举 public enum ToolType { BASH(bash, Run a shell command.), READ_FILE(read_file, Read file contents.), WRITE_FILE(write_file, Write content to file.), EDIT_FILE(edit_file, Replace exact text in file.); // ... 省略构造器 } // 2. 工具执行接口 FunctionalInterface interface ToolExecutor { String execute(MapString, Object args) throws Exception; } // 3. 注册工具处理逻辑 private static final MapString, ToolExecutor TOOL_HANDLERS new HashMap(); static { TOOL_HANDLERS.put(ToolType.BASH.name, args - { String command (String) args.get(command); return runBash(command); }); TOOL_HANDLERS.put(ToolType.READ_FILE.name, args - { String path (String) args.get(path); Integer limit (Integer) args.get(limit); return runRead(path, limit); }); TOOL_HANDLERS.put(ToolType.WRITE_FILE.name, args - { String path (String) args.get(path); String content (String) args.get(content); return runWrite(path, content); }); TOOL_HANDLERS.put(ToolType.EDIT_FILE.name, args - { String path (String) args.get(path); String oldText (String) args.get(old_text); String newText (String) args.get(new_text); return runEdit(path, oldText, newText); }); } // --- 核心循环 --- public static void agentLoop(ListMapString, Object messages) { while (true) { // ... 省略相同的 LLM 调用、消息追加逻辑 // 4. 执行工具 ListMapString, Object toolResults new ArrayList(); ListMapString, Object content (ListMapString, Object) response.get(content); for (MapString, Object block : content) { if (tool_use.equals(block.get(type))) { String toolName (String) block.get(name); // 关键新增 String toolId (String) block.get(id); MapString, Object inputArgs (MapString, Object) block.get(input); // 路由分发 ToolExecutor handler TOOL_HANDLERS.get(toolName); String output; try { if (handler ! null) { output handler.execute(inputArgs); } else { output Error: Unknown tool toolName; } } catch (Exception e) { output Error: e.getMessage(); } System.out.println( toolName : output.substring(0, Math.min(output.length(), 100))); // ... 省略相同的工具结果构造逻辑 } } // ... 省略相同的回传逻辑 } } // --- 工具具体实现 --- private static Path safePath(String p) throws IOException { Path path WORKDIR.resolve(p).normalize(); if (!path.startsWith(WORKDIR)) { throw new IOException(Path escapes workspace: p); } return path; } // ... 省略与之前相同的 runBash 实现 private static String runRead(String pathStr, Integer limit) throws IOException { Path path safePath(pathStr); String content Files.readString(path); if (limit ! null limit content.length()) { return content.substring(0, limit) ... (truncated); } return content; } private static String runWrite(String pathStr, String content) throws IOException { Path path safePath(pathStr); Files.createDirectories(path.getParent()); Files.writeString(path, content); return Wrote content.length() bytes to pathStr; } private static String runEdit(String pathStr, String oldText, String newText) throws IOException { Path path safePath(pathStr); String content Files.readString(path); if (!content.contains(oldText)) { return Error: Text not found in pathStr; } String newContent content.replace(oldText, newText); Files.writeString(path, newContent); return Edited pathStr; } }这段代码相比 s01最大的进步在于能力的扩展和安全边界。说白了就是你可以像搭积木一样给 Agent 塞入各种工具函数让它的能力边界随插件无限延伸。这段代码应该已经很清晰我这里就不多解释了工具抽象框架策略模式核心思想从硬编码工具升级为可插拔架构实现工具与主循环的解耦。java// 工具枚举 - 集中定义所有可用工具 public enum ToolType { BASH(bash, Run a shell command.), READ_FILE(read_file, Read file contents.), WRITE_FILE(write_file, Write content to file.); // 枚举定义工具名 描述 // 为LLM提供工具列表时使用 }java// 工具执行接口 - 统一调用契约 FunctionalInterface interface ToolExecutor { String execute(MapString, Object args) throws Exception; // 统一接口所有工具都实现此方法 // 参数和返回值标准化 }java// 工具注册表 - 动态路由 private static final MapString, ToolExecutor TOOL_HANDLERS new HashMap(); static { TOOL_HANDLERS.put(bash, args - { // 工具实现1 }); TOOL_HANDLERS.put(read_file, args - { // 工具实现2 }); // 注册中心工具名 - 实现函数 // 新增工具只需在这里注册 }开闭原则不修改主循环就能添加新工具统一管理所有工具注册、调用逻辑一致类型安全通过枚举定义工具避免硬编码字符串文件操作工具集核心思想为Agent提供文件系统读写能力使其能像人类开发者一样操作文件。javaprivate static Path safePath(String p) throws IOException { Path path WORKDIR.resolve(p).normalize(); if (!path.startsWith(WORKDIR)) { throw new IOException(Path escapes workspace: p); } return path; // 安全沙箱确保工具只能操作工作目录内的文件 // 防止路径逃逸攻击 }javaprivate static String runRead(String pathStr, Integer limit) throws IOException { Path path safePath(pathStr); String content Files.readString(path); if (limit ! null limit content.length()) { return content.substring(0, limit) ... (truncated); } return content; // 带限制的读取防止大文件内存溢出 // 自动截断返回友好提示 }javaprivate static String runWrite(String pathStr, String content) throws IOException { Path path safePath(pathStr); Files.createDirectories(path.getParent()); // 自动创建父目录 Files.writeString(path, content); return Wrote content.length() bytes to pathStr; // 自动创建目录用户体验优化 // 明确的结果反馈 }javaprivate static String runEdit(String pathStr, String oldText, String newText) throws IOException { Path path safePath(pathStr); String content Files.readString(path); if (!content.contains(oldText)) { return Error: Text not found in pathStr; // 错误处理 } String newContent content.replace(oldText, newText); Files.writeString(path, newContent); return Edited pathStr; // 简单的文件编辑文本查找替换 // 先验证后操作避免损坏文件 }沙箱安全所有文件操作都经过safePath检查渐进式反馈读操作支持截断避免响应过大容错处理编辑前检查文本是否存在自动化写文件时自动创建父目录动态工具路由java// 在agentLoop中 String toolName (String) block.get(name); // 从LLM响应中提取工具名 MapString, Object inputArgs (MapString, Object) block.get(input); // 根据工具名查找处理器 ToolExecutor handler TOOL_HANDLERS.get(toolName); String output; try { if (handler ! null) { output handler.execute(inputArgs); // 动态调用 } else { output Error: Unknown tool toolName; } } catch (Exception e) { output Error: e.getMessage(); // 统一错误处理 }动态分派根据LLM选择的工具名调用对应实现统一错误处理未知工具、执行异常都有统一格式的返回解耦主循环不需要知道具体工具的实现细节架构对比与价值从AgentLoop到AgentWithTools的演进维度AgentLoopAgentWithTools工具数量1个(Bash)4个(可扩展)架构设计硬编码策略模式添加新工具修改主代码注册表添加文件操作无读写编辑安全性命令检查沙箱路径代码复用低高