提示语结构化的4点内容-来自源码的启发

48 阅读3分钟

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工程化。 如果对你有帮助,帮我点赞、转发。这将是我最大的动力。万分感谢!!)