这次我们拆一个偏实战的多智能体开发方向Hermes Agent。如果你在搜索“hermes agent 中文官网”“hermes agent 安装”“langgraph 和 langchain 的区别”会发现中文资料非常碎很多内容只讲概念不给能跑起来的代码看完还是不知道怎么动手。这篇教程换一个思路不讲虚的直接从环境准备开始到组装一个可运行的多智能体再到用 LangGraph 做状态管理、条件路由、并行分支、子图最后把它封装成 API 接口。你按顺序把代码跑完手里就有一套最小可用的 Hermes Agent 多智能体骨架后面接 RAG 知识库、接 MCP 工具、接批量任务都能在这个骨架上扩展。先回答几个大家最关心的问题。Hermes Agent 本身不是一个独立的编程语言也不是一个和 LangChain 对立的框架它更偏向于“多智能体开发方案”的统称在具体落地时我们通常用 LangChain 做模型与工具的封装层用 LangGraph 做智能体的状态机和流程编排。这也就解释了为什么搜索“LangGraph 和 LangChain 的区别”会出现大量内容LangChain 提供组件LangGraph 提供流程两者配合才能把多个 Agent 组织成有状态的协作系统。这篇文章适合谁适合已经会写 Python、用过 LLM API但还没系统学过 Agent 编排的开发者。你会在这里跑通一个带回复校验、工具调用、多角色协作的 Agent 系统并且看到它如何作为 API 服务被外部调用。硬件方面如果只是学习编排逻辑纯 CPU 也够用如果需要本地跑模型做效果验证再根据模型大小考虑显存。1. Hermes Agent 多智能体核心能力速览能力项说明项目定位基于 LLM 的多智能体开发方案结合 LangChain 与 LangGraph 完成 Agent 编排主要功能Agent 构建、工具调用、状态管理、条件路由、子图、并行分支、API 封装技术基座LangChain、LangGraph、OpenAI 兼容接口、MCP 工具协议硬件门槛纯编排学习 CPU 可跑本地推理按基础模型规格评估显存是否支持批量任务支持可在 Python 层实现同步/异步批量调用是否支持 API 服务支持可用 FastAPI 或 Flask 包装启动是否支持外挂知识库支持典型做法是接入 RAG 检索链路是否支持 MCP支持通过 MCP 工具协议接入外部能力适合场景客服 Agent、数据分析 Agent、文档问答、自动化工作流、内容生成流水线学习成本中等需要掌握 Python、Pydantic 状态定义、图编排思维从材料来看Hermes Agent 的实战链路可以概括为四个组件模型层、工具层、图编排层、服务层。模型层负责 LLM 调用工具层负责让 Agent 能检索和执行外部动作图编排层用 LangGraph 决定 Agent 的执行顺序和分支服务层负责把整个系统暴露成 HTTP 接口。后面所有代码都在按这个分层思路走。2. 适用场景与使用边界2.1 适合什么场景多智能体不是“为了多而多”它解决的是单个 Agent 难以承载的复杂流程。实践中比较适合这几类多角色协作一个 Agent 负责检索资料另一个 Agent 负责结构化输出第三个 Agent 做最终审核。条件路由根据用户问题类型把请求分发到不同专家 Agent。有状态流程比如客服工单需要记住“用户来自哪个渠道”“历史消息是什么”“当前处理到哪一步”。可回退流程子 Agent 出错后主流程能捕获错误并重试或降级。这些场景的共同特点是有分支、有状态、有多步交互。如果你只是做一个简单的“单轮问答”不需要引入多智能体直接用 LangChain 链式调用或裸 LLM 调用更高效不要为了架构复杂度牺牲维护成本。2.2 不适合什么场景纯单轮翻译、单次文本分类、无状态接口不建议引入完整的多智能体体系。多智能体意味着状态同步成本、调试成本和 token 消耗都会上升。一个流程里如果只有一个决策点那么一个 Agent 加条件判断就解决了。经验判断是流程超过三个节点或者需要多个角色交替处理同一个任务时LangGraph 的价值才开始明显。2.3 安全与合规边界多智能体系统在测试阶段建议使用内部测试数据集避免把真实用户数据和未脱敏的业务数据直接灌入。如果系统涉及人脸、声音、私有文档或版权内容必须确认已获得授权。任何 Agent 生成的代码、脚本或操作指令都不能不经检查直接执行尤其是涉及文件删除、网络请求、支付操作的场景。对外提供服务前要限制接口访问范围并添加鉴权和日志审计。3. Hermes Agent 本地开发环境准备3.1 基础环境检查开发环境建议使用 Python 3.10 或 3.11。LangGraph 对 Python 3.9 以下的版本支持不够友好低版本容易出现类型注解解析问题。你可以先检查当前环境python --version如果版本偏低建议使用 pyenv 或 conda 安装新版本。文章后面涉及的代码都在 Python 3.10 环境下编写。3.2 安装 LangChain 与 LangGraph安装命令很简单直接通过 pip 安装核心包。安装时注意 Python 包不能互相冲突有 conda 环境或者 venv 环境建议单独创建# 创建虚拟环境 python -m venv hermes-env source hermes-env/bin/activate # Windows 使用 hermes-env\Scripts\activate # 安装核心依赖 pip install langchain langchain-openai langgraph fastapi uvicorn requests pydantic如果你需要读取文本文件、做文档切分可以再加装pip install langchain-community langchain-text-splitters安装完成后验证核心包是否可用python -c import langgraph; print(langgraph ok) python -c import langchain; print(langchain ok)3.3 配置模型服务Hermes Agent 的底层模型可以通过 OpenAI 兼容接口接入。你有两种选择一种是用国内大模型开放平台提供的 API另一种是本地部署 vLLM 或 Ollama 服务。无论哪种方式LangChain 层都使用相同的 OpenAI 兼容类来调用。以下是一个标准的模型配置模板import os from langchain_openai import ChatOpenAI os.environ[OPENAI_API_KEY] your-api-key os.environ[OPENAI_BASE_URL] https://your-model-endpoint/v1 llm ChatOpenAI( modelyour-model-name, temperature0.2, max_tokens1024, )代码中的OPENAI_BASE_URL需要替换为你实际的模型服务地址model需要替换为具体的模型名称。如果你用的是本地 Ollama可以设置OPENAI_BASE_URLhttp://127.0.0.1:11434/v1模型名按本地已拉取的模型填写。4. 从零构建第一个 Hermes Agent4.1 先理解 LangGraph 的执行模型LangGraph 的核心思路是把 Agent 流程定义为一个图。节点是执行单元边是执行顺序图被编译后可以反复调用。这个设计让你能清晰看到每个步骤的输入输出而不是把逻辑全塞在一个循环函数里。节点函数接收一个 state 对象经过处理后返回 state 的增量更新。这里的 state 是整个流程图运行期间共享的数据结构所有节点都可以读取和修改。4.2 创建一个带状态的基础 Agent下面是一个最小可运行的 LangGraph Agent。它包含两个节点节点 A 负责调用 LLM 生成回答节点 B 负责对回答做简单校验。这个示例展示了如何在节点函数里读取并修改状态。from typing import Annotated, TypedDict from langgraph.graph import StateGraph, START, END import operator class AgentState(TypedDict): messages: Annotated[list, operator.add] current_step: str answer: str def generate_node(state: AgentState): # 模拟调用模型实际环境可以替换为 llm.invoke() response_text 这是模型返回的回答。 return { messages: [{role: assistant, content: response_text}], current_step: validate, answer: response_text, } def validate_node(state: AgentState): answer state.get(answer, ) if len(answer.strip()) 5: return {current_step: fail} return {current_step: success} graph StateGraph(AgentState) graph.add_node(generate, generate_node) graph.add_node(validate, validate_node) graph.add_edge(START, generate) graph.add_edge(generate, validate) graph.add_edge(validate, END) app graph.compile() result app.invoke({ messages: [{role: user, content: 你好}], current_step: start, answer: , }) print(result)重点看两处。第一状态类使用了Annotated[list, operator.add]表示 messages 字段在多个节点返回时是累积合并而不是覆盖第二current_step是普通字段每次返回会直接覆盖旧值。LangGraph 对这两种状态更新方式的差异要清楚列表型字段适合做消息历史标量字段适合做流程标记。4.3 让 Agent 具备工具调用能力真实场景下Agent 需要调用搜索、数据库查询或计算工具。LangChain 的tool装饰器可以快速把函数包装成工具并让模型决定何时调用。from langchain_core.tools import tool tool def get_temperature(city: str) - str: 根据城市名返回当前温度。 # 这里替换为真实天气 API 调用 return f{city} 当前温度26℃ tools [get_temperature] llm_with_tools llm.bind_tools(tools) def agent_node(state: AgentState): user_query state[messages][-1][content] response llm_with_tools.invoke(user_query) if response.tool_calls: # 实际项目中要执行对应工具并回填结果 tool_result get_temperature.invoke(response.tool_calls[0][args]) return { messages: [{role: tool, content: tool_result}], current_step: tool_executed, } return { messages: [{role: assistant, content: response.content}], current_step: finished, }这里的关键是bind_tools它会让模型在回答中附带工具调用指令而不是直接输出自然语言。你需要实现工具执行逻辑并把执行结果作为新的消息返回给图。5. 多智能体协作实战5.1 多智能体的四种交互模式搜索“多智能体的四种交互模式包括哪些”时常见划分方式是合作模式、竞争模式、层级模式、混合模式。合作模式里多个 Agent 各自处理子任务最终汇总结果竞争模式中多个 Agent 对同一任务给出候选方案由评审 Agent 择优层级模式由一个主控 Agent 负责任务分解和结果汇总子 Agent 只能与主控通信混合模式按需组合前面几种。实际开发中LangGraph 的图结构天然能实现这四种模式合作模式对应并行边或子图合并。竞争模式对应多个候选节点连到同一个评审节点。层级模式对应 Supervisor 节点统一调度。混合模式对应条件路由加分支。5.2 实战研究型 Agent 写作型 Agent下面实现一个典型的多智能体场景一个 Agent 负责检索资料另一个 Agent 负责根据资料写作第三个 Agent 负责审核。三个角色通过共享状态协作。from typing import Annotated, TypedDict from langgraph.graph import StateGraph, START, END import operator class TeamState(TypedDict): query: str retrieved_docs: Annotated[list, operator.add] draft: str final_answer: str review_passed: bool def researcher_node(state: TeamState): # 从知识库或搜索引擎获取资料 docs [f关于 {state[query]} 的参考片段] return {retrieved_docs: docs} def writer_node(state: TeamState): # 把检索结果拼接成初稿 docs_text \n.join(state[retrieved_docs]) return {draft: f初稿{docs_text}} def reviewer_node(state: TeamState): draft state[draft] # 模拟校验正式场景可调用模型评估 if len(draft) 5: return {final_answer: draft, review_passed: True} return {final_answer: 内容不足需要重写, review_passed: False} team_graph StateGraph(TeamState) team_graph.add_node(researcher, researcher_node) team_graph.add_node(writer, writer_node) team_graph.add_node(reviewer, reviewer_node) team_graph.add_edge(START, researcher) team_graph.add_edge(researcher, writer) team_graph.add_edge(writer, reviewer) team_graph.add_edge(reviewer, END) team_app team_graph.compile() result team_app.invoke({ query: 多智能体开发的关键技术, retrieved_docs: [], draft: , final_answer: , review_passed: False, }) print(result[final_answer])这个流程用上了合作模式三个节点顺序执行状态从 query 一路演化到 final_answer。5.3 条件路由与控制流上面的流程是“线性”的真实场景需要根据条件决定下一步走哪个节点。LangGraph 中可以用conditional_edges实现这一点。这里实现一个典型场景用户问题如果是“事实型问题”就走检索节点如果是“创作型问题”就直接让写作节点生成。def route_after_intent(state: TeamState): query state[query] # 实际工程中这里可以用意图分类模型或 LLM 判断 if 是什么 in query or 怎么实现 in query: return researcher return writer team_graph.add_conditional_edges( intent, route_after_intent, { researcher: researcher, writer: writer, }, )条件路由在 LangGraph 里是一个非常常用且核心的能力。你需要先写一个返回字符串的决策函数然后用字典把返回值映射到节点名。5.4 并行分支执行多智能体最实用的能力之一是把互不依赖的任务并行执行。LangGraph 中只要多个节点共用一个前驱节点并且最终汇聚到一个合并节点就形成了并行结构。下面是一个简化示例两个 Agent 同时处理不同类别的子任务from langgraph.constants import Send def fan_out_node(state: TeamState): return [ Send(researcher, {query: state[query], segment: 技术部分}), Send(writer, {query: state[query], segment: 应用部分}), ] def merge_node(state: TeamState): # 汇总两个并行分支的结果 segments state.get(segments, []) return {final_answer: \n.join(segments)}使用Send可以动态构造并行分支这对于按任务切片分发很有效。注意并行分支会把共享状态传到每个子任务子任务必须独立处理自己拿到的字段避免状态互相覆盖。5.5 子图与循环检测当多智能体流程变复杂时不建议把所有节点塞进同一个图。LangGraph 支持子图嵌套内部小团队可以作为一个子图被外部图调用。这种设计便于维护也让流程更清晰。循环方面如果设计中出现“审核不通过则重写”的逻辑你会在图里添加一条从 reviewer 回到 writer 的边这就形成了循环。LangGraph 允许循环边但必须设置最大迭代次数否则可能无限循环。可以在节点外使用计数器字段每次重写时增加一达到阈值就强制跳转到 END。def writer_node(state: TeamState): retry_count state.get(retry_count, 0) return {retry_count: retry_count 1} def should_rewrite(state: TeamState): if not state[review_passed] and state.get(retry_count, 0) 3: return writer return finish这里的核心思路是给循环配置出口。没有出口的循环是常见的 LangGraph 事故现场后面排查章节会专门讲。6. 接口 API 与批量任务集成6.1 用 FastAPI 暴露 Agent 服务多智能体图构建完成后下一步是让它变成一个可以被业务系统调用的 HTTP 服务。FastAPI 是常用选择代码量少天然支持异步。from fastapi import FastAPI from pydantic import BaseModel app FastAPI(titleHermes Agent API) class AgentQuery(BaseModel): message: str session_id: str default class AgentResponse(BaseModel): answer: str session_id: str app.post(/agent/run, response_modelAgentResponse) def run_agent(query: AgentQuery): result team_app.invoke({ query: query.message, retrieved_docs: [], draft: , final_answer: , review_passed: False, }) return AgentResponse( answerresult[final_answer], session_idquery.session_id, ) app.get(/health) def health(): return {status: ok}启动服务uvicorn main:app --host 0.0.0.0 --port 8000对于本地测试--host建议使用127.0.0.1不要默认暴露在公网。服务启动后用浏览器或 curl 验证健康检查接口。6.2 curl 调用示例curl -X POST http://127.0.0.1:8000/agent/run \ -H Content-Type: application/json \ -d {message: 多智能体有哪些交互模式, session_id: test-001}正常返回时你会看到 JSON 格式的回答字段与 AgentResponse 一致。6.3 批量任务调用批量任务的核心思想是把多个请求组成队列逐个或并发执行。这里给出一个使用ThreadPoolExecutor并发调用的示例。并发数要控制避免瞬间打爆模型 API 速率限制。import requests from concurrent.futures import ThreadPoolExecutor, as_completed API_URL http://127.0.0.1:8000/agent/run def call_agent(session_id, message): resp requests.post( API_URL, json{message: message, session_id: session_id}, timeout120, ) resp.raise_for_status() return resp.json()[answer] tasks [ {session_id: 001, message: LangChain 是什么}, {session_id: 002, message: LangGraph 是什么}, {session_id: 003, message: MCP 是什么}, ] with ThreadPoolExecutor(max_workers3) as executor: futures { executor.submit(call_agent, item[session_id], item[message]): item for item in tasks } for future in as_completed(futures): item futures[future] try: result future.result() print(item[session_id], result) except Exception as e: print(item[session_id], failed, repr(e))批量执行时务必记录每个任务的失败状态。建议把任务 ID、请求内容、返回结果、错误信息写入日志或数据库方便重试和排障。6.4 外挂知识库RAG 接入多智能体和 RAG 结合是主流玩法。常见做法是独立维护一个向量检索模块Agent 在回答前先检索相关文档再把文档片段作为上下文交给模型。from langchain_community.vectorstores import FAISS from langchain_openai import OpenAIEmbeddings vectorstore FAISS.load_local( your_vector_index_dir, OpenAIEmbeddings(), allow_dangerous_deserializationTrue, ) def retrieve_docs(question: str, top_k: int 3): docs vectorstore.similarity_search(question, ktop_k) return [doc.page_content for doc in docs]然后在 researcher 节点内部调用retrieve_docs把返回的文档列表写入状态。这里有一个实际工程问题向量索引必须提前构建否则相似性检索无法运行。索引构建时要注意文本切分长度太长会稀释语义太短会切断上下文。6.5 接入 MCP 工具MCP 是一个工具协议层的概念核心作用是用标准格式把外部能力注册给 Agent。多智能体系统里可以让主 Agent 通过 MCP 服务器调用其他智能体或工具服务。实际对接时你需要配置 MCP 服务器的地址、工具名和参数格式。具体工具清单以 MCP 服务端提供的能力为准不同公司部署的 MCP 服务差异较大。7. 资源占用与性能观察7.1 内存与模型资源观察多智能体系统的资源消耗主要来自两个地方LangGraph 框架本身占用很小真正的内存和显存压力来自底层 LLM。如果你使用的是远端 API本地只占少量 Python 内存如果你在本地用 vLLM 或 Ollama 部署模型显存消耗就取决于模型大小和并发数。观察资源占用最简单的方法是在服务运行期间使用nvidia-smi查看显存使用htop或任务管理器查看内存。不同模型、不同上下文长度下的数值差异很大所以这里不给出固定数字建议以你本机实际测试为准。7.2 哪些因素会影响性能上下文长度消息历史越长每次请求的输入 token 越多响应变慢。并行分支数量并行节点可以提升吞吐但多个分支同时调用模型可能触发限流。工具调用次数每次工具调用都会增加一次模型往返延迟成倍增加。重试循环审核不通过进入重写循环会显著增加时间和费用。7.3 如何降低资源占用消息历史裁剪只保留最近 N 条消息或者用摘要代替旧消息。限制最大 token在模型配置中设置max_tokens。控制并行度批量请求时设置 max_workers 为 2 或 3。缓存检索结果相同或相似的问题可以缓存向量检索结果和模型回答。用更小的模型处理分类和意图识别大模型只在生成最终结果时使用。8. 常见问题与排查方法问题现象可能原因排查方式解决方案安装 LangGraph 后 import 报错Python 版本过低或包冲突执行python --version查看pip list升级到 Python 3.10重建虚拟环境API 调用报 401 或 403API Key 错误或权限不足检查环境变量查看模型服务控制台重新配置OPENAI_API_KEY确认接口权限langgraph编译时报无效的边节点名拼写错误检查add_edge的字符串参数确保节点名和 add_node 中的名称一致条件路由节点不生效决策函数返回值与字典 key 不匹配打印决策函数返回值对照条件映射字典修正 key多智能体流程无限循环循环边缺少终止条件查看日志中节点执行次数增加 retry_count 上限达到阈值跳到 END工具执行结果没传入模型没有把 tool 消息追加到 state打印节点返回值中的 messages使用Annotated[list, operator.add]累积消息FastAPI 接口超时模型推理慢或下游服务慢查看服务日志统计单次耗时调大 timeout改用异步任务队列批量任务部分失败单条请求触发限流或模型报错捕获异常并写入日志增加重试机制降低并发 worker 数RAG 检索结果质量差文档切分不合理或索引未更新检查切分长度抽样检索日志调整 chunk_size 和 overlap重建索引显存不足本地模型过大或并发数过高查看 nvidia-smi 的显存占用换更小模型降低并发开启量化排查时不要直接改代码先看日志。LangGraph 图执行过程中你可以在每个节点入口加一行print(fnode: {node_name}, state: {state})确认当前走到哪个节点、状态如何。这一步能解决大部分流程编排问题。如果服务模式涉及平台或热门框架的版本迭代建议优先检查官方文档和版本更新日志网上的旧教程很容易过期。9. 最佳实践与使用建议9.1 从最小图开始第一次跑多智能体时不要立刻堆功能。先定义两个节点跑通再加第三个节点再加条件路由。最小可运行系统是整个项目的锚点一旦后面改出问题可以直接回到这个版本。9.2 状态设计要保守LangGraph 的 state 是常驻内存的数据结构字段越多、数据越大推理延迟和内存占用越高。不要把大段文本存在 state 里反复传递能用引用或摘要就尽量用。访问范围也要注意避免多个子 Agent 修改同一个字段导致覆盖。9.3 模型调用要有兜底多智能体系统对模型输出强依赖模型一旦崩了整个流程都会失败。建议在节点内捕获异常给默认返回或者让系统在连续失败两次后自动降级到简单流程。不要隐藏错误但要提供可观测的错误标记。9.4 日志和追踪是刚需给每个请求分配request_id在节点入口、工具调用前后、API 返回之前打上日志。这样排查问题时能精确到是哪一步慢、哪一步失败。有条件的话接入 LangSmith 这类可观测平台LangGraph 的图执行过程会变成可视化追踪排障效率高很多。9.5 服务安全API 服务如果要开放前面必须加鉴权。最简单的做法是在 FastAPI 层加一个Authorization头校验或者使用网关统一管理。对外服务前限制带宽和单 IP 请求频率防止测试阶段接口被刷。10. 总结与下一步如果你的最终目标是掌握 Hermes Agent 多智能体开发最值得先做的一件事不是看更多教程而是把第 5 节的 research write review 三节点图跑起来。先把状态传递、条件路由、审核循环这三个基本动作练熟再看其他复杂框架会轻松很多。最容易踩的坑有四个状态字段覆盖导致数据丢失、条件路由返回值不匹配、循环缺少终止条件、批量任务不记录失败信息。这四类问题占到了我在实际调试中遇到的大部分排障时间。后续可以从三个方向继续扩展第一把单模型调用换成混合模型用便宜小模型做意图分类用大模型做生成第二接入 RAG 知识库让 Agent 具备回答私有文档问题的能力第三用 FastAPI 封装为服务后接入前端或 Bot 平台形成一个可实际调用的业务接口。想继续深入的话优先级建议是LangGraph 官方的条件路由和子图文档、LangChain 工具实战、MCP 协议接入。把这三个打通你的多智能体系统就不是 Demo而是一个能放进业务里迭代的工程骨架。建议直接收藏本文按顺序跑代码比存一堆概念笔记有用得多。