7.2. LangChain 集成让 Hermes 可以使用庞大的工具生态
LangChain 集成让 Hermes 可以使用庞大的工具生态
一个只靠内置技能的智能体,就像只有一只手的人——能干,但处处受限。Hermes 的 Skill 系统提供了清晰的扩展接口,而 LangChain 生态已经积累了几百个经过验证的工具:从网络搜索、数据库查询到 API 调用,几乎覆盖了日常开发中的所有外部交互。与其重复造轮子,不如用一座桥把这两端连起来。
2026 年 6 月,LangChain 的 langchain-community 工具集已经非常稳定,Hermes 的 0.4.x 版本也提供了文档化的 Skill 注册机制。这一章,你将学会编写一个不到 50 行的适配器,把任意 LangChain 工具包装成 Hermes Skill,然后立刻在混合工作流中使用这些外挂能力。读完你不仅能集成单个工具,还会掌握把整个 LangChain Agent 作为 Hermes 子 Agent 调用的模式,彻底打开“百宝箱”。
你需要什么
- 环境:Python 3.11+,已安装 Hermes Agent(
pip install hermes-agent或从源码安装)和 LangChain 核心库(pip install langchain langchain-community)。 - 工具:一个可用的 LLM API 密钥(比如 OpenAI Key),因为 Hermes 和部分 LangChain 工具需要模型推理。
- 预计时间:45 分钟(包含踩坑填坑的时间)。
最终成果
你将得到:
- 一个可复用的
HermesToolAdapter类,能把任意BaseTool转化为 Hermes Skill。 - 一个注册了多个 LangChain 工具(比如搜索与文件读取)的 Hermes Agent,能回答“帮我查一下今天北京的天气,然后总结 readme.md 的技术要点”。
- 一个将 LangChain
create_agent作为子 Agent 嵌入 Hermes 的示例,让两个智能体协作完成复杂数据分析。
步骤说明
步骤 1:编写 LangChain Tool 适配器
Hermes 的 Skill 接口要求提供一个 name、description 和一个异步执行方法 execute(**kwargs)。LangChain 的 BaseTool 同样有 name、description,但调用方式可能是同步的 run 或异步的 arun,参数通过一个字符串或字典传入。适配器的核心任务就是对齐这两个接口。
# adapter.py
from langchain_core.tools import BaseTool
from hermes.skill import BaseSkill # 导入 Hermes Skill 基类(请以当前文档为准)
class HermesToolAdapter(BaseSkill):
"""将 LangChain 工具包装为 Hermes Skill。"""
def __init__(self, lc_tool: BaseTool):
# 从 LangChain 工具获取元信息
self._name = lc_tool.name
self._description = lc_tool.description
self._lc_tool = lc_tool
@property
def name(self) -> str:
return self._name
@property
def description(self) -> str:
return self._description
async def execute(self, **kwargs) -> str:
"""
执行 LangChain 工具。
注意:LangChain 的 run 方法通常接收单个字符串或字典。
这里我们根据参数结构做适配:如果工具支持字典输入,则传入 **kwargs;
否则将 kwargs 拼接为字符串传给 run。
"""
# 不同的 LangChain 工具输入格式不同,这里给出两种常见分支
if hasattr(self._lc_tool, '_run') and not hasattr(self._lc_tool, 'args_schema'):
# 简单工具:只接收一个字符串
input_str = kwargs.get('input', ' '.join(f"{k}: {v}" for k, v in kwargs.items()))
return await self._lc_tool.arun(input_str)
else:
# 结构化工具:支持字典参数
return await self._lc_tool.arun(kwargs)
踩坑经验
⚠️ 注意:很多 LangChain 工具没有实现
arun(异步方法),调用时会回退到同步run,这会阻塞 Hermes 的事件循环。如果遇到阻塞,可以在适配器内部用loop.run_in_executor包装同步调用:import asyncio loop = asyncio.get_event_loop() result = await loop.run_in_executor(None, self._lc_tool.run, input_data)或者直接检查工具是否有
arun,没有的话就使用线程池。这个适配器已经体现了分支逻辑。
步骤 2:注册与使用
现在你可以从 LangChain 的工具箱里任意挑选工具,注册为 Hermes 的 Skill。假设我们想集成 DuckDuckGo 搜索和本地文件读取工具:
# integrate_tools.py
from hermes import Agent # 伪代码,请参照官方 Agent 初始化方式
from langchain_community.tools import DuckDuckGoSearchRun, ReadFileTool
from adapter import HermesToolAdapter
# 实例化 LangChain 工具
search_tool = DuckDuckGoSearchRun()
read_tool = ReadFileTool()
# 包装为 Hermes Skill
search_skill = HermesToolAdapter(search_tool)
read_skill = HermesToolAdapter(read_tool)
# 将 Skill 绑定到 Agent(以 Hermes 0.4.x 为例,具体注册方法请查阅最新文档)
agent = Agent(
core_skills=[search_skill, read_skill],
# ... 其他配置
)
# 启动交互或通过 Gateway 暴露 API
response = await agent.execute("用搜索引擎查到今天的北京天气,然后阅读 ./docs/readme.md 并总结技术要点")
print(response)
预期结果:Agent 会先调用 search_skill 获取天气信息,再调用 read_skill 读取文件,最后生成综合回答。
步骤 3:将 LangChain Agent 作为子 Skill 调用
有时候你需要的不是一个原子工具,而是一个能独立思考几步的子智能体,比如专门用来分析股票数据的 LangChain Agent。Hermes 支持将这种子 Agent 作为“高级 Skill”嵌入,只需让适配器的 execute 方法内部启动一个 LangChain Agent 运行循环即可。
from langchain.agents import create_react_agent, AgentExecutor
from langchain_openai import ChatOpenAI
class LangChainSubAgentSkill(BaseSkill):
"""将 LangChain Agent 封装为 Hermes 的子 Skill。"""
def __init__(self, name: str, description: str, lc_tools: list, llm=None):
self._name = name
self._description = description
# 创建一个子 Agent
self._llm = llm or ChatOpenAI(model="gpt-4o-mini")
agent = create_react_agent(self._llm, lc_tools, prompt) # prompt 需自定义
self._agent_executor = AgentExecutor(agent=agent, tools=lc_tools, verbose=False)
@property
def name(self): return self._name
@property
def description(self): return self._description
async def execute(self, **kwargs) -> str:
query = kwargs.get("input", "")
# 调用子 Agent 执行
result = await self._agent_executor.ainvoke({"input": query})
return result["output"]
使用场景:假设你有一个金融分析 LangChain Agent(配置了计算器、股票查询工具),把它包装后注册给 Hermes,Hermes 就可以在讨论投资组合时直接咨询这个“专家”。
⚠️ 注意:子 Agent 的上下文和 Hermes 的记忆是隔离的。如果你需要传递历史对话,必须在
execute参数中显式传入,避免状态分裂。
步骤 4:混合工作流实战——复杂数据查询
现在来把刚才的各个模块串起来,完成一个真实场景:用户提问“对比三支科技股(AAPL, MSFT, GOOGL)过去一年的表现,并给出投资建议,最后把结论保存到 report.md”。
我们手上已有:
- 搜索工具(获取股价新闻)
- 文件写入工具(保存报告)
- 一个金融分析子 Agent(负责计算与建议)
混合工作流依靠 Hermes 的规划与工具选择能力自动完成。你需要做的只是注册好所有 Skill,然后像这样发起调用:
agent = Agent(
core_skills=[
HermesToolAdapter(DuckDuckGoSearchRun()),
HermesToolAdapter(WriteFileTool()),
fin_agent_skill # 上一步创建的 LangChain 子 Agent
],
# 特别配置:子 Agent 需要较大思考步骤数
max_iterations=10
)
query = """
1. 搜索 AAPL、MSFT、GOOGL 近一年的股价走势新闻。
2. 使用金融分析专家分析这三支股票的风险和收益前景。
3. 生成一份 300 字的投资建议报告,并写入当前目录下的 report.md 文件。
"""
response = await agent.execute(query)
print(response)
预期结果:Agent 分步调用搜索 Skill,再调用子 Agent 分析,最后调用文件写入 Skill 生成报告。控制台输出报告内容,文件系统中也会多出一个 report.md。
踩坑集合
- 工具输入格式不一致:LangChain 工具有的接受字符串,有的接受字典。适配器里要做分支判断,否则传递参数会报
TypeError。 - 同步工具卡死:如未处理同步/异步转换,Hermes 的事件循环会被同步
run()阻塞,导致整个 Agent 假死。务必使用run_in_executor或优先使用有arun实现的工具。 - 工具输出格式期望:Hermes 的 Skill 期望返回字符串,如果 LangChain 工具返回了 JSON 对象,记得在适配器中做
json.dumps转换。 - 子 Agent 权限边界:子 Agent 看到的对话历史非常有限,容易产生幻觉。建议在
description中清晰写明它的能力范围,避免 Hermes 给它分派错误任务。
回顾
你刚刚在 45 分钟内完成了从零到一的 LangChain-Hermes 集成:
- 编写了不到 50 行的
HermesToolAdapter,打通了两个框架的工具接口。 - 将两个现成的 LangChain 工具注册为 Hermes Skill,并成功执行组合任务。
- 学会了把整个 LangChain Agent 当作一个“专家 Skill”嵌入 Hermes,实现了分层智能。
- 最后通过一个混合工作流示例,串联搜索、分析、文件输出,体验了 Hermes 编排多个异构工具的能力。
现在你的 Hermes Agent 已经拥有了整个 LangChain 生态的武器库,数百种工具随时可以被“即插即用”。但这种单 Agent + 多工具的模式在真正复杂的业务里会碰到新的瓶颈:如果一个 Agent 既要推理又要操作 UI,还要处理长期记忆,就像一个人同时做十件事,错误率会飙升。下一章《多智能体协作通过消息传递实现松耦合组合》会告诉你如何让多个 Hermes Agent 各司其职、通过消息传递协同工作——就像组建一支专业团队,而不是让万能超人疲于奔命。
Hermes Agent 系统设计与工程落地
关于 LearnKu