智能体5-LangChain 框架下的 AI Agent 构建与部署实践

本文将详细介绍并实践以下内容:

-LangChain 各组件(LLM、工具、链、记忆、Agent、提示、RAG、Retriever 等)在完整项目中的协作关系

  • 结合 DeepSeek + bge-small-zh + FAISS + DuckDuckGoSearch
  • 提供模块化代码示例,说明每部分的职责与灵活性
  • 使用 FastAPI 将 Agent 封装成 API 服务,可用于 Web 前端接入
  • Tool 封装规范、Agent 执行中间状态管理、复杂提示结构设计等

本文章将系统讲解如何基于 LangChain 框架构建一个功能齐全、可部署的智能问答 Agent。我们将结合前文核心概念(ReAct 架构、RAG 检索增强、提示工程、工具调用等)逐步展开,选用 DeepSeek 聊天模型作为 LLM、BAAI/bge-small-zh-v1.5 作为中文嵌入模型、FAISS 作为向量数据库、DuckDuckGoSearchRun 作为联网搜索工具,最终封装成 RESTful 服务。

一、LangChain框架概述

什么是LangChain?

LangChain是一个用于开发由语言模型驱动的应用程序的框架。它允许开发者将大型语言模型(LLMs)与其他计算或知识源连接起来,从而创建更强大、更灵活的AI应用。

LangChain核心组件

LangChain包含多个核心模块,这些模块可以组合使用来构建复杂的AI Agent:

  • Models:支持多种语言模型接口
  • Prompts:提示管理、优化和序列化
  • Memory:短期和长期记忆管理
  • Indexes:文档加载、处理和检索
  • Chains:调用序列和组合
  • Agents:动态决策和工具使用
  • Callbacks:日志和流式传输

二、核心概念回顾

  • ReAct 框架:是一种将推理(Reasoning)与动作(Action)相结合的交互式提示方式。LangChain 的 ReAct Agent 可以让模型在对话过程中思考 (Thought:)、采取动作 (Action:) 并观察结果 (Observation:),从而动态调用外部工具。例如,当模型面临复杂问题时,可以通过调用搜索工具或数据库工具来获取补充信息,再结合生成能力给出答案。

  • RAG(检索增强生成):指在生成回答时通过检索相关文档来提供上下文或证据的技术。RAG 适用于将领域知识融入对话,避免模型只凭「记忆」回答超出能力的问题。我们会使用向量数据库(FAISS)和文本嵌入来实现 RAG,从海量文档中检索与用户问题最相关的内容,再输入模型生成答案。

  • 提示工程:通过 PromptTemplate 等机制设计和组织模型提示,将任务指令、示例和变量拼接成最终输入。好的提示可以大幅提升模型理解和回答能力。我们将定制提示模板,明确说明用户意图及可用工具等,引导模型在 ReAct 交互中正确使用工具。

  • 工具调用:Agent 能访问的工具(如搜索引擎、知识库查询、计算器等)需封装为符合接口的 Tool 对象,包含名称、调用函数和用途说明。在 ReAct 策略下,模型可以选择某个工具并按指定格式传入参数。本文示例中,将集成联网搜索与本地向量检索两种工具供 Agent 使用。

  • 多轮对话与记忆:使用 ConversationBufferMemory 记录会话历史,实现上下文连续性。当用户提问时,上下文记忆会作为提示变量注入,让模型参考前文对话内容,使回答更具连贯性。

三、系统架构与组件选型

3.1 语言模型与嵌入

  • LLM(聊天模型):选用 DeepSeek 提供的 deepseek-chat 模型作为对话模型。DeepSeek 是一系列开源模型,支持结构化输入、工具调用等能力。DeepSeek API 使用与 OpenAI 兼容的 API 格式,可使用 LangChain 的 ChatOpenAI 进行接入,如下所示:
    首先准备环境,由于版本需要对齐:
pip install langchain==0.3.26 --force-reinstall
pip install langchain-core==0.3.66 --force-reinstall
pip install langchain-community==0.3.27 --force-reinstall
pip install langchain-text-splitters==0.3.8 --force-reinstall
import os
from langchain_community.chat_models import ChatOpenAI

API_KEY = os.getenv('DEEPSEEK_API_KEY')

llm = ChatOpenAI(
    model='deepseek-chat',  # 指定使用的模型名称,如 gpt-4、deepseek-chat 等
    openai_api_key=API_KEY,  # 设置 API 密钥
    openai_api_base='https://api.deepseek.com/v1',  # 自定义模型地址(如 DeepSeek)
    temperature=0.7,  # 控制输出的随机性,越低越保守,越高越发散
    max_tokens=1024,  # 设置生成回复的最大 token 数
    model_kwargs={  # 额外的模型参数(可选)
        "top_p": 1,
        "frequency_penalty": 0.0,
        "presence_penalty": 0.0
    },
    request_timeout=60,  # 请求超时时间(秒)
    streaming=False,  # 是否使用流式响应
    verbose=False  # 是否打印调试信息
)

✅ 参数使用建议

  1. 温度设置:
    • temperature=0.0 适合问答、摘要、代码生成等确定性任务;
    • temperature=0.7~1.0 更适合生成富有创意的内容。
  1. 兼容模型:

    • 若使用 DeepSeek、Moonshot、Azure OpenAI 等非官方 API,务必设置 openai_api_base。
  2. 高阶用法:

    • 可结合 LLMChain 或 AgentExecutor 构建复杂流程。

这样实例化后,llm.invoke([消息列表]) 即可获得模型回复。

response = llm.invoke("请简要说明“量子计算”和“经典计算”的主要区别。")
print(response)

输出:

content='量子计算与经典计算的核心区别主要体现在以下方面:\n\n### 1. **信息表示方式**\n- **经典计算**:使用二进制位(bit),每个bit只能是0或1。\n- **量子计算**:使用量子位(qubit),可处于0、1或两者的叠加态(量子叠加),同时表示多种状态。\n\n### 2. **并行计算能力**\n- **经典计算**:逐次处理任务,N位处理器一次处理一个N位状态。\n- **量子计算**:N个qubit可同时处理2^N个状态(量子并行性),适合大规模并行问题(如因数分解、搜索)。\n\n### 3. **操作原理**\n- **经典计算**:基于布尔逻辑门(AND/OR/NOT等),确定性操作。\n- **量子计算**:通过量子门操作(如Hadamard门、CNOT门),支持叠加态和纠缠态的操作,具有概率性。\n\n### 4. **纠缠与关联性**\n- **经典计算**:比特间独立或通过经典关联。\n- **量子计算**:qubit可纠缠(entanglement),一个qubit状态变化立即影响另一个,即使相距遥远(非局域性)。\n\n### 5. **算法效率**\n- **经典计算**:解决常规问题(如排序、数据库查询)效率高。\n- **量子计算**:特定问题指数级加速,如Shor算法(因数分解)、Grover算法(无序搜索)。\n\n### 6. **错误处理**\n- **经典计算**:通过冗余校验(如重复编码)纠错。\n- **量子计算**:需量子纠错码(如表面码),因量子态脆弱易受退相干影响。\n\n### 7. **物理实现**\n- **经典计算**:基于硅基半导体(CPU/GPU),技术成熟。\n- **量子计算**:需极端环境(超导、离子阱、光量子等),维持量子态难度大。\n\n### 8. **应用领域**\n- **经典计算**:通用计算,覆盖日常需求。\n- **量子计算**:专长于优化、模拟量子系统、密码学等,无法完全替代经典计算。\n\n### 总结\n量子计算利用量子力学特性(叠加、纠缠)突破经典限制,但在通用性和稳定性上仍面临挑战。两者未来可能互补共存,量子处理特定任务,经典负责其余部分。' additional_kwargs={} response_metadata={'token_usage': {'completion_tokens': 499, 'prompt_tokens': 18, 'total_tokens': 517, 'prompt_tokens_details': {'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 18}, 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_8802369eaa_prod0425fp8', 'finish_reason': 'stop', 'logprobs': None} id='run--95a492b6-37f7-4e73-b5cf-12265c945c46-0'

3.2 文档加载与预处理

在构建 Agent 之前,我们需要先将原始文档转化为可以检索的向量形式,具体包括:

(1)加载本地文档

LangChain 提供多种 Loader 来读取不同格式的文档。

  • 读取 Markdown 文件(.md):
from langchain_community.document_loaders import TextLoader

loader = TextLoader('./docs/智能体简介.md', encoding='utf-8')
documents = loader.load()
  • 读取整个目录下的 Markdown 文件:
from langchain_community.document_loaders import DirectoryLoader

loader = DirectoryLoader('./docs', glob='**/*.md', loader_cls=TextLoader, loader_kwargs={'encoding': 'utf-8'})
documents = loader.load()
  • 读取 PDF 文件:
    对于 PDF 文件,可以使用 PyPDFLoader 进行加载。它会按页读取并自动转为 Document 对象。
from langchain_community.document_loaders import PyPDFLoader

loader = PyPDFLoader('./docs/RAG测试.pdf')
documents = loader.load()

如果你希望将多个来源的文档合并处理,只需拼接多个 documents 列表即可:

all_documents = md_documents + pdf_documents + other_documents
(2)文档切分

为了让长文档适配向量数据库,我们需要按段落或语义块进行切分。推荐使用 RecursiveCharacterTextSplitter:

from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", "。", "!", "?", ".", "!", "?"]
)
split_docs = text_splitter.split_documents(documents)

此操作会将文档拆成多个短文本块,既保留上下文连续性,又便于后续的向量化处理。
与CharacterTextSplitter的区别:

from langchain.text_splitter import CharacterTextSplitter

# 示例文本
text = "Python 是一种广泛使用的高级编程语言,具有简单易学的语法。"

# 初始化 CharacterTextSplitter
text_splitter = CharacterTextSplitter(
    chunk_size=20,  # 每块最大字符数
    chunk_overlap=5  # 块之间的重叠字符数
)

# 切分文本
chunks = text_splitter.split_text(text)

# 输出结果
for i, chunk in enumerate(chunks):
    print(f"Chunk {i + 1}: {chunk}")

Chunk 1: Python 是一种广泛使用的高级编程
Chunk 2: 使用的高级编程语言,具有简单易学
Chunk 3: 具有简单易学的语法。
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 示例文本
text = """
Python 是一种广泛使用的高级编程语言,具有简单易学的语法。
它支持多种编程范式,包括面向对象、函数式编程和过程式编程。
"""

# 初始化 RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=50,  # 每块最大字符数
    chunk_overlap=10,  # 块之间的重叠字符数
    separators=["\n", " ", ""]  # 分隔符优先级
)

# 切分文本
chunks = text_splitter.split_text(text)

# 输出结果
for i, chunk in enumerate(chunks):
    print(f"Chunk {i + 1}: {chunk}")

Chunk 1: Python 是一种广泛使用的高级编程语言,
Chunk 2: 具有简单易学的语法。它支持多种编程范式,
Chunk 3: 包括面向对象、函数式编程和过程式编程。

对比总结

特性 CharacterTextSplitter RecursiveCharacterTextSplitter
分割方式 按固定字符长度切分 按分隔符递归切分,优先保留语义
分隔符支持 不支持 支持多级分隔符(如段落、句子、单词)
适用场景 适合结构化文本或固定格式文本 适合自然语言文本,保留语义完整性
复杂性 简单 较复杂
上下文保留 通过 chunk_overlap 保留部分上下文 通 过递归分割和 chunk_overlap 保留上下文
灵活性 较低 较高

3.3 向量化与嵌入模型选型

我们选用了性能与体积兼顾的中文向量模型 —— BAAI/bge-small-zh-v1.5。它支持短语级语义检索,能生成可用于相似度计算的高质量文本向量。

from langchain_community.embeddings import HuggingFaceEmbeddings

# 初始化一个中文 BGE 嵌入模型,用于将文本转换为向量表示
embed_model = HuggingFaceEmbeddings(
    model_name="BAAI/bge-small-zh-v1.5",  # 使用 BAAI 提供的 bge-small-zh 中文语义嵌入模型
    model_kwargs={"device": "cpu"},  # 指定运行设备为 CPU,如有 GPU 可改为 "cuda"
    encode_kwargs={"normalize_embeddings": True}  # 对输出的向量进行归一化,有助于相似度计算
)
  • 嵌入模型(Embedding Model) 的核心功能是将自然语言文本转换为数值向量(embedding),使得我们可以基于向量做相似度检索、聚类、语义匹配等操作。在 LangChain 中,embedding model 通常用于以下两个场景:
    1.文档入库(embedding + 存入向量数据库)
    2.用户查询转换(embedding + 相似文档检索)
    3.BGE 模型推荐在 embed_query() 之前添加查询指令(query_instruction),以获得更好的效果。
query_instruction = "为这个句子生成表示以用于检索相关文章:"
question = "人工智能是一门研究如何让计算机具有人类智能的科学"
query = query_instruction + question
vector = embed_model.embed_query(query)  # 得到向量表示(用于查询)
print(vector)
  • 向量数据库:使用 FAISS 存储文档向量。FAISS 是 Facebook 提供的高效相似度检索库,专门用于密集向量搜索。将待检索的文档列表通过 embed_model 编码后,使用 FAISS.from_documents() 构建向量索引。例如:
1. 将前面切分后的 split_docs 向量化,并存入 FAISS
from langchain.vectorstores import FAISS

vectorstore = FAISS.from_documents(split_docs, embed_model)

# 保存本地索引以供后续检索调用
vectorstore.save_local("faiss_index")
image.png

这样即可快速从 FAISS 中根据用户查询检索相关文档。

2. 检索器构造(Retriever)

我们通过 vectorstore.as_retriever() 构造一个语义检索器,支持基于向量相似度的文段召回:

retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 2})

query = "台湾省天气状况?"
docs = retriever.invoke(query)

for i, doc in enumerate(docs, 1):
    print(f"[文档 {i}]: {doc.page_content}\n")

docs内容:

[Document(metadata={total_pages': 5, 'page': 0, 'page_label': '1'}, page_content='北京市天气状况:1  \n上海市天气状况:2  \n天津市天气状况:3'), 
Document(metadata={'total_pages': 5, 'page': 1, 'page_label': '2'}, page_content='重庆市天气状况:4  \n河北省天气状况:5  \n山西省天气状况:6  \n辽宁省天气状况:7'), 
Document(metadata={'total_pages': 5, 'page': 2, 'page_label': '3'}, page_content='吉林省天气状况:8  \n黑龙江省天气状况:9  \n江苏省天气状况:10  \n浙江省天气状况:11'),
Document(metadata={'total_pages': 5, 'page': 3, 'page_label': '4'}, page_content='安徽省天气状况:12  \n福建省天气状况:13  \n江西省天气状况:14'), 
Document(metadata={'total_pages': 5, 'page': 3, 'page_label': '4'}, page_content='山东省天气状况:15  \n河南省天气状况:16  \n湖北省天气状况:17  \n湖南省天气状况:18'),
Document(metadata={'total_pages': 5, 'page': 4, 'page_label': '5'}, page_content='广东省天气状况:19  \n海南省天气状况:20  \n四川省天气状况:21'),
Document(metadata={'total_pages': 5, 'page': 4, 'page_label': '5'}, page_content='贵州省天气状况:22  \n云南省天气状况:23  \n陕西省天气状况:24'), 
Document(metadata={'total_pages': 5, 'page': 4, 'page_label': '5'}, page_content='甘肃省天气状况:25  \n青海省天气状况:26  \n内蒙古自治区天气状况:27'), 
Document(metadata={'total_pages': 5, 'page': 4, 'page_label': '5'}, page_content='广西壮族自治区天气状况:28  \n西藏自治区天气状况:29  \n宁夏回族自治区天气状况:30'), 
Document(metadata={'total_pages': 5, 'page': 4, 'page_label': '5'}, page_content='新疆维吾尔自治区天气状况:31  \n香港特别行政区天气状况:32'), 
Document(metadata={'total_pages': 5, 'page': 4, 'page_label': '5'}, page_content='澳门特别行政区天气状况:33  \n台湾省天气状况:34')]

运行后:

文档 0: 澳门特别行政区天气状况:33  
台湾省天气状况:34
文档 1: 安徽省天气状况:12  
福建省天气状况:13  
江西省天气状况:14

文档0的相似度最高,文档1的次之

3.4 联网搜索工具

使用 DuckDuckGo 搜索工具进行实时查询。LangChain 社区提供了 DuckDuckGoSearchRun 封装,可直接调用 DuckDuckGo API。示例:

from langchain_community.tools import DuckDuckGoSearchRun

query = "台湾省天气状况?"
search_tool = DuckDuckGoSearchRun()
result = search_tool.invoke(query)
print(result)

这个工具方便集成到 Agent 中,实现“需要联网搜索”时的补充信息。
由于DuckDuckGo 不稳定,我们可以使用Serper代替:

  1. 在使用Google Serper API之前,需要访问serper.dev注册一个免费账户,并获取API密钥。

  2. 在使用API之前,需要设置环境变量:

os.environ["SERPER_API_KEY"] = "your_serper_api_key"
from langchain_community.utilities import GoogleSerperAPIWrapper

# 初始化搜索实例
search = GoogleSerperAPIWrapper()

# 执行搜索
result = search.results("广东省天气状况?")
print(result) 

("搜索结果: {'searchParameters': {'q': '广东省天气状况?', 'gl': 'us', 'hl': 'en', 'type': "
 "'search', 'num': 10, 'engine': 'google'}, 'organic': [{'title': '广东 - "
 "中国气象局-天气预报-城市预报', 'link': 'https://weather.cma.cn/web/weather/59287.html', "
 "'snippet': '时间, 05:00, 08:00, 11:00, 14:00, 17:00, 20:00, 23:00, 02:00. 天气. "
 "气温, 18.3℃, 17.2℃, 27.8℃, 25.5℃, 23.4℃, 22.7℃, 19.8℃, 17.5℃.', 'position': "
 "1}, {'title': '广东天气预报- 广东', 'link': 'https://gd.weather.com.cn/index.shtml', "
 "'snippet': '天气排行 ; 最高气温. 遂溪, 29.0°C ; 最低气温. 连州, 12.7°C ; 昼夜温差. 大埔, 13.7°C.', "
 "'sitelinks': [{'title': '广州', 'link': "
 "'https://gd.weather.com.cn/guangzhou/index.shtml'}, {'title': '深圳', 'link': "
 "'https://gd.weather.com.cn/shenzhen/index.shtml'}, {'title': '天气实况', 'link': "
 "'https://gd.weather.com.cn/tqsk/index.shtml'}, {'title': '东莞', 'link': "
 "'https://gd.weather.com.cn/dongguan/index.shtml'}], 'position': 2}, "
 "{'title': '天气实况与预报 - 深圳市气象局(台)', 'link': "
 "'https://weather.sz.gov.cn/qixiangfuwu/yubaofuwu/index.html', 'snippet': "
 "'深圳市气象局门户网站为您提供权威、及时、准确的深圳天气预警、天气预报、天气实况、台风路径、深圳气候等信息服务,为深圳及其周边城市的生产生活提供全面可靠的气象 "
 "...', 'position': 3}, {'title': '广州-天气预报', 'link': "
 "'https://www.nmc.cn/publish/forecast/AGD/guangzhou.html', 'snippet': '11:00 "
 '· 12.1℃. 7.9m/s · 1022.3hPa. 49.5% ; 14:00 · 14.8℃. 7.8m/s · 1019hPa. 51.9% '
 "; 17:00 · 13.4℃. 7.4m/s · 1017.9hPa. 62.8%.', 'position': 4}, {'title': "
 "'广东省气象局', 'link': 'http://gd.cma.gov.cn/', 'snippet': '首页 · 政务公开 · 政务服务 · "
 "天气预报 · 台风路径 · 地市气象; 搜索. 快速找到您想要的. 气象预警. 暂无预警信息! 周末. 广东省气象局局史馆正式开馆.', "
 "'sitelinks': [{'title': '天气预报', 'link': 'http://gd.cma.gov.cn/qxfw/tqyb/'}, "
 "{'title': '机构与职能', 'link': 'http://gd.cma.gov.cn/zfxxgk/zwgk/jgyzn/'}, "
 "{'title': '查看更多', 'link': "
 "'http://gd.cma.gov.cn/zwgk/zwyw/gzdt/mo_index_12342.html'}, {'title': "
 "'征集调查', 'link': 'http://gd.cma.gov.cn/gzhd/yjzj/mo_index_12342.html'}], "
 "'position': 5}, {'title': '粵.港.澳大灣區天氣網站', 'link': "
 "'https://www.gbaweather.net/', 'snippet': '廣東省氣象局, 香港天文台, 澳門地球物理氣象局. 搜尋地點. "
 "搜尋地點. X ... 天氣警告. 天氣預報. 天氣預報. 氣溫. 氣溫. 相對濕度. 相對濕度. 風. 風. 一小時雨量. 一 ...', "
 "'position': 6}, {'title': '廣州, 廣東省, 中國三日天氣預報 - AccuWeather', 'link': "
 "'https://www.accuweather.com/zh/cn/guangzhou/102255/weather-forecast/102255', "
 "'snippet': '每日預報 ; 今天. 11/17. 87° 58° · 8% ; 周二. 11/18. 60° 52° · 25% ; 周三. "
 "11/19. 63° 54° · 2%.', 'position': 7}, {'title': '廣東省主要城市天氣預報', 'link': "
 "'https://www.hko.gov.hk/textonly/v2/other/wfgc.htm', 'snippet': "
 "'廣東省主要城市天氣預報. 香港天文台於2025 年11 月16 日18 時30 分發出之天氣報告 "
 "(有效時間:11月16日下午8時到11月17日下午8時) 最低溫度最高溫度城市(攝氏度) (攝氏度) ...', 'position': 8}, "
 "{'title': '广东天气预报', 'link': "
 "'https://www.weather.com.cn/html/province/guangdong.shtml', 'snippet': '天气排行 "
 "; 最高气温. 遂溪, 29.0°C ; 最低气温. 连州, 12.7°C ; 昼夜温差. 大埔, 13.7°C.', 'position': 9}, "
 "{'title': '广州天气-广州市气象台,tqyb', 'link': 'http://www.tqyb.com.cn/', 'snippet': "
 "'七天精细化预报 ; 最高气温[南沙区]null:24.8℃. 最低气温[从化区]大岭山林场:15.7℃. 站点气温分布(℃) ; "
 "最大雨量[黄埔区]湖街综合保障中心:0mm. 最小雨量[黄埔区]湖街综合 ...', 'sitelinks': [{'title': '天气雷达回波', "
 "'link': 'http://www.tqyb.com.cn/gz/weatherLive/radar/'}, {'title': '天气预警', "
 "'link': 'http://www.tqyb.com.cn/gz/weatherAlarm/otherCity/'}, {'title': "
 "'广州观测实况', 'link': 'http://www.tqyb.com.cn/gz/weatherLive/distribution/'}, "
 "{'title': '天气实况', 'link': 'http://www.tqyb.com.cn/gz/weatherLive/tqgc/'}], "
 "'position': 10}], 'relatedSearches': [{'query': '广州天气预报15天'}, {'query': "
 "'广东实时天气'}, {'query': '广州天气预报20天'}, {'query': '廣東天氣10天'}, {'query': "
 "'广东广州天气'}, {'query': '广州天气预报40天'}, {'query': '广东深圳天气'}, {'query': "
 "'广州天气预报7天'}], 'credits': 1}")

3.5 工具系统设计

所有工具统一封装为 Tool 对象,包含名称、执行函数和描述。例如,我们可以准备两个工具:网络搜索 和 向量检索。

from langchain.agents import Tool

tools = [
    Tool(
        name="Search",
        func=lambda q: GoogleSerperAPIWrapper().results(q),
        description="在互联网上搜索答案"
    ),
    Tool(
        name="Lookup",
        func=lambda q: "\n".join([doc.page_content for doc in retriever.invoke(q)]),
        description="从本地向量数据库中检索相关文档"
    ),
    # 可扩展其他工具
]

这样 Agent 在对话过程中如果决定“搜索网页”就会调用第一个工具,如果需要“查看知识库”则调用第二个。

四、代码组织与协同方式

按照 LangChain 组件化设计,我们将主要功能模块划分为不同文件或类以便维护:

Embedding 模块:

负责加载 HuggingFaceBgeEmbeddings 模型并构建 FAISS 数据库。示例代码如上,将用于后续检索。

Tool 模块:

定义各种工具。可以把搜索和检索函数封装在此,例如前述的 Search、Retrieve。

Prompt 模板:

使用 PromptTemplate 定义 ReAct 提示格式,插入工具列表和对话历史等变量,例如:

from langchain.prompts import PromptTemplate
prompt = PromptTemplate.from_template(
  "你是一个智能问答助手。你可以使用以下工具:\n{tools}\n"
  "请根据用户问题和工具结果给出答案。\n\n"
  "用户问题: {input}\n"
  "{agent_scratchpad}"
)
记忆模块:

通过 ConversationBufferMemory 保存对话记录。
ConversationBufferMemory 介绍:

from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory

# 初始化 ConversationBufferMemory
memory = ConversationBufferMemory()

# 创建对话链
conversation = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True
)

# 开始对话
response1 = conversation.predict(input="你好!你是谁?")
print(response1)

response2 = conversation.predict(input="你能做什么?")
print(response2)

response3 = conversation.predict(input="你还记得我刚才说了什么吗?")
print(response3)

输出:

Human: 你好!你是谁?
AI: 你好!我是DeepSeek,由深度求索公司创造的AI助手!😊

Human: 你能做什么?
AI: 我能做的事情可多了!让我详细为你介绍一下:
...

Human: 你还记得我刚才说了什么吗?
AI:
> Finished chain.
当然记得!在我们当前的对话中,你刚才问的是:“**你还记得我刚才说了什么吗?**”
Agent 构建:

使用 LangChain 的 ReAct Agent 构造器创建可调用的 Agent:

from langchain.agents import initialize_agent
from langchain.agents.agent_types import AgentType
from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory(memory_key="chat_history")

agent_executor = initialize_agent(
    tools=tools,
    llm=llm,
    agent=AgentType.REACT_DOCSTORE,  # 或 AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION
    memory=memory,
    verbose=True,
    handle_parsing_errors=True
)

这样得到的 agent_executor.invoke({"input": 用户问题}) 会返回模型对话输出,其中模型可以在生成过程中调用 Search 或 Lookup 等工具,并将返回结果纳入思考。

五、FastAPI 封装与示例

完成以上组件后,用 FastAPI 构建 API 服务接口:

from fastapi import FastAPI, Request
app = FastAPI()

@app.post("/chat")
async def chat_api(request: Request):
    data = await request.json()
    query = data.get("query", "")
    # 调用 AgentExecutor 得到回答
    result = agent_executor.invoke({"input": query})
    answer = result["output"]
    return {"answer": answer}

启动:

os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
# 安装依赖
def install_requirements():
    try:
        import fastapi, uvicorn, langchain
        print("✅ 依赖已安装")
    except ImportError:
        print("📦 安装依赖中...")
        subprocess.check_call([sys.executable, "-m", "pip", "install",
                             "fastapi>=0.104.0",
                             "uvicorn[standard]>=0.24.0",
                             "langchain>=0.1.0",
                             "langchain-community>=0.0.10",
                             "langsmith>=0.0.70",
                             "pydantic>=2.0.0",
                             "python-multipart>=0.0.6"])
        print("✅ 依赖安装完成")

if __name__ == "__main__":
    install_requirements()

    # 启动服务器
    print("🚀 启动服务器...")
    import uvicorn
    uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)

启动服务后,客户端即可通过 POST 请求访问,例如:


0df5b3f9-099d-4acf-8e1f-a16b74162f45.png

上述请求返回的 JSON 会包含智能体的回答。整个服务基于组件化设计,后续可替换模型、增加工具或更换向量数据库,而不影响主逻辑。

六、推荐阅读与项目结构示例

推荐阅读:深入了解 LangChain 文档,如 ReAct Agent 和工具调用机制,探索 LangGraph 新架构;学习 DeepSeek 和 BGE 模型的官方资料。
项目目录及代码详情(以模块化方式组织代码):

ai_agent_demo/
├── agents/
│   └── base_agent.py           # 构建智能体
├── tools/
│   ├── search_tool.py          # 搜索工具(DuckDuckGo)
│   ├── doc_reader.py           # 文档读取工具
│   └── vectorstore.py          # 构建向量数据库
├── multimodal/
│   └── image_captioning.py     # 图像识别/图文描述工具
├── memory/
│   └── memory.py               # 智能体记忆模块(新增)
├── app/
│   └── main.py                 # FastAPI 接口入口
├── sample.pdf                  # 示例文档
├── sample.jpg                  # 示例图像
├── main.py                     # 命令行入口
└── requirements.txt            # 依赖管理

命令行交互入口(main.py)

from agents.base_agent import build_agent


def run():
    agent = build_agent()

    print("🔧 智能体已启动... 输入 exit 退出")

    while True:
        user_input = input("\n🧑 用户: ")
        if user_input.lower() in {"exit", "quit"}:
            print("👋 再见!")
            break
        response = agent.invoke(user_input)
        print(f"\n🤖 Agent: {response}")


if __name__ == "__main__":
    run()

FastAPI 部署接口(app/main.py)

# -*- coding: utf-8 -*-

from fastapi import FastAPI, UploadFile, File
from pydantic import BaseModel
from agents.base_agent import build_agent

app = FastAPI()
agent = build_agent()


class Query(BaseModel):
    query: str


@app.post("/chat")
async def chat(q: Query):
    response = agent.invoke(q.query)
    return {"response": response}


@app.post("/upload")
async def upload_pdf(file: UploadFile = File(...)):
    content = await file.read()
    path = f"temp_{file.filename}"
    with open(path, "wb") as f:
        f.write(content)
    response = agent.invoke(f"请阅读 {path} 文件内容")
    return {"response": response}

七、 总结:

本文展示了如何将 RAG、工具调用、多轮记忆等技术融合到一个 LangChain Agent 中,结合 DeepSeek 聊天模型和本地向量数据库,实现实用的问答系统。该架构具有良好可扩展性,可根据需求添加更多工具或采用更强大的模型,以满足复杂的应用场景。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容