胡扬树 發表於 2026-3-8 12:07:00

LangChain 本地部署与 Agent 智能体助手搭建实战详解 - 指南

<style>pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; line-height: 1.6 !important; padding: 16px !important; margin: 16px 0 !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; tab-size: 4 !important; -moz-tab-size: 4 !important; max-width: 100% !important; box-sizing: border-box !important }
code { font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow-wrap: normal !important; display: inline !important; background: rgba(0, 0, 0, 0) !important; border: none !important; padding: 0 !important; margin: 0 !important; line-height: inherit !important }
pre code { background: rgba(0, 0, 0, 0) !important; border: 0 !important; border-radius: 0 !important; display: block !important; line-height: 1.6 !important; margin: 0 !important; max-width: none !important; overflow: visible !important; padding: 0 !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; color: inherit !important }
.token.comment, .token.prolog, .token.doctype, .token.cdata { color: rgba(112, 128, 144, 1) !important; font-style: italic !important }
.token.punctuation { color: rgba(153, 153, 153, 1) !important }
.token.atrule, .token.attr-value, .token.keyword { color: rgba(0, 119, 170, 1) !important; font-weight: bold !important }
.token.function, .token.class-name { color: rgba(221, 74, 104, 1) !important; font-weight: bold !important }
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: rgba(102, 153, 0, 1) !important }
.token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: rgba(153, 0, 85, 1) !important }
.cnblogs-markdown pre, .cnblogs-post-body pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; padding: 16px !important; margin: 16px 0 !important }
pre, pre, pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important }</style>
      <div class="markdown_views prism-atom-one-light" id="content_views"><svg style="display: none" xmlns="http://www.w3.org/2000/svg"><path d="M5,0 0,2.5 5,5z" id="raphael-marker-block" stroke-linecap="round" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0)"></path></svg><h2>LangChain 本地部署与 Agent 智能体助手搭建实战</h2><h3>文档概述</h3><h4>课程会带给你</h4><ol><li><p>如何本地部署 LangChain 框架及生态工具</p></li><li><p>LangChain 核心组件与 Agent 智能体工作原理</p></li><li><p>搭建 Agent 智能体助手的完整流程(工具集成、记忆管理、交互设计)</p></li><li><p>Agent 调试、优化与生产级部署技巧</p></li><li><p>基于 LangChain 构建实用型智能助手案例</p></li></ol><h4>学习目标</h4><ol><li><p>理解 LangChain 框架核心价值与生态体系</p></li><li><p>掌握 LangChain 本地部署的环境配置与依赖安装</p></li><li><p>精通 Agent 智能体的核心组件(LLM、工具、记忆、提示模板)</p></li><li><p>能够独立搭建具备工具调用能力的 Agent 智能助手</p></li><li><p>学会 Agent 调试、性能优化与生产部署最佳实践</p></li><li><p>理解 LangChain 与向量数据库、外部工具的集成逻辑</p></li></ol><h3>一、LangChain 技术概述</h3><h4>1.1 什么是 LangChain?</h4><p>LangChain 是一个用于构建基于大语言模型(LLM)的应用程序与智能体(Agent)的开源框架。它通过标准化接口整合了模型、嵌入、向量存储、工具等组件,提供模块化的架构设计,帮助开发者快速构建具备复杂逻辑、实时数据交互和工具调用能力的 AI 应用。</p><p>核心定位:<strong>连接 LLM 与外部资源的“桥梁”</strong>,解决纯 LLM 存在的知识时效性差、缺乏工具调用能力、无长期记忆等问题。</p><h4>1.2 纯 LLM 的局限性(LangChain 解决的核心痛点)</h4><ul><li><p>知识时效性:模型训练数据存在时间截止点,无法获取实时信息</p></li><li><p>工具调用缺失:无法直接操作外部系统(搜索、数据库、API 等)</p></li><li><p>长期记忆不足:对话上下文管理能力有限,难以处理长程交互</p></li><li><p>任务拆解薄弱:无法将复杂任务分解为可执行的子步骤</p></li><li><p>集成成本高:与外部数据源、业务系统的对接需要大量定制化开发</p></li></ul><h4>1.3 LangChain 核心优势</h4><table><thead><tr><th>优势维度</th><th>具体说明</th></tr></thead><tbody><tr><td>生态丰富</td><td>支持 100+ 种集成(模型、向量库、工具、API 等)</td></tr><tr><td>模块化设计</td><td>组件可自由组合,支持从快速原型到生产级应用的全流程</td></tr><tr><td>Agent 原生支持</td><td>内置 Agent 框架,简化智能体的规划、工具调用、记忆管理逻辑</td></tr><tr><td>生产级特性</td><td>集成 LangSmith 调试、监控、评估工具,支持规模化部署</td></tr><tr><td>社区活跃</td><td>开源社区持续贡献组件、模板和最佳实践</td></tr></tbody></table><h4>1.4 Agent 智能体工作原理</h4><p>Agent 是 LangChain 的核心应用场景,指具备<strong>自主决策、工具调用、任务规划</strong>能力的智能体。其工作流程如下:</p><ol><li><p>接收用户指令(Query)</p></li><li><p>基于上下文和记忆,分析任务目标</p></li><li><p>规划执行步骤(复杂任务拆解为子任务)</p></li><li><p>选择合适的工具并调用(如搜索、数据库查询、本地文档检索)</p></li><li><p>解析工具返回结果</p></li><li><p>生成最终回复(或继续迭代任务步骤)</p></li></ol><p>核心组件:</p><ul><li><p><strong>LLM</strong>:Agent 的“大脑”,负责决策、规划和语言生成</p></li><li><p><strong>Tools</strong>:Agent 可调用的外部工具(如搜索引擎、文件读取、API 调用)</p></li><li><p><strong>Memory</strong>:存储对话历史或任务状态,支持长程交互</p></li><li><p><strong>Prompt Template</strong>:定义 Agent 的行为准则、输出格式和决策逻辑</p></li><li><p><strong>LangGraph</strong>:用于构建复杂 Agent 工作流(支持循环、分支、人类介入)</p></li></ul><h3>二、LangChain 本地部署流程</h3><h4>2.1 部署环境要求</h4><ul><li><p>操作系统:Windows 10/11、macOS 12+、Linux(Ubuntu 20.04+ 推荐)</p></li><li><p>硬件配置:</p><ul><li><p>基础部署:CPU 8核+、内存 16GB+(仅运行框架和轻量模型)</p></li><li><p>Agent 实战:GPU(NVIDIA CUDA 11.8+,显存 12GB+,用于运行本地 LLM)</p></li></ul></li><li><p>软件依赖:Python 3.9-3.11(LangChain 推荐版本)、Conda(环境管理)、Git(代码拉取)</p></li></ul><h4>2.2 环境配置步骤</h4><h5>2.2.1 使用 Conda 创建独立环境</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Bash"># 创建 LangChain 专属环境(指定 Python 版本)
conda create -n langchain-agent python=3.10
# 激活环境
conda activate langchain-agent</code></pre>
<h5>2.2.2 安装核心依赖库</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Bash"># 安装 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# 文件类型识别</code></pre>
<h5>2.2.3 拉取 LangChain 源码(可选)</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Bash"># 克隆 LangChain 官方仓库(获取最新示例和源码)
git clone https://github.com/langchain-ai/langchain.git
cd langchain
# 安装开发依赖(如需修改源码或运行示例)
pip install -e .</code></pre>
<h5>2.2.4 部署验证</h5><p>运行以下代码验证环境是否配置成功:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python"># 导入 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 本地部署成功!")</code></pre>
<h3>三、模型下载(Agent 核心依赖)</h3><p>Agent 智能体需要依赖 LLM(决策核心)和 Embedding 模型(文本向量化),以下为本地部署推荐的开源模型及下载流程。</p><h4>3.1 工具准备</h4><p>使用 ModelScope 或 Hugging Face Hub 下载模型,这里以 ModelScope 为例(国内访问速度更快):</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Bash"># 安装 ModelScope SDK
pip install modelscope==1.14.0</code></pre>
<h4>3.2 下载 Embedding 模型</h4><p>推荐使用中文优化模型 BAAI/bge-base-zh-v1.5(兼顾效果与速度):</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python">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}")</code></pre>
<h4>3.3 下载 LLM 大模型</h4><p>推荐使用阿里通义千问(中文支持好、性能稳定):</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python">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}")</code></pre>
<h4>3.4 模型选择说明</h4><table><thead><tr><th>模型类型</th><th>推荐模型</th><th>硬件要求</th><th>适用场景</th></tr></thead><tbody><tr><td>Embedding</td><td>BAAI/bge-base-zh-v1.5</td><td>CPU 8GB+ 或 GPU</td><td>中文文本向量化、检索</td></tr><tr><td>LLM</td><td>Qwen2.5-7B-Instruct</td><td>GPU 12GB+</td><td>中小规模 Agent 决策、对话</td></tr><tr><td>LLM(轻量)</td><td>Qwen2.5-1.8B-Instruct</td><td>GPU 6GB+ 或 CPU 16GB+</td><td>轻量化部署、快速测试</td></tr><tr><td>LLM(高性能)</td><td>Qwen2.5-14B-Instruct</td><td>GPU 24GB+</td><td>复杂任务规划、高精度回复</td></tr></tbody></table><h3>四、Agent 智能体助手搭建实战</h3><p>以“通用智能助手”为例,具备以下能力:1. 本地文档问答;2. 实时搜索查询;3. 对话记忆管理。</p><h4>4.1 核心组件设计</h4><table><thead><tr><th>组件</th><th>选型</th><th>作用</th></tr></thead><tbody><tr><td>LLM</td><td>Qwen2.5-7B-Instruct</td><td>决策核心:解析用户需求、选择工具、生成回复</td></tr><tr><td>Embedding</td><td>BAAI/bge-base-zh-v1.5</td><td>文本向量化:支持本地文档检索</td></tr><tr><td>向量数据库</td><td>Chroma</td><td>存储文档 Embedding 向量,提供相似性检索</td></tr><tr><td>工具</td><td>本地文档检索工具 + 网络搜索工具</td><td>扩展 Agent 能力边界</td></tr><tr><td>记忆</td><td>ConversationBufferMemory</td><td>存储对话历史,支持上下文关联</td></tr><tr><td>提示模板</td><td>自定义中文 Prompt</td><td>规范 Agent 行为与输出格式</td></tr></tbody></table><h4>4.2 代码实现步骤</h4><h5>4.2.1 项目文件树形结构(含文件作用说明)</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-shell">langchain-agent-project/<span class="token comment"># 项目根目录</span>

├── .env                  <span class="token comment"># [环境配置文件] 存储敏感信息(非代码文件)</span>
│                         <span class="token comment"># 内容:SERPER_API_KEY=your_serpapi_key(搜索工具密钥)</span>
│                         <span class="token comment"># 作用:通过 python-dotenv 加载,避免硬编码敏感信息</span>

├── requirements.txt      <span class="token comment"># [依赖清单文件] 项目所有依赖库及版本(非代码文件)</span>
│                         <span class="token comment"># 内容:langchain==0.2.14、torch==2.5.1 等(完整依赖见下文)</span>
│                         <span class="token comment"># 作用:一键安装所有依赖,保证环境一致性</span>

├── README.md             <span class="token comment"># [项目说明文档](非代码文件)</span>
│                         <span class="token comment"># 内容:项目介绍、环境搭建、启动步骤、常见问题</span>
│                         <span class="token comment"># 作用:方便他人使用和维护项目</span>

├── LICENSE.md            <span class="token comment"># [版权许可文件](非代码文件)</span>
│                         <span class="token comment"># 内容:开源许可协议(如 MIT)</span>
│                         <span class="token comment"># 作用:明确项目使用权限</span>

├── config.py             <span class="token comment"># [项目配置文件] 核心参数集中配置</span>
│                         <span class="token comment"># 对应代码:存储模型路径、目录路径、超参数等</span>
│                         <span class="token comment"># 作用:统一管理配置,避免代码中分散硬编码</span>

├── main.py               <span class="token comment"># [项目主程序文件] 程序入口</span>
│                         <span class="token comment"># 对应代码:导入 Agent 核心逻辑、启动交互界面</span>
│                         <span class="token comment"># 作用:作为程序入口,提供用户交互入口</span>

├── api.py                <span class="token comment"># 后端服务化入口(新增)</span>
│                         <span class="token comment"># 对应代码:用 FastAPI 封装 Agent 为 HTTP 接口</span>
│                         <span class="token comment"># 作用:接入后端系统,支持前端调用</span>

├── agent_core/         <span class="token comment"># 存放智能体核心实现</span>
│   ├── __init__.py       <span class="token comment"># [包初始化文件]</span>
│   │                     <span class="token comment"># 作用:标记该目录为 Python 包,支持模块导入</span>
│   │
│   ├── llm_setup.py      <span class="token comment"># </span>
│   │                     <span class="token comment"># 对应代码:4.2.2 中 LLM 初始化逻辑</span>
│   │                     <span class="token comment"># 作用:封装本地 LLM 加载、Prompt 模板配置</span>
│   │
│   ├── embedding_setup.py<span class="token comment"># </span>
│   │                     <span class="token comment"># 对应代码:4.2.2 中 Embedding 模型初始化逻辑</span>
│   │                     <span class="token comment"># 作用:封装 Embedding 模型加载,供向量数据库调用</span>
│   │
│   ├── vector_db.py      <span class="token comment"># [向量数据库文件]</span>
│   │                     <span class="token comment"># 对应代码:4.2.2 中文档加载、切分、向量库构建逻辑</span>
│   │                     <span class="token comment"># 作用:封装本地文档处理和 Chroma 向量库操作</span>
│   │
│   ├── tools_setup.py    <span class="token comment"># [工具集配置文件]</span>
│   │                     <span class="token comment"># 对应代码:4.2.2 中工具加载、文档检索工具封装逻辑</span>
│   │                     <span class="token comment"># 作用:统一管理所有工具,支持工具扩展和维护</span>
│   │
│   ├── memory_setup.py   <span class="token comment"># [记忆配置文件]</span>
│   │                     <span class="token comment"># 对应代码:4.2.2 中对话记忆初始化逻辑</span>
│   │                     <span class="token comment"># 作用:封装对话记忆配置,支持记忆类型切换</span>
│   │
│   └── agent_builder.py<span class="token comment"># </span>
│                         <span class="token comment"># 对应代码:4.2.3 中 Agent 初始化逻辑</span>
│                         <span class="token comment"># 作用:整合 LLM、工具、记忆,构建完整 Agent</span>

├── agent_documents/      <span class="token comment"># [本地文档目录] 存放需检索的本地文档</span>
│   │                     <span class="token comment"># 对应代码:SimpleDirectoryReader 读取的文档路径</span>
│   │                     <span class="token comment"># 作用:存储 txt、pdf、docx 等本地知识库文档</span>
│   ├── sample1.txt       <span class="token comment"># [示例文档 1] 自定义本地知识文档</span>
│   ├── sample2.pdf       <span class="token comment"># [示例文档 2] 支持 PDF 格式文档</span>
│   └── sample3.docx      <span class="token comment"># [示例文档 3] 支持 Word 格式文档</span>

├── agent_chroma_db/      <span class="token comment"># 自动生成的向量存储目录</span>
│   │                     <span class="token comment"># 对应代码:Chroma 的 persist_directory 参数</span>
│   │                     <span class="token comment"># 作用:存储文档 Embedding 向量、索引等数据(自动生成,无需手动创建)</span>
│   ├── chroma.sqlite3    <span class="token comment"># [向量数据库文件] 存储向量索引和元数据</span>
│   └── uuid_to_path.json <span class="token comment"># [文档路径映射文件] 记录向量与原始文档的对应关系</span>

├── model_links/          <span class="token comment"># [模型软链接目录] 指向本地模型文件(避免重复存储)</span>
│   │                     <span class="token comment"># 作用:统一管理模型路径,便于代码中引用</span>
│   ├── llm -<span class="token operator">&gt;</span> D:/AIProject/modelscope/llm/Qwen/Qwen2.5-7B-Instruct/
│   │                     <span class="token comment"># 软链接:指向 Qwen 大模型本地路径</span>
│   └── embedding -<span class="token operator">&gt;</span> D:/AIProject/modelscope/embedding/BAAI/bge-base-zh-v1.5/
│                         <span class="token comment"># 软链接:指向 BAAI 嵌入模型本地路径</span>

└── logs/               <span class="token comment"># [日志目录] 存储程序运行日志(自动生成)</span>
│                     <span class="token comment"># 对应代码:logging 配置的日志输出目录</span>
│                     <span class="token comment"># 作用:记录 Agent 运行日志、错误信息,便于调试</span>
└── agent_run.log   <span class="token comment"># [运行日志文件] 自动记录程序运行过程</span></code></pre>
<h5>4.2.2 requirements.txt依赖库文件</h5><p>执行 <code>pip install -r requirements.txt</code> 即可一键安装所有依赖:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-shell"><span class="token assign-left variable">langchain</span><span class="token operator">==</span><span class="token number">0.2</span>.14
langchain-llms-huggingface<span class="token operator">==</span><span class="token number">0.1</span>.7
langchain-embeddings-huggingface<span class="token operator">==</span><span class="token number">0.1</span>.2
<span class="token assign-left variable">chromadb</span><span class="token operator">==</span><span class="token number">0.5</span>.17
llama-index-vector-stores-chroma<span class="token operator">==</span><span class="token number">0.1</span>.4
<span class="token assign-left variable">torch</span><span class="token operator">==</span><span class="token number">2.5</span>.1
<span class="token assign-left variable">torchvision</span><span class="token operator">==</span><span class="token number">0.20</span>.1
<span class="token assign-left variable">torchaudio</span><span class="token operator">==</span><span class="token number">2.5</span>.1
<span class="token assign-left variable">requests</span><span class="token operator">==</span><span class="token number">2.32</span>.3
python-dotenv<span class="token operator">==</span><span class="token number">1.0</span>.1
<span class="token assign-left variable">pdfplumber</span><span class="token operator">==</span><span class="token number">0.11</span>.4
python-magic<span class="token operator">==</span><span class="token number">0.4</span>.27
<span class="token assign-left variable">modelscope</span><span class="token operator">==</span><span class="token number">1.14</span>.0
<span class="token assign-left variable">langsmith</span><span class="token operator">==</span><span class="token number">0.1</span>.125
<span class="token assign-left variable">fastapi</span><span class="token operator">==</span><span class="token number">0.111</span>.0          <span class="token comment"># 用于后端服务化封装</span>
<span class="token assign-left variable">uvicorn</span><span class="token operator">==</span><span class="token number">0.30</span>.1         <span class="token comment"># ASGI 服务器,运行 FastAPI</span>
<span class="token assign-left variable">pydantic</span><span class="token operator">==</span><span class="token number">2.7</span>.4         <span class="token comment"># 数据校验与模型定义</span>
python-multipart<span class="token operator">==</span><span class="token number">0.0</span>.7   <span class="token comment"># 支持文件上传(可选,用于扩展文档上传功能)</span>
<span class="token assign-left variable">cors</span><span class="token operator">==</span><span class="token number">0.1</span>.10            <span class="token comment"># 解决跨域问题(前端对接必备)</span>
<span class="token assign-left variable">redis</span><span class="token operator">==</span><span class="token number">5.0</span>.1            <span class="token comment"># 用于会话记忆存储(多用户场景必备)</span></code></pre>
<h5>4.2.3导入依赖库</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python">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))</code></pre>
<h5>4.2.4 初始化核心组件</h5><h6>(1) <strong><code>创建 </code>config.py`(项目配置文件)</strong></h6><p>集中管理所有配置参数,修改时无需改动核心逻辑代码:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># 项目路径配置(自动适配系统路径)</span>
<span class="token keyword">import</span> os
<span class="token keyword">from</span> langchain<span class="token punctuation">.</span>agents <span class="token keyword">import</span> AgentType
PROJECT_ROOT <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>dirname<span class="token punctuation">(</span>os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>abspath<span class="token punctuation">(</span>__file__<span class="token punctuation">)</span><span class="token punctuation">)</span>
DOCUMENTS_DIR <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>PROJECT_ROOT<span class="token punctuation">,</span> <span class="token string">"agent_documents"</span><span class="token punctuation">)</span>
CHROMA_DB_DIR <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>PROJECT_ROOT<span class="token punctuation">,</span> <span class="token string">"agent_chroma_db"</span><span class="token punctuation">)</span>
MODEL_LINKS_DIR <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>PROJECT_ROOT<span class="token punctuation">,</span> <span class="token string">"model_links"</span><span class="token punctuation">)</span>
LOGS_DIR <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>PROJECT_ROOT<span class="token punctuation">,</span> <span class="token string">"logs"</span><span class="token punctuation">)</span>
<span class="token comment"># 创建必要目录(若不存在)</span>
<span class="token keyword">for</span> dir_path <span class="token keyword">in</span> <span class="token punctuation">[</span>DOCUMENTS_DIR<span class="token punctuation">,</span> CHROMA_DB_DIR<span class="token punctuation">,</span> MODEL_LINKS_DIR<span class="token punctuation">,</span> LOGS_DIR<span class="token punctuation">]</span><span class="token punctuation">:</span>
<span class="token keyword">if</span> <span class="token keyword">not</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>exists<span class="token punctuation">(</span>dir_path<span class="token punctuation">)</span><span class="token punctuation">:</span>
os<span class="token punctuation">.</span>makedirs<span class="token punctuation">(</span>dir_path<span class="token punctuation">)</span>
<span class="token comment"># 模型配置</span>
LLM_PATH <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>MODEL_LINKS_DIR<span class="token punctuation">,</span> <span class="token string">"llm"</span><span class="token punctuation">)</span>
EMBEDDING_MODEL_PATH <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>MODEL_LINKS_DIR<span class="token punctuation">,</span> <span class="token string">"embedding"</span><span class="token punctuation">)</span>
CONTEXT_WINDOW <span class="token operator">=</span> <span class="token number">4096</span>
MAX_NEW_TOKENS <span class="token operator">=</span> <span class="token number">2048</span>
TEMPERATURE <span class="token operator">=</span> <span class="token number">0.1</span>
<span class="token comment"># 文档处理配置</span>
CHUNK_SIZE <span class="token operator">=</span> <span class="token number">512</span>
CHUNK_OVERLAP <span class="token operator">=</span> <span class="token number">50</span>
RETRIEVE_TOP_K <span class="token operator">=</span> <span class="token number">3</span>
<span class="token comment"># Agent 配置</span>
AGENT_TYPE <span class="token operator">=</span> AgentType<span class="token punctuation">.</span>CHAT_CONVERSATIONAL_REACT_DESCRIPTION
MAX_ITERATIONS <span class="token operator">=</span> <span class="token number">5</span>
PARSING_ERROR_MSG <span class="token operator">=</span> <span class="token string">"请重试:无法解析工具调用结果,请重新选择工具"</span>
<span class="token comment"># System Prompt 配置</span>
SYSTEM_PROMPT <span class="token operator">=</span> <span class="token triple-quoted-string string">"""你是一个通用智能助手,具备以下能力:
1. 可以回答用户的各类问题,优先使用本地文档知识和实时搜索结果
2. 当需要获取实时信息(如天气、新闻、股票)时,调用搜索工具
3. 当用户询问本地文档相关内容时,调用文档检索工具
4. 回答需简洁、准确,基于工具返回结果,不编造信息
5. 记住用户之前的对话内容,提供连贯的交互体验"""</span>
<span class="token comment"># Redis 配置(用于多用户会话记忆存储,可选)</span>
REDIS_HOST <span class="token operator">=</span> <span class="token string">"localhost"</span>
REDIS_PORT <span class="token operator">=</span> <span class="token number">6379</span>
REDIS_DB <span class="token operator">=</span> <span class="token number">0</span>
REDIS_PASSWORD <span class="token operator">=</span> <span class="token string">""</span><span class="token comment"># 若无密码则留空</span></code></pre>
<h6>(2)创建 <code>agent_core/llm_setup.py</code>(LLM 配置)</h6>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python">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="&lt;<sys>&gt;\n{system_prompt}\n&lt;</sys>&gt;\n\n{query_str} ",
      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</code></pre>
<h6>(3)配置 Embedding 与向量数据库(本地文档检索)</h6>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python">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</code></pre>
<h6>(4)创建 <code>agent_core/vector_db.py</code>(向量数据库配置)</h6>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python">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</code></pre>
<h6>(5)创建 <code>agent_core/tools_setup.py</code>(工具集配置)</h6>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python">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</code></pre>
<h6>(6)创建 <code>agent_core/memory_setup.py</code>(记忆配置)</h6>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">from</span> langchain<span class="token punctuation">.</span>memory <span class="token keyword">import</span> ConversationBufferMemory
<span class="token keyword">def</span> <span class="token function">setup_memory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""封装对话记忆初始化逻辑"""</span>
memory <span class="token operator">=</span> ConversationBufferMemory<span class="token punctuation">(</span>
memory_key<span class="token operator">=</span><span class="token string">"chat_history"</span><span class="token punctuation">,</span>
return_messages<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
output_key<span class="token operator">=</span><span class="token string">"output"</span>
<span class="token punctuation">)</span>
<span class="token keyword">return</span> memory</code></pre>
<h6>(7)创建 <code>agent_core/agent_builder.py</code>(Agent 构建)</h6>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">from</span> langchain<span class="token punctuation">.</span>memory <span class="token keyword">import</span> ConversationBufferMemory<span class="token punctuation">,</span> RedisChatMessageHistory
<span class="token keyword">from</span> config <span class="token keyword">import</span> REDIS_HOST<span class="token punctuation">,</span> REDIS_PORT<span class="token punctuation">,</span> REDIS_DB<span class="token punctuation">,</span> REDIS_PASSWORD
<span class="token keyword">def</span> <span class="token function">setup_memory</span><span class="token punctuation">(</span>session_id<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token operator">=</span> <span class="token string">"default"</span><span class="token punctuation">,</span> use_redis<span class="token punctuation">:</span> <span class="token builtin">bool</span> <span class="token operator">=</span> <span class="token boolean">False</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""
封装对话记忆初始化逻辑,支持本地内存和 Redis 存储(多用户场景推荐 Redis)
:param session_id: 会话 ID(区分不同用户)
:param use_redis: 是否使用 Redis 存储记忆
:return: 配置好的 ConversationBufferMemory 实例
"""</span>
<span class="token keyword">if</span> use_redis<span class="token punctuation">:</span>
<span class="token comment"># 基于 Redis 的会话记忆(支持多用户、服务重启不丢失)</span>
message_history <span class="token operator">=</span> RedisChatMessageHistory<span class="token punctuation">(</span>
session_id<span class="token operator">=</span>session_id<span class="token punctuation">,</span>
host<span class="token operator">=</span>REDIS_HOST<span class="token punctuation">,</span>
port<span class="token operator">=</span>REDIS_PORT<span class="token punctuation">,</span>
db<span class="token operator">=</span>REDIS_DB<span class="token punctuation">,</span>
password<span class="token operator">=</span>REDIS_PASSWORD
<span class="token punctuation">)</span>
memory <span class="token operator">=</span> ConversationBufferMemory<span class="token punctuation">(</span>
memory_key<span class="token operator">=</span><span class="token string">"chat_history"</span><span class="token punctuation">,</span>
return_messages<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
output_key<span class="token operator">=</span><span class="token string">"output"</span><span class="token punctuation">,</span>
chat_memory<span class="token operator">=</span>message_history
<span class="token punctuation">)</span>
<span class="token keyword">else</span><span class="token punctuation">:</span>
<span class="token comment"># 本地内存记忆(单用户、服务重启后丢失)</span>
memory <span class="token operator">=</span> ConversationBufferMemory<span class="token punctuation">(</span>
memory_key<span class="token operator">=</span><span class="token string">"chat_history"</span><span class="token punctuation">,</span>
return_messages<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
output_key<span class="token operator">=</span><span class="token string">"output"</span>
<span class="token punctuation">)</span>
<span class="token keyword">return</span> memory</code></pre>
<h6>(8)<code>api.py</code>(后端 API 服务文件)</h6>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI<span class="token punctuation">,</span> Request<span class="token punctuation">,</span> HTTPException
<span class="token keyword">from</span> fastapi<span class="token punctuation">.</span>middleware<span class="token punctuation">.</span>cors <span class="token keyword">import</span> CORSMiddleware
<span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel
<span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional
<span class="token keyword">import</span> logging
<span class="token keyword">import</span> os
<span class="token keyword">from</span> config <span class="token keyword">import</span> LOGS_DIR<span class="token punctuation">,</span> REDIS_HOST<span class="token punctuation">,</span> REDIS_PORT
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>llm_setup <span class="token keyword">import</span> setup_llm
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>embedding_setup <span class="token keyword">import</span> setup_embedding
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>vector_db <span class="token keyword">import</span> build_vector_db
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>tools_setup <span class="token keyword">import</span> setup_tools
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>memory_setup <span class="token keyword">import</span> setup_memory
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>agent_builder <span class="token keyword">import</span> build_agent
<span class="token comment"># 初始化 FastAPI 应用</span>
app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span>title<span class="token operator">=</span><span class="token string">"LangChain Agent 智能助手 API"</span><span class="token punctuation">,</span> version<span class="token operator">=</span><span class="token string">"1.0"</span><span class="token punctuation">)</span>
<span class="token comment"># 配置 CORS(解决前端跨域问题)</span>
app<span class="token punctuation">.</span>add_middleware<span class="token punctuation">(</span>
CORSMiddleware<span class="token punctuation">,</span>
allow_origins<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token comment"># 生产环境需指定具体前端域名(如 ["http://localhost:3000"])</span>
allow_credentials<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
allow_methods<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
allow_headers<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
<span class="token comment"># 配置日志</span>
log_file <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>LOGS_DIR<span class="token punctuation">,</span> <span class="token string">"api_run.log"</span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>basicConfig<span class="token punctuation">(</span>
level<span class="token operator">=</span>logging<span class="token punctuation">.</span>INFO<span class="token punctuation">,</span>
<span class="token builtin">format</span><span class="token operator">=</span><span class="token string">"%(asctime)s - %(levelname)s - %(message)s"</span><span class="token punctuation">,</span>
handlers<span class="token operator">=</span><span class="token punctuation">[</span>
logging<span class="token punctuation">.</span>FileHandler<span class="token punctuation">(</span>log_file<span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
logging<span class="token punctuation">.</span>StreamHandler<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">]</span>
<span class="token punctuation">)</span>
<span class="token comment"># 预加载核心组件(服务启动时初始化,避免每次请求重复加载)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"API 服务启动,开始初始化 Agent 核心组件..."</span><span class="token punctuation">)</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
<span class="token comment"># 1. 加载 LLM 模型</span>
llm <span class="token operator">=</span> setup_llm<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 2. 加载 Embedding 模型</span>
embedding_model <span class="token operator">=</span> setup_embedding<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 3. 构建向量数据库</span>
doc_retriever <span class="token operator">=</span> build_vector_db<span class="token punctuation">(</span>embedding_model<span class="token punctuation">)</span>
<span class="token comment"># 4. 加载工具集</span>
tools <span class="token operator">=</span> setup_tools<span class="token punctuation">(</span>llm<span class="token punctuation">,</span> doc_retriever<span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"核心组件初始化完成,API 服务就绪!"</span><span class="token punctuation">)</span>
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
logging<span class="token punctuation">.</span>error<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"核心组件初始化失败:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> exc_info<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">raise</span>
<span class="token comment"># 请求模型定义(前端传入参数格式)</span>
<span class="token keyword">class</span> <span class="token class-name">ChatRequest</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span>
user_input<span class="token punctuation">:</span> <span class="token builtin">str</span>               <span class="token comment"># 用户输入内容</span>
session_id<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">str</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">"default"</span><span class="token comment"># 会话 ID(区分不同用户)</span>
use_redis<span class="token punctuation">:</span> Optional<span class="token punctuation">[</span><span class="token builtin">bool</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">False</span>      <span class="token comment"># 是否使用 Redis 存储会话记忆</span>
<span class="token comment"># 响应模型定义(后端返回格式)</span>
<span class="token keyword">class</span> <span class="token class-name">ChatResponse</span><span class="token punctuation">(</span>BaseModel<span class="token punctuation">)</span><span class="token punctuation">:</span>
code<span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token operator">=</span> <span class="token number">200</span>               <span class="token comment"># 状态码(200 成功,500 失败)</span>
message<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token operator">=</span> <span class="token string">"success"</span>      <span class="token comment"># 状态描述</span>
data<span class="token punctuation">:</span> <span class="token builtin">dict</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>               <span class="token comment"># 响应数据(包含回复内容、会话 ID)</span>
<span class="token comment"># 健康检查接口(用于后端监控)</span>
<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>get</span><span class="token punctuation">(</span><span class="token string">"/health"</span><span class="token punctuation">)</span>
<span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">health_check</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span>
<span class="token string">"code"</span><span class="token punctuation">:</span> <span class="token number">200</span><span class="token punctuation">,</span>
<span class="token string">"message"</span><span class="token punctuation">:</span> <span class="token string">"Agent API 服务运行正常"</span><span class="token punctuation">,</span>
<span class="token string">"data"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"redis"</span><span class="token punctuation">:</span> <span class="token string-interpolation"><span class="token string">f"连接成功"</span></span> <span class="token keyword">if</span> check_redis<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token string">"未启用或连接失败"</span><span class="token punctuation">,</span>
<span class="token string">"llm"</span><span class="token punctuation">:</span> <span class="token string">"加载成功"</span><span class="token punctuation">,</span>
<span class="token string">"vector_db"</span><span class="token punctuation">:</span> <span class="token string">"构建成功"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment"># 聊天交互接口(核心接口,前端调用该接口获取回复)</span>
<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>post</span><span class="token punctuation">(</span><span class="token string">"/chat"</span><span class="token punctuation">,</span> response_model<span class="token operator">=</span>ChatResponse<span class="token punctuation">)</span>
<span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">chat</span><span class="token punctuation">(</span>request<span class="token punctuation">:</span> ChatRequest<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
<span class="token comment"># 1. 解析请求参数</span>
user_input <span class="token operator">=</span> request<span class="token punctuation">.</span>user_input<span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span>
session_id <span class="token operator">=</span> request<span class="token punctuation">.</span>session_id
use_redis <span class="token operator">=</span> request<span class="token punctuation">.</span>use_redis
<span class="token keyword">if</span> <span class="token keyword">not</span> user_input<span class="token punctuation">:</span>
<span class="token keyword">raise</span> HTTPException<span class="token punctuation">(</span>status_code<span class="token operator">=</span><span class="token number">400</span><span class="token punctuation">,</span> detail<span class="token operator">=</span><span class="token string">"用户输入不能为空"</span><span class="token punctuation">)</span>
<span class="token comment"># 2. 初始化会话记忆(按 session_id 区分用户)</span>
memory <span class="token operator">=</span> setup_memory<span class="token punctuation">(</span>session_id<span class="token operator">=</span>session_id<span class="token punctuation">,</span> use_redis<span class="token operator">=</span>use_redis<span class="token punctuation">)</span>
<span class="token comment"># 3. 构建 Agent(每次请求创建独立实例,避免会话干扰)</span>
agent <span class="token operator">=</span> build_agent<span class="token punctuation">(</span>tools<span class="token operator">=</span>tools<span class="token punctuation">,</span> llm<span class="token operator">=</span>llm<span class="token punctuation">,</span> memory<span class="token operator">=</span>memory<span class="token punctuation">)</span>
<span class="token comment"># 4. 调用 Agent 生成回复</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"会话 [</span><span class="token interpolation"><span class="token punctuation">{</span>session_id<span class="token punctuation">}</span></span><span class="token string">] - 用户输入:</span><span class="token interpolation"><span class="token punctuation">{</span>user_input<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
response <span class="token operator">=</span> agent<span class="token punctuation">.</span>run<span class="token punctuation">(</span>user_input<span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"会话 [</span><span class="token interpolation"><span class="token punctuation">{</span>session_id<span class="token punctuation">}</span></span><span class="token string">] - Agent 回复:</span><span class="token interpolation"><span class="token punctuation">{</span>response<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 5. 返回结果</span>
<span class="token keyword">return</span> ChatResponse<span class="token punctuation">(</span>
data<span class="token operator">=</span><span class="token punctuation">{</span>
<span class="token string">"response"</span><span class="token punctuation">:</span> response<span class="token punctuation">,</span>
<span class="token string">"session_id"</span><span class="token punctuation">:</span> session_id<span class="token punctuation">,</span>
<span class="token string">"use_redis"</span><span class="token punctuation">:</span> use_redis
<span class="token punctuation">}</span>
<span class="token punctuation">)</span>
<span class="token keyword">except</span> HTTPException <span class="token keyword">as</span> e<span class="token punctuation">:</span>
logging<span class="token punctuation">.</span>error<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"会话 [</span><span class="token interpolation"><span class="token punctuation">{</span>request<span class="token punctuation">.</span>session_id<span class="token punctuation">}</span></span><span class="token string">] - 客户端错误:</span><span class="token interpolation"><span class="token punctuation">{</span>e<span class="token punctuation">.</span>detail<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">return</span> ChatResponse<span class="token punctuation">(</span>
code<span class="token operator">=</span>e<span class="token punctuation">.</span>status_code<span class="token punctuation">,</span>
message<span class="token operator">=</span><span class="token string-interpolation"><span class="token string">f"客户端错误:</span><span class="token interpolation"><span class="token punctuation">{</span>e<span class="token punctuation">.</span>detail<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span>
data<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">"session_id"</span><span class="token punctuation">:</span> request<span class="token punctuation">.</span>session_id<span class="token punctuation">}</span>
<span class="token punctuation">)</span>
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
logging<span class="token punctuation">.</span>error<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"会话 [</span><span class="token interpolation"><span class="token punctuation">{</span>request<span class="token punctuation">.</span>session_id<span class="token punctuation">}</span></span><span class="token string">] - 服务端错误:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> exc_info<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> ChatResponse<span class="token punctuation">(</span>
code<span class="token operator">=</span><span class="token number">500</span><span class="token punctuation">,</span>
message<span class="token operator">=</span><span class="token string-interpolation"><span class="token string">f"服务端错误:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span>
data<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">"session_id"</span><span class="token punctuation">:</span> request<span class="token punctuation">.</span>session_id<span class="token punctuation">}</span>
<span class="token punctuation">)</span>
<span class="token comment"># 辅助函数:检查 Redis 连接状态</span>
<span class="token keyword">def</span> <span class="token function">check_redis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token builtin">bool</span><span class="token punctuation">:</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
<span class="token keyword">import</span> redis
r <span class="token operator">=</span> redis<span class="token punctuation">.</span>Redis<span class="token punctuation">(</span>
host<span class="token operator">=</span>REDIS_HOST<span class="token punctuation">,</span>
port<span class="token operator">=</span>REDIS_PORT<span class="token punctuation">,</span>
db<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span>
password<span class="token operator">=</span>REDIS_PASSWORD<span class="token punctuation">,</span>
socket_timeout<span class="token operator">=</span><span class="token number">2</span>
<span class="token punctuation">)</span>
<span class="token keyword">return</span> r<span class="token punctuation">.</span>ping<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">except</span> Exception<span class="token punctuation">:</span>
<span class="token keyword">return</span> <span class="token boolean">False</span>
<span class="token comment"># 启动服务(命令行运行时执行)</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
<span class="token keyword">import</span> uvicorn
<span class="token comment"># 启动 ASGI 服务器(host=0.0.0.0 允许外部访问)</span>
uvicorn<span class="token punctuation">.</span>run<span class="token punctuation">(</span>
app<span class="token operator">=</span><span class="token string">"api:app"</span><span class="token punctuation">,</span>
host<span class="token operator">=</span><span class="token string">"0.0.0.0"</span><span class="token punctuation">,</span>
port<span class="token operator">=</span><span class="token number">8000</span><span class="token punctuation">,</span>
<span class="token builtin">reload</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span><span class="token comment"># 开发环境启用热重载,生产环境关闭</span>
workers<span class="token operator">=</span><span class="token number">1</span>   <span class="token comment"># 生产环境可根据 CPU 核心数调整(如 4)</span>
<span class="token punctuation">)</span></code></pre>
<h6>(9)创建 <code>main.py</code>(项目主程序)</h6>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">import</span> logging
<span class="token keyword">import</span> os
<span class="token keyword">from</span> config <span class="token keyword">import</span> LOGS_DIR
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>llm_setup <span class="token keyword">import</span> setup_llm
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>embedding_setup <span class="token keyword">import</span> setup_embedding
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>vector_db <span class="token keyword">import</span> build_vector_db
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>tools_setup <span class="token keyword">import</span> setup_tools
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>memory_setup <span class="token keyword">import</span> setup_memory
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>agent_builder <span class="token keyword">import</span> build_agent
<span class="token comment"># 配置日志(输出到文件和控制台)</span>
<span class="token keyword">def</span> <span class="token function">setup_logging</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
log_file <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>LOGS_DIR<span class="token punctuation">,</span> <span class="token string">"agent_run.log"</span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>basicConfig<span class="token punctuation">(</span>
level<span class="token operator">=</span>logging<span class="token punctuation">.</span>INFO<span class="token punctuation">,</span>
<span class="token builtin">format</span><span class="token operator">=</span><span class="token string">"%(asctime)s - %(levelname)s - %(message)s"</span><span class="token punctuation">,</span>
handlers<span class="token operator">=</span><span class="token punctuation">[</span>
logging<span class="token punctuation">.</span>FileHandler<span class="token punctuation">(</span>log_file<span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
logging<span class="token punctuation">.</span>StreamHandler<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">]</span>
<span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"日志配置完成,开始初始化 Agent..."</span><span class="token punctuation">)</span>
<span class="token comment"># 初始化 Agent 流程</span>
<span class="token keyword">def</span> <span class="token function">init_agent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
<span class="token comment"># 1. 初始化 LLM</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"加载 LLM 模型..."</span><span class="token punctuation">)</span>
llm <span class="token operator">=</span> setup_llm<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 2. 初始化 Embedding 模型</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"加载 Embedding 模型..."</span><span class="token punctuation">)</span>
embedding_model <span class="token operator">=</span> setup_embedding<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 3. 构建向量数据库和检索器</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"构建本地文档向量库..."</span><span class="token punctuation">)</span>
doc_retriever <span class="token operator">=</span> build_vector_db<span class="token punctuation">(</span>embedding_model<span class="token punctuation">)</span>
<span class="token comment"># 4. 配置工具集</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"加载工具集..."</span><span class="token punctuation">)</span>
tools <span class="token operator">=</span> setup_tools<span class="token punctuation">(</span>llm<span class="token punctuation">,</span> doc_retriever<span class="token punctuation">)</span>
<span class="token comment"># 5. 配置对话记忆</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"初始化对话记忆..."</span><span class="token punctuation">)</span>
memory <span class="token operator">=</span> setup_memory<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 6. 构建 Agent</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"构建 Agent 智能体..."</span><span class="token punctuation">)</span>
agent <span class="token operator">=</span> build_agent<span class="token punctuation">(</span>tools<span class="token punctuation">,</span> llm<span class="token punctuation">,</span> memory<span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"Agent 初始化完成!"</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> agent
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
logging<span class="token punctuation">.</span>error<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Agent 初始化失败:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> exc_info<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">raise</span>
<span class="token comment"># 交互函数</span>
<span class="token keyword">def</span> <span class="token function">agent_chat</span><span class="token punctuation">(</span>agent<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"=== 通用智能助手(输入 'quit' 退出)==="</span><span class="token punctuation">)</span>
<span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
user_input <span class="token operator">=</span> <span class="token builtin">input</span><span class="token punctuation">(</span><span class="token string">"\n用户:"</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> user_input<span class="token punctuation">.</span>lower<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token string">"quit"</span><span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"助手:再见!"</span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"用户退出交互"</span><span class="token punctuation">)</span>
<span class="token keyword">break</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"用户输入:</span><span class="token interpolation"><span class="token punctuation">{</span>user_input<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
response <span class="token operator">=</span> agent<span class="token punctuation">.</span>run<span class="token punctuation">(</span>user_input<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"助手:</span><span class="token interpolation"><span class="token punctuation">{</span>response<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"助手回复:</span><span class="token interpolation"><span class="token punctuation">{</span>response<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
error_msg <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"交互出错:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"助手:</span><span class="token interpolation"><span class="token punctuation">{</span>error_msg<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>error<span class="token punctuation">(</span>error_msg<span class="token punctuation">,</span> exc_info<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token comment"># 主函数</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
<span class="token comment"># 配置日志</span>
setup_logging<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 初始化 Agent</span>
agent <span class="token operator">=</span> init_agent<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 启动交互</span>
agent_chat<span class="token punctuation">(</span>agent<span class="token punctuation">)</span></code></pre>
<h5>4.2.5 初始化 Agent</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python"># 构建 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
)</code></pre>
<h5>4.2.6 测试 Agent 交互</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python"># 交互函数
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()</code></pre>
<h4>4.3 关键配置说明</h4><h5>(1)Agent 类型选择</h5><table><thead><tr><th>Agent 类型</th><th>适用场景</th><th>特点</th></tr></thead><tbody><tr><td>CHAT_CONVERSATIONAL_REACT_DESCRIPTION</td><td>对话型智能助手</td><td>支持记忆管理,适合多轮交互</td></tr><tr><td>ZERO_SHOT_REACT_DESCRIPTION</td><td>单轮任务处理</td><td>无需记忆,快速执行单一任务</td></tr><tr><td>STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION</td><td>结构化输出任务</td><td>支持 JSON 等格式输出,适合数据处理</td></tr></tbody></table><h5>(2)温度参数(temperature)调整</h5><ul><li><p><code>temperature=0.0</code>:输出完全确定,无随机性(适合需要精准答案的场景)</p></li><li><p><code>temperature=0.1-0.3</code>:平衡准确性与灵活性(通用场景推荐)</p></li><li><p><code>temperature=0.5-0.8</code>:输出更具创造性(适合生成类任务)</p></li></ul><h5>(3)工具调用优化</h5><ul><li><p>工具描述需清晰:让 LLM 准确理解工具的用途(如“document_retrieval 用于回答本地文档相关问题”)</p></li><li><p>限制工具数量:初期避免过多工具,减少 LLM 决策负担</p></li><li><p>增加工具优先级:通过 Prompt 引导 LLM 优先使用合适的工具</p></li></ul><h3>五、Agent 调试与优化</h3><h4>5.1 调试工具:LangSmith</h4><p>LangSmith 是 LangChain 官方推出的一站式调试、监控与评估平台,能全程追踪 Agent 从 “接收请求→决策→工具调用→生成回复” 的完整链路,精准定位每一步的问题。以下是从<strong>环境配置→代码集成→测试运行→控制台分析→问题修复</strong>的全流程详细说明,含可直接复用的代码片段。</p><h5>5.1.1 配置 LangSmith</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Bash"># 安装 LangSmith
pip install langsmith==0.1.125</code></pre>
<h6>(1) 获取 LangSmith API Key</h6><ol><li>访问 LangSmith 官网(https://smith.langchain.com),使用 GitHub/Google 账号注册并登录。</li><li>登录后,点击右上角头像 → <strong>Settings</strong> → <strong>API Keys</strong> → 点击 <strong>Create API Key</strong>,输入密钥名称(如 “agent-debug”),点击创建。</li><li>复制生成的 API Key(格式类似 <code>ls__xxxxxx</code>),后续配置会用到(密钥仅显示一次,需妥善保存)。</li></ol><h6>(2) 配置环境变量</h6><p>在 <code>.env</code> 文件中配置 API 密钥(需在 LangSmith 官网注册获取):</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Plain">LANGCHAIN_TRACING_V2=true
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
LANGCHAIN_API_KEY=your_api_key
LANGCHAIN_PROJECT=agent-debug</code></pre>
<h5>5.1.2 调试流程</h5><p>需要在 Agent 初始化时添加 LangSmith 回调,实现 “每一步操作都被记录”。以下是 <strong>命令行交互(main.py)</strong> 和 <strong>API 服务(api.py)</strong> 的完整集成代码。</p><h6>(1)命令行交互(main.py)集成示例</h6><p>在 <code>main.py</code> 中导入 LangSmith 回调相关模块,修改 <code>init_agent</code> 函数,添加 <code>CallbackManager</code> 配置:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">import</span> logging
<span class="token keyword">import</span> os
<span class="token keyword">from</span> dotenv <span class="token keyword">import</span> load_dotenv
<span class="token keyword">from</span> config <span class="token keyword">import</span> LOGS_DIR
<span class="token comment"># 导入 LangSmith 回调(新增)</span>
<span class="token keyword">from</span> langchain<span class="token punctuation">.</span>callbacks <span class="token keyword">import</span> LangChainTracer<span class="token punctuation">,</span> CallbackManager
<span class="token comment"># 导入核心模块</span>
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>llm_setup <span class="token keyword">import</span> setup_llm
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>embedding_setup <span class="token keyword">import</span> setup_embedding
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>vector_db <span class="token keyword">import</span> build_vector_db
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>tools_setup <span class="token keyword">import</span> setup_tools
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>memory_setup <span class="token keyword">import</span> setup_memory
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>agent_builder <span class="token keyword">import</span> build_agent
<span class="token comment"># 加载环境变量(包含 LangSmith 配置)</span>
load_dotenv<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">setup_logging</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
log_file <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>LOGS_DIR<span class="token punctuation">,</span> <span class="token string">"agent_run.log"</span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>basicConfig<span class="token punctuation">(</span>
level<span class="token operator">=</span>logging<span class="token punctuation">.</span>INFO<span class="token punctuation">,</span>
<span class="token builtin">format</span><span class="token operator">=</span><span class="token string">"%(asctime)s - %(levelname)s - %(message)s"</span><span class="token punctuation">,</span>
handlers<span class="token operator">=</span><span class="token punctuation">[</span>
logging<span class="token punctuation">.</span>FileHandler<span class="token punctuation">(</span>log_file<span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
logging<span class="token punctuation">.</span>StreamHandler<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">]</span>
<span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"日志配置完成,开始初始化 Agent..."</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">init_agent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
<span class="token comment"># -------------------------- 新增:LangSmith 回调配置 --------------------------</span>
<span class="token comment"># 创建 LangSmith 追踪器(关联环境变量中的 API Key 和项目名)</span>
tracer <span class="token operator">=</span> LangChainTracer<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 配置回调管理器(同时支持日志和 LangSmith 追踪)</span>
callback_manager <span class="token operator">=</span> CallbackManager<span class="token punctuation">(</span><span class="token punctuation">[</span>tracer<span class="token punctuation">,</span> logging<span class="token punctuation">.</span>StreamHandler<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token comment"># -----------------------------------------------------------------------------</span>
<span class="token comment"># 1. 加载 LLM 模型(传入 callback_manager)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"加载 LLM 模型..."</span><span class="token punctuation">)</span>
llm <span class="token operator">=</span> setup_llm<span class="token punctuation">(</span>callback_manager<span class="token operator">=</span>callback_manager<span class="token punctuation">)</span><span class="token comment"># 新增回调参数</span>
<span class="token comment"># 2. 加载 Embedding 模型</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"加载 Embedding 模型..."</span><span class="token punctuation">)</span>
embedding_model <span class="token operator">=</span> setup_embedding<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 3. 构建向量数据库和检索器</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"构建本地文档向量库..."</span><span class="token punctuation">)</span>
doc_retriever <span class="token operator">=</span> build_vector_db<span class="token punctuation">(</span>embedding_model<span class="token punctuation">)</span>
<span class="token comment"># 4. 配置工具集</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"加载工具集..."</span><span class="token punctuation">)</span>
tools <span class="token operator">=</span> setup_tools<span class="token punctuation">(</span>llm<span class="token punctuation">,</span> doc_retriever<span class="token punctuation">)</span>
<span class="token comment"># 5. 配置对话记忆</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"初始化对话记忆..."</span><span class="token punctuation">)</span>
memory <span class="token operator">=</span> setup_memory<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 6. 构建 Agent(传入 callback_manager,关键!)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"构建 Agent 智能体..."</span><span class="token punctuation">)</span>
agent <span class="token operator">=</span> build_agent<span class="token punctuation">(</span>
tools<span class="token operator">=</span>tools<span class="token punctuation">,</span>
llm<span class="token operator">=</span>llm<span class="token punctuation">,</span>
memory<span class="token operator">=</span>memory<span class="token punctuation">,</span>
callback_manager<span class="token operator">=</span>callback_manager<span class="token comment"># 让 Agent 所有操作被追踪</span>
<span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"Agent 初始化完成!(已启用 LangSmith 调试追踪)"</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> agent
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
logging<span class="token punctuation">.</span>error<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Agent 初始化失败:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> exc_info<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">raise</span>
<span class="token comment"># 交互函数和主函数保持不变...</span>
<span class="token keyword">def</span> <span class="token function">agent_chat</span><span class="token punctuation">(</span>agent<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"="</span> <span class="token operator">*</span> <span class="token number">50</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"=== 通用智能助手(支持本地文档问答、实时搜索、多轮对话)==="</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"=== 输入 'quit' 或 '退出' 即可结束交互 ==="</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"=== 所有操作已同步至 LangSmith 控制台,可前往查看轨迹 ==="</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"="</span> <span class="token operator">*</span> <span class="token number">50</span><span class="token punctuation">)</span>
<span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
user_input <span class="token operator">=</span> <span class="token builtin">input</span><span class="token punctuation">(</span><span class="token string">"\n用户:"</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> user_input<span class="token punctuation">.</span>lower<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token punctuation">[</span><span class="token string">"quit"</span><span class="token punctuation">,</span> <span class="token string">"退出"</span><span class="token punctuation">]</span><span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"助手:感谢使用,再见!"</span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"用户主动退出交互,程序结束。"</span><span class="token punctuation">)</span>
<span class="token keyword">break</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"用户输入:</span><span class="token interpolation"><span class="token punctuation">{</span>user_input<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
response <span class="token operator">=</span> agent<span class="token punctuation">.</span>run<span class="token punctuation">(</span>user_input<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"助手:</span><span class="token interpolation"><span class="token punctuation">{</span>response<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Agent 回复:</span><span class="token interpolation"><span class="token punctuation">{</span>response<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
error_msg <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"交互过程中出现错误:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"助手:</span><span class="token interpolation"><span class="token punctuation">{</span>error_msg<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>error<span class="token punctuation">(</span>error_msg<span class="token punctuation">,</span> exc_info<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
setup_logging<span class="token punctuation">(</span><span class="token punctuation">)</span>
agent <span class="token operator">=</span> init_agent<span class="token punctuation">(</span><span class="token punctuation">)</span>
agent_chat<span class="token punctuation">(</span>agent<span class="token punctuation">)</span></code></pre>
<h6>(2)同步修改 <code>agent_core/llm_setup.py</code>(接收回调参数)</h6><p>由于 <code>main.py</code> 中初始化 LLM 时传入了 <code>callback_manager</code>,需要修改 <code>llm_setup.py</code> 的 <code>setup_llm</code> 函数,支持接收该参数:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">from</span> langchain <span class="token keyword">import</span> PromptTemplate
<span class="token keyword">from</span> langchain<span class="token punctuation">.</span>llms <span class="token keyword">import</span> HuggingFaceLLM
<span class="token keyword">import</span> torch
<span class="token keyword">from</span> config <span class="token keyword">import</span> <span class="token punctuation">(</span>
LLM_PATH<span class="token punctuation">,</span> CONTEXT_WINDOW<span class="token punctuation">,</span> MAX_NEW_TOKENS<span class="token punctuation">,</span>
TEMPERATURE<span class="token punctuation">,</span> SYSTEM_PROMPT
<span class="token punctuation">)</span>
<span class="token comment"># 新增:接收 callback_manager 参数(默认 None)</span>
<span class="token keyword">def</span> <span class="token function">setup_llm</span><span class="token punctuation">(</span>callback_manager<span class="token operator">=</span><span class="token boolean">None</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""封装 LLM 初始化逻辑"""</span>
<span class="token comment"># 构建 Prompt 模板</span>
query_wrapper_prompt <span class="token operator">=</span> PromptTemplate<span class="token punctuation">(</span>
template<span class="token operator">=</span><span class="token string">"&lt;&lt;SYS&gt;&gt;\n{system_prompt}\n&lt;&lt;/SYS&gt;&gt;\n\n{query_str} "</span><span class="token punctuation">,</span>
input_variables<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"system_prompt"</span><span class="token punctuation">,</span> <span class="token string">"query_str"</span><span class="token punctuation">]</span>
<span class="token punctuation">)</span>
<span class="token comment"># 初始化本地 LLM(新增 callback_manager 配置)</span>
llm <span class="token operator">=</span> HuggingFaceLLM<span class="token punctuation">(</span>
context_window<span class="token operator">=</span>CONTEXT_WINDOW<span class="token punctuation">,</span>
max_new_tokens<span class="token operator">=</span>MAX_NEW_TOKENS<span class="token punctuation">,</span>
generate_kwargs<span class="token operator">=</span><span class="token punctuation">{</span>
<span class="token string">"temperature"</span><span class="token punctuation">:</span> TEMPERATURE<span class="token punctuation">,</span>
<span class="token string">"do_sample"</span><span class="token punctuation">:</span> <span class="token boolean">True</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
query_wrapper_prompt<span class="token operator">=</span>query_wrapper_prompt<span class="token punctuation">,</span>
tokenizer_name<span class="token operator">=</span>LLM_PATH<span class="token punctuation">,</span>
model_name<span class="token operator">=</span>LLM_PATH<span class="token punctuation">,</span>
device_map<span class="token operator">=</span><span class="token string">"auto"</span><span class="token punctuation">,</span>
model_kwargs<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">"torch_dtype"</span><span class="token punctuation">:</span> torch<span class="token punctuation">.</span>float16<span class="token punctuation">}</span><span class="token punctuation">,</span>
callback_manager<span class="token operator">=</span>callback_manager<span class="token comment"># 关联 LangSmith 回调</span>
<span class="token punctuation">)</span>
<span class="token keyword">return</span> llm</code></pre>
<h6>(3)同步修改 <code>agent_core/agent_builder.py</code>(接收回调参数)</h6><p>修改 <code>build_agent</code> 函数,支持传入 <code>callback_manager</code> 并传递给 Agent:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">from</span> langchain<span class="token punctuation">.</span>agents <span class="token keyword">import</span> initialize_agent
<span class="token keyword">from</span> config <span class="token keyword">import</span> AGENT_TYPE<span class="token punctuation">,</span> MAX_ITERATIONS<span class="token punctuation">,</span> PARSING_ERROR_MSG<span class="token punctuation">,</span> SYSTEM_PROMPT
<span class="token comment"># 新增:接收 callback_manager 参数</span>
<span class="token keyword">def</span> <span class="token function">build_agent</span><span class="token punctuation">(</span>tools<span class="token punctuation">,</span> llm<span class="token punctuation">,</span> memory<span class="token punctuation">,</span> callback_manager<span class="token operator">=</span><span class="token boolean">None</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""整合所有组件,构建 Agent"""</span>
agent <span class="token operator">=</span> initialize_agent<span class="token punctuation">(</span>
tools<span class="token operator">=</span>tools<span class="token punctuation">,</span>
llm<span class="token operator">=</span>llm<span class="token punctuation">,</span>
agent<span class="token operator">=</span>AGENT_TYPE<span class="token punctuation">,</span>
memory<span class="token operator">=</span>memory<span class="token punctuation">,</span>
verbose<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
max_iterations<span class="token operator">=</span>MAX_ITERATIONS<span class="token punctuation">,</span>
handle_parsing_errors<span class="token operator">=</span>PARSING_ERROR_MSG<span class="token punctuation">,</span>
system_message<span class="token operator">=</span>SYSTEM_PROMPT<span class="token punctuation">,</span>
callback_manager<span class="token operator">=</span>callback_manager<span class="token comment"># 关键:让 Agent 操作被 LangSmith 追踪</span>
<span class="token punctuation">)</span>
<span class="token keyword">return</span> agent</code></pre>
<p>(4)API 服务(api.py)集成示例(可选)</p><p>如果需要调试 API 接口调用场景,在 <code>api.py</code> 中添加 LangSmith 回调配置:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">from</span> fastapi <span class="token keyword">import</span> FastAPI<span class="token punctuation">,</span> Request<span class="token punctuation">,</span> HTTPException
<span class="token keyword">from</span> fastapi<span class="token punctuation">.</span>middleware<span class="token punctuation">.</span>cors <span class="token keyword">import</span> CORSMiddleware
<span class="token keyword">from</span> pydantic <span class="token keyword">import</span> BaseModel
<span class="token keyword">from</span> typing <span class="token keyword">import</span> Optional
<span class="token keyword">import</span> logging
<span class="token keyword">import</span> os
<span class="token keyword">from</span> dotenv <span class="token keyword">import</span> load_dotenv
<span class="token comment"># 导入 LangSmith 回调(新增)</span>
<span class="token keyword">from</span> langchain<span class="token punctuation">.</span>callbacks <span class="token keyword">import</span> LangChainTracer<span class="token punctuation">,</span> CallbackManager
<span class="token keyword">from</span> config <span class="token keyword">import</span> LOGS_DIR<span class="token punctuation">,</span> REDIS_HOST<span class="token punctuation">,</span> REDIS_PORT
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>llm_setup <span class="token keyword">import</span> setup_llm
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>embedding_setup <span class="token keyword">import</span> setup_embedding
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>vector_db <span class="token keyword">import</span> build_vector_db
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>tools_setup <span class="token keyword">import</span> setup_tools
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>memory_setup <span class="token keyword">import</span> setup_memory
<span class="token keyword">from</span> agent_core<span class="token punctuation">.</span>agent_builder <span class="token keyword">import</span> build_agent
<span class="token comment"># 加载环境变量(包含 LangSmith 配置)</span>
load_dotenv<span class="token punctuation">(</span><span class="token punctuation">)</span>
app <span class="token operator">=</span> FastAPI<span class="token punctuation">(</span>title<span class="token operator">=</span><span class="token string">"LangChain Agent 智能助手 API"</span><span class="token punctuation">,</span> version<span class="token operator">=</span><span class="token string">"1.0"</span><span class="token punctuation">)</span>
<span class="token comment"># 配置 CORS</span>
app<span class="token punctuation">.</span>add_middleware<span class="token punctuation">(</span>
CORSMiddleware<span class="token punctuation">,</span>
allow_origins<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
allow_credentials<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
allow_methods<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
allow_headers<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
<span class="token comment"># -------------------------- 新增:LangSmith 回调配置 --------------------------</span>
tracer <span class="token operator">=</span> LangChainTracer<span class="token punctuation">(</span><span class="token punctuation">)</span>
callback_manager <span class="token operator">=</span> CallbackManager<span class="token punctuation">(</span><span class="token punctuation">[</span>tracer<span class="token punctuation">,</span> logging<span class="token punctuation">.</span>StreamHandler<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token comment"># -----------------------------------------------------------------------------</span>
<span class="token comment"># 配置日志</span>
log_file <span class="token operator">=</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>join<span class="token punctuation">(</span>LOGS_DIR<span class="token punctuation">,</span> <span class="token string">"api_run.log"</span><span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>basicConfig<span class="token punctuation">(</span>
level<span class="token operator">=</span>logging<span class="token punctuation">.</span>INFO<span class="token punctuation">,</span>
<span class="token builtin">format</span><span class="token operator">=</span><span class="token string">"%(asctime)s - %(levelname)s - %(message)s"</span><span class="token punctuation">,</span>
handlers<span class="token operator">=</span><span class="token punctuation">[</span>
logging<span class="token punctuation">.</span>FileHandler<span class="token punctuation">(</span>log_file<span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
logging<span class="token punctuation">.</span>StreamHandler<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">]</span>
<span class="token punctuation">)</span>
<span class="token comment"># 预加载核心组件(传入 callback_manager)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"API 服务启动,开始初始化 Agent 核心组件..."</span><span class="token punctuation">)</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
llm <span class="token operator">=</span> setup_llm<span class="token punctuation">(</span>callback_manager<span class="token operator">=</span>callback_manager<span class="token punctuation">)</span><span class="token comment"># 传入回调</span>
embedding_model <span class="token operator">=</span> setup_embedding<span class="token punctuation">(</span><span class="token punctuation">)</span>
doc_retriever <span class="token operator">=</span> build_vector_db<span class="token punctuation">(</span>embedding_model<span class="token punctuation">)</span>
tools <span class="token operator">=</span> setup_tools<span class="token punctuation">(</span>llm<span class="token punctuation">,</span> doc_retriever<span class="token punctuation">)</span>
logging<span class="token punctuation">.</span>info<span class="token punctuation">(</span><span class="token string">"核心组件初始化完成,API 服务就绪!(已启用 LangSmith 调试)"</span><span class="token punctuation">)</span>
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
logging<span class="token punctuation">.</span>error<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"核心组件初始化失败:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> exc_info<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">raise</span>
<span class="token comment"># 后续的请求模型、接口定义保持不变,仅在 build_agent 时传入 callback_manager:</span>
<span class="token comment"># 在 /chat 接口中构建 Agent 时:</span>
agent <span class="token operator">=</span> build_agent<span class="token punctuation">(</span>tools<span class="token operator">=</span>tools<span class="token punctuation">,</span> llm<span class="token operator">=</span>llm<span class="token punctuation">,</span> memory<span class="token operator">=</span>memory<span class="token punctuation">,</span> callback_manager<span class="token operator">=</span>callback_manager<span class="token punctuation">)</span></code></pre>
<p>集成完成后,运行项目并执行测试用例,LangSmith 会自动记录每一步操作。以下是 3 个典型测试场景(覆盖 Agent 核心能力):</p><h6>测试用例 1:本地文档问答(验证检索工具调用)</h6><p>运行</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token comment"># 运行命令行交互</span>
python main.py</code></pre>
<p>在终端输入:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-shell">用户:sample1.txt 里记录了什么内容?</code></pre>
<ul><li>预期行为:Agent 调用 <code>document_retrieval</code> 工具,检索本地文档并返回结果。</li><li>LangSmith 会记录:文档检索的输入(查询词)、输出(检索到的文档片段)、工具调用决策过程。</li></ul><h6>测试用例 2:实时搜索查询(验证外部工具调用)</h6><p>终端输入:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-shell">用户:2026年1月北京的平均气温是多少?</code></pre>
<ul><li>预期行为:Agent 调用 <code>serpapi</code> 工具,获取实时搜索结果并整理回复。</li><li>LangSmith 会记录:搜索工具的请求参数(查询词、时间范围)、返回结果、Agent 对结果的解析过程。</li></ul><h6>测试用例 3:多轮对话记忆(验证记忆组件)</h6><p>终端输入:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-shell">用户:我刚才问的是什么问题?</code></pre>
<ul><li>预期行为:Agent 从 <code>ConversationBufferMemory</code> 中读取历史对话,回复上一轮问题。</li><li>LangSmith 会记录:记忆存储的内容、Agent 读取记忆的过程、上下文关联逻辑。</li></ul><h6>测试用例 4:故意触发错误(验证异常追踪)</h6><p>终端输入:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-shell">用户:计算 <span class="token number">123456789</span> × <span class="token number">987654321</span>(故意输入复杂计算,触发工具调用异常)</code></pre>
<ul><li>预期行为:Agent 调用 <code>llm-math</code> 工具,但可能因计算复杂度或参数问题报错。</li><li>LangSmith 会记录:错误类型、异常堆栈、工具调用失败的详细原因。</li></ul><h5>5.1.3 LangSmith 控制台分析:精准定位问题</h5><p>运行测试用例后,访问 LangSmith 控制台(https://smith.langchain.com),按以下步骤分析轨迹:</p><h6>(1) 进入项目和轨迹列表</h6><ol><li>登录后,在左侧导航栏点击 <strong>Projects</strong>,找到你配置的项目名(如 “agent-debug-project”)。</li><li>进入项目后,会看到所有测试用例的轨迹列表,每条轨迹包含:
<ul><li>运行时间、状态(成功 / 失败)、耗时、关联的 LLM / 工具。</li><li>点击轨迹名称(如 “AgentRun: 2026 年 1 月北京的平均气温是多少?”),进入详细分析页。</li></ul></li></ol><h6>(2)轨迹详细分析(核心功能)</h6><p>轨迹详细页按 “时间线” 展示 Agent 从接收请求到生成回复的全流程,每个步骤都可展开查看细节:</p><h6>1.查看 Agent 决策过程(最关键)</h6><ul><li>找到 <strong>AgentExecutor</strong> 步骤,点击展开 → 查看 <strong>Action</strong> 字段:
<ul><li><code>action</code>:Agent 选择的工具(如 “serpapi”“document_retrieval”)。</li><li><code>action_input</code>:工具的输入参数(如搜索词 “2026 年 1 月北京平均气温”)。</li><li><code>observation</code>:工具的返回结果(如搜索到的气温数据、文档片段)。</li><li><code>thought</code>:Agent 的思考过程(如 “用户需要实时气温数据,需调用搜索工具”)。</li></ul></li><li>示例:若 Agent 错误地选择了 <code>document_retrieval</code> 工具处理实时天气查询,可在此处发现 “决策逻辑错误”,问题根源可能是 Prompt 中工具用途描述不清晰。</li></ul><h6>2.查看 Prompt 实际传入内容</h6><ul><li><p>找到</p><p>LLM</p><p>步骤(如 “Qwen2.5-7B-Instruct”),点击展开 → 查看</p><p>Inputs</p><p>→</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code>formatted_prompt</code></pre>
<p>:</p><ul><li>此处展示 Agent 传给 LLM 的完整 Prompt(包含 System Prompt、用户输入、工具返回结果、对话记忆)。</li><li>示例:若发现 Prompt 中缺少 “实时信息需调用搜索工具” 的引导,可确定是 System Prompt 配置不完善,需优化 Prompt 模板。</li></ul></li></ul><h6>3.查看记忆存储与读取</h6><ul><li><p>找到</p><p>ConversationBufferMemory</p><p>步骤,点击展开 → 查看</p><p>Memory</p><p>字段:</p><ul><li><code>chat_history</code>:存储的对话历史(用户输入 + Agent 回复)。</li><li>示例:若多轮对话中 Agent 忘记上一轮问题,可在此处检查 <code>chat_history</code> 是否为空或未正确传递,问题可能是记忆组件未被正确初始化或回调未关联。</li></ul></li></ul><h6>4.查看工具调用详情</h6><ul><li><p>找到</p><p>Tool</p><p>步骤(如 “serpapi”),点击展开 → 查看:</p><ul><li><code>Input</code>:工具接收的完整参数(如搜索词、超时时间)。</li><li><code>Output</code>:工具返回的原始结果(未被 LLM 处理的原始数据)。</li><li><code>Error</code>:工具调用失败时的异常信息(如 API Key 错误、网络超时、参数格式错误)。</li><li>示例:若搜索工具调用失败,可在此处查看是否是 <code>SERPER_API_KEY</code> 配置错误,或返回结果格式不符合 Agent 预期。</li></ul></li></ul><h6>5.查看 LLM 生成过程</h6><ul><li><p>找到</p><p>LLM</p><p>步骤的</p><p>Outputs</p><p>字段:</p><ul><li>查看 LLM 生成的原始回复(包括工具调用指令、最终回复内容)。</li><li>示例:若 LLM 生成的工具调用指令格式错误(如未按要求输出 JSON),可确定是 Prompt 中工具调用格式说明不清晰,需优化 Prompt 模板。</li></ul></li></ul><h5>5.1.4 典型问题定位与修复示例(结合 LangSmith 轨迹)</h5><p>以下是 3 个 Agent 常见问题的 “LangSmith 定位 + 代码修复” 完整流程:</p><h6>问题 1:Agent 不调用工具,直接编造答案(如本地文档查询)</h6><h6>定位过程:</h6><ol><li>进入 LangSmith 轨迹详情页,找到 <strong>AgentExecutor</strong> 步骤。</li><li>查看 <code>thought</code> 字段:发现 Agent 思考 “用户查询本地文档,但未找到相关工具,直接回答”。</li><li>查看 <strong>Tools</strong> 列表:确认 <code>document_retrieval</code> 工具已被加载,但 <code>description</code> 字段过于简略(如 “用于回答本地文档问题”)。</li><li>查看 LLM 的 <code>formatted_prompt</code>:发现 System Prompt 中未明确 “本地文档查询必须调用 document_retrieval 工具”。</li></ol><h6>修复方案:</h6><p>优化 <code>tools_setup.py</code> 中工具的 <code>description</code>,明确适用场景:</p><p>运行</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># agent_core/tools_setup.py</span>
doc_tool <span class="token operator">=</span> RetrievalQAWithSourcesTool<span class="token punctuation">.</span>from_chain_type<span class="token punctuation">(</span>
llm<span class="token operator">=</span>llm<span class="token punctuation">,</span>
chain_type<span class="token operator">=</span><span class="token string">"stuff"</span><span class="token punctuation">,</span>
retriever<span class="token operator">=</span>doc_retriever<span class="token punctuation">,</span>
name<span class="token operator">=</span><span class="token string">"document_retrieval"</span><span class="token punctuation">,</span>
<span class="token comment"># 优化描述:明确“本地文档”“sample1.txt/sample2.pdf/sample3.docx”等关键词</span>
description<span class="token operator">=</span><span class="token string">"专门用于回答本地文档(包括 sample1.txt、sample2.pdf、sample3.docx 等)相关的问题,只要用户询问的内容来自这些文档,必须调用该工具"</span>
<span class="token punctuation">)</span></code></pre>
<p>同时优化 <code>config.py</code> 中的 <code>SYSTEM_PROMPT</code>:</p><p>运行</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python">SYSTEM_PROMPT <span class="token operator">=</span> <span class="token triple-quoted-string string">"""你是一个高效、精准的通用智能助手,严格遵循以下规则:
1. 若用户查询本地文档内容(如 sample1.txt、sample2.pdf、sample3.docx),必须调用 document_retrieval 工具,禁止直接编造答案;
2. 若用户查询实时信息(如天气、新闻、气温),必须调用 serpapi 工具;
3. 若用户查询数学计算,必须调用 llm-math 工具;
4. 回答需基于工具返回结果,不编造信息。"""</span></code></pre>
<h6>问题 2:多轮对话中,Agent 忘记上一轮问题(记忆丢失)</h6><h6>定位过程:</h6><ol><li>进入 LangSmith 轨迹详情页,找到 <strong>ConversationBufferMemory</strong> 步骤。</li><li>查看 <code>chat_history</code> 字段:发现仅存储了当前轮对话,上一轮对话未被保留。</li><li>查看 <strong>AgentExecutor</strong> 步骤的 <code>inputs</code> 字段:发现 <code>chat_history</code> 参数未被传递给 Agent。</li><li>检查代码:发现 <code>agent_builder.py</code> 中 <code>build_agent</code> 函数未正确关联记忆组件。</li></ol><h6>修复方案:</h6><p>确认 <code>agent_builder.py</code> 中 <code>memory</code> 参数已正确传入,且 <code>ConversationBufferMemory</code> 的 <code>return_messages=True</code>:</p><p>运行</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># agent_core/memory_setup.py(确保配置正确)</span>
<span class="token keyword">def</span> <span class="token function">setup_memory</span><span class="token punctuation">(</span>session_id<span class="token punctuation">:</span> <span class="token builtin">str</span> <span class="token operator">=</span> <span class="token string">"default"</span><span class="token punctuation">,</span> use_redis<span class="token punctuation">:</span> <span class="token builtin">bool</span> <span class="token operator">=</span> <span class="token boolean">False</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">if</span> use_redis<span class="token punctuation">:</span>
message_history <span class="token operator">=</span> RedisChatMessageHistory<span class="token punctuation">(</span>
session_id<span class="token operator">=</span>session_id<span class="token punctuation">,</span>
host<span class="token operator">=</span>REDIS_HOST<span class="token punctuation">,</span>
port<span class="token operator">=</span>REDIS_PORT<span class="token punctuation">,</span>
db<span class="token operator">=</span>REDIS_DB<span class="token punctuation">,</span>
password<span class="token operator">=</span>REDIS_PASSWORD
<span class="token punctuation">)</span>
memory <span class="token operator">=</span> ConversationBufferMemory<span class="token punctuation">(</span>
memory_key<span class="token operator">=</span><span class="token string">"chat_history"</span><span class="token punctuation">,</span>
return_messages<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span><span class="token comment"># 必须设为 True,否则无法传递对话历史</span>
output_key<span class="token operator">=</span><span class="token string">"output"</span><span class="token punctuation">,</span>
chat_memory<span class="token operator">=</span>message_history
<span class="token punctuation">)</span>
<span class="token keyword">else</span><span class="token punctuation">:</span>
memory <span class="token operator">=</span> ConversationBufferMemory<span class="token punctuation">(</span>
memory_key<span class="token operator">=</span><span class="token string">"chat_history"</span><span class="token punctuation">,</span>
return_messages<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span><span class="token comment"># 关键配置</span>
output_key<span class="token operator">=</span><span class="token string">"output"</span>
<span class="token punctuation">)</span>
<span class="token keyword">return</span> memory</code></pre>
<p>同时在 <code>main.py</code> 中确认记忆组件已传入 <code>build_agent</code>:</p><p>运行</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># main.py 中 init_agent 函数</span>
memory <span class="token operator">=</span> setup_memory<span class="token punctuation">(</span><span class="token punctuation">)</span>
agent <span class="token operator">=</span> build_agent<span class="token punctuation">(</span>tools<span class="token operator">=</span>tools<span class="token punctuation">,</span> llm<span class="token operator">=</span>llm<span class="token punctuation">,</span> memory<span class="token operator">=</span>memory<span class="token punctuation">,</span> callback_manager<span class="token operator">=</span>callback_manager<span class="token punctuation">)</span></code></pre>
<h6>问题 3:工具调用失败(如 serpapi 搜索无返回)</h6><h6>定位过程:</h6><ol><li>进入 LangSmith 轨迹详情页,找到 <strong>Tool: serpapi</strong> 步骤。</li><li>查看 <code>Error</code> 字段:显示 “API Key invalid”(API 密钥无效)。</li><li>查看 <code>Input</code> 字段:确认 <code>api_key</code> 参数未被正确传递(为空)。</li><li>检查 <code>.env</code> 文件:发现 <code>SERPER_API_KEY</code> 拼写错误(如 <code>SERPER_APIKEY</code>)。</li></ol><h6>修复方案:</h6><p>修正 <code>.env</code> 文件中的密钥名称:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># 错误:SERPER_APIKEY=your_key</span>
正确:SERPER_API_KEY<span class="token operator">=</span>your_key<span class="token comment"># 与代码中 load_dotenv() 读取的键名一致</span></code></pre>
<p>同时在 <code>tools_setup.py</code> 中确认工具加载时已读取环境变量:</p><p>运行</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># agent_core/tools_setup.py</span>
tools <span class="token operator">=</span> load_tools<span class="token punctuation">(</span>
<span class="token punctuation">[</span><span class="token string">"serpapi"</span><span class="token punctuation">,</span> <span class="token string">"llm-math"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
llm<span class="token operator">=</span>llm<span class="token comment"># load_tools 会自动从环境变量读取 SERPER_API_KEY</span>
<span class="token punctuation">)</span></code></pre>
<h4>5.2 优化方向</h4><h5>(1)检索效果优化</h5><ul><li><p>检索是本地文档问答的核心,优化需从“文档切分、Embedding模型、检索参数”三方面入手,直接提升答案相关性,以下是具体落地方案:</p><ul><li><p><strong>调整文档切分参数</strong>:原代码中<code>chunk_size=512</code>适用于通用场景,若文档多为短句、碎片化内容,可减小至256;若为长文本(如论文、报告),保持512即可,同时调整重叠度提升上下文连贯性。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python">`<span class="token comment"># 优化后文档切分代码(适配不同文档类型) ``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)`</span></code></pre>
</li><li><p><strong>更换高性能Embedding模型</strong>:原BAAI/bge-base-zh-v1.5效果够用,更换为large版本(维度从768提升至1024),可显著提升中文文本相关性,需注意模型体积增大,建议GPU运行。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python">`<span class="token comment"># 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加速,提升向量化速度 ``)`</span></code></pre>
</li><li><p><strong>优化检索参数与策略</strong>:原<code>k=3</code>可能遗漏关键片段,调整为5-8;同时添加检索分数过滤,排除低相关性片段(分数越低相关性越高,通常阈值设为0.3)。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python">`<span class="token comment"># 优化后检索工具配置 ``doc_retriever = vector_db.as_retriever( ``    search_kwargs={ ``      "k": 5,# 返回top5相关片段 ``      "score_threshold": 0.3# 过滤分数&gt;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偏向多样性 ``    } ``)`</span></code></pre>
</li></ul></li></ul><h5>(2)Agent 决策优化</h5><ul><li><p>Agent决策偏差的核心原因是“Prompt引导不足、LLM对工具认知模糊”,需通过Prompt优化、示例引导等方式,强制规范工具调用逻辑:</p><ul><li><p><strong>精准优化System Prompt</strong>:明确工具调用的“触发条件、优先级、格式要求”,避免LLM编造答案或误用工具。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># 优化后System Prompt(新增触发条件、优先级、格式约束)</span>
SYSTEM_PROMPT <span class="token operator">=</span> <span class="token triple-quoted-string string">"""你是一个严格遵循工具调用规则的通用智能助手,按以下优先级和条件工作:
1. 工具调用优先级:本地文档检索工具 &gt; 搜索工具 &gt; 数学计算工具 &gt; 直接回答
2. 触发条件:
- 询问本地文档内容(含文件名、文档内知识点)→ 必须调用document_retrieval工具
- 涉及2024年后实时信息、天气、新闻、股票、未公开数据 → 必须调用serpapi工具
- 涉及加减乘除、公式计算、数据统计 → 必须调用llm-math工具
- 仅当工具返回结果无法回答,或问题为常识性内容时,才直接回答
3. 输出要求:工具调用结果需整理成自然语言,标注信息来源(文档/搜索),不编造内容
4. 错误处理:若工具调用失败,重试1次,仍失败则告知用户无法获取对应信息"""</span></code></pre>
</li><li><p><strong>添加Few-Shot示例引导</strong>:在Prompt模板中插入2-3个典型场景示例,让LLM更易理解工具调用逻辑,尤其适配中文场景。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># 构建带Few-Shot示例的Prompt模板</span>
FEW_SHOT_EXAMPLES <span class="token operator">=</span> <span class="token triple-quoted-string string">"""示例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℃。"""</span>
<span class="token comment"># 整合示例到Prompt模板</span>
query_wrapper_prompt <span class="token operator">=</span> PromptTemplate<span class="token punctuation">(</span>
template<span class="token operator">=</span><span class="token string">"&lt;&lt;SYS&gt;&gt;\n{system_prompt}\n{few_shot_examples}\n&lt;&lt;/SYS&gt;&gt;\n\n{query_str} "</span><span class="token punctuation">,</span>
input_variables<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"system_prompt"</span><span class="token punctuation">,</span> <span class="token string">"few_shot_examples"</span><span class="token punctuation">,</span> <span class="token string">"query_str"</span><span class="token punctuation">]</span>
<span class="token punctuation">)</span>
<span class="token comment"># 初始化LLM时传入示例</span>
llm <span class="token operator">=</span> HuggingFaceLLM<span class="token punctuation">(</span>
<span class="token comment"># 原有参数不变...</span>
query_wrapper_prompt<span class="token operator">=</span>query_wrapper_prompt<span class="token punctuation">,</span>
<span class="token comment"># 其他参数...</span>
<span class="token punctuation">)</span>
<span class="token comment"># 调用Agent时传入示例(确保每次调用都携带)</span>
response <span class="token operator">=</span> agent<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token string">"query_str"</span><span class="token punctuation">:</span> user_input<span class="token punctuation">,</span>
<span class="token string">"system_prompt"</span><span class="token punctuation">:</span> SYSTEM_PROMPT<span class="token punctuation">,</span>
<span class="token string">"few_shot_examples"</span><span class="token punctuation">:</span> FEW_SHOT_EXAMPLES
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
</li><li><p><strong>强制工具调用校验</strong>:通过自定义Hook函数,校验Agent是否按规则调用工具,避免漏调、误调。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">from</span> langchain<span class="token punctuation">.</span>callbacks <span class="token keyword">import</span> BaseCallbackHandler
<span class="token keyword">class</span> <span class="token class-name">ToolCallValidator</span><span class="token punctuation">(</span>BaseCallbackHandler<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""自定义回调,校验工具调用是否符合规则"""</span>
<span class="token keyword">def</span> <span class="token function">on_agent_action</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> action<span class="token punctuation">,</span> <span class="token operator">**</span>kwargs<span class="token punctuation">)</span><span class="token punctuation">:</span>
user_query <span class="token operator">=</span> kwargs<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"inputs"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"query_str"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span>
tool_name <span class="token operator">=</span> action<span class="token punctuation">.</span>tool
<span class="token comment"># 校验本地文档查询是否调用正确工具</span>
<span class="token keyword">if</span> <span class="token builtin">any</span><span class="token punctuation">(</span>doc_keyword <span class="token keyword">in</span> user_query <span class="token keyword">for</span> doc_keyword <span class="token keyword">in</span> <span class="token punctuation">[</span><span class="token string">"sample1.txt"</span><span class="token punctuation">,</span> <span class="token string">"sample2.pdf"</span><span class="token punctuation">,</span> <span class="token string">"文档"</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">and</span> tool_name <span class="token operator">!=</span> <span class="token string">"document_retrieval"</span><span class="token punctuation">:</span>
<span class="token keyword">raise</span> ValueError<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"错误:询问文档内容应调用document_retrieval工具,当前调用</span><span class="token interpolation"><span class="token punctuation">{</span>tool_name<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 校验实时信息是否调用搜索工具</span>
<span class="token keyword">if</span> <span class="token builtin">any</span><span class="token punctuation">(</span>real_time_keyword <span class="token keyword">in</span> user_query <span class="token keyword">for</span> real_time_keyword <span class="token keyword">in</span> <span class="token punctuation">[</span><span class="token string">"2024"</span><span class="token punctuation">,</span> <span class="token string">"2025"</span><span class="token punctuation">,</span> <span class="token string">"2026"</span><span class="token punctuation">,</span> <span class="token string">"天气"</span><span class="token punctuation">,</span> <span class="token string">"新闻"</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">and</span> tool_name <span class="token operator">!=</span> <span class="token string">"serpapi"</span><span class="token punctuation">:</span>
<span class="token keyword">raise</span> ValueError<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"错误:询问实时信息应调用serpapi工具,当前调用</span><span class="token interpolation"><span class="token punctuation">{</span>tool_name<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 初始化回调管理器,添加校验器</span>
<span class="token keyword">from</span> langchain<span class="token punctuation">.</span>callbacks <span class="token keyword">import</span> CallbackManager
callback_manager <span class="token operator">=</span> CallbackManager<span class="token punctuation">(</span><span class="token punctuation">[</span>ToolCallValidator<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> logging<span class="token punctuation">.</span>StreamHandler<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token comment"># 构建Agent时传入回调(前文代码中补充)</span>
agent <span class="token operator">=</span> initialize_agent<span class="token punctuation">(</span>
<span class="token comment"># 原有参数不变...</span>
callback_manager<span class="token operator">=</span>callback_manager
<span class="token punctuation">)</span></code></pre>
</li></ul></li></ul><h5>(3)记忆管理优化</h5><ul><li><p>原ConversationBufferMemory适合短对话,长对话易导致上下文溢出、记忆冗余,需针对性优化记忆类型、过期策略:</p><ul><li><p><strong>更换记忆类型(长对话适配)</strong>:长对话场景改用ConversationSummaryMemory,自动总结历史对话,压缩上下文体积,同时保留关键信息。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># 1. 安装依赖(若未安装)</span>
<span class="token comment"># pip install langchain-core==0.2.34</span>
<span class="token comment"># 2. 初始化ConversationSummaryMemory</span>
<span class="token keyword">from</span> langchain<span class="token punctuation">.</span>memory <span class="token keyword">import</span> ConversationSummaryMemory
<span class="token keyword">from</span> langchain<span class="token punctuation">.</span>chains <span class="token keyword">import</span> LLMChain
<span class="token comment"># 构建总结链(用于总结历史对话)</span>
summary_chain <span class="token operator">=</span> LLMChain<span class="token punctuation">(</span>
llm<span class="token operator">=</span>llm<span class="token punctuation">,</span>
prompt<span class="token operator">=</span>PromptTemplate<span class="token punctuation">(</span>
input_variables<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"history"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
template<span class="token operator">=</span><span class="token string">"请简洁总结以下对话内容,保留核心问题和答案,不超过50字:\n{history}"</span>
<span class="token punctuation">)</span>
<span class="token punctuation">)</span>
<span class="token comment"># 初始化总结记忆</span>
memory <span class="token operator">=</span> ConversationSummaryMemory<span class="token punctuation">(</span>
memory_key<span class="token operator">=</span><span class="token string">"chat_history"</span><span class="token punctuation">,</span>
return_messages<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
llm_chain<span class="token operator">=</span>summary_chain<span class="token punctuation">,</span><span class="token comment"># 关联总结链</span>
output_key<span class="token operator">=</span><span class="token string">"output"</span><span class="token punctuation">,</span>
max_token_limit<span class="token operator">=</span><span class="token number">512</span><span class="token comment"># 记忆总token上限,避免溢出</span>
<span class="token punctuation">)</span>
<span class="token comment"># 补充:混合记忆(短期完整记忆+长期总结记忆)</span>
<span class="token keyword">from</span> langchain<span class="token punctuation">.</span>memory <span class="token keyword">import</span> ConversationSummaryBufferMemory
memory <span class="token operator">=</span> ConversationSummaryBufferMemory<span class="token punctuation">(</span>
memory_key<span class="token operator">=</span><span class="token string">"chat_history"</span><span class="token punctuation">,</span>
return_messages<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span>
llm<span class="token operator">=</span>llm<span class="token punctuation">,</span>
max_token_limit<span class="token operator">=</span><span class="token number">1024</span><span class="token punctuation">,</span><span class="token comment"># 总上限</span>
buffer_window<span class="token operator">=</span><span class="token number">3</span><span class="token comment"># 最近3轮对话完整保留,更早的总结压缩</span>
<span class="token punctuation">)</span></code></pre>
</li><li><p><strong>清理无关记忆(精准过滤)</strong>:通过Prompt引导和代码过滤,让Agent忽略无关对话内容(如问候语、无意义语句),减少记忆冗余。</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># 1. Prompt引导过滤</span>
SYSTEM_PROMPT <span class="token operator">+=</span> <span class="token string">"\n5. 记忆规则:忽略问候语(如你好、再见)、无意义语句(如哦、嗯),仅记忆有效问题和答案。"</span>
<span class="token comment"># 2. 代码层面过滤无关内容(在交互函数中补充)</span>
<span class="token keyword">def</span> <span class="token function">filter_irrelevant_content</span><span class="token punctuation">(</span>user_input<span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token builtin">bool</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""过滤无关内容,返回True表示需记忆,False表示忽略"""</span>
irrelevant_keywords <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"你好"</span><span class="token punctuation">,</span> <span class="token string">"您好"</span><span class="token punctuation">,</span> <span class="token string">"再见"</span><span class="token punctuation">,</span> <span class="token string">"拜拜"</span><span class="token punctuation">,</span> <span class="token string">"哦"</span><span class="token punctuation">,</span> <span class="token string">"嗯"</span><span class="token punctuation">,</span> <span class="token string">"啊"</span><span class="token punctuation">,</span> <span class="token string">"哦豁"</span><span class="token punctuation">]</span>
<span class="token keyword">return</span> <span class="token keyword">not</span> <span class="token builtin">any</span><span class="token punctuation">(</span>keyword <span class="token keyword">in</span> user_input <span class="token keyword">for</span> keyword <span class="token keyword">in</span> irrelevant_keywords<span class="token punctuation">)</span>
<span class="token comment"># 优化交互函数,过滤后再存入记忆</span>
<span class="token keyword">def</span> <span class="token function">agent_chat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"=== 通用智能助手(输入 'quit' 退出)==="</span><span class="token punctuation">)</span>
<span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>
user_input <span class="token operator">=</span> <span class="token builtin">input</span><span class="token punctuation">(</span><span class="token string">"\n用户:"</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> user_input<span class="token punctuation">.</span>lower<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token string">"quit"</span><span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"助手:再见!"</span><span class="token punctuation">)</span>
<span class="token keyword">break</span>
<span class="token comment"># 过滤无关内容,不存入记忆</span>
<span class="token keyword">if</span> <span class="token keyword">not</span> filter_irrelevant_content<span class="token punctuation">(</span>user_input<span class="token punctuation">)</span><span class="token punctuation">:</span>
response <span class="token operator">=</span> <span class="token string">"好的~"</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"助手:</span><span class="token interpolation"><span class="token punctuation">{</span>response<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">continue</span>
<span class="token comment"># 正常调用Agent</span>
response <span class="token operator">=</span> agent<span class="token punctuation">.</span>run<span class="token punctuation">(</span>user_input<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"助手:</span><span class="token interpolation"><span class="token punctuation">{</span>response<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span></code></pre>
</li></ul></li></ul><h3>六、生产级部署最佳实践</h3><h4>6.1 容器化部署(Docker)</h4><h5>6.1.1 编写 Dockerfile</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Dockerfile"># 基础镜像
FROM python:3.10-slim
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update &amp;&amp; apt-get install -y --no-install-recommends \
    gcc \
    git \
    &amp;&amp; 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"]</code></pre>
<h5>6.1.2 构建与运行容器</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Bash"># 构建镜像
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</code></pre>
<h4>6.2 服务化封装(FastAPI)</h4><p>将 Agent 封装为 HTTP API 服务,支持跨平台调用:</p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-Python"># 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"}</code></pre>
<h4>6.3 监控与评估</h4><ul><li><p><strong>监控指标</strong>:Agent 响应时间、工具调用成功率、错误率、用户满意度</p></li><li><p><strong>评估工具</strong>:LangSmith 提供的 Agent 评估模块,支持自定义评估指标</p></li><li><p><strong>持续优化</strong>:定期分析错误案例,优化 Prompt、工具配置和模型选择</p></li></ul><h3>七、常见问题解决</h3><h4>7.1 模型加载失败</h4><ul><li><p>问题原因:模型路径错误、硬件资源不足、PyTorch 版本不兼容</p></li><li><p>解决方案:</p><ol><li><p>检查模型路径是否正确(避免中文路径)</p></li><li><p>确认 GPU 显存充足(7B 模型需至少 12GB 显存)</p></li><li><p>安装与 CUDA 匹配的 PyTorch 版本</p></li></ol></li></ul><h4>7.2 Agent 工具调用错误</h4><ul><li><p>问题原因:工具描述不清晰、Prompt 引导不足、LLM 理解能力有限</p></li><li><p>解决方案:</p><ol><li><p>优化工具描述,明确工具的适用场景和输入格式</p></li><li><p>在 Prompt 中添加工具调用示例</p></li><li><p>更换更大参数量的 LLM(如 14B 模型)</p></li></ol></li></ul><h4>7.3 检索结果不准确</h4><ul><li><p>问题原因:文档切分不合理、Embedding 模型不匹配、检索参数设置不当</p></li><li><p>解决方案:</p><ol><li><p>调整 <code>chunk_size</code> 和 <code>chunk_overlap</code> 参数</p></li><li><p>使用中文优化的 Embedding 模型</p></li><li><p>增加 <code>k</code> 值(返回更多相关片段)</p></li></ol></li></ul><h4>7.4 对话记忆丢失</h4><ul><li><p>问题原因:记忆类型选择不当、上下文窗口过小</p></li><li><p>解决方案:</p><ol><li><p>使用 <code>ConversationBufferMemory</code> 或 <code>ConversationSummaryMemory</code></p></li><li><p>增大 LLM 的 <code>context_window</code> 参数</p></li><li><p>定期清理无关记忆内容</p></li></ol></li></ul><h3>八、扩展与进阶</h3><h4>8.1 工具扩展</h4><ul><li><p>集成业务系统:如数据库查询工具(SQLDatabaseToolkit)、API 调用工具(RequestsToolkit)</p></li><li><p>自定义工具:根据业务需求开发专属工具(如订单查询、数据统计工具)</p></li><li><p>工具链组合:将多个工具组合为工具链,实现复杂任务自动化(如“数据查询 → 分析 → 报告生成”)</p></li></ul><h4>8.2 LangChain 生态工具集成</h4><ul><li><p><strong>LangGraph</strong>:构建更复杂的 Agent 工作流(支持循环、分支、人类介入)</p></li><li><p><strong>LangServe</strong>:快速部署 LangChain 应用为服务</p></li><li><p><strong>LangChain Hub</strong>:共享和复用 Prompt、链、Agent 配置</p></li><li><p><strong>Deep Agents</strong>:构建具备规划能力、子Agent 协作的高级智能体</p></li></ul><h4>8.3 高级应用场景</h4><ul><li><p>智能客服:集成知识库、工单系统,提供自动化客户支持</p></li><li><p>数据分析助手:连接数据库,自动生成 SQL、分析数据并生成报告</p></li><li><p>研发助手:集成代码仓库、文档系统,辅助代码编写、文档生成</p></li><li><p>个人助理:管理日程、发送邮件、查询信息,提供个性化服务</p></li></ul><h3>总结</h3><p>本文档详细介绍了 LangChain 框架的本地部署流程、Agent 智能体的核心原理与搭建步骤,并提供了完整的代码示例和优化方案。通过 LangChain 的模块化设计,开发者可以快速构建具备工具调用、记忆管理、任务规划能力的智能助手,并基于实际需求进行扩展与优化。</p><p>随着 AI 技术的发展,LangChain 生态将持续完善,Agent 智能体的应用场景也将不断扩展。建议开发者在实践中结合 LangSmith 等工具进行调试与评估,持续优化产品体验,逐步实现从原型到生产级应用的落地。</p><blockquote></blockquote></div><br><br>
来源:https://www.cnblogs.com/yangykaifa/p/19685698
頁: [1]
查看完整版本: LangChain 本地部署与 Agent 智能体助手搭建实战详解 - 指南