LangChain V1.0 深度解析:手把手帶你跑通全新智能體架構(gòu)
LangChain V1.0 簡介
終于,萬眾矚目的 LangChain V1.0 版本正式發(fā)布了!
那對于最新的 V1.0 版本而言,其最顯著的代碼層面變化集中在 create_agent() 方法。如果你之前沒有用過舊版本的LangChain,那么以下關(guān)于更新內(nèi)容的介紹可以跳過不看。
首先,create_agent() 變成了構(gòu)建 agent 的標(biāo)準(zhǔn)入口,它封裝了底層 LangGraph 的 graph 執(zhí)行機制,將“模型調(diào)用 → 決策工具 → 執(zhí)行工具 → 返回結(jié)果”這一閉環(huán)流程封裝在一個高階接口中。所以們在文檔中也可以看到這樣一句話:
create_agent is the standard way to build agents in LangChain 1.0
其次,原來在早期版本中需要手動配置 prompts、 hook 、狀態(tài)定義等細節(jié),在 V1.0 中這些被抽象為 middleware 機制(如 before_model、wrap_tool_call 等),開發(fā)者可以通過傳 middleware 數(shù)組把通用邏輯拼入,而不需改原 agent 核心邏輯。這大大的方便了開發(fā)者能夠打造真正應(yīng)用于生產(chǎn)的智能體(過去很多時候用 LangChain 的 create_react_agent 往往打造的只是一個“玩具”而已)。
再者,參數(shù)命名和入口路徑也發(fā)生了遷移:如 prompt 變?yōu)?nbsp;system_prompt。這意味著我們不需要再從 hub (已經(jīng)移出核心框架遷移至 langchain-classic )里去輸入大段的提示詞了,只需要傳入系統(tǒng)提示詞就夠了,LangChain 后臺會自動幫我們組合成完整的提示詞引導(dǎo)模型的行為。
除此之外,舊的 create_react_agent() 和 AgentExecutor 被替換并遷移至 langchain-classic 。同時過去的傳統(tǒng)鏈(比如 LLMChain )和傳統(tǒng)記憶方式(比如 CoversationBufferMemory) 也被遷移至 langchain-classic 。
這些改動意味著:如果你之前基于較早版本開發(fā),遷移到 V1.0 將需要重構(gòu)部分 import 路徑、參數(shù)名稱、狀態(tài)定義方式、 agent 構(gòu)建方式等。并且最好將其升級為最新的鏈(LCEL)和記憶(RunnableWithMessageHistory() 或 InMemorySaver())等方法。
總的來說,LangChain V1.0 在代碼使用層面表現(xiàn)為“更統(tǒng)一、更可控、更生產(chǎn)就緒” —— 以 create_agent() 為核心入口,以 middleware 為擴展機制,以標(biāo)準(zhǔn) message 塊與統(tǒng)一接口為基礎(chǔ),為構(gòu)建現(xiàn)代 LLM agent 系統(tǒng)提供了清晰、穩(wěn)定的框架。所以下面的課程里,我們就一起來看看,如何基于最新版的 Agent 創(chuàng)建機制實現(xiàn)智能體的快速搭建吧!
前期準(zhǔn)備
在正式開始之前,我們需要準(zhǔn)備幾個事情。第一個就是安裝最新版的 LangChain。
pip install -U langchain langgraph langchain-community dashscope arxiv然后就是到阿里云獲取一下 API_Key,并且最好將其設(shè)置到環(huán)境變量之中(DASHSCOPE_API_KEY)。
那獲取到了密鑰后,只要能夠成功運行以下代碼就代表以準(zhǔn)備完成:
from langchain_community.chat_models import ChatTongyi
from langchain_core.messages import HumanMessage
import os
# 初始化模型
llm = ChatTongyi(api_key=os.environ.get("DASHSCOPE_API_KEY"))
# 發(fā)送消息
response = llm.invoke([HumanMessage(content="你好,請用一句話介紹一下你自己。")])
print(response.content)快速搭建智能體
一、智能體簡介
首先我們可以在官方文檔看到 create_agent 的 graph 形式:
圖片
從本質(zhì)上來說,create_agent 打造的就是一個基礎(chǔ)的 ReAct Agent 的形式,就是我們把問題傳給大模型,然后讓大模型思考需要使用什么工具(action),然后調(diào)用完工具獲取到的結(jié)果(observation)返回給大模型。接著大模型再去不斷的重復(fù)這個循環(huán)直到其認為已經(jīng)搜集到足夠的信息或者完成指定的任務(wù)后,就會退出這個循環(huán)(finish)并給出最終的回復(fù)。
那在這個場景下,create_agent 需要我們準(zhǔn)備以下幾個基本的組件:
- 模型(也就是前面的 ChatTongyi )
- 工具庫(內(nèi)置工具或自建工具)
- 記憶(幫助模型直到當(dāng)前進行到哪一步)
- 提示詞(引導(dǎo)模型)
那我們下面就來一個個的看看如何創(chuàng)建這些基本的組件并快速搭建一個智能體!
導(dǎo)入模型
那首先我們還是像前面一樣準(zhǔn)備好模型:
from langchain_community.chat_models import ChatTongyi
import os
llm = ChatTongyi(api_key=os.environ.get("DASHSCOPE_API_KEY"))這里的模型我們選擇 ChatTongyi 的主要原因不僅僅只是我們這個課程一直都用, 還因為在 LangChain 里其實就屬通義千問的適配性最好,而且其還支持工具調(diào)用,具體后面我們會提到。
二、導(dǎo)入工具
前面提到 LangChain 里主要有兩種方式導(dǎo)入工具,一種是內(nèi)置工具,另外一種是自行創(chuàng)建,那我們分別進行闡述一下。
(1)內(nèi)置工具
根據(jù)LangChain的官方文檔[1],目前 LangChain 提供支持的有以下幾類工具:
- 搜索工具:用于在線搜索,包括 Bing、Google、DuckDuckGo 等搜索接口。返回內(nèi)容一般包括:URL、標(biāo)題、摘要等。
- 代碼輔助工具:支持 Python、JavaScript 等語言的代碼執(zhí)行環(huán)境,可用于復(fù)雜計算或文件處理。
- 生產(chǎn)力工具:用于對接 Gmail、Office365、Slack、Jira 等辦公/協(xié)作平臺,實現(xiàn)任務(wù)自動化。
- 網(wǎng)頁瀏覽:用于瀏覽網(wǎng)頁、交互操作、信息抓?。ㄈ鏗yperbrowser 等)。
- 數(shù)據(jù)庫:支持與數(shù)據(jù)庫交互,包括 SQL、Spark SQL 等數(shù)據(jù)庫的讀取與操作。
- 其他常用工具:維基百科、ArXiv、Python REPL。
由于網(wǎng)絡(luò)的原因,其實大部分的內(nèi)置工具我們是用不了的,只有一些特定的工具我們能夠使用,包括論文查詢工具 arxiv、計算器工具 llm-math、維基百科 wikipedia 以及執(zhí)行 python 代碼的 python_repl 。
假如我們要導(dǎo)入這些內(nèi)置工具的話,我們需要使用 langchain_community 里的 load_tools 方法進行載入。
from langchain_community.agent_toolkits.load_tools import load_tools
tools = load_tools(["arxiv"])假如我們需要導(dǎo)入多個工具的話,我們可以在后面不斷添加(部分依賴語言模型來執(zhí)行計算或生成代碼需要傳入一個 LLM 實例)。例如:
tools = load_tools(["arxiv","llm-math", "wikipedia"], llm=llm)除此之外,load_tools這個方法還有一個實參是 allow_dangerous_tools,具體是在本地執(zhí)行代碼、讀寫文件等(如python_repl工具)是需要開啟,因為運行 python 代碼可能會涉及刪除文件等操作。例如:
tools = load_tools(["python_repl"], llm=llm, allow_dangerous_tools=True)(2)自定義工具
自定義工具其實本質(zhì)上就是定義一個函數(shù),比如現(xiàn)在我有一個基于 eval() 的計算器工具函數(shù) calculate:
def calculate(what):
return str(eval(what))
print(calculate("3 + 7 * 2")) # 返回 17
print(calculate("10 / 4")) # 返回 2.5假如我希望將其改造為一個 LangChain 所支持的工具的話我需要在函數(shù)上方加上一個 @tool 裝飾器:
from langchain.tools import tool
@tool
def calculate(what):
return str(eval(what))然后呢!還需要加上介紹函數(shù)相關(guān)信息的文檔字符串以及輸入輸出參數(shù)說明:
from langchain.tools import tool
@tool
def calculate(what: str) -> str:
"""
calculate:
e.g. calculate: 4 * 7 / 3
Runs a calculation and returns the number - uses Python so be sure to use floating point syntax if necessary
"""
return str(eval(what))當(dāng)然其實我們除了函數(shù)的文檔字符串以外,還可以添加輸入輸出參數(shù)的具體信息,比如我們可以通過 Pydantic 添加了一個輸入?yún)?shù)的介紹信息,然后通過 @tool 中的 args_schema 將這部分信息載入:
from pydantic import BaseModel, Field
class CalcInput(BaseModel):
"""Input for math calculation"""
what: str = Field(descriptinotallow="A mathematical expression, e.g., '4 * 7 / 3'")
from langchain.tools import tool
@tool(args_schema=CalcInput)
def calculate(what: str) -> str:
"""
calculate:
e.g. calculate: 4 * 7 / 3
Runs a calculation and returns the number - uses Python so be sure to use floating point syntax if necessary
"""
return str(eval(what))這樣的話這個工具在載入到 Agent 的時候就會創(chuàng)建成 Function Calling 的格式將這些信息傳給 LLM 進行參考使用:
functions = [
{
"name": "calculate",
"description": "Runs a calculation and returns the number - uses Python so be sure to use floating point syntax if necessary",
"parameters": {
"type": "object",
"properties": {
"what": {
"type": "string",
"description": "A mathematical expression to evaluate, e.g. '4 * 7 / 3'"
}
},
"required": ["what"]
}
}
](3)工具的組合
在定義好多個自定義工具后,我們可以將其組裝在一起傳給 Agent ,比如:
tools = [calculate, average_dog_weight]但是假如我們想要的 LangChain 的內(nèi)置工具一起傳入的話,我們的寫法需要變?yōu)椋?/p>
tools = load_tools(["arxiv"] + [calculate, average_dog_weight])那在后續(xù)的內(nèi)容里,為了簡化整個流程,我們這里就選用 arxiv 作為智能體的工具進行演示(需要先安裝 arxiv,這在前期準(zhǔn)備中已經(jīng)完成):
from langchain_community.agent_toolkits.load_tools import load_tools
tools = load_tools(["arxiv"])三、構(gòu)建短期記憶
在前面講 LCEL 的內(nèi)容里我們提到了,為了能夠包裹一個 runnable 的組件,我們所使用的是 RunnableWithMessageHistory 的記憶方法。但是由于現(xiàn)在智能體的創(chuàng)建是基于 LangGraph 實現(xiàn)的,因此我們所使用的記憶方法就不再是這個了,而是使用 InMemorySaver() 的方法實現(xiàn)短期記憶的存儲。
所謂的短期記憶呢,其實指的是只保存的是保存當(dāng)前對話輪次、臨時上下文,用于連續(xù)對話或局部推理。那 InMemorySaver() 的作用是在圖(Graph)執(zhí)行的過程中,保存 agent 的對話、狀態(tài)、工具調(diào)用等信息,讓系統(tǒng)在一次會話(session)中能“記住”先前的輸入輸出。
短期記憶的信息只存在與內(nèi)存中(RAM),一旦程序關(guān)閉、刷新或重啟,數(shù)據(jù)就會消失。假如我們需要構(gòu)建長期的記憶,我們需要把記憶存儲到數(shù)據(jù)庫中,在后面的進階內(nèi)容中我們會更進一步的講述到。
那創(chuàng)建這個記憶的方法也非常的簡單,就是像之前的 CoversationBufferMemory 一樣創(chuàng)建后就會自動的保存所有的信息了:
from langgraph.checkpoint.memory import InMemorySaver
memory = InMemorySaver()那在這個短期記憶里會怎么保存我們的記憶呢?其實和之前的類似,比如我們在與大模型對話的過程中常見的就有幾類信息:
- 系統(tǒng)提示詞(通常是第一條信息,用于引導(dǎo)模型整體的行為)
- 用戶提示詞(用戶發(fā)出的問題)
- 模型提示詞(模型對于用戶問題的回復(fù)或調(diào)用工具的指令)
- 工具提示詞(在模型發(fā)出執(zhí)行工具的指令后返回的信息)
那這個短期記憶就會把這些所有的信息都保存到 AgentState 當(dāng)中,這個 AgentState 其實一個用于管理 Agent 當(dāng)前狀態(tài)的結(jié)構(gòu)(Schema),其默認格式大概是這樣的:
{"messages": [...],
"thread_model_call_count": 1,
"run_model_call_count": 1}那這里面最重要的其實就是 "messages" (其他都是一些輔助的元數(shù)據(jù)),這里就保存了智能體在每個時間點上需要記住的所有上下文信息。比如像這樣簡單的一問一答(當(dāng)然這里面有很多的元數(shù)據(jù)也會保存起來):
[HumanMessage(cnotallow="hi! I'm bob", additional_kwargs={}, response_metadata={}, id='beb6e2ba-c211-4283-a5d6-78566f567c86'),
AIMessage(cnotallow="Hello Bob! It's nice to meet you. How can I assist you today?", additional_kwargs={}, response_metadata={'model_name': 'qwen-max', 'finish_reason': 'stop', 'request_id': 'aa493e36-a2d8-40ac-abc6-18d7d31735f7', 'token_usage': {'input_tokens': 227, 'output_tokens': 17, 'prompt_tokens_details': {'cached_tokens': 0}, 'total_tokens': 244}}, id='lc_run--ca2c7e95-ff30-46a6-8019-293b186f0bf7-0')]那后續(xù)我們講到記憶的剪裁以及刪除等高級操作其實本質(zhì)上都是對這個 AgentState 進行操作。
四、提示詞模版及智能體組裝
在前面的 LangChain 課程中我們是提到了兩種提示詞模版,一種是 PromptTemplate ,另一種是 ChatPromptTemplate 。前者簡單直接,適合單輪指令或單輸入;而后者支持多角色消息(System / Human / AI / Tool),并且可嵌入進 LCEL 表達式鏈,是 v1.0 的推薦寫法。
那在 create_agent 中,其實有一個和前面 create_react_agent 最大的不同點是我們不需要使用一大段的提示詞模版去引導(dǎo)模型進行回復(fù)了。比如說之前我們需要傳入一個像 LangChain Hub 上 hwchase17/react-chat 這樣的提示詞了:
Assistant is a large language model trained by OpenAI.
Assistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.
Assistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.
Overall, Assistant is a powerful tool that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist.
TOOLS:
------
Assistant has access to the following tools:
{tools}
To use a tool, please use the following format:
"""
Thought: Do I need to use a tool? Yes Action: the action to take, should be one of [{tool_names}] Action Input: the input to the action Observation: the result of the action
"""
When you have a response to say to the Human, or if you do not need to use a tool, you MUST use the format:
"""
Thought: Do I need to use a tool? No Final Answer: [your response here]
"""
Begin!
Previous conversation history:
{chat_history}
New input: {input}
{agent_scratchpad}在這個提示詞里我們可以看到其主要劃分為五部分:
- 系統(tǒng)角色與能力設(shè)定
- 工具介紹
- 工具調(diào)用方式(ReAct 核心)
- 無需工具時的結(jié)束協(xié)議
- 運行時上下文注入(形成 ReAct 閉環(huán))
那模型在運行時就會學(xué)著這里面的實現(xiàn)方式,比如在需要工具的時候輸出:
Thought: Do I need to use a tool? Yes
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action然后 LangChain 通過正則表達式的解析去執(zhí)行對應(yīng)的工具返回結(jié)果寫到 Observation 里:
action_match = re.search(r"Action: (.*)", text)
input_match = re.search(r"Action Input: (.*)", text)但是這樣的方法有兩個問題,一個是假如某些模型的指令跟隨能力相對比較弱一些,可能沒有辦法在多輪對話中一直保持這樣輸出的模式。一旦模版輸出錯誤了,那就可能沒有辦法去解析了導(dǎo)致報錯。另一個問題是其實這種模版有很多,其實也不通用,所以整體也不太方便。
因此 LangChain V0.3 開始就重構(gòu)了 Agent 層,從而讓開發(fā)者只描述能力,而不是再造 prompt。所以我們只需要輸入模型、工具列表、記憶以及系統(tǒng)提示詞(會在每一次傳入給模型時才傳入,不會放入記憶中)。然后在調(diào)用的時候傳入用戶提示詞,這樣 LangChain 會自動幫你構(gòu)建完整的提示詞上下文。
那假如我們沒有直接在提示詞里告訴大模型具有有哪些工具,每個工具怎么使用的話,那大模型怎么知道要用什么呢?其實這個時候就要講到的是 LangChain 中的 bind_tools 方法。這個方法要求模型支持 OpenAI 的工具調(diào)用格式 Function Calling。在國內(nèi)的大模型廠家中,明確說了模型支持 Function Calling 也就只有通義千問。這也是為什么在 LangChain 的所有課程中我們都是用 ChatTongyi 來進行演示的。
那什么是 Function Calling 呢?其實很簡單,F(xiàn)unction Calling 是大模型在對話過程中調(diào)用外部工具函數(shù)的能力,它允許模型在無法直接回答問題時,返回一個函數(shù)調(diào)用請求(結(jié)構(gòu)化的JSON)。然后開發(fā)者需要手動解析這個請求,執(zhí)行對應(yīng)的函數(shù),并將結(jié)果傳回給模型,以生成最終答案。并在最后把結(jié)果返回給模型得到最終的回復(fù)。
比如說在 OpenAI 官方的這張圖就很好的解釋了 Function Calling 的運行過程:
第一步:把工具的信息以及問題傳給模型
第二步:由于模型支持工具調(diào)用,就會返回一個調(diào)用請求
第三步:開發(fā)者解析調(diào)用請求并執(zhí)行
第四步:將調(diào)用請求的結(jié)果返回給大模型
第五步:返回最終的回復(fù)

那在 LangChain 里的話,當(dāng)我們的工具載入到了 create_agent 中時,其實就會自動的將工具注冊為 Function Calling 的格式,并且每次調(diào)用的時候都會傳給模型讓其選擇。然后假如模型決定要調(diào)用工具的時候,就會發(fā)出類似下面的這段請求:
{
"role": "assistant",
"content": "",
"tool_calls": [
{
"name": "get_weather",
"arguments": {"city": "廣州"},
"id": "tool_call_1"
}
]
}我們可以看到這里的 content 是空的,代表模型其實并沒有回復(fù)任何的內(nèi)容,只不過是發(fā)出了一個 “tool_calls” ,然后里面寫入了對應(yīng)函數(shù)的名稱,傳入的參數(shù)以及一些元數(shù)據(jù)。然后在 create_agent 內(nèi)部就會自動的去解析這部分的內(nèi)容。
假如模型已經(jīng)獲取到了必要的信息,那其回復(fù)的內(nèi)容應(yīng)該就是下面這樣的:
{
"role": "assistant",
"content": "廣州的天氣是25度,祝你出行愉快",
"tool_calls": []
}這樣的方式就能夠讓模型更加準(zhǔn)確的表達其執(zhí)行的內(nèi)容。而且 JSON 格式的內(nèi)容也是更加的通用,所以 Function Calling 這個類似于 HTTPS 協(xié)議一樣的工具也被大量的推行。
好了,扯得好像有點遠,那既然我們不需要輸入完整的提示詞了,我們只需要輸入系統(tǒng)提示詞就足夠了,那我們要在哪里去寫入呢?其實當(dāng)我們準(zhǔn)備好前面的模型、工具及記憶以后,我們就在創(chuàng)建 create_agent 中寫入就行,比如像下面這樣:
from langchain.agents import create_agent
agent = create_agent(model=llm,
tools=tools,
system_prompt="You are a helpful assistant",
checkpointer=memory)這樣我們就把我們想要傳入的系統(tǒng)提示詞給寫入進去了。
五、調(diào)用智能體
那我們組裝好了一個智能體了以后,下一步我們就是去調(diào)用智能體并且獲取回復(fù)了。那本質(zhì)上就是我們發(fā)送了一個用戶提示詞給到整體,比如像下面這樣:
{"messages": [{"role": "user", "content": "請使用 arxiv 工具查詢論文編號 1605.08386"}]}這里我們就定義了一個字典,然后往 messages 信息里傳入了一個列表,這個列表里目前就是一條用戶提問的信息。當(dāng)然我們也可以往這個列表里面添加更多的信息進去,這個就是看大家具體的需求了。
除了傳入用戶提問的問題以外呢,還有一個需要額外指定一個 記憶定位標(biāo)識。這就好比我們在使用 conda 創(chuàng)建虛擬環(huán)境時,會為每個項目單獨建立一個環(huán)境,以避免依賴沖突。同樣地,在對話系統(tǒng)中,我們也希望不同用戶或不同任務(wù)的記憶彼此獨立,不會相互干擾。為此,我們可以通過傳入一個唯一的 thread_id(線程 ID)來區(qū)分不同的會話上下文。例如,下面的配置中,我們指定了 "user_1" 作為當(dāng)前對話的標(biāo)識:
cnotallow={"configurable": {"thread_id": "user_1"}}這樣,系統(tǒng)就會在內(nèi)存中為 "user_1" 維護一份獨立的對話記憶。如果下一次調(diào)用時仍然使用相同的 thread_id,模型就能“接著上次聊”;而如果換成一個新的 ID(例如 "user_2"),那么之前的記憶不會被繼承,相當(dāng)于開啟了一場全新的對話。
準(zhǔn)備好了這兩個以后呢,我們就可以使用 LangChain 中最常用的調(diào)用方法 .invoke() 去對智能體進行調(diào)用了,具體的方法如下:
result1 = agent.invoke({"messages": [{"role": "user", "content": "請使用 arxiv 工具查詢論文編號 1605.08386"}]}, cnotallow={"configurable": {"thread_id": "user_1"}})
print(result1)這樣我們就可以成功的對模型進行調(diào)用了,調(diào)用的結(jié)果如下:
{'messages': [HumanMessage(cnotallow='請使用 arxiv 工具查
詢論文編號 1605.08386', additional_kwargs={}, response_metadata={}, id='804b6b57-a615-4797-996e-70a6822d7eeb'), AIMessage(cnotallow='', additional_kwargs={'tool_calls': [{'function': {'arguments': '{"query": "1605.08386"}', 'name': 'arxiv'}, 'id': 'call_1257191a65e448d1840fed', 'index': 0, 'type': 'function'}]}, response_metadata={'model_name': 'qwen-turbo', 'finish_reason': 'tool_calls', 'request_id': '6274123b-3ef1-4e83-85e8-3e1be634cf6c', 'token_usage': {'input_tokens': 232, 'output_tokens': 28, 'prompt_tokens_details': {'cached_tokens': 0}, 'total_tokens': 260}}, id='lc_run--5eddaf4e-bc5a-4f8b-8802-b6f6ed45b1c1-0', tool_calls=[{'name': 'arxiv', 'args': {'query': '1605.08386'}, 'id': 'call_1257191a65e448d1840fed', 'type': 'tool_call'}]), ToolMessage(cnotallow='Published: 2016-05-26\nTitle: Heat-bath random walks with Markov bases\nAuthors: Caprice Stanley, Tobias Windisch\nSummary: Graphs on lattice points are studied whose edges come from a finite set of\nallowed moves of arbitrary length. We show that the diameter of these graphs on\nfibers of a fixed integer matrix can be bounded from above by a constant. We\nthen study the mixing behaviour of heat-bath random walks on these graphs. We\nalso state explicit conditions on the set of moves so that the heat-bath random\nwalk, a generalization of the Glauber dynamics, is an expander in fixed\ndimension.', name='arxiv', id='fa8a6ea5-0e38-42b7-b846-8e872b302f3f', tool_call_id='call_1257191a65e448d1840fed'), AIMessage(cnotallow='論文編號 1605.08386 的標(biāo)題是《Heat-bath random walks with Markov bases》。該論文于 2016 年 5 月 26 日發(fā)表,作者是 Caprice Stanley 和 Tobias Windisch。\n\n這篇論文研究了由有限的允許移動集生成的格點圖,這些移動可以是任意長度的。論文展示了在固定整數(shù)矩陣的纖維上,這些圖的直徑可以被常數(shù)從上面限制。然后研究了這些圖上的熱浴隨機游走的混合行為。此外,還給出了移動集的顯式條件,以確保熱浴隨機游走(Glauber 動力學(xué)的一種推廣)在固定維度下是一個擴展器。', additional_kwargs={}, response_metadata={'model_name': 'qwen-turbo', 'finish_reason': 'stop', 'request_id': 'f75c75a1-35ca-4bbb-bc71-ea9dd4233986', 'token_usage': {'input_tokens': 416, 'output_tokens': 156, 'prompt_tokens_details': {'cached_tokens': 0}, 'total_tokens': 572}}, id='lc_run--f0bf855c-4315-4559-b598-e4f4b74e5f05-0')]}這里其實就把整個 agent 的運行過程都給打印出來了,包括:
- 用戶輸入:
HumanMessage(cnotallow='請使用 arxiv 工具查詢論文編號 1605.08386')- 模型調(diào)用工具:
AIMessage(
cnotallow='',
additional_kwargs={
'tool_calls': [
{
'function': {'name': 'arxiv', 'arguments': '{"query": "1605.08386"}'},
'id': 'call_1257191a65e448d1840fed',
'type': 'function'
}
]
},
response_metadata={'finish_reason': 'tool_calls', 'model_name': 'qwen-turbo', ...}
)- 工具執(zhí)行并返回結(jié)果:
ToolMessage(
name='arxiv',
cnotallow='Published: 2016-05-26\nTitle: Heat-bath random walks with Markov bases\nAuthors: Caprice Stanley, Tobias Windisch\nSummary: ...',
tool_call_id='call_1257191a65e448d1840fed'
)- 模型整合工具結(jié)果并生成回復(fù):
AIMessage(cnotallow='論文編號 1605.08386 的標(biāo)題是《Heat-bath random walks with Markov bases》。該論文于 2016 年 5 月 26 日發(fā)表...')- 最后輸出 finish_reasnotallow='stop’ 表示任務(wù)完成。
這其實也是 ReAct Agent 的一個基本流程,假如我們要直接取最后一條信息作為輸出的話,我們可以在打印的時候進行指定:
print(result1["messages"][-1].content)這個時候就只會回復(fù)下面的內(nèi)容:
論文編號 1605.08386 的標(biāo)題是《Heat-bath random walks with Markov bases》。該論文于 2016 年 5 月 26 日發(fā)表,作者是 Caprice Stanley 和 Tobias Windisch。\n\n這篇論文研究了由有限的允許移動集生成的格點圖,這些移動可以是任意長度的。論文展示了在固定整數(shù)矩陣的纖維上,這些圖的直徑可以被常數(shù)從上面限制。然后研究了這些圖上的熱浴隨機游走的混合行為。此外,還給出了移動集的顯式條件,以確保熱浴隨機游走(Glauber 動力學(xué)的一種推廣)在固定維度下是一個擴展器。六、完整代碼
完整的代碼如下所示:
from langchain_community.chat_models import ChatTongyi
import os
llm = ChatTongyi(api_key=os.environ.get("DASHSCOPE_API_KEY"))
from langchain_community.agent_toolkits.load_tools import load_tools
tools = load_tools(["arxiv"])
from langgraph.checkpoint.memory import InMemorySaver
memory = InMemorySaver()
from langchain.agents import create_agent
agent = create_agent(model=llm,
tools=tools,
system_prompt="You are a helpful assistant",
checkpointer=memory)
result1 = agent.invoke({"messages": [{"role": "user", "content": "請使用 arxiv 工具查詢論文編號 1605.08386"}]}, cnotallow={"configurable": {"thread_id": "user_1"}})
print(result1["messages"][-1].content)總結(jié)
總的來說,這節(jié)課我們完整講解了 LangChain V1.0 智能體(Agent)創(chuàng)建的全新機制。新版的核心在于 create_agent() 方法,它取代了舊版的 create_react_agent() 和 AgentExecutor,成為構(gòu)建智能體的標(biāo)準(zhǔn)入口。其底層基于 LangGraph 執(zhí)行機制,將“模型調(diào)用 → 工具決策 → 工具執(zhí)行 → 結(jié)果整合”這一完整閉環(huán)封裝成統(tǒng)一流程,大幅提升了代碼的簡潔性與可維護性。
可以看到,LangChain V1.0 在設(shè)計上更加“工程化”和“生產(chǎn)可用”,讓智能體的構(gòu)建更加輕量、結(jié)構(gòu)更清晰。那在下一節(jié)課中,我們將基于本節(jié)內(nèi)容進一步優(yōu)化智能體的交互能力——包括引入多工具協(xié)作、增強記憶管理與上下文控制,打造一個更接近真實應(yīng)用的多輪智能體。
參考資料
[1] LangChain的官方文檔: https://python.langchain.com/docs/integrations/tools/























