人工智能與軟件架構

轉載本文需註明出處:微信公衆號EAWorld,違者必究。前端


本文目錄:程序員


1、人工智能(AI)的目標是加強智能(IA),而不是替代人類算法

2、應對軟件架構分而治之帶來集成的挑戰,探索智能的鏈接數據庫

3、從智能鏈接入手探索在軟件架構中應用人工智能編程

4、總結數組


由於 AlphaGo 的出現,過去的 2016 年可謂是人工智能元年。記得當時咱們正在蘇州封閉研發The Platform,工做之餘討論到人機對戰的真正意義,並不在於技術上的突破,而在於對人們固有知識的影響,人工智能的應用會如雨後春筍般誕生,之後沒有人工智能的軟件你都很差意思開口了。安全


你們都在問,本身的工做與人工智能有什麼關係,如何在本身的工做中應用人工智能,如何在軟件中植入人工智能的基因,使用人工智能應該從何處入手,學習人工智能應該從哪裏開始,更深層次的問題是人工智能可否代替人類,做爲一個程序員,在人工智能可否代替人類寫程序的問題上,根據咱們團隊的實踐介紹一下如何在軟件中應用人工智能。微信


1、人工智能(AI)的目標是網絡

加強智能(IA),而不是替代人類架構


人工智能並非一個新概念,40年代維納的《控制論——關於在動物和機器中控制和通信的科學》就是人工智能。但早年的人工智能受限於計算能力,更多在解決模型的計算速度和精度上,近年來隨着雲計算技術的發展,計算能力提升了,隨着大數據的發展,更復雜的計算問題能夠用更多的數據進行修正,人工智能的可用性大大提升。可是咱們從目前人工智能應用的狀況能夠看到,人工智能並不能替代人類,例如在圖像識別、語音方面的突破,僅僅是讓機器更加聰明而已,還遠遠沒有達到人類的程度,做爲人類的智能助手更加合適。


理清人工智能、機器學習、深度學習、統計等基本概念之間的關係


把人工智能的方法應用到軟件中,咱們先梳理清楚幾個概念之間的關係:人工智能(Artificial Intelligence)是一個大的概念,是讓機器像人同樣思考甚至超越人類;而機器學習(Machine Learning)是實現人工智能的一種方法,機器學習最基本的作法,是使用算法來解析數據、從中學習,而後對真實世界中的事件作出決策和預測;深度學習(Deep learning)又是機器學習的一種實現方式,他是模擬人神經網絡的方式,用更多的層數,更多的神經元,而後給系統輸入海量的數據,來訓練網絡。而統計學是機器學習和神經網絡的一種基礎知識,從傳統分工來看,統計學通常是數學、統計等專業研究的方向,而機器學習是計算機科學的研究方向,可是目前你們的研究成果愈來愈異曲同工,有統計學的大師就認爲統計實際上一直在從事機器學習的工做。



對於深度學習、統計的專家來講,他們更加關注於模型、算法等等,找到能夠普適性解決問題的辦法,而對於咱們應用來講,具體的算法實現不須要咱們考慮太多,而是找到適合的場景、合適的模型、匹配的算法,因此,應用人工智能其實是一個計算機、統計、知識工程、行業知識的一個交叉應用,在常常涉及到的應用中,我通常在處理結構化、半結構化數據時優先考慮傳通通計學的方法,例如分類、數據相關性、迴歸等,而處理非結構化數據時(例如圖像、視頻、文本)優先考慮深度學習的方法,但這些方法也須要有統計學知識。因此,須要補課:線性代數、數理統計、Python,我以爲《機器學習實戰》這書入門不錯,上述幾方面知識都介紹了。


應用人工智能實現加強智能的三個層面


應用人工智能的時候,人們會有一個誤區,老是但願獲得一個意想不到的結果,也就是但願探索出新知識。常常有人問我,獲得的結果好像沒有什麼我不知道的,我說這就對了,由於你是專家,要是計算機獲得的結果都是不可知的,你怎麼能相信他,例如AlphaGo下的棋,絕大多數都是人類已知的,很是少很是少的狀況下,下出一招另類,這已是一個頂天星的水平了。不少人失望了,這還有啥意思,其實意義很大:


(1)計算機可讓常人快速得到以往專家才能具有的知識,例若有經驗的客戶經理,確定很是瞭解客戶的狀況,誰是優質客戶,誰須要什麼產品等等,不須要計算機,可是經過用戶畫像等人工智能的手段,計算機可讓經驗不夠豐富的人,也具有了上述經驗,這個作法價值就很是高,畢竟專家是少的;


(2)幫助專家減小重複性的工做,例如醫生在作病理檢測時,絕大多數沒有生病的狀況和有典型病理特徵的狀況,機器均可以提醒醫生,節約醫生的寶貴時間。如此看來,咱們就會理解,人工智能不是替代人,而是給人類增長一個智能的助手,是加強智能(IA  Intelligence Augmentation)


計算機做爲一個智能助手,能夠在不一樣層面和手段幫助咱們,我把他分爲機械智能、實現意圖的智能和創造意圖的智能三個方面:


(1)機械智能,咱們目前從事的主要工做都是這個,事先設定規則(代碼也是規則),讓計算機完成大量重複計算,充分利用計算機的計算能力,替代人的手工勞動,這是一個以規則爲核心的模式,而這些規則來自於人現有的知識;

(2)實現意圖智能,人知道最終結果是什麼,可是並不告訴計算機採用什麼樣的規則計算,經過大量數據訓練計算機找到規則,而後再讓計算機完成大量重複計算,計算機究竟找到的規則是什麼,有可能人並不必定能理解,其實每每也不須要理解,把計算機當成了黑盒;

(3)創造意圖智能,也就是讓計算機本身找到人並不知道的新知識,這也是咱們最嚮往的場景。


從具體的實現層面看,第一種狀況無疑是最多的,咱們須要提煉總結規則,用好第一種狀況很重要,第二種狀況之前相對少一些,但偏偏是目前須要改進的,在第二種狀況下咱們每每優先用統計學的方法處理結構化、半結構化數據(例如格式化日誌),用深度學習的方法處理非結構化數據,這就須要讓咱們的團隊具有人工智能的思惟。


實踐人工智能應用須要新思惟,不能再用規則理解計算機實現智能的方式


實踐人工智能,須要在在思惟上進行調整。咱們每每習慣於用制定規則的方式指揮計算機,輸入、計算規則和輸出結果都是已知的,也就是我上面說的機械智能方式。但後兩種模式就不是規則方式了,由於規則是計算機找到的,這也就是常常說的數據訓練。這裏我舉一個咱們本身實現的例子,讓你們理解一下什麼是模型、算法和數據訓練。


先說一個背景,咱們在梳理現有企業數據架構的時候,須要創建數據間的關聯,用人進行梳理費工費力,咱們就打算用計算機自動完成一部分,而後人工修正,這就是一個加強智能(IA)的例子。這裏面就有一個狀況,若是數據庫中沒有創建外鍵,如何把這種實際的外鍵關係找出來,咱們就用這個例子解釋一下機械智能和實現意圖智能的方法:


(1)用規則的方式查找外鍵關係。首先要定義規則,外鍵關聯的規則包括字段類型一致、長度一致、包含相同數據等等,而後在全部數據中遍歷,進行匹配。這種方式須要有完整的數據,並且是否外鍵關係的判斷規則每每有些模糊,在沒有獲得全量數據時有必定侷限性;


(2)用統計學方法查找外鍵關係。首先,咱們定義出字段的特徵(相似用戶畫像),字段特徵是一個向量,就是一個一維數組,包括表名、字段名、字段類型、註釋、樣例數據最大長度、樣例數據最小長度等等,因爲表名、字段名不是數值,咱們要把他們變成數值,能夠和同一個標準字符串做比較,也就是經過移位的方式把字符串移動成標準字符串,移動次數越少,類似度就越高,這樣就獲得了一個真正的一維數組(向量)了。


其次,咱們拿出一部分已知關係的表和字段,做爲訓練樣本,逐一計算兩個字段之間的相關係數(相關係數的計算方法是現成的,我這裏就不介紹了,一上公式我就暈,Python的發行版Anaconda裏面就有,用了這個就體會到 Python 是最好的語言了),相關係數高的說明特徵相似,認定爲外鍵關係。這時候人工判斷一下,若是結果不錯,那這個模型就是正確的,若是結果很差就換一種相關係數計算方法,或者改變數據特徵,或者對數據特徵進行加工,總之,外鍵特徵做爲一個客觀存在,必定可以找到符合的特徵,這就是數據訓練。經過數據訓練,找到合適的字段特徵(模型)和計算方法(算法),也能夠交給計算機作處理了,把全部的外鍵找出來。


你看,這裏沒有定義規則,處理方法是經過數據訓練的方式,讓計算機本身找出來的,我不須要知道相關係數這玩意究竟是什麼意思,這就是上面說的,計算機是一個黑盒。


須要說明的事,在上述例子中,我簡化了很多動做,實際上最開始還找出來不少不是外鍵關係的字段,例如 createTime,咱們還要把這種噪音字段的特徵訓練出來,剔除噪音。


這個示例說明了應用人工智能時不一樣的兩種思惟模式,簡單的說不能再用創造規則的方式指揮計算機,而是訓練計算機本身找出規律。


上面咱們分析了人工智能相應的基本概念,人工智能的幾種模式以及應用人工智能時須要的思惟突破,下面咱們從軟件架構發展和麪臨的挑戰,看看應用人工智能時的切入點在哪裏,哪裏更容易爆發出人工智能的火花。


2、應對軟件架構分而治之

帶來集成的挑戰,探索智能的鏈接


什麼是軟件架構,在InfoQ出版的《聊聊架構》中講的很清楚(感謝老王,總結很是到位),軟件架構就是(1)根據問題肯定系統邊界;(2)按必定原則進行切分;(3)創建不一樣模塊間的溝通機制;(4)總體性交付軟件功能。可見,架構的關鍵是分而治之的哲學,但切分是爲了軟件研發、運維方便,軟件的目標是總體交付,分與合存在着矛盾,這一矛盾是由集成解決的,可是集成每每是複雜的,你們在架構方面的分享,也以如何切分居多,如何集成相對較少。


集成工做的複雜度影響了複雜系統的研發


Unix的實踐無疑對軟件架構有着巨大的影響,作一個事情,作到最好,一直是 Unix 風格所倡導的,但「在理想世界中,Unix程序員只願意手工打造小巧完美的軟件寶石,每一個都那麼小巧、那麼優雅、那麼完美。然而現實中很不幸的是,太多複雜問題須要複雜的解決方案。僅僅十行的程序,再優雅也沒法控制噴氣式客機。那兒有太多的裝備、太多的通路和界面,太多不一樣的處理機,太多不一樣操做人員定義的子系統,他們甚至連基本的約定都沒法統一。即便可以成功地將航空系統全部的個體軟件部分作的優雅,但拼裝結果極可能是一堆龐大、複雜、糟糕的代碼… 噴氣客機的複雜是必然的。過去有個尖銳的觀點,不能爲簡單性而犧牲功能,由於飛機必需要能飛。正是這個事實,航空控制系統並不會產生關於複雜度的聖戰----Unix程序員每每敬而遠之。「(摘自《Unix編程藝術》)。


不幸的是,咱們面臨的每每是複雜性的系統,片面理解Unix風格分而治之每每帶來更大的集成難度。爲了下降集成的難度,咱們每每採用巨石型的系統架構,用一個大一統的方式設計系統,僅僅在系統內部進行模塊的拆分,用codebase和規範進行約束,走上了和Unix風格背道而馳的道路。當性能和可維護性壓力到來後,這樣的系統又不得不進行拆分:我過去經常看到,當軟件系統達到 100 萬行代碼規模時,人們會以爲維護困難,產生了強烈的拆分念頭,當達到 300 萬行代碼規模時,人們每每再也按耐不住拆分的慾望,當達到 500 萬行代碼規模時,再保守的組織也會做出拆分的決定。


軟件架構中複雜的集成工做須要利用人工智能方式簡化下來


回顧一下解決集成問題的歷史,咱們會發現較早的集成架構模式來自於 Unix,就是衆所周知的管道(Pipe)模式。Pipe模式將數據傳遞到一個任務序列中,管道扮演着流水線的角色,數據在這裏被處理而後傳遞到下一個步驟。管道模式做爲一種最基本的方式,理論上能夠解決全部集成問題,但涉及到具體問題時,就須要針對不一樣狀況作應對,針對各類複雜的狀況,能夠總結出更多的模式,《企業集成模式》(EIP)一書中圍繞消息集成,總結出若干集成模式,可謂是消息集成的集大成式總結。


但EIP的集成模式主要針對系統間後臺服務的集成,SOA架構提出了以Portal(前端集成)、BPM(流程集成)、ESB(服務集成)、DI(數據集成)以及事件/消息集成的多層面集成體系,更加系統性的爲集成工做提供指導。SOA的集成方式須要一系列的集成基礎設施支持,屬於一種中心化的集成方式,咱們能夠稱之爲MiddleBox的方式,在微服務架構提出後,咱們會採用把集成邏輯與業務功能部署在一塊兒的去中心化集成方式,能夠稱之爲MiddlePipe的模式。


集成方式一路演進下來,主要是集成的手段上不斷翻新,多種框架和基礎設施愈來愈多的解決了非功能需求,例如 ESB 能夠解決路由、安全、流控等問題,必定程度上減小了集成的工做量。但集成的業務複雜度還存在不少,這裏我列舉幾個常見的問題:


(1)數據的查找問題。針對業務需求,須要使用已存在的數據和服務,但在企業環境中,系統、服務、數據衆多(想象一下具備10多萬服務、10多萬數據標準的狀況),想找到適用的服務和數據,不是一件容易的事情,通常咱們都要依賴專家在這方面的知識,經過整體設計指定了數據的流向,這依賴於專家的能力,專家的能力也是慢慢積累起來的。咱們須要幫助業務更快速的找到數據和服務,幫助專家快速實現積累,減小重複勞動。


(2)數據的適配問題。經過服務方式進行集成,原子服務每每須要大量的輸入參數。舉個例子,調用一個發短信的接口,不只僅是收信人電話號碼和短信內容,還要包括不少業務含義的參數,例如發信人的姓名、組織、發信的系統、發信的緣由、發信時和客戶接觸的渠道(客服渠道、網點渠道、網銀渠道、自助終端等等)、發信時關聯的產品,這些信息是能夠用來計算成本、控制次數、避免重複騷擾客戶;用戶名、密碼、驗證碼、發送時間等這是用做安全驗證的;優先級、發送渠道等是用來作流量控制的;流水號、全局業務ID、請求ID、請求時間等等是用來作監控的。上述信息來自與每次發短信的上下文,在實際開發期間就要作不少的賦值、轉換工做,將上下文的信息傳遞給服務,這種轉換就像下圖那樣,典型的面多了加水,水多了加面。咱們須要根據當前上下文和服務的特徵,自動的進行一些適配,避免人工的重複性勞動。



(3)系統的聯動問題。當一個業務事件產生時,有不少相關聯的系統都會須要做出關聯性反映,例如一個航班延誤,就會涉及機票的改簽、酒店的改期、接車服務的改期、會議安排的變動、日程計劃的變動。通常咱們會設計一個事件中心,爲各個系統開發出監聽的程序,當事件到來時判斷上下文信息,決定產生的動做。若是事先沒有設定的規則,就沒法產生聯動,咱們期待更加自動化的創建這種聯動關係,讓計算機智能的產生動做而不只僅經過人爲設置。


相似問題還有不少,咱們期待可以更加智能的集成。


須要集成的部分不僅是軟件自己,軟件過程也是一個複雜的集成/協做工做


分而治之的軟件須要經過集成方式總體交付,軟件的生產過程也是一個多人、多組織協做的過程,也須要集成。把軟件當作是一個產品,產品就有策劃、研發、運營和退出各個階段,每一個階段可能由不一樣的人或組織完成。軟件的研發階段就是一個一個項目的實施過程,包括立項、執行和完工。這樣的過程組織起來,就是一條軟件生產的流水線。從早期瀑布式的軟件研發,到後來敏捷研發過程、CMM,到目前風頭正勁的DevOps,都是在解決軟件生產流水線不一樣階段的協做問題,敏捷針對軟件定義、設計、構建(開發)階段的協做,持續集成是構建(開發)與測試階段的協做,持續交付是從定義階段到部署(交付)階段的協做。



協做中面臨的問題,就是集成的問題,咱們能夠想到不少,這裏也舉幾個例子:


(1)需求、設計與構建(開發)的溝通問題。咱們須要把需求/設計的知識圖譜化、條目化,自動與開發工做作必定程度的適配,減小需求/設計到代碼的轉換工做; 

(2)構建(開發)與測試的溝通問題。咱們須要根據服務和數據特性以及積累的歷史數據,自動產生測試用例和測試方法;

(3)運營的溝通問題。咱們須要經過應用畫像、資源畫像等方式,服務與物理資源之間創建鏈接,快速定位問題,進行容量預測,實現更智能的運維。


在軟件架構中應用人工智能的目標:經過加強智能方式實現軟件系統與軟件工程的智能鏈接


應對複雜集成的挑戰,咱們能夠引入人工智能的思路,將人與軟件、物體與軟件之間、軟件與軟件之間、軟件生產線各環節之間經過知識使能的方式集成起來,在傳統徹底依賴規則進行集成的方式基礎上,採用新的集成方法:以上下文信息爲輸入,利用專家已有的知識,經過數據訓練和強化學習的方式,讓計算機可以理解集成的意圖,成爲咱們的智能助手,幫助咱們實現智能的鏈接,進而可讓計算機探索新的鏈接知識。這裏,我把鏈接也分爲三個層面:機械鏈接、基於知識鏈接、創造知識鏈接。


3、從智能鏈接入手探索

在軟件架構中應用人工智能


從何處入手,探索人工智能在軟件中的應用,是你們最關注的話題,這裏我把普元在探索人工智能初期經歷的幾個案例,給你們作一個介紹。普元董事長劉亞東博士早年就從事神經網絡的研究,他指出在目前並行計算等技術充分發展的今天,算法已經不是人工智能的瓶頸,應用人工智能須要有兩個突破(1)找到人工智能應用的切入點(2)團隊具有人工智能應用的思惟。因此咱們在應用人工智能的時候,不是成立一個專門的小組作研究,而是百花齊放的方式。瞭解普元的朋友會知道,普元的研發分爲雲計算&SOA、大數據、移動、工程效率與技術平臺、產品支持中心幾個團隊,咱們讓每一個團隊從數據+鏈接方向上入手,各自探索人工智能在領域上的應用場景,經過找到切入點和初步實踐,逐步創建團隊的人工智能思惟。其中雲計算&SOA團隊的方向是經過服務畫像方式解決微服務的智能運維與智能匹配,大數據團隊的方向是經過知識圖譜實現數據自服務,移動團隊的方向是UI的智能化開發,工程效率與技術平臺團隊的方向是深度學習在流程與智能製造的應用。因爲篇幅有限,這裏我把普元大數據團隊和移動團隊所作的工做作一個介紹。


案例一:基於知識圖譜,實現數據的自服務能力


先簡單介紹一下背景:你們常常會聽到有人問咱們有哪些數據,這些數據在哪裏,如何獲取數據的問題,可否創建一個平臺,讓咱們象百度搜索同樣,根據咱們的知識(業務術語)找到相關的數據,提交申請,獲得數據,這就是一個獲取數據的自助服務。


以往數據在哪裏每每經過人工梳理完成,咱們但願可以自動化一些,爲專家提供一個智能的助手,這裏的工做分爲三部分:


(1)創建知識圖譜。人進行數據搜索是經過業務術語(知識)來搜索的,而知識之間是有相互聯繫的,例如水果和蘋果是上下位關係(後者是前者的具體體現),搜索是除了要列出直接結果,還須要顯示一些關聯的知識,這就要創建知識圖譜。簡單說知識圖譜就是概念、屬性以及概念之間的關聯關係, 這個關係能夠手工創建,咱們經過對政策、法規、需求、數據庫comments、界面等多種來源,採用天然語言處理等方法,能夠創建起部分的知識圖譜,輔助專家的工做;


(2)梳理技術元數據。整理各個系統內部數據,以及數據之間的關係,造成數據地圖。這裏的難度是數據之間的關係,例如數據的血緣關係、影響度關係、關聯關係、主數據關係等,這裏咱們採用字段特徵的相關性、數據處理邏輯的詞法/語法分析等手段,配合強化學習來完成,前面列舉的查找外鍵示例,就是一部分;


(3)創建知識圖譜與技術元數據之間的關係,這裏就要經過分析界面/服務與代碼之間的關聯,創建起映射關係最終效果就是,使用數據搜索,錄入但願查找的業務術語,獲得相關結果,查看樣例數據,若是是須要的數據,提交使用申請,若是不是,繼續根據相關知識進行數據探索。提供數據自服務能力,就是在應用的設計師、數據科學家或者業務分析師與數據之間創建起鏈接,咱們的團隊就是從鏈接的思路出發,找到了人工智能的切入點。實際上,數據自服務包含有找、獲、用等衆多環節,我這裏說的是找的環節如何實現,這種找的方法,也不可能100%準確,還須要專家進行調整,以及經過強化學習等手段不斷修正,能夠看出,應用人工智能也是一個漸進完善的過程。


案例二:經過深度學習,實現移動UI的智能化開發


移動UI的智能化開發,是咱們移動團隊應用人工智能的第一個嘗試,如今看來,就是在UI設計師與開發工程師之間創建鏈接。你們會發現,設計師的設計在變成代碼實現時總會有誤差,即便一個像素的差別,也會影響界面的效果,以往咱們採起不一樣業務模板的方式,創建一些規範對設計和開發作約束,後來移動團隊以爲,能夠用深度學習的方式作一些嘗試,尋找不一樣的界面設計效果,首先經過數據標籤方式肯定頁面的風格,再經過圖像片斷的方式學習和識別設計稿中的組件,最終通過屢次的處理,變成一個樹狀的結構,把這個樹狀結構與代碼進行映射,就產生了和設計圖一致的代碼。


這個案例中,基於圖片的神經網絡學習是一個關鍵技術,可是若是單純使用這個技術,計算量會沒法承受,因此咱們將處理過程分紅了幾個階段,每一個階段進行分類,每一個階段均可以配合強化學習的方式,由人工指定策略,指導計算機的學習,提升了工程化的能力(相似作法在深藍對陣卡斯帕羅夫的時候就有應用,有一位特級大師會指導深藍當前的策略,例如進攻仍是防守,具體招數由深藍決定)。


上述兩個案例中,咱們首先在各個領域中找到可能的切入點,針對不一樣場景使用了不一樣的方案,並非都採用了深度學習/神經網絡的方法。咱們沒有首先從Tensorflow等框架學起,而是在結構化、半結構化優先使用統計方法,非結構化數據再使用深度學習,是用業務驅動的方式逐步推動,有效的避免了「深度氾濫」。


4、總結


將來的軟件必將是人工智能的軟件,但人工智能是經過技術手段實現智能加強,幫助普通人迅速具有部分專家的技能,幫助專家減小重複性的勞動,探索新的知識,而不是取代人。應用人工智能,應該在數據+鏈接的模式下,從智能的集成入手,探索人工智能在軟件中的應用。而這種探索,既包括傳統利用規則實現的機械智能,也包括利用統計學和深度學習方法支撐的實現意圖智能,還有創造意圖/尋找新知識的探索,而統計學方法每每用在結構化數據和半結構化的數據中,深度學習每每要利用非結構化數據。總之,人工智能是計算機科學、統計學、知識工程、領域知識的一個交叉學科,不能僅僅站在某個角度去理解和嘗試,正所謂「君子不羣」。


5月18日(本週四)上午9:55本文做者焦烈焱將在2017中國雲計算技術大會(北京悠唐皇冠假日酒店)主會場發表《人工智能在企業軟件中的應用》演講,歡迎屆時蒞臨交流。


關於做者 

焦烈焱

EAII-企業架構創新研究院 常務理事

2001年加入普元信息,現任CTO,全面負責普元信息技術與產品的運營工做,公司技術發展戰略的重要決策人。焦烈焱在企業技術架構研究方面有二十餘年的經驗,長期致力於分佈式環境的企業計算、 SOA與雲計算技術研究與實踐。加入普元信息後組織完成一系列核心產品的研發工做,包括SOA應用平臺、以BPM &/ESB爲核心的業務集成平臺、以復瑣事件處理/數據治理/做業調度爲核心的大數據平臺,期間主持了中國工商銀行、中國建設銀行等多家大型企業技術平臺的規劃與研發。著有《SOA中國路線圖—實施版》一書。


關於EAWorld

微服務,DevOps,元數據,企業架構原創技術分享EAii(Enterprise Architecture Innovation Institute)企業架構創新研究院旗下官方微信公衆號。


微信號:eaworld,長按二維碼關注


本文分享自微信公衆號 - EAWorld(eaworld)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索