公司动态
AI 应用工程:Tool、MCP、Skill 与 Workflow 如何接入 Agent?——搭建一个可运行的需求影响面分析 Agent
近期落地接入时发现一个共性认知偏差很多人把 Tool/MCP/Skill/Workflow 一概当成 Agent 插件统一放在一个列表里依靠模型自行走完完整流程。可业务一旦需要交付物校验、上下文拼接、强制审批等逻辑这种简单堆砌的实现方式就会出现各类问题。这篇就用一个可以直接运行的最小项目把四类能力的接入点和参与时刻讲清楚——它们不是四种并列组件而是分别落在不同的工程责任上。项目描述跑通一次“需求影响面分析”任务并输出一份带校验字段的 JSON 报告。完整DEMO项目地址https://gitcode.com/ligang2585116/agent-demo开篇先分清接入位置上一篇 已经讲过职责边界。本篇展开前先把四类能力放在同一张表里对照。维度ToolMCPSkillWorkflow本质模型可调用的一个动作/函数连接外部能力的标准协议按需加载的任务方法论SKILL.md包住 Agent 的确定性代码流程解决的问题模型自己做不了的事查数据、执行操作外部能力如何被统一发现与调用领域知识不常驻 Prompt任务匹配时才加载关键环节不允许模型自由裁量接入位置ToolRegistry暴露给模型应用侧适配层Client 把 Tool 转成 Function ToolResource 由应用拼入 Context摘要进初始上下文正文经activate_skill按需进入Agent 循环之外的应用代码谁触发模型决定调用Tool 由模型调Resource 由应用主动读模型判断任务匹配后激活代码无条件执行模型无法感知或跳过形态代码函数 Schema协议 进程Server / Client文档SKILL.md 可选资源代码普通流程逻辑本篇示例resolve_project_ownersearch_code、architecture://project-mapimpact-analysis/SKILL.md输入校验、Zod 报告校验、审批门禁这张表是本文的观察框架不是某一家厂商的统一分类。MCP Resource 是否进入 Context 由 Host 决定协议不会自动完成。1几组容易混淆的对比Tool vs MCP不是并列关系。MCP 是连接协议不是和本地 Function Tool 同层级的“另一种 Tool”。mcp-client.ts把 MCP Tool 适配进ToolRegistry之后模型看到的是同一套 Function Tool 列表根本分不出哪个来自本地、哪个来自 MCP Server。区别只在工程侧本地 Tool 是你写的函数MCP Tool 是别的进程或别的团队通过标准协议提供的能力。Tool vs SkillTool 提供‘手’Skill 提供‘操作手册’。 Tool 返回的是数据或执行结果Skill 激活后返回的是指令文本告诉模型该按什么步骤做、输出什么格式。本篇里 Skill 的激活机制本身也借助了一个 Tool——activate_skill——但这只是交付方式Skill 仍然是SKILL.md资产激活 Tool 不是把 Skill 降格成普通动作。Skill vs Workflow两者都写“流程”约束力完全不同。这是接入时最关键、也最容易混的一处SKILL.md里写的“先搜代码 → 再查依赖 → 输出 JSON”是建议模型可以不遵守workflow.ts里的if (highRisk !approved) throw是强制模型连感知它的机会都没有。判断一条规则该放 Skill 还是 Workflow只问一句这条规则被违反了能接受吗能接受 → Skill不能接受 → Workflow。Tool 是手MCP 是接手的标准插座Skill 是操作手册Workflow 是流水线上的质检关卡。前三者服务于模型的自主决策最后一个专门限制模型的自主决策。后面六节按接入顺序展开先搭 Harness再依次接入本地 Tool、MCP、Skill、Workflow最后跑通一次完整 Run。一、先搭一个最小 Agent Harness把循环写出来先把问题收窄最小 Harness 到底要做什么对本篇而言它只保留两项职责把可调用能力整理成模型可见的 Tool 定义解析模型返回的 Tool 调用把结果回填再继续循环直到出现最终文本或触发最大迭代次数。下面这段是最核心的结构摘自agent-demo/src/agent.ts的写法// 关键点模型只“请求调用”执行发生在应用侧for(letiteration0;iterationthis.maxIterations;iteration1){if(turn.typefinal)returnturn.text;constresultsawaitPromise.all(turn.calls.map((call)tools.execute(call)));turnawaitmodel.continue(results);}为什么要把“执行发生在应用侧”写进代码结构因为 Tool Calling 的协议里本质是“模型提出动作 → 应用执行 → 应用回填 → 再请求”。2Harness 不做 Workflow 的校验、不做 Skill 的激活决策、不做 MCP 发现它只负责把“动作循环”跑通并给上层流程提供一个稳定入口。二、注册第一个本地 Function Tool让模型能查负责人本地 Function Tool 解决的是模型要能提出“查询项目负责人”的调用请求。在示例里这个 Tool 叫resolve_project_owner入参只有一个projectName输出包含owner与team。核心代码在agent-demo/src/local-tools.ts。接入方式也很直接把 Tool 注册到ToolRegistry同时把输入 schema 暴露给模型 Adapter。本节只强调两点工程边界Tool Registry 是应用侧的动作目录模型只是看见 Tool 的描述与参数结构强制校验不放在 Tool。如果你把“必须校验/必须审批”也做成 Tool那么模型可以不调用Workflow 的门禁就会失效。这一点在第五节 Workflow 会反过来体现出来校验发生在应用代码里不交给模型选择。三、用 MCP 接入外部能力Tool 发现与调用在应用侧完成接入 MCP 时有三个问题必须回答Server 暴露什么、Client 发现与调用什么、接入后模型看到什么。本节依次展开。本篇选择最简单的本地 stdio 方式Harness 启动子进程作为 MCP Server再由 MCP Client 做连接、分页发现和调用。31) MCP Server暴露两个 Tool 一个 Resource示例 MCP Server 在agent-demo/src/mcp-server.ts它提供Toolsearch_codeToolget_project_dependenciesResourcearchitecture://project-mapServer 侧注册 Tool 的写法遵循 SDK 文档的示例范式registerToolinputSchema handler。32) MCP ClientlistTools/listResources callTool/readResourceHarness 在agent-demo/src/mcp-client.ts里做了两类工作listTools把工具元数据发现出来本篇实现了 cursor 分页的遍历。callTool把模型提出的 Tool Call 转发给 Server 并执行然后把返回内容转成 Harness 统一的 ToolResult。在这里要特别区分两条错误路径工具业务失败可能表现为isError: true但 JSON-RPC 协议故障会导致请求直接 reject/throw应用侧需要分别处理。43) Tool schema 映射MCP inputSchema → 模型 function parameters将 MCP Tool 适配到模型 function tool本质上是做一个“应用侧转换层”——对应开篇表里 MCP 的「接入位置」一行MCP 的inputSchema是 JSON Schema可以直接作为模型 function tool 的参数结构使用但协议消息结构、返回内容格式、以及工具执行确认都不在 MCP 里解决需要由 Harness 自己处理。1Resource 则完全不同Resource 的进入上下文由应用控制。本篇在 Workflow 里先读architecture://project-map再把它拼进任务 Context。1四、加载impact-analysisSkill只常驻 Catalog激活时再注入完整指令Skill 的目的是让“任务方法”以SKILL.md形式可复用而不是把所有规则写进一个巨长 Prompt。示例里Skill 在/skills/impact-analysis/SKILL.md它遵循开放规范YAML frontmatter Markdown 正文name与description是必填字段。51) Progressive Disclosure先 Metadata再 Instructions再按需资源在示例实现里Catalog 只包含name与description以及位置等最少信息激活时才把完整SKILL.mdbody 注入上下文。这对应官方客户端指南描述的 progressive disclosure 机制。62) 为什么要有activate_skill(name)这一层如果模型能直接读文件可以让它自己去读SKILL.md但为了统一教学示例本篇走专用激活 Tool 路径模型只给出一个activate_skill的调用请求Harness 用受控的 Skill Map 查找并读取对应 Skill 内容后再返回给模型支持配置松耦合Skill 资产在哪里、怎么组织由 loader 决定。7同时本篇 loader 做了真正的 YAML frontmatter 解析而不是用正则硬拆字段以避免多行值/引用等边界导致字段丢失。8五、Workflow把不可跳过的校验与审批写进应用代码这一节回答一个看似反直觉的问题既然 Skill 里已经写了分析步骤和输出要求为什么还要 Workflow原因很简单Skill 指令是否被执行取决于模型“理解并选择”Workflow Gate 必须由代码强制执行否则模型可能直接输出一段未经校验的文本就结束 Run绕过你预期的交付路径。示例把 Workflow 写成普通 TypeScript 函数并固定一个顺序validateInput → 读取 MCP Resourcearchitecture://project-map → runAgentTool 调用循环发生在这里 → validateReportSchema 校验发生在这里 → highRisk → approvalGate.confirm → publishvalidateReport使用 schema 校验输出字段失败直接抛出错误不进入发布路径。approvalGate也同样是代码层面控制高风险报告被拒绝时Workflow 不会“继续产出结果”。9这里直接对应官方对 Workflow 的定义取向Workflow 是预定义的路径/门禁Agent 则是模型动态决定过程与 tool usage。9六、跑通一次离线模式先验证“接入点都真的执行了”在本地按以下步骤跑通cdagent-demonpminstall--registryhttps://registry.npmjs.orgnpmtestnpmrun demonpm run demo默认是离线模式不需要OPENAI_API_KEY。你会看到一条清晰的 Trace示例输出MODEL_MODEoffline Workflow: validate input MCP:readarchitecture://project-map Model: activate impact-analysis Model: call search_code Model: call get_project_dependencies Model: call resolve_project_owner(checkout-web)Model: call resolve_project_owner(merchant-console)Model: call resolve_project_owner(finance-admin)Model: produce report Workflow: validate report Workflow: approval required Workflow: publish注意这里的“验证重点”不是评测模型好不好而是证明工程链路真的闭合MCP Client 发现与调用确实发生Skill 被激活并注入了完整指令Workflow 的校验与审批确实发生最终输出满足你在 Workflow 里定义的报告 schema。如果你想切到 Live 模式只需要把 Adapter 切到 OpenAI Responses API并配置环境变量。示例项目里也提供了MODEL_MODElive分支但默认以 offline 作为可复现基线。10七、替换 Model/Server/业务时哪些模块可以保留这一节用“替换对象”倒推职责边界帮助你避免把 demo 变成不可迁移的样板。1) 换模型 Provider只替换 Model Adapter你需要替换的是provider 专属的 Tool Call/Result Item 解析与组装但 Harness 的“动作循环”、Tool Registry、Workflow、MCP 适配层都可以保留。这也是本篇选择 Model Adapter 的原因把 Provider 差异限制在 Adapter 边界内。22) 换 MCP Server只替换 Server 配置 Tool Allowlist你需要调整的是Server 启动方式、暴露工具集合、以及 Resource 的 URIHarness 仍然沿用同一套 listTools/callTool/readResource 的调用结构尤其要保持错误路径处理一致。43) 换业务场景替换本地 Tool、Skill 与 Workflow Gate当业务规则发生变化最先动的是本地 Function Tool 与其校验 schemaSkill方法与输出模板Workflow 的结果校验与高风险判定。这三块变化的规模通常比你想象的小因为它们都与“交付物 schema 与强制门禁”直接绑定。4) 但请记住这仍然不是生产 Runtime这个最小例子能完成一次任务但它缺少第四篇要讲的生产能力如何在中断后恢复、如何追踪执行、如何在真实故障里评测与改进。所以收束一句接入链路跑通了 ≠ 生产系统完成了。适用/不适用边界适用把本文作为新团队建立 Agent 接入基线先跑通再扩展需要把“工具、外部能力、任务方法、门禁路径”拆清楚的工程训练。不适用把本文当作完整生产 Runtime没有 checkpoint/memory/evaluation/observability多厂商跨协议的通用 SDK 教程本篇锁定了具体的版本基线用于可复现。下一篇我会接着回答为什么一次任务跑通之后仍不能直接进入企业生产环境。来源索引用于支撑关键技术断言MCP Tool/Resource 边界Tool 是工具动作Resource 由应用控制如何进入 Contexthttps://modelcontextprotocol.io/specification/2025-11-25/server↩︎ ↩︎ ↩︎OpenAI Function Calling模型提出 tool call、应用执行与回填循环由应用侧完成https://developers.openai.com/api/docs/guides/function-calling↩︎ ↩︎MCP v1stdio/Streamable HTTP transport 与本地子进程集成方式https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.x/docs/server.md↩︎ ↩︎MCP Tool 错误语义isErrorvs JSON-RPC 协议故障不同处理路径https://modelcontextprotocol.io/specification/2025-11-25/server/tools↩︎ ↩︎Agent Skills 开放规范Skill 目录包含SKILL.mdfrontmatter Markdown必填name/descriptionhttps://agentskills.io/specification↩︎Agent Skills Progressive DisclosureCatalogmetadata→ 激活instructions→ 资源按需进入https://agentskills.io/client-implementation/adding-skills-support↩︎Skill 激活机制与专用激活工具模式https://agentskills.io/client-implementation/adding-skills-support↩︎YAML frontmatter 解析与分离 metadata/body官方客户端实现指南与参考解析器按需解释https://agentskills.io/client-implementation/adding-skills-support↩︎Workflow 与 Agent 的架构区分Workflow 预定义路径Agent 动态路径https://www.anthropic.com/engineering/building-effective-agents↩︎ ↩︎OpenAI 官方 TypeScript SDK 与 Responses API 作为主要接口https://github.com/openai/openai-node、releasev6.49.0调研基准日 2026-07-27 ↩︎