LangChain
LangChain是 我们 大模型应用 和 大模型之间的桥梁,是目前Agent主流的框架,
1. 在25年10月后更新的1.0版本, 才是真正langchain
安装依赖
1. 用conda创建环境和下载依赖 conda create -n langchain python=3.13 conda activate langchain conda install langchain conda install langchain-openai
简单案例
agent = create_agent( model=llm, system_prompt=SYSTEM_PROMPT, tools=[get_user_location, get_weather_for_location], context_schema=Context, response_format=ToolStrategy(ResponseFormat), checkpointer=checkpointer )
Checkpointer
Checkpointer存储的是已正式 **State(状态)**的快照,这个状态包含
-
聊天记录(message) : 和ai说的每一句话
-
上下文变量(Context): 有Content Schema 定义的部分, 就是定义了运行时上下文的结构
-
内部节点位置: Agent现在跑到了流程的那一步了
LangChain的核心组件
-
Agent (智能体)
-
llm (模型)
-
Message (消息)
-
Tools (工具)
-
中间件
-
短期记忆
-
Stream 流式输出
-
结构化输出
Agent 智能体
Agent将 大模型 和 工具 结合在一起 , 这样我们就有了一个能进行任务推理,又能决定使用那种工具,来解决我们问题的系统
例子1 : Agent的基础使用
import json import os from langchain.agents import create_agent from langchain_openai import ChatOpenAI from pprint import pprint from dotenv import load_dotenv load_dotenv() api_key = os.getenv("ARK_API_KEY") # 系统提示词 SYSTEM_PROMPT = "你是一个语文老师" api_key = os.environ["ARK_API_KEY"] # 创建大模型 llm = ChatOpenAI( model="doubao-seed-1-6-251015", temperature=0, api_key=api_key, base_url="https://ark.cn-beijing.volces.com/api/v3", ) #创建Agent 只有大模型和 系统提示词 agent = create_agent( model=llm, system_prompt=SYSTEM_PROMPT, ) response = agent.invoke( {"messages": [{"role": "user", "content": "你是谁?"}]}, ) print(json.dumps(response, indent=2, ensure_ascii=False, default=lambda x: str(x)))
返回response
{ "messages": [ { "content": "你是谁?", "additional_kwargs": {}, "response_metadata": {}, "id": "8db61c08-4444-403a-968e-4093a95edeb0" }, { "content": "我是你的语文老师呀~无论是字词含义的解析、经典文章的赏析、作文写作的指导,还是文学常识的科普,都可以随时和我交流探讨 哦!", "additional_kwargs": { "refusal": null }, "response_metadata": { "token_usage": { "completion_tokens": 177, "prompt_tokens": 45, "total_tokens": 222, "completion_tokens_details": { "accepted_prediction_tokens": null, "audio_tokens": null, "reasoning_tokens": 139, "rejected_prediction_tokens": null }, "prompt_tokens_details": { "audio_tokens": null, "cached_tokens": 0 } }, "model_provider": "openai", "model_name": "doubao-seed-1-6-251015", "system_fingerprint": null, "id": "021779109178404d124c43c387314b34f4e9e457720e339368e9c", "service_tier": "default", "finish_reason": "stop", "logprobs": null }, "id": "lc_run--019e3b2b-abd8-74e2-8f54-5d4275d36f39-0", "tool_calls": [], "invalid_tool_calls": [], "usage_metadata": { "input_tokens": 45, "output_tokens": 177, "total_tokens": 222, "input_token_details": { "cache_read": 0 }, "output_token_details": { "reasoning": 139 } } } ] }
response的各个参数
message (基础识别属性 )
决定了这条信息是谁发的, 怎么找到这条信息
-
content : 核心内容 , 是模型真正说出来的话
-
id : 唯一标识符, 为每个消息生成id, 用来在复杂图流程中(LangGraph) 中定位
-
type : 消息类型 , human 代表用户 , ai代表 ai
-
additional_kwargs : 额外参数, 各家厂家都例如 openai都有自己的一套标准,不一定完完全全用langchain的,所以这里就放langchain中没有的参数
usage_metadata (消耗统计属性 )
记录对话消耗的资源
-
input_tokens : 输入Token数
-
output_tokens : 输出token数
-
total_tokens : 总消耗token数
-
input_token_details : 输入明细
cache_read : 是否读取了之前的缓存(读取缓存token会少)
-
output_token_details : 输出明细
reasoning : 推理token, 类似于豆包,DeepSeek都支持思考模式, 模型的思考过程是不展示在正文中的,但是也消耗token
response_metadata (响应详情属性)
这是由大模型供应商返回的原始信息"快照"。
"model_provider": "openai", -->模型供应商 , 虽然用的是豆包,但用的是openai的标准 "model_name": "doubao-seed-1-6-251015", -->具体模型型号 "id": "021779109178404d124c43c387314b34f4e9e457720e339368e9c", --> 请求id,方便后续查看日志 "service_tier": "default", --> 服务层级,default表示标准服务速度 "finish_reason": "stop", --> 结束原因,stop是理想结束状态,代表模型完整的生成 "logprobs": null --> 对数概率,代表模型返回回答的信心指数(相当于人说话时,心里默念: 这句话我百分百确定 / 大概七成把握 / 随口乱说logprobs 就是把这份内心把握值记录下来。)
其他核心属性
"tool_calls": --> 工具调用指令, 如果Agent觉得需要查天气,那么这里会放查天气的tool "invalid_tool_calls": --> 非法工具调用,如果模型调用工具错误了,这里会记录错误 refusal : 拒绝回复 , 例如:我想造一个炸弹,这种模型会拒绝回复,在这里记录拒绝原因
例子2 : 动态选择大模型
# 模型调度中间件:根据对话轮次自动切换模型 @wrap_model_call def auto_switch_model(req: ModelRequest, execute_func) -> ModelResponse: # 打印请求详情日志 req_info = vars(req) print(json.dumps(req_info, ensure_ascii=False, indent=2, default=str)) print("====================对话分割线====================") chat_history = req.messages chat_round = len(chat_history) print(f"当前对话累计轮次:{chat_round}") # 核心判断逻辑不变:超过4轮用深度模型,否则轻量模型 if chat_round > 4: print("【调度】对话偏长,启用深度推理模型") target_llm = deep_reason_model else: print("【调度】简短闲聊,启用轻量化对话模型") target_llm = light_chat_model # 覆写请求指定模型并放行 return execute_func(req.override(model=target_llm))
request里包含哪些内容
-
Message : 完整的消息列表 包括 human的 , ai的
-
model : 原本使用的大模型
-
tools : 工具列表
-
state : 状态 , 例如 用户 id , 当前处理的步骤,临时变量等
例子3 : 动态选择提示词
可以用来遇到不同的用户身份
# ====================== 动态提示词中间件 ====================== @dynamic_prompt def identity_based_prompt(req: ModelRequest) -> str: # 打印请求详情(保留调试逻辑) req_detail = vars(req) print(json.dumps(req_detail, indent=2, ensure_ascii=False, default=lambda x: str(x))) print("----------------------------------\n") # 从运行时上下文获取用户身份 runtime_ctx = getattr(req.runtime, "context", {}) current_identity = runtime_ctx.get("user_identity", "default") # 基础系统提示 base_intro = "你是智能助手阿泽。" # 身份判断逻辑(完全不变) if current_identity == "expert": print("--- [动态切换] 当前身份:专业模式 ---") return f"{base_intro} 你现在是资深技术专家,回答专业、严谨、有深度。" elif current_identity == "beginner": print("--- [动态切换] 当前身份:入门模式 ---") return f"{base_intro} 你现在是耐心导师,用最简单通俗的语言解释问题。" return base_intro # ====================== 创建智能体 ====================== ai_assistant = create_agent( model=ai_model, middleware=[identity_based_prompt], context_schema=ChatContext ) # ====================== 上下文结构定义 ====================== class ChatContext(TypedDict): user_identity: str # ====================== 测试运行 ====================== if __name__ == "__main__": print("\n--- 测试 1:专业模式 ---") res_pro = ai_assistant.invoke( {"messages": [{"role": "user", "content": "你是谁"}]}, context={"user_identity": "expert"} ) print(f"专业模式回答:{res_pro['messages'][-1].content}")
- context
作用:传参、传身份、传场景、传配置 →
(你传给 Agent 的 "额外信息" ,不是用户问题,不是对话历史,让 Agent 知道当前用户是谁、处于什么场景、该用什么语气回答。)
- context_schema
作用:定义 context 的格式 → 让代码更安全、更规范 (context 的格式约束 / 类型定义。)
结构化输出
结构化输出让 Agent 返回 我们指定格式 的数据 , 这样就不需要再经过解析就能拿到 JSON , Pydantic 或者 数据类形式的数据
# ====================== 定义结构化输出格式 ====================== class PersonInfo(BaseModel): """用于存储用户个人信息的数据结构""" username: str = Field(description="用户的真实姓名") mail_address: str = Field(description="用户的电子邮箱") mobile_number: str = Field(description="用户的手机号码") # ====================== 创建结构化提取智能体 ====================== info_extractor = create_agent( model=ai_llm, system_prompt="你是专业信息提取员,能从任意文本中精准提取用户信息并按格式输出。", response_format=ToolStrategy(PersonInfo) ) # ====================== 执行提取任务 ====================== input_content = "请提取信息:李四,邮箱是 lisi@demo.com,联系电话是 13912345678" print(f"--- 待提取文本内容 ---\n{input_content}\n") # 调用智能体 response = info_extractor.invoke({ "messages": [{"role": "user", "content": input_content}] })
响应格式 (Response Format)
response_format=ToolStrategy(PersonInfo) 通过ToolStrategy 设置返回格式为 PersonInfo类 , 也就是 username: str = Field(description="用户的真实姓名") mail_address: str = Field(description="用户的电子邮箱") mobile_number: str = Field(description="用户的手机号码") 最后输出==> {'mail_address': 'lisi@demo.com', 'mobile_number': '13912345678', 'username': '李四'}
流式输出
LangChain 实现了一个流式传输系统来提供实时更新。 不需要等完整的响应构造完,就可以渐进式的显示输出,能很好的提高用户体验。
# 1. 系统提示词 SYSTEM_PROMPT = "你是专业AI助手,回答清晰、简洁、有条理,不啰嗦" # 2. 用户问题 USER_QUESTION = "请简单介绍一下人工智能的日常应用场景,50字以内." # 创建智能体 agent = create_agent( model=llm, system_prompt=SYSTEM_PROMPT, ) # ===================== 1. 完整整体输出(一次性,不流式) ===================== print("\n===== 完整整体响应 =====\n") full_response = llm.invoke(USER_QUESTION) # 直接用 llm 调用,不卡 agent print(full_response.content) # ===================== 2. 流式输出(保留你原来的逻辑) ===================== print("\n\n===== 流式分段响应 =====\n") for chunk in agent.stream( {"messages": [{"role": "user", "content": USER_QUESTION}]}, stream_mode="messages" ): print("----------------------------------\n") print(json.dumps(chunk, indent=2, ensure_ascii=False, default=lambda x: str(x)))
流式输出模式
values
: 返回完整的State对象(整个对话),是步骤级的,用于 状态追踪,持久化快照
=====> stream_mode="values" for chunk in agent.stream( {"messages": [{"role": "user", "content": USER_QUESTION}]}, stream_mode="values" ): print("----------------------------------\n") print(json.dumps(chunk, indent=2, ensure_ascii=False, default=lambda x: str(x))) ================== { "messages": [ "content='请简单介绍一下人工智能的日常应用场景,50字以内.' additional_kwargs={} response_metadata={} id='804cfb13-c11b-42a3-a307-5de220b401c0'" ] } ---------------------------------- { "messages": [ "content='请简单介绍一下人工智能的日常应用场景,50字以内.' additional_kwargs={} response_metadata={} id='804cfb13-c11b-42a3-a307-5de220b401c0'", "content='语音助手、电商推荐、人脸识别支付、智能导航、AI客服等是人工智能在日常生活中的常见应用场景。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 105, 'prompt_tokens': 68, 'total_tokens': 173, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 81, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'doubao-seed-1-6-251015', 'system_fingerprint': None, 'id': '021779239369242b47c0529c98d6cfd28de18ec7839083b7fbaeb', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019e42ee-3a52-7253-9cf1-184822ec65cc-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 68, 'output_tokens': 105, 'total_tokens': 173, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 81}}" ] }
updates
: 返回当前节点产生的增量, 是节点级的, 用于监控节点流水线执行
for chunk in agent.stream( {"messages": [{"role": "user", "content": USER_QUESTION}]}, stream_mode="updates" ): ============== ===== 流式分段响应 ===== ---------------------------------- { "model": { { "model": { "model": { "messages": [ "content='AI日常应用包括语音助手、电商推荐、地图导航、人脸识别支付、智能客服等场景。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 134, 'prompt_tokens': 68, 'total_tokens': 202, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 113, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'doubao-seed-1-6-251015', 'system_fingerprint': None, 'id': '021779239610884c2ac42b5b86809233f1159b66476f323e06698', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019e42f1-ea30-7de3-9aac-abbca9e41630-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 68, 'output_tokens': 134, 'total_tokens': 202, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 113}}" ] } }
messages
: 返回消息块(token) , 是token级(一个词一个词的), 用于实时对话,UI渲染
for chunk in agent.stream( {"messages": [{"role": "user", "content": USER_QUESTION}]}, stream_mode="messages" ): ------------------------- [ "content='等' additional_kwargs={} response_metadata={'model_provider': 'openai'} id='lc_run--019e42f3-2d75-78f0-b2ea-2663d81b7b9d' tool_calls=[] invalid_tool_calls=[] tool_call_chunks=[]", { "ls_integration": "langchain_chat_model", "langgraph_step": 1, "langgraph_node": "model", "langgraph_triggers": [ "branch:to:model" ], "langgraph_path": [ "__pregel_pull", "model" ], "langgraph_checkpoint_ns": "model:25fb39ad-5029-0f46-c4ff-3d9a41a1ede4", "checkpoint_ns": "model:25fb39ad-5029-0f46-c4ff-3d9a41a1ede4", "ls_provider": "openai", "ls_model_name": "doubao-seed-1-6-251015", "ls_model_type": "chat", "ls_temperature": 0.0 } ] ---------------------------------- [ "content='是' additional_kwargs={} response_metadata={'model_provider': 'openai'} id='lc_run--019e42f3-2d75-78f0-b2ea-2663d81b7b9d' tool_calls=[] invalid_tool_calls=[] tool_call_chunks=[]", { "ls_integration": "langchain_chat_model", "langgraph_step": 1, "langgraph_node": "model", "langgraph_triggers": [ "branch:to:model" ], "langgraph_path": [ "__pregel_pull", "model" ], "langgraph_checkpoint_ns": "model:25fb39ad-5029-0f46-c4ff-3d9a41a1ede4", "checkpoint_ns": "model:25fb39ad-5029-0f46-c4ff-3d9a41a1ede4", "ls_provider": "openai", "ls_model_name": "doubao-seed-1-6-251015", "ls_model_type": "chat", "ls_temperature": 0.0 } ] ---------------------------------- [ "content='人工智能' additional_kwargs={} response_metadata={'model_provider': 'openai'} id='lc_run--019e42f3-2d75-78f0-b2ea-2663d81b7b9d' tool_calls=[] invalid_tool_calls=[] tool_call_chunks=[]", { "ls_integration": "langchain_chat_model", "langgraph_step": 1, "langgraph_node": "model", "langgraph_triggers": [ "branch:to:model" ], "langgraph_path": [ "__pregel_pull", "model" ], "langgraph_checkpoint_ns": "model:25fb39ad-5029-0f46-c4ff-3d9a41a1ede4", "checkpoint_ns": "model:25fb39ad-5029-0f46-c4ff-3d9a41a1ede4", "ls_provider": "openai", "ls_model_name": "doubao-seed-1-6-251015", "ls_model_type": "chat", "ls_temperature": 0.0 } ] ---------------------------------- [ "content='的' additional_kwargs={} response_metadata={'model_provider': 'openai'} id='lc_run--019e42f3-2d75-78f0-b2ea-2663d81b7b9d' tool_calls=[] invalid_tool_calls=[] tool_call_chunks=[]", { "ls_integration": "langchain_chat_model", "langgraph_step": 1, "langgraph_node": "model", "langgraph_triggers": [ "branch:to:model" ], "langgraph_path": [ "__pregel_pull", "model" ], "langgraph_checkpoint_ns": "model:25fb39ad-5029-0f46-c4ff-3d9a41a1ede4", "checkpoint_ns": "model:25fb39ad-5029-0f46-c4ff-3d9a41a1ede4", "ls_provider": "openai", "ls_model_name": "doubao-seed-1-6-251015", "ls_model_type": "chat", "ls_temperature": 0.0 } ] ----------------------------------
debug
: 返回完整的执行链路日志, 非常详细,能看到执行过程中是否正常执行,用于性能分析和调试
for chunk in agent.stream( {"messages": [{"role": "user", "content": USER_QUESTION}]}, stream_mode="debug" ): =============== { "step": 1, "timestamp": "2026-05-20T01:17:10.162649+00:00", "type": "task", "payload": { "id": "c76d884a-1ad5-fd91-aa32-3927eeb6a4ee", "name": "model", "input": { "messages": [ "content='请简单介绍一下人工智能的日常应用场景,50字以内.' additional_kwargs={} response_metadata={} id='37e0b1ac-53c5-4a0f-80fb-c4745c622d10'" ] }, "triggers": [ "branch:to:model" ] } } ----- "step": 1, "timestamp": "2026-05-20T01:17:14.938457+00:00", "type": "task_result", "payload": { "id": "c76d884a-1ad5-fd91-aa32-3927eeb6a4ee", "name": "model", "print("\n\n===== 流式分段响应 =====\n") for chunk in agent.stream( {"messages": [{"role": "user", "content": USER_QUESTION}]}, stream_mode="debug" ):": null, "result": { "messages": [ "content='语音助手(如Siri)、智能推荐(电商/视频)、导航、人脸识别(解锁/支付)、智能家电等是AI日常常见应用。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 127, 'prompt_tokens': 68, 'total_tokens': 195, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 93, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'doubao-seed-1-6-251015', 'system_fingerprint': None, 'id': '0217792398301087d9c2387c122bdc91a342e02a9471447b7bafc', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019e42f5-4293-70c1-b8a6-527d582afd96-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 68, 'output_tokens': 127, 'total_tokens': 195, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 93}}" ] }, "interrupts": [] } }
工具
模型本身闭源的QA,所以有些事情例如 : 查今天天气,查热点新闻等这些大模型是做不到的。工具就类似于一些大模型可以用的组件,通过这些组件模型就可以做到一些做不到的事情。
(例如: 让模型帮我看看今天北京的天气,那么就可以创建一个可以用来查天气的工具,那么模型就可以通过这个工具拿到天气情况,再给我们返回结果)
通过@tool定义工具
@tool def get_current_city(runtime: ToolRuntime[Context]) -> str: """根据用户标识获取用户常用居住城市""" user_id = runtime.context.user_id return "杭州" if user_id == "1" else "武汉"
创建Agent时把 工具传给tools
# Create agent agent = create_agent( model=llm, system_prompt=SYSTEM_PROMPT, tools=[get_current_city, get_traffic_info], context_schema=Context, )
在执行时模型就可以根据问题,来调用需要的工具获取答案
Define system prompt SYSTEM_PROMPT = """你是专业出行规划助手,语言通俗易懂,善于贴心规划出行方案。 你可调用两个实用工具: - get_traffic_info:查询指定城市出行交通状况 - get_current_city:自动获取用户常驻城市 用户询问出行相关问题时,优先确认城市信息,未明确地点则自动调取用户所在城市再作答。""" # Define context schema @dataclass class Context: """Custom runtime context schema.""" user_id: str # Define tools @tool def get_traffic_info(city: str) -> str: """查询指定城市实时出行交通情况""" return f"{city}当前路况顺畅,公交地铁出行便捷,适合短途游玩出行!" @tool def get_current_city(runtime: ToolRuntime[Context]) -> str: """根据用户标识获取用户常用居住城市""" user_id = runtime.context.user_id return "杭州" if user_id == "1" else "武汉" # Create agent agent = create_agent( model=llm, system_prompt=SYSTEM_PROMPT, tools=[get_current_city, get_traffic_info], context_schema=Context, ) # Run agent config = {"configurable": {"thread_id": "1"}} response = agent.invoke( {"messages": [{"role": "user", "content": "最近适合出门游玩吗"}]}, config=config, context=Context(user_id="1") )
message消息
消息是 LangChain 中模型上下文的基本单位。它们代表模型的输入和输出,携带内容和元数据,用于在与 LLM 交互时表示对话状态。
消息是包含以下内容的对象:
-
角色 - 标识消息类型(例如
system、user) -
内容 - 表示消息的实际内容(例如文本、图像、音频、文档等)
-
元数据 - 可选字段,例如响应信息、消息 ID 和令牌使用情况
消息对象
1.系统消息 SystemMessage(content=SYSTEM_PROMPT), 2. 人的消息 HumanMessage(content="Can you help me learn Python?"), 3. AI消息 AIMessage("I'd be happy to help you with that question!") 4. 工具消息 ToolMessage
使用消息的最简单方式是创建消息对象,并在调用时将它们传递给模型。
SYSTEM_PROMPT = "你是专业编程答疑助手,简洁清晰、一步到位解答问题" ai_msg = AIMessage(content="Sure! I can help you with any programming problems.") messages = [ SystemMessage(content=SYSTEM_PROMPT), HumanMessage(content="Can you help me learn Python?"), ai_msg, HumanMessage(content="Perfect! Please explain what a list is."), ] for msg in messages: print(f"{msg.__class__.__name__}: {msg.content}") response = llm.invoke(messages) print("="*50) print(json.dumps(response, indent=2, ensure_ascii=False, default=lambda x: str(x)))
通过dict的方式创建消息列表 (但是这种方式最终也是会转成 上面的消息对象格式)
messages = [ {"role": "system", "content": "You are a poetry expert"}, {"role": "user", "content": "Write a haiku about spring"}, {"role": "assistant", "content": "Cherry blossoms bloom..."} ] response = model.invoke(messages)
llm模型
llm是强大的 AI 工具,能够像人类一样理解和生成文本。它们用途广泛,可用于撰写内容、翻译语言、总结信息和回答问题,而无需针对每项任务进行专门训练
除了文本生成之外,许多模型还支持:
-
工具调用 - 调用外部工具(如数据库查询或 API 调用)并将结果用于响应中。
-
结构化输出 - 模型的响应被限制为遵循定义的格式。
-
多模态 - 处理和返回非文本数据,如图像、音频和视频。
-
推理 - 模型执行多步推理以得出结论。
模型是 Agent代理 的推理引擎。它们驱动代理的决策过程,决定调用哪些工具、如何解释结果以及何时提供最终答案。
llm的基本用法
import os from langchain_openai import ChatOpenAI from dotenv import load_dotenv load_dotenv() api_key = os.getenv("ARK_API_KEY") # 初始化模型 llm = ChatOpenAI( model="doubao-seed-1-8-251228", temperature=0, api_key=api_key, base_url="https://ark.cn-beijing.volces.com/api/v3", ) # 基础调用 res = llm.invoke("简单介绍一下Python语言") # 打印结果 print(res.content)
llm和Agent的区别
llm
llm.invoke(message) ==>生成单词的 LLm 响应
-
输入 : massage列表 或 prompt
-
输出 : AIMessage (单条响应)
-
功能 :
-
简单对话生成
-
支持消息历史
-
无工具调用,无循环,无状态管理
-
agent
agent.invoke({"messages": [...]}) → 可以多步工具调用 + 最终回答
-
输入 : 消息列表
-
输出 : 完整的对话历史
-
功能 :
-
可以工具调用
-
可以ReAct (思考(Thought) → 行动(Action) → 观察(Observation) 循环,直到解完题。)
-
支持状态管理(LangGraph)
-
可以持久化、流式、结构化
-
支持 HITL (AI 干活,关键步骤停下来等人审核 / 确认 / 修正,再继续)
-
短期记忆
短期记忆 让您的应用程序能够记住单个线程 或对话中的先前交互。
通过 checkpointer=InMemorySaver(), 让Agent带有短期记忆,就可以通过config获取state
(state = Agent 的记忆 + 当前进度 + 全部上下文)
@dataclass class Context: user_id: str @tool def get_weather_info(runtime: ToolRuntime[Context], city: str = None) -> str: """获取天气信息""" if not city: user_id = runtime.context.user_id city = "佛罗里达" if user_id == "1" else "旧金山" return f"{city} 总是阳光明媚!" llm = ChatOpenAI( model="doubao-seed-1-8-251228", temperature=0, api_key=os.getenv("ARK_API_KEY"), base_url="https://ark.cn-beijing.volces.com/api/v3", ) # 核心:带短期记忆的 Agent agent = create_agent( model=llm, system_prompt="你是专业气象预报员,使用工具获取天气。", tools=[get_weather_info], context_schema=Context, checkpointer=InMemorySaver(), ) # 第一次对话 config = {"configurable": {"thread_id": "1"}} response = agent.invoke( {"messages": [{"role": "user", "content": "今天什么天气?"}]}, config=config, context=Context(user_id="1") ) # 查看记忆(短期记忆内容) state = agent.get_state(config) print("最终回答:", response["messages"][-1].content) print("\n记忆中存储的消息:") for i, msg in enumerate(state.values["messages"]): print(f"[{i}] {msg.content[:50]}...")
state
state = agent.get_state(config) ==># 使用 config 获取当前 thread_id 的最新状态
state.values : 核心数据,主要包含了mseeage列表(对话历史)
主要作用
-
上下文记忆 : 让ai知道前面说了什么,工具的返回结果是什么
-
数据传递 : 在state中定义的其他变量
-
业务逻辑
state.next (流程控制)
是一个元组,记录了图接下来要执行的节点名称 ,如果下一个节点是工具那么就是 ('tool',)
作用
-
断点续传 : 如果agent流程需要'人工审批',那么程序就会停下来,next会指向审批节点,直到你允许他继续
-
状态监控 : 通过他你可以判断 ai当前的状态是在 '思考'(agent节点),还是在调用工具(tools节点)
state.metadata
状态本身的数据
包含
-
source : 状态来源, 告诉你当前的快照是怎么产生的 ,(loop:表示自动运行,input:表示初始输入,update:表示开发者收手动调用修改了数据)
-
step : 步数,记录当前是第几次节点转换
-
parents : 父级状态映射(这个字段用于记录"当前状态是从哪个状态演变而来的"。)
作用
-
通过setp判断模型是不是陷入死循环
-
在复杂的分支流程中,parents 用于最终逻辑是怎么合并的
state.config
用于再次定位掉 当前这个状态的 Id
包含:thread_id 和唯一的 Checkpoint_id
作用:
-
如果保存了10个步骤的快照,那么可以通过checkpoint_id 调用 agent.invoke ,让ai回到那个"时间段"
-
多线程隔离,确保不同用户对话不会搞混
中间件
中间件负责Agent流程中,拦截、过滤、转发、统一处理流程 ,不直接干活,只管流程管控,可以更精细地控制代理(Agent)内部的执行流程
SummarizationMiddleware 自动压缩上下文
1. 在创建agent时通过 middleware传中间件 2. SummarizationMiddleware : 当token到达4000时,保留最后20调数据,20条前面的都给压缩成摘要 from langchain.agents import create_agent from langchain.agents.middleware import SummarizationMiddleware agent = create_agent( model="openai:gpt-4o", tools=[weather_tool, calculator_tool], middleware=[ SummarizationMiddleware( model="openai:gpt-4o-mini", max_tokens_before_summary=4000, # 在 4000 个 token 时触发摘要 messages_to_keep=20, # 摘要后保留最近 20 条消息 summary_prompt="Custom prompt for summarization...", # 可选 ), ], )
ModelCallLimitMiddleware 模型限制
给 AI 模型调用次数 "上锁" ,限制模型最多推理多少次,防止 AI 无限循环、死循环、疯狂调用、浪费 token
from langchain.agents import create_agent from langchain.agents.middleware import ModelCallLimitMiddleware agent = create_agent( model="openai:gpt-4o", tools=[...], middleware=[ ModelCallLimitMiddleware( thread_limit=10, # 每个线程(跨多次运行)最多 10 次调用 run_limit=5, # 每次运行(单次调用)最多 5 次调用 exit_behavior="end", # 或者 "error" 以引发异常 ), ], )
ToolCallLimitMiddleware 工具限制
限制智能体调用工具的最大次数,防止频繁反复调用工具、死循环调用,节约资源 + 控制流程
from langchain.agents import create_agent from langchain.agents.middleware import ToolCallLimitMiddleware # 限制所有工具调用 global_limiter = ToolCallLimitMiddleware(thread_limit=20, run_limit=10) # 限制特定工具 search_limiter = ToolCallLimitMiddleware( tool_name="search", #要限制的特定工具。如果未提供,则限制适用于所有工具。 thread_limit=5, #线程中所有运行的最大工具调用次数。默认为无限制。 run_limit=3, #单次调用中最大工具调用次数。默认为无限制 ) agent = create_agent( model="openai:gpt-4o", tools=[...], middleware=[global_limiter, search_limiter], )
ModelFallbackMiddleware模型错误兜底
主模型挂了、报错、超时、限流时,自动切换到备用模型继续运行,保证服务不中断。
from langchain.agents import create_agent from langchain.agents.middleware import ModelFallbackMiddleware agent = create_agent( model="gpt-4o", #主模型 tools=[], middleware=[ ModelFallbackMiddleware( "gpt-4o-mini", # 备用模型 "claude-3-5-sonnet-20241022", ), ], )
PIIMiddleware 敏感信息屏蔽
自动识别并脱敏屏蔽隐私敏感信息,防止手机号、身份证、住址等私密数据泄露
from langchain.agents import create_agent from langchain.agents.middleware import PIIMiddleware agent = create_agent( model="gpt-4o", tools=[], middleware=[ #邮箱 和信用卡 数据脱敏 PIIMiddleware("email", strategy="redact", apply_to_input=True), PIIMiddleware("credit_card", strategy="mask", apply_to_input=True), ], )
LLMToolSelectorMiddleware 模型选择工具
如果有多个工具时,根据用户提问语义,自动筛选匹配的工具,只把相关工具下发给模型,过滤无关工具。
from langchain.agents import create_agent from langchain.agents.middleware import LLMToolSelectorMiddleware agent = create_agent( model="gpt-4o", #主模型 tools=[tool1, tool2, tool3, tool4, tool5, ...], middleware=[ LLMToolSelectorMiddleware( model="gpt-4o-mini", # 用轻量模型专门负责选工具(省钱、快) max_tools=3, # 最多只选 3 个工具 always_include=["search"], # 不管什么情况,都带上 search 工具 ), ], )
ToolRetryMiddleware工具重试
工具调用失败时,自动重试 N 次,避免因为网络波动、接口超时、临时故障导致任务失败。
from langchain.agents import create_agent from langchain.agents.middleware import ToolRetryMiddleware agent = create_agent( model="gpt-4o", tools=[search_tool, database_tool], middleware=[ ToolRetryMiddleware( max_retries=3, # 最多重试 3 次 backoff_factor=2.0, # 每次重试等待时间翻倍 initial_delay=1.0, # 第一次重试等 1 秒 ), ], )
ModelRetryMiddleware模型重试
模型调用失败时,自动重试,解决模型临时报错、超时、限流问题,让 AI 更稳。
from langchain.agents import create_agent from langchain.agents.middleware import ModelRetryMiddleware agent = create_agent( model="gpt-4o", tools=[search_tool, database_tool], middleware=[ ModelRetryMiddleware( max_retries=3, #模型调用失败,最多自动重试 3 次 backoff_factor=2.0, #指数退避(等待时间越来越长) initial_delay=1.0, #第一次失败后 等 1 秒 再重试 ), ], )
ContextEditingMiddleware清除tools上下文
允许你在对话过程中,手动修改、插入、删除 AI 记忆里的消息(上下文),相当于直接编辑 AI 的大脑记忆。
ContextEditingMiddleware + ClearToolUsesEdit = 自动清理工具调用记录
from langchain.agents import create_agent from langchain.agents.middleware import ContextEditingMiddleware, ClearToolUsesEdit agent = create_agent( model="gpt-4o", tools=[], middleware=[ ContextEditingMiddleware( edits=[ ClearToolUsesEdit( trigger=100000, # 触发清理的长度阈值,把旧的工具调用消息删掉,防止上下文太长、爆 token keep=3, # 保留最近3条工具记录 ), ], ), ], )
ShellToolMiddleware 命令
ShellToolMiddleware = 给 AI 命令行执行加 "安全沙箱"
限制 AI 只能在指定文件夹里操作,不能乱跑、不能乱删、不能破坏系统。
当我的agent tools能力不够的时候,它自己写一个python脚本,脚本写在workspace中,理论上只要权限够,它爱干啥干啥。 from langchain.agents import create_agent from langchain.agents.middleware import ( ShellToolMiddleware, HostExecutionPolicy, ) agent = create_agent( model="gpt-4o", tools=[search_tool], middleware=[ ShellToolMiddleware( workspace_root="/workspace", #AI 只能在这个文件夹里干活! execution_policy=HostExecutionPolicy(), #允许在当前机器(本机)执行命令 ), ], )
FilesystemFileSearchMiddleware 文件搜索
from langchain.agents import create_agent from langchain.agents.middleware import FilesystemFileSearchMiddleware agent = create_agent( model="gpt-4o", tools=[], middleware=[ FilesystemFileSearchMiddleware( root_path="/workspace", #这个目录下放了很多文件,可以让agent在里面搜索文件 use_ripgrep=True, ), ], )
Agent生命周期
Agent运行的固定流程:
-
代理开始
-
准备调用模型
-
模型正在调用
-
模型调用完成
-
工具正在调用
-
代理结束
这就是 Agent 的生命周期。
中间件是怎么嵌入到Agent的生命周期的
插在生命周期各个阶段的 "钩子函数"
-
@before_agent → 代理启动前
-
@before_model → 模型调用前
-
@wrap_model_call → 包裹模型调用(进入+退出)
-
@after_model → 模型调用后
-
@wrap_tool_call → 包裹工具调用(进入+退出)
-
@after_agent → 代理结束后
1. before_agent
执行时机 :整个 Agent 流程正式启动最开始
作用:
- 初始化全局上下文、用户信息、环境变量
- 权限校验、登录鉴权、会话初始化
- 前置统一日志、全局参数注入
- 提前拦截非法请求,直接终止流程
场景:加载用户身份、初始化会话 ID、全局配置初始化
2. before_model
执行时机 :准备调用大模型之前一刻
作用
-
预处理对话上下文、裁剪冗余消息
-
动态修改本轮入参、临时追加提示词
-
提前做隐私脱敏、敏感词过滤
-
支持跳转流程(can_jump_to 直接跳到结束)
场景:精简对话历史、临时补全指令、前置风控
3. wrap_model_call
执行时机 :环绕包裹整个模型调用全过程(进入 + 执行 + 退出)
作用
-
切面监听:调用前埋点、调用后统计
-
计算 LLM 响应耗时、监控调用耗时
-
拦截模型请求、篡改请求入参
-
拦截模型返回结果、修改输出内容
-
实现模型重试、熔断、降级、备用模型切换
4. after_model
执行时机 :大模型返回结果之后,还没走工具逻辑
作用
-
校验模型输出是否合规、过滤幻觉内容
-
修正 AI 错误回答、统一格式化输出
-
提取模型意图、提前解析工具调用参数
-
统计模型输出长度、缓存本轮结果
场景:结果校验、内容修正、意图解析
5. wrap_tool_call
执行时机 :环绕包裹所有工具调用全过程
作用
-
工具调用安全审计、黑白名单拦截
-
统计工具执行耗时、记录调用日志
-
工具入参校验、出参统一封装
-
捕获工具异常、自动重试、异常兜底
-
禁止高危工具执行、权限管控
特点:管控所有 Tool,业务安全、限流、重试全靠它
6. after_agent
执行时机 :Agent 整轮对话 / 任务全部跑完结束
作用
-
会话收尾、清理临时缓存与临时数据
-
汇总全流程日志、上报运行指标
-
持久化对话记忆、归档聊天记录
-
释放资源、关闭连接、结束会话
场景:数据落库、日志上报、资源回收、会话收尾
@dynamic_prompt动态修改提示词
动态生成 / 修改系统提示词(system prompt)
根据当前对话状态、用户信息、上下文 ,实时自动改 prompt,而不是写死固定的。
普通的 system prompt 是写死的
system_prompt="你是一个助手" # 永远不变
但真实场景需要灵活变化:
-
用户是 VIP → 提示词变成 "你是 VIP 专属助手"
-
时间是晚上 → 提示词变成 "现在是晚上,说话温柔点"
-
用户在查订单 → 提示词自动加上订单相关规则
-
不同用户 → 不同语气、不同权限
@dynamic_prompt 就是干这个的:自动、实时改提示词。
@dynamic_prompt的执行时机: 1.@before_agent /agent 启动前 2.自动生成最新的 system prompt 再进入模型。
1. 根据时间和用户id动态修改提示词 @dynamic_prompt def make_dynamic_prompt(state: AgentState, runtime: ToolRuntime): user_id = runtime.context.user_id time_now = "晚上" if 18 < time.localtime().tm_hour else "白天" # 动态返回提示词! return f""" 你是智能助手。 当前用户ID:{user_id} 当前时间:{time_now} 请根据时间调整语气。 """ 2. 然后注册到 agent: agent = create_agent( model=llm, middleware=[make_dynamic_prompt], # 👈 加这里 )
MCP服务
MCP(模型上下文协议) 是 Anthropic 推出的开放标准协议 ,用来统一大模型(LLM)和外部世界(工具 / 数据 / 服务)的连接方式。
类比:电脑的USB接口,一套标准,即插即用。 核心目标:标准化、安全、可扩展 地让模型调用外部能力、读取外部数据。
我们就可以把tools换了个地方单独定义,做成MCP服务,这样很多ai都能直接调用
不同 LLM、不同框架,调用同一套工具,写法、格式、调用逻辑全都不一样,重复写适配代码累死。
把所有工具统一打包做成 MCP 服务,对外只暴露一套标准接口。
这样不管用什么llm都可以直接调用MCP,就能调用所有工具。
MCP = 工具统一中转站 / 通用接口层 所有工具只写一次,部署成 MCP Server 所有大模型、所有 AI 框架,统一一套调用方式拿工具 彻底解决:工具多、模型杂、适配麻烦
安装依赖
pip install mcp langchain-mcp-adapters langchain-openai python-dotenv
创建本地mcp服务
from mcp.server.fastmcp import FastMCP # 1. 初始化 FastMCP mcp = FastMCP("MyWeatherService") # 2. 定义查天气工具 @mcp.tool() def query_weather(city: str) -> str: """根据城市名称查询天气。""" city = city.strip() if "北京" in city: return "北京天气:晴,气温 25°C,微风。" elif "上海" in city: return "上海天气:阴,气温 22°C,局部有小雨。" elif "深圳" in city: return "深圳天气:多云,气温 28°C,体感较热。" else: return f"暂时查不到 {city} 的天气,可能那里是世外桃源吧。" if __name__ == "__main__": # 直接运行后会启动 MCP 服务,便于被 LangChain 客户端通过 stdio 连接 mcp.run(transport="stdio")
调用本地mcp服务
import asyncio import os import sys from pathlib import Path from dotenv import load_dotenv from langchain.agents import create_agent from langchain_mcp_adapters.client import MultiServerMCPClient from langchain_openai import ChatOpenAI load_dotenv() async def main() -> None: # 1. 连接本地 MCP 服务 client = MultiServerMCPClient( { "weather": { "command": sys.executable, "args": [str(Path(__file__).with_name("17.py"))], "transport": "stdio", } } ) # 2. 从 MCP 服务加载工具 tools = await client.get_tools() # 3. 初始化模型 llm = ChatOpenAI( model="doubao-seed-1-8-251228", temperature=0, api_key=os.getenv("ARK_API_KEY"), base_url="https://ark.cn-beijing.volces.com/api/v3", ) # 4. 创建 Agent agent = create_agent( model=llm, tools=tools, system_prompt="你是一个会调用天气工具的助手。", ) # 5. 发起一次查询 result = await agent.ainvoke( {"messages": [{"role": "user", "content": "帮我查一下北京天气"}]} ) print(result["messages"][-1].content) if __name__ == "__main__": asyncio.run(main())