跳到主要内容

开发指南:从工具描述到多 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_filegrep_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。