1. 开篇:Agent 不是“会聊天的模型“,而是“会干活的系统“

0. 开篇:Agent 不是"会聊天的模型",而是"会干活的系统"

普通 LLM 调用是一问一答:你把问题给它,它把答案还给你,结束。但真实任务往往不是一次问答能解决的——"帮我查一下杭州明天天气,如果下雨就给我的团队发封邮件改期",这需要查天气 → 判断 → 发邮件三步,中间还要根据第一步的结果决定第二步怎么做。Agent(智能体)就是为这种"多步、依赖反馈、需要外部能力"的任务而生的系统。

本讲义的一句话主线:create_agent 把「模型 + 工具 + 提示词」编译成一个会自己循环的状态图。你只要理解三件事——它怎么循环(1.3)、怎么调(3)、怎么加能力(4/5/6/7),就能写出生产可用的 Agent。

1. 理解 Agents

1.1 什么是 Agent?

        官方定义非常直白:"An agent is a model that can call tools, observe their results, and decide what to do next."——Agent 是一个能够调用工具、观察结果、并自行决定下一步的模型。

拆开来看,Agent 由三个动词构成闭环:

Agent 循环的完整流程(以"查天气 + 发邮件"为例)

注意关键分支:模型自己决定"再调一个工具"还是"给最终答案"——这就是 Agent 与普通链路的本质区别

1.2 Agent 与普通 LLM 调用的区别

判断标准:如果任务的步骤数量或步骤内容,在看到前面步骤的结果之前无法确定,就需要 Agent。反之——"把这段英文翻译成中文"——用普通调用即可,套 Agent 只会增加延迟和成本。

1.3 Agent 的核心组件

create_agent 把下面这些零件组装成一个状态图。理解每个零件的作用,你就掌握了全部调参空间。

组件对应参数作用与要点
模型 Modelmodel 必填Agent 的"大脑"。传字符串"openai:gpt-5.5")或模型对象ChatOpenAI(...))。必须支持工具调用,否则无法形成循环。
工具 ToolstoolsAgent 的"手脚"。@tool 函数、BaseTool 实例或 dict。框架内部自动 bind_tools你不要自己绑。为空则退化为纯模型节点,没有循环。
系统提示词system_promptAgent 的"人设与规矩"。字符串或 SystemMessage,每次调用模型时被放在消息列表最前面。实践中几乎必设。
中间件 MiddlewaremiddlewareAgent 的"拦截器"。在模型调用前/后、工具调用前后插入逻辑:重试、摘要、PII 脱敏、人在回路、动态模型切换等。
结构化输出response_format约束最终答案的形状。可为 ToolStrategy / ProviderStrategy / 裸 Schema 类型。结果在 result["structured_response"]
状态 Statestate_schema默认 AgentState 只有 messages(+ structured_response)。需要额外字段就扩展它。
运行时上下文context_schema每次调用传入的不可变数据(user_id、租户信息)。不随 checkpoint 持久化,工具通过 ToolRuntime 读取。
短期记忆checkpointer按 thread_id 持久化会话。没有它,Agent 每次调用都是全新会话;有了它,多轮对话自动续接。
长期记忆store跨会话(跨 thread_id)持久化的知识库,如用户画像、历史偏好。
名称name图/智能体的名字。出现在 LangSmith trace 中,多智能体场景用于标识身份。
中断interrupt_before / interrupt_after在指定节点前/后暂停,实现人工审批等人机协同。

AgentState:Agent 的"记忆载体"长什么样

# 默认情况下,Agent 的状态就是一个消息列表(外加结构化输出字段)
class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]   # ← 核心:只追加,不覆盖
    structured_response: ResponseT | None                  # ← 配了 response_format 才有
    jump_to: str | None                                 # ← 中间件可用来跳转节点

# 需要额外字段?继承扩展即可
class CustomState(AgentState):
    user_name: str
    tool_call_count: int          # ⚠ 会被并发工具调用争抢,建议配 reducer

agent = create_agent(model="openai:gpt-5.5", tools=tools, state_schema=CustomState)

为什么"消息列表"就是状态?因为 add_messages reducer 保证每一步都只追加不修改:用户的提问、模型的思考、工具调用请求、工具返回结果、最终答案,全部按顺序留在列表里。这意味着——Agent 做的每一件事都可审计,你能完整复现模型当时看到了什么。这是相比黑盒 Agent 框架的最大优势。

1.4 Agent 创建与调用

在 v1 之前,LangChain 里"造一个 Agent"的方式多到让人困惑。下面这些 API 全部已弃用,多数已移入 langchain-classic。认识它们,是为了能识别过时教程

# ===== ① 史前时代:initialize_agent + AgentType 枚举 =====
from langchain.agents import initialize_agent, AgentType
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION)
agent.run("今天杭州天气如何?")          # ← 字符串进、字符串出,无状态管理

# ===== ② AgentExecutor 时代:手工拼 prompt + agent + executor =====
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant"),
    MessagesPlaceholder("chat_history"),
    ("human", "{input}"),
    MessagesPlaceholder("agent_scratchpad"),   # ← 这个"草稿本"是最大的坑
])
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
executor.invoke({"input": "...", "chat_history": []})
# ===== ③ 过渡期:langgraph.prebuilt.create_react_agent =====
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(model, tools, prompt="...", checkpointer=MemorySaver())
agent.invoke({"messages": [...]})

老 API 的四个硬伤: 

① 三件套拼装——prompt / agent / executor 要手工对齐,agent_scratchpad 占位符漏了就报错;

② 输入键不统一——.run(str) vs .invoke({"input":..., "chat_history":...}) vs {"messages":[...]}

③ 记忆靠外挂——ConversationBufferMemory 等一堆 Memory 类,与图状态割裂;

④ 类型众多——ZERO_SHOT_REACT_DESCRIPTIONOPENAI_FUNCTIONSSTRUCTURED_CHAT… 选错就是踩坑。

1.4.2 全新的调用 

from langchain.agents import create_agent

def check_weather(location: str) -> str:
    """Return the weather forecast for the specified location."""
    return f"It's always sunny in {location}"

# 一次调用,全部搞定:模型 + 工具 + 提示词 → 编译好的图
graph = create_agent(
    model="anthropic:claude-sonnet-4-5-20250929",
    tools=[check_weather],
    system_prompt="You are a helpful assistant",
)

inputs = {"messages": [{"role": "user", "content": "what is the weather in sf"}]}
for chunk in graph.stream(inputs, stream_mode="updates"):
    print(chunk)

新旧对照:一张表看清迁移

维度❌ 旧(v0 / 0.x)✅ 新(v1)
创建入口initialize_agent / create_openai_tools_agent + AgentExecutor / create_react_agentcreate_agent(...) —— 一个函数搞定
输入格式.run("字符串") 或 {"input","chat_history","agent_scratchpad"}{"messages": [...]} —— 统一消息列表
工具绑定传给 executor,prompt 里还要留 agent_scratchpadcreate_agent 内部自动 bind_tools,你只需传列表
记忆ConversationBufferMemory / SummaryMemory …checkpointer + thread_id(短期)、store(长期)
返回值{"output": "字符串"} 中间步骤不可见完整 messages 轨迹 + 可选 structured_response
扩展能力改 executor 参数、自定义 agent 类middleware(重试/摘要/脱敏/人在回路…)
底层自研循环逻辑LangGraph 状态图,可渐进下沉到 StateGraph

识别过时教程的黄金标准(背下来):

  • 出现 AgentExecutor / initialize_agent / agent.run(...) → 2023 年的材料
  • 出现 ConversationBufferMemory / agent_scratchpad → 2023–2024 年的材料
  • 出现 from langgraph.prebuilt import create_react_agent 作为主推方案 → 2024 年过渡期材料
  • 用 from langchain.agents import create_agent 且传 {"messages": [...]} → 符合 v1

create_agent 完整签名

def create_agent(
    model: str | BaseChatModel,                                  # ① 模型:字符串 or 实例
    tools: Sequence[BaseTool | Callable | dict] | None = None,   # ② 工具列表
    *,
    system_prompt: str | SystemMessage | None = None,           # ③ 系统提示词
    middleware: Sequence[AgentMiddleware] = (),                  # ④ 中间件
    response_format: ResponseFormat | type | dict | None = None,  # ⑤ 结构化输出
    state_schema: type[AgentState] | None = None,               # ⑥ 自定义状态
    context_schema: type[ContextT] | None = None,               # ⑦ 运行时上下文
    checkpointer: Checkpointer | None = None,                    # ⑧ 短期记忆
    store: BaseStore | None = None,                             # ⑨ 长期记忆
    interrupt_before: list[str] | None = None,                  # ⑩ 节点前中断
    interrupt_after: list[str] | None = None,                   #    节点后中断
    debug: bool = False,                                        #    调试开关
    name: str | None = None,                                  # ⑪ 图/智能体名称
    cache: BaseCache | None = None,                             #    节点结果缓存
    transformers: Sequence[TransformerFactory] | None = None,
) -> CompiledStateGraph[AgentState[ResponseT], ContextT, ...]

返回值是 CompiledStateGraph——它同时是一个标准 Runnable,所以 invoke / stream / ainvoke / astream / batch 全都能用,与 LangChain 其他组件无缝组合。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值