使用ReAct在Wikipedia上进行搜索:Google Colab教程
技术背景
大型语言模型(LLM)在零样本设置下处理复杂推理任务时,常因缺乏外部知识而表现不佳,甚至产生幻觉。ReAct(Reasoning and Acting)是一种提示工程方法,通过让模型交替生成思考(Thought)、行动(Action)和观察(Observation)轨迹,将推理过程与外部工具(如维基百科API)结合,从而提升答案的准确性和可解释性。该方法适用于需要多步推理、事实查询或知识密集型问答的场景,如研究辅助、智能客服等。其主要限制包括依赖外部工具的质量和可用性,以及多次调用可能增加延迟和成本。
核心原理
ReAct的核心是让模型在每一步生成一个三元组:Thought(对当前情况的推理)、Action(选择执行的动作,如搜索、查找或结束)、Observation(从动作结果中获取的信息)。模型通过迭代循环,不断利用外部信息更新推理,直至得出最终答案。本教程中,模型通过少样本提示学习该模式,并利用Gemini API的stop_sequences参数模拟函数调用:当模型生成特定动作标记(如</search>)时,生成过程被中断,程序解析出动作类型和参数,调用对应的Python函数(如search),将结果作为观察反馈给模型,继续下一轮生成。这种设计使模型能够动态获取外部知识,同时保持推理轨迹的透明性。
架构分析
系统由三个核心组件构成:1) ReAct提示模板:包含指令和多个少样本示例,指导模型生成思考-行动-观察轨迹;2) Gemini模型:通过GenerativeModel接口进行多轮对话,利用stop_sequences控制生成中断;3) 工具集:封装维基百科API的search、lookup和finish函数,分别执行搜索、页面内查找和终止操作。数据流为:用户问题输入→模型生成轨迹→遇到动作标记时中断→解析并调用对应工具→观察结果作为用户消息追加到聊天历史→模型继续生成,直至finish动作或达到最大调用次数。设计决策包括:使用stop_sequences而非原生函数调用,以简化实现并展示底层原理;search函数返回摘要的前2-3句以控制上下文长度;lookup函数基于最近搜索的页面进行精确匹配。
完整实战教程
##### 版权所有 2026 Google LLC.
# @title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
使用 ReAct 搜索维基百科
本笔记本是 ReAct: Synergizing Reasoning and Acting in Language Models 的一个极简实现,使用 Google 的 gemini-3.7-flash 模型。你将使用 ReAct 提示来配置模型,使其搜索维基百科以找到用户问题的答案。
在本演练中,您将学习如何:
- 设置您的开发环境和 API 访问权限以使用 Gemini。
- 使用 ReAct 少样本提示。
- 将新提示的模型用于多轮对话(聊天)。
- 将模型连接到 Wikipedia API。
- 与模型进行对话(尝试询问诸如“埃菲尔铁塔有多高?”之类的问题),并观察它搜索 Wikipedia。
注意:本页上的非源代码材料根据知识共享-署名-相同方式共享 CC-BY-SA 4.0 许可,https://creativecommons.org/licenses/by-sa/4.0/legalcode。
背景
ReAct 是一种提示方法,它允许语言模型创建其思考过程的轨迹以及回答用户问题所需的步骤。这提高了人类可解释性和可信度。使用 ReAct 提示的模型会在每次迭代中生成“思考-行动-观察”三元组,您很快就会看到。让我们开始吧!
设置
%pip install -q "google-generativeai>=0.7.2"
%pip install -q wikipedia
注意:wikipedia 包 指出它“为易用性和简单性而设计,并非用于高级用途”,并且生产环境或重度使用应改为“使用 Pywikipediabot 或其他更高级的 Python MediaWiki API 包装器”。
import re
import os
import wikipedia
from wikipedia.exceptions import DisambiguationError, PageError
import google.generativeai as genai
要运行以下单元格,你的 API 密钥必须存储在名为 GEMINI_API_KEY 的 Colab 密钥中。如果你还没有 API 密钥,或者不确定如何创建 Colab 密钥,请参阅 身份验证 快速入门示例。
from google.colab import userdata
GEMINI_API_KEY=userdata.get('GEMINI_API_KEY')
genai.configure(api_key=GEMINI_API_KEY)
ReAct 提示词
论文中使用的提示词可在 https://github.com/ysymyth/ReAct/tree/master/prompts 获取。
在这里,你将使用以下 ReAct 提示词,并稍作调整。
注意:此处使用的提示词和上下文示例借鉴自 https://github.com/ysymyth/ReAct,该项目以 MIT 许可证 发布。
model_instructions = """Solve a question answering task with interleaving Thought, Action, Observation steps. Thought can reason about the current situation, Observation is understanding relevant information from an Action's output and Action can be of three types:
(1) <search>entity</search>, which searches the exact entity on Wikipedia and returns the first paragraph if it exists. If not, it will return some similar entities to search and you can try to search the information from those topics.
(2) <lookup>keyword</lookup>, which returns the next sentence containing keyword in the current context. This only does exact matches, so keep your searches short.
(3) <finish>answer</finish>, which returns the answer and finishes the task.
"""
使用少量样本提示,在 Gemini 中实现上下文学习
尽管大型语言模型对提示中的指令表现出良好的理解能力,但在零样本设置下处理复杂任务时,它们仍可能表现不佳。因此,你现在需要在提示中提供几个示例,以根据你的需求引导模型的输出。这种上下文学习显著提升了模型的性能。
examples = """
Here are some examples.
Question
What is the elevation range for the area that the eastern sector of the Colorado orogeny extends into?
Thought 1
I need to search Colorado orogeny, find the area that the eastern sector of the Colorado orogeny extends into, then find the elevation range of the area.
Action 1
<search>Colorado orogeny</search>
Observation 1
The Colorado orogeny was an episode of mountain building (an orogeny) in Colorado and surrounding areas.
Thought 2
It does not mention the eastern sector. So I need to look up eastern sector.
Action 2
<lookup>eastern sector</lookup>
Observation 2
The eastern sector extends into the High Plains and is called the Central Plains orogeny.
Thought 3
The eastern sector of Colorado orogeny extends into the High Plains. So I need to search High Plains and find its elevation range.
Action 3
<search>High Plains</search>
Observation 3
High Plains refers to one of two distinct land regions
Thought 4
I need to instead search High Plains (United States).
Action 4
<search>High Plains (United States)</search>
Observation 4
The High Plains are a subregion of the Great Plains. From east to west, the High Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130m).
Thought 5
High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer is 1,800 to 7,000 ft.
Action 5
<finish>1,800 to 7,000 ft</finish>
Question
Musician and satirist Allie Goertz wrote a song about the "The Simpsons" character Milhouse, who Matt Groening named after who?
Thought 1
The question simplifies to "The Simpsons" character Milhouse is named after who. I only need to search Milhouse and find who it is named after.
Action 1
<search>Milhouse</search>
Observation 1
Milhouse Mussolini Van Houten is a recurring character in the Fox animated television series The Simpsons voiced by Pamela Hayden and created by Matt Groening.
Thought 2
The paragraph does not tell who Milhouse is named after, maybe I can look up "named after".
Action 2
<lookup>named after</lookup>
Observation 2
Milhouse was named after U.S. president Richard Nixon, whose middle name was Milhous.
Thought 3
Milhouse was named after U.S. president Richard Nixon, so the answer is Richard Nixon.
Action 3
<finish>Richard Nixon</finish>
Question
Which documentary is about Finnish rock groups, Adam Clayton Powell or The Saimaa Gesture?
Thought 1
I need to search Adam Clayton Powell and The Saimaa Gesture, and find which documentary is about Finnish rock groups.
Action 1
<search>Adam Clayton Powell</search>
Observation 1
Could not find [Adam Clayton Powell]. Similar: [’Adam Clayton Powell III’, ’Seventh Avenue (Manhattan)’, ’Adam Clayton Powell Jr. State Office Building’, ’Isabel Washington Powell’, ’Adam Powell’, ’Adam Clayton Powell (film)’, ’Giancarlo Esposito’].
Thought 2
To find the documentary, I can search Adam Clayton Powell (film).
Action 2
<search>Adam Clayton Powell (film)</search>
Observation 2
Adam Clayton Powell is a 1989 American documentary film directed by Richard Kilberg. The film is about the rise and fall of influential African-American politician Adam Clayton Powell Jr.[3][4] It was later aired as part of the PBS series The American Experience.
Thought 3
Adam Clayton Powell (film) is a documentary about an African-American politician, not Finnish rock groups. So the documentary about Finnish rock groups must instead be The Saimaa Gesture.
Action 3
<finish>The Saimaa Gesture</finish>
Question
What profession does Nicholas Ray and Elia Kazan have in common?
Thought 1
I need to search Nicholas Ray and Elia Kazan, find their professions, then find the profession they have in common.
Action 1
<search>Nicholas Ray</search>
Observation 1
Nicholas Ray (born Raymond Nicholas Kienzle Jr., August 7, 1911 - June 16, 1979) was an American film director, screenwriter, and actor best known for the 1955 film Rebel Without a Cause.
Thought 2
Professions of Nicholas Ray are director, screenwriter, and actor. I need to search Elia Kazan next and find his professions.
Action 2
<search>Elia Kazan</search>
Observation 2
Elia Kazan was an American film and theatre director, producer, screenwriter and actor.
Thought 3
Professions of Elia Kazan are director, producer, screenwriter, and actor. So profession Nicholas Ray and Elia Kazan have in common is director, screenwriter, and actor.
Action 3
<finish>director, screenwriter, actor</finish>
Question
Which magazine was started first Arthur’s Magazine or First for Women?
Thought 1
I need to search Arthur’s Magazine and First for Women, and find which was started first.
Action 1
<search>Arthur’s Magazine</search>
Observation 1
Arthur’s Magazine (1844-1846) was an American literary periodical published in Philadelphia in the 19th century.
Thought 2
Arthur’s Magazine was started in 1844. I need to search First for Women next.
Action 2
<search>First for Women</search>
Observation 2
First for Women is a woman’s magazine published by Bauer Media Group in the USA.[1] The magazine was started in 1989.
Thought 3
First for Women was started in 1989. 1844 (Arthur’s Magazine) < 1989 (First for Women), so Arthur’s Magazine was started first.
Action 3
<finish>Arthur’s Magazine</finish>
Question
Were Pavel Urysohn and Leonid Levin known for the same type of work?
Thought 1
I need to search Pavel Urysohn and Leonid Levin, find their types of work, then find if they are the same.
Action 1
<search>Pavel Urysohn</search>
Observation 1
Pavel Samuilovich Urysohn (February 3, 1898 - August 17, 1924) was a Soviet mathematician who is best known for his contributions in dimension theory.
Thought 2
Pavel Urysohn is a mathematician. I need to search Leonid Levin next and find its type of work.
Action 2
<search>Leonid Levin</search>
Observation 2
Leonid Anatolievich Levin is a Soviet-American mathematician and computer scientist.
Thought 3
Leonid Levin is a mathematician and computer scientist. So Pavel Urysohn and Leonid Levin have the same type of work.
Action 3
<finish>yes</finish>
Question
{question}"""
将指令和示例一起复制到名为 model_instructions.txt 的文件中
ReAct_prompt = model_instructions + examples
with open('model_instructions.txt', 'w') as f:
f.write(ReAct_prompt)
Gemini-ReAct 流程
设置
现在,你将构建一个端到端的流水线,以支持与采用 ReAct 提示的 Gemini 模型进行多轮对话。
class ReAct:
def __init__(self, model: str, ReAct_prompt: str | os.PathLike):
"""Prepares Gemini to follow a `Few-shot ReAct prompt` by imitating
`function calling` technique to generate both reasoning traces and
task-specific actions in an interleaved manner.
Args:
model: name to the model.
ReAct_prompt: ReAct prompt OR path to the ReAct prompt.
"""
self.model = genai.GenerativeModel(model)
self.chat = self.model.start_chat(history=[])
self.should_continue_prompting = True
self._search_history: list[str] = []
self._search_urls: list[str] = []
try:
# try to read the file
with open(ReAct_prompt, 'r') as f:
self._prompt = f.read()
except FileNotFoundError:
# assume that the parameter represents prompt itself rather than path to the prompt file.
self._prompt = ReAct_prompt
@property
def prompt(self):
return self._prompt
@classmethod
def add_method(cls, func):
setattr(cls, func.__name__, func)
@staticmethod
def clean(text: str):
"""Helper function for responses."""
text = text.replace("\n", " ")
return text
定义工具
按照提示的指示,模型将生成思考-行动-观察轨迹,其中每个行动轨迹可以是以下标记之一:
- </search/> :通过外部API执行维基百科搜索。
- </lookup/> :使用维基百科API在页面上查找特定信息。
- </finish/> :停止模型执行并返回答案。
如果模型遇到这些标记中的任何一个,模型应利用提供给模型的tools。模型利用所获得的工具集从外部世界收集信息的这种理解通常被称为函数调用。因此,下一个目标是模仿这种函数调用技术,以便让ReAct提示的Gemini模型能够访问外部真实信息。
Gemini API支持函数调用,您可以使用此功能来设置您的工具。但是,在本教程中,您将学习使用stop_sequences参数来模拟它。
定义工具:
搜索
定义一个方法来执行维基百科搜索
@ReAct.add_method
def search(self, query: str):
"""Perfoms search on `query` via Wikipedia api and returns its summary.
Args:
query: Search parameter to query the Wikipedia API with.
Returns:
observation: Summary of Wikipedia search for `query` if found else
similar search results.
"""
observation = None
query = query.strip()
try:
# try to get the summary for requested `query` from the Wikipedia
observation = wikipedia.summary(query, sentences=4, auto_suggest=False)
wiki_url = wikipedia.page(query, auto_suggest=False).url
observation = self.clean(observation)
# if successful, return the first 2-3 sentences from the summary as model's context
observation = self.model.generate_content(f'Retun the first 2 or 3 \
sentences from the following text: {observation}')
observation = observation.text
# keep track of the model's search history
self._search_history.append(query)
self._search_urls.append(wiki_url)
print(f"Information Source: {wiki_url}")
# if the page is ambiguous/does not exist, return similar search phrases for model's context
except (DisambiguationError, PageError) as e:
observation = f'Could not find ["{query}"].'
# get a list of similar search topics
search_results = wikipedia.search(query)
observation += f' Similar: {search_results}. You should search for one of those instead.'
return observation
查找
在维基百科页面上查找特定短语。
@ReAct.add_method
def lookup(self, phrase: str, context_length=200):
"""Searches for the `phrase` in the lastest Wikipedia search page
and returns number of sentences which is controlled by the
`context_length` parameter.
Args:
phrase: Lookup phrase to search for within a page. Generally
attributes to some specification of any topic.
context_length: Number of words to consider
while looking for the answer.
Returns:
result: Context related to the `phrase` within the page.
"""
# get the last searched Wikipedia page and find `phrase` in it.
page = wikipedia.page(self._search_history[-1], auto_suggest=False)
page = page.content
page = self.clean(page)
start_index = page.find(phrase)
# extract sentences considering the context length defined
result = page[max(0, start_index - context_length):start_index+len(phrase)+context_length]
print(f"Information Source: {self._search_urls[-1]}")
return result
完成
指示流水线终止其执行。
@ReAct.add_method
def finish(self, _):
"""Finishes the conversation on encountering <finish> token by
setting the `self.should_continue_prompting` flag to `False`.
"""
self.should_continue_prompting = False
print(f"Information Sources: {self._search_urls}")
停止标记与函数调用模拟
现在你已经完成了函数定义,下一步是指导模型在遇到任何动作标记时中断其执行。你将使用 genai.GenerativeModel.GenerationConfig 类中的 stop_sequences 参数来指示模型何时停止。当遇到动作标记时,管道将提取 stop_sequences 参数中哪个特定标记终止了模型的执行,然后调用相应的工具(函数)。
函数的响应将被添加到模型的聊天历史中,以继续上下文链接。
@ReAct.add_method
def __call__(self, user_question, max_calls: int=8, **generation_kwargs):
"""Starts multi-turn conversation with the chat models with function calling
Args:
max_calls: max calls made to the model to get the final answer.
generation_kwargs: Same as genai.GenerativeModel.GenerationConfig
candidate_count: (int | None) = None,
stop_sequences: (Iterable[str] | None) = None,
max_output_tokens: (int | None) = None,
temperature: (float | None) = None,
top_p: (float | None) = None,
top_k: (int | None) = None
Raises:
AssertionError: if max_calls is not between 1 and 8
"""
# hyperparameter fine-tuned according to the paper
assert 0 < max_calls <= 8, "max_calls must be between 1 and 8"
if len(self.chat.history) == 0:
model_prompt = self.prompt.format(question=user_question)
else:
model_prompt = user_question
# stop_sequences for the model to imitate function calling
callable_entities = ['</search>', '</lookup>', '</finish>']
generation_kwargs.update({'stop_sequences': callable_entities})
self.should_continue_prompting = True
for idx in range(max_calls):
self.response = self.chat.send_message(content=[model_prompt],
generation_config=generation_kwargs, stream=False)
for chunk in self.response:
print(chunk.text, end=' ')
response_cmd = self.chat.history[-1].parts[-1].text
try:
# regex to extract <function name written in between angular brackets>
cmd = re.findall(r'<(.*)>', response_cmd)[-1]
print(f'</{cmd}>')
# regex to extract param
query = response_cmd.split(f'<{cmd}>')[-1].strip()
# call to appropriate function
observation = self.__getattribute__(cmd)(query)
if not self.should_continue_prompting:
break
stream_message = f"\nObservation {idx + 1}\n{observation}"
print(stream_message)
# send function's output as user's response
model_prompt = f"<{cmd}>{query}</{cmd}>'s Output: {stream_message}"
except (IndexError, AttributeError) as e:
model_prompt = "Please try to generate thought-action-observation traces \
as instructed by the prompt."
测试 ReAct 提示的 Gemini 模型
gemini_ReAct_chat = ReAct(model='gemini-3.7-flash', ReAct_prompt='model_instructions.txt')
# Note: try different combinations of generational_config parameters for variational results
gemini_ReAct_chat("What are the total of ages of the main trio from the new Percy Jackson and the Olympians TV series in real life?", temperature=0.2)
现在,尝试在不使用 ReAct 提示的情况下,向 gemini-3.7-flash 模型提出同样的问题。
gemini_ReAct_chat.model.generate_content("What is the total of ages of the main trio from the new Percy Jackson and the Olympians TV series in real life?").text
总结
ReAct 提示的 Gemini 模型由外部信息源提供依据,因此不太容易产生幻觉。此外,模型生成的思考-行动-观察轨迹通过让用户见证模型回答用户查询的推理过程,增强了人类可解释性和可信度。
后续步骤
前往这个 Streamlit 应用,与使用此代码构建的 ReAct 提示 Gemini 机器人进行交互。
常见问题
常见错误:1) API密钥未正确设置,导致认证失败——确保在Colab中创建GEMINI_API_KEY密钥并正确获取;2) wikipedia包搜索时遇到DisambiguationError或PageError——代码已处理,返回相似搜索建议,但若模型未正确使用建议,可调整提示或增加示例;3) 模型生成格式不符合预期(如未包含动作标记)——可增加温度或调整提示;4) 达到max_calls上限仍未完成——可增加max_calls(但不超过8)或优化提示;5) 网络问题导致API调用失败——检查网络连接并重试。排查方法:打印聊天历史以检查模型输出,使用try-except捕获异常,并逐步调试工具函数。生产环境优化:使用异步调用减少延迟,缓存搜索结果,使用更高效的搜索API,或采用原生函数调用以简化流程。
企业应用扩展
本教程的ReAct模式可扩展至其他工具和场景,如连接数据库、调用REST API或使用代码解释器。开发者可自定义工具集,并调整提示以适配不同任务。此外,可结合检索增强生成(RAG)技术,将维基百科替换为私有知识库,构建企业级问答系统。对于生产环境,建议使用Gemini的原生函数调用功能,以更稳定地处理复杂交互。还可探索多模型协作,如使用一个模型负责推理,另一个负责工具调用,以提升性能。
总结
本教程面向有编程基础的开发者,深入讲解如何利用Google的gemini-3.7-flash模型实现ReAct(推理与行动协同)提示方法,使模型能够通过搜索维基百科来回答复杂问题。教程涵盖环境配置、ReAct提示设计、少样本学习、工具定义(搜索、查找、完成)以及通过stop_sequences模拟函数调用的完整流程。通过实际代码示例,读者将学会构建一个可交互的问答系统,并理解如何减少模型幻觉、增强可解释性。教程还提供了常见错误排查与生产环境优化建议,帮助开发者将ReAct模式应用于实际AI工程实践。
- --
内容来源与验证
- 内容等级:PREMIUM_A
- 质量等级:A
- 难度:中级
- 验证等级:V1
- 原文作者:
- 原文日期:
- 来源许可:Apache-2.0
- 来源版本:
2ed55866c37a4915f6fcb006a683e4478e4b5fb4 - 查看原文
站内还有更多完整实战教程
加入会员,解锁全部教程、完整代码与持续更新内容。
加入会员