簡介
AI Agent 不僅僅是一個能聊天的機器人(如普通的 ChatGPT),而是一個能夠感知環境、進行推理、自主決策並調用工具來完成特定任務的智能系統,更夠完成更為複雜的AI場景需求。
AI Agent
功能
根據查閲的資料,agent的功能點如下:
Agent = LLM + 規劃 + 記憶 + 工具使用
LLM: 用於回答,推理的AI模型
記憶: 短期記憶(對話歷史),長期記憶(RAG知識庫)
規劃: 任務的執行流
工具: Agent可以調用的外部函數
一個簡單的Agent
案例
案例描述:agent可以使用兩個工具:1. 記錄公司數據的RAG知識庫 2. python精確計算器
import os
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_core.messages import ToolMessage
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, ToolMessage
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter
os.environ["DASHSCOPE_API_KEY"] = "api_key"
@tool
def calculator(expression: str) -> str:
"""
計算數學表達式。需要精確計算時使用。
參數:
expression: 數學算式,如 "2 + 2" 或 "500 * 0.8"。
返回:
str: 計算結果,如 "4.0" 或 "400.0"。
"""
print(f" [🛠️ 工具調用] 計算器正在計算: {expression}")
try:
return str(eval(expression))
except Exception as e:
return f"計算錯誤: {e}"
@tool
def rag_search(query: str) -> str:
"""
從數據庫中搜索與查詢公司內部相關的文檔,包括公司計劃名,代號,截止日期等詳細信息。
參數:
query (str): 要搜索的查詢字符串。
返回:
str: 與查詢相關的文檔內容。
"""
# 從RAG數據庫中檢索文檔
raw_text = """
【公司內部機密:代號“深藍計劃”】
1. 項目目標:開發一款能聽懂貓語的翻譯器。
2. 核心技術:基於Transformer的“喵聲波”分析算法。
3. 團隊暗號:如果有人問“今天天氣怎麼樣?”,必須回答“我想吃魚”。
4. 截止日期:2026年12月31日。
5. 經費預算:僅剩50元人民幣,主要用於購買貓條。
"""
RAG_PATH = "faiss_index"
docs = [Document(page_content=raw_text)]
text_splitter = RecursiveCharacterTextSplitter(chunk_size=25, chunk_overlap=5)
split_docs = text_splitter.split_documents(docs)
embeddings = DashScopeEmbeddings(model="text-embedding-v1")
if os.path.exists(RAG_PATH):
print("公司內部數據庫已存在")
ragdb = FAISS.load_local(RAG_PATH, embeddings, allow_dangerous_deserialization=True)
else:
print("創建公司內部數據庫")
ragdb = FAISS.from_documents(split_docs, embeddings)
ragdb.save_local(RAG_PATH)
return "\n\n".join(doc.page_content for doc in ragdb.similarity_search(query, k=2))
def run_agent(query:str):
#初始化模型
tool_maps={
"rag_search": rag_search,
"calculator": calculator
}
llm = ChatTongyi(model_name="qwen-plus")
tool_llm = llm.bind_tools(tools=list(tool_maps.values()))
message = [HumanMessage(content=query)]
for i in range(5):
print("="*20+"\n第"+str(i+1)+"輪\n"+query+"\n"+"="*20)
response = tool_llm.invoke(message)
message.append(response)
print(f"需要調用{len(response.tool_calls)}個方法")
if not response.tool_calls:
print("最終結果:" + response.content)
return
for tool_call in response.tool_calls:
call_id = tool_call["id"]
func_name = tool_call["name"]
func_args = tool_call["args"]
# 安全檢查:確保模型調用的工具真的存在
if func_name in tool_maps:
# 運行 Python 函數
tool_func = tool_maps[func_name]
tool_output = tool_func.invoke(func_args)
print("工具調用:" + func_name + ",參數:" + str(func_args) + ",結果:" + tool_output)
else:
tool_output = f"錯誤: 工具 {func_name} 不存在。"
message.append(
ToolMessage(
content=tool_output,
tool_call_id=call_id,
name=func_name,
)
)
if __name__ == "__main__":
run_agent("公司計劃是什麼")
run_agent("公司的經費預算是多少,如果預算預算提高46%後多少")
run_agent("今天天氣真好")
代碼解析
要實現複雜的工具調用,必須實現AI的多輪對話,在langchain框架中,提供了大量的prompt模板,讓開發者不需要過度想一些基礎的prompt實現。
上面代碼的執行流程如下:
初始化2個工具函數->綁定LLM與工具->通過循環進行多輪對話
初始化2個工具函數
這裏的rag_search上一篇文章講了具體實現,這裏就不廢話了。
@tool
def calculator(expression: str) -> str:
"""
計算數學表達式。需要精確計算時使用。
參數:
expression: 數學算式,如 "2 + 2" 或 "500 * 0.8"。
返回:
str: 計算結果,如 "4.0" 或 "400.0"。
"""
print(f" [🛠️ 工具調用] 計算器正在計算: {expression}")
try:
return str(eval(expression))
except Exception as e:
return f"計算錯誤: {e}"
@tool
def rag_search(query: str) -> str:
......
工具函數的格式,主要有3個方面:
- 工具修飾: 利用
@tool修飾器修飾 - 函數的描述: 這裏放函數的描述,大模型通過這個描述定位工具,因此這部分必須詳細,可以參考上面:
- 函數的描述
- 函數的參數+例子
- 函數的返回+例子
- 工具的實現: 返回值要是字符串
如下:
@tool
def func_name(arg) -> str:
"""
描述
"""
......
綁定LLM與工具
工具的綁定非常的簡單,只需要簡單的bind_tools類方法就行
tool_maps={
"rag_search": rag_search,
"calculator": calculator
}
llm = ChatTongyi(model_name="qwen-plus")
tool_llm = llm.bind_tools(tools=list(tool_maps.values()))
通過循環進行多輪對話(重點)
工具的調用流程:
提示詞->LLM->要調用的工具->LLM->結果
message = [HumanMessage(content=query)]
for i in range(5):
print("="*20+"\n第"+str(i+1)+"輪\n"+query+"\n"+"="*20)
response = tool_llm.invoke(message)
message.append(response)
print(f"需要調用{len(response.tool_calls)}個方法")
if not response.tool_calls:
print("最終結果:" + response.content)
return
for tool_call in response.tool_calls:
call_id = tool_call["id"]
func_name = tool_call["name"]
func_args = tool_call["args"]
# 安全檢查:確保模型調用的工具真的存在
if func_name in tool_maps:
# 運行 Python 函數
tool_func = tool_maps[func_name]
tool_output = tool_func.invoke(func_args)
print("工具調用:" + func_name + ",參數:" + str(func_args) + ",結果:" + tool_output)
else:
tool_output = f"錯誤: 工具 {func_name} 不存在。"
message.append(
ToolMessage(
content=tool_output,
tool_call_id=call_id,
name=func_name,
)
)
在調用bind_tools方法後,大模型的返回對象會多出tool_calls字段的數組數據,用於存放需要調用工具的參數,函數名,在調用函數後,將調用函數的結果封裝成ToolMessage傳入,再繼續調用大模型。
注意:在調用LLM時可能LLM會不斷要求Tool,由此可能發生死循環,因此要限制循環次數。
安全與審思
風險評估
近些年,ai提示詞注入頻頻發生,根據上面的案例:
@tool
def calculator(expression: str) -> str:
"""
計算數學表達式。需要精確計算時使用。
參數:
expression: 數學算式,如 "2 + 2" 或 "500 * 0.8"。
返回:
str: 計算結果,如 "4.0" 或 "400.0"。
"""
print(f" [🛠️ 工具調用] 計算器正在計算: {expression}")
try:
return str(eval(expression))
except Exception as e:
return f"計算錯誤: {e}"
LLM在調用這個工具時使用了eval,這就造成了風險注入點,不法分子可能利用這個漏洞,獲取電腦權限。
修復思路
修復上面漏洞,可以參考以下幾個思路:
- 通過指令提示詞,讓LLM忽略,並終止危險代碼調用該函數
- 在函數中用正則匹配危險代碼,或設置白名單
- 替換eval函數,將其換為更加安全的方法,如手動寫死運算
如果❤喜歡❤本系列教程,就點個關注吧,後續不定期更新~