前 言

今天主要任务是给咱们的系统增加一些日志、异常处理并且加配置管理,这样咱们系统在出错时可以不再看traceback,而是能看清楚哪一步挂了。此外,咱们前面的代码API KEY、路径和模型名字是写死在代码中的,今天咱们将添加配置管理,让他们从代码中解耦。

第一步加logging

首先创建一个设置日志的函数logger_config.py

import logging

def setup_logger():
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s | %(levelname)s | %(name)s | %(message)s"
    )
    return logging.getLogger("rag_agent")

然后在app.pyagent.pyrag_system.py里都引入:

from logger_config import setup_logger

logger = setup_logger()

关于日志这里需要补充一些相关知识:

1、关于日志设置的字段%(xxx)s是占位符,其中:
%(asctime)s:日志记录的时间戳(如 2024-01-15 10:30:45,123)
%(levelname)s:日志级别(INFO、WARNING、ERROR、DEBUG等)
%(name)s:日志记录器的名称(通常是模块名或自定义名称)
%(message)s:实际的日志消息内容
2、level=logging.INFO语句设置日志等级为信息级,这个级别以下的信息会被忽略,关于日志级别:
CRITICAL (50) ← 最严重,最少输出

ERROR (40)

WARNING (30)

INFO (20)

DEBUG (10) ← 最不严重,最多输出

第二步加异常处理

前面的代码默认我们的每一步都成功,但是在做工程项目的时候,我们最好假设每一步都“可能失败”,所以我们需要对各种操作加上异常处理,app.py中的/ask,我们需要加上异常处理:

from fastapi import HTTPException

@app.post("/ask")
def ask_question(req: QueryRequest):
    try:
        answer = run_agent(req.question, TOOLS, rag)
        return {
            "question": req.question,
            "answer": answer
        }
    except Exception as e:
        logger.exception("Error occurred in /ask")
        raise HTTPException(status_code=500, detail=str(e))

前面我们定义的get_embedding函数可能因为网络不稳导致embedding失败,我们同样可以加上异常处理:

import time
import numpy as np

def get_embedding(text, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = client2.embeddings.create(
                model="text-embedding-3-small",
                input=text
            )
            return np.array(response.data[0].embedding, dtype="float32")
        except Exception as e:
            logger.warning(f"Embedding failed, retry {attempt+1}/{max_retries}: {e}")
            time.sleep(2)

    logger.error("Embedding failed after all retries")
    raise RuntimeError("Embedding generation failed")

choose_tool中模型有时可能不按要求返回JSON,所以这里也要加保护:

def choose_tool(query, tools):
    tool_desc = "\n".join([
        f"{t['name']}: {t['description']}" for t in tools
    ])

    prompt = f"""
                You are an AI agent.
                
                Available tools:
                {tool_desc}
                
                User question:
                {query}
                
                Return JSON:
                {{"tool": "...", "input": "..."}}
              """

    try:
        response = client.chat.completions.create(
            model=CHAT_MODEL,
            messages=[{"role": "user", "content": prompt}]
        )
        content = response.choices[0].message.content
        return json.loads(content)
    except:
        logger.warning(f"Tool decision parse failed: {content}")
        return {"tool": "llm", "input": query}

第三步做配置管理

这里容易踩坑,所以要特别说一下: 为什么要做配置管理,咱们再代码中写死API KEY、BASE URL、DATA路径以及模型名字,刚开始代码肯定能跑,但是有可能在日后出现问题,因为系统有可能会遇到换模型、换平台、上传服务器部署以及上Django这种情况,如果遇到,代码量又比较大,那么就得一个个改,很麻烦,所以咱们做一个配置管理,以后想要换的话,只需要修改配置文件就可以了。

咱们前面在根目录创建过一个.env文件,那个时候咱们在里面放了两个API KEY,这回咱们将内容丰富一下,写成下面的样子:

DEEPSEEK_API_KEY=你的deepseek_key
DEEPSEEK_BASE_URL=https://api.deepseek.com

EMBEDDING_API_KEY=你的embedding_key
EMBEDDING_BASE_URL=https://api.shubiaobiao.com/v1

CHAT_MODEL=deepseek-chat
EMBEDDING_MODEL=text-embedding-3-small
DATA_DIR=data

随后,创建一个config.py文件,在里面引入咱们所有的配置信息:

from dotenv import load_dotenv
import os

load_dotenv()

DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
DEEPSEEK_BASE_URL = os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com")

EMBEDDING_API_KEY = os.getenv("EMBEDDING_API_KEY")
EMBEDDING_BASE_URL = os.getenv("EMBEDDING_BASE_URL")

CHAT_MODEL = os.getenv("CHAT_MODEL", "deepseek-chat")
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "text-embedding-3-small")
DATA_DIR = os.getenv("DATA_DIR", "data")

然后咱们就可以修改咱们代码中用到大模型的地方了,比如llm_utils.py中,咱们模型的调用部分可以按照下面的方式修改:

from dotenv import load_dotenv
import os

load_dotenv()

DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
DEEPSEEK_BASE_URL = os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com")

EMBEDDING_API_KEY = os.getenv("EMBEDDING_API_KEY")
EMBEDDING_BASE_URL = os.getenv("EMBEDDING_BASE_URL")

CHAT_MODEL = os.getenv("CHAT_MODEL", "deepseek-chat")
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "text-embedding-3-small")
DATA_DIR = os.getenv("DATA_DIR", "data")

如果这篇文章对你有帮助,可以点个赞~
完整代码地址:https://github.com/1186141415/A-Paper-Rag-Agent

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐