上篇你认清了 LangChain 是编排层——六大模块、LCEL、Agent 三阶段。地图有了,该动手插第一块「手脚」。这篇讲最小 Agent:加载环境 → 定义工具 → create_agent → 调用。
小明卡在「一轮工具」
上篇之后,小明用LangChain框架跑通了「查一次天气」:
问题: 杭州今天天气怎么样?
tool_calls: [{'name': 'get_weather', 'args': {'city': '杭州'}, ...}]
执行工具 get_weather({'city': '杭州'})
工具结果: 小雨,17°C,东北风2级
最终回答: 杭州今天小雨,17°C……
他得意了一会儿,又扔了一个问题:
先查北京天气,再算 10+20,最后用一句话总结。
「只跑一轮」的逻辑立刻露馅:模型要么只查了天气,要么算完数就不总结;他想让 Agent 自己决定调几次工具,难到又得把以前手写的 ReAct 循环抄过来。
小明去找老张:”上篇说 Agent 是指挥官。LangChain 有没有现成的指挥官,别让我每次手写 for 循环?”
老张说:”有。四个字:create_agent。Models + Tools 交给它,循环它帮你跑。”
什么是 create_agent
老张在白板上画:
你提供:
Model(大脑) + Tools(手脚)[+ system_prompt]
↓
create_agent(...)
↓
框架内部循环:
模型决策 → 有 tool_calls?
│是 │否
↓ ↓
执行工具并回填 输出最终回答
↓
再问模型……
“还记得手写 Function Calling 吗?你自己写:
if tool_calls → 执行 → 喂回去 → 再调模型
create_agent 把这套循环收进框架。你负责零件,框架负责引擎。
create_agent 给实习生一张工具清单,让他自己决定查几次、算几次,直到能交差。”
| 维度 |
一轮 bind_tools |
create_agent |
| 谁写循环 |
你 |
框架 |
| 工具调用次数 |
最多一轮(代码写死) |
多步,直到无 tool_calls |
| 你要准备的 |
Model + Tools + 手写回填 |
Model + Tools(+ system_prompt) |
| 适合 |
看清协议长什么样 |
最小可用 Agent |
| 对照手写 |
单步 FC |
框架版 ReAct 循环 |
小明:”依赖要装啥?”
” requirements.txt 里这几样就够入门:
openai>=1.30.0
langchain>=1.3.14
langchain-openai>=1.4.0
pydantic>=2.0.0
python-dotenv>=1.0.0
安装:
pip install -r requirements.txt
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
然后记住四步口诀:环境 → 工具 → Agent → 调用。”
代码拆解:四步最小 Agent
第一步:加载环境变量(模型工厂)
llm.py:
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
load_dotenv()
def get_chat_model(*, temperature: float = 0) -> ChatOpenAI:
return ChatOpenAI(
model=os.environ.get("OPENAI_MODEL", "qwen-plus"),
api_key=os.environ["OPENAI_API_KEY"],
base_url=os.environ.get("OPENAI_BASE_URL"),
temperature=temperature,
)
“.env 里放好 OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL。Agent 温度建议先 0,少胡编、好复现。”
第二步:定义工具
tools.py:
from langchain.tools import tool
@tool
def get_weather(city: str) -> str:
"""查询城市天气(模拟)。"""
data = {"杭州": "小雨,17°C", "北京": "晴,15°C", "上海": "多云,18°C"}
return data.get(city, f"{city}:晴,20°C(模拟)")
@tool
def add(a: float, b: float) -> str:
"""计算两数之和。"""
return str(a + b)
TOOLS = [get_weather, add]
TOOL_MAP = {t.name: t for t in TOOLS}
“@tool 把函数名、参数、文档字符串变成模型能看懂的 schema。TOOLS 交给 Agent;TOOL_MAP 留给手写循环按名字查找——框架路径其实只需要 TOOLS。先用上,工具一章再详细介绍”
第三步 + 第四步:create_agent 并调用
agent_loop.py 里的框架版:
from langchain.agents import create_agent
from llm import get_chat_model
from tools import TOOLS
def run_create_agent(question: str) -> str:
"""框架帮你写循环。"""
agent = create_agent(
get_chat_model(temperature=0),
tools=TOOLS,
system_prompt="你是助手。需要查天气或做加法时必须调用工具,不要编造。",
)
result = agent.invoke({"messages": [{"role": "user", "content": question}]})
last = result["messages"][-1]
return getattr(last, "content", str(last)) or ""
“逐行看:
-
create_agent(model, tools=..., system_prompt=...) —— 大脑 + 手脚 + 人设
-
invoke({\"messages\": [...]}) —— 输入是消息列表,不是裸字符串
-
返回值里的
messages 是整段轨迹;取最后一条当最终回答
工作原理心智模型:
用户问题
↓
模型:要不要用工具?
├─ 要 → tool_calls → 框架执行 TOOLS → ToolMessage 回填 → 再问模型
└─ 不要 → 直接自然语言结束
这和你手写 ReAct 是同一件事,只是循环在框架里。”
对照:手写循环长什么样
def run_handwritten_loop(question: str, max_steps: int = 5) -> str:
model = get_chat_model(temperature=0)
model_with_tools = model.bind_tools(TOOLS)
messages = [HumanMessage(content=question)]
for step in range(1, max_steps + 1):
print(f"[手写循环 步骤 {step}/{max_steps}]")
ai = model_with_tools.invoke(messages)
messages.append(ai)
if not ai.tool_calls:
return ai.content or ""
for tc in ai.tool_calls:
print(f" → {tc['name']}({tc['args']})")
result = TOOL_MAP[tc["name"]].invoke(tc["args"])
print(f" ← {result}")
messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))
print("[手写循环] 达到 max_steps,强制收尾")
return get_chat_model(temperature=0).invoke(messages).content or ""
“课件故意把两条路放一起:
-
手写:看清停止条件——无
tool_calls 结束;步数用尽强制收尾
-
create_agent:同一套语义,少写几十行胶水
入门先跑通框架版;调试协议时再看手写版。”
小明复述:”四步是环境、工具、create_agent、invoke;框架内部还是决策→执行→回填。”
“对。入口 main.py 就两行演示:”
def demo_create_agent() -> None:
print("=== B. create_agent(框架循环)===")
q2 = "北京天气怎么样?再算 10+20。"
print("问题:", q2)
print("回答:", run_create_agent(q2))
总结
老张说:”第二篇只办一件事——四步跑通最小 Agent。”
“三个核心理解:
-
create_agent = 框架版工具循环 —— 你交 Models + Tools,它负责决策→执行→回填
-
四步口诀 —— 环境变量 →
@tool → create_agent → invoke({messages})
-
手写循环 / create_agent 是一层窗户纸 —— 协议相同,封装深度不同”
LangChain 支线进度:
认识 LangChain(编排层地图)
↓
Agent 快速入门(本篇:create_agent)
↓
Models → Messages → Prompts/LCEL → Tools 深挖 → Memory → …
“下一篇把 Models 单独拆开——init_chat_model、invoke 与 stream,把大脑接口吃透。”
最小 Agent 不是神秘架构,就是:模型会选工具,框架会跑循环。create_agent 让你先跑起来,再回头看懂手写循环。