CLI vs Web:ADK Go 运行方式深度对比与生产环境选型指南

ADK Go 的启动器(Launcher)设计遵循了"一套代码,多种运行"的理念。同一个 Agent 程序,通过不同的命令行参数,可以在 CLI 交互模式、Web API 模式、Web UI 模式之间切换。这种灵活性在开发阶段很方便,但也带来了选型困惑:我的项目到底该用哪种模式?本章将从架构原理、适用场景、性能特征、安全考量四个维度,帮你做出正确的选择。

运行方式全景概览

模式启动命令进程模型会话保持适用场景生产就绪
CLIgo run agent.go单进程,标准输入输出无(每次启动新进程)调试、脚本、后台服务✅ 是
Web APIgo run agent.go web apiHTTP 服务器有(基于 Session)API 服务、第三方集成⚠️ 需自建
Web UIgo run agent.go web api webuiHTTP 服务器 + 静态文件有(基于 Session)演示、内部测试❌ 不推荐

重要声明:ADK Go 自带的 Web UI 是开发工具,官方明确不建议用于生产环境。生产部署应使用 ADK Runtime 或基于 Web API 模式自建服务。


CLI 模式:工程师的瑞士军刀

启动与工作原理

source .env
go run agent.go

CLI 模式的工作流程:

┌─────────────┐     ┌──────────────┐     ┌──────────┐     ┌─────────┐
│  用户输入    │────▶│  CLI Reader  │────▶│  Agent   │────▶│  Model  │
│  (stdin)    │     │  (bufio)     │     │  Core    │     │  API    │
└─────────────┘     └──────────────┘     └────┬─────┘     └────┬────┘
                                              │                │
                                              ▼                ▼
                                         ┌─────────┐     ┌──────────┐
                                         │  Tool   │◀────│  Tool    │
                                         │  Exec   │     │  Result  │
                                         └─────────┘     └──────────┘

CLI 模式本质上是一个同步的 REPL(Read-Eval-Print Loop)。full.NewLauncher() 创建的启动器会实例化一个 bufio.Scanner 从标准输入读取用户消息,调用 Agent 处理,然后将结果输出到标准输出。

适用场景深度分析

场景 1:开发调试(日常使用频率:90%)

CLI 是开发阶段最高效的运行方式。它的优势不仅仅是"简单":

  • 启动速度:无需初始化 HTTP 服务器、路由、静态文件服务,冷启动时间 < 1 秒
  • 日志可见性:所有 DEBUG/INFO 日志直接输出到终端,无需额外配置日志收集
  • 快速迭代:修改代码 → Ctrl+Cgo run → 测试,循环极快

我的日常开发工作流

# 终端 1:运行 Agent
source .env && go run ./cmd/agent

# 终端 2:监控日志(如果 Agent 输出结构化日志到文件)
tail -f agent.log | jq '.level == "ERROR"'

# 终端 3:编辑代码
vim internal/agent/time_agent.go

场景 2:自动化脚本与管道处理

CLI 模式的无状态特性使其天然适合 Unix Pipeline:

# 批量处理:从文件读取问题,输出到结果文件
cat questions.txt | go run agent.go > answers.txt

# 结合 jq 处理结构化输出
echo "查询北京天气" | go run agent.go | jq -r '.response'

# 定时任务:每小时执行一次,输出到日志并监控
0 * * * * cd /opt/agent && source .env && go run agent.go <<EOF >> /var/log/agent.log 2>&1
查询过去一小时的系统告警摘要
EOF

生产经验:我们在一个数据清洗流水线中,使用 CLI 模式的 Agent 对非结构化文本进行分类。通过 xargs -P 实现并行处理,单台机器可以达到每秒 50+ 的吞吐量。

场景 3:后台服务与 systemd 集成

CLI 模式配合进程管理工具,可以构建稳定的生产服务:

# 使用 nohup 脱离终端
nohup go run agent.go > agent.log 2>&1 &

# 更专业的做法:使用 systemd

systemd 服务配置示例/etc/systemd/system/adk-agent.service):

[Unit]
Description=ADK Go Agent Service
After=network.target

[Service]
Type=simple
User=adk
WorkingDirectory=/opt/adk-agent
EnvironmentFile=/opt/adk-agent/.env
ExecStart=/opt/adk-agent/bin/agent
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

# 安全加固
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true

[Install]
WantedBy=multi-user.target

关键配置解析

  • EnvironmentFile:从独立文件加载环境变量,避免将敏感信息暴露在进程列表中
  • Restart=always:进程崩溃后自动重启,提高可用性
  • ProtectSystem=strict:限制服务对系统文件的访问,防止被攻击后横向移动

Web 模式:演示与集成的利器

启动方式与架构

# 启动 API + Web UI
go run agent.go web api webui

# 仅启动 API(生产自建服务推荐)
go run agent.go web api

Web 模式启动后,会监听默认端口 8080

  • POST /api/v1/agents/{agent_id}/run:执行 Agent
  • GET /api/v1/agents/{agent_id}/sessions:获取会话列表
  • GET /webui:Web 聊天界面

工作原理与数据流

┌──────────────┐     ┌──────────────┐     ┌──────────────┐     ┌──────────┐
│   浏览器      │────▶│   Web UI     │────▶│  API Server  │────▶│  Agent   │
│  (用户界面)   │     │  (静态文件)   │     │  (HTTP/JSON) │     │  Core    │
└──────────────┘     └──────────────┘     └──────┬───────┘     └────┬─────┘
                                                 │                  │
                                                 ▼                  ▼
                                           ┌──────────┐      ┌──────────┐
                                           │ Session  │      │  Model   │
                                           │ Storage  │      │   API    │
                                           │(内存/DB) │      └──────────┘
                                           └──────────┘

Web 模式的核心价值在于会话保持(Session Management)。与 CLI 模式每次启动都是全新进程不同,Web 模式通过 Session ID 维护多轮对话的上下文:

# 第一轮请求
POST /api/v1/agents/hello_time_agent/run
Body: {"message": "你好,我是张三"}
Response: {"session_id": "sess_abc123", "response": "你好张三!有什么可以帮你的?"}

# 第二轮请求(携带 session_id)
POST /api/v1/agents/hello_time_agent/run
Body: {"session_id": "sess_abc123", "message": "我叫什么名字?"}
Response: {"session_id": "sess_abc123", "response": "你刚才说你的名字是张三。"}

适用场景深度分析

场景 1:产品演示与用户体验测试

Web UI 模式最大的价值是零门槛体验。你可以把 http://localhost:8080/webui 发给产品经理、设计师或潜在用户,他们无需安装任何软件即可与 Agent 交互。

演示技巧

# 使用 ngrok 暴露本地服务给外网访问(临时演示)
ngrok http 8080
# 获得公网 URL:https://xxxx.ngrok-free.app/webui

⚠️ 安全警告:使用 ngrok 暴露本地服务时,任何人都能访问你的 Agent。演示结束后立即关闭,且不要在 Agent 中配置敏感工具或数据访问权限。

场景 2:多轮对话与上下文保持

某些任务天然需要多轮交互:

用户:我想订一张机票
Agent:好的,请告诉我出发城市和目的地
用户:北京到上海
Agent:请告诉我出发日期
用户:明天
Agent:请告诉我您的姓名和身份证号...

CLI 模式每次启动都是独立进程,没有内置的上下文保持机制。Web 模式的 Session 管理完美解决了这个问题。

场景 3:需要持久化的业务场景

Web 模式支持将 Session 数据持久化到存储后端:

// 配置 Session 存储(示例:内存存储,生产应使用 Redis/DB)
config := &launcher.Config{
	AgentLoader: agent.NewSingleLoader(timeAgent),
	// SessionStore: redisStore, // 自定义 Session 存储实现
}

生产建议:ADK Go 默认使用内存存储 Session,进程重启后数据丢失。生产环境应实现 SessionStore 接口,使用 Redis 或 PostgreSQL 持久化。


模式切换机制与命令行参数解析

ADK Go 的启动器通过解析 os.Args[1:] 来决定运行模式:

l := full.NewLauncher()
l.Execute(ctx, config, os.Args[1:])

参数解析规则

参数组合行为等效场景
无参数启动 CLI 模式go run agent.go
web启动 Web API(无 UI)go run agent.go web
web api启动 Web API(无 UI)同上
web api webui启动完整 Web(API + UI)go run agent.go web api webui
stream启用流式输出与其他参数组合使用

代码中动态切换模式

更灵活的做法是在代码中根据环境变量决定运行模式:

package main

import (
	"context"
	"log"
	"os"

	"google.golang.org/adk/agent"
	"google.golang.org/adk/agent/llmagent"
	"google.golang.org/adk/cmd/launcher"
	"google.golang.org/adk/cmd/launcher/full"
	"google.golang.org/adk/model/gemini"
	"google.golang.org/genai"
)

func main() {
	ctx := context.Background()
	agent := initializeAgent(ctx)
	config := &launcher.Config{
		AgentLoader: agent.NewSingleLoader(agent),
	}

	mode := os.Getenv("ADK_MODE")
	args := []string{}

	switch mode {
	case "web":
		args = []string{"web", "api"}
		log.Println("[INFO] Starting in WEB API mode")
	case "webui":
		args = []string{"web", "api", "webui"}
		log.Println("[INFO] Starting in WEB UI mode")
	default:
		log.Println("[INFO] Starting in CLI mode")
	}

	l := full.NewLauncher()
	if err := l.Execute(ctx, config, args); err != nil {
		log.Fatalf("[FATAL] %v", err)
	}
}

使用方式:

ADK_MODE=web go run agent.go      # Web API 模式
ADK_MODE=webui go run agent.go    # Web UI 模式
ADK_MODE=cli go run agent.go      # CLI 模式(默认)

生产环境选型决策树

是否需要人机交互界面?
├── 是 → 是否需要多轮对话保持上下文?
│       ├── 是 → 使用 Web API 模式 + 自建前端
│       └── 否 → CLI 模式足够,或 Web UI 临时演示
└── 否 → 是否需要作为后台服务长期运行?
        ├── 是 → CLI 模式 + systemd/supervisor
        └── 否 → CLI 模式(脚本/批处理)

各场景推荐方案

场景推荐模式原因额外配置
本地开发调试CLI启动快、日志直观
自动化脚本/流水线CLI无状态、易集成结合 nohupcron
生产后台服务CLI + systemd稳定、资源占用低、易监控systemd 服务文件
内部演示Web UI零门槛、有界面注意网络安全
第三方 API 集成Web API标准化 HTTP 接口需自建认证/限流
多轮对话应用Web API + Session上下文保持Redis Session 存储

Web 模式的安全与性能配置

端口与网络绑定

# 修改监听端口(避免冲突)
go run agent.go web api webui --port 9090

# 绑定到所有网络接口(允许局域网访问)
go run agent.go web api webui --host 0.0.0.0

# 生产环境:只监听本地(配合 Nginx 反向代理)
go run agent.go web api webui --host 127.0.0.1 --port 8080

安全最佳实践

  1. 绝不直接暴露 ADK Web 到公网:ADK Web 没有内置认证、限流、HTTPS 等生产级功能
  2. 使用反向代理:Nginx/Traefik 提供 TLS 终止、访问日志、IP 白名单
  3. 防火墙规则:限制只有特定 IP 可以访问 Agent 端口

Nginx 反向代理配置示例

server {
    listen 443 ssl http2;
    server_name agent.yourcompany.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # 访问控制:只允许公司内网
    allow 10.0.0.0/8;
    deny all;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket 支持(流式输出需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

性能对比与资源占用

指标CLI 模式Web 模式
内存占用~20-30 MB~30-50 MB(含 HTTP 运行时)
启动时间~1-2 秒~2-3 秒
并发能力单会话多会话(受限于模型 API 配额)
资源占用趋势稳定随会话数增长

性能优化建议

  1. CLI 批处理:使用 xargs -P 4 实现进程级并行,充分利用多核 CPU
  2. Web 模式连接池:ADK Go 底层使用 net/http,默认连接池足够大多数场景
  3. 模型调用优化:启用流式输出(stream 参数)降低首字节延迟

下一步

两种运行方式的本质差异已经清晰:CLI 是轻量、无状态、适合工程化集成的运行单元;Web 是面向人机交互、需要上下文保持的会话容器。选择哪种模式,取决于你的应用场景和架构需求。

接下来,我们将解决 Agent 运行的"燃料"问题——API Key 的获取、管理和成本控制,以及如何在 Flash、Pro、Experimental 模型之间做出明智选择。

Hello World Agent | API Key 与 Model 选择 →


想跟着学更多 Go ADK 实战?关注「全栈之巅-梦兽编程」公众号,每周更新 Go / AI 编程实战干货。