TL;DR

我最近完成了 Udacity 的 Future AWS Agent Engineer Nanodegree Program 其中一個專案,而我能參加這個課程,是透過 AWS AI & ML Scholarship

我使用 Amazon Bedrock AgentCore、AgentCore Gateway、AWS Lambda、DynamoDB 和 FAQ 建了一個客服代理。這個代理必須理解客戶是在回報 bug、詢問可從 FAQ 回答的問題,還是提出需要真人客服支援的需求。

我大約在兩天內完成,並且第一次嘗試就通過,正確率得分為 0.83。當時我生活上有很多事情正在發生,所以沒有足夠時間回頭再精修,或再跑一次評估。

這個專案中我學到最多的,其實是某次評估失敗。對於 bug 回報,我告訴代理,在建立工單前必須有 3 個資訊:問題描述、重現步驟,以及發生時的環境。但在 2 個測試案例中,模型理解了客戶在說什麼,並且即使缺少其中一項必要資訊,仍然建立了工單。

這讓我意識到一件我以前沒有想得夠多的事:理解請求,並不等於擁有足夠資訊可以安全地採取行動。

這就是我從這個專案帶走的主要心得。打造代理,不只是讓模型有能力回答問題;也包括清楚定義:它什麼時候應該行動、什麼時候應該再追問更多資訊,以及什麼時候應該停下來把請求交給真人處理。

我知道現在已經有很多很棒的 AWS、AgentCore 和 AI 代理文章,我自己也從中學到很多。我也還在學習,所以這篇只是我建造這個專案的經驗、我在哪裡感到困惑、評估結果告訴了我什麼,以及下次我會怎麼做得不一樣。


目錄


我想先從一件誠實的事開始說起

我最近又完成了一個專案,這次對我來說有點不一樣。它是 Udacity 的 Future AWS Agent Engineer Nanodegree Program 的一部分,而我能參加,是透過 AWS AI & ML Scholarship

這個專案我大約花了 2 天完成。當時我同時還在應付生活中的很多其他事情,所以我只能盡量把手上的時間用好,繼續往前推。

<p align="center">
<img src="https://media.giphy.com/media/H1dxi6xdh4NGQCZSvz/giphy.gif" width="320"/>
</p>

我第一次嘗試就通過了,這讓我非常開心,但我也知道自己沒有像平常那樣花足夠時間去打磨它。

如果我有更多時間,我會回頭更仔細看評估結果、改進 prompt、增加更多測試案例,再跑一次評估。這次我沒有那樣做。最後的正確率得分是 0.83

一開始,我覺得自己可能應該等到分數更高再來寫這個專案。但後來我想了想,自己到底從中學到了什麼。那 2 個沒有完美通過的地方,反而是這個專案裡對我最有幫助的部分。這也是我想分享的內容。

已經有很多很棒的文章在講如何打造代理、AWS 服務,以及 AgentCore。我自己也從中學到很多。這篇不是要再寫一篇試圖把代理開發全部講完的文章;相反地,我想分享的是,作為一個還在學習的人,從我的角度看這個專案是什麼樣子。

因為當你是初學者時,有時候最難的不是程式碼,而是理解每個元件到底在做什麼,以及為什麼它們必須存在。


我做了什麼,以及各個元件如何彼此配合

這個專案是一個虛構的線上商店客服系統。客戶可以傳訊息,而代理必須理解客戶需要什麼,並決定下一步要怎麼做。

總共有三種可能的行為。第一種是 BUG_REPORT。如果客戶說像是:「我每次點擊付款時,結帳頁面都會當掉」,代理就必須辨識出這是一個技術問題。但光是辨識出是 bug 還不夠,還不能直接建立工單。要這麼做之前,代理必須先收集三項特定資訊:問題描述、重現步驟,以及發生環境

第二種是 PLATFORM_QUESTION。這些問題包含訂單、出貨、退貨、退款、付款、產品、帳號,以及隱私等主題。對這些問題,代理有一份 FAQ,預期要使用 FAQ 來回答,而不是靠模型自己憑一般知識亂答。

第三種是 OTHER_REQUEST。如果請求不是技術 bug,而且也無法透過 FAQ 回答,代理就必須把客戶導向真人客服支援。

當我不再把每個 AWS 服務分開看,而是看它們如何一起運作時,架構就變得容易理解多了。

<p align="center">
<img src="https://media.giphy.com/media/xT1R9JQhsDfuLHfpOE/giphy.gif" width="320"/>
</p>

整個流程大致上是:

Architecture diagram showing a customer support AI agent built with Amazon Bedrock AgentCore, with prompt-based routing to bug reporting, FAQ answers, or human support, and bug reports flowing through AgentCore Gateway, AWS Lambda, and DynamoDB

這就是我為這個專案建立的架構。路由是透過 system prompt 處理的,而不是透過獨立的分類器或條件節點。

那麼,每個 AWS 服務在這裡實際上是做什麼的?

如果你剛接觸 AWS,這些服務名稱會讓這類專案看起來比實際上複雜很多。對我來說有幫助的是先思考每個元件各自負責什麼,而不是一口氣想理解所有 AWS 服務。

Amazon Bedrock AgentCore Managed Harness 是代理周圍的執行環境。簡單來說,它提供了讓代理搭配模型、指令與工具運作所需的結構,而不必由我自己把所有環境都搭起來。

模型 負責理解客戶訊息,並根據收到的指令決定下一步要做什麼。它就是實際進行語言理解與決策的部分。

System prompt 定義了代理應該如何行為。這在我的專案中特別重要,因為路由邏輯是寫在 prompt 裡的。prompt 告訴模型如何辨識這 3 種請求,以及每一種請求要遵守什麼規則。

AgentCore Gateway 負責把代理連接到後端工具。模型不是直接去改資料庫。相反地,等到必要資訊收集完成後,代理可以透過 Gateway 呼叫工具。

AWS Lambda 負責實際的後端操作。當代理帶著必要資訊呼叫工具時,Lambda 會處理請求並建立 bug 回報。

Amazon DynamoDB 儲存那張 bug 工單。這對我來說也是很有幫助的一點,因為它讓我明白,代理的回應不只是文字而已。如果代理回傳了一個工單 ID,背後其實真的有一筆資料被存進 DynamoDB。

FAQ 則是平台問題的受控資訊來源。對於這類問題,代理應該使用 FAQ 裡提供的資訊來回答,而不是依賴一般知識。

當我這樣看待它之後,架構就不再像是一堆陌生的 AWS 名稱。模型理解客戶訊息,prompt 告訴它要遵守哪些規則,Gateway 把它連到可以執行動作的工具,Lambda 執行那個動作,而 DynamoDB 儲存結果。對於平台問題,FAQ 提供代理可以使用的資訊;至於超出這些範圍的請求,就交給真人客服。

這種簡單的理解方式,比起死背每個 AWS 服務各自做什麼,對我幫助更大。

一開始讓我困惑的一個字是 「classifier」。我第一次看到這個需求時,腦中想像的是會有一個獨立元件,它唯一的工作就是把客戶訊息分類,然後送到系統的正確部分。

但我做出來的並不是那樣。

在我的實作裡,路由邏輯是 system prompt 的一部分。模型被指示要從 3 條路由中選擇一條,然後依照那條路由的規則行事。

理解這件事之後,我看 prompt 的角度也改變了。我一開始主要把 prompt 想成是「告訴模型應該怎麼回應」的指令,比如:

「你是一個有幫助的客服助理。」

這樣很有用,但如果模型還要做決策和使用工具,這就不夠了。在這個專案裡,prompt 不只是告訴代理該怎麼回覆,也是在告訴它:它能做什麼、在做之前需要什麼資訊。


這個 Prompt 比我預期的還要重要

在這個專案之前,我大多把 system prompt 看成是一種告訴模型怎麼行為的方式。像這樣:

「你是一個有幫助的客服助理。」

這很有用,但當模型也要做決策並使用工具時,就還不夠。在這個專案裡,prompt 不只是告訴代理要怎麼回應,也是在告訴它什麼是它允許做的,以及在做之前需要哪些資訊。

<p align="center">
<img src="https://media.giphy.com/media/Gz5VFiWLMbxD36VKuJ/giphy.gif" width="320"/>
</p>

Prompt 在設定規則

對於 BUG_REPORT,prompt 會說明什麼算是 bug,以及在建立工單前需要哪些資訊。3 個必要欄位是 問題描述、重現步驟、發生環境。如果少了任何一項,代理必須一次只追問一個欄位,不能在 3 項都齊全之前呼叫工具。

prompt 也定義了另外兩條路徑。PLATFORM_QUESTION 必須使用提供的 FAQ 回答,而 OTHER_REQUEST 必須導向真人客服支援。

對我來說,FAQ 這部分很有趣,因為它讓我明白,為什麼有時候必須明確告訴代理哪些資訊可以用、哪些不能用。

假設客戶問:

「我有多久可以退貨?」

FAQ 說,大多數商品在 送達後 30 天內 可以退貨,前提是商品未使用且保留原包裝,除非商品本身有瑕疵。所以代理可以根據收到的資訊來回答。

但如果有人問:

「你們有提供學生優惠嗎?」

如果 FAQ 裡沒有提到學生優惠,代理就不應該自己編一個答案,因為模型可能在別的地方看過學生優惠相關內容。它應該把客戶轉給真人客服。

這件事讓我非常清楚:模型可以知道很多事情,但這不代表它知道的是你公司的政策

退款、出貨、付款政策、帳號規則,以及其他任何「自信但錯誤的答案可能造成真實問題」的資訊,也都一樣。對這個專案來說,FAQ 是一個受控的資訊來源,而 prompt 把這條界線說得很清楚。

我也必須思考客戶可能會做什麼

這個 prompt 還有一個我在專案之前沒有太思考過的工作:處理 prompt injection

其中一個測試案例基本上是在叫代理忽略指令、洩漏 system prompt,並且在沒有收集必要資訊的情況下直接建立 bug 工單。代理沒有照著那些指令做,它仍然遵守 system prompt 定義的規則。

這讓我很有收穫,因為它逼我開始思考,不能只看自己在開發時自然會寫的簡單測試。當我們自己測試代理時,通常會給它我們預期客戶會說的那種訊息。但真實使用者可能會漏掉資訊、問完全無關的內容,甚至刻意試著改變代理的行為。

所以 prompt 不能只描述 happy path,也必須把界線說清楚。

同時,通過這一個 prompt injection 測試,不代表這個代理能防住所有可能的 injection。這只代表這個特定測試案例,依照我定義的規則被正確處理了。

這也是這個專案帶給我的另一個教訓。讓代理擁有更多能力,只是工作的一部分;你還必須清楚定義這些能力什麼時候能用、什麼時候不能用。


評估結果讓我看見自己哪裡錯了

這大概是這個專案對我最有幫助的部分。

讓代理在幾個手動測試裡正確回應是一回事;用刻意不完整、也更刁鑽的輸入來評估它,又是另一回事。為了這個專案,我建立了一份測試資料集,涵蓋不同路由,包括完整的 bug 回報、缺少資訊的 bug 回報、FAQ 問題、FAQ 沒有涵蓋的問題、要求真人客服的請求,以及一個 prompt injection 案例。

最後的正確率是 0.83。大部分測試都按照我想要的方式運作。完整 bug 回報正常、缺少環境資訊的案例正常、FAQ 問題正常、不支援的問題有正確轉交、要求真人客服的請求也處理正確,而 prompt injection 也通過了。

但有兩個測試失敗了,而這兩個失敗教會我的,其實幾乎是同一件事。

<p align="center">
<img src="https://media.giphy.com/media/xUooDfXRTz4Hn78f7X/giphy.gif" width="320"/>
</p>

那兩個失敗案例

第一個案例中,客戶說產品圖片無法在分類頁載入,並提到 Safari 和 iPhone。問題描述有了,環境也有了,但客戶沒有明確提供重現步驟。代理還是建立了工單。

第二個案例中,客戶給了重現步驟和 Chrome/Windows 環境,但沒有提供清楚的問題描述。同樣地,代理還是建立了工單。

一開始,我以為是模型根本沒有理解我的 prompt。但當我更仔細看這兩個案例時,我意識到模型大概是理解客戶在說什麼的。問題在於,它把這種理解當成了足以採取下一步行動的資訊。

從一般人類對話的角度來看,這不一定有什麼問題。如果有人說:

「產品圖片在我的 iPhone 上的 Safari 無法載入。」

人類大概可以理解到底哪裡出了問題,也知道客戶在指什麼。

但這不是我給代理設定的規則。代理不應該判斷:「我懂問題了,所以我可以建立工單。」它應該在建立工單前確認 3 個必要欄位是否都有明確提供

這是一個嚴格得多的要求。

這大概是這個專案帶給我最大的教訓:理解某件事,並不等於擁有足夠資訊可以安全執行動作。

當代理開始呼叫工具時,這點尤其重要。如果同樣的假設發生在一個會建立退款、變更帳號、送出申請或更新資料庫的系統裡,模型也許只是做出一個很合理的猜測,但那個猜測仍然可能導致錯誤的動作。

所以對我來說,重點問題不再是:

「模型懂不懂客戶的意思?」

而是:

「模型在採取這個動作之前,是否已經擁有它必須具備的所有資訊?」

如果我再做一個代理,我會更重視這一點。

回頭看,我其實覺得個別評估結果比總分更有用。0.83 只能告訴我整體表現如何,但看每個案例,才能精確看到行為在哪裡出問題。

對我來說,那兩個失敗案例比單純知道分數不是 1.0 更有價值。它們指出了我在定義代理行為時的一個具體問題,而且更重要的是,它們給了我明確可改進的方向。


我會想改什麼,以及我學到了什麼

如果我還能多花一天在這個專案上,我會先處理那兩個失敗案例。

我會讓 prompt 更明確地說明什麼算是某個欄位「已存在」,尤其是「問題描述」和「重現步驟」的差別。比方說,「圖片無法載入」 是問題描述;「打開商店,進入某個分類,點擊任一商品」 才是一組可以重現問題的步驟。

我也會更明確地說:代理不應該因為上下文很容易理解,就自行補上一個缺失欄位。如果客戶沒有真的提供重現步驟,代理就應該去追問,而不是自作主張認定自己已經知道了。

接著,我會針對同一類問題增加更多測試。當客戶在同一句話裡提供兩個欄位時會怎樣?第三個欄位是晚一則訊息才補上時會怎樣?當客戶使用模糊語言時會怎樣?當資訊可能合理地同時屬於兩個欄位時又會怎樣?

這些都是我下一步會想探索的案例,因為它們是代理看起來做得不錯、實際上卻仍在做假設的情境。

看到後端,讓代理的運作更有意義

我也從這個專案的後端部分學到一些東西。在實作之前,我大多把代理想成一個「接收訊息,然後給你答案」的東西。和工具與後端一起工作之後,我才開始看到:當代理被要求真的去做某件事時,背後會發生什麼。

我這個專案的流程是:

客戶資訊
        ↓
代理確認是否有足夠資訊
        ↓
AgentCore Gateway
        ↓
Lambda
        ↓
DynamoDB
        ↓
回傳工單 ID
        ↓
客戶收到工單 ID

對我來說,最重要的是:模型的回應本身不是那個動作。當代理說工單已經建立時,背後必須真的有一個實際操作。工具呼叫會經過 AgentCore Gateway,Lambda 負責後端操作,DynamoDB 儲存工單,而那個過程產生的工單 ID 再回傳給客戶。

這讓我更清楚地理解了,一般聊天機器人和代理工作流程之間的差別。聊天機器人主要是回應你說的內容;代理則還能被賦予工具,去執行對話以外的動作。

但一旦你讓模型擁有這種能力,就必須更小心事情不如預期時會發生什麼。

如果工具失敗,模型就不該說工單已建立。它不該在沒有拿到工單 ID 時自己編一個。如果 FAQ 沒有答案,它也不該只是因為自己能產生一段看起來很像答案的文字,就自己補出來。

這些規則聽起來也許很理所當然,但真正把整個流程做出來之後,我才明白它們有多重要。模型只是應用程式的一部分。prompt 定義它該做什麼,工具負責執行動作,後端系統負責儲存或變更資訊,而應用程式本身必須確保這些部分彼此一致。

這改變了我看待代理的方式。我不再把模型視為整個應用程式,而是把它看成更大系統中的一部分,而這個系統裡的指令、工具、資料和後端都必須一起運作。


如果你也正要起步

我特別想把這段寫給初學者,因為我自己也是。

一開始做這個專案時,我並不是已經完全知道這些服務如何一起運作。以前我接觸過的很多環境,都已經先幫我把東西設好了。你只要在提供好的環境裡工作,使用現成的工具,然後慢慢了解它們怎麼拼起來。

這個專案讓我必須往下看一層。我得理解 AgentCore harness 在做什麼、為什麼需要 Gateway、Lambda 如何把工具連到後端、為什麼要用 DynamoDB,以及評估結果如何指出我以為沒問題的東西,其實沒有照需求運作。

這大概是我覺得最大的差別。

當你在做一般應用程式時,很容易把它想成:

輸入
   ↓
程式碼
   ↓
輸出

但在代理裡,模型也會決定接下來該發生什麼。所以我開始思考一些以前不太會想的問題。模型可以決定到什麼程度?它在能行動之前需要哪些資訊?資訊缺失時該怎麼做?它不知道答案時該怎麼做?有人試著讓它忽略指令時該怎麼辦?如果工具本身失敗了,又該怎麼處理?

這些問題跟連接 AWS 服務一樣重要。這是我在做這個專案之前沒有完全體會到的。

我也意識到,不需要在開始做之前就把每一個 AWS 服務都學得非常深入。對我幫助最大的是,每當遇到一個不熟悉的東西時,只問一個更簡單的問題:

這個服務在我的應用程式裡解決了什麼問題?

對 DynamoDB,我不需要先完全了解資料庫服務的所有細節。我只需要知道,我的應用程式需要一個地方來儲存 bug 回報。

對 Lambda,我不需要知道它提供的每個功能。我只需要知道,當代理呼叫工具時,必須有某個東西真的去執行後端操作。

對 AgentCore Gateway,我也不需要知道它所有能力。我只需要知道,它提供了代理和工具之間的連接。

用這種方式思考服務,讓架構對我來說沒那麼可怕了。與其先學一大堆 AWS 服務,再去想它們各自放在哪裡,我可以先從應用程式需要什麼出發,再去學解決那個問題的服務。

我也很慶幸自己開始了這個專案,即使它不是以我平常理想中的方式完成。我大約花 2 天完成它,第一次嘗試就通過,然後就得繼續往前,而不是再花一輪時間回頭修改一切,試著把 0.83 的分數往上拉。

當然,我心裡還是會想,如果我再多做一些調整,下一次評估會不會有更好的結果。但我也很慶幸自己沒有等到「完全準備好」才開始。

有些時候,我剛學到一個概念,馬上就得想辦法把它用進專案裡。這有時候會讓人不舒服,尤其是當我還在搞懂某個服務到底在做什麼的時候,但它也讓這些概念更容易記住。

我看到 AgentCore Gateway 在實際流程裡的位置,而不是只在文章裡讀到它。看到 Lambda 負責後端操作、DynamoDB 存結果。也看到評估抓到了我自己漏掉的地方。

這大概會比最後的分數更讓我記得這個專案。我是在不知道所有事情的情況下開始的,用我理解到的東西做出了一些成果,找到了可以改進的地方,並從那些地方學到了東西。


我很想聽聽你的想法

我還在學習,所以我很想聽聽不同階段的人怎麼看這件事。

如果你有 技巧、建議、自己專案中的心得、讓你學到東西的錯誤,或任何你覺得能幫助剛起步的人,請在留言中分享。

我很喜歡 DEV 的一點是,大家都有不同的背景經驗。所以如果你有什麼想補充的,即使只是小小的一點,也請分享出來。也許你一路上學到的某個東西,正好能幫助另一個剛起步的人。


一點小小的感謝

我也想感謝 Udacity 和參與 Future AWS Agent Engineer Nanodegree Program 的所有人。有了專案架構、學習材料和線上直播課,我在對某些東西感到困惑時,還是能比較容易繼續往前。

線上直播課特別有幫助,因為有時候你讀同一段內容好幾次,還是無法理解它怎麼對應到實際專案。先聽別人帶你走一遍,再自己動手試一次,真的會有差。

我還在學習,但能有這樣一個專案,讓我把這些概念真正拼在一起,比單純閱讀它們更能幫助我理解。


我的最終收穫

如果要我從這個專案只帶走一件事,那會是:

好的代理,不只是知道該做什麼;它也需要知道自己是否已經有足夠資訊去做。

現在看起來這句話很簡單,但在看到評估抓出我自己的假設之後,我對它的理解完全不同了。

模型可以理解客戶,prompt 可以給它指令,工具可以讓它採取行動,後端可以儲存結果。但這些元件仍然都需要清楚的規則,來定義什麼時候下一步真的能發生。

這就是我覺得打造這個專案最有趣的地方。

我一開始以為自己主要是在學怎麼把 AWS 服務串起來。最後我學到的,卻是代理周圍的界線有多重要。

老實說,這大概是我帶到下一個專案裡,更好的收穫。


🤝 一起保持聯繫

平台 在這裡找到我
GitHub 做東西中 → hemapriya-kanagala
LinkedIn 資源與更新 → hemapriya-kanagala
X 隨性的開發想法 → @KanagalaHema

原文出處:https://dev.to/hemapriya_kanagala/i-built-my-first-aws-agent-workflow-and-the-hardest-part-was-getting-it-to-stop-assuming-things-8fg


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝19   💬4  
278
🥈
我愛JS
3
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登