使用 IBM Granite 构建 ReWOO 推理智能体

作者

Jobit Varughese

Technical Content Writer

IBM

大型语言模型 (LLM) 及其增强型变体增强语言模型 (ALM) 已成为现代 AI 系统的支柱。通过将强大的语言生成与检索增强生成 (RAG) 等外部知识检索技术相结合,它们能够实现跨不同领域的高级推理、问答和任务自动化。然而,尽管这些模型具有卓越的能力,但在处理复杂任务时,它们常常面临诸如跨系统稳健性不一致、高令牌使用率、响应时间慢以及重复提示和冗余上下文导致的效率低下等挑战。此类限制会增加运营成本,并阻碍可扩展性和实时性能。

为了解决这些问题,ReWOO(无观察推理)框架提出了一种新的方法,重点在于将推理过程与外部知识检索分离。ReWOO 不是让单个 LLM 尝试以交错的方式进行推理、行动和观察,而是将这些问题分成不同的模块,每个模块都可能由 LLM 提供支持,但具有特定的角色。通过将流程模块化,划分为不同的规划、证据收集和综合阶段,ReWOO 提高了令牌效率和准确性。它还使系统更易于调试,并实现更简化、更有效的 AI 工作流程

ReWOO 方法

ReWOO 的工作流围绕三个关键组件:逐步推理、工具调用和总结。这些组件以模块化结构实现,由三个部分组成:规划器、工作器和求解器。

规划师

规划师将主要任务分解为一系列重点子问题,从而创建清晰的蓝图。为了避免让大型语言模型 (LLM) 一次性回答一个复杂问题,从而导致过多的令牌使用和模糊的回答,规划者会创建一个蓝图或路线图。这种逐步细分指导工作流程并保持推理过程的结构化。

工作节点

工作人员调用搜索引擎或数据库等外部工具来检索回答子问题所需的相关信息和证据。它使用 LLM 仅根据检索到的信息制定清晰、简洁的答案。这个外部观察阶段与推理过程分开,以避免不必要地重复提示并减少令牌消耗。

求解器

求解器综合所有收集到的洞察分析,以生成全新、结构合理的最终响应。这种模块化分离有助于确保大型语言模型的高效、准确和可扩展的推理。

LangChain LangGraph 等框架提供了强大的工具,可以通过使用 OpenAI、IBM Granite 或 Serper 和 Tavily 等搜索专用工具来实施 ReWOO 架构。

在本教程中,您将探索如何构建执行内容摘要任务的 ReWOO 智能体。该智能体可以:

  • 将高级任务分解为子问题
  • 使用网络搜索为每个子问题收集相关背景信息
  • 使用 IBM Granite 生成答案
  • 将结果总结为最终回应

该架构适用于:

  • 汇总任务
  • 基于外部知识的问答
  • 动态、工具增强推理

使用的技术

本分步教程利用尖端 AI 技术,包括:

  1. IBM Granite Instruct: 一个功能强大的 LLM,支持一般指令跟踪,非常适合商业和其他领域中的 AI 助手。
  2. 转换器:一个广泛使用的 Python 库,提供用于加载、标记和运行语言模型(例如 IBM Granite)的工具。它可以高效处理文本输入并生成模型输出。

步骤

第 1 步:设置环境

本教程指导您使用 Jupyter Notebook 设置本地开发环境,以运行 ReWOO 样式的推理管道。您将使用 IBM Granite 语言模型和 Serper.dev 进行实时网络搜索检索。

注意:不需要 GPU,但在基于 CPU 的系统上执行速度可能会更慢。此步骤将打开一个笔记本环境,可在其中复制本教程中的代码。本教程也可在 GitHub 上找到。

第 2 步:安装所需的依赖项

这些库是运行 ReWOO 管道并和外部工具交互所必需的:

Transformer:加载并运行 IBM Granite 大型语言模型。

torch:高效运行模型所需的深度学习框架。

加速:优化跨硬件的模型性能(可选)。

请求:将 HTTP POST 请求发送到外部 API(如 Serper)。

!pip install transformers accelerate torch requests

第 3 步:导入所需库

在此步骤中,导入构建 ReWOO 流程核心组件所需的必要 Python 库。

Transformer.AutoTokenizer:加载分词器,将文本转换为与语言模型兼容的令牌。

transformers.AutoModelForCausalLM: 加载预训练的语言模型 IBM Granite,用于生成响应。

transformers.pipeline: 提供高级接口,用于使用标记器和模型快速创建文本生成管道。

import requests
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline

第 4 步:加载 IBM Granite 模型并创建文本生成管道

在此步骤中,我们将加载 IBM Granite 语言模型,并使用 Hugging Face 的转换器库来初始化文本生成管道。在此探索 Hugging Face 上的 Granite 3.2 2B Instruct 模型。

model_id = "ibm-granite/granite-3.2-2b-instruct": 指定 Hugging Face 上托管的 IBM Granite 模型检查点的名称。该模型经过优化,适用于指令执行任务。

AutoTokenizer.from_pretrained(model_id):加载与指定模型关联的分词器。它负责将输入转换为令牌,并将输出令牌解码回输入。

AutoModelForCausalLM.from_pretrained(model_id): 加载语言模型(Granite 3.2 2B 指令),用于文本生成任务,如回答问题或摘要。

pipeline("text- Generation", Model=model,tokenizer=tokenizer): 创建一个将模型和标记器结合在一起的高级文本生成管道,以便轻松根据提示生成响应。

model_id = "ibm-granite/granite-3.2-2b-instruct"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
generator = pipeline("text-generation", model=model, tokenizer=tokenizer)

第 5 步:设置用于 Web 搜索检索的 Serper API

在此步骤中,我们定义了一个函数,作为 ReWOO 架构中的 Worker。该 Worker 使用网络搜索工具 Serper.dev 从互联网上检索相关的最新信息,以支持推理和答案生成。Serper.dev 是一种快速的轻量级 API,能够以结构化格式提供 Google 搜索结果,使其非常适合 AI 工作流中实时信息检索。

此设置允许 ReWOO 系统在 LLM 做出最终决策之前,通过查询外部知识源来“观察”现实世界。

要在 ReWOO 管道中使用 Serper,请执行以下操作:

  1. 访问 https://serper.dev 并创建一个免费帐户。
  2. 注册后,导航至仪表板并复制 API 密钥。
  3. 在代码中,安全地存储 API 密钥。现在,请直接按以下所示进行分配:

SERPER_API_KEY = "<YOUR_API_KEY>" # Replace this with your actual key

注意:切勿将 API 密钥上传到公共存储库。对于生产或团队设置,请使用 .env文件或环境变量以确保其安全性。

DefQuery_serper(question, num_results=3): 定义一个函数,该函数接受搜索问题并从排名靠前的搜索结果中返回相关片段。

Payload = {"q": question, "num": num_results}: 使用搜索词和要返回的结果数准备查询负载。

response =requests.post(...): 向 Serper API 发送包含您的查询和标头的 POST 请求。

response.raise_for_status():如果 API 响应无效或失败,则会引发错误。

snippets = [...]: 从有机搜索结果中提取片段文本。

return "\n".join(snippets):将片段连接并返回为一个字符串,作为语言模型的上下文。

注意:该函数构成了 ReWOO “observation” 步骤的核心,在此步骤中会收集外部证据以进行进一步的推理。测试时,请确保您的 API 密钥有效且不受速率限制。

SERPER_API_KEY = "your_serper_api_key_here" # Replace with your actual key
def query_serper(question, num_results=3):
    url = "https://google.serper.dev/search"
    headers = {
            "X-API-KEY": SERPER_API_KEY,
            "Content-Type": "application/json"
}
    payload = {"q": question, "num": num_results}
    response = requests.post(url, headers=headers, json=payload)
    response.raise_for_status()
    data = response.json()
    snippets = [item.get("snippet", "") for item in data.get("organic", [])]
    return "\n".join(snippets)

第 6 步:利用专家功能生成明智的答案

在此步骤中,我们将定义 expert() 函数,其充当 ReWOO 架构中的求解器。求解器综合检索到的外部证据,并使用语言模型生成最终响应。

Def Expert(question:str) -> str: expert() 函数接受一个问题(字符串)并返回 Granite 模型生成的一个答案(字符串)。它的工作方式是通过 Serper.dev 在网络上进行搜索,收集相关信息,并利用这些信息生成清晰、完整的回答。

context =Query_serper(question): 使用 Serper Web 搜索工具检索相关信息 (worker)。

prompt = f"""...""": 构建一个提示,指示模型仅使用检索到的上下文进行回答。

generator(...): 根据输入提示调用 Granite 模型生成答案。

for _ in Range(5): 此循环让模型分块生成答案,最多 5 次。如果答案很长并且无法一次性完成,这会有所帮助。

generated_text += new_text: 将每个新文本块添加到完整答案中。

if new_text.endswith(...): 如果答案看起来完整(以句号、问号或感叹号结尾),并且包含足够的单词(超过 50 个),则停止循环。

return generated_text.strip(): 返回最终整理后的结果。

注意: 提示格式很重要,它可以确保模型不会“产生幻觉”或偏离主题。它必须符合上下文的内容。我们将每个生成块限制为 120 个令牌,以控制输出长度并有效管理资源使用情况,同时防止使用过多的令牌。

def expert(question: str) -> str:
    context = query_serper(question) # your retrieval function
    prompt = f"""You are a knowledgeable expert. Based ONLY on the context below, answer the question clearly and concisely in your own words.
Do NOT mention any sources or references.
Context:
{context}
Question: {question}
Answer:"""
    input_prompt = prompt
    generated_text = ""
    last_generated = ""
    for _ in range(5): # up to 5 chunks
        outputs = generator(
            input_prompt,
            max_new_tokens=120,
            do_sample=False,
            eos_token_id=tokenizer.eos_token_id,
            # no invalid flags like 'temperature' here
        )
        text = outputs[0]["generated_text"]
        new_text = text[len(input_prompt):].strip()
        # Stop if no new content
        if new_text == last_generated:
            break
        generated_text += new_text + " "
        input_prompt = prompt + generated_text
        last_generated = new_text
        if new_text.endswith(('.', '!', '?')) and len(generated_text.split()) > 50:
            break
    return generated_text.strip()

第 7 步:定义规划器模块

在这一步中,我们定义了 Planner 函数,该函数将广泛的输入任务分解为更小、定义明确的子问题,这是 ReWOO 逐步推理的核心原则。

def planner(task: str): 该函数定义了一个名为 planner 的函数,该函数接受一个名为 task 的字符串参数(用于描述要执行的任务)。

topic = task.replace("Summarize", "").replace("the novella", "").strip(): 从任务中提取主要主题(例如,标题或主题)。它通过删除 "Summarize" 和 "the novella" 等常见提示短语来清理输入,然后修剪前导和尾随空格以隔离核心主题。

return [ ... ]: 返回一个包含特定问题的列表,这些问题用于指导 Worker 模块。

注意:您可以根据输入主题的深度和性质,使用更具体的子问题来扩展此列表。

def planner(task: str):
topic = task.replace("Summarize", "").replace("the novella", "").strip()
return [
f"What is the main plot related to {topic}?",
f"Who are the key characters in {topic}?",
f"What themes are explored in {topic}?"
]

第 8 步:定义最终摘要器(求解器模块)

在此步骤中,我们将定义 final_summarizer 函数,其充当 ReWOO 管道中的求解器。该函数采用 worker 提供的子答案(证据),并使用语言模型生成新编写的、连贯的摘要。

def final_summarizer(task: str, sub_answers: dict) -> str: 定义接收原始任务和子答案,并返回简洁摘要的函数。

insights = "\n".join(sub_answers.values()): 将所有答案合并为一个字符串,用换行符分隔,以便包含在提示中。

base_prompt = f"""...""": 构建基本提示,指示模型总结所提供的洞察分析。它引导模型仅基于子答案生成一个全新的摘要。

max_total_tokens = 400: 为生成的令牌计数设置上限,以避免输出过长。

max_cycles = 5: 最多允许 5 次迭代生成,以逐步构建摘要。

for in Range(max Loops): 使用语言模型循环生成文本块。

Response = Generator(..., max_new_tokens=100, ...): 使用生成器(管道对象)在每次循环中生成最多 100 个新令牌。采样模式 (do_sample=True) 允许响应出现变化和创意。

ifsummary.endswith(...) or total_tokens_used >= max_total_tokens: 如果摘要以适当的标点符号结束或达到令牌上限,则结束循环。

return summary.strip(): 返回最终的、完美的、没有尾随空格的摘要。

def final_summarizer(task: str, sub_answers: dict) -> str:
    insights = "\n".join(sub_answers.values())
    base_prompt = f"""You are an expert summarizer. Based on the following insights, write a fresh, concise summary of the text. The summary must be newly written and must end in a complete sentence with proper punctuation.
Insights:
{insights}
Summary:"""
    summary = ""
    current_prompt = base_prompt
    max_total_tokens = 400
    total_tokens_used = 0
    max_loops = 5
    for _ in range(max_loops):
        response = generator(current_prompt, max_new_tokens=100, do_sample=True, top_p=0.9, eos_token_id=tokenizer.eos_token_id)
        chunk = response[0]["generated_text"][len(current_prompt):].strip()
        summary += " " + chunk
        summary = summary.strip()
        total_tokens_used += len(chunk.split())
        if summary.endswith(('.', '!', '?')) or total_tokens_used >= max_total_tokens:
            break
        # Prepare prompt for next loop
        current_prompt = base_prompt + summary
    return summary.strip()

第 9 步:使用求解器函数编排 ReWOO 智能体

在此步骤中,我们将定义求解器函数,它代表 ReWOO 流程的最后一个阶段。该函数通过使用规划器、调用专家(工作节点)并使用 final_summarizer(求解器)生成摘要来编排整个过程。ReWOO 架构通过使用规划器将主任务分解为子问题,实现多步推理。每个子问题均由专家模块独立处理,最终摘要器将所有答案综合成连贯的响应。这种模块化方法使系统能够更有效地处理复杂任务。

def solver(task: str): 定义用于执行完整 ReWOO 工作流程的主控制器函数。

subquestions = planner(task):使用规划器将输入任务分解为重点子问题。

ans = expert(q): 对于每个子问题,调用专家函数来获取基于 Web 的证据并生成相关答案。规划器生成的每个子问题都作为工具输入传递给专家。专家模块使用语言模型处理输入。这可以看作是执行特定子任务的工具。

answers[q] = ans: 将每个答案与对应的问题关联存储,以便日后汇总。

final_summary = final_summarizer(task, answers): 将所有收集到的答案输入到 final_summarizer 中,生成一个干净、连贯的摘要。

print(final_summary) and return final_summary: 显示并返回原始任务的最终摘要。

注意: 由于 CPU 速度、可用 RAM 以及模型在不同硬件设置上的运行效率方面的差异,solver() 函数花费的总时间可能因系统而异。由于代码使用带有语言模型的循环生成战略,因此处理能力或内存较低的系统可能需要更长的时间。基于网络的检索和大量提示也可能导致延迟。为了提高性能,可以考虑通过使用更小或量化的模型、优化分词器和生成器管道或在支持 GPU 的环境(如 Google Colab 或 Kaggle 笔记本)中运行代码来减少 max_loops。

def solver(task: str):
    print(f"Planner: Breaking down '{task}' into sub-questions...\n")
    subquestions = planner(task)
    answers = {}
    for q in subquestions:
        print(f"🔎 Expert answering: {q}")
        ans = expert(q)
        print(f"➡ Answer: {ans}\n")
        answers[q] = ans
    print("=== Final Summary ===\n")
    final_summary = final_summarizer(task, answers)
    print(final_summary)
    return final_summary

第 10 步:运行 ReWOO 管道以生成最终摘要

在最后一步中,我们通过使用特定任务调用求解器函数来执行完整的 ReWOO 管道。

solver(“总结中篇小说《变形记》): 触发整个 ReWOO 进程; 规划、检索证据并生成输入任务的摘要:总结数据集《变形记》。

此步骤输出最终摘要,并演示 ReWOO 组件如何针对真实用例实现端到端协同工作。

solver("Summarize the novella The Metamorphosis")

关键要点

  1. ReWOO 智能体成功地将任务 (“Summarize the novella The Metamorphosis”) 分解为关于情节、人物和主题的有意义的子问题,从而实现了有针对性的信息检索。
  2. 每个小问题都通过实时网络搜索(Serper.dev)和 IBM Granite 进行回答,得出相关、结构合理的答案,抓住了文本的内核要素。
  3. 最终答案条理清晰、内容新颖且准确无误,充分展示了基于检索增强生成技术如何为文学分析任务生成高质量、类人文的摘要。

备注:要提高 ReWOO 管道的性能和可靠性,必须改进摘要质量、一致性和生成延迟等评估指标。这些指标有助于评估系统在不同任务和硬件设置中的表现。可以通过集成智能算法来扩展该架构,将大问题分解为较小的问题,并对最有用的答案进行排序。这些增强功能将实现更准确、更高效的推理,缩短生成时间并提高最终输出的整体质量。

相关解决方案
商用 AI 智能体

构建、部署和管理强大的 AI 助手和智能体,运用生成式 AI 实现工作流和流程自动化。

    探索 watsonx Orchestrate
    IBM AI 智能体解决方案

    借助值得信赖的 AI 解决方案,您可以勾勒未来业务发展蓝图。

    深入了解 AI 智能体解决方案
    IBM Consulting AI 服务

    IBM Consulting AI 服务有助于重塑企业利用 AI 实现转型的方式。

    探索人工智能服务
    采取下一步行动

    无论您是选择定制预构建的应用程序和技能,还是使用 AI 开发平台构建和部署定制代理服务,IBM watsonx 平台都能满足您的需求。

    探索 watsonx Orchestrate 深入了解 watsonx.ai