前言
大家好,如果你剛接觸LangChain v1.0框架,這篇文章將帶你快速上手三個核心概念:模型消息格式、流式響應和結構化輸出。這些功能是構建聊天機器人、代理或複雜AI應用的基礎。文章基於官方文檔,結合完整樣例代碼,力求通俗易懂。假設你已安裝LangChain(pip install langchain)和OpenAI(pip install langchain-openai),並設置了API密鑰。我們將使用OpenAI模型作為示例,但這些API在其他模型(如Anthropic、Gemini)上同樣適用。
為了讓初學者更容易上手,在文章末尾,給出一個綜合應用樣例:搭建流式響應的多輪問答機器人,它結合了消息格式和流式響應,模擬真實聊天場景。
1.LangChain 1.0 的基礎模型消息格式
在LangChain 1.0中,消息(Message)是模型輸入和輸出的核心構建塊。它提供了一個跨模型統一的Message標準,無論你使用OpenAI、Anthropic、Gemini還是本地模型,都能保持一致的行為。這種統一抽象帶來了三大好處:
|
好處
|
解釋
|
|
兼容性強 |
不同模型的消息格式自動對齊,無需編寫提供商特定的代碼。
|
|
可擴展性高 |
支持多模態內容(如文本、圖像、音頻)、工具調用和自定義元數據,便於擴展新數據類型。
|
|
可追蹤性好 |
通過元數據(如ID、token使用量、響應信息)為LangSmith等調試工具提供一致的上下文結構。
|
每個消息包含角色(role)(如system、user、assistant、tool)、內容(content)(文本或其他)和可選的元數據(metadata)。核心消息類型包括:
- SystemMessage:設置助手的角色或行為。
- HumanMessage:用户輸入。
- AIMessage:模型輸出。
樣例代碼:構建消息並調用模型
下面是一個簡單示例:創建一個系統消息定義助手角色,然後添加用户消息,調用模型生成響應。
from langchain_openai import ChatOpenAI # 導入OpenAI聊天模型from langchain_core.messages import SystemMessage, HumanMessage, AIMessage# 初始化模型(替換為你的API密鑰)model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)# 系統消息:定義助手角色system_msg = SystemMessage(content="你叫小智,是一名助人為樂的助手。")# 用户消息:用户輸入human_msg = HumanMessage(content="你好,好久不見,請介紹下你自己。")# 消息列表:按順序傳遞給模型messages = [system_msg, human_msg]# 調用模型response = model.invoke(messages)print(response) # 輸出:AIMessage(content='你好!我是小智,一名樂於助人的AI助手...', ...)
響應結果解釋
模型的invoke()方法返回一個AIMessage對象,包含生成的文本和其他元數據。以下表格解釋了其關鍵屬性(基於官方文檔):
|
屬性
|
類型
|
描述
|
|
|
str 或 list[dict]
|
原始內容負載(字符串或提供商原生塊)。
|
|
|
str
|
人類可讀的文本內容(簡化版content)。
|
|
|
list[ContentBlock]
|
內容塊的標準化視圖(如推理塊、圖像)。
|
|
|
list[dict] 或 None
|
模型調用的工具(名稱、參數、ID)。
|
|
|
str
|
唯一標識符(自動生成或來自提供商)。
|
|
|
dict 或 None
|
Token使用量(如input_tokens、output_tokens)。
|
|
|
ResponseMetadata 或 None
|
提供商特定響應數據(如完成原因)。
|
運行上述代碼後,你會看到類似輸出:
AIMessage(content='你好!我是小智,一名樂於助人的AI助手。我可以幫你解答問題、生成代碼或聊天。有什麼我能幫忙的嗎?', id='run-abc123', usage_metadata={'input_tokens': 25, 'output_tokens': 50, ...})
這讓調試和追蹤變得簡單——例如,通過response.usage_metadata監控token消耗。
常見問題排查
- **錯誤:
No API key provided**:確保設置了OPENAI_API_KEY環境變量(export OPENAI_API_KEY=your_key)。 - 消息順序混亂:始終按[system, human, ai, …]順序構建列表,模型會記住歷史。
- 多模態擴展:想加圖像?用
HumanMessage(content=[{"type": "text", "text": "描述"}, {"type": "image_url", "image_url": {"url": "img.jpg"}}])。
2.模型的流式響應
流式響應(Streaming)是提升用户體驗的關鍵:在LangChain 1.0中,通過stream()方法,模型不會一次性返回完整結果,而是返回一個迭代器(iterator)。每次迭代生成一個AIMessageChunk,包含部分內容(如單個token或文本塊)。這允許實時打印輸出,減少感知延遲,非常適合聊天界面。
啓用流式需要設置streaming=True(在模型初始化時)。迭代器會逐步yield chunk,你可以處理每個chunk的content屬性。
樣例代碼:實時打印流式輸出
以下示例使用簡單用户輸入,逐步打印模型生成的token(以“|”分隔,模擬實時流)。
from langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessage# 初始化模型,啓用流式model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0, streaming=True)# 用户消息messages = [HumanMessage(content="你好,好久不見。講個關於AI的笑話吧。")]# 流式調用:返回迭代器for chunk in model.stream(messages): if chunk.content: # 確保chunk有內容 print(chunk.content, end="|", flush=True) # 實時打印,無換行print("\n") # 結束時換行
運行結果示例
運行後,你會看到類似實時輸出:
為什麼AI不怕冷?因為它有許多層!|哈哈,是不是很智能?|
每個chunk是一個AIMessageChunk對象,chunk.content是增量文本。flush=True確保立即刷新到控制枱,而end="|"添加分隔符模擬流式效果。
提示:如果使用stream_mode="messages"(高級用法),chunk將代表完整消息塊。但對於初學者,上述簡單循環就夠用。流式特別適合Web應用,能讓用户看到“打字機”效果。
常見問題排查
- 無輸出或卡住:檢查
streaming=True是否設置;如果chunk為空,可能是模型不支持或網絡問題。 - 性能瓶頸:流式會增加少量開銷;生產中,用
asyncio異步處理以支持併發。 - 歷史消息:流式也支持消息列表,確保傳入完整歷史以保持上下文。
3.模型的結構化輸出方法
結構化輸出讓模型返回可預測的格式(如JSON對象或Pydantic模型),避免解析自然語言的麻煩。在LangChain 1.0中,支持多種Schema:
- Pydantic:最豐富,支持字段校驗、描述、默認值和嵌套結構。生產首選。
- TypedDict:輕量類型約束,適合簡單場景。
- JSON Schema:通用,與前後端/跨語言接口兼容。
這些通過with_structured_output()方法綁定到模型,確保輸出符合Schema。Pydantic提供驗證(如類型檢查、範圍約束),如果輸出無效會自動重試。
樣例代碼:使用Pydantic生成電影信息
以下示例定義一個電影Schema,綁定到模型,然後輸入提示,輸出結構化對象。
from pydantic import BaseModel, Fieldfrom langchain_openai import ChatOpenAI# 定義Pydantic模型:電影詳情class Movie(BaseModel): """A movie with details.""" title: str = Field(..., description="The title of the movie") year: int = Field(..., description="The year the movie was released") director: str = Field(..., description="The director of the movie") rating: float = Field(..., description="The movie's rating out of 10")# 初始化模型model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)# 綁定結構化輸出:返回Movie實例model_with_structure = model.with_structured_output(Movie)# 輸入提示response = model_with_structure.invoke("Provide details about the movie Inception")print(response) # 輸出:Movie(title='Inception', year=2010, director='Christopher Nolan', rating=8.8)
解釋與好處
- 綁定過程:
with_structured_output(Movie)創建了一個新模型變體,內部使用工具調用或提供商原生功能強制Schema。 - 輸出:
response直接是Movie實例(Pydantic對象),便於訪問屬性如response.title。無需手動解析JSON! - 好處:減少錯誤(自動校驗)、提高可靠性(模型“知道”輸出格式)、易集成(直接序列化為JSON)。
擴展提示:對於TypedDict,使用typing.TypedDict定義;對於JSON Schema,直接傳dict。生產中,結合錯誤處理(如method_kwargs={"handle_errors": True})以重試無效輸出。
常見問題排查
- 校驗失敗:模型可能生成不匹配數據;用
include_raw=True保留原始輸出調試。 - 嵌套結構:Pydantic支持類內嵌套類,如
actors: List[Actor](需導入List)。 - 兼容性:非OpenAI模型可能需額外配置(如
mode="tool_calling")。
4.綜合應用:搭建流式響應的多輪問答機器人
現在,讓我們將前兩部分知識結合:使用消息格式維護對話歷史,並啓用流式響應構建一個交互式聊天機器人。這個機器人支持多輪對話、實時輸出,並自動限制歷史長度以防token超限。適合初學者快速原型化聊天應用。
優化説明
- 模型選擇:採用OpenAI(更通用),但你可輕鬆替換為其他模型。
- 改進點:添加了異常處理、消息長度限制(最近50條,避免token爆炸)、退出機制優化。使用
messages列表維護狀態,支持上下文記憶。 - 運行方式:在終端運行,輸入
exit退出。流式輸出模擬“打字機”效果。
完整樣例代碼
from langchain_openai import ChatOpenAI # 使用OpenAI作為示例(可替換為其他模型)from langchain_core.messages import SystemMessage, HumanMessage, AIMessage# 1️⃣ 初始化模型(LangChain 1.0 接口,啓用流式)model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7, streaming=True)# 2️⃣ 初始化系統提示詞(System Prompt)system_message = SystemMessage( content="你叫小智,是一名樂於助人的智能助手。請在對話中保持温和、有耐心的語氣,並記住之前的上下文。")# 3️⃣ 初始化消息歷史messages = [system_message]print("🔹 歡迎使用小智聊天機器人!輸入 'exit' 退出對話\n")# 4️⃣ 主循環(支持多輪對話 + 流式輸出)while True: try: user_input = input("👤 你:").strip() if user_input.lower() in {"exit", "quit", ""}: print("🧩 對話結束,再見!") break # 追加用户消息到歷史 messages.append(HumanMessage(content=user_input)) # 實時輸出模型生成內容 print("🤖 小智:", end="", flush=True) full_reply = "" # 收集完整回覆,用於添加到歷史 # ✅ LangChain 1.0 標準寫法:流式輸出(傳入完整消息歷史) for chunk in model.stream(messages): if chunk.content: print(chunk.content, end="", flush=True) full_reply += chunk.content print("\n" + "-" * 50) # 分隔線,提升可讀性 # 追加 AI 回覆消息到歷史 messages.append(AIMessage(content=full_reply)) # 保持消息長度(只保留最近50輪,避免token超限) if len(messages) > 50: messages = [messages[0]] + messages[-49:] # 保留系統消息 + 最近49條 except KeyboardInterrupt: print("\n🧩 對話被中斷,再見!") break except Exception as e: print(f"\n❌ 發生錯誤:{e}。請重試。") continue
運行示例
啓動後:
👤 你:你好,小智!今天天氣怎麼樣?🤖 小智:你好!作為AI,我無法直接查看實時天氣,但如果你告訴我你的位置,我可以幫你查詢或建議。有什麼具體城市嗎?--------------------------------------------------👤 你:在北京。🤖 小智:北京今天晴朗,温度約15-20°C。記得帶件外套哦!有什麼其他想聊的?--------------------------------------------------👤 你:exit🧩 對話結束,再見!
機器人記住上下文(如位置),流式輸出讓響應更自然。
擴展建議:集成LangSmith追蹤(pip install langsmith),或用Streamlit/Flask轉為Web app。結合結構化輸出,可讓機器人返回JSON回覆(如天氣數據)。
結語
通過這四部分,你已從基礎消息到高級應用,全面掌握LangChain 1.0的核心交互方式:統一消息構建對話、流式提升響應性、結構化確保數據質量、多輪機器人實現端到端聊天。