# Chapter12. 用 LangChain 實作新書宣傳自動小編 :+1: 完整程式碼在 https://github.com/iamalex33329/chatgpt-develop-guide-zhtw ## 其他章節 [Chapter1. OpenAI API 入門](https://hackmd.io/@U3f2IzHERbymAst2-lDdjA/S1cNMYi6T) [Chapter2. 使用 Python 呼叫 API](https://hackmd.io/@U3f2IzHERbymAst2-lDdjA/HyZBg5ia6) [Chapter3. API 參數解析與錯誤處理](https://hackmd.io/@U3f2IzHERbymAst2-lDdjA/BJWNtsh6p) [Chapter4. 打造自己的 ChatGPT](https://hackmd.io/@112356044/Hk81U96Tp) [Chapter5. 突破時空限制 - 整合搜尋功能](https://hackmd.io/@112356044/HkbVM-ApT) [Chapter6. 讓 AI 幫 AI - 自動串接流程](https://hackmd.io/@112356044/r1Ke-GR6T) [Chapter7. 網頁版聊天程式與文字生圖 Image API](https://hackmd.io/@112356044/Hyf-AvgAT) [Chapter8. 設計 LINE AI 聊天機器人](https://hackmd.io/@112356044/r1d6HsgAa) [Chapter9. 自媒體業者必看!使用 AI 自動生成高品質字幕](https://hackmd.io/@112356044/rJ2T37V0T) [Chapter10. 把 AI 帶到 Discord](https://hackmd.io/@112356044/Sy_L-B40T) [Chapter11. AI 客製化投資理財應用實戰](https://hackmd.io/@112356044/HkUE0rER6) ## 目錄結構 [TOC] LangChain 是一個框架,可以協助開發者使用語言模型建構應用程式,藉此來簡化開發流程。 ## 認識 LangChain LangChain 的主要功能是把語言模型與外部工具**整合**成應用程式,讓應用程式自動選擇適合的工具完成要求。就像 ChatGPT Plus 能夠自行選擇合適的外掛一樣。 上述功能主要由以下元件組合: 1. Model:串接語言模型,例如使用 OpenAI 與模型互動。 2. Chain:把原本要自己依序完成的工作,依照固定的順序串接起來自動完成。 3. Memory:紀錄對話內容,像是 ChatGPT 能夠記得前幾次的對話紀錄。 4. Agent:可根據內容在必要時拆解成各個子步驟,再針對子步驟從指定工具中挑選適當的工具來完成任務。例如要回答「台灣最高的山的高度的兩倍是多少?」,Agent 能夠拆解成以下兩個步驟 1. 台灣最高的山的高度 :arrow_right: 透過搜尋工具得知最高的山為**玉山**,其高度為 3952 公尺 2. 高度的兩倍是多少 :arrow_right: 以運送工具將 3952 公尺乘以 2 倍,得出 7904 公尺 LangChain 的主要核心為 **Model**,其他元件則是依照需求結合使用。 若是需要固定順序完成的任務,可以使用 **Chain**;若是需要邏輯判斷獲釋根據前項輸出才能決定接下來的任務,則使用 **Agent** 較為恰當。 ## 熟悉 LangChain 基本功能 在 Python 中使用 LangChain 需要特別安裝套件 ``` python= !pip install langchain from langchain.chat_models import ChatOpenAI ``` ### 使用 ChatOpenAI 可以把 ChatOpenAI 當作 ChatCompletion 的抽象化版本,使用時要先建立 ChatOpenAI 物件,搭配對應到 user、system、assistant 角色訊息的 HumenMessage、SystemMessage、AIMessage 物件。 ``` python= from langchain.chat_models import ChatOpenAI from langchain.schema import ( AIMessage, SystemMessage, HumanMessage, ) import apikey model = ChatOpenAI( temperature=0, openai_api_key=apikey.OPENAI_API_KEY ) messages = ([HumanMessage(content='回答問題使用繁體中文和台灣詞語解釋, 問題:NBA 的英文全名是?')]) response = model(messages) print(response.content) ``` ### 提示模板(PromptTemplate) 前一個範例如果想要**提問別的問題**或是**使用其他語言回答**,就需要修改整個 Prompt,這邊可以使用**提示模板**的概念來解決。 提示模板可以將需要變化的部分轉為參數,等到執行時再以實際內容替換參數代入,以取得模型的回覆。 ``` python= from langchain.prompts.chat import ( ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate, ) ``` 並將剛剛的問題改為 ``` python=+ system_message = '你是一位助手,回答時答案使用 {input_language}' human_message = '問題:{question}' system_template = SystemMessagePromptTemplate.from_template(system_message) human_template = HumanMessagePromptTemplate.from_template(human_message) ``` ChatPromptTemplate 是由訊息提示模板**串列**組成的對話提示模板 ``` python=+ chat_prompt = ChatPromptTemplate.from_messages([system_template, human_template]) ``` #### 輸入參數傳回給模型 ``` python=+ message = chat_prompt.from_messages( input_language='繁體中文和台灣詞語', text='台灣最高的建築物是?' ) response = model(message) print(response.content) ``` > 但這個部分我執行出現錯誤 > > ![Screenshot 2024-03-18 at 12.24.56 AM](https://hackmd.io/_uploads/SkQDF94AT.png) > > 目前無解(囧) ### 建立 LLMChain 若是使用 LLMChain 是正常可以執行的,而且也能正確得到輸出: ``` python= from langchain import LLMChain from langchain_openai import ChatOpenAI from langchain.prompts.chat import ( ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate, ) import apikey model = ChatOpenAI( temperature=0, openai_api_key=apikey.OPENAI_API_KEY ) system_message = '你是一位助手,回答答案時使用 {input_language}' human_message = '問題:{text}' system_template = SystemMessagePromptTemplate.from_template(system_message) human_template = HumanMessagePromptTemplate.from_template(human_message) chat_prompt = ChatPromptTemplate.from_messages([system_template, human_template]) chain = LLMChain(llm=model, prompt=chat_prompt) answer = chain.run(input_language='繁體中文和台灣詞語', text='台灣最高的建築物是?') print(answer) ``` ``` 台灣最高的建築物是台北101大樓,位於台北市信義區。截至目前,台北101大樓是台灣最高的建築物,也是世界第十高的摩天大樓。 ``` ### 對話記憶 Memory 如果將上述的程式碼放到迴圈中持續問問題,沒辦法判斷上下文的脈絡或是前一個問題的答案,因此我們可以加上 `Memory` 元件幫助程式記憶問題和答案,就能實現對話記憶。 ``` python= import time from langchain_openai import ChatOpenAI from langchain.prompts import MessagesPlaceholder from langchain.chains import ConversationChain from langchain.memory import ConversationBufferMemory from langchain.prompts.chat import ( ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate, ) import apikey model = ChatOpenAI( temperature=0, openai_api_key=apikey.OPENAI_API_KEY ) ai_prompt = ChatPromptTemplate.from_messages([ SystemMessagePromptTemplate.from_template('以下是使用者與AI之間的對話,AI很健談而且能根據上下文提供具體細節,如果AI不知道問題會如實說不知道。'), MessagesPlaceholder(variable_name='history'), HumanMessagePromptTemplate.from_template('{input}') ]) memory = ConversationBufferMemory(return_messages=True) conversation = ConversationChain( memory=memory, prompt=ai_prompt, llm=model, verbose=True ) while True: question = input('Q: ') if not question.strip(): break response = conversation.predict(input=question) print(response + '\n') ``` ![Screenshot 2024-03-18 at 12.42.28 AM](https://hackmd.io/_uploads/By-taqNR6.png) ## 串接 Google search 及 Agent 代理運用 ### 建立 LangChain 代理(Agent) 上一節的機器人雖然可以記錄歷史對話,但還是無法得知最新的資訊。在 LangChain 中,提供兩種機制可以協助語言模型: 1. 外部工具:可以提供語言模型額外功能 2. 代理元件(Agent):依照使用者的輸入去判斷要使用哪種工具 這節會使用 `GoogleSearchAPIWrapper` 和 `LLMMathChain`,`GoogleSearchAPIWrapper` 會將 Google Search API 串接到 LangChain,利用搜尋功能讓程式找尋未知資料;`LLMMathChain` 則是逕行計算的數學工具。 ``` python= !pip install google-api-python-client !pip install numexpr from langchain_openai import ChatOpenAI from langchain import GoogleSearchAPIWrapper from langchain import LLMMathChain import ApiKey model = ChatOpenAI( temperature=0, openai_api_key=ApiKey.OPENAI_API_KEY ) search = GoogleSearchAPIWrapper() llm_math_chain = LLMMathChain.from_llm(llm=model, verbose=True) ``` ### 建立工具組 ``` python=+ from langchain.agents import Tool tools = [ Tool( name="Search", func=search.run, description='如果不曉得答案,用此工具搜尋資料' ), Tool( name="Calculator", func=llm_math_chain.run, description='如果需要數學計算,用此工具計算' ), ] ``` ### 建立 Agent ``` python=+ from langchain.agents import initialize_agent, AgentType agent = initialize_agent( llm=model, tools=tools, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True ) ``` > 這裡要注意,ZERO_SHOT_REACT_DESCRIPTION 沒辦法記憶歷史對話 ``` python=+ response = agent.run('台灣最高的建築物相當於世界上最高的建築物的幾倍?請注意計算單位需一致!') print(response) ``` 輸出結果: ![Screenshot 2024-03-18 at 1.02.17 AM](https://hackmd.io/_uploads/H1mmMsERa.png)