简介:做Agent时,system prompt、function call、tools、MCP、RAG、agent等名词常被混为一谈。本文按提示、机制、资源、协议、知识、编排六个层次拆解这些概念的定义与边界,对比控制权、工程复杂度与典型风险差异,并给出选型建议与落地注意事项,助你从知道概念进阶到理解原理。
做大模型应用、尤其是做Agent开发时,团队讨论中经常出现话语错位:需求其实是“查询订单状态”,有人却提议“上个RAG”;业务流程明明是固定的三步操作,有人却坚持“让Agent自主决策”。这类错位的根源在于:这些名词分别处在技术栈的不同层次,解决的问题不同,但它们的介绍往往散落在不同语境里,导致开发者只记住了概念名词,却分不清职责边界,最终要么过度设计,要么行为失控。
本文把这些概念放进同一张架构图里,按照“输入层—控制层—机制层—资源层—协议层—知识层—编排层”逐层对比,回答三个问题:它们各自解决什么问题?彼此是什么关系?什么场景该用哪一个?
先给出最小定义,后续再展开对比:
虽然层次不同,它们有明显的共同点,这也是它们容易被混用的原因:
两者都是“提示词”,但工程属性完全不同:
| 维度 | system prompt | user prompt |
|---|---|---|
| 生命周期 | 会话级持久 | 单轮生效 |
| 归属 | 开发者设计 | 终端用户输入 |
| 变更频率 | 版本化迭代,低频 | 每轮变化 |
| 内容性质 | 角色、约束、格式、工具使用策略 | 具体任务意图 |
| 主要风险 | 约束含糊导致行为漂移 | 提示注入攻击 |
实践要点:安全约束、输出格式、工具调用策略应尽量沉淀在system prompt中并纳入版本管理,随发版灰度调整;而user prompt是不可信输入,必须做输入清洗与注入检测,不能把用户原话直接拼进含指令的位置。
function call解决“模型如何表达调用意图”,tools解决“有哪些能力可被调用”。一次完整链路是:
1. 开发者注册工具(名称/描述/参数结构/执行函数)2. 模型收到任务,输出结构化调用请求3. 应用校验参数并执行真实函数4. 把执行结果回传模型,继续生成
一个典型的模型输出示意:
{"name": "query_order_status","arguments": { "order_id": "A-1024" }}
这里最常见的误区是:把函数写出来就万事大吉。实际上工具描述的质量直接决定模型选择工具的准确率——描述模糊、参数命名不一致、多个工具职责重叠,都会显著提高误调用率。工具数量增多后,还应考虑分组、路由与按需加载,而不是把几十个工具一次性塞进上下文,否则既浪费上下文空间,也会降低选择精度。
如果所有工具都由自己团队开发、在同一套服务里执行,原生function call通常足够:每个工具手写一份结构与处理器即可。
但当工具来自多个团队、多个系统甚至外部服务方时,点对点接入的问题会暴露:每接入一个工具源就要单独开发一层适配,工具的发现、鉴权、生命周期管理各不相同,维护成本随接入数量线性上升。MCP这类开放协议的价值在于把这一层标准化:工具提供方按协议实现一次,任何支持该协议的模型运行时都能以统一方式发现并调用,形成“多对多”的解耦。
| 维度 | 原生function call | 协议化接入(MCP类) |
|---|---|---|
| 集成模式 | 点对点,逐个适配 | 标准化客户端—服务端 |
| 工具发现 | 静态注册为主 | 动态列举、按需加载 |
| 提供方耦合 | 工具与应用强绑定 | 工具提供方独立演进 |
| 适合规模 | 自研少量工具 | 多来源、多消费方生态 |
| 引入成本 | 低 | 需部署并治理协议服务端 |
这是实践中最容易混淆的一对:
判断口径很简单:需求是“让模型知道某件事”用RAG;需求是“让模型做成某件事”用function call。
两者并非互斥。常见组合是把“知识检索”本身封装成一个工具,交给Agent在需要时自主调用;这比每轮都无条件检索更节省上下文与延迟,但要求模型具备判断“何时需要查”的能力,需要通过评估集验证这个判断的可靠度。
| 维度 | 固定workflow | agent |
|---|---|---|
| 流程控制方 | 开发者预定义 | 模型运行时决定 |
| 行为可预测性 | 高,路径可穷举 | 低,依赖模型决策 |
| 测试方式 | 传统集成测试 | 轨迹评估、回放对比 |
| 延迟与成本 | 相对可控 | 随循环步数波动 |
| 典型失败 | 流程设计缺陷 | 死循环、误调用、越权 |
| 适合任务 | 结构稳定的业务流 | 开放式、步骤不可预知的任务 |
一个经验判断:如果流程能画成流程图,就先做成workflow;只有“下一步做什么无法预先穷举”时,才引入agent的自主决策。Agent的自主性是拿来换确定性的,不是免费的。
Agent主循环的通用形态(伪代码):
# 伪代码:Agent 执行循环骨架history = [system_prompt]for step in range(MAX_STEPS):resp = model(history, tools=tool_schemas)if not resp.tool_calls:return resp.text # 模型认为任务完成for call in resp.tool_calls:if not permitted(call): # 权限校验result = deny_message(call)else:result = execute(call.name, call.args,timeout=TIMEOUT, audit=True)history.append(tool_result(result))return fallback_to_human() # 超过步数上限,人工接管
| 概念 | 层次 | 解决的问题 | 控制方 | 工程复杂度 | 典型风险 |
|---|---|---|---|---|---|
| user prompt | 输入层 | 表达单次意图 | 用户 | 低 | 提示注入 |
| system prompt | 控制层 | 约束行为与格式 | 开发者 | 低 | 约束被绕过 |
| function call | 机制层 | 表达调用意图 | 模型提议+程序执行 | 中 | 参数幻觉、误调用 |
| tools | 资源层 | 提供能力集合 | 开发者注册 | 中 | 权限过宽、描述劣化 |
| MCP | 协议层 | 标准化工具/上下文接入 | 协议规范 | 中高 | 生态兼容、安全边界 |
| RAG | 知识层 | 注入外部知识 | 检索管线 | 中 | 检索质量、数据时效 |
| agent | 编排层 | 自主规划与循环 | 模型自主 | 高 | 失控、成本、审计难 |
可以按四步决策链走:
注意避免两个极端:一个是“名词焦虑”,为了用上所有概念而堆架构;另一个是“一把梭”,什么任务都套agent。选型应从任务属性出发,能简单就不要复杂。
这些名词并非并列的“多选一”,而是同一技术栈从下到上的多个层次:system/user prompt负责意图与约束,function call与tools提供动作能力,MCP把能力接入标准化,RAG补足知识,agent在最上层把它们编排成自主系统。理解了层次关系,“有什么区别、怎么选”就有了统一答案:按需取层、能简不繁、确定优先、自主换护栏。当你能把一次需求准确拆解到具体层次时,这些名词就不再神秘,你对Agent的理解也就从概念进入了原理。