同样的数据,截然不同的回答——揭秘 LLM 在 Agent 与 Workflow 两种模式下的输出行为差异
你有没有遇到过这样的情况:明明 MCP 工具返回了完整的数据,大模型的回答却干巴巴的;换成把同样的数据手动拼进提示词,回答立刻变得图文并茂、有表有情?本文从一个真实的复现案例出发,深入拆解这一现象背后的机制,并给出可落地的工程应对方法。
一、一个让人困惑的现象
最近在用阿里云百炼的 qwen-plus 搭建应用时,遇到了一个耐人寻味的问题:
Agent 模式(启用 MCP,由模型自主决定工具调用)下,大模型的回复像是在完成一份作业交差——语言简短,结构扁平,没有表格,没有 emoji,有时候像是把工具返回结果念了一遍就结束了。
Workflow 模式下(外部编排好流程后直接将数据拼入提示词,不依赖模型自主调用),把同一份数据通过变量拼接注入提示词,模型的回复立刻"活"了——有结构、有层次、有表格、有情绪,像是一位认真在跟你对话的助手。
于是做了一个关键验证:将 MCP 返回的内容和 Workflow 拼接到提示词的内容做对比,发现两者字面上完全一致。
内容相同,结果却截然不同。这个差异从何而来?

二、两种模式的架构本质
在回答"为什么"之前,先澄清两种模式的架构差异。
Workflow 模式(提示词拼接)
[开始节点] → [数据获取节点] → [大模型节点]
↑
将数据拼入 System Prompt 或 User Prompt
在这个模式下,数据是在调用模型之前就被组装进提示词。模型收到的是一条完整的 user 消息,内容大致是:
你是一个助手。以下是xxx返回相关数据:
{工具返回的内容}
请根据以上信息,回答用户的问题:{用户问题}
Agent 模式(MCP / Function Calling)
[用户消息] → [模型判断] → [工具调用] → [工具返回] → [模型生成最终回复]
↑
tool_result 消息角色
在这个模式下,数据是以 tool_result 消息的形式回传给模型。模型收到的对话历史长这样:
[
{"role": "user", "content": "你是一个助手,请根据xxx返回的相关数据,回答用户的问题:。..."},
{"role": "assistant", "content": null, "tool_calls": [...]},
{"role": "tool", "tool_call_id": "xxx", "content": "{工具返回的内容}"}
]
关键差异在这里:同样的文字内容,被放在了不同的消息角色(role)中。
三、根本原因:消息角色的语义锚定
3.1 模型不只是"读文字",它读的是"结构化的对话剧本"
现代大模型经过大量对话数据的训练(SFT + RLHF),它不仅学会了如何回答问题,还学会了在不同对话角色下应该扮演什么行为模式。
| 消息角色 | 模型习得的隐式行为期望 |
|---|---|
system |
遵守规则、设定人设,持续约束整个对话 |
user |
这是"用户的诉求",我要认真、完整、友好地回应 |
assistant |
这是我之前说的话,保持一致性 |
tool / tool_result |
这是工具执行后的原始数据,我的任务是提炼并汇报 |
注意最后一行。模型从训练数据中"学到"的模式是:当它看到 tool_result 时,它的任务是功能性收尾——提取关键信息,简洁汇报,不需要做"内容创作"。
这就像给一位员工发了两种不同的指令:
- “这是资料,写一份完整的客户报告” → 员工会认真组织语言、做表格、加标注
- “工具已经查完了,结果在这里” → 员工会简短地说"查到了,结果是XXX"
3.2 训练数据分布决定了"默认行为"
这个差异不是 bug,而是模型在训练过程中对不同对话结构的拟合结果。
在工具调用(Function Calling / MCP)的训练数据中:
tool_result通常是结构化的 JSON 或原始数据片段- 模型被强化学习训练为"提炼 → 简洁作答"
- 过度展开会被视为冗余,人类标注者往往给低分
在普通对话的训练数据中:
user消息中如果包含丰富的背景信息,往往对应期望一个详细、有格式的回答- 模型被训练为"充分利用上下文,生成高质量回复"
简而言之,由于 Workflow 模式在拼接时通常会同时写入生成任务要求(例如‘请根据以上信息回答’),这种隐含的指令差异也会放大输出的丰富程度。后文提出的 System Prompt 覆盖法(方法一)本质上就是将这些指令平移进 Agent 模式。
3.3 这个现象在学术界的印证
2025年8月,arXiv 上出现了首个专门研究 LLM-MCP 交互的评估框架论文 MCPGAUGE(2508.12566)。该研究通过约 20,000 次 API 调用、覆盖 6 个商业 LLM 和 30 个 MCP 工具套件的大规模实验,得出了若干挑战业界通行假设的发现,核心结论之一是:
MCP 的最终效果不仅取决于工具返回的额外上下文,还深度依赖模型识别工具需求、正确执行调用、以及有效整合检索信息的能力。
这从实证角度支持了上文的分析”改为“这从侧面表明工具调用链路引入的整合要求是导致输出质量下降的重要环节,与本文观察到的现象一致。
四、深一层:不只是角色,还有"任务完成感"
有一个更微妙的机制值得关注:模型对"任务完成状态"的感知。
在 Agent 模式下,当模型发出工具调用请求后,从它的视角看,它已经完成了"思考 → 决策 → 调度"这个完整的认知动作。工具返回结果后,它处于一种"收尾阶段"的心智状态,倾向于用最小的输出完成闭环。
在 Workflow 模式下,模型从未"主动调用"过任何工具——它在一开始就收到了一个包含丰富背景的完整问题,处于"任务刚开始,需要全力以赴"的状态,因此输出更积极、更丰富。
这类似于人类的认知规律:当你觉得"差不多完成了"的时候,最后一步往往会做得很潦草。
五、量化感受这个差异
为了让这个差异更直观,下面用一个天气查询场景做对比示意,两种模式的 System Prompt 均未包含特殊格式要求。
数据源(两种模式完全相同):
城市: 西安
日期: 今天
天气: 多云转晴
温度: 22°C - 29°C
湿度: 68%
风速: 东南风3级
空气质量: 良(AQI 75)
建议: 适合户外活动,注意防晒
Agent 模式(MCP)的典型输出:
西安今天多云转晴,气温22-29°C,湿度68%,东南风3级,空气质量良。适合户外活动。
Workflow 模式(提示词拼接)的典型输出:
🌤️ 西安今日天气播报
项目 详情 天气状况 多云转晴 ⛅→☀️ 温度范围 22°C ~ 29°C 湿度 68% 风况 东南风 3级 🍃 空气质量 良(AQI 75)✅ 今日建议: 适合户外活动,但午后阳光较强,记得做好防晒措施 🧴☂️
如有其他出行计划,欢迎继续咨询!
两者传递的信息量基本一致,但用户体验相差甚远。
六、五种应对方法,从"治标"到"治本"
方法一:在 System Prompt 中覆盖默认行为(最简单)
在 Agent 的系统提示词中,明确要求输出格式:
你是一个专业的信息助手。无论通过什么方式获取到数据,
在向用户回复时,你必须:
- 使用 Markdown 格式组织内容
- 在适当位置使用表格展示结构化数据
- 使用 emoji 增强可读性
- 回复要详细、完整,不要简略汇报
适用场景: 快速修复,适合大多数 Agent 场景。
局限性: 需要为每个 Agent 单独配置,且与工具调用指令可能产生优先级竞争。
方法二:在工具结果后追加"整合指令"消息
在工具返回结果后、模型生成最终回复前,通过代码插入一条额外的 user 消息:
messages = [
{"role": "user", "content": user_query},
{"role": "assistant", "content": None, "tool_calls": [tool_call]},
{"role": "tool", "tool_call_id": tool_call_id, "content": tool_result},
# 追加整合指令
{"role": "user", "content": "请根据以上工具返回的数据,生成一份详细、格式美观的回复,使用 Markdown 表格和适当的 emoji。"}
]
适用场景: 对输出格式有高要求的场景,如面向 C 端用户的界面。
局限性: 多了一条 user 消息会让对话历史略显不自然,需要在前端做好处理。
注意: 请确认所用模型及网关支持 tool 消息后接 user 消息的序列;生产环境中,更稳妥的变通是在首轮用户提示中预埋整合要求(即方法一的 System Prompt 覆盖),避免破坏工具调用链路的完整性。
方法三:Few-shot 示范期望的输出风格
在 System Prompt 或首轮对话中,提供一个"工具调用后如何回复"的示范:
以下是一个工具调用后的回复示范:
[工具返回] {"city": "西安", "weather": "晴", "temp": "15-25°C"}
[期望回复]
## ☀️ 西安天气
今天西安晴空万里,气温舒适(15~25°C)。
是个出门的好日子!🌿
请按照以上风格,生成你的回复。
适用场景: 需要统一输出风格的产品场景。
局限性: 增加输入 token 消耗,需要精心设计示范案例。
方法四:架构层解耦——"数据节点 + 生成节点"分离
这是最接近 Workflow 思路的工程方案:在 Agent 架构中,引入一个专门的"整合生成节点"。
[Agent 工具调用] → [工具结果] → [后处理:提取关键字段]
↓
[独立的生成模型调用]
role: user
content: "以下数据 + 生成任务"
↓
[最终回复]
实质上,这是在 Agent 内部嵌套了一个小型 Workflow——用工具调用获取数据,用标准 user 消息触发高质量生成。该方法等于放弃 Agent 在最后一轮的自主回复,改用 Workflow 思维重生成,适用于对输出质量要求压倒一切且能接受额外延迟的场景。
适用场景: 对输出质量要求极高、且工程资源充足的场景。
局限性: 增加了调用次数和延迟,架构复杂度上升。
七、什么时候应该用哪种模式?
| 维度 | Agent + MCP | Workflow 提示词拼接 |
|---|---|---|
| 动态性 | 高(模型自主决定是否调用工具) | 低(固定流程) |
| 输出丰富度(默认) | 较低 | 较高 |
| 工程可控性 | 较低 | 高 |
| 适合场景 | 复杂多步推理、工具选择不确定 | 数据固定、输出质量优先 |
| 调试难度 | 高(行为不确定) | 低(流程可预期) |
建议原则:
- 如果你的场景是数据固定来源、输出质量敏感(如面向用户的报告、卡片),优先用 Workflow 拼接
- 如果你的场景是任务复杂、需要模型自主推理工具链,用 Agent,但务必在 System Prompt 层做格式强约束
八、总结
| 问题 | 答案 |
|---|---|
| 差异的本质是什么? | 同样的内容放在不同消息角色(user vs tool_result)中,触发了模型不同的输出行为模式 |
| 这是 Bug 吗? | 不是,这是模型在 SFT/RLHF 训练中对不同角色的隐式行为拟合结果 |
| 具有普遍性吗? | 是的,所有经过 Function Calling 微调的模型都会有类似倾向 |
| 有论文研究吗? | MCPGAUGE(arXiv:2508.12566)是目前最直接相关的实证研究 |
| 最快的解法? | 在 System Prompt 中明确要求输出格式,覆盖默认行为 |
一句话记住核心逻辑:
对大模型而言,语义位置即任务定义。你把数据放在哪里,就在告诉模型"这是什么类型的任务"。
tool_result说的是"帮我收个尾",user说的是"帮我认真做件事"。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)