Rag的评估至关重要,之前我们已经深入探讨了相关的指标和方法: 工程化RAG-无法评估,就无法改进
今天,通过仔细研读answer_relevance指标的源码,我发现了四点极具实用价值的内容,这些内容可以直接应用于我们的工程项目中。
Tip1 prompts模版文件夹
单独创建一个文件夹,用来存储项目会用到的prompts
好处是:您可以随时灵活调整提示语,而无需修改程序代码。所有用到的提示语都清晰可见,方便管理和优化。
Tip2 使用占位符
使用占位符替代变量,能够便捷地对参数进行替换。可以使用langchain或者其他方式对占位符进行替换。
好处是:能够清晰识别变量,提升提示语中变量的辨识度,同时更便于维护提示语。
Tip3 xml结构化输出
要将大型语言模型(LLM)无缝融入现有场景或流程,结构化输出是关键。 因此,在指定XML结构化输出时,最好为结构化内容设置一个明确的标志。例如,所有结构化输出都应以<result>
开头,并以</result>
结尾。这样的设计不仅清晰明了,还能确保输出的统一性和可读性。
好处:XML输出作为一种结构化输出方式,不仅清晰易读,还能无缝融入现有工作流程,提升整体效率。
Tip4 XML解析工具
约定好xml输出格式后,希望它输出格式是这样的:
<result>
<questions>
<question>generated question 1</question>
<question>generated question 2</question>
</questions>
</result>
但经常是这样的:
根据您的要求,xml的输出内容是:
<result>
<questions>
<question>generated question 1</question>
<question>generated question 2</question>
</questions>
</result>
或是这样的:
xml:
<result>
<questions>
<question>generated question 1</question>
<question>generated question 2</question>
</questions>
</result>
总之,有许多不同的输出方式,但我们只需提取result之间的内容即可。
以下这段源码设计得非常出色,不仅考虑了所有可能的情况,而且运行极其稳定。因此,完全可以放心地在项目中直接使用它:
def parse_response(response):
response = response.strip()
#考虑各种<result>以外的其他格式
start_tag, end_tag = "<result>", "</result>"
is_valid = response.startswith(start_tag) and response.endswith(end_tag)
if not is_valid:
pattern = f"(?:{start_tag})(.*)(?:{end_tag})"
p = re.compile(pattern, re.DOTALL)
m = p.search(response)
if m is not None:
response = start_tag + m.group(1) + end_tag
try:
resp_dict = xmltodict.parse(response)
except Exception as e:
print("response:", response)
print("Original Response:", repr(response))
raise e
result = Result(**resp_dict)
return result
当然考虑到通用型,需要定义一个范型类:
from pydantic.generics import GenericModel
from pydantic import BaseModel, Field
from typing import List, TypeVar, Generic
################ parse LLM output to Pydantic object ################
T = TypeVar("T")
class Result(GenericModel, Generic[T]):
value: T = Field(alias="result")
以上的代码都构建好之后,我们可以这样使用:
result = parse_response(response)#respone就是上边LLM要求输出的带有`<result>`标签的xml格式
gen_questions = result.value["questions"]["question"]
内容中不再包含result标签,直接使用result中的标签内容,这使得整个工程代码更加简洁且稳定。 当然,如果大语言模型(LLM)未能按预期输出结果,甚至还考虑到了抛出异常:
raise e
这样的设计不仅提高了代码的可靠性,还增强了系统的健壮性。
好处:解析xml结构化输出,是我们最关键的一环,所以一个稳定性的工程版本的xml解析代码很重要。
写在最后
工程化落地项目,没有最优方案,只有最佳实践。 通过像优秀的源码进行学习,可以提高工程的稳定性,也可以借鉴学习到很多优秀的知识。 希望今天这4点工程实践内容对你有所帮助。
(文章原创,我花费大量时间,希望你在AI实施的过程中少走弯路,可以将AI工程化。 如果对你有帮助,帮我点赞、转发。这将是我最大的动力。万分感谢!!)