尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AI智能体循环架构:从感知-思考-行动到自主任务执行

AI智能体循环架构:从感知-思考-行动到自主任务执行 在探索AI智能体开发的过程中你是否遇到过这样的困境智能体只能被动响应单次请求无法记住上下文更别提自主规划、执行多步任务了这背后缺失的正是一个能让智能体“思考”和“行动”起来的关键机制——循环架构。本文将深入探讨如何为AI智能体设计和实现其专属的循环架构使其能够像人类一样在感知、思考、行动、学习的过程中不断进化。我们将从零开始构建一个具备自我迭代能力的智能体核心循环涵盖架构设计、代码实现、核心组件拆解以及工程化最佳实践。无论你是对AI Agent充满好奇的初学者还是希望将智能体能力集成到复杂业务中的开发者都能从本文获得一套完整、可落地的解决方案。1. 理解AI智能体与循环架构在深入代码之前我们必须厘清两个核心概念什么是AI智能体以及为什么它需要循环架构。1.1 AI智能体超越简单问答的智能实体AI智能体AI Agent并非一个全新的概念。简单来说它是一个能够感知环境、自主决策并执行行动以实现特定目标的软件实体。与传统的聊天机器人仅完成一轮问答不同一个真正的智能体具备以下关键特征自主性Autonomy能在没有人工直接干预的情况下运行。反应性Reactivity能感知环境变化并及时做出反应。主动性Proactivity不仅对环境做出反应还能主动发起目标导向的行为。社会能力Social Ability能通过某种“语言”与其他智能体或人类进行交互。当前基于大语言模型LLM构建的智能体成为主流。LLM为智能体提供了强大的“大脑”使其能够理解复杂指令、进行推理和生成文本。然而一个裸的LLM只是一个静态的知识库和文本生成器。要让其成为智能体我们必须为其配备“感知器官”如工具调用API、“记忆系统”如向量数据库和“行动机制”如代码执行器而将这些部分有机整合并驱动其持续运行的正是循环架构。1.2 循环架构智能体的“心脏”与“工作流引擎”你可以将循环架构视为智能体的核心控制循环或“心脏”。它定义了智能体如何周而复始地运行其经典范式来源于人工智能领域的感知-思考-行动循环Perception-Thinking-Action Loop。一个典型的智能体循环架构包含以下基本阶段感知Perception接收来自用户、环境或其他系统的输入如自然语言指令、API返回数据、传感器信号。思考Thinking核心处理阶段。智能体利用其“大脑”通常是LLM结合内部状态记忆、目标对输入进行理解、规划和决策。例如决定下一步调用哪个工具或者如何分解复杂任务。行动Action执行决策可能是调用一个外部工具如搜索引擎、数据库、代码解释器生成一段回复或者修改内部状态。观察Observation获取行动的结果并将其作为新的感知输入反馈给下一个循环。这个循环会持续进行直到任务完成或达到终止条件。通过循环智能体能够处理需要多步交互的复杂任务例如“分析本周销售数据并生成报告”或“帮我在网上查找某产品的信息并比价”。2. 环境准备与核心工具选型在开始构建之前我们需要搭建开发环境并选择合适的技术栈。本文将以Python为主要语言因为它拥有最丰富的AI开发生态。2.1 基础环境与Python版本确保你的系统已安装Python。推荐使用Python 3.9或更高版本以获得更好的兼容性和性能。# 检查Python版本 python --version # 或 python3 --version建议使用虚拟环境来管理项目依赖避免包冲突。# 创建虚拟环境 python -m venv ai_agent_env # 激活虚拟环境 # Windows ai_agent_env\Scripts\activate # Linux/macOS source ai_agent_env/bin/activate2.2 核心依赖库安装我们将使用以下核心库来构建智能体LangChain / LangGraph当前构建AI应用和智能体最流行的框架之一。LangChain提供了丰富的组件链而LangGraph专门用于构建有状态的、多步骤的循环应用程序。本文将重点使用LangGraph因为它对循环架构的支持更为直观和强大。OpenAI API我们将使用GPT-4或GPT-3.5-Turbo作为智能体的“大脑”。你需要一个OpenAI的API密钥。可选本地模型如果你希望使用本地部署的模型如Qwen、Llama等可以通过ollama、vLLM或LM Studio等工具并配合LangChain的相应接口。通过pip安装所需依赖pip install langgraph langchain-openai langchain-community # 如果你需要其他工具如网络搜索 pip install duckduckgo-search # 如果需要向量数据库作为记忆 pip install chromadb langchain-chroma2.3 项目结构规划一个清晰的目录结构有助于管理复杂的智能体项目。my_ai_agent_project/ ├── agent_core/ # 智能体核心模块 │ ├── __init__.py │ ├── graph_builder.py # 定义循环图核心 │ ├── nodes.py # 定义循环中的各个节点函数 │ └── state.py # 定义智能体的状态类 ├── tools/ # 工具集 │ ├── __init__.py │ ├── calculator.py │ └── web_search.py ├── memory/ # 记忆模块 │ └── vector_store.py ├── config.py # 配置文件API密钥等 ├── main.py # 主入口文件 └── requirements.txt # 依赖列表3. 循环架构的核心组件拆解构建循环架构本质上是定义一套状态流转规则。在LangGraph中这通过定义State和Nodes并用Graph将它们连接起来实现。3.1 定义智能体状态State状态是智能体在循环中携带和更新的所有信息。我们使用Pydantic的BaseModel来定义一个强类型的State。# agent_core/state.py from typing import TypedDict, List, Annotated import operator from langchain_core.messages import BaseMessage, HumanMessage, AIMessage from langgraph.graph.message import add_messages class AgentState(TypedDict): 智能体的状态定义。 # 消息历史记录所有对话和思考过程 messages: Annotated[List[BaseMessage], add_messages] # 当前用户输入 user_input: str # 智能体思考后的下一步动作决策 next_action: str # 动作执行后的观察结果 observation: str # 任务是否完成 is_finished: bool # 循环次数防止无限循环 iteration_count: intmessages使用add_messages操作符这是一个LangGraph提供的特殊注解能自动将新消息追加到历史列表中极大简化了状态管理。user_input存储当前轮次用户的原始问题。next_action存储LLM决策出的下一步动作如“call_tool: calculator”或“final_answer”。observation存储工具调用或行动后的结果。is_finished标志循环是否应该终止。iteration_count安全阀防止智能体陷入死循环。3.2 构建工具Tools工具是智能体延伸能力的“手脚”。每个工具都是一个函数需要清晰的描述供LLM理解。# tools/calculator.py from langchain.tools import tool import math tool def calculator(expression: str) - str: 执行数学计算。输入一个数学表达式字符串返回计算结果。支持 , -, *, /, **, sqrt, sin, cos 等。 try: # 警告在生产环境中直接eval是危险的应使用安全的表达式解析库如 ast.literal_eval 或 numexpr # 此处为演示简化处理 # 可以添加一个安全表达式检查白名单 allowed_names {k: v for k, v in math.__dict__.items() if not k.startswith(_)} allowed_names.update({abs: abs, round: round}) result eval(expression, {__builtins__: {}}, allowed_names) return f计算结果: {result} except Exception as e: return f计算错误: {e} # tools/web_search.py from langchain.tools import DuckDuckGoSearchRun search_tool DuckDuckGoSearchRun() # 可以包装一下以提供更清晰的描述 tool def web_search(query: str) - str: 使用搜索引擎在互联网上搜索最新信息。当问题涉及实时、未知或特定领域知识时使用。 return search_tool.run(query)3.3 实现循环节点Nodes节点是循环中的每个步骤是一个接收和返回AgentState的函数。# agent_core/nodes.py from langchain_openai import ChatOpenAI from .state import AgentState import os from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage from langchain.tools.render import format_tool_to_openai_function from tools.calculator import calculator from tools.web_search import web_search # 初始化LLM和工具 llm ChatOpenAI(modelgpt-3.5-turbo, temperature0, api_keyos.getenv(OPENAI_API_KEY)) tools [calculator, web_search] # 将工具绑定到LLM使其知道可以调用什么 llm_with_tools llm.bind_functions(functions[format_tool_to_openai_function(t) for t in tools]) def perceive_node(state: AgentState) - AgentState: 感知节点接收用户输入初始化状态。 print(f[感知] 用户输入: {state[user_input]}) # 将用户输入添加到消息历史 new_message HumanMessage(contentstate[user_input]) state[messages].append(new_message) state[iteration_count] 1 return state def think_node(state: AgentState) - AgentState: 思考节点LLM分析当前状态决定下一步行动。 print(f[思考] 第{state[iteration_count]}轮思考...) # 调用绑定了工具的LLM ai_message llm_with_tools.invoke(state[messages]) # 检查LLM是否决定调用工具 if hasattr(ai_message, tool_calls) and ai_message.tool_calls: # 决定调用工具 tool_call ai_message.tool_calls[0] state[next_action] fcall_tool: {tool_call[name]} print(f[决策] 决定调用工具: {tool_call[name]}, 参数: {tool_call[args]}) else: # 决定直接回复最终答案 state[next_action] final_answer print(f[决策] 决定生成最终答案。) # 将LLM的思考消息可能包含工具调用请求存入历史 state[messages].append(ai_message) return state def act_node(state: AgentState) - AgentState: 行动节点执行决策。 action state[next_action] print(f[行动] 执行: {action}) if action.startswith(call_tool:): tool_name action.split(:)[1].strip() # 获取最后一次LLM消息中的工具调用信息 last_ai_msg state[messages][-1] tool_call last_ai_msg.tool_calls[0] # 找到对应的工具并执行 tool_map {tool.name: tool for tool in tools} if tool_name in tool_map: try: observation tool_map[tool_name].invoke(tool_call[args]) state[observation] str(observation) print(f[观察] 工具执行结果: {observation[:100]}...) # 打印前100字符 except Exception as e: state[observation] f工具 {tool_name} 执行出错: {e} else: state[observation] f未知工具: {tool_name} # 将工具执行结果作为观察消息存入历史 tool_message ToolMessage(contentstate[observation], tool_call_idtool_call[id]) state[messages].append(tool_message) elif action final_answer: # 如果是最终答案则标记完成观察结果就是LLM的最后一条回复内容 state[observation] state[messages][-1].content state[is_finished] True else: state[observation] f无法识别的动作: {action} return state def should_continue(state: AgentState) - str: 条件路由函数根据状态决定下一个节点。 if state[is_finished]: return end elif state[iteration_count] 10: # 防止无限循环 print([安全] 达到最大迭代次数强制结束。) return end elif state[next_action] final_answer: # 如果决策是最终答案直接进入结束流程act_node已处理 return end else: # 否则继续循环思考 - 行动 - 思考... return continue4. 组装循环图从组件到完整架构有了状态和节点现在我们可以用LangGraph的Graph对象将它们组装成一个可执行的循环工作流。# agent_core/graph_builder.py from langgraph.graph import StateGraph, END from .state import AgentState from .nodes import perceive_node, think_node, act_node, should_continue def build_agent_graph(): 构建并返回智能体的循环图。 # 1. 创建图并指定状态类型 workflow StateGraph(AgentState) # 2. 添加节点 workflow.add_node(perceive, perceive_node) # 感知 workflow.add_node(think, think_node) # 思考/规划 workflow.add_node(act, act_node) # 行动/观察 # 3. 设置入口点 workflow.set_entry_point(perceive) # 4. 添加边定义流程 workflow.add_edge(perceive, think) workflow.add_edge(act, think) # 行动后回到思考形成循环 # 5. 添加条件边从“think”节点出来根据条件路由 workflow.add_conditional_edges( think, should_continue, # 条件判断函数 { continue: act, # 继续循环 - 去行动 end: END # 结束 - 图终止 } ) # 6. 编译图 graph workflow.compile() return graph # 全局图实例 agent_graph build_agent_graph()这个图定义了以下工作流从perceive感知节点开始接收用户输入。进入think思考节点LLM决定下一步。根据should_continue函数的判断如果“continue”则进入act行动节点执行工具调用执行后自动跳回think节点开始新一轮“思考-行动”循环。如果“end”则流程终止。在act节点中如果动作是final_answer会将is_finished设为True导致下一轮should_continue返回“end”从而结束循环。5. 完整实战运行你的自循环智能体现在让我们将以上所有部分整合创建一个可运行的主程序。5.1 主程序入口# main.py import os from dotenv import load_dotenv from agent_core.graph_builder import agent_graph from agent_core.state import AgentState from langchain_core.messages import HumanMessage # 加载环境变量在项目根目录创建 .env 文件写入 OPENAI_API_KEYyour-key load_dotenv() def run_agent(user_query: str): 运行智能体处理一次用户查询。 print(f\n{*50}) print(f开始处理查询: {user_query}) print(f{*50}) # 初始化状态 initial_state: AgentState { messages: [], # 初始为空perceive_node会添加用户消息 user_input: user_query, next_action: , observation: , is_finished: False, iteration_count: 0, } # 运行图 final_state None # 我们使用流的模式来逐步查看执行过程 for event in agent_graph.stream(initial_state, stream_modevalues): # event 是一个字典key是节点名value是该节点执行后的状态 for node_name, node_state in event.items(): if node_name act: # 可以在这里查看每次行动后的观察结果 print(f\n[系统] 行动节点完成。观察: {node_state[observation][:150]}...) elif node_name __end__: final_state node_state print(f\n[系统] 智能体运行结束。) # 输出最终结果 if final_state: # 从消息历史中提取最终的AI回复 final_messages final_state[messages] for msg in reversed(final_messages): if msg.type ai and not hasattr(msg, tool_calls): print(f\n{*50}) print(最终答案:) print(f{*50}) print(msg.content) break if __name__ __main__: # 测试用例 test_queries [ 计算一下 (15 7) * 3 等于多少, 谁是现在的美国总统, 先搜索一下LangGraph是什么然后用一句话总结。, 请计算圆的面积假设半径是5。然后搜索一下π的最新计算记录。 ] for query in test_queries: run_agent(query) input(\n按Enter键继续下一个示例...)5.2 运行与结果分析在终端中运行python main.py并确保已设置OPENAI_API_KEY环境变量。你将看到类似以下的输出具体内容因模型和搜索实时结果而异 开始处理查询: 计算一下 (15 7) * 3 等于多少 [感知] 用户输入: 计算一下 (15 7) * 3 等于多少 [思考] 第1轮思考... [决策] 决定调用工具: calculator, 参数: {expression: (15 7) * 3} [行动] 执行: call_tool: calculator [观察] 工具执行结果: 计算结果: 66 [系统] 行动节点完成。观察: 计算结果: 66... [思考] 第2轮思考... [决策] 决定生成最终答案。 [系统] 智能体运行结束。 最终答案: 计算结果为 66。对于更复杂的查询“先搜索一下LangGraph是什么然后用一句话总结。”智能体会经历多轮循环感知用户输入。思考后决定调用web_search工具搜索“LangGraph”。行动节点执行搜索获得结果。观察结果被添加到历史。流程回到思考节点LLM结合搜索到的信息决定生成最终答案。行动节点生成答案并标记任务完成。6. 常见问题与排查思路在实现和运行自循环智能体时你可能会遇到以下典型问题。问题现象可能原因排查与解决思路智能体陷入无限循环1.should_continue逻辑有误未正确判断结束条件。2. LLM始终不生成final_answer而是反复调用工具。3. 工具调用结果未能让LLM满意导致其尝试其他工具。1.检查循环终止条件确保is_finished在生成最终答案时被正确设置为True。在act_node中仔细检查final_answer分支。2.增强系统提示词在给LLM的SystemMessage中明确指令例如“如果你认为已经获得足够信息来回答用户问题请直接给出最终答案不要再次调用工具。”3.添加迭代限制正如我们代码中的iteration_count设置一个硬性上限如10次并在should_continue中判断。LLM不调用工具或调用错误工具1. 工具描述不清晰LLM无法理解其用途。2. 工具绑定bind_functions失败或格式不对。3. LLM的temperature参数过高导致决策不稳定。1.优化工具描述确保tool装饰器内的文档字符串docstring精确描述了工具的功能、输入格式和适用场景。2.验证函数绑定打印llm_with_tools的functions属性查看是否成功绑定了目标函数。确保使用了format_tool_to_openai_function进行格式转换。3.调整LLM参数将temperature设为0以获得更确定性的输出。对于复杂任务可以尝试使用能力更强的模型如GPT-4。状态State更新混乱1. 在节点函数中直接修改了传入的state字典但某些字段可能未被正确识别为更新。2.add_messages等操作符使用不当。1.遵循状态更新规范在节点函数中始终返回一个新的字典或AgentState对象包含所有需要更新的字段。LangGraph会自动合并。2.使用TypedDict和注解严格按照我们state.py中的方式定义状态使用Annotated和add_messages等操作符来声明列表的追加行为这是LangGraph推荐的做法。工具执行出错或超时1. 工具函数内部代码有bug。2. 网络工具如搜索因网络问题超时。3. 工具返回的结果格式不符合LLM预期。1.单独测试工具在集成到智能体前先单独编写脚本测试每个工具函数。2.添加异常处理在act_node中调用工具时使用try...except包裹并将错误信息作为observation返回让LLM知道发生了什么。3.设置超时对于网络请求类工具使用requests库时配置timeout参数。图编译或运行时报错1. 节点函数签名不正确未接收或返回AgentState。2. 图中节点或边定义有循环依赖或指向不存在的节点。3. Python依赖版本冲突。1.检查函数签名确保所有节点函数都定义为def node_name(state: AgentState) - AgentState:。2.可视化图结构使用graph.get_graph().draw_mermaid_png()需安装pygraphviz或直接打印graph.get_graph()来检查图的结构是否正确。3.检查依赖使用pip list确认langgraph,langchain等核心库版本兼容。7. 进阶优化与工程最佳实践一个基础的循环架构跑通后我们可以从以下几个方面进行强化使其更健壮、更强大。7.1 记忆系统的增强目前的记忆仅存在于单次对话的messages列表中。对于长对话或需要持久化知识的场景需要引入更强大的记忆。向量数据库长期记忆将重要的对话片段或工具执行结果存入向量数据库如Chroma、Pinecone。在感知节点除了当前输入还可以从向量库中检索相关历史作为上下文。摘要记忆当对话轮次过多时将过长的历史消息总结成一段摘要既保留关键信息又节省Token。分层记忆区分短期工作记忆当前任务相关和长期知识记忆领域知识。7.2 规划与反思机制高级智能体不应只做一步决策。任务分解Planning在think节点让LLM先将复杂任务分解为子任务列表然后循环执行。反思Reflection在行动后增加一个reflect节点让LLM评估行动结果是否有效是否偏离目标并据此调整后续策略。这可以通过在状态中增加criticism或plan字段来实现。7.3 安全与可控性智能体越强大越需要约束。工具使用权限为不同敏感级别的工具设置使用权限并在系统提示词中声明。输入/输出过滤对用户输入和智能体输出进行内容安全过滤防止生成不当内容。人工确认环节对于关键操作如发送邮件、执行数据库写入可以在循环中插入一个“等待人工批准”的节点。7.4 可观测性与调试智能体内部状态是黑盒良好的日志和监控至关重要。结构化日志像我们示例中一样在每个节点打印结构化日志[思考][行动]。可以集成logging模块输出到文件。状态快照在每次循环后将关键状态如next_action,observation保存下来便于事后分析故障。可视化追踪利用LangGraph的内置功能或第三方工具可视化智能体的完整决策路径。7.5 性能优化异步执行如果智能体需要调用多个不依赖的工具可以将act_node改为异步并行执行。缓存对LLM的重复性查询如相同的思考步骤或工具调用如相同的搜索词结果进行缓存减少成本和延迟。流式输出对于最终答案的生成使用LLM的流式响应提升用户体验。构建一个能够自我循环的AI智能体架构是将静态大模型转化为动态、自主、有用助手的关键一步。我们从最核心的感知-思考-行动循环出发利用LangGraph框架实现了状态管理和流程控制并赋予了智能体使用工具的能力。这个过程涉及状态设计、工具封装、节点函数实现和图编排等多个环节。记住一个健壮的智能体离不开清晰的终止条件、完善的错误处理以及深度的记忆与规划能力。你可以在此基础上继续探索多智能体协作、与真实业务系统集成等更复杂的场景。
返回列表