
如何快速實(shí)現(xiàn)REST API集成以優(yōu)化業(yè)務(wù)流程
agent = initialize_agent(
tools, # 配置工具集
llm, # 配置大語言模型 負(fù)責(zé)決策
agent=AgentType.OPENAI_FUNCTIONS, # 設(shè)置 agent 類型
agent_kwargs=agent_kwargs, # 設(shè)定 agent 角色
verbose=True,
memory=memory, # 配置記憶模式 )
首先是配置工具集 Tools,代碼如下:可以看到這是一個(gè)二元數(shù)組,也就意味著本示例中的 Agent 依賴兩個(gè)工具。
from langchain.agents import initialize_agent, Tool
tools = [
Tool(
name="search",
func=search,
description="useful for when you need to answer questions about current events, data. You should ask targeted questions"
),
ScrapeWebsiteTool(),
]
先看第一個(gè)工具:在配置工具時(shí),需要聲明工具依賴的函數(shù),由于該示例實(shí)現(xiàn)的功能為依賴網(wǎng)絡(luò)收集相應(yīng)的信息,然后匯總成一篇論文,所以創(chuàng)建了一個(gè) search 函數(shù),這個(gè)函數(shù)用于調(diào)用 Google 搜索。它接受一個(gè)查詢參數(shù),然后將查詢發(fā)送給Serper API。API 的響應(yīng)會(huì)被打印出來并返回。
# 調(diào)用 Google search by Serper
def search(query):
serper_google_url = os.getenv("SERPER_GOOGLE_URL")
payload = json.dumps({
"q": query
})
headers = {
'X-API-KEY': serper_api_key,
'Content-Type': 'application/json'
}
response = requests.request("POST", serper_google_url, headers=headers, data=payload)
print(f'Google 搜索結(jié)果: \n {response.text}')
return response.text
再來看一下所依賴的第二個(gè)工具函數(shù),這里用了另一種聲明工具的方式 Class ?聲明:ScrapeWebsiteTool(),它有以下幾個(gè)屬性和方法:
class ScrapeWebsiteTool(BaseTool):
name = "scrape_website"
description = "useful when you need to get data from a website url, passing both url and objective to the function; DO NOT make up any url, the url should only be from the search results"
args_schema: Type[BaseModel] = ScrapeWebsiteInput
def _run(self, target: str, url: str):
return scrape_website(target, url)
def _arun(self, url: str):
raise NotImplementedError("error here")
name:工具的名稱,這里是 “scrape_website”;description:工具的描述;args_schema:工具的參數(shù)模式,這里是 ScrapeWebsiteInput 類,表示這個(gè)工具需要的輸入?yún)?shù),聲明代碼如下,這是一個(gè)基于 Pydantic 的模型類,用于定義 scrape_website 函數(shù)的輸入?yún)?shù)。它有兩個(gè)字段:target 和 url,分別表示用戶給Agent 的目標(biāo)和任務(wù)以及需要被爬取的網(wǎng)站的 URL。
class ScrapeWebsiteInput(BaseModel):
"""Inputs for scrape_website"""
target: str = Field(
description="The objective & task that users give to the agent")
url: str = Field(description="The url of the website to be scraped")
_run 方法:這是工具的主要執(zhí)行函數(shù),它接收一個(gè)目標(biāo)和一個(gè) URL 作為參數(shù),然后調(diào)用 scrape_website 函數(shù)來爬取網(wǎng)站并返回結(jié)果。scrape_website 函數(shù)根據(jù)給定的目標(biāo)和 URL 爬取網(wǎng)頁內(nèi)容。首先,它發(fā)送一個(gè) HTTP 請(qǐng)求來獲取網(wǎng)頁的內(nèi)容。如果請(qǐng)求成功,它會(huì)使用 BeautifulSoup 庫來解析 HTML 內(nèi)容并提取文本。如果文本長度超過 5000 個(gè)字符,它會(huì)調(diào)用 summary 函數(shù)來對(duì)內(nèi)容進(jìn)行摘要。否則,它將直接返回提取到的文本。其代碼如下:
# 根據(jù) url 爬取網(wǎng)頁內(nèi)容,給出最終解答
# target :分配給 agent 的初始任務(wù)
# url :Agent 在完成以上目標(biāo)時(shí)所需要的URL,完全由Agent自主決定并且選取,其內(nèi)容或是中間步驟需要,或是最終解答需要
def scrape_website(target: str, url: str):
print(f"開始爬取: {url}...")
headers = {
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
}
payload = json.dumps({
"url": url
})
post_url = f"https://chrome.browserless.io/content?token={browserless_api_key}"
response = requests.post(post_url, headers=headers, data=payload)
# 如果返回成功
if response.status_code == 200:
soup = BeautifulSoup(response.content, "html.parser")
text = soup.get_text()
print("爬取的具體內(nèi)容:", text)
# 控制返回內(nèi)容長度,如果內(nèi)容太長就需要切片分別總結(jié)處理
if len(text) > 5000:
# 總結(jié)爬取的返回內(nèi)容
output = summary(target, text)
return output
else:
return text
else:
print(f"HTTP請(qǐng)求錯(cuò)誤,錯(cuò)誤碼為{response.status_code}")
從上述代碼中我們可以看到其還依賴一個(gè) summary 函數(shù),用此函數(shù)解決內(nèi)容過長的問題,這個(gè)函數(shù)使用 Map-Reduce 方法對(duì)長文本進(jìn)行摘要。它首先初始化了一個(gè)大語言模型(llm),然后定義了一個(gè)大文本切割器(text_splitter)。接下來,它創(chuàng)建了一個(gè)摘要鏈(summary_chain),并使用這個(gè)鏈對(duì)輸入文檔進(jìn)行摘要。
# 如果需要處理的內(nèi)容過長,先切片分別處理,再綜合總結(jié)
# 使用 Map-Reduce 方式
def summary(target, content):
# model list :https://platform.openai.com/docs/models
# gpt-4-32k gpt-3.5-turbo-16k-0613
llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-16k-0613")
# 定義大文本切割器
# chunk_overlap 是一個(gè)在使用 OpenAI 的 GPT-3 或 GPT-4 API 時(shí)可能會(huì)遇到的參數(shù),特別是需要處理長文本時(shí)。
# 該參數(shù)用于控制文本塊(chunks)之間的重疊量。
# 上下文維護(hù):重疊確保模型在處理后續(xù)塊時(shí)有足夠的上下文信息。
# 連貫性:它有助于生成更連貫和一致的輸出,因?yàn)槟P涂梢浴坝涀 鼻耙粋€(gè)塊的部分內(nèi)容。
text_splitter = RecursiveCharacterTextSplitter(
separators=["\n\n", "\n"], chunk_size=5000, chunk_overlap=200)
docs = text_splitter.create_documents([content])
map_prompt = """
Write a summary of the following text for {target}:
"{text}"
SUMMARY:
"""
map_prompt_template = PromptTemplate(
template=map_prompt, input_variables=["text", "target"])
summary_chain
# 初始化大語言模型,負(fù)責(zé)決策
llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-16k-0613")
這段代碼初始化了一個(gè)名為 llm 的大語言模型對(duì)象,它是 ChatOpenAI 類的實(shí)例。ChatOpenAI 類用于與大語言模型(如GPT-3)進(jìn)行交互,以生成決策和回答。在初始化 ChatOpenAI 對(duì)象時(shí),提供了以下參數(shù):
temperature:一個(gè)浮點(diǎn)數(shù),表示生成文本時(shí)的溫度。溫度值越高,生成的文本將越隨機(jī)和多樣;溫度值越低,生成的文本將越確定和一致。在這里設(shè)置為 0,因?yàn)楸?Demo 的目的為生成一個(gè)論文,所以我們并不希望大模型有較多的可變性,而是希望生成非常確定和一致的回答。
model:一個(gè)字符串,表示要使用的大語言模型的名稱。在這里,我們?cè)O(shè)置為 “gpt-3.5-turbo-16k-0613″,表示使用 GPT-3.5 Turbo 模型。
首先來看一下 AgentType 這個(gè)變量的初始化,這里是用來設(shè)置 Agent 類型的一個(gè)參數(shù),具體可以參考官網(wǎng):AgentType, 如下所示:
可以看到官網(wǎng)里列舉了7種 Agent 類型,可以根據(jù)自己的需求進(jìn)行選擇,在本示例中選用的是第一種類型 OpenAI functions。此外,還要設(shè)定 Agent 角色以及記憶模式:
# 初始化agents的詳細(xì)描述
system_message = SystemMessage(
content="""您是一位世界級(jí)的研究員,可以對(duì)任何主題進(jìn)行詳細(xì)研究并產(chǎn)生基于事實(shí)的結(jié)果;
您不會(huì)憑空捏造事實(shí),您會(huì)盡最大努力收集事實(shí)和數(shù)據(jù)來支持研究。
請(qǐng)確保按照以下規(guī)則完成上述目標(biāo):
1/ 您應(yīng)該進(jìn)行足夠的研究,盡可能收集關(guān)于目標(biāo)的盡可能多的信息
2/ 如果有相關(guān)鏈接和文章的網(wǎng)址,您將抓取它以收集更多信息
3/ 在抓取和搜索之后,您應(yīng)該思考“根據(jù)我收集到的數(shù)據(jù),是否有新的東西需要我搜索和抓取以提高研究質(zhì)量?”如果答案是肯定的,繼續(xù);但不要進(jìn)行超過5次迭代
4/ 您不應(yīng)該捏造事實(shí),您只應(yīng)該編寫您收集到的事實(shí)和數(shù)據(jù)
5/ 在最終輸出中,您應(yīng)該包括所有參考數(shù)據(jù)和鏈接以支持您的研究;您應(yīng)該包括所有參考數(shù)據(jù)和鏈接以支持您的研究
6/ 在最終輸出中,您應(yīng)該包括所有參考數(shù)據(jù)和鏈接以支持您的研究;您應(yīng)該包括所有參考數(shù)據(jù)和鏈接以支持您的研究"""
)
# 初始化 agent 角色模板
agent_kwargs = {
"extra_prompt_messages": [MessagesPlaceholder(variable_name="memory")],
"system_message": system_message,
}
# 初始化記憶類型
memory = ConversationSummaryBufferMemory(
memory_key="memory", return_messages=True, llm=llm, max_token_limit=300)
在設(shè)置 agent_kwargs 時(shí):”extra_prompt_messages”:這個(gè)鍵對(duì)應(yīng)的值是一個(gè)包含 MessagesPlaceholder 對(duì)象的列表。這個(gè)對(duì)象的 variable_name 屬性設(shè)置為 “memory”,表示我們希望在構(gòu)建 Agent 的提示詞時(shí),將 memory 變量的內(nèi)容插入到提示詞中。”system_message”:這個(gè)鍵對(duì)應(yīng)的值是一個(gè) SystemMessage 對(duì)象,它包含了 Agent 的角色描述和任務(wù)要求。
# 初始化記憶類型
memory = ConversationSummaryBufferMemory(
memory_key="memory", return_messages=True, llm=llm, max_token_limit=300)
在設(shè)置memory 的記憶類型對(duì)象時(shí):利用了 ConversationSummaryBufferMemory 類的實(shí)例。該類用于在與 AI 助手的對(duì)話中緩存和管理信息。在初始化這個(gè)對(duì)象時(shí),提供了以下參數(shù):memory_key:一個(gè)字符串,表示這個(gè)記憶對(duì)象的鍵。在這里設(shè)置為 “memory”;return_messages:一個(gè)布爾值,表示是否在返回的消息中包含記憶內(nèi)容。在這里設(shè)置為 True,表示希望在返回的消息中包含記憶內(nèi)容;llm:對(duì)應(yīng)的大語言模型對(duì)象,這里是之前初始化的 llm 對(duì)象。這個(gè)參數(shù)用于指定在處理記憶內(nèi)容時(shí)使用的大語言模型;max_token_limit:一個(gè)整數(shù),表示記憶緩存的最大令牌限制。在這里設(shè)置為 300,表示希望緩存的記憶內(nèi)容最多包含 300 個(gè) token。
這里導(dǎo)入所需庫:這段代碼導(dǎo)入了一系列所需的庫,包括 os、dotenv、langchain相關(guān)庫、requests、BeautifulSoup、json 和 streamlit。
import os
from dotenv import load_dotenv
from langchain import PromptTemplate
from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
from langchain.chat_models import ChatOpenAI
from langchain.prompts import MessagesPlaceholder
from langchain.memory import ConversationSummaryBufferMemory
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains.summarize import load_summarize_chain
from langchain.tools import BaseTool
from pydantic import BaseModel, Field
from langchain.schema import SystemMessage
from typing import Type
from bs4 import BeautifulSoup
import requests
import json
import streamlit as st
# 加載必要的參數(shù)
load_dotenv()
serper_api_key=os.getenv("SERPER_API_KEY")
browserless_api_key=os.getenv("BROWSERLESS_API_KEY")
openai_api_key=os.getenv("OPENAI_API_KEY")
main 函數(shù):這是 streamlit 應(yīng)用的主函數(shù)。它首先設(shè)置了頁面的標(biāo)題和圖標(biāo),然后創(chuàng)建了一些 header,并提供一個(gè)文本輸入框讓用戶輸入查詢。當(dāng)用戶輸入查詢后,它會(huì)調(diào)用 Agent 來處理這個(gè)查詢,并將結(jié)果顯示在頁面上。
def main():
st.set_page_config(page_title="AI Assistant Agent", page_icon=":dolphin:")
st.header("LangChain 實(shí)例講解 3 -- Agent", divider='rainbow')
st.header("AI Agent :blue[助理] :dolphin:")
query = st.text_input("請(qǐng)?zhí)釂栴}和需求:")
if query:
st.write(f"開始收集和總結(jié)資料 【 {query}】 請(qǐng)稍等")
result = agent({"input": query})
st.info(result['output'])
至此 Agent 的使用示例代碼就描述完畢了,我們可以看到,其實(shí) Agent 的功能就是其會(huì)自主的去選擇并利用最合適的工具,從而解決問題,我們提供的 Tools 豐富,則其功能越強(qiáng)大。
文章轉(zhuǎn)自微信公眾號(hào)@玄姐聊AGI
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)