# [LangChain] 範例-飲食建議與分類 日期:2023/09/20 ## 敘述 - 主題:StructuredOutputParser()、MultiPromptChain()、LLMRouterChain() - 使用情境:透過此範例程式將針對提供的飲食敘述進行回應,可獲得飲食方面的建議。另外也可讓其根據食物六大類進行分類、整理,輸出一個容易理解的結構,以便後續作更多運用,例如:紀錄。 - 輸入:飲食敘述。例如:我今天吃了一份炒泡麵。 - 輸出: 1.給予飲食相關建議 2.分類、整理敘述中的飲食 3.回答任意問題 備註:此範例使用到範例-飲食敘述分類的功能。 ## 目錄 - [1. 主程式](#1-主程式) - [2. 輸入輸出](#2-輸入輸出) ____________________ ## 1. 主程式 導入套件 ```python= from dotenv import load_dotenv load_dotenv() from langchain.llms import OpenAI from langchain.chat_models import ChatOpenAI from langchain.prompts import ( PromptTemplate ) from langchain import LLMChain llm = ChatOpenAI(temperature=0) ``` ```python= from langchain.chains.router import MultiPromptChain from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE from langchain.output_parsers import StructuredOutputParser, ResponseSchema ``` 程式包含幾個功能:1.對飲食敘述給予建議 2.根據食物六大類進行分類 3.回應其他非前兩種類型的輸入。 前兩個功能分別透過各自的destination prompt實現。若敘述中包含飲食,則會使用prompt1,進而實現功能1;若敘述中有要求紀錄,則使用prompt2,進而實現功能2。若輸入接不符合上述兩個prompt,則將使用默認的prompt,進而實現功能3。 定義destination prompt。 ```python= #定義destination prompt prompt1 = """對<>中提到的飲食進行評價和建議。 <{input}>""" # prompt1 = """不論<>的內容是甚麼,只需要輸出『此為prompt1的輸出』即可。 # <{input}>""" # prompt2 = "確認<>中的句子是否包含任何飲食種類。若沒有提及,輸入Empty;若有提及,請將提到的飲食種類列舉出來: <{input}>.\n{format_instructions}" prompt2 = "請判斷<>中提及的飲食或料理,根據營養學六大類食物進行分類。\n{format_instructions}\n<{input}>" # prompt2 = """不論<>的內容是甚麼,只需要輸出『此為prompt2的輸出』即可。 # <{input}>""" #使用以下格式整理所有promtpt prompt_infos = [ { "name": "dietary recommendations", "description": "如果有提到飲食相關的敘述,請使用這個prompt。", "prompt_template": prompt1, }, { "name": "request record", "description": "若輸入中要求'紀錄',請使用這個prompt。", "prompt_template": prompt2, }, ] ``` 將不同的prompt用於定義各自的chain-chain1、chain2。 destinations_str將在之後提供給router_chain。 ```python= #使用所有prompt定義各自的chain destination_chains = {} #chain1(prompt1) p_info = prompt_infos[0] name = p_info["name"] prompt_template = p_info["prompt_template"] prompt = PromptTemplate(template=prompt_template, input_variables=["input"]) llm = ChatOpenAI(temperature=0) chain = LLMChain(llm=llm, prompt=prompt) destination_chains[name] = chain #chain2(prompt2) p_info = prompt_infos[1] name = p_info["name"] prompt_template = p_info["prompt_template"] #定義output parser response_schemas = [ ResponseSchema(name='CER', description='請將<五穀類>的食物放到此處。'), ResponseSchema(name='VEG', description='請將<蔬菜類>的食物放到此處。'), ResponseSchema(name='FRU', description='請將<水果類>的食物放到此處。'), ResponseSchema(name='M&L', description='請將<肉類和豆類>的食物放到此處。'), ResponseSchema(name='DAIRY', description='請將<奶製品類>的食物放到此處。'), ResponseSchema(name='F&N', description='請將<油脂和堅果類>的食物放到此處。'), ] output_parser = StructuredOutputParser.from_response_schemas(response_schemas) format_instructions = output_parser.get_format_instructions() prompt = PromptTemplate( template=prompt_template, input_variables=["input"], partial_variables={"format_instructions": format_instructions}, output_parser=output_parser ) chain = LLMChain(prompt=prompt, llm=llm) # chain = LLMChain(prompt=prompt, llm=OpenAI()) destination_chains[name] = chain #destinations_str包含各個不同prompt的名稱與敘述,router_chain將根據destinations_str選擇使用甚麼prompt destinations = [f"{p['name']}: {p['description']}" for p in prompt_infos] destinations_str = "\n".join(destinations) ``` 定義router_chain以及default_chain,並將所有chain都加入到MultiPromptChain()中。 ```python= #定義router_chain router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(destinations=destinations_str) router_prompt = PromptTemplate( template=router_template, input_variables=["input"], output_parser=RouterOutputParser(), ) llm = ChatOpenAI(temperature=0) # router_chain = LLMRouterChain.from_llm(llm, router_prompt) router_chain = LLMRouterChain.from_llm(OpenAI(temperature=0), router_prompt) #定義default_chain default_prompt = '''請根據<>中的敘述給予回應。 <{input}>''' default_prompt = ChatPromptTemplate.from_template(default_prompt) default_chain = LLMChain(llm=llm, prompt=default_prompt) #將chain都加入到MultiPromptChain()中 chain = MultiPromptChain( router_chain=router_chain, destination_chains=destination_chains, default_chain=default_chain, verbose=True, ) ``` ## 2. 輸入輸出 將輸入提供給程式。 測試prompt1-飲食建議。 ```python= print(chain.run("我今天吃了十顆哈密瓜、兩個蘋果派、一片巧克力蛋糕、一個素食便當。")) ``` :::success \> Entering new MultiPromptChain chain... dietary recommendations: {'input': '我今天吃了十顆哈密瓜、兩個蘋果派、一片巧克力蛋糕、一個素食便當。'} \> Finished chain. A: 對於你提到的飲食,我可以給出以下評價和建議: 1\. 十顆哈密瓜:哈密瓜是一種水分豐富、低熱量的水果,對於保持身體水分平衡和提供維生素C有益。然而,過量攝取哈密瓜可能會導致消化不良或腹瀉。建議適量食用,每天約一到兩顆。 2\. 兩個蘋果派:蘋果派含有大量的糖分和脂肪,並且烹調過程中可能添加了其他高熱量成分。過量攝取這樣的甜點可能導致體重增加和血糖波動。建議適量享用,可以考慮選擇低糖或無糖的版本。 3\. 一片巧克力蛋糕:巧克力蛋糕是高熱量、高糖分的甜點,過量攝取可能導致體重增加和血糖波動。建議限制甜點的攝取量,選擇健康的替代品,如水果或低糖的甜點。 4\. 一個素食便當:素食便當通常包含豆類、蔬菜和全穀物,提供豐富的蛋白質、纖維和營養素。這是一個健康的選擇,有助於維持身體的平衡和健康。建議繼續選擇素食便當,並確保攝取足夠的蛋白質和其他必需營養素。 總體而言,飲食的平衡和多樣性是關鍵。建議適量攝取水果和蔬菜,限制高糖和高脂肪的甜點,並確保攝取足夠的蛋白質和其他營養素。 ::: 測試prompt2-飲食分類。 ```python= print(chain.run("幫我記錄,今天吃了一份炒泡麵")) ``` :::success \> Entering new MultiPromptChain chain... request record: {'input': '幫我記錄,今天吃了一份炒泡麵'} \> Finished chain. \```json { "CER": "炒泡麵", "VEG": "", "FRU": "", "M&L": "", "DAIRY": "", "F&N": "" } \``` ::: 其他輸入測試結果如下: :::success Q: 記錄,我今天早上吃了十顆哈密瓜、兩個蘋果派;而下午時,吃了一片巧克力蛋糕、一個素食便當。 \> Entering new MultiPromptChain chain... request record: {'input': '請紀錄我今天早上吃了十顆哈密瓜、兩個蘋果派;而下午時,吃了一片巧克力蛋糕、一個素食便當。'} \> Finished chain. A: \```json { "CER": "", "VEG": "一個素食便當", "FRU": "十顆哈密瓜、兩個蘋果派", "M&L": "", "DAIRY": "", "F&N": "一片巧克力蛋糕" } \``` \------------------------------ Q: 我今天想去打球 \> Entering new MultiPromptChain chain... None: {'input': '我今天想去打球'} \> Finished chain. A: 那聽起來很棒!你打什麼球呢?