4.1 Agent基础与createagent — LangChain框架精通 智能体入门 本节导读:学完本节,你将理解 LangChain 中 Agent 的核心定义——"Agent = Model + Harness",掌握 createagent 的全部核心参数,并能独立创建一个具备多工具调用能力的生产级 Agent。 学习目标 理解 Agent 的核心循环机制:模型推理 → 工具调用 → 结果反馈 → 继续推理 掌握 createagent 的模型选择、工具注册、系统提示词三大核心参数 能够使用 LangChain Agent 构建一个具备搜索、计算、文件操作能力的多工具 Agent 理解 Agent 的调用方式(invoke / stream / astream)和会话持久化机制
本节导读:学完本节,你将理解 LangChain 中 Agent 的核心定义——"Agent = Model + Harness",掌握 create_agent 的全部核心参数,并能独立创建一个具备多工具调用能力的生产级 Agent。
在 LangChain 的设计哲学中,Agent 的定义极其简洁:Agent = Model + Harness。
模型(Model)负责理解和推理,Harness(套具)负责围绕模型构建完整的工作循环。这个循环的核心逻辑是:模型接收用户输入,决定是否需要调用工具,执行工具后将结果反馈给模型,模型继续推理,直到任务完成。
这个循环就是 Agent 的本质。LangChain 的 create_agent 函数提供的正是一个高度可配置的 Harness,它把这个循环的所有细节(提示词构建、工具格式化、结果解析、循环控制)都封装好了,你只需要告诉它三个核心要素:用哪个模型、给哪些工具、设定什么系统提示词。
Harness 不是铁板一块,它由多个可插拔的层次组成:
这种分层设计的好处是:你可以按需组合。简单场景只需要 model + tools + system_prompt 三个参数;复杂场景再逐步添加中间件、结构化输出、持久化等能力。
本节基于 LangChain 最新版本编写。在开始之前,确保你已经完成以下准备:
# 安装 LangChain 核心包和 OpenAI 集成 pip install -qU langchain "langchain[openai]" # 如果你使用其他模型提供商 pip install -qU "langchain[anthropic]" # Anthropic Claude pip install -qU "langchain[google-genai]" # Google Gemini # 设置 API Key export OPENAI_API_KEY="your-api-key-here"
前置知识要求:
我们从最简单的 Agent 开始——只有一个工具、一个模型,但它是完整可运行的。
from langchain.agents import create_agent # 定义一个简单的工具函数 def get_weather(city: str) -> str: """获取指定城市的天气信息。 Args: city: 城市名称 """ # 实际场景中这里会调用天气 API weather_data = { "北京": "晴天,温度 28°C,湿度 45%", "上海": "多云,温度 31°C,湿度 72%", "深圳": "阵雨,温度 29°C,湿度 85%", } return weather_data.get(city, f"{city}的天气数据暂不可用") # 创建 Agent —— 只需三行核心代码 agent = create_agent( model="openai:gpt-4o-mini", # 模型选择:provider:model 格式 tools=[get_weather], # 工具列表 system_prompt="你是一个天气查询助手,根据用户问题查询天气并给出建议。", ) # 调用 Agent result = agent.invoke( {"messages": [{"role": "user", "content": "北京今天天气怎么样?适合出门吗?"}]} ) # 打印最终回复 print(result["messages"][-1].content)
这段代码的执行过程是这样的:
关键点:你不需要手动写循环代码,create_agent 已经把整个"推理→调用→反馈"的循环封装好了。这就是 Harness 的价值。
真实的 Agent 通常需要多个工具。我们给 Agent 添加计算能力和搜索能力:
from langchain.tools import tool # 工具 1:天气查询(复用上面的) def get_weather(city: str) -> str: """获取指定城市的天气信息。""" weather_data = { "北京": "晴天,温度 28°C,湿度 45%", "上海": "多云,温度 31°C,湿度 72%", "深圳": "阵雨,温度 29°C,湿度 85%", } return weather_data.get(city, f"{city}的天气数据暂不可用") # 工具 2:计算器(使用 @tool 装饰器定义) @tool def calculate(expression: str) -> str: """执行数学计算。 Args: expression: 数学表达式,例如 "2 + 3 * 4" """ try: # 生产环境中不要用 eval,这里仅作演示 result = eval(expression) return str(result) except Exception as e: return f"计算错误:{str(e)}" # 工具 3:单位换算 @tool("unit_converter") def convert_unit(value: float, from_unit: str, to_unit: str) -> str: """在不同温度单位之间进行换算。 Args: value: 数值 from_unit: 原始单位,支持 celsius / fahrenheit to_unit: 目标单位,支持 celsius / fahrenheit """ if from_unit == "celsius" and to_unit == "fahrenheit": result = value * 9 / 5 + 32 elif from_unit == "fahrenheit" and to_unit == "celsius": result = (value - 32) * 5 / 9 else: return "不支持的单位转换" return f"{value}°{from_unit[0].upper()} = {result:.1f}°{to_unit[0].upper()}" # 创建多工具 Agent agent = create_agent( model="openai:gpt-4o-mini", tools=[get_weather, calculate, convert_unit], system_prompt="你是一个智能助手,可以查询天气、进行数学计算和单位换算。回答要简洁准确。", ) # 测试:一个问题触发多个工具调用 result = agent.invoke( {"messages": [{"role": "user", "content": "北京和深圳的温差是多少摄氏度?"}]} ) print(result["messages"][-1].content)
这个例子中,Agent 需要自主决策:先查北京天气,再查深圳天气,然后计算温差。整个过程模型自己编排工具调用顺序,你不需要写任何 if/else 逻辑。
三种工具定义方式的对比:
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 普通函数 | 简单工具,参数少 | 最简单,零依赖 | 无法自定义名称和描述 |
| @tool 装饰器 | 标准工具 | 可自定义名称和描述 | 需要导入装饰器 |
| @tool("name") | 需要自定义工具名 | 完全控制工具元信息 | 稍微繁琐 |
我的建议:统一使用 @tool 装饰器。它的 docstring 会自动成为工具描述(模型据此判断何时使用该工具),类型标注会自动生成输入 schema。这是最规范也最不容易出错的方式。
LangChain Agent 的一个核心设计理念是模型中立性(Model Neutrality):你可以用完全相同的代码,只改一个字符串就切换到不同的模型提供商。
# 同一套工具,切换不同模型只需改一行 providers = { "OpenAI": "openai:gpt-4o-mini", "Anthropic": "anthropic:claude-sonnet-4-6", "Google": "google_genai:gemini-2.5-flash-lite", "OpenRouter": "openrouter:anthropic/claude-sonnet-4-6", } for name, model_str in providers.items(): agent = create_agent( model=model_str, tools=[get_weather, calculate], system_prompt="你是天气助手。", ) result = agent.invoke( {"messages": [{"role": "user", "content": "28度华氏度是多少?"}]} ) print(f"[{name}] {result['messages'][-1].content[:80]}...")
模型字符串的格式统一为 "provider:model_name",provider 对应 langchain 的集成包名。这种设计让你在选型时可以快速 A/B 测试不同模型的效果,而不用重构代码。
关于模型选择的实际建议:
gpt-4o-mini 或 gemini-2.5-flash-lite,便宜、快、够用默认情况下,每次调用 agent.invoke 都是无状态的——Agent 不记得上一次对话。在真实应用中,你需要让 Agent 保持上下文连续性。LangChain 通过 checkpointer 参数实现这一点:
from langchain.agents import create_agent from langchain_core.utils.uuid import uuid7 from langgraph.checkpoint.memory import InMemorySaver # 创建带持久化的 Agent agent = create_agent( model="openai:gpt-4o-mini", tools=[get_weather, calculate], system_prompt="你是一个智能助手,记得之前的对话内容。", checkpointer=InMemorySaver(), # 内存级持久化 ) # 生成唯一的会话 ID thread_id = str(uuid7()) config = {"configurable": {"thread_id": thread_id}} # 第一轮对话 result1 = agent.invoke( {"messages": [{"role": "user", "content": "我叫张三,我在北京工作"}]}, config=config, ) print(result1["messages"][-1].content) # 第二轮对话——Agent 应该记得用户叫张三、在北京 result2 = agent.invoke( {"messages": [{"role": "user", "content": "我这边天气怎么样?"}]}, config=config, ) print(result2["messages"][-1].content)
在第二轮对话中,Agent 能根据"我这边"推断出用户指的是北京,因为第一轮对话的上下文被 checkpointer 保存了。
三种 Checkpointer 的选择:
| Checkpointer | 适用场景 | 持久化方式 |
|---|---|---|
| InMemorySaver | 开发调试、单进程 | 内存,进程重启丢失 |
| SqliteSaver | 小型生产部署 | SQLite 文件 |
| PostgresSaver | 生产环境 | PostgreSQL 数据库 |
我的建议:开发阶段用 InMemorySaver 就够了。上生产之前再切换到 PostgresSaver,改一行代码的事。
下面是一个完整的、可直接运行的多工具 Agent 示例,集成了会话持久化和流式输出:
from langchain.agents import create_agent from langchain.tools import tool from langchain_core.utils.uuid import uuid7 from langgraph.checkpoint.memory import InMemorySaver import json # ========== 工具定义 ========== @tool def search_knowledge_base(query: str) -> str: """搜索公司内部知识库,获取产品文档、FAQ 等信息。 Args: query: 搜索关键词 """ # 模拟知识库数据 kb = { "退款政策": "购买后 7 天内可申请无理由退款,15 天内可申请质量问题退款。", "配送时间": "一线城市 1-2 天,二三线城市 3-5 天,偏远地区 5-7 天。", "会员权益": "金卡会员享 9.5 折优惠,钻石会员享 8.8 折且免运费。", } for key, value in kb.items(): if key in query or any(w in query for w in key): return f"知识库结果【{key}】:{value}" return f"未找到与'{query}'相关的知识库条目。" @tool def create_order(product_name: str, quantity: int, address: str) -> str: """创建新的订单。 Args: product_name: 商品名称 quantity: 购买数量 address: 收货地址 """ order_id = f"ORD-{uuid7().hex[:8].upper()}" return json.dumps({ "order_id": order_id, "product": product_name, "quantity": quantity, "address": address, "status": "已创建", }, ensure_ascii=False, indent=2) @tool def check_order_status(order_id: str) -> str: """查询订单状态。 Args: order_id: 订单编号 """ return json.dumps({ "order_id": order_id, "status": "已发货", "logistics": "顺丰快递 SF1234567890", "estimated_delivery": "2026-07-23", }, ensure_ascii=False, indent=2) # ========== Agent 创建 ========== agent = create_agent( model="openai:gpt-4o-mini", tools=[search_knowledge_base, create_order, check_order_status], system_prompt="""你是一个电商客服 Agent。你的职责是: 1. 回答用户关于退款政策、配送时间、会员权益等问题 2. 帮助用户创建订单和查询订单状态 3. 语气友好专业,回答准确简洁 注意:创建订单前必须确认商品名称、数量和收货地址。""", checkpointer=InMemorySaver(), ) # ========== 多轮对话演示 ========== thread_id = str(uuid7()) config = {"configurable": {"thread_id": thread_id}} conversations = [ "你们的退款政策是什么?", "帮我下一个订单,买 2 个无线耳机,地址是北京市朝阳区xxx", "订单号多少?帮我查一下物流", ] for user_msg in conversations: print(f"\n👤 用户:{user_msg}") result = agent.invoke( {"messages": [{"role": "user", "content": user_msg}]}, config=config, ) print(f"🤖 Agent:{result['messages'][-1].content}")
这个示例展示了 Agent 在实际业务场景中的工作方式:它能根据用户意图自动选择调用知识库搜索、创建订单或查询物流,整个过程自然流畅。
A:create_agent 是 LangChain 推荐的新 API,取代了旧版的 AgentExecutor。两者的核心区别在于:create_agent 基于 LangGraph 构建,天然支持持久化、流式输出、人机协作等高级特性;而 AgentExecutor 是旧架构,已经进入维护模式。新项目一律用 create_agent,旧项目建议迁移。
A:默认情况下 LangChain Agent 有内置的最大迭代次数限制,通常为 25 次工具调用。你可以通过 create_agent 的 max_turns 参数来自定义这个上限。如果 Agent 在达到上限前就生成了最终回复(不包含工具调用),循环会自动终止。实践中 25 次足够覆盖绝大多数场景。
A:工具抛出的异常会被 Harness 捕获,错误信息会作为工具返回结果传递给模型。模型看到错误信息后通常会尝试修正参数重新调用,或者告知用户该操作无法完成。你不需要在工具内部做 try/except(当然加上更健壮),但 Agent 不会因为单个工具报错而崩溃。
A:不一样。OpenAI GPT-4 系列和 Anthropic Claude 系列对工具调用(Function Calling)的原生支持最好,参数推断准确率高。Google Gemini 和开源模型的支持在快速追赶。如果某个模型在工具调用上表现不佳,最直接的解决方案是换一个模型试试,而不是花大量时间调提示词。
实践 1:工具描述(docstring)是模型决策的关键依据
90% 的 Agent 调用错误都可以追溯到工具描述不清晰。模型完全依赖工具的名称、描述和参数说明来决定何时调用、传什么参数。你的 docstring 应该回答三个问题:这个工具做什么?什么时候该用?输入输出是什么格式?
实践 2:工具名称用 snake_case
有些模型提供商(特别是较新或较小的模型)对工具名中的空格和特殊字符支持不好,会导致工具调用失败。统一用 snake_case 命名(如 web_search 而非"Web Search")可以最大程度保证跨模型兼容性。
实践 3:先让 Agent 跑通,再优化提示词
很多初学者花大量时间打磨系统提示词,但 Agent 连基本的工具调用都没跑通。正确的顺序是:先用最简单的提示词让 Agent 正确调用工具,确认流程无误后再逐步优化提示词。
坑点 1:不要用 eval 执行用户输入的数学表达式
示例代码中用了 eval 来计算数学表达式,这在生产环境中是严重的安全隐患。生产环境应该用 ast.literal_eval 或专门的数学解析库(如 sympy)来替代。
坑点 2:工具函数的返回值必须是字符串
create_agent 的工具默认期望返回 str 类型。如果你的工具返回字典或列表,务必在工具内部序列化为字符串(用 json.dumps),否则 Agent 可能无法正确解析工具返回内容。
坑点 3:忘记设置 API Key 就跑 Agent
create_agent 在首次调用 invoke 时才会真正初始化模型连接。如果你忘了设置环境变量,不会在 create_agent 阶段报错,而是在 invoke 时抛出 AuthenticationError。建议在程序入口处就验证 API Key 是否可用。
本节我们从 Agent 的核心定义"Model + Harness"出发,掌握了 create_agent 的三大核心参数:model(模型选择)、tools(工具注册)、system_prompt(系统提示词)。通过四个递进式的实战步骤,从最简 Agent 到多工具、多模型、带持久化的完整 Agent,你应该已经具备了构建生产级 Agent 的基础能力。
理解了 Agent 的基本工作原理后,下一节我们将深入工具调用的进阶技巧——如何让工具访问 Agent 的运行时状态、如何使用中间件控制 Agent 行为、以及如何实现动态工具选择等高级能力。
关键词:LangChain框架精通, Agent, create_agent, 智能体, 工具调用, Harness, 教程, 实战, 最佳实践
难度:入门
预计阅读:15 分钟