精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

LangGraph實戰:從零分階打造人工智能航空客服助手 精華

發布于 2024-11-13 14:40
瀏覽
0收藏

客服助手機器人能夠幫助團隊更高效地處理日常咨詢,但要打造一個能夠穩定應對各種任務且不會讓用戶感到煩惱的機器人并非易事。

完成本教程后,你不僅會擁有一個功能完備的機器人,還將深入理解LangGraph的核心理念和架構設計。這些知識將幫助你在其他人工智能項目中運用相似的設計模式。

由于內容較多,本文將由淺入深,分四個階段進行講解,每個階段都將打造出一個具備以上描述所有能力的機器人。但受限于LLM的能力,初期階段的機器人的運行可能存在各類問題,但都將在后續階段得到解決。

你最終完成的聊天機器人將類似于以下示意圖:

LangGraph實戰:從零分階打造人工智能航空客服助手-AI.x社區

最終示意圖

現在,讓我們開啟這第一階段段的學習之旅吧!

準備工作

在開始之前,我們需要搭建好環境。本教程將安裝一些必要的先決條件,包括下載測試用的數據庫,并定義一些在后續各部分中會用到的工具。

我們會使用 Claude 作為語言模型(LLM),并創建一些定制化的工具。這些工具大多數會連接到本地的 SQLite 數據庫,無需額外依賴。此外,我們還會通過 Tavily 為代理提供網絡搜索功能。

%%capture --no-stderr
% pip install -U langgraph langchain-community langchain-anthropic tavily-python pandas

數據庫初始化

接下來,執行下面的腳本來獲取我們為這個教程準備的 SQLite 數據庫,并更新它以反映當前的數據狀態。具體細節不是重點。

import os
import requests
import sqlite3
import pandas as pd
import shutil

# 下載數據庫文件
db_url = "https://storage.googleapis.com/benchmarks-artifacts/travel-db/travel2.sqlite"
local_file = "travel2.sqlite"
backup_file = "travel2.backup.sqlite"
overwrite = False
if not os.path.exists(local_file) or overwrite:
    response = requests.get(db_url)
    response.raise_for_status()  # 確保請求成功
    with open(local_file, "wb") as file:
        file.write(response.content)

# 創建數據庫備份,以便在每個教程部分開始時重置數據庫狀態
shutil.copy(local_file, backup_file)

# 將航班數據更新為當前時間,以適應我們的教程
conn = sqlite3.connect(local_file)
cursor = conn.cursor()

# 讀取數據庫中的所有表
tables = pd.read_sql(
    "SELECT name FROM sqlite_master WHERE type='table';", conn
).name.tolist()
tdf = {}
for table_name in tables:
    tdf[table_name] = pd.read_sql(f"SELECT * from {table_name}", conn)

# 找到最早的出發時間,并計算時間差
example_time = pd.to_datetime(
    tdf["flights"]["actual_departure"].replace("\\N", pd.NaT)
).max()
current_time = pd.to_datetime("now").tz_localize(example_time.tz)
time_diff = current_time - example_time

# 更新預訂日期和航班時間
for column in ["book_date", "scheduled_departure", "scheduled_arrival", "actual_departure", "actual_arrival"]:
    tdf["flights"][column] = pd.to_datetime(
        tdf["flights"][column].replace("\\N", pd.NaT)
    ) + time_diff

# 將更新后的數據寫回數據庫
for table_name, df in tdf.items():
    df.to_sql(table_name, conn, if_exists="replace", index=False)
conn.commit()
conn.close()

# 在本教程中,我們將使用這個本地文件作為數據庫
db = local_file

工具定義

現在,我們來定義一些工具,以便助手可以搜索航空公司的政策手冊,以及搜索和管理航班、酒店、租車和遠足活動的預訂。這些工具將在教程的各個部分中重復使用,具體的實現細節不是關鍵。

查詢公司政策

助手需要檢索政策信息來回答用戶的問題。請注意,這些政策的實施還需要在工具或 API 中進行,因為語言模型可能會忽略這些信息。以下工具受限于篇幅將僅提供定義及描述,詳細代碼[1]可在github上獲取。

import re
import numpy as np
import openai
from langchain_core.tools import tool


@tool
def lookup_policy(query):
    """查詢公司政策,以確定某些選項是否允許。"""

航班管理

定義一個工具來獲取用戶的航班信息,然后定義一些工具來搜索航班和管理用戶的預訂信息,這些信息存儲在 SQL 數據庫中。

我們使用 ensure_config? 來通過配置參數傳遞 passenger_id。語言模型不需要顯式提供這些信息,它們會在圖的每次調用中提供,以確保每個用戶無法訪問其他乘客的預訂信息。

from langchain_core.runnables import ensure_config
from typing import Optional
import sqlite3
import pytz
from datetime import datetime, timedelta, date

@tool
def fetch_user_flight_information():
    """獲取用戶的所有機票信息,包括航班詳情和座位分配。"""

@tool
def search_flights(
    departure_airport=None,
    arrival_airport=None,
    start_time=None,
    end_time=None,
    limit=20,
):
    """根據出發機場、到達機場和出發時間范圍來搜索航班。"""

@tool
def update_ticket_to_new_flight(ticket_no, new_flight_id):
    """將用戶的機票更新到一個新的有效航班上。"""

@tool
def cancel_ticket(ticket_no):
    """取消用戶的機票,并從數據庫中移除。"""

租車服務

用戶預訂了航班后,可能需要租車服務。定義一些工具,讓用戶能夠在目的地搜索和預訂汽車。

from typing import Optional, Union
from datetime import datetime, date

@tool
def search_car_rentals(
    locatinotallow=None,
    name=None,
    price_tier=None,
    start_date=None,
    end_date=None,
):
    """
    根據位置、公司名稱、價格等級、開始日期和結束日期來搜索租車服務。

    參數:
        location (Optional[str]): 租車服務的位置。
        name (Optional[str]): 租車公司的名稱。
        price_tier (Optional[str]): 租車的價格等級。
        start_date (Optional[Union[datetime, date]]): 租車的開始日期。
        end_date (Optional[Union[datetime, date]]): 租車的結束日期。

    返回:
        list[dict]: 匹配搜索條件的租車服務列表。
    """

@tool
def book_car_rental(rental_id):
    """
    通過租車ID來預訂租車服務。

    參數:
        rental_id (int): 要預訂的租車服務的ID。

    返回:
        str: 預訂成功與否的消息。
    """

@tool
def update_car_rental(
    rental_id,
    start_date=None,
    end_date=None,
):
    """
    通過租車ID來更新租車服務的開始和結束日期。

    參數:
        rental_id (int): 要更新的租車服務的ID。
        start_date (Optional[Union[datetime, date]]): 新的租車開始日期。
        end_date (Optional[Union[datetime, date]]): 新的租車結束日期。

    返回:
        str: 更新成功與否的消息。
    """

@tool
def cancel_car_rental(rental_id):
    """
    通過租車ID來取消租車服務。

    參數:
        rental_id (int): 要取消的租車服務的ID。

    返回:
        str: 取消成功與否的消息。
    """

酒店預訂

用戶需要住宿,因此定義一些工具來搜索和管理酒店預訂。

@tool
def search_hotels(
    locatinotallow=None,
    name=None,
    price_tier=None,
    checkin_date=None,
    checkout_date=None,
):
    """
    根據位置、名稱、價格等級、入住日期和退房日期來搜索酒店。

    參數:
        location (Optional[str]): 酒店的位置。
        name (Optional[str]): 酒店的名稱。
        price_tier (Optional[str]): 酒店的價格等級。
        checkin_date
        
        # 入住日期和退房日期,用于搜索酒店
        checkin_date (Optional[Union[datetime, date]]): 酒店的入住日期。
        checkout_date (Optional[Union[datetime, date]]): 酒店的退房日期。

    返回:
        list[dict]: 符合搜索條件的酒店列表。
    """
    
@tool
def book_hotel(hotel_id):
    """
    通過酒店ID進行預訂。

    參數:
        hotel_id (int): 要預訂的酒店的ID。

    返回:
        str: 預訂成功與否的消息。
    """
    
@tool
def update_hotel(
    hotel_id,
    checkin_date=None,
    checkout_date=None,
):
    """
    通過酒店ID更新酒店預訂的入住和退房日期。

    參數:
        hotel_id (int): 要更新預訂的酒店的ID。
        checkin_date (Optional[Union[datetime, date]]): 新的入住日期。
        checkout_date (Optional[Union[datetime, date]]): 新的退房日期。

    返回:
        str: 更新成功與否的消息。
    """
    
@tool
def cancel_hotel(hotel_id):
    """
    通過酒店ID取消酒店預訂。

    參數:
        hotel_id (int): 要取消預訂的酒店的ID。

    返回:
        str: 取消成功與否的消息。
    """

遠足活動

最后,定義一些工具,讓用戶在到達目的地后搜索活動并進行預訂。

@tool
def search_trip_recommendations(
    locatinotallow=None,
    name=None,
    keywords=None,
):
    """
    根據位置、名稱和關鍵詞搜索旅行推薦。

    參數:
        location (Optional[str]): 旅行推薦的地點。
        name (Optional[str]): 旅行推薦的名字。
        keywords (Optional[str]): 與旅行推薦相關的關鍵詞。

    返回:
        list[dict]: 符合搜索條件的旅行推薦列表。
    """
    
@tool
def book_excursion(recommendation_id):
    """
    通過推薦ID預訂遠足活動。

    參數:
        recommendation_id (int): 要預訂的旅行推薦的ID。

    返回:
        str: 預訂成功與否的消息。
    """
    
@tool
def update_excursion(recommendation_id, details):
    """
    通過推薦ID更新旅行推薦的細節。

    參數:
        recommendation_id (int): 要更新的旅行推薦的ID。
        details (str): 旅行推薦的新細節。

    返回:
        str: 更新成功與否的消息。
    """
    
@tool
def cancel_excursion(recommendation_id):
    """
    通過推薦ID取消旅行推薦。

    參數:
        recommendation_id (int): 要取消的旅行推薦的ID。

    返回:
        str: 取消成功與否的消息。
    """

實用工具

定義一些輔助函數,以便在調試過程中美化圖形中的消息顯示,并為工具節點添加錯誤處理(通過將錯誤添加到聊天記錄中)。

from langgraph.prebuilt import ToolNode
from langchain_core.runnables import RunnableLambda

def handle_tool_error(state):
    error = state.get("error")
    tool_calls = state["messages"][-1].tool_calls
    return {
        "messages": [
            ToolMessage(
                cnotallow=f"錯誤: {repr(error)}\n請修正你的錯誤。",
                tool_call_id=tc["id"],
            )
            for tc in tool_calls
        ]
    }

def create_tool_node_with_fallback(tools):
    return ToolNode(tools).with_fallbacks(
        [RunnableLambda(handle_tool_error)], exception_key="error"
    )

def _print_event(event, _printed, max_length=1500):
    current_state = event.get("dialog_state")
    if current_state:
        print(f"當前狀態: ", current_state[-1])
    message = event.get("messages")
    if message:
        if isinstance(message, list):
            message = message[-1]
        if message.id not in _printed:
            msg_repr = message.pretty_repr(html=True)
            if len(msg_repr) > max_length:
                msg_repr = msg_repr[:max_length] + " ... (內容已截斷)"
            print(msg_repr)
            _printed.add(message.id)

第一部分:零樣本代理

在構建任何系統時,最佳實踐是從最簡單的可行方案開始,并通過使用類似LangSmith這樣的評估工具來測試其有效性。在條件相同的情況下,我們傾向于選擇簡單且可擴展的解決方案,而不是復雜的方案。然而,單一圖譜方法存在一些限制,比如機器人可能在未經用戶確認的情況下執行不希望的操作,處理復雜查詢時可能遇到困難,或者在回答時缺乏針對性。這些問題我們會在后續進行改進。 在這部分,我們將定義一個簡單的零樣本代理作為用戶的助手,并將所有工具賦予給它。我們的目標是引導它明智地使用這些工具來幫助用戶。 我們的簡單兩節點圖如下所示:

LangGraph實戰:從零分階打造人工智能航空客服助手-AI.x社區

第一部分圖解

首先,我們定義狀態。

狀態

我們將StateGraph的狀態定義為一個包含消息列表的類型化字典。這些消息構成了聊天的記錄,也就是我們簡單助手所需要的全部狀態信息。

from langgraph.graph.message import add_messages, AnyMessage
from typing_extensions import TypedDict
from typing import Annotated


class State(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]

代理

然后,我們定義助手函數。這個函數接收圖的狀態,將其格式化為提示,然后調用一個大型語言模型(LLM)來預測最佳的響應。

from langchain_core.runnables import Runnable, RunnableConfig
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_anthropic import ChatAnthropic
from langchain_core.prompts import ChatPromptTemplate


class Assistant:
    def __init__(self, runnable: Runnable):
        self.runnable = runnable

    def __call__(self, state: State, config: RunnableConfig):
        while True:
            passenger_id = config.get("passenger_id", None)
            state = {**state, "user_info": passenger_id}
            result = self.runnable.invoke(state)
            # 如果大型語言模型返回了一個空響應,我們將重新提示它給出一個實際的響應。
            if (
                not result.content
                or isinstance(result.content, list)
                and not result.content[0].get("text")
            ):
                messages = state["messages"] + [("user", "請給出一個真實的輸出。")]
                state = {**state, "messages": messages}
            else:
                break
        return {"messages": result}


# Haiku模型更快、成本更低,但準確性稍差
# llm = ChatAnthropic(model="claude-3-haiku-20240307")
llm = ChatAnthropic(model="claude-3-sonnet-20240229", temperature=1)

primary_assistant_prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "你是一個為瑞士航空提供幫助的客戶支持助手。"
            "使用提供的工具來搜索航班、公司政策和其他信息以幫助回答用戶的查詢。"
            "在搜索時,要有毅力。如果第一次搜索沒有結果,就擴大你的查詢范圍。"
            "如果搜索結果為空,不要放棄,先擴大搜索范圍。"
            "\n\n當前用戶:\n<User>\n{user_info}\n</User>"
            "\n當前時間:{time}。",
        ),
        ("placeholder", "{messages}"),
    ]
).partial(time=datetime.now())

part_1_tools = [
    TavilySearchResults(max_results=1),
    fetch_user_flight_information,
    search_flights,
    lookup_policy,
    update_ticket_to_new_flight,
    cancel_ticket,
    search_car_rentals,
    book_car_rental,
    update_car_rental,
    cancel_car_rental,
    search_hotels,
    book_hotel,
    update_hotel,
    cancel_hotel,
    search_trip_recommendations,
    book_excursion,
    update_excursion,
    cancel_excursion,
]
part_1_assistant_runnable = primary_assistant_prompt | llm.bind_tools(part_1_tools)

定義圖

現在,我們來創建圖。這張圖是我們這部分的最終助手。

from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import tools_condition, ToolNode

builder = StateGraph(State)


# 定義節點:這些節點執行具體的工作
builder.add_node("assistant", Assistant(part_1_assistant_runnable))
builder.add_node("action", create_tool_node_with_fallback(part_1_tools))
# 定義邊:這些邊決定了控制流程如何移動
builder.set_entry_point("assistant")
builder.add_conditional_edges(
    "assistant",
    tools_condition,
    # "action"調用我們的工具之一。END導致圖終止(并向用戶做出響應)
    {"action": "action", END: END},
)
builder.add_edge("action", "assistant")

# 檢查點器允許圖保存其狀態
# 這是整個圖的完整記憶。
memory = SqliteSaver.from_conn_string(":memory:")
part_1_graph = builder.compile(checkpointer=memory)

from IPython.display import Image, display

try:
    display(Image(part_1_graph.get_graph(xray=True).draw_mermaid_png()))
except:
    # 這需要一些額外的依賴項,是可選的
    pass

LangGraph實戰:從零分階打造人工智能航空客服助手-AI.x社區

示例對話

現在,讓我們通過一系列對話示例來測試我們的聊天機器人。

import uuid
import shutil

# 假設這是用戶與助手之間可能發生的對話示例
tutorial_questions = [
    "你好,我的航班是什么時候?",
    "我可以把我的航班改簽到更早的時間嗎?我想今天晚些時候離開。",
    "那就把我的航班改簽到下周某個時間吧",
    "下一個可用的選項很好",
    "住宿和交通方面有什么建議?",
    "我想在為期一周的住宿中選擇一個經濟實惠的酒店(7天),并且我還想租一輛車。",
    "好的,你能為你推薦的酒店預訂嗎?聽起來不錯。",
    "是的,去預訂任何中等價位且有可用性的酒店。",
    "對于汽車,我有哪些選擇?",
    "太棒了,我們只選擇最便宜的選項。預訂7天。",
    "那么,你對我的旅行有什么建議?",
    "在我在那里的時候,有哪些活動是可用的?",
    "有趣 - 我喜歡博物館,有哪些選擇?",
    "好的,那就為我在那里的第二天預訂一個。",
]

# 使用備份文件以便我們可以從每個部分的原始位置重新啟動
shutil.copy(backup_file, db)
thread_id = str(uuid.uuid4())

config = {
    "configurable": {
        # passenger_id 在我們的航班工具中使用
        # 以獲取用戶的航班信息
        "passenger_id": "3442 587242",
        # 檢查點通過 thread_id 訪問
        "thread_id": thread_id,
    }
}


_printed = set()
for question in tutorial_questions:
    events = part_1_graph.stream(
        {"messages": ("user", question)}, config, stream_mode="values"
    )
    for event in events:
        _print_event(event, _printed)

第一部分回顧

我們的簡單助手表現得還不錯!它能夠合理地回答所有問題,快速地在上下文中做出回應,并成功地執行了我們所有的任務。你可以通過查看LangSmith的示例跟蹤[2]來更好地了解LLM在上述交互中是如何被提示的。

如果這是一個簡單的問答機器人,我們可能會對上述結果感到滿意。由于我們的客戶支持機器人是代表用戶采取行動,因此它的一些行為有點令人擔憂:

  1. 當我們專注于住宿時,助手預訂了一輛車,然后又不得不取消并稍后重新預訂:哎呀!在預訂之前,應該讓用戶有最終決定權,以避免不需要的預訂。
  2. 助手在尋找推薦方面遇到了困難。我們可以通過添加更多的詳細指令和使用工具的示例來改進這一點,但為每個工具都這樣做可能會導致提示過長,讓代理感到不知所措。
  3. 助手不得不進行明確的搜索才能獲取用戶的相關信息。我們可以通過立即獲取用戶的旅行詳細信息,讓助手能夠直接回應,從而節省大量時間。

在下一節中,我們將解決前兩個問題,期待你的持續關注!。

Reference

[1] 詳細代碼: https://github.com/langchain-ai/langgraph/blob/main/examples/customer-support/customer-support.ipynb

[2] LangSmith的示例跟蹤: https://smith.langchain.com/public/f9e77b80-80ec-4837-98a8-254415cb49a1/r/26146720-d3f9-44b6-9bb9-9158cde61f9d

本文轉載自 ??AI小智??,作者: AI小智

收藏
回復
舉報
回復
相關推薦
亚洲成av人片在线| 成人午夜激情片| 中文字幕日韩欧美| 999这里有精品| 日本在线观看大片免费视频| 懂色av中文字幕一区二区三区| 97视频在线观看成人| 女~淫辱の触手3d动漫| 欧美成人高清视频在线观看| 综合久久给合久久狠狠狠97色| 成人av网站观看| 好吊操这里只有精品| 精品国产一区二区三区小蝌蚪 | 国产亚洲精品女人久久久久久| 国产乱论精品| 欧美日韩美少妇| 日韩一级片免费视频| 九一国产在线| 国产激情一区二区三区四区| 久久免费国产视频| 国产精品69久久久久孕妇欧美| 亚洲一区二区三区在线免费 | 亚洲天堂视频在线播放| 亚洲欧美伊人| 在线亚洲午夜片av大片| 美女黄色一级视频| 成人黄色理论片| 日本高清不卡视频| 国产日本在线播放| 黄色网址在线免费播放| 久久久久亚洲综合| 欧美va视频| 婷婷午夜社区一区| 久久久精品天堂| 99精品国产高清一区二区| 日本黄色中文字幕| 99精品国产一区二区青青牛奶| x99av成人免费| 手机看片日韩av| 欧美电影在线观看完整版| 91精品国产综合久久蜜臀| 久久精品香蕉视频| 黄色在线观看www| 成人欧美一区二区三区黑人麻豆 | 久久亚洲精华国产精华液| 7777奇米亚洲综合久久 | 视频在线观看一区| 51视频国产精品一区二区| 男女性高潮免费网站| 日韩欧美午夜| 尤物精品国产第一福利三区| 国产精品无码一区二区三区免费 | 最新av电影网站| 欧美精品色图| 亚洲一区二区黄| 男生草女生视频| 蜜臀av免费一区二区三区| 亚洲成年人在线播放| 小日子的在线观看免费第8集| 少妇精品视频在线观看| 欧美日韩国产三级| gai在线观看免费高清| 久久91超碰青草在哪里看| 欧美午夜在线观看| 天天爽夜夜爽一区二区三区| 国产麻豆久久| 欧美日韩色一区| 91高清国产视频| 91精品国产色综合久久不卡粉嫩| 欧美系列日韩一区| 17c国产在线| 免费一区二区三区在线视频| 欧美一级欧美一级在线播放| 亚洲精品国产一区二区三区| 久久视频社区| 精品国产区一区| av2014天堂网| 久草成人在线| 国产亚洲精品日韩| 麻豆网址在线观看| 国产精品videosex极品| 欧美高清videos高潮hd| 日韩美女黄色片| 水野朝阳av一区二区三区| 国产精品免费一区二区三区都可以| 在线视频 91| 国产乱子伦视频一区二区三区 | 亚洲最好看的视频| 一区二区三区四区在线观看视频| 五月天免费网站| 欧美久久一级| 日本国产精品视频| 国产一区二区在线视频观看| 国产精品99久久久久| 精品亚洲欧美日韩| 日本免费中文字幕在线| 亚洲国产精品一区二区久久恐怖片| 久久精品视频16| 国产成人免费| 亚洲第一中文字幕| 国产一级淫片久久久片a级| 欧美另类专区| 热草久综合在线| 国产女主播福利| 91丨九色丨蝌蚪丨老版| 一本一本久久a久久精品综合妖精| av中文字幕在线观看| 精品成人乱色一区二区| 自拍偷拍一区二区三区四区| 波多野结衣一区二区三区免费视频| 亚洲偷熟乱区亚洲香蕉av| 欧美三级在线免费观看| 鲁大师影院一区二区三区| 91在线网站视频| 成人在线高清视频| 亚洲午夜精品在线| 亚洲欧美国产中文| 久久99国产成人小视频| 久久777国产线看观看精品| 国产精品午夜一区二区| 不卡av电影在线播放| 影音欧美亚洲| 桃花岛tv亚洲品质| 亚洲第一天堂无码专区| 在线观看亚洲网站| 免费xxxx性欧美18vr| 精品无码久久久久国产| 手机av在线播放| 欧美日韩一区二区在线观看视频 | 精品五月天堂| 久久在线精品视频| 在线观看国产成人| 国产三级久久久| 欧美 日本 亚洲| 成人三级av在线| 欧美激情xxxx性bbbb| 97人人爽人人爽人人爽| 国产精品美日韩| 成人一区二区三| 亚洲a级精品| 午夜精品一区二区三区在线视频| 国产特级aaaaaa大片| 中文字幕一区二区三区在线观看 | 日韩av在线电影| 国产成人综合自拍| 国产在线无码精品| 久久久久久爱| 欧美高清自拍一区| 国产黄色一区二区| 夜夜精品视频一区二区| 色男人天堂av| 91av精品| 91久久国产综合久久蜜月精品| 麻豆网在线观看| 欧美精品久久一区| 99鲁鲁精品一区二区三区| 久久国产精品第一页| 最新不卡av| 久久99精品久久久野外观看| 插插插亚洲综合网| 99久久精品无免国产免费| 亚洲人成人一区二区在线观看| 中文字幕第100页| 久久一区二区三区电影| 成人美女av在线直播| 在线免费av导航| 精品久久一区二区| av大片免费观看| 久久蜜桃av一区二区天堂| 亚洲爆乳无码专区| 日本电影一区二区| 91系列在线播放| 第四色日韩影片| 亚洲精品日韩欧美| 少妇又紧又色又爽又刺激视频 | 日韩精品电影网站| 国产美女久久| 久久99精品久久久久久噜噜| 色偷偷在线观看| 日韩欧美中文字幕在线观看| 中文字幕第20页| 激情欧美日韩一区二区| 国产精品久久久久久久乖乖| 尤物tv在线精品| 国产欧美精品一区二区三区介绍| a视频在线免费看| 日韩精品高清视频| 中文字幕在线播放av| 一区二区三区免费观看| 无码人妻aⅴ一区二区三区| 日本视频在线一区| 国产午夜精品视频一区二区三区| 精品久久97| 国产女精品视频网站免费| 免费不卡av| 伊人久久综合97精品| 国产高清免费观看| 色综合激情久久| 一起操在线播放| 2019国产精品| 五月天婷婷在线观看视频| 一区二区三区国产盗摄| 日日噜噜噜夜夜爽爽| 国产精品2023| 91精品美女在线| 在线毛片观看| 九色精品美女在线| 嫩草香蕉在线91一二三区| 亚洲国产中文字幕久久网| 夜夜爽8888| 日韩欧美视频一区二区三区| 国产精品三区在线观看| 久久女同精品一区二区| 亚洲AV成人精品| 久久国产日韩欧美精品| 国产又大又硬又粗| 国产精品va| 国产一区二区激情| 日韩福利影院| a级日韩大片| 成人免费自拍视频| 欧美与亚洲与日本直播| 国产69精品久久久久99| 成人在线观看免费网站| 亚洲人成在线一二| 天天干天天草天天射| 91精品国产综合久久久蜜臀粉嫩 | 你懂得在线视频| 国产精品一区二区在线观看网站| 热久久精品免费视频| 国产精品婷婷| 欧美精品自拍视频| 亚洲色图欧美| 中文精品一区二区三区| 欧美亚洲高清| 日本在线观看不卡| 香蕉久久夜色精品国产更新时间 | 欧美精品videosex性欧美| 老司机午夜在线| 色偷偷av一区二区三区乱| 久草视频视频在线播放| 国产丝袜精品第一页| 亚洲日本香蕉视频| 日韩精品中文字幕有码专区| 日韩一区免费视频| 亚洲经典中文字幕| 亚洲人妻一区二区| 精品一区电影国产| 邻家有女韩剧在线观看国语| 亚洲精品在线看| 日本电影一区二区在线观看| 亚洲九九九在线观看| 日韩av视屏| 亚洲精品资源美女情侣酒店| 天堂91在线| 亚洲毛片在线免费观看| 黄视频在线播放| 国产一区二区日韩| 97视频精彩视频在线观看| 最近2019年日本中文免费字幕 | 久久久久久久久电影| av日韩国产| 奇米4444一区二区三区| 精品123区| 亚洲精品免费一区二区三区| 欧美午夜网站| 含羞草久久爱69一区| 日韩影视高清在线观看| 日本不卡二区高清三区| 久久高清免费| 男人的天堂avav| 国产欧美亚洲一区| 少妇黄色一级片| 国产一二三精品| 久久久午夜精品福利内容| 久久老女人爱爱| 午夜激情福利电影| 一区二区三区在线免费观看| 影音先锋亚洲天堂| 欧美性生活大片视频| 国产模特av私拍大尺度| 欧美精品一区二区三区在线播放| 污污网站免费在线观看| 国产亚洲美女久久| 影音先锋在线视频| 91高清免费在线观看| 黄色成人在线观看网站| 国产欧美日韩亚洲精品| 99精品国产一区二区三区2021| 蜜桃av色综合| 68国产成人综合久久精品| 黄页网站大全在线观看| 免费人成网站在线观看欧美高清| theporn国产精品| 91在线porny国产在线看| 国产精品酒店视频| 亚洲国产精品久久一线不卡| 亚洲大尺度在线观看| 欧美一区二区日韩| 三区在线观看| 欧美日韩成人在线播放| 欧美日韩视频免费观看| 成人午夜电影在线播放| 不卡日本视频| 3d动漫一区二区三区| 激情综合色播五月| 麻豆精品免费视频| 亚洲一区免费观看| 亚洲午夜在线播放| 日韩av在线免费观看一区| 含羞草www国产在线视频| 热久久美女精品天天吊色| 99这里只有精品视频| 夜夜春亚洲嫩草影视日日摸夜夜添夜| 99精品国产在热久久婷婷| 毛片毛片毛片毛| 久久久777精品电影网影网| 久青草视频在线观看| 欧美三级日韩在线| 男女污污视频在线观看| 欧美激情精品久久久久久蜜臀| 国产精品成人国产| 久久综合精品一区| 在线播放日韩| 在线观看你懂的视频| 中文字幕免费不卡| 免费看毛片网站| 日韩成人免费视频| 6699嫩草久久久精品影院| 91在线观看免费观看| 久久婷婷蜜乳一本欲蜜臀| 一级在线免费视频| 久久久亚洲欧洲日产国码αv| 日韩av在线播放观看| 欧美mv日韩mv国产网站app| 国产欧美久久久久久久久| 国产欧美一区二区三区久久| 日韩精品一区二区三区免费观影| 日本精品一区二区三区四区| www.成人网.com| 日韩三级视频在线| 亚洲成年人在线播放| 99thz桃花论族在线播放| 国产高清不卡av| 激情久久婷婷| 日本黄色免费观看| 五月天国产精品| 日本黄色大片视频| 欧美亚洲国产日本| 在线成人动漫av| 青青草av网站| 国产精品污www在线观看| 日韩xxx视频| 中文字幕日本精品| 久久精品资源| 一区二区视频在线播放| 激情成人综合网| 国产免费无码一区二区视频| 欧美岛国在线观看| av中文字幕电影在线看| 韩日午夜在线资源一区二区| 亚洲中字在线| 女女互磨互喷水高潮les呻吟| 日本道免费精品一区二区三区| 国产在线视频网| 国产乱肥老妇国产一区二 | 中文字幕不卡av| 欧美天堂一区| 三级在线免费观看| 成人一区在线观看| 国产精品久久久久久久久久精爆| 亚洲欧美激情视频| 日本一区二区三区中文字幕| 亚洲黄色网址在线观看| 大尺度一区二区| 国内精品福利视频| 色七七影院综合| 一区二区三区高清在线观看| 成人免费aaa| 国产日产精品一区| 99久久夜色精品国产亚洲| 久久久久久久久久久久久久久久久久av| 久草精品视频| 天美星空大象mv在线观看视频| 国产精品夫妻自拍| 日韩专区第一页| 国产精品久久二区| 午夜久久影院| 西西444www无码大胆| 欧美二区乱c少妇| 18aaaa精品欧美大片h| 天堂va久久久噜噜噜久久va| 国产精品亚洲专一区二区三区| 国产又爽又黄的视频| 日韩一区视频在线| 日韩有码一区| 乳色吐息在线观看| 欧美亚洲图片小说| 2020国产在线| 中文字幕一区二区三区四区五区|