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

资讯详情

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

从零构建智能体:Hermes Agent架构、工具集成与自我改进机制详解

从零构建智能体:Hermes Agent架构、工具集成与自我改进机制详解 1. 从“工具”到“伙伴”重新认识 Hermes Agent如果你最近在关注AI领域尤其是AI Agent智能体的动向大概率会听到“Hermes Agent”这个名字。它不像ChatGPT那样直接面向大众聊天也不像Midjourney那样专注于图像生成。Hermes Agent更像是一个藏在幕后的“全能工程师”或“超级助理”它的核心目标是让你用自然语言描述一个复杂任务它就能自主规划、调用工具、执行并完成它。想象一下你不再需要记住复杂的API接口、编写繁琐的脚本或者在不同的软件间来回切换。你只需要告诉它“帮我分析一下上周的销售数据找出表现最好的三个产品生成一份带图表的PPT报告并通过邮件发给项目组。” Hermes Agent 就能理解你的意图分解步骤调用数据分析工具、PPT生成器、邮件客户端一气呵成地完成任务。这听起来像是科幻但 Hermes Agent 正在让这一切成为可编程的现实。我最初接触它时也以为这不过是另一个包装了GPT接口的“玩具”。但深入使用后我发现它的设计哲学截然不同。许多AI工具是“问答式”的你问它答交互结束。而 Hermes Agent 是“任务驱动式”的它被设计成一个可以持续运行、拥有记忆、能够自我规划和改进的自主智能体。它的名字“Hermes”赫尔墨斯取自希腊神话中的信使之神寓意着信息与任务的传递与执行非常贴切。那么谁需要关注 Hermes Agent我认为有三类人开发者与工程师希望将AI能力深度集成到自己的工作流或产品中实现自动化。数据分析师、产品经理等知识工作者渴望一个能理解业务、操作软件、处理信息的AI副驾解放重复性劳动。AI技术爱好者希望亲手搭建和调教一个属于自己的、具备特定技能的AI智能体。本文将带你从零开始深入 Hermes Agent 的核心。我们不会停留在简单的API调用而是会拆解它的架构设计手把手完成环境设置与核心配置深入探讨如何为它赋予和扩展技能Tools并最终触及它最迷人的部分——自我改进Self-Improving机制。你会发现构建一个强大的Agent不仅是技术集成更是一场关于如何与AI协作的思维革命。2. 搭建你的第一个 Hermes Agent环境、配置与核心概念在开始编写任何代码之前我们需要一个稳固的基础。Hermes Agent 的搭建并不复杂但理解其核心组件和正确的配置方式是避免后续无数坑的关键。2.1 核心依赖与初始化环境Hermes Agent 通常构建在大型语言模型LLM之上因此你的第一项投资是选择一个合适的LLM服务。OpenAI的GPT-4系列无疑是第一梯队的选择在复杂逻辑推理和长上下文理解上表现优异。对于希望控制成本或需要更高隐私性的场景开源模型如 Claude 3通过Anthropic API、DeepSeek 或本地部署的 Llama 3 70B 也是可行的选项但需要对其在工具调用和指令遵循方面的能力进行充分评估。我的建议是在开发初期优先使用 GPT-4 Turbo 或 GPT-4o。它们在工具调用Function Calling方面的稳定性和准确性能让你更专注于Agent逻辑本身而非与模型的不确定性作斗争。接下来是环境准备。假设我们使用Python一个干净的虚拟环境是必须的。# 创建并激活虚拟环境 python -m venv hermes_env source hermes_env/bin/activate # Linux/macOS # hermes_env\Scripts\activate # Windows # 安装核心库。注意Hermes Agent 可能是一个项目代号或特定实现 # 这里我们以基于流行框架如 LangChain, AutoGen 或自定义为例。 # 假设我们使用一个简化的自定义框架结构核心需要 pip install openai anthropic # LLM 提供商SDK pip install langchain langchain-openai langchain-anthropic # 可选但强烈推荐用于快速构建 pip install python-dotenv # 管理环境变量最关键的一步是配置你的API密钥。永远不要将密钥硬编码在代码中。创建一个.env文件在你的项目根目录OPENAI_API_KEYsk-your-openai-key-here ANTHROPIC_API_KEYyour-claude-key-here # 其他API密钥...然后在你的主程序或配置模块中加载from dotenv import load_dotenv import os load_dotenv() openai_api_key os.getenv(OPENAI_API_KEY)2.2 理解 Hermes Agent 的核心架构模块在写代码前我们必须像建筑师看蓝图一样理解 Hermes Agent 的思维和运作模块。一个典型的 Hermes Agent 包含以下几个核心部分它们共同构成了一个“感知-思考-行动”的循环大脑LLM Core这是Agent的决策中心。它接收来自“感知”模块的信息用户指令、记忆、当前状态进行推理和规划然后决定下一步是“思考”还是“行动”。它负责生成最终回复和工具调用请求。记忆MemoryAgent不是金鱼它需要记住过去。记忆分为几种对话历史Conversation Memory记住当前会话中用户和AI的所有交互。这是最基本的短期记忆。长期记忆Long-term Memory通常通过向量数据库如Chroma, Pinecone, Weaviate实现。Agent可以将重要的信息、执行结果或学习到的经验存储到这里并在需要时通过语义搜索召回。这是实现“自我改进”和持续学习的基础。摘要记忆Summary Memory对于超长对话将历史压缩成摘要避免上下文窗口爆炸。技能库Tools / Skills这是Agent的“双手”。一个工具就是一个Python函数它封装了某个具体能力比如“搜索网络”、“执行Python代码”、“读写文件”、“发送邮件”。LLM大脑通过“函数调用Function Calling”机制来请求使用这些工具。Agent的能力边界完全由你赋予它的工具集决定。规划器Planner对于复杂任务大脑可能需要先制定一个计划Plan。例如“写一篇博客”可以分解为“1. 确定主题和大纲2. 搜索相关资料3. 撰写引言4. 撰写正文...”。规划器帮助Agent进行任务分解和步骤排序。简单的Agent可能将规划和执行都交给LLM复杂的则会有一个独立的规划模块。执行器Executor负责协调整个循环。它接收用户输入结合记忆调用大脑进行决策。如果大脑决定使用工具执行器就调用对应的工具函数将结果返回给大脑大脑再基于结果进行下一步决策如此循环直到任务完成或达到终止条件。下图展示了这些模块如何协同工作 注此处用文字描述架构图因禁止使用Mermaid用户输入 | v [执行器] - 结合 [记忆]历史长期 | v [大脑/LLM] 进行推理 | v 决策分支 1. 生成最终回答 - 返回给用户并更新[记忆]。 2. 决定使用[工具] - [执行器]调用对应工具。 | v 工具执行结果 | v 返回给[大脑/LLM]进行下一轮推理 - 循环...2.3 初始化你的第一个 Agent 实例现在让我们用代码将上述概念具象化。这里我们使用 LangChain 框架因为它提供了高度模块化的组件能让我们快速搭建原型。import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.memory import ConversationBufferMemory, VectorStoreRetrieverMemory from langchain.agents import initialize_agent, AgentType from langchain.agents import Tool from langchain_community.utilities import SerpAPIWrapper # 示例工具搜索 from langchain_community.llms import OpenAI # 用于简单工具 load_dotenv() # 1. 初始化大脑 - 使用 GPT-4 llm ChatOpenAI( modelgpt-4-turbo-preview, # 或 gpt-4o temperature0, # 对于任务执行低温度更确定性通常更好 api_keyos.getenv(OPENAI_API_KEY) ) # 2. 初始化记忆 - 简单的对话缓冲记忆 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 3. 定义技能工具 # 工具1网络搜索 search SerpAPIWrapper(serpapi_api_keyos.getenv(SERPAPI_API_KEY)) # 需要注册SerpAPI # 工具2计算器一个简单的Python执行器需谨慎使用 def calculator(query: str) - str: 用于执行数学计算。输入应为一个数学表达式字符串。 try: # 警告直接eval有安全风险仅用于演示。生产环境应用ast.literal_eval或专用库。 return str(eval(query)) except Exception as e: return f计算错误: {e} # 将函数封装成LangChain Tool对象 tools [ Tool( nameSearch, funcsearch.run, description当你需要回答关于实时信息、最新事件或未知事实的问题时非常有用。输入应该是一个具体的搜索查询。 ), Tool( nameCalculator, funccalculator, description用于执行数学运算。输入应该是一个清晰的数学表达式例如 3 * 5 2。 ) ] # 4. 创建执行器Agent # 使用 LangChain 的“结构化聊天代理”它非常适合工具调用。 agent_executor initialize_agent( tools, llm, agentAgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verboseTrue, # 打开详细日志可以看到Agent的“思考过程” memorymemory, handle_parsing_errorsTrue # 优雅地处理解析错误 ) # 5. 运行你的第一个Agent response agent_executor.run(请搜索一下今天比特币的价格然后用美元计算如果我持有0.5个比特币总价值是多少) print(response)运行这段代码你会看到控制台输出Agent详细的“思考-行动-观察”链条因为verboseTrue。它可能会先调用Search工具获取比特币价格然后调用Calculator工具进行乘法运算最后组织语言回复你。这就是一个最基础的 Hermes Agent 在工作。注意安全第一上面的calculator工具使用了eval()这在生产环境是极度危险的因为它允许执行任意Python代码。这里仅作演示。在实际项目中你应该使用ast.literal_eval仅支持基本数据结构或更安全的数学表达式解析库如numexpr或者直接限制工具只能调用受信任的API。3. 为 Agent 注入灵魂技能Tools的设计、实现与扩展一个只有聊天能力的Agent是平庸的。Tools技能才是Agent与现实世界交互的桥梁是其实用价值的倍增器。设计良好的工具集能让Agent从“聊天机器人”蜕变为“数字员工”。3.1 工具设计的基本原则与最佳实践设计工具不是简单地把一个函数丢给Agent。你需要站在LLM的角度思考它如何理解和使用这个工具功能单一且明确一个工具只做一件事并且把这件事做到极致。不要设计一个“文件处理器”工具它既能读、又能写、还能改格式。应该拆分成read_file、write_file、convert_file_format三个独立的工具。这降低了LLM的理解难度也提高了系统的可维护性。描述Description至关重要这是工具的灵魂。描述必须清晰、准确并包含使用场景和输入格式示例。LLM完全依赖描述来决定是否以及如何调用工具。反面教材description“处理文件”最佳实践description“从指定文件路径读取文本内容。当你需要获取文档、代码或日志文件中的信息时使用此工具。输入应该是完整的文件路径字符串例如 ‘./documents/report.txt’。仅支持UTF-8编码的文本文件。”输入参数要简单、结构化尽可能使用基本的字符串、数字、布尔值作为参数。如果参数复杂考虑将其拆分成多个工具或者要求输入一个格式清晰的JSON字符串并在描述中说明格式。LLM对结构化数据的生成能力很强。输出结果要稳定、可解析工具应返回字符串结果。如果结果是复杂数据将其转换为清晰、格式化的字符串如JSON、Markdown表格。避免返回可能包含歧义分隔符的纯文本。稳定的输出能让LLM更容易提取关键信息进行下一步推理。错误处理要友好工具内部必须做好异常捕获。当出错时不要抛出Python异常导致整个Agent崩溃而是返回一个清晰的错误信息字符串例如“错误文件 ‘data.csv’ 未找到。请检查路径是否正确。” 这能让LLM理解错误并可能尝试纠正或报告给用户。3.2 实现高级技能以“读写文件”和“执行SQL查询”为例让我们设计两个更实用、也更需要谨慎处理的工具。工具A安全的文件读取器import os from pathlib import Path from langchain.tools import Tool def safe_read_file(file_path: str) - str: 安全地读取指定路径的文本文件内容。 适用于读取代码、配置文件、日志、文档等。 Args: file_path (str): 要读取的文件的相对或绝对路径。 Returns: str: 文件的内容。如果文件不存在、无权限或不是文本文件返回错误描述。 try: path Path(file_path).resolve() # 解析为绝对路径 # 安全检查1防止路径遍历攻击例如 ../../../etc/passwd # 这里假设我们只允许读取项目根目录下的‘data’和‘docs’子目录 allowed_base Path.cwd() / data allowed_base2 Path.cwd() / docs if not (path.is_relative_to(allowed_base) or path.is_relative_to(allowed_base2)): return f错误出于安全考虑只能读取 {allowed_base}/ 或 {allowed_base2}/ 目录下的文件。请求路径{file_path} # 安全检查2检查文件是否存在且是文件 if not path.exists(): return f错误文件不存在于路径{file_path} if not path.is_file(): return f错误路径指向的不是一个文件{file_path} # 安全检查3检查文件大小防止读取超大文件 if path.stat().st_size 1_000_000: # 限制1MB return f错误文件过大{path.stat().st_size} 字节。出于性能考虑仅支持读取小于1MB的文本文件。 # 读取文件 with open(path, r, encodingutf-8) as f: content f.read() return content except UnicodeDecodeError: return f错误文件 {file_path} 似乎不是UTF-8编码的文本文件无法读取。 except PermissionError: return f错误没有权限读取文件{file_path} except Exception as e: return f读取文件时发生未知错误{type(e).__name__}: {e} # 封装成Tool read_file_tool Tool( nameread_file, funcsafe_read_file, description安全地读取文本文件。输入必须是一个明确的文件路径字符串。例如‘./data/sales_report.csv’。注意只能读取项目内‘data/’或‘docs/’目录下的文件且文件大小需小于1MB。 )工具B受限的数据库查询器SQL让Agent直接操作数据库风险极高。一个安全的模式是通过一个受限制的、只读的SQL接口来查询数据。import sqlite3 # 以SQLite为例 import pandas as pd from langchain.tools import Tool # 假设我们有一个只读的数据库连接 DB_PATH ./data/company.db def query_database(sql_query: str) - str: 对预定义的数据库执行安全的只读SQL查询。 仅允许SELECT语句用于数据分析和信息检索。 Args: sql_query (str): 一个SQL SELECT查询语句。 Returns: str: 查询结果以格式化的表格字符串形式返回。如果出错返回错误信息。 # 基础安全检查确保是SELECT语句简单示例生产环境需更严格的解析器 sql_upper sql_query.strip().upper() if not sql_upper.startswith(SELECT): return 错误此工具仅支持执行SELECT查询语句。请提供有效的SELECT查询。 # 可以添加更多安全检查例如禁止某些关键词DROP, INSERT, DELETE, UPDATE等 forbidden_keywords [DROP, INSERT, DELETE, UPDATE, ALTER, CREATE, TRUNCATE] for keyword in forbidden_keywords: if keyword in sql_upper: return f错误查询中包含被禁止的操作关键字 {keyword}。此工具仅用于数据查询。 try: conn sqlite3.connect(ffile:{DB_PATH}?modero, uriTrue) # 以只读模式打开 df pd.read_sql_query(sql_query, conn) conn.close() if df.empty: return 查询成功但结果为空。 # 将DataFrame转换为易于阅读的Markdown表格字符串 return df.to_markdown(indexFalse) except sqlite3.Error as e: return f数据库查询错误{e} except Exception as e: return f执行查询时发生未知错误{type(e).__name__}: {e} # 封装成Tool sql_tool Tool( namequery_database, funcquery_database, description对公司的销售数据库执行只读SQL查询。用于回答关于销售数据、客户信息、产品库存等问题。 输入必须是一个完整的、有效的SQL SELECT语句。 示例1: ‘SELECT product_name, SUM(quantity) FROM sales_2024 GROUP BY product_name ORDER BY SUM(quantity) DESC LIMIT 5;’ 示例2: ‘SELECT COUNT(*) FROM customers WHERE signup_date 2024-01-01;’ 注意仅支持SELECT语句不支持任何数据修改操作INSERT, UPDATE, DELETE, DROP等。 )将这些新工具加入到之前的Agent中tools.extend([read_file_tool, sql_tool]) # 重新初始化Agent载入新工具集 agent_executor initialize_agent(tools, llm, agentAgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verboseTrue, memorymemory)现在你的Agent已经可以回答诸如“读取./data/quarterly_report.md文件总结其主要观点”或者“查询数据库找出上个月销售额最高的产品是什么”这类复杂问题了。3.3 技能扩展模式集成外部API与自定义逻辑工具的威力在于其可扩展性。你可以集成任何Web API。示例集成天气APIimport requests from langchain.tools import Tool def get_weather(city_name: str) - str: 获取指定城市的当前天气情况。 Args: city_name (str): 城市名称例如“北京”、“Shanghai”。 Returns: str: 天气信息摘要。 # 这里使用一个假设的天气API端点实际使用时请替换为真实API如OpenWeatherMap api_key os.getenv(WEATHER_API_KEY) if not api_key: return 错误天气API密钥未配置。 try: url fhttps://api.weatherapi.com/v1/current.json?key{api_key}q{city_name}aqino response requests.get(url, timeout10) response.raise_for_status() data response.json() location data[location][name] temp_c data[current][temp_c] condition data[current][condition][text] humidity data[current][humidity] return f{location}的当前天气{condition}气温{temp_c}°C湿度{humidity}%。 except requests.exceptions.RequestException as e: return f获取天气信息失败网络错误 - {e} except KeyError: return f获取天气信息失败API返回的数据格式异常。 except Exception as e: return f获取天气信息时发生未知错误{e} weather_tool Tool( nameget_weather, funcget_weather, description获取全球主要城市的实时天气信息。输入应该是一个城市名称例如‘伦敦’、‘Tokyo’。 )通过这种方式你可以无限扩展Agent的能力发送邮件、调用云服务API、控制智能家居、生成图像等等。工具集的定义就是Agent能力边界的定义。4. 从“听话”到“聪明”实现 Agent 的自我改进Self-Improving一个只会执行预设工具的Agent是静态的。而一个能“自我改进”的Agent则具备了学习和进化的潜力。这是 Hermes Agent 设计中最具前瞻性的部分。这里的“自我改进”并非指AGI式的自我觉醒而是指Agent能够通过反思Reflection、从结果中学习、以及优化自身提示Prompt或工具使用策略来提升未来任务的表现。4.1 反思Reflection机制让 Agent 学会“复盘”反思是自我改进的基石。其核心思想是在Agent完成一个动作或一系列动作后不是直接结束而是让另一个“审查者”LLM或者是同一个LLM的不同角色对刚才的过程和结果进行评审找出可以改进的地方。实现一个简单的任务后反思假设Agent刚刚完成了一次数据分析并生成了报告。我们可以设计一个critic函数来引导反思。from langchain.prompts import ChatPromptTemplate from langchain.schema import SystemMessage, HumanMessage def reflect_on_task(original_task: str, agent_actions_and_observations: list, final_output: str) - str: 对Agent执行任务的过程进行反思和评价。 Args: original_task: 用户最初的任务描述。 agent_actions_and_observations: Agent的思考、工具调用和观察的历史列表。 final_output: Agent最终给用户的输出。 Returns: str: 反思总结包括做得好的地方和可改进的建议。 # 将历史记录格式化为字符串 history_str \n.join([f- {item} for item in agent_actions_and_observations]) reflection_prompt ChatPromptTemplate.from_messages([ SystemMessage(content你是一个资深的AI智能体性能评估专家。你的任务是分析一个AI智能体执行任务的全过程并提供客观、建设性的反馈以帮助其改进。), HumanMessage(contentf 请分析以下AI智能体的任务执行过程 **原始用户任务** {original_task} **智能体的执行历史** {history_str} **智能体最终给用户的输出** {final_output} 请从以下角度提供反馈 1. **任务理解**智能体是否正确理解了用户意图有无偏差 2. **规划与步骤分解**步骤是否合理、高效有无冗余或缺失的步骤 3. **工具使用**工具选择是否恰当工具输入参数是否正确 4. **结果质量**最终输出是否准确、完整、符合要求 5. **效率与成本**整个过程是否使用了不必要的工具调用增加成本和时间 请给出具体的改进建议。例如“在第一步当用户问及‘销售额’时你直接使用了搜索工具。但我们的数据库中有销售表下次可以优先尝试使用query_database工具这样更快更准确。” ) ]) # 使用一个独立的LLM或同一个LLM的不同配置来生成反思 # 为了区分这里可以使用一个更擅长分析的模型或者设置更高的temperature以激发创造性建议 critic_llm ChatOpenAI(modelgpt-4, temperature0.7) reflection critic_llm.invoke(reflection_prompt.format_messages()).content return reflection # 在Agent执行完一个主要任务后调用反思函数 # 假设我们记录了Agent的运行历史 action_history action_history [Thought: 我需要先搜索比特币价格。, Action: Search[‘比特币当前价格’], Observation: 比特币当前价格为65,000美元。, ...] final_output agent_response reflection_feedback reflect_on_task(查询比特币价值并计算持有量, action_history, final_output) print(反思反馈, reflection_feedback)接下来关键的一步是将这份反思存储到Agent的长期记忆中。这样当下次遇到类似任务时Agent可以检索到这些“经验教训”。4.2 基于向量数据库的长期记忆与经验检索我们需要一个能存储和检索非结构化文本反思、成功案例、失败教训的系统。向量数据库是完美选择。from langchain_community.vectorstores import Chroma from langchain_openai import OpenAIEmbeddings from langchain.schema import Document from langchain.text_splitter import RecursiveCharacterTextSplitter # 初始化嵌入模型和向量数据库 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) persist_directory ./chroma_db # 数据库持久化目录 # 加载或创建向量库 vectorstore Chroma( persist_directorypersist_directory, embedding_functionembeddings ) def store_experience(task_description: str, reflection: str, success_score: float 0.8): 将一次任务执行的经验反思存储到长期记忆中。 Args: task_description: 任务描述用于检索。 reflection: 反思总结文本。 success_score: 本次任务的成功度评分0-1用于后续加权检索。 # 将经验封装为一个文档 experience_text f任务{task_description}\n\n反思与经验{reflection} doc Document(page_contentexperience_text, metadata{success_score: success_score, type: reflection}) # 可以按需对长文本进行分块 text_splitter RecursiveCharacterTextSplitter(chunk_size1000, chunk_overlap200) docs text_splitter.split_documents([doc]) # 存入向量数据库 vectorstore.add_documents(docs) vectorstore.persist() # 持久化到磁盘 print(经验已存入长期记忆。) def retrieve_relevant_experiences(query: str, k3): 从长期记忆中检索与当前任务相关的经验。 Args: query: 当前任务描述或问题。 k: 返回最相关的经验数量。 Returns: list: 相关的经验文档列表。 retriever vectorstore.as_retriever(search_kwargs{k: k}) relevant_docs retriever.get_relevant_documents(query) return relevant_docs # 存储刚才的反思 store_experience(查询加密货币价格并计算持有价值, reflection_feedback) # 当新任务到来时先检索相关经验 new_task 请帮我查一下以太坊的价格并计算0.3个ETH值多少人民币。 past_experiences retrieve_relevant_experiences(new_task) if past_experiences: context_from_memory \n.join([doc.page_content for doc in past_experiences]) # 可以将这些经验作为上下文注入到给Agent的提示词中 enhanced_prompt f以下是从过去类似任务中总结的经验供你参考 {context_from_memory} 现在请执行新任务{new_task} # 使用 enhanced_prompt 作为用户输入传递给Agent通过这种方式Agent不再是“金鱼”它拥有了可积累、可检索的“工作经验库”。4.3 动态提示优化与策略调整自我改进的最终体现是Agent能调整自己的行为。我们可以将反思和经验转化为对Agent核心提示词System Prompt或决策逻辑的微调。方法一在System Prompt中注入经验总结你可以定期例如每100次任务后分析长期记忆中的高频改进建议人工或自动地提炼成几条“行动准则”更新到Agent的System Prompt中。 例如原来的System Prompt是“你是一个有帮助的AI助手。” 更新后可能是“你是一个有帮助的AI助手。请记住以下工作准则1. 当用户询问公司内部数据时优先使用query_database工具而非网络搜索。2. 在生成报告前务必使用read_file工具核对最新的数据源。3. 如果任务涉及多步计算先规划好步骤再执行。”方法二工具优先级动态调整你可以为每个工具维护一个“成功率”或“效率评分”。当检索到相关经验时如果经验指出“工具A比工具B更适合此类任务”可以在本次任务中临时提高工具A的优先级或者在描述中强调它。方法三元认知Meta-Cognition提示在任务开始前让Agent先进行一轮“规划反思”。提示词可以是“在开始之前先回顾一下你过去在类似任务如‘查询数据并计算’中常犯的错误或得到的表扬。基于这些经验你将如何调整本次任务的执行策略” 这相当于让Agent主动调用自己的长期记忆来指导本次行动。实现完整的自我改进循环是一个复杂的系统工程但它为Agent带来了质的飞跃。从一个被动执行命令的工具转变为一个能够从错误中学习、积累最佳实践、并不断优化自身性能的“智能伙伴”。5. 实战演练构建一个能自我优化的数据分析助手让我们将前面所有的知识整合起来构建一个稍微复杂点的项目一个能处理数据分析请求并能从每次分析中学习、优化后续查询的 Hermes Agent。5.1 项目目标与架构设计目标创建一个Agent用户可以用自然语言提出数据分析问题例如“上个月哪个产品的销量增长最快”、“比较Q1和Q2的 regional sales”。Agent需要理解问题并将其转化为正确的数据库查询SQL。执行查询获取数据。对数据进行初步分析和可视化如生成图表描述或简单统计。将分析结果以清晰、易懂的语言呈现给用户。关键在执行后对整个过程进行反思并将“如何将自然语言问题更好地转化为SQL”的经验存储起来用于改进未来的表现。架构组件大脑GPT-4。核心工具query_database安全只读SQL、python_repl用于数据分析和绘图需沙箱环境、read_file读取查询模板或配置文件。记忆ConversationBufferMemory短期对话Chroma向量库长期经验存储。自我改进模块Reflection函数 Experience Storage/Retrieval。5.2 核心实现代码片段import pandas as pd from langchain.agents import create_structured_chat_agent, AgentExecutor from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.tools.render import render_text_description # 1. 定义专用提示词 system_prompt 你是一个高级数据分析助手。你的专长是将用户的数据分析问题转化为精准的SQL查询执行查询并解释结果。 你拥有以下技能 1. query_database: 对公司数据库执行只读SQL查询。这是你获取数据的主要方式。 2. python_repl: 一个安全的Python执行环境你可以用它进行数据清洗、分析和生成图表使用matplotlib/seaborn。注意你生成的图表代码必须包含将图表保存为文件如‘chart.png’的指令并最终告知用户文件路径。 3. read_file: 读取项目内的文档或配置文件。 **工作流程** 1. 首先仔细理解用户的问题确定需要哪些数据。 2. 然后构思SQL查询语句。如果不确定表结构可以先查询‘sqlite_master’表或询问用户。 3. 使用query_database执行SQL。 4. 如果结果需要进一步分析或绘图使用python_repl工具。 5. 最后用简洁专业的语言向用户汇报你的发现并附上任何生成的图表。 **重要原则** - SQL查询必须准确、高效。避免SELECT *除非必要。 - 在Python中处理数据时注意检查数据格式如日期。 - 你的最终输出应该对业务人员友好避免过多的技术术语。 # 2. 创建Agent使用更底层的LangChain方法以获得更多控制 prompt ChatPromptTemplate.from_messages([ (system, system_prompt), MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), # 用于放置Agent的思考过程 ]) # 假设我们已经定义了 tools 列表 [query_database_tool, python_repl_tool, read_file_tool] formatted_tools render_text_description(tools) # 将工具描述格式化为字符串 llm ChatOpenAI(modelgpt-4-turbo-preview, temperature0) agent create_structured_chat_agent(llm, tools, prompt) agent_executor AgentExecutor(agentagent, toolstools, memorymemory, verboseTrue, handle_parsing_errorsTrue) # 3. 执行任务并捕获完整历史 def run_analysis_with_reflection(user_query: str): 执行分析任务并自动触发反思和学习。 print(f\n 处理新任务: {user_query} ) # 在执行前先检索相关经验 past_exp retrieve_relevant_experiences(user_query) if past_exp: experience_context \n.join([f[过往经验] {doc.page_content[:500]}... for doc in past_exp]) enhanced_query f{user_query}\n\n请注意以下过往相关任务的经验总结\n{experience_context} input_for_agent enhanced_query else: input_for_agent user_query # 运行Agent result agent_executor.invoke({input: input_for_agent}) final_answer result[output] # 捕获本次执行的详细历史用于反思 # 注意LangChain的AgentExecutor内部历史需要从回调或中间步骤获取这里简化处理。 # 实际中你可能需要使用Callbacks来记录每一步的Thought/Action/Observation。 action_history [] # 这里应填充从回调中获取的实际历史记录 # 触发反思 reflection reflect_on_task(user_query, action_history, final_answer) print(f\n 本次任务反思 \n{reflection}) # 评估本次任务成功度这里简化可根据结果是否包含错误、用户反馈等来评分 success_score 0.9 if 错误 not in final_answer else 0.3 # 将经验存入长期记忆 store_experience(user_query, reflection, success_score) return final_answer # 4. 示例运行 response run_analysis_with_reflection(请分析一下过去一年每个季度的总销售额趋势并用折线图展示。) print(response)5.3 效果评估与迭代循环运行几次任务后你的向量数据库里就会积累一批“经验”。你可以观察这些经验是否被有效检索和应用。例如如果第一次任务中Agent因为不知道“销售额”对应的字段名而查询失败反思可能会指出“应首先查询数据库模式”。当第二次遇到类似任务时这条经验被检索到Agent可能会先执行一个SELECT * FROM information_schema.tables或PRAGMA table_info(sales);来探查表结构从而成功完成任务。这就是一个微型的“自我改进”循环执行 - 反思 - 存储 - 检索应用 - 更好的执行。你需要不断打磨这个循环中的每一个环节反思的质量反思提示词prompt的设计决定了反馈的深度。经验的检索嵌入模型和检索策略如相似度阈值、元数据过滤决定了相关经验能否被准确召回。经验的利用如何将检索到的经验有效地整合到新的任务执行中是修改提示词还是动态调整工具优先级。这个过程不会一蹴而就但每一点改进都会让你的Agent变得更聪明、更可靠。最终你收获的不仅仅是一个自动化脚本而是一个真正能与你共同成长、不断适应新需求的AI伙伴。
返回列表