V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
chouqiu
V2EX  ›  程序员

如何让 AI 稳定的输出指定 json 结构

  •  
  •   chouqiu · 52 天前 · 3464 次点击
    这是一个创建于 52 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求是:提取 word 文档内容,翻译成多个语种

    目前的实现方式是把 word 文档里的 xml 内容提取出来,整理成一个 list ,结构如下:

    ["待翻译的文本一", "待翻译的文本二"]
    

    使用的 prompt 如下:

    system prompt

    你是一个{industry}行业的{language}翻译专家,请将用户输入的文字翻译成{language},翻译结果需要严格按照用户输入的 JSON 内容进行翻译,翻译后返回的 JSON 结构与用户输入的 JSON 结构需要完全一致。请参考用户输入的术语库翻译 JSON 数组内容,翻译结果输出 JSON 格式。
    
    下面是一个用户输入内容示例:
    术语库:
    {"你好": "hello", "什么": "what"}
    需翻译的 JSON 内容:
    {"filename": "这是文件名", "items": ["你好", "这是什么", "你好"]}
    
    请严格按照下面的要求输出翻译结果:
    1. 翻译结果为合法的标准的 JSON 对象字符串(不要输出 markdown 格式),不要过度转义,输出稳定的合法的标准的 JSON 对象字符串
    2. 翻译结果 JSON 包含 filename 和 items 两个 key ,并保证 items 数组元素数量和待翻译的 items 数组元素数量一致
    3. 翻译结果需要严格按照用户输入的 JSON 内容进行翻译,翻译后返回的 JSON 结构与用户输入的 JSON 结构需要完全一致,并保证 items 数组元素数量和待翻译的 items 数组元素数量严格保持一致。
    4. 输出示例:{"filename": "this is filename", "items": ["hello", "what is it", "hello"]}
    

    user prompt

    术语库:
    xxxxxxxxxx
    需翻译的 JSON 内容:
    xxxxxxxxxx
    
    

    但是 AI 的响应结果,有时是 json 格式,有时是 markdown 格式,有时返回的 json 里面,items 的数量和待翻译的数量又不一致

    35 条回复    2025-05-29 11:26:53 +08:00
    miracleyin
        1
    miracleyin  
       52 天前
    取决于模型,有 json 模式的模型输出会稳定不少。
    其次,使用 langfun
    Latin
        2
    Latin  
       52 天前
    matrix1010
        3
    matrix1010  
       52 天前
    现在的闭源模型或者 ollama/vllm 这些基本都支持 structed output 了吧,你直接动态构建一个 schema 传过去不就行了。数组数量不一致你可以转换为 object: {"1": "hello", "2": "what is it", ...}, 强制 structed output 符合这个结构
    qieqie
        4
    qieqie  
       52 天前
    现在 vllm, sglang 这些推理端点的结构化输出可以直接用 cfg 状态机制导,屏蔽掉不符合语法规则的 token 输出。
    mbeoliero123
        5
    mbeoliero123  
       52 天前
    插楼问下,怎么处理乱码情况,我的 api 好像比较频繁出现乱码
    liudewa
        6
    liudewa  
       52 天前
    我司搞的 结构化 就稳定输出 json 结构 就用的 提示词让返回 包含 json 格式的字符串 然后根据关键词 截取需要的 json
    mercurylanded
        7
    mercurylanded  
       52 天前
    用 function call ,json 格式作为 input
    ruoxie
        8
    ruoxie  
       52 天前
    你是一个根据以下 TypeScript 类型定义将用户请求转换为 "PageConfig" 类型的 JSON 对象的服务,并且按照字段的注释进行处理:
    ```
    export type PageConfig = {
    filters: {
    component: string;
    /**
    * @description 翻译成英文,驼峰格式
    * @type {string}
    */
    key: string;
    /**
    * @description 保持原始内容,不要翻译
    * @type {string}
    */
    label: string;
    /**
    * @description 保持原始内容,不要翻译
    * @type {string}
    */
    placeholder: string;
    }[];
    columns: {
    slot: boolean;
    /**
    * @description 保持原始内容,不要翻译
    * @type {string}
    */
    title: string;
    /**
    * @description 翻译成英文,驼峰格式
    * @type {string}
    */
    dataIndex: string;
    /**
    * @description 翻译成英文,驼峰格式
    * @type {string}
    */
    key: string;
    }[];
    pagination: {
    show: boolean;
    page: string;
    size: string;
    total: string;
    };
    includeModifyModal: boolean;
    fetchName: string;
    result: string;
    serviceName: string;
    };
    ```
    以下是用户请求:
    """
    {"filters":[{"component":"range-picker","key":"transactionTime","label":"成交时间"},{"component":"input","key":"planName","label":"提成方案名称","placeholder":"提成方案名称(个人/店组/片区)"}],"columns":[{"slot":false,"title":"成交时间","dataIndex":"成交时间","key":"成交时间"},{"slot":false,"title":"申佣时间","dataIndex":"申佣时间","key":"申佣时间"},{"slot":false,"title":"业绩来源","dataIndex":"业绩来源","key":"业绩来源"},{"slot":false,"title":"所属片区","dataIndex":"所属片区","key":"所属片区"},{"slot":false,"title":"当前组织","dataIndex":"当前组织","key":"当前组织"},{"slot":false,"title":"提成类型","dataIndex":"提成类型","key":"提成类型"},{"slot":false,"title":"员工姓名","dataIndex":"员工姓名","key":"员工姓名"},{"slot":false,"title":"成交编号","dataIndex":"成交编号","key":"成交编号"},{"slot":false,"title":"分成角色","dataIndex":"分成角色","key":"分成角色"},{"slot":false,"title":"本次申佣业绩","dataIndex":"本次申佣业绩","key":"本次申佣业绩"},{"slot":false,"title":"提成","dataIndex":"提成","key":"提成"},{"slot":false,"title":"已算提成业绩","dataIndex":"已算提成业绩","key":"已算提成业绩"},{"slot":false,"title":"当月总提成业绩","dataIndex":"当月总提成业绩","key":"当月总提成业绩"},{"slot":false,"title":"提成方案名称","dataIndex":"提成方案名称","key":"提成方案名称"},{"slot":false,"title":"方案计算类型","dataIndex":"方案计算类型","key":"方案计算类型"}],"pagination":{"show":true,"page":"page","size":"size","total":"result.total"},"includeModifyModal":false,"fetchName":"fetchTableList","result":"[\"result\"][\"records\"]","serviceName":"getTableList"}
    """
    The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:
    ruoxie
        9
    ruoxie  
       52 天前
    https://github.com/microsoft/TypeChat 配合这个对返回的结果进行校验,把错误内容发过去再问一次,不过我用了这么久基本很少出错
    yexiaoqiu358
        10
    yexiaoqiu358  
       52 天前
    https://juejin.cn/post/7491240940126158900 试了一下这个,用 zod 去验证 josn 挺好的
    mumbler
        11
    mumbler  
       52 天前
    模型不听话,换更大更贵的模型
    rogerer
        12
    rogerer  
       52 天前
    1. prompt ,现在 LLM 在对齐阶段一般做过格式的对齐,所以直接让输出 JSON 效果就会不错,如果还是不行把温度系数调一下;
    2. 受限解码,大致思想是要求 LLM 的 output 必须符合某个语法结构,如果不行就重新采样。好处是可以保证一定不会出现格式错误,但是这样做的问题是会影响本身的性能,不推荐;
    visper
        13
    visper  
       52 天前
    发现有时候模型还是喜欢输出 json 的时候加上```json ```这样的 markdown 格式,即使已经不再输出其他解释文字了。所以后来我直接叫它输出这样的格式,自己再去截取出来了。
    darkengine
        14
    darkengine  
       52 天前
    不是提示语的问题,调用 API 的时候需要指定用 Structured Outputs ,并且定义好输出需要的字段。
    ningxing
        15
    ningxing  
       52 天前
    用 gpt4 和以上,很听话的,你让他往东它绝对不敢往西
    Qinnn
        16
    Qinnn  
       52 天前
    可以试试在输出 json 这部分提示词换成英文的。
    jingdongkehu
        17
    jingdongkehu  
       52 天前
    后面加一句,如果翻译错了我就把你卸载掉 试试
    mindsucker
        18
    mindsucker  
       52 天前
    限制 AI 的输出格式,会导致 AI 的推理能力下降不少,请谨慎使用
    lyxxxh2
        19
    lyxxxh2  
       52 天前

    看文档,应该有说怎么指定的。
    yplam
        20
    yplam  
       52 天前
    openai 的 api 很久之前就可以,一直在用很稳定
    anexplore
        21
    anexplore  
       52 天前
    通过 function_calling(or tools)实现 Structured Output
    chouqiu
        22
    chouqiu  
    OP
       52 天前
    收到,谢谢各位,我研究下 response_format ,都不知道这个
    BeautifulSoap
        24
    BeautifulSoap  
       52 天前
    模型支持 json mode 或者 structured outputs 的话时最简单的
    如果不支持但支持 function call ,那就用 function call
    如果不支持 function call ,那么这里有个很全的整理

    https://www.boundaryml.com/blog/structured-output-from-llms
    lasuar
        25
    lasuar  
       52 天前
    langchain 支持 结构化输出
    findstrx
        26
    findstrx  
       51 天前
    如果是调用 API 的话,有一个参数,可以强行指定 json 返回,这比在提示词里强调效果要好的多
    mkroen
        27
    mkroen  
       51 天前
    怎么没人提 pydantic-ai ,可以将 BaseModel 派生出的类作为参数传入,工具会自行校验返回结果
    Hundredwz
        28
    Hundredwz  
       51 天前
    自己部署的话,可以看看 sglang ,支持[结构化输出]( https://docs.sglang.ai/backend/structured_outputs.html),vllm 应该也一样。
    如果使用 api ,openai 是支持的,其他的没调研过,不了解了。
    Hundredwz
        29
    Hundredwz  
       51 天前
    conn457567
        30
    conn457567  
       51 天前 via Android
    可以试试 json-repair 这个库,一些小的格式错误它能修复
    macaodoll
        31
    macaodoll  
       51 天前
    结构化输出,这个开关打开,不过也得看你用的模型支持不支持,
    m319
        32
    m319  
       51 天前
    除了 api 中指定结构化输出以外,还有一个提示词层面的小技巧,由于 llm 会模仿输入的格式,所以只要输入格式也用 json 就行,不过也看模型指令遵循情况

    如何让大语言模型输出 JSON 格式? - HowardZhangdqs 的回答 - 知乎
    https://www.zhihu.com/question/656512469/answer/3515553778
    wxxxcxx
        33
    wxxxcxx  
       51 天前
    可以学习下 anthropic 的提示工程文档,里面很多技巧是通用的。

    https://docs.anthropic.com/zh-CN/docs/build-with-claude/prompt-engineering/prefill-claudes-response
    wxxxcxx
        34
    wxxxcxx  
       51 天前
    @wxxxcxx 一般可以使用 xml 结合示例,然后使用预填充,能达到比较好的效果
    realJamespond
        35
    realJamespond  
       51 天前
    不听话可以微调 lora 参数随机生成 1000 条指定格式 json 数据
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2806 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 08:39 · PVG 16:39 · LAX 01:39 · JFK 04:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.