11.从Demo到工程:RAG/Agent系统的日志、配置与异常处理
前 言
今天主要任务是给咱们的系统增加一些日志、异常处理并且加配置管理,这样咱们系统在出错时可以不再看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.py、agent.py、rag_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
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)