说实话,搭 AI Agent 这事我折腾了大半年。从最开始用 OpenAI API 烧钱,到现在整套方案月均花费不到 50 块,踩了不少坑。今天把我的方案摊开来聊聊,给想入门的朋友一个参考。
我的结论先说
搭一个能用的 AI Agent,核心就三件事:选便宜够用的模型、写靠谱的 Tool 调用逻辑、控制好 Token 消耗。这三件事搞定了,Agent 就能跑起来;搞不定,再花哨的架构也是白搭。其他的什么向量数据库、记忆系统,都是锦上添花,别一上来就搞。
我现在的技术栈:Python + 一个开源 Agent 框架 + 国产模型。日常跑任务够用,月费控制在 50 以内。
模型选择:别上来就 GPT-4
很多人搭 Agent 第一步就是接 GPT-4,然后发现跑几次任务就几十块没了。说实话,80% 的 Agent 任务根本用不着那么强的模型。
我的方案是分级调用:
- 简单任务(格式转换、数据提取):用最便宜的模型,比如 DeepSeek-V3 或者智谱的 GLM-4-Flash,千 token 才几分钱
- 中等任务(代码生成、文案撰写):DeepSeek-V3 或 Qwen-Plus,性价比很高
- 复杂推理(多步规划、debug):才上 DeepSeek-R1 或 Claude,但这种情况其实不多
python
# 我的模型路由逻辑,简单粗暴但管用
MODEL_ROUTER = {
"simple": "glm-4-flash", # 几乎免费
"medium": "deepseek-v3", # 性价比之王
"complex": "deepseek-r1", # 重炮,偶尔用
}
def pick_model(task_type: str, token_estimate: int) -> str:
"""根据任务类型和预估token选模型"""
if task_type in ["extract", "format", "classify"]:
return MODEL_ROUTER["simple"]
if token_estimate > 8000: # 长文本走便宜模型
return MODEL_ROUTER["medium"]
return MODEL_ROUTER.get(task_type, MODEL_ROUTER["medium"])
老实讲,这个路由逻辑不完美,但省了我大概 70% 的 API 费用。关键是简单------复杂了你自己都维护不动。
Tool 调用:Agent 的灵魂
Agent 和普通 Chatbot 的区别就在 Tool 调用。模型要能理解"什么时候该调工具"和"怎么传参数"。
我踩过最大的坑:模型瞎调工具。明明不需要搜索,它非要调;参数格式不对,它反复重试然后死循环。
解决方案:
python
# 在 system prompt 里明确约束工具使用
TOOL_PROMPT = """
你可以使用以下工具:
- search_web: 搜索互联网信息。只在需要实时数据时使用。
- read_file: 读取文件。只在需要查看文件内容时使用。
- run_code: 执行代码。只在需要计算或验证时使用。
规则:
1. 每次只调用一个工具,等结果再决定下一步
2. 如果已有信息足够回答,不要调工具
3. 连续失败2次就停止,告诉用户出了什么问题
"""
这段 prompt 看起来简单,但解决了 80% 的"工具滥用"问题。剩下的 20% 得靠模型本身的能力,所以选一个工具调用能力好的模型很重要------DeepSeek-V3 在这方面表现不错。
Token 消耗控制:省钱的关键
Agent 跑着跑着 Token 就爆了,这是最常见的"暗坑"。几个实操技巧:
1. 压缩上下文
每次调用模型前,把之前的对话历史做个摘要,别全塞进去。
python
def compress_history(messages: list, max_rounds: int = 5) -> list:
"""只保留最近几轮对话,更早的做摘要"""
if len(messages) <= max_rounds * 2:
return messages
# 保留 system prompt + 最近几轮
system_msg = messages[0]
recent = messages[-(max_rounds * 2):]
# 中间的历史做一句话摘要
summary = f"[之前{len(messages)//2}轮对话的摘要: {generate_summary(messages[1:-(max_rounds*2)])}]"
return [system_msg, {"role": "system", "content": summary}] + recent
2. 设 Token 上限
每个任务设一个 Token 预算,超了就强制停止。
python
MAX_TOKENS_PER_TASK = 15000 # 单任务上限
def check_budget(used_tokens: int) -> bool:
if used_tokens >= MAX_TOKENS_PER_TASK:
print(f"Token 预算用完了 ({used_tokens}/{MAX_TOKENS_PER_TASK})")
return False
return True
3. 缓存重复结果
同一个搜索结果或文件内容,别反复读。用个简单的字典缓存就行。
python
_result_cache = {}
def cached_tool_call(tool_name: str, params: dict):
key = f"{tool_name}:{json.dumps(params, sort_keys=True)}"
if key in _result_cache:
return _result_cache[key]
result = execute_tool(tool_name, params)
_result_cache[key] = result
return result
这三个小技巧加起来,Token 消耗能降 40-60%。不夸张,我自己实测的。
完整的最小可用方案
把上面的东西串起来,一个能跑的 Agent 核心代码其实很少:
python
class CheapAgent:
def __init__(self):
self.history = []
self.cache = {}
self.token_used = 0
def run(self, user_input: str, max_steps: int = 10):
self.history.append({"role": "user", "content": user_input})
for step in range(max_steps):
# 1. 压缩历史
messages = compress_history(self.history)
# 2. 选模型
model = pick_model(
task_type=self._detect_task_type(user_input),
token_estimate=self._estimate_tokens(messages)
)
# 3. 调用模型
response = call_llm(model, messages)
self.token_used += count_tokens(response)
# 4. 检查预算
if not check_budget(self.token_used):
return "任务太复杂,Token 预算用完了。试试拆分成小任务?"
# 5. 处理工具调用
if response.has_tool_call:
tool_result = cached_tool_call(
response.tool_name,
response.tool_params
)
self.history.append(response.to_message())
self.history.append({"role": "tool", "content": tool_result})
else:
return response.content
return "步数用完了还没搞定,可能需要简化任务。"
不过这个只是骨架,真要跑起来还得加错误处理、重试逻辑这些。但核心思路就是这样------简单、省钱、够用。
踩坑总结
最后列几个我踩过的坑,希望你别再踩:
坑1: 过度设计。 一上来就搞 RAG、向量数据库、长期记忆......结果两个月都没跑起来。先让它能跑,再慢慢加功能。
坑2: 模型切换太频繁。 什么任务都想试新模型,反而增加了不稳定性。固定 2-3 个模型轮着用就够了。
坑3: 忽略 Prompt 调优。 同样的模型,Prompt 写得好不好,效果差 10 倍。花时间打磨 System Prompt 比换模型划算。
坑4: 不做成本监控。 Agent 跑着跑着钱就没了,建议每天看一眼 API 用量,设个日限额。
坑5: 工具返回结果太长。 比如搜索 API 返回一大堆内容,塞进上下文瞬间爆 Token。工具返回的结果要做截断和摘要。
我的方案不一定最优,但确实在"能用"和"省钱"之间找到了平衡点。如果你也想搭 Agent,建议先从最小方案开始,别追求大而全。跑起来了再优化,比永远在设计中强。
有啥问题评论区聊,我知道的都告诉你。