基于Langchain与text-davinci-003处理超Token限制大JSON方案问询
使用Langchain结合text-davinci-003处理超Token限制的大型JSON生成方案
原JSON扩容5倍后,GPT-3分词下Token数约17160,远超text-davinci-003的4096上下文限制,且该模型对JSON空格格式处理稳定性较差。结合Langchain的四种文档处理策略,最佳方案为Map Reduce模式 + 结构化提示约束 + 输入JSON压缩,具体分析和实现如下:
一、方案选型理由
对比Langchain的四种处理方式:
- Stuff:直接将所有内容塞入prompt,token远超限制,完全不可行。
- Map Rerank:仅针对单块内容生成评分并排序,无法生成完整结构化JSON,不适用当前需求。
- Refine:迭代更新结果,多次迭代后易出现格式漂移,非CODEX模型维护JSON完整结构的成本极高。
- Map Reduce:将大型JSON拆分为独立、结构一致的子块,每个子块独立处理生成合规JSON片段,最后合并为完整文档,既能规避Token限制,又能降低单块处理的格式出错概率,最适配当前场景。
二、关键优化措施
1. 输入JSON压缩
分块前先将原JSON转换为无空格、无换行的紧凑格式,可大幅减少Token占用:
- 示例JSON压缩后,GPT-3分词Token数可从3432降至约2200,5倍扩容后的单块Token数能稳定控制在3500以内(预留500Token给prompt和输出空间)。
2. 结构化提示约束
针对每个子块的处理,必须在prompt中明确格式要求,避免模型生成冗余空格或格式错误:
- 要求输出无多余空格的紧凑JSON片段
- 严格遵循原JSON的字段结构(
id、category、details等) - 确保
details数组内的effect、cheat字段完整
示例prompt模板:
请基于以下JSON子块,生成结构完全一致的紧凑格式JSON片段,不要添加任何额外内容或空格: {compressed_sub_json}
3. 分块策略
按原JSON的顶级对象(每个id对应的category块)拆分,5倍扩容后的20个顶级对象可直接拆分为20个独立子块,每个子块的Token数均在模型上下文范围内。
三、Langchain实现示例
from langchain.llms import OpenAI from langchain.prompts import PromptTemplate from langchain.chains.summarize import load_summarize_chain from langchain.docstore.document import Document import json # 初始化text-davinci-003模型,关闭随机性保证格式稳定 llm = OpenAI(model_name="text-davinci-003", temperature=0) # 加载并压缩扩容后的大型JSON with open("large_expanded.json", "r") as f: large_json = json.load(f) # 将每个顶级对象转换为紧凑JSON字符串 compressed_sub_blocks = [json.dumps(block, separators=(",", ":")) for block in large_json] # 转换为Langchain Document对象 docs = [Document(page_content=block) for block in compressed_sub_blocks] # 定义Map阶段prompt:处理单个子块生成合规JSON片段 map_prompt = """请基于以下JSON子块,生成结构完全一致的紧凑格式JSON片段,不要添加任何额外内容或空格: {page_content} """ map_prompt_template = PromptTemplate(input_variables=["page_content"], template=map_prompt) # 定义Combine阶段prompt:合并所有子块为完整JSON数组 combine_prompt = """请将以下所有JSON片段合并为一个完整的JSON数组,确保格式正确,无多余空格: {text} """ combine_prompt_template = PromptTemplate(input_variables=["text"], template=combine_prompt) # 加载Map Reduce链 chain = load_summarize_chain( llm=llm, chain_type="map_reduce", map_prompt=map_prompt_template, combine_prompt=combine_prompt_template, verbose=True ) # 执行链并生成结果 result = chain.run(docs) # 验证格式并保存,如需格式化显示可最后用Python处理 try: final_json = json.loads(result) # 如需带缩进的美观格式,用Python自行格式化 with open("final_large_json.json", "w") as f: json.dump(final_json, f, indent=4) except json.JSONDecodeError: print("生成的JSON格式有误,请检查prompt或子块拆分逻辑")
四、额外注意事项
- 若部分子块Token仍超标,可进一步拆分
details数组为更小的子块,处理后再合并回对应category对象。 - 始终将模型temperature设为0,避免随机性导致的格式错误。
- 最终的JSON格式化(添加空格、缩进)建议用Python的
json模块完成,规避模型处理空格的不稳定问题。
内容的提问来源于stack exchange,提问作者NotAPhoenix
相关产品推荐
相关产品推荐

