AI Agent系列记录(第一篇)

6 阅读9分钟

Python AI Agent 项目技术学习笔记(第一篇)

1. 项目整体架构

1.1 项目目录结构

api-server/
├── app/            # 应用入口
│   └── http/       # HTTP 服务配置
├── config/         # 配置管理
├── internal/       # 核心业务逻辑
│   ├── core/       # 核心功能
│   ├── exception/  # 异常处理
│   ├── extension/  # 扩展组件
│   ├── handler/    # 请求处理器
│   ├── model/      # 数据模型
│   ├── router/     # 路由管理
│   ├── schema/     # 数据验证
│   ├── server/     # 服务器配置
│   └── service/    # 业务服务
├── pkg/            # 公共包
│   ├── response/   # 响应处理
│   └── sqlalchemy/ # 数据库扩展
└── storage/        # 存储目录
    └── memory/     # 聊天历史存储

1.2 核心组件关系

flowchart TD
    A[app.py 入口] --> B[Http 服务器]
    B --> C[Router 路由]
    C --> D[AppHandler 处理器]
    D --> E[AppService 服务]
    D --> F[LangChain AI]
    E --> G[数据库模型]
    F --> H[OpenAI/Kimi API]

2. 核心组件详解

2.1 应用入口 (app.py)

文件位置: app/http/app.py

import sys
import os

# 添加项目根目录到Python路径,确保导入模块时可以找到
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))

# 先导入其他模块,确保 sys.path 已经设置好
from internal.server import Http
from internal.router import Router
from injector import Injector, Module, Binder
from config import Config
from internal.extension.database_extension import db
from pkg.sqlalchemy import SQLAlchemy
from flask_migrate import Migrate


# 定义扩展Module,用于绑定SQLAlchemy和Migrate实例
class ExtensionModule(Module):
    def configure(self, binder: Binder):
        binder.bind(SQLAlchemy, to=db)
        binder.bind(Migrate, to=Migrate())


# 加载环境变量
import dotenv

dotenv.load_dotenv()

inject = Injector([ExtensionModule])

# 应用配置
conf = Config()

app = Http(
    __name__,
    router=inject.get(Router),
    db=inject.get(SQLAlchemy),
    migrate=inject.get(Migrate),
    conf=conf,
)

if __name__ == "__main__":
    app.run(debug=True, port=5001, host='0.0.0.0')

关键概念解释

  • Python 路径设置sys.path.append() 用于添加项目根目录到 Python 路径,确保模块导入正常
  • 依赖注入:使用 Injector 管理依赖,类似于前端的依赖注入容器(如 Angular 的 DI)
  • 环境变量:使用 dotenv 加载环境变量,类似于前端的 .env 文件

2.2 HTTP 服务器 (Http 类)

文件位置: internal/server/http.py

from flask import Flask
from internal.router import Router
from config import Config
from internal.exception import CustomException
from pkg.response import Response, json
from pkg.response.http_code import HttpCode
from pkg.sqlalchemy import SQLAlchemy
from internal.model import App
from flask_migrate import Migrate
from flask_cors import CORS


class Http(Flask):
    # HTTP服务引擎
    def __init__(
        self,
        *args,
        router: Router,
        db: SQLAlchemy,
        migrate: Migrate,
        conf: Config,
        **kwargs
    ):
        # 初始化HTTP服务引擎
        super().__init__(*args, **kwargs)

        # 应用配置
        self.config.from_object(conf)

        # 异常错误处理
        self.register_error_handler(Exception, self._register_error_handler)

        # 注册数据库扩展
        db.init_app(self)

        # 注册CORS扩展(跨域设置)
        CORS(
            self,
            resources={
                r"/*": {
                    "origins": "http://localhost:5173",
                    "supports_credentials": True,
                    "allow_headers": "Content-Type",
                    "allow_methods": "GET, POST",
                }
            },
        )

        # 注册迁移扩展
        migrate.init_app(self, db, directory="internal/migration")

        # 注册路由
        router.register_routes(self)

    def _register_error_handler(self, error: Exception):
        print("异常:", error)
        # 处理自定义异常
        if isinstance(error, CustomException):
            return json(
                Response(
                    code=error.code,
                    message=error.message,
                    data=error.data if error.data is not None else {},
                )
            )

        return json(Response(code=HttpCode.FAIL, message=str(error), data={}))

关键概念解释

  • 类继承Http 类继承自 Flask,类似于前端的类继承
  • 构造函数__init__ 方法用于初始化对象,接受多个参数
  • CORS 配置:设置跨域资源共享,允许前端从 http://localhost:5173 访问
  • 异常处理:统一处理应用中的异常,返回标准格式的错误响应

2.3 路由管理 (Router 类)

文件位置: internal/router/router.py

from flask import Flask,Blueprint
from internal.handler import AppHandler
from injector import inject
from dataclasses import dataclass

@inject
@dataclass
class Router:
    # 路由注册器
    app_handler: AppHandler

    def register_routes(self, app: Flask):
        # 创建一个蓝图
        bp = Blueprint("llmops", __name__,url_prefix="")
        # URL与路由绑定
        bp.add_url_rule("/ping",  view_func=self.app_handler.ping)
        bp.add_url_rule("/apps/<uuid:app_id>/debug",  view_func=self.app_handler.debug, methods=["POST"])
        
        bp.add_url_rule("/app",  view_func=self.app_handler.create_app, methods=["POST"])
        bp.add_url_rule("/app/<uuid:id>",  view_func=self.app_handler.get_app)
        bp.add_url_rule("/app/<uuid:id>",  view_func=self.app_handler.update_app, methods=["POST"])
        bp.add_url_rule("/app/<uuid:id>/delete",  view_func=self.app_handler.delete_app, methods=["POST"])
        
        
        # 注册蓝图
        app.register_blueprint(bp) 

关键概念解释

  • 装饰器@inject@dataclass 是 Python 装饰器,类似于前端的装饰器(如 React 的 @useState
  • 蓝图Blueprint 是 Flask 中用于组织路由的方式,类似于前端的路由模块
  • URL 规则add_url_rule 用于绑定 URL 与处理函数
  • UUID 类型<uuid:app_id> 是 Flask 的 URL 参数类型,用于匹配 UUID 格式的参数

2.4 应用处理器 (AppHandler 类)

文件位置: internal/handler/app_handler.py

from flask import request, jsonify
from openai import OpenAI, RateLimitError
import os
from internal.schema.app_schema import CompletionReq
from internal.service.app_service import AppService
from dataclasses import dataclass
from injector import inject, Injector
from operator import itemgetter
import uuid

from langchain_classic.memory import ConversationBufferWindowMemory
from langchain_community.chat_message_histories import FileChatMessageHistory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
from langchain_openai import ChatOpenAI


from pkg.response import (
    success_json,
    validate_error_json,
    success_message,
)


# 应用控制器
@inject
@dataclass
class AppHandler:

    app_service: AppService

    def create_app(self):
        app = self.app_service.create_app()
        return success_message(f"应用创建成功,应用ID: {app.id}")
    def get_app(self, id: uuid.UUID):
        app = self.app_service.get_app(id)
        return success_json({
            "id": app.id,
            "name": app.name,
            "account_id": app.account_id,
            "icon": app.icon,
            "description": app.description,
        })
    def update_app(self, id: uuid.UUID):
        app = self.app_service.update_app(id)
        return success_message(f"应用更新成功,应用ID: {app.name}")
    def delete_app(self, id: uuid.UUID):
        app = self.app_service.delete_app(id)
        return success_message(f"应用删除成功,应用ID: {app.id}")

    def debug(self, app_id: uuid.UUID):
        """聊天接口"""
        # 1.定义请求参数的验证规则
        req = CompletionReq(data=request.json)
        if not req.validate():
            return validate_error_json(req.errors)
        # 从环境变量获取API密钥
        moonshot_api_key = os.getenv("MOONSHOT_API_KEY")
        moonshot_api_url = os.getenv("MOONSHOT_API_URL")
        
        # langchain 调用方式
        # 2.创建prompt与记忆
        prompt = ChatPromptTemplate.from_messages([
            ("system", "你是一个强大的聊天机器人,能根据用户的提问回复对应的问题"),
            MessagesPlaceholder("history"),
            ("human", "{query}"),
        ])
        memory = ConversationBufferWindowMemory(
            k=3,
            input_key="query",
            output_key="output",
            return_messages=True,
            chat_memory=FileChatMessageHistory("./storage/memory/chat_history.txt"),
        )

        # 3.创建llm
        llm = ChatOpenAI(model="kimi-k2.5", api_key=moonshot_api_key, base_url=moonshot_api_url)

        # 4.创建链应用
        chain = RunnablePassthrough.assign(
            history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
        ) | prompt | llm | StrOutputParser()

        # 5.调用链生成内容
        chain_input = {"query": req.query.data}
        content = chain.invoke(chain_input)
        memory.save_context(chain_input, {"output": content})
        return success_json({"content": content})

    def ping(self):
        return success_json({"ping": "pong"})

关键概念解释

  • 数据验证:使用 CompletionReq 验证请求参数,类似于前端的表单验证
  • 环境变量:使用 os.getenv() 获取环境变量,类似于前端的 process.env
  • LangChain 集成:使用 LangChain 框架构建 AI 对话系统
    • Prompt:定义系统提示和用户输入模板
    • Memory:使用 ConversationBufferWindowMemory 保存对话历史
    • LLM:使用 ChatOpenAI 调用 Kimi 模型
    • Chain:构建处理链,将多个组件连接起来
  • UUID 类型:使用 uuid.UUID 类型注解,类似于 TypeScript 的类型注解

3. AI Agent 核心实现

3.1 LangChain 链构建

核心代码

# 2.创建prompt与记忆
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个强大的聊天机器人,能根据用户的提问回复对应的问题"),
    MessagesPlaceholder("history"),
    ("human", "{query}"),
])
memory = ConversationBufferWindowMemory(
    k=3,  # 保留最近3轮对话
    input_key="query",
    output_key="output",
    return_messages=True,
    chat_memory=FileChatMessageHistory("./storage/memory/chat_history.txt"),
)

# 3.创建llm
llm = ChatOpenAI(model="kimi-k2.5", api_key=moonshot_api_key, base_url=moonshot_api_url)

# 4.创建链应用
chain = RunnablePassthrough.assign(
    history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
) | prompt | llm | StrOutputParser()

# 5.调用链生成内容
chain_input = {"query": req.query.data}
content = chain.invoke(chain_input)
memory.save_context(chain_input, {"output": content})

工作流程

  1. 构建提示模板:定义系统消息、历史消息占位符和用户输入模板
  2. 初始化记忆:创建对话记忆,保存最近3轮对话
  3. 创建LLM实例:配置Kimi模型
  4. 构建处理链
    • 加载对话历史
    • 应用提示模板
    • 调用LLM生成回复
    • 解析输出
  5. 执行链:传入用户查询,获取回复
  6. 保存上下文:将用户查询和AI回复保存到记忆中

3.2 对话记忆管理

核心代码

memory = ConversationBufferWindowMemory(
    k=3,  # 保留最近3轮对话
    input_key="query",
    output_key="output",
    return_messages=True,
    chat_memory=FileChatMessageHistory("./storage/memory/chat_history.txt"),
)

# 保存对话
memory.save_context(chain_input, {"output": content})

功能说明

  • 窗口大小k=3 表示只保留最近3轮对话,避免记忆过大
  • 持久化:使用 FileChatMessageHistory 将对话历史保存到文件中
  • 输入输出键:指定输入和输出的键名,确保链中数据传递正确

4. 前端开发者需要了解的 Python 概念

4.1 装饰器

Python 装饰器

@inject
@dataclass
class Router:
    # 路由注册器
    app_handler: AppHandler

前端类比

  • 类似于 React 的 HOC (Higher-Order Component)
  • 类似于 JavaScript 的装饰器提案
  • 用于增强函数或类的功能

4.2 数据类

Python 数据类

from dataclasses import dataclass

@dataclass
class AppHandler:
    app_service: AppService

前端类比

  • 类似于 TypeScript 的接口或类型
  • 类似于 JavaScript 的类
  • 用于定义数据结构

4.3 依赖注入

Python 依赖注入

from injector import Injector, Module, Binder

class ExtensionModule(Module):
    def configure(self, binder: Binder):
        binder.bind(SQLAlchemy, to=db)
        binder.bind(Migrate, to=Migrate())

inject = Injector([ExtensionModule])
app_handler = inject.get(AppHandler)

前端类比

  • 类似于 Angular 的依赖注入系统
  • 类似于 React 的 Context API
  • 用于管理组件依赖

4.4 类型注解

Python 类型注解

def get_app(self, id: uuid.UUID):
    app = self.app_service.get_app(id)
    return success_json({...})

前端类比

  • 类似于 TypeScript 的类型注解
  • 用于静态类型检查
  • 提高代码可读性和可维护性

4.5 模块导入

Python 模块导入

import sys
import os

# 添加项目根目录到Python路径
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))

from internal.server import Http

前端类比

  • 类似于 ES6 的 import 语句
  • 类似于 CommonJS 的 require
  • 用于导入其他模块的功能

5. 与前端的交互

5.1 API 接口

接口路径方法功能
/pingGET健康检查
/apps/<app_id>/debugPOSTAI 聊天接口
/appPOST创建应用
/app/<id>GET获取应用详情
/app/<id>POST更新应用
/app/<id>/deletePOST删除应用

5.2 响应格式

成功响应

{
  "code": "success",
  "message": "操作成功",
  "data": {...}
}

失败响应

{
  "code": "fail",
  "message": "错误信息",
  "data": {}
}

5.3 CORS 配置

CORS(
    self,
    resources={
        r"/*": {
            "origins": "http://localhost:5173",
            "supports_credentials": True,
            "allow_headers": "Content-Type",
            "allow_methods": "GET, POST",
        }
    },
)

配置说明

  • origins:允许的前端域名
  • supports_credentials:是否支持携带凭证
  • allow_headers:允许的请求头
  • allow_methods:允许的 HTTP 方法

6. 项目启动与运行

6.1 环境变量配置

创建 .env 文件:

# 数据库配置
DATABASE_URL="postgresql://username:password@localhost:5432/llmops"

#  moonshot API 配置
MOONSHOT_API_KEY="your_api_key"
MOONSHOT_API_URL="https://api.moonshot.cn/v1"

# Flask 配置
FLASK_APP="app/http/app.py"
FLASK_ENV="development"

6.2 安装依赖

pip3 install -r requirements.txt

6.3 启动服务

python3 app/http/app.py

服务将在 http://127.0.0.1:5001 启动。

7. 代码优化建议

7.1 错误处理优化

当前实现

def _register_error_handler(self, error: Exception):
    print("异常:", error)
    # 处理自定义异常
    if isinstance(error, CustomException):
        return json(
            Response(
                code=error.code,
                message=error.message,
                data=error.data if error.data is not None else {},
            )
        )

    return json(Response(code=HttpCode.FAIL, message=str(error), data={}))

优化建议

def _register_error_handler(self, error: Exception):
    import traceback
    # 记录详细错误信息
    print("异常:", error)
    traceback.print_exc()
    
    # 处理自定义异常
    if isinstance(error, CustomException):
        return json(
            Response(
                code=error.code,
                message=error.message,
                data=error.data if error.data is not None else {},
            )
        )
    
    # 处理不同类型的异常
    if isinstance(error, RateLimitError):
        return json(Response(code=HttpCode.FAIL, message="API 速率限制,请稍后再试", data={}))
    elif isinstance(error, FileNotFoundError):
        return json(Response(code=HttpCode.FAIL, message="文件不存在", data={}))

    return json(Response(code=HttpCode.FAIL, message=str(error), data={}))

7.2 记忆管理优化

当前实现

memory = ConversationBufferWindowMemory(
    k=3,
    input_key="query",
    output_key="output",
    return_messages=True,
    chat_memory=FileChatMessageHistory("./storage/memory/chat_history.txt"),
)

优化建议

# 使用应用ID作为文件名,实现每个应用独立的聊天历史
chat_history_file = f"./storage/memory/chat_history_{app_id}.txt"
# 确保目录存在
os.makedirs(os.path.dirname(chat_history_file), exist_ok=True)

memory = ConversationBufferWindowMemory(
    k=5,  # 增加历史记录数量
    input_key="query",
    output_key="output",
    return_messages=True,
    chat_memory=FileChatMessageHistory(chat_history_file),
)

7.3 配置管理优化

当前实现

# 从环境变量获取API密钥
moonshot_api_key = os.getenv("MOONSHOT_API_KEY")
moonshot_api_url = os.getenv("MOONSHOT_API_URL")

优化建议

# 从配置对象获取,集中管理配置
moonshot_api_key = self.conf.MOONSHOT_API_KEY
moonshot_api_url = self.conf.MOONSHOT_API_URL

# 添加配置验证
if not moonshot_api_key:
    raise CustomException(code=HttpCode.FAIL, message="MOONSHOT_API_KEY 未配置")
if not moonshot_api_url:
    raise CustomException(code=HttpCode.FAIL, message="MOONSHOT_API_URL 未配置")

8. 总结

本项目是一个基于 Python Flask 框架的 AI Agent 后端服务,核心功能包括:

  1. RESTful API:提供应用管理和 AI 聊天接口
  2. LangChain 集成:使用 LangChain 框架构建 AI 对话系统
  3. 依赖注入:使用 injector 管理组件依赖
  4. 数据库集成:使用 SQLAlchemy 管理数据模型
  5. CORS 配置:支持前端跨域访问

第二篇笔记总结中...