--- #該區塊是此page style設定,更動時注意! slideOptions: slideNumber: true #顯示頁碼 #type: slide #投影片模式 tags: LLM,LangChain,TAIA,HIT #設定標籤 disqus: hackmd #允許讀者在文件下方留下評論 --- :::info ## 構建ChatGPT應用系統 ::: ![image](https://hackmd.io/_uploads/SJDzw3Awa.png) ![image](https://hackmd.io/_uploads/B1bNP2RwT.png) ==範例中使用ChatGPT Model 為穩定版"gpt-3.5-turbo"而另外"GPT-3.5-Turbo-0301"版本將停用,最新版本的 GPT-3.5-Turbo-0613 和 GPT-4-0613 模型裡,最大的特色是 Function calling 函數呼叫功能,開發者向這兩個最新模型描述函數後,模型會自動建立程式碼來執行指定的函數。新的模型經過微調,能會依照使用者輸入的要求檢測什麼時候需要執行函數。== ```python= import os import openai from dotenv import load_dotenv, find_dotenv _ = load_dotenv(find_dotenv()) # read local .env file openai.api_key = os.environ['OPENAI_API_KEY'] ``` :::info ## 直接向框架創建者 Harrison Chase 學習 LangChain ::: ### 一、LangChain: Models, Prompts and Output Parsers :::success LangChain: Models, Prompts and Output Parsers ::: ```python= #!pip install --upgrade langchain from langchain.chat_models import ChatOpenAI # To control the randomness and creativity of the generated # text by an LLM, use temperature = 0.0 chat = ChatOpenAI(temperature=0.0, model=llm_model) ``` ```python= # account for deprecation of LLM model import datetime # Get the current date current_date = datetime.datetime.now().date() # Define the date after which the model should be set to "gpt-3.5-turbo" target_date = datetime.date(2024, 6, 12) # Set the model variable based on the current date if current_date > target_date: llm_model = "gpt-3.5-turbo" else: llm_model = "gpt-3.5-turbo-0613" ``` ==llm_model建立大型語言模型,當中使用temperature調整執為0~2之間,當調整值越大,權重越低的token值會越有可能挑選到,反之越小值則以權重較大的token優先挑選,但注意的是當設定最大值2時API回應會執行很久,且可能最挑出不適當的token字元。== ==0. **Model**== ```python= from langchain.chat_models import ChatOpenAI # To control the randomness and creativity of the generated # text by an LLM, use temperature = 0.0 chat = ChatOpenAI(temperature=0.0, model=llm_model) chat ``` ==1. **Prompt template**== ![image](https://hackmd.io/_uploads/rygo8smw6.png =80%x) ==範例中為設計一個鍊試結構的聊天模組,可以定義模板內容(template_string),範例中將{text}轉換為{style}樣式。而這裡設計轉換的樣式為'美式英文口音以平靜而尊重的語氣'。== ```python= ##執行程式 template_string = """Translate the text \ that is delimited by triple backticks \ into a style that is {style}. \ text: ```{text}``` """ from langchain.prompts import ChatPromptTemplate prompt_template = ChatPromptTemplate.from_template(template_string) prompt_template.messages[0].prompt ``` :::spoiler **顯示結果** >PromptTemplate(input_variables=['style', 'text'], output_parser=None, partial_variables={}, template='Translate the text that is delimited by triple backticks into a style that is {style}. text: ```{text}```\n', template_format='f-string', validate_template=True) ::: ```python= ##執行程式 prompt_template.messages[0].prompt.input_variables customer_style = """American English \ in a calm and respectful tone """ customer_email = """ Arrr, I be fuming that me blender lid \ flew off and splattered me kitchen walls \ with smoothie! And to make matters worse, \ the warranty don't cover the cost of \ cleaning up me kitchen. I need yer help \ right now, matey! """ customer_messages = prompt_template.format_messages( style=customer_style, text=customer_email) print(type(customer_messages)) print(type(customer_messages[0])) print(customer_messages[0]) ``` :::spoiler **顯示結果(原本粗暴語氣)** >content="Translate the text that is delimited by triple backticks into a style that is American English in a calm and respectful tone\n. text: ```\nArrr, I be fuming that me blender lid flew off and splattered me kitchen walls with smoothie! And to make matters worse, the warranty don't cover the cost of cleaning up me kitchen. I need yer help right now, matey!\n```\n" additional_kwargs={} example=False ::: ```python= ##執行程式 # Call the LLM to translate to the style of the customer message customer_response = chat(customer_messages) print(customer_response.content) ``` :::spoiler 顯示結果(轉換美國腔和緩語氣) >**I'm really frustrated** that my blender lid flew off and made a mess of my kitchen walls with smoothie. To add to my frustration, the warranty doesn't cover the cost of cleaning up my kitchen. **Can you please help me out, friend**? ::: ```python= ##執行程式 service_reply = """Hey there customer, \ the warranty does not cover \ cleaning expenses for your kitchen \ because it's your fault that \ you misused your blender \ by forgetting to put the lid on before \ starting the blender. \ Tough luck! See ya! """ service_style_pirate = """\ a polite tone \ that speaks in English Pirate\ """ service_messages = prompt_template.format_messages( style=service_style_pirate, text=service_reply) print(service_messages[0].content) ``` :::spoiler 顯示結果(範本英國海盜腔禮貌語氣) >Translate the text that is delimited by triple backticks into a style that is a polite tone that speaks in English Pirate. text: ```**Hey there customer**, the warranty does not cover cleaning expenses for your kitchen because it's your fault that you misused your blender by forgetting to put the lid on before starting the blender. **Tough luck! See ya!** ::: ```python= ##執行程式 service_response = chat(service_messages) print(service_response.content) ``` :::spoiler 顯示結果(轉換英國海盜腔禮貌語氣) >Ahoy there, me hearty customer! I be sorry to inform ye that the warranty be not coverin' the expenses o' cleaning yer galley, as 'tis yer own fault fer misusin' yer blender by forgettin' to put the lid on afore startin' it. Aye, tough luck! Farewell and may the winds be in yer favor! ::: ==2. **Output Parsers** Let's start with defining how we would like the LLM output to look like:== ![image](https://hackmd.io/_uploads/BJA6do7PT.png =80%x) ==**在這**裡Output Parsers**的設定中可以指定以JSON格式回答,這邊定義了三個分別為禮物"gift"、送貨天數"delivery_days"、價格"price_value",並且可以定義評論範本(review_template),從文本來源(customer_review)引入到範本中的text: {text},來解析顧客評論,以下為程式碼說明:**== ```json= #執行程式 { "gift": False, "delivery_days": 5, "price_value": "pretty affordable!" } ``` ```python= customer_review = """\ This leaf blower is pretty amazing. It has four settings:\ candle blower, gentle breeze, windy city, and tornado. \ It arrived in two days, just in time for my wife's \ anniversary present. \ I think my wife liked it so much she was speechless. \ So far I've been the only one using it, and I've been \ using it every other morning to clear the leaves on our lawn. \ It's slightly more expensive than the other leaf blowers \ out there, but I think it's worth it for the extra features. """ review_template = """\ For the following text, extract the following information: gift: Was the item purchased as a gift for someone else? \ Answer True if yes, False if not or unknown. delivery_days: How many days did it take for the product \ to arrive? If this information is not found, output -1. price_value: Extract any sentences about the value or price,\ and output them as a comma separated Python list. Format the output as JSON with the following keys: gift delivery_days price_value text: {text} """ ``` #### 2.1 Parse the LLM output string into a JSON ```python= ##執行程式 from langchain.prompts import ChatPromptTemplate prompt_template = ChatPromptTemplate.from_template(review_template) print(prompt_template) messages = prompt_template.format_messages(text=customer_review) chat = ChatOpenAI(temperature=0.0, model=llm_model) response = chat(messages) print(response.content) type(response.content) # You will get an error by running this line of code # because'gift' is not a dictionary # 'gift' is a string response.content.get('gift') ``` :::spoiler **顯示結果** ```json= { "gift": true, "delivery_days": 2, "price_value": ["It's slightly more expensive than the other leaf blowers out there, but I think it's worth it for the extra features."] } ``` ::: #### 2.2 Parse the LLM output string into dictionary ```python= ##執行程式 from langchain.output_parsers import ResponseSchema from langchain.output_parsers import StructuredOutputParser ``` ==這邊將之前以JSON樣式設定的內容,改以Python Dictionary來設定Schema,並且設定response_schemas為陣列型態。== ```python= ##執行程式 gift_schema = ResponseSchema(name="gift", description="Was the item purchased\ as a gift for someone else? \ Answer True if yes,\ False if not or unknown.") delivery_days_schema = ResponseSchema(name="delivery_days", description="How many days\ did it take for the product\ to arrive? If this \ information is not found,\ output -1.") price_value_schema = ResponseSchema(name="price_value", description="Extract any\ sentences about the value or \ price, and output them as a \ comma separated Python list.") response_schemas = [gift_schema, delivery_days_schema, price_value_schema] ``` ```python= ##執行程式 output_parser = StructuredOutputParser.from_response_schemas(response_schemas) ``` ```python= ##執行程式 format_instructions = output_parser.get_format_instructions() ``` ```python= review_template_2 = """\ For the following text, extract the following information: gift: Was the item purchased as a gift for someone else? \ Answer True if yes, False if not or unknown. delivery_days: How many days did it take for the product\ to arrive? If this information is not found, output -1. price_value: Extract any sentences about the value or price,\ and output them as a comma separated Python list. text: {text} {format_instructions} """ ``` ```python= ##執行程式 prompt = ChatPromptTemplate.from_template(template=review_template_2) messages = prompt.format_messages(text=customer_review, format_instructions=format_instructions) ``` ==如同之前我們將設定好的要回應的output_parser樣式,給予parse定義為format_instructions參數,以ChatPromptTemplate函式庫引入review_template_2作為一個prompt,接下來串接== ```python= messages=prompt.format_messages(text=customer_review,format_instructions=format_instructions) ``` ==作為chat的response message,一樣的我們作一個JSON轉換,同樣的可以得到之前相同JSON格式回應。== ![image](https://hackmd.io/_uploads/BJlD-R-vp.png =80%x) ### 二、LangChain: Memory :::success LangChain: Memory ::: ![老年癡呆](https://hackmd.io/_uploads/rJDdC00P6.jpg) ==此記憶體功能在使用chat和AI對話時,ChatOpenAI會將之前的問題和回答紀錄起來,當你訊問重複問題時他會記得你給予的問題和答案,重新response。== ![image](https://hackmd.io/_uploads/ryjYD6XPp.png =80%x) ==聊天機器人似乎透過提供完整的對話作為「上下文」來擁有記憶== ![image](https://hackmd.io/_uploads/S1ta3TQPa.png =80%x) * ==1.該記憶體允許儲存訊息,然後將訊息提取到變數中== * ==2.此記憶體保存了一段時間內對話互動的清單。 它只使用最後 K 個互動。== * ==3.該內存在記憶體中保存最近互動的緩衝區,並使用Token長度取代互動數量來確定何時刷新。== * ==4.該記憶會隨著時間的推移創建對話摘要== ![image](https://hackmd.io/_uploads/S1kdRpQw6.png =80%x) ```python= ##執行程式 from langchain.chat_models import ChatOpenAI from langchain.chains import ConversationChain from langchain.memory import ConversationBufferMemory ``` ```python= ##執行程式 llm = ChatOpenAI(temperature=0.0, model=llm_model) memory = ConversationBufferMemory() conversation = ConversationChain( llm=llm, memory = memory, verbose=True ) conversation.predict(input="Hi, my name is Andrew") conversation.predict(input="What is 1+1?") conversation.predict(input="What is my name?") ``` ==此外也可以對於記憶內容作另外編輯,儲存成另外的問答紀錄。== ```python= ##執行程式 memory.load_memory_variables({}) ``` ![image](https://hackmd.io/_uploads/rJqq4TXDa.png =80%x) ### ConversationSummaryMemory ```python= ##執行程式 from langchain.memory import ConversationSummaryBufferMemory # create a long string schedule = "There is a meeting at 8am with your product team. \ You will need your powerpoint presentation prepared. \ 9am-12pm have time to work on your LangChain \ project which will go quickly because Langchain is such a powerful tool. \ At Noon, lunch at the italian resturant with a customer who is driving \ from over an hour away to meet you to understand the latest in AI. \ Be sure to bring your laptop to show the latest LLM demo." memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100) memory.save_context({"input": "Hello"}, {"output": "What's up"}) memory.save_context({"input": "Not much, just hanging"}, {"output": "Cool"}) memory.save_context({"input": "What is on the schedule today?"}, {"output": f"{schedule}"}) ``` ```python= ##執行程式 memory.load_memory_variables({}) ``` ==providing the full conversation as 'context'== :::spoiler **顯示結果** > {'history': "System: The human and AI engage in small talk before discussing the day's schedule. The AI informs the human of a morning meeting with the product team, time to work on the LangChain project, and a lunch meeting with a customer interested in the latest AI developments."} ::: ```python= ##執行程式 conversation = ConversationChain( llm=llm, memory = memory, verbose=True ) conversation.predict(input="What would be a good demo to show?") ``` :::spoiler **顯示結果** Entering new ConversationChain chain... Prompt after formatting: >The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. Current conversation: >System: The human and AI engage in small talk before discussing the day's schedule. The AI informs the human of a morning meeting with the product team, time to work on the LangChain project, and a lunch meeting with a customer interested in the latest AI developments. Human: What would be a good demo to show? AI: Finished chain. >"Based on the customer's interest in AI developments, I would suggest showcasing our latest natural language processing capabilities. We could demonstrate how our AI can accurately understand and respond to complex language queries, and even provide personalized recommendations based on the user's preferences. Additionally, we could highlight our AI's ability to learn and adapt over time, making it a valuable tool for businesses looking to improve their customer experience." ::: ```python= ##執行程式 memory.load_memory_variables({}) ``` :::spoiler **顯示結果** >{'history': "System: The human and AI engage in small talk before discussing the day's schedule. The AI informs the human of a morning meeting with the product team, time to work on the LangChain project, and a lunch meeting with a customer interested in the latest AI developments. The human asks what would be a good demo to show.\nAI: Based on the customer's interest in AI developments, I would suggest showcasing our latest natural language processing capabilities. We could demonstrate how our AI can accurately understand and respond to complex language queries, and even provide personalized recommendations based on the user's preferences. Additionally, we could highlight our AI's ability to learn and adapt over time, making it a valuable tool for businesses looking to improve their customer experience."} ::: ### 三、 LangChain: Chains :::success ### LangChain: Chains ::: ![image](https://hackmd.io/_uploads/rJYOF9rwT.png =80%x) :::warning #### 3.1 LLM Chain ::: ```python= from langchain.chat_models import ChatOpenAI from langchain.prompts import ChatPromptTemplate from langchain.chains import LLMChain llm = ChatOpenAI(temperature=0.9, model=llm_model) prompt = ChatPromptTemplate.from_template( "What is the best name to describe \ a company that makes {product}?" ) chain = LLMChain(llm=llm, prompt=prompt) product = "Queen Size Sheet Set" chain.run(product) ``` :::spoiler **顯示結果** >'Royal Linens Inc.' ::: - - - :::warning #### 3.2 Router Chain ::: ![image](https://hackmd.io/_uploads/rJf02NVPT.png =80%x) - - - ![image](https://hackmd.io/_uploads/rko-cqSvT.png =80%x) - - - :::warning #### 3.3 Sequential Chain ::: ![image](https://hackmd.io/_uploads/SkgzBgEw6.png =80%x) - - - ![image](https://hackmd.io/_uploads/rJB59EVP6.png =80%x) ```python= from langchain.chains import SimpleSequentialChain llm = ChatOpenAI(temperature=0.9, model=llm_model) # prompt template 1 first_prompt = ChatPromptTemplate.from_template( "What is the best name to describe \ a company that makes {product}?" ) # Chain 1 chain_one = LLMChain(llm=llm, prompt=first_prompt) # prompt template 2 second_prompt = ChatPromptTemplate.from_template( "Write a 20 words description for the following \ company:{company_name}" ) # chain 2 chain_two = LLMChain(llm=llm, prompt=second_prompt) overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two],verbose=True) overall_simple_chain.run(product) ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/r1udrlyuT.png) ::: - - - ![image](https://hackmd.io/_uploads/Hy3rsEVD6.png =80%x) - - - ![image](https://hackmd.io/_uploads/rJy4vjSDa.png =80%x) - - - ```python= from langchain.chains import SequentialChain llm = ChatOpenAI(temperature=0.9, model=llm_model) # prompt template 1: translate to english first_prompt = ChatPromptTemplate.from_template( "Translate the following review to english:" "\n\n{Review}" ) # chain 1: input= Review and output= English_Review chain_one = LLMChain(llm=llm, prompt=first_prompt,output_key="English_Review" ) second_prompt = ChatPromptTemplate.from_template( "Can you summarize the following review in 1 sentence:" "\n\n{English_Review}" ) # chain 2: input= English_Review and output= summary chain_two = LLMChain(llm=llm, prompt=second_prompt, output_key="summary" ) # prompt template 3: translate to english third_prompt = ChatPromptTemplate.from_template( "What language is the following review:\n\n{Review}" ) # chain 3: input= Review and output= language chain_three = LLMChain(llm=llm, prompt=third_prompt, output_key="language" ) # prompt template 4: follow up message fourth_prompt = ChatPromptTemplate.from_template( "Write a follow up response to the following " "summary in the specified language:" "\n\nSummary: {summary}\n\nLanguage: {language}" ) # chain 4: input= summary, language and output= followup_message chain_four = LLMChain(llm=llm, prompt=fourth_prompt, output_key="followup_message" ) # overall_chain: input= Review # and output= English_Review,summary, followup_message overall_chain = SequentialChain( chains=[chain_one, chain_two, chain_three, chain_four], input_variables=["Review"], output_variables=["English_Review", "summary","followup_message"], verbose=True ) review = df.Review[5] overall_chain(review) ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/Bk15IeJda.png) ::: :::warning #### 3.4 Document Chains ::: ![image](https://hackmd.io/_uploads/rJf02NVPT.png =80%x) - - - ![image](https://hackmd.io/_uploads/ryjnwjBw6.png =80%x) - - - > overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two],verbose=True)重前幾行程式中可以看到SequentialChain將LLMChain產生的chain_one和chain_two合併,成一個新的overall_simple_chain.以上鍊結共有[chain_one, chain_two, chain_three, chain_four]4種,以output_key來呼叫使用,上述使用了["English_Review","summary","followup_message"]因此引入了3種鍊結,這邊{review}來源使用CSV檔案中第5行資料DataFrame.Review[5]的文本資料。 :::spoiler **physics_template** ```python= physics_template = """You are a very smart physics professor. \ You are great at answering questions about physics in a concise\ and easy to understand manner. \ When you don't know the answer to a question you admit\ that you don't know. Here is a question: {input}""" ``` ::: :::spoiler **math_template** ```python= math_template = """You are a very good mathematician. \ You are great at answering math questions. \ You are so good because you are able to break down \ hard problems into their component parts, answer the component parts, and then put them together\ to answer the broader question. Here is a question: {input}""" ``` ::: :::spoiler **history_template** ```python= history_template = """You are a very good historian. \ You have an excellent knowledge of and understanding of people,\ events and contexts from a range of historical periods. \ You have the ability to think, reflect, debate, discuss and \ evaluate the past. You have a respect for historical evidence\ and the ability to make use of it to support your explanations \ and judgements. Here is a question: {input}""" ``` ::: :::spoiler **computerscience_template** ```python= computerscience_template = """ You are a successful computer scientist.\ You have a passion for creativity, collaboration,\ forward-thinking, confidence, strong problem-solving capabilities,\ understanding of theories and algorithms, and excellent communication \ skills. You are great at answering coding questions. \ You are so good because you know how to solve a problem by \ describing the solution in imperative steps \ that a machine can easily interpret and you know how to \ choose a solution that has a good balance between \ time complexity and space complexity. Here is a question: {input}""" ``` ::: :::spoiler **prompt_infos** ```json= prompt_infos = [ { "name": "physics", "description": "Good for answering questions about physics", "prompt_template": physics_template }, { "name": "math", "description": "Good for answering math questions", "prompt_template": math_template }, { "name": "History", "description": "Good for answering history questions", "prompt_template": history_template }, { "name": "computer science", "description": "Good for answering computer science questions", "prompt_template": computerscience_template } ] ``` ::: ```python= from langchain.chains.router import MultiPromptChain from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParser from langchain.prompts import PromptTemplate llm = ChatOpenAI(temperature=0, model=llm_model) destination_chains = {} for p_info in prompt_infos: name = p_info["name"] prompt_template = p_info["prompt_template"] prompt = ChatPromptTemplate.from_template(template=prompt_template) chain = LLMChain(llm=llm, prompt=prompt) destination_chains[name] = chain destinations = [f"{p['name']}: {p['description']}" for p in prompt_infos] destinations_str = "\n".join(destinations) default_prompt = ChatPromptTemplate.from_template("{input}") default_chain = LLMChain(llm=llm, prompt=default_prompt) ``` :::spoiler **MULTI_PROMPT_ROUTER_TEMPLATE** ```python= MULTI_PROMPT_ROUTER_TEMPLATE = """Given a raw text input to a \ language model select the model prompt best suited for the input. \ You will be given the names of the available prompts and a \ description of what the prompt is best suited for. \ You may also revise the original input if you think that revising\ it will ultimately lead to a better response from the language model. << FORMATTING >> Return a markdown code snippet with a JSON object formatted to look like: ```json {{{{ "destination": string \ name of the prompt to use or "DEFAULT" "next_inputs": string \ a potentially modified version of the original input }}}} REMEMBER: "destination" MUST be one of the candidate prompt \ names specified below OR it can be "DEFAULT" if the input is not\ well suited for any of the candidate prompts. REMEMBER: "next_inputs" can just be the original input \ if you don't think any modifications are needed. << CANDIDATE PROMPTS >> {destinations} << INPUT >> {{input}} << OUTPUT (remember to include the ```json)>>""" ``` ::: ```python= router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format( destinations=destinations_str ) router_prompt = PromptTemplate( template=router_template, input_variables=["input"], output_parser=RouterOutputParser(), ) router_chain = LLMRouterChain.from_llm(llm, router_prompt) chain = MultiPromptChain(router_chain=router_chain, destination_chains=destination_chains, default_chain=default_chain, verbose=True ) chain.run("What is black body radiation?") ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/rkMKse1uT.png) ::: ```python= chain.run("what is 2 + 2") ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/rJaoox1_a.png) ::: ```python= chain.run("Why does every cell in our body contain DNA?") ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/rk412eJuT.png) ::: ### 四、LangChain: Retriveal Q&A over Documents :::success LangChain: Retriveal Q&A over Documents ::: ![image](https://hackmd.io/_uploads/rJRK9Zk_T.png =80%x) :::warning #### 4.1 Dataset Loader-Search ::: [![image](https://hackmd.io/_uploads/Sk4LTby_6.png =80%x)](https://python.langchain.com/docs/integrations/document_loaders) :::warning #### 4.2 VectorStore DataBase ::: ![image](https://hackmd.io/_uploads/rJQCr_SD6.png) ![image](https://hackmd.io/_uploads/SJI1oWkdT.png) :::warning #### 4.3 Embedding ::: ==詞崁入法(word embedding)是低維的浮點向量(密集向量),在處理大量的詞彙時通常只有256維、512維及1024維。Embedding層是把整數索引(代表特定的單字)對應到[密集向量]的Python字典的最好作法。== ![image](https://hackmd.io/_uploads/ByfJC-HPp.png =80%x) ![image](https://hackmd.io/_uploads/B1CprzBv6.png =80%x) ![image](https://hackmd.io/_uploads/ryKlUfHDp.png =80%x) :::warning #### 4.4 Retrieval QA ::: ==程式範例使用RetrievalQA是專門用於問答任務上的Chain元件,通過資料檢索器(retriever)查詢取得資料,在丟入模型中生成答案。== ![image](https://hackmd.io/_uploads/SyHKujBDa.png =80%x) ![image](https://hackmd.io/_uploads/SyKKqMSwp.png =80%x) ![image](https://hackmd.io/_uploads/rJ8xFsrwp.png =80%x) ![image](https://hackmd.io/_uploads/rJZLsGrwp.png =80%x) :::warning #### 4.5 Retriveal Q&A over Documents 範例程式 ::: ==使用VectorstoreIndexCreator類別可以在資料匯入後自動完成資料處理、轉成向量和儲存到向量資料庫的步驟,接下來以逐步方式展示說明== ```python= from langchain.chains import RetrievalQA from langchain.chat_models import ChatOpenAI from langchain.document_loaders import CSVLoader from langchain.vectorstores import DocArrayInMemorySearch from IPython.display import display, Markdown ``` ==Step1== 以CSVLoader讀取'OutdoorClothingCatalog_1000.csv'內容作為文本document。 ```python= file = 'OutdoorClothingCatalog_1000.csv' loader = CSVLoader(file_path=file) ``` ==Step2== 使用OpenAIEmbeddings中的.embed_query將詢問句轉換為密集向量。並以DocArrayInMemorySearch.from_documents將所有document轉換為向量資料庫db型態,透過similarity_search方法將Query查詢句找尋相似文本。此查詢出總共有4筆相近(似)。 ```python= from langchain.indexes import VectorstoreIndexCreator index = VectorstoreIndexCreator( vectorstore_cls=DocArrayInMemorySearch ).from_loaders([loader]) query ="Please list all your shirts with sun protection \ in a table in markdown and summarize each one." response = index.query(query) display(Markdown(response)) ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/HJhbtiyu6.png) ::: ==Step3== 此程式碼以retriever帶入建立好的向量資料庫,並以llm模型為大型語言模型,使用嵌入技術建立文件檢索DocArrayInMemorySearch,以便對查詢進行相似性搜尋。執行相似性搜索,基於給定的查詢文字(例如:"Please suggest a shirt with sunblocking")來檢索相關文件。llm.call_as_llm() 方法用於向 ChatOpenAI 模型提供拼接好的文檔內容作為歷史對話文本,並針對這個文本和特定問題發起對話生成請求。 * RetrievalQA 實例化: 透過 RetrievalQA.from_chain_type() 方法建立了一個 RetrievalQA 物件 qa_stuff。 * 執行檢索式問答(Retrieval-based QA): 使用 qa_stuff.run(query) 方法執行檢索式問答,其中的 query 是一個問題,即:"Please list all your shirts with sun protection in a table in markdown and summarize each one."qa_stuff 實例將利用 ChatOpenAI 模型 llm 和擷取器 retriever 來尋找答案,並產生相關的回應。 * 建構向量索引: VectorstoreIndexCreator 類別用於建立向量索引。使用 from_loaders([loader]) 方法,將先前建立的載入器 loader 套用至向量索引的建置。在建立向量索引之前,執行了查詢操作index.query(query, llm=llm),可能表示嘗試在索引建置之前先查詢相關資訊。 :::spoiler **回顧一下前述步驟** ![image](https://hackmd.io/_uploads/B1K3sOHva.png =80%x) ![image](https://hackmd.io/_uploads/Byh-ndBwT.png =80%x) ![image](https://hackmd.io/_uploads/BJty6_HP6.png =80%x) ::: ==Step1載入文檔:== 使用 CSVLoader 從CSV檔案載入文件集合(假設檔案路徑透過 file 變數提供)。 載入後的文檔儲存在 docs 變數中。 ```python= from langchain.document_loaders import CSVLoader loader = CSVLoader(file_path=file) docs = loader.load() docs[0] ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/SkAg5ikOa.png =80%x) ::: ==Step2嵌入查詢文字:== 使用 OpenAIEmbeddings 類別為查詢文字進行嵌入。 程式碼示範如何對字串 "Hi my name is Harrison" 進行嵌入。 嵌入向量的長度和前五個元素會輸出。 ```python= from langchain.embeddings import OpenAIEmbeddings embeddings = OpenAIEmbeddings() embed = embeddings.embed_query("Hi my name is Harrison") print(len(embed)) print(embed[:5]) ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/SJ049jyOp.png =80%x) ::: ==Step3建構文件檢索與相似性搜尋:== 使用嵌入技術建立文件檢索器 DocArrayInMemorySearch,以便對查詢進行相似性搜尋。 執行相似性搜索,基於給定的查詢文字(例如:"Please suggest a shirt with sunblocking")來檢索相關文件。 ```python= db = DocArrayInMemorySearch.from_documents( docs, embeddings ) query = "Please suggest a shirt with sunblocking" docs = db.similarity_search(query) len(docs) docs[0] ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/r1fF9iJdp.png =80%x) ![image](https://hackmd.io/_uploads/HJJ5coJOa.png =80%x) ::: ==Step4執行語言模型產生對話:== 建立一個 ChatOpenAI 實例,可能用於執行對話產生或問答任務使用該模型產生對話,例如建構一個問題來請求 Markdown 表格中具有防曬功能的襯衫,並總結每個襯衫的資訊。 ```python= retriever = db.as_retriever() llm = ChatOpenAI(temperature = 0.0, model=llm_model) qdocs = "".join([docs[i].page_content for i in range(len(docs))]) response = llm.call_as_llm(f"{qdocs} Question: Please list all your \ shirts with sun protection in a table in markdown and summarize each one.") display(Markdown(response)) ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/rkeesj1OT.png =80%x) ::: ==Step5執行檢索式問答:== 使用 RetrievalQA 類別執行從檢索器中檢索的問答任務。 程式碼中給了一個問題 ("Please list all your shirts with sun protection in a table in markdown and summarize each one.") 來取得特定資訊。 ```python= qa_stuff = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever, verbose=True ) query = "Please list all your shirts with sun protection in a table \ in markdown and summarize each one." response = qa_stuff.run(query) display(Markdown(response)) ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/SyX_soy_a.png =80%x) ![image](https://hackmd.io/_uploads/B16Fsi1dp.png =80%x) ![image](https://hackmd.io/_uploads/SyY5ji1dp.png =80%x) ::: ==Step6建構索引:== 使用 VectorstoreIndexCreator 類別從載入器(loader)建立索引,該索引可用於後續的查詢和檢索任務。 ```python= response = index.query(query, llm=llm) index = VectorstoreIndexCreator( vectorstore_cls=DocArrayInMemorySearch, embedding=embeddings, ).from_loaders([loader]) ``` ### 五、LangChain: Evaluation :::success LangChain: Evaluation ::: * 設定模型及載入資料: 透過 datetime 模組設定了一個日期標誌來確定使用的模型版本,使用了 gpt-3.5-turbo 或 gpt-3.5-turbo-0301 中的一個。 使用了 CSVLoader 載入了一個名為 OutdoorClothingCatalog_1000.csv 的檔案。 ```python= from langchain.chains import RetrievalQA from langchain.chat_models import ChatOpenAI from langchain.document_loaders import CSVLoader from langchain.indexes import VectorstoreIndexCreator from langchain.vectorstores import DocArrayInMemorySearch file = 'OutdoorClothingCatalog_1000.csv' loader = CSVLoader(file_path=file) data = loader.load() ``` * 建立向量索引和模型實例: 使用 VectorstoreIndexCreator 和 DocArrayInMemorySearch 建立了一個向量索引。 ChatOpenAI 被用作模型實例,其中 temperature = 0.0 是溫度參數的設定。 ```python= index = VectorstoreIndexCreator( vectorstore_cls=DocArrayInMemorySearch ).from_loaders([loader]) llm = ChatOpenAI(temperature = 0.0, model=llm_model) ``` * 建立檢索式問答(Retrieval-based QA): 使用 RetrievalQA.from_chain_type 建立了一個 RetrievalQA 實例,設定了檢索器和相關參數。 chain_type_kwargs 中可能指定了特定的文檔分隔符號。 ```python= llm = ChatOpenAI(temperature = 0.0, model=llm_model) qa = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=index.vectorstore.as_retriever(), verbose=True, chain_type_kwargs = { "document_separator": "<<<<>>>>>" } ) data[10] ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/ry3uP3JdT.png) ::: ```pyton= data[11] ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/HyD9w31ua.png) ::: * 資料處理與問題回答產生: 在 examples 清單中定義了一些問題及其預期答案。 **Hard-coded examples** ```json= examples = [ { "query": "Do the Cozy Comfort Pullover Set\ have side pockets?", "answer": "Yes" }, { "query": "What collection is the Ultra-Lofty \ 850 Stretch Down Hooded Jacket from?", "answer": "The DownTek collection" } ] ``` 使用 QAGenerateChain.from_llm 建立了一個新的 QAGenerateChain,然後將其應用於資料集中的文件以產生更多問題及答案。 **LLM-Generated examples** ```python= from langchain.evaluation.qa import QAGenerateChain example_gen_chain = QAGenerateChain.from_llm(ChatOpenAI(model=llm_model)) new_examples = example_gen_chain.apply_and_parse( [{"doc": t} for t in data[:5]] ) new_examples[0] ``` :::spoiler **顯示結果(自動產生QA)** ![image](https://hackmd.io/_uploads/HJC9OhJ_T.png) ::: ```python= data[0] ``` :::spoiler **顯示結果(原始內容)** ![image](https://hackmd.io/_uploads/BkE1Kn1dT.png) ::: **Combine examples** 運行了 QA 模型(透過 qa.run)來回答一個問題。 ```python= examples += new_examples qa.run(examples[0]["query"]) ``` :::spoiler **顯示結果(原始內容)** ![image](https://hackmd.io/_uploads/H1u_Yhkdp.png) ::: **Manual Evaluation** * 預測結果評估: 設定了 langchain 的 debug 模式,用於記錄偵錯資訊。 應用了 QAEvalChain 來評估問題回答的品質。 * 輸出訊息: 最後,循環列印了一些範例的問題、真實答案、模型預測的結果和評分資訊。 ```python= import langchain langchain.debug = True qa.run(examples[0]["query"]) ``` :::spoiler **顯示結果(評估品質)** ```json= [chain/start] [1:chain:RetrievalQA] Entering Chain run with input: { "query": "Do the Cozy Comfort Pullover Set have side pockets?" } [chain/start] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain] Entering Chain run with input: [inputs] [chain/start] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain > 3:chain:LLMChain] Entering Chain run with input: { "question": "Do the Cozy Comfort Pullover Set have side pockets?", "context": ": 10\nname: Cozy Comfort Pullover Set, Stripe\ndescription: Perfect for lounging, this striped knit set lives up to its name. We used ultrasoft fabric and an easy design that's as comfortable at bedtime as it is when we have to make a quick run out.\n\nSize & Fit\n- Pants are Favorite Fit: Sits lower on the waist.\n- Relaxed Fit: Our most generous fit sits farthest from the body.\n\nFabric & Care\n- In the softest blend of 63% polyester, 35% rayon and 2% spandex.\n\nAdditional Features\n- Relaxed fit top with raglan sleeves and rounded hem.\n- Pull-on pants have a wide elastic waistband and drawstring, side pockets and a modern slim leg.\n\nImported.<<<<>>>>>: 73\nname: Cozy Cuddles Knit Pullover Set\ndescription: Perfect for lounging, this knit set lives up to its name. We used ultrasoft fabric and an easy design that's as comfortable at bedtime as it is when we have to make a quick run out. \n\nSize & Fit \nPants are Favorite Fit: Sits lower on the waist. \nRelaxed Fit: Our most generous fit sits farthest from the body. \n\nFabric & Care \nIn the softest blend of 63% polyester, 35% rayon and 2% spandex.\n\nAdditional Features \nRelaxed fit top with raglan sleeves and rounded hem. \nPull-on pants have a wide elastic waistband and drawstring, side pockets and a modern slim leg. \nImported.<<<<>>>>>: 632\nname: Cozy Comfort Fleece Pullover\ndescription: The ultimate sweater fleece \u2013 made from superior fabric and offered at an unbeatable price. \n\nSize & Fit\nSlightly Fitted: Softly shapes the body. Falls at hip. \n\nWhy We Love It\nOur customers (and employees) love the rugged construction and heritage-inspired styling of our popular Sweater Fleece Pullover and wear it for absolutely everything. From high-intensity activities to everyday tasks, you'll find yourself reaching for it every time.\n\nFabric & Care\nRugged sweater-knit exterior and soft brushed interior for exceptional warmth and comfort. Made from soft, 100% polyester. Machine wash and dry.\n\nAdditional Features\nFeatures our classic Mount Katahdin logo. Snap placket. Front princess seams create a feminine shape. Kangaroo handwarmer pockets. Cuffs and hem reinforced with jersey binding. Imported.\n\n \u2013 Official Supplier to the U.S. Ski Team\nTHEIR WILL TO WIN, WOVEN RIGHT IN. LEARN MORE<<<<>>>>>: 151\nname: Cozy Quilted Sweatshirt\ndescription: Our sweatshirt is an instant classic with its great quilted texture and versatile weight that easily transitions between seasons. With a traditional fit that is relaxed through the chest, sleeve, and waist, this pullover is lightweight enough to be worn most months of the year. The cotton blend fabric is super soft and comfortable, making it the perfect casual layer. To make dressing easy, this sweatshirt also features a snap placket and a heritage-inspired Mt. Katahdin logo patch. For care, machine wash and dry. Imported." } [llm/start] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain > 3:chain:LLMChain > 4:llm:ChatOpenAI] Entering LLM run with input: { "prompts": [ "System: Use the following pieces of context to answer the users question. \nIf you don't know the answer, just say that you don't know, don't try to make up an answer.\n----------------\n: 10\nname: Cozy Comfort Pullover Set, Stripe\ndescription: Perfect for lounging, this striped knit set lives up to its name. We used ultrasoft fabric and an easy design that's as comfortable at bedtime as it is when we have to make a quick run out.\n\nSize & Fit\n- Pants are Favorite Fit: Sits lower on the waist.\n- Relaxed Fit: Our most generous fit sits farthest from the body.\n\nFabric & Care\n- In the softest blend of 63% polyester, 35% rayon and 2% spandex.\n\nAdditional Features\n- Relaxed fit top with raglan sleeves and rounded hem.\n- Pull-on pants have a wide elastic waistband and drawstring, side pockets and a modern slim leg.\n\nImported.<<<<>>>>>: 73\nname: Cozy Cuddles Knit Pullover Set\ndescription: Perfect for lounging, this knit set lives up to its name. We used ultrasoft fabric and an easy design that's as comfortable at bedtime as it is when we have to make a quick run out. \n\nSize & Fit \nPants are Favorite Fit: Sits lower on the waist. \nRelaxed Fit: Our most generous fit sits farthest from the body. \n\nFabric & Care \nIn the softest blend of 63% polyester, 35% rayon and 2% spandex.\n\nAdditional Features \nRelaxed fit top with raglan sleeves and rounded hem. \nPull-on pants have a wide elastic waistband and drawstring, side pockets and a modern slim leg. \nImported.<<<<>>>>>: 632\nname: Cozy Comfort Fleece Pullover\ndescription: The ultimate sweater fleece \u2013 made from superior fabric and offered at an unbeatable price. \n\nSize & Fit\nSlightly Fitted: Softly shapes the body. Falls at hip. \n\nWhy We Love It\nOur customers (and employees) love the rugged construction and heritage-inspired styling of our popular Sweater Fleece Pullover and wear it for absolutely everything. From high-intensity activities to everyday tasks, you'll find yourself reaching for it every time.\n\nFabric & Care\nRugged sweater-knit exterior and soft brushed interior for exceptional warmth and comfort. Made from soft, 100% polyester. Machine wash and dry.\n\nAdditional Features\nFeatures our classic Mount Katahdin logo. Snap placket. Front princess seams create a feminine shape. Kangaroo handwarmer pockets. Cuffs and hem reinforced with jersey binding. Imported.\n\n \u2013 Official Supplier to the U.S. Ski Team\nTHEIR WILL TO WIN, WOVEN RIGHT IN. LEARN MORE<<<<>>>>>: 151\nname: Cozy Quilted Sweatshirt\ndescription: Our sweatshirt is an instant classic with its great quilted texture and versatile weight that easily transitions between seasons. With a traditional fit that is relaxed through the chest, sleeve, and waist, this pullover is lightweight enough to be worn most months of the year. The cotton blend fabric is super soft and comfortable, making it the perfect casual layer. To make dressing easy, this sweatshirt also features a snap placket and a heritage-inspired Mt. Katahdin logo patch. For care, machine wash and dry. Imported.\nHuman: Do the Cozy Comfort Pullover Set have side pockets?" ] } [llm/end] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain > 3:chain:LLMChain > 4:llm:ChatOpenAI] [680.713ms] Exiting LLM run with output: { "generations": [ [ { "text": "The Cozy Comfort Pullover Set, Stripe has side pockets.", "generation_info": null, "message": { "content": "The Cozy Comfort Pullover Set, Stripe has side pockets.", "additional_kwargs": {}, "example": false } } ] ], "llm_output": { "token_usage": { "prompt_tokens": 734, "completion_tokens": 13, "total_tokens": 747 }, "model_name": "gpt-3.5-turbo-0301" } } [chain/end] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain > 3:chain:LLMChain] [681.335ms] Exiting Chain run with output: { "text": "The Cozy Comfort Pullover Set, Stripe has side pockets." } [chain/end] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain] [852.117ms] Exiting Chain run with output: { "output_text": "The Cozy Comfort Pullover Set, Stripe has side pockets." } [chain/end] [1:chain:RetrievalQA] [1.02s] Exiting Chain run with output: { "result": "The Cozy Comfort Pullover Set, Stripe has side pockets." } 'The Cozy Comfort Pullover Set, Stripe has side pockets.' ``` ::: ```python= # Turn off the debug mode langchain.debug = False ``` **LLM assisted evaluation** ```python= predictions = qa.apply(examples) from langchain.evaluation.qa import QAEvalChain llm = ChatOpenAI(temperature=0, model=llm_model) eval_chain = QAEvalChain.from_llm(llm) graded_outputs = eval_chain.evaluate(examples, predictions) for i, eg in enumerate(examples): print(f"Example {i}:") print("Question: " + predictions[i]['query']) print("Real Answer: " + predictions[i]['answer']) print("Predicted Answer: " + predictions[i]['result']) print("Predicted Grade: " + graded_outputs[i]['text']) print() ``` :::spoiler **顯示結果(評估結果)** ![image](https://hackmd.io/_uploads/H1rOs3JOT.png) ![image](https://hackmd.io/_uploads/Bknqshy_T.png) ![image](https://hackmd.io/_uploads/rkrjonkd6.png) ![image](https://hackmd.io/_uploads/HyJhjnJO6.png) ![image](https://hackmd.io/_uploads/Bkc3o31up.png) ![image](https://hackmd.io/_uploads/SJrpon1_6.png) ![image](https://hackmd.io/_uploads/B1lCj31_6.png) ![image](https://hackmd.io/_uploads/S16Cjny_T.png) ::: **LangChain evaluation platform** The LangChain evaluation platform, LangChain Plus, can be accessed here [https://www.langchain.plus/.](https://www.langchain.plus/.) Use the invite code lang_learners_2023 ### 六、LangChain: Agents :::success LangChain: Agents ::: ![image](https://hackmd.io/_uploads/rymp5jSvp.png =80%x) - - - ![image](https://hackmd.io/_uploads/ByCz3srDa.png =80%x) - - - ![image](https://hackmd.io/_uploads/Bk3g2sHva.png =80%x) - - - ![image](https://hackmd.io/_uploads/BJnHhiHPp.png =80%x) - - - ![image](https://hackmd.io/_uploads/rywtCsrw6.png =80%x) - - - ==範例程式 Using built in LangChain tools: DuckDuckGo search and Wikipedia== initialize_agent: 函數的目的是要建立一個對話代理程式。 參數包括: 1. tools: 工具參數,可能是一些處理對話或回應的輔助工具。 2. llm: Chat OpenAI 模型,用於實作代理的聊天功能。 3. agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION: 這可能是指定代理程式的類型。 在這種情況下,它是一個零-shot響應描述型代理。 4. handle_parsing_errors=True: 這個參數指定是否要處理解析錯誤。如果設定為 True,則代理程式會嘗試處理可能發生的解析錯誤。 5. verbose=True: 這個參數可能用於在代理程式運行過程中提供詳細資訊和日誌,以便更好地追蹤代理的行為和輸出。 ```python= #!pip install -U wikipedia from langchain.agents.agent_toolkits import create_python_agent from langchain.agents import load_tools, initialize_agent from langchain.agents import AgentType from langchain.tools.python.tool import PythonREPLTool from langchain.python import PythonREPL from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(temperature=0, model=llm_model) tools = load_tools(["llm-math","wikipedia"], llm=llm) agent= initialize_agent( tools, llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, handle_parsing_errors=True, verbose = True) agent("What is the 25% of 300?") ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/rJSR6n1O6.png) ::: **Wikipedia example** ```python= question = "Tom M. Mitchell is an American computer scientist \ and the Founders University Professor at Carnegie Mellon University (CMU)\ what book did he write?" result = agent(question) ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/S1kf021ua.png) ![image](https://hackmd.io/_uploads/Sksf03yua.png) ![image](https://hackmd.io/_uploads/BJOXC2Ju6.png) ::: **Python Agent** ```python= agent = create_python_agent( llm, tool=PythonREPLTool(), verbose=True ) customer_list = [["Harrison", "Chase"], ["Lang", "Chain"], ["Dolly", "Too"], ["Elle", "Elem"], ["Geoff","Fusion"], ["Trance","Former"], ["Jen","Ayai"]] ``` ```python= agent.run(f"""Sort these customers by \ last name and then first name \ and print the output: {customer_list}""") ``` :::spoiler **顯示結果** ![image](https://hackmd.io/_uploads/rJWnJpy_p.png) ![image](https://hackmd.io/_uploads/rkTn16kd6.png) ![image](https://hackmd.io/_uploads/SJcpJaJdp.png) ![image](https://hackmd.io/_uploads/B1f016JdT.png) ::: **View detailed outputs of the chains** ```python= import langchain langchain.debug=True agent.run(f"""Sort these customers by \ last name and then first name \ and print the output: {customer_list}""") langchain.debug=False ``` :::spoiler **顯示結果** ```json= [chain/start] [1:chain:AgentExecutor] Entering Chain run with input: { "input": "Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]" } [chain/start] [1:chain:AgentExecutor > 2:chain:LLMChain] Entering Chain run with input: { "input": "Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]", "agent_scratchpad": "", "stop": [ "\nObservation:", "\n\tObservation:" ] } [llm/start] [1:chain:AgentExecutor > 2:chain:LLMChain > 3:llm:ChatOpenAI] Entering LLM run with input: { "prompts": [ "Human: You are an agent designed to write and execute python code to answer questions.\nYou have access to a python REPL, which you can use to execute python code.\nIf you get an error, debug your code and try again.\nOnly use the output of your code to answer the question. \nYou might know the answer without running any code, but you should still run the code to get the answer.\nIf it does not seem like you can write code to answer the question, just return \"I don't know\" as the answer.\n\n\nPython REPL: A Python shell. Use this to execute python commands. Input should be a valid python command. If you want to see the output of a value, you should print it out with `print(...)`.\n\nUse the following format:\n\nQuestion: the input question you must answer\nThought: you should always think about what to do\nAction: the action to take, should be one of [Python REPL]\nAction Input: the input to the action\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\nThought: I now know the final answer\nFinal Answer: the final answer to the original input question\n\nBegin!\n\nQuestion: Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nThought:" ] } [llm/end] [1:chain:AgentExecutor > 2:chain:LLMChain > 3:llm:ChatOpenAI] [5.64s] Exiting LLM run with output: { "generations": [ [ { "text": "I can use the sorted() function to sort the list of customers by last name and then first name. I will need to provide a key function to sorted() that returns a tuple of the last name and first name in that order.\nAction: Python REPL\nAction Input:\n```\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nfor customer in sorted_customers:\n print(customer)\n```", "generation_info": null, "message": { "content": "I can use the sorted() function to sort the list of customers by last name and then first name. I will need to provide a key function to sorted() that returns a tuple of the last name and first name in that order.\nAction: Python REPL\nAction Input:\n```\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nfor customer in sorted_customers:\n print(customer)\n```", "additional_kwargs": {}, "example": false } } ] ], "llm_output": { "token_usage": { "prompt_tokens": 327, "completion_tokens": 144, "total_tokens": 471 }, "model_name": "gpt-3.5-turbo-0301" } } [chain/end] [1:chain:AgentExecutor > 2:chain:LLMChain] [5.64s] Exiting Chain run with output: { "text": "I can use the sorted() function to sort the list of customers by last name and then first name. I will need to provide a key function to sorted() that returns a tuple of the last name and first name in that order.\nAction: Python REPL\nAction Input:\n```\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nfor customer in sorted_customers:\n print(customer)\n```" } [tool/start] [1:chain:AgentExecutor > 4:tool:Python REPL] Entering Tool run with input: "``` customers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']] sorted_customers = sorted(customers, key=lambda x: (x[1], x[0])) for customer in sorted_customers: print(customer) ```" [tool/end] [1:chain:AgentExecutor > 4:tool:Python REPL] [0.325ms] Exiting Tool run with output: "['Jen', 'Ayai'] ['Lang', 'Chain'] ['Harrison', 'Chase'] ['Elle', 'Elem'] ['Trance', 'Former'] ['Geoff', 'Fusion'] ['Dolly', 'Too']" [chain/start] [1:chain:AgentExecutor > 5:chain:LLMChain] Entering Chain run with input: { "input": "Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]", "agent_scratchpad": "I can use the sorted() function to sort the list of customers by last name and then first name. I will need to provide a key function to sorted() that returns a tuple of the last name and first name in that order.\nAction: Python REPL\nAction Input:\n```\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nfor customer in sorted_customers:\n print(customer)\n```\nObservation: ['Jen', 'Ayai']\n['Lang', 'Chain']\n['Harrison', 'Chase']\n['Elle', 'Elem']\n['Trance', 'Former']\n['Geoff', 'Fusion']\n['Dolly', 'Too']\n\nThought:", "stop": [ "\nObservation:", "\n\tObservation:" ] } [llm/start] [1:chain:AgentExecutor > 5:chain:LLMChain > 6:llm:ChatOpenAI] Entering LLM run with input: { "prompts": [ "Human: You are an agent designed to write and execute python code to answer questions.\nYou have access to a python REPL, which you can use to execute python code.\nIf you get an error, debug your code and try again.\nOnly use the output of your code to answer the question. \nYou might know the answer without running any code, but you should still run the code to get the answer.\nIf it does not seem like you can write code to answer the question, just return \"I don't know\" as the answer.\n\n\nPython REPL: A Python shell. Use this to execute python commands. Input should be a valid python command. If you want to see the output of a value, you should print it out with `print(...)`.\n\nUse the following format:\n\nQuestion: the input question you must answer\nThought: you should always think about what to do\nAction: the action to take, should be one of [Python REPL]\nAction Input: the input to the action\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\nThought: I now know the final answer\nFinal Answer: the final answer to the original input question\n\nBegin!\n\nQuestion: Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nThought:I can use the sorted() function to sort the list of customers by last name and then first name. I will need to provide a key function to sorted() that returns a tuple of the last name and first name in that order.\nAction: Python REPL\nAction Input:\n```\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nfor customer in sorted_customers:\n print(customer)\n```\nObservation: ['Jen', 'Ayai']\n['Lang', 'Chain']\n['Harrison', 'Chase']\n['Elle', 'Elem']\n['Trance', 'Former']\n['Geoff', 'Fusion']\n['Dolly', 'Too']\n\nThought:" ] } [llm/end] [1:chain:AgentExecutor > 5:chain:LLMChain > 6:llm:ChatOpenAI] [2.86s] Exiting LLM run with output: { "generations": [ [ { "text": "The customers are now sorted by last name and then first name. \nFinal Answer: [['Jen', 'Ayai'], ['Lang', 'Chain'], ['Harrison', 'Chase'], ['Elle', 'Elem'], ['Trance', 'Former'], ['Geoff', 'Fusion'], ['Dolly', 'Too']]", "generation_info": null, "message": { "content": "The customers are now sorted by last name and then first name. \nFinal Answer: [['Jen', 'Ayai'], ['Lang', 'Chain'], ['Harrison', 'Chase'], ['Elle', 'Elem'], ['Trance', 'Former'], ['Geoff', 'Fusion'], ['Dolly', 'Too']]", "additional_kwargs": {}, "example": false } } ] ], "llm_output": { "token_usage": { "prompt_tokens": 526, "completion_tokens": 68, "total_tokens": 594 }, "model_name": "gpt-3.5-turbo-0301" } } [chain/end] [1:chain:AgentExecutor > 5:chain:LLMChain] [2.86s] Exiting Chain run with output: { "text": "The customers are now sorted by last name and then first name. \nFinal Answer: [['Jen', 'Ayai'], ['Lang', 'Chain'], ['Harrison', 'Chase'], ['Elle', 'Elem'], ['Trance', 'Former'], ['Geoff', 'Fusion'], ['Dolly', 'Too']]" } [chain/end] [1:chain:AgentExecutor] [8.51s] Exiting Chain run with output: { "output": "[['Jen', 'Ayai'], ['Lang', 'Chain'], ['Harrison', 'Chase'], ['Elle', 'Elem'], ['Trance', 'Former'], ['Geoff', 'Fusion'], ['Dolly', 'Too']]" } ``` ::: **Define your own tool** ==PythonREPLTool() 可能是指一個 Python 互動式環境(REPL),通常用於互動式地執行和測試 Python 程式碼。 這個函數或物件可以提供一個互動式介面,允許使用者輸入和執行 Python 程式碼,並立即看到執行結果。== ```python= #!pip install DateTime from langchain.agents import tool from datetime import date @tool def time(text: str) -> str: """Returns todays date, use this for any \ questions related to knowing todays date. \ The input should always be an empty string, \ and this function will always return todays \ date - any date mathmatics should occur \ outside this function.""" return str(date.today()) agent= initialize_agent( tools + [time], llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, handle_parsing_errors=True, verbose = True) ``` ```python= try: result = agent("whats the date today?") except: print("exception on external access") ``` :::spoiler **顯示結果** ```json= > Entering new AgentExecutor chain... Thought: I need to use the `time` tool to get today's date. Action: ``` { "action": "time", "action_input": "" } ``` Observation: 2024-01-01 Thought:I made a mistake in my observation. The correct date should be today's date. Action: ``` { "action": "time", "action_input": "" } ``` Observation: 2024-01-01 Thought:I need to fix the date format to be more readable. Action: ``` { "action": "time", "action_input": "" } ``` Observation: 2024-01-01 Thought:I need to fix the action_input to be an empty string. Action: ``` { "action": "time", "action_input": "" } ``` Observation: 2024-01-01 Thought:I now know the final answer. Final Answer: Today's date is 2022-02-22. > Finished chain. ``` ::: - - - :::success ### **參考文獻** ::: 1.[DeepLearning.AI](https://learn.deeplearning.ai/langchain/lesson/1/introduction) 2.[九天玩轉Langchain!第四講-數據鏈結](https://www.youtube.com/watch?v=CLejfWTvxMo&list=PLAr9oL1AT4OElxInUijCzCgU3CpgHTjTI&index=4) 3.[Prompt Inhect Intro to Large Language Models](https://www.youtube.com/watch?v=zjkBMFhNj_g ) 4.[Getting Started with Gemini Pro on Google AI Studio](https://www.youtube.com/watch?v=HN96QDFBD0g) 5.[使用 AutoGPTQ 和 transformers 讓大型語言模型更輕量化](https://huggingface.co/blog/zh/gptq-integration) 6.[Getting Started with Gemini Pro on Google AI Studio](https://www.youtube.com/watch?v=HN96QDFBD0g) 7.[醫療爭議常見Q&A](https://www.thrf.org.tw/dispute/109?page=2) 8.[ChatGPT的原理與應用(師範大學)](chrome-extension://cdonnmffkdaoajfknoeeecmchibpmkmg/assets/pdf/web/viewer.html?file=https%3A%2F%2Fweb.ntnu.edu.tw%2F~samtseng%2Fpresent%2F2023_ChatGPT.pdf)