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

兩難抉擇:自己定制LLM代理還是使用現有LLM代理框架?

譯文 精選
人工智能
這篇文章旨在讓這個選擇變得更容易一些。在過去的幾周里,我使用當前主流的人工智能開發框架構建了相同的LLM代理,以便在技術層面檢查每個框架的優缺點。

譯者 | 朱先忠

審校 | 重樓

本文旨在幫助你在使用自己定制的LLM代理還是使用現有LLM代理框架之間作出正確的選擇。

簡介

首先,要感謝John Gilhuly對本文的貢獻。

當下,人工智能代理暫時處在大休整時期。隨著多個新的AI開發框架的不斷出現和人們對該領域不斷進行新的投資,現代人工智能代理正在克服不穩定的初始階段,迅速取代RAG而成為實施重點。那么,2024年最終會成為什么樣的年份呢?是自主人工智能系統接管我們人工來書寫電子郵件、預訂航班、處理數據,還是與任何其他年份一樣以相似方式執行上述任務呢?

也許情況與前者一樣,但是要達到這種程度還有很多工作要做。任何構建LLM代理的開發人員不僅必須選擇基礎開發設施——使用哪種模型、使用場景和架構——還必須選擇要利用哪種開發框架。你是選擇長期使用的LangGraph,還是新進入市場的LlamaIndex工作流?還是你走傳統路線,自己編寫整個代碼呢?

這篇文章旨在讓這個選擇變得更容易一些。在過去的幾周里,我使用當前主流的人工智能開發框架構建了相同的LLM代理,以便在技術層面檢查每個框架的優缺點。本文中涉及的每個代理的所有源代碼都可以在倉庫地址處找到。

LLM代理類型

當前,業界主要用于測試目的的LLM代理開發涉及到很多方面的內容,例如函數調用、多種相關工具或技能、與外部資源的連接以及共享狀態或內存,等等。

歸納起來看,幾乎所有LLM代理都具有以下功能:

  • 回答知識庫中的問題。
  • 與數據對話:回答有關LLM應用程序遙測數據的問題。
  • 分析數據:分析檢索到的遙測數據中的高級趨勢和模式。

為了完成這些任務,LLM代理需要具備三個基礎技能:使用產品文檔的RAG、在跟蹤數據庫上生成SQL和數據分析。一種典型的實現方案是,使用開源的Python包Gradio來快速構建一個代理用戶界面,而LLM代理本身被構造為聊天機器人。

基于定制代碼的代理(無框架方案)

開發LLM代理時,你的第一個選擇很可能是完全跳過市場上現有框架,而完全由自己來構建一個代理。在最開始著手做這種項目時,這是我采用的方法。

純代碼架構

下面展示的基于代碼的代理是由一個OpenAI驅動的路由器組成的,該路由器使用函數調用來選擇要使用的正確技能。該技能完成后,它將返回路由器以調用另一個技能或者是對用戶作出響應。

在這個代理中,始終保持一個持續的消息和響應列表,在每次調用時將其完全傳遞到路由器中,以便在循環中保留相應的上下文信息。

def router(messages):
if not any(
isinstance(message, dict) and message.get("role") == "system" for message in messages
):
system_prompt = {"role": "system", "content": SYSTEM_PROMPT}
messages.append(system_prompt)

response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=skill_map.get_combined_function_description_for_openai(),
)

messages.append(response.choices[0].message)
tool_calls = response.choices[0].message.tool_calls
if tool_calls:
handle_tool_calls(tool_calls, messages)
return router(messages)
else:
return response.choices[0].message.content

技能本身是在自己的類中定義的(例如GenerateSQLQuery),而所有這些技能信息共同保存在SkillMap類中。路由器本身只與SkillMap類交互,它使用SkillMap類實現來加載技能名稱、描述和可調用函數。這種方法意味著,向代理添加新技能就像將該技能編寫為自己的類一樣簡單,然后將其添加到SkillMap類中的技能列表中。這里的想法是,在不干擾路由器代碼的情況下輕松添加新技能。

class SkillMap:
def __init__(self):
skills = [AnalyzeData(), GenerateSQLQuery()]

self.skill_map = {}
for skill in skills:
self.skill_map[skill.get_function_name()] = (
skill.get_function_dict(),
skill.get_function_callable(),
)

def get_function_callable_by_name(self, skill_name) -> Callable:
return self.skill_map[skill_name][1]

def get_combined_function_description_for_openai(self):
combined_dict = []
for _, (function_dict, _) in self.skill_map.items():
combined_dict.append(function_dict)
return combined_dict

def get_function_list(self):
return list(self.skill_map.keys())

def get_list_of_function_callables(self):
return [skill[1] for skill in self.skill_map.values()]

def get_function_description_by_name(self, skill_name):
return str(self.skill_map[skill_name][0]["function"])

總體而言,這種方法實施起來相當簡單,不過也存在一些挑戰。

純代碼代理方案的挑戰

第一個難點在于構建路由器系統提示。通常,上述示例中的路由器堅持自己生成SQL,而不是將其委托給合適的技能。如果你曾經試圖不讓LLM做某事,你就會知道這種經歷有多么令人沮喪;找到一個可用的提示需要進行多輪調試。考慮到每個步驟的不同輸出格式也是很棘手的。由于我選擇不使用結構化輸出,因此我必須為路由器和技能中每個LLM調用的多種不同格式做好準備。

純代碼代理方案的優點

基于代碼的方法提供了一個很好的基礎架構和起點,提供了一種學習代理如何工作的好方法,而不是依賴于主流框架中的現成的代理教程。盡管說服LLM的行為可能具有挑戰性,但代碼結構本身足夠簡單,可以使用,并且可能對某些使用場景也極有意義。有關這些使用場景的更多信息,請參閱接下來的分析。

LangGraph

LangGraph是歷史最悠久的代理框架之一,于2024年1月首次發布。該框架旨在通過采用Pregel圖結構來解決現有管道和鏈的非循環性。LangGraph通過添加節點、邊和條件邊的概念來遍歷圖,使得在代理中定義循環變得更加容易。LangGraph構建在LangChain之上,并使用LangChain框架中的對象和類型。

LangGraph架構

LangGraph代理看起來與其原論文中的基于代碼的代理相似,但它后臺的實現代碼卻截然不同。LangGraph在技術上仍然使用“路由器”,因為它通過函數調用OpenAI,并使用響應繼續進行新的步驟。然而,程序在技能之間移動的方式完全不同。

tools = [generate_and_run_sql_query, data_analyzer]
model = ChatOpenAI(model="gpt-4o", temperature=0).bind_tools(tools)

def create_agent_graph():
workflow = StateGraph(MessagesState)

tool_node = ToolNode(tools)
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)

workflow.add_edge(START, "agent")
workflow.add_conditional_edges(
"agent",
should_continue,
)
workflow.add_edge("tools", "agent")

checkpointer = MemorySaver()
app = workflow.compile(checkpointer=checkpointer)
return app

這里定義的圖有一個用于初始OpenAI調用的節點,上面稱為“agent”,還有一個用于工具處理步驟的節點,稱為“tools”。LangGraph提供了一個名為ToolNode的內置對象,它負責獲取可調用工具的列表,并根據ChatMessage響應觸發它們,然后再次返回“agent”節點。

def should_continue(state: MessagesState):
messages = state["messages"]
last_message = messages[-1]
if last_message.tool_calls:
return "tools"
return END

def call_model(state: MessagesState):
messages = state["messages"]
response = model.invoke(messages)
return {"messages": [response]}

在每次調用“agent”節點(換句話說:基于代碼的代理中的路由器)后,should_concontinue邊決定是將響應返回給用戶還是傳遞給ToolNode來處理工具調用。

在每個節點中,“state”存儲來自OpenAI的消息和響應列表,這一點類似于基于代碼的代理的方法。

LangGraph方案的挑戰

示例中LangGraph實現的大部分困難在于LangChain對象的使用,此方案需要借助這個對象來使事情順利進行。

挑戰#1:函數調用驗證

為了使用ToolNode對象,我必須重構我現有的大部分Skill代碼。ToolNode接受一個可調用函數列表,這最初讓我認為我可以使用現有的函數,但由于我設計的函數參數方面的原因,事情發生了一些變化。

這些技能都被定義為具有可調用成員函數的類。這意味著,它們的第一個參數是“self”。GPT-4o足夠聰明,不會在生成的函數調用中包含“self”參數,但不幸的是LangGraph將其解讀為由于缺少參數而導致的驗證錯誤。

這花了我幾個小時才弄清楚,因為錯誤消息將函數中的第三個參數(數據分析技能上的“args”)標記為缺少的參數:

pydantic.v1.error_wrappers.ValidationError: 1 validation error for data_analysis_toolSchema
args field required (type=value_error.missing)

值得一提的是,錯誤消息來自Pydantic,而不是LangGraph。

最終,我咬緊牙關,用Langchain的@tool裝飾器將我的技能重新定義為一些基本方法,終于使得代碼正常進行。

@tool
def generate_and_run_sql_query(query: str):
"""根據提示符生成并運行一個SQL查詢。

參數:
query (str): 一個包含原始用戶提示符的字符串。

返回值:
str: SQL查詢的結果。
"""

挑戰#2:調試

正如前文所述,在框架內進行調試是頗為困難的事情。這主要歸結為令人困惑的錯誤消息和抽象概念,使查看變量變得更加困難。

抽象概念主要出現在嘗試調試代理周圍發送的消息時。LangGraph將這些消息存儲在狀態[“messages”]中。圖中的一些節點會自動從這些消息中提取信息,這可能會使節點訪問消息時難以理解消息的含義。

代理動作的順序視圖

LangGraph方案的優點

LangGraph的主要優點之一是易于使用,因為圖形結構代碼干凈且易于訪問。特別是如果你有復雜的節點邏輯時,只通過圖的單一視圖有助于更容易地理解代理是如何連接在一起的。LangGraph方案也使得轉換現有的基于LangChain構建的應用程序變得非常簡單。

小結

如果你僅使用LangGraph框架中的所有內容,那么LangGraph會順利地工作。但是,如果你還想使用框架外的一些內容進行開發的話,那么你需要為調試一些難題做好準備。

LlamaIdex工作流

工作流是LLM代理框架領域的新方案,于今年夏天早些時候首次亮相。與LangGraph一樣,它旨在使循環代理更容易構建。另外,LLM工作流還特別關注異步運行方式。

LLM工作流的一些元素似乎是對LangGraph的直接響應,特別是它使用事件而不是邊和條件邊。工作流使用步驟(類似于LangGraph中的節點)來容納邏輯,并且在步驟之間發送和接收事件。

上面的結構看起來與LangGraph結構相似,只是增加了一點內容。我在工作流中添加了一個設置步驟來負責準備代理上下文,下面將進一步介紹這方面內容。值得注意的是,盡管這兩種方案的結構相似,但是驅動它們的代碼卻大不相同。

工作流架構

下面的代碼定義了一個工作流結構。與LangGraph方案中代碼類似,這是我準備狀態并將技能附加到LLM對象的地方。

class AgentFlow(Workflow):
def __init__(self, llm, timeout=300):
super().__init__(timeout=timeout)
self.llm = llm
self.memory = ChatMemoryBuffer(token_limit=1000).from_defaults(llm=llm)
self.tools = []
for func in skill_map.get_function_list():
self.tools.append(
FunctionTool(
skill_map.get_function_callable_by_name(func),
metadata=ToolMetadata(
name=func, description=skill_map.get_function_description_by_name(func)
),
)
)

@step
async def prepare_agent(self, ev: StartEvent) -> RouterInputEvent:
user_input = ev.input
user_msg = ChatMessage(role="user", content=user_input)
self.memory.put(user_msg)

chat_history = self.memory.get()
return RouterInputEvent(input=chat_history)

這也是我定義額外步驟“prepare_agent”的地方。此步驟根據用戶輸入創建ChatMessage并將其添加到工作流內存中。將其拆分為一個單獨的步驟意味著,當代理循環執行步驟時,我們確實會返回它,這樣就避免了將用戶消息重復添加到內存中。

在LangGraph的例子中,我用一個位于圖外的run_agent方法完成了同樣的事情。這種變化主要是風格上的,但在我看來,像我們在這里所做的那樣,用工作流和圖形來容納這種邏輯會更清晰。

設置好工作流后,我定義了路由代碼:

@step
async def router(self, ev: RouterInputEvent) -> ToolCallEvent | StopEvent:
messages = ev.input

if not any(
isinstance(message, dict) and message.get("role") == "system" for message in messages
):
system_prompt = ChatMessage(role="system", content=SYSTEM_PROMPT)
messages.insert(0, system_prompt)

with using_prompt_template(template=SYSTEM_PROMPT, version="v0.1"):
response = await self.llm.achat_with_tools(
model="gpt-4o",
messages=messages,
tools=self.tools,
)

self.memory.put(response.message)

tool_calls = self.llm.get_tool_calls_from_response(response, error_on_no_tool_call=False)
if tool_calls:
return ToolCallEvent(tool_calls=tool_calls)
else:
return StopEvent(result=response.message.content)

以及工具調用處理代碼:

@step
async def tool_call_handler(self, ev: ToolCallEvent) -> RouterInputEvent:
tool_calls = ev.tool_calls

for tool_call in tool_calls:
function_name = tool_call.tool_name
arguments = tool_call.tool_kwargs
if "input" in arguments:
arguments["prompt"] = arguments.pop("input")

try:
function_callable = skill_map.get_function_callable_by_name(function_name)
except KeyError:
function_result = "Error: Unknown function call"

function_result = function_callable(arguments)
message = ChatMessage(
role="tool",
content=function_result,
additional_kwargs={"tool_call_id": tool_call.tool_id},
)

self.memory.put(message)

return RouterInputEvent(input=self.memory.get())

上面兩部分代碼看起來都比LangGraph代理更類似于基于代碼的代理。這主要是因為工作流將條件路由邏輯保留在步驟中,而不是保留在條件邊中——其中的部分代碼行以前是對應于LangGraph中的條件邊,而現在它們只是路由步驟的一部分——而且LangGraph有一個ToolNode對象,它幾乎可以自動執行tool_call_handler方法中的所有操作。

經過路由步驟,我很高興看到的一件事是,我可以將我的SkillMap和基于代碼的代理中的現有技能與工作流一起使用。這些不需要更改即可使用工作流,這讓我的工作變得更加輕松。

工作流程方案的挑戰

挑戰#1:同步與異步

雖然異步執行更適合實時代理,但調試同步代理要容易得多。工作流被設計為異步工作;因此,試圖強制同步執行變得非常困難。

我最初以為我可以刪除“async”方法名稱,并從“achat_with_tools”切換到“chat_with_tools”。然而,由于Workflow類中的底層方法也被標記為異步,因此有必要重新定義這些方法以便同步運行。我最終堅持使用異步方法,但這并沒有使調試變得更加困難。

代理動作的順序視圖

在LangGraph方案的困境重演過程中,圍繞技能上令人困惑的Pydantic驗證錯誤出現了類似的問題。幸運的是,這次這些問題更容易解決,因為工作流能夠很好地處理成員函數。最終,我不得不更加規范地為我的技能創建LlamaIndex FunctionTool對象:

for func in skill_map.get_function_list(): 
self.tools.append(FunctionTool(
skill_map.get_function_callable_by_name(func), 
metadata=ToolMetadata(name=func, description=skill_map.get_function_description_by_name(func))))

這段代碼摘自構建FunctionTools工具類的函數AgentFlow__init__。

工作流方案的優點

我構建工作流代理比構建LangGraph代理容易得多,主要是因為工作流仍然要求我自己編寫路由邏輯和工具處理代碼,而不是提供內置函數。這也意味著,我的工作流代理看起來與我的基于代碼的代理非常相似。

最大的區別在于事件的使用。我使用了兩個自定義事件在代理中的步驟之間移動:

class ToolCallEvent(Event):
tool_calls: list[ToolSelection]

class RouterInputEvent(Event):
input: list[ChatMessage]

基于事件的“發射器-接收器”架構取代了直接調用代理中的一些方法,如工具調用處理程序。

如果你有更復雜的系統,其中有多個異步觸發的步驟的話,可能會發出多個事件,那么這種架構對于清晰地管理這些步驟非常有幫助。

工作流的其他好處包括:此方案非常輕量級,不會給你強加太多的結構(除了使用某些LlamaIdex對象),而且它基于事件的架構為直接函數調用提供了一種有用的替代方案,特別是對于復雜的異步應用程序而言。

框架比較

縱觀上述三種方法,每種方法都各有其優點。

無框架方法是最容易實現的。因為任何抽象都是由開發人員自己定義的(即上例中的SkillMap對象),所以保持各種類型和對象的簡潔是很容易的。然而,代碼的可讀性和可訪問性完全取決于單個開發人員。很容易看出,在沒有采用一些強制的結構定義的情況下,越來越復雜的代理會變得一團糟。

LangGraph框架本身提供了相當多的結構,這使得代理的定義非常清晰。如果一個更大的團隊正在合作開發一個代理,這種結構將提供一種有助于實施架構的方法。LangGraph也可能為那些不熟悉結構的人提供一個很好的代理起點。然而,有一個權衡——由于LangGraph為你做了很多工作,如果你不完全接受該框架,可能會感覺有些頭痛;代碼可能非常干凈,但你可能會為其付出更多的調試代價。

在上述三種方法中,工作流方案位于中間。基于事件的架構可能對某些項目非常有幫助;事實上,在使用LlamaIdex類型方面所需的編碼量更少,這為那些在應用程序中沒有完全使用過該框架的人提供了更大的靈活性。

最終,核心問題可能歸結為“你已經在使用LlamaIndex或LangChain來編排你的應用程序了嗎?”LangGraph和工作流都與各自的底層框架緊密相連,以至于每個特定于代理的框架的額外好處可能不會讓你只憑優點來切換它們。

不過,純代碼方法可能永遠是一個具有吸引力的選擇。如果你有足夠的嚴謹性來記錄和執行任何創建的抽象的話,那么就很容易確保外部框架中沒有任何設置會減緩你的開發速度。

選擇代理框架的關鍵問題

當然,“視情況而定”從來不是一個令人滿意的答案。下面的三個問題可以幫助你決定在下一個代理項目中使用哪個框架。

  • 你是否已經在項目的重要部分使用LlamaIndex或LangChain?

如果是,請先優先分析這種選擇方案。

  • 你熟悉常見的代理結構嗎?還是想知道你應該如何構建代理?

如果你大致屬于后一種情形,請嘗試工作流方案。不過,如果你真的屬于后一種情形,試試LangGraph方案吧。

  • 以前構建過你自己的代理嗎?

框架方案的好處之一是,每個框架都有許多教程和示例。相比而言,可用于構建純代碼代理的示例代碼要少得多。

結論

無論如何,選擇一個代理框架只是影響生成式人工智能系統生產結果的眾多選擇之一。與往常一樣,構建強大的保護措施并進行LLM跟蹤是非常值得推薦的做法,并且隨著新的代理框架、研究成果和模型不斷顛覆既定技術,這樣做也變得更為機動靈活。

譯者介紹

朱先忠,51CTO社區編輯,51CTO專家博客、講師,濰坊一所高校計算機教師,自由編程界老兵一枚。

原文標題:Choosing Between LLM Agent Frameworks,作者:Aparna Dhinakaran

責任編輯:姜華 來源: 51CTO內容精選
相關推薦

2014-11-06 09:56:22

應用程序自主構建購買

2024-07-11 16:16:27

ChatGPTLLM

2025-02-14 08:18:33

2025-03-11 08:00:00

LLM開發深度學習

2010-10-19 10:12:11

數據中心外包

2025-03-28 10:16:15

2024-08-12 17:05:21

2021-04-14 14:37:05

算法大數據場景化

2013-09-03 12:48:25

創業CEO創業產品

2025-09-08 15:08:41

GeminiOpenAILLM

2011-03-25 13:32:06

推遲新版本Android

2011-05-12 12:45:54

程序員

2011-05-12 09:27:15

程序員創業

2022-12-09 07:25:58

.NET項目微軟

2022-04-19 10:22:43

AI計算機就業

2024-06-18 14:01:17

2024-08-26 08:00:00

2023-06-30 09:00:00

Falcon LLM開源

2012-03-28 09:46:32

2012-02-07 09:22:22

數據中心外包云計算
點贊
收藏

51CTO技術棧公眾號

欧美一级大片免费看| 午夜精品免费视频| 97超碰人人看| 久久久久黄久久免费漫画| 99久久久精品| 国产精品精品一区二区三区午夜版| 亚洲女人毛茸茸高潮| 国产精品视频3p| 欧美影视一区二区三区| 奇米777四色影视在线看| 黄色电影免费在线看| 国产在线一区二区| 奇门遁甲1982国语版免费观看高清 | 国产伦精品一区二区三区视频黑人 | 国产在线精品一区免费香蕉 | 麻豆网站在线观看| 99久久婷婷国产综合精品电影 | 无码人妻丰满熟妇区毛片18| 含羞草www国产在线视频| 国产亚洲欧美在线| 成人女人免费毛片| 亚洲一区二区天堂| 久久亚洲精选| 国内精品小视频在线观看| 国产精品www爽爽爽| 米奇精品关键词| 日韩午夜精品视频| 亚洲天堂av一区二区| 欧美大片免费| 亚洲a一区二区| 97在线免费视频观看| 欧美日韩视频在线播放| 国产网站一区二区| 欧美日韩大片一区二区三区| 亚洲第一免费视频| 国内精品在线播放| 国产精品三级网站| 国产一级片免费视频| 亚洲在线网站| 2021久久精品国产99国产精品| 国产精品丝袜一区二区| 999精品视频| 一本一本久久a久久精品综合小说| 精品国产av色一区二区深夜久久 | 青草草在线视频| 99精品综合| 最新中文字幕亚洲| 亚洲综合第一区| 日本成人小视频| 尤物九九久久国产精品的分类| 欧美精品欧美极品欧美激情| 久久人人爽人人爽人人片av不| 日韩写真欧美这视频| ass极品水嫩小美女ass| 麻豆精品国产| 日韩美女一区二区三区| 女人扒开腿免费视频app| 视频一区中文字幕精品| 精品国产91乱码一区二区三区| 国产精品99久久久精品无码| 国产精品中文字幕制服诱惑| 精品国产精品网麻豆系列 | 伊人网视频在线| 麻豆国产91在线播放| 国产精品午夜一区二区欲梦| 一本一道精品欧美中文字幕| 国模少妇一区二区三区| 91在线视频精品| 亚洲第一页在线观看| 成人h动漫精品| 久久久婷婷一区二区三区不卡| 国产精品国产高清国产| 久久一区二区视频| 色999五月色| 黄色免费在线看| 亚洲一二三级电影| 一本久道综合色婷婷五月| 国产精品成人国产| 欧美一级片免费看| 精品国产av色一区二区深夜久久 | 99re99热| 91吃瓜在线观看| 欧美亚洲综合久久| 日本黄色大片在线观看| 啄木系列成人av电影| 色偷偷亚洲男人天堂| 久久午夜无码鲁丝片午夜精品| 亚洲欧美成人| 91丝袜美腿美女视频网站| 涩涩视频免费看| 中文一区在线播放| www精品久久| 精品亚洲a∨| 欧美精品一区二区三区四区| 国产女主播喷水高潮网红在线| 四虎8848精品成人免费网站| 亚州成人av在线| 中文字幕一区2区3区| 床上的激情91.| 亚洲国产高清国产精品| 91黄页在线观看| 欧美精品在线一区二区三区| 一级黄色免费毛片| 精品视频国产| 国内精品久久久| 亚洲中文一区二区三区| 99re6这里只有精品视频在线观看 99re8在线精品视频免费播放 | 久久久av网站| 国产乱码77777777| 成人精品亚洲人成在线| 91免费网站视频| 樱桃视频成人在线观看| 日韩丝袜美女视频| 成人一级片免费看| 久久久蜜桃一区二区人| 国产99在线免费| 成人影院在线看| 在线观看不卡视频| 日本japanese极品少妇| 亚洲自拍偷拍网| 国产精品午夜一区二区欲梦| 黄色大片在线看| 午夜亚洲福利老司机| 色欲无码人妻久久精品| 日韩在线理论| 国产精品久久久久久久久免费看 | 一个人看的www久久| 中文字幕亚洲精品一区| 成人激情视频网站| 超薄肉色丝袜足j调教99| 成人深夜福利| 中文字幕欧美国内| 国产又粗又猛又黄视频| 91丝袜美腿高跟国产极品老师| 欧美精品久久久久久久久久久| 精品一区二区三区免费看| 日韩最新免费不卡| 伊人网站在线观看| 国产精品久久午夜夜伦鲁鲁| 日韩在线第三页| 欧美国产不卡| 91精品国产高清久久久久久久久| 动漫av一区二区三区| 亚洲精品国产精品乱码不99 | 久久综合国产精品| 国产一区二区网| 琪琪久久久久日韩精品| 欧美有码在线观看| 男人天堂亚洲二区| 在线视频你懂得一区| 精品人妻无码一区二区三区换脸| 久久精品电影| 日韩久久不卡| www.国产精品| 日韩一级裸体免费视频| 91精品国产乱码久久久| 亚洲人精品一区| 91精品国产高清91久久久久久 | 九色国产在线观看| 欧美在线观看一区| 少妇高潮惨叫久久久久| 国产精品一级黄| 免费视频爱爱太爽了| 极品国产人妖chinesets亚洲人妖| 久久久视频在线| 深夜福利视频在线免费观看| 91久久久免费一区二区| 人妻熟人中文字幕一区二区| 国产乱人伦偷精品视频免下载 | 精品国内片67194| 精品一区在线视频| 久久影院视频免费| 日韩av在线中文| 欧美三级小说| 蜜桃成人在线| 亚洲成人毛片| 久久久久中文字幕| 黄色毛片在线看| 欧美一级片免费看| 国产99久久久| 亚洲精品亚洲人成人网在线播放| 色哟哟视频在线| 天堂蜜桃一区二区三区| 自拍偷拍视频在线| 久久悠悠精品综合网| 国产精品va在线| 在线播放免费av| 亚洲性av在线| 黑人精品一区二区三区| 欧美专区日韩专区| 国产盗摄x88av| 欧美国产日本韩| 少妇精品无码一区二区| 日韩精品免费专区| 欧美国产视频一区| 日本精品三区| 久久精品ww人人做人人爽| 亚州欧美在线| 欧美中文在线字幕| 韩国av网站在线| 亚洲日韩欧美视频一区| 国产超碰人人模人人爽人人添| 精品久久久久久久久久| 亚洲人与黑人屁股眼交| 91麻豆国产福利精品| 麻豆传媒在线看| 美腿丝袜亚洲一区| 无码精品国产一区二区三区免费| 女人香蕉久久**毛片精品| 欧美一区1区三区3区公司 | 亚洲精品99久久久久| 国产口爆吞精一区二区| 91福利国产成人精品照片| 不卡的免费av| 亚洲精品免费电影| 国产精品麻豆免费版现看视频| 久久综合国产精品| 天堂www中文在线资源| 国产尤物一区二区在线| 国产又大又黄又粗又爽| 性欧美xxxx大乳国产app| 少妇大叫太大太粗太爽了a片小说| 久久一区二区中文字幕| 欧洲av一区| 视频小说一区二区| 国产一区二区三区四区hd| 午夜电影一区| 91沈先生作品| 精品国产乱码久久久久久樱花| 国产精品白丝jk喷水视频一区| 欧美gv在线| 91国产视频在线| 97人澡人人添人人爽欧美| 欧美精品videosex极品1| 日本动漫同人动漫在线观看| 大胆欧美人体视频| 成人影院在线看| 九九热这里只有精品免费看| 日本不卡不卡| 久久久999国产精品| 高h视频在线观看| 免费97视频在线精品国自产拍| www.欧美日本韩国| 欧美日韩xxx| 欧美xxxx做受欧美88bbw| 久久久久久尹人网香蕉| 第一av在线| 国内精品一区二区三区四区| 热色播在线视频| 日本视频久久久| 美女网站视频一区| 国产日韩在线免费| 精品久久亚洲| 高清av免费一区中文字幕| 亚洲欧洲国产精品一区| 国产嫩草一区二区三区在线观看| 日韩激情网站| 新呦u视频一区二区| 999久久久精品国产| av磁力番号网| 一区二区三区成人精品| 国产精品99久久免费黑人人妻| 日韩黄色一级片| www.欧美激情.com| 成人午夜看片网址| 黄色国产在线观看| 国产欧美一区二区精品婷婷 | 91精品视频大全| 一区二区三区亚洲变态调教大结局| 国产午夜精品一区| 国产在视频线精品视频www666| 亚洲视频导航| 亚洲性视频h| 欧美一级片中文字幕| 麻豆精品精品国产自在97香蕉| 三大队在线观看| 久久久天堂av| 欧美三级小视频| 欧美视频在线免费| 国产精品女同一区二区| 亚洲第一区中文99精品| 黄视频在线观看免费| 欧美另类暴力丝袜| www成人在线视频| 91亚色免费| 国产精品羞羞答答在线观看| 在线观看污视频| 另类av一区二区| 欧美老女人bb| 国产色产综合产在线视频| 日本a级片视频| 日韩欧美成人区| 精品乱子伦一区二区| 亚洲欧美一区二区三区久久| 污污片在线免费视频| 日本欧美中文字幕| 久久久精品区| 婷婷五月色综合| 亚洲成人资源| 婷婷激情综合五月天| 国产亚洲欧洲一区高清在线观看| 玖玖爱免费视频| 欧美日韩国产影片| 亚洲aaaaaaa| 九色成人免费视频| 日本午夜精品久久久久| 欧美男人的天堂| 伊人久久大香线蕉av超碰演员| 亚洲成人福利在线| 久久网站热最新地址| 麻豆一区产品精品蜜桃的特点| 欧美日韩在线免费视频| 欧洲一区av| 久久久亚洲精选| 精品视频一二| 中文字幕一区二区三区最新 | 黄色a一级视频| 亚洲线精品一区二区三区八戒| ,一级淫片a看免费| 在线亚洲国产精品网| 欧美gay囗交囗交| 久久精品国产理论片免费| 欧美日韩视频一区二区三区| 亚洲娇小娇小娇小| 国产午夜精品理论片a级大结局| 国产精品suv一区二区三区| 精品不卡在线视频| 变态调教一区二区三区| 3d动漫啪啪精品一区二区免费| 国产精品99视频| 天天干天天操天天做| 国产欧美一区二区三区网站| 日批视频免费在线观看| 亚洲男人的天堂网站| 欧美电影免费观看| 欧美日韩在线观看一区二区三区| 亚洲一区图片| 亚欧洲乱码视频| 91成人国产精品| 99re在线视频| 成人激情综合网| 中出一区二区| 日韩大尺度视频| 亚洲国产成人高清精品| 蜜臀av中文字幕| 欧美一区第一页| 久久不见久久见免费视频7| 两根大肉大捧一进一出好爽视频| 2022国产精品视频| 欧美日韩a v| 丝袜美腿精品国产二区| 亚洲免费一区| 国产免费裸体视频| 99久久精品国产网站| 日韩综合在线观看| 三级精品视频久久久久| 精品一级视频| 97视频在线免费| 91在线精品一区二区| 少妇高潮av久久久久久| 国产一区二区日韩| 日韩电影精品| 亚洲 欧美 综合 另类 中字| 99久久er热在这里只有精品66| 亚洲第一在线播放| 少妇高潮久久77777| 国产视频网站一区二区三区| 97久久国产亚洲精品超碰热| 91在线视频网址| 中文字幕日本人妻久久久免费 | 日本三级欧美三级| 亚洲国产欧美一区二区三区同亚洲| 亚洲一级少妇| 在线视频精品一区| 成人av电影在线网| 久久久精品毛片| 欧美另类在线播放| 欧美**字幕| 国产大片一区二区三区| 亚洲v日本v欧美v久久精品| 国产在线一在线二| 99久久精品免费看国产四区 | 国产精品久久精品| 欧美日韩免费| 久久久视频6r| 精品国产伦一区二区三区观看方式 | 亚洲男人的天堂在线aⅴ视频| 人妻一区二区三区四区| 国产欧美日韩精品在线观看| 亚洲黄色影片| 在线观看黄网址| 亚洲美女在线观看| 欧美久久亚洲| 国产成人综合一区| 亚洲福利视频导航| 青青青青在线| 欧美一区观看| 成人做爰69片免费看网站| 真实新婚偷拍xxxxx| 亚洲97在线观看|