资讯动态

从零构建AI智能体:hermes-agent实战与架构解析

发布时间:2026/9/9 3:04:23 来源:尧图企业网站定制
hermes-agent 这个名字第一眼看上去会以为是某个跟微服务网关有关的项目但实际上它是我最近一直在折腾的一个 AI 智能体Agent系统——用开源大模型搭一个能自己规划任务、调用外部工具、完成闭环操作的自动化助手。项目取名借用希腊神话里信使神 Hermes因为在我看来Agent 最核心的职责就是充当大模型和真实世界之间的“信使”模型负责思考Agent 负责把思考转化成行动再把行动结果带回来。这半年我把它从一个小脚本一路演进成一个带记忆、支持多智能体协作的框架踩了不少坑也沉淀了一些很实在的经验这篇就完整复盘一下。这套东西适合谁两类人。一类是已经玩过 ChatGPT 这类产品、想自己动手做点自动化工具的技术爱好者另一类是已经在用 LangChain 或 AutoGPT但觉得太重、想从零理解 Agent 内部原理的开发者。不需要你有多深的研究背景但最好熟悉 Python 基础语法知道什么是 API、什么是 JSON。下面我会从设计思路、架构选型、实战编码到问题排查完整走一遍。1. 先说清楚hermes-agent 到底解决什么问题很多人第一次接触 Agent会把它理解成“一个更聪明的聊天机器人”。这个理解不算错但远远不够。聊天机器人是你说一句、它回一句信息到了对话就结束了Agent 则是你说一个目标它自己拆解步骤、调用工具、执行操作、检查结果直到把目标完成。差别就像“问服务员有什么菜”和“让服务员根据你的口味把菜点好、催菜、结账”之间的差别。1.1 为什么叫 Hermes智能体本质上是信息的“信使”Hermes 是希腊神话里的信使神负责在奥林匹斯众神和凡人之间传递消息。我觉得这个隐喻特别贴合 Agent 的定位。想象一下大模型是一个大脑但它没有手、没有脚、也看不到外部世界的实时数据搜索引擎、数据库、代码执行器、业务 API 这些东西有手有脚但不懂人类的模糊指令。Agent 站在中间左手接住模型的意图右手去调用工具再把工具的结果翻译成模型能理解的语言。所以 hermes-agent 的设计目标从一开始就不是做一个“更大的模型”而是做一个“更可靠的传话系统”。模型可以换工具可以加但 Agent 这个中间层的稳定性决定了整个系统的上限。1.2 和普通 Chatbot 的区别从“对话”到“行动”用一张表就能看明白 Agent 和 Chatbot 的核心差异维度传统 Chatbothermes-agent 这类智能体交互模式单轮问答或闲聊多轮任务执行与反馈记忆范围当前会话上下文短期上下文 长期向量记忆外部能力基本没有可调用搜索、代码、API 等工具输出形式文本回复文本回复 实际行动失败处理换个说法再答一次自主重试、换工具、拆解子任务举一个我实际用到的例子。我每周要整理一份竞品动态简报以前的做法是打开好几个网站、复制粘贴、然后自己写摘要。现在用 hermes-agent我的指令就是一句“帮我整理本周竞品动态按功能更新、价格调整、市场活动三类输出”。它会自己去搜索、抓取页面、用模型做摘要、分类、然后生成 Markdown 文件放到指定目录。中间我没有做任何手工干预。这就是“从对话到行动”的意思。模型负责理解和生成Agent 负责让这些理解和生成落地。1.3 这套方案适合什么场景基于我这半年的实践hermes-agent 的架构比较适合三类场景信息聚合类舆情监控、竞品分析、新闻摘要、周报生成。核心是搜索 抓取 总结。自动化操作类定时任务调度、文件整理、数据清洗、报表生成。核心是代码执行 文件操作。个人助理类日程管理、邮件草拟、知识库问答。核心是多工具协同 长期记忆。不太适合的场景是那些需要高并发、低延迟、强一致性的生产级业务系统。Agent 的推理过程天然带有不确定性你可以把它当作一个聪明的实习生但暂时还不能当成一个可靠的线上服务。2. 整体架构设计与关键决策如果你只是用现成的 Agent 框架其实不用关心架构但如果你想自己写一个或者想理解框架内部发生了什么架构设计就是第一步。我前后重构了三版最终沉淀下来的结构很清晰。2.1 Agent 的核心循环感知-规划-行动-观察整个 hermes-agent 的引擎就是一个循环学术上叫 ReActReasoning Acting。循环一共四步感知接收用户指令并把自己的记忆、可用工具列表都拼进提示词里。规划让模型分析当前情况决定这一步是要调用工具、还是直接回答。行动如果模型决定调用工具Agent 解析出工具名和参数执行工具函数。观察把工具的返回结果作为新的上下文喂回给模型让它判断任务是否完成。这个循环会一直重复直到模型认为任务已经完成或者达到设定的最大步数。我当初选择 ReAct 而不是别的方法原因很简单它的逻辑足够朴素每一步都留有人工介入的空间。你可以在任何一轮循环里打印出模型的思考过程清楚地看到它为什么决定调用这个工具、传了什么参数。这一点对于调试来说太重要了。相比之下一些基于复杂图编排的方案虽然理论上更强但出了问题很难定位。2.2 模型选型为什么选择 Hermes 系开源模型项目叫 hermes-agent模型我也优先选了 Nous Research 出的开源 Hermes 系列。理由不是情怀而是实测出来的Hermes 系列模型在 function calling函数调用和工具选择上做得很稳尤其是在显式格式遵循方面比同尺寸的不少开源模型都要可靠。不过我要说清楚hermes-agent 并不绑定某个模型。我采用 OpenAI 兼容的接口规范来做模型适配层这样后面不管接 OpenAI、Anthropic、智谱、还是本地 Ollama 部署的开源模型都只是改一下 base_url 和 model_name 的事。实际使用中如果你的机器能跑得动Hermes 3 70B 或者 Qwen 系列的大参数版本效果会更好如果只是本机体验7B 到 8B 级别的量化模型也够用。选模型的核心指标有三个指令遵循能力能不能严格按系统提示词工作不乱说话。工具调用能力能不能在需要时输出结构化工具调用请求而不是用自然语言假装调用。上下文长度至少要能处理 8K 以上的上下文否则多轮工具调用很容易溢出。2.3 工具层设计如何让模型安全地调用外部能力工具层是整个 Agent 最危险、也最关键的部分。危险在于你把模型的输出直接变成代码执行或 API 调用如果模型被恶意提示词诱导可能会执行危险操作。关键是你必须给工具调用设一道防火墙。我做了三层防护第一层是工具白名单。Agent 只能调用你在代码里显式注册过的工具任何未注册的函数都不可能被调用。这意味着模型最多只能搞砸你允许它搞砸的事情。第二层是参数校验。模型的输出是 JSON 字符串你不能直接拿它去执行。我习惯用 Pydantic 对工具参数做类型校验和范围校验比如路径参数必须限制在某个目录内、数字参数必须大于 0。校验失败就返回错误信息给模型让它重新生成参数而不是直接抛异常中断。第三层是敏感操作双重确认。对于删除文件、发送邮件、执行 shell 命令这类不可逆操作我会在工具函数里加一个require_confirmTrue的标记。Agent 执行到这一步时不是直接执行而是先把操作意图打印出来等人工确认。这样既保留了自动化能力又控制了风险。2.4 记忆与上下文管理Agent 跑几轮之后最头疼的问题就是上下文爆炸。一次工具调用的结果可能就有几千 token十轮下来上下文就满了。我试过几套方案最终采用的是“短期窗口 长期向量检索”的混合记忆。短期记忆就是一个滑动窗口只保留最近 N 轮对话和工具调用记录。更早的内容会被压缩成摘要摘要的 token 数远小于原始内容但能保留关键信息。长期记忆则是把重要的用户偏好、历史任务结论、常用代码片段等用嵌入模型转成向量存入本地向量库。每次任务开始前先做一次相关性检索把最相关的几条记忆注入系统提示词。这样做的好处是Agent 不会忘记三天前你告诉过它的偏好也不用把所有历史都塞进上下文里。3. 实操从零搭建一个可运行的 hermes-agent理论部分说再多都不如跑一个真东西来得直接。下面是我目前这套代码的精简版本去掉了很多装饰性的细节保留了核心骨架。你可以跟着一步步敲半小时内就能在本地跑起来。3.1 环境准备与依赖安装我用 Python 3.10 以上版本配合一个虚拟环境。先把项目目录建好然后安装依赖。mkdir hermes-agent cd hermes-agent python3 -m venv venv source venv/bin/activate需要安装的库不多核心就四个openai镜像接口调用、pydantic参数校验、rich终端美观打印、tiktokentoken 估算。pip install openai pydantic rich tiktoken如果你用的是本地 Ollama确保已经启动了服务并且拉取了一个支持工具调用的模型比如hermes3:8b或qwen2.5:7b。Ollama 本身暴露的是 OpenAI 兼容接口所以代码不需要做额外适配。3.2 定义 Agent 核心数据结构我习惯把 Agent 的输入输出定义成标准的数据类而不是到处用裸字典。这样后续加字段、做校验都方便。from dataclasses import dataclass, field from typing import Optional dataclass class ToolCall: 模型请求调用的工具 name: str arguments: dict dataclass class AgentMessage: Agent 内部流转的消息 role: str # system / user / assistant / tool content: str tool_calls: Optional[list[ToolCall]] None tool_call_id: Optional[str] None dataclass class AgentConfig: Agent 配置 model: str hermes3:8b base_url: str http://localhost:11434/v1 api_key: str ollama max_steps: int 15 temperature: float 0.3 system_prompt: str 你是一个任务执行助手请严格按用户指令完成任务。这里的base_url和api_key是我的环境配置。如果你是接 OpenAI 服务就改成官方地址和自己的 key接国内厂商就改成对应平台的地址。这个设计让我在不同模型之间切换几乎零成本。3.3 实现工具注册与 function calling工具注册是 Agent 的“能力清单”。我写了一个装饰器把普通函数变成可被模型调用的工具。import inspect import json TOOL_REGISTRY {} def tool(name: str, description: str, parameters: dict): 注册一个可被 Agent 调用的工具 def decorator(func): TOOL_REGISTRY[name] { function: func, description: description, parameters: parameters, } return func return decorator def get_tool_schemas() - list[dict]: 生成 OpenAI 格式的 tools 参数 schemas [] for name, meta in TOOL_REGISTRY.items(): schemas.append({ type: function, function: { name: name, description: meta[description], parameters: meta[parameters], } }) return schemas下面注册一个加法工具和一个当前时间工具作为示例import datetime tool( nameadd_numbers, description计算两个数字的和用于数学运算, parameters{ type: object, properties: { a: {type: number, description: 第一个加数}, b: {type: number, description: 第二个加数}, }, required: [a, b], } ) def add_numbers(a: float, b: float) - str: return json.dumps({result: a b}) tool( nameget_current_time, description获取当前的日期和时间, parameters{ type: object, properties: {}, } ) def get_current_time() - str: return json.dumps({now: datetime.datetime.now().isoformat()})注意工具描述和参数描述一定要写清楚。这个对模型来说就是操作手册写得太模糊模型就会乱传参数。3.4 实现主循环主循环是 Agent 的心脏。我用 OpenAI 的 Chat Completions 接口开启工具调用支持然后反复执行“模型思考-工具调用-结果返回”的过程。from openai import OpenAI class HermesAgent: def __init__(self, config: AgentConfig): self.config config self.client OpenAI( base_urlconfig.base_url, api_keyconfig.api_key, ) self.messages [{role: system, content: config.system_prompt}] def run(self, user_input: str) - str: self.messages.append({role: user, content: user_input}) for step in range(self.config.max_steps): print(f 第 {step 1} 步请求模型...) resp self.client.chat.completions.create( modelself.config.model, messagesself.messages, toolsget_tool_schemas(), temperatureself.config.temperature, ) msg resp.choices[0].message self.messages.append({ role: assistant, content: msg.content or , tool_calls: [ { id: tc.id, type: function, function: { name: tc.function.name, arguments: tc.function.arguments, }, } for tc in (msg.tool_calls or []) ], }) # 没有工具调用说明模型准备直接回答 if not msg.tool_calls: return msg.content or 无响应 # 逐个执行工具调用 for tc in msg.tool_calls: name tc.function.name args_text tc.function.arguments print(f 工具调用: {name}({args_text})) if name not in TOOL_REGISTRY: result json.dumps({error: f未知工具 {name}}) else: try: args json.loads(args_text) if args_text else {} func TOOL_REGISTRY[name][function] result func(**args) except Exception as e: result json.dumps({error: str(e)}) self.messages.append({ role: tool, tool_call_id: tc.id, content: result, }) raise RuntimeError(f超过最大步数 {self.config.max_steps}任务未完成)这个循环大约 60 行但已经具备了一个 Agent 的完整骨架。你跑一下试试if __name__ __main__: agent HermesAgent(AgentConfig()) response agent.run(现在几点了然后帮我算一下 123 加 456 等于多少) print(response)预期输出是这样一串过程模型会先后调用get_current_time和add_numbers两个工具最后给出整合后的答案。打印出来的 step 信息能让你看到模型每一步的决策过程——这就是 ReAct 循环的可解释性来源。3.5 加一层轻量记忆主循环跑通之后第一个痛点就是“失忆”。你在同一会话里让它做什么它记得但第二天再开新会话什么都忘了。轻量解法是把历史对话摘要落盘。import os from pathlib import Path class DraftMemory: 极简文件记忆把历史对话摘要存成 Markdown 文件 def __init__(self, memory_dir: str memory): self.memory_dir Path(memory_dir) self.memory_dir.mkdir(exist_okTrue) def save(self, title: str, content: str): safe_name title.replace(/, _).replace( , _)[:30] path self.memory_dir / f{safe_name}.md path.write_text(content, encodingutf-8) def load_recent(self, limit: int 5) - str: files sorted(self.memory_dir.glob(*.md), keylambda p: p.stat().st_mtime, reverseTrue)[:limit] return \n\n.join(f# {p.stem}\n{p.read_text(encodingutf-8)} for p in files)然后在run开始时把load_recent()的结果注入 system promptAgent 就拥有了跨会话的“长期记忆”。这一步对体验的提升非常明显相当于从“金鱼记忆”升级到“笔记本记忆”。4. 进阶玩法从单 Agent 到多 Agent 协作把单个 Agent 跑通只是第一步。我真正觉得 hermes-agent 变得强大是在实现多 Agent 协作之后。单个 Agent 就像一个全能型员工什么都会一点但一遇到需要并行处理或多步骤长流程的任务就会变得又慢又容易出错。多 Agent 协作则像组建了一个团队。4.1 Hermes 作为“信使总线”在多 Agent 架构里我把 HermesAgent 这个主实例改造成一个“信使总线”。它不再直接执行所有工具而是把任务拆解后分发给各个子 Agent再回收子 Agent 的执行结果。关键在于主 Agent 的工具注册表里每一项“工具”指向的是一个子 Agent 的入口函数。把子 Agent 的run方法封装成一个工具函数整个过程就串起来了。from dataclasses import dataclass dataclass class SubAgentSpec: name: str description: str agent: HermesAgent class AgentBus: 信使总线负责注册和调度子 Agent def __init__(self, config: AgentConfig): self.config config self.sub_agents {} def register(self, spec: SubAgentSpec): self.sub_agents[spec.name] spec # 动态注册为工具参数固定为一个 task 字段 tool( namespec.name, descriptionspec.description, parameters{ type: object, properties: { task: {type: string, description: 需要该子 Agent 完成的任务描述} }, required: [task] } )(spec.agent.run) def get_summary(self) - str: return \n.join(f- {name}: {spec.description} for name, spec in self.sub_agents.items())你可能会问这不就是工具调用的变体吗对本质上就是。但“子 Agent”和“普通工具”有一个关键区别子 Agent 有自己的专用系统提示词、专用工具集和专用记忆。整理资料类的任务丢给“搜索 Agent”数据计算类的任务丢给“代码 Agent”每个子 Agent 都在自己的专业上下文里工作效果远好于一个万能 Agent 临场切换角色。4.2 子 Agent 注册与路由我在实际项目里注册了三个常用子 Agent搜索 Agent、代码 Agent、读写 Agent。每个都有自己的职责边界。搜索 Agent负责网络搜索、网页抓取、摘要提炼系统提示词里强调“只返回经过验证的事实”。代码 Agent负责写代码、执行代码、返回结果工作在沙箱目录里禁止删除文件。读写 Agent负责读取本地文档、整理笔记、生成 Markdown 报告。注册代码长这样def build_specialized_agent(system_prompt: str, config: AgentConfig) - HermesAgent: cfg AgentConfig( modelconfig.model, base_urlconfig.base_url, api_keyconfig.api_key, system_promptsystem_prompt, ) return HermesAgent(cfg) bus AgentBus(AgentConfig()) bus.register(SubAgentSpec( namesearch_agent, description搜索并总结实时信息输出事实摘要, agentbuild_specialized_agent(你是一个信息搜索专家。你的任务是通过搜索获取最新信息并输出整合后的摘要。, AgentConfig()), )) bus.register(SubAgentSpec( namecode_agent, description编写并执行 Python 代码处理计算和数据问题, agentbuild_specialized_agent(你是一个谨慎的代码执行专家。只执行必要的代码不进行任何破坏性操作。, AgentConfig()), ))主 Agent 收到一个复杂任务时会先在大脑里规划然后把子任务分发给对应的子 Agent。比如“查一下最近的 AI 新闻然后整理成表格文件”——它可能会先派搜索 Agent 去收集新闻再派读写 Agent 去生成文件。4.3 一个具体例子让 Agent 帮你整理一周数据报表我之前做过一个演示任务让 Agent 读取目录下的日志文件统计错误数量然后写一份周报。单 Agent 也能做但会很吃力因为既要理解文件结构又要做数据统计还要写报告每一步都在切换上下文。多 Agent 的方式是这样进行的主 Agent 收到指令“统计 logs 目录下近 7 天的错误日志数量输出一份周报 Markdown 文件”。主 Agent 规划后先派读写 Agent 去读取 logs 目录结构了解有哪些日志文件。读写 Agent 返回文件列表后主 Agent 派代码 Agent 去写一段 Python 脚本做统计。代码 Agent 返回统计结果主 Agent 再派读写 Agent 把结果格式化成周报文件。主 Agent 最后输出总结告诉你文件生成在哪个路径。整个过程里每个子 Agent 专注于自己的那一小步主 Agent 负责把步骤串联起来。这就像一个项目经理在协调组员而不是一个人干所有活。5. 真实运行中踩过的坑与排查技巧代码跑通只是开始真正考验工作量的是让 Agent 在真实场景里稳定运行。下面这些坑全是我实际踩过的有些在官方文档里根本找不到。5.1 工具调用失败模型返回了不存在的函数名这是最初的坑率最高的问题。模型可能因为提示词写的工具说明不清晰或者模型本身在 function calling 上训练不足输出了一个没有注册过的工具名。一旦出现这种情况Agent 就会卡在“我调用了某个工具但没有人响应”的状态。我的解决办法是双管齐下。首先在提示词里明确强调“只能使用给定的工具禁止编造工具名”其次在代码里对未知工具名做兜底处理返回明确错误消息让模型知道“这个工具不存在请换一个”。if name not in TOOL_REGISTRY: result json.dumps({error: f未知工具 {name}。可用工具: {list(TOOL_REGISTRY.keys())}})这个兜底在排查时特别有用因为模型一旦看到可用的工具列表绝大多数情况下会自己纠正。5.2 上下文溢出对话一长就“失忆”这是 Agent 项目绕不开的痛。每轮工具调用都会往消息列表里追加一条 assistant 记录和一条 tool 记录十轮下来就可能上万 token。开源模型在 8K 到 32K 上下文中还能维持一定质量一旦超出就会被截断Agent 开始“忘记”最初的指令。我的做法是给消息列表加一个“压缩策略”当累计 token 数超过阈值时把中间轮次的对话发给模型生成摘要替换成一条 system 摘要消息。def compress_messages(self, messages: list[dict]) - list[dict]: # 简单的压缩超过 6000 token 就触发 estimated_tokens sum(len(m.get(content, )) len(str(m.get(tool_calls, ))) for m in messages) // 4 if estimated_tokens 6000: return messages # 把最旧的一半消息合并成摘要 half len(messages) // 2 to_compress messages[:half] keep messages[half:] summary_resp self.client.chat.completions.create( modelself.config.model, messages[ {role: system, content: 请把下面的对话历史浓缩成 200 字以内的摘要保留关键事实、用户意图和已完成的工具结果。}, *to_compress, ], temperature0.0, ) summary summary_resp.choices[0].message.content return [{role: system, content: f[历史摘要] {summary}}, *keep]压缩不是免费的摘要本身会丢信息但总比完全失忆好。5.3 循环失控Agent 陷入无限重试有一段时间Agent 会在某个工具报错之后反复调用同一个工具就像一个死循环。原因很典型工具返回了错误消息模型想通过重试来修复但错误的根源没有被修正于是越试越乱。给循环加“重试熔断”非常有用。我在工具结果里附加一个计数器同一工具连续失败三次后模型会被强制要求停下反思替代方案。另外在主循环里可以设定max_steps上限到了就主动终止并把当前状态输出出来供人工分析。# 在工具结果中加入失败计数 failure_counts[name] failure_counts.get(name, 0) 1 if failure_counts[name] 3: result json.dumps({error: f工具 {name} 连续失败请停止调用并改用其他方法})这个思路跟搜索引擎的熔断机制类似不是所有故障都应通过重试解决有时候停下来才是最快的修正。5.4 参数校验数字参数被模型“幻觉”成字符串这个坑非常隐蔽。注册 add_numbers 工具时你定义了参数a和b类型是 number但有些模型返回的 JSON 里面是a: 3.14把数字放在字符串里。Python 的函数定义a: float并不会自动把字符串转成浮点数直接执行3.14 2就会炸。我的解法是统一做一次“宽容解析”把参数值里的数字字符串转成真正的 float 或 int其他类型原样保留。def coerce_args(args: dict, schema: dict) - dict: props schema.get(properties, {}) coerced {} for key, value in args.items(): if key not in props: continue expected props[key].get(type, ) if expected number: try: coerced[key] float(value) except (TypeError, ValueError): coerced[key] value elif expected integer: try: coerced[key] int(float(value)) except (TypeError, ValueError): coerced[key] value else: coerced[key] value return coerced这样处理之后工具函数的参数就很少因为类型问题崩了。5.5 快速排查速查表我把平时最容易遇到的几个问题整理成了速查表方便后续开发时快速定位现象可能原因排查方法解决建议模型不断调用不存在的工具工具 schema 描述不清晰打印 messages 看模型收到什么补充工具描述兜底返回错误任务进行到一半就停止上下文被截断检查 estimated_tokens加摘要压缩策略工具调用陷入死循环错误没有针对性反馈打印失败计数连续失败三次强制熔断参数类型报错模型输出字符串数字观察工具调用 logs做宽容类型转换模型忽略系统提示词上下文太长老指令被淹没检查 system 消息位置把关键约束重复放在 user 消息里Agent 生成结果不准确工具返回值过长被截断检查 tool 消息内容工具返回前先做截断和摘要5.6 一个真实调试案例最后分享一个真实调试过程。有个用户反馈说让 Agent 查“北京今天天气”的时候它一直不调用天气工具反而自己编了一个温度回答。我第一反应是工具注册有问题于是打印了工具列表发现天气工具根本没注册上。排查后发现问题出在注册顺序上天气工具的注册代码放在主循环已经运行之后也就是说工具是“运行时后添加”的而get_tool_schemas()在第一次请求时已经生成了旧的 schemas 列表。模型压根不知道有天气工具当然只能编造。解决办法在每次请求前动态调用get_tool_schemas()而不是缓存结果。如果你的 Agent 支持热加载插件一定要确保 schema 生成是即时性的。这个案例的教训是Agent 的“幻觉”很多时候其实是你代码逻辑的 bug 造成的假象。模型不懂的东西它只能编。6. 一些个人体会与后续扩展方向如果你坚持看到了这里应该已经对 Agent 的底层原理、核心代码和常见坑都有了比较完整的认识。最后分享几条带点个人色彩的经验。我最大的体会是Agent 的能力上限几乎完全由工具质量和上下文的组织方式决定而不是模型参数大小。同一个 7B 模型配上一套设计良好的工具系统能完成的事情远超裸跑一个 70B 模型。这就像给一个实习生配上全套办公软件和详细手册他的产出可能比一个什么工具都没有的资深员工还要好。另一个体会是调试 Agent 要有耐心而且要善用日志。我习惯在每一步都打印模型返回的原始 JSON、工具参数和执行结果看起来啰嗦但每一次问题定位都离不开这些细节。Agent 跟传统程序最大的不同在于它会在你不知道的地方做出意想不到的决定——日志是你唯一能回溯它思考路径的线索。后续的扩展方向我目前的工作重点主要有三个。第一把长期记忆从简单的文件存储升级成向量数据库让记忆检索更精准。第二给子 Agent 之间加一层“反馈回路”让子 Agent 之间可以互相质疑和验证结果而不是只靠主 Agent 单向调度。第三把工具调用结果做结构化的缓存避免同一份数据被反复抓取加快执行速度。这个项目我还会继续迭代下去。如果你也在折腾自己的 Agent或者对 Hermes 系列模型有什么实战心得很期待交流。毕竟Agent 这个领域发展太快闭门造车是最容易落后的事情。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价