自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

基于Llama 3的AI代理開發(fā)實戰(zhàn)演練 原創(chuàng)

發(fā)布于 2024-8-7 08:28
瀏覽
0收藏

通過本文,您將學會基于開源的深度學習模型可視化工具Gradio構(gòu)建一個具有Llama 3模型函數(shù)調(diào)用功能的AI代理的完整過程。

簡介

想象一下,你想買點東西。于是,你訪問某個電子商務(wù)網(wǎng)站并使用搜索選項查找所需內(nèi)容。也許你有很多東西要買,所以這個過程不是很有效。現(xiàn)在,請考慮一下這樣一個場景:打開一個應(yīng)用程序,用簡單的英語描述一下你想要的東西,然后按下回車鍵。你不必擔心搜索和價格比較,因為應(yīng)用程序會自動為你處理了。很酷,對吧?這正是我們將在本文中要構(gòu)建的目標程序。

下面,先讓我們先看一些例子。

基于Llama 3的AI代理開發(fā)實戰(zhàn)演練-AI.x社區(qū)

用戶同時請求多個產(chǎn)品

基于Llama 3的AI代理開發(fā)實戰(zhàn)演練-AI.x社區(qū)

用戶咨詢他/她能做出的最劃算的購買

接下來,讓我們?yōu)檫@個應(yīng)用程序增強一些功能。我們將使用Meta公司開發(fā)的具有函數(shù)調(diào)用功能的Llama 3開源模型。不過,本文示例程序也可以使用此模型的3.1版本來實現(xiàn)。根據(jù)Meta公司的公告(https://ai.meta.com/blog/meta-llama-3-1/),3.1版本模型可以更有效地使用工具和函數(shù)。

【注意】這些模型是支持多語言的,具有128K的更長的上下文長度和最先進的工具使用能力和整體更強的推理能力。

我將在本文示例開發(fā)中使用Groq云平臺,特別是他們在本文中的大數(shù)據(jù)模型。此應(yīng)用程序的初始工作流程包括一個嵌入模型、一個檢索器,還有兩個主要工具,用于處理用戶購買興趣和與成本相關(guān)的問題。總之,我們需要類似于下圖所述的組件內(nèi)容。

基于Llama 3的AI代理開發(fā)實戰(zhàn)演練-AI.x社區(qū)

示例應(yīng)用程序架構(gòu)圖

現(xiàn)在,我們必須要在開發(fā)中選擇使用一個LLM組件框架。為此,我選擇了我一直最喜歡的生產(chǎn)級開源AI平臺框架Haystack(https://haystack.deepset.ai/)。

準備好了我們需要的內(nèi)容后,接下來就讓我們開始投入關(guān)鍵的開發(fā)工作吧!

加載和索引數(shù)據(jù)

由于我們本示例程序中使用了一個RAG管道,我們首先構(gòu)建一個文檔索引服務(wù),將使用Haystack提供的內(nèi)存向量數(shù)據(jù)庫。請注意,我們矢量數(shù)據(jù)庫中的每個文檔都包含如下字段:

  • 內(nèi)容(Content)——我們用來執(zhí)行相似性搜索的內(nèi)容
  • Id——唯一標識符
  • 價格(Price)——產(chǎn)品價格
  • URL——產(chǎn)品URL

當調(diào)用我們的RAG管道時,Content字段用于向量搜索。所有其他字段都作為元數(shù)據(jù)包含在矢量數(shù)據(jù)庫中。注意,保存這些元數(shù)據(jù)是至關(guān)重要的,因為它們在用戶的前端演示中至關(guān)重要。

接下來,讓我們看看如何實現(xiàn)這一點。

from haystack import Pipeline, Document
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.writers import DocumentWriter
from haystack.components.embedders import SentenceTransformersDocumentEmbedder
from haystack.components.generators import OpenAIGenerator
from haystack.utils import Secret
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.builders import PromptBuilder
from haystack.components.embedders import SentenceTransformersTextEmbedder
from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever
from haystack.dataclasses import ChatMessage
import pandas as pd

#從CSV加載產(chǎn)品數(shù)據(jù)
df = pd.read_csv("product_sample.csv")

#初始化內(nèi)存中的文檔存儲區(qū)
document_store = InMemoryDocumentStore()

#將產(chǎn)品數(shù)據(jù)轉(zhuǎn)換為Haystack文檔對象
documents = [
Document(
content=item.product_name, 
meta={
"id": item.uniq_id, 
"price": item.selling_price, 
"url": item.product_url
}
) for item in df.itertuples()
]

#創(chuàng)建一個用于編制文檔索引的管道
indexing_pipeline = Pipeline()

#使用句子轉(zhuǎn)換器模型向管道中添加一個文檔嵌入器
indexing_pipeline.add_component(
instance=SentenceTransformersDocumentEmbedder(model="sentence-transformers/all-MiniLM-L6-v2"), name="doc_embedder"
)

# 向管道中添加文檔寫入器,以便在文檔存儲區(qū)中存儲文檔
indexing_pipeline.add_component(instance=DocumentWriter(document_store=document_store), name="doc_writer")

#將嵌入器的輸出連接到寫入器的輸入
indexing_pipeline.connect("doc_embedder.documents", "doc_writer.documents")

#運行索引管道來處理和存儲文檔
indexing_pipeline.run({"doc_embedder": {"documents": documents}})

太好了,我們已經(jīng)完成了AI代理應(yīng)用程序的第一步。現(xiàn)在,是時候構(gòu)建產(chǎn)品標識符函數(shù)工具了。為了更好地理解產(chǎn)品標識符的主要任務(wù),讓我們考慮下面的示例。

用戶查詢內(nèi)容如下:

英語原文: I want to buy a camping boot, a charcoal and google pixel 9 back cover.

中文意思:我想買一雙露營靴、一塊木炭和谷歌pixel 9手機外殼。

現(xiàn)在,先讓我們了解一下產(chǎn)品標識符函數(shù)的理想化工作流程。

基于Llama 3的AI代理開發(fā)實戰(zhàn)演練-AI.x社區(qū)

產(chǎn)品標識函數(shù)工作流程

首先,我們需要創(chuàng)建一個工具來分析用戶查詢并識別用戶感興趣的產(chǎn)品。我們可以使用下面的代碼片段構(gòu)建這樣一個工具。

構(gòu)建用戶查詢分析器

template = """
Understand the user query and list of products the user is interested in and return product names as list.
You should always return a Python list. Do not return any explanation.

Examples:
Question: I am interested in camping boots, charcoal and disposable rain jacket.
Answer: ["camping_boots","charcoal","disposable_rain_jacket"]

Question: Need a laptop, wireless mouse, and noise-cancelling headphones for work.
Answer: ["laptop","wireless_mouse","noise_cancelling_headphones"]

Question: {{ question }}
Answer:
"""

product_identifier = Pipeline()

product_identifier.add_component("prompt_builder", PromptBuilder(template=template))
product_identifier.add_component("llm", generator())

product_identifier.connect("prompt_builder", "llm")

好了,現(xiàn)在我們已經(jīng)完成了第一個函數(shù)的一半,現(xiàn)在是時候通過添加RAG管道來完成該函數(shù)了。

基于Llama 3的AI代理開發(fā)實戰(zhàn)演練-AI.x社區(qū)

產(chǎn)品標識功能工作流程

創(chuàng)建RAG管道

template = """
Return product name, price, and url as a python dictionary. 
You should always return a Python dictionary with keys price, name and url for single product.
You should always return a Python list of dictionaries with keys price, name and url for multiple products.
Do not return any explanation.

Legitimate Response Schema:
{"price": "float", "name": "string", "url": "string"}
Legitimate Response Schema for multiple products:
[{"price": "float", "name": "string", "url": "string"},{"price": "float", "name": "string", "url": "string"}]

Context:
{% for document in documents %}
product_price: {{ document.meta['price'] }}
product_url: {{ document.meta['url'] }}
product_id: {{ document.meta['id'] }}
product_name: {{ document.content }}
{% endfor %}
Question: {{ question }}
Answer:
"""

rag_pipe = Pipeline()
rag_pipe.add_component("embedder", SentenceTransformersTextEmbedder(model="sentence-transformers/all-MiniLM-L6-v2"))
rag_pipe.add_component("retriever", InMemoryEmbeddingRetriever(document_store=document_store, top_k=5))
rag_pipe.add_component("prompt_builder", PromptBuilder(template=template))
rag_pipe.add_component("llm", generator())

rag_pipe.connect("embedder.embedding", "retriever.query_embedding")
rag_pipe.connect("retriever", "prompt_builder.documents")
rag_pipe.connect("prompt_builder", "llm")

執(zhí)行上面的代碼之后,我們就完成了RAG和查詢分析管道的構(gòu)建?,F(xiàn)在是時候把它轉(zhuǎn)換成一個工具了。為此,我們可以使用常規(guī)函數(shù)聲明,如下所示。為AI代理創(chuàng)建工具就像創(chuàng)建Python函數(shù)一樣。如果你有類似于下面這樣的問題:

代理如何調(diào)用這個函數(shù)?

解決方案很簡單:利用特定于模型的工具模式。當然,我們將在稍后的步驟中加入該模式?,F(xiàn)在,是時候創(chuàng)建一個同時使用查詢分析器和RAG管道的包裝器函數(shù)了。

還是先讓我們來明確一下這個函數(shù)的目標。

目標1:識別用戶感興趣的所有產(chǎn)品,并將其作為列表返回。

目標2:對于每個已識別的產(chǎn)品,從數(shù)據(jù)庫中檢索最多五個產(chǎn)品及其元數(shù)據(jù)。

實現(xiàn)產(chǎn)品標識符函數(shù)

def product_identifier_func(query: str):
"""
根據(jù)給定的查詢來標識產(chǎn)品,并檢索每個已標識的產(chǎn)品的相關(guān)詳細信息。

參數(shù):
query (str): 用于標識產(chǎn)品的查詢字符串。

返回值:
dict: 一個字典,其中鍵是產(chǎn)品名稱,值是每個產(chǎn)品的詳細信息。如果沒有找到產(chǎn)品,則返回“No product found”。
"""
product_understanding = product_identifier.run({"prompt_builder": {"question": query}})

try:
product_list = literal_eval(product_understanding["llm"]["replies"][0])
except:
return "No product found"

results = {}

for product in product_list:
response = rag_pipe.run({"embedder": {"text": product}, "prompt_builder": {"question": product}})
try:
results[product] = literal_eval(response["llm"]["replies"][0])
except:
results[product] = {}

return results

基于Llama 3的AI代理開發(fā)實戰(zhàn)演練-AI.x社區(qū)

產(chǎn)品標識函數(shù)工作流程

至此,我們完成了代理的第一個工具的構(gòu)建。現(xiàn)在,先讓我們來看看它是否按預(yù)期工作。

query = "I want crossbow and woodstock puzzle"
#執(zhí)行函數(shù)
product_identifier_func(query)

# {'crossbow': {'name': 'DB Longboards CoreFlex Crossbow 41" Bamboo Fiberglass '
#                        'Longboard Complete',
#                'price': 237.68,
#                'url': 'https://www.amazon.com/DB-Longboards-CoreFlex-Fiberglass-Longboard/dp/B07KMVJJK7'},
#  'woodstock_puzzle': {'name': 'Woodstock- Collage 500 pc Puzzle',
#                       'price': 17.49,
#                       'url': 'https://www.amazon.com/Woodstock-Collage-500-pc-Puzzle/dp/B07MX21WWX'}}

成功了!然而,值得注意的是這里返回的輸出模式。下面給出輸出的總體模式架構(gòu)。

{
"product_key": {
"name": "string",
"price": "float",
"url": "string"
}
}

這正是我們建議RAG管道中生成的模式。下一步,讓我們構(gòu)建一個名為find_budget_friend_option的可選工具函數(shù)。

def find_budget_friendly_option(selected_product_details):
"""
為每一類產(chǎn)品找到最經(jīng)濟友好的選擇。

參數(shù):
selected_product_details (dict): 一個字典,其中的鍵是產(chǎn)品類別和值是列表的產(chǎn)品細節(jié)。每個產(chǎn)品的細節(jié)都應(yīng)該是一個包含一個“price”鍵的字典。

返回結(jié)果:
dict: 一個字典,其中鍵是產(chǎn)品類別,值是每個類別的最經(jīng)濟友好的產(chǎn)品詳細信息。
"""
budget_friendly_options = {}

for category, items in selected_product_details.items():
if isinstance(items, list):
lowest_price_item = min(items, key=lambda x: x['price'])
else:
lowest_price_item = items

budget_friendly_options[category] = lowest_price_item

return budget_friendly_options

讓我們關(guān)注這個應(yīng)用程序最關(guān)鍵的方面,也就是,讓AI代理能夠根據(jù)需要使用這些功能。正如我們之前所討論的,這可以通過特定于模型的工具模式來實現(xiàn)。因此,我們需要定位特定于所選模型的工具模式。幸運的是,Groq模型庫(https://huggingface.co/Groq/Llama-3-Groq-70B-Tool-Use)中提到了這一點。我們僅需要把它調(diào)整一下,以適應(yīng)我們的使用場景即可。

最終確定聊天模板

chat_template = '''<|start_header_id|>system<|end_header_id|>

You are a function calling AI model. You are provided with function signatures within <tools></tools> XML tags. You may call one or more functions to assist with the user query. Don't make assumptions about what values to plug into functions. For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:
<tool_call>
{"name": <function-name>,"arguments": <args-dict>}
</tool_call>

Here are the available tools:
<tools>
{
"name": "product_identifier_func",
"description": "To understand user interested products and its details",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The query to use in the search. Infer this from the user's message. It should be a question or a statement"
}
},
"required": ["query"]
}
},
{
"name": "find_budget_friendly_option",
"description": "Get the most cost-friendly option. If selected_product_details has morethan one key this should return most cost-friendly options",
"parameters": {
"type": "object",
"properties": {
"selected_product_details": {
"type": "dict",
"description": "Input data is a dictionary where each key is a category name, and its value is either a single dictionary with 'price', 'name', and 'url' keys or a list of such dictionaries; example: {'category1': [{'price': 10.5, 'name': 'item1', 'url': 'http://example.com/item1'}, {'price': 8.99, 'name': 'item2', 'url': 'http://example.com/item2'}], 'category2': {'price': 15.0, 'name': 'item3', 'url': 'http://example.com/item3'}}"
}
},
"required": ["selected_product_details"]
}
}
</tools><|eot_id|><|start_header_id|>user<|end_header_id|>

I need to buy a crossbow<|eot_id|><|start_header_id|>assistant<|end_header_id|>

<tool_call>
{"id":"call_deok","name":"product_identifier_func","arguments":{"query":"I need to buy a crossbow"}}
</tool_call><|eot_id|><|start_header_id|>tool<|end_header_id|>

<tool_response>
{"id":"call_deok","result":{'crossbow': {'price': 237.68,'name': 'crossbow','url': 'https://www.amazon.com/crossbow/dp/B07KMVJJK7'}}}
</tool_response><|eot_id|><|start_header_id|>assistant<|end_header_id|>
'''

現(xiàn)在,只剩下幾步了。在做任何事情之前,還是先讓我們來測試一下我們的代理。

##測試代理
messages = [
ChatMessage.from_system(
chat_template
),
ChatMessage.from_user("I need to buy a crossbow for my child and Pokémon for myself."),
]

chat_generator = get_chat_generator()
response = chat_generator.run(messages=messages)
pprint(response)

## 響應(yīng)結(jié)果
{'replies': [ChatMessage(content='<tool_call>\n'
'{"id": 0, "name": "product_identifier_func", '
'"arguments": {"query": "I need to buy a '
'crossbow for my child"}}\n'
'</tool_call>\n'
'<tool_call>\n'
'{"id": 1, "name": "product_identifier_func", '
'"arguments": {"query": "I need to buy a '
'Pokemon for myself"}}\n'
'</tool_call>',
role=<ChatRole.ASSISTANT: 'assistant'>,
name=None,
meta={'finish_reason': 'stop',
'index': 0,
'model': 'llama3-groq-70b-8192-tool-use-preview',
'usage': {'completion_time': 0.217823967,
'completion_tokens': 70,
'prompt_time': 0.041348261,
'prompt_tokens': 561,
'total_time': 0.259172228,
'total_tokens': 631}})]}

至此,我們已經(jīng)完成了大約90%的工作。

基于Llama 3的AI代理開發(fā)實戰(zhàn)演練-AI.x社區(qū)

工作接近尾聲。

在上述響應(yīng)結(jié)果中,你可能已經(jīng)注意到XML標簽<tool_call>包含了工具調(diào)用。因此,我們需要開發(fā)一種機制來提取tool_call對象。

def extract_tool_calls(tool_calls_str):
json_objects = re.findall(r'<tool_call>(.*?)</tool_call>', tool_calls_str, re.DOTALL)

result_list = [json.loads(obj) for obj in json_objects]

return result_list

available_functions = {
"product_identifier_func": product_identifier_func, 
"find_budget_friendly_option": find_budget_friendly_option
}

完成此步驟后,當代理調(diào)用工具時,我們可以直接訪問代理的響應(yīng)。現(xiàn)在唯一懸而未決的是獲取工具調(diào)用對象并相應(yīng)地執(zhí)行函數(shù)。讓我們也把這一部分完成。

messages.append(ChatMessage.from_user(message))
response = chat_generator.run(messages=messages)

if response and "<tool_call>" in response["replies"][0].content:
function_calls = extract_tool_calls(response["replies"][0].content)
for function_call in function_calls:
# 解析函數(shù)調(diào)用信息
function_name = function_call["name"]
function_args = function_call["arguments"]

#找到相應(yīng)的函數(shù)并用給定的參數(shù)調(diào)用它
function_to_call = available_functions[function_name]
function_response = function_to_call(**function_args)

# 使用`ChatMessage.from_function`在消息列表中附加函數(shù)響應(yīng)
messages.append(ChatMessage.from_function(content=json.dumps(function_response), name=function_name))
response = chat_generator.run(messages=messages)

現(xiàn)在,是時候?qū)⑶懊娴拿總€組件連接在一起,從而構(gòu)建一個完整的聊天應(yīng)用程序了。為此,我選擇使用強大的開源的深度學習模型可視化工具Gradio。

import gradio as gr

messages = [ChatMessage.from_system(chat_template)]
chat_generator = get_chat_generator()

def chatbot_with_fc(message, messages):
messages.append(ChatMessage.from_user(message))
response = chat_generator.run(messages=messages)

while True:
if response and "<tool_call>" in response["replies"][0].content:
function_calls = extract_tool_calls(response["replies"][0].content)
for function_call in function_calls:
#解析函數(shù)調(diào)用信息
function_name = function_call["name"]
function_args = function_call["arguments"]

#找到相應(yīng)的函數(shù)并用給定的參數(shù)調(diào)用它
function_to_call = available_functions[function_name]
function_response = function_to_call(**function_args)

# 使用`ChatMessage.from_function`在消息列表中附加函數(shù)響應(yīng)
messages.append(ChatMessage.from_function(content=json.dumps(function_response), name=function_name))
response = chat_generator.run(messages=messages)

# 定期對話
else:
messages.append(response["replies"][0])
break
return response["replies"][0].content


def chatbot_interface(user_input, state):
response_content = chatbot_with_fc(user_input, state)
return response_content, state

with gr.Blocks() as demo:
gr.Markdown("# AI Purchase Assistant")
gr.Markdown("Ask me about products you want to buy!")

state = gr.State(value=messages)

with gr.Row():
user_input = gr.Textbox(label="Your message:")
response_output = gr.Markdown(label="Response:")

user_input.submit(chatbot_interface, [user_input, state], [response_output, state])
gr.Button("Send").click(chatbot_interface, [user_input, state], [response_output, state])


demo.launch()

就是這么簡單!至此,我們已經(jīng)成功構(gòu)建了一個基于Llama 3模型的人工智能代理程序,它本身具有函數(shù)調(diào)用功能。你可以從GitHub倉庫(https://github.com/Ransaka/ai-agents-with-llama3)訪問其完整的源代碼。

此外,你可以通過Kaggle鏈接(https://www.kaggle.com/datasets/promptcloud/amazon-product-dataset-2020)訪問本文中使用的數(shù)據(jù)集。

結(jié)論

歸納來看,在構(gòu)建基于人工智能代理的系統(tǒng)程序時,重要的是要考慮完成任務(wù)所需的時間以及每個任務(wù)所使用的API調(diào)用(令牌)的數(shù)量。這方面開發(fā)面臨的一個主要挑戰(zhàn)是減少系統(tǒng)中的幻覺,這也是當前一個十分活躍的研究領(lǐng)域。因此,構(gòu)建LLM和代理系統(tǒng)沒有固定的規(guī)則。開發(fā)團隊有必要耐心和戰(zhàn)略性地規(guī)劃工作,以確保人工智能代理LLM正常運行。

最后,除非另有說明,本文中所有圖片均由作者本人提供。

參考資料

譯者介紹

朱先忠,51CTO社區(qū)編輯,51CTO專家博客、講師,濰坊一所高校計算機教師,自由編程界老兵一枚。

原文標題:Using Llama 3 for Building AI Agents,作者:Ransaka Ravihara

?著作權(quán)歸作者所有,如需轉(zhuǎn)載,請注明出處,否則將追究法律責任
已于2024-8-7 08:29:15修改
收藏
回復
舉報
回復
相關(guān)推薦