LangChain 从入门到 Agent 实战:用 Python 搭建一个真正能调用工具和知识库的 AI 助手

很多人第一次接触 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。
相关推荐
米小虾1 小时前
告别逐 token 蹦字:扩散语言模型(dLLM)到底能不能终结自回归?
人工智能·llm
火山引擎开发者社区1 小时前
从多模态数据湖到 Agent 湖:Lance 的格式设计与实践|Lance Meetup 火热报名中
人工智能
一枚爱吃大蒜的程序员1 小时前
CSDN文章-注意力约束QLoRA教育大模型微调
人工智能·机器学习·语言模型·qlora·大模型微调·注意力约束
郝学胜-神的一滴1 小时前
Qt 高级编程 045:坐标体系深度实战
开发语言·c++·windows·python·qt·程序人生
技术小事2 小时前
AI挖出6个curl漏洞 但另外23份是噪音
人工智能·网络安全·漏洞挖掘·cve·curl·ai安全
米小虾2 小时前
一周 AI 观察(9.1–9.7):模型能力开始"过剩",行业真正卷的是落地
人工智能·llm
weixin_500452512 小时前
2026合肥geo优化服务选择与避坑指南
人工智能
X7766X2 小时前
暴雨装备推出2U24全闪存储服务器倒逼信创存储迈入“极速时代”
人工智能
元启数宇2 小时前
2026建筑AI审图平台综合评测榜单:元启数宇位列第一
人工智能