为什么“声明工具”会改变模型回答风格?一次排查记录

为什么“声明工具”会改变模型回答风格?一次排查记录

最近在对比 OpenRouter 与直连 DeepSeek 原生接口时,我遇到了一个非常容易让人误判的问题:

同一个问题,OpenRouter 上的回答明显更完整、更结构化;而直连 DeepSeek 时,即使 prompt 基本一致,回答却明显更短。

问题示例:

请介绍港英时期的立法局。

在 OpenRouter 上,模型通常会给出一篇结构清晰、分节完整的长回答;但在原生调用时,回答明显简短。

起初我怀疑了很多方向,最后却发现真正影响风格的变量是:tools 字段的存在。

即使工具从未被真正调用,模型的输出风格也会发生明显变化。

下面是完整排查过程与当前判断。


一、问题是如何出现的

测试问题非常简单:

请介绍港英时期的立法局。

在 OpenRouter 上,回答通常包含:

  • 历史沿革
  • 议员构成
  • 权力变化
  • 关键改革节点
  • 制度转型

而直连 DeepSeek 时,即便做了如下处理:

  • system prompt 为空或接近为空
  • 显式设置 reasoning_effort=high
  • max_tokens 拉到 128000
  • 检查流式输出是否丢 chunk

结果仍然是:回答偏短。

当时最困惑的一点是:

prompt 差不多,为什么输出风格差这么多?


二、排除的几个错误方向

1️⃣ 不是 max_tokens 问题

即使把 max_tokens 提到 128000,回答依然简短。

✅ 排除“被截断”的可能。


2️⃣ 不是流式输出解析问题

我将完整请求与响应全部落盘,包括原始流式事件。

回溯后确认:

✅ 数据没有在解析过程中丢失。


3️⃣ 不只是 reasoning_effort=high

怀疑 OpenRouter 默认推理强度更高。

但测试发现:

✅ 单纯提高推理强度,并不能稳定复现那种“像写完一篇文章”的结构化输出。


三、关键发现:OpenRouter 不是“裸请求”

翻查 OpenRouter 的对话链后发现:

  • assistant 曾发起 tool_calls
  • 调用了 openrouter_datetime
  • 存在 tool 角色返回

也就是说,我对比的并不是:

用户提问 → 模型回答

而更像是:

带 agent 环境的上下文运行模式

模型知道自己:

  • 可以调用工具
  • 处于 agent 执行环境
  • 需要先规划再交付结果

于是我做了一个对照实验:

在原生 DeepSeek 请求中,也注册同名工具 openrouter_datetime

结果:

✅ 输出风格立即变长
✅ 出现提纲式推理
✅ 正文结构明显更完整

而这个工具——根本没有真正被调用。


四、真正起作用的是什么?

不是工具返回的信息。

而是:

工具的“存在”本身改变了模型的任务理解。

工具字段并不是可以忽略的小参数。

它是一个强环境信号:

  • 你现在不只是聊天
  • 你处在 agent 环境
  • 你拥有外部行动能力
  • 你需要先判断是否要调用工具
  • 你应该规划答案,而不是随口给个简答

五、为什么没调用工具也会影响输出?

LLM 并不是按代码分支执行:

if 调用工具:  
    进入 A 模式  
else:  
    忽略 tools  

模型会把整个请求体当作上下文的一部分。

包括:

  • 用户问题
  • 工具名称
  • 工具描述
  • 参数 schema
  • 当前支持 tool calling 的环境

即使最后没发起 tool_call,这些信息已经影响了行为方式。


六、我观察到的三层效应

1️⃣ 规划倾向增强

模型更像“执行任务的助手”,而非闲聊机器人。

更容易:

  • 先分析任务
  • 列出回答结构
  • 再展开正文

2️⃣ 完整性标准提高

普通问答模式:

给个正确简答就够。

Agent 模式:

需要交付一份完整结果。

于是背景、分期、定义、结论自动补齐。


3️⃣ Tool-calling 训练“溢出”

现代模型大量训练过:

  • tool use
  • function calling
  • agent workflow

这些训练带来的不仅是“会调工具”,还包括:

  • 审题
  • 找信息缺口
  • 规划步骤
  • 组织结构
  • 最终交付

即便没有真正调用工具,这套行为模式可能已经被触发。


七、工具名本身也可能是变量

实验中使用的工具名:

openrouter_datetime  

这个名字语义很强,暗示:

  • 类似 OpenRouter 的环境
  • agent 框架内置工具

对比:

  • openrouter_datetime
  • get_time
  • f1

直觉上,第一个更像真实 agent 环境。

虽然无法百分百证明工具名权重,但它很可能也是影响因子。


八、对开发者的启示

很多人做模型对比时,只对齐:

  • prompt
  • model 名字
  • token 限制

但真正影响模型状态的还包括:

  • 是否声明 tools
  • 工具名称
  • 工具描述
  • 是否存在多轮 agent 上下文
  • 平台是否注入隐藏 system prompt
  • 是否允许 function calling
  • 是否存在 planner / router / middleware

很多“模型质量差异”,本质可能是:

运行时环境差异。


九、一句话总结

工具不一定要被调用,光是“工具存在”,就足以把模型从普通问答模式推向 agent 模式。

于是现象变得合理:

  • OpenRouter 更详细
  • 原生 DeepSeek 裸调用更短
  • 加上 tools 后风格突然靠近

十、可以继续做的对照实验

1️⃣ 有工具 vs 无工具

只改 tools 字段,其余完全不变。


2️⃣ 工具名有语义 vs 无语义

对比:

  • openrouter_datetime
  • get_time
  • f1

3️⃣ 工具描述详细 vs 敷衍

对比:

  • Get the current datetime in UTC.
  • tool

4️⃣ 有 thinking vs 无 thinking

拆开控制:

  • 工具模式
  • 推理模式

看两者是叠加关系还是单一主导。


结语

对大模型来说,API 参数不是“纯配置”。

很多字段本身就是 prompt 的一部分。

tools 表面是功能开关,实际上在告诉模型:

  • 你扮演什么角色
  • 你处在什么环境
  • 你的能力边界
  • 输出应该达到什么标准

有时候改变输出的不是“信息变多”,而是:

模型意识到这次不能随便答一下。

如果你也遇到:

  • 同样问题在不同平台回答风格差很多
  • prompt 很像但一个版本更完整
  • 开了 function calling 之后模型突然“变聪明”

建议回头检查:

你比较的可能不是同一个 prompt,甚至不是同一种任务模式。