微信扫码
添加专属顾问
我要投稿
从单Agent到多Agent架构的优化实践,Token消耗直降60%,代码更简洁高效! 核心内容: 1. 从单Agent多Tool到主Agent+多Sub-Agent的架构演进 2. 优化提示词与引入缓存带来的显著Token降幅 3. ADK框架相比LangChain的代码简洁优势与性能提升
在Agent:从零到一的实践指南(含关键代码)" data-itemshowtype="0" linktype="text" data-linktype="2">用 LangChain 打造你的第一个 AI Agent:从零到一的实践指南(含关键代码)这篇文章中,我用 LangChain实现了一个 AI Agent,结构是单主 Agent + 多个 Tool(如:DatabaseInfoTool
、TableSchemaTool
、QueryExecutorTool
、SampleDataTool
等)。后来我用 Google ADK把这个 Agent 重写了一遍,依旧沿用了“一个主 Agent 带多个 Tool”的思路。
在随后的分析中从ReAct流程看LangChain和Google ADK的Agent设计理念差异,我发现:在 ADK 框架中,单 Agent 多 Tool 的架构 Token 消耗偏高。于是我提出一个设计思路:ADK 更适合“主 Agent + 多个 Sub-Agent”的结构——每个 Sub-Agent 只包含一个 Tool,职责单一、边界清晰。
一、优化效果:立竿见影
我按这个思路把 ADK 架构改成了1 个主 Agent 负责调度,多个 Sub-Agent 负责执行,且每个 Sub-Agent 只绑定 1 个 Tool,严格遵守“单一职责”原则。
主要做了以下两方面的调整:
第一步(架构从单 Agent 多 Tool → 主 + 多 Sub-Agent):Token 立减约 35%。
第二步(在此基础上优化提示词 + 引入缓存):总降幅达到约 60%。
由于ADK 框架使用了 LLM 的原生能力(如工具筛选、Function Call等),所以在 Agent 的代码实现上确实更加的简洁。调整完成后,项目总代码量大约为 1800 行,比 LangChain 版本的体量小很多。
说明:上述降幅是在同一任务下统计的,统计口径一致(包括 prompt、function call等Agent和LLM之间交互的所有 token)。
之前:单 Agent 多 Tool
统一持有多个 Tool,路由调度集中在主 Agent 内部。
上下文容易“越滚越大”,无形增加 Token。
工具候选多时,模型在选择与澄清上会产生大量Token消耗,也容易造成额外的交互。
现在:主 Agent + 多 Sub-Agent(每个 Sub-Agent 仅 1 个 Tool)
主 Agent 只负责意图识别和任务分发。
Sub-Agent 处理单一职责,上下文短、交互简单。
路由清晰,减少无效澄清与工具试探。
为什么能省:
上下文更短:Sub-Agent 只携带本职所需的少量上下文与历史信息。
工具候选更少:每个 Sub-Agent 仅 1 个 Tool,减少工具选择带来的额外 token。
调度更“干脆”:主 Agent 明确路由,避免在一个 Agent 里多轮试错。
工具描述更精简:职责切分后,工具描述能够更加的精简,可以删除大量的冗长描述。
2. 项目结构
sqlite-multi-agent/├── sqlite_agent/ # 主要智能体代码│ ├── agent.py # 主智能体实现│ ├── config.py # 配置管理│ ├── tools.py # 工具函数│ ├── utils.py # 工具类│ ├── prompts.py # 提示词模板│ ├── monitored_llm.py # LLM监控包装器(LLM必须,监控为可选)│ └── sub_agents/ # 子智能体│ ├── list_tables/ # 表列表智能体│ ├── table_info/ # 表信息智能体│ ├── query_execution/ # 查询执行智能体│ └── sample_data/ # 样本数据智能体├── examples/ # 示例代码├── tests/ # 测试代码└── deployment/ # 部署脚本
def execute_query(query: str) -> str:
"""Execute a SELECT query on the SQLite database. Use for data retrieval, filtering, aggregation, and analysis. Only SELECT queries are allowed."""
config = get_sqlite_config()
# Validate query for safety
validation_result = validate_query(query)
if not validation_result["valid"]:
return f"Query validation failed: {validation_result['error']}"
try:
with get_database_connection(config.database_path) as conn:
cursor = conn.cursor()
cursor.execute(query)
# Get column names
columns = [description[0] for description in cursor.description] if cursor.description else []
# Fetch results with limit
results = cursor.fetchmany(config.max_results)
if not results:
return "Query executed successfully but returned no results."
# Format results
return format_results(results, columns, config.max_results)
except Exception as e:
return f"Error executing query: {str(e)}"
# Create ADK function tools
list_tables_tool = FunctionTool(list_tables)
get_table_info_tool = FunctionTool(get_table_info)
execute_query_tool = FunctionTool(execute_query)
get_sample_data_tool = FunctionTool(get_sample_data)
# Export all tools
sqlite_tools = [
list_tables_tool,
get_table_info_tool,
execute_query_tool,
get_sample_data_tool
]
结果格式化:
def format_results(results: List[Any], columns: List[str], max_results: int) -> str:
"""Format query results for display."""
if not results:
return "No results found."
# Convert results to list of lists for tabulate
formatted_rows = []
for row in results:
if hasattr(row, '_fields'): # sqlite3.Row object
formatted_rows.append([str(value) if value is not None else 'NULL' for value in row])
else:
formatted_rows.append([str(value) if value is not None else 'NULL' for value in row])
# Create table
table = tabulate(formatted_rows, headers=columns, tablefmt="grid")
result = f"Query Results ({len(results)} rows):\n\n{table}"
# Add warning if results were limited
if len(results) >= max_results:
result += f"\n\n⚠️ Results limited to {max_results} rows. Use LIMIT clause for more control."
return result
import os
from typing import Optional
from datetime import datetime
from google.adk.agents import Agent
from google.adk.agents.callback_context import CallbackContext
from google.adk.models.lite_llm import LiteLlm
from google.adk.tools.agent_tool import AgentTool
from google.genai import types
from .config import get_sqlite_config, get_model_name, get_DeepSeek_api_key
from .prompts import get_sqlite_agent_instructions
from .utils import create_sample_database, get_database_connection
from .sub_agents import (
list_tables,
table_info,
query_execution,
sample_data
)
from .monitored_llm import create_monitored_llm
# 创建多Agent协调的SQLite Agentsqlite_agent = Agent( name="sqlite_agent", model=create_monitored_llm(model=get_model_name()), description="SQLite数据库助手,通过协调多个专门的子agent来完成数据库操作", instruction=get_sqlite_agent_instructions, sub_agents=[ list_tables, table_info, query_execution, sample_data, ], before_agent_callback=setup_database, generate_content_config=types.GenerateContentConfig( safety_settings=[ types.SafetySetting( category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, ), ], temperature=0.1, top_p=0.8, max_output_tokens=2048, ),)
def get_sqlite_agent_instructions(ctx) -> str: """Get the main instructions for the SQLite agent.""" return f"""你是专业的SQLite数据库助手,通过协调专门的子agent来高效完成数据库操作。## 核心职责- 分析用户意图,精准选择最合适的agent- 确保查询结果准确、格式清晰- 主动识别潜在需求,提供相关建议## 可用agent选择指南### list_tables - 表发现**用途**:当用户询问"有哪些表"、"显示所有表"、"查看数据库结构"时使用**关键词**:表、列表、所有、结构、数据库### table_info - 表结构分析 **用途**:当用户询问"表结构"、"字段信息"、"列信息"、"schema"时使用**关键词**:结构、字段、列、schema、信息、详情### query_execution - 数据查询**用途**:当用户需要执行具体查询、分析数据、筛选记录时使用**关键词**:查询、查找、统计、分析、最贵、最新、数量、总和### sample_data - 样本数据**用途**:当用户想"看看数据"、"预览内容"、"示例数据"时使用**关键词**:看看、样本、示例、预览、数据## 智能选择策略1. **探索阶段**:用户首次接触数据库 → list_tables2. **结构了解**:用户想了解特定表 → table_info 3. **数据分析**:用户有具体查询需求 → query_execution4. **快速预览**:用户想快速了解数据 → sample_data## 响应要求- 直接调用agent,不解释选择过程- 确保结果对用户可见- 中文问题用中文回答- 表格数据用清晰格式展示当前数据库表:{', '.join(ctx.state.get('available_tables', []))}"""
"""Query execution agent - specialized agent for executing SQL queries."""from google.adk.agents import Agentfrom google.genai import typesfrom ...config import get_model_namefrom ...tools import execute_query_tool, get_table_info_toolfrom ...monitored_llm import create_monitored_llmfrom .prompt import QUERY_EXECUTION_AGENT_INSTRquery_execution = Agent( name="query_execution", model=create_monitored_llm(model=get_model_name()), description="专门负责执行SQLite数据库查询的agent,遵循单一职责原则", instruction=QUERY_EXECUTION_AGENT_INSTR, tools=[execute_query_tool], # 仅执行查询,避免多余表结构查询 disallow_transfer_to_parent=True, disallow_transfer_to_peers=True, generate_content_config=types.GenerateContentConfig( temperature=0.1, top_p=0.8, max_output_tokens=2048, ),)
"""Query execution agent - specialized agent for executing SQL queries."""from google.adk.agents import Agentfrom google.genai import typesfrom ...config import get_model_namefrom ...tools import execute_query_tool, get_table_info_toolfrom ...monitored_llm import create_monitored_llmfrom .prompt import QUERY_EXECUTION_AGENT_INSTRquery_execution = Agent( name="query_execution", model=create_monitored_llm(model=get_model_name()), description="专门负责执行SQLite数据库查询的agent,遵循单一职责原则", instruction=QUERY_EXECUTION_AGENT_INSTR, tools=[execute_query_tool], # 仅执行查询,避免多余表结构查询 disallow_transfer_to_parent=True, disallow_transfer_to_peers=True, generate_content_config=types.GenerateContentConfig( temperature=0.1, top_p=0.8, max_output_tokens=2048, ),)
"""Prompts for the query execution agent."""QUERY_EXECUTION_AGENT_INSTR = """执行SQL查询专家。直接执行查询并返回结果给用户。**使用execute_query工具:**- 将用户问题直接转换为SQL查询- 例如:"最贵的订单" → "SELECT * FROM orders ORDER BY total_amount DESC LIMIT 1"- 例如:"最新用户" → "SELECT * FROM users ORDER BY created_at DESC LIMIT 1"**输出格式:**```sql[实际SQL]```[查询结果表格]统计:X条记录**规则:**- 仅执行SELECT查询- 直接回答,不解释过程"""
def create_monitored_llm(model: str, **kwargs) -> LiteLlm: """创建带监控功能的LLM实例""" return LiteLlm(model=model, **kwargs)
先确定设计原则:单 Agent 多 Tool vs 主 + 多 Sub-Agent。
子 Agent 职责切到最小:每个 Sub-Agent 只干一件事。
主 Agent 只负责调度:主 Agent 只做意图识别与任务分发。
精简系统提示:优化 Sub-Agent 提示词,不要背不必要的上下文。
逐步优化 Token:深入分析 Token 的损耗点,逐步进行优化。
把架构从“单 Agent 多 Tool”切到“主 Agent + 多个单一职责的 Sub-Agent”,再配合提示词精简,我的 Token 消耗最终降到了原来的约 40%。这次改造对工程复杂度的增加可控,重构后的代码结构更加合理,而且对成本和吞吐的改善非常可观。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-08-30
大模型的“思维链”(Chain-of-Thought):AI 是怎么一步步“推理”的
2025-08-30
Agentic AI与WorkFlow的相互成就
2025-08-29
刚刚,xAI 发布 Grok Code Fast 1 编程模型,快、便宜、免费
2025-08-29
大模型时代有了自己的「价值高速公路」
2025-08-29
A I智能革命——上下文工程新突破
2025-08-29
知识库检索准不准,关键看模型选没选对!一份评测指南请收好
2025-08-29
我如何用Prompt工程将大模型调教成风控专家
2025-08-29
度小满金融大模型技术创新与应用探索
2025-08-21
2025-06-21
2025-08-21
2025-08-19
2025-06-07
2025-06-12
2025-06-19
2025-06-13
2025-07-29
2025-06-15
2025-08-28
2025-08-28
2025-08-28
2025-08-28
2025-08-27
2025-08-26
2025-08-25
2025-08-25