avatar

命令行小屋

A text-focused Halo theme

  • Ai
  • Linux
  • 游戏
  • 数据库
  • Apache Hadoop
  • Windows
  • 手机
主页 LangChain Agent 完全指南:从 Tools 到 ReAct 循环的工程实践
文章

LangChain Agent 完全指南:从 Tools 到 ReAct 循环的工程实践

发表于 最近 更新于 最近
作者 KennethCheng
339~435 分钟 阅读

智能体 (Agent) = 大语言模型 + 工具 + 系统提示,让 LLM 拥有"手脚"和"行为准则",能自主规划、调用工具、迭代求解复杂任务。

本文基于 LangChain v1.0,系统梳理 Agent 的核心概念、Tools 定义、Agent 构建、系统提示、结构化输出与多种调用方式,配套可直接拷贝运行的代码示例。


目录

  1. Agent 是什么
  2. Tools:让 LLM 拥有"手脚"
  3. 创建你的第一个 Agent
  4. 动态模型与中间件
  5. 系统提示:静态与动态
  6. 结构化输出
  7. 多种调用方式
  8. 总结速记

1. Agent 是什么

智能体 (Agent) 是将语言模型与工具相结合,创建可以推理任务、决定使用哪些工具并迭代寻求解决方案的智能系统。

1.1 关键要素拆解

要素含义
语言模型智能体的"大脑",负责推理与决策
工具智能体的"手脚",负责与外部世界交互
推理任务理解目标、拆解步骤、规划路径
决定使用哪些工具根据任务动态选择最合适的工具
迭代寻求解决方案多轮循环(观察 → 思考 → 行动 → 反思)直至完成

1.2 与纯 LLM 的区别

  • 纯 LLM:仅依赖模型内部知识生成回答
  • Agent:在 LLM 基础上,自主选择并调用工具,可与外部数据 / API / 环境互动,并能多轮迭代

1.3 ReAct 工作循环

🤖 Agent 循环 (ReAct)
Thought
Action
Observation
任务/问题
最终回复
(Final Reply)
🧠 Model
推理并选择动作
Thought
🛠️ Tool
执行所选择动作
Action
📋 Observation
获取执行结果
Observation
👤 User
用户

典型工作流:

  1. Thought(思考):分析当前任务,推理下一步行动
  2. Action(行动):选择并调用合适的工具
  3. Observation(观察):获取工具返回结果
  4. Reflection(反思):判断是否达成目标,必要时回到第 1 步继续循环

2. Tools:让 LLM 拥有"手脚"

Tools 是 model 与外部世界交互的接口,扩展模型能力边界,使大语言模型能够执行用户定义的动作,例如搜索网页、执行代码、访问数据库或调用其他服务。

2.1 工具的定义

from langchain_core.tools import tool

@tool
def calculate(expression: str) -> str:
    """Perform mathematical calculations and return the result.
    Args:
        expression: Mathematical expression to evaluate
        (e.g., "2 + 3 * 4", "sqrt(16)", "sin(pi/2)")
    Returns:
        The calculated result as a string
    """
    result = str(eval(expression))
    return result

三大要点:

  • 利用 @tool 装饰器将函数转化为工具
  • 入参类型要明确标注
  • 工具描述(docstring)会帮助 model 理解何时 / 如何使用该工具

2.2 @tool 装饰器的属性自定义

@tool("calculator", description="执行算术计算。用于解决任何数学问题。")
def calculate(expression: str) -> str:
    """评估数学表达式。"""
    return str(eval(expression))

用 Pydantic 定义 args_schema:

from pydantic import BaseModel, Field
from typing import Literal

class WeatherInput(BaseModel):
    """天气查询的输入参数。"""
    location: str = Field(description="城市名称或坐标")
    units: Literal["celsius", "fahrenheit"] = Field(
        default="celsius",
        description="温度单位偏好"
    )

@tool(args_schema=WeatherInput)
def get_weather(location: str, units: str = "celsius") -> str:
    """获取当前天气和可选预报。"""
    temp = 22 if units == "celsius" else 72
    return f"{location}当前天气: {temp}度{units[0].upper()}"

2.3 StructuredTool 类的关键属性

通过 @tool 装饰器装饰,会将函数封装为结构化工具(StructuredTool 类)。

属性类型说明
namestr工具的独特名称,命名应当直观且方便模型理解
descriptionstr告诉模型如何 / 何时 / 为何使用工具,可加入 few-shot 示例
response_format["content", "content_and_artifact"]工具的响应格式,默认为 "content"
方法用途
invoke / ainvoke直接对工具进行调用(同步 / 异步)
get_input_schema获取工具的输入策略
get_output_schema获取可用于工具已定义的输出 Pydantic 模型

2.4 多种工具类型

# 本地数据浏览
import csv, json
from typing import List, Dict

@tool
def search_csv(query: str, csv_path: str, limit: int = 10) -> str:
    """在本地 csv 文件中按关键词简单搜索,返回前 limit 条匹配记录(JSON 字符串)。"""
    query_lower = query.lower()
    results: List[Dict[str, str]] = []
    with open(csv_path, "r", encoding="utf-8-sig", newline="") as f:
        reader = csv.DictReader(f)
        for row in reader:
            if any(query_lower in str(value).lower() for value in row.values()):
                results.append(row)
                if len(results) >= limit:
                    break
    return json.dumps(results, ensure_ascii=False, indent=2)

# 网络搜索 API
@tool
def internet_search(
    query: str,
    max_results: int = 5,
    topic: Literal["general", "news", "finance"] = "general",
    include_raw_content: bool = False,
):
    """使用 Tavily 搜索引擎在互联网上搜索信息"""
    return tavily_client.search(
        query,
        max_results=max_results,
        include_raw_content=include_raw_content,
        topic=topic,
    )

tools = [internet_search, calculate, get_weather]

2.5 7 步工具集成流程

步骤关键点
1. 函数 → 工具@tool 装饰 + 类型注解 + 文档字符串
2. 命名描述可选 name= / description=,动词开头
3. 参数模式自动推导或 args_schema=Pydantic
4. 返回格式默认 content;需额外数据用 content_and_artifact
5. 绑定模型model.bind_tools([tools])
6. 触发调用invoke 后查看 ai_msg.tool_calls
7. 解析请求取 name / args / id,多条调用按 id 对应

3. 创建你的第一个 Agent

3.1 准备模型

from langchain.chat_models import init_chat_model

model = init_chat_model(
    "openai:gpt-4.1",
    temperature=0.7,
    max_tokens=1000,
    timeout=30,
    max_retries=2,
    api_key="sk-......",
    base_url="https://api.deepseek.com/v1",  # 走 OpenAI 兼容协议
)

3.2 两种静态创建方法

from langchain.agents import create_agent

# 方式一:使用模型标识符字符串
agent = create_agent(
    "openai:gpt-4",
    tools=tools,
)

# 方式二:使用模型实例(推荐)
model = init_chat_model("openai:gpt-4o-mini")
agent = create_agent(model, tools=tools)

3.3 调用 Agent

res = agent.invoke({
    "messages": [
        {"role": "user",
         "content": "deepseek在2024-2025年之间,用户增长了百分多少??"}
    ]
})

消息轨迹(典型 ReAct 流程):

[
    # 1. 用户提问
    HumanMessage(content="deepseek在2024-2025年之间,用户增长了百分多少??"),

    # 2. 模型决定调用搜索工具
    AIMessage(content="", additional_kwargs={'tool_calls': [{
        'id': 'call_niDwiOVimm1zkCcsG2DoDxQD',
        'function': {'arguments': '{"query": "deepseek user growth 2024 to 2025"}',
                     'name': 'internet_search'}
    }]}),

    # 3. 搜索工具返回结果
    ToolMessage(content='{"query": "...", "results": [...]}',
                name='internet_search',
                tool_call_id='call_niDwiOVimm1zkCcsG2DoDxQD'),

    # 4. 模型决定调用计算工具
    AIMessage(content="", additional_kwargs={'tool_calls': [{
        'id': 'call_lMtSVMcYCelvsFqzPZe348So',
        'function': {'arguments': '{"expression": "(125-61)/61*100"}',
                     'name': 'calculate'}
    }]}),

    # 5. 计算工具返回结果
    ToolMessage(content='104.91803278688525',
                name='calculate',
                tool_call_id='call_lMtSVMcYCelvsFqzPZe348So'),

    # 6. 模型总结答复
    AIMessage(content="在2024年到2025年之间,DeepSeek的用户增长了约104.92%。")
]

执行流程图:

🧮 calculate🌐 internet_search🤖 Agent👤 User🧮 calculate🌐 internet_search🤖 Agent👤 Userdeepseek 2024-2025 用户增长 %?query="deepseek user growth 2024 to 2025"返回 Deepseek Statistics ...expression="(125-61)/61*100"104.91803278688525在2024-2025年之间,DeepSeek用户增长了约 104.92%

4. 动态模型与中间件

动态模型在运行时根据当前状态和上下文进行选择,这使得复杂的路由逻辑和成本优化成为可能。

4.1 利用中间件定义动态模型 Agent

from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from langchain.chat_models import init_chat_model

# 1️⃣ 定义两个备选模型
basic_model = init_chat_model("openai:gpt-4o-mini")
advanced_model = init_chat_model("openai:gpt-4o")

# 2️⃣ 定义模型选择逻辑
@wrap_model_call
def dynamic_model_selection(request: ModelRequest, handler) -> ModelResponse:
    """Choose model based on conversation complexity."""
    message_count = len(request.state["messages"])

    if message_count > 5:
        # 使用高级模型进行更长时间的对话
        model = advanced_model
    else:
        model = basic_model

    request.model = model
    return handler(request)

# 3️⃣ 创建 Agent
agent = create_agent(
    model=basic_model,   # Default model
    tools=tools,
    middleware=[dynamic_model_selection]
)

4.2 调用效果

# 短消息(≤5 条)→ 走 gpt-4o-mini
agent.invoke({"messages": [{"role": "user", "content": "你好"}]})
# AIMessage(content='你好!有什么我可以帮助你的吗?', 
#           ...'model_name': 'gpt-4o-mini-2024-07-18', ...)

# 长消息(>5 条)→ 走 gpt-4o
res["messages"].append({"role": "user", 
                        "content": "你认为接下来deepseek的发展前景如何会如何??"})
agent.invoke(res)
# AIMessage(content='DeepSeek的未来发展前景在业内被…', 
#           ...'model_name': 'gpt-4o', …)

4.3 适用场景

  • 成本优化:简单任务用小模型,复杂任务用大模型
  • 路由分发:按主题 / 语言 / 用户等级路由到不同模型
  • A/B 测试:不同用户走不同模型,对比效果
  • 降级兜底:主模型不可用时切到备用模型

5. 系统提示:静态与动态

我们可以通过提供系统提示来确定 Agent 处理任务的方式。system_prompt 参数可以以字符串形式提供。

5.1 静态系统提示

agent = create_agent(
    model,
    tools,
    system_prompt="你是我的得力助手。要做到言简意赅,准确无误的回答我的问题。"
)

💡 字符串形式直接传入即可,适合固定不变的角色设定。

5.2 动态系统提示词

让系统提示根据上下文动态生成,从而适配不同的用户角色、场景等。

from typing import TypedDict
from langchain.agents import create_agent
from langchain.agents.middleware import dynamic_prompt, ModelRequest


# 1️⃣ 定义上下文结构
class Context(TypedDict):
    user_role: str


# 2️⃣ 编写动态提示函数
@dynamic_prompt
def user_role_prompt(request: ModelRequest) -> str:
    """Generate system prompt based on user role."""
    user_role = request.runtime.context.get("user_role", "user")
    base_prompt = "你是我的得力助手。"

    if user_role == "expert":
        return f"{base_prompt} 提供详细的技术答复。"
    elif user_role == "beginner":
        return f"{base_prompt} 简单解释概念,避免行话。"

    return base_prompt


# 3️⃣ 创建 Agent(绑定 context_schema)
agent = create_agent(
    model="openai:gpt-4o",
    tools=tools,
    middleware=[user_role_prompt],
    context_schema=Context
)

# 4️⃣ 调用时显式传入 context
result = agent.invoke(
    {"messages": [{"role": "user", "content": "为我解释机器学习这个概念。"}]},
    context={"user_role": "expert"}   # 👈 关键
)

5.3 核心机制

expert
beginner
其他
agent.invoke
messages + context
dynamic_prompt 中间件
从 request.runtime.context 读取
判断 user_role
提供详细技术答复
简单解释避免行话
base_prompt 默认
注入到 system_prompt
模型生成回复

5.4 静态 vs 动态 对比

维度静态 system_prompt动态 @dynamic_prompt
写法字符串直接传参装饰器 + 函数返回字符串
变化性创建时固定每次调用按 context 重新生成
上下文感知❌✅(request.runtime.context)
上下文传递无context_schema=Context + invoke(context=...)
适用场景角色固定多角色 / 多场景 / 多语言

6. 结构化输出

在某些情况下,我们可能希望 Agent 以特定格式来返回输出。LangChain 通过 response_format 参数提供了结构化输出的配置。ToolStrategy 使用人工工具调用来生成结构化输出,适用于任何支持工具调用的模型。

6.1 定义输出格式

from pydantic import BaseModel
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy

# 1️⃣ 用 Pydantic 定义期望的输出结构
class ContactInfo(BaseModel):
    name: str
    email: str
    phone: str

# 2️⃣ 在创建 Agent 时通过 response_format 注入
agent = create_agent(
    model="openai:gpt-4o-mini",
    tools=tools,
    response_format=ToolStrategy(ContactInfo)   # 👈 关键
)

6.2 调用并取出结果

result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": """从以下内容中提取信息:大家都觉得非常靠谱的小明,
        他的具体联系渠道我这里可以给你。他总是能及时回复邮件,
        所以如果你有文件或详细问题,发邮件到 xiaoming@gmail.com 这个邮箱地址。
        当然,如果事情比较紧急,或者需要实时语音沟通确认细节,
        你也可以直接拨打他的个人办公电话号码是 (04xx) 123-4567,
        这个号码通常在工作日的办公时间内都能接通"""}
    ]
})

print(result["structured_response"])
# ContactInfo(
#     name='小明',
#     email='xiaoming@gmail.com',
#     phone='(04xx) 123-4567'
# )

6.3 ToolStrategy 名字由来

  • Tool:借助"工具调用"机制让模型按 schema 输出
  • Strategy:它是一种输出策略(区别于直接 prompt 让模型生成 JSON)
  • 优点:不依赖模型原生结构化输出能力 → 任何支持 tool calling 的模型都能用

7. 多种调用方式

所有 Agent 都有自身状态 (state),其中包含一连串信息;对 Agent 的调用,实际上是在"状态"中增加新的信息,并更新代理状态。除了基本的 invoke 方法,与 model 类似,我们还可以通过其他方法对 agent 进行调用以满足不同需求。

7.1 同步调用 invoke

response = model.invoke("Why do parrots have colorful feathers?")

7.2 批量调用 batch

responses = model.batch([
    "为什么鹦鹉有彩色羽毛?",
    "飞机是如何飞行的?",
    "什么是量子计算?"
])

7.3 流式调用 stream

for chunk in model.stream("为什么鹦鹉有彩色羽毛?"):
    print(chunk.content, end="", flush=True)

# 构建完整的流式响应消息
full_response = None
for chunk in model.stream("天空是什么颜色的?"):
    full_response = chunk if full_response is None else full_response + chunk
print(full_response.content)

7.4 异步调用 ainvoke / astream

async def async_invoke():
    response = await model.ainvoke("为什么鹦鹉会模仿人类说话?")
    return response

async def async_stream():
    async for chunk in model.astream("解释机器学习"):
        print(chunk.content, end="", flush=True)

7.5 Agent 的流式调用

for chunk in agent.stream(
    {"messages": [{"role": "user", 
                   "content": "deepseek在2024-2025年之间,用户增长了百分之多少??"}]},
    stream_mode="values",   # 每个 chunk 是"到目前为止的完整 state"
):
    latest_message = chunk["messages"][-1]

    if latest_message.content:
        print(f"Agent: {latest_message.content}")
    elif latest_message.tool_calls:
        print(f"Calling tools: {[tc['name'] for tc in latest_message.tool_calls]}")

7.6 调用方式速查表

调用方式适用场景性能特点用户体验
同步调用简单应用、测试调试、低并发响应时间中等,资源占用低需要等待完整响应
批量调用数据处理、报表生成、批量任务高吞吐量,适合密集任务延迟较高,适合后台任务
流式调用实时对话、长文本生成、演示首字延迟低,渐进式输出体验最佳,过程透明
异步调用Web 服务、高并发应用、实时系统高并发,资源利用率高取决于具体实现
方法同步/异步用途
invoke同步单次调用,等待完整结果
ainvoke异步Web 服务 / 高并发
stream同步流式实时观察 AI 思考与工具调用
astream异步流式异步环境 + 流式体验
batch同步批量离线批量任务
abatch异步批量高并发批量任务

7.7 多轮对话:复用 state 追加新消息

# 第一次调用
res = agent.invoke({"messages": [{"role": "user", "content": "你好"}]})

# 追加新问题(保留上下文)
res["messages"].append({
    "role": "user",
    "content": "你认为接下来deepseek的发展前景如何会如何??"
})
res = agent.invoke(res)

💡 关键点:传入的 res 同时也是"新的输入",Agent 会自动追加消息并更新 state。


8. 总结速记

8.1 Agent 一句话公式

Agent = create_agent(model, tools, middleware, system_prompt, response_format)
调用 = invoke / ainvoke / stream / astream / batch

8.2 5 大主题回顾

主题关键 API一句话
基本创建create_agent(model, tools)静态绑定模型与工具
动态模型wrap_model_call + middleware=[...]按消息数 / 复杂度路由模型
系统提示system_prompt 或 @dynamic_prompt静态 / 动态角色设定
结构化输出response_format=ToolStrategy(Schema)让模型按 Pydantic 字段输出
多种调用invoke / stream / ainvoke ...同步 / 异步 / 流式 / 批量

8.3 5 大主题思维导图

Agentcreate_agentmodel / toolswrap_model_callmiddlewaresystem_promptdynamic_promptcontext_schemaresponse_formatToolStrategy + Pydanticinvoke / ainvokestream / astreambatch

8.4 选型决策树

是
否
是
否
是
否
需要构建 Agent?
模型固定?
create_agent + 模型实例
create_agent + middleware
wrap_model_call
角色固定?
system_prompt 字符串
dynamic_prompt + context_schema
需要结构化输出?
response_format=ToolStrategy
直接 invoke
调用方式?
invoke / ainvoke / stream / astream / batch

参考资料

  • LangChain 官方文档 - Agents
  • LangChain 官方文档 - Tools
  • ReAct: Synergizing Reasoning and Acting in Language Models

如果本文对你有帮助,欢迎点赞 / 收藏 / 分享 💖

Ai, LangChain
LangChain Ai
许可协议:  CC BY 4.0
分享

相关文章

7月 29, 2026

LangChain Agent 完全指南:从 Tools 到 ReAct 循环的工程实践

智能体 (Agent) = 大语言模型 + 工具 + 系统提示,让 LLM 拥有"手脚"和"行为准则",能自主规划、调用工具、迭代求解复杂任务。 本文基于 LangChain v1.0,系统梳理 Agent 的核心概念、Tools 定义、Agent 构建、系统提示、结构化输出与多种调用方式,配套可直

4月 21, 2026

Gemma-4 本地量化与部署全流程

Gemma-4 本地量化与部署全流程 本文记录了在 Windows 环境下,利用 N 卡 GPU 算力,通过 llama.cpp 从零开始下载、转换、量化并部署大型语言模型(以 gemma-4-26B-A4B-it 为例)的完整操作流程。 一、 环境准备与校验 在开始前,需确保系统的 CUDA 环境

下一篇

上一篇

故障排查记录:阿里云 fnOS 网络不可达 (Network is Unreachable)

最近更新

  • LangChain Agent 完全指南:从 Tools 到 ReAct 循环的工程实践
  • 故障排查记录:阿里云 fnOS 网络不可达 (Network is Unreachable)
  • 阿里云fNOS 上优雅部署 WireGuard 客户端
  • JetBrains IntelliJ IDEA 激活指南
  • Gemma-4 本地量化与部署全流程

热门标签

samsung WireGuard Chevereto docker 破解 llama LangChain Ai Python Gemma

目录

©2026 命令行小屋. 保留部分权利。

使用 Halo 主题 Chirpy