声明:本文部分内容使用AI辅助生成,经人工编辑、审核和补充个人经验。
更新说明:本文最后更新于 2026-05-08。
AI Agent开发实战踩坑记录
折腾AI Agent半年多,从最简单的单Agent工具调用到复杂的多Agent协作系统,踩过的坑够写本书。记录一下开发过程中的问题和解决方案。
Agent架构选型
框架对比踩坑
开始选框架时就纠结,试了LangChain、AutoGen、MetaGPT、CrewAI…每个都说自己最牛逼。
实际项目用下来:
| 框架 |
学习曲线 |
灵活性 |
社区生态 |
生产就绪 |
适用场景 |
| LangChain |
中等 |
高 |
丰富 |
成熟 |
通用Agent |
| AutoGen |
陡峭 |
中 |
一般 |
较新 |
多Agent对话 |
| MetaGPT |
陡峭 |
低 |
弱 |
实验性 |
软件开发 |
| CrewAI |
平缓 |
中 |
增长中 |
较新 |
工作流编排 |
最终选择:LangChain做底层+AutoGen做多Agent协作。原因:LangChain生态最全,工具多;AutoGen多Agent对话模型比较成熟。
LangChain版本混乱
LangChain版本更新快,0.1到0.2 breaking changes一大堆。
1 2 3 4 5 6
| from langchain import OpenAI, LLMChain
from langchain_openai import ChatOpenAI from langchain.chains import LLMChain
|
迁移血泪史:
langchain.chat_models → langchain_community.chat_models
langchain.llms → langchain_community.llms
- 很多类名改了,文档又跟不上
建议:新项目直接用0.2+,旧项目别轻易升级。
工具调用踩坑
工具定义格式
LangChain的 tool decorator 看起来简单,实际坑多:
1 2 3 4 5
| @tool def search_product(name: str) -> str: """搜索商品""" return f"搜索结果: {name}"
|
LLM根本不知道怎么用这个工具,name应该传什么。
正确做法:详细描述每个参数:
1 2 3 4 5 6 7
| @tool def search_product( name: str = Field(description="商品名称,如'iPhone 15'、'MacBook Pro'") ) -> str: """在电商平台搜索商品信息,返回价格、库存、评价等信息""" return search_in_db(name)
|
工具选择问题
定义了10个工具,Agent每次都选错,或者一次调用多个无关工具。
问题根源:工具描述不够区分度。
解决方案:
- 工具描述要突出区别
1 2 3 4 5 6 7 8 9
| @tool def search_product(query: str) -> str: """当用户想买东西、查价格、比价格时使用。搜索商品信息。""" pass
@tool def track_order(order_id: str) -> str: """当用户问'我的订单在哪'、'快递到哪了'时使用。查询物流信息。""" pass
|
- 限制一次最多调用工具数
1 2 3 4 5 6 7 8
| from langchain.agents import AgentExecutor
agent_executor = AgentExecutor( agent=agent, tools=tools, max_iterations=5, max_execution_time=30, )
|
工具返回值处理
工具返回的数据格式不对,Agent理解不了。
1 2 3 4 5 6 7 8 9 10 11
| @tool def get_weather(city: str) -> str: result = api_call(city) return json.dumps(result)
@tool def get_weather(city: str) -> str: result = api_call(city) return f"{city}今天{result['weather']},温度{result['temp']}度,{result['wind']}风。"
|
Agent记忆管理
短记忆vs长记忆
默认的ConversationBufferMemory会把所有对话都塞给LLM,token爆炸。
1 2 3 4 5
| from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory()
|
解决方案1:窗口记忆
1 2 3 4
| from langchain.memory import ConversationBufferWindowMemory
memory = ConversationBufferWindowMemory(k=5)
|
解决方案2:向量记忆(长时记忆)
1 2 3 4 5 6 7
| from langchain.memory import VectorStoreRetrieverMemory
retriever = Chroma(...).as_retriever() memory = VectorStoreRetrieverMemory(retriever=retriever)
|
记忆总结
更好的方案是定期总结对话:
1 2 3 4 5 6 7 8 9 10
| from langchain.memory import ConversationSummaryMemory from langchain_openai import ChatOpenAI
memory = ConversationSummaryMemory( llm=ChatOpenAI(temperature=0), max_token_limit=1000 )
|
坑:总结用的小模型效果不好,大模型又贵。
折中方案:Entity Memory,只提取关键实体:
1 2 3 4
| from langchain.memory import ConversationEntityMemory
memory = ConversationEntityMemory(llm=llm)
|
ReAct模式详解
Thought-Action-Observation循环
ReAct是Agent的核心模式,但实现细节坑多。
1 2 3
| from langchain.agents import create_react_agent
agent = create_react_agent(llm, tools, prompt)
|
坑1:Thought格式不对
LLM输出的Thought必须严格按格式,否则解析失败。
1 2 3 4 5 6 7 8 9
| # 正确的Thought格式 Thought: 用户想知道北京天气,我需要调用天气工具。 Action: get_weather Action Input: {"city": "北京"}
# 错误的格式(会被解析失败) Thought: 调用天气API Action:get_weather Action Input:{city: "北京"}
|
解决方案:用结构化输出:
1 2 3 4 5 6 7 8
| from langchain.output_parsers import StructuredOutputParser
parser = StructuredOutputParser.from_response_schemas([ ResponseSchema(name="thought", description="思考过程"), ResponseSchema(name="action", description="要执行的动作"), ResponseSchema(name="action_input", description="动作参数") ])
|
Observation处理
工具返回的结果,LLM可能理解不了或者误解。
案例:搜索工具返回”iPhone 15价格5999元起”
LLM理解:
- 正确:iPhone 15售价5999元
- 错误:所有iPhone都是5999元
解决方案:Observation加说明
1 2 3 4
| @tool def search_price(product: str) -> str: result = api.search(product) return f"【注意:这只是参考价,实际价格以官网为准】{result}"
|
多Agent协作
AutoGen多Agent配置
用AutoGen做多Agent,配置复杂度高。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| from autogen import ConversableAgent, GroupChat
planner = ConversableAgent( name="planner", system_message="你是任务规划专家...", llm_config={"config_list": config_list} )
coder = ConversableAgent( name="coder", system_message="你是Python开发专家...", llm_config={"config_list": config_list} )
reviewer = ConversableAgent( name="reviewer", system_message="你是代码审查专家...", llm_config={"config_list": config_list} )
groupchat = GroupChat( agents=[planner, coder, reviewer], messages=[], max_round=10 )
|
坑1:Agent循环对话
两个Agent互相踢皮球,永远结束不了:
1 2 3 4 5
| Agent A: 我觉得应该用方案1 Agent B: 我不同意,方案2更好 Agent A: 还是方案1吧 Agent B: 坚持方案2 ...(无限循环)
|
解决方案:
- 设置max_round限制
- 加终结Agent判断何时停止
- 用function call强制结束
1 2 3 4 5 6 7
| def terminate_chat(message): if "TERMINATE" in message: return True return False
coder.system_message += "如果代码已完成,回复'TERMINATE'结束对话。"
|
坑2:信息传递丢失
多Agent传递信息时,关键细节丢失。
案例:Planner说”实现登录功能”,Coder不知道要支持微信登录还是密码登录。
解决方案:结构化消息传递
1 2 3 4 5 6
| plan = { "task": "实现登录功能", "requirements": ["支持微信扫码", "支持手机号+验证码"], "constraints": ["不使用密码", "JWT Token有效期24小时"] }
|
人机协作
复杂任务需要人类介入审核。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from autogen import UserProxyAgent
user_proxy = UserProxyAgent( name="user", human_input_mode="ALWAYS", code_execution_config=False )
user_proxy = UserProxyAgent( name="user", human_input_mode="TERMINAL", is_termination_msg=lambda msg: "请审核" in msg["content"] )
|
实际项目部署
异步处理
Agent执行慢,同步API会超时。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from fastapi import FastAPI from celery import Celery
app = FastAPI() celery_app = Celery('agent', broker='redis://localhost:6379')
@celery_app.task def run_agent_task(query: str): """后台执行Agent任务""" result = agent_executor.invoke({"input": query}) return result
@app.post("/agent") async def agent_endpoint(request: QueryRequest): task = run_agent_task.delay(request.query) return {"task_id": task.id, "status": "processing"}
@app.get("/agent/{task_id}") async def get_result(task_id: str): task = run_agent_task.AsyncResult(task_id) return {"status": task.status, "result": task.result}
|
并发控制
多个用户同时调用,LLM API限流或OOM。
解决方案:信号量控制并发
1 2 3 4 5 6 7 8 9
| import asyncio from asyncio import Semaphore
semaphore = Semaphore(3)
async def limited_agent_run(query: str): async with semaphore: return await agent_executor.ainvoke({"input": query})
|
成本优化
Agent多次调用LLM,费用爆炸。
实测数据:
- 简单查询:平均3次LLM调用,$0.015/次
- 复杂任务:平均15次调用,$0.075/次
- 1000次复杂任务 = $75
优化方案:
- 缓存常见查询
1 2 3 4 5 6
| from langchain.cache import InMemoryCache import langchain
langchain.llm_cache = InMemoryCache()
|
- 分级模型策略
1 2 3 4 5
| def smart_llm_call(prompt: str, complexity: str): if complexity == "simple": return cheap_model.invoke(prompt) else: return expensive_model.invoke(prompt)
|
- 本地模型兜底
1 2 3 4 5
| try: result = openai_model.invoke(prompt) except RateLimitError: result = local_llm.invoke(prompt)
|
调试技巧
LangSmith追踪
LangSmith是调试Agent的神器,但配置麻烦。
1 2 3 4 5 6
| import os os.environ["LANGCHAIN_TRACING_V2"] = "true" os.environ["LANGCHAIN_API_KEY"] = "your-api-key" os.environ["LANGCHAIN_PROJECT"] = "agent-debug"
|
能追踪的信息:
- 每次LLM调用的输入输出
- 工具调用详情
- Token使用量
- 延迟时间
日志记录
生产环境必须记录详细日志。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import logging
logger = logging.getLogger(__name__)
class LoggingAgent: def run(self, query: str): logger.info(f"Agent开始执行: {query}")
try: for step in self.agent_executor.iter(query): logger.debug(f"Step: {step}")
result = self.agent_executor.invoke(query) logger.info(f"Agent执行成功: {result}") return result
except Exception as e: logger.error(f"Agent执行失败: {e}", exc_info=True) raise
|
安全与权限
工具权限控制
Agent能调用敏感工具,必须控制权限。
1 2 3 4 5 6 7 8 9 10
| @tool def delete_database(): """危险!不能随便调用""" pass
def check_permission(user_id: str, tool_name: str): allowed_tools = get_user_permissions(user_id) if tool_name not in allowed_tools: raise PermissionError(f"用户{user_id}无权使用工具{tool_name}")
|
Prompt注入防护
用户可能通过Prompt让Agent执行恶意操作。
攻击示例:
防护方案:
1 2 3 4 5 6 7 8 9 10 11 12
| FORBIDDEN_WORDS = ["删除", "drop", "delete"]
def sanitize_input(user_input: str): for word in FORBIDDEN_WORDS: if word in user_input.lower(): raise ValueError("输入包含敏感词")
SAFE_SYSTEM_PROMPT = """你是助手,只能执行以下操作:... 严禁执行删除、修改等危险操作。 如果用户要求危险操作,拒绝并提醒。"""
|
性能优化
LLM调用优化
批量调用:
1 2 3 4 5
| results = [llm.invoke(q) for q in queries]
results = llm.batch(queries)
|
Streaming输出:
1 2 3
| async for chunk in llm.astream(prompt): yield chunk
|
总结
AI Agent开发的核心经验:
- 框架选择:LangChain+AutoGen组合目前最稳
- 工具设计:描述要详细,返回值要自然语言化
- 记忆管理:短记忆用Window,长记忆用向量数据库
- 多Agent:一定要设置终止条件和消息格式
- 成本控制:缓存+分级模型+本地兜底
踩坑最多的地方:
- LangChain版本breaking changes
- Agent循环调用不终止
- 工具描述不清晰导致选错
- 记忆管理不当token爆炸
- 没有权限控制的安全风险