本章节参考博客
代码开源Github

在大模型应用开发中,智能体(Agent) 是连接语言模型与现实世界能力的核心桥梁。它不仅能推理,还能调用工具、处理错误、动态切换模型、记住用户上下文,甚至按需返回结构化数据。本文将通过一系列递进式实验,初步了解 LangChain/LangGraph 中 Agent 的高级用法。


1. 基础 Agent 与工具调用

首先创建一个基础 Agent,并为其配备三个工具:

  • 网络搜索(MyWebSearchTool
  • RAG 检索(RAGTool
  • 一个简单的除法函数 divide
model_manager = ModelManager()
llm = model_manager.get_qwen_model()

web_search_tool = MyWebSearchTool()
rag_tool = RAGTool()

@tool('divide', parse_docstring=True)
def divide(a: int, b: int) -> int:
    """计算两个数值的除法结果。
    
    Args:
        a (int): 被除数,
        b (int): 除数。
    
    Returns:
        int: 计算结果。
    """
    return a / b

tools = [web_search_tool, rag_tool, divide]

agent = create_agent(model=llm, tools=tools)

然后发起一个涉及计算的问题:

state = {"messages": [{"role": "user", "content": "湖南省和河南省各有多少人口?它们之间的人口比例是多少?"}]}
for event in agent.invoke(state)['messages']:
    event.pretty_print()

结果

执行我的Web搜索工具,输入的参数为: 湖南省和河南省各有多少人口?它们之间的人口比例是多少?
================================ Human Message =================================

湖南省和河南省各有多少人口?它们之间的人口比例是多少??
================================== Ai Message ==================================
Tool Calls:
  web_search_tool (call_c2540c1c985b4312b6cb89)
 Call ID: call_c2540c1c985b4312b6cb89
  Args:
    query: 湖南省和河南省各有多少人口?它们之间的人口比例是多少?
================================= Tool Message =================================
Name: web_search_tool

3月30日,河南省统计局网站发布了《2023年河南省国民经济和社会发展统计公报》。至此,2023年中部六省常住人口变动情况悉数公布.....
================================== Ai Message ==================================

根据2023年末的数据:
1. **河南省**的常住人口为 **9815万人**。
2. **湖南省**的常住人口为 **6568万人**。
两者之间的人口比例可以通过计算得出:
$$
\text{人口比例} = \frac{\text{湖南省人口}}{\text{河南省人口}} = \frac{6568}{9815}
$$

接下来我将进行计算,以提供更具体的比例信息。
Tool Calls:
  divide (call_2024a723fd454aecb75514)
 Call ID: call_2024a723fd454aecb75514
  Args:
    a: 6568
    b: 9815
================================= Tool Message =================================
Name: divide

0.6691798267957209
================================== Ai Message ==================================

根据计算结果:

- 湖南省和河南省的人口比例约为 **0.67:1**,即湖南省人口大约是河南省人口的 **67%**。

2. 自定义工具错误处理

工具执行可能失败(如除零错误)。我们可以通过中间件拦截异常并返回友好提示。

定义错误处理中间件:

from langchain.agents.middleware import wrap_tool_call
from langchain_core.messages import ToolMessage

@wrap_tool_call
def handle_tool_errors(request, handler):
    try:
        return handler(request)
    except Exception as e:
        return ToolMessage(
            content=f"Tool error: Please check your input and try again. ({str(e)})",
            tool_call_id=request.tool_call["id"]
        )

模拟错误工具:

@tool('divide_error', parse_docstring=True)
def divide_error(a: int, b: int) -> int:
    return 1 / 0  # 故意制造错误

创建带错误处理的 Agent:

tools = [web_search_tool, rag_tool, divide_error]
agent = create_agent(
			model=llm, 
			tools=tools, 
			middleware=[handle_tool_errors]
			)

# 调用
for event in agent.invoke(state)['messages']:
    event.pretty_print()

结果
divide_error 被调用时,Agent 收到的是我们自定义的错误消息,而非原始异常堆栈。

执行我的Web搜索工具,输入的参数为: 湖南省和河南省各有多少人口?
================================ Human Message =================================

湖南省和河南省各有多少人口?它们之间的人口比例是多少??
================================== Ai Message ==================================
Tool Calls:
  web_search_tool (call_02db215cff38499ab56410)
 Call ID: call_02db215cff38499ab56410
  Args:
    query: 湖南省和河南省各有多少人口?
================================= Tool Message =================================
Name: web_search_tool

湖北省与河南省同属于中国华中区域的省份,河南位于华中区域的偏北端,湖北位于华中区域的中心地带,湖南省位于华中区域的偏南处。湖北省现有面积为185900平方公里,现在的人口数量为5844万人...
================================== Ai Message ==================================

根据最新数据:

1. **河南省**:2023年末常住人口为**9815万人**。
2. **湖南省**:2023年末常住人口为**6568万人**。

### 人口比例计算:
我们使用除法来计算两者的人口比例。公式是:

$$
\text{人口比例} = \frac{\text{湖南省人口}}{\text{河南省人口}}
$$

将数值代入公式:

$$
\text{人口比例} = \frac{6568}{9815}
$$

现在我将调用 `divide_error` 工具来计算这个比例。
Tool Calls:
  divide_error (call_7a3bfc5bf40648e8b97121)
 Call ID: call_7a3bfc5bf40648e8b97121
  Args:
    a: 6568
    b: 9815
================================= Tool Message =================================

Tool error: Please check your input and try again. (division by zero)
================================== Ai Message ==================================

看起来出现了计算错误。实际上,我们已经知道河南省人口为9815万人,湖南省人口为6568万人,可以直接进行比例计算:

$$
\text{人口比例} = \frac{6568}{9815} \approx 0.67
$$

这意味着湖南省的人口约为河南省的 **67%**。

可以看到上面打印的输出,这是我们之前在中间件中定义的输出格式,Tool error: Please check your input and try again.


3. 动态模型选择:根据上下文切换 LLM

有时我们需要根据用户需求切换底层模型(如 Qwen vs DeepSeek)。

定义上下文类:

from dataclasses import dataclass
from typing import Literal

@dataclass
class CustomContext:
    provider: Literal["qwen", "deepseek"]

实现模型选择中间件:

@wrap_model_call
def dynamic_model_selection(request, handler):
    provider = request.runtime.context.provider
    print(f"获取到provider={provider}")
    request.model = qwen_model if provider == "qwen" else deepseek_model
    return handler(request)

调用时指定模型:

result = agent.invoke(
    {"messages": [{"role": "user", "content": "你是哪个公司下面的AI?"}]},
    context=CustomContext(provider="deepseek")
)

效果
Agent 将使用 DeepSeek 模型回答,而非默认的 Qwen。

获取到provider=deepseek
执行我的Web搜索工具,输入的参数为: DeepSeek是谁开发的?
获取到provider=deepseek
================================ Human Message =================================

你的老板是谁?
================================== Ai Message ==================================

我会调用搜索工具来查找相关的信息:
Tool Calls:
  web_search_tool (call_77oisnyc5sbeqj0ymjhs0vk4)
 Call ID: call_77oisnyc5sbeqj0ymjhs0vk4
  Args:
    query: DeepSeek是谁开发的?
================================= Tool Message =================================
Name: web_search_tool

DeepSeek4j简介
DeepSeek4j Spring Boot Starter为开发者提供了一种简便的方式来集成DeepSeek AI的强大功能到Spring Boot项目中。通过简单的配置和易于使用的API,即使是AI初学者也能轻松上手。该库支持流式返回、高级对话管理等功...
================================== Ai Message ==================================

DeepSeek是由杭州深度求索人工智能基础技术研究有限公司开发的。该公司于2023年4月由知名私募巨头幻方量化创立,并在2025年1月20日正式发布了高性能AI推理模型**DeepSeek-R1**,实现了国产AI技术的重大突破。

如果您需要更详细的技术文档或开发集成指南,可以随时进一步提问!

4. 动态系统提示词:个性化交互风格

我们可以根据用户角色(如“专家”或“初学者”)动态调整系统提示。

@dynamic_prompt
def user_level_prompt(request: ModelRequest) -> str:
    level = request.runtime.context.get("level", "beginner")
    base = "你是一个精通机器学习方面的专家."
    if level == "expert":
        return f"{base} 解释问题时提供更多的细节."
    else:
        return f"{base} 用小朋友都能听懂的方式表达."

agent = create_agent(
    model=llm,
    tools=tools,
    middleware=[user_level_prompt],
    context_schema={"level": str}
)

分别以 "expert""beginner" 调用:

result = agent.invoke(
    {"messages": [{"role": "user", "content": "解释一下朴素贝叶斯算法"}]},
    context={"level": "expert"}
) 
result = agent.invoke(
    {"messages": [{"role": "user", "content": "解释一下朴素贝叶斯算法"}]},
    context={"level": "beginner"}
) 

预期差异

  • 专家版:包含公式、术语、推导过程;
  • 初学者版:使用比喻、生活例子、避免数学。

[专家版输出]

现在的用户level:expert
{'messages': [HumanMessage(content='解释一下朴素贝叶斯算法', additional_kwargs={}, response_metadata={}, id='8bacbc64-aad3-46dd-a46d-05c91f906a3e'), AIMessage(content='朴素贝叶斯算法是一种基于贝叶斯定理并假设特征之间相互独立的概率分类方法。它广泛应用于文本分类、垃圾邮件过滤、情感分析等自然语言处理领域。\n\n### 贝叶斯定理\n朴素贝叶斯的核心是**贝叶斯定理**,其数学表达式为:\n$$ P(A|B) = \\frac{P(B|A) \\cdot P(A)}{P(B)} $$\n\n其中:\n- $ P(A|B) $:在已知 B 的情况下 A 发生的概率(后验概率)。\n- $ P(B|A) $:在已知 A 的情况下 B 发生的概率(似然度)。\n- $ P(A) $:A 发生的先验概率。\n- $ P(B) $:B 发生的先验概率。\n\n### 朴素贝叶斯的“朴素”假设\n朴素贝叶斯的关键假设是**特征之间的条件独立性**。也就是说,在给定类别的情况下,所有特征彼此独立。这使得计算更加简单,并且在许多实际应用中表现良好。\n\n### 算法流程\n1. **数据准备**:\n   - 将数据集划分为训练集和测试集。\n   - 对于文本分类问题,通常需要对文本进行分词、去停用词、提取特征等预处理操作。\n\n2. **训练模型**:\n   - 统计每个类别下各个特征出现的频率。\n   - 计算先验概率 $ P(C_k) $,即每个类别的概率。\n   - 计算条件概率 $ P(x_i | C_k) $,即在某个类别下某个特征出现的概率。\n\n3. **预测新样本**:\n   - 对于一个新的样本,计算其属于每个类别的后验概率 $ P(C_k | x_1, x_2, ..., x_n) $。\n   - 根据最大后验概率原则,选择概率最大的类别作为预测结果。\n\n### 常见变种\n朴素贝叶斯有几种常见的变种,适用于不同类型的数据:\n\n1. **多项式朴素贝叶斯(Multinomial Naive Bayes)**:\n   - 适用于离散特征,尤其是文本分类中的词频统计。\n   - 条件概率公式为:\n     $$ P(x_i | C_k) = \\frac{\\text{count}(x_i, C_k) + \\alpha}{\\sum_{j} \\text{count}(x_j, C_k) + \\alpha \\cdot V} $$\n     其中 $ \\alpha $ 是平滑参数,$ V $ 是词汇表大小。\n\n2. **伯努利朴素贝叶斯(Bernoulli Naive Bayes)**:\n   - 适用于二值特征(0 或 1),例如是否包含某个单词。\n   - 条件概率公式为:\n     $$ P(x_i | C_k) = \\begin{cases} \n     p_{i,k} & \\text{if } x_i = 1 \\\\\n     1 - p_{i,k} & \\text{if } x_i = 0 \n     \\end{cases} $$\n     其中 $ p_{i,k} $ 是在类别 $ C_k $ 下特征 $ x_i $ 出现的概率。\n\n3. **高斯朴素贝叶斯(Gaussian Naive Bayes)**:\n   - 适用于连续特征,假设特征服从正态分布。\n   - 条件概率公式为:\n     $$ P(x_i | C_k) = \\frac{1}{\\sqrt{2\\pi\\sigma_k^2}} \\exp\\left(-\\frac{(x_i - \\mu_k)^2}{2\\sigma_k^2}\\right) $$\n     其中 $ \\mu_k $ 和 $ \\sigma_k $ 分别是类别 $ C_k $ 下特征 $ x_i $ 的均值和标准差。\n\n### 优缺点\n#### 优点:\n1. **简单高效**:计算复杂度低,适合大规模数据集。\n2. **对小规模数据有效**:即使在小样本情况下也能取得较好的效果。\n3. **对缺失数据不敏感**:能够处理部分缺失的数据。\n\n#### 缺点:\n1. **特征独立性假设过于理想化**:现实世界中特征之间可能存在相关性,这会影响模型的准确性。\n2. **对输入数据的分布敏感**:如果特征不服从假设的分布(如高斯分布),可能会影响模型性能。\n\n### 应用场景\n朴素贝叶斯算法因其简单性和高效性,常用于以下场景:\n- **文本分类**:如新闻分类、垃圾邮件检测、情感分析等。\n- **推荐系统**:根据用户的历史行为预测兴趣。\n- **医学诊断**:根据患者的症状预测疾病类型。\n\n### 总结\n朴素贝叶斯是一种简单但强大的分类算法,尤其适合处理文本数据。虽然它的“朴素”假设在某些情况下可能不太合理,但在实践中往往能取得很好的效果。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 1064, 'prompt_tokens': 495, 'total_tokens': 1559, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen3-32B', 'system_fingerprint': None, 'id': 'chatcmpl-00ee2b2f-0021-4fb8-be16-ec56012b26f2', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--25c8b7bd-2203-4a58-9a9d-d5e71990ddb1-0', usage_metadata={'input_tokens': 495, 'output_tokens': 1064, 'total_tokens': 1559, 'input_token_details': {}, 'output_token_details': {}})]}

[初学者版输出]

现在的用户level:beginner
{'messages': [HumanMessage(content='解释一下朴素贝叶斯算法', additional_kwargs={}, response_metadata={}, id='609572f6-3404-47f7-8d67-d09ed38c2440'), AIMessage(content='朴素贝叶斯算法是一种帮助我们做决定的聪明方法。我们可以把它想象成一个猜谜游戏,这个游戏根据我们看到的东西来猜出答案。\n\n比如说,如果我们想要猜一封邮件是不是垃圾邮件,朴素贝叶斯就会看看这封邮件里有哪些词。如果它看到很多像“免费”、“赢取大奖”这样的词,它可能会猜这是一封垃圾邮件。但如果它看到的是“会议”、“报告”这样的词,它可能猜这不是垃圾邮件。\n\n这个算法之所以叫“朴素”,是因为它假设每个词都是独立的,也就是说,它不考虑这些词之间的关系,只是单独地看每一个词。虽然这是一个简单的假设,但它在很多情况下都工作得很好!\n\n所以,总结一下,朴素贝叶斯就是通过观察一些特征(比如邮件里的词),然后根据这些特征出现的概率来做预测的一种方法。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 179, 'prompt_tokens': 499, 'total_tokens': 678, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen3-32B', 'system_fingerprint': None, 'id': 'chatcmpl-e308bde6-f71c-47ec-b588-54f0e917452a', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--2f33fe73-92e6-4429-bdb0-df695eef9e6b-0', usage_metadata={'input_tokens': 499, 'output_tokens': 179, 'total_tokens': 678, 'input_token_details': {}, 'output_token_details': {}})]}

5. 结构化输出:强制返回 JSON

当需要从文本中提取结构化信息时,可指定 response_format

class Resume(TypedDict):
    name: str
    age: str
    phone: str

agent = create_agent(
    model=llm,
    tools=tools,
    response_format=ToolStrategy(Resume)
)

result = agent.invoke({
    "messages": [{"role": "user", "content": "我叫宋昌,今年35岁,电话13812345678"}]
})
print(result["structured_response"])

结果
直接获得标准 JSON 对象,无需后处理。

{'messages': [HumanMessage(content='从以下信息中提取Resume信息。我叫宋昌,今年35岁,我的电话号码是13812345678', additional_kwargs={}, response_metadata={}, id='2f94d017-40ee-452d-915e-45defed616e0'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 42, 'prompt_tokens': 576, 'total_tokens': 618, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen3-32B', 'system_fingerprint': None, 'id': 'chatcmpl-02d310af-c4db-4046-871b-3fe5c7a46e0f', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--fd0db0ef-6c3b-4211-b6e8-746a25ef7c21-0', tool_calls=[{'name': 'Resume', 'args': {'age': '35', 'name': '宋昌', 'phone': '13812345678'}, 'id': 'call_f850f162d81f41e08875bf', 'type': 'tool_call'}], usage_metadata={'input_tokens': 576, 'output_tokens': 42, 'total_tokens': 618, 'input_token_details': {}, 'output_token_details': {}}), ToolMessage(content="Returning structured response: {'name': '宋昌', 'age': '35', 'phone': '13812345678'}", name='Resume', id='4e5ad143-157b-46a3-a157-0424f87eb4ee', tool_call_id='call_f850f162d81f41e08875bf')], 'structured_response': {'name': '宋昌', 'age': '35', 'phone': '13812345678'}}
{'name': '宋昌', 'age': '35', 'phone': '13812345678'}

6. 扩展 Agent 记忆:保存自定义状态

Agent 默认记住对话历史(messages),但我们还可以添加自定义字段,如 user_info

方法一:通过中间件(适合需要干预流程的场景)

class CustomState(AgentState):
    user_info: dict

class CustomMiddleware(AgentMiddleware):
    state_schema = CustomState
    def before_model(self, state, runtime):
        if state["user_info"]["title"] == "大将军":
            return {"messages": [SystemMessage(content="将军好!……"), *state["messages"]]}

agent = create_agent(llm, tools=tools, middleware=[CustomMiddleware()])

result = agent.invoke({
    "messages": [{"role": "user", "content": "我喜欢研究理论"}],
    "user_info": {"name": "赵无恤", "title": "大将军"}
})

输出如下:

当前状态: {'messages': [HumanMessage(content='我喜欢研究理论', additional_kwargs={}, response_metadata={}, id='3a726091-e837-474a-afe6-14e69e6829e7')], 'user_info': {'name': '赵无恤', 'title': '大将军'}}
【系统提示词】: 你正在与一位军事统帅对话,请使用庄重语气,并在交流前加上“将军好!”的表达。
{'messages': [HumanMessage(content='我喜欢研究理论', additional_kwargs={}, response_metadata={}, id='3a726091-e837-474a-afe6-14e69e6829e7'), SystemMessage(content='你正在与一位军事统帅对话,请使用庄重语气,并在交流前加上“将军好!”的表达。', additional_kwargs={}, response_metadata={}, id='c2c05fb1-d1ec-4861-9b04-ab856d8898dc'), AIMessage(content='将军好!理论研究是智慧的源泉,也是制定战略与决策的重要基础。您对哪一方面的理论感兴趣?无论是兵法、政治、哲学还是其他领域,我都很乐意为您提供相关信息或进行深入探讨。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 47, 'prompt_tokens': 500, 'total_tokens': 547, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen3-32B', 'system_fingerprint': None, 'id': 'chatcmpl-732de714-22e5-4a38-be2c-f73205b148ac', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--2b6b0aff-5d33-496f-81f1-5d3f5f5a4ee3-0', usage_metadata={'input_tokens': 500, 'output_tokens': 47, 'total_tokens': 547, 'input_token_details': {}, 'output_token_details': {}})], 'user_info': {'name': '赵无恤', 'title': '大将军'}}

方法二:通过 state_schema(简洁,仅扩展数据)

agent = create_agent(model=llm, tools=tools, state_schema=CustomState)

# 第一轮
state1= agent.invoke({
    "messages": [{"role": "user", "content": "我喜欢研究军事理论"}],
    "user_info": {"name": "赵无恤", "title": "大将军"},
})

输出如下:

{'messages': [HumanMessage(content='我喜欢研究军事理论', additional_kwargs={}, response_metadata={}, id='2044bd7c-e1e4-4bc4-8440-8c1ad9a7690c'), AIMessage(content='那非常有趣!军事理论涉及战略、战术、武器系统、军队组织等多个方面。你对哪个具体领域感兴趣呢?比如现代战争中的信息战、网络战,还是传统的陆海空三军作战理论?我可以为你提供一些相关的知识或资料。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 56, 'prompt_tokens': 475, 'total_tokens': 531, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen3-32B', 'system_fingerprint': None, 'id': 'chatcmpl-9d7ea05a-5378-4703-9c33-5c2eab5e8374', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--5380d835-ad4f-4812-8b63-d2b2b10d1c84-0', usage_metadata={'input_tokens': 475, 'output_tokens': 56, 'total_tokens': 531, 'input_token_details': {}, 'output_token_details': {}})], 'user_info': {'name': '赵无恤', 'title': '大将军'}}
# 第二轮:传递完整 state 实现记忆延续
state2 = agent.invoke({
    **state1,
    "messages": state1["messages"] + [{"role": "user", "content": "推荐几本经典著作?"}]
})

输出如下:

执行我的Web搜索工具,输入的参数为: 军事理论经典著作推荐
根据网络搜索的结果,以下是几本经典的军事理论著作推荐给你:

1. **《孙子兵法》**  
   - 作者:孙武(春秋时期)  
   - 内容简介:这是中国古代最著名的军事著作,被誉为“兵学圣典”。全书共十三篇,涵盖了战争的基本原则、战略思想、战术运用以及治军原则等内容。书中提出的“知己知彼,百战不殆”等经典军事思想,至今仍被广泛研究和应用。

2. **《战争论》**  
   - 作者:卡尔·冯·克劳塞维茨(普鲁士)  
   - 内容简介:这部著作是西方近代军事理论的经典之作,提出了“战争无非是政治通过另一种手段的继续”的著名论断。书中详细探讨了战争的性质、战略、战斗、军队组织等方面的内容,对后世军事思想产生了深远影响。

3. **《大战略》**  
   - 作者:约翰·柯林斯(美国)  
   - 内容简介:这本书系统地论述了美国的战略思想和军事战略,涵盖了对外政策、地理、经济和科学技术等问题,对于研究美国的军事战略具有重要参考价值。

4. **《海权论》**  
   - 作者:阿尔弗雷德·塞耶·马汉(美国)  
   - 内容简介:这本书被认为是近代制海权理论的奠基之作。作者通过分析英国在拿破仑时代的海上霸权,强调了强大的海军控制海洋的重要性。

5. **《制空权》**  
   - 作者:朱利奥·杜黑(意大利)  
   - 内容简介:这本书系统地提出了空军建设和作战的理论,认为掌握制空权是现代战争的关键。

6. **《论持久战》**  
   - 作者:毛泽东(中国)  
   - 内容简介:这是毛泽东在抗日战争期间的重要军事著作,批判了“亡国论”和“速胜论”,提出了持久战的战略思想,对中国抗日战争的胜利起到了重要作用。

这些书籍不仅对军事理论有深入的探讨,也对政治、经济、外交等多个领域有重要的借鉴意义。希望你能从中获得启发!如果你对某本书特别感兴趣,我可以为你提供更详细的介绍或相关内容。

✅ 这样,Agent 能够记得对话,实现真正个性化服务。


总结

本文通过六个递进式实验,系统性地展示了 LangChain/LangGraph 框架下构建高阶 Agent 的关键技术路径。以下从技术架构层面进行归纳:

能力维度 技术实现机制 核心价值 典型应用场景
工具集成与推理链编排 通过 @tool 装饰器注册函数或类工具,结合 ReAct 或 Plan-and-Execute 等策略,由 LLM 动态决定工具调用顺序与参数。Agent 在单次推理中可完成“检索 → 计算 → 总结”的多步协同。 实现 LLM 与外部能力(API、数据库、计算函数)的语义桥接,突破纯文本生成的局限。 多跳问答、数据驱动决策、自动化报告生成等需组合多种能力的任务。
工具执行异常的中间件拦截 利用 wrap_tool_call 中间件对工具调用进行包装,在 handler(request) 执行前后插入异常捕获逻辑,并返回符合 ToolMessage 协议的结构化错误响应。 将底层运行时异常转化为 Agent 可理解、可恢复的语义信号,避免流程中断,提升鲁棒性。 生产环境中对不可靠工具(如第三方 API、用户自定义函数)的安全封装。
上下文感知的动态模型路由 通过自定义 Context 类携带元信息(如 provider),配合 wrap_model_call 中间件在请求分发前动态替换 request.model 字段,实现运行时模型切换。 解耦 Agent 逻辑与具体 LLM 实现,支持按任务类型、成本、性能或合规要求动态调度异构模型。 多租户 SaaS 应用、混合模型部署(如 Qwen 用于通用对话,DeepSeek 用于代码生成)。
个性化系统提示(Dynamic Prompting) 基于运行时上下文(如用户角色 level)动态生成 system prompt,通过 @dynamic_prompt 中间件注入到模型输入前缀中,引导 LLM 输出风格与深度。 实现细粒度的输出控制,无需训练多个专用模型即可适配不同用户认知水平或业务语境。 教育产品(初学者/专家模式)、客服系统(普通用户/管理员视图)、医疗问答(患者/医生视角)。
强约束结构化输出(Structured Output) 利用 response_format=ToolStrategy(schema) 指令,强制 LLM 以工具调用形式返回符合 Pydantic/TypedDict Schema 的 JSON 对象,绕过自由文本解析。 消除后处理环节的不确定性,确保输出可直接用于下游系统(如数据库写入、API 响应),提升端到端可靠性。 信息抽取(简历、票据、日志)、表单填充、API 参数生成等需高精度结构化结果的场景。
可扩展的状态管理(Custom State Schema) 通过继承 AgentState 定义包含 user_info 等字段的自定义状态类型,并在 state_schema 中声明;中间件或后续步骤可读写该状态,实现跨轮次上下文持久化。 超越仅维护消息历史的限制,支持业务相关上下文(如用户身份、会话偏好、任务进度)的端到端传递与更新。 多轮复杂对话(如订票、诊断)、个性化推荐、带状态的工作流自动化。

架构启示:上述能力均基于 LangGraph 提供的可组合中间件(Middleware)机制显式状态图(State Graph)抽象。这种设计将传统 Agent 的“黑盒推理”转化为可观测、可干预、可扩展的执行流水线,为构建企业级可靠 AI 应用奠定了工程基础。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐