LangChain 本地部署与 Agent 智能体助手搭建实战

文档概述

课程会带给你

  1. 如何本地部署 LangChain 框架及生态工具

  2. LangChain 核心组件与 Agent 智能体工作原理

  3. 搭建 Agent 智能体助手的完整流程(工具集成、记忆管理、交互设计)

  4. Agent 调试、优化与生产级部署技巧

  5. 基于 LangChain 构建实用型智能助手案例

学习目标

  1. 理解 LangChain 框架核心价值与生态体系

  2. 掌握 LangChain 本地部署的环境配置与依赖安装

  3. 精通 Agent 智能体的核心组件(LLM、工具、记忆、提示模板)

  4. 能够独立搭建具备工具调用能力的 Agent 智能助手

  5. 学会 Agent 调试、性能优化与生产部署最佳实践

  6. 理解 LangChain 与向量数据库、外部工具的集成逻辑

一、LangChain 技术概述

1.1 什么是 LangChain?

LangChain 是一个用于构建基于大语言模型(LLM)的应用程序与智能体(Agent)的开源框架。它通过标准化接口整合了模型、嵌入、向量存储、工具等组件,提供模块化的架构设计,帮助开发者快速构建具备复杂逻辑、实时数据交互和工具调用能力的 AI 应用。

核心定位:连接 LLM 与外部资源的“桥梁”,解决纯 LLM 存在的知识时效性差、缺乏工具调用能力、无长期记忆等问题。

1.2 纯 LLM 的局限性(LangChain 解决的核心痛点)

  • 知识时效性:模型训练数据存在时间截止点,无法获取实时信息

  • 工具调用缺失:无法直接操作外部系统(搜索、数据库、API 等)

  • 长期记忆不足:对话上下文管理能力有限,难以处理长程交互

  • 任务拆解薄弱:无法将复杂任务分解为可执行的子步骤

  • 集成成本高:与外部数据源、业务系统的对接需要大量定制化开发

1.3 LangChain 核心优势

优势维度 具体说明
生态丰富 支持 100+ 种集成(模型、向量库、工具、API 等)
模块化设计 组件可自由组合,支持从快速原型到生产级应用的全流程
Agent 原生支持 内置 Agent 框架,简化智能体的规划、工具调用、记忆管理逻辑
生产级特性 集成 LangSmith 调试、监控、评估工具,支持规模化部署
社区活跃 开源社区持续贡献组件、模板和最佳实践

1.4 Agent 智能体工作原理

Agent 是 LangChain 的核心应用场景,指具备自主决策、工具调用、任务规划能力的智能体。其工作流程如下:

  1. 接收用户指令(Query)

  2. 基于上下文和记忆,分析任务目标

  3. 规划执行步骤(复杂任务拆解为子任务)

  4. 选择合适的工具并调用(如搜索、数据库查询、本地文档检索)

  5. 解析工具返回结果

  6. 生成最终回复(或继续迭代任务步骤)

核心组件:

  • LLM:Agent 的“大脑”,负责决策、规划和语言生成

  • Tools:Agent 可调用的外部工具(如搜索引擎、文件读取、API 调用)

  • Memory:存储对话历史或任务状态,支持长程交互

  • Prompt Template:定义 Agent 的行为准则、输出格式和决策逻辑

  • LangGraph:用于构建复杂 Agent 工作流(支持循环、分支、人类介入)

二、LangChain 本地部署流程

2.1 部署环境要求

  • 操作系统:Windows 10/11、macOS 12+、Linux(Ubuntu 20.04+ 推荐)

  • 硬件配置:

    • 基础部署:CPU 8核+、内存 16GB+(仅运行框架和轻量模型)

    • Agent 实战:GPU(NVIDIA CUDA 11.8+,显存 12GB+,用于运行本地 LLM)

  • 软件依赖:Python 3.9-3.11(LangChain 推荐版本)、Conda(环境管理)、Git(代码拉取)

2.2 环境配置步骤

2.2.1 使用 Conda 创建独立环境

# 创建 LangChain 专属环境(指定 Python 版本)
conda create -n langchain-agent python=3.10
# 激活环境
conda activate langchain-agent
2.2.2 安装核心依赖库

# 安装 LangChain 核心框架(最新稳定版)
pip install langchain==0.2.14

# 安装 LLM 相关依赖(支持本地模型调用)
pip install langchain-llms-huggingface==0.1.7
pip install langchain-embeddings-huggingface==0.1.2

# 安装向量数据库(以 Chroma 为例,轻量且适合本地部署)
pip install chromadb==0.5.17
pip install llama-index-vector-stores-chroma==0.1.4

# 安装 PyTorch(GPU 版本,需匹配 CUDA 版本)
pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cu118

# 安装工具集成依赖(搜索、文件处理等)
pip install requests==2.32.3  # 网络请求工具
pip install python-dotenv==1.0.1  # 环境变量管理
pip install pdfplumber==0.11.4  # PDF 文档读取
pip install python-magic==0.4.27  # 文件类型识别
2.2.3 拉取 LangChain 源码(可选)

# 克隆 LangChain 官方仓库(获取最新示例和源码)
git clone https://github.com/langchain-ai/langchain.git
cd langchain
# 安装开发依赖(如需修改源码或运行示例)
pip install -e .[all]
2.2.4 部署验证

运行以下代码验证环境是否配置成功:


# 导入 LangChain 核心模块
from langchain import LangChain
from langchain.llms import HuggingFaceLLM
from langchain.embeddings import HuggingFaceEmbeddings

# 验证模块导入
print("LangChain 版本:", LangChain.__version__)
print("HuggingFaceLLM 导入成功")
print("HuggingFaceEmbeddings 导入成功")

# 简单测试:创建 Embedding 模型实例
embedding = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
test_embedding = embedding.embed_query("LangChain 部署测试")
print(f"Embedding 向量维度:{len(test_embedding)}")
print("LangChain 本地部署成功!")

三、模型下载(Agent 核心依赖)

Agent 智能体需要依赖 LLM(决策核心)和 Embedding 模型(文本向量化),以下为本地部署推荐的开源模型及下载流程。

3.1 工具准备

使用 ModelScope 或 Hugging Face Hub 下载模型,这里以 ModelScope 为例(国内访问速度更快):


# 安装 ModelScope SDK
pip install modelscope==1.14.0

3.2 下载 Embedding 模型

推荐使用中文优化模型 BAAI/bge-base-zh-v1.5(兼顾效果与速度):


from modelscope import snapshot_download

# 下载 Embedding 模型到本地目录
embedding_model_dir = snapshot_download(
    model_id="BAAI/bge-base-zh-v1.5",
    cache_dir="D:/AIProject/modelscope/embedding"  # 本地存储路径
)
print(f"Embedding 模型下载完成,路径:{embedding_model_dir}")

3.3 下载 LLM 大模型

推荐使用阿里通义千问(中文支持好、性能稳定):


from modelscope import snapshot_download

# 下载 7B 量级模型(平衡性能与硬件需求)
llm_model_dir = snapshot_download(
    model_id="Qwen/Qwen2.5-7B-Instruct",
    cache_dir="D:/AIProject/modelscope/llm"  # 本地存储路径
)
print(f"LLM 模型下载完成,路径:{llm_model_dir}")

3.4 模型选择说明

模型类型 推荐模型 硬件要求 适用场景
Embedding BAAI/bge-base-zh-v1.5 CPU 8GB+ 或 GPU 中文文本向量化、检索
LLM Qwen2.5-7B-Instruct GPU 12GB+ 中小规模 Agent 决策、对话
LLM(轻量) Qwen2.5-1.8B-Instruct GPU 6GB+ 或 CPU 16GB+ 轻量化部署、快速测试
LLM(高性能) Qwen2.5-14B-Instruct GPU 24GB+ 复杂任务规划、高精度回复

四、Agent 智能体助手搭建实战

以“通用智能助手”为例,具备以下能力:1. 本地文档问答;2. 实时搜索查询;3. 对话记忆管理。

4.1 核心组件设计

组件 选型 作用
LLM Qwen2.5-7B-Instruct 决策核心:解析用户需求、选择工具、生成回复
Embedding BAAI/bge-base-zh-v1.5 文本向量化:支持本地文档检索
向量数据库 Chroma 存储文档 Embedding 向量,提供相似性检索
工具 本地文档检索工具 + 网络搜索工具 扩展 Agent 能力边界
记忆 ConversationBufferMemory 存储对话历史,支持上下文关联
提示模板 自定义中文 Prompt 规范 Agent 行为与输出格式

4.2 代码实现步骤

4.2.1 项目文件树形结构(含文件作用说明)
langchain-agent-project/  # 项目根目录
│
├── .env                  # [环境配置文件] 存储敏感信息(非代码文件)# 内容:SERPER_API_KEY=your_serpapi_key(搜索工具密钥)# 作用:通过 python-dotenv 加载,避免硬编码敏感信息
│
├── requirements.txt      # [依赖清单文件] 项目所有依赖库及版本(非代码文件)# 内容:langchain==0.2.14、torch==2.5.1 等(完整依赖见下文)# 作用:一键安装所有依赖,保证环境一致性
│
├── README.md             # [项目说明文档](非代码文件)# 内容:项目介绍、环境搭建、启动步骤、常见问题# 作用:方便他人使用和维护项目
│
├── LICENSE.md            # [版权许可文件](非代码文件)# 内容:开源许可协议(如 MIT)# 作用:明确项目使用权限
│
├── config.py             # [项目配置文件] 核心参数集中配置# 对应代码:存储模型路径、目录路径、超参数等# 作用:统一管理配置,避免代码中分散硬编码
│
├── main.py               # [项目主程序文件] 程序入口# 对应代码:导入 Agent 核心逻辑、启动交互界面# 作用:作为程序入口,提供用户交互入口
│
├── api.py                # [API 服务文件] 后端服务化入口(新增)# 对应代码:用 FastAPI 封装 Agent 为 HTTP 接口# 作用:接入后端系统,支持前端调用
│
├── agent_core/           # [Agent 核心逻辑目录] 存放智能体核心实现
│   ├── __init__.py       # [包初始化文件]
│   │                     # 作用:标记该目录为 Python 包,支持模块导入
│   │
│   ├── llm_setup.py      # [LLM 配置文件]
│   │                     # 对应代码:4.2.2 中 LLM 初始化逻辑
│   │                     # 作用:封装本地 LLM 加载、Prompt 模板配置
│   │
│   ├── embedding_setup.py# [Embedding 配置文件]
│   │                     # 对应代码:4.2.2 中 Embedding 模型初始化逻辑
│   │                     # 作用:封装 Embedding 模型加载,供向量数据库调用
│   │
│   ├── vector_db.py      # [向量数据库文件]
│   │                     # 对应代码:4.2.2 中文档加载、切分、向量库构建逻辑
│   │                     # 作用:封装本地文档处理和 Chroma 向量库操作
│   │
│   ├── tools_setup.py    # [工具集配置文件]
│   │                     # 对应代码:4.2.2 中工具加载、文档检索工具封装逻辑
│   │                     # 作用:统一管理所有工具,支持工具扩展和维护
│   │
│   ├── memory_setup.py   # [记忆配置文件]
│   │                     # 对应代码:4.2.2 中对话记忆初始化逻辑
│   │                     # 作用:封装对话记忆配置,支持记忆类型切换
│   │
│   └── agent_builder.py  # [Agent 构建文件]# 对应代码:4.2.3 中 Agent 初始化逻辑# 作用:整合 LLM、工具、记忆,构建完整 Agent
│
├── agent_documents/      # [本地文档目录] 存放需检索的本地文档
│   │                     # 对应代码:SimpleDirectoryReader 读取的文档路径
│   │                     # 作用:存储 txt、pdf、docx 等本地知识库文档
│   ├── sample1.txt       # [示例文档 1] 自定义本地知识文档
│   ├── sample2.pdf       # [示例文档 2] 支持 PDF 格式文档
│   └── sample3.docx      # [示例文档 3] 支持 Word 格式文档
│
├── agent_chroma_db/      # [Chroma 向量数据库目录] 自动生成的向量存储目录
│   │                     # 对应代码:Chroma 的 persist_directory 参数
│   │                     # 作用:存储文档 Embedding 向量、索引等数据(自动生成,无需手动创建)
│   ├── chroma.sqlite3    # [向量数据库文件] 存储向量索引和元数据
│   └── uuid_to_path.json # [文档路径映射文件] 记录向量与原始文档的对应关系
│
├── model_links/          # [模型软链接目录] 指向本地模型文件(避免重复存储)
│   │                     # 作用:统一管理模型路径,便于代码中引用
│   ├── llm -> D:/AIProject/modelscope/llm/Qwen/Qwen2.5-7B-Instruct/
│   │                     # 软链接:指向 Qwen 大模型本地路径
│   └── embedding -> D:/AIProject/modelscope/embedding/BAAI/bge-base-zh-v1.5/
│                         # 软链接:指向 BAAI 嵌入模型本地路径
│
└── logs/                 # [日志目录] 存储程序运行日志(自动生成)# 对应代码:logging 配置的日志输出目录# 作用:记录 Agent 运行日志、错误信息,便于调试
    └── agent_run.log     # [运行日志文件] 自动记录程序运行过程
4.2.2 requirements.txt依赖库文件

执行 pip install -r requirements.txt 即可一键安装所有依赖:

langchain==0.2.14
langchain-llms-huggingface==0.1.7
langchain-embeddings-huggingface==0.1.2
chromadb==0.5.17
llama-index-vector-stores-chroma==0.1.4
torch==2.5.1
torchvision==0.20.1
torchaudio==2.5.1
requests==2.32.3
python-dotenv==1.0.1
pdfplumber==0.11.4
python-magic==0.4.27
modelscope==1.14.0
langsmith==0.1.125
fastapi==0.111.0          # 用于后端服务化封装
uvicorn==0.30.1           # ASGI 服务器,运行 FastAPI
pydantic==2.7.4           # 数据校验与模型定义
python-multipart==0.0.7   # 支持文件上传(可选,用于扩展文档上传功能)
cors==0.1.10              # 解决跨域问题(前端对接必备)
redis==5.0.1              # 用于会话记忆存储(多用户场景必备)
4.2.3导入依赖库

import logging
import sys
import torch
from dotenv import load_dotenv
from langchain import PromptTemplate, LLMChain
from langchain.agents import AgentType, initialize_agent, load_tools
from langchain.memory import ConversationBufferMemory
from langchain.llms import HuggingFaceLLM
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma
from langchain.document_loaders import SimpleDirectoryReader
from langchain.text_splitter import SentenceSplitter

# 加载环境变量(存储 API 密钥等敏感信息)
load_dotenv()

# 日志配置
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
4.2.4 初始化核心组件
(1) 创建 config.py`(项目配置文件)

集中管理所有配置参数,修改时无需改动核心逻辑代码:

# 项目路径配置(自动适配系统路径)
import os
from langchain.agents import AgentType

PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
DOCUMENTS_DIR = os.path.join(PROJECT_ROOT, "agent_documents")
CHROMA_DB_DIR = os.path.join(PROJECT_ROOT, "agent_chroma_db")
MODEL_LINKS_DIR = os.path.join(PROJECT_ROOT, "model_links")
LOGS_DIR = os.path.join(PROJECT_ROOT, "logs")

# 创建必要目录(若不存在)
for dir_path in [DOCUMENTS_DIR, CHROMA_DB_DIR, MODEL_LINKS_DIR, LOGS_DIR]:
    if not os.path.exists(dir_path):
        os.makedirs(dir_path)

# 模型配置
LLM_PATH = os.path.join(MODEL_LINKS_DIR, "llm")
EMBEDDING_MODEL_PATH = os.path.join(MODEL_LINKS_DIR, "embedding")
CONTEXT_WINDOW = 4096
MAX_NEW_TOKENS = 2048
TEMPERATURE = 0.1

# 文档处理配置
CHUNK_SIZE = 512
CHUNK_OVERLAP = 50
RETRIEVE_TOP_K = 3

# Agent 配置
AGENT_TYPE = AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION
MAX_ITERATIONS = 5
PARSING_ERROR_MSG = "请重试:无法解析工具调用结果,请重新选择工具"

# System Prompt 配置
SYSTEM_PROMPT = """你是一个通用智能助手,具备以下能力:
1. 可以回答用户的各类问题,优先使用本地文档知识和实时搜索结果
2. 当需要获取实时信息(如天气、新闻、股票)时,调用搜索工具
3. 当用户询问本地文档相关内容时,调用文档检索工具
4. 回答需简洁、准确,基于工具返回结果,不编造信息
5. 记住用户之前的对话内容,提供连贯的交互体验"""

# Redis 配置(用于多用户会话记忆存储,可选)
REDIS_HOST = "localhost"
REDIS_PORT = 6379
REDIS_DB = 0
REDIS_PASSWORD = ""  # 若无密码则留空
(2)创建 agent_core/llm_setup.py(LLM 配置)
from langchain import PromptTemplate
from langchain.llms import HuggingFaceLLM
import torch
from config import (
    LLM_PATH, CONTEXT_WINDOW, MAX_NEW_TOKENS,
    TEMPERATURE, SYSTEM_PROMPT
)

def setup_llm():
    """封装 LLM 初始化逻辑"""
    # 构建 Prompt 模板
    query_wrapper_prompt = PromptTemplate(
        template="[INST]<<SYS>>\n{system_prompt}\n<</SYS>>\n\n{query_str}[/INST] ",
        input_variables=["system_prompt", "query_str"]
    )

    # 初始化本地 LLM
    llm = HuggingFaceLLM(
        context_window=CONTEXT_WINDOW,
        max_new_tokens=MAX_NEW_TOKENS,
        generate_kwargs={
            "temperature": TEMPERATURE,
            "do_sample": True
        },
        query_wrapper_prompt=query_wrapper_prompt,
        tokenizer_name=LLM_PATH,
        model_name=LLM_PATH,
        device_map="auto",
        model_kwargs={"torch_dtype": torch.float16}
    )
    return llm
(3)配置 Embedding 与向量数据库(本地文档检索)
from langchain.embeddings import HuggingFaceEmbeddings
from config import EMBEDDING_MODEL_PATH

def setup_embedding():
    """封装 Embedding 模型初始化逻辑"""
    embedding_model = HuggingFaceEmbeddings(
        model_name=EMBEDDING_MODEL_PATH
    )
    return embedding_model
(4)创建 agent_core/vector_db.py(向量数据库配置)
from langchain.document_loaders import SimpleDirectoryReader
from langchain.text_splitter import SentenceSplitter
from langchain.vectorstores import Chroma
from config import DOCUMENTS_DIR, CHROMA_DB_DIR, CHUNK_SIZE, CHUNK_OVERLAP, RETRIEVE_TOP_K

def build_vector_db(embedding_model):
    """加载本地文档,构建 Chroma 向量数据库"""
    # 加载文档
    documents = SimpleDirectoryReader(
        DOCUMENTS_DIR,
        required_exts=[".txt", ".pdf", ".docx"]
    ).load_data()

    # 文档切分
    text_splitter = SentenceSplitter(
        chunk_size=CHUNK_SIZE,
        chunk_overlap=CHUNK_OVERLAP
    )
    split_docs = text_splitter.split_documents(documents)

    # 构建向量库
    vector_db = Chroma.from_documents(
        documents=split_docs,
        embedding=embedding_model,
        persist_directory=CHROMA_DB_DIR
    )
    vector_db.persist()

    # 构建检索器
    doc_retriever = vector_db.as_retriever(
        search_kwargs={"k": RETRIEVE_TOP_K}
    )
    return doc_retriever
(5)创建 agent_core/tools_setup.py(工具集配置)
from langchain.agents import load_tools
from langchain.tools import RetrievalQAWithSourcesTool
from config import RETRIEVE_TOP_K

def setup_tools(llm, doc_retriever):
    """加载内置工具 + 集成本地文档检索工具"""
    # 加载内置工具(serpapi:搜索,llm-math:数学计算)
    tools = load_tools(
        ["serpapi", "llm-math"],
        llm=llm
    )

    # 封装本地文档检索工具
    doc_tool = RetrievalQAWithSourcesTool.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=doc_retriever,
        name="document_retrieval",
        description="用于回答本地文档相关的问题,当用户询问文档内容时调用"
    )

    # 合并工具集
    tools.append(doc_tool)
    return tools
(6)创建 agent_core/memory_setup.py(记忆配置)
from langchain.memory import ConversationBufferMemory

def setup_memory():
    """封装对话记忆初始化逻辑"""
    memory = ConversationBufferMemory(
        memory_key="chat_history",
        return_messages=True,
        output_key="output"
    )
    return memory
(7)创建 agent_core/agent_builder.py(Agent 构建)
from langchain.memory import ConversationBufferMemory, RedisChatMessageHistory
from config import REDIS_HOST, REDIS_PORT, REDIS_DB, REDIS_PASSWORD

def setup_memory(session_id: str = "default", use_redis: bool = False):
    """
    封装对话记忆初始化逻辑,支持本地内存和 Redis 存储(多用户场景推荐 Redis)
    :param session_id: 会话 ID(区分不同用户)
    :param use_redis: 是否使用 Redis 存储记忆
    :return: 配置好的 ConversationBufferMemory 实例
    """
    if use_redis:
        # 基于 Redis 的会话记忆(支持多用户、服务重启不丢失)
        message_history = RedisChatMessageHistory(
            session_id=session_id,
            host=REDIS_HOST,
            port=REDIS_PORT,
            db=REDIS_DB,
            password=REDIS_PASSWORD
        )
        memory = ConversationBufferMemory(
            memory_key="chat_history",
            return_messages=True,
            output_key="output",
            chat_memory=message_history
        )
    else:
        # 本地内存记忆(单用户、服务重启后丢失)
        memory = ConversationBufferMemory(
            memory_key="chat_history",
            return_messages=True,
            output_key="output"
        )
    return memory
(8)api.py(后端 API 服务文件)
from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional
import logging
import os
from config import LOGS_DIR, REDIS_HOST, REDIS_PORT
from agent_core.llm_setup import setup_llm
from agent_core.embedding_setup import setup_embedding
from agent_core.vector_db import build_vector_db
from agent_core.tools_setup import setup_tools
from agent_core.memory_setup import setup_memory
from agent_core.agent_builder import build_agent

# 初始化 FastAPI 应用
app = FastAPI(title="LangChain Agent 智能助手 API", version="1.0")

# 配置 CORS(解决前端跨域问题)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 生产环境需指定具体前端域名(如 ["http://localhost:3000"])
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 配置日志
log_file = os.path.join(LOGS_DIR, "api_run.log")
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    handlers=[
        logging.FileHandler(log_file, encoding="utf-8"),
        logging.StreamHandler()
    ]
)

# 预加载核心组件(服务启动时初始化,避免每次请求重复加载)
logging.info("API 服务启动,开始初始化 Agent 核心组件...")
try:
    # 1. 加载 LLM 模型
    llm = setup_llm()
    # 2. 加载 Embedding 模型
    embedding_model = setup_embedding()
    # 3. 构建向量数据库
    doc_retriever = build_vector_db(embedding_model)
    # 4. 加载工具集
    tools = setup_tools(llm, doc_retriever)
    logging.info("核心组件初始化完成,API 服务就绪!")
except Exception as e:
    logging.error(f"核心组件初始化失败:{str(e)}", exc_info=True)
    raise

# 请求模型定义(前端传入参数格式)
class ChatRequest(BaseModel):
    user_input: str               # 用户输入内容
    session_id: Optional[str] = "default"  # 会话 ID(区分不同用户)
    use_redis: Optional[bool] = False      # 是否使用 Redis 存储会话记忆

# 响应模型定义(后端返回格式)
class ChatResponse(BaseModel):
    code: int = 200               # 状态码(200 成功,500 失败)
    message: str = "success"      # 状态描述
    data: dict = {}               # 响应数据(包含回复内容、会话 ID)

# 健康检查接口(用于后端监控)
@app.get("/health")
async def health_check():
    return {
        "code": 200,
        "message": "Agent API 服务运行正常",
        "data": {
            "redis": f"连接成功" if check_redis() else "未启用或连接失败",
            "llm": "加载成功",
            "vector_db": "构建成功"
        }
    }

# 聊天交互接口(核心接口,前端调用该接口获取回复)
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    try:
        # 1. 解析请求参数
        user_input = request.user_input.strip()
        session_id = request.session_id
        use_redis = request.use_redis

        if not user_input:
            raise HTTPException(status_code=400, detail="用户输入不能为空")

        # 2. 初始化会话记忆(按 session_id 区分用户)
        memory = setup_memory(session_id=session_id, use_redis=use_redis)

        # 3. 构建 Agent(每次请求创建独立实例,避免会话干扰)
        agent = build_agent(tools=tools, llm=llm, memory=memory)

        # 4. 调用 Agent 生成回复
        logging.info(f"会话 [{session_id}] - 用户输入:{user_input}")
        response = agent.run(user_input)
        logging.info(f"会话 [{session_id}] - Agent 回复:{response}")

        # 5. 返回结果
        return ChatResponse(
            data={
                "response": response,
                "session_id": session_id,
                "use_redis": use_redis
            }
        )
    except HTTPException as e:
        logging.error(f"会话 [{request.session_id}] - 客户端错误:{e.detail}")
        return ChatResponse(
            code=e.status_code,
            message=f"客户端错误:{e.detail}",
            data={"session_id": request.session_id}
        )
    except Exception as e:
        logging.error(f"会话 [{request.session_id}] - 服务端错误:{str(e)}", exc_info=True)
        return ChatResponse(
            code=500,
            message=f"服务端错误:{str(e)}",
            data={"session_id": request.session_id}
        )

# 辅助函数:检查 Redis 连接状态
def check_redis() -> bool:
    try:
        import redis
        r = redis.Redis(
            host=REDIS_HOST,
            port=REDIS_PORT,
            db=0,
            password=REDIS_PASSWORD,
            socket_timeout=2
        )
        return r.ping()
    except Exception:
        return False

# 启动服务(命令行运行时执行)
if __name__ == "__main__":
    import uvicorn
    # 启动 ASGI 服务器(host=0.0.0.0 允许外部访问)
    uvicorn.run(
        app="api:app",
        host="0.0.0.0",
        port=8000,
        reload=True,  # 开发环境启用热重载,生产环境关闭
        workers=1     # 生产环境可根据 CPU 核心数调整(如 4)
    )
(9)创建 main.py(项目主程序)
import logging
import os
from config import LOGS_DIR
from agent_core.llm_setup import setup_llm
from agent_core.embedding_setup import setup_embedding
from agent_core.vector_db import build_vector_db
from agent_core.tools_setup import setup_tools
from agent_core.memory_setup import setup_memory
from agent_core.agent_builder import build_agent

# 配置日志(输出到文件和控制台)
def setup_logging():
    log_file = os.path.join(LOGS_DIR, "agent_run.log")
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s - %(levelname)s - %(message)s",
        handlers=[
            logging.FileHandler(log_file, encoding="utf-8"),
            logging.StreamHandler()
        ]
    )
    logging.info("日志配置完成,开始初始化 Agent...")

# 初始化 Agent 流程
def init_agent():
    try:
        # 1. 初始化 LLM
        logging.info("加载 LLM 模型...")
        llm = setup_llm()

        # 2. 初始化 Embedding 模型
        logging.info("加载 Embedding 模型...")
        embedding_model = setup_embedding()

        # 3. 构建向量数据库和检索器
        logging.info("构建本地文档向量库...")
        doc_retriever = build_vector_db(embedding_model)

        # 4. 配置工具集
        logging.info("加载工具集...")
        tools = setup_tools(llm, doc_retriever)

        # 5. 配置对话记忆
        logging.info("初始化对话记忆...")
        memory = setup_memory()

        # 6. 构建 Agent
        logging.info("构建 Agent 智能体...")
        agent = build_agent(tools, llm, memory)

        logging.info("Agent 初始化完成!")
        return agent
    except Exception as e:
        logging.error(f"Agent 初始化失败:{str(e)}", exc_info=True)
        raise

# 交互函数
def agent_chat(agent):
    print("=== 通用智能助手(输入 'quit' 退出)===")
    while True:
        try:
            user_input = input("\n用户:")
            if user_input.lower() == "quit":
                print("助手:再见!")
                logging.info("用户退出交互")
                break
            logging.info(f"用户输入:{user_input}")
            response = agent.run(user_input)
            print(f"助手:{response}")
            logging.info(f"助手回复:{response}")
        except Exception as e:
            error_msg = f"交互出错:{str(e)}"
            print(f"助手:{error_msg}")
            logging.error(error_msg, exc_info=True)

# 主函数
if __name__ == "__main__":
    # 配置日志
    setup_logging()
    # 初始化 Agent
    agent = init_agent()
    # 启动交互
    agent_chat(agent)
4.2.5 初始化 Agent

# 构建 Agent
agent = initialize_agent(
    tools=tools,
    llm=llm,
    agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,  # 对话型 Agent
    memory=memory,
    verbose=True,  # 打印详细日志(便于调试)
    max_iterations=5,  # 最大迭代次数(避免无限循环)
    handle_parsing_errors="请重试:无法解析工具调用结果,请重新选择工具",
    system_message=SYSTEM_PROMPT
)
4.2.6 测试 Agent 交互

# 交互函数
def agent_chat():
    print("=== 通用智能助手(输入 'quit' 退出)===")
    while True:
        user_input = input("\n用户:")
        if user_input.lower() == "quit":
            print("助手:再见!")
            break
        # 调用 Agent 生成回复
        response = agent.run(user_input)
        print(f"助手:{response}")

# 启动交互
if __name__ == "__main__":
    agent_chat()

4.3 关键配置说明

(1)Agent 类型选择
Agent 类型 适用场景 特点
CHAT_CONVERSATIONAL_REACT_DESCRIPTION 对话型智能助手 支持记忆管理,适合多轮交互
ZERO_SHOT_REACT_DESCRIPTION 单轮任务处理 无需记忆,快速执行单一任务
STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION 结构化输出任务 支持 JSON 等格式输出,适合数据处理
(2)温度参数(temperature)调整
  • temperature=0.0:输出完全确定,无随机性(适合需要精准答案的场景)

  • temperature=0.1-0.3:平衡准确性与灵活性(通用场景推荐)

  • temperature=0.5-0.8:输出更具创造性(适合生成类任务)

(3)工具调用优化
  • 工具描述需清晰:让 LLM 准确理解工具的用途(如“document_retrieval 用于回答本地文档相关问题”)

  • 限制工具数量:初期避免过多工具,减少 LLM 决策负担

  • 增加工具优先级:通过 Prompt 引导 LLM 优先使用合适的工具

五、Agent 调试与优化

5.1 调试工具:LangSmith

LangSmith 是 LangChain 官方推出的一站式调试、监控与评估平台,能全程追踪 Agent 从 “接收请求→决策→工具调用→生成回复” 的完整链路,精准定位每一步的问题。以下是从环境配置→代码集成→测试运行→控制台分析→问题修复的全流程详细说明,含可直接复用的代码片段。

5.1.1 配置 LangSmith

# 安装 LangSmith
pip install langsmith==0.1.125
(1) 获取 LangSmith API Key
  1. 访问 LangSmith 官网(https://smith.langchain.com),使用 GitHub/Google 账号注册并登录。
  2. 登录后,点击右上角头像 → SettingsAPI Keys → 点击 Create API Key,输入密钥名称(如 “agent-debug”),点击创建。
  3. 复制生成的 API Key(格式类似 ls__xxxxxx),后续配置会用到(密钥仅显示一次,需妥善保存)。
(2) 配置环境变量

.env 文件中配置 API 密钥(需在 LangSmith 官网注册获取):


LANGCHAIN_TRACING_V2=true
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
LANGCHAIN_API_KEY=your_api_key
LANGCHAIN_PROJECT=agent-debug
5.1.2 调试流程

需要在 Agent 初始化时添加 LangSmith 回调,实现 “每一步操作都被记录”。以下是 命令行交互(main.py)API 服务(api.py) 的完整集成代码。

(1)命令行交互(main.py)集成示例

main.py 中导入 LangSmith 回调相关模块,修改 init_agent 函数,添加 CallbackManager 配置:

import logging
import os
from dotenv import load_dotenv
from config import LOGS_DIR
# 导入 LangSmith 回调(新增)
from langchain.callbacks import LangChainTracer, CallbackManager
# 导入核心模块
from agent_core.llm_setup import setup_llm
from agent_core.embedding_setup import setup_embedding
from agent_core.vector_db import build_vector_db
from agent_core.tools_setup import setup_tools
from agent_core.memory_setup import setup_memory
from agent_core.agent_builder import build_agent

# 加载环境变量(包含 LangSmith 配置)
load_dotenv()

def setup_logging():
    log_file = os.path.join(LOGS_DIR, "agent_run.log")
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s - %(levelname)s - %(message)s",
        handlers=[
            logging.FileHandler(log_file, encoding="utf-8"),
            logging.StreamHandler()
        ]
    )
    logging.info("日志配置完成,开始初始化 Agent...")

def init_agent():
    try:
        # -------------------------- 新增:LangSmith 回调配置 --------------------------
        # 创建 LangSmith 追踪器(关联环境变量中的 API Key 和项目名)
        tracer = LangChainTracer()
        # 配置回调管理器(同时支持日志和 LangSmith 追踪)
        callback_manager = CallbackManager([tracer, logging.StreamHandler()])
        # -----------------------------------------------------------------------------

        # 1. 加载 LLM 模型(传入 callback_manager)
        logging.info("加载 LLM 模型...")
        llm = setup_llm(callback_manager=callback_manager)  # 新增回调参数

        # 2. 加载 Embedding 模型
        logging.info("加载 Embedding 模型...")
        embedding_model = setup_embedding()

        # 3. 构建向量数据库和检索器
        logging.info("构建本地文档向量库...")
        doc_retriever = build_vector_db(embedding_model)

        # 4. 配置工具集
        logging.info("加载工具集...")
        tools = setup_tools(llm, doc_retriever)

        # 5. 配置对话记忆
        logging.info("初始化对话记忆...")
        memory = setup_memory()

        # 6. 构建 Agent(传入 callback_manager,关键!)
        logging.info("构建 Agent 智能体...")
        agent = build_agent(
            tools=tools,
            llm=llm,
            memory=memory,
            callback_manager=callback_manager  # 让 Agent 所有操作被追踪
        )

        logging.info("Agent 初始化完成!(已启用 LangSmith 调试追踪)")
        return agent
    except Exception as e:
        logging.error(f"Agent 初始化失败:{str(e)}", exc_info=True)
        raise

# 交互函数和主函数保持不变...
def agent_chat(agent):
    print("=" * 50)
    print("=== 通用智能助手(支持本地文档问答、实时搜索、多轮对话)===")
    print("=== 输入 'quit' 或 '退出' 即可结束交互 ===")
    print("=== 所有操作已同步至 LangSmith 控制台,可前往查看轨迹 ===")
    print("=" * 50)
    while True:
        try:
            user_input = input("\n用户:")
            if user_input.lower() in ["quit", "退出"]:
                print("助手:感谢使用,再见!")
                logging.info("用户主动退出交互,程序结束。")
                break
            logging.info(f"用户输入:{user_input}")
            response = agent.run(user_input)
            print(f"助手:{response}")
            logging.info(f"Agent 回复:{response}")
        except Exception as e:
            error_msg = f"交互过程中出现错误:{str(e)}"
            print(f"助手:{error_msg}")
            logging.error(error_msg, exc_info=True)

if __name__ == "__main__":
    setup_logging()
    agent = init_agent()
    agent_chat(agent)
(2)同步修改 agent_core/llm_setup.py(接收回调参数)

由于 main.py 中初始化 LLM 时传入了 callback_manager,需要修改 llm_setup.pysetup_llm 函数,支持接收该参数:

from langchain import PromptTemplate
from langchain.llms import HuggingFaceLLM
import torch
from config import (
    LLM_PATH, CONTEXT_WINDOW, MAX_NEW_TOKENS,
    TEMPERATURE, SYSTEM_PROMPT
)

# 新增:接收 callback_manager 参数(默认 None)
def setup_llm(callback_manager=None):
    """封装 LLM 初始化逻辑"""
    # 构建 Prompt 模板
    query_wrapper_prompt = PromptTemplate(
        template="[INST]<<SYS>>\n{system_prompt}\n<</SYS>>\n\n{query_str}[/INST] ",
        input_variables=["system_prompt", "query_str"]
    )

    # 初始化本地 LLM(新增 callback_manager 配置)
    llm = HuggingFaceLLM(
        context_window=CONTEXT_WINDOW,
        max_new_tokens=MAX_NEW_TOKENS,
        generate_kwargs={
            "temperature": TEMPERATURE,
            "do_sample": True
        },
        query_wrapper_prompt=query_wrapper_prompt,
        tokenizer_name=LLM_PATH,
        model_name=LLM_PATH,
        device_map="auto",
        model_kwargs={"torch_dtype": torch.float16},
        callback_manager=callback_manager  # 关联 LangSmith 回调
    )
    return llm
(3)同步修改 agent_core/agent_builder.py(接收回调参数)

修改 build_agent 函数,支持传入 callback_manager 并传递给 Agent:

from langchain.agents import initialize_agent
from config import AGENT_TYPE, MAX_ITERATIONS, PARSING_ERROR_MSG, SYSTEM_PROMPT

# 新增:接收 callback_manager 参数
def build_agent(tools, llm, memory, callback_manager=None):
    """整合所有组件,构建 Agent"""
    agent = initialize_agent(
        tools=tools,
        llm=llm,
        agent=AGENT_TYPE,
        memory=memory,
        verbose=True,
        max_iterations=MAX_ITERATIONS,
        handle_parsing_errors=PARSING_ERROR_MSG,
        system_message=SYSTEM_PROMPT,
        callback_manager=callback_manager  # 关键:让 Agent 操作被 LangSmith 追踪
    )
    return agent

(4)API 服务(api.py)集成示例(可选)

如果需要调试 API 接口调用场景,在 api.py 中添加 LangSmith 回调配置:

from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional
import logging
import os
from dotenv import load_dotenv
# 导入 LangSmith 回调(新增)
from langchain.callbacks import LangChainTracer, CallbackManager
from config import LOGS_DIR, REDIS_HOST, REDIS_PORT
from agent_core.llm_setup import setup_llm
from agent_core.embedding_setup import setup_embedding
from agent_core.vector_db import build_vector_db
from agent_core.tools_setup import setup_tools
from agent_core.memory_setup import setup_memory
from agent_core.agent_builder import build_agent

# 加载环境变量(包含 LangSmith 配置)
load_dotenv()

app = FastAPI(title="LangChain Agent 智能助手 API", version="1.0")

# 配置 CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# -------------------------- 新增:LangSmith 回调配置 --------------------------
tracer = LangChainTracer()
callback_manager = CallbackManager([tracer, logging.StreamHandler()])
# -----------------------------------------------------------------------------

# 配置日志
log_file = os.path.join(LOGS_DIR, "api_run.log")
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    handlers=[
        logging.FileHandler(log_file, encoding="utf-8"),
        logging.StreamHandler()
    ]
)

# 预加载核心组件(传入 callback_manager)
logging.info("API 服务启动,开始初始化 Agent 核心组件...")
try:
    llm = setup_llm(callback_manager=callback_manager)  # 传入回调
    embedding_model = setup_embedding()
    doc_retriever = build_vector_db(embedding_model)
    tools = setup_tools(llm, doc_retriever)
    logging.info("核心组件初始化完成,API 服务就绪!(已启用 LangSmith 调试)")
except Exception as e:
    logging.error(f"核心组件初始化失败:{str(e)}", exc_info=True)
    raise

# 后续的请求模型、接口定义保持不变,仅在 build_agent 时传入 callback_manager:
# 在 /chat 接口中构建 Agent 时:
agent = build_agent(tools=tools, llm=llm, memory=memory, callback_manager=callback_manager)

集成完成后,运行项目并执行测试用例,LangSmith 会自动记录每一步操作。以下是 3 个典型测试场景(覆盖 Agent 核心能力):

测试用例 1:本地文档问答(验证检索工具调用)

运行

# 运行命令行交互
python main.py

在终端输入:

用户:sample1.txt 里记录了什么内容?
  • 预期行为:Agent 调用 document_retrieval 工具,检索本地文档并返回结果。
  • LangSmith 会记录:文档检索的输入(查询词)、输出(检索到的文档片段)、工具调用决策过程。
测试用例 2:实时搜索查询(验证外部工具调用)

终端输入:

用户:2026年1月北京的平均气温是多少?
  • 预期行为:Agent 调用 serpapi 工具,获取实时搜索结果并整理回复。
  • LangSmith 会记录:搜索工具的请求参数(查询词、时间范围)、返回结果、Agent 对结果的解析过程。
测试用例 3:多轮对话记忆(验证记忆组件)

终端输入:

用户:我刚才问的是什么问题?
  • 预期行为:Agent 从 ConversationBufferMemory 中读取历史对话,回复上一轮问题。
  • LangSmith 会记录:记忆存储的内容、Agent 读取记忆的过程、上下文关联逻辑。
测试用例 4:故意触发错误(验证异常追踪)

终端输入:

用户:计算 123456789 × 987654321(故意输入复杂计算,触发工具调用异常)
  • 预期行为:Agent 调用 llm-math 工具,但可能因计算复杂度或参数问题报错。
  • LangSmith 会记录:错误类型、异常堆栈、工具调用失败的详细原因。
5.1.3 LangSmith 控制台分析:精准定位问题

运行测试用例后,访问 LangSmith 控制台(https://smith.langchain.com),按以下步骤分析轨迹:

(1) 进入项目和轨迹列表
  1. 登录后,在左侧导航栏点击 Projects,找到你配置的项目名(如 “agent-debug-project”)。
  2. 进入项目后,会看到所有测试用例的轨迹列表,每条轨迹包含:
    • 运行时间、状态(成功 / 失败)、耗时、关联的 LLM / 工具。
    • 点击轨迹名称(如 “AgentRun: 2026 年 1 月北京的平均气温是多少?”),进入详细分析页。
(2)轨迹详细分析(核心功能)

轨迹详细页按 “时间线” 展示 Agent 从接收请求到生成回复的全流程,每个步骤都可展开查看细节:

1.查看 Agent 决策过程(最关键)
  • 找到 AgentExecutor 步骤,点击展开 → 查看 Action 字段:
    • action:Agent 选择的工具(如 “serpapi”“document_retrieval”)。
    • action_input:工具的输入参数(如搜索词 “2026 年 1 月北京平均气温”)。
    • observation:工具的返回结果(如搜索到的气温数据、文档片段)。
    • thought:Agent 的思考过程(如 “用户需要实时气温数据,需调用搜索工具”)。
  • 示例:若 Agent 错误地选择了 document_retrieval 工具处理实时天气查询,可在此处发现 “决策逻辑错误”,问题根源可能是 Prompt 中工具用途描述不清晰。
2.查看 Prompt 实际传入内容
  • 找到

    LLM

    步骤(如 “Qwen2.5-7B-Instruct”),点击展开 → 查看

    Inputs

    formatted_prompt
    

    • 此处展示 Agent 传给 LLM 的完整 Prompt(包含 System Prompt、用户输入、工具返回结果、对话记忆)。
    • 示例:若发现 Prompt 中缺少 “实时信息需调用搜索工具” 的引导,可确定是 System Prompt 配置不完善,需优化 Prompt 模板。
3.查看记忆存储与读取
  • 找到

    ConversationBufferMemory

    步骤,点击展开 → 查看

    Memory

    字段:

    • chat_history:存储的对话历史(用户输入 + Agent 回复)。
    • 示例:若多轮对话中 Agent 忘记上一轮问题,可在此处检查 chat_history 是否为空或未正确传递,问题可能是记忆组件未被正确初始化或回调未关联。
4.查看工具调用详情
  • 找到

    Tool

    步骤(如 “serpapi”),点击展开 → 查看:

    • Input:工具接收的完整参数(如搜索词、超时时间)。
    • Output:工具返回的原始结果(未被 LLM 处理的原始数据)。
    • Error:工具调用失败时的异常信息(如 API Key 错误、网络超时、参数格式错误)。
    • 示例:若搜索工具调用失败,可在此处查看是否是 SERPER_API_KEY 配置错误,或返回结果格式不符合 Agent 预期。
5.查看 LLM 生成过程
  • 找到

    LLM

    步骤的

    Outputs

    字段:

    • 查看 LLM 生成的原始回复(包括工具调用指令、最终回复内容)。
    • 示例:若 LLM 生成的工具调用指令格式错误(如未按要求输出 JSON),可确定是 Prompt 中工具调用格式说明不清晰,需优化 Prompt 模板。
5.1.4 典型问题定位与修复示例(结合 LangSmith 轨迹)

以下是 3 个 Agent 常见问题的 “LangSmith 定位 + 代码修复” 完整流程:

问题 1:Agent 不调用工具,直接编造答案(如本地文档查询)
定位过程:
  1. 进入 LangSmith 轨迹详情页,找到 AgentExecutor 步骤。
  2. 查看 thought 字段:发现 Agent 思考 “用户查询本地文档,但未找到相关工具,直接回答”。
  3. 查看 Tools 列表:确认 document_retrieval 工具已被加载,但 description 字段过于简略(如 “用于回答本地文档问题”)。
  4. 查看 LLM 的 formatted_prompt:发现 System Prompt 中未明确 “本地文档查询必须调用 document_retrieval 工具”。
修复方案:

优化 tools_setup.py 中工具的 description,明确适用场景:

运行

# agent_core/tools_setup.py
doc_tool = RetrievalQAWithSourcesTool.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=doc_retriever,
    name="document_retrieval",
    # 优化描述:明确“本地文档”“sample1.txt/sample2.pdf/sample3.docx”等关键词
    description="专门用于回答本地文档(包括 sample1.txt、sample2.pdf、sample3.docx 等)相关的问题,只要用户询问的内容来自这些文档,必须调用该工具"
)

同时优化 config.py 中的 SYSTEM_PROMPT

运行

SYSTEM_PROMPT = """你是一个高效、精准的通用智能助手,严格遵循以下规则:
1. 若用户查询本地文档内容(如 sample1.txt、sample2.pdf、sample3.docx),必须调用 document_retrieval 工具,禁止直接编造答案;
2. 若用户查询实时信息(如天气、新闻、气温),必须调用 serpapi 工具;
3. 若用户查询数学计算,必须调用 llm-math 工具;
4. 回答需基于工具返回结果,不编造信息。"""
问题 2:多轮对话中,Agent 忘记上一轮问题(记忆丢失)
定位过程:
  1. 进入 LangSmith 轨迹详情页,找到 ConversationBufferMemory 步骤。
  2. 查看 chat_history 字段:发现仅存储了当前轮对话,上一轮对话未被保留。
  3. 查看 AgentExecutor 步骤的 inputs 字段:发现 chat_history 参数未被传递给 Agent。
  4. 检查代码:发现 agent_builder.pybuild_agent 函数未正确关联记忆组件。
修复方案:

确认 agent_builder.pymemory 参数已正确传入,且 ConversationBufferMemoryreturn_messages=True

运行

# agent_core/memory_setup.py(确保配置正确)
def setup_memory(session_id: str = "default", use_redis: bool = False):
    if use_redis:
        message_history = RedisChatMessageHistory(
            session_id=session_id,
            host=REDIS_HOST,
            port=REDIS_PORT,
            db=REDIS_DB,
            password=REDIS_PASSWORD
        )
        memory = ConversationBufferMemory(
            memory_key="chat_history",
            return_messages=True,  # 必须设为 True,否则无法传递对话历史
            output_key="output",
            chat_memory=message_history
        )
    else:
        memory = ConversationBufferMemory(
            memory_key="chat_history",
            return_messages=True,  # 关键配置
            output_key="output"
        )
    return memory

同时在 main.py 中确认记忆组件已传入 build_agent

运行

# main.py 中 init_agent 函数
memory = setup_memory()
agent = build_agent(tools=tools, llm=llm, memory=memory, callback_manager=callback_manager)
问题 3:工具调用失败(如 serpapi 搜索无返回)
定位过程:
  1. 进入 LangSmith 轨迹详情页,找到 Tool: serpapi 步骤。
  2. 查看 Error 字段:显示 “API Key invalid”(API 密钥无效)。
  3. 查看 Input 字段:确认 api_key 参数未被正确传递(为空)。
  4. 检查 .env 文件:发现 SERPER_API_KEY 拼写错误(如 SERPER_APIKEY)。
修复方案:

修正 .env 文件中的密钥名称:

# 错误:SERPER_APIKEY=your_key
正确:SERPER_API_KEY=your_key  # 与代码中 load_dotenv() 读取的键名一致

同时在 tools_setup.py 中确认工具加载时已读取环境变量:

运行

# agent_core/tools_setup.py
tools = load_tools(
    ["serpapi", "llm-math"],
    llm=llm  # load_tools 会自动从环境变量读取 SERPER_API_KEY
)

5.2 优化方向

(1)检索效果优化
  • 检索是本地文档问答的核心,优化需从“文档切分、Embedding模型、检索参数”三方面入手,直接提升答案相关性,以下是具体落地方案:

    • 调整文档切分参数:原代码中chunk_size=512适用于通用场景,若文档多为短句、碎片化内容,可减小至256;若为长文本(如论文、报告),保持512即可,同时调整重叠度提升上下文连贯性。

       `# 优化后文档切分代码(适配不同文档类型) ``text_splitter = SentenceSplitter( ``    chunk_size=256,  # 短句文档用256,长文本用512 ``    chunk_overlap=64  # 重叠度提升至64,减少上下文断裂 ``) ``split_docs = text_splitter.split_documents(documents) ``# 补充:针对PDF长文档,可先按页面拆分,再按token切分 ``from langchain.text_splitter import RecursiveCharacterTextSplitter ``# 适配长文本的分级切分(优先按段落、句子拆分) ``text_splitter = RecursiveCharacterTextSplitter( ``    chunk_size=512, ``    chunk_overlap=64, ``    separators=["\n\n", "\n", "。", ",", " "]  # 中文适配分隔符 ``) ``split_docs = text_splitter.split_documents(documents)`
      
    • 更换高性能Embedding模型:原BAAI/bge-base-zh-v1.5效果够用,更换为large版本(维度从768提升至1024),可显著提升中文文本相关性,需注意模型体积增大,建议GPU运行。

       `# 1. 先下载large版本模型(同前文下载逻辑,仅修改model_id) ``from modelscope import snapshot_download ``embedding_model_dir = snapshot_download( ``    model_id="BAAI/bge-large-zh-v1.5", ``    cache_dir="D:/AIProject/modelscope/embedding" ``) ``# 2. 初始化优化后的Embedding模型 ``embedding_model = HuggingFaceEmbeddings( ``    model_name=embedding_model_dir, ``    model_kwargs={"device": "cuda"}  # 强制GPU加速,提升向量化速度 ``)`
      
    • 优化检索参数与策略:原k=3可能遗漏关键片段,调整为5-8;同时添加检索分数过滤,排除低相关性片段(分数越低相关性越高,通常阈值设为0.3)。

       `# 优化后检索工具配置 ``doc_retriever = vector_db.as_retriever( ``    search_kwargs={ ``        "k": 5,  # 返回top5相关片段 ``        "score_threshold": 0.3  # 过滤分数>0.3的低相关片段 ``    }, ``    search_type="similarity_score_threshold"  # 启用分数过滤策略 ``) ``# 补充:复杂场景可用混合检索(相似性+MMR),平衡相关性与多样性 ``doc_retriever = vector_db.as_retriever( ``    search_type="mmr",  # 最大边际相关性 ``    search_kwargs={ ``        "k": 5, ``        "fetch_k": 20,  # 先获取20个候选片段,再筛选5个 ``        "lambda_mult": 0.7  # 0.7偏向相关性,0.3偏向多样性 ``    } ``)`
      
(2)Agent 决策优化
  • Agent决策偏差的核心原因是“Prompt引导不足、LLM对工具认知模糊”,需通过Prompt优化、示例引导等方式,强制规范工具调用逻辑:

    • 精准优化System Prompt:明确工具调用的“触发条件、优先级、格式要求”,避免LLM编造答案或误用工具。

      # 优化后System Prompt(新增触发条件、优先级、格式约束)
      SYSTEM_PROMPT = """你是一个严格遵循工具调用规则的通用智能助手,按以下优先级和条件工作:
      1. 工具调用优先级:本地文档检索工具 > 搜索工具 > 数学计算工具 > 直接回答
      2. 触发条件:
         - 询问本地文档内容(含文件名、文档内知识点)→ 必须调用document_retrieval工具
         - 涉及2024年后实时信息、天气、新闻、股票、未公开数据 → 必须调用serpapi工具
         - 涉及加减乘除、公式计算、数据统计 → 必须调用llm-math工具
         - 仅当工具返回结果无法回答,或问题为常识性内容时,才直接回答
      3. 输出要求:工具调用结果需整理成自然语言,标注信息来源(文档/搜索),不编造内容
      4. 错误处理:若工具调用失败,重试1次,仍失败则告知用户无法获取对应信息"""
      
    • 添加Few-Shot示例引导:在Prompt模板中插入2-3个典型场景示例,让LLM更易理解工具调用逻辑,尤其适配中文场景。

      # 构建带Few-Shot示例的Prompt模板
      FEW_SHOT_EXAMPLES = """示例1(本地文档查询):
      用户:sample1.txt里记录的LangChain核心组件有哪些?
      思考:用户询问本地文档内容,调用document_retrieval工具
      工具调用:document_retrieval(查询词="LangChain核心组件")
      工具返回:LangChain核心组件包括LLM、Tools、Memory、Prompt Template
      回答:根据sample1.txt内容,LangChain核心组件包括LLM、Tools、Memory、Prompt Template。
      
      示例2(实时搜索查询):
      用户:2026年2月北京的平均气温是多少?
      思考:问题涉及2026年实时信息,调用serpapi工具
      工具调用:serpapi(查询词="2026年2月北京平均气温")
      工具返回:2026年2月北京平均气温为-2℃~8℃
      回答:根据实时搜索结果,2026年2月北京平均气温为-2℃~8℃。"""
      
      # 整合示例到Prompt模板
      query_wrapper_prompt = PromptTemplate(
          template="[INST]<<SYS>>\n{system_prompt}\n{few_shot_examples}\n<</SYS>>\n\n{query_str}[/INST] ",
          input_variables=["system_prompt", "few_shot_examples", "query_str"]
      )
      
      # 初始化LLM时传入示例
      llm = HuggingFaceLLM(
          # 原有参数不变...
          query_wrapper_prompt=query_wrapper_prompt,
          # 其他参数...
      )
      
      # 调用Agent时传入示例(确保每次调用都携带)
      response = agent.run({
          "query_str": user_input,
          "system_prompt": SYSTEM_PROMPT,
          "few_shot_examples": FEW_SHOT_EXAMPLES
      })
      
    • 强制工具调用校验:通过自定义Hook函数,校验Agent是否按规则调用工具,避免漏调、误调。

      from langchain.callbacks import BaseCallbackHandler
      
      class ToolCallValidator(BaseCallbackHandler):
          """自定义回调,校验工具调用是否符合规则"""
          def on_agent_action(self, action, **kwargs):
              user_query = kwargs.get("inputs", {}).get("query_str", "")
              tool_name = action.tool
              # 校验本地文档查询是否调用正确工具
              if any(doc_keyword in user_query for doc_keyword in ["sample1.txt", "sample2.pdf", "文档"]) and tool_name != "document_retrieval":
                  raise ValueError(f"错误:询问文档内容应调用document_retrieval工具,当前调用{tool_name}")
              # 校验实时信息是否调用搜索工具
              if any(real_time_keyword in user_query for real_time_keyword in ["2024", "2025", "2026", "天气", "新闻"]) and tool_name != "serpapi":
                  raise ValueError(f"错误:询问实时信息应调用serpapi工具,当前调用{tool_name}")
      
      # 初始化回调管理器,添加校验器
      from langchain.callbacks import CallbackManager
      callback_manager = CallbackManager([ToolCallValidator(), logging.StreamHandler()])
      
      # 构建Agent时传入回调(前文代码中补充)
      agent = initialize_agent(
          # 原有参数不变...
          callback_manager=callback_manager
      )
      
(3)记忆管理优化
  • 原ConversationBufferMemory适合短对话,长对话易导致上下文溢出、记忆冗余,需针对性优化记忆类型、过期策略:

    • 更换记忆类型(长对话适配):长对话场景改用ConversationSummaryMemory,自动总结历史对话,压缩上下文体积,同时保留关键信息。

      # 1. 安装依赖(若未安装)
      # pip install langchain-core==0.2.34
      
      # 2. 初始化ConversationSummaryMemory
      from langchain.memory import ConversationSummaryMemory
      from langchain.chains import LLMChain
      
      # 构建总结链(用于总结历史对话)
      summary_chain = LLMChain(
          llm=llm,
          prompt=PromptTemplate(
              input_variables=["history"],
              template="请简洁总结以下对话内容,保留核心问题和答案,不超过50字:\n{history}"
          )
      )
      
      # 初始化总结记忆
      memory = ConversationSummaryMemory(
          memory_key="chat_history",
          return_messages=True,
          llm_chain=summary_chain,  # 关联总结链
          output_key="output",
          max_token_limit=512  # 记忆总token上限,避免溢出
      )
      
      # 补充:混合记忆(短期完整记忆+长期总结记忆)
      from langchain.memory import ConversationSummaryBufferMemory
      memory = ConversationSummaryBufferMemory(
          memory_key="chat_history",
          return_messages=True,
          llm=llm,
          max_token_limit=1024,  # 总上限
          buffer_window=3  # 最近3轮对话完整保留,更早的总结压缩
      )
      
    • 清理无关记忆(精准过滤):通过Prompt引导和代码过滤,让Agent忽略无关对话内容(如问候语、无意义语句),减少记忆冗余。

      # 1. Prompt引导过滤
      SYSTEM_PROMPT += "\n5. 记忆规则:忽略问候语(如你好、再见)、无意义语句(如哦、嗯),仅记忆有效问题和答案。"
      
      # 2. 代码层面过滤无关内容(在交互函数中补充)
      def filter_irrelevant_content(user_input: str) -> bool:
          """过滤无关内容,返回True表示需记忆,False表示忽略"""
          irrelevant_keywords = ["你好", "您好", "再见", "拜拜", "哦", "嗯", "啊", "哦豁"]
          return not any(keyword in user_input for keyword in irrelevant_keywords)
      
      # 优化交互函数,过滤后再存入记忆
      def agent_chat():
          print("=== 通用智能助手(输入 'quit' 退出)===")
          while True:
              user_input = input("\n用户:")
              if user_input.lower() == "quit":
                  print("助手:再见!")
                  break
              # 过滤无关内容,不存入记忆
              if not filter_irrelevant_content(user_input):
                  response = "好的~"
                  print(f"助手:{response}")
                  continue
              # 正常调用Agent
              response = agent.run(user_input)
              print(f"助手:{response}")
      

六、生产级部署最佳实践

6.1 容器化部署(Docker)

6.1.1 编写 Dockerfile

# 基础镜像
FROM python:3.10-slim

# 设置工作目录
WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    git \
    && rm -rf /var/lib/apt/lists/*

# 复制依赖文件
COPY requirements.txt .

# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制项目文件
COPY . .

# 复制模型文件(或通过挂载目录方式挂载)
COPY ./modelscope /app/modelscope

# 暴露端口
EXPOSE 8000

# 启动命令(使用 FastAPI 封装 Agent 为 API 服务)
CMD ["uvicorn", "agent_api:app", "--host", "0.0.0.0", "--port", "8000"]
6.1.2 构建与运行容器

# 构建镜像
docker build -t langchain-agent .

# 运行容器(挂载模型目录和向量库)
docker run -d \
    -p 8000:8000 \
    -v D:/AIProject/modelscope:/app/modelscope \
    -v ./agent_chroma_db:/app/agent_chroma_db \
    --name langchain-agent-container \
    langchain-agent

6.2 服务化封装(FastAPI)

将 Agent 封装为 HTTP API 服务,支持跨平台调用:


# agent_api.py
from fastapi import FastAPI, Request
from pydantic import BaseModel
from agent_core import agent  # 导入之前构建的 Agent

app = FastAPI(title="LangChain Agent API")

# 请求模型
class ChatRequest(BaseModel):
    user_input: str
    session_id: str = "default"

# 响应模型
class ChatResponse(BaseModel):
    response: str
    session_id: str

# 聊天接口
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    try:
        # 调用 Agent 生成回复
        response = agent.run(request.user_input)
        return ChatResponse(
            response=response,
            session_id=request.session_id
        )
    except Exception as e:
        return ChatResponse(
            response=f"出错了:{str(e)}",
            session_id=request.session_id
        )

# 健康检查接口
@app.get("/health")
async def health_check():
    return {"status": "healthy"}

6.3 监控与评估

  • 监控指标:Agent 响应时间、工具调用成功率、错误率、用户满意度

  • 评估工具:LangSmith 提供的 Agent 评估模块,支持自定义评估指标

  • 持续优化:定期分析错误案例,优化 Prompt、工具配置和模型选择

七、常见问题解决

7.1 模型加载失败

  • 问题原因:模型路径错误、硬件资源不足、PyTorch 版本不兼容

  • 解决方案:

    1. 检查模型路径是否正确(避免中文路径)

    2. 确认 GPU 显存充足(7B 模型需至少 12GB 显存)

    3. 安装与 CUDA 匹配的 PyTorch 版本

7.2 Agent 工具调用错误

  • 问题原因:工具描述不清晰、Prompt 引导不足、LLM 理解能力有限

  • 解决方案:

    1. 优化工具描述,明确工具的适用场景和输入格式

    2. 在 Prompt 中添加工具调用示例

    3. 更换更大参数量的 LLM(如 14B 模型)

7.3 检索结果不准确

  • 问题原因:文档切分不合理、Embedding 模型不匹配、检索参数设置不当

  • 解决方案:

    1. 调整 chunk_sizechunk_overlap 参数

    2. 使用中文优化的 Embedding 模型

    3. 增加 k 值(返回更多相关片段)

7.4 对话记忆丢失

  • 问题原因:记忆类型选择不当、上下文窗口过小

  • 解决方案:

    1. 使用 ConversationBufferMemoryConversationSummaryMemory

    2. 增大 LLM 的 context_window 参数

    3. 定期清理无关记忆内容

八、扩展与进阶

8.1 工具扩展

  • 集成业务系统:如数据库查询工具(SQLDatabaseToolkit)、API 调用工具(RequestsToolkit)

  • 自定义工具:根据业务需求开发专属工具(如订单查询、数据统计工具)

  • 工具链组合:将多个工具组合为工具链,实现复杂任务自动化(如“数据查询 → 分析 → 报告生成”)

8.2 LangChain 生态工具集成

  • LangGraph:构建更复杂的 Agent 工作流(支持循环、分支、人类介入)

  • LangServe:快速部署 LangChain 应用为服务

  • LangChain Hub:共享和复用 Prompt、链、Agent 配置

  • Deep Agents:构建具备规划能力、子Agent 协作的高级智能体

8.3 高级应用场景

  • 智能客服:集成知识库、工单系统,提供自动化客户支持

  • 数据分析助手:连接数据库,自动生成 SQL、分析数据并生成报告

  • 研发助手:集成代码仓库、文档系统,辅助代码编写、文档生成

  • 个人助理:管理日程、发送邮件、查询信息,提供个性化服务

总结

本文档详细介绍了 LangChain 框架的本地部署流程、Agent 智能体的核心原理与搭建步骤,并提供了完整的代码示例和优化方案。通过 LangChain 的模块化设计,开发者可以快速构建具备工具调用、记忆管理、任务规划能力的智能助手,并基于实际需求进行扩展与优化。

随着 AI 技术的发展,LangChain 生态将持续完善,Agent 智能体的应用场景也将不断扩展。建议开发者在实践中结合 LangSmith 等工具进行调试与评估,持续优化产品体验,逐步实现从原型到生产级应用的落地。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐