整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          B端設(shè)計指南:“按鈕”究竟應(yīng)該如何設(shè)計?

          鈕是最常使用的組件之一,但是在與人交流時,還是會覺得大家存在很多誤區(qū),所以本文將圍繞如何使用按鈕展開分析,希望能給大家?guī)硪恍┬碌乃伎肌?/p>

          按鈕是任何用戶界面當(dāng)中(無論是桌面還是移動用戶界面)必備的交互元素:甚至可以說,如果頁面中沒有一個按鈕,整個頁面設(shè)計將是不完整的。在日常生活中,按鈕也是隨處可見的,一個電燈開關(guān)、遙控器按鈕,現(xiàn)實生活中按鈕反復(fù)的出現(xiàn)也可以幫助我們不斷去理解屏幕世界中按鈕應(yīng)該如何操作,從而衍生出屏幕世界中的按鈕的具體形態(tài)。

          人機交互中最重要的就是把我們從小到大對于這個世界的認(rèn)識映射到屏幕世界中,比如蘋果最為經(jīng)典iOS的滑動解鎖。

          而到了屏幕世界中,控件的設(shè)計更應(yīng)該與物理世界保持相對的一致,這也是按鈕設(shè)計中,尤為重要的一個環(huán)節(jié)。

          最近常問身邊的朋友,按鈕究竟是什么?

          他們多數(shù)的回答:“按鈕就是按鈕唄,還能是什么~”

          因為對于他們而言,按鈕不就是一個操作區(qū)域加上文字,沒什么特別的,也正因如此,對于按鈕的具體構(gòu)造也不太了解。這篇文章主要是根據(jù)自身的工作經(jīng)驗,結(jié)合當(dāng)下對于按鈕設(shè)計的理解,去分析如何進(jìn)行更合理的按鈕設(shè)計。

          聊聊按鈕的痛點

          對于每個設(shè)計師來說按鈕并不陌生,在每天的設(shè)計中,都會使用按鈕進(jìn)行頁面設(shè)計;但又不是每一個設(shè)計師都能夠?qū)粹o設(shè)計好,因為它存在三個方面的復(fù)雜性:

          • 它使用的場景過多:不是每個場景都需要相同的按鈕,比如在登錄頁當(dāng)中,登錄和注冊就是使用不同的按鈕形式。這些情況特別在B端產(chǎn)品中,業(yè)務(wù)在每個步驟中需要突出和強調(diào)的點不同,導(dǎo)致設(shè)計師很難通過具體場景進(jìn)行按鈕設(shè)計;
          • 按鈕出現(xiàn)的頻率太高:B端產(chǎn)品中,每個頁面當(dāng)中都會有按鈕不停的重復(fù),而高頻的出現(xiàn)會讓我們感到麻木,導(dǎo)致很多設(shè)計師都將其忽略;
          • 按鈕形式太多:在我總結(jié)的按鈕形式當(dāng)中,一共分為10類,且情況多種多樣,很多時候都沒有意識到不同形式之間的差距,導(dǎo)致亂用混用。

          因此一個看上去小小的按鈕,其實經(jīng)常會困擾著我們,如果剛開始沒有將按鈕進(jìn)行整體的梳理,那么在你的設(shè)計過程中,按鈕會經(jīng)常打斷自己的設(shè)計思維,為了讓大家能夠?qū)Π粹o有更深的理解,我將按鈕進(jìn)行系統(tǒng)的拆解,結(jié)合實際案例,能夠使按鈕更淺顯易懂。

          在文章按鈕類型的分析中,我將按鈕分為兩大類、十小類,將其分類也是為了更好的為大家去分析每一個按鈕所涉及到的狀態(tài),當(dāng)我們理解按鈕之前,你需要了解它的內(nèi)部構(gòu)造。

          一、按鈕類型

          首先,拋出一個問題給大家,下圖中,共有幾種按鈕形式?分別是什么?給大家五秒鐘時間思考。

          如果你對上圖的按鈕形式并不完全了解,建議你拿好小本本,做好筆記~

          在開始講常見按鈕類型前,我們必須要搞清楚一個重要的知識點:按鈕狀態(tài)。

          1.1 什么是按鈕狀態(tài)?

          按鈕狀態(tài),可以讓用戶知道這個按鈕當(dāng)前是在進(jìn)行哪一種操作,方便幫助用戶進(jìn)行判斷。

          常見的按鈕狀態(tài)分為:正常狀態(tài)(Normal)、聚焦?fàn)顟B(tài)(Focus)、懸停狀態(tài)(Hover)、激活狀態(tài)(Active)、加載狀態(tài)(Loading)、禁用狀態(tài)(Disabled),下面分別對這六大狀態(tài)進(jìn)行拆解。

          正常狀態(tài) (Normal):除了其他五種狀態(tài)外的情況都是正常狀態(tài),它是按鈕最為常規(guī)的狀態(tài)形式,也是設(shè)計師必須設(shè)計的一種狀態(tài)。

          聚焦?fàn)顟B(tài) (Focus):主要是用于展示當(dāng)前電腦光標(biāo)所在的具體位置。聽起來有點玄乎,我來講他背后的原理,主要是方便一些鍵盤使用的用戶,可以使用Tab鍵或者方向鍵來對網(wǎng)頁進(jìn)行訪問輸入。

          比如在Mac OS 以及 Windows的使用中,通過點擊Tab,便展示出文件的Focus狀態(tài)。

          Focus狀態(tài)是一個非常重要的交互形式,但是很多設(shè)計師都會忽略,甚至在很多網(wǎng)站,直接就是將這個樣式所去除,導(dǎo)致使用Tab鍵無法獲取聚焦的反饋,比如常見的百度、Google再到各大操作系統(tǒng)都會有這類反饋,去除這類反饋,會導(dǎo)致用戶無法用方向鍵控制光標(biāo)位置,在很大程度上降低用戶使用的可能性。

          懸停狀態(tài) (Hover):在桌面端的設(shè)計當(dāng)中,即使用戶知道它是可以點擊的,但是你還是需要設(shè)計懸停狀態(tài),表明鼠標(biāo)現(xiàn)在正在按鈕上。平板電腦和移動端的設(shè)備上用永遠(yuǎn)不會展示懸停狀態(tài),因為你的手指是無法在屏幕上進(jìn)行懸停的(雖然IPad OS 更新了13.4版本后,會有Hover態(tài)的出現(xiàn),但是是通過鼠標(biāo)進(jìn)行操作,因此這里不予以討論)。

          激活狀態(tài) (Active):激活狀態(tài)因為叫法不同,在有的地方也稱之為Press狀態(tài),它的表現(xiàn)就是將按鈕按壓下,將顏色變深同時會涉及到內(nèi)陰影等效果的出現(xiàn)。

          禁用狀態(tài) (Disable):按鈕禁用狀態(tài)作為最難設(shè)計的狀態(tài)之一,主要在于禁用狀態(tài)的表現(xiàn)形式以及禁用狀態(tài)與激活狀態(tài)之間如何的切換,我具體來分析一下兩個難點。

          難點一:禁用狀態(tài)在顏色上首先會給人灰色塊的感覺,行業(yè)里也稱之為置灰,在設(shè)計上,也需要注意光標(biāo)移動時需要展示禁用光標(biāo),即讓前端大哥將Cursor的hover狀態(tài)更改為not-allowed,你可以優(yōu)雅的在前端面前裝個X(之后會出一期,簡單聊聊我與前端如何協(xié)作如何裝X)。

          難點二:禁用與激活狀態(tài)的切換,比如在一個注冊頁面中,需要姓名與電話必填,當(dāng)用戶沒有填寫完成姓名與電話時,應(yīng)該將按鈕置灰,提示用戶不可以點擊,當(dāng)用戶填寫完成必填字段后,將禁用按鈕轉(zhuǎn)變?yōu)榧せ畎粹o,提示用戶可以點擊登錄。

          加載狀態(tài)/Loading:按鈕需要時間進(jìn)行加載的一種狀態(tài),通常會被用戶忽略,但是在B端產(chǎn)品中,Loading狀態(tài)尤為重要,這里有很多細(xì)節(jié)和小技巧,展開講篇幅太大,在文中4.3(按鈕細(xì)節(jié))會詳細(xì)解答。

          1.2 主按鈕 (Primary Button)

          主按鈕為頁面中按鈕區(qū)最為核心的操作,在日常場景中,主要按鈕一般都為新建、編輯、保存這一類正向的操作,強調(diào)頁面中最為核心的功能,能夠讓用戶一看到主按鈕就明白大致在頁面中需要如何操作。

          但在主按鈕的使用中,要遵循以下兩個原則:

          1)在頁面當(dāng)中,按鈕區(qū)域的主按鈕最好只有一個,否則會對頁面的主要功能造成干擾。

          2)并不是每一個頁面都需要有主按鈕,不要因為頁面缺失主按鈕而強行加上。因為在實際使用中,時常遇到按鈕之間為平級的關(guān)系,強行添加,容易造成頁面層級混亂。

          在主按鈕中,按鈕狀態(tài)的設(shè)計也會跟隨物理世界進(jìn)行相應(yīng)的映射,因此在設(shè)計時需考慮現(xiàn)實生活中的狀態(tài)。

          比如用戶的Hover時,一般都將按鈕抬起并亮度增加,其目的是為了提示用戶可以點擊,而用戶在按下時,用加黑來表示用戶按下的狀態(tài),與現(xiàn)實生活中按鈕的狀態(tài)類似,因此按鈕狀態(tài)應(yīng)該映射物理世界。

          1.3 次按鈕/標(biāo)準(zhǔn)按鈕(Default Button)

          次按鈕在頁面中出現(xiàn)最為頻繁,在日常使用中,如果你不太確定使用何種按鈕時,那使用它,大概率沒有錯。因為它運用廣泛,出現(xiàn)頻率也最高,因此也被人們稱為標(biāo)準(zhǔn)按鈕。

          在次按鈕的設(shè)計形式中,我們團(tuán)隊將設(shè)計形式分為兩類:

          第一類 字線型

          此按鈕整體以文字+邊框的形式,這類形式在視覺層面上感知較弱,適合幾個按鈕同時展示,在B端項目中,字線型也是在使用中最為頻繁的形式。

          第二種 字面型

          字面型更偏向表達(dá)按鈕整體,常見于各類移動端的按鈕當(dāng)中,整體的表達(dá)也更適合移動端這類屏幕尺寸較少的設(shè)備當(dāng)中,更符合卡片化設(shè)計的思路,反而不太適合桌面端的設(shè)計。

          1.4 文字按鈕/鏈接(Text Button/Link)

          文字按鈕為頁面中視覺層級較低的按鈕形式,因而可以在頁面中大面積的重復(fù)使用,文字按鈕與鏈接(Link)基本一致,且沒有太多區(qū)分,所以在設(shè)計上,文字按鈕與鏈接基本相同。

          文字按鈕重復(fù)的出現(xiàn),以表格頁面當(dāng)中的操作列表最為突出,因為表格當(dāng)中常用的操作最好能夠直接展示出來,因此表格中基本都采取文字按鈕的形式。

          1.5 圖標(biāo)按鈕(Icon Button)

          圖標(biāo)按鈕為頁面中控件占比最小的按鈕,所以在頁面中的使用也是最為高效的。因為沒有了文字元素,會導(dǎo)致用戶在圖標(biāo)的理解上出現(xiàn)偏差。為了解決這一問題,主要是通過用戶在Hover時使用展示Tooltip提示按鈕的含義,同時建議在圖標(biāo)按鈕的使用上多為高頻且易理解的圖標(biāo)。

          我舉一個簡單例子,在桌面端產(chǎn)品中,幫助文檔一定是非常重要的一個入口,當(dāng)用戶對頁面中的功能有所疑惑時,可以通過此來幫助用戶進(jìn)行理解,通常需要在大多數(shù)頁面當(dāng)中展示幫助中心的入口,這時圖標(biāo)按鈕就變得最為合適。

          因此,我們可以得出圖標(biāo)按鈕的應(yīng)用場景通常為:當(dāng)頁面中需要高效的展示一個或幾個圖標(biāo)時,同時圖標(biāo)按鈕的展示最為頻繁時,當(dāng)同時滿足以上兩點,使用圖標(biāo)按鈕就是一個更優(yōu)的解決方案方案。

          1.6 按鈕菜單(Menu Button)

          按鈕菜單為頁面中許多操作的集合,通常是將高頻的操作以及一些低頻的操作進(jìn)行整合,組成的按鈕菜單。這樣既能夠減少頁面元素的冗雜,同時也能夠滿足業(yè)務(wù)對于功能的需求。

          舉個例子,在表格頁面當(dāng)中,B端設(shè)計師最常見到的按鈕菜單就是新建,這類新建按鈕其實是必不可少的,同時業(yè)務(wù)需要,還需要多個業(yè)務(wù)按鈕進(jìn)行展示,按鈕菜單的出現(xiàn),幫助用戶進(jìn)行按鈕的整理,同時也滿足業(yè)務(wù)需求。

          1.7 按鈕中加圖標(biāo)(Icon add Button)

          這其實是主按鈕的一種衍生,通過圖標(biāo)對主按鈕的含義進(jìn)行解釋,從而幫助用戶提高這個按鈕的識別性。如果一個按鈕你想比主按鈕更加強調(diào),那便可使用在按鈕中添加圖標(biāo),這樣既能夠強化圖標(biāo)的含義,同時也加深了用戶對于按鈕的印象。

          在六個常見按鈕形式中,我們根據(jù)重要的優(yōu)先級,給常見按鈕進(jìn)行一個簡單的排序:

          圖標(biāo)按鈕-按鈕菜單-主按鈕-次按鈕-文字按鈕-圖標(biāo)按鈕

          二、特殊按鈕類型

          2.1 危險按鈕(Danger Button)

          危險按鈕在刪除操作中最為常見,通常是為了警告用戶,這個數(shù)據(jù)刪除不可恢復(fù),讓用戶謹(jǐn)慎考慮。在常見的刪除操作中,都需要用戶進(jìn)行二次確認(rèn),避免用戶誤操作。

          當(dāng)然,在實際業(yè)務(wù)中,危險按鈕不宜過多,如果業(yè)務(wù)當(dāng)中無法避免,需要展示多個刪除按鈕時,推薦采取圖標(biāo)按鈕進(jìn)行展示或者Hover過后將其呼出。

          2.2 幽靈按鈕(Ghost Button)

          幽靈按鈕,看它的名字就能想到它的作用:像幽靈一般透明的存在。

          它沒有使用復(fù)雜的顏色、樣式,而是用線條表示外部輪廓,證明它還是一個按鈕。同時內(nèi)部只用文字展示按鈕名稱。它只出現(xiàn)在按鈕背景復(fù)雜的頁面當(dāng)中,比如:漸變色、紋理、動態(tài)圖片背景的情況下,幽靈按鈕能夠完美融入到環(huán)境當(dāng)中。

          而現(xiàn)如今,傳統(tǒng)意義上的幽靈按鈕已經(jīng)很少,畢竟在現(xiàn)如今的官網(wǎng)當(dāng)中,幽靈按鈕已經(jīng)不再流行,更多的是出現(xiàn)在復(fù)雜頁面的“實心按鈕”,而在某種意義上講,這類按鈕才是幽靈按鈕現(xiàn)在的狀態(tài)。

          幽靈按鈕和次按鈕有何不同?

          在形式上,幽靈按鈕和次按鈕看起來沒有并什么不同,因此會有很多疑惑,那我什么時候用幽靈按鈕什么時候用次按鈕呢?

          首先幽靈按鈕是屬于特殊按鈕體系中,因此它不會受整個按鈕體系的束縛,比如我在一個設(shè)計系統(tǒng)中,分別定義了常規(guī)按鈕的尺寸分別是24px、32px、40px,但是我在一個官網(wǎng)落地頁當(dāng)中需要有一個46px的按鈕出現(xiàn),次按鈕就完全不合適。其次幽靈按鈕邊框粗細(xì)、字體大小都是和常規(guī)按鈕體系不同,因此幽靈按鈕就和次按鈕有所不同。

          第二個方面在次按鈕的設(shè)計形式中,不僅僅只有描邊按鈕這一種形式,因此幽靈按鈕與次按鈕它們可能會有交集,但是屬于兩種不同類型的場景,因此也不能將它們混用。

          2.3 懸浮按鈕(Floating Action Button)

          在Material Design 出現(xiàn)之初,懸浮按鈕受到了很多人的追捧,它也是安卓設(shè)計的代名詞。主要是用于頁面當(dāng)中最常用的操作,是整個APP中最核心的按鈕,能夠代表這個產(chǎn)品的核心功能,比如記賬軟件的添加賬單記錄,印象筆記的新增筆記(安卓)。

          但沉浸式設(shè)計的出現(xiàn),使得移動端寸土寸金的地方,需要固定一個按鈕的情況就變得更加少見。

          而在B端的設(shè)計過程中,逐漸衍生出了B端行業(yè)特有的方式。

          懸浮按鈕在B端場景中,主要是幫助用戶進(jìn)行輔助咨詢的功能,例如在一些用戶需要得到幫助的頁面中,可以通過懸浮按鈕,使用戶的又疑問的頁面進(jìn)行快速提問,幫助用戶能夠進(jìn)行快速的跳轉(zhuǎn),在飛書的應(yīng)用列表中,其實用戶剛開始理解應(yīng)用列表其實存在一個理解成本,就可以通過懸浮按鈕進(jìn)行展示(后面有機會聊聊B端改版厭惡時也會提到)。

          2.4 行為號召按鈕(Call to Actiontion)

          行為號召按鈕簡稱:CTA按鈕,主要目的是為了號召人們在某些特定的頁面中使用此按鈕來提高轉(zhuǎn)化,比如立即購買、聯(lián)系我們、立即訂閱等等…

          大多數(shù)時候,CTA按鈕都是成對出現(xiàn)的。“是與否“ 、“登錄與注冊”、“確認(rèn)與取消”等。因此,分析清楚CTA按鈕后設(shè)計出視覺層級合理的頁面稱為非常重要的點。在設(shè)計中,一般會采取漸變色、主題色、主題色的互補色等等,它經(jīng)常獨立出現(xiàn)。

          在B端軟件的場景中,官網(wǎng)是CTA按鈕出現(xiàn)最為重要的頁面,一般在官網(wǎng)中,使用CTA按鈕將用戶引導(dǎo)從潛在客戶向付費客戶進(jìn)行轉(zhuǎn)變(點擊過后一般是一個聯(lián)系表單進(jìn)行信息的填寫),這也是在B端產(chǎn)品中非常重要的指標(biāo):潛客向付費客戶轉(zhuǎn)變。可以引導(dǎo)用戶進(jìn)入到下一個階段,如果CTA按鈕設(shè)計不好,人們對于官網(wǎng)只是瀏覽,不會有任何轉(zhuǎn)化。

          因此,在設(shè)計CTA按鈕的形式與位置時,需要與產(chǎn)品、設(shè)計、運營等共同確定并討論使用,大家站在不同的立場希望得到一個完美的方案,因為設(shè)計出清晰的結(jié)構(gòu)層次將直接引導(dǎo)用戶朝著理想的使用路徑前進(jìn),從而極大提高轉(zhuǎn)化率。

          三、按鈕細(xì)節(jié)

          3.1 按鈕文案

          在我們?nèi)粘TO(shè)計中,常常會遇到一些棘手的文案問題:登陸、登錄、確認(rèn)、確定、發(fā)送、發(fā)布,在許許多多的工作場景中,猶豫究竟應(yīng)該在按鈕上使用哪種文案,這就需要我們通過具體的案例場景進(jìn)行展示相應(yīng)文案。

          • 登陸(Land):這是網(wǎng)絡(luò)中錯別字最為頻繁的用此,很多人都會把登陸放到登錄頁面中,其實是錯的。這個詞里的“陸”字,就是陸地的意思,其基本含義只是登上陸地而已,拓展出來還會有“登陸到某一個市場”,但登陸網(wǎng)站的說法是絕對錯誤的。
          • 登錄(Login):這是“登記記錄、記載”的含義,我們正常輸入賬號密碼就是為了去記錄我們的一個信息,一般為官網(wǎng)登錄頁。
          • 確認(rèn)(Confirm):這是帶有一些不可逆我操作的提示,一般用于用戶配置、選擇項等。
          • 確定(Yes):這是詢問用戶是否進(jìn)行某項不可逆操作,一般為一個單獨的操作。
          • 發(fā)送(Send):這是盡快傳遞對方的聊天消息,一般為即時性的聊天發(fā)送。
          • 發(fā)布(Publish):這是用于用戶填寫的觀點、意見、文章等反饋信息發(fā)布到一些正式場合,如論壇、社區(qū)等。

          這些細(xì)節(jié)的文案就是幫助用戶去理解頁面中所傳達(dá)的真正含義,多將文字放置到場景中,文案也更好的輔佐他們作出選擇

          3.2 按鈕圓角

          圓角在每一個軟件中,隨處可見。圓角大小所帶來的不僅僅是視覺表現(xiàn),還更多影響著用戶的使用體驗以及對于產(chǎn)品而言的整體的認(rèn)知,如果在開始設(shè)計之前,沒有對按鈕圓角有具體的規(guī)劃,很容易踩坑,如何設(shè)計好圓角,我們來進(jìn)行系統(tǒng)分析

          在下文中我們將按鈕的圓角大小,分為以下三類:直角、圓角、半圓。

          直角:

          按鈕四角的方向,具有很強烈的引導(dǎo)性,看上去也會更加刺眼,使得在頁面當(dāng)中注意力會減弱。同時,直角在按鈕排列當(dāng)中看上去更加統(tǒng)一,相同的東西在視覺上不太能引起我們的注意。

          圓角:

          相比與直角按鈕,在使用圓角的按鈕中,視覺上總是給人一種柔和親近的感覺,當(dāng)幾個圓角按鈕進(jìn)行排列時,能夠感受到圓角按鈕更容易被點擊。因此在使用的按鈕中,建議添加圓角的細(xì)節(jié)元素。

          為何直角的物體會給人更嚴(yán)肅的感受——每一個人都認(rèn)為圓角會更好,但是并不是每一個人都能夠解答為什么圓角更好。

          在巴羅神經(jīng)病學(xué)研究所對拐角的科學(xué)研究發(fā)現(xiàn),“拐角的感知程度隨著角度線性變化。銳角比鈍角產(chǎn)生更強的幻覺顯著性”。換句話說,拐角越尖,則出現(xiàn)越亮。拐角越多,越難看。

          圓角還有另一種解釋,是因為現(xiàn)實生活中有圓角的物體會更友好。從小,我們就知道尖角的物體會讓人受傷,圓角的物體會更安全。這就是小孩在玩皮球與刀的時候,家長的反應(yīng)完全不同。

          小朋友玩刀會讓家長十分的緊張,趕緊讓孩子放下;而小朋友玩皮球時,家長則是非常的放心。這激起了神經(jīng)科學(xué)所謂的尖銳邊緣“回避反應(yīng)”。因此,我們傾向于“避免鋒利的邊緣,因為在自然界中它們可能會構(gòu)成危險”。

          圓角是不是越大越好?

          通常在移動端場景中,半圓按鈕隨處可見,移動端手指觸摸操作上,對于圓角的影響小之又小;而到了桌面端的場景下,鼠標(biāo)的使用,半圓按鈕就會有所不妥。

          如果相同面積中,按鈕的圓角增大,相應(yīng)的對于按鈕的可操作區(qū)域就會隨之減小,在同等尺寸下的按鈕中,小圓角的按鈕明顯比大圓角的按鈕更容易操作。

          當(dāng)然,麻煩事還不僅僅于操作區(qū)域,在結(jié)合實際業(yè)務(wù),我們的按鈕常常作為原子(原子設(shè)計理論)用來組成為下拉菜單進(jìn)行聯(lián)動,半圓按鈕在下拉菜單的設(shè)計中,也會因為半圓的局限,使下拉菜單的設(shè)計會更加困難,同樣在設(shè)計上,半圓角對于下拉菜單的適配也會相當(dāng)突兀,因此在考慮這方面設(shè)計時,需要你多去思考之后的業(yè)務(wù)場景。

          3.3 重要的Loading狀態(tài)

          按鈕的狀態(tài)中,Loading狀態(tài)通常不會對用戶進(jìn)行直接展示,因為大多數(shù)情況下,Loading狀態(tài)就發(fā)生在一秒鐘以內(nèi),但是對于B端場景中有很多重要操作,在長時間等待中不展示loading狀態(tài),會導(dǎo)致用戶在使用時犯下錯誤。

          需要在合理的時間進(jìn)行反饋

          • 當(dāng)按鈕響應(yīng)時間小于1秒時,通常正常反饋即可。
          • 當(dāng)按鈕響應(yīng)時間長于1秒時,我們通常會采取加載動畫,減緩用戶等待的焦慮感。

          舉個例子:比如一個確認(rèn)提交的按鈕,由于網(wǎng)絡(luò)或者服務(wù)器等原因,需要長時間加載資源,而用戶不知道我剛才按下的按鈕是否有效,這時用戶慌張,想要多按下幾次這個按鈕,系統(tǒng)就會不停提交數(shù)據(jù),最后網(wǎng)絡(luò)變好時,窗口就會一瞬間瘋狂展示,導(dǎo)致用戶體驗下降。

          為了防止這類事情的發(fā)生,需要在設(shè)計師考慮到按鈕在加載一秒以后的狀態(tài),應(yīng)當(dāng)提示用戶在網(wǎng)頁已經(jīng)收到請求,正在加載,同時在按鈕狀態(tài)中應(yīng)該為不可操作狀態(tài)。同時會給出加載轉(zhuǎn)圈的動畫,緩解用戶的焦慮。

          當(dāng)你完成了第一步的設(shè)計后,想想在按鈕的狀態(tài)中,是否更能夠幫助用戶進(jìn)行體驗上的提升呢?

          這也是在面試某大型互聯(lián)網(wǎng)公司時,被問到過的一個問題~敲黑板。

          對用戶操作的適當(dāng)反饋是用戶界面設(shè)計的最基本準(zhǔn)則。讓用戶了解當(dāng)前狀態(tài)、位置、是否成功、進(jìn)度如何,減少不確定性;并引導(dǎo)他們在正確的方向上交互,而不是浪費精力在重復(fù)操作上。

          在Loading的加載過程中,等待焦慮一直是用戶想要了解到的,為了緩解類似情況,可以將等待的進(jìn)度狀態(tài)進(jìn)行展示,使的用戶在等待的過程中,能夠清晰的清楚自己的按鈕目前處于何種狀態(tài),我大概還需要等待多久,緩解用戶在等待過程中的焦慮。

          以上兩個方式均是尼爾森十大原則的內(nèi)容,能夠在按鈕Loading狀態(tài)中,緩解用戶在按鈕加載過程中、重復(fù)提交、等待焦慮的問題,通過一些設(shè)計小細(xì)節(jié),幫助產(chǎn)品提升用戶體驗。

          四、按鈕實際的使用場景

          通過上文對于按鈕的解釋,大致明白按鈕在設(shè)計中的作用,接下來我結(jié)合一個工作中的實際案例,來看看我們應(yīng)該如何優(yōu)化常見按鈕在頁面當(dāng)中的設(shè)計。

          項目背景:在桌面端,我們需要對整個導(dǎo)航欄進(jìn)行設(shè)計改版,但其中涉及到對于導(dǎo)航的一個整體優(yōu)化,主要是由于業(yè)務(wù)功能發(fā)生變化,我們需要在導(dǎo)航欄上增加快捷添加入口和通知中心,來滿足導(dǎo)航的后續(xù)的功能需求,由于保密協(xié)議的原因,就不放自家產(chǎn)品。

          第一步根據(jù)用戶瀏覽模式確定按鈕順序

          在桌面端中,瀏覽模式大致分為兩類,F(xiàn)型瀏覽模式、Z型瀏覽模式(下方知識拓展會有講到)。

          首先,因為導(dǎo)航在整個頁面的頂部,結(jié)合兩種瀏覽模式在頂部時統(tǒng)一都為從左到右的瀏覽順序。

          因此確定整個導(dǎo)航按鈕初步的按鈕重要層級排序。

          第二步交互路徑優(yōu)化

          我們對于用戶的按鈕層級有著明顯的劃分,因為在整個導(dǎo)航右側(cè),又因為其的特殊性,我們把操作空間分為三部分:

          左側(cè)為操作路徑最短的區(qū)域,因為桌面端的產(chǎn)品需要通過鼠標(biāo)進(jìn)行交互操作,而其中移動鼠標(biāo)的長短直接決定用戶是否愿意點擊這個按鈕,因此,靠左的按鈕適合放置用戶最常使用的操作。

          中部為按鈕內(nèi)部區(qū),可以放置一些低頻,但是又必須出現(xiàn)在這個區(qū)域的按鈕操作(比如:幫助中心、通知中心等等…)。

          右側(cè)為按鈕最為重要層級最弱的區(qū)域,同時它也有一些特殊性。

          一般在瀏覽器的右側(cè),為用戶最容易定位的操作區(qū)域,因為靠近邊緣導(dǎo)致在用戶定位當(dāng)中能夠幫助用戶進(jìn)行快速選擇。

          回到頁面中信息層級較高、同時需要精準(zhǔn)定位的按鈕就會將個人中心放置在最右側(cè),方便用戶進(jìn)行快速定位。

          因此我們講導(dǎo)航當(dāng)中按鈕重要層級進(jìn)行簡單排序,得到下圖:

          第三步信息整合優(yōu)化按鈕結(jié)構(gòu)

          通過親密性原則,我們將除去左右兩側(cè)確定好的按鈕之外的按鈕進(jìn)行簡單分類,將有關(guān)聯(lián)的按鈕進(jìn)行組合,形成較強的關(guān)聯(lián)性~

          第四步視覺調(diào)整

          視覺調(diào)整作為最重要的一步,主要是為了在最后的按鈕重要層級上,將一部分按鈕突出、一部分按鈕弱化,達(dá)到我們想要的整個層級效果。

          通過團(tuán)隊內(nèi)部討論,將我們的新增按鈕定位CTA按鈕,因為它關(guān)聯(lián)到我們每個使用系統(tǒng)的人都會用到,屬于最高頻的操作按鈕,也因此將其突出。

          F型瀏覽模式:

          是新聞平臺、博客等文字為主的網(wǎng)站布局所采取的閱讀模式。

          該閱讀模式由尼爾森團(tuán)隊的眼動追蹤研究結(jié)果從而進(jìn)行普及,在這個研究中記錄了超過200位用戶瀏覽網(wǎng)頁時,發(fā)現(xiàn)用戶的主要閱讀行為在許多網(wǎng)站和場景中表現(xiàn)得相當(dāng)一致。這個閱讀模式看起來有點像字母F,因此也被叫做F型瀏覽模式。

          首先用戶以水平方向進(jìn)行閱讀,通常是在閱讀區(qū)域的上半部分。

          接下來,他們在屏幕左側(cè)垂直瀏覽,尋找段落開篇幾句中感興趣的內(nèi)容。當(dāng)他們找到感興趣的內(nèi)容時,他們在第二個水平方向上快速瀏覽,通常這塊內(nèi)容區(qū)比上一個內(nèi)容區(qū)更短小、更簡潔。這部分元素形成了F的下半部分。

          最后,用戶在垂直方向上瀏覽內(nèi)容的左側(cè)區(qū)域。

          Z型瀏覽模式:

          是掃描滾動的網(wǎng)站的典型模式。

          正如你所期望的,“z”型模式的布局遵循字母Z的形狀。“Z”型模式的設(shè)計跟蹤了人眼掃描頁面時的路線——從左到右,從上到下:

          • 首先,人們從左上角到右上角進(jìn)行掃描,形成一條水平線
          • 接下來,向頁面的左下側(cè)掃描,鏈接成一條對角線
          • 最后,再次向右轉(zhuǎn),形成第二條水平線

          當(dāng)觀眾的視角以這種模式移動時,它形成一個虛構(gòu)的“Z”字形。

          五、按鈕設(shè)計中與開發(fā)還原細(xì)節(jié)

          在實際工作中,經(jīng)常遇到自己設(shè)計的按鈕與開發(fā)實際還原的按鈕差距很大,一些沒有經(jīng)驗的設(shè)計師會和開發(fā)說,你看我設(shè)計稿,每一個按鈕都要按照設(shè)計稿的來,這樣設(shè)計師與前端開發(fā)之間的矛盾就會越來越深。其實在按鈕設(shè)計的細(xì)節(jié)中,開發(fā)怎么完美的還原,里面還有很多細(xì)節(jié)。

          5.1 Padding思維

          首先要想讓開發(fā)完全還原你的設(shè)計稿,就必須了解開發(fā)實現(xiàn)的思維方式,針對它的思維方式進(jìn)行相應(yīng)的思考。

          又由于Sketch與開發(fā)常使用的VScode之間邏輯上存在較大差異,導(dǎo)致設(shè)計師設(shè)計出來的很多設(shè)計稿開發(fā)根本無法實現(xiàn),這也是B端設(shè)計師擺在你面前的第一個問題。

          對你沒看錯,無法實現(xiàn),我舉一個例子:

          這是一位同學(xué)問我的一個問題,他說我這個按鈕為啥實現(xiàn)不了,前端不就是多幾個代碼去適配我的設(shè)計稿就可以了嗎?

          如果你也有很多疑問,那就接著看下去~

          什么是Padding

          在按鈕當(dāng)中,通俗的理解Padding就是文字與按鈕之間的間距。

          因為Sketch等軟件在按鈕的設(shè)計中,只有圖形位置的概念,沒有內(nèi)間距Padding的概念,因此需要對按鈕還原要明確的描述。

          比如上圖,前端同學(xué)在開發(fā)就會將Padding設(shè)置為24px,所以整個按鈕長度便為24px*2+20px(文本寬度)=68px。

          而為什么說上面的設(shè)計規(guī)范實現(xiàn)不了,因為對于前端而言,Padding通常都是統(tǒng)一且固定的,只會根據(jù)按鈕文字長度進(jìn)行相應(yīng)的調(diào)整,比如我上面舉的錯誤栗子,其實在前端同學(xué)面前這類設(shè)計是不能夠被共用,而且對前端同學(xué)項目會變得越來越不能維護(hù),所以按鈕設(shè)計應(yīng)該更規(guī)劃。

          5.2 Min-Width思維

          但是如果真的需要去實現(xiàn)兩個文字按鈕長度和四個字的一樣怎么辦,需要去設(shè)定按鈕的最小寬度。

          按鈕最小寬度的設(shè)定一般為4個字文字的長度,假設(shè)字體大小為16px,左右的Paddung為24px。

          最小寬度為:88px,因此在按鈕的標(biāo)注中,需要展示最小間距為102px,方便前端進(jìn)行CSS開發(fā)。

          5.3 按鈕的邊框

          在我們的sketch中,按鈕邊框有三種,內(nèi)邊框、居中邊框、外邊框,默認(rèn)為居中,但是在前端的CSS代碼中沒有居中邊框,沒有居中邊框,沒有居中邊框(重要的事情說三遍),默認(rèn)為內(nèi)邊框,如果需要調(diào)整為外邊框,最好能夠標(biāo)注。

          按鈕雖然作為一個最基礎(chǔ)的元素,但是在整個設(shè)計體系中,它一直都扮演著一個十分重要的位置,在思維中,任何組件都可以通過上面按鈕的思維,對每個組件進(jìn)行拆解分析,無論是組件的狀態(tài)、組件的類型,在實際工作中,都需要你去深入思考。關(guān)于我呢, 也因為踩了很多坑,因此想分享給大家。

          參考鏈接

          https://blog.prototypr.io/8-rules-for-perfect-button-design-185d1202ee9c

          https://medium.com/@uxmovement/when-you-need-to-show-a-buttons-loading-state-41fc4d5e3c65

          https://atlassian.design/guidelines/product/components/buttons

          https://uxmovement.com/thinking/why-rounded-corners-are-easier-on-the-eyes/

          相關(guān)閱讀

          B端設(shè)計:盤點篩選控件的基本知識

          B端設(shè)計:導(dǎo)航菜單的設(shè)計5步法

          作者:CE,2B行業(yè)的2B設(shè)計師~。公眾號:CeDesign

          本文由 @CE 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載

          題圖來自Unsplash,基于CC0協(xié)議。

          文主要介紹了如何才能設(shè)計一個具有行為召喚能力的按鈕,并從形狀、色彩、按鈕樣式、添加圖標(biāo)、文字字體、位置等方面提出了建議。

          “按鈕”在UI設(shè)計中是一種常用的UI控件,一個成功的按鈕控件可以有效的提高交互體驗,引導(dǎo)用戶,提升產(chǎn)品轉(zhuǎn)化率。目前我們所熟知的按鈕按功能類型主要分為六大類,分別是行為召喚按鈕(CTA)、懸浮按鈕、標(biāo)簽按鈕、表格按鈕、命令按鈕及開關(guān)按鈕。

          其中,行為召喚按鈕(Call To Action),簡稱CTA按鈕,即用戶在訪問某頁面后引導(dǎo)用戶去點擊并且跳轉(zhuǎn)至下一個流程(如購買、聯(lián)系、關(guān)注等行為)的一類按鈕控件,其主要目的就是為了提高特定頁面或屏幕的轉(zhuǎn)化率,從而達(dá)到預(yù)期設(shè)定的結(jié)果。因此,CTA按鈕也具有不同于其他種類按鈕的特性。那么如何才能設(shè)計一個具有行為召喚能力的按鈕呢?

          尺寸

          結(jié)合CTA按鈕的先前目標(biāo)是吸引用戶的注意,提高轉(zhuǎn)化,因此按鈕尺寸越大,它被用戶發(fā)現(xiàn)和點擊的概率就越高,但也不宜過大,以免破壞布局的視覺組合和層次結(jié)構(gòu)。最好的按鈕和按鈕文字應(yīng)該遵循頁面的比例進(jìn)行設(shè)計,以便用戶更好識別。

          圖1

          另外,移動端的設(shè)計還需要考慮按鈕與手指的適配度,為了保證按鈕的最佳點擊區(qū)域,設(shè)計師在繪制按鈕時要保證其點擊范圍至少高度要在30px以上,例如主流的參考設(shè)計規(guī)范:蘋果的HIQ中要求CTA按鈕至少為 44×44 px,而微軟則建議至少為34×26 px。具體的大小還是會根據(jù)實際情況而變。

          圖2

          色彩

          除了通過尺寸差異來營造視覺吸引力外,一個能夠激勵用戶點擊的按鈕需要具備的另外一個關(guān)鍵元素就是顏色的選擇與運用。好的色彩運用能夠從情緒與視覺上干預(yù)用戶,吸引其注意力。所以設(shè)計師在進(jìn)行按鈕設(shè)計時,需要考慮到整體的配色方案,使CTA按鈕能夠在眾多UI控件中脫穎而出。

          介于文章篇幅原因,簡潔明了的來說,我們知道色彩經(jīng)由色相、明度、純度的變化與調(diào)和,可以產(chǎn)生豐富多樣的層次變化,而能夠吸引人目光的色彩特性我們可以稱之為誘目性。

          在能夠使誘目性變高的色彩中,與無色彩對比,有色彩的比較好;與低純度色對比,高純度色的比較好;與低明度色比較,高明度色的較好。

          所以為了讓CTA按鈕的顏色與整體頁面形成和諧但又顯著的對比,目前采用最多的設(shè)計原則是遵循高反差度原則,即通過合理運用色彩的色相、明度、純度的對比方式,來凸顯CTA按鈕的重要性。

          如下圖(圖3)案例所示,整體界面的色彩選擇是白色,如果像左圖中按鈕依然選擇純度較低的藍(lán)色,不僅會使整個頁面顯得“輕飄飄”,毫無著落點外,CTA按鈕也無法凸顯出來,而右圖中的按鈕不論是在色相還是純度上都選擇了與背景色反差較大的藍(lán)色,直接誘導(dǎo)用戶進(jìn)行點擊。

          圖3

          按鈕形狀

          我們常說藝術(shù)來源于模仿,設(shè)計來源于生活。這句話對于按鈕外形的繪制非常適用,因為在現(xiàn)實生活中按鈕的使用率也非常高,比如開關(guān)燈、開電腦、敲鍵盤等,所以設(shè)計師在設(shè)計過程中會吸取現(xiàn)實生活中按鈕的形狀,擇優(yōu)選擇水平矩形或者圓角矩形來表示CTA按鈕。

          另一方面,一些研究建議圓角矩形更能加強信息的傳遞并且能夠?qū)⑷说囊暰€集中在中心位置上。

          當(dāng)然我們有時也可以根據(jù)自己的創(chuàng)意去使用其他的形狀,比如圓形,三角形或者自定義形,但是一定要確保統(tǒng)一性能夠把控你的界面設(shè)計,以便用戶能夠識別出這個按鈕元素。如下左圖所示,在此處使用圓形按鈕不僅打破了頁面設(shè)計的統(tǒng)一性,而且相較于右圖示中的圓矩形按鈕提示的作用也被削弱了不少。

          --

          圖4

          按鈕樣式

          突出的按鈕樣式,特別是矩形或圓矩形按鈕,利用投影等樣式有效還原生活中按鈕的模樣,提示用戶按鈕是可以進(jìn)行點擊的。這與扁平化的按鈕樣式對比在空間維度上增加了一度,在復(fù)雜或?qū)捲5目臻g中更能起到強調(diào)的作用。

          圖5

          但在追尋簡潔設(shè)計的界面中,有些設(shè)計師也會首選扁平化的設(shè)計風(fēng)格,來保證界面的內(nèi)容設(shè)計不被打擾。所以,在這類扁平化的按鈕設(shè)計中需要注意的是顏色的篩選與運用,在即保證界面風(fēng)格統(tǒng)一的情況下,也要保證用戶能夠順利的找到按鈕元素,保證頁面轉(zhuǎn)化的效果。

          文本字體

          文本內(nèi)容的字體、大小、粗細(xì)等因素都會影響到CTA按鈕的視覺權(quán)重。一般設(shè)計遵循高優(yōu)先級按鈕使用粗體文本,低優(yōu)先級按鈕使用細(xì)體文本的原則,以此來影響用戶閱讀它們時的優(yōu)先級,因此CTA按鈕文本盡量選擇粗體文本,誘使用戶進(jìn)行點擊,提高轉(zhuǎn)化率。

          圖6

          添加圖標(biāo)

          添加圖標(biāo)同樣也可以給CTA按鈕增加用戶額外的視覺重量,提高用戶在瀏覽頁面時優(yōu)先關(guān)注的概率,增加CTA按鈕的轉(zhuǎn)化效果。如下圖的對比,視覺上會更加直觀的注意到帶有圖標(biāo)的按鈕。

          圖7

          位置

          CTA按鈕的設(shè)計,可以說是整個頁面轉(zhuǎn)化的核心與靈魂,尤其決定了一些付費推廣的轉(zhuǎn)化成果。所以除去按鈕本身的設(shè)計外,CTA按鈕的位置擺放也尤為關(guān)鍵。

          一般來說按鈕的位置與頁面內(nèi)容的繁簡程度以及用戶行動成本存在著一定關(guān)聯(lián)性,文本內(nèi)容愈簡單,用戶無需了解更多信息或者用戶的行動成本很低甚至沒有,用戶就越容易在頁面瀏覽之前點擊按鈕,此時按鈕可以放置在頁面相對靠前的位置,相反如果用戶需要為采取的行動付出一定代價時,比如給出聯(lián)系方式、關(guān)注、付款等情況下,用戶采取預(yù)期CTA行動的時間就會推后,一般會瀏覽完頁面后再進(jìn)行考量,此時按鈕的位置建議放置在瀏覽頁面的下端。

          所以CTA的位置隨內(nèi)容的簡單到復(fù)雜遞降,即從頁面上端到頁面下端,如圖所示:

          圖8

          綜上所述,關(guān)于如何設(shè)計一款真正具有行為召喚的按鈕,實現(xiàn)具體的動態(tài)行為交互,設(shè)計師一方面需要了解CTA的重要性,另一方面更要著重注意影響其表現(xiàn)的所有細(xì)節(jié)。

          以上關(guān)于CTA按鈕設(shè)計的相關(guān)規(guī)則,希望可以給大家?guī)硪恍﹨⒖肌?/p>

          本文由 @IQS開發(fā)者社區(qū) 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載。

          題圖來自 Unsplash,基于CC0協(xié)議

          者 | 無名之輩FTER

          責(zé)編 | 夕顏

          出品 | 程序人生(ID:coder_life)

          本文翻譯自Rasa官方文檔,并融合了自己的理解和項目實戰(zhàn),同時對文檔中涉及到的技術(shù)點進(jìn)行了一定程度的擴展,目的是為了更好的理解Rasa工作機制。與本文配套的項目GitHub地址:ChitChatAssistant https://github.com/jiangdongguo/ChitChatAssistant,歡迎star和issues,我們共同討論、學(xué)習(xí)!

          對話管理

          1.1 多輪對話

          多輪對話是相對于單輪對話而言的,單輪對話側(cè)重于一問一答,即直接根據(jù)用戶的問題給出精準(zhǔn)的答案。問答更接近一個信息檢索的過程,雖然也可能涉及簡單的上下文處理,但通常是通過指代消解和 query 補全來完成的,而多輪對話側(cè)重于需要維護(hù)一個用戶目標(biāo)狀態(tài)的表示和一個決策過程來完成任務(wù),具體來說就是用戶帶著明確的目的而來,希望得到滿足特定限制條件的信息或服務(wù),例如:訂餐,訂票,尋找音樂、電影或某種商品等。因為用戶的需求可以比較復(fù)雜,可能需要分多輪進(jìn)行陳述,用戶也可能在對話過程中不斷修改或完善自己的需求。此外,當(dāng)用戶的陳述的需求不夠具體或明確的時候,機器也可以通過詢問、澄清或確認(rèn)來幫助用戶找到滿意的結(jié)果。

          因此,任務(wù)驅(qū)動的多輪對話不是一個簡單的自然語言理解加信息檢索的過程,而是一個決策過程,需要機器在對話過程中不斷根據(jù)當(dāng)前的狀態(tài)決策下一步應(yīng)該采取的最優(yōu)動作(如:提供結(jié)果,詢問特定限制條件,澄清或確認(rèn)需求,等等)從而最有效的輔助用戶完成信息或服務(wù)獲取的任務(wù)。

          注:任務(wù)驅(qū)動的多輪對話系統(tǒng)通常為封閉域(domain)(閑聊系統(tǒng)為開放域),而特定限制條件對應(yīng)于槽(Slot),也就是說,用戶在滿足特定限制條件時就是一次槽值填充的過程,如果用戶能夠在一次會話中,滿足全部的限制條件,那么就不必進(jìn)行多輪對話,即可直接使用戶得到滿意的信息或服務(wù)。

          1.2 對話管理

          對話管理,即Dialog Management(DM),它控制著人機對話的過程,是人機對話系統(tǒng)的重要組成部分。DM會根據(jù)NLU模塊輸出的語義表示執(zhí)行對話狀態(tài)的更新和追蹤,并根據(jù)一定策略選擇相應(yīng)的候選動作。簡單來說,就是DM會根據(jù)對話歷史信息,決定此刻對用戶的反應(yīng),比如在任務(wù)驅(qū)動的多輪對話系統(tǒng)中,用戶帶著明確的目的如訂餐、訂票等,用戶需求比較復(fù)雜,有很多限制條件,可能需要分多輪進(jìn)行陳述,一方面,用戶在對話過程中可以不斷修改或完善自己的需求,另一方面,當(dāng)用戶的陳述的需求不夠具體或明確的時候,機器也可以通過詢問、澄清或確認(rèn)來幫助用戶找到滿意的結(jié)果。如下圖所示,DM 的輸入就是用戶輸入的語義表達(dá)(或者說是用戶行為,是 NLU 的輸出)和當(dāng)前對話狀態(tài),輸出就是下一步的系統(tǒng)行為和更新的對話狀態(tài)。這是一個循環(huán)往復(fù)不斷流轉(zhuǎn)直至完成任務(wù)的過程。

          從本質(zhì)上來說,**任務(wù)驅(qū)動的對話管理實際就是一個決策過程,系統(tǒng)在對話過程中不斷根據(jù)當(dāng)前狀態(tài)決定下一步應(yīng)該采取的最優(yōu)動作(如:提供結(jié)果,詢問特定限制條件,澄清或確認(rèn)需求等),從而最有效的輔助用戶完成信息或服務(wù)獲取的任務(wù)。**對話管理的任務(wù)大致有:

          • 對話狀態(tài)維護(hù)(dialog state tracking, DST)

          對話狀態(tài)是指記錄了哪些槽位已經(jīng)被填充、下一步該做什么、填充什么槽位,還是進(jìn)行何種操作。用數(shù)學(xué)形式表達(dá)為,t+1 時刻的對話狀態(tài)S(t+1),依賴于之前時刻 t 的狀態(tài)St,和之前時刻 t 的系統(tǒng)行為At,以及當(dāng)前時刻 t+1 對應(yīng)的用戶行為O(t+1)。可以寫成S(t+1)←St+At+O(t+1)。

          • 生成系統(tǒng)決策(dialog policy)

          根據(jù) DST 中的對話狀態(tài)(DS),產(chǎn)生系統(tǒng)行為(dialog act),決定下一步做什么 dialog act 可以表示觀測到的用戶輸入(用戶輸入 -> DA,就是 NLU 的過程),以及系統(tǒng)的反饋行為(DA -> 系統(tǒng)反饋,就是 NLG 的過程)。

          • 作為接口與后端/任務(wù)模型進(jìn)行交互

          Rasa Core

          Rasa Core是Rasa框架提供的對話管理模塊,它類似于聊天機器人的大腦,主要的任務(wù)是維護(hù)更新對話狀態(tài)和動作選擇,然后對用戶的輸入作出響應(yīng)。所謂對話狀態(tài)是一種機器能夠處理的對聊天數(shù)據(jù)的表征,對話狀態(tài)中包含所有可能會影響下一步?jīng)Q策的信息,如自然語言理解模塊的輸出、用戶的特征等;所謂動作選擇,是指基于當(dāng)前的對話狀態(tài),選擇接下來合適的動作,例如向用戶追問需補充的信息、執(zhí)行用戶要求的動作等。舉一個具體的例子,用戶說“幫我媽媽預(yù)定一束花”,此時對話狀態(tài)包括自然語言理解模塊的輸出、用戶的位置、歷史行為等特征。在這個狀態(tài)下,系統(tǒng)接下來的動作可能是:

          • 向用戶詢問可接受的價格,如“請問預(yù)期價位是多少?”;

          • 向用戶確認(rèn)可接受的價格,如“像上次一樣買價值200的花可以嗎?”

          • 直接為用戶預(yù)訂

          2.1 Stories

          Rasa的故事是一種訓(xùn)練數(shù)據(jù)的形式,用來訓(xùn)練Rasa的對話管理模型。故事是用戶和人工智能助手之間的對話的表示,轉(zhuǎn)換為特定的格式,其中用戶輸入表示為相應(yīng)的意圖(和必要的實體),而助手的響應(yīng)表示為相應(yīng)的操作名稱。Rasa核心對話系統(tǒng)的一個訓(xùn)練示例稱為一個故事。這是一個故事數(shù)據(jù)格式的指南。兩段對話樣本示例:

          <!-- ##表示story的描述,沒有實際作用 -->## greet + location/price + cuisine + num people* greet - utter_greet* inform{"location": "rome", "price": "cheap"} - action_on_it - action_ask_cuisine* inform{"cuisine": "spanish"} - action_ask_numpeople * inform{"people": "six"} - action_ack_dosearch
          <!-- Form Action-->## happy path * request_weather - weather_form - form{"name": "weather_form"} - form{"name": }

          Story格式大致包含三個部分:

          • 1. 用戶輸入(User Messages)

          使用*開頭的語句表示用戶的輸入消息,我們無需使用包含某個具體內(nèi)容的輸入,而是使用NLU管道輸出的intent和entities來表示可能的輸入。需要注意的是,如果用戶的輸入可能包含entities,建議將其包括在內(nèi),將有助于policies預(yù)測下一步action。這部分大致包含三種形式,示例如下:

          (1)* greet 表示用戶輸入沒有entity情況;

          (2)* inform{"people": "six"} 表示用戶輸入包含entity情況,響應(yīng)這類intent為普通action;

          (3)* request_weather 表示用戶輸入Message對應(yīng)的intent為form action情況;

          • 2. 動作(Actions)

          使用-開頭的語句表示要執(zhí)行動作(Action),可分為utterance actions和custom actions,其中,前者在domain.yaml中定義以utter_為前綴,比如名為greet的意圖,它的回復(fù)應(yīng)為utter_greet;后者為自定義動作,具體邏輯由我們自己實現(xiàn),雖然在定義action名稱的時候沒有限制,但是還是建議以action_為前綴,比如名為inform的意圖fetch_profile的意圖,它的response可為action_fetch_profile。

          • 3. 事件(Events)

          Events也是使用-開頭,主要包含槽值設(shè)置(SlotSet)和激活/注銷表單(Form),它是是Story的一部分,并且必須顯示的寫出來。Slot Events和Form Events的作用如下:

          (1)Slot Events

          Slot Events的作用當(dāng)我們在自定義Action中設(shè)置了某個槽值,那么我們就需要在Story中Action執(zhí)行之后顯著的將這個SlotSet事件標(biāo)注出來,格式為- slot{"slot_name": "value"}。比如,我們在action_fetch_profile中設(shè)置了Slot名為account_type的值,代碼如下:

          from rasa_sdk.actions import Actionfrom rasa_sdk.events import SlotSetimport requests

          class FetchProfileAction(Action): def name(self): return "fetch_profile"

          def run(self, dispatcher, tracker, domain): url = "http://myprofileurl.com" data = requests.get(url).json return [SlotSet("account_type", data["account_type"])]

          那么,就需要在Story中執(zhí)行action_fetch_profile之后,添加- slot{"account_type" : "premium"}。雖然,這么做看起來有點多余,但是Rasa規(guī)定這么做必須的,目的是提高訓(xùn)練時準(zhǔn)確度。

          ## fetch_profile* fetch_profile - action_fetch_profile - slot{"account_type" : "premium"} - utter_welcome_premium

          當(dāng)然,如果您的自定義Action中將槽值重置為None,則對應(yīng)的事件為-slot{"slot_name": }。

          (2)Form Events

          在Story中主要存在三種形式的表單事件(Form Events),它們可表述為:

          • Form Action事件

          Form Action即表單動作事件,是自定義Action的一種,用于一個表單操作。示例如下:

          - restaurant_form
          • Form activation事件

          form activation即激活表單事件,當(dāng)form action事件執(zhí)行后,會立馬執(zhí)行該事件。示例如下:

          - form{"name": "restaurant_form"}
          • Form deactivation事件

          form deactivation即注銷表單事件,作用與form activation相反。示例如下:

          - form{"name": }

          總之,我們在構(gòu)建Story時,可以說是多種多樣的,因為設(shè)計的故事情節(jié)是多種多樣的,這就意味著上述三種內(nèi)容的組合也是非常靈活的。另外,在設(shè)計Story時Rasa還提供了Checkpoints 和OR statements兩種功能,來提升構(gòu)建Story的靈活度,但是需要注意的是,東西雖好,但是不要太貪了,過多的使用不僅增加了復(fù)雜度,同時也會拖慢訓(xùn)練的速度。其中,Checkpoints用于模塊化和簡化訓(xùn)練數(shù)據(jù),示例如下:

          ## first story* greet - action_ask_user_question> check_asked_question

          ## user affirms question> check_asked_question* affirm - action_handle_affirmation> check_handled_affirmation

          ## user denies question> check_asked_question* deny - action_handle_denial> check_handled_denial

          ## user leaves> check_handled_denial> check_handled_affirmation* goodbye - utter_goodbye

          在上面的例子中,可以使用> check_asked_question表示first story,這樣在其他story中,如果有相同的first story部分,可以直接用> check_asked_question代替。而OR Statements主要用于實現(xiàn)某一個action可同時響應(yīng)多個意圖的情況,比如下面的例子:

          ## story* affirm OR thankyou - action_handle_affirmation

          2.2 Domain

          Domain,譯為**“領(lǐng)域”**,它描述了對話機器人應(yīng)知道的所有信息,類似于“人的大腦”,存儲了意圖intents、實體entities、插槽slots以及動作actions等信息,其中,intents、entities在NLU訓(xùn)練樣本中定義,slots對應(yīng)于entities類型,只是表現(xiàn)形式不同。domain.yml文件組成結(jié)構(gòu)如下:

          具體介紹如下:

          1. intents

          intents: - affirm - deny - greet - request_weather - request_number - inform - inform_business - stop - chitchat

          intents,即意圖,是指我們輸入一段文本,希望Bot能夠明白這段文本是什么意思。在Rasa框架中,意圖的定義是在NLU樣本中實現(xiàn)的,并且在每個意圖下面我們需要枚舉盡可多的樣本用于訓(xùn)練,以達(dá)到Bot能夠準(zhǔn)確識別出我們輸入的一句話到底想要干什么。

          2. session_config

          session_config: carry_over_slots_to_new_session: true session_expiration_time: 60

          session_config,即會話配置,這部分的作用為配置一次會話(conversation session)是否有超時限制。上例演示的是,每次會話的超時時間為60s,如果用戶開始一段會話后,在60s內(nèi)沒有輸入任何信息,那么這次會話將被結(jié)束,然后Bot又會開啟一次新的會話,并將上一次會話的Slot值拷貝過來。當(dāng)然,我們希望舍棄上一次會話Slot的值,可以將carry_over_slots_to_new_session設(shè)置為false。另外,當(dāng)session_expiration_time被設(shè)置為0時,Bot永遠(yuǎn)不會結(jié)束當(dāng)前會話并一直等待用戶輸入(注:執(zhí)行action_session_start仍然可以開始一次新的會話,在設(shè)置為0的情況下)。

          3. slots

          slots: date_time: type: unfeaturized auto_fill: false address: type: unfeaturized auto_fill: false

          Slots,即插槽,它就像對話機器人的內(nèi)存,它通過鍵值對的形式可用來收集存儲用戶輸入的信息(實體)或者查詢數(shù)據(jù)庫的數(shù)據(jù)等。關(guān)于Slots的設(shè)計與使用,詳情請見本文2.6小節(jié)。

          4. entities

          entities: - date_time - address

          entities,即實體,類似于輸入文本中的關(guān)鍵字,需要在NLU樣本中進(jìn)行標(biāo)注,然后Bot進(jìn)行實體識別,并將其填充到Slot槽中,便于后續(xù)進(jìn)行相關(guān)的業(yè)務(wù)操作。

          5. actions

          actions: - utter_answer_affirm # utter_開頭的均為utter actions - utter_answer_deny - utter_answer_greet - utter_answer_goodbye - utter_answer_thanks - utter_answer_whoareyou - utter_answer_whattodo - utter_ask_date_time - utter_ask_address - utter_ask_number - utter_ask_business - utter_ask_type - action_default_fallback # default actions

          當(dāng)Rasa NLU識別到用戶輸入Message的意圖后,Rasa Core對話管理模塊就會對其作出回應(yīng),而完成這個回應(yīng)的模塊就是action。Rasa Core支持三種action,即default actions、utter actions以及 custom actions。關(guān)于如何實現(xiàn)Actions和處理業(yè)務(wù)邏輯,我們在一篇文章中詳談,這里僅作簡單了解。

          6. forms

          forms: - weather_form

          forms,即表單,該部分列舉了在NLU樣本中定義了哪些Form Actions。關(guān)于Form Actions的相關(guān)知識,請移步至本文的2.7小節(jié)。

          7. responses

          responses: utter_answer_greet: - text: "您好!請問我可以幫到您嗎?" - text: "您好!很高興為您服務(wù)。請說出您要查詢的功能?"
          utter_ask_date_time: - text: "請問您要查詢哪一天的天氣?"

          utter_ask_address: - text: "請問您要查下哪里的天氣?"
          utter_default: - text: "沒聽懂,請換種說法吧~"

          responses部分就是描述UtterActions具體的回復(fù)內(nèi)容,并且每個UtterAction下可以定義多條信息,當(dāng)用戶發(fā)起一個意圖,比如 “你好!”,就觸發(fā)utter_answer_greet操作,Rasa Core會從該action的模板中自動選擇其中的一條信息作為結(jié)果反饋給用戶。

          2.3 Responses

          Responses的作用就是自動響應(yīng)用戶輸入的信息,因此我們需要管理這些響應(yīng)(Responses)。Rasa框架提供了三種方式來管理Responses,它們是:

          • 在domain.yaml文件中存儲Responses;

          • 在訓(xùn)練數(shù)據(jù)中存儲Responses;

          • 自定義一個NLG服務(wù)來生成Responses。

          由于第一種我們在本文2.2(7)小節(jié)有過介紹,而創(chuàng)建NLG服務(wù)是這樣的:

          nlg: url: http://localhost:5055/nlg # url of the nlg endpoint # you can also specify additional parameters, if you need them: # headers: # my-custom-header: value # token: "my_authentication_token" # will be passed as a get parameter # basic_auth: # username: user # password: pass# example of redis external tracker store configtracker_store: type: redis url: localhost port: 6379 db: 0 password: password record_exp: 30000# example of mongoDB external tracker store config#tracker_store: #type: mongod #url: mongodb://localhost:27017 #db: rasa #user: username #password: password

          2.4 Actions

          當(dāng)Rasa NLU識別到用戶輸入Message的意圖后,Rasa Core對話管理模塊就會對其作出回應(yīng),而完成這個回應(yīng)的模塊就是action。Rasa Core支持三種action,即default actions、utter actions以及 custom actions。關(guān)于如何實現(xiàn)Actions和處理業(yè)務(wù)邏輯,我們在一篇文章中詳談,這里僅作簡單了解。

          1. default actions

          DefaultAction是Rasa Core默認(rèn)的一組actions,我們無需定義它們,直接可以story和domain中使用。包括以下三種action:

          • action_listen:監(jiān)聽action,Rasa Core在會話過程中通常會自動調(diào)用該action;

          • action_restart:重置狀態(tài),比初始化Slots(插槽)的值等;

          • action_default_fallback:當(dāng)Rasa Core得到的置信度低于設(shè)置的閾值時,默認(rèn)執(zhí)行該action;

          2. utter actions

          UtterAction是以utter_為開頭,僅僅用于向用戶發(fā)送一條消息作為反饋的一類actions。定義一個UtterAction很簡單,只需要在domain.yml文件中的actions:字段定義以utter_為開頭的action即可,而具體回復(fù)內(nèi)容將被定義在templates:部分,這個我們下面有專門講解。定義utter actions示例如下:

          actions: - utter_answer_greet - utter_answer_goodbye - utter_answer_thanks - utter_introduce_self - utter_introduce_selfcando - utter_introduce_selffrom

          3. custom actions

          CustomAction,即自定義action,允許開發(fā)者執(zhí)行任何操作并反饋給用戶,比如簡單的返回一串字符串,或者控制家電、檢查銀行賬戶余額等等。它與DefaultAction不同,自定義action需要我們在domain.yml文件中的actions部分先進(jìn)行定義,然后在指定的webserver中實現(xiàn)它,其中,這個webserver的url地址在endpoint.yml文件中指定,并且這個webserver可以通過任何語言實現(xiàn),當(dāng)然這里首先推薦python來做,畢竟Rasa Core為我們封裝好了一個rasa-core-sdk專門用來處理自定義action。關(guān)于action web的搭建和action的具體實現(xiàn),我們在后面詳細(xì)講解,這里我們看下在在Rasa Core項目中需要做什么。假如我們在天氣資訊的人機對話系統(tǒng)需提供查詢天氣和空氣質(zhì)量兩個業(yè)務(wù),那么我們就需要在domain.yml文件中定義查詢天氣和空氣質(zhì)量的action,即:

          actions: ...  - action_search_weather

          另外,F(xiàn)ormAction也是自定義actions,但是需要在domainl.yaml文件的forms字段聲明。

          forms: - weather_form

          2.5 Policies

          Policies是Rasa Core中的策略模塊,對應(yīng)類rasa_core.policies.Policy,它的作用就是使用合適的策略(Policy)來預(yù)測一次對話后要執(zhí)行的行為(Actions)。預(yù)測的原理是衡量命中的哪些Policies哪個置信度高,由置信度高的Policy選擇合適的Action執(zhí)行。假如出現(xiàn)不同的Policy擁有相同的置信度,那么就由它們的優(yōu)先級決定,即選擇優(yōu)先級高的Policy。Rasa對提供的Policies進(jìn)行了優(yōu)先級排序,具體如下表:

          它們的描述與作用如下:

          • Memoization Policy

          MemoizationPolicy只記住(memorizes)訓(xùn)練數(shù)據(jù)中的對話。如果訓(xùn)練數(shù)據(jù)中存在這樣的對話,那么它將以置信度為1.0預(yù)測下一個動作,否則將預(yù)測為None,此時置信度為0.0。下面演示了如何在策略配置文件config.yml文件中,配置MemoizationPlicy策略,其中,max_history(超參數(shù))決定了模型查看多少個對話歷史以決定下一個執(zhí)行的action。

           policies: - name: "MemoizationPolicy" max_history: 5

          注:max_history值越大訓(xùn)練得到的模型就越大并且訓(xùn)練時間會變長,關(guān)于該值到底該設(shè)置多少,我們可以舉這么個例子,比如有這么一個Intent:out_of_scope來描述用戶輸入的消息off-topic(離題),當(dāng)用戶連續(xù)三次觸發(fā)out_of_scope意圖,這時候我們就需要主動告知用戶需要向其提供幫助,如果要Rasa Core能夠?qū)W習(xí)這種模型,max_history應(yīng)該至少為3。story.md中表現(xiàn)如下:

          * out_of_scope - utter_default* out_of_scope - utter_default* out_of_scope - utter_help_message
          • Keras Policy

          KerasPolicy策略是Keras框架中實現(xiàn)的神經(jīng)網(wǎng)絡(luò)來預(yù)測選擇執(zhí)行下一個action,它默認(rèn)的框架使用LSTM(Long Short-Term Memory,長短期記憶網(wǎng)絡(luò))算法,但是我們也可以重寫KerasPolicy.model_architecture函數(shù)來實現(xiàn)自己的框架(architecture)。KerasPolicy的模型很簡單,只是單一的LSTM+Dense+softmax,這就需要我們不斷地完善自己的story來把各種情況下的story進(jìn)行補充。下面演示了如何在策略配置文件config.yml文件中,配置KerasPolicy策略,其中,epochs表示訓(xùn)練的次數(shù),max_history同上。

          policies: - name: KerasPolicy epochs: 100 max_history: 5
          • Embedding Policy

          基于機器學(xué)習(xí)的對話管理能夠?qū)W習(xí)復(fù)雜的行為以完成任務(wù),但是將其功能擴展到新領(lǐng)域并不簡單,尤其是不同策略處理不合作用戶行為的能力,以及在學(xué)習(xí)新任務(wù)(如預(yù)訂酒店)時,如何將完成一項任務(wù)(如餐廳預(yù)訂)重新應(yīng)用于該任務(wù)時的情況。EmbeddingPolicy,即循環(huán)嵌入式對話策略(Recurrent Embedding Dialogue Policy,REDP),它通過將actions和對話狀態(tài)嵌入到相同的向量空間(vector space)能夠獲得較好的效果,REDP包含一個基于改進(jìn)的Neural Turing Machine的記憶組件和注意機制,在該任務(wù)上顯著優(yōu)于基線LSTM分類器。

          EmbeddingPolicy效果上優(yōu)于KerasPolicy,但是它有個問題是耗時,因為它沒有使用GPU、沒有充分利用CPU資源。KerasPolicy和EmbeddingPolicy比較示意圖如下:

          配置EmbeddingPolicy參數(shù):

          policies: - name: EmbeddingPolicy epochs: 100 featurizer: - name: FullDialogueTrackerFeaturizer state_featurizer: - name: LabelTokenizerSingleStateFeaturizer

          注:新版的Rasa將EmbeddingPolicy重命名為TEDPolicy,但是我在config.yml配置文件中將其替換后,提示無法找到TEDPolicy異常,具體原因不明,暫還未涉及源碼分析。

          • Form Policy

          FormPolicy是MemoizationPolicy的擴展,用于處理(form)表單的填充事項。當(dāng)一個FormAction被調(diào)用時,F(xiàn)ormPolicy將持續(xù)預(yù)測表單動作,直到表單中的所有槽都被填滿,然后再執(zhí)行對應(yīng)的FormAction。如果在Bot系統(tǒng)中使用了FormActions,就需要在config.yml配置文件中進(jìn)行配置。

          policies: - name: FormPolicy
          • Mapping Policy

          MappingPolicy可用于直接將意圖映射到要執(zhí)行的action,從而實現(xiàn)被映射的action總會被執(zhí)行,其中,這種映射是通過triggers屬性實現(xiàn)的。舉個栗子(domain.yml文件中):

          intents: - greet: {triggers: utter_goodbye}

          其中,greet是意圖;utter_goodbye是action。一個意圖最多只能映射到一個action,我們的機器人一旦收到映射意圖的消息,它將執(zhí)行對應(yīng)的action。然后,繼續(xù)監(jiān)聽下一條message。需要注意的是,對于上述映射,我們還需要要在story.md文件中添加如下樣本,否則,任何機器學(xué)習(xí)策略都可能被預(yù)測的action_greet在dialouge歷史中突然出現(xiàn)而混淆。

          • Fallback Policy

          如果意圖識別的置信度低于nlu_threshold,或者沒有任何對話策略預(yù)測的action置信度高于core_threshold,F(xiàn)allbackPolicy將執(zhí)行fallback action。通俗來說,就是我們的對話機器人意圖識別和action預(yù)測的置信度沒有滿足對應(yīng)的閾值,該策略將使機器人執(zhí)行指定的默認(rèn)action。configs.yml配置如下:

          policies: - name: "FallbackPolicy" # 意圖理解置信度閾值 nlu_threshold: 0.3 # action預(yù)測置信度閾值 core_threshold: 0.3 # fallback action fallback_action_name: 'action_default_fallback'

          其中,action_default_fallback是Rasa Core中的一個默認(rèn)操作,它將向用戶發(fā)送utter_default模板消息,因此我們需要確保在domain.yml文件中指定此模板。當(dāng)然,我們也可以在fallback_action_name字段自定義默認(rèn)回復(fù)的action,比如my_fallback_cation,就可以這么改:

          policies: - name: "FallbackPolicy" nlu_threshold: 0.4 core_threshold: 0.3 fallback_action_name: "my_fallback_action"

          2.6 Slots

          Slots,槽值,相當(dāng)于機器人的內(nèi)存(memory),它們以鍵值對的形式存在,用于存儲用戶輸入時消息時比較重要的信息,而這些信息將為Action的執(zhí)行提供關(guān)鍵數(shù)據(jù)。Slots的定義位于domain.yaml文件中,它們通常與Entities相對應(yīng),即Entities有哪些,Slots就有哪些,并且Slots存儲的值就是NLU模型提取的Entities的值。

          2.6.1 Slots Type

          1. Text類型

          示例:

          # domain.yamlslots: cuisine: type: text

          2. Boolean類型

          示例:

          slots: is_authenticated: type: bool

          3. categorical類型

          示例:

          slots: risk_level: type: categorical values: - low - medium - high

          4. Float類型

          示例:

          slots: temperature: type: float min_value: -100.0 max_value: 100.0

          5. List類型

          示例:

          slots: shopping_items: type: list

          6. Unfeaturized 類型

          示例:

          slots: internal_user_id: type: unfeaturized

          2.6.2 Slots Set

          Slots值填充有多種方式,它們的操作方式如下:

          1. Slots Initial

          # domain.yamlslots: name: type: text initial_value: "human"

          在domain.yaml文件中聲明slots時,可以通過initial_value字段為當(dāng)前slot提供一個初始值,也就是說,當(dāng)會話開始時,被設(shè)定初始值的slot已經(jīng)被填充好。當(dāng)然,這個操作不是必須的。

          2. Slots Set from NLU

          # stories.md# story_01* greet{"name": "Ali"} - slot{"name": "Ali"} - utter_greet

          假如在stories.md文件添加一個包含-slot{}的story,這就意味著當(dāng)NLU模型提取到一個名為name的實體且這個實體有在domain.yaml中定義,那么NLU模型提取到的實體值會被自動填充到name槽中。實際上,對于Rasa來說,就算你不添加-slot{}字段,這個實體值也會被提取并自動填充到name槽中。當(dāng)然,如果你希望禁止這種自動填充行為,改為添加-slot{}字段填充,可以在domain.yaml定義slot時,設(shè)置auto_fill的值為False,即:

          # domain.yamlslots: name: type: text auto_fill: False

          3. Slots Set By Clicking Buttons

          # domain.yamlutter_ask_color:- text: "what color would you like?" buttons: - title: "blue"  payload: '/choose{"color": "blue"}' # 格式 '/intent{"entity":"value",...}'  - title: "red" payload: '/choose{"color": "red"}' 

          在點擊Button時填充Slots的值,是指當(dāng)我們的Bot(Rasa Core)在回復(fù)用戶時,可以在回復(fù)的消息中附加Button信息,這種Button類似于快捷鍵,用戶獲取到之后,可以直接將其發(fā)送給Rasa Core,它會直接進(jìn)行解析以識別intent和提取entity,并將entity的值填充到slot中。比如你讓用戶通過點擊一個按鈕來選擇一種顏色,那么可以在domain.yaml中utter_ask_color的回復(fù)中添加buttons:/choose{"color": "blue"}和/choose{"color": "red"}。注:通常每個button由title和payload字段組成。

          4. Slots Set by Actions

          from rasa_sdk.actions import Actionfrom rasa_sdk.events import SlotSetimport requests

          class FetchProfileAction(Action): def name(self): return "fetch_profile"

          def run(self, dispatcher, tracker, domain): url = "http://myprofileurl.com" data = requests.get(url).json return [SlotSet("account_type", data["account_type"])]

          該示例演示了如何在Custom Action中通過返回事件來填充Slots的值,即調(diào)用SlotSet事件函數(shù)并將該事件return。需要注意的是,為了達(dá)到這個目的,我們在編寫Story時必須包含該Slot,即使用-slot{}實現(xiàn),只有這樣Rasa Core就會從提供的信息中進(jìn)行學(xué)習(xí),并決定執(zhí)行正確的action。Story.md示例如下:

          # story_01* greet - action_fetch_profile - slot{"account_type" : "premium"} - utter_welcome_premium

          # story_02* greet - action_fetch_profile - slot{"account_type" : "basic"} - utter_welcome_basic

          其中,account_type在domain.yaml中定義如下:

          slots: account_type: type: categorical values: - premium - basic

          2.6.3 Slots Get

          目前主要有兩種獲取Slots值方式:

          1. Get Slot in responses

          responses: utter_greet: - text: "Hey, {name}. How are you?"

          在domain.yaml的responses部分,可以通過{slotname}的形式獲取槽值。

          2. Get Slot in Custom Action

          from rasa_sdk.actions import Actionfrom rasa_sdk.events import SlotSetimport requests

          class FetchProfileAction(Action): def name(self): return "fetch_profile"

          def run(self, dispatcher, tracker, domain): # 獲取slot account_type的值 account_type = tracker.get_slot('account_type') return

          Tracker,可理解為跟蹤器,作用是以會話會話的形式維護(hù)助手和用戶之間的對話狀態(tài)。通過Tracker,能夠輕松獲取整個對話信息,其中就包括Slot的值。

          2.7 Form

          在Rasa Core中,當(dāng)我們執(zhí)行一個action需要同時填充多個slot時,可以使用FormAction來實現(xiàn),因為FormAction會遍歷監(jiān)管的所有slot,當(dāng)發(fā)現(xiàn)相關(guān)的slot未被填充時,就會向用戶主動發(fā)起詢問,直到所有slot被填充完畢,才會執(zhí)行接下來的業(yè)務(wù)邏輯。使用步驟如下:

          (1)構(gòu)造story

          在story中,不僅需要考慮用戶按照我們的設(shè)計準(zhǔn)確的提供有效信息,而且還要考慮用戶在中間過程改變要執(zhí)行的意圖情況或稱輸入無效信息,因為對于FormAction來說,如果無法獲得預(yù)期的信息就會報錯,這里我們分別稱這兩種情況為happy path、unhappy path。示例如下:

          ## happy path* request_weather - weather_form - form{"name": "weather_form"} 激活form - form{"name": } 使form無效## unhappy path* request_weather - weather_form - form{"name": "weather_form"}* stop - utter_ask_continue* deny - action_deactivate_form - form{"name": }

          注:* request_restaurant為意圖;- restaurant_form為form action;- form{"name": "restaurant_form"}為激活form;- form{"name": }為注銷form;- action_deactivate_form為默認(rèn)的action,它的作用是用戶可能在表單操作過程中改變主意,決定不繼續(xù)最初的請求,我們使用這個default action來禁止(取消)表單,同時重置要請求的所有slots。

          構(gòu)建stroy最好使用官方提供的Interactive Learning,防止漏掉信息,詳細(xì)見本文2.8小節(jié)。

          (2)添加form字段到Domain

          在doamin文件下新增forms:部分,并將所有用到的form名稱添加到該字段下:

          intents: - request_weather
          forms: - weather_form

          (3)配置FormPolicy

          在工程的配置文件configs.yml中,新增FormPolicy策略:

          policies: - name: EmbeddingPolicy epochs: 100 max_history: 5 - name: FallbackPolicy fallback_action_name: 'action_default_fallback' - name: MemoizationPolicy max_history: 5 - name: FormPolicy

          (4)Form Action實現(xiàn)

          class WeatherForm(FormAction):

          def name(self) -> Text: """Unique identifier of the form"""

          return "weather_form"

          @staticmethod def required_slots(tracker: Tracker) -> List[Text]: """A list of required slots that the form has to fill"""

          return ["date_time", "address"]

          def submit( self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any], ) -> List[Dict]: """Define what the form has to do after all required slots are filled""" address = tracker.get_slot('address') date_time = tracker.get_slot('date_time')

          return

          當(dāng)form action第一被調(diào)用時,form就會被激活并進(jìn)入FormPolicy策略模式。每次執(zhí)行form action,required_slots會被調(diào)用,當(dāng)發(fā)現(xiàn)某個還未被填充時,會主動去調(diào)用形式為uter_ask_{slotname}的模板(注:定義在domain.yml的templates字段中);當(dāng)所有slot被填充完畢,submit方法就會被調(diào)用,此時本次form操作完畢被取消激活。

          2.8 Interactive Learning

          雖然我們可以容易的人工構(gòu)建story樣本數(shù)據(jù),但是往往會出現(xiàn)一些考慮不全,甚至出錯等問題,基于此,Rasa Core框架為我們提供了一種交互式學(xué)習(xí)(Interactive Learning)來獲得所需的樣本數(shù)據(jù)。在互動學(xué)習(xí)模式中,當(dāng)你與機器人交談時,你會向它提供反饋,這是一種強大的方法來探索您的機器人可以做什么,也是修復(fù)它所犯錯誤的最簡單的方法。基于機器學(xué)習(xí)的對話的一個優(yōu)點是,當(dāng)你的機器人還不知道如何做某事時,你可以直接教它。

          (1)開啟Action Server

          python -m rasa run actions --port 5055 --actions actions --debug

          (2)開啟Interactive Learning

          python -m rasa interactive -m models/20200313-101055.tar.gz --endpoints configs/endpoints.yml --config configs/config.yml # 或者(沒有已訓(xùn)練模型情況)# rasa會先訓(xùn)練好模型,再開啟交互式學(xué)習(xí)會話python -m rasa interactive --data /data --domain configs/domain.yml --endpoints configs/endpoints.yml --config configs/config.yml 

          分別執(zhí)行(1)、(2)命令后,我們可以預(yù)設(shè)一個交互場景根據(jù)終端的提示操作即可。如果一個交互場景所有流程執(zhí)行完畢,按Ctrl+C結(jié)束并選擇Start Fresh進(jìn)入下一個場景即可。當(dāng)然Rasa還提供了可視化界面,以幫助你了解每個Story樣本構(gòu)建的過程,網(wǎng)址:http://localhost:5005/visualization.html。

          執(zhí)行流程大致如下:

          Bot loaded. Visualisation at http://localhost:5006/visualization.html .Type a message and press enter (press 'Ctr-c' to exit).? Your input -> 查詢身份證439912199008071234? Is the intent 'request_idcard' correct for '查詢身份證[439912199008071234](id_number)' and are all entities labeled correctly? Yes------Chat History

          # Bot You ─────────────────────────────────────────────────────────────────── 1 action_listen─────────────────────────────────────────────────────────────────── 2 查詢身份證[439912199008071234](id_number) intent: request_idcard 1.00



          Current slots: address: None, business: None, date-time: None, id_number: None, requested_slot: None

          ------? The bot wants to run 'number_form', correct? YesChat History

          # Bot You ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 1 action_listen────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 2 查詢身份證[439912199008071234](id_number) intent: request_idcard 1.00────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 3 number_form 1.00 您要查詢的身份證號碼439912199008071234所屬人為張三,湖南長沙人,現(xiàn)在就職于地球村物業(yè)。 form{"name": "number_form"} slot{"id_number": "439912199008071234"} form{"name": } slot{"requested_slot": }



          Current slots: address: None, business: None, date-time: None, id_number: 439912199008071234, requested_slot: None

          ------? The bot wants to run 'action_listen', correct? Yes

          生成的一個Story示例如下:

          ## interactive_story_10# unhappy path:chitchat stop but continue path* greet - utter_answer_greet* request_number{"type": "身份證號碼"} - number_form - form{"name": "number_form"} - slot{"type": "身份證號碼"} - slot{"number": } - slot{"business": } - slot{"requested_slot": "number"}* chitchat - utter_chitchat - number_form - slot{"requested_slot": "number"}* stop - utter_ask_continue* affirm - number_form - slot{"requested_slot": "number"}* form: request_number{"number": "440123199087233467"} - form: number_form - slot{"number": "440123199087233467"} - slot{"type": "身份證號碼"} - form{"name": } - slot{"requested_slot": }* thanks - utter_noworries

          改進(jìn)ChitChatAssistant項目

          3.1 config.yml

          # zh_jieba_mitie_embeddings_config.yml

          language: "zh"

          pipeline:- name: "MitieNLP" model: "data/total_word_feature_extractor_zh.dat"- name: "JiebaTokenizer" dictionary_path: "data/dict"- name: "MitieEntityExtractor"- name: "EntitySynonymMapper"- name: "RegexFeaturizer"- name: "MitieFeaturizer"- name: "EmbeddingIntentClassifier"

          policies: - name: FallbackPolicy nlu_threshold: 0.5 ambiguity_threshold: 0.1 core_threshold: 0.5 fallback_action_name: 'action_default_fallback' - name: MemoizationPolicy max_history: 5 - name: FormPolicy - name: MappingPolicy - name: EmbeddingPolicy epochs: 500

          考慮到目前項目的樣本較少,這里使用MITIE+EmbeddingPolicy組合,雖然訓(xùn)練時慢了點,但是能夠保證實體提取的準(zhǔn)確性,同時又能夠提高意圖識別的命中率。

          3.2 weather_stories.md

          ## happy path* request_weather - weather_form - form{"name": "weather_form"} - form{"name": }
          ## happy path* greet - utter_answer_greet* request_weather - weather_form - form{"name": "weather_form"} - form{"name": }* thanks - utter_noworries

          ## unhappy path* greet - utter_answer_greet* request_weather - weather_form - form{"name": "weather_form"}* chitchat - utter_chitchat - weather_form - form{"name": }* thanks - utter_noworries

          ## very unhappy path* greet - utter_answer_greet* request_weather - weather_form - form{"name": "weather_form"}* chitchat - utter_chitchat - weather_form* chitchat - utter_chitchat - weather_form* chitchat - utter_chitchat - weather_form - form{"name": }* thanks - utter_noworries

          ## stop but continue path* greet - utter_answer_greet* request_weather - weather_form - form{"name": "weather_form"}* stop - utter_ask_continue* affirm - weather_form - form{"name": }* thanks - utter_noworries

          ## stop and really stop path* greet - utter_answer_greet* request_weather - weather_form - form{"name": "weather_form"}* stop - utter_ask_continue* deny - action_deactivate_form - form{"name": }

          ## chitchat stop but continue path* request_weather - weather_form - form{"name": "weather_form"}* chitchat - utter_chitchat - weather_form* stop - utter_ask_continue* affirm - weather_form - form{"name": }* thanks - utter_noworries

          ## stop but continue and chitchat path* greet - utter_answer_greet* request_weather - weather_form - form{"name": "weather_form"}* stop - utter_ask_continue* affirm - weather_form* chitchat - utter_chitchat - weather_form - form{"name": }* thanks - utter_noworries

          ## chitchat stop but continue and chitchat path* greet - utter_answer_greet* request_weather - weather_form - form{"name": "weather_form"}* chitchat - utter_chitchat - weather_form* stop - utter_ask_continue* affirm - weather_form* chitchat - utter_chitchat - weather_form - form{"name": }* thanks - utter_noworries

          ## chitchat, stop and really stop path* greet - utter_answer_greet* request_weather - weather_form - form{"name": "weather_form"}* chitchat - utter_chitchat - weather_form* stop - utter_ask_continue* deny - action_deactivate_form - form{"name": }
          ## interactive_story_1## 天氣 + 時間 + 地點 + 地點* request_weather - weather_form - form{"name": "weather_form"} - slot{"requested_slot": "date_time"}* form: inform{"date_time": "明天"} - form: weather_form - slot{"date_time": "明天"} - slot{"requested_slot": "address"}* form: inform{"address": "廣州"} - form: weather_form - slot{"address": "廣州"} - form{"name": } - slot{"requested_slot": }* inform{"date_time": "后天"} OR request_weather{"date_time": "后天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "廣州"} - slot{"date_time": "后天"} - form{"name": } - slot{"requested_slot": }* thanks - utter_answer_thanks

          ## interactive_story_1## 天氣 + 時間 + 地點 + 時間* request_weather - weather_form - form{"name": "weather_form"} - slot{"requested_slot": "date_time"}* form: inform{"date_time": "明天"} - form: weather_form - slot{"date_time": "明天"} - slot{"requested_slot": "address"}* form: inform{"address": "廣州"} - form: weather_form - slot{"address": "廣州"} - form{"name": } - slot{"requested_slot": }* inform{"address": "上海"} OR request_weather{"address": "深圳"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "廣州"} - slot{"address": "上海"} - form{"name": } - slot{"requested_slot": }* affirm - utter_answer_affirm

          ## interactive_story_2## 天氣/時間/地點 + 地點* request_weather{"date_time": "明天", "address": "上海"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "上海"} - form{"name": } - slot{"requested_slot": }* inform{"address": "廣州"} OR request_weather{"address": "廣州"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "上海"} - slot{"address": "廣州"} - form{"name": } - slot{"requested_slot": }* thanks - utter_answer_thanks

          ## interactive_story_3## 天氣/時間/地點 + 時間* request_weather{"address": "深圳", "date_time": "后天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "后天"} - slot{"address": "深圳"} - form{"name": } - slot{"requested_slot": }* inform{"date_time": "大后天"} OR request_weather{"date_time": "大后天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "后天"} - slot{"address": "深圳"} - slot{"date_time": "大后天"} - form{"name": } - slot{"requested_slot": }* thanks - utter_answer_thanks

          ## interactive_story_2## 天氣/時間/地點 + 地點 + 時間* request_weather{"date_time": "明天", "address": "上海"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "上海"} - form{"name": } - slot{"requested_slot": }* inform{"address": "北京"} OR request_weather{"address": "北京"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "上海"} - slot{"address": "北京"} - form{"name": } - slot{"requested_slot": }* inform{"date_time": "后天"} OR request_weather{"date_time": "后天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "北京"} - slot{"date_time": "后天"} - form{"name": } - slot{"requested_slot": }* affirm - utter_answer_affirm

          ## interactive_story_3## 天氣/時間/地點 + 地點 + 地點* request_weather{"date_time": "后天", "address": "北京"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "后天"} - slot{"address": "北京"} - form{"name": } - slot{"requested_slot": }* inform{"address": "深圳"} OR request_weather{"address": "深圳"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "后天"} - slot{"address": "北京"} - slot{"address": "深圳"} - form{"name": } - slot{"requested_slot": }* inform{"address": "南京"} OR request_weather{"address": "南京"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "后天"} - slot{"address": "深圳"} - slot{"address": "南京"} - form{"name": } - slot{"requested_slot": }* thanks - utter_answer_thanks

          ## interactive_story_4## 天氣/時間/地點 + 時間 + 地點* request_weather{"date_time": "明天", "address": "長沙"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "長沙"} - form{"name": } - slot{"requested_slot": }* inform{"date_time": "后天"} OR request_weather{"date_time": "后天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "長沙"} - slot{"date_time": "后天"} - form{"name": } - slot{"requested_slot": }* inform{"date_time": "大后天"} OR request_weather{"date_time": "大后天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "后天"} - slot{"address": "長沙"} - slot{"date_time": "大后天"} - form{"name": } - slot{"requested_slot": }* affirm - utter_answer_affirm

          ## interactive_story_5## 天氣/時間/地點 + 時間 + 時間* request_weather{"date_time": "后天", "address": "深圳"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "后天"} - slot{"address": "深圳"} - form{"name": } - slot{"requested_slot": }* inform{"date_time": "明天"} OR request_weather{"date_time": "明天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "后天"} - slot{"address": "深圳"} - slot{"date_time": "明天"} - form{"name": } - slot{"requested_slot": }* inform{"address": "廣州"} OR request_weather{"address": "廣州"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "深圳"} - slot{"address": "廣州"} - form{"name": } - slot{"requested_slot": }* thanks - utter_answer_thanks

          ## interactive_story_4## 天氣/時間 + 地點 + 時間* request_weather{"date_time": "明天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"requested_slot": "address"}* form: inform{"address": "廣州"} - form: weather_form - slot{"address": "廣州"} - form{"name": } - slot{"requested_slot": }* inform{"date_time": "后天"} OR request_weather{"date_time": "后天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "明天"} - slot{"address": "廣州"} - slot{"date_time": "后天"} - form{"name": } - slot{"requested_slot": }* thanks - utter_answer_thanks

          ## interactive_story_5## 天氣/地點 + 時間 + 時間* request_weather{"address": "廣州"} - weather_form - form{"name": "weather_form"} - slot{"address": "廣州"} - slot{"requested_slot": "date_time"}* form: inform{"date_time": "后天"} - form: weather_form - slot{"date_time": "后天"} - form{"name": } - slot{"requested_slot": }* inform{"date_time": "明天"} OR request_weather{"date_time": "明天"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "后天"} - slot{"address": "廣州"} - slot{"date_time": "明天"} - form{"name": } - slot{"requested_slot": }* thanks - utter_answer_thanks
          ## interactive_story_1## 天氣/時間/地點 + chit + chit(restart)+詢問天氣* request_weather{"date_time": "今天", "address": "廣州"} - weather_form - form{"name": "weather_form"} - slot{"date_time": "今天"} - slot{"address": "廣州"} - form{"name": } - slot{"requested_slot": }* chitchat - utter_chitchat* chitchat - utter_chitchat - action_restart* request_weather - weather_form - form{"name": "weather_form"} - slot{"requested_slot": "date_time"}* form: inform{"date_time": "今天"} - form: weather_form - slot{"date_time": "今天"} - slot{"requested_slot": "address"}* form: inform{"address": "廣州"} - form: weather_form - slot{"address": "廣州"} - form{"name": } - slot{"requested_slot": }* thanks - utter_answer_thanks

          在構(gòu)建Story樣本時,主要是使用Interactive Learning工具實現(xiàn),以確保枚舉盡可能多的unhappy story,同時又能夠防止在構(gòu)建樣本時出現(xiàn)信息遺漏的情況。此外,本版本中除了查詢天氣這個案例,還新增了其他案例,并列舉了如何使用同義詞、自定義字典以及正則表達(dá)式的使用方法,詳細(xì)見最新版項目。

          GitHub地址:ChitChatAssistant https://github.com/jiangdongguo/ChitChatAssistant,歡迎star和issues,我們共同討論、學(xué)習(xí)!

          原文鏈接:

          https://blog.csdn.net/AndrExpert/article/details/105434136

          ?沒有監(jiān)控和日志咋整?老程序員來支招

          ?朱廣權(quán)李佳琦直播掉線,1.2億人在線等

          ?RPC的超時設(shè)置,一不小心就是線上事故!

          ?拿下Gartner容器產(chǎn)品第一,阿里云打贏云原生關(guān)鍵一戰(zhàn)!

          ?深聊Solidity的測試場景、方法和實踐,太詳細(xì)了,必須收藏!

          ?萬字干貨:一步步教你如何在容器上構(gòu)建持續(xù)部署!

          ?據(jù)說,這是當(dāng)代極客們的【技術(shù)風(fēng)向標(biāo)】...

          今日福利:評論區(qū)留言入選,可獲得價值299元的「2020 AI開發(fā)者萬人大會」在線直播門票一張。 快來動動手指,寫下你想說的話吧。


          上一篇:「HTML4」HTML入門
          下一篇:HTML5 Audio(音頻)
          主站蜘蛛池模板: 国产乱子伦一区二区三区| 在线|一区二区三区四区| 日韩精品无码一区二区三区不卡 | 亚洲综合激情五月色一区| 一区二区三区精品高清视频免费在线播放 | 久久99久久无码毛片一区二区| 亚洲av乱码一区二区三区| 日韩精品一区二区三区大桥未久| 精品视频在线观看一区二区| 精品国产免费一区二区| 精品无人乱码一区二区三区| 亚欧免费视频一区二区三区 | 精品日韩一区二区| 国产SUV精品一区二区88| 3d动漫精品啪啪一区二区中文 | 亚洲一区二区三区AV无码| 91国在线啪精品一区| 一区二区三区在线视频播放| 极品少妇伦理一区二区| 国产在线一区视频| 国产一区二区三区在线观看免费| 成人丝袜激情一区二区| 日韩免费视频一区| 国产一区二区三区内射高清| 风流老熟女一区二区三区| 制服美女视频一区| 成人精品一区二区三区中文字幕| 一区二区日韩国产精品| 欧洲精品无码一区二区三区在线播放 | 日韩免费视频一区二区| 日本伊人精品一区二区三区| 亚洲欧洲精品一区二区三区| 日韩免费一区二区三区在线| 无码夜色一区二区三区| 亚洲av日韩综合一区久热| 精品中文字幕一区二区三区四区| 极品少妇伦理一区二区| 寂寞一区在线观看| 99精品国产高清一区二区麻豆| 无码精品一区二区三区| 无码日韩精品一区二区人妻 |