[Go to site: main page, start]

Skip to content

使用 API 服务器

在 ADK 中支持Python v0.1.0TypeScript v0.2.0Go v0.1.0Java v0.1.0

在部署智能体之前,你应该先对其进行测试,确保它按预期运行。使用 ADK 中的 API 服务器通过 REST API 暴露你的智能体,以便进行编程测试和集成。

ADK API Server

开始 API 服务器

使用以下命令在 ADK API 服务器中运行你的智能体:

adk api_server
npx adk api_server

Go 中没有独立的 adk CLI。相反,你需要将启动器直接嵌入到智能体的 main.go 中。full.NewLauncher() 辅助函数将 REST API、Web UI 和其他模式打包到一个二进制文件中:

main.go
import (
    "google.golang.org/adk/v2/cmd/launcher"
    "google.golang.org/adk/v2/cmd/launcher/full"
)

func main() {
    // ... 构建你的智能体和配置 ...
    l := full.NewLauncher()
    if err := l.Execute(ctx, config, os.Args[1:]); err != nil {
        log.Fatalf("Run failed: %v\n\n%s", err, l.CommandLineSyntax())
    }
}

然后通过命令行传递 webapi 子命令来启动 API 服务器:

go run agent.go web api

web 关键字激活 HTTP 服务器。api 添加 ADK REST API 后端,默认在 /api 路径前缀下注册所有路由。

请确保更新端口号。

使用 Maven 编译并运行 ADK Web 服务器:

mvn compile exec:java \
 -Dexec.args="--adk.agents.source-dir=src/main/java/agents --server.port=8080"

使用 Gradle 时,build.gradlebuild.gradle.kts 构建文件的 plugins 部分应包含以下 Java 插件:

plugins {
    id('java')
    // 其他插件
}
然后,在构建文件的其他位置,顶层创建一个新任务:

tasks.register('runADKWebServer', JavaExec) {
    dependsOn classes
    classpath = sourceSets.main.runtimeClasspath
    mainClass = 'com.google.adk.web.AdkWebServer'
    args '--adk.agents.source-dir=src/main/java/agents', '--server.port=8080'
}

最后,在命令行中运行以下命令:

gradle runADKWebServer

在 Java 中,Dev UI 和 API 服务器打包在一起。

此命令将启动一个本地 Web 服务器,你可以在其中运行 cURL 命令或发送 API 请求来测试你的智能体。默认情况下,服务器运行在 http://localhost:8000

高级用法和调试

有关所有可用端点、请求/响应格式以及调试技巧的完整参考(包括如何使用交互式 API 文档),请参阅下方的 ADK API 服务器指南

本地测试

本地测试涉及启动本地 Web 服务器、创建会话和向智能体发送查询。首先,确保你在正确的工作目录中。

对于 TypeScript,你应该位于智能体项目目录本身内。

parent_folder/
└── my_sample_agent/  <-- 对于 TypeScript,从这里运行命令
    └── agent.py (or Agent.java or agent.ts)

启动本地服务器

接下来,使用上面列出的命令启动本地服务器。

输出应类似于:

INFO:     Started server process [12345]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:8000 (Press CTRL+C to quit)
+-----------------------------------------------------------------------------+
| ADK Web Server started                                                      |
|                                                                             |
| For local testing, access at http://localhost:8000.                         |
+-----------------------------------------------------------------------------+
2025/01/01 00:00:00 Starting the web server: &{port:8080 ...}
2025/01/01 00:00:00 Web servers starts on http://localhost:8080
2025/01/01 00:00:00        api:  you can access API using http://localhost:8080/api
2025/01/01 00:00:00        api:      for instance: http://localhost:8080/api/list-apps

Go:默认端口和路径前缀

Go API 服务器默认使用端口 8080(不是 8000),并在 /api 路径前缀下提供所有 REST 端点。请相应调整下面所有示例 curl 命令:

Python/TypeScript/Java Go
http://localhost:8000/list-apps http://localhost:8080/api/list-apps
http://localhost:8000/apps/… http://localhost:8080/api/apps/…
http://localhost:8000/run http://localhost:8080/api/run
http://localhost:8000/run_sse http://localhost:8080/api/run_sse

可以通过 web 子命令的 -port 标志更改端口,通过 api 子命令的 -path_prefix 标志更改前缀。例如:

go run agent.go web -port 8000 api -path_prefix ""
2025-05-13T23:32:08.972-06:00  INFO 37864 --- [ebServer.main()] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-05-13T23:32:08.980-06:00  INFO 37864 --- [ebServer.main()] com.google.adk.web.AdkWebServer          : Started AdkWebServer in 1.15 seconds (process running for 2.877)
2025-05-13T23:32:08.981-06:00  INFO 37864 --- [ebServer.main()] com.google.adk.web.AdkWebServer          : AdkWebServer application started successfully.

你的服务器现在正在本地运行。确保在所有后续命令中使用正确的 端口号

创建新会话

在 API 服务器仍在运行的情况下,打开一个新的终端窗口或标签页,使用以下命令创建一个新的智能体会话:

curl -X POST http://localhost:8000/apps/my_sample_agent/users/u_123/sessions/s_123 \
  -H "Content-Type: application/json" \
  -d '{"key1": "value1", "key2": 42}'

下面来解释一下发生了什么:

  • http://localhost:8000/apps/my_sample_agent/users/u_123/sessions/s_123:这会为你的智能体 my_sample_agent(即智能体文件夹的名称)创建一个新会话,关联一个用户 ID(u_123)和一个会话 ID(s_123)。你可以将 my_sample_agent 替换为你的智能体文件夹名称,将 u_123 替换为特定的用户 ID,将 s_123 替换为特定的会话 ID。
  • {"key1": "value1", "key2": 42}:这是可选的。你可以用它在创建会话时自定义智能体的预设状态(字典)。

如果创建成功,应返回会话信息。输出应类似于:

{"id":"s_123","appName":"my_sample_agent","userId":"u_123","state":{"key1":"value1","key2":42},"events":[],"lastUpdateTime":1743711430.022186}

Info

你不能使用完全相同的用户 ID 和会话 ID 创建多个会话。如果尝试这样做,你可能会看到如下响应: {"detail":"Session already exists: s_123"}。要解决此问题,你可以删除该会话(例如 s_123),或选择一个不同的会话 ID。

发送查询

有两种方式可以通过 POST 向你的智能体发送查询,分别是 /run/run_sse 路由。

  • POST http://localhost:8000/run:将所有事件收集为一个列表并一次性返回。适合大多数用户(如果不确定,建议使用此方式)。
  • POST http://localhost:8000/run_sse:以服务器发送事件(Server-Sent Events)的形式返回,即事件对象的流。适合希望在事件可用时立即收到通知的用户。使用 /run_sse 时,你还可以将 streaming 设置为 true 来启用逐 token 级别的流式传输。

使用 /run

curl -X POST http://localhost:8000/run \
-H "Content-Type: application/json" \
-d '{
"appName": "my_sample_agent",
"userId": "u_123",
"sessionId": "s_123",
"newMessage": {
    "role": "user",
    "parts": [{
    "text": "Hey whats the weather in new york today"
    }]
}
}'

在 TypeScript 中,目前仅支持 camelCase 字段名称(例如 appNameuserIdsessionId 等)。

如果使用 /run,你会一次性看到所有事件的完整输出,形式为列表,应类似于:

[{"content":{"parts":[{"functionCall":{"id":"af-e75e946d-c02a-4aad-931e-49e4ab859838","args":{"city":"new york"},"name":"get_weather"}}],"role":"model"},"invocationId":"e-71353f1e-aea1-4821-aa4b-46874a766853","author":"weather_time_agent","actions":{"stateDelta":{},"artifactDelta":{},"requestedAuthConfigs":{}},"longRunningToolIds":[],"id":"2Btee6zW","timestamp":1743712220.385936},{"content":{"parts":[{"functionResponse":{"id":"af-e75e946d-c02a-4aad-931e-49e4ab859838","name":"get_weather","response":{"status":"success","report":"The weather in New York is sunny with a temperature of 25 degrees Celsius (41 degrees Fahrenheit)."}}}],"role":"user"},"invocationId":"e-71353f1e-aea1-4821-aa4b-46874a766853","author":"weather_time_agent","actions":{"stateDelta":{},"artifactDelta":{},"requestedAuthConfigs":{}},"id":"PmWibL2m","timestamp":1743712221.895042},{"content":{"parts":[{"text":"OK. The weather in New York is sunny with a temperature of 25 degrees Celsius (41 degrees Fahrenheit).\n"}],"role":"model"},"invocationId":"e-71353f1e-aea1-4821-aa4b-46874a766853","author":"weather_time_agent","actions":{"stateDelta":{},"artifactDelta":{},"requestedAuthConfigs":{}},"id":"sYT42eVC","timestamp":1743712221.899018}]

使用 /run_sse

curl -X POST http://localhost:8000/run_sse \
-H "Content-Type: application/json" \
-d '{
"appName": "my_sample_agent",
"userId": "u_123",
"sessionId": "s_123",
"newMessage": {
    "role": "user",
    "parts": [{
    "text": "Hey whats the weather in new york today"
    }]
},
"streaming": false
}'

你可以将 streaming 设置为 true 来启用逐 token 级别的流式传输,这意味着响应将以多个片段的形式返回给你,输出应类似于:

data: {"content":{"parts":[{"functionCall":{"id":"af-f83f8af9-f732-46b6-8cb5-7b5b73bbf13d","args":{"city":"new york"},"name":"get_weather"}}],"role":"model"},"invocationId":"e-3f6d7765-5287-419e-9991-5fffa1a75565","author":"weather_time_agent","actions":{"stateDelta":{},"artifactDelta":{},"requestedAuthConfigs":{}},"longRunningToolIds":[],"id":"ptcjaZBa","timestamp":1743712255.313043}

data: {"content":{"parts":[{"functionResponse":{"id":"af-f83f8af9-f732-46b6-8cb5-7b5b73bbf13d","name":"get_weather","response":{"status":"success","report":"The weather in New York is sunny with a temperature of 25 degrees Celsius (41 degrees Fahrenheit)."}}}],"role":"user"},"invocationId":"e-3f6d7765-5287-419e-9991-5fffa1a75565","author":"weather_time_agent","actions":{"stateDelta":{},"artifactDelta":{},"requestedAuthConfigs":{}},"id":"5aocxjaq","timestamp":1743712257.387306}

data: {"content":{"parts":[{"text":"OK. The weather in New York is sunny with a temperature of 25 degrees Celsius (41 degrees Fahrenheit).\n"}],"role":"model"},"invocationId":"e-3f6d7765-5287-419e-9991-5fffa1a75565","author":"weather_time_agent","actions":{"stateDelta":{},"artifactDelta":{},"requestedAuthConfigs":{}},"id":"rAnWGSiV","timestamp":1743712257.391317}
使用 /run/run_sse 发送带有 base64 编码文件的查询

curl -X POST http://localhost:8000/run \
-H 'Content-Type: application/json' \
-d '{
   "appName":"my_sample_agent",
   "userId":"u_123",
   "sessionId":"s_123",
   "newMessage":{
      "role":"user",
      "parts":[
         {
            "text":"Describe this image"
         },
         {
            "inlineData":{
               "displayName":"my_image.png",
               "data":"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAACXBIWXMAAAsTAAALEwEAmpw...",
               "mimeType":"image/png"
            }
         }
      ]
   },
   "streaming":false
}'

Info

如果你使用 /run_sse,你应该能在每个事件可用时立即看到它。

集成

ADK 使用回调来与第三方可观测性工具集成。这些集成捕获智能体调用和交互的详细跟踪信息,对于理解行为、调试问题和评估性能至关重要。

部署你的智能体

既然你已经验证了智能体的本地运行,你就可以开始部署你的智能体了!以下是一些部署方式:

  • 部署到 Agent Runtime,这是一种将你的 ADK 智能体部署到 Google Cloud 上 Agent Platform 托管服务的简单方式。
  • 部署到 Cloud Run,使用 Google Cloud 上的无服务器架构,完全掌控智能体的扩展和管理方式。

交互式 API 文档

仅限 Python 和 TypeScript

Swagger UI 交互式文档仅由 Python 和 TypeScript ADK API 服务器在 /docs 提供。Go API 服务器不暴露 /docs 端点。要探索 Go REST API,请使用下方的端点参考或直接使用 curl 发送请求。

API 服务器使用 Swagger UI 自动生成交互式 API 文档。这是一个非常有价值的工具,可用于探索端点、理解请求格式以及直接从浏览器测试你的智能体。

要访问交互式文档,请启动 API 服务器并在浏览器中导航到 http://localhost:8000/docs

你将看到所有可用 API 端点的完整交互式列表,展开后可查看参数、请求体和响应模式的详细信息。你甚至可以点击"Try it out"向正在运行的智能体发送实时请求。

API 端点

以下部分详细介绍了与智能体交互的主要端点。

JSON 命名约定

  • 请求和响应体均使用 camelCase 作为字段名称(例如 "appName")。

工具端点

列出可用智能体

返回服务器发现的所有智能体应用的列表。

  • 方法: GET
  • 路径: /list-apps

请求示例

curl -X GET http://localhost:8000/list-apps

响应示例

["my_sample_agent", "another_agent"]


会话管理

会话存储特定用户与智能体交互的状态和事件历史。

更新会话

Go 中不可用

PATCH 会话更新端点未在 Go ADK REST API 服务器中实现。要在 Go 中修改会话状态,请改为在 /run/run_sse 请求体中传递 stateDelta 字段。

更新现有会话。

  • 方法: PATCH
  • 路径: /apps/{app_name}/users/{user_id}/sessions/{session_id}

请求体

{
  "stateDelta": {
    "key1": "value1",
    "key2": 42
  }
}

请求示例

curl -X PATCH http://localhost:8000/apps/my_sample_agent/users/u_123/sessions/s_abc \
  -H "Content-Type: application/json" \
  -d '{"stateDelta":{"visit_count": 5}}'

响应示例

{"id":"s_abc","appName":"my_sample_agent","userId":"u_123","state":{"visit_count":5},"events":[],"lastUpdateTime":1743711430.022186}

获取会话

检索特定会话的详细信息,包括其当前状态和所有关联的事件。

  • 方法: GET
  • 路径: /apps/{app_name}/users/{user_id}/sessions/{session_id}

请求示例

curl -X GET http://localhost:8000/apps/my_sample_agent/users/u_123/sessions/s_abc

响应示例

{"id":"s_abc","appName":"my_sample_agent","userId":"u_123","state":{"visit_count":5},"events":[...],"lastUpdateTime":1743711430.022186}

删除会话

删除一个会话及其所有关联数据。

  • 方法: DELETE
  • 路径: /apps/{app_name}/users/{user_id}/sessions/{session_id}

请求示例

curl -X DELETE http://localhost:8000/apps/my_sample_agent/users/u_123/sessions/s_abc

响应示例 成功删除后返回空响应。Python 和 TypeScript 返回 204 No Content 状态码。Go 返回 200 OK 并带有空响应体。


智能体执行

这些端点用于向智能体发送新消息并获取响应。

运行智能体(单次响应)

执行智能体并在运行完成后以单个 JSON 数组返回所有生成的事件。

  • 方法: POST
  • 路径: /run

请求体

{
  "appName": "my_sample_agent",
  "userId": "u_123",
  "sessionId": "s_abc",
  "newMessage": {
    "role": "user",
    "parts": [
      { "text": "What is the capital of France?" }
    ]
  }
}

在 TypeScript 中,目前仅支持 camelCase 字段名称(例如 appNameuserIdsessionId 等)。

请求示例

curl -X POST http://localhost:8000/run \
  -H "Content-Type: application/json" \
  -d '{
    "appName": "my_sample_agent",
    "userId": "u_123",
    "sessionId": "s_abc",
    "newMessage": {
      "role": "user",
      "parts": [{"text": "What is the capital of France?"}]
    }
  }'

运行智能体(流式)

执行智能体,并使用服务器发送事件(SSE)在事件生成时将它们流式返回给客户端。

  • 方法: POST
  • 路径: /run_sse

请求体 请求体与 /run 相同,另外有一个可选的 streaming 标志。

{
  "appName": "my_sample_agent",
  "userId": "u_123",
  "sessionId": "s_abc",
  "newMessage": {
    "role": "user",
    "parts": [
      { "text": "What is the weather in New York?" }
    ]
  },
  "streaming": true
}
- streaming:(可选)设置为 true 可为模型响应启用逐 token 级别的流式传输。默认为 false

请求示例

curl -X POST http://localhost:8000/run_sse \
  -H "Content-Type: application/json" \
  -d '{
    "appName": "my_sample_agent",
    "userId": "u_123",
    "sessionId": "s_abc",
    "newMessage": {
      "role": "user",
      "parts": [{"text": "What is the weather in New York?"}]
    },
    "streaming": false
  }'