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
相关产品推荐
相关产品推荐

