
很多人第一次接触 LangChain,会觉得它只是给大模型套了一层 API。
比如:
python
question = "Redis 和 MySQL 怎么保证数据一致性?"
response = llm.invoke(question)
print(response)
但如果只是调用一次大模型,其实完全没有必要使用 LangChain。
LangChain 真正有价值的地方,是把:
text
大模型
+
Prompt
+
Tool
+
Memory
+
RAG
+
Agent
+
工作流
这些东西组织起来。
最后让大模型从一个:
text
输入问题 -> 输出答案
的聊天机器人,变成:
text
理解任务
↓
判断是否需要工具
↓
调用工具
↓
读取工具结果
↓
继续分析
↓
必要时再次调用工具
↓
生成最终答案
这就是 Agent。
这一篇,我们从最基础的 LangChain 调用开始,一直做到一个完整的 AI Agent。
一、LangChain 到底是什么?
我们先不讲复杂概念。
假设现在直接调用一个大模型:
python
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="your-model",
messages=[
{
"role": "user",
"content": "帮我分析一下 Redis 缓存雪崩"
}
]
)
print(response.choices[0].message.content)
流程非常简单:
text
User
↓
LLM
↓
Answer
但是现实中的 AI 应用通常没有这么简单。
比如用户问:
text
帮我查询数据库里面今天新增了多少用户,
然后和昨天的数据比较,
最后分析增长原因。
大模型本身并不知道你的数据库数据。
所以需要:
text
用户
↓
Agent
↓
判断:需要查询数据库
↓
调用 MySQL Tool
↓
获得今天用户数
↓
再次调用 MySQL Tool
↓
获得昨天用户数
↓
LLM 分析
↓
最终答案
LangChain 做的,就是帮我们把这些组件连接起来。
二、准备开发环境
建议使用 Python 3.11+。
创建项目:
bash
mkdir langchain-agent-demo
cd langchain-agent-demo
创建虚拟环境:
bash
python -m venv .venv
Mac / Linux:
bash
source .venv/bin/activate
Windows:
bash
.venv\Scripts\activate
安装依赖:
bash
pip install -U langchain langchain-openai
后面做 RAG 还会用到:
bash
pip install -U langchain-text-splitters
如果使用 .env:
bash
pip install python-dotenv
项目结构:
text
langchain-agent-demo/
├── .env
├── main.py
├── simple_chat.py
├── prompt_demo.py
├── tool_demo.py
├── agent_demo.py
├── memory_demo.py
├── rag_demo.py
└── data/
└── knowledge.txt
三、第一次调用大模型
创建:
text
simple_chat.py
代码:
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
load_dotenv()
llm = ChatOpenAI(
model="your-model",
api_key=os.getenv("OPENAI_API_KEY"),
)
response = llm.invoke(
"什么是 Redis 缓存穿透?用程序员能看懂的方式解释。"
)
print(response.content)
.env:
env
OPENAI_API_KEY=你的API_KEY
运行:
bash
python simple_chat.py
这里最关键的是:
python
llm.invoke()
LangChain 把不同模型厂商尽量封装成统一调用方式。
所以以后即使换模型,业务层代码通常不需要大规模修改。
四、连接 OpenAI Compatible API
现在很多模型服务都兼容 OpenAI API 格式。
这种情况下可以配置:
python
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="your-model-name",
api_key="sk-xxxx",
base_url="https://example.com/v1",
)
response = llm.invoke("你好,介绍一下你自己")
print(response.content)
也可以通过环境变量:
python
import os
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model=os.getenv("MODEL_NAME"),
api_key=os.getenv("OPENAI_API_KEY"),
base_url=os.getenv("OPENAI_BASE_URL"),
)
.env:
env
OPENAI_API_KEY=sk-xxxx
OPENAI_BASE_URL=https://example.com/v1
MODEL_NAME=your-model
这样以后切模型只修改配置文件。
五、Message 消息对象
实际开发中,很少只发送字符串。
通常会构造消息。
例如:
python
from langchain_core.messages import (
SystemMessage,
HumanMessage,
)
messages = [
SystemMessage(
content="""
你是一名拥有10年经验的后端架构师。
你擅长:
1. Java
2. Python
3. MySQL
4. Redis
5. Kafka
6. Docker
7. Kubernetes
回答技术问题时:
- 尽量给代码
- 解释底层原理
- 给实际工程案例
"""
),
HumanMessage(
content="Redis 和 MySQL 如何保证数据一致性?"
),
]
response = llm.invoke(messages)
print(response.content)
可以理解为:
text
SystemMessage
↓
告诉模型:你是谁
HumanMessage
↓
告诉模型:用户问了什么
后面 Agent、Memory、RAG,本质上仍然是在构造越来越复杂的上下文。
六、PromptTemplate
如果 Prompt 是固定的,直接写字符串还可以。
但真实业务通常存在变量。
比如:
text
你是一名 {role}
请使用 {language} 回答下面的问题:
{question}
LangChain 提供了 PromptTemplate。
python
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate.from_template(
"""
你是一名经验丰富的 {role}。
请使用 {language} 给出解决方案。
问题:
{question}
要求:
1. 先解释原理
2. 再给代码
3. 最后给生产环境建议
"""
)
result = prompt.invoke({
"role": "后端架构师",
"language": "Java",
"question": "如何实现 Redis 分布式锁?",
})
print(result)
也可以直接和模型组合。
七、LCEL:用管道连接组件
LangChain 中经常能看到:
python
prompt | llm
例如:
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="your-model"
)
prompt = ChatPromptTemplate.from_messages([
(
"system",
"""
你是一名资深后端工程师。
回答技术问题时必须:
1. 给出核心原理
2. 给代码
3. 给生产环境注意事项
"""
),
(
"human",
"{question}"
)
])
chain = prompt | llm
response = chain.invoke({
"question": "什么是数据库连接池?"
})
print(response.content)
这里:
python
prompt | llm
可以理解成:
text
输入参数
↓
Prompt
↓
LLM
↓
答案
以后还可以继续:
text
Prompt
↓
LLM
↓
Parser
这就是 LangChain 一个非常重要的思想:
text
把复杂 AI 应用拆成组件,
再把组件连接起来。
八、结构化输出
真实项目中,最好不要让模型随便输出一大段文字。
比如做用户意图识别:
text
用户输入:
帮我看看今天服务器 CPU 为什么这么高
期望:
{
"category": "server",
"priority": "high",
"need_tool": true
}
可以定义 Pydantic 对象。
python
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
class UserIntent(BaseModel):
category: str = Field(
description="问题分类"
)
priority: str = Field(
description="优先级:low、medium、high"
)
need_tool: bool = Field(
description="是否需要调用外部工具"
)
summary: str = Field(
description="问题摘要"
)
llm = ChatOpenAI(
model="your-model"
)
structured_llm = llm.with_structured_output(
UserIntent
)
result = structured_llm.invoke(
"帮我查一下生产服务器为什么 CPU 突然到 95% 了"
)
print(result)
print(result.category)
print(result.priority)
print(result.need_tool)
得到的数据就不再是普通字符串,而是:
python
UserIntent(
category="server",
priority="high",
need_tool=True,
summary="生产服务器CPU使用率异常升高"
)
这种能力在 Agent 项目里非常重要。
比如可以做:
text
用户请求
↓
意图识别
↓
数据库任务?
服务器任务?
搜索任务?
代码任务?
↓
路由到不同 Agent
九、Tool:让 AI 拥有外部能力
接下来进入 LangChain 最重要的部分之一:
text
Tool
普通 LLM 只能根据上下文回答。
它不知道:
text
现在几点
数据库数据
服务器状态
实时天气
公司内部数据
GitHub 最新数据
但是 Agent 可以调用 Tool。
例如:
python
from langchain.tools import tool
@tool
def get_user_count() -> str:
"""
查询系统当前用户数量。
"""
return "系统当前共有 12898 个用户"
重点是:
python
@tool
它把一个普通 Python 函数变成了 AI 可以调用的 Tool。
十、带参数的 Tool
例如查询订单:
python
from langchain.tools import tool
@tool
def query_order(order_id: str) -> str:
"""
根据订单ID查询订单状态。
Args:
order_id: 订单ID
Returns:
订单状态
"""
mock_orders = {
"10001": "已支付",
"10002": "待支付",
"10003": "已退款",
}
return mock_orders.get(
order_id,
"订单不存在"
)
直接测试:
python
result = query_order.invoke({
"order_id": "10001"
})
print(result)
输出:
text
已支付
但是 Tool 本身还不算 Agent。
关键是:
text
让模型自己判断什么时候调用它。
十一、创建第一个 Agent
现在正式创建 Agent。
python
from langchain.agents import create_agent
from langchain.tools import tool
@tool
def query_order(order_id: str) -> str:
"""
根据订单ID查询订单状态。
"""
mock_orders = {
"10001": "已支付,等待发货",
"10002": "待支付",
"10003": "退款处理中",
}
return mock_orders.get(
order_id,
"没有找到该订单"
)
agent = create_agent(
model="openai:your-model",
tools=[
query_order
],
system_prompt="""
你是一名电商客服AI。
当用户询问具体订单状态时,
必须调用 query_order 工具获取真实数据。
禁止自己猜测订单状态。
"""
)
result = agent.invoke({
"messages": [
{
"role": "user",
"content": "帮我看看订单10001现在什么状态?"
}
]
})
print(
result["messages"][-1].content
)
这时候整个执行过程大概变成:
text
用户:
订单10001怎么样?
↓
Agent
↓
模型发现:
需要订单数据
↓
query_order
↓
返回:
已支付,等待发货
↓
Model
↓
最终回答:
订单10001目前已经支付,
正在等待发货。
这就是 Agent 最基本的工作循环。
当前 LangChain 的 Agent 核心就是让模型持续判断是否需要调用工具,直到任务完成。
十二、一个 Agent 配多个工具
真实 Agent 一般不会只有一个 Tool。
例如:
python
from datetime import datetime
from langchain.agents import create_agent
from langchain.tools import tool
@tool
def get_current_time() -> str:
"""
获取当前服务器时间。
"""
return datetime.now().strftime(
"%Y-%m-%d %H:%M:%S"
)
@tool
def query_user(user_id: str) -> str:
"""
根据用户ID查询用户信息。
"""
users = {
"1001": {
"name": "张三",
"level": "VIP",
"balance": 120.5
},
"1002": {
"name": "李四",
"level": "普通用户",
"balance": 20.0
}
}
user = users.get(user_id)
if not user:
return "用户不存在"
return str(user)
@tool
def query_order(order_id: str) -> str:
"""
查询订单信息。
"""
orders = {
"20001": {
"user_id": "1001",
"status": "已支付",
"amount": 199
}
}
order = orders.get(order_id)
if not order:
return "订单不存在"
return str(order)
agent = create_agent(
model="openai:your-model",
tools=[
get_current_time,
query_user,
query_order,
],
system_prompt="""
你是一个后台管理系统AI助手。
你可以帮助管理员:
1. 查询用户
2. 查询订单
3. 查询系统时间
涉及真实业务数据时必须调用工具,
禁止虚构数据。
"""
)
result = agent.invoke({
"messages": [
{
"role": "user",
"content": """
帮我查询订单20001是谁下的,
这个用户是什么等级?
"""
}
]
})
print(result["messages"][-1].content)
这里已经出现 Agent 非常重要的一种能力:
text
多工具组合调用
它可能执行:
text
query_order("20001")
↓
获得 user_id=1001
↓
query_user("1001")
↓
获得 VIP
↓
最终回答
也就是说:
text
Tool A 的结果
可以成为:
text
Tool B 的参数
这时候已经非常接近真正的 AI Agent。
十三、让 Agent 调用数据库
接下来做一个更真实的例子。
安装:
bash
pip install pymysql
数据库:
sql
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(100),
email VARCHAR(200),
status INT,
created_at DATETIME
);
插入数据:
sql
INSERT INTO users
(username, email, status, created_at)
VALUES
(
'JavaPub',
'demo@example.com',
1,
NOW()
);
封装数据库:
python
import pymysql
def get_connection():
return pymysql.connect(
host="127.0.0.1",
port=3306,
user="root",
password="123456",
database="agent_demo",
charset="utf8mb4",
cursorclass=pymysql.cursors.DictCursor,
)
创建 Tool:
python
from langchain.tools import tool
@tool
def query_user_by_id(
user_id: int
) -> dict:
"""
根据用户ID查询用户信息。
"""
conn = get_connection()
try:
with conn.cursor() as cursor:
sql = """
SELECT
id,
username,
email,
status,
created_at
FROM users
WHERE id = %s
LIMIT 1
"""
cursor.execute(
sql,
(user_id,)
)
result = cursor.fetchone()
if result is None:
return {
"success": False,
"message": "用户不存在"
}
return {
"success": True,
"data": result
}
finally:
conn.close()
Agent:
python
from langchain.agents import create_agent
agent = create_agent(
model="openai:your-model",
tools=[
query_user_by_id
],
system_prompt="""
你是一名后台管理系统助手。
需要获取用户真实信息时,
必须使用 query_user_by_id。
不要编造数据库中的用户信息。
"""
)
调用:
python
result = agent.invoke({
"messages": [
{
"role": "user",
"content": "帮我查询用户ID 1 的账号信息"
}
]
})
print(result["messages"][-1].content)
这时候:
text
LLM
已经真正开始操作:
text
MySQL
了。
十四、千万不要直接让 Agent 执行任意 SQL
很多教程会直接写:
python
@tool
def execute_sql(sql: str):
...
例如:
python
@tool
def execute_sql(sql: str):
cursor.execute(sql)
这种写法非常危险。
因为模型可能生成:
sql
DELETE FROM users;
甚至:
sql
DROP TABLE users;
生产环境更推荐:
text
一个业务能力
=
一个 Tool
例如:
python
query_user()
python
query_order()
python
get_today_register_count()
python
get_server_status()
而不是提供一个:
python
execute_anything()
让 AI 随便执行。
十五、实现一个数据分析 Tool
比如管理员问:
text
今天新增多少用户?
可以封装:
python
@tool
def get_today_user_count() -> dict:
"""
查询今天新增用户数量。
"""
conn = get_connection()
try:
with conn.cursor() as cursor:
sql = """
SELECT COUNT(*) AS count
FROM users
WHERE DATE(created_at) = CURDATE()
"""
cursor.execute(sql)
row = cursor.fetchone()
return {
"date": "today",
"count": row["count"]
}
finally:
conn.close()
再增加昨天:
python
@tool
def get_yesterday_user_count() -> dict:
"""
查询昨天新增用户数量。
"""
conn = get_connection()
try:
with conn.cursor() as cursor:
sql = """
SELECT COUNT(*) AS count
FROM users
WHERE DATE(created_at)
= DATE_SUB(
CURDATE(),
INTERVAL 1 DAY
)
"""
cursor.execute(sql)
row = cursor.fetchone()
return {
"date": "yesterday",
"count": row["count"]
}
finally:
conn.close()
Agent:
python
agent = create_agent(
model="openai:your-model",
tools=[
get_today_user_count,
get_yesterday_user_count,
],
system_prompt="""
你是一名数据分析助手。
分析系统运营数据时:
1. 必须调用工具获取真实数据
2. 不允许编造数字
3. 如果进行同比、环比分析,需要展示计算过程
"""
)
用户:
python
result = agent.invoke({
"messages": [
{
"role": "user",
"content": """
分析一下今天新增用户和昨天相比增长了多少。
"""
}
]
})
Agent 可能自动:
text
get_today_user_count
↓
今天 120
get_yesterday_user_count
↓
昨天 100
计算:
(120 - 100) / 100 × 100%
↓
20%
最后回答:
text
今天新增用户120人,
昨天新增100人。
新增20人,
增长率为20%。
这已经是一个很典型的:
text
Data Agent
十六、给 Agent 增加计算器
为了避免模型自己做复杂计算,可以单独提供计算工具。
python
from langchain.tools import tool
@tool
def calculate_growth_rate(
current: float,
previous: float
) -> dict:
"""
计算增长率。
Args:
current: 当前数据
previous: 上一期数据
"""
if previous == 0:
return {
"success": False,
"message": "上一期数据不能为0"
}
change = current - previous
rate = (
change / previous
) * 100
return {
"current": current,
"previous": previous,
"change": change,
"growth_rate": round(rate, 2)
}
然后:
python
agent = create_agent(
model="openai:your-model",
tools=[
get_today_user_count,
get_yesterday_user_count,
calculate_growth_rate,
],
system_prompt="""
你是一名专业数据分析助手。
所有真实数据必须通过工具查询。
涉及增长率计算时,
优先调用 calculate_growth_rate,
不要自行猜测。
"""
)
于是工作流变成:
text
用户
↓
get_today_user_count
↓
get_yesterday_user_count
↓
calculate_growth_rate
↓
LLM解释结果
这就是 Tool Chain。
十七、Memory:让 Agent 记住上下文
普通调用:
python
agent.invoke(...)
如果每次都是完全独立的输入,Agent 不一定知道之前聊了什么。
例如:
text
用户:
查一下用户1001
AI:
张三,VIP用户
用户:
他最近的订单呢?
第二句话中的:
text
他
指的是用户 1001。
所以 Agent 需要保存会话上下文。
当前 LangChain Agent 底层基于 LangGraph,可以通过 checkpointer 保存线程级状态,从而实现短期记忆。
例如:
python
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent
checkpointer = InMemorySaver()
agent = create_agent(
model="openai:your-model",
tools=[
query_user,
query_order
],
checkpointer=checkpointer,
system_prompt="""
你是后台管理助手。
"""
)
第一次:
python
config = {
"configurable": {
"thread_id": "user-session-001"
}
}
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "帮我查询用户1001"
}
]
},
config=config
)
print(result["messages"][-1].content)
继续:
python
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "他是什么会员等级?"
}
]
},
config=config
)
print(result["messages"][-1].content)
因为:
python
thread_id
相同,所以可以关联上下文。
不同用户:
python
config = {
"configurable": {
"thread_id": "user-session-002"
}
}
就是另外一段独立会话。
十八、什么是 RAG?
前面 Tool 解决的是:
text
让 Agent 操作外部系统。
但还有另外一种问题:
text
公司内部文档怎么办?
例如:
text
开发规范
产品说明书
企业 Wiki
项目 README
API 文档
会议记录
技术文档
PDF
Markdown
这些内容大模型默认不知道。
如果全部塞 Prompt:
text
Prompt = 100MB文档 + 用户问题
显然不现实。
所以出现了:
text
RAG
全称:
text
Retrieval-Augmented Generation
简单理解:
text
用户提问
↓
搜索知识库
↓
找出最相关内容
↓
把内容给模型
↓
模型根据资料回答
也就是:
text
先查资料
再回答
十九、RAG 的完整流程
一个典型 RAG 系统:
text
原始文档
↓
Document Loader
↓
Text Splitter
↓
Chunks
↓
Embedding
↓
Vector Store
↓
Retriever
用户查询:
text
Question
↓
Embedding
↓
向量搜索
↓
Top K 文档
↓
LLM
↓
Answer
二十、先准备一个知识库
创建:
text
data/knowledge.txt
写入:
text
ShiyuAdmin 是一个后台管理系统。
项目主要用于快速搭建企业后台管理平台。
系统包含:
用户管理
角色管理
菜单管理
权限管理
部门管理
日志管理
权限系统采用 RBAC 模型。
Redis 主要用于缓存和部分高频数据。
MySQL 用于保存核心业务数据。
部署可以采用 Docker Compose。
二十一、文本切片
安装:
bash
pip install -U langchain-text-splitters
代码:
python
from langchain_text_splitters import (
RecursiveCharacterTextSplitter
)
with open(
"data/knowledge.txt",
"r",
encoding="utf-8"
) as f:
text = f.read()
splitter = RecursiveCharacterTextSplitter(
chunk_size=200,
chunk_overlap=30,
)
chunks = splitter.create_documents(
[text]
)
for index, doc in enumerate(chunks):
print(
f"----- chunk {index} -----"
)
print(doc.page_content)
对于普通文本,RecursiveCharacterTextSplitter 是 LangChain 官方文档推荐优先尝试的通用切分器。
二十二、Embedding
文本切开以后,需要把文字转换成向量。
例如:
text
Redis 是一个内存数据库
可能变成:
text
[
0.021,
-0.135,
0.743,
...
]
这种向量就叫:
text
Embedding
代码:
python
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(
model="your-embedding-model"
)
二十三、创建内存向量数据库
测试阶段可以直接使用:
python
InMemoryVectorStore
例如:
python
from langchain_core.vectorstores import (
InMemoryVectorStore
)
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(
model="your-embedding-model"
)
vector_store = (
InMemoryVectorStore.from_documents(
documents=chunks,
embedding=embeddings,
)
)
查询:
python
results = vector_store.similarity_search(
"项目的权限系统是什么?",
k=3
)
for doc in results:
print(
doc.page_content
)
官方当前示例同样可以通过 InMemoryVectorStore 配合 Embedding 构建一个最小可运行的语义检索系统。
二十四、把 Retriever 变成 Agent Tool
这一步非常关键。
我们不直接:
text
RAG -> LLM
而是:
text
Agent
↓
发现需要知识库
↓
调用 RAG Tool
↓
搜索知识库
↓
继续回答
创建 Tool:
python
from langchain.tools import tool
@tool
def search_knowledge_base(
query: str
) -> str:
"""
查询项目内部知识库。
当用户询问项目架构、
技术栈、部署方式、
权限设计等内部知识时使用。
"""
docs = vector_store.similarity_search(
query,
k=4
)
if not docs:
return "知识库没有找到相关内容"
result = []
for index, doc in enumerate(docs):
result.append(
f"""
[知识片段 {index + 1}]
{doc.page_content}
"""
)
return "\n".join(result)
测试:
python
print(
search_knowledge_base.invoke({
"query": "权限系统怎么设计的?"
})
)
二十五、创建 RAG Agent
现在:
python
agent = create_agent(
model="openai:your-model",
tools=[
search_knowledge_base
],
system_prompt="""
你是项目技术助手。
当用户询问项目自身的信息时:
必须优先调用 search_knowledge_base
查询内部知识库。
回答必须基于查询到的内容。
如果知识库没有相关信息,
明确告诉用户不知道,
禁止编造。
"""
)
调用:
python
result = agent.invoke({
"messages": [
{
"role": "user",
"content": "这个项目权限系统采用什么模型?"
}
]
})
print(
result["messages"][-1].content
)
Agent 会:
text
用户问题
↓
判断属于项目知识
↓
search_knowledge_base
↓
向量搜索
↓
找到:
权限系统采用 RBAC 模型
↓
LLM
↓
生成答案
这就是:
text
Agentic RAG
二十六、把数据库 Tool + RAG Tool 放到一起
真正有意思的地方来了。
我们可以同时给 Agent:
text
数据库
+
知识库
+
计算器
+
服务器
+
API
比如:
python
agent = create_agent(
model="openai:your-model",
tools=[
query_user_by_id,
get_today_user_count,
get_yesterday_user_count,
calculate_growth_rate,
search_knowledge_base,
],
system_prompt="""
你是一个企业后台智能 Agent。
你拥有以下能力:
1. 查询用户数据
2. 查询运营数据
3. 计算增长率
4. 查询内部项目知识库
规则:
涉及业务真实数据时,
必须调用数据库工具。
涉及项目知识时,
必须调用知识库工具。
涉及数学计算时,
优先使用计算工具。
禁止伪造工具返回结果。
"""
)
用户可以问:
text
今天新增用户比昨天增长多少?
Agent:
text
数据库 Tool
+
计算 Tool
用户问:
text
我们的权限系统是什么模型?
Agent:
text
RAG Tool
用户问:
text
查一下用户1,然后告诉我这个系统的权限设计是否适合他所在的角色体系。
甚至可能:
text
Database
↓
RAG
↓
LLM
这就是 Agent 真正强大的地方。
二十七、完整项目代码
下面我们把前面的内容整合一下。
python
import os
from datetime import datetime
import pymysql
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_openai import (
ChatOpenAI,
OpenAIEmbeddings,
)
from langchain_core.vectorstores import (
InMemoryVectorStore,
)
from langchain_text_splitters import (
RecursiveCharacterTextSplitter,
)
load_dotenv()
# ==================================================
# 1. 初始化大模型
# ==================================================
llm = ChatOpenAI(
model=os.getenv(
"MODEL_NAME",
"your-model"
),
api_key=os.getenv(
"OPENAI_API_KEY"
),
base_url=os.getenv(
"OPENAI_BASE_URL"
),
)
# ==================================================
# 2. MySQL
# ==================================================
def get_connection():
return pymysql.connect(
host=os.getenv(
"MYSQL_HOST",
"127.0.0.1"
),
port=int(
os.getenv(
"MYSQL_PORT",
"3306"
)
),
user=os.getenv(
"MYSQL_USER",
"root"
),
password=os.getenv(
"MYSQL_PASSWORD",
"123456"
),
database=os.getenv(
"MYSQL_DATABASE",
"agent_demo"
),
charset="utf8mb4",
cursorclass=(
pymysql.cursors.DictCursor
),
)
# ==================================================
# 3. 用户查询 Tool
# ==================================================
@tool
def query_user_by_id(
user_id: int
) -> dict:
"""
根据用户ID查询用户信息。
"""
conn = get_connection()
try:
with conn.cursor() as cursor:
sql = """
SELECT
id,
username,
email,
status,
created_at
FROM users
WHERE id = %s
LIMIT 1
"""
cursor.execute(
sql,
(user_id,)
)
result = cursor.fetchone()
if result is None:
return {
"success": False,
"message": "用户不存在"
}
if result.get("created_at"):
result["created_at"] = (
result["created_at"]
.strftime(
"%Y-%m-%d %H:%M:%S"
)
)
return {
"success": True,
"data": result
}
finally:
conn.close()
# ==================================================
# 4. 今日用户统计
# ==================================================
@tool
def get_today_user_count() -> dict:
"""
查询今天新增用户数量。
"""
conn = get_connection()
try:
with conn.cursor() as cursor:
cursor.execute(
"""
SELECT COUNT(*) AS count
FROM users
WHERE DATE(created_at)
= CURDATE()
"""
)
row = cursor.fetchone()
return {
"period": "today",
"count": row["count"]
}
finally:
conn.close()
# ==================================================
# 5. 昨日用户统计
# ==================================================
@tool
def get_yesterday_user_count() -> dict:
"""
查询昨天新增用户数量。
"""
conn = get_connection()
try:
with conn.cursor() as cursor:
cursor.execute(
"""
SELECT COUNT(*) AS count
FROM users
WHERE DATE(created_at)
=
DATE_SUB(
CURDATE(),
INTERVAL 1 DAY
)
"""
)
row = cursor.fetchone()
return {
"period": "yesterday",
"count": row["count"]
}
finally:
conn.close()
# ==================================================
# 6. 增长率 Tool
# ==================================================
@tool
def calculate_growth_rate(
current: float,
previous: float
) -> dict:
"""
根据当前值和上一期数据计算增长率。
"""
if previous == 0:
return {
"success": False,
"message": "previous不能为0"
}
change = current - previous
growth_rate = (
change / previous
) * 100
return {
"success": True,
"current": current,
"previous": previous,
"change": change,
"growth_rate": round(
growth_rate,
2
)
}
# ==================================================
# 7. 当前时间
# ==================================================
@tool
def get_current_time() -> str:
"""
获取当前服务器时间。
"""
return datetime.now().strftime(
"%Y-%m-%d %H:%M:%S"
)
# ==================================================
# 8. 初始化知识库
# ==================================================
def create_vector_store():
knowledge_file = (
"data/knowledge.txt"
)
with open(
knowledge_file,
"r",
encoding="utf-8"
) as f:
text = f.read()
splitter = (
RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=80,
)
)
documents = (
splitter.create_documents(
[text]
)
)
embeddings = OpenAIEmbeddings(
model=os.getenv(
"EMBEDDING_MODEL",
"your-embedding-model"
),
api_key=os.getenv(
"OPENAI_API_KEY"
),
base_url=os.getenv(
"OPENAI_BASE_URL"
),
)
return (
InMemoryVectorStore
.from_documents(
documents=documents,
embedding=embeddings,
)
)
vector_store = create_vector_store()
# ==================================================
# 9. 知识库搜索 Tool
# ==================================================
@tool
def search_knowledge_base(
query: str
) -> str:
"""
搜索项目内部知识库。
当问题涉及项目架构、
技术设计、功能说明、
开发文档、部署方法时调用。
"""
docs = (
vector_store
.similarity_search(
query,
k=4
)
)
if not docs:
return (
"内部知识库没有找到相关信息"
)
contents = []
for index, doc in enumerate(docs):
contents.append(
f"""
========== 知识片段 {index + 1} ==========
{doc.page_content}
"""
)
return "\n".join(contents)
# ==================================================
# 10. 创建 Agent
# ==================================================
agent = create_agent(
model=llm,
tools=[
query_user_by_id,
get_today_user_count,
get_yesterday_user_count,
calculate_growth_rate,
get_current_time,
search_knowledge_base,
],
system_prompt="""
你是企业后台管理系统中的AI Agent。
你的主要工作包括:
1. 查询用户数据
2. 分析运营数据
3. 查询项目内部知识
4. 完成简单的数据计算
5. 为管理员提供决策建议
=============================
数据规则
=============================
涉及真实用户数据时,
必须调用数据库工具。
涉及今日、昨日等运营数据时,
必须调用统计工具。
禁止编造数据库数据。
=============================
知识库规则
=============================
涉及项目功能、架构、
开发规范、技术设计、
部署方式等内容时:
优先调用 search_knowledge_base。
如果知识库没有相关信息,
明确告诉用户。
禁止根据常识伪造项目内部事实。
=============================
计算规则
=============================
涉及增长率计算,
优先调用 calculate_growth_rate。
=============================
回答要求
=============================
回答尽量简洁。
如果调用多个工具,
需要综合工具返回结果后再回答。
不要把内部推理过程直接展示给用户。
"""
)
# ==================================================
# 11. CLI
# ==================================================
def main():
print(
"LangChain Agent 已启动"
)
print(
"输入 exit 退出\n"
)
while True:
question = input(
"User > "
).strip()
if not question:
continue
if question.lower() in [
"exit",
"quit",
"q"
]:
break
try:
result = agent.invoke({
"messages": [
{
"role": "user",
"content": question
}
]
})
answer = (
result["messages"][-1]
.content
)
print(
f"\nAgent > {answer}\n"
)
except Exception as e:
print(
f"\nAgent执行失败:{e}\n"
)
if __name__ == "__main__":
main()
二十八、最终 .env
env
OPENAI_API_KEY=sk-xxxx
OPENAI_BASE_URL=https://example.com/v1
MODEL_NAME=your-model
EMBEDDING_MODEL=your-embedding-model
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=123456
MYSQL_DATABASE=agent_demo
二十九、测试我们的 Agent
启动:
bash
python main.py
测试数据库:
text
帮我查询用户1
测试统计:
text
今天新增多少用户?
测试多 Tool:
text
今天新增用户和昨天相比增长了多少?
Agent 可能:
text
get_today_user_count
↓
get_yesterday_user_count
↓
calculate_growth_rate
↓
最终回答
测试 RAG:
text
这个项目的权限系统采用什么设计?
Agent:
text
search_knowledge_base
↓
找到 RBAC
↓
回答
甚至可以问:
text
查询用户1的信息,
然后结合我们系统的权限架构,
分析应该如何给这个用户设计角色。
Agent 就可能:
text
query_user_by_id
↓
search_knowledge_base
↓
LLM综合分析
↓
最终答案
这时候它已经不是一个单纯的聊天机器人。
而是一个真正拥有:
text
LLM
+
Tool
+
Database
+
RAG
+
Reasoning
能力的 AI Agent。
三十、LangChain Agent 的核心到底是什么?
看到这里,其实可以发现 Agent 没有什么神秘的。
最核心的逻辑就是:
python
while True:
result = model(messages)
if result.need_tool:
tool_result = call_tool()
messages.append(
tool_result
)
else:
return result.answer
LangChain 帮我们解决的是外围大量工程问题:
text
模型统一接口
Prompt
Messages
Tool Schema
Tool Calling
Agent Loop
状态管理
Memory
RAG
Middleware
Tracing
工作流编排
所以可以把 LangChain Agent 简单理解为:
text
Model
+
Tools
+
Prompt
+
Agent Loop
而 LangChain 当前的 create_agent 也正是围绕这个思路设计的。
三十一、普通大模型、RAG 和 Agent 的区别
可以记住下面三个公式。
普通聊天:
text
LLM
RAG:
text
Retrieval
+
LLM
Agent:
text
LLM
+
Tools
+
Loop
复杂 Agent:
text
LLM
+
Tools
+
Memory
+
RAG
+
Workflow
+
Middleware
这也是目前开发 AI 应用非常值得掌握的一条技术路线。
三十二、生产环境还需要解决什么?
上面的代码已经可以跑,但是距离生产环境还有一段距离。
至少还需要考虑下面这些问题。
1. Tool 权限
不能让 Agent 拥有无限权限。
例如:
text
查询订单
可以自动执行。
但是:
text
删除订单
退款
封禁用户
转账
删除数据库
应该增加人工确认。
比较合理的架构:
text
低风险操作
↓
自动执行
高风险操作
↓
Human Approval
↓
执行
2. Tool 参数校验
不要直接相信模型生成的参数。
例如:
python
@tool
def refund_order(
order_id: str,
amount: float
):
应该先验证:
python
if amount <= 0:
raise ValueError(
"退款金额必须大于0"
)
还应该验证:
text
订单是否存在
订单是否属于用户
订单是否已经退款
退款金额是否超过付款金额
当前操作人是否有权限
Agent 只是决策层。
真正的数据安全还是应该由业务系统保证。
3. Timeout
工具调用一定要限制超时时间。
例如:
python
import requests
response = requests.get(
url,
timeout=10
)
否则某个 Tool 卡住:
text
Agent
↓
Tool
↓
无限等待
整个 Agent 都会被拖死。
4. 日志
至少记录:
text
request_id
user_id
session_id
tool_name
tool_args
tool_result
model
latency
token_usage
error
真实 Agent 系统最难排查的问题通常不是:
text
代码报错
而是:
text
为什么 AI 刚才选择了 Tool A,
没有选择 Tool B?
所以 Trace 非常重要。
LangChain 官方生态中的 LangSmith 就主要用于查看模型调用、Tool Call、状态转换、延迟以及 Agent 执行轨迹。
三十三、一个真正生产级 Agent 的架构
最终可以逐渐扩展成:
text
User
↓
API Gateway
↓
Agent Service
↓
Intent / Router
↓
┌─────────────┼─────────────┐
↓ ↓ ↓
RAG Tool MySQL Tool API Tool
↓ ↓ ↓
Vector DB MySQL Business API
└─────────────┼─────────────┘
↓
LLM
↓
Final Answer
继续复杂一些:
text
User
↓
Main Agent
↓
Planner
↓
┌──────────────┬──────────────┬──────────────┐
↓ ↓ ↓
RAG Agent SQL Agent DevOps Agent
↓ ↓ ↓
Vector DB MySQL Docker/K8s
└──────────────┴──────────────┴──────────────┘
↓
Main Agent
↓
Response
这就是:
text
Multi-Agent
也就是多个 Agent 分工协作。
三十四、最后总结
如果刚开始学习 LangChain,我不建议一上来就研究非常复杂的 Multi-Agent。
建议按这个顺序学习:
text
第一步
LLM.invoke()
↓
text
第二步
Prompt
+
LLM
↓
text
第三步
Structured Output
↓
text
第四步
Tool Calling
↓
text
第五步
create_agent
↓
text
第六步
Memory
↓
text
第七步
Embedding
+
Vector Store
+
RAG
↓
text
第八步
Agent
+
RAG
+
Database
+
API
↓
最后再进入:
text
LangGraph
Multi-Agent
Human in the Loop
Long-term Memory
MCP
Agent Middleware
生产级 Agent
如果把 LangChain 只理解成:
text
"大模型 API 的封装"
其实很难理解为什么还需要它。
真正进入 Agent 开发之后,你会发现 LangChain 更像是在做:
text
AI 应用的组织层。
大模型负责:
text
理解
推理
决策
Tool 负责:
text
真正执行操作
Memory 负责:
text
保存状态
RAG 负责:
text
提供外部知识
而 Agent 负责:
text
把这一切串起来。
最终我们得到的不再是:
text
一个会聊天的大模型。
而是:
text
一个能够理解任务、
查询资料、
访问数据库、
调用工具、
分析结果,
并最终完成任务的 AI Agent。