<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Langchain使用 | 模型、提示和解析器、存儲(chǔ)

          共 30090字,需瀏覽 61分鐘

           ·

          2024-04-24 08:17

          零、LangChain介紹

          • 為各種不同基礎(chǔ)模型提供統(tǒng)一接口- 幫助管理提示的框架- 一套中心化接口,用于處理長期記憶(參見Memory)、外部數(shù)據(jù)(參見Indexes)、其他 LLM(參見Chains)以及 LLM 無法處理的任務(wù)的其他代理(例如,計(jì)算或搜索)。

          總的來說,有六大核心模塊:

          • Models:從不同的 LLM 和嵌入模型中進(jìn)行選擇

          • Prompts:管理 LLM 輸入

          • Chains:將 LLM 與其他組件相結(jié)合

          • Indexes:訪問外部數(shù)據(jù)

          • Memory:記住以前的對話

          • Agents:代理涉及 LLM 做出行動(dòng)決策、執(zhí)行該行動(dòng)、查看一個(gè)觀察結(jié)果,并重復(fù)該過程直到完成。LangChain 提供了一個(gè)標(biāo)準(zhǔn)的代理接口,

          一系列可供選擇的代理,以及端到端代理的示例。

          一、模型、提示和解析器

          1. 提示

          # 讓模型用指定語氣進(jìn)行回答
          def get_completion(prompt, model="gpt-3.5-turbo"):
              
              messages = [{<!-- -->"role""user""content": prompt}]
              
              response = openai.ChatCompletion.create(
                  model=model,
                  messages=messages,
                  temperature=0
              )
              return response.choices[0].message["content"]

          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!
          """


          # 美式英語 + 平靜、尊敬的語調(diào)
          style = """American English \
          in a calm and respectful tone
          """

          response = get_completion(prompt)

          # 如果用英文,要求模型根據(jù)給出的語調(diào)進(jìn)行轉(zhuǎn)化
          prompt = f"""Translate the text \
          that is delimited by triple backticks 
          into a style that is {<!-- -->style}.
          text: ```{<!-- -->customer_email}```
          """

          print(prompt)

          # 如果用中文, 要求模型根據(jù)給出的語調(diào)進(jìn)行轉(zhuǎn)化
          prompt = f"""把由三個(gè)反引號(hào)分隔的文本text\
          翻譯成一種{<!-- -->style}風(fēng)格。
          text: ```{<!-- -->customer_email}```
          """

          print(prompt)

          2. 使用langchain寫提示

          • 構(gòu)造langchain提示模板- 使用模板利用prompt_template.format_messages得到提示消息- 調(diào)用實(shí)例化的ChatOpenAI對象提取信息
          !pip install -q --upgrade langchain

          from langchain.chat_models import ChatOpenAI
          api_key = "..."
          chat = ChatOpenAI(temperature=0.0, openai_api_key = api_key)
          # 構(gòu)造模板
          template_string = """Translate the text \
          that is delimited by triple backticks \
          into a style that is {style}. \
          text: ```{text}```
          """

          # 中文
          template_string = """把由三個(gè)反引號(hào)分隔的文本text\
          翻譯成一種{style}風(fēng)格。\
          text: ```{text}```
          """

          # 需要安裝最新版的 LangChain
          from langchain.prompts import ChatPromptTemplate
          prompt_template = ChatPromptTemplate.from_template(template_string)
          # prompt_template.messages[0].prompt

          # prompt_template.messages[0].prompt.input_variables
          # ['style', 'text']

          langchain提示模版prompt_template需要兩個(gè)輸入變量: styletext。 這里分別對應(yīng)

          • customer_style: 我們想要的顧客郵件風(fēng)格- customer_email: 顧客的原始郵件文本。- 對于給定的customer_stylecustomer_email, 我們可以使用提示模版prompt_templateformat_messages方法生成想要的客戶消息customer_messages
          customer_messages = prompt_template.format_messages(
                              style=customer_style,
                              text=customer_email)
          customer_response = chat(customer_messages)
          customer_response.content # str類型

          其他提示模板舉例:

              prompt = """ 你的任務(wù)是判斷學(xué)生的解決方案是正確的還是不正確的

              要解決該問題,請執(zhí)行以下操作:
               - 首先,制定自己的問題解決方案
               - 然后將您的解決方案與學(xué)生的解決方案進(jìn)行比較
               并評估學(xué)生的解決方案是否正確。
              ...
              使用下面的格式:

              問題:

          問題文本

          學(xué)生的解決方案:

          學(xué)生的解決方案文本

          實(shí)際解決方案:

          ... 制定解決方案的步驟以及您的解決方案請參見此處

          學(xué)生的解決方案和實(shí)際解決方案是否相同 \
          只計(jì)算:

          是或者不是

          學(xué)生的成績

          正確或者不正確

          在建立大模型應(yīng)用時(shí),通常希望模型的輸出為給定的格式,比如在輸出使用特定的關(guān)鍵詞來讓輸出結(jié)構(gòu)化。 下面為一個(gè)使用大模型進(jìn)行鏈?zhǔn)剿伎纪评砝?,對于問題:What is the elevation range for the area that the eastern sector of the Colorado orogeny extends into?, 通過使用LangChain庫函數(shù),輸出采用"Thought"(思考)、“Action”(行動(dòng))、“Observation”(觀察)作為鏈?zhǔn)剿伎纪评淼年P(guān)鍵詞,讓輸出結(jié)構(gòu)化。在中,可以查看使用LangChain和OpenAI進(jìn)行鏈?zhǔn)剿伎纪评淼牧硪粋€(gè)代碼實(shí)例。

          """
          Thought: I need to search Colorado orogeny, find the area that the eastern sector of the Colorado orogeny extends into, then find the elevation range of the area.
          Action: Search[Colorado orogeny]
          Observation: The Colorado orogeny was an episode of mountain building (an orogeny) in Colorado and surrounding areas.

          Thought: It does not mention the eastern sector. So I need to look up eastern sector.
          Action: Lookup[eastern sector]
          Observation: (Result 1 / 1) The eastern sector extends into the High Plains and is called the Central Plains orogeny.

          Thought: The eastern sector of Colorado orogeny extends into the High Plains. So I need to search High Plains and find its elevation range.
          Action: Search[High Plains]
          Observation: High Plains refers to one of two distinct land regions

          Thought: I need to instead search High Plains (United States).
          Action: Search[High Plains (United States)]
          Observation: The High Plains are a subregion of the Great Plains. From east to west, the High Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130 m).[3]

          Thought: High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer is 1,800 to 7,000 ft.
          Action: Finish[1,800 to 7,000 ft]

          """


          """
          想法:我需要搜索科羅拉多造山帶,找到科羅拉多造山帶東段延伸到的區(qū)域,然后找到該區(qū)域的高程范圍。
          行動(dòng):搜索[科羅拉多造山運(yùn)動(dòng)]
          觀察:科羅拉多造山運(yùn)動(dòng)是科羅拉多州及周邊地區(qū)造山運(yùn)動(dòng)(造山運(yùn)動(dòng))的一次事件。

          想法:它沒有提到東區(qū)。 所以我需要查找東區(qū)。
          行動(dòng):查找[東區(qū)]
          觀察:(結(jié)果1 / 1)東段延伸至高原,稱為中原造山運(yùn)動(dòng)。

          想法:科羅拉多造山運(yùn)動(dòng)的東段延伸至高原。 所以我需要搜索高原并找到它的海拔范圍。
          行動(dòng):搜索[高地平原]
          觀察:高原是指兩個(gè)不同的陸地區(qū)域之一

          想法:我需要搜索高地平原(美國)。
          行動(dòng):搜索[高地平原(美國)]
          觀察:高地平原是大平原的一個(gè)分區(qū)。 從東到西,高原的海拔從 1,800 英尺左右上升到 7,000 英尺(550 到 2,130 米)。[3]

          想法:高原的海拔從大約 1,800 英尺上升到 7,000 英尺,所以答案是 1,800 到 7,000 英尺。
          動(dòng)作:完成[1,800 至 7,000 英尺]

          "
          ""

          3. 輸出解析器

          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}
          "
          ""

          使用Langchain輸出解析器:

          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}
          """


          prompt = ChatPromptTemplate.from_template(template=review_template_2)
          # 構(gòu)造輸出解析器
          from langchain.output_parsers import ResponseSchema
          from langchain.output_parsers import StructuredOutputParser

          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]
          output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
          format_instructions = output_parser.get_format_instructions()
          print(format_instructions)
          # 利用模板得到提示消息
          messages = prompt.format_messages(text=customer_review, format_instructions=format_instructions)
          # 調(diào)用chat模型得到結(jié)果
          response = chat(messages)
          print(response.content)
          # 使用輸出解析器解析輸出
          output_dict = output_parser.parse(response.content)
          output_dict
          # {'gift': False, 'delivery_days': '2', 'price_value': '它比其他吹葉機(jī)稍微貴一點(diǎn)'}
          # 這時(shí)就是dict,可以用get(key)
          output_dict.get('delivery_days')

          中文版本:

          # 中文
          review_template = """\
          對于以下文本,請從中提取以下信息:

          禮物:該商品是作為禮物送給別人的嗎? \
          如果是,則回答 是的;如果否或未知,則回答 不是。

          交貨天數(shù):產(chǎn)品需要多少天\
          到達(dá)? 如果沒有找到該信息,則輸出-1。

          價(jià)錢:提取有關(guān)價(jià)值或價(jià)格的任何句子,\
          并將它們輸出為逗號(hào)分隔的 Python 列表。

          使用以下鍵將輸出格式化為 JSON:
          禮物
          交貨天數(shù)
          價(jià)錢

          文本: {text}
          """


          # 中文
          review_template_2 = """\
          對于以下文本,請從中提取以下信息::

          禮物:該商品是作為禮物送給別人的嗎?
          如果是,則回答 是的;如果否或未知,則回答 不是。

          交貨天數(shù):產(chǎn)品到達(dá)需要多少天? 如果沒有找到該信息,則輸出-1。

          價(jià)錢:提取有關(guān)價(jià)值或價(jià)格的任何句子,并將它們輸出為逗號(hào)分隔的 Python 列表。

          文本: {text}

          {format_instructions}
          """


          # 中文
          from langchain.output_parsers import ResponseSchema
          from langchain.output_parsers import StructuredOutputParser

          gift_schema = ResponseSchema(name="禮物",
                                       description="這件物品是作為禮物送給別人的嗎?\
                                      如果是,則回答 是的,\
                                      如果否或未知,則回答 不是。"
          )

          delivery_days_schema = ResponseSchema(name="交貨天數(shù)",
                                                description="產(chǎn)品需要多少天才能到達(dá)?\
                                                如果沒有找到該信息,則輸出-1。"
          )

          price_value_schema = ResponseSchema(name="價(jià)錢",
                                              description="提取有關(guān)價(jià)值或價(jià)格的任何句子,\
                                              并將它們輸出為逗號(hào)分隔的 Python 列表"
          )


          response_schemas = [gift_schema, 
                              delivery_days_schema,
                              price_value_schema]
          output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
          format_instructions = output_parser.get_format_instructions()
          print(format_instructions)

          # 結(jié)果如下
          The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "\`\`\`json" and "\`\`\`":

          ```json
          {<!-- -->
           "禮物": string  // 這件物品是作為禮物送給別人的嗎?                            如果是,則回答 是的,                            如果否或未知,則回答 不是。
           "交貨天數(shù)": string  // 產(chǎn)品需要多少天才能到達(dá)?                                      如果沒有找到該信息,則輸出-1。
           "價(jià)錢": string  // 提取有關(guān)價(jià)值或價(jià)格的任何句子,                                    并將它們輸出為逗號(hào)分隔的 Python 列表
          }

          4. 鏈?zhǔn)剿伎纪评?ReAct)

          !pip install -q wikipedia
          from langchain.docstore.wikipedia import Wikipedia
          from langchain.llms import OpenAI
          from langchain.agents import initialize_agent, Tool, AgentExecutor
          from langchain.agents.react.base import DocstoreExplorer

          docstore=DocstoreExplorer(Wikipedia())
          tools = [
            Tool(
              name="Search",
              func=docstore.search,
              description="Search for a term in the docstore.",
            ),
            Tool(
              name="Lookup",
              func=docstore.lookup,
              description="Lookup a term in the docstore.",
            )
          ]

          # 使用大語言模型
          llm = OpenAI(
            model_name="gpt-3.5-turbo",
            temperature=0,
            openai_api_key = api_key
          )

          # 初始化ReAct代理
          react = initialize_agent(tools, llm, agent="react-docstore", verbose=True)
          agent_executor = AgentExecutor.from_agent_and_tools(
            agent=react.agent,
            tools=tools,
            verbose=True,
          )


          question = "Author David Chanoff has collaborated with a U.S. Navy admiral who served as the ambassador to the United Kingdom under which President?"
          agent_executor.run(question) 

          二、存儲(chǔ)

          1. 對話緩存存儲(chǔ)

          dotenv模塊使用解析:

          • 安裝方式:pip install python-dotenv- load_dotenv()函數(shù)用于加載環(huán)境變量,- find_dotenv()函數(shù)用于尋找并定位.env文件的路徑- 接下來的代碼 _ = load_dotenv(find_dotenv()) ,通過find_dotenv()函數(shù)找到.env文件的路徑,并將其作為參數(shù)傳遞給load_dotenv()函數(shù)。load_dotenv()函數(shù)會(huì)讀取該.env文件,并將其中的環(huán)境變量加載到當(dāng)前的運(yùn)行環(huán)境中
          import os
          import warnings
          warnings.filterwarnings('ignore')
          # 讀取本地的.env文件,并將其中的環(huán)境變量加載到代碼的運(yùn)行環(huán)境中,以便在代碼中可以直接使用這些環(huán)境變量
          from dotenv import load_dotenv, find_dotenv
          _ = load_dotenv(find_dotenv()) 
          from langchain.chat_models import ChatOpenAI
          from langchain.chains import ConversationChain
          from langchain.memory import ConversationBufferMemory

          OPENAI_API_KEY = "..."     
          llm = ChatOpenAI(temperature=0.0,openai_api_key=OPENAI_API_KEY) 
          # memory.buffer存儲(chǔ)所有的對話內(nèi)容, memory.load_memory_variables({})也可以
          memory = ConversationBufferMemory()
          # 新建一個(gè)對話鏈(關(guān)于鏈后面會(huì)提到更多的細(xì)節(jié))
          conversation = ConversationChain(   
              llm=llm, 
              memory = memory,
              verbose=True   #查看Langchain實(shí)際上在做什么,設(shè)為FALSE的話只給出回答,看到不到下面綠色的內(nèi)容
          )
          conversation.predict(input="你好, 我叫山頂夕景")
          conversation.predict(input="What is 1+1?")
          conversation.predict(input="What is my name?"# 還記得名字


          注意:

          • ConversationChainverbose參數(shù),是查看Langchain實(shí)際上在做什么,設(shè)為FALSE的話只給出回答,看到不到下面綠色的內(nèi)容(prompt format + 完整對話內(nèi)容)。- 上面的memory.buffer存儲(chǔ)所有的對話內(nèi)容, memory.load_memory_variables({})也可以- 添加指定的輸入輸出內(nèi)容到記憶緩存區(qū)
          memory = ConversationBufferMemory()  #新建一個(gè)空的對話緩存記憶
          memory.save_context({<!-- -->"input""Hi"},    #向緩存區(qū)添加指定對話的輸入輸出
                              {<!-- -->"output""What's up"})
          memory.load_memory_variables({<!-- -->})  #再次加載記憶變量, 內(nèi)容不變

          2. 對話緩存窗口存儲(chǔ)

          from langchain.memory import ConversationBufferWindowMemory
          memory = ConversationBufferWindowMemory(k=1)     
          # k=1表明只保留一個(gè)對話記憶, 即上一輪信息

          3. 對話token緩存存儲(chǔ)

          !pip install tiktoken    
          # 限制token數(shù)量, 用到之前定義的llm對象
          memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=30)
          memory.save_context({<!-- -->"input""AI is what?!"},
                              {<!-- -->"output""Amazing!"})
          memory.save_context({<!-- -->"input""Backpropagation is what?"},
                              {<!-- -->"output""Beautiful!"})
          memory.save_context({<!-- -->"input""Chatbots are what?"}, 
                              {<!-- -->"output""Charming!"})       

          ChatGPT使用一種基于字節(jié)對編碼(Byte Pair Encoding,BPE)的方法來進(jìn)行tokenization(將輸入文本拆分為token)。 BPE是一種常見的tokenization技術(shù),它將輸入文本分割成較小的子詞單元。

          OpenAI在其官方GitHub上公開了一個(gè)最新的開源Python庫:tiktoken,這個(gè)庫主要是用來計(jì)算tokens數(shù)量的。相比較Hugging Face的tokenizer,其速度提升了好幾倍

          具體token計(jì)算方式,特別是漢字和英文單詞的token區(qū)別,參考

          4. 對話摘要緩存存儲(chǔ)

          • 這里不用前面兩種的窗口輪次存儲(chǔ)或token限制緩存,而是讓大模型先對過去的歷史信息做個(gè)概述,不同的是用ConversationSummaryBufferMemory實(shí)例化memory對象
          from langchain.memory import ConversationSummaryBufferMemory
          from langchain.chat_models import ChatOpenAI
          from langchain.chains import ConversationChain
          memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100

          三、利用Langchain導(dǎo)入ChatGLM6b推理

          • 在 CPU 上運(yùn)行時(shí),會(huì)根據(jù)硬件自動(dòng)編譯 CPU Kernel ,請確保已安裝 GCC 和 OpenMP (Linux一般已安裝,對于Windows則需手動(dòng)安裝),以獲得最佳并行計(jì)算能力,所以最好用cuda GPU加速推理。

          • 如下栗子,繼承langchain.llms.base.LLM的模型ChatGLM2類,重寫_call類方法進(jìn)行模型推理:首先對user輸入的prompt進(jìn)行編碼,將編碼結(jié)果和self.history歷史對話內(nèi)容一起傳參給模型響應(yīng),將響應(yīng)結(jié)果加入歷史記錄self.history中。

          • @property裝飾器將_llm_type方法轉(zhuǎn)為【只讀屬性】,即可以被類訪問,而不需要實(shí)例的方法來訪問(比如model._llm_type == ChatGLM2的結(jié)果為true)。對其他具體感興趣的讀者可以參考父類LLM代碼。

          from langchain.llms.base import LLM
          from langchain.llms.utils import enforce_stop_tokens
          from transformers import AutoTokenizer, AutoModel
          from typing import List, Optional


          class ChatGLM2(LLM):
              max_token: int = 4096
              temperature: float = 0.8
              top_p = 0.9
              tokenizer: object = None
              model: object = None
              history = []

              def __init__(self):
                  super().__init__()

              @property
              def _llm_type(self) -&gtstr:
                  return "ChatGLM2"

              # 定義load_model方法,進(jìn)行模型的加載
              def load_model(self, model_path = None):
                  self.tokenizer = AutoTokenizer.from_pretrained(model_path,trust_remote_code=True)
                  self.model = AutoModel.from_pretrained(model_path, trust_remote_code=True).float()

              # 實(shí)現(xiàn)_call方法,進(jìn)行模型的推理
              def _call(self,prompt:str, stop: Optional[List[str]] = None) -&gtstr:
                  response, _ = self.model.chat(
                              self.tokenizer,
                              prompt,
                              history=self.history,
                              max_length=self.max_token,
                              temperature=self.temperature,
                              top_p=self.top_p)
                  if stop is not None:
                      response = enforce_stop_tokens(response, stop)
                  self.history = self.history + [[None, response]]
                  return response

          if __name__ == "__main__":
              llm=ChatGLM2()
              model_path = "/Users/andy/Desktop/LLM/model/chatglm-6b-int4"
              llm.load_model(model_path)
              print(llm._call("如何打好羽毛球?"))

          可以用以下一些prompt測試模型回答質(zhì)量:

          非洲土地肥沃,為什么很多非洲人寧可挨餓也不種地?

          水一百度會(huì)開,下一句是什么?

          四、其他類似工具:guidance

          同時(shí)也包含使用 {<!-- -->{#select}}...{<!-- -->{or}}...{<!-- -->{/select}} 命令進(jìn)行控制流的選擇:

          import guidance

          # set the default language model used to execute guidance programs
          guidance.llm = guidance.llms.OpenAI("text-davinci-003")

          # define the few shot examples
          examples = [
              {<!-- -->'input''I wrote about shakespeare',
              'entities': [{<!-- -->'entity''I''time''present'}, {<!-- -->'entity''Shakespeare''time''16th century'}],
              'reasoning''I can write about Shakespeare because he lived in the past with respect to me.',
              'answer''No'},
              {<!-- -->'input''Shakespeare wrote about me',
              'entities': [{<!-- -->'entity''Shakespeare''time''16th century'}, {<!-- -->'entity''I''time''present'}],
              'reasoning''Shakespeare cannot have written about me, because he died before I was born',
              'answer''Yes'}
          ]

          # define the guidance program
          structure_program = guidance(
          '''Given a sentence tell me whether it contains an anachronism (i.e. whether it could have happened or not based on the time periods associated with the entities).
          ----

          {<!-- -->{~! display the few-shot examples ~}}
          {<!-- -->{~#each examples}}
          Sentence: {<!-- -->{this.input}}
          Entities and dates:{<!-- -->{#each this.entities}}
          {<!-- -->{this.entity}}: {<!-- -->{this.time}}{<!-- -->{/each}}
          Reasoning: {<!-- -->{this.reasoning}}
          Anachronism: {<!-- -->{this.answer}}
          ---
          {<!-- -->{~/each}}

          {<!-- -->{~! place the real question at the end }}
          Sentence: {<!-- -->{input}}
          Entities and dates:
          {<!-- -->{gen "entities"}}
          Reasoning:{<!-- -->{gen "reasoning"}}
          Anachronism:{<!-- -->{#select "answer"}} Yes{<!-- -->{or}} No{<!-- -->{/select}}'''
          )

          # execute the program
          out = structure_program(
              examples=examples,
              input='The T-rex bit my dog'
          )


          瀏覽 56
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人国产精品秘 欧美高清 | 国产精品肏屄视频 | 特黄AAAAAAAAA视频免费 | 波多野结衣无码AⅤ一区t二区三区 | 黑人在线 |