通过开发 GPT 联网模式了解 OpenAI Function Call

1,359 阅读1分钟

OpenAI Function Call 就是给 GPT 描述一下我们的函数,然后 gpt 会告诉我们调用哪个函数以及通过什么参数调用。

下面是联网模式的例子

1. 首先准备我们的函数,这里以 google 搜索为例

yarn add googleapis
const searchGoogle = async (input: string): Promise<customsearch_v1.Schema$Result[]> => {  
    try {  
        const customSearch = google.customsearch('v1')  
        const res = await customSearch.cse.list({  
            cx: config.google.searchId,  
            key: config.google.apiKey,  
            q: input,  
            start: 1,  
            num: 5,  
            hl: 'zh-CN',  
            safe: 'active',  
            cr: 'countryCN',  
            gl: 'cn',  
            filter: '1',  
        })  
        const items = res.data.items  
        if (items && items.length) {  
            return items  
        }  
        return undefined  
    } catch (e) {  
    console.error(e)  
    }  
    return undefined  
}

async function* search(json?: string): AsyncIterableIterator<string> {  
    if (!json) {  
        return  
    }  
    const args = JSON.parse(json)  
    const query = args.query  
    if (!query) {  
        return  
    }  
    const searchRes = await pluginService.googleSearch(query)  
    if (!searchRes) {  
        yield '搜索失败❌,请重试'
        return  
    }
    const msg = `这是我的提问:${question}\n这是我在${type}搜索“${query}”的结果:\n${  
        JSON.stringify(
            searchRes.map(s => ({  
                title: s.title,  
                snippet: s.snippet,  
            }))
        ) 
    }\n请结合搜索结果回答`
    yield* chatService.chatStream(user, msg)  
}

2. 然后是给 openai 的 functions 描述

const searchGoogleGptFunction: ChatCompletionFunctions = {  
    name: 'search_google_when_gpt_cannot_answer',  
    description: '当 gpt 遇到无法回答的或者需要搜索引擎协助回答时从 google 搜索',  
    parameters: {  
        type: 'object',  
        properties: {  
            query: {  
                type: 'string',  
                description: '搜索句,支持中文或者英文',  
            }  
        },  
    }  
}

3. 最后是调用 openai

async function* chatStream(  
    user: string | any
    question: string,
): AsyncIterableIterator<string> {  
    const histories = [] //todo getHistories
    const messages: GptMsg[] = [...histories, { role: 'user', content: question }]  
    const res = await openai.createChatCompletion({  
        model: model,  
        messages: messages,  
        stream: true,  
        functions: [searchGoogleGptFunction],  
        function_call: fun?.function_call,  
    }, {  
        responseType: 'stream',  
    })  
    let hasFunctionCall = false  
    let functionName = ''  
    let functionArguments = ''  
    readData: for await (const chunk of res.data) {  
        const lines = chunk  
            .toString()  
            .split('\n\n')  
            .filter((line: any) => line.trim().startsWith('data: '))  
  
        let text = ''  
        for (const line of lines) {  
            const data = line.replace(/^data: /, '').trim()  
            if (data === '[DONE]') {  
                break readData  
            }  
  
            const json = JSON.parse(data)  
            const delta = json.choices[0].delta  
            const functionCall = delta.function_call  
            if (functionCall) {  
                hasFunctionCall = true  
                if (functionCall.name) {  
                    functionName = functionCall.name  
                }  
                if (functionCall.arguments) {  
                    functionArguments += functionCall.arguments  
                }  
            } else {  
                const token = delta.content  
                if (token) {  
                    text += token  
                }  
            }  
        }  
        if (text) {  
            yield text  
        }  
    }  
    if (hasFunctionCall && name === 'search_google_when_gpt_cannot_answer') {  
        yield* search(functionArguments)  
    } 
}