V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
lqw3030
V2EX  ›  问与答

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

  •  
  •   lqw3030 · 16 天前 · 2699 次点击
    • 最近遇到一个问题,无论我用哪家(智谱、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}”。 想请教下各位是怎么解决的
    33 条回复    2024-06-05 23:02:36 +08:00
    mekingname
        1
    mekingname  
       16 天前   ❤️ 3
    我使用 tool calling 来实现。

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

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

    以下是一个输出示例
    leehaoze98
        26
    leehaoze98  
       15 天前   ❤️ 1
    不小心发出去了,续楼上:

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

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

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

    只能是多种策略一起用,完全指望模型,代价高不稳定
    lqw3030
        27
    lqw3030  
    OP
       15 天前
    @Cyron 晚些试了下,不知道是否是我调用的 API 问题,我参照文内编辑了 prompt ,整体输出质量是提高了,但是还是会出现类似```json 这样的 markdonw 头,好在简单的 substring 可以处理
    cheng6563
        28
    cheng6563  
       15 天前
    问题是语言模型你不让他滔滔不绝说一堆的话,他的智力会有不少限制。
    yangyaofei
        29
    yangyaofei  
       15 天前
    用 CFG 去控制, 比如 Guidance 和 OutLines 这种项目
    RRRoger
        30
    RRRoger  
       15 天前
    https://mp.weixin.qq.com/s/gMdQBlTdvGbhzi_NL3HGXQ
    大语言模型下的 JSON 数据格式交互
    zhangwugui
        31
    zhangwugui  
       15 天前
    那返回 json 的话,还能流式输出么
    Cyron
        32
    Cyron  
       15 天前
    @lqw3030 #27 是的文本补全只能自己处理,如果想要 100%可用的 JSON 就用大模型的 JSON Mode ,参考 https://platform.openai.com/docs/guides/text-generation/json-mode
    Ironpan
        33
    Ironpan  
       12 天前
    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   ·   实用小工具   ·   2953 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 12:46 · PVG 20:46 · LAX 05:46 · JFK 08:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.