找到問題了!重新部屬範例程式後成功運行遠端 Agent,發現差異在於 Agent 的類別:
multi_tool_agent
部屬時的類別是 google.adk.agents.Agent
trip_agent
部屬時的類別是 vertexai.preview.reasoning_engines.AdkApp
從程式碼來看,差異在於部屬時使用的參數:
# multi_tool_agent
remote_agent = agent_engines.create(
agent_engine=Agent(...),
...
)
# AdkApp
remote_agent = agent_engines.create(
agent_engine=AdkApp(agent=Agent(...)),
...
)
也就是多包了一層,而錯誤訊息顯示:
Input should be a valid dictionary or instance of BaseAgent [type=model_type, input_value=<vertexai.preview.reasoni...bject at 0x7f77a61289d0>, input_type=AdkApp]
其實就是在說執行時應該要使用 BaseAgent
的實例或是 Dictionary
。但這算是 Bug 嗎?部屬時沒事,執行時卻出問題且沒有噴錯訊息,要進 Logs Explorer 才能看到。
我會使用 AdkApp
部屬的原因是 Agent Development Kit 文件中部屬前的 app
變數是 AdkApp
:
後面部屬時用的就是 app
變數:
而 Quickstart: Develop and deploy agents on Vertex AI Agent Engine 文件內也是使用 AdkApp
來部屬:
所以想跟我一樣用 ADK 建立 Vertex AI Agent Engine 的要注意一下。
接下來請 LLM 幫我產個 Cloud Run 專案用來架設 API server,當 API 收到以下的請求格式時呼叫 Agent Engine:
{"locations": ["Tokyo"], "startDate": "2025-09-10", "days": 2, "language": "Chinese Traditional"}
將產好的專案部屬到 Cloud Run 不意外地遇到錯誤:
看起來是 remote_agent.async_stream_query
呼叫時出錯,為了方便 Debug 先弄個本地版本:
docker run --env-file .dockerenv -p 8098:8080 -it apiserver
結果又遇到其他錯誤:
File "/usr/local/lib/python3.10/site-packages/google/cloud/aiplatform/initializer.py", line 119, in _set_project_as_env_var_or_google_auth_default
credentials, _ = google.auth.default(scopes=constants.DEFAULT_AUTHED_SCOPES)
File "/usr/local/lib/python3.10/site-packages/google/auth/_default.py", line 685, in default
raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)
google.auth.exceptions.DefaultCredentialsError: Your default credentials were not found. To set up Application Default Credentials, see https://cloud.google.com/docs/authentication/external/set-up-adc for more information.
看起來是沒有設定 Google Cloud 的驗證權限導致。查了一下,如果部屬在 Google Cloud 上就不用擔心這個,但要在本地 Docker 跑的話要把 application_default_credentials.json
放進去,所以先將檔案 mount 進 /tmp/adc.json
:
docker run --env-file .dockerenv -e PORT=8080 -p 8098:8080 -v ~/.config/gcloud/application_default_credentials.json:/tmp/adc.json -it apiserver
然後 .dockerenv
裡面要多設定變數指向 /tmp/adc.json
:
GOOGLE_APPLICATION_CREDENTIALS=/tmp/adc.json
另外補充一下,為了使用環境變數控制部屬在容器內的 Port ,在 Dockerfile
要這樣寫:
CMD ["sh", "-c", "uvicorn main:api --host 0.0.0.0 --port $PORT"]
不能這樣寫:
CMD ["uvicorn", "main:api", "--host", "0.0.0.0", "--port", "$PORT"]
因為沒用 sh
包起來的話,等同於直接把 $PORT
字串當作參數餵給 uvicorn
。要使用 sh -c
包起來 $PORT
變數才會被 sh
解析然後餵給 uvicorn
。可以參考 docker - Using ENV var in CMD in the Dockerfile - Stack Overflow。
解決了環境問題後回到呼叫 API 的部分,剛剛的 remote_agent.async_stream_query
問題只是少給了 user_id
參數。設定好後又遇到 JSON 解析錯誤,原因是 Agent 回傳 childActivity: []
而 Pydantic 沒有處理。
為了讓 childActivity
可以接受空陣列,要這樣定義:
childActivities: List[ChildActivity] = Field(default_factory=list)
另外還要允許 transportType
是 null
,之後就成功了!