LangChain 开发Agent基础

使用LangChain开发Agent相较于其他语言来说可以节省不必要的工作量,就拿工具来举例,在LangChain中只需写好工具即可,调用模型时,LangChain自动将工具信息拿给模型

环境准备

开发LangChain依赖Python环境,版本和开发工具都有要求

python version >=3.13

pycharm version >= 2024.3.2 ,因为要集成UV虚拟环境,所以高版本工具才有支持

在项目中添加LangChain环境

bash 复制代码
uv add langchain

在项目中添加要集成的大语言模型依赖

这里采用deepseek,当然也有其他的模型依赖支持情况,比如langchain-openai langchain-ropic langchain-ollama等langchain集成页面

bash 复制代码
uv add langchain-deepseek

安装过后,在UV的配置依赖管理中可以看到当前的执行效果和依赖项

配置环境变量.env

这里的环境变量名称不是随意写的,需要参考langchain的官网进行写入,比如deepseek的env就要这样写DEEPSEEK_API_KEY

调用模型

.env文件如下所示,这里边的API_KEY经过加工,不可以直接使用

bash 复制代码
DEEPSEEK_API_KEY=sk-80ad1wertwetrewrterwtb6

调用模型python代码

python 复制代码
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model

load_dotenv()
# init_chat_model会根据前缀匹配模型,自动获取base_url,并从环境变量中获取api key
model = init_chat_model(model="deepseek-v4-pro",temperature=0.7)

# 阻塞式调用模型
#response=model.invoke("你是谁?")
#print(response)

# 流式调用模型 end="" 取消换行
response=model.stream("你是谁?")
for item in response:
    print(item.content,end="")

调用模型有两种方式,第一种阻塞方式,模型拿到所有的内容返回之后在返回,第二种是流式返回,得到一个返回一个

阻塞方式调用 :response=model.invoke("你是谁?")

流式调用:response=model.stream("你是谁?")

创建智能体

上述集成了使用LangChain调用模型,但是LangChain的主要作用是来做智能体,下面将讲述如何在LangChain中创建智能体,创建智能体有两种方式

第一种直接使用上述初始化好的model:agent = create_agent(model=model)

第二种直接传入model:agent = create_agent(model= "deepseek-v4-pro")

python 复制代码
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model

load_dotenv()
# init_chat_model会根据前缀匹配模型,自动获取base_url,并从环境变量中获取api key
model = init_chat_model(model="deepseek-v4-pro",temperature=0.7)

agent = create_agent(model=model)

调用智能体

阻塞式调用

python 复制代码
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model

load_dotenv()
# init_chat_model会根据前缀匹配模型,自动获取base_url,并从环境变量中获取api key
model = init_chat_model(model="deepseek-v4-pro",temperature=0.7)

#初始化Agent
agent = create_agent(model=model)

response = agent.invoke({
    "messages": [
        {
            "content": "你是谁?",
            "role": "user"
        }
    ]
})
print(response)

流式调用

python 复制代码
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model

load_dotenv()
# init_chat_model会根据前缀匹配模型,自动获取base_url,并从环境变量中获取api key
model = init_chat_model(model="deepseek-v4-pro",temperature=0.7)

#初始化Agent
agent = create_agent(model=model)

# response = agent.invoke({
#     "messages": [
#         {
#             "content": "你是谁?",
#             "role": "user"
#         }
#     ]
# })

response = agent.stream({
    "messages": [
        {
            "content": "你是谁?",
            "role": "user"
        }
    ],
},
    stream_mode="messages",
)
for token,metadata in response:
    if token.content:
        print(token.content,end="",flush=True)

调用智能体返回

可以发现,智能体的返回比直接调用模型返回的信息要复杂的多,这也是调用模型传递参数为字典的原因之一

python 复制代码
{'messages': [HumanMessage(content='你是谁?', additional_kwargs={}, response_metadata={}, id='b38b9592-306f-49a5-b6d0-fb188117f34e'), AIMessage(content='你好呀!我是DeepSeek,由深度求索公司创造的AI助手。😊\n\n简单来说,我是一个纯文本模型,可以帮你解答问题、处理文档、进行对话交流。虽然我不支持多模态识别(也就是"看"图片),但我可以读取你上传的图像、PDF、Word、Excel等文件中的文字信息来帮助你。\n\n我的一些特点包括:\n- **完全免费**使用\n- **上下文长度1M**(可以一次性处理像《三体》三部曲那么大体量的内容)\n- 支持**联网搜索**(需要你手动点开联网按钮)\n- 在App端还支持**语音输入**\n\n我的知识截止到2025年5月,会尽我所能为你提供准确、有用的帮助。\n\n有什么我可以帮你的吗?无论是学习、工作还是日常问题,尽管问我!🌟', additional_kwargs={'refusal': None, 'reasoning_content': '好的,用户问"你是谁?",这是一个非常简单的自我介绍问题。用户可能是初次接触,想了解我的基本身份和功能。\n\n我需要清晰、友好地介绍自己,说明我是谁、由谁创造、核心特点,并表达愿意提供帮助的态度。可以用热情的开场,然后分点列出关键特点,最后以开放性问题结束,邀请用户提出具体需求。\n\n想到了用"你好呀!"开头,然后说明我是DeepSeek,由深度求索公司开发。接着用几个要点概括主要特点,比如免费、大上下文、文件处理、联网搜索等,最后说明知识截止时间并询问需要什么帮助。'}, response_metadata={'token_usage': {'completion_tokens': 306, 'prompt_tokens': 6, 'total_tokens': 312, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 131, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 6}, 'model_provider': 'deepseek', 'model_name': 'deepseek-v4-pro', 'system_fingerprint': 'fp_9954b31ca7_prod0820_fp8_kvcache_20260402', 'id': '83c119cf-8c9c-4068-a2ce-bc64cfc9d89f', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019e3a51-8a8f-7180-be04-2e79aafd0ad0-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 6, 'output_tokens': 306, 'total_tokens': 312, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 131}})]}

智能体消息

在LangChain中,发送给模型的消息,模型返回的消息都被统一封装为BaseMessage,并且准备了多个BaseMessage的子类对应不同角色类型的消息

  • SystemMessge : Role:System
  • HumanMessage: Role:user
  • AIMessage : Role:assistant
  • ToolMessage : Role tool
python 复制代码
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_core.messages import SystemMessage,HumanMessage,AIMessage

load_dotenv()


@tool
def get_weather(location: str) -> str:
    """
    获取天气工具
    :param location: 接受的地区
    :return: 天气返回结果
    """
    return f"Current weather at {location} is rain"


#初始化Agent
agent = create_agent(model="deepseek-chat",tools=[get_weather])

response = agent.invoke({
    "messages": [
        SystemMessage(content="请使用工具获取天气信息"),
        AIMessage(content="您好,有什么可以帮您?"),
        HumanMessage(content="今天北京天气怎么样?")
    ],
}
)

for message in response["messages"]:
    message.pretty_print()

美化输出

for message in response["messages"]:

message.pretty_print()

bash 复制代码
================================ System Message ================================

请使用工具获取天气信息
================================== Ai Message ==================================

您好,有什么可以帮您?
================================ Human Message =================================

今天北京天气怎么样?
================================== Ai Message ==================================

好的,我来帮您查一下北京今天的天气情况。
Tool Calls:
  get_weather (call_00_gVpgkZE6OO67CXBiLA9m5918)
 Call ID: call_00_gVpgkZE6OO67CXBiLA9m5918
  Args:
    location: 北京
================================= Tool Message =================================
Name: get_weather

Current weather at 北京 is rain
================================== Ai Message ==================================

北京今天**下雨** 🌧️,出门记得带伞哦!如果需要了解更多详细信息,随时告诉我~

**WARN:**处遇到一个问题,就是使用init_chat_model初始化的模型再创建agent,会调用报错,原因是init_chat_model会走模型底层的dispath流程,而 create_agent会绕开init_chat_model的 provider dispatch 问题

智能体提示词工程

所谓提示词工程(Prompt Engineering),就是通过优化提示词使模型输出的结果更符合业务需要的过程。

系统提示词的组成部分

一般来说,系统提示词(System Prompt)会包含以下几个部分,通常按此顺序排列:

**身份角色(ldentity):**描述AI的职责、沟通风格和总体目标。

**指令说明(Instructions):**请指导模型如何生成所需的响应。它应该遵循哪些规则?模型应该做什么,以及模型绝对不能做什么?

**对话示例(Examples):**提供可能的输入示例,以及模型期望的输出。

**背景信息(Context):**向模型提供生成响应所需的任何额外信息,例如RAG的额外知识库数据,或您认为特别相关的任何其他数据。

在编写System Prompt时,您可以使用Markdown格式和XML标签的组合来帮助模型理解提示和上下文数据的逻辑边界。
Markdown 的标题和列表有助于标记提示的不同部分,并向模型传达层级结构。它们还可以提高开发过程中提示的可读性。
XML标签可以帮助明确区分一段内容(例如用作参考的辅助文档)的起始和结束位置。

智能体工具

所谓的工具(Tool),本质就是一个可调用的函数,但是这个函数不是我们自己去调用,而是给模型调用。因此除了定义函数外,我们还需要清晰描述这个工具,让模型知道这个工具如何使用,工具会提供以下信息

  • 工具名
  • 工具的作用
  • 工具需要的参数

在LangChain中,定义工具需要用到@tool装饰器,我们可以通过装饰器来定义工具名、工具的作用

如果不@tool装饰器没有定义工具名和作用描述,此时
**工具名:**默认就是函数名工具所需默认就是函数的参数列表

**工具所需的参数:**默认就是函数的参数列表

**工具作用的描述:**默认就是函数的文档注释

python 复制代码
@tool
def get_weather(location: str) -> str:
    """
    获取天气工具
    :param location: 接受的地区
    :return: 天气返回结果
    """
    return f"Current weather at {location} is rain"

如果工具比较复杂的话,通过pydantic model来描述参数列表

BaseModel: 用来定义"数据结构"

Field:用来给字段增加规则、描述、默认值等元信息

python 复制代码
class WeatherInput(BaseModel):
    location: str = Field(description="City name or coordinates")
    units: Literal["metric", "imperial"] = Field(default="imperial",description="Units of measurement")

@tool(args_schema=WeatherInput)
def get_weather(location: str, units: str) -> str:
    """
    获取天气工具
    :param units:
    :param location: 接受的地区
    :return: 天气返回结果
    """
    return f"Current weather at {location} is rain,{units} is metric"

智能体记忆

模型记忆有几种方式:

第一种:上下文记忆(也叫短期记忆),实现方式是滚雪球方式,将一个对话的所有chat问答和回复以全量的形式在次提供给模型

针对于Langchain中使用短期记忆,需要在创建Agent的时候指定checkpointer,这里我使用的是内存的方式,调用模型的时候还需要传入{"configurable": {"thread_id": "1"}},下方有官网的调用示例

python 复制代码
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain_core.messages import SystemMessage,HumanMessage,AIMessage
from langgraph.checkpoint.memory import InMemorySaver

load_dotenv()



#初始化Agent
agent = create_agent(model="deepseek-chat",checkpointer=InMemorySaver())

response = agent.invoke({
    "messages": [
        HumanMessage(content="你好呀 我是二哥?"),
    ],
},
{"configurable": {"thread_id": "1"}},
)

for message in response["messages"]:
    message.pretty_print()

生产中的处理方式,推荐使用的记忆存储在数据库中

自定义智能体管理内存

LangChain的记忆原理,默认情况下,代理使用 AgentState 来管理短期记忆,特别是通过 messages 键来管理对话历史

你可以扩展 AgentState 来添加额外的字段。自定义状态模式通过 state_schema 参数传递给 create_agent

python 复制代码
from dotenv import load_dotenv
from langchain.agents import create_agent, AgentState
from langchain_core.messages import SystemMessage,HumanMessage,AIMessage
from langgraph.checkpoint.memory import InMemorySaver

load_dotenv()


class CustomAgentState(AgentState):
    user_id: str
    preferences: dict

#初始化Agent
agent = create_agent(model="deepseek-chat",state_schema=CustomAgentState,checkpointer=InMemorySaver())

response = agent.invoke({
    "messages": [
        HumanMessage(content="你好呀 我是二哥?"),
    ],
    "user_id": "user_123",
    "preferences": {"theme": "dark"}
},
{"configurable": {"thread_id": "1"}},
)

for message in response["messages"]:
    message.pretty_print()

智能体流式输出,打印步骤

这里使用updates,version="v2"必须指定,这代表使用第二代agent协议

  • updates:在每个智能体的操作完成后,都会更新相关状态信息。如果在同一操作过程中进行了多次更新(例如,同时处理了多个节点),那么这些更新会分别被传输出去
  • messages:从所有调用了大语言模型的图节点中,提取 (token, metadata) 的元组数据
  • custom:利用流式写入器,可以从图节点内部输出自定义数据。
python 复制代码
from dotenv import load_dotenv
from langchain.agents import create_agent, AgentState
from langchain_core.messages import SystemMessage,HumanMessage,AIMessage
from langgraph.checkpoint.memory import InMemorySaver

load_dotenv()



#初始化Agent
agent = create_agent(model="deepseek-chat")

response = agent.stream({
    "messages": [
        HumanMessage(content="你好呀 我是二哥?"),
    ]
},
    stream_mode="updates",
    version="v2",
)
for message in response:
    if message["type"] == "updates":
        for step, data in message["data"].items():
            print(f"step: {step}")
            print(f"content: {data['messages'][-1].content_blocks}")
相关推荐
云姜.1 小时前
如何快速使用Langchain上手编程
python·langchain
情绪总是阴雨天~2 小时前
深度解析:LangChain、Agent、RAG、FC、ReAct、LangGraph、A2A、MCP — 区别、联系与全景图
python·langchain·agent·rag·langgraph·mcp·a2a
赢乐2 小时前
AI大模型学习笔记:LangChain核心组件-工具(Tools)
langchain·大模型·agent·function_call·工具(tools)·tool装饰器·定义工具
秦歌6662 小时前
LangChain-9-中间件middleware
langchain
哥本哈士奇3 小时前
LangChain DeepAgents 学习笔记
笔记·学习·langchain
JavaEdge.3 小时前
06-LangChain Tool 加载与使用指南:预制工具、SerpAPI、edge-tts、GraphQL
chrome·langchain·graphql
Restart-AHTCM3 小时前
LangChain学习之环境搭建与基础概念 - 练习(1/8)
学习·langchain
糖果店的幽灵4 小时前
LangChain 基于 Python 的技术- agent模块使用总结
开发语言·python·langchain
花千树-0104 小时前
SubAgent 基础:拥有自主工具的子代理
java·langchain·llm·agent·langgraph·subagent·harness