用 LangGraph 构建会“记住上下文”的 AI 算术助手:从工具调用到状态记忆

一句话摘要:本文带你用 LangChain + LangGraph 实现一个支持多轮对话、能调用自定义函数、并具备“记忆”能力的智能算术助手——它不仅能算 3+4,还能接着把结果乘以 2!


引言:为什么我们需要“有状态”的 Agent?

在传统的 LLM 调用中,每次请求都是无状态的。比如你问“3加4等于多少”,模型回答7;再问“乘以2是多少”,它可能不知道你指的是哪个结果。

但现实中的智能体(Agent)必须能记住上下文调用工具、并在多轮交互中保持一致性。这正是 LangGraph 的核心价值:它让你用图(Graph)的方式构建具备状态、记忆和决策能力的 AI 系统。

今天,我们就用一个极简但完整的例子,手把手搭建一个带记忆的算术助手


第一步:准备环境与密钥

我们使用 OpenAI 兼容的 API(例如 DeepSeek、Moonshot 或你自己的代理),并通过 getpass 安全输入密钥:

1
2
3
4
5
6
7
8
import os, getpass

def _set_env(var: str):
if not os.environ.get(var):
os.environ[var] = getpass.getpass(f"{var}: ")

_set_env("OPENAI_API_KEY")
_set_env("OPENAI_BASE_URL") # 例如:https://api.apiyi.com/v1

💡 提示:OPENAI_BASE_URL 可指向任何兼容 OpenAI 协议的后端,包括本地部署的 vLLM、DeepSeek API 等。

同时启用 LangSmith 追踪(可选但推荐):

1
2
3
_set_env("LANGSMITH_API_KEY")
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_PROJECT"] = "FlyAIBox"

第二步:定义“工具”——让 AI 能做精确计算

大模型擅长推理,但不擅长精确算术(尤其涉及浮点或大数)。我们通过工具调用(Tool Calling)把计算任务交给 Python 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
def add(a: int, b: int) -> int:
"""将 a 与 b 相加。"""
return a + b

def multiply(a: int, b: int) -> int:
"""将 a 与 b 相乘。"""
return a * b

def divide(a: int, b: int) -> float:
"""将 a 除以 b。"""
return a / b

tools = [add, multiply, divide]

这些函数带有清晰的 docstring,LangChain 会自动将其转换为 OpenAI Tool Schema。


第三步:绑定工具到 LLM

我们选用 deepseek-chat 模型(或其他支持工具调用的模型),并绑定工具:

1
2
3
4
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="deepseek-chat")
llm_with_tools = llm.bind_tools(tools)

现在,当用户提问时,模型会自主决定是否调用工具,并生成符合格式的 tool_call


第四步:用 LangGraph 构建反应式智能体(ReAct Agent)

LangGraph 的核心是 状态图(State Graph)。我们使用预定义的 MessagesState,它自动管理消息历史。

1. 定义系统提示

1
2
from langchain_core.messages import SystemMessage
sys_msg = SystemMessage(content="你是一个能执行算术运算的助手。")

2. 定义“助手”节点

1
2
3
4
5
from langgraph.graph import MessagesState

def assistant(state: MessagesState):
response = llm_with_tools.invoke([sys_msg] + state["messages"])
return {"messages": [response]}

3. 构建图结构

1
2
3
4
5
6
7
8
9
10
11
12
from langgraph.graph import START, StateGraph
from langgraph.prebuilt import tools_condition, ToolNode

builder = StateGraph(MessagesState)
builder.add_node("assistant", assistant)
builder.add_node("tools", ToolNode(tools))

builder.add_edge(START, "assistant")
builder.add_conditional_edges("assistant", tools_condition)
builder.add_edge("tools", "assistant")

react_graph = builder.compile()

这个图实现了经典的 ReAct(Reason + Act)循环

  • 助手思考 → 决定是否调用工具
  • 若需调用 → 执行工具 → 返回结果 → 继续思考

第五步:加入“记忆”——让多轮对话连贯起来

关键来了!我们希望第二轮提问“把上一个结果乘以2”时,AI 能知道“上一个结果”是 7。

LangGraph 通过 Checkpointer 实现状态持久化:

1
2
3
4
from langgraph.checkpoint.memory import MemorySaver

memory = MemorySaver()
react_graph_memory = builder.compile(checkpointer=memory)

然后,为每次会话指定一个 thread_id(相当于会话 ID):

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

可视化

graph TD
    A[start] --> B[assistant]
    B -.-> C[end]
    B -.-> D[tools]
    D --> B

测试多轮对话

第一轮

1
2
3
4
messages = [HumanMessage(content="3加4等于多少")]
result = react_graph_memory.invoke({"messages": messages}, config)
for m in result['messages']:
m.pretty_print()

输出:

1
2
[{'function_call': {'name': 'add', 'arguments': '{"a": 3, "b": 4}'}},
{'content': '3加4等于7。'}]

第二轮(关键!):

1
2
3
4
messages = [HumanMessage(content="将上一个结果乘以2等于多少")]
result = react_graph_memory.invoke({"messages": messages}, config)
for m in result['messages']:
m.pretty_print()

输出:

1
2
[{'function_call': {'name': 'multiply', 'arguments': '{"a": 7, "b": 2}'}},
{'content': '上一个结果是7,乘以2等于14。'}]

✅ 成功!模型利用了前一轮的上下文,完成了跨轮次推理。


总结:从函数到智能体的进化路径

阶段 能力 技术组件
1. 基础函数 精确计算 add, multiply
2. 工具调用 LLM 触发函数 bind_tools
3. ReAct 循环 自主决策+执行 LangGraph + ToolNode
4. 状态记忆 多轮上下文 MemorySaver + thread_id

这正是现代 AI 应用的典型演进路径:从孤立工具 → 到可编排的智能体 → 再到具备记忆的持续对话系统


下一步建议

  • MemorySaver 替换为数据库(如 Redis、PostgreSQL)实现持久化
  • 添加更多工具(如查天气、读数据库)
  • 用 FastAPI 封装为 Web 服务,结合你熟悉的 CLIP/FAISS 构建多模态 Agent

🌟 小贴士:所有代码均可在 Jupyter Notebook 中运行,并配合 LangSmith 可视化每一步的调用链路。