黑马大模型RAG与Agent智能体实战教程LangChain提示词——26、RAG开发——JSONLoader(文档加载器、BaseLoader、JsonLines文件、text_content)jq
教程:https://www.bilibili.com/video/BV1yjz5BLEoY
代码:https://github.com/shangxiang0907/HeiMa-AI-LLM-RAG-Agent-Dev
-
JSONLoader 参数:
- file_path: 文件路径
- jq_schema: jq schema 语法,用于指定提取规则
- text_content: 抽取的是否是字符串,默认 True(False 时提取为 Python 对象)
- json_lines: 是否是 JsonLines 文件(每一行都是 JSON 的文件),默认 False
-
text_content总结:就是说如果用text_content=True,解析为字符串,那么使用jq_schema获取的类型必须是字符串,不能为其他类型比如字典、列表 -
原始的结果类型,完全由 jq_schema + JSON 结构 决定。text_content 决定这个结果能不能当作 page_content
文章目录
- RAG开发-24、JSONLoader
-
- jq介绍(JSONLoader依赖于jq)
- JSONLoader介绍
- →提示词:帮我根据图片内容,在目录@AI_LLM_RAG_Agent_Dev 创建代码29,介绍JSONLoader
- ←AI回复
- 运行代码
- 结果
- →问AI:@AI_LLM_RAG_Agent_Dev/29_LangChain_JSONLoader.py:138-139 我发现文件中存储utf-8编码的汉字是正常显示的,但是读取出来打印,变成unicode格式类似`\u`这种的值了,这是为什么,只需回答不用改代码
- ←AI回复
- →问AI:JSONLoader text_content参数string format是什么意思,我不太理解
- ←AI回复
- 问AI:使用JSONLoader text_content=False相较text_content=True有什么好处呢?
- AI回复
- →问AI:page_content 的类型是怎么决定的?是自动判断的吗?
- ←AI回复
- 问AI:所以说jq_schema和 JSON 结构 就已经决定了page_content的类型是吗?
- AI回复
- 总结
RAG开发-24、JSONLoader
jq介绍(JSONLoader依赖于jq)

JSONLoader介绍

→提示词:帮我根据图片内容,在目录@AI_LLM_RAG_Agent_Dev 创建代码29,介绍JSONLoader



←AI回复
查看现有代码结构和数据文件,以便创建 JSONLoader 示例代码。
[3 tools called]
创建 JSONLoader 示例代码。先创建所需的 JSON 示例文件,然后编写演示代码。
[1 tool called]
创建 JSON 示例文件,然后编写 JSONLoader 演示代码。
[4 tools called]
检查代码是否有错误:
[1 tool called]
已创建 JSONLoader 示例代码。内容如下:
创建的文件
- 29_LangChain_JSONLoader.py - 主演示文件
- stu.json - 单个 JSON 对象示例(包含嵌套对象和数组)
- stus.json - JSON 数组示例
- stu_json_lines.json - JsonLines 格式示例
代码包含的示例
-
示例1:jq_schema 基本语法 - 演示从单个 JSON 对象中提取数据
.- 提取整个对象.name- 提取字段.hobby[1]- 提取数组元素.other.addr- 提取嵌套字段
-
示例2:JSON 数组提取 - 演示从 JSON 数组中提取数据
.[]- 遍历数组.[].name- 提取所有对象的 name 字段
-
示例3:JsonLines 格式 - 演示加载 JsonLines 格式文件
- 使用
json_lines=True参数
- 使用
-
示例4:text_content 参数 - 演示
text_content参数的区别True:提取为字符串False:提取为 Python 对象
-
示例5:lazy_load() 方法 - 演示延迟流式加载
-
示例6:复杂 jq_schema - 演示更复杂的提取规则
代码遵循了现有代码风格(参考 28_LangChain_CSVLoader.py),包含中文注释和说明。可直接运行查看效果。
注意:使用 JSONLoader 前需要安装 jq 库:
pip install jq
运行代码
python3 AI_LLM_RAG_Agent_Dev/29_LangChain_JSONLoader.py
结果
================================================================================
LangChain JSONLoader 文档加载器示例
================================================================================
================================================================================
【示例1】jq_schema 基本语法 - 单个 JSON 对象
--------------------------------------------------------------------------------
创建示例 JSON 文件:./stu.json
示例 JSON 文件已创建:./stu.json
. - 提取整个 JSON 对象
--------------------------------------------------------------------------------
成功加载 1 个文档
文档 1:
page_content: {"name": "\u5468\u6770\u8f6e", "age": 11, "hobby": ["\u5531", "\u8df3", "RAP"], "other": {"addr": "\u6df1\u5733", "tel": "12332112321"}}
metadata: {'source': '/home/devbox/project/stu.json', 'seq_num': 1}
.name - 提取 name 字段(周杰轮)
--------------------------------------------------------------------------------
成功加载 1 个文档
文档 1:
page_content: 周杰轮
metadata: {'source': '/home/devbox/project/stu.json', 'seq_num': 1}
.hobby - 提取 hobby 数组
--------------------------------------------------------------------------------
成功加载 1 个文档
文档 1:
page_content: ["\u5531", "\u8df3", "RAP"]
metadata: {'source': '/home/devbox/project/stu.json', 'seq_num': 1}
.hobby[1] - 提取 hobby 数组的第二个元素(跳)
--------------------------------------------------------------------------------
成功加载 1 个文档
文档 1:
page_content: 跳
metadata: {'source': '/home/devbox/project/stu.json', 'seq_num': 1}
.other.addr - 提取嵌套对象 other 中的 addr 字段(深圳)
--------------------------------------------------------------------------------
成功加载 1 个文档
文档 1:
page_content: 深圳
metadata: {'source': '/home/devbox/project/stu.json', 'seq_num': 1}
================================================================================
【示例2】JSONLoader - JSON 数组提取
--------------------------------------------------------------------------------
创建示例 JSON 数组文件:./stus.json
示例 JSON 数组文件已创建:./stus.json
.[] - 提取数组中的每个对象(得到 3 个字典)
--------------------------------------------------------------------------------
成功加载 3 个文档
文档 1:
page_content: {"name": "\u5468\u6770\u8f6e", "age": 11, "gender": "\u7537"}
metadata: {'source': '/home/devbox/project/stus.json', 'seq_num': 1}
文档 2:
page_content: {"name": "\u8521\u4f9d\u4e34", "age": 12, "gender": "\u5973"}
metadata: {'source': '/home/devbox/project/stus.json', 'seq_num': 2}
文档 3:
page_content: {"name": "\u738b\u529b\u9e3f", "age": 11, "gender": "\u7537"}
metadata: {'source': '/home/devbox/project/stus.json', 'seq_num': 3}
.[].name - 提取数组中所有对象的 name 字段(得到 3 个名字)
--------------------------------------------------------------------------------
成功加载 3 个文档
文档 1:
page_content: 周杰轮
metadata: {'source': '/home/devbox/project/stus.json', 'seq_num': 1}
文档 2:
page_content: 蔡依临
metadata: {'source': '/home/devbox/project/stus.json', 'seq_num': 2}
文档 3:
page_content: 王力鸿
metadata: {'source': '/home/devbox/project/stus.json', 'seq_num': 3}
.[].age - 提取数组中所有对象的 age 字段
--------------------------------------------------------------------------------
成功加载 3 个文档
文档 1:
page_content: 11
metadata: {'source': '/home/devbox/project/stus.json', 'seq_num': 1}
文档 2:
page_content: 12
metadata: {'source': '/home/devbox/project/stus.json', 'seq_num': 2}
文档 3:
page_content: 11
metadata: {'source': '/home/devbox/project/stus.json', 'seq_num': 3}
================================================================================
【示例3】JSONLoader - JsonLines 格式
--------------------------------------------------------------------------------
创建示例 JsonLines 文件:./stu_json_lines.json
JsonLines 格式:每行都是一个独立的 JSON 对象
示例 JsonLines 文件已创建:./stu_json_lines.json
使用 JSONLoader 加载 JsonLines 文件:
--------------------------------------------------------------------------------
成功加载 3 个文档
所有文档内容:
文档 1:
page_content: {"name": "\u5468\u6770\u8f6e", "age": 11, "gender": "\u7537"}
metadata: {'source': '/home/devbox/project/stu_json_lines.json', 'seq_num': 1}
文档 2:
page_content: {"name": "\u8521\u4f9d\u4e34", "age": 12, "gender": "\u5973"}
metadata: {'source': '/home/devbox/project/stu_json_lines.json', 'seq_num': 2}
文档 3:
page_content: {"name": "\u738b\u529b\u9e3f", "age": 11, "gender": "\u7537"}
metadata: {'source': '/home/devbox/project/stu_json_lines.json', 'seq_num': 3}
================================================================================
【示例4】JSONLoader - text_content 参数区别
--------------------------------------------------------------------------------
1. text_content=True - 提取简单字符串值
--------------------------------------------------------------------------------
使用 jq_schema='.name' 提取字符串字段
成功加载 1 个文档
page_content 类型: <class 'str'>
page_content: 周杰轮
2. text_content=False - 提取复杂对象(字典、数组)
--------------------------------------------------------------------------------
使用 jq_schema='.' 提取整个 JSON 对象
成功加载 1 个文档
page_content 类型: <class 'str'>
page_content: {"name": "\u5468\u6770\u8f6e", "age": 11, "hobby": ["\u5531", "\u8df3", "RAP"], "other": {"addr": "\u6df1\u5733", "tel": "12332112321"}}
3. 错误示例:提取字典对象但 text_content=True
--------------------------------------------------------------------------------
使用 jq_schema='.' 提取整个对象,但 text_content=True(会报错)
预期的错误:Expected page_content is string, got <class 'dict'> instead. Set `text_content=False` if the desired input for `page_content` is not a string
解决方案:当 jq_schema 提取的是字典或数组时,必须设置 text_content=False
================================================================================
【示例5】JSONLoader lazy_load() 方法 - 延迟流式加载
--------------------------------------------------------------------------------
使用 lazy_load() 方法逐个加载文档:
--------------------------------------------------------------------------------
文档 1:
page_content: {"name": "\u5468\u6770\u8f6e", "age": 11, "gender": "\u7537"}
metadata: {'source': '/home/devbox/project/stu_json_lines.json', 'seq_num': 1}
文档 2:
page_content: {"name": "\u8521\u4f9d\u4e34", "age": 12, "gender": "\u5973"}
metadata: {'source': '/home/devbox/project/stu_json_lines.json', 'seq_num': 2}
文档 3:
page_content: {"name": "\u738b\u529b\u9e3f", "age": 11, "gender": "\u7537"}
metadata: {'source': '/home/devbox/project/stu_json_lines.json', 'seq_num': 3}
... (其余文档省略)
================================================================================
【示例6】JSONLoader - 复杂 jq_schema 用法
--------------------------------------------------------------------------------
创建复杂 JSON 文件:./complex_stu.json
复杂 JSON 文件已创建:./complex_stu.json
.[].name - 提取所有对象的 name 字段
--------------------------------------------------------------------------------
成功加载 2 个文档
文档 1:
page_content: 周杰轮
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 1}
文档 2:
page_content: 蔡依临
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 2}
.[].hobby - 提取所有对象的 hobby 数组
--------------------------------------------------------------------------------
成功加载 2 个文档
文档 1:
page_content: ["\u5531", "\u8df3", "RAP"]
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 1}
文档 2:
page_content: ["\u5531", "\u8df3"]
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 2}
.[].hobby[] - 提取所有对象的所有 hobby 元素(扁平化)
--------------------------------------------------------------------------------
成功加载 5 个文档
文档 1:
page_content: 唱
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 1}
文档 2:
page_content: 跳
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 2}
文档 3:
page_content: RAP
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 3}
... (还有 2 个文档)
.[].other.addr - 提取所有对象的地址
--------------------------------------------------------------------------------
成功加载 2 个文档
文档 1:
page_content: 深圳
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 1}
文档 2:
page_content: 北京
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 2}
.[] | {name: .name, addr: .other.addr} - 提取并组合多个字段
--------------------------------------------------------------------------------
成功加载 2 个文档
文档 1:
page_content: {"name": "\u5468\u6770\u8f6e", "addr": "\u6df1\u5733"}
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 1}
文档 2:
page_content: {"name": "\u8521\u4f9d\u4e34", "addr": "\u5317\u4eac"}
metadata: {'source': '/home/devbox/project/complex_stu.json', 'seq_num': 2}
已清理临时文件:./complex_stu.json
================================================================================
演示结束
================================================================================
提示:
- 示例 JSON 文件已创建在当前目录:
- stu.json(单个对象)
- stus.json(数组对象)
- stu_json_lines.json(JsonLines 格式)
- 可以手动编辑这些文件来测试不同的 JSON 格式
- 更多 jq 语法请参考:https://stedolan.github.io/jq/manual/
- 更多文档加载器请参考:https://docs.langchain.com/oss/python/integrations/document_loaders
→问AI:@AI_LLM_RAG_Agent_Dev/29_LangChain_JSONLoader.py:138-139 我发现文件中存储utf-8编码的汉字是正常显示的,但是读取出来打印,变成unicode格式类似\u这种的值了,这是为什么,只需回答不用改代码



←AI回复
出现这种情况的原因:
原因
-
JSON 序列化行为:JSONLoader 内部使用 Python 的
json模块处理数据。json.dumps()默认会将非 ASCII 字符(如中文)转义为\uXXXX格式,这是 JSON 标准允许的表示方式。 -
Python 对象的 repr() 显示:当
text_content=False时,page_content是字典/列表等 Python 对象。打印这些对象时,Python 会调用repr(),它也会将非 ASCII 字符显示为 Unicode 转义序列,这是 Python 的默认行为。 -
实际数据未改变:文件中的 UTF-8 汉字在内存中仍是正确的 Unicode 字符串;只是打印时被转义显示。
验证方法
可以这样验证实际内容:
# 如果 page_content 是字符串
print(doc.page_content.encode('utf-8')) # 查看实际字节
# 如果 page_content 是字典
import json
print(json.dumps(doc.page_content, ensure_ascii=False)) # 确保不转义 ASCII
总结:这是显示层面的转义,数据本身是正确的。如果需要避免转义显示,可以在打印时使用 json.dumps(..., ensure_ascii=False) 或直接访问字典的键值。
→问AI:JSONLoader text_content参数string format是什么意思,我不太理解
←AI回复
简短结论:text_content 的作用,就是决定 Document.page_content 里放的是“字符串”还是“原始 Python 对象(字典/列表等)”。
具体含义
-
text_content=True(默认,string format)- JSONLoader 会把抽取到的结果转成字符串,再放进
Document.page_content。 - 无论你用
jq_schema拿到的是一个字符串、数字、字典还是数组,最后都会被str(...)成一个字符串。 - 这样做的好处:后面的文本处理(切分、嵌入、向量检索等)都统一处理字符串,更简单。
- JSONLoader 会把抽取到的结果转成字符串,再放进
-
text_content=False- JSONLoader 会保持原始结构,按 JSON 解析后的 Python 对象存到
page_content中:- 对象 →
dict - 数组 →
list - 数字 →
int/float - 字符串 →
str(本来就是字符串)
- 对象 →
- 适合你想对结构化数据做进一步编程处理,而不仅仅当成纯文本时。
- JSONLoader 会保持原始结构,按 JSON 解析后的 Python 对象存到
结合你代码中的这两行
loader = JSONLoader(
file_path=json_file,
jq_schema=jq_schema,
text_content=False,
)
这里设置 text_content=False,意思是:按 jq_schema 抽取出来的 JSON 片段,不再转成字符串,而是按原始的 JSON 结构(dict / list 等)放进 Document.page_content,你打印时看到的是 Python 对这些对象的显示形式,而不是“文本格式”的 JSON。
问AI:使用JSONLoader text_content=False相较text_content=True有什么好处呢?
AI回复
一句话概括:text_content=False 的好处,是保留原始 JSON 结构(dict/list 等)做“结构化处理”,而不是把一切都压成字符串做“纯文本处理”。
和 text_content=True 的核心区别
-
text_content=True(默认)- 把 jq 抽取到的结果统一转成字符串放到
page_content。 - 更适合:后面要做的是纯文本相关的事情(切分、向量化、语义检索、LLM 问答等)。
- 把 jq 抽取到的结果统一转成字符串放到
-
text_content=False- 把 jq 抽取到的结果保留为原始 Python 对象:
dict/list/int/float/str。 - 更适合:后面要做的是结构化数据处理 / 编程逻辑,比如:
- 直接访问字段:
doc.page_content["name"]、doc.page_content["age"] > 18 - 过滤 / 聚合:求平均年龄、按性别分组等
- 再组装成别的结构写回数据库 / ES / DataFrame
- 直接访问字段:
- 把 jq 抽取到的结果保留为原始 Python 对象:
具体好处
-
1. 保留类型信息,不丢结构
True:{"age": 11}变成"{'age': 11}"这样的字符串,你要先解析回对象才能计算。False:直接是{"age": 11}(dict),可以立刻做数值运算、逻辑判断。
-
2. 方便写“业务逻辑”
- 例如只保留年龄 > 18 的学生:
True:需要先eval/json.loads或正则再取字段。False:[d for d in docs if d.page_content["age"] > 18]一行搞定。
- 例如只保留年龄 > 18 的学生:
-
3. 避免多次序列化 / 反序列化
True:JSON -> Python 对象 -> 字符串 ->(你再用时)字符串 -> Python 对象。False:JSON -> Python 对象,一次到位,少一次来回转换和出错点。
-
4. 控制输出格式
False时,你可以自己决定怎么序列化:json.dumps(obj, ensure_ascii=False, indent=2)保留中文、不转\uXXXX。
True时,内容已经是“字符串表示”,再控制就比较别扭。
什么时候用哪个?
- 偏“LLM / 文本检索”:大多数时候用
text_content=True,因为后面都是把page_content当纯文本喂给模型。 - 偏“数据分析 / ETL / 规则引擎 / 数值计算”:更推荐
text_content=False,直接拿结构化数据做处理,再按需要自己转成文本。
→问AI:page_content 的类型是怎么决定的?是自动判断的吗?
错误:Expected page_content is string, got <class 'dict'> instead.
←AI回复
核心结论先说清楚
-
为什么
page_content是dict?
因为你现在的jq_schema=".",对这个stu.json来说,.表示“整个根对象”,而根是{ ... },在 Python 里就是dict,所以 jq 返回的是一个字典,JSONLoader也就把这个字典放进了page_content里。 -
这个类型是怎么决定的?是自动判断的吗?
分两层来理解:-
1)jq 层决定“原始类型”
- jq 根据 JSON 结构返回结果:
- 顶层
{ ... }→ jq 返回对象 → Python 里就是dict - 顶层
[ ... ]→ jq 返回数组 → Python 里就是list - 顶层
"xxx"→ jq 返回字符串 → Python 里就是str - 顶层
123→ Pythonint/float
- 顶层
- 也就是说:
jq_schema+ JSON 结构 = 决定“原始结果”的 Python 类型。
- jq 根据 JSON 结构返回结果:
-
2)
JSONLoader再根据text_content处理这个“原始结果”text_content=True(默认)时,JSONLoader认为:“jq 返回的应该是字符串(或简单标量),我会把它作为
Document.page_content文本用。”- 如果实际拿到的是
str→ 正常 - 如果实际拿到的是
dict/list→ 抛错:Expected page_content is string, got <class 'dict'> instead. Set text_content=False ...
- 如果实际拿到的是
text_content=False时,JSONLoader认为:“jq 返回的是结构化数据(dict/list 等),我就按原样当 Python 对象保存,不强制转成字符串。”
所以:它不会“智能自动判断然后帮你改类型”,而是:
- jq 决定“结果本身是什么类型”;
- 你用
text_content告诉JSONLoader:- “这个结果我打算当字符串用”(True),
- 还是“这个结果就当结构化对象用”(False)。
如果两者不匹配(比如结果是 dict,你却说要当字符串),它就直接报错提醒你。
-
对应你代码里的这一段具体说明
loader = JSONLoader(
file_path=json_file,
jq_schema=".", # 对 stu.json 来说,返回整个对象 -> dict
text_content=True, # 这里声明“我要字符串”
)
- jq:
.→ 返回整个stu.json对象 → Pythondict。 JSONLoader看见text_content=True,期望拿到的是str,结果拿到dict→ 报你看到的这个错。
如果你想:
- 拿到 dict:
loader = JSONLoader(
file_path=json_file,
jq_schema=".",
text_content=False, # 告诉它:这是对象,不是字符串
)
-
还是想要字符串,但内容是整个对象:
-
方式 1:在 jq 里转:
loader = JSONLoader( file_path=json_file, jq_schema=". | tostring", text_content=True, # 现在 jq 已经保证是字符串了 ) -
方式 2:先
text_content=False拿到 dict,再用json.dumps(...)自己转成你想要的字符串格式。
-
问AI:所以说jq_schema和 JSON 结构 就已经决定了page_content的类型是吗?
AI回复
可以这样理解,但要加一个“小尾巴”:
-
1)
jq_schema决定“原始结果的 Python 类型”
jq 根据jq_schema在 JSON 里取数据,取出来是什么就是什么:.对{...}→dict.name对"周杰轮"→str.hobby对[...]→list
所以:原始的结果类型,完全由jq_schema + JSON 结构决定。
-
2)
text_content决定这个结果能不能当作page_contenttext_content=True:要求这个“原始结果”是字符串,否则报错。text_content=False:允许dict/list等复杂对象,直接当作page_content保存。
总结一句:jq_schema 决定“结果本身是什么类型”,text_content 决定“这个类型能不能被当成 page_content 用,以及用什么方式用”。
总结

更多推荐


所有评论(0)