跳转到主内容

2 篇带有“tavily”标签的文章

查看所有标签

研究的未来是混合模式

·阅读时长 8 分钟
Assaf Elovic
GPT Researcher 和 Tavily 的创建者

Hyrbrid Research with GPT Researcher

在过去几年中,我们见证了旨在颠覆研究方式的新型人工智能工具的爆炸式增长。其中一些工具,如 ChatPDFConsensus,专注于从文档中提取见解。另一些工具,如 Perplexity,则擅长在网络上搜索信息。但问题在于:这些工具没有一个能将网络搜索和本地文档搜索结合在单一的、有上下文的研究流程中。

这就是为什么我很高兴能向大家介绍 GPT Researcher 的最新进展——现在它能够针对任何给定的任务和文档进行混合研究。

基于网络的研究往往缺乏特定背景,有信息过载的风险,并且可能包含过时或不可靠的数据。另一方面,基于本地的研究仅限于历史数据和现有知识,可能造成组织内部的“回音室效应”,并错过关键的市场趋势或竞争对手的动态。这两种方法如果孤立使用,都可能导致不完整或有偏见的见解,从而妨碍您做出充分知情的决策。

今天,我们将改变这一局面。在本指南的最后,您将学会如何进行混合研究,它结合了网络和本地两种方式的优点,使您能够进行更彻底、更相关、更有见地的研究。

为什么混合研究效果更好

通过结合网络和本地来源,混合研究解决了这些局限性,并提供了几个关键优势:

  1. 有依据的上下文:本地文档提供了经过验证的、特定于组织的信息基础。这将研究建立在已有知识之上,减少了偏离核心概念或误解行业特定术语的风险。

    示例:一家制药公司在研究新药开发机会时,可以将其内部研究论文和临床试验数据作为基础,然后用网上最新发表的研究和监管更新来补充。

  2. 提高准确性:网络来源提供最新信息,而本地文档提供历史背景。这种结合可以进行更准确的趋势分析和决策。

    示例:一家金融服务公司在分析市场趋势时,可以将其历史交易数据与实时市场新闻和社交媒体情绪分析相结合,从而做出更明智的投资决策。

  3. 减少偏见:通过同时从网络和本地来源获取信息,我们降低了任何单一来源中可能存在的偏见风险。

    示例:一家科技公司在评估其产品路线图时,可以将内部功能请求和使用数据与外部客户评论和竞争对手分析相平衡,确保获得全面的视角。

  4. 改进规划和推理:大语言模型(LLM)可以利用本地文档的背景信息,更好地规划其网络研究策略,并对在网上找到的信息进行推理。

    示例:一个由人工智能驱动的市场研究工具,可以利用公司过去的市场活动数据来指导其在网上搜索当前的市场趋势,从而获得更相关、更具可操作性的见解。

  5. 定制化见解:混合研究允许将专有信息与公共数据相结合,从而产生独特的、特定于组织的见解。

    示例:一家零售连锁店可以将其销售数据与网络抓取的竞争对手定价和经济指标相结合,以优化其在不同地区的定价策略。

这些只是可以利用混合研究的商业用例中的几个例子,但闲话少说——让我们开始构建吧!

构建混合研究助手

在我们深入探讨细节之前,值得一提的是,GPT Researcher 开箱即用,具备进行混合研究的能力!然而,为了真正理解其工作原理并让您更深入地了解该过程,我们将深入其内部一探究竟。

GPT Researcher hybrid research

如上图所示,GPT Researcher 根据本地文档自动生成的计划进行网络研究。然后,它从本地和网络数据中检索相关信息,用于最终的研究报告。

我们将探讨如何使用 LangChain 处理本地文档,这是 GPT Researcher 文档处理的关键组成部分。然后,我们将向您展示如何利用 GPT Researcher 进行混合研究,结合网络搜索和您的本地文档知识库的优势。

使用 Langchain 处理本地文档

LangChain 提供了多种文档加载器,使我们能够处理不同的文件类型。在处理多样化的本地文档时,这种灵活性至关重要。以下是如何进行设置:

from langchain_community.document_loaders import (
PyMuPDFLoader,
TextLoader,
UnstructuredCSVLoader,
UnstructuredExcelLoader,
UnstructuredMarkdownLoader,
UnstructuredPowerPointLoader,
UnstructuredWordDocumentLoader
)
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma

def load_local_documents(file_paths):
documents = []
for file_path in file_paths:
if file_path.endswith('.pdf'):
loader = PyMuPDFLoader(file_path)
elif file_path.endswith('.txt'):
loader = TextLoader(file_path)
elif file_path.endswith('.csv'):
loader = UnstructuredCSVLoader(file_path)
elif file_path.endswith('.xlsx'):
loader = UnstructuredExcelLoader(file_path)
elif file_path.endswith('.md'):
loader = UnstructuredMarkdownLoader(file_path)
elif file_path.endswith('.pptx'):
loader = UnstructuredPowerPointLoader(file_path)
elif file_path.endswith('.docx'):
loader = UnstructuredWordDocumentLoader(file_path)
else:
raise ValueError(f"Unsupported file type: {file_path}")

documents.extend(loader.load())

return documents

# Use the function to load your local documents
local_docs = load_local_documents(['company_report.pdf', 'meeting_notes.docx', 'data.csv'])

# Split the documents into smaller chunks for more efficient processing
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(local_docs)

# Create embeddings and store them in a vector database for quick retrieval
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(documents=splits, embedding=embeddings)

# Example of how to perform a similarity search
query = "What were the key points from our last strategy meeting?"
relevant_docs = vectorstore.similarity_search(query, k=3)

for doc in relevant_docs:
print(doc.page_content)

使用 GPT Researcher 进行网络研究

现在我们已经学会了如何处理本地文档,让我们快速了解一下 GPT Researcher 的工作原理:

GPT Researcher Architecture

如上所述,GPT Researcher 通过生成潜在的研究查询,为给定的任务创建一个研究计划,这些查询可以共同提供对该主题的客观而广泛的概述。一旦生成这些查询,GPT Researcher 会使用像 Tavily 这样的搜索引擎来查找相关结果。每个抓取的结果随后会保存在一个向量数据库中。最后,检索与研究任务最相关的前 k 个数据块,以生成最终的研究报告。

GPT Researcher 支持混合研究,这涉及一个额外的步骤,即在检索最相关的信息之前对本地文档进行分块(使用 Langchain 实现)。经过社区的大量评估,我们发现混合研究将最终结果的正确性提高了 40% 以上!

使用 GPT Researcher 运行混合研究

现在您对混合研究的工作原理有了更好的理解,让我们来演示一下使用 GPT Researcher 实现这一点是多么容易。

第一步:使用 PIP 安装 GPT Researcher

pip install gpt-researcher

第二步:设置环境

我们将使用 OpenAI 作为大语言模型(LLM)供应商,Tavily 作为搜索引擎来运行 GPT Researcher。在继续之前,您需要获取这两者的 API 密钥。然后,在您的命令行界面(CLI)中按如下方式导出环境变量:

export OPENAI_API_KEY={your-openai-key}
export TAVILY_API_KEY={your-tavily-key}

步骤 3:使用混合研究配置初始化 GPT Researcher

GPT Researcher 可以通过参数轻松初始化,以指示其运行混合研究。您可以进行多种形式的研究,请前往文档页面了解更多信息。

要让 GPT Researcher 运行混合研究,您需要将所有相关文件放入 my-docs 目录中(如果不存在,请创建它),并将实例的 report_source 设置为 "hybrid",如下所示。一旦报告源设置为 hybrid,GPT Researcher 将在 my-docs 目录中查找现有文档并将其包含在研究中。如果不存在任何文档,它将忽略该设置。

from gpt_researcher import GPTResearcher
import asyncio

async def get_research_report(query: str, report_type: str, report_source: str) -> str:
researcher = GPTResearcher(query=query, report_type=report_type, report_source=report_source)
research = await researcher.conduct_research()
report = await researcher.write_report()
return report

if __name__ == "__main__":
query = "How does our product roadmap compare to emerging market trends in our industry?"
report_source = "hybrid"

report = asyncio.run(get_research_report(query=query, report_type="research_report", report_source=report_source))
print(report)

如上所示,我们可以对以下示例进行研究:

  • 研究任务:“我们的产品路线图与我们行业的新兴市场趋势相比如何?”
  • 网络:当前市场趋势、竞争对手公告和行业预测
  • 本地:内部产品路线图文件和功能优先级列表

经过各种社区评估,我们发现这种研究的结果将研究的质量和正确性提高了 40% 以上,并将幻觉减少了 50%。此外,如上所述,本地信息有助于大语言模型(LLM)改进规划和推理,使其能够做出更好的决策并研究更相关的网络资源。

但等等,还有更多!GPT Researcher 还包括一个使用 NextJS 和 Tailwind 构建的精美前端应用程序。要了解如何运行它,请查看文档页面。您可以轻松地使用拖放功能来处理文档,以进行混合研究。

结论

混合研究代表了数据收集和决策制定方面的一大进步。通过利用 GPT Researcher 等工具,团队现在可以进行更全面、更具上下文感知能力和更具可操作性的研究。这种方法解决了孤立使用网络或本地资源的局限性,带来了诸如有依据的上下文、更高的准确性、减少偏见、改进规划和推理以及定制化见解等好处。

混合研究的自动化可以使团队能够更快、更数据驱动地做出决策,最终提高生产力,并在分析不断扩大的非结构化和动态信息池方面提供竞争优势。

如何构建可访问互联网的 OpenAI 助理

·6分钟阅读
Assaf Elovic
GPT Researcher 和 Tavily 的创建者

OpenAI 再次通过一次开创性的开发者日活动,展示了其系列工具、产品和服务的最新改进。其中一个重大发布是新的 Assistants API,它使开发者能够更轻松地构建自己的、有目标并能调用模型和工具的辅助型 AI 应用。

新的 Assistants API 目前支持三种类型的工具:代码解释器(Code Interpreter)、检索(Retrieval)和函数调用(Function calling)。尽管您可能期望检索工具支持在线信息检索(例如搜索 API 或作为 ChatGPT 插件),但它目前仅支持原始数据,如文本或 CSV 文件。

本博客将演示如何利用最新的 Assistants API 和函数调用工具来获取在线信息。

如果想跳过下面的教程,可以直接查看完整的 Github Gist

从高层次来看,一次典型的 Assistants API 集成包含以下步骤:

  • 通过在 API 中定义其自定义指令并选择一个模型,来创建一个助手(Assistant)。如果需要,可以启用代码解释器、检索和函数调用等工具。
  • 当用户开始对话时,创建一个对话线程(Thread)
  • 随着用户提问,向对话线程中添加消息(Message)
  • 在对话线程上运行(Run)助手以触发响应。这将自动调用相关工具。

如下所示,一个助手对象包含用于存储和处理助手与用户之间对话会话的对话线程(Threads),以及用于在对话线程上调用助手的运行(Run)。

OpenAI Assistant Object

让我们一步步来实施这些步骤吧!在这个例子中,我们将构建一个能够提供金融问题见解的金融 GPT。我们将使用 OpenAI Python SDK v1.2Tavily 搜索 API

首先,我们来定义助手的指令:

assistant_prompt_instruction = """You are a finance expert. 
Your goal is to provide answers based on information from the internet.
You must use the provided Tavily search API function to find relevant online information.
You should never use your own knowledge to answer questions.
Please include relevant url sources in the end of your answers.
"""

接下来,让我们完成步骤 1,使用最新的 GPT-4 Turbo 模型(128K 上下文)创建一个助手,并使用 Tavily 网络搜索 API 调用函数。

# Create an assistant
assistant = client.beta.assistants.create(
instructions=assistant_prompt_instruction,
model="gpt-4-1106-preview",
tools=[{
"type": "function",
"function": {
"name": "tavily_search",
"description": "Get information on recent events from the web.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "The search query to use. For example: 'Latest news on Nvidia stock performance'"},
},
"required": ["query"]
}
}
}]
)

第2步和第3步非常直接,我们将启动一个新的对话线程,并用一条用户消息来更新它。

thread = client.beta.threads.create()
user_input = input("You: ")
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content=user_input,
)

最后,我们将在对话线程上运行助手,以触发函数调用并获取响应。

run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant_id,
)

到目前为止一切顺利!但这里开始变得有点复杂了。与常规的 GPT API 不同,Assistants API 不会返回同步响应,而是返回一个状态。这允许在不同助手中进行异步操作,但需要更多的开销来获取状态并手动处理每一个。

Status Diagram

为了管理这个状态生命周期,让我们构建一个可复用的函数来处理等待各种状态(例如‘requires_action’)的情况。

# Function to wait for a run to complete
def wait_for_run_completion(thread_id, run_id):
while True:
time.sleep(1)
run = client.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run_id)
print(f"Current run status: {run.status}")
if run.status in ['completed', 'failed', 'requires_action']:
return run

只要运行尚未最终完成(例如,状态为已完成或需要函数调用操作),此函数就会休眠。

我们快要完成了!最后,让我们来处理助手想要调用网页搜索 API 的情况。

# Function to handle tool output submission
def submit_tool_outputs(thread_id, run_id, tools_to_call):
tool_output_array = []
for tool in tools_to_call:
output = None
tool_call_id = tool.id
function_name = tool.function.name
function_args = tool.function.arguments

if function_name == "tavily_search":
output = tavily_search(query=json.loads(function_args)["query"])

if output:
tool_output_array.append({"tool_call_id": tool_call_id, "output": output})

return client.beta.threads.runs.submit_tool_outputs(
thread_id=thread_id,
run_id=run_id,
tool_outputs=tool_output_array
)

如上所示,如果助手判断应该触发函数调用,我们会提取所需的函数参数,并将其传回可运行的线程。我们捕捉到这个状态,并如下所示调用我们的函数:

if run.status == 'requires_action':
run = submit_tool_outputs(thread.id, run.id, run.required_action.submit_tool_outputs.tool_calls)
run = wait_for_run_completion(thread.id, run.id)

就这样!我们现在拥有一个可以工作的 OpenAI 助手,它能利用实时的在线信息来回答金融问题。以下是完整的可运行代码:

import os
import json
import time
from openai import OpenAI
from tavily import TavilyClient

# Initialize clients with API keys
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])

assistant_prompt_instruction = """You are a finance expert.
Your goal is to provide answers based on information from the internet.
You must use the provided Tavily search API function to find relevant online information.
You should never use your own knowledge to answer questions.
Please include relevant url sources in the end of your answers.
"""

# Function to perform a Tavily search
def tavily_search(query):
search_result = tavily_client.get_search_context(query, search_depth="advanced", max_tokens=8000)
return search_result

# Function to wait for a run to complete
def wait_for_run_completion(thread_id, run_id):
while True:
time.sleep(1)
run = client.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run_id)
print(f"Current run status: {run.status}")
if run.status in ['completed', 'failed', 'requires_action']:
return run

# Function to handle tool output submission
def submit_tool_outputs(thread_id, run_id, tools_to_call):
tool_output_array = []
for tool in tools_to_call:
output = None
tool_call_id = tool.id
function_name = tool.function.name
function_args = tool.function.arguments

if function_name == "tavily_search":
output = tavily_search(query=json.loads(function_args)["query"])

if output:
tool_output_array.append({"tool_call_id": tool_call_id, "output": output})

return client.beta.threads.runs.submit_tool_outputs(
thread_id=thread_id,
run_id=run_id,
tool_outputs=tool_output_array
)

# Function to print messages from a thread
def print_messages_from_thread(thread_id):
messages = client.beta.threads.messages.list(thread_id=thread_id)
for msg in messages:
print(f"{msg.role}: {msg.content[0].text.value}")

# Create an assistant
assistant = client.beta.assistants.create(
instructions=assistant_prompt_instruction,
model="gpt-4-1106-preview",
tools=[{
"type": "function",
"function": {
"name": "tavily_search",
"description": "Get information on recent events from the web.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "The search query to use. For example: 'Latest news on Nvidia stock performance'"},
},
"required": ["query"]
}
}
}]
)
assistant_id = assistant.id
print(f"Assistant ID: {assistant_id}")

# Create a thread
thread = client.beta.threads.create()
print(f"Thread: {thread}")

# Ongoing conversation loop
while True:
user_input = input("You: ")
if user_input.lower() == 'exit':
break

# Create a message
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content=user_input,
)

# Create a run
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant_id,
)
print(f"Run ID: {run.id}")

# Wait for run to complete
run = wait_for_run_completion(thread.id, run.id)

if run.status == 'failed':
print(run.error)
continue
elif run.status == 'requires_action':
run = submit_tool_outputs(thread.id, run.id, run.required_action.submit_tool_outputs.tool_calls)
run = wait_for_run_completion(thread.id, run.id)

# Print messages from the thread
print_messages_from_thread(thread.id)

这个助手可以通过使用额外的检索信息、OpenAI 的代码解释器等功能进行进一步的定制和改进。此外,您还可以添加更多的函数工具,让助手变得更智能。

如果您有任何其他问题,请随时在下方留言!