LangChain 简介 LangChain 是一个用于构建大语言模型(LLM)应用的 Python 框架。LangChain 提供统一的接口来连接各种 AI 模型,并支持构建能够自动调用工具、检索知识、记住上下文的智能 Agent
组件
作用
核心功能
常见用途
Models(模型)
连接大语言模型
统一模型接口 支持多模型切换 调用 GPT / Claude / Gemini 等
聊天机器人 文本生成 AI 问答
Prompts(提示词模板)
管理 Prompt 模板
Prompt 参数化 动态变量替换 模板复用
AI 对话 内容生成 结构化输出
Document Loader(文档加载)
读取外部文档数据
加载 PDF / TXT / DOCX 读取网页与数据库 统一文档格式
知识库 RAG 系统 文档问答
Text Splitter(文本切分)
拆分长文本
文本 Chunk 切分 控制 Token 长度 优化向量检索
RAG 向量数据库 长文本处理
Memory(记忆)
实现上下文记忆
保存聊天历史 长期记忆 对话状态管理
聊天机器人 AI 助手 Agent
Retriever(检索器)
检索相关知识内容
向量搜索 语义检索 RAG 数据召回
企业知识库 AI 搜索 文档问答
Tools(工具)
调用外部工具与 API
搜索互联网 数据库查询 执行代码
AI Agent 自动化任务 数据分析
Output Parser(输出解析器)
解析模型输出结果
结构化输出 JSON 解析 格式校验
API 返回 自动化系统 数据处理
Chains(链)
组合多个组件形成工作流
多步骤执行 流程编排 组件串联
复杂 AI 应用 RAG 工作流 Agent 系统
LangChain 是一个模块化的 LLM 应用开发框架,它包含三个层次:
层次
说明
包名
核心抽象层
定义模型、工具、消息等基础接口
langchain-core
用户接口层
提供 init_chat_model、create_agent 等高阶 API
langchain
集成层
连接 OpenAI、Anthropic、Ollama 等第三方服务
langchain-openai 等
第一个程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import osfrom dotenv import load_dotenvfrom langchain_deepseek import ChatDeepSeekload_dotenv() llm = ChatDeepSeek( model="deepseek-chat" , temperature=0 , max_tokens=None , timeout=None , max_retries=2 , ) response = llm.invoke("用一句话解释什么是 LangChain。" ) print (type (response)) print (response.content) print (response.usage_metadata)
invoke() 返回的是 AIMessage 对象,不是纯字符串;取文本用 .content。
temperature=0 适合事实问答、分类、抽取等需要确定性的任务;写作、头脑风暴可用 0.7~1.3。
理解消息(Messages)与多轮对话 聊天模型的输入本质上是消息列表 。LangChain 定义了几种标准消息类型:
类型
角色
说明
SystemMessage
system
设定模型的行为 / 人设
HumanMessage
user
用户输入
AIMessage
assistant
模型回复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from dotenv import load_dotenvfrom langchain_core.messages import SystemMessage, HumanMessage, AIMessagefrom langchain_deepseek import ChatDeepSeekload_dotenv() llm = ChatDeepSeek(model="deepseek-chat" , temperature=0 ) messages = [ SystemMessage(content="你是一个将中文翻译成英文的助手,只输出译文。" ), HumanMessage(content="我喜欢编程。" ), ] ai_msg = llm.invoke(messages) print (ai_msg.content) messages2 = [ ("system" , "你是一个将中文翻译成日语的助手,只输出译文。" ), ("human" , "我喜欢编程。" ), ] ai_msg2 = llm.invoke(messages2) print (ai_msg2.content) chat_history = [ SystemMessage(content="你是一个简洁的助手,回答不超过 50 字。" ), HumanMessage(content="中国的首都是哪里?" ), ] reply1 = llm.invoke(chat_history) print ("AI:" , reply1.content)chat_history.append(AIMessage(content=reply1.content)) chat_history.append(HumanMessage(content="那它的人口大约是多少?" )) reply2 = llm.invoke(chat_history) print ("AI:" , reply2.content)
大模型 API 本身是无状态 的 —— 所谓” 记忆”,就是每次请求都把完整历史发过去。
提示词模板(Prompt Templates) 硬编码提示词难以维护,ChatPromptTemplate 让你把提示词参数化、复用化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 from dotenv import load_dotenvfrom langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholderfrom langchain_deepseek import ChatDeepSeekload_dotenv() llm = ChatDeepSeek(model="deepseek-chat" , temperature=0.7 ) prompt = ChatPromptTemplate.from_template( "请用不超过 {limit} 个字,向一个 {audience} 解释什么是 {topic}。" ) rendered = prompt.invoke({"limit" : 50 , "audience" : "小学生" , "topic" : "区块链" }) print (rendered.to_messages())prompt2 = ChatPromptTemplate.from_messages([ ("system" , "你是一位资深{role},回答风格{style}。" ), ("human" , "{question}" ), ]) chain_input = {"role" : "Python 工程师" , "style" : "幽默" , "question" : "什么是装饰器?" } response = llm.invoke(prompt2.invoke(chain_input)) print (response.content)prompt3 = ChatPromptTemplate.from_messages([ ("system" , "你是一个乐于助人的助手。" ), MessagesPlaceholder(variable_name="history" ), ("human" , "{question}" ), ]) value = prompt3.invoke({ "history" : [ ("human" , "我叫小明。" ), ("ai" , "你好小明,很高兴认识你!" ), ], "question" : "我刚才说我叫什么?" , }) print (llm.invoke(value).content)
MessagesPlaceholder 是构建带记忆应用的关键,它告诉模板” 这里要塞进一段长度不定的历史消息”。
LCEL:用管道符构建链(Chain) LCEL(LangChain Expression Language)是 LangChain 的核心编排语法:用 | 把组件串成链,上一个组件的输出自动成为下一个组件的输入。
1 2 prompt → model → output_parser (字典进,消息出)(消息进,AIMessage 出)(AIMessage 进,字符串出)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 from dotenv import load_dotenvfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.runnables import RunnablePassthrough, RunnableParallelfrom langchain_deepseek import ChatDeepSeekload_dotenv() llm = ChatDeepSeek(model="deepseek-chat" , temperature=0 ) prompt = ChatPromptTemplate.from_messages([ ("system" , "你是一个{src}到{dst}的翻译专家,只输出译文。" ), ("human" , "{text}" ), ]) chain = prompt | llm | StrOutputParser() result = chain.invoke({"src" : "中文" , "dst" : "英文" , "text" : "人工智能改变世界" }) print (result) single_prompt = ChatPromptTemplate.from_template("讲一个关于{subject}的冷笑话。" ) single_chain = {"subject" : RunnablePassthrough()} | single_prompt | llm | StrOutputParser() print (single_chain.invoke("程序员" ))analysis_prompt = ChatPromptTemplate.from_template("分析这句话的情感倾向(正面/负面/中性):{text}" ) summary_prompt = ChatPromptTemplate.from_template("用 10 个字总结这句话:{text}" ) parallel = RunnableParallel( sentiment=analysis_prompt | llm | StrOutputParser(), summary=summary_prompt | llm | StrOutputParser(), ) result = parallel.invoke({"text" : "这家餐厅的菜太难吃了,但服务员态度特别好。" }) print (result)
链本身也是 Runnable,同样拥有 invoke / stream / batch / ainvoke 等全套方法。
RunnableParallel 中的多个分支是并行 执行的,适合” 同一输入做多件事” 的场景。
输出解析器(Output Parsers) 模型返回的是自由文本,输出解析器负责把它变成程序可用的结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 from dotenv import load_dotenvfrom langchain_core.output_parsers import StrOutputParser, JsonOutputParser, CommaSeparatedListOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_deepseek import ChatDeepSeekload_dotenv() llm = ChatDeepSeek(model="deepseek-chat" , temperature=0 ) prompt = ChatPromptTemplate.from_template("用一句话介绍{city}。" ) chain = prompt | llm | StrOutputParser() print (chain.invoke({"city" : "杭州" }))list_prompt = ChatPromptTemplate.from_template("列出 5 个{category},用英文逗号分隔。" ) list_chain = list_prompt | llm | CommaSeparatedListOutputParser() print (list_chain.invoke({"category" : "中国地级市" }))from pydantic import BaseModel, Fieldclass Person (BaseModel ): name: str = Field(description="人物姓名" ) birth_year: int = Field(description="出生年份" ) achievements: list [str ] = Field(description="主要成就,最多3条" ) json_parser = JsonOutputParser(pydantic_object=Person) json_prompt = ChatPromptTemplate.from_messages([ ("system" , "从用户输入中提取人物信息。\n{format_instructions}" ), ("human" , "{text}" ), ]) json_chain = json_prompt | llm | json_parser result = json_chain.invoke({ "text" : "爱因斯坦,1879年出生,提出了相对论,获得诺贝尔物理学奖,推动了现代物理学发展。" , "format_instructions" : json_parser.get_format_instructions(), }) print (type (result), result)
get_format_instructions() 生成的格式说明比手写” 请输出 JSON” 可靠得多。
结构化输出(Structured Output) with_structured_output() 利用模型原生的工具调用 / JSON 模式能力,直接返回 Pydantic 对象 —— 比输出解析器更可靠,推荐优先使用 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 from typing import Literal from dotenv import load_dotenvfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_deepseek import ChatDeepSeekfrom pydantic import BaseModel, Fieldload_dotenv() llm = ChatDeepSeek(model="deepseek-chat" , temperature=0 ) class MovieReview (BaseModel ): """电影评价抽取结果""" title: str = Field(description="电影名称" ) sentiment: Literal ["positive" , "negative" , "mixed" ] = Field(description="情感倾向" ) rating: float = Field(description="评分,0-10" , ge=0 , le=10 ) pros: list [str ] = Field(description="优点列表" ) cons: list [str ] = Field(description="缺点列表" ) structured_llm = llm.with_structured_output(MovieReview) text = """ 《流浪地球2》特效炸裂,太空电梯那段堪称国产科幻巅峰,刘德华和吴京的演技都在线。 不过剧情节奏有些拖沓,中间一段文戏略显冗长。总体值得一看,我给8分。 """ review = structured_llm.invoke(f"从以下影评中提取信息:\n{text} " ) print (type (review)) print (review.title) print (review.sentiment) print (review.rating) prompt = ChatPromptTemplate.from_messages([ ("system" , "你是影评分析专家。" ), ("human" , "分析这条影评:{text}" ), ]) chain = prompt | structured_llm result = chain.invoke({"text" : text}) print (result.model_dump_json(indent=2 ))
流式输出(Streaming) 长文本生成时,流式输出可以逐 token 返回,显著改善用户体验(类似 ChatGPT 打字机效果)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 from dotenv import load_dotenvfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_deepseek import ChatDeepSeekload_dotenv() llm = ChatDeepSeek(model="deepseek-chat" , streaming=True ) print ("=== 模型直接流式输出 ===" )for chunk in llm.stream("写一首关于秋天的五言绝句。" ): print (chunk.content, end="" , flush=True ) print ()prompt = ChatPromptTemplate.from_template("给我讲一个{topic}方面的趣事,100字左右。" ) chain = prompt | llm | StrOutputParser() print ("\n=== 链式流式输出 ===" )for chunk in chain.stream({"topic" : "程序员" }): print (chunk, end="" , flush=True ) print ()import asyncioasync def demo_events (): async for event in llm.astream_events("数到5" , version="v2" ): if event["event" ] == "on_chat_model_stream" : print (event["data" ]["chunk" ].content, end="" , flush=True ) print () asyncio.run(demo_events())
链中的组件只要有一个支持流式,整条链就能流式输出 ——LCEL 会自动处理。
astream_events 能拿到链中每一步(prompt 渲染、模型生成、解析)的事件,构建复杂 UI 时很有用。
异步调用与批量处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import asyncioimport timefrom dotenv import load_dotenvfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_deepseek import ChatDeepSeekload_dotenv() llm = ChatDeepSeek(model="deepseek-chat" , temperature=0 ) prompt = ChatPromptTemplate.from_template("用一句话介绍{country}的首都。" ) chain = prompt | llm | StrOutputParser() countries = ["中国" , "日本" , "法国" , "巴西" , "埃及" ] inputs = [{"country" : c} for c in countries] start = time.time() results = chain.batch(inputs, config={"max_concurrency" : 5 }) print (f"batch 耗时: {time.time() - start:.2 f} s" )for c, r in zip (countries, results): print (f"{c} : {r} " ) async def async_demo (): result = await chain.ainvoke({"country" : "德国" }) print ("ainvoke:" , result) async for chunk in chain.astream({"country" : "意大利" }): print (chunk, end="" , flush=True ) print () results = await asyncio.gather(*[ chain.ainvoke({"country" : c}) for c in ["美国" , "英国" , "俄罗斯" ] ]) print ("gather:" , results) asyncio.run(async_demo()) results = chain.batch(inputs, config={"max_concurrency" : 5 }, return_exceptions=True ) for c, r in zip (countries, results): if isinstance (r, Exception): print (f"{c} : 调用失败 - {r} " ) else : print (f"{c} : {r} " )
处理大批量任务时优先用 batch/abatch,配合 max_concurrency 控制并发数,避免触发 API 限流。
对话记忆(Chat Memory) 用 RunnableWithMessageHistory 让链自动读写历史消息,支持多会话隔离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 from dotenv import load_dotenvfrom langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistoryfrom langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholderfrom langchain_core.runnables.history import RunnableWithMessageHistoryfrom langchain_deepseek import ChatDeepSeekload_dotenv() llm = ChatDeepSeek(model="deepseek-chat" , temperature=0.7 ) prompt = ChatPromptTemplate.from_messages([ ("system" , "你是一个友好的助手,请记住用户告诉你的信息。" ), MessagesPlaceholder(variable_name="history" ), ("human" , "{question}" ), ]) chain = prompt | llm store = {} def get_session_history (session_id: str ) -> BaseChatMessageHistory: if session_id not in store: store[session_id] = InMemoryChatMessageHistory() return store[session_id] with_memory = RunnableWithMessageHistory( chain, get_session_history, input_messages_key="question" , history_messages_key="history" , ) config = {"configurable" : {"session_id" : "user_001" }} r1 = with_memory.invoke({"question" : "我叫小明,我喜欢打篮球。" }, config=config) print ("AI:" , r1.content)r2 = with_memory.invoke({"question" : "我叫什么名字?我喜欢什么运动?" }, config=config) print ("AI:" , r2.content)r3 = with_memory.invoke( {"question" : "我叫什么名字?" }, config={"configurable" : {"session_id" : "user_002" }}, ) print ("AI(新会话):" , r3.content) from langchain_core.messages import trim_messagesfrom langchain_core.runnables import RunnablePassthroughtrimmer = trim_messages( max_tokens=500 , strategy="last" , token_counter=llm, include_system=True , ) chain_with_trimming = ( RunnablePassthrough.assign(history=trimmer) | prompt | llm ) with_memory_trimmed = RunnableWithMessageHistory( chain_with_trimming, get_session_history, input_messages_key="question" , history_messages_key="history" , )
InMemoryChatMessageHistory 只适合演示;生产环境可换成 Redis、SQL 等持久化实现(实现 BaseChatMessageHistory 接口即可)。
长对话一定要用 trim_messages 或摘要策略控制历史长度,否则 token 成本和延迟会持续增长。
工具调用让模型能” 请求” 执行你定义的函数:模型输出调用参数,你的代码执行后把结果喂回模型。
工具调用让模型能” 请求” 执行你定义的函数:模型输出调用参数,你的代码执行后把结果喂回模型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 from dotenv import load_dotenvfrom langchain_core.messages import HumanMessage, ToolMessagefrom langchain_core.tools import toolfrom langchain_deepseek import ChatDeepSeekload_dotenv() @tool def get_current_weather (city: str ) -> str : """查询指定城市的实时天气。 Args: city: 城市名称,例如"北京" """ fake_db = {"北京" : "晴,25°C" , "上海" : "多云,28°C" , "深圳" : "雷阵雨,30°C" } return fake_db.get(city, f"{city} :暂无数据" ) @tool def calculator (expression: str ) -> str : """计算一个数学表达式的值。 Args: expression: 合法的 Python 数学表达式,例如 "1024 * 768" """ try : return str (eval (expression, {"__builtins__" : {}}, {})) except Exception as e: return f"计算出错: {e} " tools = [get_current_weather, calculator] tools_by_name = {t.name: t for t in tools} llm = ChatDeepSeek(model="deepseek-chat" , temperature=0 ) llm_with_tools = llm.bind_tools(tools) messages = [HumanMessage(content="北京现在天气怎么样?另外帮我算一下 1024*768 等于多少。" )] ai_msg = llm_with_tools.invoke(messages) print ("模型请求调用的工具:" , ai_msg.tool_calls)messages.append(ai_msg) for call in ai_msg.tool_calls: tool_result = tools_by_name[call["name" ]].invoke(call["args" ]) messages.append(ToolMessage(content=tool_result, tool_call_id=call["id" ])) print (f"工具 {call['name' ]} 返回: {tool_result} " ) final = llm_with_tools.invoke(messages) print ("最终回答:" , final.content)
工具的函数名、参数名、docstring 都是给模型看的,写清楚能显著提高调用准确率。
tool_calls 只是模型的” 请求”,工具由你的代码执行 —— 这也保证了安全性。
请勿在生产代码中对用户输入直接使用 eval,这里仅为演示。
构建 Agent(智能体) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from dotenv import load_dotenvfrom langchain_core.tools import toolfrom langchain_deepseek import ChatDeepSeekfrom langgraph.prebuilt import create_react_agentload_dotenv() @tool def search_product (query: str ) -> str : """在商品库中搜索商品,返回商品名称和价格。""" fake_db = [ {"name" : "机械键盘" , "price" : 299 }, {"name" : "无线鼠标" , "price" : 99 }, {"name" : "27寸显示器" , "price" : 1299 }, ] hits = [f"{p['name' ]} (¥{p['price' ]} )" for p in fake_db if query in p["name" ]] return ";" .join(hits) if hits else "未找到相关商品" @tool def calculate_total (prices: list [float ] ) -> float : """计算一组价格的总和。""" return sum (prices) llm = ChatDeepSeek(model="deepseek-chat" , temperature=0 ) agent = create_react_agent( llm, tools=[search_product, calculate_total], prompt="你是一个购物助手。用户想买什么就先搜索,再帮忙算总价。" , ) result = agent.invoke({ "messages" : [("user" , "我想买个机械键盘和一个无线鼠标,一共多少钱?" )] }) for msg in result["messages" ]: msg.pretty_print()
create_react_agent 内部是 LangGraph 状态图,天然支持流式(agent.stream(...))、中断、持久化(checkpointer)。
Agent 会自主决定调用几次工具、按什么顺序调用;你需要做的是把工具和系统提示词写好。
RAG 实战:基于私有文档的问答 RAG(检索增强生成)流程:加载文档 → 切分 → 向量化入库 → 检索相关片段 → 拼进提示词 → 生成答案 。
DeepSeek 官方暂无 Embedding API,示例使用 OpenAI Embedding(可无缝替换为任意 LangChain 支持的 Embedding 模型)。
1 pip install -U langchain-openai langchain-community faiss-cpu
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 import osfrom dotenv import load_dotenvfrom langchain_community.vectorstores import FAISSfrom langchain_core.documents import Documentfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.runnables import RunnablePassthroughfrom langchain_deepseek import ChatDeepSeekfrom langchain_openai import OpenAIEmbeddingsfrom langchain_text_splitters import RecursiveCharacterTextSplitterload_dotenv() raw_docs = [ Document(page_content="公司年假政策:员工入职满一年后可享受 5 天带薪年假," "工龄每增加一年年假增加 1 天,上限 15 天。年假需在当年 12 月 31 日前休完。" ), Document(page_content="报销制度:差旅报销需在出差结束后 10 个工作日内提交," "住宿标准为一线城市每晚不超过 500 元,其他城市不超过 350 元。" ), Document(page_content="考勤制度:标准工作时间为 9:00-18:00,弹性打卡范围为 8:30-10:00," "每月允许 3 次迟到(10 分钟以内),超出按事假处理。" ), ] splitter = RecursiveCharacterTextSplitter(chunk_size=200 , chunk_overlap=20 ) splits = splitter.split_documents(raw_docs) print (f"切分出 {len (splits)} 个片段" )embeddings = OpenAIEmbeddings() vectorstore = FAISS.from_documents(splits, embeddings) retriever = vectorstore.as_retriever(search_kwargs={"k" : 2 }) prompt = ChatPromptTemplate.from_messages([ ("system" , "你是公司制度问答助手。仅根据以下检索到的资料回答问题," "资料中没有的信息就回答'制度中未提及',不要编造。\n\n资料:\n{context}" ), ("human" , "{question}" ), ]) llm = ChatDeepSeek(model="deepseek-chat" , temperature=0 ) def format_docs (docs ): return "\n\n" .join(doc.page_content for doc in docs) rag_chain = ( {"context" : retriever | format_docs, "question" : RunnablePassthrough()} | prompt | llm | StrOutputParser() ) print (rag_chain.invoke("我工龄 3 年,有几天年假?" ))print (rag_chain.invoke("在北京出差住宿费一晚 600 能报销吗?" ))print (rag_chain.invoke("公司有健身房吗?" ))
{"context": retriever | format_docs, "question": RunnablePassthrough()} 这一行是 RAG 链的精髓:输入的问题同时走两条路 —— 一条进检索器取资料,一条原样传给提示词。
文档加载器按需选择:PyPDFLoader(PDF)、WebBaseLoader(网页)、DirectoryLoader(整个目录)等。
向量库可换成 Chroma、Milvus、PGVector 等,接口完全一致。
命令行智能聊天机器人 记忆 + 流式 + 工具调用(Agent)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 from dotenv import load_dotenvfrom langchain_core.tools import toolfrom langchain_deepseek import ChatDeepSeekfrom langgraph.checkpoint.memory import MemorySaverfrom langgraph.prebuilt import create_react_agentload_dotenv() @tool def get_current_time () -> str : """获取当前的日期和时间。""" from datetime import datetime return datetime.now().strftime("%Y-%m-%d %H:%M:%S" ) @tool def calculate (expression: str ) -> str : """计算数学表达式。参数 expression 为合法数学表达式字符串。""" try : return str (eval (expression, {"__builtins__" : {}}, {})) except Exception as e: return f"错误: {e} " llm = ChatDeepSeek(model="deepseek-chat" , streaming=True ) memory = MemorySaver() agent = create_react_agent( llm, tools=[get_current_time, calculate], prompt="你是一个聪明友好的中文助手,回答简洁明了。" , checkpointer=memory, ) config = {"configurable" : {"thread_id" : "cli-session-1" }} print ("🤖 聊天机器人已启动(输入 quit 退出,输入 clear 清空记忆)\n" )while True : user_input = input ("你: " ).strip() if not user_input: continue if user_input.lower() == "quit" : print ("再见!" ) break if user_input.lower() == "clear" : config = {"configurable" : {"thread_id" : f"cli-session-{id (user_input)} " }} print ("🤖: 记忆已清空。\n" ) continue print ("🤖: " , end="" , flush=True ) for chunk, metadata in agent.stream( {"messages" : [("user" , user_input)]}, config=config, stream_mode="messages" , ): if metadata.get("langgraph_node" ) == "agent" and chunk.content: print (chunk.content, end="" , flush=True ) print ("\n" )