利用 LangChain 代理生成音乐推荐
对于我们的解决方案,我们将采用代理驱动的方法。传统的 LLMs 有一个简单的思维流程:问答。通过代理,引入了一种更符合逻辑、类似人类的方法,以推理为中心。具体来说,我们将探索在我们的用例中一个ReAct(推理 + 行动)代理。通过 ReAct 代理,我们允许在采取行动之前进行观察和思考(推理)。我们如何启用这个代理,它与传统的 LLMs 有何不同?我们为这个代理提供了工具,这些工具本质上提供了访问
原文:
towardsdatascience.com/generate-music-recommendations-utilizing-langchain-agents-d0e531de95df
图片来自Unsplash的**Marcela Laskoski
如我们在之前的文章中所探讨的,大型语言模型(LLMs)包含大量的知识,并且能够仅从它们已经进行微调的数据中回答许多领域的问题。在过去,我们分析了如何利用诸如检索增强生成(RAG)等技术来通过提供可以辅助模型生成更准确输出的额外数据来增强响应。虽然 RAG 和微调可以用来使模型熟悉特定的数据/知识库,但有时模型需要访问可能发生变化的资料来源。
这的一个例子是实时数据源。例如,如果我们要求模型提供今天的天气,它将无法生成适当的响应。
ChatGPT 响应(作者截图)
LLMs 普遍存在的一个大问题是它们无法访问外部数据源。模型是在某个特定时间段内训练的,因此可能无法访问我们需要提供正确答案的最新和最佳信息。
我们如何增强我们的 LLM 以实现实时数据访问?代理是一种生成式 AI 构建,它将简单的问答或文本生成提升到了一个新的层次。通过代理,我们提供访问不同的工具或 API,并允许模型本身推理出正确的行动方案。以天气为例,我们会给我们的代理提供访问天气 API 的权限,并允许它检索回答上述问题所需的数据。
在数据访问的主题下,我想到了我有时遇到的一个问题。我是一个热衷于听音乐的人,有时我只想要求一些我听过的艺术家的顶级歌曲推荐。在过去,人们已经构建了推荐引擎/系统来解决此类个性化用例。虽然这仍然适用,但对我来说,一个无需构建特定模型或进行训练的解决方案会更好。
在这个例子中,我们看看如何使用 LangChain 创建一个代理,并将其与 Spotify API (Spotipy) 集成,根据我的查询生成音乐推荐。为什么我们不能使用 RAG?如果你已经积累了一个包含所有歌曲的大型数据库,你可以使用 RAG,但你必须不断更新和维护这个数据源。通过代理,我们可以通过 Spotify API 访问最新的数据。在需要实时或任何基于 API 的数据访问的用例中,采用代理驱动的方法是理想的。请注意,在某些用例中,你甚至可以通过你的代理提供对 RAG 工作流程的访问,并让它确定这是否是采取正确行动的正确途径。既然我们已经确定了问题,让我们开始构建解决方案。
注意:本文假设对 Python、LLMs 和 LangChain 有一定的了解。关于 LangChain 的优秀入门文章可以在这里找到。
免责声明:我是 AWS 的机器学习架构师,我的观点是我自己的。
目录
-
解决方案概述
-
代理驱动解决方案 a. 设置 b. 自定义工具类 c. 代理创建与调用
-
其他资源与结论
1. 解决方案概述
对于我们的解决方案,我们将采用代理驱动的方法。传统的 LLMs 有一个简单的思维流程:问答。通过代理,引入了一种更符合逻辑、类似人类的方法,以推理为中心。具体来说,我们将探索在我们的用例中一个 ReAct(推理 + 行动)代理。通过 ReAct 代理,我们允许在采取行动之前进行观察和思考(推理)。
我们如何启用这个代理,它与传统的 LLMs 有何不同?我们为这个代理提供了工具,这些工具本质上提供了访问不同数据源的能力,例如在本用例中的 Spotify API。在工具本身中,我们提供了何时使用这些工具的自然语言理解。根据用户输入,LLM 将根据这些指令推断出正确的工具。
高级架构(由作者制作)
让我们了解我们将要使用的实现此解决方案的堆栈:
-
LangChain:LangChain 是一个流行的 Python 框架,它通过提供现成的模块来简化生成式 AI 应用程序,这些模块有助于提示工程、RAG 实现和 LLM 工作流程编排。在这个特定的用例中,我们使用 LangChain 构建我们的 ReAct 代理。
-
代理: LangChain 提供了不同类型的代理,在这种情况下,我们将使用一个 ReAct 代理,并为其提供访问我们所需工具的权限。
-
工具: LangChain 内置了各种工具,如维基百科、谷歌搜索等。如果没有原生 API 集成,你可以构建一个自定义工具。在我们的项目中,我们构建了一个与 Spotify API 集成的自定义工具,并返回音乐推荐。
-
Spotipy (Spotify API): Spotipy 是我们将用于与服务交互的 Spotify 开源 Python 包。要开始,你需要创建一个 Spotify 项目并获取你的凭证。请参阅此指南进行设置。
-
Bedrock Claude: 我们将利用 Amazon Bedrock 通过 Claude 作为驱动我们代理的 LLM。Bedrock 也与 LangChain 中的 LLM 类原生集成,这使得构建我们的代理更加容易。
现在我们已经了解了我们解决方案的不同部分,让我们看看我们如何构建它。
2. 代理驱动解决方案
a. 设置
在这个例子中,我们将在一个 SageMaker Studio Notebook 中工作,使用 ml.t3.medium 实例。只要你可以安装以下库,你就可以在你的选择的开发环境中工作:
!pip install spotipy langchain
注意,在我们开始之前,如果你还没有,你需要创建一个 Spotify 开发者账户。在你的 Spotify 开发者账户中,确保你已经创建了一个应用程序,这将显示与 API 一起工作的凭证。一旦创建,你应该能够在仪表板上的项目中可视化你的凭证(设置选项卡)和 API 请求。
Spotify Dashboard (截图由作者提供)
在我们的笔记本中,我们实例化我们将用于与 Spotify 一起工作的客户端。
import spotipy
import spotipy.util as util
from spotipy.oauth2 import SpotifyClientCredentials
import random
client_id = 'Enter Client ID'
client_secret = 'Enter Client Secret'
# instantitate spotipy client
sp = spotipy.Spotify(client_credentials_manager=
SpotifyClientCredentials(client_id=client_id,
client_secret=client_secret))
现在我们已经设置了 Spotify 客户端,我们就可以进入代理编排部分。
b. 自定义工具类
正如我们讨论的那样,LangChain 代理需要访问工具,以便它们能够与外部数据源一起工作。有许多内置工具,如维基百科,你可以在 LangChain 中简单地指定包,如下所示:
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
目前,与 Spotify API 没有原生集成,因此我们需要继承自 BaseTool 类并构建一个 Spotify 工具,然后将其提供给我们的代理。
我们定义了一个扩展 BaseTool 类的 Spotify 工具:
from langchain.tools import BaseTool, StructuredTool, tool
class SpotifyTool(BaseTool):
name = "Spotify Music Recommender"
description = "Use this tool when asked music recommendations."
注意,我们提供了何时使用此工具的描述,这允许 LLM 使用自然语言理解来推断何时使用该工具。我们还提供了工具应期望的输入模式。在这种情况下,我们指定了两个参数:
-
艺术家:我们感兴趣的艺术家列表,基于此,LLM 将推荐该艺术家的更多热门曲目。
-
曲目数量:我希望显示的推荐曲目数量。
from langchain.pydantic_v1 import BaseModel, Field
# schema
class MusicInput(BaseModel):
artists: list = Field(description="A list of artists that they'd like to see music from")
tracks: int = Field(description="The number of tracks/songs they want returned.")
class SpotifyTool(BaseTool):
name = "Spotify Music Recommender"
description = "Use this tool when asked music recommendations."
args_schema: Type[BaseModel] = MusicInput # define schema
现在我们已经了解了 LLM 应在提示中寻找哪些输入,我们可以定义几个不同的方法来处理 Spotipy 包:
# utils
@staticmethod
def retrieve_id(artist_name: str) -> str:
results = sp.search(q='artist:' + artist_name, type='artist')
if len(results) > 0:
artist_id = results['artists']['items'][0]['id']
else:
raise ValueError(f"No artists found with this name: {artist_name}")
return artist_id
@staticmethod
def retrieve_tracks(artist_id: str, num_tracks: int) -> list:
if num_tracks > 10:
raise ValueError("Can only provide up to 10 tracks per artist")
tracks = []
top_tracks = sp.artist_top_tracks(artist_id)
for track in top_tracks['tracks'][:num_tracks]:
tracks.append(track['name'])
return tracks
@staticmethod
def all_top_tracks(artist_array: list) -> list:
complete_track_arr = []
for artist in artist_array:
artist_id = SpotifyTool.retrieve_id(artist)
all_tracks = {artist: SpotifyTool.retrieve_tracks(artist_id, 10)}
complete_track_arr.append(all_tracks)
return complete_track_arr
这些方法基本上会获取你检索到的艺术家,并返回这些艺术家的热门曲目。注意,目前对于 Spotipy API 来说,只能检索到前 10 首曲目。
然后,我们定义一个主要执行函数,其中我们获取请求艺术家的所有热门曲目,并根据我们在提示中请求的曲目数量进行解析:
# main execution
def _run(self, artists: list, tracks: int) -> list:
num_artists = len(artists)
max_tracks = num_artists * 10
all_tracks_map = SpotifyTool.all_top_tracks(artists) # map for artists with top 10 tracks
all_tracks = [track for artist_map in all_tracks_map for artist, tracks in artist_map.items() for track in tracks] #complete list of tracks
# only 10 tracks per artist
if tracks > max_tracks:
raise ValueError(f"Only 10 tracks per artist, max tracks for this many artists is: {max_tracks}")
final_tracks = random.sample(all_tracks, tracks)
return final_tracks
如果你想通过 API(构建自己的播放列表)添加额外功能,你可以在该工具本身中定义这些额外方法。
现在我们已经定义了我们的自定义工具类,我们可以专注于将其与其他组件拼接在一起以创建代理。
c. 代理创建与调用
虽然我们已经定义了代理需要的输入/输出规范,但我们必须定义 LLM,它将是操作的头脑。
在这个例子中,我们通过 Amazon Bedrock 使用Anthropic Claude:
from langchain.llms import Bedrock
model_id = "anthropic.claude-v2:1"
model_params = {"max_tokens_to_sample": 500,
"top_k": 100,
"top_p": .95,
"temperature": .5}
llm = Bedrock(
model_id=model_id,
model_kwargs=model_params
)
# sample Bedrock Inference
llm("What is the capitol of the United States?")
然后,我们可以实例化我们的工具类,并将其与 LLM 一起使用来创建我们的代理。注意,我们指定代理类型为 ReAct,根据你使用的代理类型进行调整。
from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
tools = [SpotifyTool()]
agent = initialize_agent(tools, llm,
agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose = True)
一旦我们的代理构建完成,我们可以运行一个示例推理(我知道的艺术家随机混合),并查看思维链,因为我们已启用详细模式。
print(agent.run("""I like the following artists: [Arijit Singh, Future,
The Weekend], can I get 12 song recommendations with them in it."""))
代理响应一(作者截图)
代理响应二(作者截图)
注意,代理会特别寻找我们指定的两个参数来使用此工具,一旦它识别出这些参数,它就能够采取逻辑行动,并使用我们提交的值正确地进行推理。
注意,在这个提示中,我们直接传递一个数组,但你可以通过使用 LangChain 提示模板来结构化你的提示,使其更简洁。
3. 其他资源与结论
GenAI-Samples/LangChain-Agents-Spotify/langchain-agents-spotify.ipynb at master ·…
整个示例的代码可以在上面的链接中找到,包括我其他生成式 AI 代码示例。使用代理的优势在于你可以指定后端功能,以获取所需的内容。在这个示例中,我们只是检索艺术家的顶级曲目,但你可以在你的工具中添加适当的 API 调用,将这个示例扩展到直接在你的 Spotify 账户中创建播放列表。请注意,对于更真实或个性化的用例,你也可以利用 RAG(Retrieval Augmented Generation)让你的代理访问你自己的数据/音乐,并让它从可访问的内容中得出建议。
我希望这篇文章能帮助你了解如何将 API 与你的生成式 AI 代理集成,以解决挑战性问题。请继续关注这个领域的更多内容!
如往常一样,感谢阅读,欢迎留下任何反馈。
更多推荐



所有评论(0)