You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中如何提前判断OpenAI Chat Completion返回函数调用或消息?

解决NestJS中OpenAI函数调用与流式响应的适配问题

核心矛盾是OpenAI无法提前告知返回类型,无需纠结“提前判断”,直接通过调用策略调整适配需求,以下是几个可行方案:

方案一:先执行非流式调用判断类型,再分支处理

先发起一次非流式的createChatCompletion调用,拿到完整返回结果后判断是否需要执行函数:

  • 检查返回结果中choices[0].message.function_call是否存在,或finish_reason是否为function_call
  • 如果存在函数调用:执行对应的数据库保存逻辑,再发起流式调用生成最终回答返回给客户端
  • 如果不存在函数调用:直接发起流式调用返回普通消息

NestJS代码示例

import { Injectable } from '@nestjs/common';
import { OpenAIApi, Configuration, CreateChatCompletionResponse } from 'openai';

@Injectable()
export class ChatService {
  private openai: OpenAIApi;

  constructor() {
    const config = new Configuration({ apiKey: process.env.OPENAI_API_KEY });
    this.openai = new OpenAIApi(config);
  }

  async handleChat(messages: Array<{role: string, content: string}>) {
    // 第一步:非流式调用判断是否需要函数调用
    const nonStreamResponse = await this.openai.createChatCompletion({
      model: 'gpt-3.5-turbo-0613',
      messages: messages,
      functions: [
        {
          name: 'save_record',
          description: '保存聊天记录到数据库',
          parameters: {
            type: 'object',
            properties: {
              content: { type: 'string', description: '聊天内容' },
              userId: { type: 'string', description: '用户ID' }
            },
            required: ['content', 'userId']
          }
        }
      ],
      function_call: 'auto' // 让AI自动决定是否调用函数
    });

    const message = nonStreamResponse.data.choices[0].message;
    if (message.function_call) {
      // 解析函数参数并执行数据库保存
      const args = JSON.parse(message.function_call.arguments);
      await this.saveRecordToDb(args.content, args.userId);

      // 保存后发起流式调用生成最终回答
      return this.openai.createChatCompletion({
        model: 'gpt-3.5-turbo-0613',
        messages: [
          ...messages,
          message, // 把AI的函数调用消息加入上下文
          {
            role: 'function',
            name: 'save_record',
            content: JSON.stringify({ status: 'success' }) // 告知AI函数执行结果
          }
        ],
        stream: true
      });
    } else {
      // 无函数调用,直接返回流式回答
      return this.openai.createChatCompletion({
        model: 'gpt-3.5-turbo-0613',
        messages: messages,
        stream: true
      });
    }
  }

  private async saveRecordToDb(content: string, userId: string) {
    // 数据库保存逻辑实现
  }
}

方案二:流式调用中途判断,动态切换逻辑

发起流式调用后,先监听返回的chunk,判断是否出现函数调用的标识:

  • 流式返回的每个chunk中,choices[0].delta.function_call会逐步返回函数调用的内容(name和arguments片段)
  • 一旦检测到delta.function_call存在,立即终止当前流的客户端推送
  • 拼接完整的函数调用参数,执行数据库保存
  • 重新发起流式调用生成最终回答并返回

注意事项

  • 需要在NestJS中处理流式响应的中断,比如用Observable控制流的订阅与取消
  • 要确保函数调用的参数拼接完整,避免因中途中断导致参数缺失

方案三:通过Prompt约束减少不确定性

在system prompt中明确告知AI的行为规则,比如:

仅当用户明确要求“保存聊天记录”或类似指令时,调用save_record函数;其他所有情况直接返回自然语言回答,不得调用任何函数。

这种方式能降低AI误触发函数调用的概率,让判断逻辑更可控,但无法完全避免AI的偏差,适合对精度要求不是极高的场景。

额外提示

  • 方案一的缺点是会多消耗一次API的token,且增加少量延迟,但胜在逻辑简单可靠
  • 方案二更节省token,但需要处理流式中断和参数拼接的细节,复杂度稍高

内容的提问来源于stack exchange,提问作者DeonV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 14:07:41