
1. 项目概述这不是在云上跑个模型而是在构建可进化的数字神经系统“Deploying Agentic AI on GCP”这个标题里藏着一个被严重低估的范式转移信号。它不是教你如何把一个现成的大语言模型API封装成微服务也不是简单地用Vertex AI部署一个微调后的checkpoint——那是2023年的玩法。今天我们要谈的是把AI从“被动应答的客服机器人”升级为“主动感知、自主规划、持续学习、跨系统协同”的数据原生智能体Data-Native Intelligent Agent。我在GCP上落地过7个生产级Agent系统从金融风控的实时决策中枢到制造业设备预测性维护的调度大脑最深的体会是真正的Agentic AI其复杂度80%不在模型层而在数据流、状态管理与执行闭环的设计里。核心关键词——Agentic AI、GCP、Data-Native、Scalable——每一个都不是修饰词而是硬性约束条件。Agentic AI意味着必须支持长期记忆、工具调用、多步推理与失败重试GCP不是背景板而是你架构的DNA决定了你能否天然获得无缝的Pub/Sub事件驱动、BigQuery的秒级分析能力、Cloud Scheduler的精准编排Data-Native不是口号是指Agent的每一次思考、每一次行动、每一次失败都必须自动沉淀为结构化数据反哺自身迭代Scalable则直指要害——当你的Agent集群从处理100个并发请求突然要应对电商大促期间的5万QPS时底层的StatefulSet扩缩容策略、Redis集群的分片键设计、甚至Cloud Storage中临时文件的生命周期管理都会成为生死线。这篇文章就是我踩着坑、撕开文档、反复压测后整理出的一套可直接抄作业的GCP Agent工程化手册。它不讲LLM原理不堆砌概念只聚焦一件事如何让一个有目标、有记忆、会调工具、能纠错的AI在Google Cloud上真正活下来并且越活越壮。适合正在评估Agent落地路径的架构师、带团队做AI产品化的技术负责人以及那些已经写完第一个ReAct循环、却卡在“上线就崩”阶段的工程师。2. 整体架构设计为什么必须放弃单体Agent拥抱“蜂群式”微服务编排2.1 传统思路的致命陷阱把Agent当成一个黑盒服务来部署很多团队的第一反应是把整个Agent逻辑LLM调用提示工程工具选择记忆检索打包成一个Flask/FastAPI服务丢进Cloud Run或GKE。我试过也崩溃过。问题出在三个根本矛盾上状态悖论Agent需要长期记忆Conversation History, Tool Execution Logs, Plan State但Cloud Run是无状态的每次请求都可能落在不同实例上。你不能指望一个实例记住上一次用户问了什么更不能让它保存一个正在执行的、耗时30秒的数据库ETL任务的状态。强行用外部Redis存所有状态那Redis瞬间变成单点瓶颈和性能黑洞。工具异构性一个真实的Agent要调用的工具五花八门——可能是Cloud SQL的JDBC连接也可能是Vertex AI的自定义模型Endpoint还可能是第三方SaaS的REST API。它们的认证方式Service Account Key vs OAuth2 Token、超时策略毫秒级vs分钟级、错误码语义429是限流还是配额超完全不同。把它们全塞进一个Python进程里等于把所有风险集中在一个熔断点上。扩展性错配用户A的Agent在做轻量级文本摘要用户B的Agent在调度一个包含12个步骤的跨系统工作流。它们的CPU、内存、网络IO需求天差地别。用同一个K8s Deployment去扩缩容要么小任务浪费资源要么大任务OOM被K8s杀掉。提示我见过最惨的案例是某客户把所有Agent逻辑塞进一个Cloud Function。大促期间函数冷启动时间飙升到8秒而他们的业务SLA要求端到端响应2秒。最后发现80%的冷启动时间花在了加载一个根本没用上的、2GB的PyTorch模型权重上。2.2 “蜂群式”架构用GCP原生服务解耦Agent的四大核心能力我们彻底重构了思路将一个“全能Agent”拆解为四个独立、可伸缩、职责单一的微服务它们通过GCP的Pub/Sub消息总线松耦合协作。这不仅是工程最佳实践更是对GCP服务矩阵的深度利用Orchestrator编排器这是Agent的“大脑皮层”。它不碰任何具体工具只负责接收用户初始请求Pub/Sub Topic:user-requests基于LLM我们固定用gemini-1.5-pro生成高层计划Plan然后将计划中的每个原子任务Task发布到task-queue主题。它的唯一输出是plan_id和task_id。它被部署在Cloud Run上因为它的计算是短暂、无状态的且Cloud Run的自动扩缩容完美匹配突发流量。Executor执行器这是Agent的“小脑和肌肉”。它订阅task-queue根据task_type如sql_query,api_call,file_process动态加载对应的执行插件。每个插件都是一个独立的、预编译的二进制Go/Rust通过gRPC与Executor主进程通信。Executor本身不处理业务逻辑只负责安全地沙箱化执行、捕获异常、记录执行元数据耗时、输入、输出、错误堆栈并将结果发回task-results主题。它被部署在GKE Autopilot上因为我们需要对CPU/内存进行精细控制并利用Autopilot的自动节点池管理来应对不同工具的资源需求波动。Memory Manager记忆管理器这是Agent的“海马体”。它监听task-results和user-requests两个主题将所有结构化数据用户原始输入、LLM生成的Plan、每个Task的执行详情清洗、打标plan_id,session_id,tool_name并以Parquet格式批量写入BigQuery。同时它提供一个低延迟的REST APICloud Run供Orchestrator在生成新Plan前快速检索相关历史上下文例如“用户上次查询的订单ID是什么”。它的核心价值在于把“记忆”从一个易失、难扩展的缓存变成了一个可SQL分析、可版本化、可审计的数据资产。State Store状态存储这是Agent的“工作记忆”。它是一个高度优化的Redis ClusterCloud Memorystore但只存两样东西1当前正在执行的Plan的完整状态快照JSON2每个活跃Session的短期上下文如最近3轮对话的摘要。它的Key设计极其关键plan:{plan_id}和session:{session_id}:context。我们禁用了所有持久化选项RDB/AOF因为状态是瞬时的一旦Plan完成或超时Key会被自动清理。它的存在是为了让Orchestrator能在毫秒级内恢复一个中断的Plan而不是从头开始。这套架构的威力在于它把GCP的每一块积木都用到了刀刃上Pub/Sub提供高吞吐、低延迟、至少一次投递的消息管道BigQuery承担起“记忆”的终极归宿让Agent的历史行为可追溯、可分析、可训练Cloud Run和GKE Autopilot则分别解决了无状态编排与有状态执行的弹性伸缩难题。它不是一个理论模型而是我们线上系统稳定运行18个月、日均处理2.3亿次Agent交互的基石。2.3 为什么拒绝Serverless Functions而选择Cloud Run GKE Autopilot的混合模式关于“是否全部用Serverless”的争论我有非常明确的实操结论纯Serverless是Agent的温柔乡也是它的坟墓。原因如下冷启动不可控Cloud Function的冷启动时间方差极大100ms - 5s而Agent的Plan生成环节对延迟极其敏感。一个5秒的冷启动会让整个Agent交互体验降级为“卡顿”。Cloud Run虽然也有冷启动但通过预热Pre-warming和最小实例数Min Instances配置我们可以将其稳定在200ms以内。更重要的是Cloud Run的冷启动只影响Orchestrator不影响Executor——Executor是常驻的GKE Pod永远在线。资源粒度太粗Cloud Function的内存配置是离散的128MB - 10GB而一个Executor插件比如一个数据库连接池可能只需要1.2GB内存。你被迫选2GB白白浪费40%的资源成本。GKE Autopilot的资源请求Requests是连续的你可以精确指定memory: 1200Mi实现近乎完美的资源利用率。调试与可观测性地狱当一个Cloud Function执行失败你只能看到一行模糊的错误日志。而在GKE Autopilot上你可以直接kubectl logs查看Pod日志用kubectl exec进入容器排查环境变量甚至用Cloud Profiler抓取CPU火焰图。对于一个由数十个插件组成的复杂Executor这种深度可观测性不是锦上添花而是救命稻草。网络策略的刚性需求我们的Executor插件需要访问内部的Cloud SQL和Private Google Access的Vertex AI Endpoint。Cloud Function的VPC Connector配置复杂且无法为不同函数设置不同的网络出口IP。而GKE Autopilot的Pod可以绑定到特定的VPC子网并通过Cloud NAT获得固定的出口IP这让我们能轻松地在Cloud SQL的白名单里只加一个IP就放行所有Executor流量。所以最终的混合模式不是妥协而是深思熟虑后的最优解用Cloud Run的极致弹性承载“思考”用GKE Autopilot的确定性承载“行动”。两者通过Pub/Sub这个GCP原生的、企业级的消息总线无缝缝合构成了一个既敏捷又稳健的Agent基础设施。3. 核心细节解析Data-Native的真正含义与落地四原则3.1 Data-Native不是形容词而是四个必须落地的工程原则“Data-Native”这个词在标题里被反复强调但它绝非营销话术。在我经手的所有失败案例中90%的根源都在于团队把它当成了一个可选的、锦上添花的特性而不是一个强制的、贯穿始终的工程约束。真正的Data-Native体现在以下四个铁律上原则一一切皆事件Everything is an EventAgent的每一次心跳都必须是一个结构化的、可溯源的事件。这包括用户原始请求含request_id,timestamp,user_id、Orchestrator生成的Plan含plan_id,llm_model,prompt_tokens、每个Task的执行详情含task_id,tool_name,input_hash,execution_time_ms,error_code、甚至LLM返回的原始JSON响应。这些事件不是日志Log而是事实Fact必须以标准Schema写入BigQuery。我们为此定义了一个核心表agent_events其Schema经过12次迭代才稳定下来核心字段如下CREATE TABLE myproject.mydataset.agent_events ( event_id STRING NOT NULL, event_type STRING NOT NULL, -- user_request, plan_generated, task_executed, task_failed plan_id STRING, task_id STRING, session_id STRING, user_id STRING, timestamp TIMESTAMP NOT NULL, payload STRUCT... -- 嵌套结构根据event_type动态变化 );注意payload字段是STRUCT类型而非STRING。这意味着BigQuery可以直接对嵌套字段如payload.sql_query.duration_ms进行SQL聚合和过滤无需先用UDF解析JSON。这是Data-Native的底层能力也是后续所有分析的基础。原则二状态即数据State is Data不要把Agent的“状态”理解为内存里的一个Python dict。在我们的架构里“状态”就是BigQuery里的一行或多行记录。Orchestrator在生成新Plan前会发起一个SQL查询SELECT * FROM myproject.mydataset.agent_events WHERE session_id session_id AND event_type IN (user_request, task_executed) AND timestamp TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR) ORDER BY timestamp DESC LIMIT 10;这个查询的结果就是Orchestrator的“上下文”。它不依赖任何外部缓存数据一致性由BigQuery的强一致性保证。当Executor执行一个Task失败时它不会修改内存状态而是向agent_events表插入一条event_type task_failed的新记录。Orchestrator下次收到重试请求会自然地读取到这条失败记录并据此生成新的、修正过的Plan。状态的变更就是数据的写入。原则三数据即反馈Data is Feedback所有写入BigQuery的事件都必须能立刻转化为可操作的反馈。我们建立了实时监控看板Looker Studio核心指标包括Plan成功率plan_generated/user_request、Task平均耗时按tool_name分组、高频失败工具TOP5。当sql_query的失败率超过5%看板会自动触发一个Cloud Function该函数会扫描最近1000条task_failed事件提取出所有失败的SQL语句用一个专门的LLM Agent对其进行语法检查和重写建议并将报告发送给DBA团队。数据在这里完成了从“记录”到“诊断”再到“行动”的闭环。原则四数据即资产Data is Asset最终agent_events表本身就是一个高价值的训练数据集。我们每月用它来微调Orchestrator的LLM。具体流程是从表中筛选出event_type plan_generated且后续所有task_executed都成功的记录提取user_request和payload.plan_json构成一个高质量的Instruction-Tuning数据集。这个数据集比公开的Alpaca数据集更贴近真实业务场景因为它包含了我们自己业务特有的术语、流程和边界条件。微调后的模型在生成Plan时的工具选择准确率提升了37%。这就是Data-Native的终极回报你投入的每一行代码都在为Agent的自我进化积累燃料。3.2 Scalable的硬核指标与GCP服务选型的量化依据“Scalable”不是一句空话它必须对应到GCP服务的具体参数和可测量的指标上。我们为线上系统设定了三套硬性SLA并据此反向推导出所有服务的配置SLA指标目标值对应GCP服务关键配置与依据端到端P95延迟 1.8秒Cloud Run (Orchestrator)设置min-instances2,max-instances100, CPU为1。压测显示当并发请求数从100升至5000时P95延迟从320ms升至1.75秒仍在SLA内。若用cpu2成本翻倍但延迟仅降低8%ROI极低。Task执行吞吐量10,000 QPSGKE Autopilot (Executor)Executor Pod的resources.requests.memory1200Mi。一个Pod可稳定处理120 QPS。因此节点池需自动扩缩容至84个Pod10000/120≈83.3。Autopilot的自动扩缩容时间约为90秒足够应对流量脉冲。事件写入延迟 200msBigQuery Streaming Insert启用streaming_buffer所有事件通过bq insert命令批量写入batch size500。压测表明单次500条事件的写入延迟稳定在120-180ms。若用单条Insert延迟会飙升至1.2秒完全不可接受。状态恢复时间 50msCloud Memorystore (Redis)使用redis-cachetiernode_count3主从哨兵。GET plan:{id}操作的P99延迟为38ms。我们禁用所有持久化因为状态是瞬时的且BigQuery是唯一真相源。这些数字不是拍脑袋定的而是我们在GCP的us-central1区域用k6工具进行了为期两周的阶梯式压测从100 QPS开始每5分钟100 QPS直到5000 QPS后得出的结论。每一个配置项背后都有详尽的压测报告支撑。例如为什么Executor的内存请求是1200Mi而不是1Gi因为1Gi1024Mi会导致GKE Autopilot分配一个e2-standard-4节点4vCPU, 16GB RAM而1200Mi会分配e2-standard-22vCPU, 8GB RAM后者成本低42%且性能无损。这种抠到字节的优化才是Scalable的真谛。3.3 Agentic AI的“心跳”机制如何让Agent在GCP上真正“活”起来一个静态的、只响应请求的Agent永远称不上“Agentic”。真正的智能体必须具备“自主性”——它能感知环境变化主动发起行动而不需要用户每次都敲下回车。在GCP上我们用一套组合拳实现了这一点称之为“Agent Heartbeat”。心跳源头Pub/Sub的事件驱动我们创建了多个专用的Pub/Sub主题作为Agent的“感官器官”>if event.topic data-updates and event.data.table_name orders: # 主动发起一个“订单异常检测”Plan plan llm.generate_plan( promptfAnalyze the latest orders data in BigQuery. Look for anomalies like duplicate orders, unusually high values, or missing payment methods. ) publish_to_task_queue(plan.tasks) elif event.topic system-alerts and high_cpu in event.data.alert_name: # 主动发起一个“资源扩容”Plan plan llm.generate_plan( promptfScale up the Executor node pool in GKE Autopilot to handle increased load. Current CPU usage is {event.data.cpu_percent}%. ) # 此Plan会调用GKE的REST API publish_to_task_queue(plan.tasks)这个规则引擎不是硬编码的if-else而是一个用Vertex AI定制的、可在线更新的小型分类模型它能根据事件的topic、data和timestamp预测最可能需要执行的Plan类型。模型的训练数据就来自我们过去一年积累的agent_events表。心跳保障幂等性与死信队列DLQ心跳机制最大的风险是重复执行。我们为所有心跳事件的处理强制实施幂等性每个Pub/Sub消息都带有唯一的message_id。Orchestrator在处理前先查询BigQuery的agent_events表检查是否存在event_typeheartbeat_processed AND payload.message_id {current_id}的记录。如果存在则跳过处理如果不存在则先插入一条heartbeat_processed事件再执行Plan生成逻辑。同时我们为所有心跳主题配置了Dead Letter TopicDLQ。当一条消息在7天内被重试10次仍失败它会被自动路由到DLQ。我们有一个专门的“DLQ巡检Agent”它每天扫描DLQ用LLM分析失败原因是网络超时还是权限不足并自动生成修复工单Jira API。这套“心跳”机制让我们的Agent从一个被动的“应答者”变成了一个主动的“协作者”。它不再等待指令而是时刻关注着数据、系统和业务的变化并在恰当的时机伸出援手。这才是Agentic AI的灵魂所在。4. 实操过程详解从零搭建一个可运行的Demo Agent4.1 环境准备与基础服务部署15分钟所有操作均在gcloudCLI下完成假设你已安装gcloud并登录了拥有Owner权限的GCP项目。我们将创建一个名为agent-demo的独立命名空间避免污染现有环境。创建Pub/Sub主题与订阅这是整个架构的“神经中枢”必须最先建立# 创建四个核心主题 gcloud pubsub topics create user-requests gcloud pubsub topics create task-queue gcloud pubsub topics create task-results gcloud pubsub topics create heartbeat-events # 为Orchestrator创建订阅拉取模式 gcloud pubsub subscriptions create orchestrator-sub \ --topicuser-requests \ --push-endpoint \ --ack-deadline60 gcloud pubsub subscriptions create heartbeat-sub \ --topicheartbeat-events \ --push-endpoint \ --ack-deadline60 # 为Executor创建订阅拉取模式 gcloud pubsub subscriptions create executor-sub \ --topictask-queue \ --push-endpoint \ --ack-deadline300 # Executor可能执行长时间任务部署Cloud Memorystore (Redis) 实例这是State Store的物理载体配置必须精简# 创建一个最小规格的Redis实例 gcloud redis instances create agent-state-store \ --size1 \ --regionus-central1 \ --tierSTANDARD \ --redis-versionREDIS_6_X \ --networkdefault \ --no-requirepass \ --transit-encryption-modeDISABLED \ --maintenance-window-dayMONDAY \ --maintenance-window-hour2 # 获取Redis的连接地址稍后配置Executor gcloud redis instances describe agent-state-store --regionus-central1 \ --formatvalue(host)创建BigQuery数据集与表这是Data-Native的基石Schema必须一步到位# 创建数据集 bq mk --dataset myproject:agent_demo # 创建核心事件表使用上面定义的Schema bq mk --table myproject:agent_demo.agent_events \ event_id:STRING, event_type:STRING, plan_id:STRING, task_id:STRING, session_id:STRING, user_id:STRING, timestamp:TIMESTAMP, payload:RECORD创建GKE Autopilot集群这是Executor的家园配置要兼顾成本与性能# 创建集群 gcloud container clusters create-auto agent-executor-cluster \ --regionus-central1 \ --release-channelregular # 获取集群凭据 gcloud container clusters get-credentials agent-executor-cluster --regionus-central1 # 创建一个专用的命名空间 kubectl create namespace agent-executor实操心得这15分钟的初始化看似简单却是整个项目成败的关键。我曾因忘记为Pub/Sub订阅设置--ack-deadline导致Executor处理一个慢任务时消息被重复投递了37次最终拖垮了整个Redis。务必逐行执行并用gcloud pubsub subscriptions describe确认ack_deadline_seconds的值。4.2 Orchestrator服务开发与部署Cloud RunOrchestrator是整个系统的“指挥官”其代码必须极度精简、可靠。我们用Python FastAPI实现核心逻辑只有200行。核心代码 (main.py)from fastapi import FastAPI, BackgroundTasks, HTTPException from google.cloud import pubsub_v1, bigquery import json, uuid, time, logging from vertexai.generative_models import GenerativeModel app FastAPI() publisher pubsub_v1.PublisherClient() subscriber pubsub_v1.SubscriberClient() bq_client bigquery.Client() # 初始化Gemini模型 model GenerativeModel(gemini-1.5-pro) app.post(/process_request) async def process_request(request: dict): # 1. 生成唯一ID request_id str(uuid.uuid4()) session_id request.get(session_id, request_id) # 2. 将用户请求写入BigQuery bq_client.insert_rows_json( myproject.agent_demo.agent_events, [{ event_id: request_id, event_type: user_request, session_id: session_id, user_id: request.get(user_id, anonymous), timestamp: time.time(), payload: {raw_input: request} }] ) # 3. 检索历史上下文过去1小时内的10条相关事件 context_sql f SELECT * FROM myproject.agent_demo.agent_events WHERE session_id {session_id} AND timestamp TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR) ORDER BY timestamp DESC LIMIT 10 context_rows list(bq_client.query(context_sql)) # 4. 调用Gemini生成Plan plan_prompt f You are an AI orchestrator. Based on the users request and the recent context, generate a detailed execution plan. User Request: {json.dumps(request)} Recent Context (last 10 events): {json.dumps([dict(row) for row in context_rows])} Output ONLY valid JSON with keys: plan_id, tasks (array of objects with task_id, tool_name, input). response model.generate_content(plan_prompt) plan_data json.loads(response.text) # 5. 将Plan写入BigQuery bq_client.insert_rows_json( myproject.agent_demo.agent_events, [{ event_id: str(uuid.uuid4()), event_type: plan_generated, plan_id: plan_data[plan_id], session_id: session_id, timestamp: time.time(), payload: plan_data }] ) # 6. 将每个Task发布到task-queue主题 topic_path publisher.topic_path(myproject, task-queue) for task in plan_data[tasks]: task_id str(uuid.uuid4()) task_message { task_id: task_id, plan_id: plan_data[plan_id], session_id: session_id, tool_name: task[tool_name], input: task[input] } publisher.publish(topic_path, json.dumps(task_message).encode(utf-8)) return {status: success, plan_id: plan_data[plan_id]} # 启动一个后台任务持续拉取heartbeat-events app.on_event(startup) async def startup_event(): def pull_heartbeats(): subscription_path subscriber.subscription_path(myproject, heartbeat-sub) streaming_pull_future subscriber.subscribe( subscription_path, callbacklambda message: handle_heartbeat(message) ) try: streaming_pull_future.result() except Exception as e: logging.error(fHeartbeat pull failed: {e}) streaming_pull_future.cancel() import threading thread threading.Thread(targetpull_heartbeats, daemonTrue) thread.start() def handle_heartbeat(message): # 解析心跳事件并触发相应的Plan生成逻辑 event_data json.loads(message.data.decode(utf-8)) # ... 此处省略具体的规则引擎逻辑与3.3节一致 message.ack()DockerfileFROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [uvicorn, main:app, --host, 0.0.0.0:8080, --port, 8080]部署到Cloud Run# 构建并推送镜像 gcloud builds submit --tag gcr.io/myproject/agent-orchestrator # 部署服务 gcloud run deploy agent-orchestrator \ --image gcr.io/myproject/agent-orchestrator \ --platform managed \ --region us-central1 \ --allow-unauthenticated \ --min-instances 2 \ --max-instances 20 \ --cpu 1 \ --memory 512Mi \ --set-env-varsGOOGLE_CLOUD_PROJECTmyproject # 获取服务URL gcloud run services describe agent-orchestrator --regionus-central1 --formatvalue(status.url)实操心得Orchestrator的代码里handle_heartbeat函数是整个“心跳”机制的入口。我最初把它写在了FastAPI的路由里结果发现心跳事件的处理被HTTP请求的生命周期锁死了。后来才意识到必须用app.on_event(startup)启动一个独立的后台线程来持续拉取消息。这是一个典型的GCP Serverless与长连接服务的适配陷阱。4.3 Executor服务开发与部署GKE AutopilotExecutor是“肌肉”必须高效、安全、可插拔。我们用Go语言编写利用其出色的并发性能和内存安全性。核心代码 (executor/main.go)package main import ( context encoding/json fmt log net/http os time cloud.google.com/go/pubsub google.golang.org/api/option github.com/go-redis/redis/v8 ) var ( ctx context.Background() rdb *redis.Client pubClient *pubsub.Client ) type TaskMessage struct { TaskID string json:task_id PlanID string json:plan_id SessionID string json:session_id ToolName string json:tool_name Input map[string]interface{} json:input } func main() { // 初始化Redis客户端 rdb redis.NewClient(redis.Options{ Addr: os.Getenv(REDIS_HOST) :6379, Password: , DB: 0, }) // 初始化Pub/Sub客户端 pubClient, _ pubsub.NewClient(ctx, os.Getenv(GOOGLE_CLOUD_PROJECT), option.WithCredentialsFile(/var/secrets/google/key.json)) // 订阅task-queue主题 sub : pubClient.Subscription(executor-sub) sub.ReceiveSettings.MaxExtension 5 * time.Minute // 启动接收循环 err : sub.Receive(ctx, func(ctx context.Context, msg *pubsub.Message) { defer msg.Ack() var task TaskMessage if err : json.Unmarshal(msg.Data, task); err ! nil { log.Printf(Failed to unmarshal task: %v, err) return } // 执行任务 result, err : executeTool(task.ToolName, task.Input) if err ! nil { log.Printf(Task %s failed: %v, task.TaskID, err) // 写入失败事件到BigQuery此处简化实际调用BQ API writeEventToBQ(task_failed, task, err.Error()) return } // 写入成功事件 writeEventToBQ(task_executed, task, result) }) if err ! nil { log.Fatal(err) } } func executeTool(toolName string, input map[string]interface{}) (map[string]interface{}, error) { switch toolName { case sql_query: return executeSQL(input) case http_get: return executeHTTPGet(input) default: return nil, fmt.Errorf(unknown tool: %s, toolName) } } func executeSQL(input map[string]interface{}) (map[string]interface{}, error) { // 这里调用Cloud SQL的Go驱动 // ... 实际代码省略 return map[string]interface{}{rows: 123}, nil } func executeHTTPGet(input map[string]interface{}) (map[string]interface{}, error) { // 这里用Go的net/http包 // ... 实际代码省略 return map[string]interface{}{status: ok}, nil } func writeEventToBQ(eventType string, task TaskMessage, result interface{}) { // 构造BigQuery的JSON行并调用BQ Streaming Insert API // ... 实际代码省略 }Kubernetes部署清单 (k8s/deployment.yaml)apiVersion: apps/v1 kind: Deployment metadata: name: agent-executor namespace: agent-executor spec: replicas: 3 selector: matchLabels: app: agent-executor template: metadata: labels: app: agent-executor spec: containers: - name: executor image: gcr.io/myproject/agent-executor:v1.0 resources: requests: memory: 1200Mi