5分钟用ADK+Ollama搭建本地AI客服:手把手教你调用Gemma模型(附避坑指南)
从零到一:用ADK与Ollama打造你的专属本地AI客服
最近在折腾AI应用落地的朋友,估计都绕不开一个核心痛点:如何快速、低成本地构建一个可控、可定制的智能对话系统? 无论是想给自家产品加个智能助手,还是为内部团队开发一个效率工具,直接调用云端大模型API虽然方便,但总会遇到成本、数据隐私、响应延迟和模型定制化程度不足等问题。
这时候,本地化部署的优势就凸显出来了。而谷歌开源的 Agent Development Kit (ADK),恰好为我们提供了一条从“玩具级”Demo快速迈向“生产级”应用的清晰路径。它不像一些框架那样需要你从零开始造轮子,而是把智能体开发中那些繁琐的架构、编排、工具集成问题都封装好了,让你能像搭积木一样,专注于业务逻辑本身。
今天,我们就聚焦一个非常具体且实用的场景:为个人项目或中小企业,搭建一个运行在本地的AI客服原型。我们将完全使用开源方案,核心是 ADK 框架 + Ollama 本地模型。我会带你走通从环境准备、模型选择、智能体构建到多轮对话测试的完整流程,并重点分享几个我实际趟过的“坑”和解决方案。
1. 环境准备与核心工具栈解析
在动手写代码之前,我们需要先理解并搭建好整个技术栈的基石。这套方案的核心思想是“框架标准化,模型本地化”。
1.1 为什么选择 ADK + Ollama 这个组合?
市面上AI智能体框架不少,比如微软的AutoGen、LangChain等。ADK作为后来者,有几个特点让我觉得它特别适合快速原型开发:
- “开箱即用”的完整性:ADK不仅仅是一个SDK,它自带Web UI、命令行交互和HTTP API服务。这意味着你写完核心逻辑,立刻就有三种方式与你的智能体交互,省去了自己搭建前后端的麻烦。
- 对多模型的原生友好:虽然背靠谷歌,但ADK在设计上就是模型无关的。通过集成
LiteLLM这样的抽象层,它可以无缝对接 OpenAI、Anthropic 乃至任何提供兼容API的模型,当然也包括我们本地运行的Ollama。 - 清晰的智能体编排范式:ADK对“顺序执行”、“循环”、“并行”等工作流有内置支持。这对于构建一个先理解用户问题、再查询知识库、最后组织回答的客服流程来说,结构会非常清晰。
而 Ollama 则是当前在个人电脑上运行开源大模型最便捷的工具,没有之一。它解决了模型下载、环境配置、服务启动等一系列脏活累活。
我们的技术栈全景图如下:
[你的本地机器]
├── Python 3.9+ 环境
├── Ollama 服务 (运行 Gemma 2B/7B 等模型)
└── ADK 应用 (包含你的客服智能体逻辑)
├── 通过 LiteLLM 调用本地 Ollama API
├── 集成自定义工具(如知识库查询)
├── 提供 Web/CLI/HTTP 接口
1.2 逐步安装与验证
我们一步步来,确保每个环节都正确无误。
第一步:安装并验证 Ollama
访问 Ollama 官网下载并安装。安装后,打开终端,拉取一个适合本地运行的轻量级模型。对于客服场景,我们需要模型有较好的指令遵循和对话能力。Google 的 Gemma 系列是一个不错的起点,它在英文和中文上都有尚可的表现,且对硬件要求相对友好。
# 拉取 Gemma 2B 模型(对内存要求最低,适合初次尝试)
ollama pull gemma:2b
# 或者,如果你的机器内存足够(建议8G以上),可以尝试能力更强的 7B 版本
# ollama pull gemma:7b
拉取完成后,启动 Ollama 服务(通常安装后会自动运行)。可以通过以下命令验证:
# 查看已安装的模型
ollama list
# 简单测试模型是否能正常响应
ollama run gemma:2b "Hello, what's your name?"
如果模型能返回自我介绍,说明 Ollama 部分已就绪。
第二步:创建 Python 虚拟环境并安装 ADK
强烈建议使用虚拟环境来管理依赖,避免包冲突。
# 创建并进入一个名为 adk-customer-service 的目录
mkdir adk-customer-service && cd adk-customer-service
# 创建 Python 虚拟环境(这里使用 venv,你也可以用 conda)
python -m venv .venv
# 激活虚拟环境
# 在 macOS/Linux 上:
source .venv/bin/activate
# 在 Windows PowerShell 上:
# .venv\Scripts\Activate.ps1
# 安装 Google ADK 核心库
pip install google-adk
# 安装 LiteLLM,它是 ADK 连接非谷歌模型(如 Ollama)的桥梁
pip install litellm
安装完成后,可以快速验证 ADK 命令行工具是否可用:
adk --help
你应该能看到 run, web, api-server 等子命令的帮助信息。
至此,最基础的环境已经准备好了。接下来,我们将进入核心的智能体创建环节。
2. 创建你的第一个本地模型智能体
现在,让我们用不到20行代码,创建一个能与本地 Gemma 模型对话的智能体。这是验证整个链路是否打通的关键一步。
2.1 项目结构与核心文件
在 adk-customer-service 目录下,创建如下标准的 ADK 项目结构:
adk-customer-service/
├── .env # 环境变量配置文件(暂时可为空)
├── customer_service_agent/
│ ├── __init__.py # 空文件,使文件夹成为Python包
│ └── agent.py # 智能体的核心代码
└── requirements.txt # 可选,记录依赖
agent.py 是我们所有魔法的发生地。让我们先创建一个最简单的版本。
2.2 编写基础智能体代码
打开 customer_service_agent/agent.py,输入以下内容:
from google.adk.agents import LlmAgent
from google.adk.models.lite_llm import LiteLlm
# 创建根智能体
root_agent = LlmAgent(
# 核心:通过 LiteLLM 指定使用本地 Ollama 服务的 Gemma 2B 模型
# 格式固定为 "ollama/<模型名>"
model=LiteLlm(model="ollama/gemma:2b"),
name="local_customer_assistant",
description="一个运行在本地的、基于Gemma模型的客服助手原型。",
instruction=(
"你是一个专业的客服助手,负责回答用户关于产品使用、服务咨询和一般性问题。"
"请保持友好、耐心且专业的语气。"
"如果你不知道答案,请诚实地告知用户,并建议他们通过其他渠道联系人工客服。"
"请用中文进行对话。"
),
# 目前 tools 列表为空,智能体仅具备基础对话能力
tools=[],
)
代码解读:
LlmAgent是 ADK 中用于构建基于大语言模型智能体的核心类。model=LiteLlm(model="ollama/gemma:2b")是连接本地模型的关键。LiteLlm是一个包装器,它理解ollama/前缀,并会将请求发送到本地的 Ollama API 服务(默认在http://localhost:11434)。instruction中的提示词非常重要,它设定了智能体的“人设”和行为准则。我们明确要求它用中文对话,并扮演客服角色。
2.3 运行与测试智能体
ADK 提供了三种交互方式,我们逐一尝试。
方式一:Web 界面(最直观)
在项目根目录(adk-customer-service)下执行:
adk web
你会看到类似 Starting server at http://localhost:8000 的输出。用浏览器打开这个地址,你将看到一个简洁的聊天界面。在左上角的下拉菜单中,选择我们刚创建的 local_customer_assistant。
现在,尝试输入一些问题,比如:“你们的产品支持哪些操作系统?” 或 “我的账号无法登录,该怎么办?”。观察 Gemma 模型的回复。你可能会立刻发现两个问题:
- 回复可能是英文的,尽管我们在
instruction中要求了中文。 - 回复可能比较简短或笼统,缺乏客服场景的细节。
这是我们遇到的第一个“坑”:某些较小的开源模型对中文指令的遵循能力有限,并且缺乏特定领域的知识。别担心,我们会在后续章节解决它。
方式二:命令行交互
在另一个终端窗口(确保虚拟环境已激活),运行:
adk run customer_service_agent
这会进入一个交互式命令行界面,你可以直接与智能体对话。按 Ctrl+C 退出。
方式三:HTTP API 服务
这对于将智能体集成到其他系统(如你的网站后端)非常有用。
adk api-server
服务启动后,你可以使用 curl 或 Postman 等工具向 http://localhost:8000/v1/run 发送 POST 请求来调用智能体。具体的 API 格式可以参考 ADK 文档。
提示:在开发过程中,Web 界面是最方便的,因为它不仅能对话,还能在右侧面板查看详细的执行事件流(Event Stream),包括模型接收的提示词、思考过程和工具调用情况,这对调试至关重要。
3. 增强智能体:工具集成与中文优化
一个只会闲聊的模型还不是合格的客服。我们需要赋予它“超能力”——查询知识库、处理特定任务。同时,也要优化其中文表现。
3.1 为智能体添加自定义工具(函数)
工具(Tools)是智能体与外部世界交互的桥梁。在 ADK 中,任何 Python 函数都可以通过简单的装饰或配置,变成一个智能体可以调用的工具。
假设我们有一个简单的“产品知识库”,实际上可能是一个字典或一个小型数据库。我们创建一个函数来模拟查询过程。
在 agent.py 中,添加以下代码:
# 模拟一个简单的产品知识库
PRODUCT_KB = {
"subscription_plans": {
"basic": {"price": "$10/month", "features": ["10GB存储", "基础支持"]},
"pro": {"price": "$25/month", "features": ["100GB存储", "优先支持", "API访问"]},
"enterprise": {"price": "定制", "features": ["无限存储", "专属客户经理", "SLA保障"]}
},
"supported_os": ["Windows 10/11", "macOS 10.15+", "主流Linux发行版"],
"common_issues": {
"login_failure": "请尝试:1. 检查网络;2. 清除浏览器缓存;3. 重置密码。",
"upload_error": "通常是由于文件格式不支持或大小超限。请确保文件小于2GB,且为常见格式。"
}
}
def query_product_knowledge(topic: str, detail: str = None) -> str:
"""
查询产品知识库。
参数:
topic: 查询主题,如 'subscription_plans', 'supported_os', 'common_issues'
detail: 可选,查询具体项,如 'pro' (对于subscription_plans) 或 'login_failure'
返回:
查询到的信息字符串。
"""
try:
if topic not in PRODUCT_KB:
return f"抱歉,知识库中没有关于 '{topic}' 的主题信息。"
data = PRODUCT_KB[topic]
if detail:
if isinstance(data, dict) and detail in data:
result = data[detail]
if isinstance(result, dict):
# 格式化返回,例如套餐详情
features = ", ".join(result.get('features', []))
return f"{detail} 套餐:价格 {result.get('price', 'N/A')},包含功能:{features}。"
else:
return f"{detail}: {result}"
else:
return f"在主题 '{topic}' 下未找到关于 '{detail}' 的详细信息。"
else:
# 返回整个主题的摘要
if isinstance(data, dict):
return f"关于 {topic},我们有:{', '.join(data.keys())}。请告诉我你想了解的具体项。"
elif isinstance(data, list):
return f"支持的操作系统包括:{', '.join(data)}。"
else:
return str(data)
except Exception as e:
return f"查询知识库时出错:{str(e)}"
现在,我们需要修改 root_agent 的配置,将这个函数添加到 tools 列表中:
root_agent = LlmAgent(
model=LiteLlm(model="ollama/gemma:2b"),
name="local_customer_assistant",
description="一个运行在本地的、基于Gemma模型的客服助手原型,可以查询产品知识库。",
instruction=(
"你是一个专业的客服助手,负责回答用户关于产品使用、服务咨询和一般性问题。"
"请保持友好、耐心且专业的语气。"
"**重要**:当用户询问价格、套餐、功能、支持的系统或常见问题时,你必须使用 `query_product_knowledge` 工具来获取准确信息,然后基于信息组织回答。"
"如果你不知道答案,请诚实地告知用户,并建议他们通过其他渠道联系人工客服。"
"请用中文进行对话。"
),
# 将我们的函数作为工具添加进来
tools=[query_product_knowledge],
)
重启 adk web 服务,再次与智能体对话。现在尝试问:“你们的Pro套餐多少钱?包含什么功能?” 观察事件流(Event Stream),你应该能看到智能体识别了用户意图,调用了 query_product_knowledge 工具,并基于返回的结果生成了回答。
这个流程的威力在于:你将动态、结构化的数据查询能力赋予了大模型,而模型负责理解自然语言和组织回答。这是构建实用AI应用的核心模式。
3.2 攻克中文与上下文难题
在使用较小的本地模型时,你可能会遇到:
- “语言漂移”:聊着聊着又变回英文。
- “上下文健忘”:在多轮对话中忘记之前的约定或信息。
- “工具调用不稳定”:有时不调用工具直接胡编乱造。
这里有一些经过实践验证的调优技巧:
1. 强化系统提示词(Instruction) 不要只在开头说“请用中文”。在提示词中反复、多角度地强调语言和角色要求。可以尝试这样写:
instruction=(
"你是一个专业的、只说中文的客服助手。你的所有思考和回复都必须使用简体中文。"
"你的名字是‘小智’。"
"你的核心职责是帮助用户解决产品相关问题。"
"**工具使用规则**:当用户的问题涉及以下关键词时,你必须调用 `query_product_knowledge` 工具:'价格'、'套餐'、'多少钱'、'功能'、'支持'、'系统'、'操作系统'、'问题'、'错误'、'登录'、'上传'。调用工具后,严格依据工具返回的事实信息进行回答,不得编造。"
"**对话风格**:亲切、简洁、直接。每次回答尽量控制在3句话以内。如果工具返回的信息不足以回答问题,请告知用户并引导他们提供更多细节或联系人工客服。"
"现在,开始与用户对话吧。"
)
2. 利用会话状态(Session State)
ADK 内置了会话管理。虽然对于基础 LlmAgent 是自动的,但了解其原理有助于调试。模型在每次调用时,都会接收到包含整个对话历史的上下文。确保你的 Ollama 模型支持足够长的上下文长度(Gemma 2B 可能只有 4K token)。对于更长的对话,你可能需要考虑启用 ADK 的上下文压缩或总结功能。
3. 考虑升级模型 如果经过大量提示词优化后,Gemma 2B 的表现仍不理想,这是硬件和模型能力本身的限制。可以考虑:
- 升级到 Gemma 7B(需要更多内存)。
- 尝试专门为中文优化的模型,如 Qwen2.5-1.5B/7B(同样可通过 Ollama 获取:
ollama pull qwen2.5:7b),并在model参数中改为ollama/qwen2.5:7b。
更换模型后,你可能会立刻感受到中文理解、遵循指令和调用工具能力的显著提升。这往往是性价比最高的优化手段。
4. 构建多阶段客服工作流
一个成熟的客服流程往往不是一问一答那么简单。它可能包含:问题分类 -> 信息查询 -> 答案组织 -> 必要时升级或确认。ADK 的 SequentialAgent(顺序智能体)非常适合编排这样的多阶段工作流。
让我们构建一个稍微复杂一点的客服流水线:
from google.adk.agents.sequential_agent import SequentialAgent
from google.adk.agents.llm_agent import LlmAgent
from google.adk.models.lite_llm import LiteLlm
# 共享的模型配置
local_model = LiteLlm(model="ollama/qwen2.5:7b") # 假设我们升级到了Qwen
# **阶段1:问题分类器**
classifier_agent = LlmAgent(
name="QuestionClassifier",
model=local_model,
instruction=(
"分析用户输入,判断问题类型。只输出一个类型标签,不要任何其他文字。"
"可选标签:"
"1. `product_info` - 询问产品功能、价格、套餐等。"
"2. `technical_support` - 遇到使用错误、无法登录等技术问题。"
"3. `general_query` - 一般性咨询,如营业时间、联系方式。"
"4. `complaint` - 用户投诉或不满。"
),
output_key="question_type" # 将输出存储到会话状态中
)
# **阶段2:信息检索员** (根据不同类型使用不同工具或策略)
# 这里我们创建一个统一的检索员,但在实际中可以为不同类型配置不同的子智能体
retriever_agent = LlmAgent(
name="InfoRetriever",
model=local_model,
instruction=(
"根据会话状态中的 `question_type` 和用户原始问题,调用合适的工具获取信息。"
"如果类型是 `product_info`,调用 `query_product_knowledge`。"
"如果类型是 `technical_support`,首先尝试从知识库查询,如果没有,则生成标准排查建议。"
"其他类型,根据常识和公司政策生成初步回复框架。"
"输出格式:'检索结果:[这里放获取到的信息或生成的框架]'"
),
tools=[query_product_knowledge], # 可以添加更多工具,如搜索网络、查询工单系统
output_key="retrieved_info"
)
# **阶段3:回答生成器**
response_agent = LlmAgent(
name="ResponseGenerator",
model=local_model,
instruction=(
"你是一名专业的客服代表。"
"请结合以下信息,生成最终给用户的回复:"
"1. 用户原始问题。"
"2. 问题类型 (`question_type`)。"
"3. 检索到的信息 (`retrieved_info`)。"
"要求:回复必须友好、专业、简洁、有用,并使用中文。如果信息不足,请引导用户提供更多细节或转人工。"
),
output_key="final_response"
)
# **用 SequentialAgent 串联起整个流水线**
customer_service_pipeline = SequentialAgent(
name="CustomerServicePipeline",
sub_agents=[classifier_agent, retriever_agent, response_agent]
)
# **最终的根智能体,将流水线作为其子智能体**
root_agent = LlmAgent(
name="EnhancedCustomerAssistant",
model=local_model,
instruction="你是最终的客服助手接口。将用户问题交给内部流水线处理,并将流水线的最终结果返回给用户。",
sub_agents=[customer_service_pipeline]
)
这个架构的优势在于:
- 模块化:每个智能体职责单一,易于单独测试和优化。
- 可控性强:你可以精确控制每个阶段的输入输出,例如,确保分类阶段不会胡编乱造类型。
- 可观测性:在 ADK 的 Web 事件流中,你可以清晰地看到问题如何流经分类 -> 检索 -> 生成三个阶段,每个阶段的输入输出是什么,极大方便了调试。
要使用这个流水线,你只需像之前一样运行 adk web,然后与 EnhancedCustomerAssistant 对话。你会发现,对于复杂问题,它的处理流程更加结构化,回答的准确性和专业性也更有保障。
5. 部署考量与进阶路线
当你有了一个运行良好的本地原型后,可能会考虑下一步:如何让它更稳定、更强大,甚至部署到生产环境?
5.1 性能与稳定性优化
- 模型服务化:Ollama 默认运行在开发模式。对于更稳定的服务,可以考虑将模型部署到更专业的推理服务器上,如 vLLM 或 TGI,它们能提供更高的吞吐量、更低的延迟和更好的并发支持。然后让 ADK 通过 LiteLLM 连接到这个新的 API 端点。
- 记忆与状态持久化:ADK 默认使用内存存储会话。对于需要长期记忆或重启后恢复的场景,你需要实现自定义的
SessionService和ArtifactService,将会话数据保存到数据库(如 Redis、PostgreSQL)中。 - 评估与监控:ADK 内置了评估框架。你可以创建一组测试用例(例如,100个典型的客服问题),定期运行评估,监控智能体回答的质量、工具调用准确率等指标,确保其表现不会随着迭代而下降。
5.2 集成外部能力(MCP协议)
客服系统经常需要连接外部数据源:CRM、订单系统、内部Wiki等。手动为每个系统编写API调用工具很繁琐。这时,Model Context Protocol (MCP) 就派上用场了。
MCP 是一种标准协议,允许各种数据源(如数据库、文件系统、Notion、GitHub)以统一的方式向AI模型暴露“工具”。ADK 原生支持 MCP。这意味着你可以直接使用社区里现成的 MCP 服务器,快速让你的客服智能体获得查询数据库、读取文件等能力,而无需编写大量胶水代码。
例如,你可以运行一个连接公司 PostgreSQL 数据库的 MCP 服务器,然后在 ADK 智能体中配置使用它,你的客服就能直接回答“用户XXX的最新订单状态是什么?”这类具体问题了。
5.3 从本地原型到可部署服务
ADK 应用本质上是一个 Python 应用。你可以很容易地将其容器化:
# Dockerfile 示例
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["adk", "api-server", "--host", "0.0.0.0", "--port", "8000"]
然后使用 Docker Compose 或 Kubernetes 进行部署,同时将 Ollama 或其他模型服务作为另一个容器运行。对于生产环境,谷歌也提供了将 ADK 智能体直接部署到 Google Cloud Vertex AI Agent Engine 的选项,可以获得完全托管的、可扩展的运行环境。
回过头看,我们从一行命令安装 Ollama 开始,到构建出一个具备知识库查询能力、结构化工作流的本地AI客服原型,整个过程的核心在于 ADK 对复杂性的封装 和 Ollama 对本地模型运行的简化。这套组合拳让开发者能快速越过基础设施的障碍,直接聚焦在创造有价值的智能体逻辑上。
本地模型的能力边界正在快速扩展,而像 ADK 这样的框架正在大幅降低智能体应用的开发门槛。今天搭建的这个客服系统,虽然简单,但已经包含了智能体技术的核心要素:模型调用、工具使用、工作流编排。你可以以此为起点,不断融入更强大的模型、更丰富的工具、更复杂的业务逻辑,最终打造出真正能解决实际问题的AI助手。
更多推荐

所有评论(0)