大家是如何限制 LLM 输出格式为 JSON - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xyooyx
V2EX    问与答

大家是如何限制 LLM 输出格式为 JSON

  • &nsp;
  •   xyooyx 2024-06-02 10:34:48 +08:00 7358 次点击
    这是一个创建于 565 天前的主题,其中的信息可能已经有所发展或是发生改变。
    • 最近遇到一个问题,无论我用哪家(智谱、moonshot 、DeepSeek...等)都会存在有一定概率回复带引导词,或非完整的 json:
    { "usage": { "prompt_tokens": 185, "completion_tokens": 304, "total_tokens": 489 }, "created": 1717295221, "model": "GLM-4", "id": "123", "error": null, "choices": [ { "finish_reason": "stop", "index": 0, "message": { "role": "assistant", "content": "根据您提供的信息,我为您做了以下规划:\n\n```json\n{\n \"planDays\": [\n {\n \"dayPlanOrder\": 0,\n \"dayStations\": [\n {\n \"stationName\": \"腾格里沙漠\",\n \"stationOrder\": 0,\n \"stationDescription\": \"中国第四大沙漠,体验沙漠探险和沙丘摩托\",\n \"stationTag\": \"探险,自然景观\",\n \"stationActivity\": \"沙漠徒步,骑骆驼,沙丘摩托\",\n \"timeUsed\": 120\n },\n {\n \"stationName\": \"贺兰山\",\n \"stationOrder\": 1,\n \"stationDescription\": \"阿拉善著名景点,参观贺兰山岩画\",\n \"stationTag\": \"历史,文化,自然景观\",\n \"stationActivity\": \"参观岩画,登山\",\n \"timeUsed\": 90\n },\n {\n \"stationName\": \"巴丹吉林沙漠\",\n \"stationOrder\": 2,\n \"stationDescription\": \"中国第三大沙漠,欣赏沙漠日落\",\n \"stationTag\": \"自然景观\",\n \"stationActivity\": \"欣赏日落\",\n \"timeUsed\": 60\n }\n ]\n }\n ]\n}\n```\n\n 这个行程涵盖了阿拉善的主要景点,您可以根据个人兴趣选择参加的活动。如果选择自驾出行,可以在景点附近寻找停车场。祝您在阿拉善度过愉快的一天!", "name": null, "tool_call_id": null, "tool_calls": null }, "delta": null } ], "task_id": null, "request_id": null, "task_status": null } 
    • 上述 content 字段中期望的理想的是只有纯粹的 json ,但实际字段中多出了“根据您提供的信息,我为您做了以下规划:\n\n```json\n”,并且是 markdown 格式的
    • 尽管我已经在 prompt 中加入了“参照以下格式输出,直接给出规划的结果,不需要添加任何引导性文本,输出的结果符合标准 json 格式{someKey:someValue}”。 想请教下各位是怎么解决的
    第 1 条附言    193 天前

    以下是spring ai项目中使用的prompt实测能够达到比较高的约束力,给各位朋友提供个思路:

    Your response should be in JSON format.Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation.Do not include markdown code blocks in your response.Remove the ```json markdown from the output.Here is the JSON Schema instance your output must adhere to: ```{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"someString":{"type":"string"}},"additionalProperties":false}``` 
    33 条回复    2024-06-05 23:02:36 +08:00
    mekingname
        1
    mekingname  
       2024-06-02 10:41:04 +08:00   3
    我使用 tool calling 来实现。

    定义一个函数,接受 n 个参数,这些参数就是你的 json 里面对应的各个字段。然后让大模型通过 tool calling 去调用这个函数就可以了。在函数里面拿到这些参数,就是你需要的已经格式化以后的数据。
    xyooyx
        2
    xyooyx  
    OP
       2024-06-02 10:44:55 +08:00
    @mekingname tool/funcation call 有碰到过非期望响应的情况不
    yinmin
        3
    yinmin  
       2024-06-02 10:45:55 +08:00 via iPhone   2
    调用 api 时,可以是多组对话,因此,你加几组“一问一答”到 message 里,给 gpt 做参考,而不是写在一条信息里
    maolon
        4
    maolon  
    2024-06-02 10:48:54 +08:00 via Android
    可能无关: gpt 可以指定 return as json object ,以及比较好奇楼上的 tool calling 能否解决嵌套字段问题?
    mumbler
        5
    mumbler  
       2024-06-02 11:32:44 +08:00
    指令跟随能力还是不够好,我用 gemini ,可以设置"response_mime_type": "application/json",几乎没遇到过加料的情况
    june4
        6
    june4  
       2024-06-02 11:36:00 +08:00
    就象楼上说的,给几个例子基本不可能出意外。
    yorhaha123
        7
    yorhaha123  
       2024-06-02 11:38:35 +08:00   1
    直接用正则表达式提取了
    yushi17
        8
    yushi17  
       2024-06-02 11:56:55 +08:00
    没有必要让大模型输出纯粹的 json 。你只要从里面找到 json 然后 parse 出来就行了。
    yushi17
        9
    yushi17  
       2024-06-02 11:58:09 +08:00
    可以参考 TypeChat: https://github.com/microsoft/TypeChat 就是我说的这个思路。
    izzy27
        10
    izzy27  
       2024-06-02 12:24:29 +08:00
    langchain 的 json parser
    m0unta1n886
        11
    m0unta1n886  
       2024-06-02 13:44:19 +08:00
    有个 github 项目专门处理这个问题的。
    codehz
        12
    codehz  
       2024-06-02 13:45:09 +08:00
    有些模型是自带这个的,不是我打广告,但是 minimax 那家是真的有,最关键是还能限制 json 格式,用一个类似 json schema 的语法
    (虽然实际用下来 bug 不少,尤其是和 array 类型配合,还是和模型本身的基础能力有关系。。。)
    akira
        13
    akira  
       2024-06-02 13:46:08 +08:00
    gpt 的话,有参数可以限制输出格式
    devliu1
        14
    devliu1  
       2024-06-02 14:22:07 +08:00 via Android
    gpt 可以直接指定
    xyooyx
        15
    xyooyx  
    OP
       2024-06-02 14:24:59 +08:00
    @m0unta1n886 https://github.com/RealAlexandreAI/json-repair 这个吗,我现在的做法是直接读取第一个{和最后一个},想说从语言模型本身出发解决这个问题
    xyooyx
        16
    xyooyx  
    OP
       2024-06-02 14:27:09 +08:00
    @yinmin 我去尝试下,先前的 prompt 模板都是参照 https://baoyu.io/translations/prompt-engineering/how-i-won-singapores-gpt-4-prompt-engineering-competition 里面建议的思路写的,我觉得你说的这个是个好主意
    xyooyx
        17
    xyooyx  
    OP
       2024-06-02 14:29:07 +08:00
    @maolon funcation 确实 function call 就是复杂的结构不好指定
    xyooyx
        18
    xyooyx  
    OP
       2024-06-02 14:35:27 +08:00
    @mumbler 我觉得可以这么指是最好得了,受限于调用环境,用的都是国内厂商的模型
    Cyron
        19
    Cyron  
       2024-06-02 14:47:48 +08:00 via iPhone   6
    之前做了几个试验性项目,用 dsl 约束+json_mode 效果稳定,写了个总结
    《 LLM 生成 Json 结构化数据的几种方案》 https://juejin.cn/post/7325429835387404307
    shampoo
        20
    shampoo  
       2024-06-02 16:43:35 +08:00
    题外话,做程序要讲究思维严谨、语义清晰:
    “限制输出格式为 JSON”这句话有歧义,应该改为“指定输出格式为 JSON 。”
    TheWalkingDead
        21
    TheWalkingDead  
       2024-06-02 19:48:57 +08:00
    @shampoo 你这真的是钻牛角尖,此地无银三百两。
    mekingname
        22
    mekingname  
       2024-06-02 20:14:45 +08:00
    @lqw3030 JSON 不能嵌套太深,否则可能拿到的结果跟预期不一致。
    wuyiccc
        23
    wuyiccc  
       2024-06-02 21:27:03 +08:00
    用的 langchain 的 output parser
    macaodoll
        24
    macaodoll  
       2024-06-02 21:57:18 +08:00 via Android
    国产的如果涉及到某些敏感词直接不按提示来的,用外面的没这个问题
    leehaoze98
        25
    leehaoze98  
       2024-06-02 23:48:30 +08:00
    模型本身支持限定输出为格式为 application/json 这种的效果最好,本身就是微调在模型内的。
    通过 Prompt 的方式约束,直接在 Prompt 内举出一个返回的示例效果是最好的,比如:

    ## 输出要求
    你的输出为 JSON 格式的字符串,压缩在一行内,包含两个字段,"KeyA"代表 XX ,"KeyB"代表 XX

    以下是一个输出示例
    leehaoze98
        26
    leehaoze98 &bsp;
       2024-06-02 23:51:04 +08:00   1
    不小心发出去了,续楼上:

    以下是一个输出示例:
    {"KeyA":"ValA","KeyB":"ValB"}

    通过举例子的方法约束吼,只能保证返回的 JSON 大概率是你要求的格式,但是模型还是有概率在 JSON 后追加一些自然语言来进行解释,或者是加入 MarkDown 语法(有些模型就这么调的)。

    这个时候只能是对大模型的返回进行处理,已经有些现成的库,比如 LangChain 的 Parser ,Python 、TS 和 Go 都有一个 JSON Repair 库。

    只能是多种策略一起用,完全指望模型,代价高不稳定
    xyooyx
        27
    xyooyx  
    OP
       2024-06-02 23:59:33 +08:00
    @Cyron 晚些试了下,不知道是否是我调用的 API 问题,我参照文内编辑了 prompt ,整体输出质量是提高了,但是还是会出现类似```json 这样的 markdonw 头,好在简单的 substring 可以处理
    cheng6563
        28
    cheng6563  
       2024-06-03 09:07:21 +08:00
    问题是语言模型你不让他滔滔不绝说一堆的话,他的智力会有不少限制。
    yangyaofei
        29
    yangyaofei  
       2024-06-03 09:25:57 +08:00
    用 CFG 去控制, 比如 Guidance 和 OutLines 这种项目
    RRRoger
        30
    RRRoger  
       2024-06-03 09:39:24 +08:00
    https://mp.weixin.qq.com/s/gMdQBlTdvGbhzi_NL3HGXQ
    大语言模型下的 JSON 数据格式交互
    zhangwugui
        31
    zhangwugui  
       2024-06-03 15:40:36 +08:00
    那返回 json 的话,还能流式输出么
    Cyron
        32
    Cyron  
       2024-06-03 17:46:45 +08:00
    @lqw3030 #27 是的文本补全只能自己处理,如果想要 100%可用的 JSON 就用大模型的 JSON Mode ,参考 https://platform.openai.com/docs/guides/text-generation/json-mode
    Ironpan
        33
    Ironpan  
       2024-06-05 23:02:36 +08:00
    1. function_call/tools 能力
    2. 模型支持直接 mode 为 json 的, 例如 gpt-3.5 好像现在就行了?
    3. prompt: ReAct/Few shot(带几个例子进去)/langextract 里面有个提取结构化数据的核心 prompt 可以去找找, 然后改改
    4. 一些细节:
    4.1 prompt 使用 markdown 格式, 且添加标题, 如果返回的 json 里有注释, 你可以用 markdown 的格式添加注意事项叫它不要输出其他无关的内容, 或者不要加注释.
    4.2 上下文里不一定都是一个 human+ai 的成对消息. 可以是一个 system message + 一个/多个 ai 消息(补充说明) + user 消息. 然后自己看情况调整.
    4.3 我自己使用的时候返回的 json, 一般都是 markdown, 然后正则解析.

    希望有所帮助.
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5053 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 42ms UTC 06:02 PVG 14:02 LAX 22:02 JFK 01:02
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86