news 2026/7/26 20:40:29

复盘我的第一个 大模型Agent:从核心循环到模块化架构的演进之路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
复盘我的第一个 大模型Agent:从核心循环到模块化架构的演进之路

复盘我的第一个 大模型Agent:从核心循环到模块化架构的演进之路

引言:从“对话”到“行动”的跃迁在接触大模型Agent之前,我的认知止于“LLM = 对话机器人”。直到我尝试构建第一个能调用工具、执行多步任务的Agent时,才意识到真正的挑战在于:如何让LLM从“被动回答”转向“主动规划与执行”。这篇文章将复盘我从零搭建Agent的过程,剖析从“核心循环”到“模块化架构”的演进思路,并用可运行的代码示例展示每个阶段的原理。## 一、核心循环:Agent的“大脑”与“手脚”### 1.1 核心概念:感知-思考-行动循环Agent的底层逻辑是循环:接收输入(感知)→ LLM生成推理(思考)→ 执行工具(行动)→ 反馈结果。最简单的实现只需要一个while循环、一个LLM接口和一组工具函数。### 1.2 最小实现:单循环Agent下面是一个纯Python实现的“思考-行动”循环,使用OpenAI API和一个简单的计算器工具:pythonimport openaiimport json# 工具函数:一个简单的计算器def calculator(expression: str) -> str: """安全计算数学表达式,返回字符串结果""" try: # 注意:这里仅演示,生产环境应使用更安全的eval result = eval(expression, {"__builtins__": {}}, {}) return str(result) except Exception as e: return f"计算错误: {e}"# 核心循环def agent_loop(user_input: str, max_steps: int = 5): messages = [ {"role": "system", "content": "你是一个能调用工具的助手。工具格式: {\"name\": \"calculator\", \"arguments\": {\"expression\": \"1+1\"}}"}, {"role": "user", "content": user_input} ] step = 0 while step < max_steps: # 思考:调用LLM生成响应 response = openai.ChatCompletion.create( model="gpt-4", messages=messages, functions=[{ "name": "calculator", "description": "执行数学计算", "parameters": { "type": "object", "properties": { "expression": {"type": "string", "description": "数学表达式,如 2+3"} }, "required": ["expression"] } }], function_call="auto" ) message = response["choices"][0]["message"] # 如果LLM决定调用工具 if message.get("function_call"): func_name = message["function_call"]["name"] args = json.loads(message["function_call"]["arguments"]) # 行动:执行工具 result = calculator(args["expression"]) print(f"[Step {step}] 调用工具 {func_name}({args}) -> {result}") # 反馈:将结果加入对话 messages.append(message) messages.append({ "role": "function", "name": func_name, "content": result }) else: # 否则直接输出最终答案 print(f"[Step {step}] 最终回答: {message['content']}") break step += 1# 运行示例agent_loop("计算 12345 * 6789 的结果")原理分析: -functions参数定义了工具规范,LLM根据描述自主决定是否调用 - 每次循环,LLM输出要么是工具调用(包含名称和参数),要么是自然语言回答 - 工具执行结果通过function角色注入对话历史,形成连续推理上下文 这段代码只有30行,但完整展示了Agent的核心循环。然而,它存在明显问题:工具扩展性差、错误处理薄弱、无法处理多步复杂任务。这促使我转向模块化设计。## 二、模块化架构:从“硬编码”到“可插拔”### 2.1 为什么需要模块化?随着任务复杂度提升,单循环Agent暴露出三个痛点: 1.工具管理混乱:每个工具都需要在LLM调用中显式注册 2.状态维护困难:无法暂停/恢复多步任务 3.可测试性差:循环逻辑与业务逻辑耦合 模块化架构将Agent拆分为:调度器(Orchestrator)工具注册表(Tool Registry)记忆管理器(Memory Manager)策略引擎(Policy Engine)。### 2.2 模块化实现:可扩展的Agent框架以下代码展示了一个模块化Agent的骨架,支持动态注册工具、持久化记忆和可配置策略:pythonfrom typing import Dict, Any, Callable, Listimport json# 1. 工具注册表:管理所有可用工具class ToolRegistry: def __init__(self): self._tools = {} def register(self, name: str, func: Callable, description: str, parameters: dict): self._tools[name] = { "function": func, "spec": { "name": name, "description": description, "parameters": parameters } } def execute(self, name: str, arguments: Dict[str, Any]) -> str: tool = self._tools.get(name) if not tool: return f"错误:工具 {name} 不存在" try: result = tool["function"](**arguments) return str(result) except Exception as e: return f"执行错误: {e}" def get_specs(self) -> list: return [t["spec"] for t in self._tools.values()]# 2. 记忆管理器:维护对话历史class MemoryManager: def __init__(self): self.history = [] def add_message(self, role: str, content: str): self.history.append({"role": role, "content": content}) def add_function_call(self, message: dict, result: str): self.history.append(message) self.history.append({ "role": "function", "name": message["function_call"]["name"], "content": result }) def get_context(self) -> list: return self.history# 3. 调度器:协调循环class AgentOrchestrator: def __init__(self, tool_registry: ToolRegistry, memory: MemoryManager): self.tools = tool_registry self.memory = memory self.max_steps = 10 def set_strategy(self, strategy: str = "auto"): """设置工具调用策略:auto/force/none""" self.strategy = strategy def run(self, user_input: str): self.memory.add_message("user", user_input) for step in range(self.max_steps): # 调度器调用LLM(此处用模拟代替实际API调用) llm_response = self._simulate_llm(step) if llm_response["type"] == "tool_call": tool_name = llm_response["tool_name"] args = llm_response["arguments"] result = self.tools.execute(tool_name, args) print(f"[Step {step}] 工具 {tool_name} 返回: {result}") self.memory.add_function_call(llm_response["message"], result) else: print(f"[Step {step}] 最终回答: {llm_response['content']}") return llm_response['content'] return "达到最大步骤数" def _simulate_llm(self, step: int): """模拟LLM决策,实际应替换为真实API调用""" # 模拟:第一步调用工具,第二步回答 if step == 0: return { "type": "tool_call", "tool_name": "calculator", "arguments": {"expression": "2+2"}, "message": { "role": "assistant", "content": None, "function_call": { "name": "calculator", "arguments": '{"expression": "2+2"}' } } } else: return { "type": "answer", "content": "根据计算,2+2=4,这是最终答案。" }# 使用示例registry = ToolRegistry()registry.register( name="calculator", func=lambda expression: str(eval(expression)), description="执行数学计算", parameters={ "type": "object", "properties": { "expression": {"type": "string", "description": "数学表达式"} }, "required": ["expression"] })memory = MemoryManager()agent = AgentOrchestrator(registry, memory)agent.run("帮我计算2+2")架构优势: -可扩展性:通过ToolRegistry.register()动态添加工具,无需修改循环逻辑 -可测试性:每个模块独立测试,例如单独测试工具执行、记忆回溯 -可配置性:通过set_strategy()切换工具调用策略(例如强制使用某个工具) ## 三、演进之路:从原型到生产级架构### 3.1 第一阶段:单循环原型-特征:所有逻辑挤在一个while循环里 -教训:当工具数量超过5个时,代码难以维护;LLM调用频率过高导致成本失控 -改进点:引入工具注册表、添加调用频率限制 ### 3.2 第二阶段:模块化重构-特征:分离工具管理、记忆、调度 -关键调整: - 将工具描述从system prompt移到functions参数,避免prompt爆炸 - 使用max_steps控制循环次数,防止死循环 - 添加retry机制处理API调用失败 ### 3.3 第三阶段:生产级增强-加入缓存层:对重复的LLM请求(如相同context)使用LRU缓存 -异步化:使用asyncio并发执行多个工具调用 -安全沙箱:工具执行在隔离的docker容器中运行 ## 四、总结从单循环到模块化架构,我的第一个Agent经历了从“能跑”到“能维护”的蜕变。核心循环是Agent的“心跳”——感知、思考、行动、反馈永不停歇;而模块化架构则是“骨架”——让每个部件各司其职。给初学者的建议: 1. 先用10行代码跑通核心循环,理解“思考-行动”的本质 2. 当工具数量超过3个时,立刻进行模块化重构 3. 始终关注可观测性:记录每次LLM调用和工具执行的日志 Agent的本质不是“智能”,而是“结构化的交互”。当你把LLM看作一个“会思考的调度器”,将工具调用、记忆管理、错误处理封装为独立模块时,Agent才真正从玩具变成工具。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/26 20:40:28

投了100份简历0面试?软件测试秋招“卡关”的5个真相

关注 「软件测试就业联盟」公众号&#xff0c;陪你走好校招求职的每一步 投了100份简历&#xff0c;一个面试电话都没有。今年秋招&#xff0c;不少测试人的邮箱安静得让人发慌。 一个应届生私信我&#xff0c;他把招聘App上能搜到的测试岗全投了一遍&#xff0c;每天睁眼第一…

作者头像 李华
网站建设 2026/7/26 20:40:27

深入理解seckill项目架构:分层设计与各组件协作原理

深入理解seckill项目架构&#xff1a;分层设计与各组件协作原理 【免费下载链接】seckill Java高并发秒杀API&#xff08;慕课网&#xff09; 项目地址: https://gitcode.com/gh_mirrors/secki/seckill seckill是一个基于Java构建的高并发秒杀API项目&#xff0c;采用分…

作者头像 李华
网站建设 2026/7/26 20:36:21

netjj项目30天重构实战:技术债务量化与架构升级经验

最近在技术社区里&#xff0c;不少开发者都在讨论一个现象&#xff1a;为什么有些看似简单的项目重构&#xff0c;实际推进起来却困难重重&#xff1f;特别是当项目已经运行多年&#xff0c;技术债务累积到一定程度时&#xff0c;"重新开始"这个选项到底值不值得选&a…

作者头像 李华
网站建设 2026/7/26 20:35:54

5个技巧让Minecraft地图艺术创作变得简单:SlopeCraft完全指南

5个技巧让Minecraft地图艺术创作变得简单&#xff1a;SlopeCraft完全指南 【免费下载链接】SlopeCraft Map pixel art generator for Minecraft. 项目地址: https://gitcode.com/gh_mirrors/sl/SlopeCraft SlopeCraft是一款革命性的开源工具&#xff0c;专为Minecraft玩…

作者头像 李华
网站建设 2026/7/26 20:35:10

AntiDupl.NET完整指南:智能图片去重工具的高效实战教程

AntiDupl.NET完整指南&#xff1a;智能图片去重工具的高效实战教程 【免费下载链接】AntiDupl A program to search similar and defect pictures on the disk 项目地址: https://gitcode.com/gh_mirrors/an/AntiDupl 在现代数字生活中&#xff0c;我们每个人都会积累大…

作者头像 李华