RAG 是2023年最流行的基于 LLM 的應(yīng)用系統(tǒng)架構(gòu)。有許多產(chǎn)品幾乎完全建立在 RAG 之上,覆蓋了結(jié)合網(wǎng)絡(luò)搜索引擎和 LLM 的問答服務(wù),到成千上萬個(gè)數(shù)據(jù)聊天的應(yīng)用程序。很多人將RAG和Agent 作為大模型應(yīng)用的兩種主流架構(gòu),但什么是RAG呢?RAG又涉及了哪些具體的技術(shù)呢?
RAG即檢索增強(qiáng)生成,為 LLM 提供了從某些數(shù)據(jù)源檢索到的信息,并基于此修正生成的答案。RAG 基本上是 Search + LLM 提示,可以通過大模型回答查詢,并將搜索算法所找到的信息作為大模型的上下文。查詢和檢索到的上下文都會(huì)被注入到發(fā)送到 LLM 的提示語中。
嵌入式搜索引擎可以通過 Faiss 來實(shí)現(xiàn),向量搜索領(lǐng)域成為了RAG的一個(gè)助力。像pinecone 這樣的向量數(shù)據(jù)庫可以構(gòu)建開源搜索索引,為輸入文本增加了額外的存儲(chǔ)空間,還增加了一些其他工具。關(guān)于向量數(shù)據(jù)庫,可以參考解讀向量數(shù)據(jù)庫。
面向RAG的開發(fā)框架,對(duì)于基于 LLM 的流水線和應(yīng)用程序,有兩個(gè)最著名的開源工具—— LangChain 和 LlamaIndex,分別是在2022年10月和11月創(chuàng)建的,隨著 ChatGPT 爆發(fā),也在2023年獲得了大量采用。LlamaIndex 和 LangChain 都是令人驚嘆的開源項(xiàng)目,它們的發(fā)展速度非???。
RAG 系統(tǒng)的起點(diǎn)一般是一個(gè)文本文檔的語料庫,簡單看起來是這樣的: 把文本分割成塊,然后把這些分塊嵌入到向量與transformer編碼器模型,把所有這些向量建立索引,最后創(chuàng)建一個(gè) LLM 提示語,告訴模型回答用戶的查詢,給出在搜索步驟中找到的上下文。在運(yùn)行時(shí),我們用相同的編碼器模型完成用戶查詢的向量化,然后執(zhí)行這個(gè)查詢向量的索引搜索,找到top-k 的結(jié)果,從數(shù)據(jù)庫中檢索到相應(yīng)的文本塊,并提供給 LLM 提示語Prompt作為上下文。
在OpenAI 平臺(tái)上,提示詞Prompt可以是這樣的:
def question_answering(context, query):
prompt = f""" my query text...
"""
response = get_completion(instruction, prompt, model="gpt-3.5-turbo")
answer = response.choices[0].message["content"]
return answer
關(guān)于提示詞和提示詞工程的更多介紹可以參考OpenAI 的提示詞工程手冊以及解讀提示工程(Prompt Engineering)。
顯然,盡管 OpenAI 在LLM 市場上處于領(lǐng)先地位,但還是有很多替代方案,比如 Anthroic 的 Claude,還有最近流行的更小但功能強(qiáng)大的模型,比如 Mistral,微軟的 Phi-2 以及許多開源選項(xiàng),比如 Llama2,OpenLLaMA,F(xiàn)alcon等都可以用來開發(fā)面向RAG的大模型產(chǎn)品。
盡管并不是所有RAG系統(tǒng)中的高級(jí)技術(shù)都可以輕松地在一張圖中可視化,但給出一個(gè)描述核心步驟和算法的方案還是有意義的。
首先,要?jiǎng)?chuàng)建一個(gè)向量索引表示我們的文檔內(nèi)容,然后在運(yùn)行時(shí)搜索所有這些向量和查詢向量之間最小距離對(duì)應(yīng)的最接近語義。
由于transformer模型有固定的輸入序列長度,即使輸入上下文的窗口很大,一個(gè)或幾個(gè)句子的向量也比一個(gè)在幾頁文本上取平均值的向量更能代表它們的語義意義 ,所以數(shù)據(jù)分塊是一個(gè)有意義的技術(shù)。把初始文檔分成一定大小的塊,同時(shí)又不失去它們的意義,也就是把文本分成句子或段落,而不是把一個(gè)句子分成兩部分。而且,已經(jīng)有了各種能夠執(zhí)行此任務(wù)的文本分割器實(shí)現(xiàn)。例如,在 LlamaIndex 中,NodeParser 就提供了一些高級(jí)選項(xiàng),如定義自己的文本分割器、元數(shù)據(jù)、節(jié)點(diǎn)/塊關(guān)系等。
數(shù)據(jù)塊的大小是一個(gè)需要考慮的參數(shù),它取決于使用的嵌入模型及其token容量,標(biāo)準(zhǔn)的transformer編碼模型,如BERT 的句子轉(zhuǎn)換器,最多只能使用512個(gè)token,OpenAI ada-002能夠處理更長的序列,如8191個(gè)token,但這里的折衷是足夠的上下文,讓 LLM 能夠推理以及特定的足夠文本嵌入,以便有效地執(zhí)行搜索。
下一步是選擇一個(gè)模型來生產(chǎn)所選塊的嵌入,同樣有很多方法,例如搜索優(yōu)化的模型( bge-large 或者E5 系列),MTEB 排行榜可以得到最新的一些方法信息。關(guān)于文檔分塊和向量化步驟的端到端實(shí)現(xiàn),可以具體地參考https://docs.llamaindex.ai/en/latest/moduleguides/loading/ingestionpipeline/root.html#。
面向RAG的大模型應(yīng)用的關(guān)鍵部分是用于搜索的索引,它存儲(chǔ)前面得到的向量化內(nèi)容。當(dāng)然,查詢總是首先向量化,對(duì)于 top k 分塊也是一樣的。最簡單的實(shí)現(xiàn)使用一個(gè)平鋪的索引,在查詢向量和所有塊向量之間進(jìn)行距離計(jì)算并遍歷。
一個(gè)合適的搜索索引,為了在一萬多個(gè)元素的尺度上有效地檢索而優(yōu)化,需要一個(gè)向量索引, faiss,nmslib 或 annoy等使用一些近似最近鄰方式實(shí)現(xiàn),如聚類,樹或 HNSW 算法。還有一些受管理的解決方案,比如 ElasticSearch以及向量數(shù)據(jù)庫,它們負(fù)責(zé)處理數(shù)據(jù)攝取的流水線。
根據(jù)索引的選擇,數(shù)據(jù)和搜索需求還可以將元數(shù)據(jù)與向量一起存儲(chǔ),然后使用元數(shù)據(jù)過濾器在某些日期或數(shù)據(jù)源中搜索信息。LlamaIndex 支持許多向量存儲(chǔ)索引,也支持其他更簡單的索引實(shí)現(xiàn),如列表索引、樹索引和關(guān)鍵字表索引。
如果有許多文檔,就需要能夠有效地在其中進(jìn)行搜索,找到相關(guān)信息,并將其聚合在一個(gè)帶有源引用的答案中。對(duì)于大型數(shù)據(jù)庫,一個(gè)有效的方法是創(chuàng)建兩個(gè)索引,一個(gè)由摘要組成,另一個(gè)由文檔塊組成,然后分兩個(gè)步驟進(jìn)行搜索,首先通過摘要過濾掉相關(guān)文檔,然后再通過相關(guān)組進(jìn)行搜索。
另一種方法是要求 LLM 為每個(gè)塊生成一個(gè)問題,并將這些問題嵌入到向量中,在運(yùn)行時(shí)對(duì)這個(gè)問題的向量索引執(zhí)行查詢搜索(在索引中用問題向量替換塊向量) ,然后路由到原始文本塊并將它們作為 LLM 獲得答案的上下文發(fā)送。這種方法提高了搜索質(zhì)量,因?yàn)榕c實(shí)際塊相比,查詢和假設(shè)問題之間具有更高的語義相似性。還有一種被稱為 HyDE 的反向邏輯方法, 要求一個(gè) LLM 生成一個(gè)假設(shè)的給定查詢的響應(yīng),然后使用它的向量和查詢向量來提高搜索質(zhì)量。
為了獲得更好的搜索質(zhì)量而檢索更小的塊,就要為 LLM 添加周圍的上下文。有兩種選擇,一個(gè)是句子窗口檢索,即在檢索到的較小塊周圍按句子展開上下文,另一個(gè)是父文檔檢索,即遞歸地將文檔分割成若干較大的父塊,其中包含較小的子塊。
在句子窗口檢索方案中,文檔中的每個(gè)句子都是單獨(dú)嵌入,這為上下文余弦距離搜索提供了很高的準(zhǔn)確性。在獲取最相關(guān)的單個(gè)句子之后,為了更好地推理找到的上下文,在檢索到的句子之前和之后將上下文窗口擴(kuò)展為k個(gè)句子,然后將這個(gè)擴(kuò)展的上下文發(fā)送給 LLM。
父文檔檢索與句子窗口檢索非常相似,都是搜索更細(xì)粒度的信息,然后在將上下文提供給 LLM 進(jìn)行推理之前擴(kuò)展過的上下文窗口。文檔被拆分成引用較大父塊中的較小子塊。具體而言,文檔被分割成塊的層次結(jié)構(gòu),然后最小的葉子塊被發(fā)送到索引。在檢索期間,獲取較小的塊,然后如果在top-k 檢索的塊中有超過 n 個(gè)塊鏈接到同一個(gè)父節(jié)點(diǎn)(較大的塊) ,就用這個(gè)父節(jié)點(diǎn)替換提供給 LLM 的上下文。需要注意的是,搜索僅在子節(jié)點(diǎn)索引中執(zhí)行。
還有一個(gè)相對(duì)較老的思路,可以像 tf-idf 或BM25這樣的稀疏檢索算法那樣從現(xiàn)代語義或向量搜索中獲取最佳結(jié)果,并將其結(jié)合在一個(gè)檢索結(jié)果中。這里唯一的技巧是將檢索到的結(jié)果與不同的相似度得分恰當(dāng)?shù)亟Y(jié)合起來,這個(gè)問題通常借助于Reciprocal Rank 融合算法(RRF)來解決,對(duì)檢索到的結(jié)果重新排序以得到最終的輸出。
在 LangChain中,這是在集成檢索器類中實(shí)現(xiàn)的,例如,一個(gè) Faiss 矢量索引和一個(gè)基于 BM25的檢索器,并使用 RRF 進(jìn)行重新排序。在 LlamaIndex 中,也是以一種非常類似的方式完成的。
混合或融合搜索通常在考慮查詢和存儲(chǔ)文檔之間有語義相似性和關(guān)鍵字匹配的情況下,將兩種互補(bǔ)的搜索算法結(jié)合起來,提供更好的檢索結(jié)果。
在得到了檢索結(jié)果后,需要通過過濾來重新排序。LlamaIndex 提供了多種可用的后處理程序,根據(jù)相似度評(píng)分、關(guān)鍵詞、元數(shù)據(jù)過濾掉結(jié)果,或者用其他模型對(duì)結(jié)果進(jìn)行重新排序,比如基于句子transformer的交叉編碼器、 根據(jù)元數(shù)據(jù)(比如日期最近性)內(nèi)聚重新排序等等。這是將檢索到的上下文提供給 LLM 以獲得結(jié)果答案之前的最后一步。
查詢轉(zhuǎn)換是一系列使用 LLM 作為推理引擎來修改用戶輸入以提高檢索質(zhì)量的技術(shù),有很多不同的技術(shù)選擇。
如果查詢很復(fù)雜,LLM 可以將其分解為幾個(gè)子查詢。例如,如果問“ 在Github上Langchain 或 LlamaIndex 上哪個(gè)有更多顆星?”,不太可能在語料庫中找到直接的對(duì)比,將這個(gè)問題分解為兩個(gè)子查詢是有意義的,前提是要有更簡單和更具體的信息檢索,例如 “ Langchain 在 Github 上有多少顆星?”“Llamaindex 在 Github 上有多少顆星?”它們將并行執(zhí)行,然后將檢索到的上下文組合在一個(gè)提示語中,以便 LLM 合成對(duì)初始查詢的最終答案。在 Langchain 作為多查詢檢索器,在 Llamaindex 作為子問題查詢引擎。
后退提示(Step-back prompting)使用 LLM 生成一個(gè)更一般的查詢,為此檢索獲得一個(gè)更一般或更高級(jí)別的上下文,以便將原始查詢的答案建立在這個(gè)上下文上。此外,還將執(zhí)行對(duì)原始查詢的檢索,并在最后的應(yīng)答生成步驟中將兩個(gè)上下文提供給 LLM。LangChain 有一個(gè)參考實(shí)現(xiàn)https://github.com/langchain-ai/langchain/blob/master/cookbook/stepback-qa.ipynb。query重寫使用 LLM 重新制定初始查詢,以提高檢索效率。LangChain 和 LlamaIndex 都有實(shí)現(xiàn),但 LlamaIndex 參考實(shí)現(xiàn)更強(qiáng)大https://llamahub.ai/l/llamapacks-fusionretriever-query_rewrite。
如果使用多個(gè)來源來生成一個(gè)答案,要么是由于初始查詢的復(fù)雜性,需要必須執(zhí)行多個(gè)子查詢,然后將檢索到的上下文合并到一個(gè)答案中,要么是在多個(gè)文檔中發(fā)現(xiàn)了單個(gè)查詢的相關(guān)上下文,能夠準(zhǔn)確地反向引用。可以將這個(gè)引用任務(wù)插入到提示語中,并要求 LLM 提供所使用源的 id,然后將生成的響應(yīng)部分與索引中的原始文本塊匹配,Llamaindex 為這種情況提供了一種有效的基于模糊匹配的解決方案。
構(gòu)建一個(gè)可以在單個(gè)查詢中多次運(yùn)行RAG系統(tǒng)的一個(gè)重要特性是聊天邏輯,考慮到對(duì)話上下文,就像在 LLM 時(shí)代之前的經(jīng)典聊天機(jī)器人一樣。這是支持后續(xù)問題,重復(fù)指代,或任意用戶命令相關(guān)的以前對(duì)話上下文所必需的。查詢壓縮技術(shù)可以同時(shí)考慮聊天上下文和用戶查詢。有幾種方法可以實(shí)現(xiàn)上下文壓縮,一種流行且相對(duì)簡單的 ContextChatEngine,首先檢索與用戶查詢相關(guān)的上下文,然后將其連同聊天歷史從存緩發(fā)送給 LLM,讓 LLM 在生成下一個(gè)答案時(shí)能夠意識(shí)到前一個(gè)上下文。
更復(fù)雜的實(shí)現(xiàn)是 CondensePlusContextMode,在每次交互中,聊天歷史記錄和最后一條消息被壓縮成一個(gè)新的查詢,然后這個(gè)查詢進(jìn)入索引,檢索到的上下文被傳遞給 LLM連同原始用戶消息來生成一個(gè)答案。
Query路由是由 LLM 驅(qū)動(dòng)的決策步驟,在給定用戶查詢的情況下,決定接下來做什么。這些選項(xiàng)通常是總結(jié)、針對(duì)某些數(shù)據(jù)索引執(zhí)行搜索或嘗試多種不同的路由,然后在一個(gè)答案中綜合它們的輸出。
Query路由還可以用于選擇索引,或者更廣泛的數(shù)據(jù)存儲(chǔ),將用戶查詢發(fā)送到何處,例如,經(jīng)典的向量存儲(chǔ)和圖形數(shù)據(jù)庫或關(guān)系數(shù)據(jù)庫。對(duì)于多文檔存儲(chǔ)來說,一個(gè)非常經(jīng)典的情況是一個(gè)摘要索引和另一個(gè)文檔塊向量索引。
定義Query路由包括設(shè)置它可以做出的選擇。路由選擇是通過一個(gè) LLM 調(diào)用來執(zhí)行的,它以預(yù)定義的格式返回結(jié)果,用于將查詢路由到給定的索引。如果采用了代理的方式,則將查詢路由到子鏈甚至其他代理,如下面的多文檔代理方案所示。LlamaIndex 和 LangChain 都支持Query路由。
智能體Agent幾乎自第一個(gè) LLM API 發(fā)布以來就一直存在,其想法是為一個(gè)能夠推理的 LLM 提供一套工具以及需要完成的任務(wù)。這些工具可能包括一些確定性函數(shù),比如任何代碼函數(shù)或外部 API,甚至包括其他代理,這種 LLM 鏈接思想就是 LangChain 來源。
代理本身就是一個(gè)巨大的話題,OpenAI 助手基本上已經(jīng)實(shí)現(xiàn)了很多圍繞 LLM 所需的工具,也許最重要的是函數(shù)調(diào)用 API。后者提供了將自然語言轉(zhuǎn)換為對(duì)外部工具或數(shù)據(jù)庫查詢的 API 調(diào)用的功能。在 LlamaIndex 中,有一個(gè) OpenAIAgent 類將這種高級(jí)邏輯與 ChatEngine 和 QueryEngine 結(jié)合在一起,提供基于知識(shí)和上下文感知的聊天功能,以及一次性調(diào)用多個(gè) OpenAI 函數(shù)的能力,這確實(shí)帶來了智能代理的使用方式。
以多文檔代理為例,在每個(gè)文檔上會(huì)初始化一個(gè)代理(OpenAIAgent) ,能夠進(jìn)行文檔摘要和經(jīng)典的 QA 機(jī)制,以及一個(gè)頂級(jí)總代理,負(fù)責(zé)將查詢路由到文檔代理和最終答案合成。每個(gè)文檔代理都有兩個(gè)工具ーー向量存儲(chǔ)索引和摘要索引,并根據(jù)路由查詢決定使用哪個(gè)工具。該體系結(jié)構(gòu)由每個(gè)相關(guān)代理做出大量的路由決策。這種方法的好處是能夠比較不同的解決方案或?qū)嶓w,這些解決方案或?qū)嶓w在不同的文檔及其摘要以及經(jīng)典的單一文檔摘要和QA 機(jī)制中進(jìn)行了描述,這基本上涵蓋了最常見的與文檔集聊天的使用場景。
該方案由于在內(nèi)部使用 LLM 進(jìn)行了多次來回迭代,因此速度有點(diǎn)慢。為了防萬一,LLM 調(diào)用通過 RAG 流水線中最長的搜索操作來優(yōu)化速度。因此,對(duì)于大型多文檔存儲(chǔ),可以對(duì)該方案進(jìn)行一些簡化,使其具有可伸縮性。
響應(yīng)合成是任何 RAG 流水線的最后一步,根據(jù)檢索的所有上下文和初始用戶查詢生成一個(gè)答案。最簡單的方法是將所有獲取的上下文(高于某個(gè)相關(guān)性閾值)與查詢一起連接并提供給 LLM。但是,還有其他更復(fù)雜的選項(xiàng)涉及多個(gè) LLM 調(diào)用,以細(xì)化檢索到的上下文并生成更好的答案。響應(yīng)合成的主要方法有:
通過逐塊向LLM發(fā)送檢索到的上下文來迭代地細(xì)化答案;
總結(jié)檢索到的上下文以適應(yīng)提示;
根據(jù)不同的上下文塊生成多個(gè)答案,然后將其連接或總結(jié)。
有關(guān)響應(yīng)合成的更多信息,可以參考文檔中的示例https://docs.llamaindex.ai/en/stable/moduleguides/querying/responsesynthesizers/root.html。
對(duì) RAG 流水線中涉及的深度學(xué)習(xí)模型進(jìn)行一些微調(diào),一個(gè)是負(fù)責(zé)嵌入質(zhì)量從而提高上下文檢索質(zhì)量的 Transformer Encoder,另一個(gè)負(fù)責(zé)利用提供的上下文來回答用戶查詢的 LLM。可以使用 GPT-4這樣的高端 LLM 來生成高質(zhì)量的合成數(shù)據(jù)集。但是應(yīng)該始終注意到,采用一個(gè)大型數(shù)據(jù)集進(jìn)行訓(xùn)練的開源模型,并使用小型合成數(shù)據(jù)集進(jìn)行快速調(diào)優(yōu),可能會(huì)削弱模型的總體能力。
較新版本的transformer編碼器優(yōu)化搜索是相當(dāng)有效的,bge-large-en-v1.5即便在筆記本電腦環(huán)境中仍能夠有較大的檢索質(zhì)量提升。
一個(gè)很好的老選擇是有一個(gè)交叉編碼器。如果不完全信任基本編碼器,交叉編碼器可以對(duì)檢索到的結(jié)果重新排序。它的工作原理是把查詢和每個(gè)最高k個(gè)檢索到的文本塊傳遞給交叉編碼器,用一個(gè)標(biāo)記分隔,然后對(duì)它進(jìn)行微調(diào),相關(guān)的塊輸出為1,不相關(guān)的塊輸出為0。這種調(diào)整過程可以參考https://docs.llamaindex.ai/en/latest/examples/finetuning/crossencoderfinetuning/crossencoderfinetuning.html#。
最近 OpenAI 開始提供 LLM 微調(diào) API,LlamaIndex 有一個(gè)關(guān)于在 RAG 設(shè)置中微調(diào) GPT-3.5-turbo 以“提取”一些 GPT-4知識(shí)的教程。基本思路是獲取一個(gè)文檔,使用 GPT-3.5-turbo 生成一系列問題,然后使用 GPT-4根據(jù)文檔內(nèi)容生成這些問題的答案即構(gòu)建一個(gè)基于 GPT4的 RAG 流水線 ,然后在問答對(duì)的數(shù)據(jù)集上對(duì) GPT-3.5-turbo 進(jìn)行微調(diào)。通過對(duì) RAG 流水線的評(píng)估,可以初步確定經(jīng)過微調(diào)的 GPT 3.5-turbo 模型比原始模型能夠更好地利用所提供的上下文來生成其答案。
在論文 RA-DIT: Meta AI Research 的檢索增強(qiáng)雙指令優(yōu)化中,有一種更為復(fù)雜的方法,提出了一種在查詢、上下文和答案這個(gè)三元組上同時(shí)優(yōu)化 LLM 和檢索器(原論文中的雙重編碼器)的技術(shù)。這種技術(shù)被用于通過微調(diào) API 和 Llama2開源模型來微調(diào) OpenAI LLM (在原論文中) ,導(dǎo)致知識(shí)密集型任務(wù)指標(biāo)增加約5% (與使用 RAG 的 Llama265B 相比) ,并且常識(shí)推理任務(wù)增加了幾個(gè)百分點(diǎn)。有關(guān)實(shí)施細(xì)節(jié),可以參考https://docs.llamaindex.ai/en/stable/examples/finetuning/knowledge/finetuneretrievalaug.html#fine-tuning-with-retrieval-augmentation。
有幾個(gè)框架都可以應(yīng)用于RAG 系統(tǒng)的性能評(píng)估,指標(biāo)包括總體答案相關(guān)性、答案溯源性、可信度和檢索到的上下文相關(guān)性等等。
Ragas框架,使用可信度和答案相關(guān)性作為 RAG 檢索部分生成答案的質(zhì)量指標(biāo)和經(jīng)典的上下文準(zhǔn)召率。評(píng)估框架 Truelens 建議采用檢索與查詢的上下文相關(guān)性、答案溯源性以及與查詢的答案相關(guān)性,將這三個(gè)指標(biāo)作為 RAG 系統(tǒng)的性能評(píng)估三元組。其中,關(guān)鍵且最可控的指標(biāo)是檢索到的上下文相關(guān)性,其次是答案相關(guān)性和溯源性。
LangChain 有一個(gè)非常先進(jìn)的評(píng)估框架 LangSmith,可以實(shí)現(xiàn)自定義的評(píng)估器,還可以跟蹤 RAG 流水線的運(yùn)行狀態(tài),以使系統(tǒng)更加透明。而在LlamaIndex 中有一個(gè)rag_evaluator的包,提供了一個(gè)簡便工具使用公共數(shù)據(jù)集來評(píng)估RAG系統(tǒng)。
RAG 系統(tǒng)的主要挑戰(zhàn)除了答案的相關(guān)性和可信度之外,還有就是速度。然而,還有很多其他事情需要考慮,比如基于網(wǎng)絡(luò)搜索的 RAG,與Agent架構(gòu)的深度融合,以及關(guān)于 LLM 長期記憶的一些方式方法。即便如此,RAG 仍然有著廣泛的應(yīng)用范圍,我們在使用RAG落地應(yīng)用的時(shí)候, 希望本文中提到的這些技術(shù)能夠?qū)Υ蠹矣兴鶐椭?/span>
ps:新春佳節(jié)將至, 人民郵電出版社有促銷的活動(dòng), 在當(dāng)當(dāng)網(wǎng)上《一書讀懂物聯(lián)網(wǎng)》不足40元半價(jià)銷售,https://product.dangdang.com/29661591.html, 對(duì)物聯(lián)網(wǎng)及其相關(guān)架構(gòu)感興趣的朋友應(yīng)該是超值的機(jī)會(huì),順祝朋友們新春快樂,有所得,有所成!
聯(lián)系客服