Python RAG 开发:两类特殊字符串解析实战
前言在做 Langchain RAG 项目开发的时候经常会遇到工具返回、日志打印产生的字符串这些字符串看着像列表、对象但本质只是文本无法直接读取。下面两个是实操高频遇到的问题。问题 1字符串格式的列表转为 Python 列表对象场景拿到字符串python运行raw_str [qwen-turbo,qwen-plus,deepseek]目标把这个字符串变成真正的 Python 列表对象。错误做法直接使用eval()。eval会执行字符串内任意代码如果字符串来源是用户输入会造成代码注入安全漏洞生产环境禁止使用。方案 1ast.literal_eval【推荐】ast.literal_eval只解析 Python 字面量不会执行逻辑代码安全性高同时兼容单引号、双引号。python运行import ast raw_str [qwen-turbo,qwen-plus,deepseek] result ast.literal_eval(raw_str) print(result) print(type(result)) #输出 #[qwen-turbo, qwen-plus, deepseek] #class list方案 2json.loads当字符串严格遵循 JSON 标准全部使用双引号时可以使用。python运行import json raw_str [qwen-turbo,qwen-plus,deepseek] result json.loads(raw_str)缺点如果字符串内部出现单引号json 直接抛出解析异常RAG 项目中经常遇到单引号因此优先选择ast.literal_eval。问题 2字符串化的 Document 对象提取 page 属性场景描述Tool 打印输出得到下面一长串字符串它不是标准 JSON只是对象print()之后的文本。里面包含多个Document实例需要拿到每一个的page页码。python运行s [Document(metadata{pk: 12, page: 2}, page_content2. 费⽤报销 业务活动中产⽣的费⽤须凭真 实、合规的发票并写明事由经审批后⽅可报销。严禁虚报、\\n谎报费⽤。\\n第五章 奖惩制度 \\n第13条 奖励\\n对于符合下列条件的员⼯公司将视情况给予通报表扬、奖⾦、晋升等奖励\\n1. 超额完成销售指标业绩突出者。\\n2. 提出合理化建议经采纳后为公司带来显著效益者。\\n3. 在维护公司利益和声誉⽅⾯有重 ⼤贡献者。), Document(metadata{pk: 27, page: 2}, page_content2. 费⽤报销 业务活动中产⽣的费⽤须凭真实、合规的发票并写明事由经审批后⽅可报销。严禁虚报、\\n谎报费⽤。\\n第五章 奖惩制度 \\n第13条 奖励\\n对于符合下列条件的员⼯公司将视情况给予通报表扬、奖⾦、晋升等奖励\\n1. 超额完成销售指标业绩突出者。\\n2. 提出合理化建议经采纳后为公司带来显著效益者。\\n3. 在维护公司利益和 声誉⽅⾯有重⼤贡献者。), Document(metadata{pk: 14, page: 3}, page_content3. 最后警告 情节严重留司察看。\\n4. ⽴即解雇 对于严重违纪者公司有权单⽅⾯⽆条件解除劳动合同⽆需⽀付经济补偿⾦。严重违纪包括但\\n不限于\\n贪污、受贿、泄露核⼼商业秘密。\\n虚报业绩、伪造销售记录或报销凭证。\\n⻓期旷⼯连续三天或⽉累计五天。\\n严重失职给公司造成重⼤经济损失或声誉损害。\\n违反国家法律法规被依法追究刑事责任。\\n第六章 附则 \\n第15条 守则的修订与解释)]方案 A正则表达式提取只需要 page推荐不需要还原完整 Document 对象直接正则匹配捕获page后的数字速度快不需要导入类。python运行import re s [Document(metadata{pk: 12, page: 2}, page_contentxxx),Document(metadata{pk: 14, page: 3}, page_contentyyy)] pattern re.compile(rmetadata\{.*?page:\s*(\d)) match_list pattern.findall(s) page_list [int(item) for item in match_list] print(page_list) #输出 [2,3]方案 Beval 完整还原对象仅限内部可控日志⚠️风险只允许处理程序内部产生字符串禁止接收外部用户输入存在安全风险。 必须提前导入Document类否则会报Document未定义。python运行from langchain_core.documents import Document s [Document(metadata{pk: 12, page: 2}, page_content测试),Document(metadata{pk: 14, page: 3}, page_content测试2)] doc_list eval(s) page_list [doc.metadata[page] for doc in doc_list] print(page_list) #输出 [2,3]✅工程最佳实践不要把 Document 对象直接序列化为字符串传递。 写 Tool 的时候不要直接返回list[Document]提前提取字段返回字典列表后续就不需要做复杂解析。python运行# 不推荐 return docs #推荐 return [{page:d.metadata[page], content:d.page_content} for d in docs]总结普通字符串列表解析优先ast.literal_eval安全兼容单引号打印出来的Document(...)字符串只取页码优先正则完整还原使用eval仅限内部可控数据RAG 开发中尽量避免传递对象字符串Tool 直接返回字典减少解析麻烦。