使用langchain框架开发智能问答系统,需要有mcp服务和工具调用

从零开发带工具调用能力的智能问答系统,核心是把 LLM(大脑)+ Tools(外部能力)+ Memory(记忆)+ Agent 编排 四块拼起来。LangChain 现在的推荐做法是:业务内简单工具用 @tool 直接封装,跨系统、要复用的能力走 MCP(Model Context Protocol) 标准化接入。下面按可落地的顺序一步步来。

一、整体架构与选型

一个生产可用的问答智能体通常包含:

复制代码
用户问题 → Agent(LLM 推理) → 选择工具 → 执行工具(API/MCP/RAG) → 观察结果 → 组织答案
                                      ↑                                        |
                                      └─────────────── 多轮循环 ───────────────┘

关键选型

  • 模型 :支持 tool calling 的大模型(GPT-4o、Claude、Qwen、DeepSeek 等均可,通过 langchain-openaibase_url 接兼容接口)
  • Agent 框架langchain + langgraph(LangChain 官方现在主推 LangGraph 做 Agent 编排)
  • 工具
    • 简单/业务紧耦合 → @tool 原生封装
    • 跨系统/需复用/独立部署 → MCP Server ,通过 langchain-mcp-adapters 接入
  • MCP 与 Function Calling 的关系互补而非替代。MCP 解决"工具接口标准化、多 Agent 共享",Function Calling 解决"单次模型如何调 API"。完整链路是:MCP Client 把 Server 的工具注册进来 → 转成模型的 tools 参数 → 模型用 Function Calling 选定工具 → Client 经 MCP Server 执行 → 结果回传模型。

二、环境准备

bash 复制代码
# 核心依赖
pip install langchain langchain-openai langchain-community langgraph
pip install langchain-mcp-adapters   # MCP 适配器
pip install python-dotenv           # 环境变量管理

# 如需本地 MCP Server(Node 版)
npm install -g @modelcontextprotocol/server-filesystem

.env 文件:

复制代码
OPENAI_API_KEY=你的key
OPENAI_BASE_URL=模型代理地址(可选,用于对接兼容接口)
MODEL_NAME=gpt-4o-mini

三、Step 1:搭建最小可跑通的 Agent(原生 @tool)

先用最简单的计算器工具跑通"思考→选工具→执行→回答"闭环:

python 复制代码
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool
from langchain_community.chat_message_histories import FileChatMessageHistory

load_dotenv()

# 1. 自定义工具:用 @tool 装饰器封装
@tool
def calculator(num1: float, num2: float, op: str) -> str:
    """数字计算工具,用于两个数字运算
    :param num1: 第一个数字
    :param num2: 第二个数字
    :param op: 运算符号,支持 + - * /
    """
    if op == "+": res = num1 + num2
    elif op == "-": res = num1 - num2
    elif op == "*": res = num1 * num2
    elif op == "/": res = num1 / num2
    else: return "不支持该运算符"
    return f"计算结果:{res}"

tools = [calculator]

# 2. 初始化 LLM
llm = ChatOpenAI(model=os.getenv("MODEL_NAME", "gpt-4o-mini"), temperature=0)

# 3. Prompt 模板(必须包含 agent_scratchpad)
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个擅长使用工具完成任务的助手,优先调用工具获取结果,不要凭空编造数据。"),
    MessagesPlaceholder(variable_name="chat_history"),
    ("user", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad"),
])

# 4. 创建 Agent 与 Executor
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 5. 持久化记忆
history = FileChatMessageHistory("./agent_memory.json")

while True:
    user_input = input("\n请输入你的问题(输入 exit 退出):")
    if user_input == "exit": break
    resp = agent_executor.invoke({"input": user_input, "chat_history": history.messages})
    print(f"AI:{resp['output']}")
    history.add_user_message(user_input)
    history.add_ai_message(resp["output"])

💡 工具描述的写法直接影响工具选择准确率。docstring 要写清:这个工具做什么、何时用、参数含义。模糊的描述会让模型乱调工具。


四、Step 2:接入外部 API 作为工具

真实问答系统几乎一定要调外部 REST API(订单查询、天气、搜索等)。用 @tool 封装 HTTP 请求即可:

python 复制代码
import requests
from langchain_core.tools import tool

@tool
def query_order(order_id: str) -> str:
    """查询订单状态,输入为订单ID(如 ORD12345)"""
    try:
        resp = requests.get(
            f"https://api.your-domain.com/orders/{order_id}",
            timeout=5
        )
        resp.raise_for_status()
        data = resp.json()
        return f"订单 {order_id} 状态: {data.get('status')}, 物流: {data.get('tracking_no')}"
    except requests.RequestException as e:
        return f"查询失败: {e}"

@tool
def get_weather(city: str) -> str:
    """获取指定城市的当前天气"""
    api_key = os.getenv("WEATHER_API_KEY")
    resp = requests.get(
        "https://api.weatherapi.com/v1/current.json",
        params={"key": api_key, "q": city},
        timeout=5
    )
    data = resp.json()
    return f"{city}: {data['current']['temp_c']}°C, {data['current']['condition']['text']}"

工具开发的最佳实践

  1. 异常处理:网络请求必须 try/except,返回友好错误信息而非抛异常
  2. 超时控制 :所有 HTTP 调用设 timeout
  3. 参数校验 :用 Pydantic StructuredTool 做强类型校验
  4. 敏感信息:API Key 走环境变量,禁止硬编码
  5. 幂等性:工具最好设计为可重复调用

把 API 工具加入 tools 列表即可让 Agent 自主调用:

python 复制代码
tools = [calculator, query_order, get_weather]

五、Step 3:接入 MCP 服务(重点)

当工具需要跨项目复用、独立部署、或被多个 Agent 共享时,应该把它做成 MCP Server。

5.1 编写一个 MCP Server

用 Python 的 FastMCP 写一个提供数学工具的 Server(math_server.py):

python 复制代码
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Math")

@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b

@mcp.tool()
def multiply(a: int, b: int) -> int:
    """Multiply two numbers"""
    return a * b

if __name__ == "__main__":
    mcp.run(transport="stdio")

也可以用 Node.js 写,两端完全解耦,互不干扰

5.2 在 LangChain 中接入 MCP 工具

langchain-mcp-adapters 支持 stdio(本地进程)Streamable HTTP(远程服务) 两种传输方式:

python 复制代码
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent

async def main():
    # 连接多个 MCP Server(stdio + http 混合)
    client = MultiServerMCPClient({
        "math": {
            "command": "python",
            "args": ["./math_server.py"],
            "transport": "stdio",
        },
        "weather": {
            "url": "http://localhost:8000/mcp",
            "transport": "http",
        }
    })

    tools = await client.get_tools()
    print(f"加载了 {len(tools)} 个 MCP 工具")

    # 创建 Agent
    agent = create_agent("openai:gpt-4.1", tools)

    result = await agent.ainvoke({"messages": "what's (3 + 5) x 12?"})
    print(result["output"])

asyncio.run(main())

如果用 JS/TS,@langchain/mcp-adapters 支持更丰富的配置(认证头、OAuth、自动重连等):

javascript 复制代码
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { createAgent } from "langchain";
import { ChatOpenAI } from "@langchain/openai";

const client = new MultiServerMCPClient({
  mcpServers: {
    math: {
      transport: "stdio",
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-math"],
    },
    weather: {
      url: "https://example.com/weather/mcp",
      headers: { Authorization: "Bearer token123" }
    }
  }
});

const tools = await client.getTools();
const model = new ChatOpenAI({ model: "gpt-4o-mini", temperature: 0 });
const agent = createAgent({ llm: model, tools });

⚠️ 生产环境务必 Pin MCP Server 版本,避免远程 Server 升级导致工具签名变化。

5.3 原生 @tool vs MCP 怎么选

维度 原生 @tool MCP Server
复用性 仅当前应用 任意 MCP 客户端可用
跨语言 不支持 Python/Node/Rust 全兼容
部署 随应用一起 可独立部署、升级
适用场景 快速原型、1-2 个工具 多系统共享、需独立运维

经验法则 :工具会被多个项目用到 → MCP;只是当前业务的简单封装 → @tool


六、Step 4:RAG + Agent 组合(知识库问答)

纯工具调用适合"操作类"问题,但企业问答往往需要基于私有文档回答。把 RAG 检索也封装成一个工具即可:

python 复制代码
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.tools import tool

# 假设已构建好向量库
vectorstore = Chroma(collection_name="docs", embedding_function=OpenAIEmbeddings())

@tool
def search_knowledge_base(query: str) -> str:
    """在企业知识库中检索相关文档,用于回答产品、政策、规范类问题"""
    docs = vectorstore.similarity_search(query, k=3)
    return "\n\n".join([doc.page_content for doc in docs])

# 工具组合:RAG + API + 计算
tools = [search_knowledge_base, query_order, calculator]

这样 Agent 会根据问题自主决定:是查知识库、还是调 API、还是直接计算。


七、Step 5:生产级增强

7.1 多轮记忆与上下文

除了上面演示的 FileChatMessageHistory,生产环境建议用 Redis 或数据库:

python 复制代码
from langchain_redis import RedisChatMessageHistory

history = RedisChatMessageHistory(session_id="user_123", url="redis://localhost:6379")

7.2 工具调用治理

  • 工具数量控制 :单个 Agent 工具数建议 10-15 个以内,过多会干扰模型选择
  • 超时与熔断:给每个工具设超时,失败重试 1-2 次
  • 日志与追踪:用 LangSmith 或 OpenTelemetry 记录每次 tool call 的输入输出
  • 权限控制:敏感工具(如退款、删除)加人工确认环节

7.3 错误处理模式

python 复制代码
agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,
    max_iterations=10,               # 防止无限循环
    handle_parsing_errors=True,      # 解析错误时优雅降级
    return_intermediate_steps=True,  # 返回中间步骤便于调试
)

八、完整项目结构建议

复制代码
my-agent/
├── .env                    # API Keys
├── math_server.py          # MCP Server(独立进程)
├── agent.py                # 主 Agent 入口
├── tools/                   # 原生 @tool 工具
│   ├── api_tools.py        # 外部 API 封装
│   └── rag_tool.py         # 知识库检索工具
├── config/
│   └── mcp_servers.json    # MCP Server 配置
└── memory/                  # 持久化记忆(如果用文件)

启动 MCP 增强的 Agent:

python 复制代码
import json
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from tools.api_tools import query_order, get_weather
from tools.rag_tool import search_knowledge_base

# 1. 加载 MCP 配置
with open("config/mcp_servers.json") as f:
    mcp_config = json.load(f)["mcpServers"]

# 2. 原生工具 + MCP 工具合并
mcp_client = MultiServerMCPClient(mcp_config)
mcp_tools = await mcp_client.get_tools()
native_tools = [query_order, get_weather, search_knowledge_base]
all_tools = native_tools + mcp_tools

# 3. 构建 Agent
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个企业智能助手,可调用工具查询订单、天气、知识库等。优先用工具获取真实数据。"),
    MessagesPlaceholder("chat_history"),
    ("user", "{input}"),
    MessagesPlaceholder("agent_scratchpad"),
])
agent = create_tool_calling_agent(llm, all_tools, prompt)
executor = AgentExecutor(agent=agent, tools=all_tools, verbose=True)

# 4. 运行
result = executor.invoke({"input": "查一下订单 ORD12345 的状态,并告诉我北京今天天气"})
print(result["output"])

九、调试与上线路径

  1. 本地跑通 :用 verbose=True 观察 Agent 的思考链
  2. 单元测试 :对每个 @tool 单独测试,确保输入输出符合预期
  3. 集成测试:用 LangSmith 追踪完整调用链路
  4. 生产部署
    • Agent 服务化(FastAPI 封装)
    • MCP Server 独立部署,通过 HTTP 传输
    • 加限流、鉴权、审计日志
    • 监控工具调用成功率与耗时

📌 最容易踩的坑

  • 忘记在 Prompt 里加 agent_scratchpad → Agent 无法写入思考过程
  • 工具 docstring 太模糊 → 模型选错工具
  • MCP Server 用 stdio 传输但路径不对 → 子进程拉起失败
  • 工具执行时间长阻塞主线程 → 改用异步工具

按这个路径,从零搭建的智能问答系统既能查知识库(RAG),又能调业务 API,还能通过 MCP 复用外部工具生态------这才是 2026 年生产级 Agent 的标准形态。

相关推荐
Joy T3 小时前
Agent 开源项目全景解析(下):LlamaIndex、Dify、FastGPT 与真实工程选型
langchain·开源·框架·agent·springai·langgraph·mcp
迷路爸爸1808 小时前
RAG 优化方案汇总介绍
python·langchain·agent·rag
做前端的娜娜子9 小时前
文档加载工程:多格式数据接入与 Document 标准化
langchain·ai编程·掘金·金石计划
北斗落凡尘11 小时前
LangGraph 入门实战(5)
python·langchain
董可伦12 小时前
RAG 工具怎么选:LangChain、LlamaIndex、Dify 实测对比
人工智能·ai·langchain·大模型
草莓熊Lotso13 小时前
【LangChain】核心技术:嵌入模型与向量存储完全指南
服务器·网络·python·langchain
65岁退休Coder1 天前
LangChain v1.3.4 笔记 - 07 补充:链式调用 LCEL
后端·python·langchain
做前端的娜娜子1 天前
Embedding 向量模型:从语义表示到相似度计算
langchain·openai·掘金·金石计划
leo_messi941 天前
langchain学习(三) - tools使用
学习·langchain