写在前面
上回说到,在优化了Prompt并增加了信息源之后,RAG demo的回答质量得到了提升。这篇文章,优化一下RAG的结构。 原本的RAG架构是这样的:
graph LR
UserInput-->A(Retriever)-->B(Prompt)-->C(output)
UserInput-->B
classDef default fill:#fff,stroke:#222,stroke-width:2px;
首先,可以重写用户的输入,以使得其更适合于进行向量库检索;其次,可以使模型判断Retriever内容与用户问题的相关性,如果不相关,则再次重写用户输入;则整体架构可以改写成下述形式:
graph LR
UserInput-->A(LLM optimize search)-->B(retriever)-->C(LLM judge)--Y-->D(LLM+Prompt output)
C--N-->A
classDef default fill:#fff,stroke:#222,stroke-width:2px;
正文
首先,设计optimize search、LLM Judge的Prompt
----ROLE----
关键词优化专家
----Profile----
你是一位专业的关键词优化专家,擅长分析用户需求,提炼和构建高效搜索关键词
----WorkFlow----
1. 深入理解用户查询的背景和目的。
2. 分析当前关键词的覆盖面和搜索引擎的表现。
3. 结合用户需求和搜索引擎优化(SEO)原则,重构关键词。
----Constrains----
你的输出应当为如下格式:
{{
key_words:'your key word'
}}
除此以外不要输出额外的信息。
用户的输入为{question},你的输出是:
----ROLE----
检索内容审查专家
----Profile----
你是一位专业的内容审查专家,擅长审查文档内容是否能解决用户的问题。
----Workflow----
1. 深入理解用户查询的目的
2. 分析输入的文档是否能解决用户的需求
3. 输出是否能解决用户的需求,若能,输出True,反之则输出False
----Constrains----
你的输出应当为如下格式:
{{
judge:'True or False'
reason:'Your reason'
}}
除此以外不要输出额外的信息。
用户的输入为{question},文档内容是{context},你的输出是:
然后重构输入流程:
max_retry = 5
for i in range max_retry:
rewrite_entity = rewrite_prompt.format(question=question)
print(f"{GREEN}{rewrite_prompt}{RESET}")
response = llm.invoke(rewrite_entity).content
print(f"{BLUE}{response}{RESET}")
keywords=eval(response)
retriever_content = retriever.invoke(keywords.get("key_words"))
print(f"{RED}{retriever}{RESET}")
judge_entity = judge_prompt.format(question=question,context=retriever_content)
print(f"{GREEN}{judge_entity}{RESET}")
response = llm.invoke(judge_entity).content
print(f"{BLUE}{response}{RESET}")
judge = eval(response)
if judge.get('judge'):
output_entity=output_prompt.format(question=question,context=retriever_context)
print(f"{GREEN}{output_entity}{RESET}")
response = llm.invoke(output_entity)
break
else:
continue
这样就构建好了优化后的RAG流程。
However,在非首次进行检索关键词重写时,应当加入历史消息记录,避免模型进行重复作业。这一点还可以继续优化。
写在后面
这一篇重构了RAG的架构,使其在逻辑上更具鲁棒性。然而对于请求模型失败等问题,还需要进行特定的处理,以满足实际业务中的需求。希望下一篇,变得更强