Langchain和fastapi组合,可以构建一个强大的 AI 大模型后端框架,

  • FastAPI 是 Web 后端框架:负责处理 HTTP 请求、路由、并发、API 文档等标准后端任务。

  • LangChain 是 AI 应用框架:负责编排与大模型的交互、管理提示词、检索数据、调用工具等 AI 专属任务

ps:完整代码放在文章末尾,运行结果可以通过Swagger UI查看。

导入所需要的类和工具

import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Dict

# 导入LangChain 组件
from config import OPENAI_API_KEY
from langchain_openai import ChatOpenAI
from langchain_classic.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 ChatMessageHistory
from langchain_core.runnables import RunnableWithMessageHistory

稍微解释一下

  • HTTPException 用于返回错误

  • CORSMiddleware是一个中间件,它的核心作用就是让不同服务器(不同源)上的前端和后端能够正常通信

  • MessagesPlaceholder是一个占位符,用于对多条消息进行占位

初始化fastapi

app = FastAPI(title="猫娘 AI 助手后端")

# 解决跨域问题
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 生产环境建议改为具体的域名
    allow_methods=["*"],
    allow_headers=["*"],
)

这里allow_origins后面的可以改成具体的生产环境,比如特定的请求头、HTTP方法;除此之外,有了这个,你可以自己基于vue框架写一个前端文件实现前后端分离的应用。



Agent搭建

首先初始化模型,这里用的是国产模型deepseek,可以根据调用的模型使用相应的api-key

注意:api-key属于重要信息,应该放在config.py配置文件中再导入主程序。

llm = ChatOpenAI(
    model='deepseek-chat',
    base_url='https://api.deepseek.com',
    api_key=OPENAI_API_KEY,
)

定义工具


# 定义工具
@tool
def get_weather(location: str):
    '''获取天气信息'''
    return f'{location}今天天气晴朗,适合出门玩耍喵~'


tools = [get_weather]

这里的工具比较简单,我们模拟了一个获取天气消息的工具函数,实际上复杂一点的工具函数可以调用向量数据库从而获取信息。

注意:这里工具函数中的文本字符串是不可少的,目的是告诉llm这个工具的作用

定义prompt

# 定义提示词
prompt = ChatPromptTemplate.from_messages([
    ('system', '你是一个智能助手,并且可以通过调用工具解决问题'),
    MessagesPlaceholder(variable_name='history'),
    ('user', '{input}'),
    MessagesPlaceholder(variable_name='agent_scratchpad'),
])
  • ChatPromptTemplate是专门负责生成提示词模板

  • ‘system’表示系统,‘user’表示用户,这个列表就是Openai要求的对话格式;system后面的字符串就是对模型输入的提示词prompt,你可以根据你的需要修改这个字符串,比如你可以改成‘你是一只猫娘‘

  • MessagesPlaceholder是一个占位符,variable_name='history'表示插入历史聊天记录,variable_name='agent_scratchpad'非常重要,它负责实现模型工具调用功能。

构建agent

agent = create_tool_calling_agent(llm=llm, prompt=prompt, tools=tools)
agent_executor = AgentExecutor(agent=agent, tools=tools)

# 内存历史记录存储
store: Dict[str, ChatMessageHistory] = {}


def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    return store[session_id]

先通过create_tool_calling_agent封装agent,再通过AgentExecutor让agent能够自主调用工具

这里store: Dict[str, ChatMessageHistory] = {}简单地创建了一个字典来存储历史聊天记录,实际开发过程中可以替换成数据库。

get_session_history函数负责根据不同的用户id(session_id),来获取对应的聊天记录

带记忆的agent

agent_with_memory = RunnableWithMessageHistory(
    runnable=agent_executor,
    get_session_history=get_session_history,
    input_messages_key="input",
    history_messages_key="history",  # 务必确保与 Prompt 中的变量名一致
)

最后这里我们使用RunnableWithMessageHistory函数对原来的agent进行封装让agent具有“记忆功能”,我们完成一个简单的、具有记忆、调用工具能力的agent。

定义协议接口

class ChatRequest(BaseModel):
    message: str
    session_id: str


class ChatResponse(BaseModel):
    output: str
    session_id: str

这里我们定义两个数据模型,用于规范 FastAPI 接口的请求体响应体的格式;告诉前端发来的数据应该长什么样,后端返回的数据又该长什么样

所以ChatRequest在客户端发送 POST 请求时使用,ChatResponse在服务器返回数据时使用


​​​​​​定义API路由


@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    try:
        # 调用 LangChain 逻辑
        result = agent_with_memory.invoke(
            {"input": request.message},
            config={"configurable": {"session_id": request.session_id}}
        )

        # 返回结果
        return ChatResponse(
            output=result["output"],
            session_id=request.session_id
        )
    except Exception as e:
        # 捕获异常并返回 500 错误
        raise HTTPException(status_code=500, detail=str(e))

这里首先定义了一个post接口,路径为/chat

这个response_model是一个fastapi的关键字,负责指定响应格式模型response_model=ChatResponse 表明返回数据必须符合ChatResponse格式

agent_with_memory.invoke()是在将输入喂给llm并把输出返回给result,最后返回的result其实是个字典,键“output”的值才是真正的llm返回文本,并把llm返回的内容封装成ChatResponse格式

except Exception as e:表示当 try 块中的代码出错时,捕获异常,然后返回一个标准的 HTTP 500 错误响应给客户端。

完整代码如下:

import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Dict

# 导入你之前的 LangChain 组件
from config import OPENAI_API_KEY
from langchain_openai import ChatOpenAI
from langchain_classic.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 ChatMessageHistory
from langchain_core.runnables import RunnableWithMessageHistory


app = FastAPI(title="AI 助手后端")

# 解决跨域问题(让你的 Vue 前端可以访问)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  
    allow_methods=["*"],
    allow_headers=["*"],
)




llm = ChatOpenAI(
    model='deepseek-chat',
    base_url='https://api.deepseek.com',
    api_key=OPENAI_API_KEY,
)



@tool
def get_weather(location: str):
    '''获取天气信息'''
    return f'{location}今天天气晴朗,适合出门玩耍喵~'


tools = [get_weather]

prompt = ChatPromptTemplate.from_messages([
    ('system', '你是一个智能助手,并且你会调用工具解决问题。'),
    MessagesPlaceholder(variable_name='history'),
    ('user', '{input}'),
    MessagesPlaceholder(variable_name='agent_scratchpad'),
])


agent = create_tool_calling_agent(llm=llm, prompt=prompt, tools=tools)
agent_executor = AgentExecutor(agent=agent, tools=tools)


store: Dict[str, ChatMessageHistory] = {}


def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    return store[session_id]


agent_with_memory = RunnableWithMessageHistory(
    runnable=agent_executor,
    get_session_history=get_session_history,
    input_messages_key="input",
    history_messages_key="history",  # 务必确保与 Prompt 中的变量名一致
)



class ChatRequest(BaseModel):
    message: str
    session_id: str


class ChatResponse(BaseModel):
    output: str
    session_id: str



@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    try:
       
        result = agent_with_memory.invoke(
            {"input": request.message},
            config={"configurable": {"session_id": request.session_id}}
        )

        
        return ChatResponse(
            output=result["output"],
            session_id=request.session_id
        )
    except Exception as e:
       
        raise HTTPException(status_code=500, detail=str(e))


if __name__ == '__main__':
    uvicorn.run(app, host="127.0.0.1", port=8000)

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐