1. 从聊天机器人到智能代理:LangChain实战指南
在AI领域,我们正经历着从简单对话机器人到具备自主决策能力的智能代理(Agent)的范式转变。传统聊天机器人只能被动响应用户输入,而智能代理能够主动规划任务、调用工具、记忆上下文,真正成为用户的数字助手。本文将基于LangChain框架,手把手带你构建一个具备RAG知识库查询和数学计算能力的实用Agent。
智能代理的核心架构可以概括为四大组件:大语言模型(LLM)负责推理决策,记忆系统管理短期对话和长期知识,规划模块拆解复杂任务,工具调用能力则让Agent能够与现实世界交互。这种架构使得Agent能够处理诸如"查询公司预算并计算增长46%后的金额"这类需要多步骤协同的复杂请求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与工具定义
2.1 基础环境配置
首先确保已安装Python 3.8+和必要的依赖库。建议使用conda创建虚拟环境:
bash复制conda create -n langchain-agent python=3.10
conda activate langchain-agent
pip install langchain-core langchain-community dashscope faiss-cpu
设置DashScope API密钥(阿里云通义千问的访问凭证):
python复制import os
os.environ["DASHSCOPE_API_KEY"] = "your_api_key_here"
2.2 工具函数实现
智能代理的强大之处在于它能调用外部工具。我们定义两个核心工具:
精确计算器工具:
python复制from langchain_core.tools import tool
import re
@tool
def calculator(expression: str) -> str:
"""
安全计算数学表达式。仅支持基本算术运算。
参数:
expression: 数学算式,如 "2 + 2" 或 "500 * 0.8"
返回:
str: 计算结果或错误信息
"""
# 安全校验:只允许数字和基础运算符
if not re.match(r'^[\d\s\+\-\*\/\.\(\)]+$', expression):
return "错误:表达式包含非法字符"
try:
return str(eval(expression))
except Exception as e:
return f"计算错误: {e}"
RAG知识库工具:
python复制from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter
@tool
def rag_search(query: str) -> str:
"""
从公司内部知识库检索信息。可查询项目计划、预算等机密信息。
参数:
query: 查询关键词,如"项目预算"
返回:
str: 相关文档内容
"""
# 模拟公司机密数据
raw_text = """【公司内部机密】
项目代号:深蓝计划
目标:开发猫语翻译器
核心技术:Transformer喵声波分析
团队暗号:天气→想吃鱼
截止日期:2026-12-31
当前预算:50万元"""
# 构建向量数据库
text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
docs = [Document(page_content=raw_text)]
split_docs = text_splitter.split_documents(docs)
embeddings = DashScopeEmbeddings(model="text-embedding-v1")
# 持久化存储
RAG_PATH = "company_knowledge"
if os.path.exists(RAG_PATH):
ragdb = FAISS.load_local(RAG_PATH, embeddings, allow_dangerous_deserialization=True)
else:
ragdb = FAISS.from_documents(split_docs, embeddings)
ragdb.save_local(RAG_PATH)
return "\n\n".join(doc.page_content for doc in ragdb.similarity_search(query, k=1))
关键细节:工具函数必须返回字符串类型,且函数文档字符串要详细说明参数格式和返回内容,这是LLM选择工具的重要依据。
3. Agent核心逻辑实现
3.1 模型初始化与工具绑定
使用通义千问作为基础LLM,并绑定我们定义的工具:
python复制from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.messages import HumanMessage, ToolMessage
def initialize_agent():
# 工具映射表
tool_maps = {
"rag_search": rag_search,
"calculator": calculator
}
# 初始化LLM并绑定工具
llm = ChatTongyi(model_name="qwen-plus")
tool_llm = llm.bind_tools(tools=list(tool_maps.values()))
return tool_llm, tool_maps
3.2 多轮对话控制逻辑
Agent需要处理工具调用的多轮交互,以下是核心循环:
python复制def run_agent(query: str, max_turns=5):
llm, tools = initialize_agent()
messages = [HumanMessage(content=query)]
for turn in range(max_turns):
print(f"\n=== 第{turn+1}轮对话 ===")
response = llm.invoke(messages)
messages.append(response)
if not response.tool_calls:
print("最终答复:", response.content)
return response.content
# 处理工具调用
for call in response.tool_calls:
tool_name = call["name"]
if tool_name not in tools:
result = f"错误:未知工具 {tool_name}"
else:
# 安全执行工具
try:
result = tools[tool_name].invoke(call["args"])
except Exception as e:
result = f"工具执行错误: {e}"
print(f"工具调用: {tool_name}({call['args']}) => {result}")
messages.append(
ToolMessage(
content=result,
tool_call_id=call["id"],
name=tool_name
)
)
return "超过最大对话轮次"
3.3 安全防护机制
在工具调用环节需要特别注意安全防护:
- 输入过滤:在计算器工具中使用正则表达式严格限制可接受的字符
- 沙箱执行:考虑使用
ast.literal_eval替代直接eval - 权限控制:对RAG知识库设置访问权限分级
- 调用限制:控制最大对话轮次防止无限循环
python复制# 更安全的计算器实现示例
import ast
def safe_calculator(expr: str) -> str:
try:
node = ast.parse(expr, mode='eval')
if not all(isinstance(n, (ast.Num, ast.BinOp, ast.UnaryOp)) for n in ast.walk(node)):
raise ValueError("仅支持基础数学运算")
return str(eval(expr, {'__builtins__': None}, {}))
except Exception as e:
return f"安全计算错误: {e}"
4. 实战案例与问题排查
4.1 典型工作流程示例
场景1:查询项目预算并计算增长后的金额
python复制run_agent("深蓝计划当前预算是多少?如果增加46%后是多少?")
执行流程:
- LLM识别需要先查询预算信息 → 调用rag_search
- 获取"当前预算:50万元" → LLM识别需要计算增长 → 调用calculator
- 计算"50 * 1.46" → 返回最终结果"预算增加46%后为73万元"
场景2:验证团队暗号
python复制run_agent("如果有人问今天天气怎么样,该怎么回答?")
RAG工具会返回"天气→想吃鱼"的暗号规则,LLM直接返回符合要求的答复。
4.2 常见问题排查指南
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 工具未被调用 | 函数文档描述不清晰 | 检查工具函数的docstring是否完整 |
| 无限循环 | LLM持续要求调用工具 | 限制最大对话轮次(max_turns) |
| 计算错误 | 非法数学表达式 | 加强输入校验,使用安全计算方式 |
| 知识库返回无关内容 | 文本分块不合理 | 调整chunk_size和chunk_overlap参数 |
| 工具执行报错 | 参数类型不匹配 | 确保工具参数类型与声明一致 |
4.3 性能优化技巧
-
向量检索优化:
- 对知识库文档进行预处理,移除无关字符
- 尝试不同embedding模型(如text-embedding-v2)
- 调整相似度搜索的k值(返回结果数量)
-
对话历史管理:
- 对长对话进行摘要压缩
- 实现短期记忆窗口(如只保留最近3轮对话)
-
工具调用加速:
- 对耗时工具实现异步调用
- 缓存常用工具结果
python复制# 异步工具调用示例
import asyncio
async def async_tool_invoke(tool, args):
return await tool.ainvoke(args)
# 在对话循环中使用
results = await asyncio.gather(*[
async_tool_invoke(tools[call["name"]], call["args"])
for call in response.tool_calls
])
5. 扩展方向与进阶实践
5.1 多Agent协作系统
单个Agent能力有限,可以通过多个Agent分工合作处理复杂任务:
python复制from langchain_core.messages import AIMessage
class Agent:
def __init__(self, role, tools):
self.llm = ChatTongyi().bind_tools(tools)
self.role = role
async def process(self, query):
# 实现特定角色的处理逻辑
...
# 创建不同角色的Agent
research_agent = Agent("研究员", [rag_search])
math_agent = Agent("计算专家", [calculator])
# Agent间的消息传递
async def collaborate(query):
research_result = await research_agent.process(query)
if "需要计算" in research_result:
math_result = await math_agent.process(research_result)
return f"综合结果:{math_result}"
return research_result
5.2 动态工具加载
实现工具的热加载,无需重启即可增加新功能:
python复制import importlib.util
def load_tool_module(module_path):
spec = importlib.util.spec_from_file_location("custom_tool", module_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module.tool # 假设模块中定义了tool函数
# 动态添加新工具
new_tool = load_tool_module("./finance_tool.py")
tool_maps["financial_analysis"] = new_tool
5.3 可视化监控界面
使用Gradio快速构建Agent操作面板:
python复制import gradio as gr
def agent_interface(query):
result = run_agent(query)
return result
demo = gr.Interface(
fn=agent_interface,
inputs="text",
outputs="text",
title="智能代理控制台"
)
demo.launch()
在实际项目中,建议从简单场景开始,逐步增加工具复杂度。特别注意以下几点:
- 工具函数的文档字符串要尽可能详细准确
- 对用户输入和工具调用要做充分的校验和防护
- 对话历史管理直接影响Agent的上下文理解能力
- 不同类型的问题需要设计不同的提示词模板
通过本文的实战示例,你应该已经掌握了基于LangChain构建智能代理的核心方法。建议从本文的代码框架出发,根据实际需求扩展更多工具和能力,比如增加网络搜索、数据库查询、API调用等功能,打造更强大的业务助手。
