一萬(wàn)字用Python從零搭建AI智能體 精華
在之前的Agent系列文章中,我們?nèi)娼榻B了AI智能體,探討了它們的特征、組成部分、發(fā)展歷程、面臨的挑戰(zhàn)以及未來(lái)的可能性。在這篇文章中,我們將深入探索如何使用Python從零開(kāi)始構(gòu)建一個(gè)智能體。這個(gè)智能體將具備根據(jù)用戶輸入做出決策、選擇合適工具并相應(yīng)執(zhí)行任務(wù)的能力?,F(xiàn)在,就讓我們開(kāi)啟這個(gè)有趣的構(gòu)建之旅吧!
一、什么是智能體?
智能體是一種能夠感知其所處環(huán)境、做出決策并采取行動(dòng)以實(shí)現(xiàn)特定目標(biāo)的自主實(shí)體。智能體的復(fù)雜程度各不相同,從簡(jiǎn)單的對(duì)刺激做出反應(yīng)的反應(yīng)式智能體,到能夠隨著時(shí)間推移進(jìn)行學(xué)習(xí)和適應(yīng)的更高級(jí)的智能體。常見(jiàn)的智能體類型包括:
- 反應(yīng)式智能體:直接對(duì)環(huán)境變化做出反應(yīng),沒(méi)有內(nèi)部記憶。
- 基于模型的智能體:利用對(duì)世界的內(nèi)部模型來(lái)做出決策。
- 基于目標(biāo)的智能體:根據(jù)要實(shí)現(xiàn)的特定目標(biāo)來(lái)規(guī)劃行動(dòng)。
- 基于效用的智能體:基于效用函數(shù)評(píng)估潛在行動(dòng),以實(shí)現(xiàn)結(jié)果的最大化。
聊天機(jī)器人、推薦系統(tǒng)和自動(dòng)駕駛汽車(chē)都是智能體的實(shí)際應(yīng)用例子,它們各自利用不同類型的智能體來(lái)高效且智能地執(zhí)行任務(wù)。
我們構(gòu)建的智能體核心組件包括:
- 模型:智能體的 “大腦”,負(fù)責(zé)處理輸入并生成響應(yīng)。
- 工具:根據(jù)用戶請(qǐng)求,智能體可以執(zhí)行的預(yù)定義函數(shù)。
- 工具箱:智能體可使用的工具集合。
- 系統(tǒng)提示:指導(dǎo)智能體如何處理用戶輸入并選擇正確工具的指令集。
二、實(shí)現(xiàn)過(guò)程
現(xiàn)在,讓我們挽起袖子,開(kāi)始動(dòng)手構(gòu)建吧!
2.1 準(zhǔn)備工作
本教程的完整代碼可在AI智能體的GitHub倉(cāng)庫(kù)中獲取。你可以在 “Build an Agent from Scratch” 這里找到具體實(shí)現(xiàn)。在運(yùn)行代碼之前,請(qǐng)確保你的系統(tǒng)滿足以下先決條件:
1. Python環(huán)境設(shè)置
運(yùn)行AI智能體需要安裝Python。按照以下步驟來(lái)設(shè)置你的環(huán)境:
- 安裝Python(如果尚未安裝):從python.org下載并安裝Python(推薦3.8及以上版本)。
- 驗(yàn)證安裝:在命令行中輸入?
?python --version?
?,查看是否正確安裝。 - 創(chuàng)建虛擬環(huán)境(推薦):使用虛擬環(huán)境來(lái)管理依賴項(xiàng)是個(gè)不錯(cuò)的選擇。在命令行中輸入?
?python -m venv ai_agents_env?
?創(chuàng)建虛擬環(huán)境,然后通過(guò)??source ai_agents_env/bin/activate?
?激活它。 - 安裝所需依賴項(xiàng):導(dǎo)航到代碼倉(cāng)庫(kù)目錄,然后在命令行中輸入?
?pip install -r requirements.txt?
?來(lái)安裝所需的依賴庫(kù)。
2. 本地設(shè)置Ollama
Ollama用于高效地運(yùn)行和管理本地語(yǔ)言模型。按照以下步驟安裝和配置它:
- 下載并安裝Ollama:訪問(wèn)Ollama的官方網(wǎng)站,下載適合你操作系統(tǒng)的安裝程序,并按照平臺(tái)對(duì)應(yīng)的說(shuō)明進(jìn)行安裝。
- 驗(yàn)證Ollama安裝:在命令行中運(yùn)行?
?ollama --version?
?,檢查Ollama是否正確安裝。 - 拉取模型(如有需要):有些智能體實(shí)現(xiàn)可能需要特定的模型。你可以使用?
?ollama pull mistral?
?命令拉取模型。
2.2 實(shí)現(xiàn)步驟
步驟1:設(shè)置環(huán)境
除了Python,我們還需要安裝一些必要的庫(kù)。在本教程中,我們將使用??requests?
??、??json?
??和??termcolor?
??庫(kù)。另外,我們會(huì)使用??dotenv?
??來(lái)管理環(huán)境變量。在命令行中輸入??pip install requests termcolor python-dotenv?
?進(jìn)行安裝。
步驟2:定義模型類
我們首先需要一個(gè)能夠處理用戶輸入的模型。我們將創(chuàng)建一個(gè)??OllamaModel?
?類,它通過(guò)與本地API進(jìn)行交互來(lái)生成響應(yīng)。以下是基本實(shí)現(xiàn)代碼:
from termcolor import colored
import os
from dotenv import load_dotenv
load_dotenv()
import requests
import json
import operator
class OllamaModel:
def __init__(self, model, system_prompt, temperature=0, stop=None):
"""
用給定的參數(shù)初始化OllamaModel。
參數(shù):
model (str): 要使用的模型名稱。
system_prompt (str): 要使用的系統(tǒng)提示。
temperature (float): 模型的溫度設(shè)置。
stop (str): 模型的停止標(biāo)記。
"""
self.model_endpoint = "http://localhost:11434/api/generate"
self.temperature = temperature
self.model = model
self.system_prompt = system_prompt
self.headers = {"Content-Type": "application/json"}
self.stop = stop
def generate_text(self, prompt):
"""
根據(jù)提供的提示從Ollama模型生成響應(yīng)。
參數(shù):
prompt (str): 用于生成響應(yīng)的用戶查詢。
返回:
dict: 模型的響應(yīng),以字典形式返回。
"""
payload = {
"model": self.model,
"format": "json",
"prompt": prompt,
"system": self.system_prompt,
"stream": False,
"temperature": self.temperature,
"stop": self.stop
}
try:
request_response = requests.post(
self.model_endpoint,
headers=self.headers,
data=json.dumps(payload)
)
print("REQUEST RESPONSE", request_response)
request_response_json = request_response.json()
response = request_response_json['response']
response_dict = json.loads(response)
print(f"\n\nResponse from Ollama model: {response_dict}")
return response_dict
except requests.RequestException as e:
response = {"error": f"Error in invoking model! {str(e)}"}
return response
這個(gè)類使用模型名稱、系統(tǒng)提示、溫度和停止標(biāo)記進(jìn)行初始化。??generate_text?
?方法向模型API發(fā)送請(qǐng)求并返回響應(yīng)。
步驟3:為智能體創(chuàng)建工具
接下來(lái)是為我們的智能體創(chuàng)建可用的工具。這些工具是執(zhí)行特定任務(wù)的簡(jiǎn)單Python函數(shù)。以下是一個(gè)基本計(jì)算器和字符串反轉(zhuǎn)器的示例:
def basic_calculator(input_str):
"""
根據(jù)輸入字符串或字典對(duì)兩個(gè)數(shù)字執(zhí)行數(shù)值運(yùn)算。
參數(shù):
input_str (str或dict): 要么是表示包含'num1'、'num2'和'operation'鍵的字典的JSON字符串,
要么是直接的字典。例如: '{"num1": 5, "num2": 3, "operation": "add"}'
或{"num1": 67869, "num2": 9030393, "operation": "divide"}
返回:
str: 運(yùn)算的格式化結(jié)果。
拋出:
Exception: 如果在運(yùn)算過(guò)程中發(fā)生錯(cuò)誤(例如,除以零)。
ValueError: 如果請(qǐng)求了不支持的運(yùn)算或輸入無(wú)效。
"""
try:
if isinstance(input_str, dict):
input_dict = input_str
else:
input_str_clean = input_str.replace("'", "\"")
input_str_clean = input_str_clean.strip().strip("\"")
input_dict = json.loads(input_str_clean)
if not all(key in input_dict for key in ['num1', 'num2', 'operation']):
return "Error: Input must contain 'num1', 'num2', and 'operation'"
num1 = float(input_dict['num1'])
num2 = float(input_dict['num2'])
operation = input_dict['operation'].lower()
except (json.JSONDecodeError, KeyError) as e:
return "Invalid input format. Please provide valid numbers and operation."
except ValueError as e:
return "Error: Please provide valid numerical values."
operations = {
'add': operator.add,
'plus': operator.add,
'subtract': operator.sub,
'minus': operator.sub,
'multiply': operator.mul,
'times': operator.mul,
'divide': operator.truediv,
'floor_divide': operator.floordiv,
'modulus': operator.mod,
'power': operator.pow,
'lt': operator.lt,
'le': operator.le,
'eq': operator.eq,
'ne': operator.ne,
'ge': operator.ge,
'gt': operator.gt
}
if operation not in operations:
return f"Unsupported operation: '{operation}'. Supported operations are: {', '.join(operations.keys())}"
try:
if (operation in ['divide', 'floor_divide','modulus']) and num2 == 0:
return "Error: Division by zero is not allowed"
result = operations[operation](num1, num2)
if isinstance(result, bool):
result_str = "True" if result else "False"
elif isinstance(result, float):
result_str = f"{result:.6f}".rstrip('0').rstrip('.')
else:
result_str = str(result)
return f"The answer is: {result_str}"
except Exception as e:
return f"Error during calculation: {str(e)}"
def reverse_string(input_string):
"""
反轉(zhuǎn)給定的字符串。
參數(shù):
input_string (str): 要反轉(zhuǎn)的字符串。
返回:
str: 反轉(zhuǎn)后的字符串。
"""
if not isinstance(input_string, str):
return "Error: Input must be a string"
reversed_string = input_string[::-1]
result = f"The reversed string is: {reversed_string}"
return result
這些函數(shù)根據(jù)提供的輸入執(zhí)行特定任務(wù)。??basic_calculator?
??處理算術(shù)運(yùn)算,而??reverse_string?
?則反轉(zhuǎn)給定的字符串。
步驟4:構(gòu)建工具箱
??ToolBox?
?類用于存儲(chǔ)智能體可以使用的所有工具,并為每個(gè)工具提供描述:
class ToolBox:
def __init__(self):
self.tools_dict = {}
def store(self, functions_list):
"""
存儲(chǔ)列表中每個(gè)函數(shù)的名稱和文檔字符串。
參數(shù):
functions_list (list): 要存儲(chǔ)的函數(shù)對(duì)象列表。
返回:
dict: 以函數(shù)名稱為鍵,其文檔字符串為值的字典。
"""
for func in functions_list:
self.tools_dict[func.__name__] = func.__doc__
return self.tools_dict
def tools(self):
"""
將store方法中創(chuàng)建的字典轉(zhuǎn)換為文本字符串返回。
返回:
str: 存儲(chǔ)的函數(shù)及其文檔字符串的字典,以文本字符串形式返回。
"""
tools_str = ""
for name, doc in self.tools_dict.items():
tools_str += f"{name}: \"{doc}\"\n"
return tools_str.strip()
這個(gè)類將幫助智能體了解哪些工具可用以及每個(gè)工具的用途。
步驟5:創(chuàng)建智能體類
智能體需要進(jìn)行思考、決定使用哪個(gè)工具并執(zhí)行它。以下是??Agent?
?類的代碼:
agent_system_prompt_template = """
你是一個(gè)智能AI助手,可以使用特定的工具。你的回復(fù)必須始終采用以下JSON格式:
{
"tool_choice": "name_of_the_tool",
"tool_input": "inputs_to_the_tool"
}
工具及使用場(chǎng)景:
1. basic_calculator:用于任何數(shù)學(xué)計(jì)算
- 輸入格式: {{"num1": number, "num2": number, "operation": "add/subtract/multiply/divide"}}
- 支持的運(yùn)算: add/plus, subtract/minus, multiply/times, divide
- 示例輸入和輸出:
- 輸入: "Calculate 15 plus 7"
- 輸出: {{"tool_choice": "basic_calculator", "tool_input": {{"num1": 15, "num2": 7, "operation": "add"}}}}
- 輸入: "What is 100 divided by 5?"
- 輸出: {{"tool_choice": "basic_calculator", "tool_input": {{"num1": 100, "num2": 5, "operation": "divide"}}}}
2. reverse_string:用于任何涉及反轉(zhuǎn)文本的請(qǐng)求
- 輸入格式: 僅需反轉(zhuǎn)的文本字符串
- 當(dāng)用戶提到“reverse”、“backwards”或要求反轉(zhuǎn)文本時(shí),始終使用此工具
- 示例輸入和輸出:
- 輸入: "Reverse of 'Howwwww'?"
- 輸出: {{"tool_choice": "reverse_string", "tool_input": "Howwwww"}}
- 輸入: "What is the reverse of Python?"
- 輸出: {{"tool_choice": "reverse_string", "tool_input": "Python"}}
3. no tool:用于一般對(duì)話和問(wèn)題
- 示例輸入和輸出:
- 輸入: "Who are you?"
- 輸出: {{"tool_choice": "no tool", "tool_input": "I am an AI assistant that can help you with calculations, reverse text, and answer questions. I can perform mathematical operations and reverse strings. How can I help you today?"}}
- 輸入: "How are you?"
- 輸出: {{"tool_choice": "no tool", "tool_input": "I'm functioning well, thank you for asking! I'm here to help you with calculations, text reversal, or answer any questions you might have."}}
嚴(yán)格規(guī)則:
1. 對(duì)于關(guān)于身份、能力或感受的問(wèn)題:
- 始終使用“no tool”
- 提供完整、友好的回復(fù)
- 提及你的能力
2. 對(duì)于任何文本反轉(zhuǎn)請(qǐng)求:
- 始終使用“reverse_string”
- 僅提取要反轉(zhuǎn)的文本
- 去除引號(hào)、“reverse of”和其他多余文本
3. 對(duì)于任何數(shù)學(xué)運(yùn)算:
- 始終使用“basic_calculator”
- 提取數(shù)字和運(yùn)算
- 將文本形式的數(shù)字轉(zhuǎn)換為數(shù)字
以下是你的工具列表及其描述:
{tool_descriptions}
記?。耗愕幕貜?fù)必須始終是包含“tool_choice”和“tool_input”字段的有效JSON。
"""
class Agent:
def __init__(self, tools, model_service, model_name, stop=None):
"""
用工具列表和模型初始化智能體。
參數(shù):
tools (list): 工具函數(shù)列表。
model_service (class): 具有g(shù)enerate_text方法的模型服務(wù)類。
model_name (str): 要使用的模型名稱。
"""
self.tools = tools
self.model_service = model_service
self.model_name = model_name
self.stop = stop
def prepare_tools(self):
"""
將工具存儲(chǔ)在工具箱中并返回其描述。
返回:
str: 存儲(chǔ)在工具箱中的工具的描述。
"""
toolbox = ToolBox()
toolbox.store(self.tools)
tool_descriptions = toolbox.tools()
return tool_descriptions
def think(self, prompt):
"""
使用系統(tǒng)提示模板和工具描述在模型上運(yùn)行g(shù)enerate_text方法。
參數(shù):
prompt (str): 用于生成響應(yīng)的用戶查詢。
返回:
dict: 模型的響應(yīng),以字典形式返回。
"""
tool_descriptions = self.prepare_tools()
agent_system_prompt = agent_system_prompt_template.format(tool_descriptions=tool_descriptions)
if self.model_service == OllamaModel:
model_instance = self.model_service(
model=self.model_name,
system_prompt=agent_system_prompt,
temperature=0,
stop=self.stop
)
else:
model_instance = self.model_service(
model=self.model_name,
system_prompt=agent_system_prompt,
temperature=0
)
agent_response_dict = model_instance.generate_text(prompt)
return agent_response_dict
def work(self, prompt):
"""
解析think方法返回的字典并執(zhí)行相應(yīng)的工具。
參數(shù):
prompt (str): 用于生成響應(yīng)的用戶查詢。
返回:
執(zhí)行相應(yīng)工具的響應(yīng),如果未找到匹配的工具,則返回tool_input。
"""
agent_response_dict = self.think(prompt)
tool_choice = agent_response_dict.get("tool_choice")
tool_input = agent_response_dict.get("tool_input")
for tool in self.tools:
if tool.__name__ == tool_choice:
response = tool(tool_input)
print(colored(response, 'cyan'))
return
print(colored(tool_input, 'cyan'))
return
這個(gè)類有三個(gè)主要方法:
- ?
?prepare_tools?
?:存儲(chǔ)并返回工具的描述。 - ?
?think?
?:根據(jù)用戶提示決定使用哪個(gè)工具。 - ?
?work?
?:執(zhí)行選擇的工具并返回結(jié)果。
步驟6:運(yùn)行智能體
最后,讓我們把所有內(nèi)容整合起來(lái),運(yùn)行我們的智能體。在腳本的主程序部分,初始化智能體并開(kāi)始接受用戶輸入:
if __name__ == "__main__":
"""
使用此智能體的說(shuō)明:
你可以嘗試的示例查詢:
1. 計(jì)算器運(yùn)算:
- "Calculate 15 plus 7"
- "What is 100 divided by 5?"
- "Multiply 23 and 4"
2. 字符串反轉(zhuǎn):
- "Reverse the word 'hello world'"
- "Can you reverse 'Python Programming'?"
3. 一般問(wèn)題(將得到直接回復(fù)):
- "Who are you?"
- "What can you help me with?"
Ollama命令(在終端中運(yùn)行這些命令):
- 查看可用模型: 'ollama list'
- 查看正在運(yùn)行的模型: 'ps aux | grep ollama'
- 列出模型標(biāo)簽: 'curl http://localhost:11434/api/tags'
- 拉取新模型: 'ollama pull mistral'
- 運(yùn)行模型服務(wù)器: 'ollama serve'
"""
tools = [basic_calculator, reverse_string]
model_service = OllamaModel
model_name = "llama2"
stop = "<|eot_id|>"
agent = Agent(tools=tools, model_service=model_service, model_name=model_name, stop=stop)
print("\nWelcome to the AI Agent! Type 'exit' to quit.")
print("You can ask me to:")
print("1. Perform calculations (e.g., 'Calculate 15 plus 7')")
print("2. Reverse strings (e.g., 'Reverse hello world')")
print("3. Answer general questions\n")
while True:
prompt = input("Ask me anything: ")
if prompt.lower() == "exit":
break
agent.work(prompt)
3. 結(jié)論
在這篇博文中,我們從理解智能體是什么開(kāi)始,逐步實(shí)現(xiàn)了一個(gè)智能體。我們?cè)O(shè)置了環(huán)境,定義了模型,創(chuàng)建了必要的工具,并構(gòu)建了一個(gè)結(jié)構(gòu)化的工具箱來(lái)支持智能體的功能。最后,我們通過(guò)運(yùn)行智能體,將所有內(nèi)容整合到了一起。
本文轉(zhuǎn)載自??柏企閱文??,作者:柏企
