跳到主要内容

开发指南:从工具描述到多 Agent 生产架构

七天实战

本文与 Hermes 七天子站课表 Day 2–Day 6 逐日对齐。Morning 读概念、Afternoon 写代码、Evening 在 Persona Lab / Code Sandbox 验证假设。文档站负责「可检索的深度」;子站负责「可交互的肌肉记忆」。

Hermes Agent 开发的核心不是「让模型多说几句」,而是 把不确定性关进可观测、可限幅、可回滚的 Tool Graph。本指南按工程落地顺序展开:先写好工具描述(模型选对的概率),再设计 System Prompt 五层(角色不漂移),再编排多 Agent 与工具链,最后接入记忆、推理模式与框架选型。


一、工具描述工程(Tool Description Engineering)​

工具描述是 模型与外部世界之间的 API 文档。Hermes 系列模型在 Function Calling 上训练充分,但描述质量仍决定 工具选择准确率(Tool Selection Accuracy, TSA) 与 参数合法率(Argument Validity Rate, AVR)。

1.1 Active vs Passive 描述​

类型写法特征模型行为适用场景
Passive(被动)只列参数名、类型模型常在「该用却不用」与「乱用」间摇摆内部调试、模型已强熟悉域
Active(主动)明确 何时调用 / 何时禁止 / 失败时怎么办边界清晰,误调用下降生产、多工具并存

Passive 反例(不要照搬):

{
"name": "search_web",
"description": "Search the web.",
"parameters": { "type": "object", "properties": { "query": { "type": "string" } } }
}

Active 正例(Hermes 推荐风格):

{
"name": "search_web",
"description": "当用户问题需要实时信息、新闻、股价或你不确定的 factual 断言时调用。禁止用于:纯数学推导、已在上文给出的事实复述、用户明确要求「不要搜索」。若 query 超过 120 字,先 summarize 再搜。",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "英文关键词检索串;中文问题请翻译为 3–8 个英文关键词"
},
"max_results": {
"type": "integer",
"enum": [3, 5, 10],
"default": 5,
"description": "返回条数;闲聊用 3,研究报告用 10"
}
},
"required": ["query"]
}
}

设计原则:

  1. 触发条件写在前半句——模型先匹配意图,再填参数。
  2. 否定条件写在后半句——减少与其他工具抢调用。
  3. 与相邻工具做 diff——若 read_file 与 grep_code 并存,各自 description 必须互斥。

1.2 Schema 设计:枚举、默认值、嵌套​

技巧作用示例
enum消除幻觉参数"format": {"enum": ["json", "markdown", "plain"]}
default降低必填字段认知负担可选 timeout_sec 默认 30
嵌套 object表达结构化动作git_operation: { branch, files[] }
minLength / pattern拦截非法输入邮箱、路径前缀
字段级 description比顶层 description 更精准每个 property 单独说明单位

DevOps Agent(Day 3 实战)工具片段:

from pydantic import BaseModel, Field
from typing import Literal

class TailLogInput(BaseModel):
"""拉取 CI 日志尾部——仅在用户询问构建失败原因或指定 job_id 时调用。"""
job_id: str = Field(..., pattern=r"^[a-z0-9-]{8,64}$")
lines: Literal[50, 200, 500] = Field(200, description="行数;初步排查 50,深挖 500")
severity: Literal["error", "warn", "all"] = "error"

将 Pydantic 模型 model_json_schema() 导出为 OpenAI Tools JSON,可保证 运行时校验与描述同源。

1.3 Few-shot 嵌入策略​

在 System Prompt 的 Tools 层(见下文五层结构)嵌入 1–2 个 完整工具调用轨迹,比堆叠自然语言规则更有效。

## 工具调用示例(仅供格式参考,勿复述示例内容)

用户:把 report.pdf 总结成三点并算总页数。
Assistant 思考:需要 read_pdf → summarize → count_pages 线性链。
Tool: read_pdf {"path": "report.pdf", "max_pages": 20}
Observation: [二进制已转文本,省略]
Tool: summarize {"text": "...", "bullets": 3}
Tool: count_pages {"path": "report.pdf"}

Few-shot 纪律:

  • 示例中的工具名必须与实际 Registry 完全一致。
  • 展示 错误恢复:第二个示例可以是「第一次参数非法 → 读 error → 修正再调」。
  • 不超过 2 个完整链,否则挤占工作记忆 token。

1.4 描述版本化与回归​

每次改 description,用固定 benchmark(见 Day 6)跑 TSA/AVR。建议维护 tools/CHANGELOG.md:

版本工具变更TSA 变化
v1.2search_web增加「禁止搜已给事实」71% → 89%
v1.3run_shell增加路径前缀 enumAVR +12%

二、System Prompt 五层结构(Day 2 核心)​

角色工程不是「你是一个友好的助手」,而是 可测试的行为契约。推荐五层,从上到下优先级递增:

2.1 各层详解与验收标准​

层必答问题验收(人工或自动)
Identity你是谁、为谁服务100 轮抽样角色自称一致率 ≥ 95%
Expertise专业边界在哪越界问题拒答率、转介率
Tone用户感知情感标注一致、禁词零出现
Constraints什么绝对不能做红队用例通过率
Tools工具优先序TSA、越权调用率

心理咨询工作室(Day 2 实战)Constraints 示例:

## Constraints(高于一切友好语气)
- 不提供医学诊断、不开处方、不替代危机热线。
- 检测到自伤关键词 → 立即停止探索式提问 → 输出本地危机资源 → handoff 至 supervisor Agent。
- 禁止调用 send_email / 任何对外通信工具,除非用户签署 informed consent 且 supervisor 批准。

2.2 五层与 Token 预算​

层建议 token 占比压缩策略
Identity + Expertise15%稳定不变,可缓存
Tone5%合并为 3 条 bullet
Constraints25%不可压缩
Tools + Few-shot35%按场景动态裁剪工具子集
预留20%给 episodic 记忆注入

三、多 Agent 架构(Day 2 & Day 6)​

单 Agent 在跨域任务上易出现 能力稀释 与 约束冲突。多 Agent 的本质是 分治 + 显式 Handoff 协议。

3.1 模式对照表​

模式拓扑典型场景Hermes 实现要点
专家委员会并行分析 → 主席综合架构评审、投资分析各专家独立上下文,主席只看摘要
师徒(Mentor–Apprentice)师傅审学徒产出代码生成、合规文书学徒工具权限 ⊂ 师傅
红蓝对抗攻击 Agent vs 防守 AgentPrompt 注入、越权测试Day 6 必修;见 §8
HandoffA 打包 → B 续跑接待 → 专科 → 督导结构化 handoff payload
意图路由Router 选下游客服分流、DevOps 分类小模型或规则 + LLM fallback
防漂移周期提醒 + 记忆隔离长对话、多轮咨询每 N 轮注入 Identity 摘要

3.2 Handoff Payload 规范​

Handoff 不是把整个 chat history 粘贴给下一个 Agent——那是 上下文炸弹。推荐 JSON 包:

{
"handoff_version": "1.0",
"from_agent": "intake_reception",
"to_agent": "cbt_specialist",
"user_goal": "近期失眠与焦虑",
"facts_verified": ["持续 2 周", "无用药史"],
"open_questions": ["触发事件是否明确"],
"risk_flags": [],
"forbidden_actions": ["diagnosis"],
"suggested_tools": ["breathing_exercise_guide"],
"transcript_digest": "用户描述工作压力…(≤500 tokens)"
}

3.3 意图路由实现​

层级实现延迟准确
L0 规则关键词 + 正则毫秒级中
L1 分类器小模型 / embedding百 ms高
L2 LLMroute_intent 工具秒级最高

推荐: L0 拦截明确指令(「查 CI」「翻译」)→ L1 处理模糊句 → L2 仅兜底。

3.4 防漂移(Anti-Drift)​

长对话中模型会逐渐 忘记 Constraints。三道防线:

  1. 周期性 Identity 注入(每 8–12 轮):「Reminder: 你是 X,禁止 Y。」
  2. 角色记忆隔离:业务 Agent 不读其他 Agent 的私有 scratchpad。
  3. 输出校验器:正则 / 小模型检测禁词、越权工具名。

Day 2 子站 Persona Lab 可 A/B 测试不同 reminder 间隔对漂移率的影响。


四、工具链编排(Day 3)​

Tool Graph 有三种基础拓扑;生产系统常组合使用。

4.1 线性链(Pipeline)​

A → B → C
read_pdf → summarize → send_slack

适用: 数据形态逐步变换,后步依赖前步输出。

代码骨架(LangChain 风格伪代码):

async def linear_chain(state):
doc = await tools.read_pdf(state["path"])
summary = await tools.summarize(doc.text, bullets=3)
await tools.notify_slack(channel=state["channel"], text=summary)
return {"summary": summary}

4.2 条件链(Router / Branch)​

实现方式:

  • 显式: Planner 输出 branch 字段,Executor 解释执行。
  • 隐式: 模型在 ReAct 环中自行选择下一工具(需强 description)。

4.3 并行链(Fan-out / Fan-in)​

         ┌→ metrics_query ─┐
用户请求 ─┼→ log_search ─┼→ aggregate_report
└→ git_blame ─┘

要点:

  • Fan-out 工具应 无写冲突 或写不同资源。
  • Fan-in 需要 聚合策略:按时间排序、去重、摘要超长结果。
  • 设置 并行超时:最慢分支决定总延迟,用 asyncio.wait(..., timeout=30)。
拓扑失败传播重试策略
线性中断或 skip 后续从失败步重试
条件仅执行分支内分支独立 retry
并行部分失败标记 partial,Fan-in 说明缺失

五、自定义工具安全(Day 3 & Day 6)​

Agent 的工具等于 给模型的 shell 账号。安全不是可选项。

5.1 输入验证:Pydantic 双层​

from pydantic import BaseModel, Field, field_validator
import os

class ReadFileInput(BaseModel):
path: str = Field(..., description="相对 workspace 的路径")

@field_validator("path")
@classmethod
def no_path_traversal(cls, v: str) -> str:
normalized = os.path.normpath(v)
if normalized.startswith("..") or normalized.startswith("/"):
raise ValueError("path must stay inside workspace")
return normalized
层位置作用
Schema 层模型填参前引导合法 JSON
Runtime 层工具 execute 前硬拦截注入与越界

5.2 超时分级​

等级超时典型工具失败处理
T010s计算器、格式化立即重试 1 次
T130sHTTP GET、DB 读指数退避 ×2
T260s大文件解析、编译转异步 job + 通知
T3120s+仅 E2B 沙箱必须人工审批

5.3 E2B 沙箱执行​

对用户代码、不可信脚本,使用 E2B 等 一次性 VM:

from e2b_code_interpreter import Sandbox

async def run_untrusted_python(code: str) -> str:
with Sandbox(timeout=60) as sbx:
execution = sbx.run_code(code)
if execution.error:
return f"RuntimeError: {execution.error}"
return execution.text

纪律: 主进程 never exec() 用户代码;沙箱 无网络 或仅 allowlist;每次调用 销毁实例。

5.4 失败策略矩阵​

策略配置适用
Retrymax=2, backoff瞬时网络错误
Fallback Toolprimary→secondary API数据源冗余
Self-Correcterror as Observation参数格式错误
Abort + Handoff人工 ticket支付、删库类

六、推理模式(Day 5)​

推理模式决定 Agent 如何规划、调用工具、修正错误。

6.1 模式总览​

模式核心循环优势风险
ReAct+Thought → Action → Observation(+ 反思句)简单、可解释步数膨胀
Plan-and-ExecutePlanner 出计划 → Executor 逐步执行长任务稳定计划过时
Tree of Tools多分支试探 → 选最优叶探索性任务Token 成本高
Self-Refine生成 → 自评 → 修订质量提升延迟 ×2–3
HTN层次任务网络分解复杂域可复用需领域模板

6.2 ReAct+ 增强点​

标准 ReAct 在 Observation 后直接 Thought。ReAct+ 增加 Reflect 步:

Observation: search 返回 0 条结果
Reflect: 关键词过窄,应改用英文同义词并放宽时间范围
Thought: 调用 search_web,query="LLM agent benchmark 2024"

研究 Agent(Day 5)建议 max_steps=12,超过则强制 summarize 已收集证据。

6.3 Plan-and-Execute 计划模板​

{
"goal": "撰写某技术对比报告",
"steps": [
{"id": 1, "action": "search", "success_criteria": "≥5 篇 primary source"},
{"id": 2, "action": "read_and_note", "depends_on": [1]},
{"id": 3, "action": "outline", "depends_on": [2]},
{"id": 4, "action": "draft", "depends_on": [3]},
{"id": 5, "action": "self_refine", "depends_on": [4]}
],
"replan_triggers": ["step_failed_twice", "new_user_constraint"]
}

Executor 不得擅自增删步骤;需 replan 时交还 Planner。

6.4 Tree of Tools(简化版)​

对多种工具组合不确定时,并行展开 K 个候选分支(K≤3),用 轻量评分函数(步数、错误数、来源数)选叶:

root → [branch_A: search+read] [branch_B: api_direct] [branch_C: cache_lookup]
↓ score 0.7 ↓ score 0.4 ↓ score 0.9 → 选 C

6.5 Self-Refine 与 HTN​

  • Self-Refine: 同一 Agent 扮演 Critic,检查清单化(事实有引用?逻辑跳步?)。
  • HTN: 把「写 DevOps 报告」分解为 HTN 模板:Gather → Analyze → Format;子任务可映射到固定工具子图。

七、多模态与 Playwright(Day 3 扩展)​

Hermes Agent 不仅是文本 Tool Calling;感知类工具 把 UI、截图、PDF 纳入 Observation。

7.1 多模态工具分类​

类型工具示例模型输入
文档read_pdf, ocr_image文本或 vision 模型
视觉screenshot_analyzebase64 + prompt
浏览器playwright_navigateDOM snapshot / a11y tree

7.2 Playwright 集成模式​

# 工具描述(Active)
# "当任务需要登录后操作、填表、抓动态渲染内容时调用;禁止用于纯静态页(用 fetch 即可)"

async def playwright_snapshot(url: str, wait_until: str = "networkidle") -> dict:
from playwright.async_api import async_playwright
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto(url, wait_until=wait_until, timeout=30000)
text = await page.inner_text("body")
await browser.close()
return {"url": url, "text_digest": text[:8000]}

安全: 浏览器跑在 隔离容器;禁止访问内网 RFC1918;Cookie 用 一次性 profile。

7.3 视觉 + 文本双通道​

对复杂 dashboard:截图 → vision 模型描述 + DOM 文本 互为校验,降低幻觉表格数据。


八、记忆四层(Day 4)​

层存储写入时机读取策略
工作Context window每轮自动全量(受 token 限)
情节Session store会话结束 / 每 10 轮摘要注入 System
语义Pinecone / Milvus / pgvector用户确认的事实、RAG ingestTop-k 检索
程序JSON / Neo4j任务成功且用户点赞相似任务 few-shot

长期记忆 RAG Agent(Day 4 实战)流水线:

  1. 用户说「记住:我偏好 metric 单位」→ 写入 semantic + 用户画像 slot。
  2. 新会话开始 → 检索画像 → 注入 Identity 层下方 User Profile 块。
  3. 会话过长 → 情节压缩:旧轮次变 bullet summary,原文归档。

程序记忆示例:

{
"task_signature": "pdf_summary_slack",
"successful_chain": ["read_pdf", "summarize", "slack_post"],
"params_pattern": {"max_pages": 20, "bullets": 3}
}

九、框架选型:LangChain / AutoGen / MCP(Day 3–5)​

维度LangChain + LangGraphAutoGenMCP
定位单 Agent 工具链、状态图多 Agent 对话工具服务器协议
Tool Binding@tool / bind_toolsregister_functionstdio/SSE 暴露 tools
多 AgentLangGraph 节点ConversableAgent 原生多 server 组合
可观测LangSmith自建各 server 日志
Hermes 课表Day 1 默认Day 2 多 AgentDay 3 工具生态

推荐组合:

  • Day 1–3: LangChain 跑通 Tool Graph + Inspector 字段对齐。
  • Day 2 多角色: AutoGen GroupChat 或自研 Handoff orchestrator。
  • Day 3+ 工具爆炸: 把 SQL、Git、Slack 拆成 MCP Server,Agent 仅维护 thin client。

MCP 的价值是 工具与 Prompt 解耦:换模型不改 server;换 server 不改 orchestrator。


十、Day 2–Day 6 每日落地清单​

天文档章节子站实验验收
Day 2§二 §三Persona Lab三 Agent Handoff 无上下文丢失
Day 3§一 §四 §五 §九Code SandboxDevOps 并行链 + 1 个 MCP tool
Day 4§八Memory Lab跨会话记住用户偏好
Day 5§六Research sandboxPlan-and-Execute 完成 5 步报告
Day 6§五 §三 红蓝Red Team deckBFCL 子集 TSA ≥ 80%

十一、调试与可观测​

对齐子站 Tool Call Inspector 字段,生产 trace 建议包含:

字段含义
model_raw模型原始输出
parsed_tool_call解析后工具名+参数
validation_errorPydantic 拦截
tool_latency_ms执行耗时
branch_id条件链分支
agent_id多 Agent 标识
drift_reminder_count防漂移注入次数

十二、常见反模式​

反模式后果修复
60 工具全量塞给模型TSA 暴跌按意图动态 subset ≤8
Handoff 粘贴全历史超窗 + 漂移结构化 digest
无超时 shell 工具挂死T0–T3 分级
Plan 与 Execute 同一 Prompt计划中途乱调工具角色分离
记忆无 TTL陈旧事实污染episodic 过期 + 用户更正入口

延伸阅读​

当你能在 Inspector 里解释「为何这一步走条件链分支 B 而非 A」,并给出 description 改动假设,你就具备了 Hermes Agent 开发指南 所定义的工程判断力。下一步打开子站 Day 2,把五层 Prompt 写成可版本化的 YAML。

作者:mr stone · 联系:chenxiaoshivivid@126.com · StoneXYZ · 思之维 AI