LangChain相关
LangChain是目前最通用的Agent开发框架,诞生之初,开发者对开发者对大模型的想象主要是希望用其搭建一个又一个工作流,而这也成为LangChain的核心技术目标,LangChain中“Chain”就是指链、也就是搭建工作流的意思。
LangGraph核心概念
LangGraph和LangChain的底层架构完全相同、接口完全相通。从开发者角度来说,LangGraph也是使用LangChain底层API来接入各类大模型、LangGraph也完全兼容LangChain内置的一系列工具。LangGraph的核心功能都是依托LangChain来完成。但是和LangChain的链式工作流哲学完全不同的是,LangGraph的基础哲学是构建图结构的工作流,并引入“状态”这一核心概念来描绘任务执行情况,从而拓展了LangChain LCEL链式语法的功能灵活程度。
图状的工作流比链式工作流更灵活,功能可扩展性更强。但图本身也是一条条chain连接起来的,其背后仍然是靠着LangChain的chain来实现的。
以下是LangGraph常见的概念:
- 状态图(graph):定义图中边和节点的输入或输出规范,即数据怎么在图中进行传递。
- 状态(state):每个节点输入输出的共享上下文(支持记忆),字典类型(一个Graph实例中只有一个state)。
messages: Annotated[list, add_messages]
如何更新messages:
-
- 追加式:典型方式,这个要求节点方法返回参数必须是dict字典类型;特别是messages这个key,它的值是list类型,借助add_messages,会把新messages内容追加到State已有的messages中。
- 覆盖式:节点返回参数必须是Graph定义的State类型,这样旧State会被新State覆盖。
- 节点(node):图中节点就是一个函数,第一个参数即上面定义的State类,返回值是状态中一些键值。这些函数的输入如上述定义的TypedDict,因此每个节点都可以通过state["grapg_state"]访问键graph_state。每个节点都返回状态graph_state的一个新值。默认情况下,每个节点返回的新值会覆盖先前的状态值。
return {"graph_state": state["graph_state"] + "I am"}
- 边(edge):用来链接节点。分为普通边和条件边。如果两个节点间传递是不变的,即a节点下一个节点一定是b,则使用普通边。如果两个节点的传递是可选的(可以是规则条件,也可以用大模型来动态决策),则使用条件边。
LangGraph官方文档
github.com/langgraph4j…,java版本的langgraph
简单demo
from langchain.chat_models import init_chat_model
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")
def chatbot(state: State):
return {"messages": [llm.invoke(state["messages"])]}
# The first argument is the unique node name
# The second argument is the function or object that will be called whenever
# the node is used.
graph_builder.add_node("chatbot", chatbot)
# 开始节点,告诉图每次从哪开始运行
graph_builder.add_edge(START, "chatbot")
# 结束节点,告诉图在哪里完成执行
graph_builder.add_edge("chatbot", END)
# 运行图前,需要编译图
graph = graph_builder.compile()
# 现在您可以随时通过输入 quit、exit 或 q 退出聊天循环。
def stream_graph_updates(user_input: str):
# 流式输出
for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}):
for value in event.values():
print("Assistant:", value["messages"][-1].content)
while True:
try:
user_input = input("User: ")
if user_input.lower() in ["quit", "exit", "q"]:
print("Goodbye!")
break
stream_graph_updates(user_input)
except:
# fallback if input() is not available
user_input = "What do you know about LangGraph?"
print("User: " + user_input)
stream_graph_updates(user_input)
break
智能体
支持同步和异步模式:
同步模式:.invoke() or .stream(),一种是非流式,另一种是流式输出。
异步模式:await .ainvoke() or .astream()。
以下是预构建中提供的快速创建agent的方法:
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(...)
response = agent.invoke({"messages": [{"role": "user", "content": "what is the weather in sf"}]})
多智能体
在多智能体系统中,智能体需要相互通信。常见的多智能体架构有:
- 监督者:由一个中心监督智能体协调各个智能体。监督者负责所有通信和任务委托,根据当前上下文和任务需求决策调用哪个智能体。
- 群集:智能体根据其专业化动态地相互通信。系统会记住上次活动的智能体,确保在后续交互中,对话与该智能体继续进行。
工具
自定义工具用法如下:
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
# 直接调用工具
tool.invoke(1, 2) -> 输出2
在agent中如何使用工具:
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet",
tools=[multiply]
)
agent.invoke({"messages": [{"role": "user", "content": "what's 42 x 7?"}]})
Memory
in_memory_store与检查点协同工作:检查点将状态保存到线程中,它允许我们存储任意信息以供跨线程访问。
短期记忆
可用于Agent跟踪多轮对话。
用法:
checkpointer = InMemorySaver()
长期记忆
实践
可参考下面这篇文章:
blog.csdn.net/u013172930/…
总结
Agent开发框架或者Agent平台固然好用,但目前AI发展迅速,协议还并没有一统;如果使用框架上手AI应用开发,容易被框架束缚,在复杂的业务需求中,框架和平台可能无法为业务定制,可能需要开发自己基于框架源码做单独定制,引入了复杂度。因此,在复杂的企业需求中,我们更倾向于手搓源码(在自己的业务中,我们也是手搓源码)。
一、框架的 “双刃剑”:效率与束缚的博弈
框架 / 平台的核心价值在于降低入门门槛、标准化基础流程。比如 LangChain、AutoGPT 等 Agent 框架,已经封装了工具调用、记忆管理、任务拆解等通用模块,能让开发者跳过 “重复造轮子” 的阶段,快速搭建出具备基础能力的 AI 应用(比如简单的问答机器人)。
但这种 “标准化” 在复杂业务中可能变成 “枷锁”:
- 协议适配局限:当业务需要对接特殊工具(如企业内部私有 API、非标准协议的硬件设备)时,框架预设的工具调用接口可能无法兼容,此时要么妥协修改业务逻辑,要么深入框架源码改底层,反而增加复杂度;
- 业务逻辑固化:框架的流程设计(如 “思考 - 调用 - 生成” 的固定链路)未必适配复杂场景(比如需要动态调整工具优先级、工具之间存在依赖关系等);
- 迭代滞后性:AI 技术迭代太快,框架对新特性(如长上下文管理优化)的支持往往滞后,而业务可能需要快速跟进这些特性。
二、手搓源码的 “自由度”:灵活与成本的平衡
手搓源码的核心优势在于完全掌控业务逻辑:
- 复杂业务:某些业务复杂,需要框架或者平台对其进行定制化开发,此时从零搭建核心模块(如自定义工具注册中心、动态任务调度器),反而比修改框架源码更清晰,便于业务快速迭代;
- 协议探索期场景:如果业务涉及前沿领域(如多 Agent 跨平台协作、MCP、A2A等新兴协议落地),框架可能尚无成熟方案,手搓源码能快速验证协议可行性,避免被框架的 “过时设计” 带偏;
但手搓的代价也很明显:
- 开发成本陡增:需要自己实现记忆机制(如向量数据库存储对话历史)、工具调用异常处理(如超时重试、格式校验)、多轮对话上下文管理等基础功能,团队需要具备扎实的 AI 工程化能力;