Build Agent Syetem with Langgraph & DeepSeek


Build Agent Syetem with Langgraph & DeepSeek


Environment

首先使用 pip 安装相关依赖包:

    pip install langchain
    pip install langgraph

配置一下 API 和 URL:

from dotenv import load_dotenv

import os

  

load_dotenv(".env")

  

BASE_URL = "https://api.deepseek.com"

API_KEY = os.environ.get("API_KEY")

  

deepseek_chat_model = "deepseek-chat"

Initialization Agent

一共有三种方式来初始化 Agent:

# 1. langchain: init model,invoke,prompt template(比较简单通用)
# 2. langgraph memory
# 3. langgraph create_react_agent

Langchain

DeepSeek 兼容 openai sdk,因此可以调用 langchain_openai 来导入模型。不过 DeepSeek 自己也有 langchain 专门的一个 sdk,也可以直接调用。这种方法就是 ChatXXX Model 来进行一个初始化。

from langchain_openai import ChatOpenAI

# from langchain_deepseek import ChatDeepSeek

from langchain_core.messages import HumanMessage

from langchain_core.prompts import ChatPromptTemplate

  

llm1 = ChatOpenAI(model=deepseek_chat_model, api_key=API_KEY, base_url=BASE_URL)

  

result = llm1.invoke([HumanMessage("给我讲个笑话吧")])

print(result.content)

更通用的一个方法是使用更统一的 langchain.chat_models 导入:

from langchain.chat_models import init_chat_model

  

llm2 = init_chat_model(

    deepseek_chat_model,

    api_key=API_KEY,

    base_url=BASE_URL

)

  

result = llm2.invoke([HumanMessage("给我讲个笑话吧")])

print(result.content)

初始化模型后,我们接下来可以去创建提示词模版。使用提示词模版的好处在于,每次输入的时候并不需要都传一个 message 参数,大部分时候我们的输入都只是改变其中的一部分内容,所以可以对提示词模版中的部分元素进行一个变量替换。通过方括号 “{}” 可以在 template 里替换掉对应的部分。

这个提示词模版可以用 langchain 里通用的调用接口 invoke() 来调用。针对 llm 的 invoke 是调用 AI 服务,发送消息到 AI 模型,接收回复并返回结果。而提示词模版对象的调用是文本处理,不涉及 AI 调用。

当然,invoke() 也支持一些其它对象的调用,比如 tools,chains,而这就是 langchain 的统一对象接口调用理念的体现。

使用提示词模版的时候,我们可以直接利用 langchain 里的 chain 来进行模版填充和模型回复。

这里直接构造 chain = prompt | llm1,所起到的作用就是对 | 的两端同时调用 invoke() 方法。得益于 invoke() 对不同对象的适用性,这就使得 langchain 可以将多个模型、工具、提示词串联,来构造 agent 工作流。

# 构建prompt template

from langchain_core.prompts import ChatPromptTemplate

  

prompt = ChatPromptTemplate(

    [

        ("system", "你是一个笑话大王,请给我讲个笑话"),

        ("user", "帮我写一个主题为{topic}的笑话")

    ]

)

  

prompt.invoke({"topic": "狗"}).to_messages()

print(prompt.input_variables)

  

# langchian里chain的体现

# | 连接的两侧必须是可以被invoke的,在调用时会自动调用两侧的invoke方法

# 左边的输出会作为右边的输入

chain = prompt | llm1

  

ans = chain.invoke(

    {"topic": "狗"}

)

  

print(ans.content)

生成的笑话,虽然有点冷,,

补充:事实上一般在我们去做一些文本生成、数据生成等任务的时候,我们可能更希望有一个 json 格式的输出结果。如何让模型的输出结果自动返回 json 格式呢?

  1. 首先,我们可以借助 Pydantic 库,定义一个匹配我们需求的输出 json 格式的数据结构。Pydantic 的 BaseModel 类用于进行数据验证、类型转换等操作,确保返回格式符合需求的 json 格式要求;
  2. 接下来,我们利用模型 API 的 with_structured_output() 输出方法,将 Pydantic 模型转换为 JSON Schema 并使用 Function Calling 机制,在提示词中嵌入结构要求,令模型的输出结果符合所需的 json 格式。
from pydantic import BaseModel, Field

  

class Joke(BaseModel):

    "joke to tell user"

    setup: str = Field(description="The setup of the joke")

    punchline: str = Field(description="The punchline of the joke")

  

joke_chain = prompt | ChatDeepSeek(

    model=deepseek_chat_model,

    api_key=API_KEY,

    base_url=BASE_URL

).with_structured_output(Joke)

  

ans = joke_chain.invoke({"topic": "狗"})

print(ans.setup)

print(ans.punchline)

注意,这里的方法仅适用于支持 Function Calling 的模型

因为实际上我们采用 with_structured_output(class) 来让模型输出 json 格式时,其实是虚拟了一个自定义的 function,这个 function 规定了一个 json 转换的模式,在调用 API 的时候会打开 function calling 采用这个虚拟 function,来实现 json 格式的转换,并通过 pydantic 库验证输出。

function calling 就是自定义函数支持。简单来说,用户可以预先定义好函数(比如天气获取函数),模型可以选择调用函数,执行函数并返回结果,最终模型基于函数结果生成回答。

函数信息可以通过每次调用 API 时传递,模型在收到这样的消息,判断要调用一些函数,便不生成实际回复,而是生成一个函数调用并结束该次响应。应用程序执行函数 → 再次调用模型 → 模型基于结果生成最终回答。

当然也有模型直接支持启用 json 模式,这时候生成结果就是 json 格式的:

llm_with_json = ChatOpenAI(

    model="gpt-4-1106-preview",  # 支持 JSON Mode

    response_format={"type": "json_object"}

)


result = llm_with_json.invoke([HumanMessage("生成笑话")])

Langgraph Memory

langgraph 基于图结构来编排 Agent 工作流,其关键点就在于图结构的 message memory 储存机制。LangGraph的核心理念是将应用逻辑表示为一个图(Graph),其中:

  • 节点(Nodes):代表工作流中的独立组件或智能体,可以视为以特定方式相互交互的”参与者”。每个节点可以执行特定的功能,如生成文本、分析数据或调用外部工具。
  • 边(Edges):是Python中的函数,基于当前状态决定下一个要执行的节点,实现了工作流中的条件逻辑和控制流。
  • 状态(State):作为一种”记忆库”,记录和跟踪AI系统处理的所有有价值的信息,确保系统能够维持上下文并做出连贯的响应。

图驱动的架构使 langgraph 在需要上下文连贯性的应用中表现比较出色。

# memory: message & output, 通过维护图结构来保存

  

# class MessagesState(TypedDict):

#     messages: Annotated[list[AnyMessage], add_messages]

#     {

#         "messages": []

#     }

通过维护消息状态,langgraph 会通过合并消息、新增消息节点等来进行状态管理。

这其实就是一个图结构的 Agent Memory,实现的是一个短期记忆。对话消息上下文会通过图结构的维护来传递给 Agent。

from langgraph.checkpoint.memory import MemorySaver

from langgraph.graph import MessagesState, START, StateGraph, END

  

workflow = StateGraph(MessagesState)

  

def call_model(state: MessagesState):

    return {"messages": [llm1.invoke(state["messages"])]}

  

workflow.add_node("node1", call_model)

workflow.add_edge(START, "node1")

  

# Add Memory

memory = MemorySaver()

graph = workflow.compile(checkpointer=memory)

  

# config标识线程id,是通过线程id来存储历史消息的

config = {"configurable": {"thread_id": "1"}}

query = "你好啊,我是Cyan。"

  

input_messages = [HumanMessage(content=query)]

output_messages = graph.invoke(input_messages, config=config)

print(output_messages["messages"][-1].content)

# 这里的output包含所有历史消息,langgraph做了一个消息拼接,[-1] 获取最后一条消息(最新的AI回复)

  

query = "我叫什么名字?"

input_messages = [HumanMessage(content=query)]

output_messages = graph.invoke(input_messages, config=config)

print(output_messages["messages"][-1].content)

Single Agent (with tools)

使用 function calling 来 create 一个 ReAct 的单 agent 系统,agent 能够在推理过程中去调用已有声明的自定义函数帮助完成推理过程:

from langgraph.prebuilt import create_react_agent

  

def add(a:int, b:int):

    return a + b

  

def multiply(a:int, b:int):

    return a * b

  

agent = create_react_agent(

    model=llm1,

    tools=[add, multiply],

    config={"configurable": {"thread_id": "1"}}

)

  

input_messages = [HumanMessage(content="计算10+20,然后计算10*20")]

output_messages = agent.invoke(input_messages)

  

for message in output_messages["messages"]:

    print(message.content)

文章作者: Cyan.
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Cyan. !
评论
 上一篇
2025年(26届)四非CS保研经验帖 2025年(26届)四非CS保研经验帖
一切尘埃落定,三年的生活交上了一个答案。于是简单记了一个经验帖,总结了一下半年来的心路历程。总之,是时候在新的起点向前继续迈进了。
2025-10-16 Cyan.
下一篇 
A-Mem:Agentic Memory for LLM Agents:记忆动态更新的 Agent 记忆系统 A-Mem:Agentic Memory for LLM Agents:记忆动态更新的 Agent 记忆系统
论文提出了一种名为 A-MEM 的适用于 Agent 的主动式记忆系统,通过构建笔记、链接生成、记忆进化三个环节,来尝试解决现有 LLM 代理记忆系统结构僵化、适应性不足的问题。
2025-10-10 Cyan.
  目录