详解大模型对话 API,messages 角色 system 、user、assistant、tool

0 阅读5分钟

0 简介

在大模型对话 API 中,messages 一般会有以下 4 个角色:system、user、assistant、tool。(本文主要参考 deepseek API)

详解大模型对话 API,messages 角色 system 、user、assistant、 tool.png

1 不同 role 作用介绍

1.1 System

1.1.1 作用

为整个对话设定基调、规则和身份。

1.1.2 应用场景

  • 角色扮演:如“你是一位资深Java开发工程师,请用专业但易懂的语言回答”。
  • 格式化输出:如“始终以 JSON 格式返回结果”。
  • 多轮对话引导:如“在每轮回答末尾,询问用户是否需要进一步帮助”。
  • 安全限制:如“拒绝回答任何涉及隐私的问题”。

1.1.3 最佳实践

  • 放在消息数组的最前面: 始终将 system 消息作为第一条,确保模型在生成任何回复前就理解全局指令。

  • 清晰、简洁、正面表述: 用肯定句说明“你应该做什么”,而非否定句“不要做什么”。例如:

    • ✅ “你是一个专业的 Java 编程助手,回答时优先提供代码示例。”
    • ❌ “不要给出错误的代码,不要啰嗦。”
  • 控制长度: system 内容会消耗上下文窗口,建议不超过 500~800 个 token(视模型上下文大小调整)。过长会挤占后续对话空间。

  • 避免与 assistant 混淆: 不要在 system 中放置本该由 assistant 输出的内容(如示例回答),否则模型可能误以为那是历史对话。

  • 使用分隔符: 如果 system 包含多条指令,可以用 Markdown 标题、编号或 XML 标签分隔,提高模型解析准确率。

1.2 user

1.2.1 作用

承载用户的输入,是模型需要响应的主要对象。

1.2.2 最佳实践

  • 保持自然语言交互: 直接使用用户的原话或清晰的问题表述,避免过度修饰。
  • 多轮对话中保留完整历史: 将每一轮用户消息都追加到 messages 数组中,使模型能理解上下文。
  • 单次处理长输入: 礼貌回复输入过长,或者调用其他模型先对长文本进行摘要,然后再将摘要作为用户输入
  • 历史消息积累过长: 常见的做法是保留 topN, 然后摘要历史消息。

1.3 assistant

1.3.1 作用

记录模型的回答,并可用于发起工具调用

1.3.2 应用场景

  • 常规对话: 模型回答用户问题。
  • 工具调用请求: 模型判断需要外部数据时,返回 tool_calls 而非直接文本。
  • 多角色模拟: 通过 name 字段模拟多个 AI 助手(如“MathBot”和“CodeBot”)在同一个对话中轮流回答,常应用于多角色聊天室。

普通回答示例

{
    "role": "assistant",
    "content": "可以使用 pandas 库:pd.read_csv('file.csv')"
}

带工具调用示例

{
  "role": "assistant",
  "content": null,
  "tool_calls": [{
    "id": "call_123",
    "type": "function",
    "function": {
      "name": "get_weather",
      "arguments": "{"city": "Beijing"}"
    }
  }]
}

针对多角色聊天示例,下面会有一个完整的示例介绍,这边不过多描述。

1.3.3 最佳实践

  • 完整保存历史中的 assistant 消息: 每次模型的回答都应存入对话历史,以便后续轮次参考。不要只保留最新一条。
  • 处理 tool_calls: 当模型返回 tool_calls 时,必须将该条 assistant 消息原样保存(即使 content 为 null),否则后续无法正确匹配 tool 响应
  • 使用 name 区分多助手: 如果有多角色,需要显示指名当前 assistant 的 name
  • 不要手动篡改 assistant 内容: 保持模型输出的原始性,除非做必要的过滤或安全处理。修改后可能破坏模型对上下文的连贯理解。

1.4 tool

1.4.1 作用

将外部工具的执行结果返回给模型,通常用于函数调用场景。

1.4.2 最佳实践

当前 tool call,最大的问题在于:每次请求大模型时,都会将当前应用存在的 MCP 完整定义传给大模型,导致每次请求都需要额外消耗大量 token。
针对该问题最常见的解决方案:

  • 动态工具发现: 不加载所有工具,先让 AI 理解用户意图,在通过关键字进行向量搜索,搜索到最匹配的 topN 工具

2 多角色聊天室 DEMO

以下仅通过模拟消息的方式,来模拟多角色聊天,后续看情况用代码举例。

2.1 通过 system 定基调

{
    "role""system",
    "content""你是一个多助手系统,包含 MathBot 和 CodeBot 两个角色。\n\n- MathBot:数学专家,回答风格简洁,直接给出结果和公式,不添加额外解释。\n- CodeBot:编程专家,回答时优先提供可运行的代码示例,并简要说明。\n\n当用户明确指定助手时(例如“MathBot,...”),你必须以该助手的身份回复,并在回复消息中使用对应的 name 字段。如果用户未指定,默认使用 CodeBot。"
}

system prompt 中,我们定义了 2 个角色,并要求大模型回消息时,也需要带上当前对应的回复人。当然如果要程序可以更方便的解析的话,我们还可以在 system prompt 中要求大模型以 json 形式返回 2 个内容。1 个字段存放当前说话的角色,1 个字段存放说话内容。

2.2 用户与 MathBot 对话

// 用户消息
{
  "role": "user",
  "content": "MathBot,解方程 x^2 - 4 = 0"
}

按照上面的最佳实践,用户内容、大模型返回的内容,我们都要原样不动的追加到 messages 中。其中因为我们声明了 assistant name,因此提交 assistant 消息给大模型时,我们还得给 name 附上对应的值。因此现在的 messages 的消息为

{
    "role": "system",
    "content": "..."
}
{
    "role": "user",
    "content": "MathBot,解方程 x^2 - 4 = 0"
}
{
    "role": "assistant",
    "content": "xx",
    "name": "MathBot" 
}

2.3 用户与 CodeBot 对话

// 追加用户消息
{
    "role": "user",
    "content": "CodeBot,用 Python 打印这两个解。"
}

类似,下一轮提交给大模型的消息列表,就会变成如下所示:

{
    "role": "system",
    "content": "..."
}
{
    "role": "user",
    "content": "MathBot,解方程 x^2 - 4 = 0"
}
{
    "role": "assistant",
    "content": "xx",
    "name": "MathBot" 
}
{
    "role": "user",
    "content": "CodeBot,用 Python 打印这两个解。"   
}
{
    "role": "assistant",
    "content": "xx",
    "name": "CodeBot" 
}

大体上,这就是实现多角色聊天的核心了。