agent-architecture.md 3.6 KB

智能体分层架构(Agent / MCP / Skill)

一、三层职责(边界即纪律)

层 职责 不该做的事
Agent(决策) 决定「这轮调不调工具、调哪个、怎么串」 不直接 import Skill;不含协议细节
MCP(协议) 把工具暴露成统一协议;把调用转成执行 不做业务编排;不持有凭据(浏览器场景)
Skill(实现) 真正干活(出图/转写/分析),纯能力 不假设调用方是谁;不藏全局态

换框架不动 MCP/Skill 是分层的验收标准: 本项目把 Agent 从 PageAgent 换到 LangGraph,design-mcp.js 与 image-service.js 零改动。

二、Agent 侧:图编排 vs Re-act

维度 显式图(LangGraph) Re-act 循环
可观测 节点轨迹可展示、可断点、可回滚 只能看到「思考中…」
Token 控制 可在节点里预筛工具、按需检索 后再进 LLM 全量工具 schema + 线性历史,膨胀
失败分支 「没出图」是显式分支 只能事后靠猜兜底
成本 需 importmap + 替身(浏览器) 轻

建议:要 token 可控 + 可观测 → 显式图;只是简单问答 → Re-act 足够。

2.1 节点切分原则(本项目 7 节点实例)

route(本地预筛,零 LLM/零 token)
  → recall(检索式记忆,按需召回)
  → plan(唯一一次"决定做什么"的 LLM)
  → invoke(执行工具)
  → assert(断言"真出图了吗")
  → reflect(给一句说明,不带工具,避免它再调一次)
  → respond(收尾)
  • 不调 LLM 的节点放最前(route/recall)→ 省 token 且几乎不花时间。
  • 工具产物直接进 State,不做「消息序列化往返」。
  • 独立 assert 节点让「工具说了要干活但没干成」成为显式分支。

2.2 State 放什么(关键)

State 只存索引与摘要,大对象(图片 URL、历史正文)放 service / IndexedDB。

  • 好处:checkpoint 序列化快、快照不膨胀、State 可安全进日志。
  • 凭据不进 State:State 会被快照序列化 → token 进 State 等于进快照。运行时上下文 挂在 config.configurable.__dc(不是闭包,闭包会把首轮 token 固化进编译产物)。
  • ⚠️ LangGraph 节点签名是 node(state, config),第二参是 RunnableConfig 不是你的 ctx(实测坑)。

三、MCP 侧

见 agent-mcp-skill.md(契约、命名空间、Worker 约束、凭据纪律)。

四、可观测性(一套埋点,三处复用)

无论几个 MCP/Skill,口径必须统一:

  • Token:每次 LLM 调用记 system/tools/history/retrieved 分项;有 usage 真值以真值为准。
  • 输入/输出比例:分别记 prompt_tokens / completion_tokens。
  • 耗时:框架调度与IO(LLM/网络)分开记。 ⚠️ 实测踩坑:用 t0() 包住整个 await LLM 会把 LLM 的 1.4s 算进「框架开销」, 占比虚高到 96%。正确做法:await 期间暂停框架计时,只把「发起调用前后」算框架的。

详见 measurement.md。

五、降级与失败隔离

  • 每个外部依赖都有降级路径:本项目 MCP 起不来 → 自动走「直连 Skill 出图」,用户总能拿到图。
  • 失败如实说明,不静默兜底:工具没出图就明说「这次没出图」,不偷偷换条路再出一张(用户会困惑)。
  • 一个组件失败不拖垮整体:一个 MCP 挂 → 其它 MCP 与 Agent 仍可用。