当前位置:首页 > 技术分析 > 正文内容

如何控制 LLM 的输出格式和解析其输出结果?

ruisui885个月前 (01-23)技术分析22

深入了解我们如何使用生成式 Al 模型进行创新实验,从而拓宽 GitHub Copilot 在开发者整个生命周期中的应用。

本文经授权转载宝玉老师的个人博客(微博@宝玉xp ),链 接https://baoyu.io/blog/prompt-engineering/how-to-parse-the-output-from-llm


责编 | 夏萌
出处 | baoyu.io

现在很多人对于如何使用像 ChatGPT 这样的 LLM 已经比较有经验了,可以使用各种不同的 Prompt 得到自己想要的结果。但有时候我们的使用场景不局限于手动操作,而是需要结合程序去调用 API,并且解析 API 的返回结果,从而实现一些自动化的功能。但是 LLM 的输出不确定性很大,所以我们需要想办法去控制 LLM 的输出格式,从而让程序得到稳定的输出,并且进一步对输出结果进行解析。

方法一:使用 Function Calling

Function Calling 是 OpenAI 不久前退出的针对 GPT API 的一个功能,可以让 LLM 决定在输出最终结果前,是否需要调用某个特定函数。比如说有用户问今天天气是什么,那么 LLM 在输出结果前,会先输出一个中间结果,告诉你需要调用天气相关的函数,并且传入这个函数的参数是“今天”。这样你就可以去调用天气函数,拿到结果后告诉 LLM,再输出最终结果给用户。

这个功能本意不是用来控制格式输出的,但是它在告诉我们该调用什么函数时,为了方便解析,给我们输出的是一个标准 JSON 格式,即使是 GPT-3.5,也能得到比较稳定的 JSON 格式。所以我们可以利用这个特性,来控制 LLM 的输出格式。

我们可以把要 ChatGPT 输出的内容定义成一个函数,但我们实际上不需要执行这个函数,只要 LLM 给我们的输出结果。

举例来说,我希望 ChatGPT 给我输出的格式是一个 Object:

{ "name": "John", "age": 30, "city": "New York"}
我们可以在调用 GPT 的时候定义一个函数,将函数的参数格式和要输出的 JSON 格式对应起来:
{ "name": "getUserInfo", "description": "Get user information", "parameters": { "type": "object", "properties": { "name": { "type": "string", "description": "User's fullname" }, "age": { "type": "number", "description": "User's age" }, "name": { "type": "string", "description": "User's city" }, }, "required": ["name", "age", "city"] }}

然后在调用 GPT 的时候,我们可以这样写:

messages = [{"role": "user", "content": "My name is John, I'm 30 years old, and I live in New York."}]functions = [{ "name": "getUserInfo", "description": "Get user information", "parameters": { "type": "object", "properties": { "name": { "type": "string", "description": "User's fullname" }, "age": { "type": "number", "description": "User's age" }, "name": { "type": "string", "description": "User's city" }, }, "required": ["name", "age", "city"] }}]openai.ChatCompletion.create( model="gpt-3.5-turbo-0613", messages=messages, functions=functions, function_call={ name: "getUserInfo" }, # 强制指定调用 getUserInfo 函数)

这样我们就可以得到一个稳定的 JSON 格式的输出结果。这种方法的局限在于必须 API 支持 Function Calling。

Function Calling 的具体用法可以参考 OpenAI 的文档:https://platform.openai.com/docs/guides/gpt/function-calling

方法二:使用 few-shot,给出输出格式样例

如果 API 不支持 Function Calling,那么我们可以使用 few-shot 的方式,给出一个甚至多个输出格式的样例,让 LLM 按照这个样例去输出结果。

比如我在翻译时,会让 LLM 翻译两次,一次直译一次意译,然后采用意译的结果。这种情况下我不需要用 JSON 格式,只需要简单的用特殊字符将两次结果隔开,然后按照特殊字符一分割,就可以得到意译的结果。

You are a friendly translation assistant. You'll help me translate English text into Chinese in two simple steps, ensuring the translation is easy to understand and free from any filler words like "you know", "so", and "eme". Here's how you will assist:
Literal translation focuses on preserving the original text's literal meaning, while free translation adjusts the expression based on the target language's habits while maintaining the original meaning.
1. You will provide a Literal Translation, preserving the original line breaks and paragraph format.2. You will then provide a free translation based on the literal translation, again preserving the format.
Please ensure that your output only contains the Literal Translation and the free translation, separated by "----" and new lines.
Output:[Literal Translation]
----
[free translation]

如果是 JSON 格式,也可以用 few-shot 说明,但是对于 GPT-3.5,稳定性不够好,有时候会出现不符合格式的情况。

Ensure that your response can be parsed by Python json, use the following format as an example:{ "name": "John", "age": 30, "city": "New York"}

方法三:使用 TypeScript 类型声明

这个方法仅适用于 GPT-4,你可以在 Prompt 中,将要输出的格式,用 TypeScript 的类型定义出来,甚至你还可以写上注释对部分字段进行详细的说明。这样 GPT-4 就会按照你的类型定义,输出符合格式的结果。

Your output should resemble a VALID JSON Object with the type TranslatedResult as illustrated below:type TranslatedResult = { // The comprehensive translated content from step 1 fullTranslatedContent: string; // All individual translated sentences. translatedSentences: Array<{ // A distinct translated sentence. translated: string; // Related input items, 1 translated sentence corresponds to 1 or more input items related: Array<{ // The timestamp of the input item timestamp: number; // The initial word of the related input item. firstWord: string; }> }>;};

输出结果参考

ChatGPT 的输出结果控制

如果是 ChatGPT,由于是网页直接操作,并且它支持 Markdown 格式,通常我会把我想要的结果放在 Markdown 的代码块中,这样就可以直接复制粘贴出来,但有时候也不是很稳定。

参考 Prompt:

请按照上面的规则和下面的格式打印翻译结果,返回格式如下,"{xxx}"表示占位符:### 直译{直译结果}####### 意译\`\`\`{意译结果}\`\`\`

容错处理

由于生成式 AI 现阶段的特点,我们很难保证输出结果的稳定性,所以我们需要对输出结果进行容错处理,以防止程序出错。这是我的一些经验总结:

1. 降低 temprature 参数的值会让结果更稳定。

temprature 越低,输出结果越稳定,当然温度低会影响输出结果的多样性,你可以灵活运用,比如出错后降低 temprature 值。

2. 对 JSON 结果进行容错处理

即使是 GPT-4,输出 JSON 时也不够稳定,经常会错误输出多余的逗号或者引号,但是老是重试也废 token,所以最好是用日志把出错的结果都记录下来,找出其中的规律,然后做一些字符串预处理,降低出错概率。

比如这里是我针对我的程序写的一个处理 JSON 错误的函数:

export const parseJson = (text: string) => { try { return JSON.parse(text); } catch (e) { let fixedContent = text .replace(/"},"\n/g, '"},\n') .replace(/"}"\n/g, '"}\n') .replace(/}"$/g, "}") .replace(/}]}]"/g, "}]}]") .replace(/]"\n?$/g, "]") .replace(/}]},"/g, "}]},") .replace(/}]}"/g, "}]}"); return JSON.parse(fixedContent); }};

仅供参考,最好还是你根据自己的 JSON 格式,记录日志,然后针对你的错误情况去写容错函数。

以上就是我对于我在日常使用 LLM 中,如何控制输出结果格式,以及如何对输出结果进行解析的一些经验总结,希望对你有帮助。也欢迎分享你的经验,一起进步。

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/490.html

分享给朋友:

“如何控制 LLM 的输出格式和解析其输出结果?” 的相关文章

vue:组件中之间的传值

一、父子组件之间的传值----props/$emit1、父组件向子组件传值--props2.子组件想父组件传值-this.$emit('select',item)二、父组件向下(深层)子组件传值----provide/injectprovide:Object | () => O...

vue中组件之间的通信方式

** 1.1 父子组件**a. 父向子传数据: 第1种: 父通过属性传值,子组件通过props接收数据(注:props传过来的数据是单向的,不可以进行修改)第2种:子组件可以通过$parent来获取父组件里的数据和调用父组件的方法(注:数据是双向的,还要注意如用了UI组件并且在该UI组件里重新定义一...

Gitlab之间进行同步备份

目前,我们公司有两个研发团队,分别在北京和武汉,考虑到访问速度的问题,原有武汉的研发环境在近端部署。也就是北京和武汉分别有两套独立的研发管理环境,虽然这解决了近端访问速度的问题,但是管理上较为分散,比如研发环境备份和恢复就是最重要的问题之一。最近,处于对安全性和合规性的考虑,希望将北京和武汉的源代码...

全新斯柯达柯珞克Karoq深度评测:大众替代品

“斯柯达柯珞克是一款出色的全能家庭 SUV,具有许多有用的功能”价格36,605 英镑- 49,190 英镑优点方便的 VarioFlex 后排座椅非常适合家庭入住驾驶乐趣缺点保修期短保守的内饰性格比Yeti少结论——斯柯达柯珞克是一辆好车吗?斯柯达柯珞克是在辉煌的七座 斯柯达柯迪亚克之后推出的,因...

数组、去重、排序、合并、过滤、删除

ES6数字去重 Array.from(new Set([1,2,3,3,4,4])) //[1,2,3,4] [...new Set([1,2,3,3,4,4])] //[1,2,3,4]2、ES6数字排序 [1,2,3,4].sort(); // [1, 2,3,4],默认是升序...

vue-router是如何解析query参数呢? #前端

vue-router 中的 query 解析。1. 大家好,我是龙仔。今天来分享 vue-router 是如何解析快乐参数的,因为使用 vue 路由会传 query 参数和快乐参数,所以从 vue 的角度来看如何解析传递的快乐参数。2. 基础知识大家应知道,快乐参数结构如:a、b、c、a、b、c、a...