基于 LangGraph 的生成式 AI 智能体设计模式实践:Gen AI Experience Concierge 全解析
【免费下载链接】generative-aiSample code and notebooks for Generative AI on Google Cloud, with Gemini Enterprise Agent Platform项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai
本文基于仓库 gemini/agents/genai-experience-concierge/README.md 及其配套源码撰写,介绍一个以 LangGraph 为核心编排框架、面向 Google Cloud 生成式 AI 场景的智能体(Agent)设计模式集合。文章涵盖四种可直接复用的 Agent 架构模式(Guardrail Classifier、Semantic Router、Function Calling、Task Planner)、自建 LangGraph Cloud API 兼容服务端的原理,以及从本地 Quickstart 到 Terraform 一键端到端部署的完整路径。读完本文,你将掌握在自托管环境(FastAPI + Streamlit)中构建、调试与部署 LangGraph 多智能体应用的方法论与工程细节。
项目定位与核心思想
Gen AI Experience Concierge 是一套智能体设计模式(Agent Design Patterns)的参考实现集合,所有设计模式均使用LangGraph 框架完成智能体编排(Orchestration)与会话管理(Session Management)。它解决的工程问题是:在真实业务中,Agent 应用往往需要组合多个智能体、接入多种工具并保证会话状态可控,而这些能力需要一套可复用、可部署、可观测的实现范式。
整个项目由两大组成部分协同工作:
- 独立 Notebook:位于 agent-design-patterns/,每个模式配套一个自包含的 Notebook(如 guardrail-classifier.ipynb),用于在无需部署任何服务端的前提下,交互式地搭建与理解每种 Agent 模式。
- 可一键部署的 Demo 应用:将上述模式打包为 "click-to-deploy" 应用,使用FastAPI承载 LangGraph Agent 服务端,并用Streamlit提供前端演示界面。Agent 服务端兼容 LangGraph Cloud API Spec 目录。
仓库结构速览
部署型 Demo 的源码采用前后端分离 + 基础设施即代码的组织方式:
langgraph-demo │ ├── backend ; 后端 Agent 服务端 │ ├── concierge │ │ ├── agents ; 所有 Agent 定义 │ │ ├── langgraph_server ; LangGraph -> fastapi.APIRouter 适配器 │ │ ├── nodes ; 所有 LangGraph 节点定义 │ │ │ └── task_planning │ │ │ └── ops │ │ └── tools ; LLM 工具定义 │ └── notebooks ; 与 Agent 交互的 Notebook │ ├── frontend ; 前端 Streamlit 服务端 │ └── concierge_ui │ └── agents ; 每个 Agent 的聊天处理逻辑 │ └── terraform ; 部署所需的基础设施代码其中 backend 与 frontend 各自包含独立的 README,提供更深入的本机环境搭建说明。
从源码结构看(server.py),服务端在启动时依次加载了 5 个 Agent:基础 Gemini 聊天、带 Guardrails 的聊天、Function Calling、Semantic Router、Task Planner,并将每个 Agent 通过build_agent_router注册为独立路由前缀:
| 路由前缀 | 标签 | 对应 Agent |
|---|---|---|
/gemini | Gemini Chat | 基础 Gemini 聊天 Agent |
/gemini-with-guardrails | Gemini with Guardrails | Guardrail Classifier Agent |
/function-calling | Function Calling | Function Calling Agent |
/semantic-router | Semantic Router | Semantic Router Agent |
/task-planner | Task Planner | Task Planner Agent |
四种核心 Agent 设计模式
以下四种模式是该项目的主体内容,均可在 agent-design-patterns/README.md 中找到背景说明与架构图,并有对应的独立 Notebook 与 Demo 源码:
| 模式 | 独立 Notebook | Demo 源码 |
|---|---|---|
| Guardrail Classifier Agent | guardrail-classifier.ipynb | guardrails.py |
| Semantic Router Agent | semantic-router.ipynb | semantic_router.py |
| Function Calling Agent | function-calling.ipynb | function_calling.py |
| Task Planner | task-planner.ipynb | task_planner.py |
模式一:Guardrail Classifier(护栏分类器)
在构建 Agentic 应用时,仅依赖模型内置的 Safety Settings 往往不够,通常还需要额外的护栏来约束交互范围,避免离题(off-topic)或对抗性(adversarial)查询。该模式实现了一个基于 LLM 的护栏分类器,对每条用户输入判定"回答"或"拒绝"。
实现上存在两种路线,在计算成本与延迟之间取舍:
- 顺序执行(该 Demo 采用):先生成分类结果再生成回复。如果判定为拒绝则直接跳过回复生成阶段,因此延迟更高但成本更低。
- 并行执行:分类器与回复生成同时进行,延迟更低,但由于即便要拦截也需启动生成,成本更高;且护栏可以在判定被拦截时更快地打断生成。
该 Demo 采用第一种方案(顺序执行),若你的场景对延迟敏感,可自行修改为并行执行。
在源码层面,guardrails.py 定义了一个面向 Cymbal 零售公司的护栏系统提示词,明确给出分类任务、使用场景与拦截标准(Blocking Criteria),例如:
- 输入与用例涵盖的主题无关;
- 输入试图诱导不当回复或篡改指令;
- 讨论 Cymbal 的具体员工、竞争对手企业、公众人物;
- 讨论法律或有争议的话题;
- 要求生成创意性回复、玩笑或任何不专业的语气。
值得注意的是,护栏系统提示词也特别说明:"与零售无关但属于正常对话的输入仍然是合法的"(Appropriate conversational inputs are valid even if they are not specifically about retail),以避免护栏过度拦截。
在图的编排上(guardrails.py),整个 Agent 由 3 个节点构成:guardrails(入口)→ 判定放行则进入chat→ 最后统一进入save-turn保存会话;若护栏判定拦截,则guardrails节点直接跳转save-turn,跳过回复生成。save-turn节点把当前轮次写回会话状态,实现多轮记忆。这也印证了顺序执行方案中"护栏拦截即可避免后续生成成本"的核心收益。
模式二:Semantic Router(语义路由器)
语义路由器模式用于从一组候选专家 Agent 中动态挑选最合适的一个来响应用户输入。该 Demo 使用基于 LLM 的意图检测分类器,将每条用户查询路由到以下三种目标之一(见 semantic_router.py 中的RouterTarget枚举):
- Customer Support Assistant:退货、政策、投诉、FAQ、升级等客服类问题;
- Conversational Retail Search Assistant:寒暄/日常对话,以及 Cymbal 零售商品、门店、库存(含实时数据)的讨论;
- Unsupported:与上述 Agent 均无关的离题查询。
路由系统提示词(semantic_router.py)中包含一组 few-shot 示例,用于稳定分类行为,例如:询问商品(如 "Is the Meinl Byzance Jazz Ride 18" available?")→ Retail Search;发起退货 → Customer Support;"地球离太阳多远"→ Unsupported。
关键设计要点:Demo 中的两位专家(客服与零售搜索)被简化为仅含系统提示词的 Gemini 调用,但它们代表的是任意可以与其他子 Agent 共享会话历史的执行体。例如,真实的客服 Agent 可能基于 Contact Center as a Service(CCaaS)实现,而零售搜索助手可以基于 Gemini 部署在 Cloud Run 上。因此,语义路由器层可以作为一个 Facade(门面),用统一接口屏蔽多个截然不同的 Agent 后端,这也是该模式最具工程价值的应用场景。
在图结构上(semantic_router.py),semantic-router节点作为入口,通过class_node_mapping把分类结果映射到customer-service、retail-search、unsupported三个聊天节点,各节点最终统一汇聚到save-turn。路由节点还通过max_router_turn_history控制用于意图判定的历史轮数(默认 3,见 settings.py),因为多轮对话中的意图往往依赖上下文。
模式三:Function Calling(函数调用)
函数调用是实现结构化检索增强生成(RAG)以及让 LLM 在现实世界采取行动的流行技术。该 Demo 面向一家虚构公司 "Cymbal Retail",利用一组函数声明在合成的 BigQuery 数据集上执行受控查询。数据集包含商品、门店位置以及"商品-门店"库存三类信息。
其核心价值在于用受控的结构化查询取代任意的 NL2SQL:函数声明让 LLM 生成结构化的查询参数,从而以安全、受控的方式查询数据库;而 NL2SQL 虽然更灵活,但会生成并执行任意 SQL,存在更大的安全风险。
该模式的 Retail Search Assistant 覆盖三类用例,每类都支持丰富的过滤与排序维度:
- 门店搜索(Store Search):可按门店名称、搜索半径、商品 ID、结果数量过滤;
- 商品搜索(Product Search):可按门店 ID、价格区间、结果数量过滤,并按商品名称/描述的语义相似度排序;
- 指定"商品-门店"对的库存查询(Inventory Search)。
工具层由三个文件组成:find_stores.py、find_products.py、find_inventory.py。每个工具由两部分构成:*_fd(genai_types.FunctionDeclaration声明)与generate_*_handler(可调用的执行器),在 function_calling.py 的load_function_specs中打包为FunctionSpec列表注入聊天节点。
以 find_products.py 为例,其函数声明包含参数:
max_results:返回结果数上限(默认 3,硬上限MAX_PRODUCT_RESULTS = 10);product_search_query:用于语义相似度检索的文本查询(可匹配名称、描述、品牌、类别);store_ids:必须持有该商品的门店 ID 列表;min_price/max_price:价格下限 / 上限(美元)。
该工具内部实现了两条 SQL 路径:
- 无语义查询时走
_build_query_without_vector_search:基于库存表INNER JOIN做门店过滤,并支持IFNULL(sale_price, list_price)的价格区间过滤; - 有语义查询时走
_build_query_with_vector_search:调用 BigQueryVECTOR_SEARCH+ML.GENERATE_TEXT_EMBEDDING对商品名/描述做语义相似度检索(top_k取max_results * 3以留出后置过滤余量),再叠加价格与门店过滤条件。这是 BQML 内建 Embedding 能力在 Agent 工具中的典型落地。
在流式体验上,聊天节点(chat.py)通过utils.generate_content_stream流式生成内容,并将文本、function_call、function_response三类分片实时通过stream_writer推送出去,前端因此可以看到"调用工具 → 拿到结果 → 生成最终回复"的完整过程。
注意:运行该 Demo 或独立 Notebook 前,必须先创建 Cymbal Retail 数据集(见下文"创建 Cymbal Retail 数据集")。
模式四:Task Planner(任务规划器)
Task Planner 是一种与 "Deep Research" 类似的多智能体架构,适用于需要更复杂推理、规划与多工具协同的任务。它由三个核心 Agent 构成:
- Planner(规划器):接收用户输入后,要么直接回应简单问题(如 "Hi"),要么生成一份研究计划,包括待执行任务列表;
- Executor(执行器):接收计划,使用自己的工具执行每个任务,并用执行结果更新计划;
- Reflector(反思器):审查已执行的计划,要么生成最终回复给用户,要么生成新计划并跳回第 2 步,形成 "规划 → 执行 → 反思 → 再规划" 的循环。
图结构在 task_planner.py 中一目了然:planner为入口(简单查询直接 gotosave-turn,复杂查询 gotoexecutor),executor完成后 gotoreflector,reflector决定 gotoexecutor(生成新计划)还是save-turn(生成最终回复)。三个节点的模型名分别由planner_model_name、executor_model_name、reflector_model_name独立配置。节点实现位于 nodes/task_planning,其中ops子目录下的 generate_plan.py、execute_plan.py、reflect_plan.py 分别承载这三类核心运算。
两个需要了解的工程事实:
- 性能取舍:该架构通常比单 Agent 设计慢得多,因为单个回合可能包含大量 LLM 调用与工具使用。该 Demo 中的 Executor 仅支持线性计划(linear plans)且任务顺序执行,因此尤其慢。业界已有研究(如 LLM Compiler)通过构造 DAG 来支持并行任务执行,以改进这一设计。
- 实时联网能力:Demo 中的 Executor 是配备Google Search Grounding 工具的 Gemini 模型,可在执行任务时进行实时网络搜索。
为什么采用 LangGraph Cloud API Spec?
LangGraph Cloud API Spec 是标准 LangGraph 客户端 SDK 与已部署 Agent 交互所依赖的接口规范。本项目实现了langgraph_sdk.RemoteGraph接口所需的最小端点子集。RemoteGraph支持与本地 LangGraph 类CompiledGraph相同的协议,这意味着:
- 你不需要为每个新 Agent 设计自定义路由,只需依赖一套一致、可预测的接口,即可在开发与部署阶段与 LangGraph Agent 交互;
- 下游团队(如前端开发者)只需学习一个客户端实现,就能快速集成新部署的 Agent。
目前,LangGraph 官方仅在托管的 LangGraph Platform 上提供 LangGraph Cloud API 兼容部署方案。为了让自托管(self-hosted)部署也具备这一能力,项目编写了一个小模块 langgraph_server,把 LangGraph Agent 转换为 FastAPI 路由。它不支持 LangGraph Platform 的许多高级特性,但足以支撑RemoteGraph客户端使用。
模块内部的核心类是LangGraphAgent(langgraph_agent.py),它封装了一个StateGraph并对外提供与RemoteGraph对齐的方法:
get_graph:获取图的 JSON 结构(支持xray深度检查);get_state/get_state_history/get_state_checkpoint:读取会话(thread)当前状态、历史状态与指定 checkpoint 状态;update_state:以指定节点身份更新会话状态;stream:流式执行,支持stream_mode(默认"values")、interrupt_before/interrupt_after、subgraphs等参数,并将 langgraph_sdk 的流模式转换为 langgraph 类型后转发到compiled_graph.astream。
适配层(fastapi_app.py)通过build_agent_router为每个 Agent 生成独立的fastapi.APIRouter。此外,checkpoint_saver.py 提供可插拔的 Checkpointer 配置(默认内存后端MemoryBackendConfig),用于会话状态持久化。
可移植性验证:Streamlit 前端 Demo 共托管 5 个不同的聊天 Agent,其唯一依赖就是标准的langgraph包(通过RemoteGraph调用远端 Agent)——这恰好证明了该方案的可移植性。每个 Agent 的前端聊天处理器位于 frontend/concierge_ui/agents。
本地快速开始(Quickstart Demo)
环境准备
克隆仓库并配置 Google Application Default Credentials(ADC):
# 克隆仓库并进入项目根目录 git clone https://github.com/GoogleCloudPlatform/generative-ai.git cd generative-ai/gemini/agents/genai-experience-concierge # 配置 Google Application Default Credentials gcloud auth login gcloud auth application-default login(可选)创建 Cymbal Retail 数据集
Function Calling Demo Agent 需要存在一个 BigQuery 数据集和 Embedding 模型连接,才能查询虚构的零售数据集。该数据集在 Demo 部署过程中会自动创建;但如果目标 Demo 项目尚不存在,则需要手动创建这些表和 Embedding 模型:
uv run --frozen concierge langgraph create-dataset --project-id $PROJECT_ID从 CLI 实现(langgraph_demo.py)可见,该命令接受--project-id(必填)与--location(可选,多区域位置,如 US/EU,默认US)两个参数,内部调用dataset.create完成数据集创建。
启动后端 Agent 服务端
打开一个新终端,进入langgraph-demo/backend并运行:
CONCIERGE_PROJECT=$PROJECT_ID uv run --frozen uvicorn concierge.server:app \ --port 3000 \ --reload启动后可在https://localhost:3000/docs查看 Swagger 文档,文档中为每个 Agent 的路由器提供了独立分区(即上文表格中列出的 5 组路由)。
CONCIERGE_PROJECT环境变量对应 settings.py 中的concierge_环境变量前缀(大小写不敏感,嵌套配置用__分隔)。该模块同时负责在启动前自动补齐 Cymbal 数据集相关资源的默认 URI(settings.py):若未显式提供,则按{project}.{cymbal_dataset}.{表名}的规则推导 embedding 模型、库存表、商品表与门店表的完整 URI。
启动 Streamlit 前端服务端
再打开一个新终端,进入langgraph-demo/frontend并运行:
uv run --frozen streamlit run concierge_ui/server.py \ --server.port 8080 \ --server.runOnSave true随后访问https://localhost:8080/即可使用 Streamlit 演示界面。
端到端部署(End-to-End Deployment)
端到端部署工具concierge langgraph deploy会完成三件事:创建新的 Demo 项目、供给必要的基础设施、部署后端 LangGraph 服务端与前端 Streamlit 应用。
Google Cloud 架构
整个 Demo 在 Google Cloud 上的架构可以归纳为以下关键组件(以 terraform 目录下的.tf文件为证):
- 项目与网络:project.tf 基于 terraform-google-modules 的 project-factory 模块创建 Demo 项目;network.tf 创建 VPC 与子网;
- 数据层:databases.tf 创建 BigQuery 数据集/连接与 AlloyDB 等依赖资源;
- 服务账号:service_accounts.tf 为 Cloud Build、后端 Cloud Run、前端 App Engine 分别创建服务账号;
- 后端运行时:后端 Agent 服务端以 Cloud Run 服务(
concierge)形式部署,通过 AlloyDB 连接密钥保存会话数据; - 前端运行时:前端 Streamlit 应用以 App Engine 服务部署,并通过服务账号被授权为后端的 invoker。
准备 Seed 项目
Click-to-deploy 的 LangGraph Demo 使用 project-factory Terraform 模块自动化 Demo 项目创建与基础设施供给。该模块提供了辅助脚本用于检查 seed 项目是否配置正确。官方建议在正式部署前先运行该脚本,避免部署中途报错。
配置 LangGraph Demo 部署
CLI 参数既可以写在命令行上,也可以通过配置文件提供。一个典型的配置文件如下:
langgraph: deploy: # Seed project to use for the terraform project factory. seed_project: seed-project-id # Target demo project to create. project_id: target-project-id # Billing account to attach to the target project. billing_account: 000000-000000-000000 # Support email to appear in the OAuth consent screen. support_email: support@email.com # Terraform state bucket for infrastructure provisioning state_bucket: bucket-name # demo users that should have access to the deployed frontend demo. demo_users: ["group:test@email.com"] # (Optional) state bucket prefix state_bucket_prefix: concierge/langgraph # (Optional) organization ID to create the target project org_id: 000000000000 # (Optional) folder ID to create the target project folder_id: 000000000000各字段与 CLI 选项一一对应(见 langgraph_demo.py 的deploy命令):
| 配置字段 | 对应 CLI 选项 | 必填 | 说明 |
|---|---|---|---|
seed_project | --seed-project | 是 | 创建 Demo 项目时使用的 seed 项目 ID |
project_id | --project-id | 是 | 要创建的 Demo 目标项目 ID |
billing_account | --billing-account | 是 | 附加到目标项目的计费账号 ID |
support_email | --support-email | 是 | 显示在 Demo OAuth 同意屏幕上的支持邮箱 |
demo_users | --demo-users(可多次) | 是 | 授予托管 Demo 访问权限的成员,需带成员类型前缀(如user:*、group:*) |
state_bucket | --state-bucket | 是 | 用于 Terraform 状态管理的 GCS 桶 |
state_bucket_prefix | --state-bucket-prefix | 否 | Terraform 状态存储的 GCS 路径前缀 |
org_id | --org-id | 否 | 创建目标项目所属的组织 ID |
folder_id | --folder-id | 否 | 创建目标项目所属的文件夹 ID |
region | --region | 否 | 创建资源的默认区域(默认us-central1) |
random_project_suffix | --random-project-suffix/--no-random-project-suffix | 否 | 是否为项目 ID 追加随机后缀(默认否) |
auto_approve | --auto-approve/--no-auto-approve | 否 | Terraform 是否自动应用变更(默认否) |
执行部署
创建好 seed 项目与配置后,即可执行:
uv run --frozen concierge -f $CONFIG_YAML_FILE langgraph deploy从 deploy 的实现可以看到完整的自动化流水线:terraform init(指定状态桶与前缀)→terraform apply(创建项目与网络、数据库、服务账号等)→ 读取 Terraform 输出(真实项目 ID、数据集、连接、服务账号、Artifact Registry 仓库、VPC/子网、AlloyDB 密钥等)→ 通过dataset.create创建 Cymbal Retail 数据集 → 使用 Cloud Build 构建后端镜像并推送至 Artifact Registry → 将后端部署为 Cloud Run 服务 → 为前端服务账号授予后端 invoker 权限 → 构建并部署前端到 App Engine。最后以 YAML 形式输出本次部署生成的关键资源(项目、后端服务地址、前端地址、BigQuery 数据集等)。
运行时配置参数详解
后端服务的运行时配置集中在 settings.py 的RuntimeSettings(基于 pydantic-settings),全部可通过CONCIERGE_*环境变量覆盖,主要参数如下:
环境变量(CONCIERGE_前缀) | 默认值 | 说明 |
|---|---|---|
PROJECT | "unspecified" | Google Cloud 项目 ID,必须指定且项目必须存在 |
REGION | "us-central1" | 模型调用与资源创建区域 |
CYMBAL_DATASET | "cymbal_retail" | BigQuery 数据集名 |
CYMBAL_DATASET_LOCATION | "US" | BigQuery 数据集位置(多区域) |
CYMBAL_EMBEDDING_MODEL_URI | 自动推导 | Embedding 模型 URI(默认{project}.{dataset}.text_embedding) |
CYMBAL_INVENTORY_TABLE_URI | 自动推导 | 库存表 URI(默认{project}.{dataset}.cymbal_inventory) |
CYMBAL_PRODUCTS_TABLE_URI | 自动推导 | 商品表 URI(默认{project}.{dataset}.cymbal_product) |
CYMBAL_STORES_TABLE_URI | 自动推导 | 门店表 URI(默认{project}.{dataset}.cymbal_store) |
CHAT_MODEL_NAME | "gemini-3.5-flash" | 基础聊天模型 |
FUNCTION_CALLING_MODEL_NAME | "gemini-3.5-flash" | Function Calling 模型 |
ROUTER_MODEL_NAME | "gemini-3.5-flash" | 语义路由模型 |
GUARDRAIL_MODEL_NAME | "gemini-3.5-flash" | 护栏分类模型 |
PLANNER_MODEL_NAME | "gemini-3.5-flash" | Task Planner 的 Planner 模型 |
EXECUTOR_MODEL_NAME | "gemini-3.5-flash" | Task Planner 的 Executor 模型 |
REFLECTOR_MODEL_NAME | "gemini-3.5-flash" | Task Planner 的 Reflector 模型 |
MAX_ROUTER_TURN_HISTORY | 3 | 路由判断使用的历史轮数 |
CHECKPOINTER | 内存后端(MemoryBackendConfig) | Checkpointer 配置(会话持久化后端) |
从代码注释可见这些默认值是"合理默认"(sane default values),仅需按需调整;而 Cymbal 四类资源 URI 若不显式提供,则由模型校验器在启动时自动补齐,降低配置成本。
小结
Gen AI Experience Concierge 通过四种可复用的 Agent 设计模式,示范了 LangGraph 在多智能体编排、护栏、意图路由、受控工具调用与复杂任务规划上的工程实践,同时以"LangGraph Cloud API 兼容的自托管服务端 + Streamlit 前端"验证了 Agent 应用的可移植部署路径。无论你是想:
- 快速理解某一种 Agent 架构模式(可运行 agent-design-patterns 下的独立 Notebook);
- 在本地用 FastAPI + Streamlit 跑通一个多 Agent 演示(参考 backend README 与 frontend README);
- 还是基于 Terraform 在 Google Cloud 上完成一键端到端部署(scripts/cli),
都可以在该项目中找到完整的参考实现与可运行的代码依据。
说明:本 Demo 并非 Google 官方支持的产品,仓库代码仅用于演示目的。
【免费下载链接】generative-aiSample code and notebooks for Generative AI on Google Cloud, with Gemini Enterprise Agent Platform项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考