掘金 人工智能 05月16日 10:48
LangChain 框架下的 AI Agent 构建与部署实践
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文详细介绍了如何使用LangChain框架构建一个功能齐全、可部署的智能问答Agent。文章结合ReAct架构、RAG检索增强、提示工程、工具调用等核心概念,选用DeepSeek聊天模型、BAAI/bge-small-zh-v1.5嵌入模型、FAISS向量数据库和DuckDuckGoSearchRun联网搜索工具。通过模块化代码示例,展示了LangChain各组件在完整项目中的协作关系,并使用FastAPI将Agent封装成API服务,方便Web前端接入。文章还涵盖了Tool封装规范、Agent执行中间状态管理、复杂提示结构设计等主题。

💡**LangChain框架核心组件**:LangChain包含Models、Prompts、Memory、Indexes、Chains和Agents等核心模块,支持多种语言模型接口,提供提示管理、记忆管理、文档处理和动态决策等功能,可以组合使用来构建复杂的AI Agent。

🛠️**工具系统设计**:所有工具统一封装为Tool对象,包含名称、执行函数和描述。文章示例中,集成了联网搜索(DuckDuckGoSearchRun)与本地向量检索(FAISS)两种工具,Agent可以根据对话内容选择合适的工具。

🔗**ReAct框架与RAG**:ReAct框架允许模型在对话过程中思考、采取动作并观察结果,从而动态调用外部工具。RAG技术通过检索相关文档来提供上下文或证据,适用于将领域知识融入对话,避免模型只凭“记忆”回答超出能力的问题。

🌐**FastAPI封装与API服务**:文章演示了如何使用FastAPI将构建好的Agent封装成API服务接口,客户端可以通过POST请求访问该接口,获取智能体的回答。这种组件化设计方便后续替换模型、增加工具或更换向量数据库。

    专栏系列第 6 篇 · 智能体纪元

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

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

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

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

二、核心概念回顾

三、系统架构与组件选型

3.1 语言模型与嵌入

import osfrom langchain_community.chat_models import ChatOpenAIAPI_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  # 是否打印调试信息)

✅ 参数使用建议

    温度设置
      temperature=0.0 适合问答、摘要、代码生成等确定性任务;temperature=0.7~1.0 更适合生成富有创意的内容。
    兼容模型
      若使用 DeepSeek、Moonshot、Azure OpenAI 等非官方 API,务必设置 openai_api_base
    高阶用法
      可结合 LLMChainAgentExecutor 构建复杂流程。

这样实例化后,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 来读取不同格式的文档。

from langchain_community.document_loaders import TextLoaderloader = TextLoader('./docs/智能体简介.md', encoding='utf-8')documents = loader.load()

from langchain_community.document_loaders import DirectoryLoaderloader = DirectoryLoader('./docs', glob='**/*.md', loader_cls=TextLoader, loader_kwargs={'encoding': 'utf-8'})documents = loader.load()

对于 PDF 文件,可以使用 PyPDFLoader 进行加载。它会按页读取并自动转为 Document 对象。

from langchain_community.document_loaders import PyPDFLoaderloader = PyPDFLoader('./docs/GB+38031-2025.pdf')documents = loader.load()

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

all_documents = md_documents + pdf_documents + other_documents

(2)文档切分

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

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

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

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 + 存入向量数据库)用户查询转换(embedding + 相似文档检索)BGE 模型推荐在 embed_query() 之前添加查询指令(query_instruction),以获得更好的效果。
query_instruction = "为这个句子生成表示以用于检索相关文章:"question = "人工智能是一门研究如何让计算机具有人类智能的科学"query = query_instruction + questionvector = embed_model.embed_query(query)  # 得到向量表示(用于查询)print(vector)

输出:

1. 将前面切分后的 split_docs 向量化,并存入 FAISS

from langchain.vectorstores import FAISSvectorstore = FAISS.from_documents(split_docs, embed_model)# 保存本地索引以供后续检索调用vectorstore.save_local("faiss_index")

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

2. 检索器构造(Retriever)

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

retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 4})query = "电动汽车用动力蓄电池按照8.2.1进行振动试验后应达到什么要求?"docs = retriever.get_relevant_documents(query)for i, doc in enumerate(docs, 1):    print(f"[文档 {i}]: {doc.page_content}\n")

输出:

3.4 联网搜索工具

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

from langchain_community.tools import DuckDuckGoSearchRunsearch_tool = DuckDuckGoSearchRun()result = search_tool.invoke("最近一次 SpaceX 火箭发射是什么时候?成功了吗?")

这个工具方便集成到 Agent 中,实现“需要联网搜索”时的补充信息。

3.5 工具系统设计

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

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

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

四、代码组织与协同方式

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

from langchain.prompts import PromptTemplateprompt = PromptTemplate.from_template(  "你是一个智能问答助手。你可以使用以下工具:\n{tools}\n"  "请根据用户问题和工具结果给出答案。\n\n"  "用户问题: {input}\n"  "{agent_scratchpad}")
from langchain.agents import initialize_agentfrom langchain.agents.agent_types import AgentTypefrom langchain.memory import ConversationBufferMemorymemory = 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": 用户问题}) 会返回模型对话输出,其中模型可以在生成过程中调用 SearchLookup 等工具,并将返回结果纳入思考。

response = agent_executor.invoke({"input": "中国政府对电动汽车用动力蓄电池有什么新的要求?"})print(response)

输出:

> Finished chain.{'input': '中国政府对电动汽车用动力蓄电池有什么新的要求?', 'chat_history': '', 'output': '中国政府对电动汽车用动力蓄电池的新要求包括加强安全性能测试、推行生产者责任延伸制度、鼓励低碳生产、提高技术标准与性能要求,以及实施全生命周期溯源管理。'}

五、FastAPI 封装与示例

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

from fastapi import FastAPI, Requestapp = 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}

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

curl -X POST http://localhost:8000/chat -H "Content-Type: application/json" -d '{"query":"上海天气怎么样?"}'

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

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

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            # 依赖管理

详细代码调试完毕后会更新。

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

LangChain 智能问答Agent ReAct框架 RAG FastAPI
相关文章