1"use strict";(self.webpackChunkhermes_agent_cn=self.webpackChunkhermes_agent_cn||[]).push([[32724],{35478:(e,n,s)=>{s.d(n,{R:()=>o,x:()=>l});var t=s(58101);const r={},i=t.createContext(r);function o(e){const n=t.useContext(i);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),t.createElement(i.Provider,{value:n},e.children)}},77562:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>h,frontMatter:()=>o,metadata:()=>t,toc:()=>c});const t=JSON.parse('{"id":"developer-guide/adding-tools","title":"\u6dfb\u52a0\u5de5\u5177","description":"\u5982\u4f55\u5411 Hermes Agent \u6dfb\u52a0\u65b0\u5de5\u5177 \u2014\u2014 \u6a21\u5f0f\u3001\u5904\u7406\u5668\u3001\u6ce8\u518c\u548c\u5de5\u5177\u96c6","source":"@site/docs/developer-guide/adding-tools.md","sourceDirName":"developer-guide","slug":"/developer-guide/adding-tools","permalink":"/docs/developer-guide/adding-tools","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2,"title":"\u6dfb\u52a0\u5de5\u5177","description":"\u5982\u4f55\u5411 Hermes Agent \u6dfb\u52a0\u65b0\u5de5\u5177 \u2014\u2014 \u6a21\u5f0f\u3001\u5904\u7406\u5668\u3001\u6ce8\u518c\u548c\u5de5\u5177\u96c6","translationStatus":"translated","upstreamPath":"website/docs/developer-guide/adding-tools.md","upstreamSha":"76f8477e378796d67cff09bf4537cc828e61316c","sourceUrl":"https://github.com/NousResearch/hermes-agent/blob/main/website/docs/developer-guide/adding-tools.md","translatedAt":"2026-04-11T03:21:38.109Z","translationModel":"qwen/qwen3-30b-a3b-instruct-2507"},"sidebar":"docs","previous":{"title":"\u7a0b\u5e8f\u5316\u96c6\u6210","permalink":"/docs/developer-guide/programmatic-integration"},"next":{"title":"\u6dfb\u52a0\u63d0\u4f9b\u8005","permalink":"/docs/developer-guide/adding-providers"}}');var r=s(25105),i=s(35478);const o={sidebar_position:2,title:"\u6dfb\u52a0\u5de5\u5177",description:"\u5982\u4f55\u5411 Hermes Agent \u6dfb\u52a0\u65b0\u5de5\u5177 \u2014\u2014 \u6a21\u5f0f\u3001\u5904\u7406\u5668\u3001\u6ce8\u518c\u548c\u5de5\u5177\u96c6",translationStatus:"translated",upstreamPath:"website/docs/developer-guide/adding-tools.md",upstreamSha:"76f8477e378796d67cff09bf4537cc828e61316c",sourceUrl:"https://github.com/NousResearch/hermes-agent/blob/main/website/docs/developer-guide/adding-tools.md",translatedAt:new Date("2026-04-11T03:21:38.109Z"),translationModel:"qwen/qwen3-30b-a3b-instruct-2507"},l="\u6dfb\u52a0\u5de5\u5177 {#adding-tools}",d={},c=[{value:"\u6982\u8ff0",id:"overview",level:2},{value:"\u7b2c\u4e00\u6b65\uff1a\u521b\u5efa\u5de5\u5177\u6587\u4ef6",id:"step-1-create-the-tool-file",level:2},{value:"\u5173\u952e\u89c4\u5219",id:"key-rules",level:3},{value:"\u7b2c\u4e8c\u6b65\uff1a\u6dfb\u52a0\u5230\u5de5\u5177\u96c6",id:"step-2-add-to-a-toolset",level:2},{value:"\u7b2c\u4e09\u6b65\uff1a\u6dfb\u52a0\u53d1\u73b0\u5bfc\u5165",id:"step-3-add-discovery-import",level:2},{value:"\u5f02\u6b65\u5904\u7406\u51fd\u6570",id:"async-handlers",level:2},{value:"\u9700\u8981 task_id \u7684\u5904\u7406\u51fd\u6570",id:"handlers-that-need-task_id",level:2},{value:"\u88ab Agent \u5faa\u73af\u62e6\u622a\u7684\u5de5\u5177",id:"agent-loop-intercepted-tools",level:2},{value:"\u53ef\u9009\uff1a\u8bbe\u7f6e\u5411\u5bfc\u96c6\u6210",id:"optional-setup-wizard-integration",level:2},{value:"\u68c0\u67e5\u6e05\u5355",id:"checklist",level:2}];function a(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",input:"input",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"adding-tools",children:"\u6dfb\u52a0\u5de5\u5177"})}),"\n",(0,r.jsxs)(n.p,{children:["\u5728\u7f16\u5199\u5de5\u5177\u4e4b\u524d\uff0c\u8bf7\u95ee\u81ea\u5df1\uff1a",(0,r.jsxs)(n.strong,{children:["\u8fd9\u5e94\u8be5\u662f\u4e00\u4e2a ",(0,r.jsx)(n.a,{href:"creating-skills",children:"\u6280\u80fd"})," \u5417\uff1f"]})]}),"\n",(0,r.jsxs)(n.p,{children:["\u5f53\u67d0\u4e2a\u529f\u80fd\u53ef\u4ee5\u8868\u793a\u4e3a\u6307\u4ee4 + shell \u547d\u4ee4 + \u73b0\u6709\u5de5\u5177\uff08\u5982 arXiv \u641c\u7d22\u3001git \u5de5\u4f5c\u6d41\u3001Docker \u7ba1\u7406\u3001PDF \u5904\u7406\uff09\u65f6\uff0c\u8bf7\u5c06\u5176\u4f5c\u4e3a ",(0,r.jsx)(n.strong,{children:"\u6280\u80fd"}),"\u3002"]}),"\n",(0,r.jsxs)(n.p,{children:["\u5f53\u9700\u8981\u4e0e API \u5bc6\u94a5\u8fdb\u884c\u7aef\u5230\u7aef\u96c6\u62
110\u3001\u81ea\u5b9a\u4e49\u5904\u7406\u903b\u8f91\u3001\u4e8c\u8fdb\u5236\u6570\u636e\u5904\u7406\u6216\u6d41\u5f0f\u5904\u7406\uff08\u5982\u6d4f\u89c8\u5668\u81ea\u52a8\u5316\u3001TTS\u3001\u89c6\u89c9\u5206\u6790\uff09\u65f6\uff0c\u8bf7\u5c06\u5176\u4f5c\u4e3a ",(0,r.jsx)(n.strong,{children:"\u5de5\u5177"}),"\u3002"]}),"\n",(0,r.jsx)(n.h2,{id:"overview",children:"\u6982\u8ff0"}),"\n",(0,r.jsxs)(n.p,{children:["\u6dfb\u52a0\u4e00\u4e2a\u5de5\u5177\u9700\u8981\u4fee\u6539 ",(0,r.jsx)(n.strong,{children:"3 \u4e2a\u6587\u4ef6"}),"\uff1a"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"tools/your_tool.py"})})," \u2014 \u5904\u7406\u51fd\u6570\u3001\u6a21\u5f0f\u3001\u68c0\u67e5\u51fd\u6570\u3001",(0,r.jsx)(n.code,{children:"registry.register()"})," \u8c03\u7528"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"toolsets.py"})})," \u2014 \u5c06\u5de5\u5177\u540d\u79f0\u6dfb\u52a0\u5230 ",(0,r.jsx)(n.code,{children:"_HERMES_CORE_TOOLS"}),"\uff08\u6216\u7279\u5b9a\u5de5\u5177\u96c6\uff09"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"model_tools.py"})})," \u2014 \u5c06 ",(0,r.jsx)(n.code,{children:'"tools.your_tool"'})," \u6dfb\u52a0\u5230 ",(0,r.jsx)(n.code,{children:"_discover_tools()"})," \u5217\u8868\u4e2d"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"step-1-create-the-tool-file",children:"\u7b2c\u4e00\u6b65\uff1a\u521b\u5efa\u5de5\u5177\u6587\u4ef6"}),"\n",(0,r.jsx)(n.p,{children:"\u6bcf\u4e2a\u5de5\u5177\u6587\u4ef6\u90fd\u9075\u5faa\u76f8\u540c\u7684\u7ed3\u6784\uff1a"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'# tools/weather_tool.py\n"""Weather Tool -- \u67e5\u627e\u67d0\u4e2a\u4f4d\u7f6e\u7684\u5f53\u524d\u5929\u6c14\u3002"""\n\nimport json\nimport os\nimport logging\n\nlogger = logging.getLogger(__name__)\n\n\n# --- \u53ef\u7528\u6027\u68c0\u67e5 ---\n\ndef check_weather_requirements() -> bool:\n """Return True if the tool\'s dependencies are available."""\n return bool(os.getenv("WEATHER_API_KEY"))\n\n\n# --- \u5904\u7406\u7a0b\u5e8f ---\n\ndef weather_tool(location: str, units: str = "metric") -> str:\n """Fetch weather for a location. Returns JSON string."""\n api_key = os.getenv("WEATHER_API_KEY")\n if not api_key:\n return json.dumps({"error": "WEATHER_API_KEY not configured"})\n try:\n # ...\u8c03\u7528\u5929\u6c14 API ...\n return json.dumps({"location": location, "temp": 22, "units": units})\n except Exception as e:\n return json.dumps({"error": str(e)})\n\n\n# --- Schema \u5b9a\u4e49 ---\n\nWEATHER_SCHEMA = {\n "name": "weather",\n "description": "Get current weather for a location.",\n "parameters": {\n "type": "object",\n "properties": {\n "location": {\n "type": "string",\n "description": "City name or coordinates (e.g. \'London\' or \'51.5,-0.1\')"\n },\n "units": {\n "type": "string",\n "enum": ["metric", "imperial"],\n "description": "Temperature units (default: metric)",\n "default": "metric"\n }\n },\n "required": ["location"]\n }\n}\n\n\n# --- \u6ce8\u518c ---\n\nfrom tools.registry import registry\n\nregistry.register(\n name="weather",\n toolset="weather",\n schema=WEATHER_SCHEMA,\n handler=lambda args, **kw: weather_tool(\n location=args.get("location", ""),\n units=args.get("units", "metric")),\n check_fn=check_weather_requirements,\n requires_env=["WEATHER_API_KEY"],\n)\n'})}),"\n",(0,r.jsx)(n.h3,{id:"key-rules",children:"\u5173\u952e\u89c4\u5219"}),"\n",(0,r.jsx)(n.admonition,{title:"\u91cd\u8981",type:"danger",children:(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u5904\u7406\u51fd\u6570 ",(0,r.jsx)(n.strong,{children:"\u5fc5\u987b"})," \u8fd4\u56de JSON \u5b57\u7b26\u4e32\uff08\u901a\u8fc7 ",(0,r.jsx)(n.code,{children:"json.dumps()"}),"\uff09\uff0c\u4e0d\u80fd\u8fd4\u56de\u539f\u59cb\u5b57\u5178"]}),"\n",(0,r.jsxs)(n.li,{children:["\u9519\u8bef ",(0,r.jsx)(n.strong,{children:"\u5fc5\u987b"})," \u4ee5 ",(0,r.jsx)(n.code,{children:'{"error": "message"}'})," \u5f62\u5f0f\u8fd4\u56de\uff0c\u4e0d\u80fd\u629b\u51fa\u5f02\u5e38"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"check_fn"})," \u5728\u6784\u5efa\u5de5\u5177\u5b9a\u4e49\u65f6\u88ab\u8c03\u7528 \u2014\u2014 \u5982\u679c\u8fd4\u56de ",(0,r.jsx)(n.code,{children:"False"}),"\uff0c\u8be5\u5de5\u5177\u5c06\u88ab\u9759\u9ed8\u6392\u9664"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"handler"})," \u63a5\u6536 ",(0,r.jsx)(n.code,{children:"(args: dict, **kwargs)"}),"\uff0c\u5176\u4e2d ",(0,r.jsx)(n.code,{children:"args"})," \u662f LLM \u5de5\u5177\u8c03\u7528\u7684\u53c2\u6570"]}),"\n"]})}),"\n",(0,r.jsx)(n.h2,{id:"step-2-add-to-a-toolset",children:"\u7b2c\u4e8c\u6b65\uff1a\u6dfb\u52a0\u5230\u5de5\u5177\u96c6"}),"\n",(0,r.jsxs)(n.p,{children:["\u5728 ",(0,r.jsx)(n.code,{children:"toolsets.py"})," \u4e2d\u6dfb\u52a0\u5de5\u5177\u540d\u79f0\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'# \u5982\u679c\u5b83\u5e94\u8be5\u5728\u6240\u6709\u5e73\u53f0\u4e0a\u53ef\u7528\uff08CLI + \u6d88\u606f\u5e73\u53f0\uff09\uff1a\n_HERMES_CORE_TOOLS = [\n ...\n "weather", # <-- \u5728\u6b64\u6dfb\u52a0\n]\n\n# \u6216\u8005\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u72ec\u7acb Toolset\uff1a\n"weather": {\n "description": "Weather lookup tools",\n "tools": ["weather"],\n "includes": []\n},\n'})}),"\n",(0,r.jsx)(n.h2,{id:"step-3-add-discovery-import",children:"\u7b2c\u4e09\u6b65\uff1a\u6dfb\u52a0\u53d1\u73b0\u5bfc\u5165"}),"\n",(0,r.jsxs)(n.p,{children:["\u5728 ",(0,r.jsx)(n.code,{children:"model_tools.py"})," \u4e2d\u5c06\u6a21\u5757\u6dfb\u52a0\u5230 ",(0,r.jsx)(n.code,{children:"_discover_tools()"})," \u5217\u8868\u4e2d\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'def _discover_tools():\n _modules = [\n ...\n "tools.weather_tool", # <-- \u5728\u6b64\u6dfb\u52a0\n ]\n'})}),"\n",(0,r.jsxs)(n.p,{children:["\u6b64\u5bfc\u5165\u4f1a\u89e6\u53d1\u5de5\u5177\u6587\u4ef6\u672b\u5c3e\u7684 ",(0,r.jsx)(n.code,{children:"registry.register()"})," \u8c03\u7528\u3002"]}),"\n",(0,r.jsx)(n.h2,{id:"async-handlers",children:"\u5f02\u6b65\u5904\u7406\u51fd\u6570"}),"\n",(0,r.jsxs)(n.p,{children:["\u5982\u679c\u5904\u7406\u51fd\u6570\u9700\u8981\u5f02\u6b65\u4ee3\u7801\uff0c\u8bf7\u4f7f\u7528 ",(0,r.jsx)(n.code,{children:"is_async=True"})," \u6807\u8bb0\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'async def weather_tool_async(location: str) -> str:\n async with aiohttp.ClientSession() as session:\n ...\n return json.dumps(result)\n\nregistry.register(\n name="weather",\n toolset="weather",\n schema=WEATHER_SCHEMA,\n handler=lambda args, **kw: weather_tool_async(args.get("location", "")),\n check_fn=check_weather_requirements,\n is_async=True, # \u6ce8\u518c\u8868\u81ea\u52a8\u8c03\u7528 _run_async()\n)\n'})}),"\n",(0,r.jsxs)(n.p,{children:["\u6ce8\u518c\u8868\u4f1a\u900f\u660e\u5730\u5904\u7406\u5f02\u6b65\u6865\u63a5 \u2014\u2014 \u4f60\u65e0\u9700\u81ea\u884c\u8c03\u7528 ",(0,r.jsx)(n.code,{children:"asyncio.run()"}),"\u3002"]}),"\n",(0,r.jsx)(n.h2,{id:"handlers-that-need-task_id",children:"\u9700\u8981 task_id \u7684\u5904\u7406\u51fd\u6570"}),"\n",(0,r.jsxs)(n.p,{children:["\u7ba1\u7406\u4f1a\u8bdd\u7ea7\u72b6\u6001\u7684\u5de5\u5177\u4f1a\u901a\u8fc7 ",(0,r.jsx)(n.code,{children:"**kwargs"})," \u63a5\u6536 ",(0,r.jsx)(n.code,{children:"task_id"}),"\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'def _handle_weather(args, **kw):\n task_id = kw.get("task_id")\n return weather_tool(args.get("location", ""), task_id=task_id)\n\nregistry.register(\n name="weather",\n ...\n handler=_handle_weather,\n)\n'})}),"\n",(0,r.jsx)(n.h2,{id:"agent-loop-intercepted-tools",children:"\u88ab Agent \u5faa\u73af\u62e6\u622a\u7684\u5de5\u5177"}),"\n",(0,r.jsxs)(n.p,{children:["\u67d0\u4e9b\u5de5\u5177\uff08\u5982 ",(0,r.jsx)(n.code,{children:"todo"}),"\u3001",(0,r.jsx)(n.code,{children:"memory"}),"\u3001",(0,r.jsx)(n.code,{children:"session_search"}),"\u3001",(0,r.jsx)(n.code,{children:"delegate_task"}),"\uff09\u9700\u8981\u8bbf\u95ee\u4f1a\u8bdd\u7ea7 Agent \u72b6\u6001\u3002\u8fd9\u4e9b\u5de5\u5177\u5728\u5230\u8fbe\u6ce8\u518c\u8868\u4e4b\u524d\u4f1a\u88ab ",(0,r.jsx)(n.code,{children:"run_agent.py"})," \u62e6\u622a\u3002\u6ce8\u518c\u8868\u4ecd\u7136\u4fdd\u5b58\u5b83\u4eec\u7684\u6a21\u5f0f\uff0c\u4f46\u5982\u679c\u62e6\u622a\u88ab\u7ed5\u8fc7\uff0c",(0,r.jsx)(n.code,{children:"dispatch()"})," \u5c06\u8fd4\u56de\u4e00\u4e2a\u56de\u9000\u9519\u8bef\u3002"]}),"\n",(0,r.jsx)(n.h2,{id:"optional-setup-wizard-integration",children:"\u53ef\u9009\uff1a\u8bbe\u7f6e\u5411\u5bfc\u96c6\u62
110"}),"\n",(0,r.jsxs)(n.p,{children:["\u5982\u679c\u5de5\u5177\u9700\u8981 API \u5bc6\u94a5\uff0c\u8bf7\u5c06\u5176\u6dfb\u52a0\u5230 ",(0,r.jsx)(n.code,{children:"hermes_cli/config.py"}),"\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'OPTIONAL_ENV_VARS = {\n ...\n "WEATHER_API_KEY": {\n "description": "Weather API key for weather lookup",\n "prompt": "Weather API key",\n "url": "https://weatherapi.com/",\n "tools": ["weather"],\n "password": True,\n },\n}\n'})}),"\n",(0,r.jsx)(n.h2,{id:"checklist",children:"\u68c0\u67e5\u6e05\u5355"}),"\n",(0,r.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","\u5df2\u521b\u5efa\u5de5\u5177\u6587\u4ef6\uff0c\u5305\u542b\u5904\u7406\u51fd\u6570\u3001\u6a21\u5f0f\u3001\u68c0\u67e5\u51fd\u6570\u548c\u6ce8\u518c\u8c03\u7528"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","\u5df2\u5728 ",(0,r.jsx)(n.code,{children:"toolsets.py"})," \u4e2d\u6dfb\u52a0\u5230\u9002\u5f53\u7684\u5de5\u5177\u96c6\u4e2d"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","\u5df2\u5728 ",(0,r.jsx)(n.code,{children:"model_tools.py"})," \u4e2d\u6dfb\u52a0\u53d1\u73b0\u5bfc\u5165"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","\u5904\u7406\u51fd\u6570\u8fd4\u56de JSON \u5b57\u7b26\u4e32\uff0c\u9519\u8bef\u4ee5 ",(0,r.jsx)(n.code,{children:'{"error": "..."}'})," \u5f62\u5f0f\u8fd4\u56de"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","\u53ef\u9009\uff1a\u5df2\u5c06 API \u5bc6\u94a5\u6dfb\u52a0\u5230 ",(0,r.jsx)(n.code,{children:"hermes_cli/config.py"})," \u4e2d\u7684 ",(0,r.jsx)(n.code,{children:"OPTIONAL_ENV_VARS"})]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","\u53ef\u9009\uff1a\u5df2\u6dfb\u52a0\u5230 ",(0,r.jsx)(n.code,{children:"toolset_distributions.py"})," \u4ee5\u652f\u6301\u6279\u91cf\u5904\u7406"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","\u5df2\u4f7f\u7528 ",(0,r.jsx)(n.code,{children:'hermes chat -q "Use the weather tool for London"'})," \u6d4b\u8bd5"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.