从零构建智能代理:基于LLM的Agent核心架构与Python实践

📅 2026/8/11 10:52:56
从零构建智能代理:基于LLM的Agent核心架构与Python实践
1. 从“智能体”到“智能代理”一个概念的澄清与落地最近和不少同行交流发现一个挺有意思的现象大家聊起“Agent”时脑子里想的画面可能完全不一样。有人觉得是科幻电影里无所不能的AI助手有人觉得是自动化流程里一个简单的脚本触发器还有人觉得是游戏里那些会跑会跳的NPC。这种认知上的差异恰恰是我们从零开始构建自己的Agent时第一个要厘清的核心问题。在技术领域尤其是当前AI驱动的自动化浪潮下我们谈论的“Agent”更准确的翻译是“智能代理”或“智能体”。它不是一个具象的、有物理形态的机器人而是一个具备感知、决策、执行和持续学习能力的软件实体。它的核心使命是在给定的目标或任务框架下能够自主地与环境包括用户、其他系统、数据源等进行交互并采取一系列行动来达成目标而无需或仅需极少人工的逐步干预。为什么这个概念现在如此火热因为大语言模型LLM的突破为Agent赋予了前所未有的“大脑”。过去的自动化脚本或规则引擎其“智能”上限被预先编写的规则牢牢锁死。而一个由LLM驱动的Agent其核心优势在于理解与泛化。它能够理解用自然语言描述的、模糊的、甚至未曾预见的任务指令并规划出合理的执行步骤。这就像是从一个只会按固定乐谱演奏的钢琴机器人进化成了一个能听懂“来段欢快的曲子”并即兴发挥的音乐家。所以当我们说“从零实现自己的Agent”时我们不是在造一个终结者而是在构建一个以LLM为核心决策引擎能够调用工具、处理信息、并朝着目标持续行动的软件系统。这个系统可以小到帮你自动整理日报、筛选邮件也可以复杂到成为一个独立处理客户咨询、协调内部资源的虚拟员工。理解这个本质是我们一切实践的开端。2. 拆解Agent的核心组件不止是“大模型聊天”如果认为接上一个ChatGPT的API然后让它“自己干活”就是一个Agent那可能会很快陷入困惑。一个功能完整、鲁棒的Agent其内部结构远比一个对话接口复杂。我们可以将其核心抽象为四个相互协作的模块这构成了我们实现时的基本蓝图。2.1 感知模块世界的“眼睛”和“耳朵”感知模块是Agent与外界交互的入口。它的职责是接收、解析和结构化各种输入。这不仅仅是用户的一句自然语言指令。指令解析这是最基础的部分。当用户说“帮我查一下上周的销售数据做个总结并找出表现最好的三个产品”感知模块需要能完整捕获这个复合指令。上下文感知Agent需要知道“现在是什么时候”上周指哪个具体日期范围“我是谁”是否有权限访问销售数据“对话历史是什么”用户之前是否已经问过相关问题。这通常通过维护一个“上下文窗口”或记忆系统来实现。多模态输入高级的Agent可能需要处理图像、文档、音频甚至传感器数据。例如用户上传一张产品故障图Agent需要能“看到”并理解图片内容将其转化为可处理的文本描述或结构化数据。工具状态感知Agent需要知道它能调用哪些工具后文会详述以及这些工具当前是否可用、上次调用结果如何。在实现上感知模块很大程度上依赖于LLM本身强大的多轮对话和上下文理解能力。我们通常会将用户当前指令、历史对话、系统预设的角色描述、以及可用的工具列表共同拼接成一个精心设计的提示词Prompt喂给LLM。这个提示词的质量直接决定了LLM对任务理解的准确度。2.2 规划与决策模块Agent的“大脑”这是Agent最核心、最体现“智能”的部分。接收到结构化或半结构化的感知信息后规划模块需要回答“我现在应该做什么分几步做”任务分解将复杂的顶层目标拆解为一系列可执行的原子子任务。例如“总结销售数据并找最佳产品”可以分解为1. 查询数据库获取原始数据2. 对数据进行聚合分析3. 按销售额排序4. 生成文本总结。路径规划子任务之间可能存在依赖关系必须先查数据才能分析也可能有并行执行的可能。规划模块需要理清这些依赖制定一个高效的执行序列。工具选择对于每个原子子任务需要决定调用哪个工具或组合来完成。是调用“数据库查询工具”还是“网络搜索工具”或是“Python代码执行工具”应对不确定性当执行过程中出现意外如工具调用失败、返回结果异常规划模块需要能够重新评估形势调整计划例如重试、选择备用工具或向用户请求澄清。目前实现规划能力的主流范式是“ReAct”Reasoning Acting框架。其核心思想是让LLM以“思考-行动-观察”的循环模式运作。LLM会先输出一段“思考”内部推理说明接下来要做什么以及为什么然后输出一个具体的“行动”如调用某个工具及其参数执行后得到“观察”工具返回的结果再基于此进行下一轮思考。通过这种循环LLM实现了动态的任务规划和决策。2.3 工具调用模块Agent的“双手”LLM本身是一个“思考者”但它无法直接操作世界。工具调用模块就是为LLM赋予“动手能力”的桥梁。工具可以是任何能够通过API、函数调用或命令行来访问的能力。工具的定义与封装每个工具都需要被清晰地定义包括工具名称、功能描述、必需的输入参数及其类型、格式、返回值的结构。例如tools [ { name: get_weather, description: 获取指定城市的当前天气信息, parameters: { type: object, properties: { city: {type: string, description: 城市名称如‘北京’} }, required: [city] } }, { name: search_web, description: 使用搜索引擎进行网络搜索, parameters: {...} } ]工具的执行引擎当决策模块发出工具调用指令后执行引擎需要负责安全、可靠地调用对应的函数或服务处理认证、网络错误、超时等问题并将结果规范化后返回给Agent。工具的扩展性一个强大的Agent生态意味着可以轻松地“即插即用”新的工具。这要求工具调用模块有良好的抽象和注册机制。注意工具的描述至关重要。LLM完全依赖你对工具功能的文字描述来决定是否以及如何调用它。模糊或不准确的描述会导致错误的工具调用。2.4 记忆与学习模块Agent的“经验”一个只会机械执行单次任务、过后就忘的Agent是初级的。记忆模块让Agent能够拥有“经验”从而更高效、更个性化。短期记忆/对话记忆保存当前会话的上下文确保Agent在多轮对话中不迷失。这通常由LLM的上下文窗口长度限制对于长对话需要借助摘要、向量检索等技术来压缩关键信息。长期记忆/知识库存储跨会话的、重要的信息。例如用户偏好“我喜欢用Markdown格式看报告”、历史任务执行结果、从以往交互中学到的经验“上次用A方法处理这类数据失败了这次试试B方法”。这通常需要外部存储数据库、向量数据库来实现。学习与适应基于记忆Agent可以优化自身行为。例如通过强化学习根据任务完成效果调整策略或通过检索增强生成RAG从知识库中动态获取相关信息来辅助当前决策。这四个模块并非总是泾渭分明在简单实现中可能高度耦合。但理解这个架构能帮助我们在设计和实现时清晰地定位问题所在。例如如果Agent总是错误理解指令可能是感知模块的提示词设计有问题如果它步骤混乱可能是规划逻辑有缺陷如果它无法完成实际操作可能是工具模块集成不到位。3. 一个极简Agent的实现骨架用代码说话理论说得再多不如动手写几行代码来得实在。下面我将用一个尽可能简单的Python示例勾勒出一个具备基础规划与工具调用能力的Agent骨架。我们使用OpenAI的Chat Completions API假设你已具备API Key和其支持的“Function Calling”函数调用功能来实现。这个例子将完成一个经典任务查询天气并给出穿衣建议。3.1 环境准备与工具定义首先我们需要安装必要的库并定义我们的“工具”。这里我们模拟一个天气查询工具。# 安装依赖 (假设使用OpenAI API) # pip install openai import openai import json import os # 设置你的OpenAI API Key openai.api_key os.getenv(OPENAI_API_KEY) # 模拟的天气查询工具真实场景中这里会调用如和风天气、OpenWeatherMap等API def get_weather(city: str) - str: 模拟获取城市天气信息。 在实际项目中此处应替换为真实的API调用。 # 这里为了演示返回一个模拟的固定数据 weather_data { 北京: {temperature: 22°C, condition: 晴朗, humidity: 40%}, 上海: {temperature: 25°C, condition: 多云, humidity: 65%}, 广州: {temperature: 30°C, condition: 雷阵雨, humidity: 85%}, } if city in weather_data: info weather_data[city] return f{city}的天气是{info[condition]}气温{info[temperature]}湿度{info[humidity]}。 else: return f未找到{city}的天气信息。 # 将工具函数封装成OpenAI Function Calling所需的格式 tools [ { type: function, function: { name: get_weather, description: 获取指定城市的当前天气信息, parameters: { type: object, properties: { city: { type: string, description: 城市名称例如北京、上海, } }, required: [city], }, }, } ]3.2 Agent核心循环ReAct模式的简易实现接下来我们实现一个简单的循环让LLM根据对话决定是直接回答还是调用工具。def run_agent_conversation(user_input: str, conversation_history: list None): 运行一个简单的Agent对话轮次。 if conversation_history is None: conversation_history [] # 1. 将用户输入和历史对话组合成消息列表 messages [ {role: system, content: 你是一个有帮助的助手可以查询天气。请根据用户需求决定是否需要调用工具。如果需要请严格按照工具要求的格式调用。} ] messages.extend(conversation_history) messages.append({role: user, content: user_input}) # 2. 调用LLM并告知它可用的工具 response openai.chat.completions.create( modelgpt-3.5-turbo, # 或 gpt-4 messagesmessages, toolstools, tool_choiceauto, # 让模型自行决定是否调用工具 ) response_message response.choices[0].message tool_calls response_message.tool_calls # 3. 将LLM的回复添加到历史中 conversation_history.append({role: user, content: user_input}) conversation_history.append(response_message) # 包含可能的tool_calls # 4. 检查LLM是否决定调用工具 if tool_calls: print(fAgent决定调用工具...) available_functions { get_weather: get_weather, } # 遍历所有工具调用理论上一次可能调用多个 for tool_call in tool_calls: function_name tool_call.function.name function_to_call available_functions[function_name] function_args json.loads(tool_call.function.arguments) # 执行工具函数 function_response function_to_call(**function_args) print(f 调用 {function_name}参数 {function_args}结果: {function_response}) # 5. 将工具执行结果作为新的消息反馈给LLM messages.append({ role: tool, tool_call_id: tool_call.id, content: function_response, }) conversation_history.append({ role: tool, tool_call_id: tool_call.id, content: function_response, name: function_name }) # 6. 获取LLM基于工具结果的最终回答 second_response openai.chat.completions.create( modelgpt-3.5-turbo, messagesmessages, ) final_message second_response.choices[0].message.content conversation_history.append({role: assistant, content: final_message}) print(fAgent最终回复: {final_message}) return final_message, conversation_history else: # 没有调用工具直接返回LLM的回复 final_message response_message.content conversation_history.append({role: assistant, content: final_message}) print(fAgent直接回复: {final_message}) return final_message, conversation_history # 模拟一次对话 print( 对话开始 ) history [] reply, history run_agent_conversation(北京天气怎么样, history) # 输出: Agent决定调用工具... 调用 get_weather ... Agent最终回复: 北京目前天气晴朗气温22°C湿度40%。... reply, history run_agent_conversation(那适合穿什么衣服, history) # 输出: Agent直接回复: 根据北京的当前天气晴朗22°C建议穿着轻薄的长袖衬衫、薄外套或针织衫搭配长裤或裙子。早晚温差可能稍大可以准备一件备用外套。...这个简单的例子展示了Agent工作的核心闭环理解指令 - 规划决定调用工具- 执行调用get_weather- 观察结果 - 生成最终回答。虽然它没有复杂的任务分解和长期记忆但已经具备了智能代理的雏形。4. 超越Demo构建实用Agent必须面对的挑战当你把上面的Demo跑通兴奋之余很快就会遇到现实问题。一个玩具级的Agent和一个能在生产环境可靠运行的Agent之间隔着无数个需要填平的坑。以下是几个你必须提前思考和设计的关键挑战。4.1 可靠性当LLM“胡言乱语”或工具调用失败时LLM的本质是概率模型它可能产生“幻觉”生成看似合理但错误或虚构的信息也可能在规划时做出不合逻辑的决策。工具调用也可能因为网络、权限、输入错误而失败。幻觉与错误规划的缓解结构化输出与约束强制要求LLM在规划时必须按照预定义的JSON格式输出这能大幅减少其自由发挥导致格式错误的风险。可以使用Pydantic等库来定义严格的输出模型。验证与回退机制对LLM生成的计划或工具调用参数进行有效性检查。例如检查城市参数是否在支持列表中数字参数是否在合理范围内。如果检查失败则触发回退策略如要求LLM重新生成、使用默认值或直接向用户报错。多步验证与“慢思考”对于关键任务可以引入“自我验证”步骤。例如让LLM在给出最终答案前先输出其推理链再由另一个验证环节可以是规则也可以是另一个LLM调用来评估推理的合理性。工具调用的容错重试与超时为工具调用设置合理的超时时间和重试次数。优雅降级如果首选工具失败是否有备选方案例如搜索API挂了是否可以查询本地知识库结果校验工具返回的结果可能为空、格式异常。需要对这些边缘情况进行处理并将清晰的错误信息反馈给规划模块以便其调整策略。4.2 效率与成本Token就是金钱每一次LLM的调用尤其是使用GPT-4等大型模型都产生费用。一个复杂的任务如果规划不当可能导致多次不必要的LLM调用和冗长的上下文成本激增。上下文管理对话历史会不断增长消耗大量Token。需要策略性地管理上下文摘要压缩将冗长的历史对话或工具返回结果用LLM摘要成简洁的要点再存入上下文。向量检索记忆将长期记忆存入向量数据库。当需要相关历史信息时不是把全部历史塞进上下文而是根据当前问题检索最相关的几条记忆嵌入上下文。这是RAG技术在Agent领域的典型应用。分层记忆区分短期本次会话、中期近期会话、长期用户画像、重要事实记忆采用不同的存储和加载策略。规划优化避免让LLM进行过于细粒度的、一步步的规划。可以通过设计更高效的提示词或训练特定的小型规划模型来一次性生成更合理的完整计划树。4.3 安全与可控性给“智能”套上缰绳一个能自主调用工具的Agent其潜在风险远大于一个单纯的聊天机器人。必须建立严格的安全边界。工具权限沙箱这是重中之重。Agent绝对不能拥有不受限制的系统访问权限。最小权限原则每个工具只授予完成其功能所必需的最小权限。例如一个文件读取工具只能访问特定目录。操作确认对于高风险操作如删除文件、发送邮件、线上支付可以设计需要用户明确确认的机制或在开发/测试阶段完全禁用。输入净化与校验对所有从LLM生成并传递给工具的参数进行严格的校验和净化防止注入攻击如通过城市参数传入恶意命令。内容安全与合规对Agent的输入和输出进行内容过滤防止生成有害、偏见或不合规的信息。这需要在LLM调用前后加入安全层。可解释性与审计Agent做出的每一个关键决策特别是调用工具都应该有迹可循。需要记录完整的思维链Chain-of-Thought、工具调用日志和结果以便在出现问题时进行调试和归因。4.4 评估与迭代如何知道你的Agent在变好开发Agent不是一个一蹴而就的过程需要一个持续的评估和改进循环。评估指标你需要定义什么是“好”的Agent。任务完成率给定100个测试任务成功完成的比例是多少步骤效率完成同一个任务平均需要调用多少次LLM和工具步骤越少通常意味着规划越高效。结果质量对于生成文本类任务可以使用BLEU、ROUGE等指标或更重要的人工评估其准确性、有用性和流畅性。成本平均完成一个任务花费多少Token和API调用费用测试集构建收集或构造一批覆盖主要场景和边缘案例的测试任务例如“查询北京天气”、“查询一个不存在的城市天气”、“在查询天气后问一个无关问题”。持续迭代基于评估结果有针对性地改进。可能是优化提示词工程可能是增加新的工具或改进现有工具的描述也可能是引入更复杂的记忆机制。从零开始实现一个Agent就像教一个天赋异禀但毫无经验的新手员工。你需要先告诉他公司的规章制度安全边界、工作流程规划逻辑、可以使用的办公软件工具集以及如何从过去的项目中学习记忆模块。第一期我们重点就是搞清楚这个“新手员工”到底是谁定义他的基本能力构成是什么架构以及如何让他完成第一个简单任务骨架实现。有了这个坚实的基础在后续的实践中我们才能深入每个模块去解决更具体的工程问题比如如何设计一个强大的规划器如何集成复杂的工具链如何构建有效的记忆系统最终打造出一个真正实用、可靠的智能助手。