当前位置: 首页 > news >正文

【从0到1构建一个ClaudeAgent】工具与执行-Agent循环

while True: response = client.messages.create(messages=messages, tools=tools) if response.stop_reason != "tool_use": break for tool_call in response.content: result = execute_tool(tool_call.name, tool_call.input) messages.append(result)

这段代码人工翻译一下就是:

  1. 调模型(给指令)
  2. 执行工具(读写文件、跑命令)
  3. 回传结果(告诉模型干了啥)
  4. 继续迭代(直到任务干完)

就这?就这。剩下的全是围绕这个循环的各种优化和补丁。

用 Java 来写,核心循环大概是这样:

java

while (true) { MessageResponse response = client.messagesCreate(messages, tools); if (!"tool_use".equals(response.getStopReason())) { break; } for (ToolCall toolCall : response.getContent()) { ToolResult result = executeTool(toolCall.getName(), toolCall.getInput()); messages.add(result); } }

正是考虑到我们的读者多数是Java同学,因此我决定用Java来和大家一块学习下

渐进式学习路径

网站将这 12 个阶段(s01-s12)归纳为五个核心能力的进阶,看看一个成熟的 Agent 系统是如何一步步被做出来的:

S01 Agent 循环

最小可用的 Agent 内核仅仅需要:一个 while 循环 + 一个工具。

说白了就是Agent 最本质的“大脑-手脚”循环

Java实现代码

java

public class AgentLoop { // 模拟 Anthropic API 客户端 private static final String API_KEY = System.getenv("ANTHROPIC_API_KEY"); private static final String MODEL_ID = System.getenv("MODEL_ID"); private static final HttpClient client = HttpClient.newHttpClient(); // 核心循环 public static void agentLoop(List<Map<String, Object>> messages) { while (true) { // 1. 调用 LLM System.out.println(">>> 正在思考..."); Map<String, Object> response = callLLM(messages); // 2. 将助手回复加入历史 messages.add(response); // 3. 检查停止原因 // 注意:这里简化了逻辑,实际需解析 JSON 中的 stop_reason String stopReason = (String) response.get("stop_reason"); if (!"tool_use".equals(stopReason)) { return; // 任务完成,退出循环 } // 4. 执行工具 List<Map<String, Object>> toolResults = new ArrayList<>(); List<Map<String, Object>> content = (List<Map<String, Object>>) response.get("content"); for (Map<String, Object> block : content) { if ("tool_use".equals(block.get("type"))) { Map<String, Object> input = (Map<String, Object>) block.get("input"); String command = (String) input.get("command"); String toolId = (String) block.get("id"); System.out.println("\033[33m$ " + command + "\033[0m"); // 黄色输出命令 // 执行 Bash String output = runBash(command); System.out.println(output.length() > 200 ? output.substring(0, 200) + "..." : output); // 构造工具结果 Map<String, Object> result = new HashMap<>(); result.put("type", "tool_result"); result.put("tool_use_id", toolId); result.put("content", output); toolResults.add(result); } } // 5. 将工具结果作为用户输入再次加入历史 Map<String, Object> userTurn = new HashMap<>(); userTurn.put("role", "user"); userTurn.put("content", toolResults); messages.add(userTurn); } } // 模拟 LLM 调用 (实际需替换为 SDK 调用) private static Map<String, Object> callLLM(List<Map<String, Object>> messages) { // 这里是一个占位符,实际应发送 HTTP 请求给 Anthropic API // 返回结构需匹配 API 响应 return new HashMap<>(); } // 执行 Shell 命令 private static String runBash(String command) { // 安全检查 if (command.contains("rm -rf /") || command.contains("sudo")) { return "Error: Dangerous command blocked"; } try { ProcessBuilder pb = new ProcessBuilder("bash", "-c", command); pb.redirectErrorStream(true); Process p = pb.start(); // 读取输出 BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); StringBuilder output = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { output.append(line).append("\n"); } // 等待完成 (带超时) if (!p.waitFor(120, TimeUnit.SECONDS)) { p.destroyForcibly(); return "Error: Timeout (120s)"; } String result = output.toString().trim(); return result.isEmpty() ? "(no output)" : result.substring(0, Math.min(result.length(), 50000)); } catch (IOException | InterruptedException e) { return "Error: " + e.getMessage(); } } public static void main(String[] args) { List<Map<String, Object>> history = new ArrayList<>(); Scanner scanner = new Scanner(System.in); System.out.println("Agent 已启动 (输入 'q' 退出)"); while (true) { System.out.print("\033[36ms01 >> \033[0m"); String query = scanner.nextLine(); if (query.trim().equalsIgnoreCase("q") || query.isEmpty()) { break; } Map<String, Object> userMsg = new HashMap<>(); userMsg.put("role", "user"); userMsg.put("content", query); history.add(userMsg); agentLoop(history); // 打印最终回复 System.out.println("Agent 执行完毕。"); } } }

这段代码包含了所有 AI Agent 的灵魂

核心模式:ReAct 循环

代码中的while循环是 Agent 的心脏。它的逻辑是:

  1. 思考:问 LLM "该做什么?"
  2. 行动:如果 LLM 说要调工具(比如写代码、运行命令),代码就去执行这个工具
  3. 观察:把工具执行的结果(输出、报错)再次告诉 LLM。
  4. 循环:LLM 根据结果决定是继续干,还是说“搞定了”。

java

while (true) { // 1. 调用 LLM Map<String, Object> response = callLLM(messages); messages.add(response); // 2. 检查是否结束 String stopReason = (String) response.get("stop_reason"); if (!"tool_use".equals(stopReason)) { return; // 任务完成 } // 3. 执行工具 List<Map<String, Object>> toolResults = executeTools(response); // 4. 将结果返回给 LLM messages.add(createUserTurn(toolResults)); }

状态管理

messages列表。它不仅仅是聊天记录,它是 Agent 的短期记忆

  • 每次循环,我们都要把新的对话(无论是人的指令,还是工具的执行结果)append进去。
  • 如果不把工具结果放回去,LLM 就不知道自己刚才执行的命令成功了没有,也就无法进行下一步。

工具定义的标准化

在 代码的TOOLS变量里,我们会定义了工具长什么样(名字、参数)。

java

// 遍历响应中的工具调用块 for (Map<String, Object> block : content) { if ("tool_use".equals(block.get("type"))) { // 提取命令 Map<String, Object> input = (Map<String, Object>) block.get("input"); String command = (String) input.get("command"); String toolId = (String) block.get("id"); // 执行 Bash String output = runBash(command); // 构建工具结果 Map<String, Object> result = new HashMap<>(); result.put("type", "tool_result"); result.put("tool_use_id", toolId); result.put("content", output); toolResults.add(result); } }

关键点:LLM 不会真的“运行”代码,它只是输出一个符合这个格式的 JSON(比如{"name": "bash", "arguments": {"command": "ls"}})。而代码才是负责解析这个 JSON 并真的去执行Runtime.exec()

安全围栏

代码里的run_bash函数不仅仅是执行命令,它还充当了防火墙

java

private static String runBash(String command) { // 安全检查 if (command.contains("rm -rf /") || command.contains("sudo")) { return "Error: Dangerous command blocked"; } // 带超时的命令执行 if (!p.waitFor(120, TimeUnit.SECONDS)) { p.destroyForcibly(); return "Error: Timeout (120s)"; } // 限制输出长度 return result.substring(0, Math.min(result.length(), 50000));
http://www.gsyq.cn/news/1624609.html

相关文章:

  • 强力解锁浏览器画中画功能:告别视频观看的割裂体验
  • CI/CD 回滚演练:能发布,也要能撤回来
  • 贝叶斯优化:用高斯过程与采集函数实现智能超参数调优
  • 统一多模态Agent编排:用单一模型驱动多感官任务的可行性与边界
  • 基于HuggingFace生态的Zero_NLP项目实战指南:从Transformer模型微调到中文文本分类与NER任务的深度解析
  • Claude Code 国内安装与实战指南:AI 编程助手从零到项目集成
  • FanControl终极指南:3步搞定Windows风扇控制,告别噪音与高温
  • 企业级AI集成实战:Agent、RAG与MCP架构深度解析
  • Three.js 本地模型加载教程
  • 离线运行的 3D 模型处理工具,保密项目的稳妥选择
  • openEuler Compiler-docs技术白皮书解读:LLVM构建openEuler的完整技术方案
  • 批处理策略的数学建模:从静态 Batching 到 Continuous Batching 的吞吐分析
  • AI驱动的Three.js渲染优化:霓虹城市的智能帧率管理
  • 航天电路板为啥不能出一点错?
  • Agent越来越智能,但我发现软件工程仍然很重要
  • 【 Elasticsearch】安装配置 GitHub Copilot CLI 插件
  • 2025-6-15模拟测验
  • 从 Paper 到产品原型:只取能验证商业假设的部分
  • 跨境电商选灵爪AI开发需看真实案例与预算
  • 163MusicLyrics:如何免费获取网易云QQ音乐歌词的终极解决方案
  • 全面战争模组制作的技术解构:RPFM架构深度解析与进阶实践
  • 动态工具加载与热重载:构建 MCP Server 的插件体系及生命周期管理
  • AI 辅助前端代码生成:先给边界,再谈效率
  • MySQL 慢查询根治指南:从 EXPLAIN 看懂到索引覆盖率优化的完整链路
  • Serverless 事件流水线:自动发布不等于无人值守
  • Ollydbg逆向工程入门:从CrackMe破解实战理解程序验证逻辑
  • WPS回应C盘占用争议:缓存清理始终免费,7月版本优化管理入口
  • 大模型业务基准测试实战指南
  • AI 无障碍评审:让界面被看见,也能被读懂
  • AI 存储异常检测:先定义指标拓扑,再谈智能告警